Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Federation][init-10b] Update local kubeconfig with the new federation API server credentials. #36047

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion federation/pkg/kubefed/init/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,15 @@ go_library(
"//pkg/api/resource:go_default_library",
"//pkg/apis/extensions:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library",
"//pkg/client/unversioned/clientcmd:go_default_library",
"//pkg/client/unversioned/clientcmd/api:go_default_library",
"//pkg/kubectl/cmd/templates:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/util/cert:go_default_library",
"//pkg/util/cert/triple:go_default_library",
"//pkg/util/intstr:go_default_library",
"//pkg/util/wait:go_default_library",
"//pkg/version:go_default_library",
"//vendor:github.com/spf13/cobra",
],
)
Expand All @@ -36,5 +39,22 @@ go_test(
srcs = ["init_test.go"],
library = "go_default_library",
tags = ["automanaged"],
deps = [],
deps = [
"//federation/pkg/kubefed/testing:go_default_library",
"//federation/pkg/kubefed/util:go_default_library",
"//pkg/api:go_default_library",
"//pkg/api/errors:go_default_library",
"//pkg/api/resource:go_default_library",
"//pkg/api/testapi:go_default_library",
"//pkg/api/unversioned:go_default_library",
"//pkg/api/v1:go_default_library",
"//pkg/apis/extensions/v1beta1:go_default_library",
"//pkg/client/restclient/fake:go_default_library",
"//pkg/client/typed/dynamic:go_default_library",
"//pkg/client/unversioned/clientcmd:go_default_library",
"//pkg/kubectl/cmd/testing:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/util/intstr:go_default_library",
"//vendor:k8s.io/client-go/pkg/util/diff",
],
)
82 changes: 74 additions & 8 deletions federation/pkg/kubefed/init/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,23 @@ import (
"k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/apis/extensions"
client "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
certutil "k8s.io/kubernetes/pkg/util/cert"
triple "k8s.io/kubernetes/pkg/util/cert/triple"
"k8s.io/kubernetes/pkg/util/intstr"
"k8s.io/kubernetes/pkg/util/wait"
"k8s.io/kubernetes/pkg/version"

"github.com/spf13/cobra"
)

const (
APIServerCN = "federation-apiserver"
ControllerManagerCN = "federation-controller-manager"
AdminCN = "admin"
HostClusterLocalDNSZoneName = "cluster.local."

lbAddrRetryInterval = 5 * time.Second
Expand Down Expand Up @@ -92,7 +96,7 @@ var (
"module": "federation-controller-manager",
}

hyperkubeImage = "gcr.io/google_containers/hyperkube-amd64:v1.5.0"
hyperkubeImageName = "gcr.io/google_containers/hyperkube-amd64"
)

// NewCmdInit defines the `init` command that bootstraps a federation
Expand All @@ -109,15 +113,19 @@ func NewCmdInit(cmdOut io.Writer, config util.AdminConfig) *cobra.Command {
},
}

defaultImage := fmt.Sprintf("%s:%s", hyperkubeImageName, version.Get())

util.AddSubcommandFlags(cmd)
cmd.Flags().String("dns-zone-name", "", "DNS suffix for this federation. Federated Service DNS names are published with this suffix.")
cmd.Flags().String("image", defaultImage, "Image to use for federation API server and controller manager binaries.")
return cmd
}

type entityKeyPairs struct {
ca *triple.KeyPair
server *triple.KeyPair
controllerManager *triple.KeyPair
admin *triple.KeyPair
}

// initFederation initializes a federation control plane.
Expand All @@ -129,6 +137,7 @@ func initFederation(cmdOut io.Writer, config util.AdminConfig, cmd *cobra.Comman
return err
}
dnsZoneName := cmdutil.GetFlagString(cmd, "dns-zone-name")
image := cmdutil.GetFlagString(cmd, "image")

hostFactory := config.HostFactory(initFlags.Host, initFlags.Kubeconfig)
hostClientset, err := hostFactory.ClientSet()
Expand Down Expand Up @@ -189,14 +198,26 @@ func initFederation(cmdOut io.Writer, config util.AdminConfig, cmd *cobra.Comman
advertiseAddress = ips[0]
}

