diff --git a/cmd/controller/controller.go b/cmd/controller/controller.go index 40bcd9ace826..d3a7bce163cd 100644 --- a/cmd/controller/controller.go +++ b/cmd/controller/controller.go @@ -1,3 +1,5 @@ +//go:build unix + /* Copyright 2021 k0s authors diff --git a/cmd/controller/controller_test.go b/cmd/controller/controller_test.go index 2f3f270775e8..16d05c94faca 100644 --- a/cmd/controller/controller_test.go +++ b/cmd/controller/controller_test.go @@ -17,6 +17,7 @@ limitations under the License. package controller_test import ( + "runtime" "strconv" "strings" "testing" @@ -28,6 +29,10 @@ import ( ) func TestControllerCmd_Help(t *testing.T) { + if runtime.GOOS != "linux" { + t.Skip("Running controllers is only supported on Linux") + } + defaultConfigPath := strconv.Quote(constant.K0sConfigPathDefault) defaultDataDir := strconv.Quote(constant.DataDirDefault) diff --git a/cmd/install/controller.go b/cmd/install/controller.go index 36e62c01b252..06f665237af2 100644 --- a/cmd/install/controller.go +++ b/cmd/install/controller.go @@ -1,3 +1,5 @@ +//go:build linux + /* Copyright 2021 k0s authors @@ -19,8 +21,11 @@ package install import ( "errors" "fmt" + "os" + "testing/iotest" "github.com/k0sproject/k0s/pkg/config" + "github.com/k0sproject/k0s/pkg/install" "github.com/spf13/cobra" ) @@ -38,14 +43,17 @@ With the controller subcommand you can setup a single node cluster by running: `, Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, _ []string) error { - opts, err := config.GetCmdOpts(cmd) - if err != nil { - return err + if os.Geteuid() != 0 { + return errors.New("this command must be run as root") } - c := (*command)(opts) + cmd.SetIn(iotest.ErrReader(errors.New("cannot read configuration from standard input when installing k0s"))) + k0sVars, err := config.NewCfgVars(cmd) + if err != nil { + return fmt.Errorf("failed to initialize configuration variables: %w", err) + } - nodeConfig, err := c.K0sVars.NodeConfig() + nodeConfig, err := k0sVars.NodeConfig() if err != nil { return fmt.Errorf("failed to load node config: %w", err) } @@ -59,10 +67,17 @@ With the controller subcommand you can setup a single node cluster by running: return err } - flagsAndVals = append([]string{"controller"}, flagsAndVals...) - if err := c.setup("controller", flagsAndVals, installFlags); err != nil { - return err + systemUsers := nodeConfig.Spec.Install.SystemUsers + homeDir := k0sVars.DataDir + if err := install.EnsureControllerUsers(systemUsers, homeDir); err != nil { + return fmt.Errorf("failed to create controller users: %w", err) + } + + args := append([]string{"controller"}, flagsAndVals...) + if err := install.InstallService(args, installFlags.envVars, installFlags.force); err != nil { + return fmt.Errorf("failed to install controller service: %w", err) } + return nil }, } diff --git a/cmd/install/controller_test.go b/cmd/install/controller_test.go index bfab32f960c3..33abab182580 100644 --- a/cmd/install/controller_test.go +++ b/cmd/install/controller_test.go @@ -1,3 +1,5 @@ +//go:build linux + /* Copyright 2024 k0s authors diff --git a/cmd/install/install.go b/cmd/install/install.go index 11bd266faa30..850c42cd7cee 100644 --- a/cmd/install/install.go +++ b/cmd/install/install.go @@ -17,18 +17,11 @@ limitations under the License. package install import ( - "errors" - "fmt" - "os" - "github.com/k0sproject/k0s/pkg/config" - "github.com/k0sproject/k0s/pkg/install" "github.com/spf13/cobra" ) -type command config.CLIOptions - type installFlags struct { force bool envVars []string @@ -44,37 +37,11 @@ func NewInstallCmd() *cobra.Command { Run: func(*cobra.Command, []string) { /* Enforce arg validation. */ }, } - cmd.AddCommand(installControllerCmd(&installFlags)) cmd.AddCommand(installWorkerCmd(&installFlags)) + addPlatformSpecificCommands(cmd, &installFlags) + cmd.PersistentFlags().BoolVar(&installFlags.force, "force", false, "force init script creation") cmd.PersistentFlags().StringArrayVarP(&installFlags.envVars, "env", "e", nil, "set environment variable") cmd.PersistentFlags().AddFlagSet(config.GetPersistentFlagSet()) return cmd } - -// The setup functions: -// - Ensures that the proper users are created. -// - Sets up startup and logging for k0s. -func (c *command) setup(role string, args []string, installFlags *installFlags) error { - if os.Geteuid() != 0 { - return errors.New("this command must be run as root") - } - - nodeConfig, err := c.K0sVars.NodeConfig() - if err != nil { - return err - } - - if role == "controller" { - systemUsers := nodeConfig.Spec.Install.SystemUsers - homeDir := c.K0sVars.DataDir - if err := install.EnsureControllerUsers(systemUsers, homeDir); err != nil { - return fmt.Errorf("failed to create controller users: %w", err) - } - } - err = install.EnsureService(args, installFlags.envVars, installFlags.force) - if err != nil { - return fmt.Errorf("failed to install k0s service: %w", err) - } - return nil -} diff --git a/cmd/restore/restore_windows.go b/cmd/install/install_linux.go similarity index 59% rename from cmd/restore/restore_windows.go rename to cmd/install/install_linux.go index a23e2e4cb6f2..6c306f7548cd 100644 --- a/cmd/restore/restore_windows.go +++ b/cmd/install/install_linux.go @@ -1,5 +1,5 @@ /* -Copyright 2021 k0s authors +Copyright 2025 k0s authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,22 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -package restore +package install import ( - "errors" - "github.com/spf13/cobra" ) -var restoredConfigPath string - -func NewRestoreCmd() *cobra.Command { - return &cobra.Command{ - Use: "restore", - Short: "restore k0s state from given backup archive. Not supported in Windows OS", - RunE: func(cmd *cobra.Command, args []string) error { - return errors.New("unsupported Operating System for this command") - }, - } +func addPlatformSpecificCommands(install *cobra.Command, installFlags *installFlags) { + install.AddCommand(installControllerCmd(installFlags)) } diff --git a/cmd/install/install_other.go b/cmd/install/install_other.go new file mode 100644 index 000000000000..8764e65a3c7b --- /dev/null +++ b/cmd/install/install_other.go @@ -0,0 +1,25 @@ +//go:build !linux + +/* +Copyright 2025 k0s 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 install + +import "github.com/spf13/cobra" + +func addPlatformSpecificCommands(*cobra.Command, *installFlags) { + // no-op +} diff --git a/cmd/install/util.go b/cmd/install/util.go index 6ba8e661c0bd..f71f50c46221 100644 --- a/cmd/install/util.go +++ b/cmd/install/util.go @@ -23,7 +23,6 @@ import ( "strings" "github.com/spf13/cobra" - "github.com/spf13/pflag" ) diff --git a/cmd/install/worker.go b/cmd/install/worker.go index 55c79cb7dc8a..cbcd0649c688 100644 --- a/cmd/install/worker.go +++ b/cmd/install/worker.go @@ -17,9 +17,15 @@ limitations under the License. package install import ( + "errors" + "fmt" + "os" + "runtime" + "github.com/spf13/cobra" "github.com/k0sproject/k0s/pkg/config" + "github.com/k0sproject/k0s/pkg/install" ) func installWorkerCmd(installFlags *installFlags) *cobra.Command { @@ -32,20 +38,18 @@ All default values of worker command will be passed to the service stub unless o Windows flags like "--api-server", "--cidr-range" and "--cluster-dns" will be ignored since install command doesn't yet support Windows services`, Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, _ []string) error { - opts, err := config.GetCmdOpts(cmd) - if err != nil { - return err + if runtime.GOOS != "windows" && os.Geteuid() != 0 { + return errors.New("this command must be run as root") } - c := (*command)(opts) flagsAndVals, err := cmdFlagsToArgs(cmd) if err != nil { return err } - flagsAndVals = append([]string{"worker"}, flagsAndVals...) - if err := c.setup("worker", flagsAndVals, installFlags); err != nil { - return err + args := append([]string{"worker"}, flagsAndVals...) + if err := install.InstallService(args, installFlags.envVars, installFlags.force); err != nil { + return fmt.Errorf("failed to install worker service: %w", err) } return nil diff --git a/cmd/reset/reset.go b/cmd/reset/reset.go index 59dd16d1a5dd..3e9f886d64e2 100644 --- a/cmd/reset/reset.go +++ b/cmd/reset/reset.go @@ -1,3 +1,5 @@ +//go:build linux + /* Copyright 2021 k0s authors diff --git a/cmd/root.go b/cmd/root.go index 3892d83c5cb6..923bbd18c92c 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -20,22 +20,16 @@ import ( "errors" "net/http" "os" - "runtime" "github.com/k0sproject/k0s/cmd/airgap" "github.com/k0sproject/k0s/cmd/api" - "github.com/k0sproject/k0s/cmd/backup" configcmd "github.com/k0sproject/k0s/cmd/config" - "github.com/k0sproject/k0s/cmd/controller" "github.com/k0sproject/k0s/cmd/ctr" "github.com/k0sproject/k0s/cmd/etcd" "github.com/k0sproject/k0s/cmd/install" "github.com/k0sproject/k0s/cmd/kubeconfig" "github.com/k0sproject/k0s/cmd/kubectl" - "github.com/k0sproject/k0s/cmd/reset" - "github.com/k0sproject/k0s/cmd/restore" "github.com/k0sproject/k0s/cmd/start" - "github.com/k0sproject/k0s/cmd/status" "github.com/k0sproject/k0s/cmd/stop" "github.com/k0sproject/k0s/cmd/sysinfo" "github.com/k0sproject/k0s/cmd/token" @@ -82,24 +76,13 @@ func NewRootCmd() *cobra.Command { cmd.AddCommand(airgap.NewAirgapCmd()) cmd.AddCommand(api.NewAPICmd()) - cmd.AddCommand(backup.NewBackupCmd()) - cmd.AddCommand(controller.NewControllerCmd()) cmd.AddCommand(ctr.NewCtrCommand()) cmd.AddCommand(configcmd.NewConfigCmd()) cmd.AddCommand(etcd.NewEtcdCmd()) cmd.AddCommand(install.NewInstallCmd()) cmd.AddCommand(kubeconfig.NewKubeConfigCmd()) cmd.AddCommand(kubectl.NewK0sKubectlCmd()) - if runtime.GOOS == "linux" { - // Currently only supported on Linux - cmd.AddCommand(reset.NewResetCmd()) - } - cmd.AddCommand(restore.NewRestoreCmd()) cmd.AddCommand(start.NewStartCmd()) - if runtime.GOOS == "linux" { - // Currently only supported on Linux - cmd.AddCommand(status.NewStatusCmd()) - } cmd.AddCommand(stop.NewStopCmd()) cmd.AddCommand(sysinfo.NewSysinfoCmd()) cmd.AddCommand(token.NewTokenCmd()) @@ -109,6 +92,8 @@ func NewRootCmd() *cobra.Command { cmd.AddCommand(newCompletionCmd()) cmd.AddCommand(newDocsCmd()) + addPlatformSpecificCommands(cmd) + cmd.DisableAutoGenTag = true longDesc = "k0s - The zero friction Kubernetes - https://k0sproject.io" if build.EulaNotice != "" { diff --git a/cmd/root_linux.go b/cmd/root_linux.go new file mode 100644 index 000000000000..ed88c3d69c17 --- /dev/null +++ b/cmd/root_linux.go @@ -0,0 +1,35 @@ +/* +Copyright 2025 k0s 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 cmd + +import ( + "github.com/k0sproject/k0s/cmd/backup" + "github.com/k0sproject/k0s/cmd/controller" + "github.com/k0sproject/k0s/cmd/reset" + "github.com/k0sproject/k0s/cmd/restore" + "github.com/k0sproject/k0s/cmd/status" + + "github.com/spf13/cobra" +) + +func addPlatformSpecificCommands(root *cobra.Command) { + root.AddCommand(backup.NewBackupCmd()) + root.AddCommand(controller.NewControllerCmd()) + root.AddCommand(reset.NewResetCmd()) + root.AddCommand(restore.NewRestoreCmd()) + root.AddCommand(status.NewStatusCmd()) +} diff --git a/pkg/cleanup/bridge_other.go b/cmd/root_other.go similarity index 79% rename from pkg/cleanup/bridge_other.go rename to cmd/root_other.go index 215f255e2395..24b49be8ba17 100644 --- a/pkg/cleanup/bridge_other.go +++ b/cmd/root_other.go @@ -1,7 +1,7 @@ //go:build !linux /* -Copyright 2021 k0s authors +Copyright 2025 k0s authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -16,8 +16,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -package cleanup +package cmd -func newBridgeStep() Step { - return nil -} +import "github.com/spf13/cobra" + +func addPlatformSpecificCommands(root *cobra.Command) { /* no-op */ } diff --git a/cmd/root_test.go b/cmd/root_test.go index 263c45c80ca8..e3bc7eec7327 100644 --- a/cmd/root_test.go +++ b/cmd/root_test.go @@ -21,6 +21,7 @@ import ( "errors" "fmt" "io" + "runtime" "slices" "strings" "testing" @@ -75,12 +76,16 @@ func TestRootCmd_Flags(t *testing.T) { func TestUnknownSubCommandsAreRejected(t *testing.T) { commandsWithArguments := []string{ - "controller", "kubeconfig create", - "restore", "token invalidate", "worker", } + if runtime.GOOS == "linux" { + commandsWithArguments = append(commandsWithArguments, + "controller", + "restore", + ) + } t.Cleanup(func() { if !t.Failed() { assert.Empty(t, commandsWithArguments, "Some sub-commands are listed unnecessarily") diff --git a/cmd/start/start.go b/cmd/start/start.go index c0e511e04bb8..46197c08a0f7 100644 --- a/cmd/start/start.go +++ b/cmd/start/start.go @@ -19,6 +19,7 @@ package start import ( "errors" "os" + "runtime" "github.com/k0sproject/k0s/pkg/install" @@ -32,7 +33,7 @@ func NewStartCmd() *cobra.Command { Short: "Start the k0s service configured on this host. Must be run as root (or with sudo)", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, _ []string) error { - if os.Geteuid() != 0 { + if runtime.GOOS != "windows" && os.Geteuid() != 0 { return errors.New("this command must be run as root") } svc, err := install.InstalledService() diff --git a/cmd/status/status.go b/cmd/status/status.go index f797b6ebd033..258ab2adffdc 100644 --- a/cmd/status/status.go +++ b/cmd/status/status.go @@ -1,3 +1,5 @@ +//go:build unix + /* Copyright 2021 k0s authors @@ -20,7 +22,6 @@ import ( "encoding/json" "fmt" "io" - "path/filepath" "github.com/k0sproject/k0s/pkg/component/status" "github.com/k0sproject/k0s/pkg/config" @@ -56,7 +57,7 @@ func NewStatusCmd() *cobra.Command { } cmd.PersistentFlags().StringVarP(&output, "out", "o", "", "sets type of output to json or yaml") - cmd.PersistentFlags().StringVar(&config.StatusSocket, "status-socket", filepath.Join(config.K0sVars.RunDir, "status.sock"), "Full file path to the socket file.") + cmd.PersistentFlags().String("status-socket", "", "Full file path to the socket file. (default: /status.sock)") cmd.AddCommand(NewStatusSubCmdComponents()) return cmd } diff --git a/cmd/stop/stop.go b/cmd/stop/stop.go index 69429b9d26c0..7c1368505186 100644 --- a/cmd/stop/stop.go +++ b/cmd/stop/stop.go @@ -19,6 +19,7 @@ package stop import ( "errors" "os" + "runtime" "github.com/k0sproject/k0s/pkg/install" @@ -32,7 +33,7 @@ func NewStopCmd() *cobra.Command { Short: "Stop the k0s service configured on this host. Must be run as root (or with sudo)", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, _ []string) error { - if os.Geteuid() != 0 { + if runtime.GOOS != "windows" && os.Geteuid() != 0 { return errors.New("this command must be run as root") } svc, err := install.InstalledService() diff --git a/cmd/token/create.go b/cmd/token/create.go index 05e24e45ae2c..724870c19fe0 100644 --- a/cmd/token/create.go +++ b/cmd/token/create.go @@ -1,3 +1,5 @@ +//go:build unix + /* Copyright 2021 k0s authors diff --git a/cmd/token/token.go b/cmd/token/token.go index dee7086113d7..1c1dc674ca71 100644 --- a/cmd/token/token.go +++ b/cmd/token/token.go @@ -32,10 +32,11 @@ func NewTokenCmd() *cobra.Command { Run: func(*cobra.Command, []string) { /* Enforce arg validation. */ }, } - cmd.AddCommand(tokenCreateCmd()) cmd.AddCommand(tokenListCmd()) cmd.AddCommand(tokenInvalidateCmd()) cmd.AddCommand(preSharedCmd()) + addPlatformSpecificCommands(cmd) + return cmd } diff --git a/cmd/token/token_other.go b/cmd/token/token_other.go new file mode 100644 index 000000000000..9ff8da998678 --- /dev/null +++ b/cmd/token/token_other.go @@ -0,0 +1,25 @@ +//go:build !unix + +/* +Copyright 2025 k0s 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 token + +import ( + "github.com/spf13/cobra" +) + +func addPlatformSpecificCommands(*cobra.Command) { /* no-op */ } diff --git a/cmd/backup/backup_windows.go b/cmd/token/token_unix.go similarity index 60% rename from cmd/backup/backup_windows.go rename to cmd/token/token_unix.go index bd2a43661168..c203937b3aa6 100644 --- a/cmd/backup/backup_windows.go +++ b/cmd/token/token_unix.go @@ -1,5 +1,7 @@ +//go:build unix + /* -Copyright 2021 k0s authors +Copyright 2025 k0s authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,23 +16,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -package backup +package token import ( - "errors" - "github.com/spf13/cobra" ) -var savePath string - -func NewBackupCmd() *cobra.Command { - return &cobra.Command{ - Use: "backup", - Short: "Back-Up k0s configuration. Not supported on Windows OS", - Args: cobra.NoArgs, - RunE: func(cmd *cobra.Command, args []string) error { - return errors.New("unsupported Operating System for this command") - }, - } +func addPlatformSpecificCommands(token *cobra.Command) { + token.AddCommand(tokenCreateCmd()) } diff --git a/cmd/worker/worker.go b/cmd/worker/worker.go index 9b4f23e1ba33..51eb2e917fac 100644 --- a/cmd/worker/worker.go +++ b/cmd/worker/worker.go @@ -27,11 +27,9 @@ import ( internallog "github.com/k0sproject/k0s/internal/pkg/log" "github.com/k0sproject/k0s/internal/pkg/sysinfo" - "github.com/k0sproject/k0s/pkg/build" "github.com/k0sproject/k0s/pkg/component/iptables" "github.com/k0sproject/k0s/pkg/component/manager" "github.com/k0sproject/k0s/pkg/component/prober" - "github.com/k0sproject/k0s/pkg/component/status" "github.com/k0sproject/k0s/pkg/component/worker" workerconfig "github.com/k0sproject/k0s/pkg/component/worker/config" "github.com/k0sproject/k0s/pkg/component/worker/containerd" @@ -172,31 +170,7 @@ func (c *Command) Start(ctx context.Context) error { certManager := worker.NewCertificateManager(kubeletKubeconfigPath) - // if running inside a controller, status component is already running - if !c.SingleNode && !c.EnableWorker { - componentManager.Add(ctx, &status.Status{ - Prober: prober.DefaultProber, - StatusInformation: status.K0sStatus{ - Pid: os.Getpid(), - Role: "worker", - Args: os.Args, - Version: build.Version, - Workloads: true, - SingleNode: false, - K0sVars: c.K0sVars, - // worker does not have cluster config. this is only shown in "k0s status -o json". - // todo: if it's needed, a worker side config client can be set up and used to load the config - ClusterConfig: nil, - }, - CertManager: certManager, - Socket: c.K0sVars.StatusSocketPath, - }) - } - - componentManager.Add(ctx, &worker.Autopilot{ - K0sVars: c.K0sVars, - CertManager: certManager, - }) + addPlatformSpecificComponents(ctx, componentManager, c.K0sVars, &c.ControllerOptions, certManager) // extract needed components if err := componentManager.Init(ctx); err != nil { diff --git a/cmd/worker/worker_other.go b/cmd/worker/worker_other.go new file mode 100644 index 000000000000..2f0ef1153dc8 --- /dev/null +++ b/cmd/worker/worker_other.go @@ -0,0 +1,31 @@ +//go:build !unix + +/* +Copyright 2025 k0s 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 worker + +import ( + "context" + + "github.com/k0sproject/k0s/pkg/component/manager" + "github.com/k0sproject/k0s/pkg/component/worker" + "github.com/k0sproject/k0s/pkg/config" +) + +func addPlatformSpecificComponents(context.Context, *manager.Manager, *config.CfgVars, *config.ControllerOptions, *worker.CertificateManager) { + // no-op +} diff --git a/cmd/worker/worker_unix.go b/cmd/worker/worker_unix.go new file mode 100644 index 000000000000..0f4908f9cd5c --- /dev/null +++ b/cmd/worker/worker_unix.go @@ -0,0 +1,59 @@ +//go:build unix + +/* +Copyright 2025 k0s 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 worker + +import ( + "context" + "os" + + "github.com/k0sproject/k0s/pkg/build" + "github.com/k0sproject/k0s/pkg/component/manager" + "github.com/k0sproject/k0s/pkg/component/prober" + "github.com/k0sproject/k0s/pkg/component/status" + "github.com/k0sproject/k0s/pkg/component/worker" + "github.com/k0sproject/k0s/pkg/config" +) + +func addPlatformSpecificComponents(ctx context.Context, m *manager.Manager, k0sVars *config.CfgVars, opts *config.ControllerOptions, certManager *worker.CertificateManager) { + // if running inside a controller, status component is already running + if !opts.SingleNode && !opts.EnableWorker { + m.Add(ctx, &status.Status{ + Prober: prober.DefaultProber, + StatusInformation: status.K0sStatus{ + Pid: os.Getpid(), + Role: "worker", + Args: os.Args, + Version: build.Version, + Workloads: true, + SingleNode: false, + K0sVars: k0sVars, + // worker does not have cluster config. this is only shown in "k0s status -o json". + // todo: if it's needed, a worker side config client can be set up and used to load the config + ClusterConfig: nil, + }, + CertManager: certManager, + Socket: k0sVars.StatusSocketPath, + }) + } + + m.Add(ctx, &worker.Autopilot{ + K0sVars: k0sVars, + CertManager: certManager, + }) +} diff --git a/internal/pkg/users/lookup_other.go b/internal/pkg/users/lookup_other.go new file mode 100644 index 000000000000..ec86cfdb7112 --- /dev/null +++ b/internal/pkg/users/lookup_other.go @@ -0,0 +1,29 @@ +//go:build !unix + +/* +Copyright 2024 k0s 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 users + +import ( + "errors" + "fmt" + "runtime" +) + +func LookupUID(string) (int, error) { + return 0, fmt.Errorf("%w on %s", errors.ErrUnsupported, runtime.GOOS) +} diff --git a/internal/pkg/users/lookup_unix.go b/internal/pkg/users/lookup_unix.go new file mode 100644 index 000000000000..4cb1f617c269 --- /dev/null +++ b/internal/pkg/users/lookup_unix.go @@ -0,0 +1,67 @@ +//go:build unix + +/* +Copyright 2024 k0s 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 users + +import ( + "bytes" + "errors" + "fmt" + "os/exec" + "os/user" + "strconv" +) + +// Lookup looks up a user's UID by username. If the user cannot be found, the +// returned error is [ErrNotExist]. If an error is returned, the returned UID +// will be [UnknownUID]. +func LookupUID(name string) (int, error) { + var uid string + + if entry, err := user.Lookup(name); err != nil { + if !errors.Is(err, user.UnknownUserError(name)) { + return UnknownUID, err + } + + err = ErrNotExist + + // fallback to call external `id` in case NSS is used + out, idErr := exec.Command("id", "-u", name).Output() + if idErr != nil { + var exitErr *exec.ExitError + if errors.As(idErr, &exitErr) { + return UnknownUID, fmt.Errorf("%w (%w: %s)", err, idErr, bytes.TrimSpace(exitErr.Stderr)) + } + return UnknownUID, fmt.Errorf("%w (%w)", err, idErr) + } + + uid = string(bytes.TrimSpace(out)) + } else { + uid = entry.Uid + } + + parsedUID, err := strconv.Atoi(uid) + if err != nil { + return UnknownUID, fmt.Errorf("UID %q is not a decimal integer: %w", uid, err) + } + if parsedUID < 0 { + return UnknownUID, fmt.Errorf("UID is negative: %d", parsedUID) + } + + return parsedUID, nil +} diff --git a/internal/pkg/users/users_test.go b/internal/pkg/users/lookup_unix_test.go similarity index 90% rename from internal/pkg/users/users_test.go rename to internal/pkg/users/lookup_unix_test.go index befd9c6d84b8..a240d173887a 100644 --- a/internal/pkg/users/users_test.go +++ b/internal/pkg/users/lookup_unix_test.go @@ -1,3 +1,5 @@ +//go:build unix + /* Copyright 2022 k0s authors @@ -18,17 +20,12 @@ package users import ( "os/exec" - "runtime" "testing" "github.com/stretchr/testify/assert" ) -func TestGetUID(t *testing.T) { - if runtime.GOOS == "windows" { - t.Skip("No numeric user IDs on Windows") - } - +func TestLookupUID(t *testing.T) { uid, err := LookupUID("root") if assert.NoError(t, err, "Failed to get UID for root user") { assert.Equal(t, 0, uid, "root's UID is not 0?") diff --git a/internal/pkg/users/users.go b/internal/pkg/users/users.go index e633a9e17fd1..f8927424246d 100644 --- a/internal/pkg/users/users.go +++ b/internal/pkg/users/users.go @@ -17,12 +17,7 @@ limitations under the License. package users import ( - "bytes" "errors" - "fmt" - "os/exec" - "os/user" - "strconv" ) const ( @@ -39,42 +34,3 @@ const ( ) var ErrNotExist = errors.New("user does not exist") - -// Lookup looks up a user's UID by username. If the user cannot be found, the -// returned error is [ErrNotExist]. If an error is returned, the returned UID -// will be [UnknownUID]. -func LookupUID(name string) (int, error) { - var uid string - - if entry, err := user.Lookup(name); err != nil { - if !errors.Is(err, user.UnknownUserError(name)) { - return UnknownUID, err - } - - err = ErrNotExist - - // fallback to call external `id` in case NSS is used - out, idErr := exec.Command("id", "-u", name).Output() - if idErr != nil { - var exitErr *exec.ExitError - if errors.As(idErr, &exitErr) { - return UnknownUID, fmt.Errorf("%w (%w: %s)", err, idErr, bytes.TrimSpace(exitErr.Stderr)) - } - return UnknownUID, fmt.Errorf("%w (%w)", err, idErr) - } - - uid = string(bytes.TrimSpace(out)) - } else { - uid = entry.Uid - } - - parsedUID, err := strconv.Atoi(uid) - if err != nil { - return UnknownUID, fmt.Errorf("UID %q is not a decimal integer: %w", uid, err) - } - if parsedUID < 0 { - return UnknownUID, fmt.Errorf("UID is negative: %d", parsedUID) - } - - return parsedUID, nil -} diff --git a/pkg/autopilot/controller/root_controller.go b/pkg/autopilot/controller/root_controller.go index b332a7439d8a..13290b2ff4bb 100644 --- a/pkg/autopilot/controller/root_controller.go +++ b/pkg/autopilot/controller/root_controller.go @@ -1,3 +1,5 @@ +//go:build unix + // Copyright 2021 k0s authors // // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/pkg/autopilot/controller/root_controller_test.go b/pkg/autopilot/controller/root_controller_test.go index 9c778fd10194..2c3d2d3697d7 100644 --- a/pkg/autopilot/controller/root_controller_test.go +++ b/pkg/autopilot/controller/root_controller_test.go @@ -1,3 +1,5 @@ +//go:build unix + // Copyright 2021 k0s authors // // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/pkg/autopilot/controller/root_worker.go b/pkg/autopilot/controller/root_worker.go index 8bb43c670700..531e556cb64c 100644 --- a/pkg/autopilot/controller/root_worker.go +++ b/pkg/autopilot/controller/root_worker.go @@ -1,3 +1,5 @@ +//go:build unix + // Copyright 2022 k0s authors // // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/pkg/autopilot/controller/setup.go b/pkg/autopilot/controller/setup.go index d39075e0fe12..fa6d4f0e36f4 100644 --- a/pkg/autopilot/controller/setup.go +++ b/pkg/autopilot/controller/setup.go @@ -1,3 +1,5 @@ +//go:build unix + // Copyright 2022 k0s authors // // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/pkg/autopilot/controller/signal/init.go b/pkg/autopilot/controller/signal/init.go index 4c51c1315b3b..980cf7bd42cf 100644 --- a/pkg/autopilot/controller/signal/init.go +++ b/pkg/autopilot/controller/signal/init.go @@ -1,3 +1,5 @@ +//go:build unix + // Copyright 2022 k0s authors // // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/pkg/autopilot/controller/signal/k0s/apply.go b/pkg/autopilot/controller/signal/k0s/apply.go index 003792f7fc77..c25910db5e3b 100644 --- a/pkg/autopilot/controller/signal/k0s/apply.go +++ b/pkg/autopilot/controller/signal/k0s/apply.go @@ -36,6 +36,8 @@ import ( crpred "sigs.k8s.io/controller-runtime/pkg/predicate" ) +const ApplyingUpdate = "ApplyingUpdate" + // applyingUpdateEventFilter creates a controller-runtime predicate that governs which // objects will make it into reconciliation, and which will be ignored. func applyingUpdateEventFilter(hostname string, handler apsigpred.ErrorHandler) crpred.Predicate { diff --git a/pkg/autopilot/controller/signal/k0s/cordon.go b/pkg/autopilot/controller/signal/k0s/cordon.go index d449990284f0..8c132b5b7d91 100644 --- a/pkg/autopilot/controller/signal/k0s/cordon.go +++ b/pkg/autopilot/controller/signal/k0s/cordon.go @@ -22,11 +22,13 @@ import ( autopilotv1beta2 "github.com/k0sproject/k0s/pkg/apis/autopilot/v1beta2" apcomm "github.com/k0sproject/k0s/pkg/autopilot/common" + apconst "github.com/k0sproject/k0s/pkg/autopilot/constant" apdel "github.com/k0sproject/k0s/pkg/autopilot/controller/delegate" apsigpred "github.com/k0sproject/k0s/pkg/autopilot/controller/signal/common/predicate" apsigv2 "github.com/k0sproject/k0s/pkg/autopilot/signaling/v2" cr "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" crcli "sigs.k8s.io/controller-runtime/pkg/client" crev "sigs.k8s.io/controller-runtime/pkg/event" crman "sigs.k8s.io/controller-runtime/pkg/manager" @@ -38,6 +40,8 @@ import ( "k8s.io/kubectl/pkg/drain" ) +const Cordoning = "Cordoning" + // cordoningEventFilter creates a controller-runtime predicate that governs which objects // will make it into reconciliation, and which will be ignored. func cordoningEventFilter(hostname string, handler apsigpred.ErrorHandler) crpred.Predicate { @@ -204,3 +208,16 @@ func (r *cordoning) drainNode(ctx context.Context, signalNode crcli.Object) erro return nil } + +func needsCordoning(signalNode client.Object) bool { + kind := signalNode.GetObjectKind().GroupVersionKind().Kind + if kind == "Node" { + return true + } + for k, v := range signalNode.GetAnnotations() { + if k == apconst.K0SControlNodeModeAnnotation && v == apconst.K0SControlNodeModeControllerWorker { + return true + } + } + return false +} diff --git a/pkg/autopilot/controller/signal/k0s/download.go b/pkg/autopilot/controller/signal/k0s/download.go index 721d7f7877eb..36c1048e7bd1 100644 --- a/pkg/autopilot/controller/signal/k0s/download.go +++ b/pkg/autopilot/controller/signal/k0s/download.go @@ -33,6 +33,8 @@ import ( crpred "sigs.k8s.io/controller-runtime/pkg/predicate" ) +const Downloading = "Downloading" + // downloadEventFilter creates a controller-runtime predicate that governs which objects // will make it into reconciliation, and which will be ignored. func downloadEventFilter(hostname string, handler apsigpred.ErrorHandler) crpred.Predicate { diff --git a/pkg/autopilot/controller/signal/k0s/init.go b/pkg/autopilot/controller/signal/k0s/init.go index 82b5fa21dfe4..aafb5f074d4f 100644 --- a/pkg/autopilot/controller/signal/k0s/init.go +++ b/pkg/autopilot/controller/signal/k0s/init.go @@ -1,3 +1,5 @@ +//go:build unix + // Copyright 2021 k0s authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,26 +23,14 @@ import ( "path/filepath" apcomm "github.com/k0sproject/k0s/pkg/autopilot/common" - apconst "github.com/k0sproject/k0s/pkg/autopilot/constant" apdel "github.com/k0sproject/k0s/pkg/autopilot/controller/delegate" apsigpred "github.com/k0sproject/k0s/pkg/autopilot/controller/signal/common/predicate" - apsigv2 "github.com/k0sproject/k0s/pkg/autopilot/signaling/v2" "github.com/k0sproject/k0s/pkg/component/status" "github.com/sirupsen/logrus" - "sigs.k8s.io/controller-runtime/pkg/client" crman "sigs.k8s.io/controller-runtime/pkg/manager" ) -const ( - Downloading = "Downloading" - Cordoning = "Cordoning" - CordoningFailed = "CordoningFailed" - UnCordoning = "UnCordoning" - ApplyingUpdate = "ApplyingUpdate" - Restart = "Restart" -) - // RegisterControllers registers all of the autopilot controllers used for updating `k0s` // to the controller-runtime manager. func RegisterControllers(ctx context.Context, logger *logrus.Entry, mgr crman.Manager, delegate apdel.ControllerDelegate, clusterID string) error { @@ -59,7 +49,11 @@ func RegisterControllers(ctx context.Context, logger *logrus.Entry, mgr crman.Ma logger.Infof("Using effective hostname = '%v'", hostname) - if err := registerSignalController(logger, mgr, signalControllerEventFilter(hostname, apsigpred.DefaultErrorHandler(logger, "k0s signal")), delegate, clusterID); err != nil { + k0sVersionHandler := func() (string, error) { + return getK0sVersion(DefaultK0sStatusSocketPath) + } + + if err := registerSignalController(logger, mgr, signalControllerEventFilter(hostname, apsigpred.DefaultErrorHandler(logger, "k0s signal")), delegate, clusterID, k0sVersionHandler); err != nil { return fmt.Errorf("unable to register k0s 'signal' controller: %w", err) } @@ -100,34 +94,3 @@ func getK0sVersion(statusSocketPath string) (string, error) { return status.Version, nil } - -// getK0sPid returns the PID of a running k0s based on its status socket. -func getK0sPid(statusSocketPath string) (int, error) { - status, err := status.GetStatusInfo(statusSocketPath) - if err != nil { - return -1, err - } - - return status.Pid, nil -} - -// signalDataUpdateCommandK0sPredicate creates a predicate that ensures that the -// provided SignalData is an 'k0s' update. -func signalDataUpdateCommandK0sPredicate() apsigpred.SignalDataPredicate { - return func(signalData apsigv2.SignalData) bool { - return signalData.Command.K0sUpdate != nil - } -} - -func needsCordoning(signalNode client.Object) bool { - kind := signalNode.GetObjectKind().GroupVersionKind().Kind - if kind == "Node" { - return true - } - for k, v := range signalNode.GetAnnotations() { - if k == apconst.K0SControlNodeModeAnnotation && v == apconst.K0SControlNodeModeControllerWorker { - return true - } - } - return false -} diff --git a/pkg/autopilot/controller/signal/k0s/restart_windows.go b/pkg/autopilot/controller/signal/k0s/restart_other.go similarity index 97% rename from pkg/autopilot/controller/signal/k0s/restart_windows.go rename to pkg/autopilot/controller/signal/k0s/restart_other.go index 9c32a1a665e9..1c151bf09aee 100644 --- a/pkg/autopilot/controller/signal/k0s/restart_windows.go +++ b/pkg/autopilot/controller/signal/k0s/restart_other.go @@ -1,3 +1,5 @@ +//go:build !unix + // Copyright 2022 k0s authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,6 +24,8 @@ import ( crpred "sigs.k8s.io/controller-runtime/pkg/predicate" ) +const Restart = "Restart" + // restartEventFilter creates a controller-runtime predicate that governs which // objects will make it into reconciliation, and which will be ignored. func restartEventFilter(hostname string, handler apsigpred.ErrorHandler) crpred.Predicate { diff --git a/pkg/autopilot/controller/signal/k0s/restart_unix.go b/pkg/autopilot/controller/signal/k0s/restart_unix.go index 4059b0f35166..44e6010edb15 100644 --- a/pkg/autopilot/controller/signal/k0s/restart_unix.go +++ b/pkg/autopilot/controller/signal/k0s/restart_unix.go @@ -26,6 +26,7 @@ import ( apdel "github.com/k0sproject/k0s/pkg/autopilot/controller/delegate" apsigpred "github.com/k0sproject/k0s/pkg/autopilot/controller/signal/common/predicate" apsigv2 "github.com/k0sproject/k0s/pkg/autopilot/signaling/v2" + "github.com/k0sproject/k0s/pkg/component/status" "github.com/sirupsen/logrus" cr "sigs.k8s.io/controller-runtime" @@ -35,6 +36,8 @@ import ( crpred "sigs.k8s.io/controller-runtime/pkg/predicate" ) +const Restart = "Restart" + const ( restartRequeueDuration = 5 * time.Second ) @@ -149,3 +152,13 @@ func (r *restart) Reconcile(ctx context.Context, req cr.Request) (cr.Result, err return cr.Result{}, nil } + +// getK0sPid returns the PID of a running k0s based on its status socket. +func getK0sPid(statusSocketPath string) (int, error) { + status, err := status.GetStatusInfo(statusSocketPath) + if err != nil { + return -1, err + } + + return status.Pid, nil +} diff --git a/pkg/autopilot/controller/signal/k0s/signal.go b/pkg/autopilot/controller/signal/k0s/signal.go index 63c4741f6770..379241ce9aa8 100644 --- a/pkg/autopilot/controller/signal/k0s/signal.go +++ b/pkg/autopilot/controller/signal/k0s/signal.go @@ -40,6 +40,14 @@ const ( type k0sVersionHandlerFunc func() (string, error) +// signalDataUpdateCommandK0sPredicate creates a predicate that ensures that the +// provided SignalData is an 'k0s' update. +func signalDataUpdateCommandK0sPredicate() apsigpred.SignalDataPredicate { + return func(signalData apsigv2.SignalData) bool { + return signalData.Command.K0sUpdate != nil + } +} + // signalControllerEventFilter creates a controller-runtime predicate that governs which objects // will make it into reconciliation, and which will be ignored. func signalControllerEventFilter(hostname string, handler apsigpred.ErrorHandler) crpred.Predicate { @@ -71,7 +79,7 @@ type signalControllerHandler struct { // // This controller is only interested in changes to its own annotations, and is the main // mechanism in identifying incoming autopilot k0s signaling updates. -func registerSignalController(logger *logrus.Entry, mgr crman.Manager, eventFilter crpred.Predicate, delegate apdel.ControllerDelegate, clusterID string) error { +func registerSignalController(logger *logrus.Entry, mgr crman.Manager, eventFilter crpred.Predicate, delegate apdel.ControllerDelegate, clusterID string, k0sVersionHandler k0sVersionHandlerFunc) error { logr := logger.WithFields(logrus.Fields{"updatetype": "k0s"}) logr.Infof("Registering 'signal' reconciler for '%s'", delegate.Name()) @@ -86,11 +94,9 @@ func registerSignalController(logger *logrus.Entry, mgr crman.Manager, eventFilt mgr.GetClient(), delegate, &signalControllerHandler{ - timeout: SignalResponseProcessingTimeout, - clusterID: clusterID, - k0sVersionHandler: func() (string, error) { - return getK0sVersion(DefaultK0sStatusSocketPath) - }, + timeout: SignalResponseProcessingTimeout, + clusterID: clusterID, + k0sVersionHandler: k0sVersionHandler, }, ), ) diff --git a/pkg/autopilot/controller/signal/k0s/signal_test.go b/pkg/autopilot/controller/signal/k0s/signal_test.go index 88aaaeb59a8f..2a4726c0ac29 100644 --- a/pkg/autopilot/controller/signal/k0s/signal_test.go +++ b/pkg/autopilot/controller/signal/k0s/signal_test.go @@ -1,3 +1,5 @@ +//go:build unix + // Copyright 2021 k0s authors // // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/pkg/autopilot/controller/signal/k0s/uncordon.go b/pkg/autopilot/controller/signal/k0s/uncordon.go index 0f03fa9316f4..ee8a3290d966 100644 --- a/pkg/autopilot/controller/signal/k0s/uncordon.go +++ b/pkg/autopilot/controller/signal/k0s/uncordon.go @@ -38,6 +38,8 @@ import ( crpred "sigs.k8s.io/controller-runtime/pkg/predicate" ) +const UnCordoning = "UnCordoning" + // unCordoningEventFilter creates a controller-runtime predicate that governs which objects // will make it into reconciliation, and which will be ignored. func unCordoningEventFilter(hostname string, handler apsigpred.ErrorHandler) crpred.Predicate { diff --git a/pkg/autopilot/controller/updates/periodicupdater.go b/pkg/autopilot/controller/updates/periodicupdater.go index fae29196b6ac..0332c0b2afe9 100644 --- a/pkg/autopilot/controller/updates/periodicupdater.go +++ b/pkg/autopilot/controller/updates/periodicupdater.go @@ -1,3 +1,5 @@ +//go:build unix + // Copyright 2023 k0s authors // // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/pkg/autopilot/controller/updates/update_controller.go b/pkg/autopilot/controller/updates/update_controller.go index ab574a9efd92..4ccfa70ab8cc 100644 --- a/pkg/autopilot/controller/updates/update_controller.go +++ b/pkg/autopilot/controller/updates/update_controller.go @@ -1,3 +1,5 @@ +//go:build unix + // Copyright 2021 k0s authors // // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/pkg/autopilot/controller/updates/updater.go b/pkg/autopilot/controller/updates/updater.go index 89fadaa3c725..6ad3ccadc86c 100644 --- a/pkg/autopilot/controller/updates/updater.go +++ b/pkg/autopilot/controller/updates/updater.go @@ -1,3 +1,5 @@ +//go:build unix + // Copyright 2021 k0s authors // // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/pkg/cleanup/cleanup.go b/pkg/cleanup/cleanup.go index a2d97571ac97..756a1819d417 100644 --- a/pkg/cleanup/cleanup.go +++ b/pkg/cleanup/cleanup.go @@ -1,3 +1,5 @@ +//go:build linux + /* Copyright 2021 k0s authors diff --git a/pkg/cleanup/cni.go b/pkg/cleanup/cni_linux.go similarity index 100% rename from pkg/cleanup/cni.go rename to pkg/cleanup/cni_linux.go diff --git a/pkg/cleanup/users.go b/pkg/cleanup/users_linux.go similarity index 100% rename from pkg/cleanup/users.go rename to pkg/cleanup/users_linux.go diff --git a/pkg/component/controller/autopilot.go b/pkg/component/controller/autopilot.go index 04c95249af12..4794393a0865 100644 --- a/pkg/component/controller/autopilot.go +++ b/pkg/component/controller/autopilot.go @@ -1,3 +1,5 @@ +//go:build unix + /* Copyright 2022 k0s authors diff --git a/pkg/component/status/client.go b/pkg/component/status/client.go index f2278a170e92..9c37736d41e0 100644 --- a/pkg/component/status/client.go +++ b/pkg/component/status/client.go @@ -1,3 +1,5 @@ +//go:build unix + /* Copyright 2022 k0s authors @@ -43,7 +45,6 @@ type K0sStatus struct { ClusterConfig *v1beta1.ClusterConfig K0sVars *config.CfgVars } - type ProbeStatus struct { Message string Success bool diff --git a/pkg/component/status/status.go b/pkg/component/status/status.go index 888f42ce4326..1ac61fab7b03 100644 --- a/pkg/component/status/status.go +++ b/pkg/component/status/status.go @@ -1,3 +1,5 @@ +//go:build unix + /* Copyright 2021 k0s authors @@ -41,6 +43,7 @@ import ( type Stater interface { State(maxCount int) prober.State } + type Status struct { StatusInformation K0sStatus Prober Stater diff --git a/pkg/component/worker/autopilot.go b/pkg/component/worker/autopilot.go index d6bcc772c86e..44a7a2ac22b0 100644 --- a/pkg/component/worker/autopilot.go +++ b/pkg/component/worker/autopilot.go @@ -1,3 +1,5 @@ +//go:build unix + /* Copyright 2022 k0s authors diff --git a/pkg/config/cli.go b/pkg/config/cli.go index a567b5a3c8ab..874e32149cf6 100644 --- a/pkg/config/cli.go +++ b/pkg/config/cli.go @@ -36,7 +36,6 @@ var ( CfgFile string Debug bool DebugListenOn string - StatusSocket string K0sVars CfgVars workerOpts WorkerOptions Verbose bool @@ -200,7 +199,7 @@ func GetPersistentFlagSet() *pflag.FlagSet { flagset.BoolVarP(&Debug, "debug", "d", false, "Debug logging (default: false)") flagset.BoolVarP(&Verbose, "verbose", "v", false, "Verbose logging (default: false)") flagset.String("data-dir", constant.DataDirDefault, "Data Directory for k0s. DO NOT CHANGE for an existing setup, things will break!") - flagset.StringVar(&StatusSocket, "status-socket", "", "Full file path to the socket file. (default: /status.sock)") + flagset.String("status-socket", "", "Full file path to the socket file. (default: /status.sock)") flagset.StringVar(&DebugListenOn, "debugListenOn", ":6060", "Http listenOn for Debug pprof handler") return flagset } diff --git a/pkg/install/service.go b/pkg/install/service.go index c7cccd5d4b1c..531b11031c23 100644 --- a/pkg/install/service.go +++ b/pkg/install/service.go @@ -18,7 +18,6 @@ package install import ( "errors" - "fmt" "github.com/kardianos/service" "github.com/sirupsen/logrus" @@ -65,9 +64,8 @@ func InstalledService() (service.Service, error) { return s, errors.New("k0s has not been installed as a service") } -// EnsureService installs the k0s service, per the given arguments, and the detected platform -func EnsureService(args []string, envVars []string, force bool) error { - var deps []string +// InstallService installs the k0s service, per the given arguments, and the detected platform +func InstallService(args []string, envVars []string, force bool) error { var svcConfig *service.Config prg := &Program{} @@ -83,37 +81,14 @@ func EnsureService(args []string, envVars []string, force bool) error { return err } - // fetch service type - svcType := s.Platform() - switch svcType { - case "linux-openrc": - deps = []string{"need cgroups", "need net", "use dns", "after firewall"} - svcConfig.Option = map[string]interface{}{ - "OpenRCScript": openRCScript, - } - case "linux-upstart": - svcConfig.Option = map[string]interface{}{ - "UpstartScript": upstartScript, - } - case "unix-systemv": - svcConfig.Option = map[string]interface{}{ - "SysVScript": sysvScript, - } - case "linux-systemd": - deps = []string{"After=network-online.target", "Wants=network-online.target"} - svcConfig.Option = map[string]interface{}{ - "SystemdScript": systemdScript, - "LimitNOFILE": 999999, - } - default: - } + configureServicePlatform(s, svcConfig) if len(envVars) > 0 { svcConfig.Option["Environment"] = envVars } - svcConfig.Dependencies = deps svcConfig.Arguments = args + if force { logrus.Infof("Uninstalling %s service", svcConfig.Name) err = s.Uninstall() @@ -121,12 +96,9 @@ func EnsureService(args []string, envVars []string, force bool) error { logrus.Warnf("failed to uninstall service: %v", err) } } + logrus.Infof("Installing %s service", svcConfig.Name) - err = s.Install() - if err != nil { - return fmt.Errorf("failed to install service: %w", err) - } - return nil + return s.Install() } func UninstallService(role string) error { diff --git a/pkg/install/service_linux.go b/pkg/install/service_linux.go new file mode 100644 index 000000000000..641ab957c011 --- /dev/null +++ b/pkg/install/service_linux.go @@ -0,0 +1,43 @@ +/* +Copyright 2025 k0s 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 install + +import "github.com/kardianos/service" + +func configureServicePlatform(s service.Service, svcConfig *service.Config) { + switch s.Platform() { + case "linux-openrc": + svcConfig.Dependencies = []string{"need cgroups", "need net", "use dns", "after firewall"} + svcConfig.Option = map[string]interface{}{ + "OpenRCScript": openRCScript, + } + case "linux-upstart": + svcConfig.Option = map[string]interface{}{ + "UpstartScript": upstartScript, + } + case "unix-systemv": + svcConfig.Option = map[string]interface{}{ + "SysVScript": sysvScript, + } + case "linux-systemd": + svcConfig.Dependencies = []string{"After=network-online.target", "Wants=network-online.target"} + svcConfig.Option = map[string]interface{}{ + "SystemdScript": systemdScript, + "LimitNOFILE": 999999, + } + } +} diff --git a/pkg/install/service_other.go b/pkg/install/service_other.go new file mode 100644 index 000000000000..0c3c6b7f0acc --- /dev/null +++ b/pkg/install/service_other.go @@ -0,0 +1,25 @@ +//go:build !linux + +/* +Copyright 2025 k0s 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 install + +import "github.com/kardianos/service" + +func configureServicePlatform(s service.Service, svcConfig *service.Config) { + // no-op +} diff --git a/pkg/install/users.go b/pkg/install/users_linux.go similarity index 97% rename from pkg/install/users.go rename to pkg/install/users_linux.go index 9a85ec83aeaf..ebe83d7689d6 100644 --- a/pkg/install/users.go +++ b/pkg/install/users_linux.go @@ -65,6 +65,8 @@ func DeleteControllerUsers(systemUsers *v1beta1.SystemUser) error { if err := deleteUser(userName); err != nil { errs = append(errs, err) } + } else if !errors.Is(err, users.ErrNotExist) { + errs = append(errs, err) } }