diff --git a/src/k8s/api/v1/bootstrap_config.go b/src/k8s/api/v1/bootstrap_config.go index 8efa4797c..679679962 100644 --- a/src/k8s/api/v1/bootstrap_config.go +++ b/src/k8s/api/v1/bootstrap_config.go @@ -1,4 +1,4 @@ -package v1 +package apiv1 import ( "encoding/json" diff --git a/src/k8s/api/v1/bootstrap_config_test.go b/src/k8s/api/v1/bootstrap_config_test.go index 400be832f..02cc2522d 100644 --- a/src/k8s/api/v1/bootstrap_config_test.go +++ b/src/k8s/api/v1/bootstrap_config_test.go @@ -1,4 +1,4 @@ -package v1_test +package apiv1_test import ( "testing" diff --git a/src/k8s/api/v1/capi_config.go b/src/k8s/api/v1/capi_config.go index 21ad91042..c00fbd00f 100644 --- a/src/k8s/api/v1/capi_config.go +++ b/src/k8s/api/v1/capi_config.go @@ -1,4 +1,4 @@ -package v1 +package apiv1 // SetClusterAPIAuthTokenRequest is used to request to set the auth token for ClusterAPI. type SetClusterAPIAuthTokenRequest struct { diff --git a/src/k8s/api/v1/cluster.go b/src/k8s/api/v1/cluster.go index 5c5e9a351..4b61e9a3f 100644 --- a/src/k8s/api/v1/cluster.go +++ b/src/k8s/api/v1/cluster.go @@ -1,4 +1,4 @@ -package v1 +package apiv1 // GetClusterStatusRequest is used to request the current status of the cluster. type GetClusterStatusRequest struct{} diff --git a/src/k8s/api/v1/cluster_config.go b/src/k8s/api/v1/cluster_config.go index 76d97b7b7..0e13e3270 100644 --- a/src/k8s/api/v1/cluster_config.go +++ b/src/k8s/api/v1/cluster_config.go @@ -1,4 +1,4 @@ -package v1 +package apiv1 import ( "fmt" diff --git a/src/k8s/api/v1/cluster_node.go b/src/k8s/api/v1/cluster_node.go index e3f158645..10e384ab8 100644 --- a/src/k8s/api/v1/cluster_node.go +++ b/src/k8s/api/v1/cluster_node.go @@ -1,4 +1,4 @@ -package v1 +package apiv1 // JoinClusterRequest is used to request to add a node to the cluster. type JoinClusterRequest struct { diff --git a/src/k8s/api/v1/join_config.go b/src/k8s/api/v1/join_config.go index 7a69aaa52..8cbafcacf 100644 --- a/src/k8s/api/v1/join_config.go +++ b/src/k8s/api/v1/join_config.go @@ -1,4 +1,4 @@ -package v1 +package apiv1 import ( "fmt" diff --git a/src/k8s/api/v1/kubernetes_auth_tokens.go b/src/k8s/api/v1/kubernetes_auth_tokens.go index 3f3547e62..1a2617ca3 100644 --- a/src/k8s/api/v1/kubernetes_auth_tokens.go +++ b/src/k8s/api/v1/kubernetes_auth_tokens.go @@ -1,4 +1,4 @@ -package v1 +package apiv1 // GenerateKubernetesAuthTokenRequest is used to request a new Kubernetes auth token. type GenerateKubernetesAuthTokenRequest struct { diff --git a/src/k8s/api/v1/node.go b/src/k8s/api/v1/node.go index 2c69bb573..4624c0c84 100644 --- a/src/k8s/api/v1/node.go +++ b/src/k8s/api/v1/node.go @@ -1,4 +1,4 @@ -package v1 +package apiv1 // GetNodeStatusResponse is the response for "GET 1.0/k8sd/node". type GetNodeStatusResponse struct { diff --git a/src/k8s/api/v1/tokens.go b/src/k8s/api/v1/tokens.go index deda5b91c..cb897fde1 100644 --- a/src/k8s/api/v1/tokens.go +++ b/src/k8s/api/v1/tokens.go @@ -1,4 +1,4 @@ -package v1 +package apiv1 // GetJoinTokenRequest is used to request a token for joining a node to the cluster. type GetJoinTokenRequest struct { diff --git a/src/k8s/api/v1/types.go b/src/k8s/api/v1/types.go index 1826256c2..e3a737e40 100644 --- a/src/k8s/api/v1/types.go +++ b/src/k8s/api/v1/types.go @@ -1,4 +1,4 @@ -package v1 +package apiv1 import ( "fmt" diff --git a/src/k8s/api/v1/types_test.go b/src/k8s/api/v1/types_test.go index 68a126c4e..b220e3020 100644 --- a/src/k8s/api/v1/types_test.go +++ b/src/k8s/api/v1/types_test.go @@ -1,4 +1,4 @@ -package v1_test +package apiv1_test import ( "testing" diff --git a/src/k8s/api/v1/util.go b/src/k8s/api/v1/util.go index 005e8c98a..f4453fdc5 100644 --- a/src/k8s/api/v1/util.go +++ b/src/k8s/api/v1/util.go @@ -1,4 +1,4 @@ -package v1 +package apiv1 func getField[T any](val *T) T { if val != nil { diff --git a/src/k8s/api/v1/worker.go b/src/k8s/api/v1/worker.go index 4b2dd935a..daff634d1 100644 --- a/src/k8s/api/v1/worker.go +++ b/src/k8s/api/v1/worker.go @@ -1,4 +1,4 @@ -package v1 +package apiv1 // WorkerNodeInfoRequest is used by a worker node to retrieve the required credentials // to join a cluster. diff --git a/src/k8s/cmd/k8s/k8s.go b/src/k8s/cmd/k8s/k8s.go index cbb091639..921c66e6c 100644 --- a/src/k8s/cmd/k8s/k8s.go +++ b/src/k8s/cmd/k8s/k8s.go @@ -87,9 +87,7 @@ func NewRootCmd(env cmdutil.ExecutionEnvironment) *cobra.Command { addCommands( cmd, nil, - newGenerateAuthTokenCmd(env), newLocalNodeStatusCommand(env), - newRevokeAuthTokenCmd(env), newGenerateDocsCmd(env), newHelmCmd(env), xPrintShimPidsCmd, diff --git a/src/k8s/cmd/k8s/k8s_bootstrap.go b/src/k8s/cmd/k8s/k8s_bootstrap.go index 5a4dacc9b..c6f321da0 100644 --- a/src/k8s/cmd/k8s/k8s_bootstrap.go +++ b/src/k8s/cmd/k8s/k8s_bootstrap.go @@ -79,14 +79,14 @@ func newBootstrapCmd(env cmdutil.ExecutionEnvironment) *cobra.Command { return } - client, err := env.Client(cmd.Context()) + client, err := env.Snap.K8sdClient("") if err != nil { cmd.PrintErrf("Error: Failed to create a k8sd client. Make sure that the k8sd service is running.\n\nThe error was: %v\n", err) env.Exit(1) return } - if client.IsBootstrapped(cmd.Context()) { + if _, err := client.NodeStatus(cmd.Context()); err == nil { cmd.PrintErrln("Error: The node is already part of a cluster") env.Exit(1) return @@ -134,7 +134,7 @@ func newBootstrapCmd(env cmdutil.ExecutionEnvironment) *cobra.Command { ctx, cancel := context.WithTimeout(cmd.Context(), opts.timeout) cobra.OnFinalize(cancel) - node, err := client.Bootstrap(ctx, request) + node, err := client.BootstrapCluster(ctx, request) if err != nil { cmd.PrintErrf("Error: Failed to bootstrap the cluster.\n\nThe error was: %v\n", err) env.Exit(1) diff --git a/src/k8s/cmd/k8s/k8s_bootstrap_test.go b/src/k8s/cmd/k8s/k8s_bootstrap_test.go index a10fc922d..c82839383 100644 --- a/src/k8s/cmd/k8s/k8s_bootstrap_test.go +++ b/src/k8s/cmd/k8s/k8s_bootstrap_test.go @@ -93,7 +93,7 @@ var testCases = []testCase{ { name: "InvalidKeys", yamlConfig: bootstrapConfigInvalidKeys, - expectedError: "field cluster-cidr not found in type v1.BootstrapConfig", + expectedError: "field cluster-cidr not found in type apiv1.BootstrapConfig", }, { name: "InvalidYAML", diff --git a/src/k8s/cmd/k8s/k8s_config.go b/src/k8s/cmd/k8s/k8s_config.go index 5e9afdb01..5a16acbdc 100644 --- a/src/k8s/cmd/k8s/k8s_config.go +++ b/src/k8s/cmd/k8s/k8s_config.go @@ -25,14 +25,14 @@ func newKubeConfigCmd(env cmdutil.ExecutionEnvironment) *cobra.Command { opts.timeout = minTimeout } - client, err := env.Client(cmd.Context()) + client, err := env.Snap.K8sdClient("") if err != nil { cmd.PrintErrf("Error: Failed to create a k8sd client. Make sure that the k8sd service is running.\n\nThe error was: %v\n", err) env.Exit(1) return } - if !client.IsBootstrapped(cmd.Context()) { + if _, err := client.NodeStatus(cmd.Context()); err != nil { cmd.PrintErrln("Error: The node is not part of a Kubernetes cluster. You can bootstrap a new cluster with:\n\n sudo k8s bootstrap") env.Exit(1) return diff --git a/src/k8s/cmd/k8s/k8s_disable.go b/src/k8s/cmd/k8s/k8s_disable.go index 698a3ef12..e14493198 100644 --- a/src/k8s/cmd/k8s/k8s_disable.go +++ b/src/k8s/cmd/k8s/k8s_disable.go @@ -80,7 +80,7 @@ func newDisableCmd(env cmdutil.ExecutionEnvironment) *cobra.Command { Config: config, } - client, err := env.Client(cmd.Context()) + client, err := env.Snap.K8sdClient("") if err != nil { cmd.PrintErrf("Error: Failed to create a k8sd client. Make sure that the k8sd service is running.\n\nThe error was: %v\n", err) env.Exit(1) @@ -90,7 +90,7 @@ func newDisableCmd(env cmdutil.ExecutionEnvironment) *cobra.Command { cmd.PrintErrf("Disabling %s from the cluster. This may take a few seconds, please wait.\n", strings.Join(args, ", ")) ctx, cancel := context.WithTimeout(cmd.Context(), opts.timeout) cobra.OnFinalize(cancel) - if err := client.UpdateClusterConfig(ctx, request); err != nil { + if err := client.SetClusterConfig(ctx, request); err != nil { cmd.PrintErrf("Error: Failed to disable %s from the cluster.\n\nThe error was: %v\n", strings.Join(args, ", "), err) env.Exit(1) return diff --git a/src/k8s/cmd/k8s/k8s_disable_test.go b/src/k8s/cmd/k8s/k8s_disable_test.go index 8b7fa50ee..ee424459a 100644 --- a/src/k8s/cmd/k8s/k8s_disable_test.go +++ b/src/k8s/cmd/k8s/k8s_disable_test.go @@ -2,15 +2,14 @@ package k8s_test import ( "bytes" - "context" - "github.com/canonical/k8s/pkg/utils" "testing" apiv1 "github.com/canonical/k8s/api/v1" "github.com/canonical/k8s/cmd/k8s" cmdutil "github.com/canonical/k8s/cmd/util" - "github.com/canonical/k8s/pkg/k8s/client" - "github.com/canonical/k8s/pkg/k8s/client/mock" + k8sdmock "github.com/canonical/k8s/pkg/client/k8sd/mock" + snapmock "github.com/canonical/k8s/pkg/snap/mock" + "github.com/canonical/k8s/pkg/utils" . "github.com/onsi/gomega" ) @@ -64,14 +63,16 @@ func TestDisableCmd(t *testing.T) { stdout := &bytes.Buffer{} stderr := &bytes.Buffer{} - mockClient := &mock.Client{} + mockClient := &k8sdmock.Mock{} var returnCode int env := cmdutil.ExecutionEnvironment{ Stdout: stdout, Stderr: stderr, Getuid: func() int { return 0 }, - Client: func(ctx context.Context) (client.Client, error) { - return mockClient, nil + Snap: &snapmock.Snap{ + Mock: snapmock.Mock{ + K8sdClient: mockClient, + }, }, Exit: func(rc int) { returnCode = rc }, } @@ -85,7 +86,7 @@ func TestDisableCmd(t *testing.T) { g.Expect(returnCode).To(Equal(tt.expectedCode)) if tt.expectedCode == 0 { - g.Expect(mockClient.UpdateClusterConfigCalledWith).To(Equal(tt.expectedCall)) + g.Expect(mockClient.SetClusterConfigCalledWith).To(Equal(tt.expectedCall)) } }) } diff --git a/src/k8s/cmd/k8s/k8s_enable.go b/src/k8s/cmd/k8s/k8s_enable.go index 091fbe992..0844e93cd 100644 --- a/src/k8s/cmd/k8s/k8s_enable.go +++ b/src/k8s/cmd/k8s/k8s_enable.go @@ -80,7 +80,7 @@ func newEnableCmd(env cmdutil.ExecutionEnvironment) *cobra.Command { Config: config, } - client, err := env.Client(cmd.Context()) + client, err := env.Snap.K8sdClient("") if err != nil { cmd.PrintErrf("Error: Failed to create a k8sd client. Make sure that the k8sd service is running.\n\nThe error was: %v\n", err) env.Exit(1) @@ -90,7 +90,7 @@ func newEnableCmd(env cmdutil.ExecutionEnvironment) *cobra.Command { cmd.PrintErrf("Enabling %s on the cluster. This may take a few seconds, please wait.\n", strings.Join(args, ", ")) ctx, cancel := context.WithTimeout(cmd.Context(), opts.timeout) cobra.OnFinalize(cancel) - if err := client.UpdateClusterConfig(ctx, request); err != nil { + if err := client.SetClusterConfig(ctx, request); err != nil { cmd.PrintErrf("Error: Failed to enable %s on the cluster.\n\nThe error was: %v\n", strings.Join(args, ", "), err) env.Exit(1) return diff --git a/src/k8s/cmd/k8s/k8s_enable_test.go b/src/k8s/cmd/k8s/k8s_enable_test.go index 3cfa1a560..59df399bb 100644 --- a/src/k8s/cmd/k8s/k8s_enable_test.go +++ b/src/k8s/cmd/k8s/k8s_enable_test.go @@ -2,15 +2,14 @@ package k8s_test import ( "bytes" - "context" - "github.com/canonical/k8s/pkg/utils" "testing" apiv1 "github.com/canonical/k8s/api/v1" "github.com/canonical/k8s/cmd/k8s" cmdutil "github.com/canonical/k8s/cmd/util" - "github.com/canonical/k8s/pkg/k8s/client" - "github.com/canonical/k8s/pkg/k8s/client/mock" + k8sdmock "github.com/canonical/k8s/pkg/client/k8sd/mock" + snapmock "github.com/canonical/k8s/pkg/snap/mock" + "github.com/canonical/k8s/pkg/utils" . "github.com/onsi/gomega" ) @@ -64,14 +63,16 @@ func TestK8sEnableCmd(t *testing.T) { stdout := &bytes.Buffer{} stderr := &bytes.Buffer{} - mockClient := &mock.Client{} + mockClient := &k8sdmock.Mock{} var returnCode int env := cmdutil.ExecutionEnvironment{ Stdout: stdout, Stderr: stderr, Getuid: func() int { return 0 }, - Client: func(ctx context.Context) (client.Client, error) { - return mockClient, nil + Snap: &snapmock.Snap{ + Mock: snapmock.Mock{ + K8sdClient: mockClient, + }, }, Exit: func(rc int) { returnCode = rc }, } @@ -85,7 +86,7 @@ func TestK8sEnableCmd(t *testing.T) { g.Expect(returnCode).To(Equal(tt.expectedCode)) if tt.expectedCode == 0 { - g.Expect(mockClient.UpdateClusterConfigCalledWith).To(Equal(tt.expectedCall)) + g.Expect(mockClient.SetClusterConfigCalledWith).To(Equal(tt.expectedCall)) } }) } diff --git a/src/k8s/cmd/k8s/k8s_generate_auth_token.go b/src/k8s/cmd/k8s/k8s_generate_auth_token.go deleted file mode 100644 index c878f027d..000000000 --- a/src/k8s/cmd/k8s/k8s_generate_auth_token.go +++ /dev/null @@ -1,48 +0,0 @@ -package k8s - -import ( - "time" - - apiv1 "github.com/canonical/k8s/api/v1" - cmdutil "github.com/canonical/k8s/cmd/util" - "github.com/spf13/cobra" -) - -func newGenerateAuthTokenCmd(env cmdutil.ExecutionEnvironment) *cobra.Command { - var opts struct { - username string - groups []string - timeout time.Duration - } - - cmd := &cobra.Command{ - Use: "generate-auth-token --username [--groups ,]", - Hidden: true, - PreRun: chainPreRunHooks(hookRequireRoot(env)), - Run: func(cmd *cobra.Command, args []string) { - if opts.timeout < minTimeout { - cmd.PrintErrf("Timeout %v is less than minimum of %v. Using the minimum %v instead.\n", opts.timeout, minTimeout, minTimeout) - opts.timeout = minTimeout - } - - client, err := env.Client(cmd.Context()) - if err != nil { - cmd.PrintErrf("Error: Failed to create a k8sd client. Make sure that the k8sd service is running.\n\nThe error was: %v\n", err) - env.Exit(1) - return - } - - token, err := client.GenerateAuthToken(cmd.Context(), apiv1.GenerateKubernetesAuthTokenRequest{Username: opts.username, Groups: opts.groups}) - if err != nil { - cmd.PrintErrf("Error: Failed to generate the requested Kubernetes auth token.\n\nThe error was: %v\n", err) - env.Exit(1) - return - } - cmd.Println(token) - }, - } - cmd.Flags().StringVar(&opts.username, "username", "", "Username") - cmd.Flags().StringSliceVar(&opts.groups, "groups", nil, "Groups") - cmd.Flags().DurationVar(&opts.timeout, "timeout", 90*time.Second, "the max time to wait for the command to execute") - return cmd -} diff --git a/src/k8s/cmd/k8s/k8s_get.go b/src/k8s/cmd/k8s/k8s_get.go index 3c2114948..20eb1422e 100644 --- a/src/k8s/cmd/k8s/k8s_get.go +++ b/src/k8s/cmd/k8s/k8s_get.go @@ -28,7 +28,7 @@ func newGetCmd(env cmdutil.ExecutionEnvironment) *cobra.Command { opts.timeout = minTimeout } - client, err := env.Client(cmd.Context()) + client, err := env.Snap.K8sdClient("") if err != nil { cmd.PrintErrf("Error: Failed to create a k8sd client. Make sure that the k8sd service is running.\n\nThe error was: %v\n", err) env.Exit(1) @@ -38,7 +38,7 @@ func newGetCmd(env cmdutil.ExecutionEnvironment) *cobra.Command { ctx, cancel := context.WithTimeout(cmd.Context(), opts.timeout) cobra.OnFinalize(cancel) - config, err := client.GetClusterConfig(ctx, apiv1.GetClusterConfigRequest{}) + config, err := client.GetClusterConfig(ctx) if err != nil { cmd.PrintErrf("Error: Failed to get the current cluster configuration.\n\nThe error was: %v\n", err) env.Exit(1) diff --git a/src/k8s/cmd/k8s/k8s_get_join_token.go b/src/k8s/cmd/k8s/k8s_get_join_token.go index c794bde9e..2b346e571 100644 --- a/src/k8s/cmd/k8s/k8s_get_join_token.go +++ b/src/k8s/cmd/k8s/k8s_get_join_token.go @@ -30,7 +30,7 @@ func newGetJoinTokenCmd(env cmdutil.ExecutionEnvironment) *cobra.Command { opts.timeout = minTimeout } - client, err := env.Client(cmd.Context()) + client, err := env.Snap.K8sdClient("") if err != nil { cmd.PrintErrf("Error: Failed to create a k8sd client. Make sure that the k8sd service is running.\n\nThe error was: %v\n", err) env.Exit(1) @@ -46,7 +46,7 @@ func newGetJoinTokenCmd(env cmdutil.ExecutionEnvironment) *cobra.Command { return } - cmd.Println(token) + cmd.Println(token.EncodedToken) }, } diff --git a/src/k8s/cmd/k8s/k8s_helm.go b/src/k8s/cmd/k8s/k8s_helm.go index 7bd5b0a6c..16f5cfb9d 100644 --- a/src/k8s/cmd/k8s/k8s_helm.go +++ b/src/k8s/cmd/k8s/k8s_helm.go @@ -5,8 +5,8 @@ import ( "path" "syscall" + apiv1 "github.com/canonical/k8s/api/v1" cmdutil "github.com/canonical/k8s/cmd/util" - snaputil "github.com/canonical/k8s/pkg/snap/util" "github.com/spf13/cobra" ) @@ -17,30 +17,21 @@ func newHelmCmd(env cmdutil.ExecutionEnvironment) *cobra.Command { DisableFlagParsing: true, PreRun: chainPreRunHooks(hookRequireRoot(env)), Run: func(cmd *cobra.Command, args []string) { - isWorker, err := snaputil.IsWorker(env.Snap) - if err != nil { - cmd.PrintErrf("Error: Failed to check if this is worker-only node.\n\nThe error was: %v\n", err) - env.Exit(1) - return - } - - if isWorker { - cmd.PrintErrln("Error: k8s helm commands are not allowed on worker nodes") - env.Exit(1) - return - } - - client, err := env.Client(cmd.Context()) + client, err := env.Snap.K8sdClient("") if err != nil { cmd.PrintErrf("Error: Failed to create a k8sd client. Make sure that the k8sd service is running.\n\nThe error was: %v\n", err) env.Exit(1) return } - if !client.IsBootstrapped(cmd.Context()) { + if status, err := client.NodeStatus(cmd.Context()); err != nil { cmd.PrintErrln("Error: The node is not part of a Kubernetes cluster. You can bootstrap a new cluster with:\n\n sudo k8s bootstrap") env.Exit(1) return + } else if status.ClusterRole == apiv1.ClusterRoleWorker { + cmd.PrintErrln("Error: k8s helm commands are not allowed on worker nodes.") + env.Exit(1) + return } binary, err := exec.LookPath("helm") diff --git a/src/k8s/cmd/k8s/k8s_join_cluster.go b/src/k8s/cmd/k8s/k8s_join_cluster.go index 0bf5e4ac8..45b855ab7 100644 --- a/src/k8s/cmd/k8s/k8s_join_cluster.go +++ b/src/k8s/cmd/k8s/k8s_join_cluster.go @@ -62,14 +62,14 @@ func newJoinClusterCmd(env cmdutil.ExecutionEnvironment) *cobra.Command { return } - client, err := env.Client(cmd.Context()) + client, err := env.Snap.K8sdClient("") if err != nil { cmd.PrintErrf("Error: Failed to create a k8sd client. Make sure that the k8sd service is running.\n\nThe error was: %v\n", err) env.Exit(1) return } - if client.IsBootstrapped(cmd.Context()) { + if _, err := client.NodeStatus(cmd.Context()); err == nil { cmd.PrintErrln("Error: The node is already part of a cluster") env.Exit(1) return diff --git a/src/k8s/cmd/k8s/k8s_kubectl.go b/src/k8s/cmd/k8s/k8s_kubectl.go index 18b0ac14e..65e12009a 100644 --- a/src/k8s/cmd/k8s/k8s_kubectl.go +++ b/src/k8s/cmd/k8s/k8s_kubectl.go @@ -5,8 +5,8 @@ import ( "path" "syscall" + apiv1 "github.com/canonical/k8s/api/v1" cmdutil "github.com/canonical/k8s/cmd/util" - snaputil "github.com/canonical/k8s/pkg/snap/util" "github.com/spf13/cobra" ) @@ -17,30 +17,21 @@ func newKubectlCmd(env cmdutil.ExecutionEnvironment) *cobra.Command { DisableFlagParsing: true, PreRun: chainPreRunHooks(hookRequireRoot(env)), Run: func(cmd *cobra.Command, args []string) { - isWorker, err := snaputil.IsWorker(env.Snap) - if err != nil { - cmd.PrintErrf("Error: Failed to check if this is worker-only node.\n\nThe error was: %v\n", err) - env.Exit(1) - return - } - - if isWorker { - cmd.PrintErrln("Error: k8s kubectl commands are not allowed on worker nodes") - env.Exit(1) - return - } - - client, err := env.Client(cmd.Context()) + client, err := env.Snap.K8sdClient("") if err != nil { cmd.PrintErrf("Error: Failed to create a k8sd client. Make sure that the k8sd service is running.\n\nThe error was: %v\n", err) env.Exit(1) return } - if !client.IsBootstrapped(cmd.Context()) { + if status, err := client.NodeStatus(cmd.Context()); err != nil { cmd.PrintErrln("Error: The node is not part of a Kubernetes cluster. You can bootstrap a new cluster with:\n\n sudo k8s bootstrap") env.Exit(1) return + } else if status.ClusterRole == apiv1.ClusterRoleWorker { + cmd.PrintErrln("Error: k8s helm commands are not allowed on worker nodes.") + env.Exit(1) + return } binary, err := exec.LookPath("kubectl") diff --git a/src/k8s/cmd/k8s/k8s_local_node_status.go b/src/k8s/cmd/k8s/k8s_local_node_status.go index 0e31100f1..81422feb9 100644 --- a/src/k8s/cmd/k8s/k8s_local_node_status.go +++ b/src/k8s/cmd/k8s/k8s_local_node_status.go @@ -15,14 +15,14 @@ func newLocalNodeStatusCommand(env cmdutil.ExecutionEnvironment) *cobra.Command Hidden: true, PreRun: chainPreRunHooks(hookRequireRoot(env), hookInitializeFormatter(env, &opts.outputFormat)), Run: func(cmd *cobra.Command, args []string) { - client, err := env.Client(cmd.Context()) + client, err := env.Snap.K8sdClient("") if err != nil { cmd.PrintErrf("Error: Failed to create a k8sd client. Make sure that the k8sd service is running.\n\nThe error was: %v\n", err) env.Exit(1) return } - status, err := client.LocalNodeStatus(cmd.Context()) + status, err := client.NodeStatus(cmd.Context()) if err != nil { cmd.PrintErrf("Error: Failed to get the status of the local node.\n\nThe error was: %v\n", err) env.Exit(1) diff --git a/src/k8s/cmd/k8s/k8s_remove_node.go b/src/k8s/cmd/k8s/k8s_remove_node.go index 9f6780361..8df922433 100644 --- a/src/k8s/cmd/k8s/k8s_remove_node.go +++ b/src/k8s/cmd/k8s/k8s_remove_node.go @@ -35,7 +35,7 @@ func newRemoveNodeCmd(env cmdutil.ExecutionEnvironment) *cobra.Command { opts.timeout = minTimeout } - client, err := env.Client(cmd.Context()) + client, err := env.Snap.K8sdClient("") if err != nil { cmd.PrintErrf("Error: Failed to create a k8sd client. Make sure that the k8sd service is running.\n\nThe error was: %v\n", err) env.Exit(1) diff --git a/src/k8s/cmd/k8s/k8s_revoke_auth_token.go b/src/k8s/cmd/k8s/k8s_revoke_auth_token.go deleted file mode 100644 index 255afd505..000000000 --- a/src/k8s/cmd/k8s/k8s_revoke_auth_token.go +++ /dev/null @@ -1,36 +0,0 @@ -package k8s - -import ( - apiv1 "github.com/canonical/k8s/api/v1" - cmdutil "github.com/canonical/k8s/cmd/util" - "github.com/spf13/cobra" -) - -func newRevokeAuthTokenCmd(env cmdutil.ExecutionEnvironment) *cobra.Command { - var opts struct { - token string - } - cmd := &cobra.Command{ - Use: "revoke-auth-token --token ", - Hidden: true, - PreRun: chainPreRunHooks(hookRequireRoot(env)), - Run: func(cmd *cobra.Command, args []string) { - - client, err := env.Client(cmd.Context()) - if err != nil { - cmd.PrintErrf("Error: Failed to create a k8sd client. Make sure that the k8sd service is running.\n\nThe error was: %v\n", err) - env.Exit(1) - return - } - - if err := client.RevokeAuthToken(cmd.Context(), apiv1.RevokeKubernetesAuthTokenRequest{Token: opts.token}); err != nil { - cmd.PrintErrf("Error: Failed to revoke the auth token.\n\nThe error was: %v\n", err) - env.Exit(1) - return - } - }, - } - - cmd.Flags().StringVar(&opts.token, "token", "", "Token") - return cmd -} diff --git a/src/k8s/cmd/k8s/k8s_set.go b/src/k8s/cmd/k8s/k8s_set.go index 496ea6e50..327b5eb45 100644 --- a/src/k8s/cmd/k8s/k8s_set.go +++ b/src/k8s/cmd/k8s/k8s_set.go @@ -42,7 +42,7 @@ func newSetCmd(env cmdutil.ExecutionEnvironment) *cobra.Command { } } - client, err := env.Client(cmd.Context()) + client, err := env.Snap.K8sdClient("") if err != nil { cmd.PrintErrf("Error: Failed to create a k8sd client. Make sure that the k8sd service is running.\n\nThe error was: %v\n", err) env.Exit(1) @@ -56,7 +56,7 @@ func newSetCmd(env cmdutil.ExecutionEnvironment) *cobra.Command { ctx, cancel := context.WithTimeout(cmd.Context(), opts.timeout) cobra.OnFinalize(cancel) - if err := client.UpdateClusterConfig(ctx, request); err != nil { + if err := client.SetClusterConfig(ctx, request); err != nil { cmd.PrintErrf("Error: Failed to apply requested cluster configuration changes.\n\nThe error was: %v\n", err) env.Exit(1) return diff --git a/src/k8s/cmd/k8s/k8s_status.go b/src/k8s/cmd/k8s/k8s_status.go index a52786d62..e5ffdec5b 100644 --- a/src/k8s/cmd/k8s/k8s_status.go +++ b/src/k8s/cmd/k8s/k8s_status.go @@ -25,7 +25,7 @@ func newStatusCmd(env cmdutil.ExecutionEnvironment) *cobra.Command { opts.timeout = minTimeout } - client, err := env.Client(cmd.Context()) + client, err := env.Snap.K8sdClient("") if err != nil { cmd.PrintErrf("Error: Failed to create a k8sd client. Make sure that the k8sd service is running.\n\nThe error was: %v\n", err) env.Exit(1) @@ -35,7 +35,7 @@ func newStatusCmd(env cmdutil.ExecutionEnvironment) *cobra.Command { ctx, cancel := context.WithTimeout(cmd.Context(), opts.timeout) cobra.OnFinalize(cancel) - if !client.IsBootstrapped(ctx) { + if _, err := client.NodeStatus(cmd.Context()); err != nil { cmd.PrintErrln("Error: The node is not part of a Kubernetes cluster. You can bootstrap a new cluster with:\n\n sudo k8s bootstrap") env.Exit(1) return diff --git a/src/k8s/cmd/k8s/k8s_x_capi.go b/src/k8s/cmd/k8s/k8s_x_capi.go index 9889b4d60..193df8e95 100644 --- a/src/k8s/cmd/k8s/k8s_x_capi.go +++ b/src/k8s/cmd/k8s/k8s_x_capi.go @@ -19,7 +19,7 @@ func newXCAPICmd(env cmdutil.ExecutionEnvironment) *cobra.Command { return } - client, err := env.Client(cmd.Context()) + client, err := env.Snap.K8sdClient("") if err != nil { cmd.PrintErrf("Error: Failed to create a k8sd client. Make sure that the k8sd service is running.\n\nThe error was: %v\n", err) env.Exit(1) diff --git a/src/k8s/cmd/k8s/k8s_x_snapd_config.go b/src/k8s/cmd/k8s/k8s_x_snapd_config.go index c6ee24b8c..2064d5e5b 100644 --- a/src/k8s/cmd/k8s/k8s_x_snapd_config.go +++ b/src/k8s/cmd/k8s/k8s_x_snapd_config.go @@ -1,7 +1,6 @@ package k8s import ( - apiv1 "github.com/canonical/k8s/api/v1" cmdutil "github.com/canonical/k8s/cmd/util" "github.com/canonical/k8s/pkg/utils/experimental/snapdconfig" "github.com/spf13/cobra" @@ -47,13 +46,13 @@ func newXSnapdConfigCmd(env cmdutil.ExecutionEnvironment) *cobra.Command { cmd.PrintErrln("Warning: meta.orb is none, skipping reconcile actions") return case "k8sd": - client, err := env.Client(cmd.Context()) + client, err := env.Snap.K8sdClient("") if err != nil { cmd.PrintErrf("Error: failed to create k8sd client: %v\n", err) env.Exit(1) return } - config, err := client.GetClusterConfig(cmd.Context(), apiv1.GetClusterConfigRequest{}) + config, err := client.GetClusterConfig(cmd.Context()) if err != nil { cmd.PrintErrf("Error: failed to retrieve cluster configuration: %v\n", err) env.Exit(1) @@ -65,7 +64,7 @@ func newXSnapdConfigCmd(env cmdutil.ExecutionEnvironment) *cobra.Command { return } case "snapd": - client, err := env.Client(cmd.Context()) + client, err := env.Snap.K8sdClient("") if err != nil { cmd.PrintErrf("Error: failed to create k8sd client: %v\n", err) env.Exit(1) diff --git a/src/k8s/cmd/util/environ.go b/src/k8s/cmd/util/environ.go index 73e6f894f..9c19ab6ef 100644 --- a/src/k8s/cmd/util/environ.go +++ b/src/k8s/cmd/util/environ.go @@ -1,13 +1,11 @@ package cmdutil import ( - "context" "fmt" "io" "os" "strings" - "github.com/canonical/k8s/pkg/k8s/client" "github.com/canonical/k8s/pkg/snap" ) @@ -27,8 +25,6 @@ type ExecutionEnvironment struct { Getuid func() int // Snap provides the snap environment for the command. Snap snap.Snap - // Client is used to retrieve a k8sd client. - Client func(ctx context.Context) (client.Client, error) } // DefaultExecutionEnvironment is used to run the CLI. @@ -57,9 +53,6 @@ func DefaultExecutionEnvironment() ExecutionEnvironment { Environ: os.Environ(), Getuid: os.Getuid, Snap: s, - Client: func(ctx context.Context) (client.Client, error) { - return client.New(ctx, s) - }, } } diff --git a/src/k8s/pkg/client/k8sd/cluster.go b/src/k8s/pkg/client/k8sd/cluster.go new file mode 100644 index 000000000..49793ec22 --- /dev/null +++ b/src/k8s/pkg/client/k8sd/cluster.go @@ -0,0 +1,63 @@ +package k8sd + +import ( + "context" + "fmt" + + apiv1 "github.com/canonical/k8s/api/v1" + "github.com/canonical/k8s/pkg/utils/control" + "github.com/canonical/lxd/shared/api" +) + +func (c *k8sd) BootstrapCluster(ctx context.Context, request apiv1.PostClusterBootstrapRequest) (apiv1.NodeStatus, error) { + if err := c.app.Ready(ctx); err != nil { + return apiv1.NodeStatus{}, fmt.Errorf("k8sd is not ready: %w", err) + } + + var response apiv1.NodeStatus + if err := c.client.Query(ctx, "POST", api.NewURL().Path("k8sd", "cluster"), request, &response); err != nil { + return apiv1.NodeStatus{}, fmt.Errorf("failed to POST /k8sd/cluster: %w", err) + } + + return response, nil +} + +func (c *k8sd) JoinCluster(ctx context.Context, request apiv1.JoinClusterRequest) error { + if err := c.app.Ready(ctx); err != nil { + return fmt.Errorf("k8sd is not ready: %w", err) + } + + if err := c.client.Query(ctx, "POST", api.NewURL().Path("k8sd", "cluster", "join"), request, nil); err != nil { + return fmt.Errorf("failed to POST /k8sd/cluster/join: %w", err) + } + + // NOTE(neoaggelos): we should not ignore this error + _ = control.WaitUntilReady(ctx, func() (bool, error) { + nodeStatus, err := c.NodeStatus(ctx) + switch { + case err != nil: + return false, fmt.Errorf("failed to get node status: %w", err) + case nodeStatus.DatastoreRole == apiv1.DatastoreRolePending: + // still waiting for node to join + return false, nil + } + return true, nil + }) + + return nil +} + +func (c *k8sd) RemoveNode(ctx context.Context, request apiv1.RemoveNodeRequest) error { + if err := c.client.Query(ctx, "POST", api.NewURL().Path("k8sd", "cluster", "remove"), request, nil); err != nil { + return fmt.Errorf("failed to POST /k8sd/cluster/remove: %w", err) + } + return nil +} + +func (c *k8sd) GetJoinToken(ctx context.Context, request apiv1.GetJoinTokenRequest) (apiv1.GetJoinTokenResponse, error) { + var response apiv1.GetJoinTokenResponse + if err := c.client.Query(ctx, "POST", api.NewURL().Path("k8sd", "cluster", "tokens"), request, &response); err != nil { + return apiv1.GetJoinTokenResponse{}, fmt.Errorf("failed to POST /k8sd/cluster/tokens: %w", err) + } + return response, nil +} diff --git a/src/k8s/pkg/client/k8sd/clusterapi.go b/src/k8s/pkg/client/k8sd/clusterapi.go new file mode 100644 index 000000000..d65fdd9af --- /dev/null +++ b/src/k8s/pkg/client/k8sd/clusterapi.go @@ -0,0 +1,16 @@ +package k8sd + +import ( + "context" + "fmt" + + apiv1 "github.com/canonical/k8s/api/v1" + "github.com/canonical/lxd/shared/api" +) + +func (c *k8sd) SetClusterAPIAuthToken(ctx context.Context, request apiv1.SetClusterAPIAuthTokenRequest) error { + if err := c.client.Query(ctx, "POST", api.NewURL().Path("x", "capi", "set-auth-token"), request, nil); err != nil { + return fmt.Errorf("failed to POST /x/capi/set-auth-token: %w", err) + } + return nil +} diff --git a/src/k8s/pkg/client/k8sd/config.go b/src/k8s/pkg/client/k8sd/config.go new file mode 100644 index 000000000..8bf524fde --- /dev/null +++ b/src/k8s/pkg/client/k8sd/config.go @@ -0,0 +1,25 @@ +package k8sd + +import ( + "context" + "fmt" + + apiv1 "github.com/canonical/k8s/api/v1" + "github.com/canonical/lxd/shared/api" +) + +func (c *k8sd) SetClusterConfig(ctx context.Context, request apiv1.UpdateClusterConfigRequest) error { + if err := c.client.Query(ctx, "PUT", api.NewURL().Path("k8sd", "cluster", "config"), request, nil); err != nil { + return fmt.Errorf("failed to PUT /k8sd/cluster/config: %w", err) + } + return nil +} + +func (c *k8sd) GetClusterConfig(ctx context.Context) (apiv1.UserFacingClusterConfig, error) { + var response apiv1.GetClusterConfigResponse + if err := c.client.Query(ctx, "GET", api.NewURL().Path("k8sd", "cluster", "config"), nil, &response); err != nil { + return apiv1.UserFacingClusterConfig{}, fmt.Errorf("failed to GET /k8sd/cluster/config: %w", err) + } + + return response.Config, nil +} diff --git a/src/k8s/pkg/client/k8sd/interface.go b/src/k8s/pkg/client/k8sd/interface.go new file mode 100644 index 000000000..b0858d2b6 --- /dev/null +++ b/src/k8s/pkg/client/k8sd/interface.go @@ -0,0 +1,55 @@ +package k8sd + +import ( + "context" + + apiv1 "github.com/canonical/k8s/api/v1" +) + +// ClusterClient implements methods for managing the cluster members. +type ClusterClient interface { + // BootstrapCluster initializes a new cluster using the provided configuration. + BootstrapCluster(context.Context, apiv1.PostClusterBootstrapRequest) (apiv1.NodeStatus, error) + // GetJoinToken generates a token for nodes to join the cluster. + GetJoinToken(context.Context, apiv1.GetJoinTokenRequest) (apiv1.GetJoinTokenResponse, error) + // JoinCluster joins an existing cluster. + JoinCluster(context.Context, apiv1.JoinClusterRequest) error + // RemoveNode removes a node from the cluster. + RemoveNode(context.Context, apiv1.RemoveNodeRequest) error +} + +// StatusClient implements methods for retrieving the current status of the cluster. +type StatusClient interface { + // NodeStatus retrieves the current status of the local node. + NodeStatus(ctx context.Context) (apiv1.NodeStatus, error) + // ClusterStatus retrieves the current status of the Kubernetes cluster. + ClusterStatus(ctx context.Context, waitReady bool) (apiv1.ClusterStatus, error) +} + +// ConfigClient implements methods to retrieve and manage the cluster configuration. +type ConfigClient interface { + // GetClusterConfig retrieves the k8sd cluster configuration. + GetClusterConfig(context.Context) (apiv1.UserFacingClusterConfig, error) + // SetClusterConfig updates the k8sd cluster configuration. + SetClusterConfig(context.Context, apiv1.UpdateClusterConfigRequest) error +} + +// UserClient implements methods to enable accessing the cluster. +type UserClient interface { + // KubeConfig retrieves a kubeconfig file that can be used to access the cluster. + KubeConfig(context.Context, apiv1.GetKubeConfigRequest) (string, error) +} + +// ClusterAPIClient implements methods related to ClusterAPI endpoints. +type ClusterAPIClient interface { + // SetClusterAPIAuthToken sets the well-known token that can be used authenticating requests to the ClusterAPI related endpoints. + SetClusterAPIAuthToken(context.Context, apiv1.SetClusterAPIAuthTokenRequest) error +} + +type Client interface { + ClusterClient + StatusClient + ConfigClient + UserClient + ClusterAPIClient +} diff --git a/src/k8s/pkg/client/k8sd/k8sd.go b/src/k8s/pkg/client/k8sd/k8sd.go new file mode 100644 index 000000000..2b750f562 --- /dev/null +++ b/src/k8s/pkg/client/k8sd/k8sd.go @@ -0,0 +1,44 @@ +package k8sd + +import ( + "fmt" + + "github.com/canonical/microcluster/client" + "github.com/canonical/microcluster/microcluster" +) + +// k8sd implements Client. +type k8sd struct { + app *microcluster.MicroCluster + client *client.Client +} + +// New creates a new k8sd client. +// stateDir is the root k8sd state directory, where server.crt and server.key certificates are found. +// address must be left empty to interact with k8sd using the local unix socket from stateDir. +func New(stateDir string, address string) (*k8sd, error) { + app, err := microcluster.App(microcluster.Args{ + StateDir: stateDir, + }) + if err != nil { + return nil, fmt.Errorf("failed to initialize microcluster app: %w", err) + } + + var client *client.Client + if address == "" { + if client, err = app.LocalClient(); err != nil { + return nil, fmt.Errorf("failed to create local microcluster client: %w", err) + } + } else { + if client, err = app.RemoteClient(address); err != nil { + return nil, fmt.Errorf("failed to create remote microcluster client to %q: %w", address, err) + } + } + + return &k8sd{ + app: app, + client: client, + }, nil +} + +var _ Client = &k8sd{} diff --git a/src/k8s/pkg/client/k8sd/mock/mock.go b/src/k8s/pkg/client/k8sd/mock/mock.go new file mode 100644 index 000000000..bd73bf727 --- /dev/null +++ b/src/k8s/pkg/client/k8sd/mock/mock.go @@ -0,0 +1,88 @@ +package mock + +import ( + "context" + + apiv1 "github.com/canonical/k8s/api/v1" + "github.com/canonical/k8s/pkg/client/k8sd" +) + +// Mock is a mock implementation of k8sd.Client. +type Mock struct { + // k8sd.ClusterClient + BootstrapClusterCalledWith apiv1.PostClusterBootstrapRequest + BootstrapClusterResult apiv1.NodeStatus + BootstrapClusterErr error + GetJoinTokenCalledWith apiv1.GetJoinTokenRequest + GetJoinTokenResult apiv1.GetJoinTokenResponse + GetJoinTokenErr error + JoinClusterCalledWith apiv1.JoinClusterRequest + JoinClusterErr error + RemoveNodeCalledWith apiv1.RemoveNodeRequest + RemoveNodeErr error + + // k8sd.StatusClient + NodeStatusResult apiv1.NodeStatus + NodeStatusErr error + ClusterStatusResult apiv1.ClusterStatus + ClusterStatusErr error + + // k8sd.ConfigClient + GetClusterConfigResult apiv1.UserFacingClusterConfig + GetClusterConfigErr error + SetClusterConfigCalledWith apiv1.UpdateClusterConfigRequest + SetClusterConfigErr error + + // k8sd.UserClient + KubeConfigCalledWith apiv1.GetKubeConfigRequest + KubeConfigResult string + KubeConfigErr error + + // k8sd.ClusterAPIClient + SetClusterAPIAuthTokenCalledWith apiv1.SetClusterAPIAuthTokenRequest + SetClusterAPIAuthTokenErr error +} + +func (m *Mock) BootstrapCluster(_ context.Context, request apiv1.PostClusterBootstrapRequest) (apiv1.NodeStatus, error) { + m.BootstrapClusterCalledWith = request + return m.BootstrapClusterResult, m.BootstrapClusterErr +} +func (m *Mock) GetJoinToken(_ context.Context, request apiv1.GetJoinTokenRequest) (apiv1.GetJoinTokenResponse, error) { + m.GetJoinTokenCalledWith = request + return m.GetJoinTokenResult, m.GetJoinTokenErr +} +func (m *Mock) JoinCluster(_ context.Context, request apiv1.JoinClusterRequest) error { + m.JoinClusterCalledWith = request + return m.JoinClusterErr +} +func (m *Mock) RemoveNode(_ context.Context, request apiv1.RemoveNodeRequest) error { + m.RemoveNodeCalledWith = request + return m.RemoveNodeErr +} + +func (m *Mock) NodeStatus(_ context.Context) (apiv1.NodeStatus, error) { + return m.NodeStatusResult, m.NodeStatusErr +} +func (m *Mock) ClusterStatus(_ context.Context, waitReady bool) (apiv1.ClusterStatus, error) { + return m.ClusterStatusResult, m.ClusterStatusErr +} + +func (m *Mock) GetClusterConfig(_ context.Context) (apiv1.UserFacingClusterConfig, error) { + return m.GetClusterConfigResult, m.GetClusterConfigErr +} +func (m *Mock) SetClusterConfig(_ context.Context, request apiv1.UpdateClusterConfigRequest) error { + m.SetClusterConfigCalledWith = request + return m.SetClusterConfigErr +} + +func (m *Mock) KubeConfig(_ context.Context, request apiv1.GetKubeConfigRequest) (string, error) { + m.KubeConfigCalledWith = request + return m.KubeConfigResult, m.KubeConfigErr +} + +func (m *Mock) SetClusterAPIAuthToken(_ context.Context, request apiv1.SetClusterAPIAuthTokenRequest) error { + m.SetClusterAPIAuthTokenCalledWith = request + return m.SetClusterAPIAuthTokenErr +} + +var _ k8sd.Client = &Mock{} diff --git a/src/k8s/pkg/client/k8sd/status.go b/src/k8s/pkg/client/k8sd/status.go new file mode 100644 index 000000000..21ee5a464 --- /dev/null +++ b/src/k8s/pkg/client/k8sd/status.go @@ -0,0 +1,31 @@ +package k8sd + +import ( + "context" + "fmt" + + apiv1 "github.com/canonical/k8s/api/v1" + "github.com/canonical/k8s/pkg/utils/control" + "github.com/canonical/lxd/shared/api" +) + +func (c *k8sd) NodeStatus(ctx context.Context) (apiv1.NodeStatus, error) { + var response apiv1.GetNodeStatusResponse + if err := c.client.Query(ctx, "GET", api.NewURL().Path("k8sd", "node"), nil, &response); err != nil { + return apiv1.NodeStatus{}, fmt.Errorf("failed to GET /k8sd/node: %w", err) + } + return response.NodeStatus, nil +} + +func (c *k8sd) ClusterStatus(ctx context.Context, waitReady bool) (apiv1.ClusterStatus, error) { + var response apiv1.GetClusterStatusResponse + if err := control.WaitUntilReady(ctx, func() (bool, error) { + if err := c.client.Query(ctx, "GET", api.NewURL().Path("k8sd", "cluster"), nil, &response); err != nil { + return false, fmt.Errorf("failed to GET /k8sd/cluster: %w", err) + } + return !waitReady || response.ClusterStatus.Ready, nil + }); err != nil { + return apiv1.ClusterStatus{}, err + } + return response.ClusterStatus, nil +} diff --git a/src/k8s/pkg/client/k8sd/user.go b/src/k8s/pkg/client/k8sd/user.go new file mode 100644 index 000000000..e7e8a4a79 --- /dev/null +++ b/src/k8s/pkg/client/k8sd/user.go @@ -0,0 +1,17 @@ +package k8sd + +import ( + "context" + "fmt" + + apiv1 "github.com/canonical/k8s/api/v1" + "github.com/canonical/lxd/shared/api" +) + +func (c *k8sd) KubeConfig(ctx context.Context, request apiv1.GetKubeConfigRequest) (string, error) { + var response apiv1.GetKubeConfigResponse + if err := c.client.Query(ctx, "GET", api.NewURL().Path("k8sd", "kubeconfig"), request, &response); err != nil { + return "", fmt.Errorf("failed to GET /k8sd/kubeconfig: %w", err) + } + return response.KubeConfig, nil +} diff --git a/src/k8s/pkg/k8s/client/capi_auth.go b/src/k8s/pkg/k8s/client/capi_auth.go deleted file mode 100644 index db7cb5934..000000000 --- a/src/k8s/pkg/k8s/client/capi_auth.go +++ /dev/null @@ -1,17 +0,0 @@ -package client - -import ( - "context" - "fmt" - - apiv1 "github.com/canonical/k8s/api/v1" - "github.com/canonical/lxd/shared/api" -) - -// SetClusterAPIAuthToken calls "POST 1.0/x/capi/set-auth-token". -func (c *k8sdClient) SetClusterAPIAuthToken(ctx context.Context, request apiv1.SetClusterAPIAuthTokenRequest) error { - if err := c.mc.Query(ctx, "POST", api.NewURL().Path("x", "capi", "set-auth-token"), request, nil); err != nil { - return fmt.Errorf("failed to POST /x/capi/set-auth-token: %w", err) - } - return nil -} diff --git a/src/k8s/pkg/k8s/client/client.go b/src/k8s/pkg/k8s/client/client.go deleted file mode 100644 index 6475eabeb..000000000 --- a/src/k8s/pkg/k8s/client/client.go +++ /dev/null @@ -1,40 +0,0 @@ -package client - -import ( - "context" - "fmt" - - "github.com/canonical/k8s/pkg/snap" - "github.com/canonical/microcluster/client" - "github.com/canonical/microcluster/microcluster" -) - -// k8sdClient interacts with the k8sd REST-API via unix-socket. -type k8sdClient struct { - m *microcluster.MicroCluster - mc *client.Client - snap snap.Snap -} - -// New returns a client to interact with the k8sd REST-API. -func New(ctx context.Context, snap snap.Snap) (*k8sdClient, error) { - if snap == nil { - panic("snap must not be nil") - } - m, err := microcluster.App(microcluster.Args{ - StateDir: snap.K8sdStateDir(), - }) - if err != nil { - return nil, fmt.Errorf("failed to initialize microcluster app: %w", err) - } - mc, err := m.LocalClient() - if err != nil { - return nil, fmt.Errorf("failed to create local microcluster client: %w", err) - } - - return &k8sdClient{ - snap: snap, - m: m, - mc: mc, - }, nil -} diff --git a/src/k8s/pkg/k8s/client/cluster.go b/src/k8s/pkg/k8s/client/cluster.go deleted file mode 100644 index 8b7ca6cd8..000000000 --- a/src/k8s/pkg/k8s/client/cluster.go +++ /dev/null @@ -1,53 +0,0 @@ -package client - -import ( - "context" - "fmt" - - apiv1 "github.com/canonical/k8s/api/v1" - "github.com/canonical/k8s/pkg/utils/control" - "github.com/canonical/lxd/shared/api" -) - -// IsBootstrapped checks if the cluster is already up and initialized. -func (c *k8sdClient) IsBootstrapped(ctx context.Context) bool { - _, err := c.m.Status(ctx) - return err == nil -} - -// Bootstrap bootstraps the k8s cluster -func (c *k8sdClient) Bootstrap(ctx context.Context, request apiv1.PostClusterBootstrapRequest) (apiv1.NodeStatus, error) { - if err := c.m.Ready(ctx); err != nil { - return apiv1.NodeStatus{}, fmt.Errorf("k8sd API is not ready: %w", err) - } - response := apiv1.NodeStatus{} - - if err := c.mc.Query(ctx, "POST", api.NewURL().Path("k8sd", "cluster"), request, &response); err != nil { - - c.CleanupNode(ctx, request.Name) - return response, fmt.Errorf("failed to bootstrap new cluster using POST /k8sd/cluster: %w", err) - } - - return response, nil -} - -// ClusterStatus returns the current status of the cluster. -func (c *k8sdClient) ClusterStatus(ctx context.Context, waitReady bool) (apiv1.ClusterStatus, error) { - var response apiv1.GetClusterStatusResponse - err := control.WaitUntilReady(ctx, func() (bool, error) { - if err := c.mc.Query(ctx, "GET", api.NewURL().Path("k8sd", "cluster"), nil, &response); err != nil { - return false, fmt.Errorf("failed to GET /k8sd/cluster: %w", err) - } - return !waitReady || response.ClusterStatus.Ready, nil - }) - return response.ClusterStatus, err -} - -// KubeConfig returns admin kubeconfig to connect to the cluster. -func (c *k8sdClient) KubeConfig(ctx context.Context, request apiv1.GetKubeConfigRequest) (string, error) { - response := apiv1.GetKubeConfigResponse{} - if err := c.mc.Query(ctx, "GET", api.NewURL().Path("k8sd", "kubeconfig"), request, &response); err != nil { - return "", fmt.Errorf("failed to GET /k8sd/kubeconfig: %w", err) - } - return response.KubeConfig, nil -} diff --git a/src/k8s/pkg/k8s/client/cluster_config.go b/src/k8s/pkg/k8s/client/cluster_config.go deleted file mode 100644 index 9dde6aa7c..000000000 --- a/src/k8s/pkg/k8s/client/cluster_config.go +++ /dev/null @@ -1,27 +0,0 @@ -package client - -import ( - "context" - "fmt" - - apiv1 "github.com/canonical/k8s/api/v1" - api "github.com/canonical/lxd/shared/api" -) - -func (c *k8sdClient) UpdateClusterConfig(ctx context.Context, request apiv1.UpdateClusterConfigRequest) error { - var response apiv1.UpdateClusterConfigResponse - if err := c.mc.Query(ctx, "PUT", api.NewURL().Path("k8sd", "cluster", "config"), request, &response); err != nil { - return fmt.Errorf("failed to PUT /k8sd/cluster/config: %w", err) - } - return nil -} - -func (c *k8sdClient) GetClusterConfig(ctx context.Context, request apiv1.GetClusterConfigRequest) (apiv1.UserFacingClusterConfig, error) { - var response apiv1.GetClusterConfigResponse - - if err := c.mc.Query(ctx, "GET", api.NewURL().Path("k8sd", "cluster", "config"), nil, &response); err != nil { - return apiv1.UserFacingClusterConfig{}, fmt.Errorf("failed to GET /k8sd/cluster/config: %w", err) - } - - return response.Config, nil -} diff --git a/src/k8s/pkg/k8s/client/cluster_node.go b/src/k8s/pkg/k8s/client/cluster_node.go deleted file mode 100644 index 3302403ad..000000000 --- a/src/k8s/pkg/k8s/client/cluster_node.go +++ /dev/null @@ -1,85 +0,0 @@ -package client - -import ( - "context" - "fmt" - "os" - - apiv1 "github.com/canonical/k8s/api/v1" - snaputil "github.com/canonical/k8s/pkg/snap/util" - "github.com/canonical/k8s/pkg/utils/control" - "github.com/canonical/lxd/shared/api" -) - -func (c *k8sdClient) JoinCluster(ctx context.Context, request apiv1.JoinClusterRequest) error { - if err := c.m.Ready(ctx); err != nil { - return fmt.Errorf("k8sd API is not ready: %w", err) - } - - if err := c.mc.Query(ctx, "POST", api.NewURL().Path("k8sd", "cluster", "join"), request, nil); err != nil { - // TODO(neoaggelos): only return error that join cluster failed - fmt.Fprintln(os.Stderr, "Cleaning up, error was", err) - c.CleanupNode(ctx, request.Name) - return fmt.Errorf("failed to POST /k8sd/cluster/join: %w", err) - } - - c.WaitForDqliteNodeToBeReady(ctx, request.Name) - return nil -} - -func (c *k8sdClient) RemoveNode(ctx context.Context, request apiv1.RemoveNodeRequest) error { - if err := c.mc.Query(ctx, "POST", api.NewURL().Path("k8sd", "cluster", "remove"), request, nil); err != nil { - return fmt.Errorf("failed to DELETE /k8sd/cluster/remove: %w", err) - } - return nil -} - -func (c *k8sdClient) ResetNode(ctx context.Context, name string, force bool) error { - if err := c.mc.ResetClusterMember(ctx, name, force); err != nil { - return fmt.Errorf("failed to ResetClusterMember: %w", err) - } - return nil -} - -// WaitForDqliteNodeToBeReady waits until the underlying dqlite node of the microcluster is not in PENDING state. -// While microcluster checkReady will validate that the nodes API server is ready, it will not check if the -// dqlite node is properly setup yet. -func (c *k8sdClient) WaitForDqliteNodeToBeReady(ctx context.Context, nodeName string) error { - return control.WaitUntilReady(ctx, func() (bool, error) { - clusterStatus, err := c.ClusterStatus(ctx, false) - if err != nil { - return false, fmt.Errorf("failed to get the cluster status: %w", err) - } - - for _, member := range clusterStatus.Members { - if member.Name == nodeName { - if member.DatastoreRole == apiv1.DatastoreRolePending { - return false, nil - } - return true, nil - } - } - return false, fmt.Errorf("cluster does not contain node %s", nodeName) - }) -} - -// CleanupNode resets the nodes configuration and cluster state. -// The cleanup will happen on a best-effort base. Any error that occurs will be ignored. -func (c *k8sdClient) CleanupNode(ctx context.Context, nodeName string) { - - // For self-removal, microcluster expects the dqlite node to not be in pending state. - c.WaitForDqliteNodeToBeReady(ctx, nodeName) - - // Delete the node from the cluster. - // This will fail if this is the only member in the cluster. - c.RemoveNode(ctx, apiv1.RemoveNodeRequest{Name: nodeName, Force: false}) - // Reset the local state and daemon. - // This is required to reset a bootstrapped node before - // joining another cluster. - c.ResetNode(ctx, nodeName, true) - - snaputil.StopControlPlaneServices(ctx, c.snap) - snaputil.StopK8sDqliteServices(ctx, c.snap) - - snaputil.MarkAsWorkerNode(c.snap, false) -} diff --git a/src/k8s/pkg/k8s/client/interface.go b/src/k8s/pkg/k8s/client/interface.go deleted file mode 100644 index c5b8b0474..000000000 --- a/src/k8s/pkg/k8s/client/interface.go +++ /dev/null @@ -1,41 +0,0 @@ -package client - -import ( - "context" - - apiv1 "github.com/canonical/k8s/api/v1" -) - -// Client defines the interface for interacting with a k8s cluster. -type Client interface { - // Bootstrap initializes a new cluster member using the provided bootstrap configuration. - Bootstrap(ctx context.Context, request apiv1.PostClusterBootstrapRequest) (apiv1.NodeStatus, error) - // IsBootstrapped checks whether the current node is already bootstrapped. - IsBootstrapped(ctx context.Context) bool - // CleanupNode performs cleanup operations for a specific node in the cluster. - CleanupNode(ctx context.Context, nodeName string) - // ClusterStatus retrieves the current status of the Kubernetes cluster. - ClusterStatus(ctx context.Context, waitReady bool) (apiv1.ClusterStatus, error) - // LocalNodeStatus retrieves the current status of the local node. - LocalNodeStatus(ctx context.Context) (apiv1.NodeStatus, error) - // GetJoinToken generates a token for a new node to join the cluster. - GetJoinToken(ctx context.Context, request apiv1.GetJoinTokenRequest) (string, error) - // GenerateAuthToken generates an authentication token for a specific user with given groups. - GenerateAuthToken(ctx context.Context, request apiv1.GenerateKubernetesAuthTokenRequest) (string, error) - // RevokeAuthToken revokes an authentication token given a token. - RevokeAuthToken(ctx context.Context, request apiv1.RevokeKubernetesAuthTokenRequest) error - // JoinCluster adds a new node to the cluster using the provided parameters. - JoinCluster(ctx context.Context, request apiv1.JoinClusterRequest) error - // KubeConfig retrieves the Kubernetes configuration for the current node. - KubeConfig(ctx context.Context, request apiv1.GetKubeConfigRequest) (string, error) - // RemoveNode removes a node from the cluster. - RemoveNode(ctx context.Context, request apiv1.RemoveNodeRequest) error - // UpdateClusterConfig updates configuration of the cluster. - UpdateClusterConfig(ctx context.Context, request apiv1.UpdateClusterConfigRequest) error - // GetClusterConfig retrieves configuration of the cluster. - GetClusterConfig(ctx context.Context, request apiv1.GetClusterConfigRequest) (apiv1.UserFacingClusterConfig, error) - // SetClusterAPIAuthToken sets the auth token for the CAPI provider. - SetClusterAPIAuthToken(ctx context.Context, request apiv1.SetClusterAPIAuthTokenRequest) error -} - -var _ Client = &k8sdClient{} diff --git a/src/k8s/pkg/k8s/client/kubernetes_auth_tokens.go b/src/k8s/pkg/k8s/client/kubernetes_auth_tokens.go deleted file mode 100644 index 234ad3418..000000000 --- a/src/k8s/pkg/k8s/client/kubernetes_auth_tokens.go +++ /dev/null @@ -1,29 +0,0 @@ -package client - -import ( - "context" - "fmt" - - apiv1 "github.com/canonical/k8s/api/v1" - "github.com/canonical/lxd/shared/api" -) - -// GenerateAuthToken calls "POST 1.0/kubernetes/auth/tokens". -func (c *k8sdClient) GenerateAuthToken(ctx context.Context, request apiv1.GenerateKubernetesAuthTokenRequest) (string, error) { - response := apiv1.CreateKubernetesAuthTokenResponse{} - - if err := c.mc.Query(ctx, "POST", api.NewURL().Path("kubernetes", "auth", "tokens"), request, &response); err != nil { - return "", fmt.Errorf("failed to POST /kubernetes/auth/tokens: %w", err) - } - - return response.Token, nil -} - -// RevokeAuthToken calls "DELETE 1.0/kubernetes/auth/tokens". -func (c *k8sdClient) RevokeAuthToken(ctx context.Context, request apiv1.RevokeKubernetesAuthTokenRequest) error { - if err := c.mc.Query(ctx, "DELETE", api.NewURL().Path("kubernetes", "auth", "tokens"), request, nil); err != nil { - return fmt.Errorf("failed to DELETE /kubernetes/auth/tokens: %w", err) - } - - return nil -} diff --git a/src/k8s/pkg/k8s/client/mock/mock.go b/src/k8s/pkg/k8s/client/mock/mock.go deleted file mode 100644 index b2b807b40..000000000 --- a/src/k8s/pkg/k8s/client/mock/mock.go +++ /dev/null @@ -1,123 +0,0 @@ -package mock - -import ( - "context" - - apiv1 "github.com/canonical/k8s/api/v1" - "github.com/canonical/k8s/pkg/k8s/client" -) - -// Client is a mock implementation for k8s Client. -type Client struct { - BootstrapCalledWith struct { - Ctx context.Context - Request apiv1.PostClusterBootstrapRequest - } - BootstrapClusterMember apiv1.NodeStatus - BootstrapErr error - IsBootstrappedReturn bool - CleanupNodeCalledWith struct { - Ctx context.Context - NodeName string - } - ClusterStatusReturn apiv1.ClusterStatus - ClusterStatusErr error - NodeStatusReturn apiv1.NodeStatus - NodeStatusErr error - GetJoinTokenCalledWith apiv1.GetJoinTokenRequest - GetJoinTokenReturn struct { - Token string - Err error - } - GenerateAuthTokenCalledWith apiv1.GenerateKubernetesAuthTokenRequest - GenerateAuthTokenReturn struct { - Token string - Err error - } - RevokeAuthTokenCalledWith apiv1.RevokeKubernetesAuthTokenRequest - RevokeAuthTokenErr error - JoinClusterCalledWith apiv1.JoinClusterRequest - JoinClusterErr error - KubeConfigReturn string - KubeConfigErr error - RemoveNodeCalledWith apiv1.RemoveNodeRequest - RemoveNodeErr error - GetClusterConfigCalledWith apiv1.GetClusterConfigRequest - GetClusterConfigReturn struct { - Config apiv1.UserFacingClusterConfig - Err error - } - UpdateClusterConfigCalledWith apiv1.UpdateClusterConfigRequest - UpdateClusterConfigErr error - SetClusterAPIAuthTokenCalledWith apiv1.SetClusterAPIAuthTokenRequest - SetClusterAPIAuthTokenErr error -} - -func (c *Client) Bootstrap(ctx context.Context, request apiv1.PostClusterBootstrapRequest) (apiv1.NodeStatus, error) { - c.BootstrapCalledWith.Ctx = ctx - c.BootstrapCalledWith.Request = request - return c.BootstrapClusterMember, c.BootstrapErr -} - -func (c *Client) IsBootstrapped(ctx context.Context) bool { - return c.IsBootstrappedReturn -} - -func (c *Client) CleanupNode(ctx context.Context, nodeName string) { - c.CleanupNodeCalledWith.Ctx = ctx - c.CleanupNodeCalledWith.NodeName = nodeName -} - -func (c *Client) ClusterStatus(ctx context.Context, waitReady bool) (apiv1.ClusterStatus, error) { - return c.ClusterStatusReturn, c.ClusterStatusErr -} - -func (c *Client) LocalNodeStatus(ctx context.Context) (apiv1.NodeStatus, error) { - return c.NodeStatusReturn, c.NodeStatusErr -} - -func (c *Client) GetJoinToken(ctx context.Context, request apiv1.GetJoinTokenRequest) (string, error) { - c.GetJoinTokenCalledWith = request - return c.GetJoinTokenReturn.Token, c.GetJoinTokenReturn.Err -} - -func (c *Client) GenerateAuthToken(ctx context.Context, request apiv1.GenerateKubernetesAuthTokenRequest) (string, error) { - c.GenerateAuthTokenCalledWith = request - return c.GenerateAuthTokenReturn.Token, c.GenerateAuthTokenReturn.Err -} - -func (c *Client) RevokeAuthToken(ctx context.Context, request apiv1.RevokeKubernetesAuthTokenRequest) error { - c.RevokeAuthTokenCalledWith = request - return c.RevokeAuthTokenErr -} - -func (c *Client) JoinCluster(ctx context.Context, request apiv1.JoinClusterRequest) error { - c.JoinClusterCalledWith = request - return c.JoinClusterErr -} - -func (c *Client) KubeConfig(ctx context.Context, request apiv1.GetKubeConfigRequest) (string, error) { - return c.KubeConfigReturn, c.KubeConfigErr -} - -func (c *Client) RemoveNode(ctx context.Context, request apiv1.RemoveNodeRequest) error { - c.RemoveNodeCalledWith = request - return c.RemoveNodeErr -} - -func (c *Client) UpdateClusterConfig(ctx context.Context, request apiv1.UpdateClusterConfigRequest) error { - c.UpdateClusterConfigCalledWith = request - return c.UpdateClusterConfigErr -} - -func (c *Client) GetClusterConfig(ctx context.Context, request apiv1.GetClusterConfigRequest) (apiv1.UserFacingClusterConfig, error) { - c.GetClusterConfigCalledWith = request - return c.GetClusterConfigReturn.Config, c.GetClusterConfigReturn.Err -} - -func (c *Client) SetClusterAPIAuthToken(ctx context.Context, request apiv1.SetClusterAPIAuthTokenRequest) error { - c.SetClusterAPIAuthTokenCalledWith = request - return c.SetClusterAPIAuthTokenErr -} - -var _ client.Client = &Client{} diff --git a/src/k8s/pkg/k8s/client/node.go b/src/k8s/pkg/k8s/client/node.go deleted file mode 100644 index 501007d0f..000000000 --- a/src/k8s/pkg/k8s/client/node.go +++ /dev/null @@ -1,19 +0,0 @@ -package client - -import ( - "context" - "fmt" - - apiv1 "github.com/canonical/k8s/api/v1" - "github.com/canonical/lxd/shared/api" -) - -// NodeStatus queries the local node status -func (c *k8sdClient) LocalNodeStatus(ctx context.Context) (apiv1.NodeStatus, error) { - var response apiv1.GetNodeStatusResponse - - if err := c.mc.Query(ctx, "GET", api.NewURL().Path("k8sd", "node"), nil, &response); err != nil { - return apiv1.NodeStatus{}, fmt.Errorf("failed to GET /k8sd/node: %w", err) - } - return response.NodeStatus, nil -} diff --git a/src/k8s/pkg/k8s/client/tokens.go b/src/k8s/pkg/k8s/client/tokens.go deleted file mode 100644 index fe85b3950..000000000 --- a/src/k8s/pkg/k8s/client/tokens.go +++ /dev/null @@ -1,17 +0,0 @@ -package client - -import ( - "context" - "fmt" - - apiv1 "github.com/canonical/k8s/api/v1" - "github.com/canonical/lxd/shared/api" -) - -func (c *k8sdClient) GetJoinToken(ctx context.Context, request apiv1.GetJoinTokenRequest) (string, error) { - response := apiv1.GetJoinTokenResponse{} - if err := c.mc.Query(ctx, "POST", api.NewURL().Path("k8sd", "cluster", "tokens"), request, &response); err != nil { - return "", fmt.Errorf("failed to POST /k8sd/cluster/tokens: %w", err) - } - return response.EncodedToken, nil -} diff --git a/src/k8s/pkg/snap/interface.go b/src/k8s/pkg/snap/interface.go index 7ff10723f..7613deea9 100644 --- a/src/k8s/pkg/snap/interface.go +++ b/src/k8s/pkg/snap/interface.go @@ -5,6 +5,7 @@ import ( "github.com/canonical/k8s/pkg/client/dqlite" "github.com/canonical/k8s/pkg/client/helm" + "github.com/canonical/k8s/pkg/client/k8sd" "github.com/canonical/k8s/pkg/client/kubernetes" "github.com/canonical/k8s/pkg/k8sd/types" ) @@ -57,5 +58,7 @@ type Snap interface { K8sDqliteClient(ctx context.Context) (*dqlite.Client, error) // go-dqlite client for k8s-dqlite + K8sdClient(address string) (k8sd.Client, error) // k8sd client + PreInitChecks(ctx context.Context, config types.ClusterConfig) error // pre-init checks before k8s-snap can start } diff --git a/src/k8s/pkg/snap/mock/mock.go b/src/k8s/pkg/snap/mock/mock.go index f84d9a4b6..093e8eca4 100644 --- a/src/k8s/pkg/snap/mock/mock.go +++ b/src/k8s/pkg/snap/mock/mock.go @@ -6,6 +6,7 @@ import ( "github.com/canonical/k8s/pkg/client/dqlite" "github.com/canonical/k8s/pkg/client/helm" + "github.com/canonical/k8s/pkg/client/k8sd" "github.com/canonical/k8s/pkg/client/kubernetes" "github.com/canonical/k8s/pkg/k8sd/types" "github.com/canonical/k8s/pkg/snap" @@ -41,6 +42,7 @@ type Mock struct { KubernetesNodeClient *kubernetes.Client HelmClient helm.Client K8sDqliteClient *dqlite.Client + K8sdClient k8sd.Client SnapctlGet map[string][]byte } @@ -173,6 +175,9 @@ func (s *Snap) HelmClient() helm.Client { func (s *Snap) K8sDqliteClient(context.Context) (*dqlite.Client, error) { return s.Mock.K8sDqliteClient, nil } +func (s *Snap) K8sdClient(address string) (k8sd.Client, error) { + return s.Mock.K8sdClient, nil +} func (s *Snap) SnapctlGet(ctx context.Context, args ...string) ([]byte, error) { s.SnapctlGetCalledWith = append(s.SnapctlGetCalledWith, args) return s.Mock.SnapctlGet[strings.Join(args, " ")], s.SnapctlGetErr diff --git a/src/k8s/pkg/snap/snap.go b/src/k8s/pkg/snap/snap.go index 7d71d63d6..64ffa2080 100644 --- a/src/k8s/pkg/snap/snap.go +++ b/src/k8s/pkg/snap/snap.go @@ -11,6 +11,7 @@ import ( "github.com/canonical/k8s/pkg/client/dqlite" "github.com/canonical/k8s/pkg/client/helm" + "github.com/canonical/k8s/pkg/client/k8sd" "github.com/canonical/k8s/pkg/client/kubernetes" "github.com/canonical/k8s/pkg/k8sd/types" "github.com/canonical/k8s/pkg/utils" @@ -235,6 +236,10 @@ func (s *snap) K8sDqliteClient(ctx context.Context) (*dqlite.Client, error) { return client, nil } +func (s *snap) K8sdClient(address string) (k8sd.Client, error) { + return k8sd.New(filepath.Join(s.snapCommonDir, "var", "lib", "k8sd", "state"), address) +} + func (s *snap) SnapctlGet(ctx context.Context, args ...string) ([]byte, error) { var b bytes.Buffer if err := s.runCommand(ctx, append([]string{"snapctl", "get"}, args...), func(c *exec.Cmd) { c.Stdout = &b }); err != nil { diff --git a/src/k8s/pkg/utils/experimental/snapdconfig/snapd_to_k8s.go b/src/k8s/pkg/utils/experimental/snapdconfig/snapd_to_k8s.go index 486e14cd2..255165bea 100644 --- a/src/k8s/pkg/utils/experimental/snapdconfig/snapd_to_k8s.go +++ b/src/k8s/pkg/utils/experimental/snapdconfig/snapd_to_k8s.go @@ -6,12 +6,12 @@ import ( "fmt" apiv1 "github.com/canonical/k8s/api/v1" - "github.com/canonical/k8s/pkg/k8s/client" + "github.com/canonical/k8s/pkg/client/k8sd" "github.com/canonical/k8s/pkg/snap" ) // SetK8sdFromSnapd updates the k8sd cluster configuration from the current local snapd configuration. -func SetK8sdFromSnapd(ctx context.Context, client client.Client, snap snap.Snap) error { +func SetK8sdFromSnapd(ctx context.Context, client k8sd.Client, snap snap.Snap) error { b, err := snap.SnapctlGet(ctx, "-d", "dns", "network", "local-storage", "load-balancer", "ingress", "gateway") if err != nil { return fmt.Errorf("failed to retrieve snapd configuration: %w", err) @@ -22,7 +22,7 @@ func SetK8sdFromSnapd(ctx context.Context, client client.Client, snap snap.Snap) return fmt.Errorf("failed to parse snapd configuration: %w", err) } - if err := client.UpdateClusterConfig(ctx, apiv1.UpdateClusterConfigRequest{Config: config}); err != nil { + if err := client.SetClusterConfig(ctx, apiv1.UpdateClusterConfigRequest{Config: config}); err != nil { return fmt.Errorf("failed to update k8s configuration: %w", err) }