Commit 3c7616eb authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

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. ```
parents 2976cb82 85b4313a
......@@ -10,6 +10,7 @@ load(
go_library(
name = "go_default_library",
srcs = [
"annotations.go",
"doc.go",
"register.go",
"types.go",
......
/*
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"
......@@ -14,6 +14,7 @@ go_library(
tags = ["automanaged"],
deps = [
"//cmd/kubeadm/app/util/kubeconfig:go_default_library",
"//federation/apis/federation:go_default_library",
"//federation/pkg/kubefed/util:go_default_library",
"//pkg/api:go_default_library",
"//pkg/api/v1:go_default_library",
......@@ -42,6 +43,7 @@ go_test(
library = ":go_default_library",
tags = ["automanaged"],
deps = [
"//federation/apis/federation:go_default_library",
"//federation/pkg/kubefed/testing:go_default_library",
"//federation/pkg/kubefed/util:go_default_library",
"//pkg/api:go_default_library",
......
......@@ -42,6 +42,7 @@ import (
"k8s.io/client-go/dynamic"
"k8s.io/client-go/rest/fake"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/kubernetes/federation/apis/federation"
kubefedtesting "k8s.io/kubernetes/federation/pkg/kubefed/testing"
"k8s.io/kubernetes/federation/pkg/kubefed/util"
"k8s.io/kubernetes/pkg/api"
......@@ -619,6 +620,9 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
},
ObjectMeta: metav1.ObjectMeta{
Name: namespaceName,
Annotations: map[string]string{
federation.FederationNameAnnotation: federationName,
},
},
}
......@@ -631,6 +635,9 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
Namespace: namespaceName,
Name: svcName,
Labels: componentLabel,
Annotations: map[string]string{
federation.FederationNameAnnotation: federationName,
},
},
Spec: v1.ServiceSpec{
Type: apiserverServiceType,
......@@ -664,6 +671,9 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
ObjectMeta: metav1.ObjectMeta{
Name: credSecretName,
Namespace: namespaceName,
Annotations: map[string]string{
federation.FederationNameAnnotation: federationName,
},
},
Data: nil,
}
......@@ -676,6 +686,9 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
ObjectMeta: metav1.ObjectMeta{
Name: cmKubeconfigSecretName,
Namespace: namespaceName,
Annotations: map[string]string{
federation.FederationNameAnnotation: federationName,
},
},
Data: nil,
}
......@@ -688,6 +701,9 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
ObjectMeta: metav1.ObjectMeta{
Name: dnsProviderSecretName,
Namespace: namespaceName,
Annotations: map[string]string{
federation.FederationNameAnnotation: federationName,
},
},
Data: nil,
}
......@@ -703,6 +719,7 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
Labels: componentLabel,
Annotations: map[string]string{
"volume.alpha.kubernetes.io/storage-class": "yes",
federation.FederationNameAnnotation: federationName,
},
},
Spec: v1.PersistentVolumeClaimSpec{
......@@ -726,6 +743,9 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
Name: "federation-controller-manager",
Namespace: namespaceName,
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",
Namespace: namespaceName,
Labels: componentLabel,
Annotations: map[string]string{
federation.FederationNameAnnotation: federationName,
},
},
Rules: []rbacv1beta1.PolicyRule{
{
......@@ -757,6 +780,9 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
Name: "federation-system:federation-controller-manager",
Namespace: namespaceName,
Labels: componentLabel,
Annotations: map[string]string{
federation.FederationNameAnnotation: federationName,
},
},
Subjects: []rbacv1beta1.Subject{
{
......@@ -838,17 +864,19 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
APIVersion: testapi.Extensions.GroupVersion().String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: svcName,
Namespace: namespaceName,
Labels: componentLabel,
Name: svcName,
Namespace: namespaceName,
Labels: componentLabel,
Annotations: map[string]string{federation.FederationNameAnnotation: federationName},
},
Spec: v1beta1.DeploymentSpec{
Replicas: &replicas,
Selector: nil,
Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Name: svcName,
Labels: apiserverPodLabels,
Name: svcName,
Labels: apiserverPodLabels,
Annotations: map[string]string{federation.FederationNameAnnotation: federationName},
},
Spec: v1.PodSpec{
Containers: []v1.Container{
......@@ -954,7 +982,8 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
Namespace: namespaceName,
Labels: componentLabel,
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{
......@@ -962,8 +991,9 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
Selector: nil,
Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Name: cmName,
Labels: controllerManagerPodLabels,
Name: cmName,
Labels: controllerManagerPodLabels,
Annotations: map[string]string{federation.FederationNameAnnotation: federationName},
},
Spec: v1.PodSpec{
Containers: []v1.Container{
......@@ -1196,6 +1226,7 @@ func fakeInitHostFactory(apiserverServiceType v1.ServiceType, federationName, na
case cmName:
want = *cm
}
//want = *cm
if !apiequality.Semantic.DeepEqual(got, want) {
return nil, fmt.Errorf("unexpected deployment object\n\tDiff: %s", diff.ObjectGoPrintDiff(got, want))
}
......
......@@ -23,6 +23,7 @@ import (
"k8s.io/apimachinery/pkg/runtime"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/kubernetes/federation/apis/federation"
"k8s.io/kubernetes/federation/pkg/kubefed/util"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/kubectl"
......@@ -150,6 +151,12 @@ func (j *joinFederation) Run(f cmdutil.Factory, cmdOut io.Writer, config util.Ad
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
// `RunCreateSubcommand` as we do to the cluster resource below
// 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.
// 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(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 {
glog.V(2).Infof("Failed creating the cluster credentials secret: %v", 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
// just registered cluster which will be consumed by the kube-dns
// 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 {
glog.V(2).Infof("Failed creating the config map in cluster: %v", 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
// 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
// relevant to the cluster we are registering.
newClientConfig, err := minifyConfig(clientConfig, contextName)
......@@ -230,13 +237,13 @@ func createSecret(clientset internalclientset.Interface, clientConfig *clientcmd
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
// which stores the information about this federation zone name.
// 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)
if err != nil {
return nil, err
......@@ -258,6 +265,10 @@ func createConfigMap(hostClientSet internalclientset.Interface, config util.Admi
ObjectMeta: metav1.ObjectMeta{
Name: util.KubeDnsConfigmapName,
Namespace: metav1.NamespaceSystem,
Annotations: map[string]string{
federation.FederationNameAnnotation: federationName,
federation.ClusterNameAnnotation: targetClusterName,
},
},
Data: map[string]string{
util.FedDomainMapKey: domainMap,
......@@ -366,3 +377,19 @@ func appendConfigMapString(existing string, toAppend string) string {
}
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
}
......@@ -30,6 +30,7 @@ import (
"k8s.io/client-go/rest/fake"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/kubernetes/federation/apis/federation"
federationapi "k8s.io/kubernetes/federation/apis/federation/v1beta1"
kubefedtesting "k8s.io/kubernetes/federation/pkg/kubefed/testing"
"k8s.io/kubernetes/federation/pkg/kubefed/util"
......@@ -41,6 +42,11 @@ import (
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) {
cmdErrMsg := ""
cmdutil.BehaviorOnFatal(func(str string, code int) {
......@@ -253,6 +259,10 @@ func fakeJoinHostFactory(clusterName, clusterCtx, secretName, server, token stri
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
Namespace: util.DefaultFederationSystemNamespace,
Annotations: map[string]string{
federation.FederationNameAnnotation: testFederationName,
federation.ClusterNameAnnotation: clusterName,
},
},
Data: map[string][]byte{
"kubeconfig": configBytes,
......@@ -275,7 +285,8 @@ func fakeJoinHostFactory(clusterName, clusterCtx, secretName, server, token stri
Name: cmName,
Namespace: util.DefaultFederationSystemNamespace,
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{
Name: util.KubeDnsConfigmapName,
Namespace: metav1.NamespaceSystem,
Annotations: map[string]string{
federation.FederationNameAnnotation: testFederationName,
federation.ClusterNameAnnotation: clusterName,
},
},
Data: map[string]string{
util.FedDomainMapKey: fmt.Sprintf("%s=%s", clusterCtx, "test-dns-zone"),
......
......@@ -148,18 +148,26 @@ func (o *SubcommandOptions) SetName(cmd *cobra.Command, args []string) error {
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)
if err != nil {
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
// kubeconfig content.
secret := &api.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
Name: name,
Namespace: namespace,
Annotations: annotations,
},
Data: map[string][]byte{
KubeconfigSecretDataKey: configBytes,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment