mirror of
https://github.com/siderolabs/talos.git
synced 2025-08-19 05:31:14 +02:00
feat: add create and overwrite file operations
This adds `create` and `overwrite` file operations so that we can have better sanity checks around extra files. Signed-off-by: Andrew Rynhard <andrew@andrewrynhard.com>
This commit is contained in:
parent
ad863a7f92
commit
fa4fb4d444
@ -242,6 +242,10 @@ install:
|
|||||||
#### files
|
#### files
|
||||||
|
|
||||||
Allows the addition of user specified files.
|
Allows the addition of user specified files.
|
||||||
|
The value of `op` can be `create`, `overwrite`, or `append`.
|
||||||
|
In the case of `create`, `path` must not exist.
|
||||||
|
In the case of `overwrite`, and `append`, `path` must be a valid file.
|
||||||
|
If an `op` value of `append` is used, the existing file will be appended.
|
||||||
Note that the file contents are not required to be base64 encoded.
|
Note that the file contents are not required to be base64 encoded.
|
||||||
|
|
||||||
Type: `array`
|
Type: `array`
|
||||||
@ -249,11 +253,12 @@ Type: `array`
|
|||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
kubelet:
|
files:
|
||||||
contents: |
|
- content: |
|
||||||
...
|
...
|
||||||
permissions: 0666
|
permissions: 0666
|
||||||
path: /tmp/file.txt
|
path: /tmp/file.txt
|
||||||
|
op: append
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ Put into each machine the PEM encoded certificate:
|
|||||||
machine:
|
machine:
|
||||||
...
|
...
|
||||||
files:
|
files:
|
||||||
- contents: |
|
- content: |
|
||||||
-----BEGIN CERTIFICATE-----
|
-----BEGIN CERTIFICATE-----
|
||||||
...
|
...
|
||||||
-----END CERTIFICATE-----
|
-----END CERTIFICATE-----
|
||||||
|
@ -31,12 +31,30 @@ func (task *ExtraFiles) TaskFunc(mode runtime.Mode) phase.TaskFunc {
|
|||||||
return task.runtime
|
return task.runtime
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint: gocyclo
|
||||||
func (task *ExtraFiles) runtime(r runtime.Runtime) (err error) {
|
func (task *ExtraFiles) runtime(r runtime.Runtime) (err error) {
|
||||||
var result *multierror.Error
|
var result *multierror.Error
|
||||||
|
|
||||||
for _, f := range r.Config().Machine().Files() {
|
for _, f := range r.Config().Machine().Files() {
|
||||||
// Slurp existing file if append is our op and add contents to it
|
content := f.Content
|
||||||
if f.Op == "append" {
|
|
||||||
|
switch f.Op {
|
||||||
|
case "create":
|
||||||
|
if err = doesNotExists(f.Path); err != nil {
|
||||||
|
result = multierror.Append(result, fmt.Errorf("file must not exist: %q", f.Path))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
case "overwrite":
|
||||||
|
if err = existsAndIsFile(f.Path); err != nil {
|
||||||
|
result = multierror.Append(result, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
case "append":
|
||||||
|
if err = existsAndIsFile(f.Path); err != nil {
|
||||||
|
result = multierror.Append(result, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
var existingFileContents []byte
|
var existingFileContents []byte
|
||||||
|
|
||||||
existingFileContents, err = ioutil.ReadFile(f.Path)
|
existingFileContents, err = ioutil.ReadFile(f.Path)
|
||||||
@ -45,7 +63,10 @@ func (task *ExtraFiles) runtime(r runtime.Runtime) (err error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
f.Contents = string(existingFileContents) + "\n" + f.Contents
|
content = string(existingFileContents) + "\n" + f.Content
|
||||||
|
default:
|
||||||
|
result = multierror.Append(result, fmt.Errorf("unknown operation for file %q: %q", f.Path, f.Op))
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine if supplied path is in /var or not.
|
// Determine if supplied path is in /var or not.
|
||||||
@ -62,12 +83,18 @@ func (task *ExtraFiles) runtime(r runtime.Runtime) (err error) {
|
|||||||
inVar = false
|
inVar = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We do not want to support creating new files anywhere outside of
|
||||||
|
// /var. If a valid use case comes up, we can reconsider then.
|
||||||
|
if !inVar && f.Op == "create" {
|
||||||
|
return fmt.Errorf("create operation not allowed outside of /var: %q", f.Path)
|
||||||
|
}
|
||||||
|
|
||||||
if err = os.MkdirAll(filepath.Dir(p), os.ModeDir); err != nil {
|
if err = os.MkdirAll(filepath.Dir(p), os.ModeDir); err != nil {
|
||||||
result = multierror.Append(result, err)
|
result = multierror.Append(result, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = ioutil.WriteFile(p, []byte(f.Contents), f.Permissions); err != nil {
|
if err = ioutil.WriteFile(p, []byte(content), f.Permissions); err != nil {
|
||||||
result = multierror.Append(result, err)
|
result = multierror.Append(result, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -82,3 +109,35 @@ func (task *ExtraFiles) runtime(r runtime.Runtime) (err error) {
|
|||||||
|
|
||||||
return result.ErrorOrNil()
|
return result.ErrorOrNil()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func doesNotExists(p string) (err error) {
|
||||||
|
_, err = os.Stat(p)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("file exists")
|
||||||
|
}
|
||||||
|
|
||||||
|
func existsAndIsFile(p string) (err error) {
|
||||||
|
var info os.FileInfo
|
||||||
|
|
||||||
|
info, err = os.Stat(p)
|
||||||
|
if err != nil {
|
||||||
|
if !os.IsNotExist(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("file must exist: %q", p)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !info.Mode().IsRegular() {
|
||||||
|
return fmt.Errorf("invalid mode: %q", info.Mode().String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -44,7 +44,7 @@ type Env = map[string]string
|
|||||||
|
|
||||||
// File represents a file to write to disk.
|
// File represents a file to write to disk.
|
||||||
type File struct {
|
type File struct {
|
||||||
Contents string `yaml:"contents"`
|
Content string `yaml:"content"`
|
||||||
Permissions os.FileMode `yaml:"permissions"`
|
Permissions os.FileMode `yaml:"permissions"`
|
||||||
Path string `yaml:"path"`
|
Path string `yaml:"path"`
|
||||||
Op string `yaml:"op"`
|
Op string `yaml:"op"`
|
||||||
|
@ -125,14 +125,19 @@ type MachineConfig struct {
|
|||||||
MachineInstall *InstallConfig `yaml:"install,omitempty"`
|
MachineInstall *InstallConfig `yaml:"install,omitempty"`
|
||||||
// description: |
|
// description: |
|
||||||
// Allows the addition of user specified files.
|
// Allows the addition of user specified files.
|
||||||
|
// The value of `op` can be `create`, `overwrite`, or `append`.
|
||||||
|
// In the case of `create`, `path` must not exist.
|
||||||
|
// In the case of `overwrite`, and `append`, `path` must be a valid file.
|
||||||
|
// If an `op` value of `append` is used, the existing file will be appended.
|
||||||
// Note that the file contents are not required to be base64 encoded.
|
// Note that the file contents are not required to be base64 encoded.
|
||||||
// examples:
|
// examples:
|
||||||
// - |
|
// - |
|
||||||
// kubelet:
|
// files:
|
||||||
// contents: |
|
// - content: |
|
||||||
// ...
|
// ...
|
||||||
// permissions: 0666
|
// permissions: 0666
|
||||||
// path: /tmp/file.txt
|
// path: /tmp/file.txt
|
||||||
|
// op: append
|
||||||
MachineFiles []machine.File `yaml:"files,omitempty"` // Note: The specified `path` is relative to `/var`.
|
MachineFiles []machine.File `yaml:"files,omitempty"` // Note: The specified `path` is relative to `/var`.
|
||||||
// description: |
|
// description: |
|
||||||
// The `env` field allows for the addition of environment variables to a machine.
|
// The `env` field allows for the addition of environment variables to a machine.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user