diff --git a/charts/multicluster-controlplane/templates/deployment.yaml b/charts/multicluster-controlplane/templates/deployment.yaml index 72f6112..14b1029 100644 --- a/charts/multicluster-controlplane/templates/deployment.yaml +++ b/charts/multicluster-controlplane/templates/deployment.yaml @@ -32,6 +32,9 @@ spec: {{- if eq .Values.enableSelfManagement true }} - "--self-management" {{- end }} + {{- if .Values.selfManagementClusterName }} + - "--self-management-cluster-name={{ .Values.selfManagementClusterName }}" + {{- end }} {{- if eq .Values.enableDelegatingAuthentication true }} - "--delegating-authentication" {{- end }} diff --git a/charts/multicluster-controlplane/values.yaml b/charts/multicluster-controlplane/values.yaml index d193a43..f7eae75 100644 --- a/charts/multicluster-controlplane/values.yaml +++ b/charts/multicluster-controlplane/values.yaml @@ -13,6 +13,7 @@ autoApprovalBootstrapUsers: "" # TODO: should add restriction while enable selfmanagement enableSelfManagement: false +selfManagementClusterName: "" enableDelegatingAuthentication: false diff --git a/pkg/certificate/certificate.go b/pkg/certificate/certificate.go index dbdfd44..fcdf359 100644 --- a/pkg/certificate/certificate.go +++ b/pkg/certificate/certificate.go @@ -264,6 +264,17 @@ func InitKubeconfig( return err } + // save controlplane in-cluster kubeconfig to the data directory for self management + if err := util.KubeconfigWriteToFile( + InclusterKubeconfigFile(certDir), + fmt.Sprintf("https://multicluster-controlplane.%s.svc/", util.GetComponentNamespace()), + inClusterTrustBundlePEM, + kubeconfigCertPEM, + kubeconfigKeyPEM, + ); err != nil { + return err + } + // expose controlplane in-cluster kubeconfig in a secret if err := util.KubeconfigWroteToSecret( config, diff --git a/pkg/certificate/certificateinfo.go b/pkg/certificate/certificateinfo.go index 5547efe..e94afde 100644 --- a/pkg/certificate/certificateinfo.go +++ b/pkg/certificate/certificateinfo.go @@ -8,8 +8,9 @@ import ( ) const ( - ServiceAccountKeyFileName = "kube-serviceaccount.key" - KubeconfigFileName = "kube-aggregator.kubeconfig" + ServiceAccountKeyFileName = "kube-serviceaccount.key" + KubeconfigFileName = "kube-aggregator.kubeconfig" + InclusterKubeconfigFileName = "incluster.kubeconfig" // client user info UserAdmin = "system:admin" UserKubeApiserver = "kube-apiserver" @@ -53,6 +54,9 @@ func ServiceAccountKeyFile(certsDir string) string { func KubeConfigFile(certsDir string) string { return filepath.Join(certsDir, KubeconfigFileName) } +func InclusterKubeconfigFile(certsDir string) string { + return filepath.Join(certsDir, InclusterKubeconfigFileName) +} func DefaultRootCAFile(certsDir string) string { return filepath.Join(certsDir, RootCACertDirName, certchains.CACertFileName) } diff --git a/pkg/controllers/ocmcontroller/ocmagent.go b/pkg/controllers/ocmcontroller/ocmagent.go index 36be83b..7957b43 100644 --- a/pkg/controllers/ocmcontroller/ocmagent.go +++ b/pkg/controllers/ocmcontroller/ocmagent.go @@ -19,14 +19,22 @@ import ( clusterclient "open-cluster-management.io/api/client/cluster/clientset/versioned" clusterv1 "open-cluster-management.io/api/cluster/v1" + "open-cluster-management.io/sdk-go/pkg/helpers" "open-cluster-management.io/multicluster-controlplane/pkg/agent" + "open-cluster-management.io/multicluster-controlplane/pkg/certificate" "open-cluster-management.io/multicluster-controlplane/pkg/servers/options" "open-cluster-management.io/multicluster-controlplane/pkg/util" ) const SelfManagementClusterLabel = "multicluster-controlplane.open-cluster-management.io/selfmanagement" +type ClusterInfo struct { + ClusterName string + URL string + CABundle []byte +} + func InstallSelfManagementCluster(options options.ServerRunOptions) func(<-chan struct{}, *aggregatorapiserver.Config) error { return func(stopCh <-chan struct{}, aggregatorConfig *aggregatorapiserver.Config) error { inClusterConfig, err := rest.InClusterConfig() @@ -52,13 +60,32 @@ func InstallSelfManagementCluster(options options.ServerRunOptions) func(<-chan } } - go EnableSelfManagement(ctx, hubRestConfig, options.ControlplaneDataDir, clusterName) + kubeClient, err := kubernetes.NewForConfig(inClusterConfig) + if err != nil { + return err + } + apiserverURL, err := helpers.GetAPIServer(kubeClient) + if err != nil { + return err + } + caBundle, err := helpers.GetCACert(kubeClient) + if err != nil { + return err + } + + selfClusterInfo := ClusterInfo{ + ClusterName: clusterName, + URL: apiserverURL, + CABundle: caBundle, + } + + go EnableSelfManagement(ctx, hubRestConfig, options.ControlplaneDataDir, &selfClusterInfo) return nil } } -func EnableSelfManagement(ctx context.Context, hubRestConfig *rest.Config, controlplaneCertDir, selfClusterName string) { +func EnableSelfManagement(ctx context.Context, hubRestConfig *rest.Config, controlplaneCertDir string, selfClusterInfo *ClusterInfo) { kubeClient, err := kubernetes.NewForConfig(hubRestConfig) if err != nil { klog.Fatalf("Failed to kube client, %v", err) @@ -69,16 +96,16 @@ func EnableSelfManagement(ctx context.Context, hubRestConfig *rest.Config, contr klog.Fatalf("Failed to cluster client, %v", err) } - if err := createNamespace(ctx, kubeClient, selfClusterName); err != nil { + if err := createNamespace(ctx, kubeClient, selfClusterInfo.ClusterName); err != nil { klog.Fatalf("Failed to create self managed cluster namespace, %v", err) } // TODO need a controller to maintain the self managed cluster - if err := waitForSelfManagedCluster(ctx, clusterClient, selfClusterName); err != nil { + if err := waitForSelfManagedCluster(ctx, clusterClient, selfClusterInfo); err != nil { klog.Fatalf("Failed to create self managed cluster, %v", err) } - bootstrapKubeConfig := path.Join(controlplaneCertDir, "cert", "kube-aggregator.kubeconfig") + bootstrapKubeConfig := path.Join(controlplaneCertDir, "cert", certificate.InclusterKubeconfigFileName) agentHubKubeconfigDir := path.Join(controlplaneCertDir, "agent", "hub-kubeconfig") if err := os.MkdirAll(agentHubKubeconfigDir, os.ModePerm); err != nil { klog.Fatalf("Failed to create dir %s, %v", agentHubKubeconfigDir, err) @@ -86,7 +113,7 @@ func EnableSelfManagement(ctx context.Context, hubRestConfig *rest.Config, contr // TODO also need provide feature gates klusterletAgent := agent.NewAgentOptions(). - WithClusterName(selfClusterName). + WithClusterName(selfClusterInfo.ClusterName). WithBootstrapKubeconfig(bootstrapKubeConfig). WithHubKubeconfigDir(agentHubKubeconfigDir). WithWorkloadSourceDriverConfig(agentHubKubeconfigDir + "/kubeconfig") @@ -114,21 +141,27 @@ func createNamespace(ctx context.Context, kubeClient kubernetes.Interface, ns st return err } -func waitForSelfManagedCluster(ctx context.Context, clusterClient clusterclient.Interface, selfClusterName string) error { +func waitForSelfManagedCluster(ctx context.Context, clusterClient clusterclient.Interface, selfClusterInfo *ClusterInfo) error { return wait.PollUntilContextCancel(ctx, 5*time.Second, true, func(ctx context.Context) (bool, error) { - selfCluster, err := clusterClient.ClusterV1().ManagedClusters().Get(ctx, selfClusterName, metav1.GetOptions{}) + selfCluster, err := clusterClient.ClusterV1().ManagedClusters().Get(ctx, selfClusterInfo.ClusterName, metav1.GetOptions{}) if errors.IsNotFound(err) { _, err := clusterClient.ClusterV1().ManagedClusters().Create( ctx, &clusterv1.ManagedCluster{ ObjectMeta: metav1.ObjectMeta{ - Name: selfClusterName, + Name: selfClusterInfo.ClusterName, Labels: map[string]string{ SelfManagementClusterLabel: "", }, }, Spec: clusterv1.ManagedClusterSpec{ HubAcceptsClient: true, + ManagedClusterClientConfigs: []clusterv1.ClientConfig{ + { + URL: selfClusterInfo.URL, + CABundle: selfClusterInfo.CABundle, + }, + }, }, }, metav1.CreateOptions{}, diff --git a/pkg/servers/options/plugins.go b/pkg/servers/options/plugins.go index 44cd7c1..3a91f3b 100644 --- a/pkg/servers/options/plugins.go +++ b/pkg/servers/options/plugins.go @@ -78,7 +78,7 @@ func RegisterAllAdmissionPlugins(plugins *admission.Plugins) { // DefaultOffAdmissionPlugins get admission plugins off by default for kube-apiserver. func DefaultOffAdmissionPlugins() sets.Set[string] { - defaultOnPlugins := sets.New( + defaultOnPlugins := sets.New[string]( lifecycle.PluginName, // NamespaceLifecycle serviceaccount.PluginName, // ServiceAccount mutatingwebhook.PluginName, // MutatingAdmissionWebhook diff --git a/pkg/util/util.go b/pkg/util/util.go index e71d7d6..a780951 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -22,7 +22,7 @@ import ( "k8s.io/apimachinery/pkg/util/uuid" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" - clientcmd "k8s.io/client-go/tools/clientcmd" + "k8s.io/client-go/tools/clientcmd" clientcmdapi "k8s.io/client-go/tools/clientcmd/api" "k8s.io/client-go/util/retry" "k8s.io/klog/v2"