Skip to content

Commit

Permalink
fix: merge extension service config files by mountPath
Browse files Browse the repository at this point in the history
Allow overwriting config file content.

Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
Co-authored-by: Noel Georgi <git@frezbo.dev>
  • Loading branch information
smira and frezbo committed Aug 26, 2024
1 parent 5ba1df4 commit e4f8cb8
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,12 @@ machine:
apiVersion: v1alpha1
kind: SideroLinkConfig
apiUrl: https://siderolink.api/join?jointoken=secret&user=alice
---
apiVersion: v1alpha1
kind: ExtensionServiceConfig
name: foo
configFiles:
- content: hello
mountPath: /etc/foo
environment:
- FOO=BAR
12 changes: 12 additions & 0 deletions pkg/machinery/config/configpatcher/testdata/multidoc/expected.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,15 @@ cluster: null
apiVersion: v1alpha1
kind: SideroLinkConfig
apiUrl: https://siderolink.api/join?jointoken=secret&user=bob
---
apiVersion: v1alpha1
kind: ExtensionServiceConfig
name: foo
configFiles:
- content: hello world
mountPath: /etc/foo
- content: another hello
mountPath: /etc/bar
environment:
- FOO=BAR
- XXX=YYY
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
apiVersion: v1alpha1
kind: SideroLinkConfig
apiUrl: https://siderolink.api/join?jointoken=secret&user=bob
---
apiVersion: v1alpha1
kind: ExtensionServiceConfig
name: foo
configFiles:
- content: hello world
mountPath: /etc/foo
- content: another hello
mountPath: /etc/bar
environment:
- XXX=YYY
44 changes: 43 additions & 1 deletion pkg/machinery/config/types/runtime/extensions/service_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

"github.com/siderolabs/talos/pkg/machinery/config/config"
"github.com/siderolabs/talos/pkg/machinery/config/internal/registry"
"github.com/siderolabs/talos/pkg/machinery/config/merge"
"github.com/siderolabs/talos/pkg/machinery/config/types/meta"
"github.com/siderolabs/talos/pkg/machinery/config/validation"
)
Expand Down Expand Up @@ -53,12 +54,53 @@ type ServiceConfigV1Alpha1 struct {
ServiceName string `yaml:"name"`
// description: |
// The config files for the extension service.
ServiceConfigFiles []ConfigFile `yaml:"configFiles,omitempty"`
ServiceConfigFiles ConfigFileList `yaml:"configFiles,omitempty"`
// description: |
// The environment for the extension service.
ServiceEnvironment []string `yaml:"environment,omitempty"`
}

// ConfigFileList is a list of ConfigFiles.
//
//docgen:alias
type ConfigFileList []ConfigFile

// Merge the config files by mountPath.
func (list *ConfigFileList) Merge(other any) error {
otherFiles, ok := other.(ConfigFileList)
if !ok {
return fmt.Errorf("unexpected type for config file merge %T", other)
}

for _, configFile := range otherFiles {
if err := list.mergeConfigFile(configFile); err != nil {
return err
}
}

return nil
}

func (list *ConfigFileList) mergeConfigFile(configFile ConfigFile) error {
var existing *ConfigFile

for idx, cf := range *list {
if cf.ConfigFileMountPath == configFile.ConfigFileMountPath {
existing = &(*list)[idx]

break
}
}

if existing != nil {
return merge.Merge(existing, &configFile)
}

*list = append(*list, configFile)

return nil
}

// ConfigFile is a config file for extension services.
type ConfigFile struct {
// description: |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/stretchr/testify/require"

"github.com/siderolabs/talos/pkg/machinery/config/encoder"
"github.com/siderolabs/talos/pkg/machinery/config/merge"
"github.com/siderolabs/talos/pkg/machinery/config/types/runtime/extensions"
)

Expand All @@ -38,3 +39,33 @@ func TestExtensionServiceConfigMarshalStability(t *testing.T) {

assert.Equal(t, expectedExtensionServiceConfigDocument, marshaled)
}

func TestExtensionServiceConfigMerge(t *testing.T) {
t.Parallel()

cfgLeft := extensions.NewServicesConfigV1Alpha1()
cfgLeft.ServiceName = "foo"
cfgLeft.ServiceConfigFiles = []extensions.ConfigFile{
{
ConfigFileContent: "hello",
ConfigFileMountPath: "/etc/foo",
},
}

cfgRight := cfgLeft.DeepCopy()
cfgRight.ServiceConfigFiles[0].ConfigFileContent = "hello world"

cfgRight.ServiceConfigFiles = append(cfgRight.ServiceConfigFiles,
extensions.ConfigFile{
ConfigFileContent: "bar",
ConfigFileMountPath: "/etc/bar",
},
)

require.NoError(t, merge.Merge(cfgLeft, cfgRight))

require.Len(t, cfgLeft.ConfigFiles(), 2)

assert.Equal(t, "hello world", cfgLeft.ConfigFiles()[0].Content())
assert.Equal(t, "bar", cfgLeft.ConfigFiles()[1].Content())
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ There are some special rules:
- `network.interfaces` section is merged with the value in the machine config if there is a match on `interface:` or `deviceSelector:` keys
- `network.interfaces.vlans` section is merged with the value in the machine config if there is a match on the `vlanId:` key
- `cluster.apiServer.auditPolicy` value is replaced on merge
- `ExtensionServiceConfig.configFiles` section is merged matching on `mountPath` (replacing `content` if matches)

When patching a [multi-document machine configuration]({{< relref "../../reference/configuration" >}}), following rules apply:

Expand Down

0 comments on commit e4f8cb8

Please sign in to comment.