mirror of
https://github.com/siderolabs/talos.git
synced 2025-08-18 21:21:10 +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
|
||||
|
||||
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.
|
||||
|
||||
Type: `array`
|
||||
@ -249,11 +253,12 @@ Type: `array`
|
||||
Examples:
|
||||
|
||||
```yaml
|
||||
kubelet:
|
||||
contents: |
|
||||
...
|
||||
permissions: 0666
|
||||
path: /tmp/file.txt
|
||||
files:
|
||||
- content: |
|
||||
...
|
||||
permissions: 0666
|
||||
path: /tmp/file.txt
|
||||
op: append
|
||||
|
||||
```
|
||||
|
||||
|
@ -10,7 +10,7 @@ Put into each machine the PEM encoded certificate:
|
||||
machine:
|
||||
...
|
||||
files:
|
||||
- contents: |
|
||||
- content: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
...
|
||||
-----END CERTIFICATE-----
|
||||
|
@ -31,12 +31,30 @@ func (task *ExtraFiles) TaskFunc(mode runtime.Mode) phase.TaskFunc {
|
||||
return task.runtime
|
||||
}
|
||||
|
||||
// nolint: gocyclo
|
||||
func (task *ExtraFiles) runtime(r runtime.Runtime) (err error) {
|
||||
var result *multierror.Error
|
||||
|
||||
for _, f := range r.Config().Machine().Files() {
|
||||
// Slurp existing file if append is our op and add contents to it
|
||||
if f.Op == "append" {
|
||||
content := f.Content
|
||||
|
||||
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
|
||||
|
||||
existingFileContents, err = ioutil.ReadFile(f.Path)
|
||||
@ -45,7 +63,10 @@ func (task *ExtraFiles) runtime(r runtime.Runtime) (err error) {
|
||||
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.
|
||||
@ -62,12 +83,18 @@ func (task *ExtraFiles) runtime(r runtime.Runtime) (err error) {
|
||||
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 {
|
||||
result = multierror.Append(result, err)
|
||||
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)
|
||||
continue
|
||||
}
|
||||
@ -82,3 +109,35 @@ func (task *ExtraFiles) runtime(r runtime.Runtime) (err error) {
|
||||
|
||||
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.
|
||||
type File struct {
|
||||
Contents string `yaml:"contents"`
|
||||
Content string `yaml:"content"`
|
||||
Permissions os.FileMode `yaml:"permissions"`
|
||||
Path string `yaml:"path"`
|
||||
Op string `yaml:"op"`
|
||||
|
@ -125,14 +125,19 @@ type MachineConfig struct {
|
||||
MachineInstall *InstallConfig `yaml:"install,omitempty"`
|
||||
// description: |
|
||||
// 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.
|
||||
// examples:
|
||||
// - |
|
||||
// kubelet:
|
||||
// contents: |
|
||||
// ...
|
||||
// permissions: 0666
|
||||
// path: /tmp/file.txt
|
||||
// files:
|
||||
// - content: |
|
||||
// ...
|
||||
// permissions: 0666
|
||||
// path: /tmp/file.txt
|
||||
// op: append
|
||||
MachineFiles []machine.File `yaml:"files,omitempty"` // Note: The specified `path` is relative to `/var`.
|
||||
// description: |
|
||||
// The `env` field allows for the addition of environment variables to a machine.
|
||||
|
Loading…
x
Reference in New Issue
Block a user