endpoint := advertiseAddress
if advertiseAddress == "" && len(hostnames) > 0 {
endpoint = hostnames[0]
}

// 6. Create federation API server
_, err = createAPIServer(hostClientset, initFlags.FederationSystemNamespace, serverName, serverCredName, pvc.Name, advertiseAddress)
_, 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, cmKubeconfigName, dnsZoneName)
_, err = createControllerManager(hostClientset, initFlags.FederationSystemNamespace, initFlags.Name, cmName, image, cmKubeconfigName, dnsZoneName)
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
}
Expand Down Expand Up @@ -282,10 +303,15 @@ func genCerts(svcNamespace, name, svcName, localDNSZoneName string, ips, hostnam
if err != nil {
return nil, fmt.Errorf("failed to create federation controller manager client key and certificate: %v", err)
}
admin, err := triple.NewClientKeyPair(ca, AdminCN)
if err != nil {
return nil, fmt.Errorf("failed to create client key and certificate for an admin: %v", err)
}
return &entityKeyPairs{
ca: ca,
server: server,
controllerManager: cm,
admin: admin,
}, nil
}

Expand All @@ -305,7 +331,6 @@ func createAPIServerCredentialsSecret(clientset *client.Clientset, namespace, cr

// Boilerplate to create the secret in the host cluster.
return clientset.Core().Secrets(namespace).Create(secret)

}

func createControllerManagerKubeconfigSecret(clientset *client.Clientset, namespace, name, svcName, kubeconfigName string, entKeyPairs *entityKeyPairs) (*api.Secret, error) {
Expand Down Expand Up @@ -356,7 +381,7 @@ func createPVC(clientset *client.Clientset, namespace, svcName string) (*api.Per
return clientset.Core().PersistentVolumeClaims(namespace).Create(pvc)
}

func createAPIServer(clientset *client.Clientset, namespace, name, credentialsName, pvcName, advertiseAddress string) (*extensions.Deployment, error) {
func createAPIServer(clientset *client.Clientset, namespace, name, image, credentialsName, pvcName, advertiseAddress string) (*extensions.Deployment, error) {
command := []string{
"/hyperkube",
"federation-apiserver",
Expand Down Expand Up @@ -394,7 +419,7 @@ func createAPIServer(clientset *client.Clientset, namespace, name, credentialsNa
Containers: []api.Container{
{
Name: "apiserver",
Image: hyperkubeImage,
Image: image,
Command: command,
Ports: []api.ContainerPort{
{
Expand Down Expand Up @@ -456,7 +481,7 @@ func createAPIServer(clientset *client.Clientset, namespace, name, credentialsNa
return clientset.Extensions().Deployments(namespace).Create(dep)
}

func createControllerManager(clientset *client.Clientset, namespace, name, cmName, kubeconfigName, dnsZoneName string) (*extensions.Deployment, error) {
func createControllerManager(clientset *client.Clientset, namespace, name, cmName, image, kubeconfigName, dnsZoneName string) (*extensions.Deployment, error) {
dep := &extensions.Deployment{
ObjectMeta: api.ObjectMeta{
Name: cmName,
Expand All @@ -474,7 +499,7 @@ func createControllerManager(clientset *client.Clientset, namespace, name, cmNam
Containers: []api.Container{
{
Name: "controller-manager",
Image: hyperkubeImage,
Image: image,
Command: []string{
"/hyperkube",
"federation-controller-manager",
Expand Down Expand Up @@ -527,3 +552,44 @@ func printSuccess(cmdOut io.Writer, ips, hostnames []string) error {
_, err := fmt.Fprintf(cmdOut, "Federation API server is running at: %s\n", strings.Join(svcEndpoints, ", "))
return err
}

func updateKubeconfig(config util.AdminConfig, name, endpoint string, entKeyPairs *entityKeyPairs) 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

// Write the update kubeconfig.
if err := clientcmd.ModifyConfig(po, *kubeconfig, true); err != nil {
return err
}

return nil
}
Loading