// unjoinFederation is the implementation of the `unjoin` command. func unjoinFederation(f cmdutil.Factory, cmdOut, cmdErr io.Writer, config util.AdminConfig, cmd *cobra.Command, args []string) error { unjoinFlags, err := util.GetSubcommandFlags(cmd, args) if err != nil { return err } cluster, err := popCluster(f, unjoinFlags.Name) if err != nil { return err } if cluster == nil { fmt.Fprintf(cmdErr, "WARNING: cluster %q not found in federation, so its credentials' secret couldn't be deleted", unjoinFlags.Name) return nil } // We want a separate client factory to communicate with the // federation host cluster. See join_federation.go for details. hostFactory := config.HostFactory(unjoinFlags.Host, unjoinFlags.Kubeconfig) err = deleteSecret(hostFactory, cluster.Spec.SecretRef.Name, unjoinFlags.FederationSystemNamespace) if isNotFound(err) { fmt.Fprintf(cmdErr, "WARNING: secret %q not found in the host cluster, so it couldn't be deleted", cluster.Spec.SecretRef.Name) } else if err != nil { return err } _, err = fmt.Fprintf(cmdOut, "Successfully removed cluster %q from federation\n", unjoinFlags.Name) return err }
// joinFederation is the implementation of the `join federation` command. func joinFederation(f cmdutil.Factory, cmdOut io.Writer, config util.AdminConfig, cmd *cobra.Command, args []string) error { joinFlags, err := util.GetSubcommandFlags(cmd, args) if err != nil { return err } dryRun := cmdutil.GetDryRunFlag(cmd) glog.V(2).Infof("Args and flags: name %s, host: %s, host-system-namespace: %s, kubeconfig: %s, dry-run: %s", joinFlags.Name, joinFlags.Host, joinFlags.FederationSystemNamespace, joinFlags.Kubeconfig, dryRun) po := config.PathOptions() po.LoadingRules.ExplicitPath = joinFlags.Kubeconfig clientConfig, err := po.GetStartingConfig() if err != nil { return err } generator, err := clusterGenerator(clientConfig, joinFlags.Name) if err != nil { glog.V(2).Infof("Failed creating cluster generator: %v", err) return err } glog.V(2).Infof("Created cluster generator: %#v", generator) hostFactory := config.HostFactory(joinFlags.Host, joinFlags.Kubeconfig) // We are not using the `kubectl create secret` machinery through // `RunCreateSubcommand` as we do to the cluster resource below // because we have a bunch of requirements that the machinery does // not satisfy. // 1. We want to create the secret in a specific namespace, which // is neither the "default" namespace nor the one specified // via the `--namespace` flag. // 2. `SecretGeneratorV1` requires LiteralSources in a string-ified // form that it parses to generate the secret data key-value // pairs. We, however, have the key-value pairs ready without a // need for parsing. // 3. The result printing mechanism needs to be mostly quiet. We // don't have to print the created secret in the default case. // Having said that, secret generation machinery could be altered to // suit our needs, but it is far less invasive and readable this way. _, err = createSecret(hostFactory, clientConfig, joinFlags.FederationSystemNamespace, joinFlags.Name, dryRun) if err != nil { glog.V(2).Infof("Failed creating the cluster credentials secret: %v", err) return err } glog.V(2).Infof("Cluster credentials secret created") return kubectlcmd.RunCreateSubcommand(f, cmd, cmdOut, &kubectlcmd.CreateSubcommandOptions{ Name: joinFlags.Name, StructuredGenerator: generator, DryRun: dryRun, OutputFormat: cmdutil.GetFlagString(cmd, "output"), }) }
func waitSrvHealthy(config util.AdminConfig, context, kubeconfig string) error { fedClientSet, err := config.FederationClientset(context, kubeconfig) if err != nil { return err } fedDiscoveryClient := fedClientSet.Discovery() err = wait.PollInfinite(podWaitInterval, func() (bool, error) { body, err := fedDiscoveryClient.RESTClient().Get().AbsPath("/healthz").Do().Raw() if err != nil { return false, nil } if strings.EqualFold(string(body), "ok") { return true, nil } return false, nil }) return err }
func updateKubeconfig(config util.AdminConfig, name, endpoint string, entKeyPairs *entityKeyPairs, dryRun bool) error { po := config.PathOptions() kubeconfig, err := po.GetStartingConfig() if err != nil { return err } // Populate API server endpoint info. cluster := clientcmdapi.NewCluster() // Prefix "https" as the URL scheme to endpoint. if !strings.HasPrefix(endpoint, "https://") { endpoint = fmt.Sprintf("https://%s", endpoint) } cluster.Server = endpoint cluster.CertificateAuthorityData = certutil.EncodeCertPEM(entKeyPairs.ca.Cert) // Populate credentials. authInfo := clientcmdapi.NewAuthInfo() authInfo.ClientCertificateData = certutil.EncodeCertPEM(entKeyPairs.admin.Cert) authInfo.ClientKeyData = certutil.EncodePrivateKeyPEM(entKeyPairs.admin.Key) authInfo.Username = AdminCN // Populate context. context := clientcmdapi.NewContext() context.Cluster = name context.AuthInfo = name // Update the config struct with API server endpoint info, // credentials and context. kubeconfig.Clusters[name] = cluster kubeconfig.AuthInfos[name] = authInfo kubeconfig.Contexts[name] = context if !dryRun { // Write the update kubeconfig. if err := clientcmd.ModifyConfig(po, *kubeconfig, true); err != nil { return err } } return nil }
// initFederation initializes a federation control plane. // See the design doc in https://github.com/kubernetes/kubernetes/pull/34484 // for details. func initFederation(cmdOut io.Writer, config util.AdminConfig, cmd *cobra.Command, args []string) error { initFlags, err := util.GetSubcommandFlags(cmd, args) if err != nil { return err } dnsZoneName := cmdutil.GetFlagString(cmd, "dns-zone-name") image := cmdutil.GetFlagString(cmd, "image") dnsProvider := cmdutil.GetFlagString(cmd, "dns-provider") hostFactory := config.HostFactory(initFlags.Host, initFlags.Kubeconfig) hostClientset, err := hostFactory.ClientSet() if err != nil { return err } serverName := fmt.Sprintf("%s-apiserver", initFlags.Name) serverCredName := fmt.Sprintf("%s-credentials", serverName) cmName := fmt.Sprintf("%s-controller-manager", initFlags.Name) cmKubeconfigName := fmt.Sprintf("%s-kubeconfig", cmName) // 1. Create a namespace for federation system components _, err = createNamespace(hostClientset, initFlags.FederationSystemNamespace) if err != nil { return err } // 2. Expose a network endpoint for the federation API server svc, err := createService(hostClientset, initFlags.FederationSystemNamespace, serverName) if err != nil { return err } ips, hostnames, err := waitForLoadBalancerAddress(hostClientset, svc) if err != nil { return err } // 3. Generate TLS certificates and credentials entKeyPairs, err := genCerts(initFlags.FederationSystemNamespace, initFlags.Name, svc.Name, HostClusterLocalDNSZoneName, ips, hostnames) if err != nil { return err } _, err = createAPIServerCredentialsSecret(hostClientset, initFlags.FederationSystemNamespace, serverCredName, entKeyPairs) if err != nil { return err } // 4. Create a kubeconfig secret _, err = createControllerManagerKubeconfigSecret(hostClientset, initFlags.FederationSystemNamespace, initFlags.Name, svc.Name, cmKubeconfigName, entKeyPairs) if err != nil { return err } // 5. Create a persistent volume and a claim to store the federation // API server's state. This is where federation API server's etcd // stores its data. pvc, err := createPVC(hostClientset, initFlags.FederationSystemNamespace, svc.Name) if err != nil { return err } // Since only one IP address can be specified as advertise address, // we arbitrarily pick the first availabe IP address advertiseAddress := "" if len(ips) > 0 { advertiseAddress = ips[0] } endpoint := advertiseAddress if advertiseAddress == "" && len(hostnames) > 0 { endpoint = hostnames[0] } // 6. Create federation API server _, err = createAPIServer(hostClientset, initFlags.FederationSystemNamespace, serverName, image, serverCredName, pvc.Name, advertiseAddress) if err != nil { return err } // 7. Create federation controller manager _, err = createControllerManager(hostClientset, initFlags.FederationSystemNamespace, initFlags.Name, cmName, image, cmKubeconfigName, dnsZoneName, dnsProvider) if err != nil { return err } // 8. Write the federation API server endpoint info, credentials // and context to kubeconfig err = updateKubeconfig(config, initFlags.Name, endpoint, entKeyPairs) if err != nil { return err } return printSuccess(cmdOut, ips, hostnames) }