mirror of https://github.com/kubernetes/kops.git
218 lines
5.9 KiB
Go
218 lines
5.9 KiB
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
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/golang/glog"
|
|
"k8s.io/api/core/v1"
|
|
k8sapiv1 "k8s.io/api/core/v1"
|
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
|
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/client-go/kubernetes"
|
|
kopsapi "k8s.io/kops/pkg/apis/kops"
|
|
"k8s.io/kops/pkg/client/simple"
|
|
"k8s.io/kops/pkg/kubeconfig"
|
|
"k8s.io/kubernetes/federation/apis/federation/v1beta1"
|
|
"k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset"
|
|
)
|
|
|
|
type FederationCluster struct {
|
|
FederationNamespace string
|
|
|
|
ControllerKubernetesClients []kubernetes.Interface
|
|
FederationClient federation_clientset.Interface
|
|
|
|
ClusterSecretName string
|
|
|
|
ClusterName string
|
|
ApiserverHostname string
|
|
}
|
|
|
|
func (o *FederationCluster) Run(clientset simple.Clientset, cluster *kopsapi.Cluster) error {
|
|
keyStore, err := clientset.KeyStore(cluster)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
secretStore, err := clientset.SecretStore(cluster)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
status := &kopsapi.NoopStatusStore{}
|
|
conf, err := kubeconfig.BuildKubecfg(cluster, keyStore, secretStore, status)
|
|
if err != nil {
|
|
return fmt.Errorf("error building connection information for cluster %q: %v", cluster.ObjectMeta.Name, err)
|
|
}
|
|
|
|
user := kubeconfig.KubectlUser{
|
|
ClientCertificateData: conf.ClientCert,
|
|
ClientKeyData: conf.ClientKey,
|
|
}
|
|
// username/password or bearer token may be set, but not both
|
|
if conf.KubeBearerToken != "" {
|
|
user.Token = conf.KubeBearerToken
|
|
} else {
|
|
user.Username = conf.KubeUser
|
|
user.Password = conf.KubePassword
|
|
}
|
|
|
|
for _, k8s := range o.ControllerKubernetesClients {
|
|
if err := o.ensureFederationSecret(k8s, conf.CACert, user); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if err := o.ensureFederationCluster(o.FederationClient); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (o *FederationCluster) ensureFederationSecret(k8s kubernetes.Interface, caCertData []byte, user kubeconfig.KubectlUser) error {
|
|
_, err := mutateSecret(k8s, o.FederationNamespace, o.ClusterSecretName, func(s *v1.Secret) (*v1.Secret, error) {
|
|
var kubeconfigData []byte
|
|
var err error
|
|
|
|
{
|
|
conf := &kubeconfig.KubectlConfig{
|
|
ApiVersion: "v1",
|
|
Kind: "Config",
|
|
}
|
|
|
|
cluster := &kubeconfig.KubectlClusterWithName{
|
|
Name: o.ClusterName,
|
|
Cluster: kubeconfig.KubectlCluster{
|
|
Server: "https://" + o.ApiserverHostname,
|
|
},
|
|
}
|
|
|
|
if caCertData != nil {
|
|
cluster.Cluster.CertificateAuthorityData = caCertData
|
|
}
|
|
|
|
conf.Clusters = append(conf.Clusters, cluster)
|
|
|
|
user := &kubeconfig.KubectlUserWithName{
|
|
Name: o.ClusterName,
|
|
User: user,
|
|
}
|
|
conf.Users = append(conf.Users, user)
|
|
|
|
context := &kubeconfig.KubectlContextWithName{
|
|
Name: o.ClusterName,
|
|
Context: kubeconfig.KubectlContext{
|
|
Cluster: cluster.Name,
|
|
User: user.Name,
|
|
},
|
|
}
|
|
conf.CurrentContext = o.ClusterName
|
|
conf.Contexts = append(conf.Contexts, context)
|
|
|
|
kubeconfigData, err = kopsapi.ToRawYaml(conf)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error building kubeconfig: %v", err)
|
|
}
|
|
}
|
|
|
|
if s == nil {
|
|
s = &v1.Secret{}
|
|
s.Type = v1.SecretTypeOpaque
|
|
}
|
|
if s.Data == nil {
|
|
s.Data = make(map[string][]byte)
|
|
}
|
|
|
|
s.Data["kubeconfig"] = kubeconfigData
|
|
return s, nil
|
|
})
|
|
|
|
return err
|
|
}
|
|
|
|
func (o *FederationCluster) ensureFederationCluster(federationClient federation_clientset.Interface) error {
|
|
_, err := mutateCluster(federationClient, o.ClusterName, func(c *v1beta1.Cluster) (*v1beta1.Cluster, error) {
|
|
if c == nil {
|
|
c = &v1beta1.Cluster{}
|
|
}
|
|
|
|
// How to connect to the member cluster
|
|
c.Spec.ServerAddressByClientCIDRs = []v1beta1.ServerAddressByClientCIDR{
|
|
{
|
|
// The CIDR with which clients can match their IP to figure out the server address that they should use.
|
|
ClientCIDR: "0.0.0.0/0",
|
|
// Address of this server, suitable for a client that matches the above CIDR.
|
|
// This can be a hostname, hostname:port, IP or IP:port.
|
|
ServerAddress: "https://" + o.ApiserverHostname,
|
|
},
|
|
}
|
|
|
|
// Secret containing credentials for connecting to cluster
|
|
c.Spec.SecretRef = &k8sapiv1.LocalObjectReference{
|
|
Name: o.ClusterSecretName,
|
|
}
|
|
return c, nil
|
|
})
|
|
|
|
return err
|
|
}
|
|
|
|
func findCluster(k8s federation_clientset.Interface, name string) (*v1beta1.Cluster, error) {
|
|
glog.V(2).Infof("querying k8s for federation cluster %s", name)
|
|
c, err := k8s.Federation().Clusters().Get(name, meta_v1.GetOptions{})
|
|
if err != nil {
|
|
if apierrors.IsNotFound(err) {
|
|
return nil, nil
|
|
} else {
|
|
return nil, fmt.Errorf("error reading federation cluster %s: %v", name, err)
|
|
}
|
|
}
|
|
return c, nil
|
|
}
|
|
|
|
func mutateCluster(k8s federation_clientset.Interface, name string, fn func(s *v1beta1.Cluster) (*v1beta1.Cluster, error)) (*v1beta1.Cluster, error) {
|
|
existing, err := findCluster(k8s, name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
createObject := existing == nil
|
|
updated, err := fn(existing)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
updated.Name = name
|
|
|
|
if createObject {
|
|
glog.V(2).Infof("creating federation cluster %s", name)
|
|
created, err := k8s.Federation().Clusters().Create(updated)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error creating federation cluster %s: %v", name, err)
|
|
}
|
|
return created, nil
|
|
} else {
|
|
glog.V(2).Infof("updating federation cluster %s", name)
|
|
created, err := k8s.Federation().Clusters().Update(updated)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error updating federation cluster %s: %v", name, err)
|
|
}
|
|
return created, nil
|
|
}
|
|
}
|