From 49853fc2ecb846898d66d90fc76e6d875b775901 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Fri, 5 Mar 2021 21:19:05 +0300 Subject: [PATCH] fix: mkdir source of the extra mounts for the kubelet This makes sure source directory exists before performing mount operation. Also adds an ability to patch the config bundle configs with JSON patch, which is exposed in `talosctl cluster create`, this allowed me to easily test this fix: ``` talosctl cluster create ... --config-patch='[{"op": "add", "path": "/machine/kubelet/extraMounts", "value": [{"destination": "/var/log/containers", "type": "bind", "source": "/var/log/containers", "options": ["rshared", "rbind", "rw"]}]}]' ``` Signed-off-by: Andrey Smirnov --- cmd/talosctl/cmd/mgmt/cluster/create.go | 14 +++++ .../machined/pkg/system/services/kubelet.go | 8 ++- .../config/types/v1alpha1/bundle/bundle.go | 8 +++ .../config/types/v1alpha1/bundle/options.go | 16 +++++- .../v1alpha1/v1alpha1_configurator_bundle.go | 51 +++++++++++++++++++ website/content/docs/v0.9/Reference/cli.md | 1 + 6 files changed, 96 insertions(+), 2 deletions(-) diff --git a/cmd/talosctl/cmd/mgmt/cluster/create.go b/cmd/talosctl/cmd/mgmt/cluster/create.go index bf4b858a2c..f0f17caad1 100644 --- a/cmd/talosctl/cmd/mgmt/cluster/create.go +++ b/cmd/talosctl/cmd/mgmt/cluster/create.go @@ -19,6 +19,7 @@ import ( "time" humanize "github.com/dustin/go-humanize" + jsonpatch "github.com/evanphx/json-patch" "github.com/spf13/cobra" "github.com/talos-systems/go-blockdevice/blockdevice/encryption" talosnet "github.com/talos-systems/net" @@ -102,6 +103,7 @@ var ( encryptStatePartition bool encryptEphemeralPartition bool useVIP bool + configPatch string ) // createCmd represents the cluster up command. @@ -411,6 +413,17 @@ func create(ctx context.Context) (err error) { ) } + 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, bundle.WithJSONPatch(jsonPatch)) + configBundle, err := bundle.NewConfigBundle(configBundleOpts...) if err != nil { return err @@ -772,5 +785,6 @@ 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") Cmd.AddCommand(createCmd) } diff --git a/internal/app/machined/pkg/system/services/kubelet.go b/internal/app/machined/pkg/system/services/kubelet.go index d1841b7f35..ced18b8ce9 100644 --- a/internal/app/machined/pkg/system/services/kubelet.go +++ b/internal/app/machined/pkg/system/services/kubelet.go @@ -172,7 +172,13 @@ func (k *Kubelet) Runner(r runtime.Runtime) (runner.Runner, error) { // TODO(andrewrynhard): We should verify that the mount source is // allowlisted. There is the potential that a user can expose // sensitive information. - mounts = append(mounts, r.Config().Machine().Kubelet().ExtraMounts()...) + for _, mount := range r.Config().Machine().Kubelet().ExtraMounts() { + if err = os.MkdirAll(mount.Source, 0o700); err != nil { + return nil, err + } + + mounts = append(mounts, mount) + } env := []string{} for key, val := range r.Config().Machine().Env() { diff --git a/pkg/machinery/config/types/v1alpha1/bundle/bundle.go b/pkg/machinery/config/types/v1alpha1/bundle/bundle.go index 70183702b6..97177fc8b9 100644 --- a/pkg/machinery/config/types/v1alpha1/bundle/bundle.go +++ b/pkg/machinery/config/types/v1alpha1/bundle/bundle.go @@ -60,6 +60,10 @@ func NewConfigBundle(opts ...Option) (*v1alpha1.ConfigBundle, error) { } } + if err := bundle.ApplyJSONPatch(options.JSONPatch); err != nil { + return nil, fmt.Errorf("error patching configs: %w", err) + } + // Pull existing talosconfig talosConfig, err := os.Open(filepath.Join(options.ExistingConfigs, "talosconfig")) if err != nil { @@ -120,6 +124,10 @@ func NewConfigBundle(opts ...Option) (*v1alpha1.ConfigBundle, error) { } } + if err = bundle.ApplyJSONPatch(options.JSONPatch); err != nil { + return nil, fmt.Errorf("error patching configs: %w", err) + } + bundle.TalosCfg, err = generate.Talosconfig(input, options.InputOptions.GenOptions...) if err != nil { return bundle, err diff --git a/pkg/machinery/config/types/v1alpha1/bundle/options.go b/pkg/machinery/config/types/v1alpha1/bundle/options.go index 796ed2a165..4486e9e080 100644 --- a/pkg/machinery/config/types/v1alpha1/bundle/options.go +++ b/pkg/machinery/config/types/v1alpha1/bundle/options.go @@ -4,7 +4,11 @@ package bundle -import "github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/generate" +import ( + jsonpatch "github.com/evanphx/json-patch" + + "github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/generate" +) // Option controls config options specific to config bundle generation. type Option func(o *Options) error @@ -22,6 +26,7 @@ type Options struct { ExistingConfigs string // path to existing config files Verbose bool // wheither to write any logs during generate InputOptions *InputOptions + JSONPatch jsonpatch.Patch } // DefaultOptions returns default options. @@ -57,3 +62,12 @@ func WithVerbose(verbose bool) Option { return nil } } + +// WithJSONPatch allows patching every config in a bundle with a patch. +func WithJSONPatch(patch jsonpatch.Patch) Option { + return func(o *Options) error { + o.JSONPatch = append(o.JSONPatch, patch...) + + return nil + } +} diff --git a/pkg/machinery/config/types/v1alpha1/v1alpha1_configurator_bundle.go b/pkg/machinery/config/types/v1alpha1/v1alpha1_configurator_bundle.go index a5cde37bbd..afedba4857 100644 --- a/pkg/machinery/config/types/v1alpha1/v1alpha1_configurator_bundle.go +++ b/pkg/machinery/config/types/v1alpha1/v1alpha1_configurator_bundle.go @@ -10,8 +10,12 @@ import ( "path/filepath" "strings" + jsonpatch "github.com/evanphx/json-patch" + "gopkg.in/yaml.v3" + clientconfig "github.com/talos-systems/talos/pkg/machinery/client/config" "github.com/talos-systems/talos/pkg/machinery/config" + "github.com/talos-systems/talos/pkg/machinery/config/configpatcher" "github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/machine" ) @@ -82,3 +86,50 @@ func (c *ConfigBundle) Write(outputDir string, types ...machine.Type) error { return nil } + +// ApplyJSONPatch patches every config type with a patch. +func (c *ConfigBundle) ApplyJSONPatch(patch jsonpatch.Patch) error { + if len(patch) == 0 { + return nil + } + + apply := func(in *Config) (out *Config, err error) { + var marshaled []byte + + marshaled, err = in.Bytes() + if err != nil { + return nil, err + } + + var patched []byte + + patched, err = configpatcher.JSON6902(marshaled, patch) + if err != nil { + return nil, err + } + + out = &Config{} + err = yaml.Unmarshal(patched, out) + + return out, err + } + + var err error + + c.InitCfg, err = apply(c.InitCfg) + 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 + } + + return nil +} diff --git a/website/content/docs/v0.9/Reference/cli.md b/website/content/docs/v0.9/Reference/cli.md index 9d6aad2d62..9a3120bc51 100644 --- a/website/content/docs/v0.9/Reference/cli.md +++ b/website/content/docs/v0.9/Reference/cli.md @@ -82,6 +82,7 @@ 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.9.0-alpha.5/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 --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)