diff --git a/pkg/config/config.go b/pkg/config/config.go index 07ca8f44e..eb41aa8b6 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -23,7 +23,6 @@ import ( "fmt" "io" "os" - "path/filepath" "reflect" "sort" @@ -37,6 +36,7 @@ import ( "sigs.k8s.io/kwok/pkg/apis/v1alpha1" "sigs.k8s.io/kwok/pkg/config/compatibility" "sigs.k8s.io/kwok/pkg/log" + "sigs.k8s.io/kwok/pkg/utils/file" "sigs.k8s.io/kwok/pkg/utils/maps" "sigs.k8s.io/kwok/pkg/utils/patch" "sigs.k8s.io/kwok/pkg/utils/path" @@ -329,27 +329,32 @@ func Load(ctx context.Context, src ...string) ([]InternalObject, error) { } // Save saves the given objects to the given path. -func Save(ctx context.Context, path string, objs []InternalObject) error { - err := os.MkdirAll(filepath.Dir(path), 0750) +func Save(ctx context.Context, dist string, objs []InternalObject) error { + dist = path.Clean(dist) + err := file.MkdirAll(path.Dir(dist)) if err != nil { return err } - file, err := os.OpenFile(filepath.Clean(path), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0640) + f, err := file.Open(dist) if err != nil { return err } defer func() { - _ = file.Close() + _ = f.Close() if err != nil { - _ = os.Remove(path) + _ = file.Remove(dist) } }() + return SaveTo(ctx, f, objs) +} +// SaveTo saves the given objects to the given writer. +func SaveTo(ctx context.Context, w io.Writer, objs []InternalObject) error { logger := log.FromContext(ctx) for i, obj := range objs { if i != 0 { - _, err = file.WriteString("\n---\n") + _, err := w.Write([]byte("\n---\n")) if err != nil { return err } @@ -386,7 +391,7 @@ func Save(ctx context.Context, path string, objs []InternalObject) error { return err } - _, err = file.Write(data) + _, err = w.Write(data) if err != nil { return err } @@ -418,7 +423,7 @@ func FilterWithoutType[T InternalObject](objs []InternalObject) (out []InternalO // FilterWithTypeFromContext returns all objects of the given type from the context. func FilterWithTypeFromContext[T metav1.Object](ctx context.Context) (out []T) { - objs := getFromContext(ctx) + objs := GetFromContext(ctx) if len(objs) == 0 { return nil } @@ -427,7 +432,7 @@ func FilterWithTypeFromContext[T metav1.Object](ctx context.Context) (out []T) { // FilterWithoutTypeFromContext returns all objects from the context that are not of the given type. func FilterWithoutTypeFromContext[T InternalObject](ctx context.Context) (out []InternalObject) { - objs := getFromContext(ctx) + objs := GetFromContext(ctx) if len(objs) == 0 { return nil } diff --git a/pkg/config/context.go b/pkg/config/context.go index b8d96fc5e..5e8481056 100644 --- a/pkg/config/context.go +++ b/pkg/config/context.go @@ -49,8 +49,8 @@ func addToContext(ctx context.Context, objs ...InternalObject) { val.Objects = append(val.Objects, objs...) } -// getFromContext returns the objects from the context. -func getFromContext(ctx context.Context) []InternalObject { +// GetFromContext returns the objects from the context. +func GetFromContext(ctx context.Context) []InternalObject { v := ctx.Value(configCtx(0)) val, ok := v.(*configValue) if !ok { diff --git a/pkg/config/context_test.go b/pkg/config/context_test.go index e53e80ed3..3379ef17e 100644 --- a/pkg/config/context_test.go +++ b/pkg/config/context_test.go @@ -36,7 +36,7 @@ func TestContext(t *testing.T) { Name: "second", }) - objs := getFromContext(ctx) + objs := GetFromContext(ctx) if len(objs) != 2 { t.Errorf("expected 2 objects, got %d", len(objs)) } diff --git a/pkg/kwokctl/cmd/config/config.go b/pkg/kwokctl/cmd/config/config.go new file mode 100644 index 000000000..ced2331e6 --- /dev/null +++ b/pkg/kwokctl/cmd/config/config.go @@ -0,0 +1,45 @@ +/* +Copyright 2023 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package config provides the kwokctl config command. +package config + +import ( + "context" + + "github.com/spf13/cobra" + + "sigs.k8s.io/kwok/pkg/kwokctl/cmd/config/reset" + "sigs.k8s.io/kwok/pkg/kwokctl/cmd/config/tidy" + "sigs.k8s.io/kwok/pkg/kwokctl/cmd/config/view" +) + +// NewCommand returns a new cobra.Command for config +func NewCommand(ctx context.Context) *cobra.Command { + cmd := &cobra.Command{ + Args: cobra.NoArgs, + Use: "config [command]", + Short: "Manage [reset, tidy, view] default config", + RunE: func(cmd *cobra.Command, args []string) error { + return cmd.Help() + }, + } + + cmd.AddCommand(reset.NewCommand(ctx)) + cmd.AddCommand(tidy.NewCommand(ctx)) + cmd.AddCommand(view.NewCommand(ctx)) + return cmd +} diff --git a/pkg/kwokctl/cmd/config/reset/reset.go b/pkg/kwokctl/cmd/config/reset/reset.go new file mode 100644 index 000000000..1a6334bba --- /dev/null +++ b/pkg/kwokctl/cmd/config/reset/reset.go @@ -0,0 +1,56 @@ +/* +Copyright 2023 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package reset provides the kwokctl config reset command. +package reset + +import ( + "context" + + "github.com/spf13/cobra" + + "sigs.k8s.io/kwok/pkg/config" + "sigs.k8s.io/kwok/pkg/consts" + "sigs.k8s.io/kwok/pkg/kwokctl/dryrun" + "sigs.k8s.io/kwok/pkg/utils/file" + "sigs.k8s.io/kwok/pkg/utils/path" +) + +// NewCommand returns a new cobra.Command for config reset +func NewCommand(ctx context.Context) *cobra.Command { + cmd := &cobra.Command{ + Args: cobra.NoArgs, + Use: "reset", + Short: "Remove the default config file", + RunE: func(cmd *cobra.Command, args []string) error { + return runE(cmd.Context()) + }, + } + return cmd +} + +func runE(_ context.Context) error { + p := path.Join(config.WorkDir, consts.ConfigName) + if dryrun.DryRun { + dryrun.PrintMessage("# Removing config file %s", p) + return nil + } + err := file.Remove(p) + if err != nil { + return err + } + return nil +} diff --git a/pkg/kwokctl/cmd/config/tidy/tidy.go b/pkg/kwokctl/cmd/config/tidy/tidy.go new file mode 100644 index 000000000..1cee7f5db --- /dev/null +++ b/pkg/kwokctl/cmd/config/tidy/tidy.go @@ -0,0 +1,56 @@ +/* +Copyright 2023 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package tidy provides a command to tidy the config file +package tidy + +import ( + "context" + + "github.com/spf13/cobra" + + "sigs.k8s.io/kwok/pkg/config" + "sigs.k8s.io/kwok/pkg/consts" + "sigs.k8s.io/kwok/pkg/kwokctl/dryrun" + "sigs.k8s.io/kwok/pkg/utils/path" +) + +// NewCommand returns a new cobra.Command for config save +func NewCommand(ctx context.Context) *cobra.Command { + cmd := &cobra.Command{ + Args: cobra.NoArgs, + Use: "tidy", + Short: "Tidy the default config file with --config", + RunE: func(cmd *cobra.Command, args []string) error { + return runE(cmd.Context()) + }, + } + return cmd +} + +func runE(ctx context.Context) error { + list := config.GetFromContext(ctx) + p := path.Join(config.WorkDir, consts.ConfigName) + if dryrun.DryRun { + dryrun.PrintMessage("# Tidy the config file") + return nil + } + err := config.Save(ctx, p, list) + if err != nil { + return err + } + return nil +} diff --git a/pkg/kwokctl/cmd/config/view/view.go b/pkg/kwokctl/cmd/config/view/view.go new file mode 100644 index 000000000..7ee956028 --- /dev/null +++ b/pkg/kwokctl/cmd/config/view/view.go @@ -0,0 +1,57 @@ +/* +Copyright 2023 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package view provides the kwokctl config view command. +package view + +import ( + "context" + "os" + + "github.com/spf13/cobra" + + "sigs.k8s.io/kwok/pkg/config" + "sigs.k8s.io/kwok/pkg/consts" + "sigs.k8s.io/kwok/pkg/kwokctl/dryrun" + "sigs.k8s.io/kwok/pkg/utils/path" +) + +// NewCommand returns a new cobra.Command for config view +func NewCommand(ctx context.Context) *cobra.Command { + cmd := &cobra.Command{ + Args: cobra.NoArgs, + Use: "view", + Short: "Display the default config file with --config", + RunE: func(cmd *cobra.Command, args []string) error { + return runE(cmd.Context()) + }, + } + return cmd +} + +func runE(ctx context.Context) error { + p := path.Join(config.WorkDir, consts.ConfigName) + if dryrun.DryRun { + dryrun.PrintMessage("# Displaying config file %s", p) + return nil + } + list := config.GetFromContext(ctx) + err := config.SaveTo(ctx, os.Stdout, list) + if err != nil { + return err + } + return nil +} diff --git a/pkg/kwokctl/cmd/root.go b/pkg/kwokctl/cmd/root.go index 8034ba443..44332009d 100644 --- a/pkg/kwokctl/cmd/root.go +++ b/pkg/kwokctl/cmd/root.go @@ -23,6 +23,7 @@ import ( "github.com/spf13/cobra" "sigs.k8s.io/kwok/pkg/config" + conf "sigs.k8s.io/kwok/pkg/kwokctl/cmd/config" "sigs.k8s.io/kwok/pkg/kwokctl/cmd/create" del "sigs.k8s.io/kwok/pkg/kwokctl/cmd/delete" "sigs.k8s.io/kwok/pkg/kwokctl/cmd/etcdctl" @@ -56,6 +57,7 @@ func NewCommand(ctx context.Context) *cobra.Command { cmd.TraverseChildren = true cmd.AddCommand( + conf.NewCommand(ctx), create.NewCommand(ctx), del.NewCommand(ctx), get.NewCommand(ctx), diff --git a/site/content/en/docs/generated/kwokctl.md b/site/content/en/docs/generated/kwokctl.md index 9e385ae90..7a3096158 100644 --- a/site/content/en/docs/generated/kwokctl.md +++ b/site/content/en/docs/generated/kwokctl.md @@ -18,6 +18,7 @@ kwokctl [command] [flags] ### SEE ALSO +* [kwokctl config](kwokctl_config.md) - Manage [reset, tidy, view] default config * [kwokctl create](kwokctl_create.md) - Creates one of [cluster] * [kwokctl delete](kwokctl_delete.md) - Deletes one of [cluster] * [kwokctl etcdctl](kwokctl_etcdctl.md) - etcdctl in cluster diff --git a/site/content/en/docs/generated/kwokctl_config.md b/site/content/en/docs/generated/kwokctl_config.md new file mode 100644 index 000000000..aa88dcd5b --- /dev/null +++ b/site/content/en/docs/generated/kwokctl_config.md @@ -0,0 +1,30 @@ +## kwokctl config + +Manage [reset, tidy, view] default config + +``` +kwokctl config [command] [flags] +``` + +### Options + +``` + -h, --help help for config +``` + +### Options inherited from parent commands + +``` + -c, --config stringArray config path (default [~/.kwok/kwok.yaml]) + --dry-run Print the command that would be executed, but do not execute it + --name string cluster name (default "kwok") + -v, --v log-level number for the log level verbosity (DEBUG, INFO, WARN, ERROR) or (-4, 0, 4, 8) (default INFO) +``` + +### SEE ALSO + +* [kwokctl](kwokctl.md) - kwokctl is a tool to streamline the creation and management of clusters, with nodes simulated by kwok +* [kwokctl config reset](kwokctl_config_reset.md) - Remove the default config file +* [kwokctl config tidy](kwokctl_config_tidy.md) - Tidy the default config file with --config +* [kwokctl config view](kwokctl_config_view.md) - Display the default config file with --config + diff --git a/site/content/en/docs/generated/kwokctl_config_reset.md b/site/content/en/docs/generated/kwokctl_config_reset.md new file mode 100644 index 000000000..8d4dafb47 --- /dev/null +++ b/site/content/en/docs/generated/kwokctl_config_reset.md @@ -0,0 +1,27 @@ +## kwokctl config reset + +Remove the default config file + +``` +kwokctl config reset [flags] +``` + +### Options + +``` + -h, --help help for reset +``` + +### Options inherited from parent commands + +``` + -c, --config stringArray config path (default [~/.kwok/kwok.yaml]) + --dry-run Print the command that would be executed, but do not execute it + --name string cluster name (default "kwok") + -v, --v log-level number for the log level verbosity (DEBUG, INFO, WARN, ERROR) or (-4, 0, 4, 8) (default INFO) +``` + +### SEE ALSO + +* [kwokctl config](kwokctl_config.md) - Manage [reset, tidy, view] default config + diff --git a/site/content/en/docs/generated/kwokctl_config_tidy.md b/site/content/en/docs/generated/kwokctl_config_tidy.md new file mode 100644 index 000000000..8a3c7261e --- /dev/null +++ b/site/content/en/docs/generated/kwokctl_config_tidy.md @@ -0,0 +1,27 @@ +## kwokctl config tidy + +Tidy the default config file with --config + +``` +kwokctl config tidy [flags] +``` + +### Options + +``` + -h, --help help for tidy +``` + +### Options inherited from parent commands + +``` + -c, --config stringArray config path (default [~/.kwok/kwok.yaml]) + --dry-run Print the command that would be executed, but do not execute it + --name string cluster name (default "kwok") + -v, --v log-level number for the log level verbosity (DEBUG, INFO, WARN, ERROR) or (-4, 0, 4, 8) (default INFO) +``` + +### SEE ALSO + +* [kwokctl config](kwokctl_config.md) - Manage [reset, tidy, view] default config + diff --git a/site/content/en/docs/generated/kwokctl_config_view.md b/site/content/en/docs/generated/kwokctl_config_view.md new file mode 100644 index 000000000..c88fb8043 --- /dev/null +++ b/site/content/en/docs/generated/kwokctl_config_view.md @@ -0,0 +1,27 @@ +## kwokctl config view + +Display the default config file with --config + +``` +kwokctl config view [flags] +``` + +### Options + +``` + -h, --help help for view +``` + +### Options inherited from parent commands + +``` + -c, --config stringArray config path (default [~/.kwok/kwok.yaml]) + --dry-run Print the command that would be executed, but do not execute it + --name string cluster name (default "kwok") + -v, --v log-level number for the log level verbosity (DEBUG, INFO, WARN, ERROR) or (-4, 0, 4, 8) (default INFO) +``` + +### SEE ALSO + +* [kwokctl config](kwokctl_config.md) - Manage [reset, tidy, view] default config +