Skip to content

Commit

Permalink
feat: add --config-patch flag by node type
Browse files Browse the repository at this point in the history
The problem is that some patches can't be applied to join config, as
some nodes don't even exist in the config, for example
`/cluster/apiServer` node, and applying such patches doesn't make any
sense.

Signed-off-by: Andrey Smirnov <smirnov.andrey@gmail.com>
(cherry picked from commit 0f49722)
  • Loading branch information
smira committed May 5, 2021
1 parent 801808c commit e415c81
Show file tree
Hide file tree
Showing 7 changed files with 189 additions and 59 deletions.
30 changes: 26 additions & 4 deletions cmd/talosctl/cmd/mgmt/cluster/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ var (
encryptEphemeralPartition bool
useVIP bool
configPatch string
configPatchControlPlane string
configPatchJoin string
)

// createCmd represents the cluster up command.
Expand Down Expand Up @@ -414,16 +416,34 @@ func create(ctx context.Context) (err error) {
)
}

var jsonPatch jsonpatch.Patch
addConfigPatch := func(configPatch string, configOpt func(jsonpatch.Patch) bundle.Option) error {
if configPatch == "" {
return nil
}

var jsonPatch jsonpatch.Patch

if configPatch != "" {
jsonPatch, err = jsonpatch.DecodePatch([]byte(configPatch))
if err != nil {
return fmt.Errorf("error parsing config JSON patch: %w", err)
}

configBundleOpts = append(configBundleOpts, configOpt(jsonPatch))

return nil
}

configBundleOpts = append(configBundleOpts, bundle.WithJSONPatch(jsonPatch))
if err = addConfigPatch(configPatch, bundle.WithJSONPatch); err != nil {
return err
}

if err = addConfigPatch(configPatchControlPlane, bundle.WithJSONPatchControlPlane); err != nil {
return err
}

if err = addConfigPatch(configPatchJoin, bundle.WithJSONPatchJoin); err != nil {
return err
}

configBundle, err := bundle.NewConfigBundle(configBundleOpts...)
if err != nil {
Expand Down Expand Up @@ -786,6 +806,8 @@ func init() {
createCmd.Flags().BoolVar(&encryptEphemeralPartition, "encrypt-ephemeral", false, "enable ephemeral partition encryption")
createCmd.Flags().StringVar(&talosVersion, "talos-version", "", "the desired Talos version to generate config for (if not set, defaults to image version)")
createCmd.Flags().BoolVar(&useVIP, "use-vip", false, "use a virtual IP for the controlplane endpoint instead of the loadbalancer")
createCmd.Flags().StringVar(&configPatch, "config-patch", "", "patch generated machineconfigs")
createCmd.Flags().StringVar(&configPatch, "config-patch", "", "patch generated machineconfigs (applied to all node types)")
createCmd.Flags().StringVar(&configPatchControlPlane, "config-patch-control-plane", "", "patch generated machineconfigs (applied to 'init' and 'controlplane' types)")
createCmd.Flags().StringVar(&configPatchJoin, "config-patch-join", "", "patch generated machineconfigs (applied to 'join' type)")
Cmd.AddCommand(createCmd)
}
56 changes: 39 additions & 17 deletions cmd/talosctl/cmd/mgmt/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,21 @@ import (
)

var genConfigCmdFlags struct {
additionalSANs []string
configVersion string
dnsDomain string
kubernetesVersion string
talosVersion string
installDisk string
installImage string
outputDir string
configPatch string
registryMirrors []string
persistConfig bool
withExamples bool
withDocs bool
additionalSANs []string
configVersion string
dnsDomain string
kubernetesVersion string
talosVersion string
installDisk string
installImage string
outputDir string
configPatch string
configPatchControlPlane string
configPatchJoin string
registryMirrors []string
persistConfig bool
withExamples bool
withDocs bool
}

// genConfigCmd represents the gen config command.
Expand Down Expand Up @@ -162,15 +164,33 @@ func genV1Alpha1Config(args []string) error {
),
}

if genConfigCmdFlags.configPatch != "" {
addConfigPatch := func(configPatch string, configOpt func(jsonpatch.Patch) bundle.Option) error {
if configPatch == "" {
return nil
}

var jsonPatch jsonpatch.Patch

jsonPatch, err = jsonpatch.DecodePatch([]byte(genConfigCmdFlags.configPatch))
jsonPatch, err = jsonpatch.DecodePatch([]byte(configPatch))
if err != nil {
return fmt.Errorf("error parsing config JSON patch: %w", err)
}

configBundleOpts = append(configBundleOpts, bundle.WithJSONPatch(jsonPatch))
configBundleOpts = append(configBundleOpts, configOpt(jsonPatch))

return nil
}

if err = addConfigPatch(genConfigCmdFlags.configPatch, bundle.WithJSONPatch); err != nil {
return err
}

if err = addConfigPatch(genConfigCmdFlags.configPatchControlPlane, bundle.WithJSONPatchControlPlane); err != nil {
return err
}

if err = addConfigPatch(genConfigCmdFlags.configPatchJoin, bundle.WithJSONPatchJoin); err != nil {
return err
}

configBundle, err := bundle.NewConfigBundle(configBundleOpts...)
Expand Down Expand Up @@ -220,7 +240,9 @@ func init() {
genConfigCmd.Flags().StringVar(&genConfigCmdFlags.talosVersion, "talos-version", "", "the desired Talos version to generate config for (backwards compatibility, e.g. v0.8)")
genConfigCmd.Flags().StringVar(&genConfigCmdFlags.kubernetesVersion, "kubernetes-version", "", "desired kubernetes version to run")
genConfigCmd.Flags().StringVarP(&genConfigCmdFlags.outputDir, "output-dir", "o", "", "destination to output generated files")
genConfigCmd.Flags().StringVar(&genConfigCmdFlags.configPatch, "config-patch", "", "patch generated machineconfigs")
genConfigCmd.Flags().StringVar(&genConfigCmdFlags.configPatch, "config-patch", "", "patch generated machineconfigs (applied to all node types)")
genConfigCmd.Flags().StringVar(&genConfigCmdFlags.configPatchControlPlane, "config-patch-control-plane", "", "patch generated machineconfigs (applied to 'init' and 'controlplane' types)")
genConfigCmd.Flags().StringVar(&genConfigCmdFlags.configPatchJoin, "config-patch-join", "", "patch generated machineconfigs (applied to 'join' type)")
genConfigCmd.Flags().StringSliceVar(&genConfigCmdFlags.registryMirrors, "registry-mirror", []string{}, "list of registry mirrors to use in format: <registry host>=<mirror URL>")
genConfigCmd.Flags().BoolVarP(&genConfigCmdFlags.persistConfig, "persist", "p", true, "the desired persist value for configs")
genConfigCmd.Flags().BoolVarP(&genConfigCmdFlags.withExamples, "with-examples", "", true, "renders all machine configs with the commented examples")
Expand Down
55 changes: 48 additions & 7 deletions internal/integration/cli/gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ func (suite *GenSuite) TestGenConfigURLValidation() {
base.StderrShouldMatch(regexp.MustCompile(regexp.QuoteMeta(`try: "https://192.168.0.1:2000"`))))
}

// TestGenConfigPatch verify that gen config --config-patch works.
// TestGenConfigPatch verifies that gen config --config-patch works.
func (suite *GenSuite) TestGenConfigPatch() {
patch, err := json.Marshal([]map[string]interface{}{
{
Expand All @@ -146,12 +146,53 @@ func (suite *GenSuite) TestGenConfigPatch() {

suite.Assert().NoError(err)

suite.RunCLI([]string{"gen", "config", "foo", "https://192.168.0.1:6443", "--config-patch", string(patch)})

cfg, err := configloader.NewFromFile("controlplane.yaml")

suite.Assert().NoError(err)
suite.Assert().Equal("bar", cfg.Cluster().Name())
for _, tt := range []struct {
flag string
shouldAffect map[string]bool
}{
{
flag: "config-patch",
shouldAffect: map[string]bool{
"init.yaml": true,
"controlplane.yaml": true,
"join.yaml": true,
},
},
{
flag: "config-patch-control-plane",
shouldAffect: map[string]bool{
"init.yaml": true,
"controlplane.yaml": true,
},
},
{
flag: "config-patch-join",
shouldAffect: map[string]bool{
"join.yaml": true,
},
},
} {
tt := tt

suite.Run(tt.flag, func() {
suite.RunCLI([]string{"gen", "config", "foo", "https://192.168.0.1:6443", "--" + tt.flag, string(patch)})

for _, configName := range []string{"init.yaml", "controlplane.yaml", "join.yaml"} {
cfg, err := configloader.NewFromFile(configName)

suite.Assert().NoError(err)

switch {
case tt.shouldAffect[configName]:
suite.Assert().Equal("bar", cfg.Cluster().Name(), "checking %q", configName)
case configName == "join.yaml":
suite.Assert().Equal("", cfg.Cluster().Name(), "checking %q", configName)
default:
suite.Assert().Equal("foo", cfg.Cluster().Name(), "checking %q", configName)
}
}
})
}
}

func init() {
Expand Down
24 changes: 20 additions & 4 deletions pkg/machinery/config/types/v1alpha1/bundle/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ func NewConfigBundle(opts ...Option) (*v1alpha1.ConfigBundle, error) {
}
}

if err := bundle.ApplyJSONPatch(options.JSONPatch); err != nil {
return nil, fmt.Errorf("error patching configs: %w", err)
if err := applyJSONPatches(bundle, options); err != nil {
return nil, err
}

// Pull existing talosconfig
Expand Down Expand Up @@ -124,8 +124,8 @@ func NewConfigBundle(opts ...Option) (*v1alpha1.ConfigBundle, error) {
}
}

if err = bundle.ApplyJSONPatch(options.JSONPatch); err != nil {
return nil, fmt.Errorf("error patching configs: %w", err)
if err = applyJSONPatches(bundle, options); err != nil {
return nil, err
}

bundle.TalosCfg, err = generate.Talosconfig(input, options.InputOptions.GenOptions...)
Expand All @@ -135,3 +135,19 @@ func NewConfigBundle(opts ...Option) (*v1alpha1.ConfigBundle, error) {

return bundle, nil
}

func applyJSONPatches(bundle *v1alpha1.ConfigBundle, options Options) error {
if err := bundle.ApplyJSONPatch(options.JSONPatch, true, true); err != nil {
return fmt.Errorf("error patching configs: %w", err)
}

if err := bundle.ApplyJSONPatch(options.JSONPatchControlPlane, true, false); err != nil {
return fmt.Errorf("error patching control plane configs: %w", err)
}

if err := bundle.ApplyJSONPatch(options.JSONPatchJoin, false, true); err != nil {
return fmt.Errorf("error patching worker config: %w", err)
}

return nil
}
23 changes: 22 additions & 1 deletion pkg/machinery/config/types/v1alpha1/bundle/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ type Options struct {
ExistingConfigs string // path to existing config files
Verbose bool // wheither to write any logs during generate
InputOptions *InputOptions
JSONPatch jsonpatch.Patch

JSONPatch jsonpatch.Patch
JSONPatchControlPlane jsonpatch.Patch
JSONPatchJoin jsonpatch.Patch
}

// DefaultOptions returns default options.
Expand Down Expand Up @@ -71,3 +74,21 @@ func WithJSONPatch(patch jsonpatch.Patch) Option {
return nil
}
}

// WithJSONPatchControlPlane allows patching init and controlplane config in a bundle with a patch.
func WithJSONPatchControlPlane(patch jsonpatch.Patch) Option {
return func(o *Options) error {
o.JSONPatchControlPlane = append(o.JSONPatchControlPlane, patch...)

return nil
}
}

// WithJSONPatchJoin allows patching join (worker) config in a bundle with a patch.
func WithJSONPatchJoin(patch jsonpatch.Patch) Option {
return func(o *Options) error {
o.JSONPatchJoin = append(o.JSONPatchJoin, patch...)

return nil
}
}
26 changes: 15 additions & 11 deletions pkg/machinery/config/types/v1alpha1/v1alpha1_configurator_bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func (c *ConfigBundle) Write(outputDir string, commentsFlags encoder.CommentsFla
}

// ApplyJSONPatch patches every config type with a patch.
func (c *ConfigBundle) ApplyJSONPatch(patch jsonpatch.Patch) error {
func (c *ConfigBundle) ApplyJSONPatch(patch jsonpatch.Patch, patchControlPlane, patchJoin bool) error {
if len(patch) == 0 {
return nil
}
Expand Down Expand Up @@ -117,19 +117,23 @@ func (c *ConfigBundle) ApplyJSONPatch(patch jsonpatch.Patch) error {

var err error

c.InitCfg, err = apply(c.InitCfg)
if err != nil {
return err
}
if patchControlPlane {
c.InitCfg, err = apply(c.InitCfg)
if err != nil {
return err
}

c.ControlPlaneCfg, err = apply(c.ControlPlaneCfg)
if err != nil {
return err
c.ControlPlaneCfg, err = apply(c.ControlPlaneCfg)
if err != nil {
return err
}
}

c.JoinCfg, err = apply(c.JoinCfg)
if err != nil {
return err
if patchJoin {
c.JoinCfg, err = apply(c.JoinCfg)
if err != nil {
return err
}
}

return nil
Expand Down
34 changes: 19 additions & 15 deletions website/content/docs/v0.10/Reference/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,9 @@ talosctl cluster create [flags]
--cni-bundle-url string URL to download CNI bundle from (VM only) (default "https://github.com/talos-systems/talos/releases/download/v0.10.0/talosctl-cni-bundle-${ARCH}.tar.gz")
--cni-cache-dir string CNI cache directory path (VM only) (default "/home/user/.talos/cni/cache")
--cni-conf-dir string CNI config directory path (VM only) (default "/home/user/.talos/cni/conf.d")
--config-patch string patch generated machineconfigs
--config-patch string patch generated machineconfigs (applied to all node types)
--config-patch-control-plane string patch generated machineconfigs (applied to 'init' and 'controlplane' types)
--config-patch-join string patch generated machineconfigs (applied to 'join' type)
--cpus string the share of CPUs as fraction (each container/VM) (default "2.0")
--crashdump print debug crashdump to stderr when cluster startup fails
--custom-cni-url string install custom CNI from the URL (Talos cluster)
Expand Down Expand Up @@ -1080,20 +1082,22 @@ talosctl gen config <cluster name> <cluster endpoint> [flags]
### Options

```
--additional-sans strings additional Subject-Alt-Names for the APIServer certificate
--config-patch string patch generated machineconfigs
--dns-domain string the dns domain to use for cluster (default "cluster.local")
-h, --help help for config
--install-disk string the disk to install to (default "/dev/sda")
--install-image string the image used to perform an installation (default "ghcr.io/talos-systems/installer:latest")
--kubernetes-version string desired kubernetes version to run
-o, --output-dir string destination to output generated files
-p, --persist the desired persist value for configs (default true)
--registry-mirror strings list of registry mirrors to use in format: <registry host>=<mirror URL>
--talos-version string the desired Talos version to generate config for (backwards compatibility, e.g. v0.8)
--version string the desired machine config version to generate (default "v1alpha1")
--with-docs renders all machine configs adding the documentation for each field (default true)
--with-examples renders all machine configs with the commented examples (default true)
--additional-sans strings additional Subject-Alt-Names for the APIServer certificate
--config-patch string patch generated machineconfigs (applied to all node types)
--config-patch-control-plane string patch generated machineconfigs (applied to 'init' and 'controlplane' types)
--config-patch-join string patch generated machineconfigs (applied to 'join' type)
--dns-domain string the dns domain to use for cluster (default "cluster.local")
-h, --help help for config
--install-disk string the disk to install to (default "/dev/sda")
--install-image string the image used to perform an installation (default "ghcr.io/talos-systems/installer:latest")
--kubernetes-version string desired kubernetes version to run
-o, --output-dir string destination to output generated files
-p, --persist the desired persist value for configs (default true)
--registry-mirror strings list of registry mirrors to use in format: <registry host>=<mirror URL>
--talos-version string the desired Talos version to generate config for (backwards compatibility, e.g. v0.8)
--version string the desired machine config version to generate (default "v1alpha1")
--with-docs renders all machine configs adding the documentation for each field (default true)
--with-examples renders all machine configs with the commented examples (default true)
```

### Options inherited from parent commands
Expand Down

0 comments on commit e415c81

Please sign in to comment.