Merge pull request #42683 from perotinus/annotations

Automatic merge from submit-queue

[Federation][kubefed] Annotate all Federation API objects with the federation name and (if applicable) the cluster name.

Address part of #42324.

```release-note
Adds annotations to all Federation objects created by kubefed.
```
This commit is contained in:
Kubernetes Submit Queue 2017-04-10 18:42:00 -07:00 committed by GitHub
commit 3c7616eb19
8 changed files with 183 additions and 58 deletions

View File

@ -10,6 +10,7 @@ load(
go_library( go_library(
name = "go_default_library", name = "go_default_library",
srcs = [ srcs = [
"annotations.go",
"doc.go", "doc.go",
"register.go", "register.go",
"types.go", "types.go",

View File

@ -0,0 +1,28 @@
/*
Copyright 2016 The Kubernetes 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 federation
// FederationNameAnnotation is the annotation which holds the name of
// the federation that an object is associated with. It must be
// applied to all API objects associated with that federation.
const FederationNameAnnotation = "federation.alpha.kubernetes.io/federation-name"
// ClusterNameAnnotation is the annotation which holds the name of
// the cluster that an object is associated with. If the object is
// not associated with any cluster, then this annotation is not
// required.
const ClusterNameAnnotation = "federation.alpha.kubernetes.io/cluster-name"

View File

@ -14,6 +14,7 @@ go_library(
tags = ["automanaged"], tags = ["automanaged"],
deps = [ deps = [
"//cmd/kubeadm/app/util/kubeconfig:go_default_library", "//cmd/kubeadm/app/util/kubeconfig:go_default_library",
"//federation/apis/federation:go_default_library",
"//federation/pkg/kubefed/util:go_default_library", "//federation/pkg/kubefed/util:go_default_library",
"//pkg/api:go_default_library", "//pkg/api:go_default_library",
"//pkg/api/v1:go_default_library", "//pkg/api/v1:go_default_library",
@ -42,6 +43,7 @@ go_test(
library = ":go_default_library", library = ":go_default_library",
tags = ["automanaged"], tags = ["automanaged"],
deps = [ deps = [
"//federation/apis/federation:go_default_library",
"//federation/pkg/kubefed/testing:go_default_library", "//federation/pkg/kubefed/testing:go_default_library",
"//federation/pkg/kubefed/util:go_default_library", "//federation/pkg/kubefed/util:go_default_library",
"//pkg/api:go_default_library", "//pkg/api:go_default_library",

View File

@ -40,6 +40,7 @@ import (
certutil "k8s.io/client-go/util/cert" certutil "k8s.io/client-go/util/cert"
triple "k8s.io/client-go/util/cert/triple" triple "k8s.io/client-go/util/cert/triple"
kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig" kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig"
"k8s.io/kubernetes/federation/apis/federation"
"k8s.io/kubernetes/federation/pkg/kubefed/util" "k8s.io/kubernetes/federation/pkg/kubefed/util"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/v1" "k8s.io/kubernetes/pkg/api/v1"
@ -276,13 +277,13 @@ func (i *initFederation) Run(cmdOut io.Writer, config util.AdminConfig) error {
} }
// 1. Create a namespace for federation system components // 1. Create a namespace for federation system components
_, err = createNamespace(hostClientset, i.commonOptions.FederationSystemNamespace, i.options.dryRun) _, err = createNamespace(hostClientset, i.commonOptions.Name, i.commonOptions.FederationSystemNamespace, i.options.dryRun)
if err != nil { if err != nil {
return err return err
} }
// 2. Expose a network endpoint for the federation API server // 2. Expose a network endpoint for the federation API server
svc, ips, hostnames, err := createService(hostClientset, i.commonOptions.FederationSystemNamespace, serverName, i.options.apiServerAdvertiseAddress, i.options.apiServerServiceType, i.options.dryRun) svc, ips, hostnames, err := createService(hostClientset, i.commonOptions.FederationSystemNamespace, serverName, i.commonOptions.Name, i.options.apiServerAdvertiseAddress, i.options.apiServerServiceType, i.options.dryRun)
if err != nil { if err != nil {
return err return err
} }
@ -294,7 +295,7 @@ func (i *initFederation) Run(cmdOut io.Writer, config util.AdminConfig) error {
} }
// 3b. Create the secret containing the credentials. // 3b. Create the secret containing the credentials.
_, err = createAPIServerCredentialsSecret(hostClientset, i.commonOptions.FederationSystemNamespace, serverCredName, credentials, i.options.dryRun) _, err = createAPIServerCredentialsSecret(hostClientset, i.commonOptions.FederationSystemNamespace, serverCredName, i.commonOptions.Name, credentials, i.options.dryRun)
if err != nil { if err != nil {
return err return err
} }
@ -310,7 +311,7 @@ func (i *initFederation) Run(cmdOut io.Writer, config util.AdminConfig) error {
// stores its data. // stores its data.
var pvc *api.PersistentVolumeClaim var pvc *api.PersistentVolumeClaim
if i.options.etcdPersistentStorage { if i.options.etcdPersistentStorage {
pvc, err = createPVC(hostClientset, i.commonOptions.FederationSystemNamespace, svc.Name, i.options.etcdPVCapacity, i.options.dryRun) pvc, err = createPVC(hostClientset, i.commonOptions.FederationSystemNamespace, svc.Name, i.commonOptions.Name, i.options.etcdPVCapacity, i.options.dryRun)
if err != nil { if err != nil {
return err return err
} }
@ -325,7 +326,7 @@ func (i *initFederation) Run(cmdOut io.Writer, config util.AdminConfig) error {
} }
// 6. Create federation API server // 6. Create federation API server
_, err = createAPIServer(hostClientset, i.commonOptions.FederationSystemNamespace, serverName, i.options.image, advertiseAddress, serverCredName, i.options.apiServerEnableHTTPBasicAuth, i.options.apiServerEnableTokenAuth, i.options.apiServerOverrides, pvc, i.options.dryRun) _, err = createAPIServer(hostClientset, i.commonOptions.FederationSystemNamespace, serverName, i.commonOptions.Name, i.options.image, advertiseAddress, serverCredName, i.options.apiServerEnableHTTPBasicAuth, i.options.apiServerEnableTokenAuth, i.options.apiServerOverrides, pvc, i.options.dryRun)
if err != nil { if err != nil {
return err return err
} }
@ -339,21 +340,21 @@ func (i *initFederation) Run(cmdOut io.Writer, config util.AdminConfig) error {
if rbacAvailable { if rbacAvailable {
// 7a. Create a service account in the host cluster for federation // 7a. Create a service account in the host cluster for federation
// controller manager. // controller manager.
sa, err = createControllerManagerSA(rbacVersionedClientset, i.commonOptions.FederationSystemNamespace, i.options.dryRun) sa, err = createControllerManagerSA(rbacVersionedClientset, i.commonOptions.FederationSystemNamespace, i.commonOptions.Name, i.options.dryRun)
if err != nil { if err != nil {
return err return err
} }
// 7b. Create RBAC role and role binding for federation controller // 7b. Create RBAC role and role binding for federation controller
// manager service account. // manager service account.
_, _, err = createRoleBindings(rbacVersionedClientset, i.commonOptions.FederationSystemNamespace, sa.Name, i.options.dryRun) _, _, err = createRoleBindings(rbacVersionedClientset, i.commonOptions.FederationSystemNamespace, sa.Name, i.commonOptions.Name, i.options.dryRun)
if err != nil { if err != nil {
return err return err
} }
} }
// 7c. Create a dns-provider config secret // 7c. Create a dns-provider config secret
dnsProviderSecret, err := createDNSProviderConfigSecret(hostClientset, i.commonOptions.FederationSystemNamespace, dnsProviderSecretName, dnsProviderConfigBytes, i.options.dryRun) dnsProviderSecret, err := createDNSProviderConfigSecret(hostClientset, i.commonOptions.FederationSystemNamespace, dnsProviderSecretName, i.commonOptions.Name, dnsProviderConfigBytes, i.options.dryRun)
if err != nil { if err != nil {
return err return err
} }
@ -400,10 +401,11 @@ func (i *initFederation) Run(cmdOut io.Writer, config util.AdminConfig) error {
return err return err
} }
func createNamespace(clientset client.Interface, namespace string, dryRun bool) (*api.Namespace, error) { func createNamespace(clientset client.Interface, federationName, namespace string, dryRun bool) (*api.Namespace, error) {
ns := &api.Namespace{ ns := &api.Namespace{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: namespace, Name: namespace,
Annotations: map[string]string{federation.FederationNameAnnotation: federationName},
}, },
} }
@ -414,12 +416,13 @@ func createNamespace(clientset client.Interface, namespace string, dryRun bool)
return clientset.Core().Namespaces().Create(ns) return clientset.Core().Namespaces().Create(ns)
} }
func createService(clientset client.Interface, namespace, svcName, apiserverAdvertiseAddress string, apiserverServiceType v1.ServiceType, dryRun bool) (*api.Service, []string, []string, error) { func createService(clientset client.Interface, namespace, svcName, federationName, apiserverAdvertiseAddress string, apiserverServiceType v1.ServiceType, dryRun bool) (*api.Service, []string, []string, error) {
svc := &api.Service{ svc := &api.Service{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: svcName, Name: svcName,
Namespace: namespace, Namespace: namespace,
Labels: componentLabel, Labels: componentLabel,
Annotations: map[string]string{federation.FederationNameAnnotation: federationName},
}, },
Spec: api.ServiceSpec{ Spec: api.ServiceSpec{
Type: api.ServiceType(apiserverServiceType), Type: api.ServiceType(apiserverServiceType),
@ -563,7 +566,7 @@ func genCerts(svcNamespace, name, svcName, localDNSZoneName string, ips, hostnam
}, nil }, nil
} }
func createAPIServerCredentialsSecret(clientset client.Interface, namespace, credentialsName string, credentials *credentials, dryRun bool) (*api.Secret, error) { func createAPIServerCredentialsSecret(clientset client.Interface, namespace, credentialsName, federationName string, credentials *credentials, dryRun bool) (*api.Secret, error) {
// Build the secret object with API server credentials. // Build the secret object with API server credentials.
data := map[string][]byte{ data := map[string][]byte{
"ca.crt": certutil.EncodeCertPEM(credentials.certEntKeyPairs.ca.Cert), "ca.crt": certutil.EncodeCertPEM(credentials.certEntKeyPairs.ca.Cert),
@ -579,8 +582,9 @@ func createAPIServerCredentialsSecret(clientset client.Interface, namespace, cre
secret := &api.Secret{ secret := &api.Secret{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: credentialsName, Name: credentialsName,
Namespace: namespace, Namespace: namespace,
Annotations: map[string]string{federation.FederationNameAnnotation: federationName},
}, },
Data: data, Data: data,
} }
@ -602,10 +606,10 @@ func createControllerManagerKubeconfigSecret(clientset client.Interface, namespa
certutil.EncodeCertPEM(entKeyPairs.controllerManager.Cert), certutil.EncodeCertPEM(entKeyPairs.controllerManager.Cert),
) )
return util.CreateKubeconfigSecret(clientset, config, namespace, kubeconfigName, dryRun) return util.CreateKubeconfigSecret(clientset, config, namespace, kubeconfigName, name, "", dryRun)
} }
func createPVC(clientset client.Interface, namespace, svcName, etcdPVCapacity string, dryRun bool) (*api.PersistentVolumeClaim, error) { func createPVC(clientset client.Interface, namespace, svcName, federationName, etcdPVCapacity string, dryRun bool) (*api.PersistentVolumeClaim, error) {
capacity, err := resource.ParseQuantity(etcdPVCapacity) capacity, err := resource.ParseQuantity(etcdPVCapacity)
if err != nil { if err != nil {
return nil, err return nil, err
@ -618,7 +622,7 @@ func createPVC(clientset client.Interface, namespace, svcName, etcdPVCapacity st
Labels: componentLabel, Labels: componentLabel,
Annotations: map[string]string{ Annotations: map[string]string{
"volume.alpha.kubernetes.io/storage-class": "yes", "volume.alpha.kubernetes.io/storage-class": "yes",
}, federation.FederationNameAnnotation: federationName},
}, },
Spec: api.PersistentVolumeClaimSpec{ Spec: api.PersistentVolumeClaimSpec{
AccessModes: []api.PersistentVolumeAccessMode{ AccessModes: []api.PersistentVolumeAccessMode{
@ -639,7 +643,7 @@ func createPVC(clientset client.Interface, namespace, svcName, etcdPVCapacity st
return clientset.Core().PersistentVolumeClaims(namespace).Create(pvc) return clientset.Core().PersistentVolumeClaims(namespace).Create(pvc)
} }
func createAPIServer(clientset client.Interface, namespace, name, image, advertiseAddress, credentialsName string, hasHTTPBasicAuthFile, hasTokenAuthFile bool, argOverrides map[string]string, pvc *api.PersistentVolumeClaim, dryRun bool) (*extensions.Deployment, error) { func createAPIServer(clientset client.Interface, namespace, name, federationName, image, advertiseAddress, credentialsName string, hasHTTPBasicAuthFile, hasTokenAuthFile bool, argOverrides map[string]string, pvc *api.PersistentVolumeClaim, dryRun bool) (*extensions.Deployment, error) {
command := []string{ command := []string{
"/hyperkube", "/hyperkube",
"federation-apiserver", "federation-apiserver",
@ -669,16 +673,18 @@ func createAPIServer(clientset client.Interface, namespace, name, image, adverti
dep := &extensions.Deployment{ dep := &extensions.Deployment{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: name,
Namespace: namespace, Namespace: namespace,
Labels: componentLabel, Labels: componentLabel,
Annotations: map[string]string{federation.FederationNameAnnotation: federationName},
}, },
Spec: extensions.DeploymentSpec{ Spec: extensions.DeploymentSpec{
Replicas: 1, Replicas: 1,
Template: api.PodTemplateSpec{ Template: api.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: name,
Labels: apiserverPodLabels, Labels: apiserverPodLabels,
Annotations: map[string]string{federation.FederationNameAnnotation: federationName},
}, },
Spec: api.PodSpec{ Spec: api.PodSpec{
Containers: []api.Container{ Containers: []api.Container{
@ -756,15 +762,17 @@ func createAPIServer(clientset client.Interface, namespace, name, image, adverti
return dep, nil return dep, nil
} }
return clientset.Extensions().Deployments(namespace).Create(dep) createdDep, err := clientset.Extensions().Deployments(namespace).Create(dep)
return createdDep, err
} }
func createControllerManagerSA(clientset client.Interface, namespace string, dryRun bool) (*api.ServiceAccount, error) { func createControllerManagerSA(clientset client.Interface, namespace, federationName string, dryRun bool) (*api.ServiceAccount, error) {
sa := &api.ServiceAccount{ sa := &api.ServiceAccount{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: ControllerManagerSA, Name: ControllerManagerSA,
Namespace: namespace, Namespace: namespace,
Labels: componentLabel, Labels: componentLabel,
Annotations: map[string]string{federation.FederationNameAnnotation: federationName},
}, },
} }
if dryRun { if dryRun {
@ -773,15 +781,16 @@ func createControllerManagerSA(clientset client.Interface, namespace string, dry
return clientset.Core().ServiceAccounts(namespace).Create(sa) return clientset.Core().ServiceAccounts(namespace).Create(sa)
} }
func createRoleBindings(clientset client.Interface, namespace, saName string, dryRun bool) (*rbac.Role, *rbac.RoleBinding, error) { func createRoleBindings(clientset client.Interface, namespace, saName, federationName string, dryRun bool) (*rbac.Role, *rbac.RoleBinding, error) {
roleName := "federation-system:federation-controller-manager" roleName := "federation-system:federation-controller-manager"
role := &rbac.Role{ role := &rbac.Role{
// a role to use for bootstrapping the federation-controller-manager so it can access // a role to use for bootstrapping the federation-controller-manager so it can access
// secrets in the host cluster to access other clusters. // secrets in the host cluster to access other clusters.
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: roleName, Name: roleName,
Namespace: namespace, Namespace: namespace,
Labels: componentLabel, Labels: componentLabel,
Annotations: map[string]string{federation.FederationNameAnnotation: federationName},
}, },
Rules: []rbac.PolicyRule{ Rules: []rbac.PolicyRule{
rbac.NewRule("get", "list", "watch").Groups(legacyAPIGroup).Resources("secrets").RuleOrDie(), rbac.NewRule("get", "list", "watch").Groups(legacyAPIGroup).Resources("secrets").RuleOrDie(),
@ -793,6 +802,7 @@ func createRoleBindings(clientset client.Interface, namespace, saName string, dr
return nil, nil, err return nil, nil, err
} }
rolebinding.Labels = componentLabel rolebinding.Labels = componentLabel
rolebinding.Annotations = map[string]string{federation.FederationNameAnnotation: federationName}
if dryRun { if dryRun {
return role, &rolebinding, nil return role, &rolebinding, nil
@ -839,15 +849,17 @@ func createControllerManager(clientset client.Interface, namespace, name, svcNam
// https://github.com/kubernetes/dns/blob/master/pkg/dns/federation/federation.go // https://github.com/kubernetes/dns/blob/master/pkg/dns/federation/federation.go
// TODO v2: Until kube-dns can handle trailing periods we strip them all. // TODO v2: Until kube-dns can handle trailing periods we strip them all.
// See https://github.com/kubernetes/dns/issues/67 // See https://github.com/kubernetes/dns/issues/67
util.FedDomainMapKey: fmt.Sprintf("%s=%s", name, strings.TrimRight(dnsZoneName, ".")), util.FedDomainMapKey: fmt.Sprintf("%s=%s", name, strings.TrimRight(dnsZoneName, ".")),
federation.FederationNameAnnotation: name,
}, },
}, },
Spec: extensions.DeploymentSpec{ Spec: extensions.DeploymentSpec{
Replicas: 1, Replicas: 1,
Template: api.PodTemplateSpec{ Template: api.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: cmName, Name: cmName,
Labels: controllerManagerPodLabels, Labels: controllerManagerPodLabels,
Annotations: map[string]string{federation.FederationNameAnnotation: name},
}, },
Spec: api.PodSpec{ Spec: api.PodSpec{
Containers: []api.Container{ Containers: []api.Container{
@ -1049,15 +1061,16 @@ func updateKubeconfig(config util.AdminConfig, name, endpoint, kubeConfigPath st
return nil return nil
} }
func createDNSProviderConfigSecret(clientset client.Interface, namespace, name string, dnsProviderConfigBytes []byte, dryRun bool) (*api.Secret, error) { func createDNSProviderConfigSecret(clientset client.Interface, namespace, name, federationName string, dnsProviderConfigBytes []byte, dryRun bool) (*api.Secret, error) {
if dnsProviderConfigBytes == nil { if dnsProviderConfigBytes == nil {
return nil, nil return nil, nil
} }
secretSpec := &api.Secret{ secretSpec := &api.Secret{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: name,
Namespace: namespace, Namespace: namespace,
Annotations: map[string]string{federation.FederationNameAnnotation: federationName},
}, },
Data: map[string][]byte{ Data: map[string][]byte{
name: dnsProviderConfigBytes, name: dnsProviderConfigBytes,

View File

@ -42,6 +42,7 @@ import (
"k8s.io/client-go/dynamic" "k8s.io/client-go/dynamic"
"k8s.io/client-go/rest/fake" "k8s.io/client-go/rest/fake"
"k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd"
"k8s.io/kubernetes/federation/apis/federation"
kubefedtesting "k8s.io/kubernetes/federation/pkg/kubefed/testing" kubefedtesting "k8s.io/kubernetes/federation/pkg/kubefed/testing"
"k8s.io/kubernetes/federation/pkg/kubefed/util" "k8s.io/kubernetes/federation/pkg/kubefed/util"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
@ -619,6 +620,9 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
}, },
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: namespaceName, Name: namespaceName,
Annotations: map[string]string{
federation.FederationNameAnnotation: federationName,
},
}, },
} }
@ -631,6 +635,9 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
Namespace: namespaceName, Namespace: namespaceName,
Name: svcName, Name: svcName,
Labels: componentLabel, Labels: componentLabel,
Annotations: map[string]string{
federation.FederationNameAnnotation: federationName,
},
}, },
Spec: v1.ServiceSpec{ Spec: v1.ServiceSpec{
Type: apiserverServiceType, Type: apiserverServiceType,
@ -664,6 +671,9 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: credSecretName, Name: credSecretName,
Namespace: namespaceName, Namespace: namespaceName,
Annotations: map[string]string{
federation.FederationNameAnnotation: federationName,
},
}, },
Data: nil, Data: nil,
} }
@ -676,6 +686,9 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: cmKubeconfigSecretName, Name: cmKubeconfigSecretName,
Namespace: namespaceName, Namespace: namespaceName,
Annotations: map[string]string{
federation.FederationNameAnnotation: federationName,
},
}, },
Data: nil, Data: nil,
} }
@ -688,6 +701,9 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: dnsProviderSecretName, Name: dnsProviderSecretName,
Namespace: namespaceName, Namespace: namespaceName,
Annotations: map[string]string{
federation.FederationNameAnnotation: federationName,
},
}, },
Data: nil, Data: nil,
} }
@ -703,6 +719,7 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
Labels: componentLabel, Labels: componentLabel,
Annotations: map[string]string{ Annotations: map[string]string{
"volume.alpha.kubernetes.io/storage-class": "yes", "volume.alpha.kubernetes.io/storage-class": "yes",
federation.FederationNameAnnotation: federationName,
}, },
}, },
Spec: v1.PersistentVolumeClaimSpec{ Spec: v1.PersistentVolumeClaimSpec{
@ -726,6 +743,9 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
Name: "federation-controller-manager", Name: "federation-controller-manager",
Namespace: namespaceName, Namespace: namespaceName,
Labels: componentLabel, Labels: componentLabel,
Annotations: map[string]string{
federation.FederationNameAnnotation: federationName,
},
}, },
} }
@ -738,6 +758,9 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
Name: "federation-system:federation-controller-manager", Name: "federation-system:federation-controller-manager",
Namespace: namespaceName, Namespace: namespaceName,
Labels: componentLabel, Labels: componentLabel,
Annotations: map[string]string{
federation.FederationNameAnnotation: federationName,
},
}, },
Rules: []rbacv1beta1.PolicyRule{ Rules: []rbacv1beta1.PolicyRule{
{ {
@ -757,6 +780,9 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
Name: "federation-system:federation-controller-manager", Name: "federation-system:federation-controller-manager",
Namespace: namespaceName, Namespace: namespaceName,
Labels: componentLabel, Labels: componentLabel,
Annotations: map[string]string{
federation.FederationNameAnnotation: federationName,
},
}, },
Subjects: []rbacv1beta1.Subject{ Subjects: []rbacv1beta1.Subject{
{ {
@ -838,17 +864,19 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
APIVersion: testapi.Extensions.GroupVersion().String(), APIVersion: testapi.Extensions.GroupVersion().String(),
}, },
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: svcName, Name: svcName,
Namespace: namespaceName, Namespace: namespaceName,
Labels: componentLabel, Labels: componentLabel,
Annotations: map[string]string{federation.FederationNameAnnotation: federationName},
}, },
Spec: v1beta1.DeploymentSpec{ Spec: v1beta1.DeploymentSpec{
Replicas: &replicas, Replicas: &replicas,
Selector: nil, Selector: nil,
Template: v1.PodTemplateSpec{ Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: svcName, Name: svcName,
Labels: apiserverPodLabels, Labels: apiserverPodLabels,
Annotations: map[string]string{federation.FederationNameAnnotation: federationName},
}, },
Spec: v1.PodSpec{ Spec: v1.PodSpec{
Containers: []v1.Container{ Containers: []v1.Container{
@ -954,7 +982,8 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
Namespace: namespaceName, Namespace: namespaceName,
Labels: componentLabel, Labels: componentLabel,
Annotations: map[string]string{ Annotations: map[string]string{
util.FedDomainMapKey: fmt.Sprintf("%s=%s", federationName, strings.TrimRight(dnsZoneName, ".")), util.FedDomainMapKey: fmt.Sprintf("%s=%s", federationName, strings.TrimRight(dnsZoneName, ".")),
federation.FederationNameAnnotation: federationName,
}, },
}, },
Spec: v1beta1.DeploymentSpec{ Spec: v1beta1.DeploymentSpec{
@ -962,8 +991,9 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
Selector: nil, Selector: nil,
Template: v1.PodTemplateSpec{ Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: cmName, Name: cmName,
Labels: controllerManagerPodLabels, Labels: controllerManagerPodLabels,
Annotations: map[string]string{federation.FederationNameAnnotation: federationName},
}, },
Spec: v1.PodSpec{ Spec: v1.PodSpec{
Containers: []v1.Container{ Containers: []v1.Container{
@ -1196,6 +1226,7 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
case cmName: case cmName:
want = *cm want = *cm
} }
//want = *cm
if !apiequality.Semantic.DeepEqual(got, want) { if !apiequality.Semantic.DeepEqual(got, want) {
return nil, fmt.Errorf("unexpected deployment object\n\tDiff: %s", diff.ObjectGoPrintDiff(got, want)) return nil, fmt.Errorf("unexpected deployment object\n\tDiff: %s", diff.ObjectGoPrintDiff(got, want))
} }

View File

@ -23,6 +23,7 @@ import (
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api" clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/kubernetes/federation/apis/federation"
"k8s.io/kubernetes/federation/pkg/kubefed/util" "k8s.io/kubernetes/federation/pkg/kubefed/util"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl"
@ -150,6 +151,12 @@ func (j *joinFederation) Run(f cmdutil.Factory, cmdOut io.Writer, config util.Ad
return err return err
} }
federationName, err := getFederationName(hostClientset, j.commonOptions.FederationSystemNamespace)
if err != nil {
glog.V(2).Infof("Failed to get the federation name: %v", err)
return err
}
// We are not using the `kubectl create secret` machinery through // We are not using the `kubectl create secret` machinery through
// `RunCreateSubcommand` as we do to the cluster resource below // `RunCreateSubcommand` as we do to the cluster resource below
// because we have a bunch of requirements that the machinery does // because we have a bunch of requirements that the machinery does
@ -165,7 +172,7 @@ func (j *joinFederation) Run(f cmdutil.Factory, cmdOut io.Writer, config util.Ad
// don't have to print the created secret in the default case. // don't have to print the created secret in the default case.
// Having said that, secret generation machinery could be altered to // Having said that, secret generation machinery could be altered to
// suit our needs, but it is far less invasive and readable this way. // suit our needs, but it is far less invasive and readable this way.
_, err = createSecret(hostClientset, clientConfig, j.commonOptions.FederationSystemNamespace, j.options.clusterContext, j.options.secretName, j.options.dryRun) _, err = createSecret(hostClientset, clientConfig, j.commonOptions.FederationSystemNamespace, federationName, j.commonOptions.Name, j.options.clusterContext, j.options.secretName, j.options.dryRun)
if err != nil { if err != nil {
glog.V(2).Infof("Failed creating the cluster credentials secret: %v", err) glog.V(2).Infof("Failed creating the cluster credentials secret: %v", err)
return err return err
@ -185,7 +192,7 @@ func (j *joinFederation) Run(f cmdutil.Factory, cmdOut io.Writer, config util.Ad
// We further need to create a configmap named kube-config in the // We further need to create a configmap named kube-config in the
// just registered cluster which will be consumed by the kube-dns // just registered cluster which will be consumed by the kube-dns
// of this cluster. // of this cluster.
_, err = createConfigMap(hostClientset, config, j.commonOptions.FederationSystemNamespace, j.options.clusterContext, j.commonOptions.Kubeconfig, j.options.dryRun) _, err = createConfigMap(hostClientset, config, j.commonOptions.FederationSystemNamespace, federationName, j.commonOptions.Name, j.options.clusterContext, j.commonOptions.Kubeconfig, j.options.dryRun)
if err != nil { if err != nil {
glog.V(2).Infof("Failed creating the config map in cluster: %v", err) glog.V(2).Infof("Failed creating the config map in cluster: %v", err)
return err return err
@ -213,7 +220,7 @@ func minifyConfig(clientConfig *clientcmdapi.Config, context string) (*clientcmd
// createSecret extracts the kubeconfig for a given cluster and populates // createSecret extracts the kubeconfig for a given cluster and populates
// a secret with that kubeconfig. // a secret with that kubeconfig.
func createSecret(clientset internalclientset.Interface, clientConfig *clientcmdapi.Config, namespace, contextName, secretName string, dryRun bool) (runtime.Object, error) { func createSecret(clientset internalclientset.Interface, clientConfig *clientcmdapi.Config, namespace, federationName, clusterName, contextName, secretName string, dryRun bool) (runtime.Object, error) {
// Minify the kubeconfig to ensure that there is only information // Minify the kubeconfig to ensure that there is only information
// relevant to the cluster we are registering. // relevant to the cluster we are registering.
newClientConfig, err := minifyConfig(clientConfig, contextName) newClientConfig, err := minifyConfig(clientConfig, contextName)
@ -230,13 +237,13 @@ func createSecret(clientset internalclientset.Interface, clientConfig *clientcmd
return nil, err return nil, err
} }
return util.CreateKubeconfigSecret(clientset, newClientConfig, namespace, secretName, dryRun) return util.CreateKubeconfigSecret(clientset, newClientConfig, namespace, secretName, federationName, clusterName, dryRun)
} }
// createConfigMap creates a configmap with name kube-dns in the joining cluster // createConfigMap creates a configmap with name kube-dns in the joining cluster
// which stores the information about this federation zone name. // which stores the information about this federation zone name.
// If the configmap with this name already exists, its updated with this information. // If the configmap with this name already exists, its updated with this information.
func createConfigMap(hostClientSet internalclientset.Interface, config util.AdminConfig, fedSystemNamespace, targetClusterContext, kubeconfigPath string, dryRun bool) (*api.ConfigMap, error) { func createConfigMap(hostClientSet internalclientset.Interface, config util.AdminConfig, fedSystemNamespace, federationName, targetClusterName, targetClusterContext, kubeconfigPath string, dryRun bool) (*api.ConfigMap, error) {
cmDep, err := getCMDeployment(hostClientSet, fedSystemNamespace) cmDep, err := getCMDeployment(hostClientSet, fedSystemNamespace)
if err != nil { if err != nil {
return nil, err return nil, err
@ -258,6 +265,10 @@ func createConfigMap(hostClientSet internalclientset.Interface, config util.Admi
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: util.KubeDnsConfigmapName, Name: util.KubeDnsConfigmapName,
Namespace: metav1.NamespaceSystem, Namespace: metav1.NamespaceSystem,
Annotations: map[string]string{
federation.FederationNameAnnotation: federationName,
federation.ClusterNameAnnotation: targetClusterName,
},
}, },
Data: map[string]string{ Data: map[string]string{
util.FedDomainMapKey: domainMap, util.FedDomainMapKey: domainMap,
@ -366,3 +377,19 @@ func appendConfigMapString(existing string, toAppend string) string {
} }
return fmt.Sprintf("%s,%s", existing, toAppend) return fmt.Sprintf("%s,%s", existing, toAppend)
} }
// getFederationName gets the federation name from the appropriate annotation on the
// control manager deployment.
func getFederationName(hostClientSet internalclientset.Interface, fedNamespace string) (string, error) {
d, err := getCMDeployment(hostClientSet, fedNamespace)
if err != nil {
return "", err
}
name, ok := d.Annotations[federation.FederationNameAnnotation]
if !ok {
return "", fmt.Errorf("Federation control manager does not have federation name annotation. Please recreate the federation with a newer version of kubefed, or use an older version of kubefed to join this cluster.")
}
return name, nil
}

View File

@ -30,6 +30,7 @@ import (
"k8s.io/client-go/rest/fake" "k8s.io/client-go/rest/fake"
"k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api" clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/kubernetes/federation/apis/federation"
federationapi "k8s.io/kubernetes/federation/apis/federation/v1beta1" federationapi "k8s.io/kubernetes/federation/apis/federation/v1beta1"
kubefedtesting "k8s.io/kubernetes/federation/pkg/kubefed/testing" kubefedtesting "k8s.io/kubernetes/federation/pkg/kubefed/testing"
"k8s.io/kubernetes/federation/pkg/kubefed/util" "k8s.io/kubernetes/federation/pkg/kubefed/util"
@ -41,6 +42,11 @@ import (
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
) )
// testFederationName is a name to use for the federation in tests. Since the federation
// name is recovered from the federation itself, this constant is an appropriate
// functional replica.
const testFederationName = "test-federation"
func TestJoinFederation(t *testing.T) { func TestJoinFederation(t *testing.T) {
cmdErrMsg := "" cmdErrMsg := ""
cmdutil.BehaviorOnFatal(func(str string, code int) { cmdutil.BehaviorOnFatal(func(str string, code int) {
@ -253,6 +259,10 @@ func fakeJoinHostFactory(clusterName, clusterCtx, secretName, server, token stri
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: secretName, Name: secretName,
Namespace: util.DefaultFederationSystemNamespace, Namespace: util.DefaultFederationSystemNamespace,
Annotations: map[string]string{
federation.FederationNameAnnotation: testFederationName,
federation.ClusterNameAnnotation: clusterName,
},
}, },
Data: map[string][]byte{ Data: map[string][]byte{
"kubeconfig": configBytes, "kubeconfig": configBytes,
@ -275,7 +285,8 @@ func fakeJoinHostFactory(clusterName, clusterCtx, secretName, server, token stri
Name: cmName, Name: cmName,
Namespace: util.DefaultFederationSystemNamespace, Namespace: util.DefaultFederationSystemNamespace,
Annotations: map[string]string{ Annotations: map[string]string{
util.FedDomainMapKey: fmt.Sprintf("%s=%s", clusterCtx, "test-dns-zone"), util.FedDomainMapKey: fmt.Sprintf("%s=%s", clusterCtx, "test-dns-zone"),
federation.FederationNameAnnotation: testFederationName,
}, },
}, },
}, },
@ -324,6 +335,10 @@ func fakeJoinTargetClusterFactory(clusterName, clusterCtx string) (cmdutil.Facto
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: util.KubeDnsConfigmapName, Name: util.KubeDnsConfigmapName,
Namespace: metav1.NamespaceSystem, Namespace: metav1.NamespaceSystem,
Annotations: map[string]string{
federation.FederationNameAnnotation: testFederationName,
federation.ClusterNameAnnotation: clusterName,
},
}, },
Data: map[string]string{ Data: map[string]string{
util.FedDomainMapKey: fmt.Sprintf("%s=%s", clusterCtx, "test-dns-zone"), util.FedDomainMapKey: fmt.Sprintf("%s=%s", clusterCtx, "test-dns-zone"),

View File

@ -148,18 +148,26 @@ func (o *SubcommandOptions) SetName(cmd *cobra.Command, args []string) error {
return nil return nil
} }
func CreateKubeconfigSecret(clientset client.Interface, kubeconfig *clientcmdapi.Config, namespace, name string, dryRun bool) (*api.Secret, error) { func CreateKubeconfigSecret(clientset client.Interface, kubeconfig *clientcmdapi.Config, namespace, name, federationName, clusterName string, dryRun bool) (*api.Secret, error) {
configBytes, err := clientcmd.Write(*kubeconfig) configBytes, err := clientcmd.Write(*kubeconfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
annotations := map[string]string{
federationapi.FederationNameAnnotation: federationName,
}
if clusterName != "" {
annotations[federationapi.ClusterNameAnnotation] = clusterName
}
// Build the secret object with the minified and flattened // Build the secret object with the minified and flattened
// kubeconfig content. // kubeconfig content.
secret := &api.Secret{ secret := &api.Secret{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: name, Name: name,
Namespace: namespace, Namespace: namespace,
Annotations: annotations,
}, },
Data: map[string][]byte{ Data: map[string][]byte{
KubeconfigSecretDataKey: configBytes, KubeconfigSecretDataKey: configBytes,