Switch to github.com/golang/dep for vendoring
Signed-off-by: Mrunal Patel <mrunalp@gmail.com>
This commit is contained in:
parent
d6ab91be27
commit
8e5b17cf13
15431 changed files with 3971413 additions and 8881 deletions
84
vendor/k8s.io/kubernetes/federation/pkg/kubefed/BUILD
generated
vendored
Normal file
84
vendor/k8s.io/kubernetes/federation/pkg/kubefed/BUILD
generated
vendored
Normal file
|
@ -0,0 +1,84 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"join.go",
|
||||
"kubefed.go",
|
||||
"unjoin.go",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/apis/federation:go_default_library",
|
||||
"//federation/pkg/kubefed/init:go_default_library",
|
||||
"//federation/pkg/kubefed/util:go_default_library",
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
||||
"//pkg/client/unversioned/clientcmd/api:go_default_library",
|
||||
"//pkg/kubectl:go_default_library",
|
||||
"//pkg/kubectl/cmd:go_default_library",
|
||||
"//pkg/kubectl/cmd/templates:go_default_library",
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//pkg/kubectl/resource:go_default_library",
|
||||
"//pkg/util/flag:go_default_library",
|
||||
"//vendor:github.com/golang/glog",
|
||||
"//vendor:github.com/spf13/cobra",
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/errors",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"join_test.go",
|
||||
"unjoin_test.go",
|
||||
],
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/apis/federation:go_default_library",
|
||||
"//federation/apis/federation/v1beta1:go_default_library",
|
||||
"//federation/pkg/kubefed/testing:go_default_library",
|
||||
"//federation/pkg/kubefed/util:go_default_library",
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/testapi:go_default_library",
|
||||
"//pkg/api/v1: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/client/unversioned/clientcmd/api:go_default_library",
|
||||
"//pkg/kubectl/cmd/testing:go_default_library",
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//vendor:k8s.io/apimachinery/pkg/api/errors",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/diff",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//federation/pkg/kubefed/init:all-srcs",
|
||||
"//federation/pkg/kubefed/testing:all-srcs",
|
||||
"//federation/pkg/kubefed/util:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
72
vendor/k8s.io/kubernetes/federation/pkg/kubefed/init/BUILD
generated
vendored
Normal file
72
vendor/k8s.io/kubernetes/federation/pkg/kubefed/init/BUILD
generated
vendored
Normal file
|
@ -0,0 +1,72 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["init.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//cmd/kubeadm/app/phases/kubeconfig:go_default_library",
|
||||
"//federation/pkg/kubefed/util:go_default_library",
|
||||
"//pkg/api:go_default_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/version:go_default_library",
|
||||
"//vendor:github.com/spf13/cobra",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/wait",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["init_test.go"],
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/pkg/kubefed/testing:go_default_library",
|
||||
"//federation/pkg/kubefed/util:go_default_library",
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/resource:go_default_library",
|
||||
"//pkg/api/testapi: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/apimachinery/pkg/api/errors",
|
||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||
"//vendor:k8s.io/apimachinery/pkg/util/diff",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
681
vendor/k8s.io/kubernetes/federation/pkg/kubefed/init/init.go
generated
vendored
Normal file
681
vendor/k8s.io/kubernetes/federation/pkg/kubefed/init/init.go
generated
vendored
Normal file
|
@ -0,0 +1,681 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
// TODO(madhusdancs):
|
||||
// 1. Make printSuccess prepend protocol/scheme to the IPs/hostnames.
|
||||
// 1. Add a dry-run support.
|
||||
// 2. Make all the API object names customizable.
|
||||
// Ex: federation-apiserver, federation-controller-manager, etc.
|
||||
// 3. Make image name and tag customizable.
|
||||
// 4. Separate etcd container from API server pod as a first step towards enabling HA.
|
||||
// 5. Generate credentials of the following types for the API server:
|
||||
// i. "known_tokens.csv"
|
||||
// ii. "basic_auth.csv"
|
||||
// 6. Add the ability to customize DNS domain suffix. It should probably be derived
|
||||
// from cluster config.
|
||||
// 7. Make etcd PVC size configurable.
|
||||
// 8. Make API server and controller manager replicas customizable via the HA work.
|
||||
package init
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
kubeadmkubeconfigphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/kubeconfig"
|
||||
"k8s.io/kubernetes/federation/pkg/kubefed/util"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"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/version"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const (
|
||||
APIServerCN = "federation-apiserver"
|
||||
ControllerManagerCN = "federation-controller-manager"
|
||||
AdminCN = "admin"
|
||||
HostClusterLocalDNSZoneName = "cluster.local."
|
||||
|
||||
lbAddrRetryInterval = 5 * time.Second
|
||||
podWaitInterval = 2 * time.Second
|
||||
)
|
||||
|
||||
var (
|
||||
init_long = templates.LongDesc(`
|
||||
Initialize a federation control plane.
|
||||
|
||||
Federation control plane is hosted inside a Kubernetes
|
||||
cluster. The host cluster must be specified using the
|
||||
--host-cluster-context flag.`)
|
||||
init_example = templates.Examples(`
|
||||
# Initialize federation control plane for a federation
|
||||
# named foo in the host cluster whose local kubeconfig
|
||||
# context is bar.
|
||||
kubectl init foo --host-cluster-context=bar`)
|
||||
|
||||
componentLabel = map[string]string{
|
||||
"app": "federated-cluster",
|
||||
}
|
||||
|
||||
apiserverSvcSelector = map[string]string{
|
||||
"app": "federated-cluster",
|
||||
"module": "federation-apiserver",
|
||||
}
|
||||
|
||||
apiserverPodLabels = map[string]string{
|
||||
"app": "federated-cluster",
|
||||
"module": "federation-apiserver",
|
||||
}
|
||||
|
||||
controllerManagerPodLabels = map[string]string{
|
||||
"app": "federated-cluster",
|
||||
"module": "federation-controller-manager",
|
||||
}
|
||||
|
||||
hyperkubeImageName = "gcr.io/google_containers/hyperkube-amd64"
|
||||
)
|
||||
|
||||
// NewCmdInit defines the `init` command that bootstraps a federation
|
||||
// control plane inside a set of host clusters.
|
||||
func NewCmdInit(cmdOut io.Writer, config util.AdminConfig) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "init FEDERATION_NAME --host-cluster-context=HOST_CONTEXT",
|
||||
Short: "init initializes a federation control plane",
|
||||
Long: init_long,
|
||||
Example: init_example,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := initFederation(cmdOut, config, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
},
|
||||
}
|
||||
|
||||
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.")
|
||||
cmd.Flags().String("dns-provider", "google-clouddns", "Dns provider to be used for this deployment.")
|
||||
cmd.Flags().String("etcd-pv-capacity", "10Gi", "Size of persistent volume claim to be used for etcd.")
|
||||
cmd.Flags().Bool("dry-run", false, "dry run without sending commands to server.")
|
||||
cmd.Flags().String("storage-backend", "etcd2", "The storage backend for persistence. Options: 'etcd2' (default), 'etcd3'.")
|
||||
return cmd
|
||||
}
|
||||
|
||||
type entityKeyPairs struct {
|
||||
ca *triple.KeyPair
|
||||
server *triple.KeyPair
|
||||
controllerManager *triple.KeyPair
|
||||
admin *triple.KeyPair
|
||||
}
|
||||
|
||||
// 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")
|
||||
etcdPVCapacity := cmdutil.GetFlagString(cmd, "etcd-pv-capacity")
|
||||
dryRun := cmdutil.GetDryRunFlag(cmd)
|
||||
storageBackend := cmdutil.GetFlagString(cmd, "storage-backend")
|
||||
|
||||
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, dryRun)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 2. Expose a network endpoint for the federation API server
|
||||
svc, err := createService(hostClientset, initFlags.FederationSystemNamespace, serverName, dryRun)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ips, hostnames, err := waitForLoadBalancerAddress(hostClientset, svc, dryRun)
|
||||
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, dryRun)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 4. Create a kubeconfig secret
|
||||
_, err = createControllerManagerKubeconfigSecret(hostClientset, initFlags.FederationSystemNamespace, initFlags.Name, svc.Name, cmKubeconfigName, entKeyPairs, dryRun)
|
||||
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, etcdPVCapacity, dryRun)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Since only one IP address can be specified as advertise address,
|
||||
// we arbitrarily pick the first available 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, storageBackend, dryRun)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 7. Create federation controller manager
|
||||
_, err = createControllerManager(hostClientset, initFlags.FederationSystemNamespace, initFlags.Name, svc.Name, cmName, image, cmKubeconfigName, dnsZoneName, dnsProvider, dryRun)
|
||||
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, dryRun)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !dryRun {
|
||||
fedPods := []string{serverName, cmName}
|
||||
err = waitForPods(hostClientset, fedPods, initFlags.FederationSystemNamespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = waitSrvHealthy(config, initFlags.Name, initFlags.Kubeconfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return printSuccess(cmdOut, ips, hostnames)
|
||||
}
|
||||
_, err = fmt.Fprintf(cmdOut, "Federation control plane runs (dry run)\n")
|
||||
return err
|
||||
}
|
||||
|
||||
func createNamespace(clientset *client.Clientset, namespace string, dryRun bool) (*api.Namespace, error) {
|
||||
ns := &api.Namespace{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: namespace,
|
||||
},
|
||||
}
|
||||
|
||||
if dryRun {
|
||||
return ns, nil
|
||||
}
|
||||
|
||||
return clientset.Core().Namespaces().Create(ns)
|
||||
}
|
||||
|
||||
func createService(clientset *client.Clientset, namespace, svcName string, dryRun bool) (*api.Service, error) {
|
||||
svc := &api.Service{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: svcName,
|
||||
Namespace: namespace,
|
||||
Labels: componentLabel,
|
||||
},
|
||||
Spec: api.ServiceSpec{
|
||||
Type: api.ServiceTypeLoadBalancer,
|
||||
Selector: apiserverSvcSelector,
|
||||
Ports: []api.ServicePort{
|
||||
{
|
||||
Name: "https",
|
||||
Protocol: "TCP",
|
||||
Port: 443,
|
||||
TargetPort: intstr.FromInt(443),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if dryRun {
|
||||
return svc, nil
|
||||
}
|
||||
|
||||
return clientset.Core().Services(namespace).Create(svc)
|
||||
}
|
||||
|
||||
func waitForLoadBalancerAddress(clientset *client.Clientset, svc *api.Service, dryRun bool) ([]string, []string, error) {
|
||||
ips := []string{}
|
||||
hostnames := []string{}
|
||||
|
||||
if dryRun {
|
||||
return ips, hostnames, nil
|
||||
}
|
||||
|
||||
err := wait.PollImmediateInfinite(lbAddrRetryInterval, func() (bool, error) {
|
||||
pollSvc, err := clientset.Core().Services(svc.Namespace).Get(svc.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
if ings := pollSvc.Status.LoadBalancer.Ingress; len(ings) > 0 {
|
||||
for _, ing := range ings {
|
||||
if len(ing.IP) > 0 {
|
||||
ips = append(ips, ing.IP)
|
||||
}
|
||||
if len(ing.Hostname) > 0 {
|
||||
hostnames = append(hostnames, ing.Hostname)
|
||||
}
|
||||
}
|
||||
if len(ips) > 0 || len(hostnames) > 0 {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return ips, hostnames, nil
|
||||
}
|
||||
|
||||
func genCerts(svcNamespace, name, svcName, localDNSZoneName string, ips, hostnames []string) (*entityKeyPairs, error) {
|
||||
ca, err := triple.NewCA(name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create CA key and certificate: %v", err)
|
||||
}
|
||||
server, err := triple.NewServerKeyPair(ca, APIServerCN, svcName, svcNamespace, localDNSZoneName, ips, hostnames)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create federation API server key and certificate: %v", err)
|
||||
}
|
||||
cm, err := triple.NewClientKeyPair(ca, ControllerManagerCN)
|
||||
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
|
||||
}
|
||||
|
||||
func createAPIServerCredentialsSecret(clientset *client.Clientset, namespace, credentialsName string, entKeyPairs *entityKeyPairs, dryRun bool) (*api.Secret, error) {
|
||||
// Build the secret object with API server credentials.
|
||||
secret := &api.Secret{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: credentialsName,
|
||||
Namespace: namespace,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"ca.crt": certutil.EncodeCertPEM(entKeyPairs.ca.Cert),
|
||||
"server.crt": certutil.EncodeCertPEM(entKeyPairs.server.Cert),
|
||||
"server.key": certutil.EncodePrivateKeyPEM(entKeyPairs.server.Key),
|
||||
},
|
||||
}
|
||||
|
||||
if dryRun {
|
||||
return secret, nil
|
||||
}
|
||||
// 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, dryRun bool) (*api.Secret, error) {
|
||||
config := kubeadmkubeconfigphase.MakeClientConfigWithCerts(
|
||||
fmt.Sprintf("https://%s", svcName),
|
||||
name,
|
||||
"federation-controller-manager",
|
||||
certutil.EncodeCertPEM(entKeyPairs.ca.Cert),
|
||||
certutil.EncodePrivateKeyPEM(entKeyPairs.controllerManager.Key),
|
||||
certutil.EncodeCertPEM(entKeyPairs.controllerManager.Cert),
|
||||
)
|
||||
|
||||
return util.CreateKubeconfigSecret(clientset, config, namespace, kubeconfigName, dryRun)
|
||||
}
|
||||
|
||||
func createPVC(clientset *client.Clientset, namespace, svcName, etcdPVCapacity string, dryRun bool) (*api.PersistentVolumeClaim, error) {
|
||||
capacity, err := resource.ParseQuantity(etcdPVCapacity)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pvc := &api.PersistentVolumeClaim{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: fmt.Sprintf("%s-etcd-claim", svcName),
|
||||
Namespace: namespace,
|
||||
Labels: componentLabel,
|
||||
Annotations: map[string]string{
|
||||
"volume.alpha.kubernetes.io/storage-class": "yes",
|
||||
},
|
||||
},
|
||||
Spec: api.PersistentVolumeClaimSpec{
|
||||
AccessModes: []api.PersistentVolumeAccessMode{
|
||||
api.ReadWriteOnce,
|
||||
},
|
||||
Resources: api.ResourceRequirements{
|
||||
Requests: api.ResourceList{
|
||||
api.ResourceStorage: capacity,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if dryRun {
|
||||
return pvc, nil
|
||||
}
|
||||
|
||||
return clientset.Core().PersistentVolumeClaims(namespace).Create(pvc)
|
||||
}
|
||||
|
||||
func createAPIServer(clientset *client.Clientset, namespace, name, image, credentialsName, pvcName, advertiseAddress, storageBackend string, dryRun bool) (*extensions.Deployment, error) {
|
||||
command := []string{
|
||||
"/hyperkube",
|
||||
"federation-apiserver",
|
||||
"--bind-address=0.0.0.0",
|
||||
"--etcd-servers=http://localhost:2379",
|
||||
"--secure-port=443",
|
||||
"--client-ca-file=/etc/federation/apiserver/ca.crt",
|
||||
"--tls-cert-file=/etc/federation/apiserver/server.crt",
|
||||
"--tls-private-key-file=/etc/federation/apiserver/server.key",
|
||||
fmt.Sprintf("--storage-backend=%s", storageBackend),
|
||||
}
|
||||
|
||||
if advertiseAddress != "" {
|
||||
command = append(command, fmt.Sprintf("--advertise-address=%s", advertiseAddress))
|
||||
}
|
||||
|
||||
dataVolumeName := "etcddata"
|
||||
|
||||
dep := &extensions.Deployment{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
Labels: componentLabel,
|
||||
},
|
||||
Spec: extensions.DeploymentSpec{
|
||||
Replicas: 1,
|
||||
Template: api.PodTemplateSpec{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: name,
|
||||
Labels: apiserverPodLabels,
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Name: "apiserver",
|
||||
Image: image,
|
||||
Command: command,
|
||||
Ports: []api.ContainerPort{
|
||||
{
|
||||
Name: "https",
|
||||
ContainerPort: 443,
|
||||
},
|
||||
{
|
||||
Name: "local",
|
||||
ContainerPort: 8080,
|
||||
},
|
||||
},
|
||||
VolumeMounts: []api.VolumeMount{
|
||||
{
|
||||
Name: credentialsName,
|
||||
MountPath: "/etc/federation/apiserver",
|
||||
ReadOnly: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "etcd",
|
||||
Image: "gcr.io/google_containers/etcd:3.0.14-alpha.1",
|
||||
Command: []string{
|
||||
"/usr/local/bin/etcd",
|
||||
"--data-dir",
|
||||
"/var/etcd/data",
|
||||
},
|
||||
VolumeMounts: []api.VolumeMount{
|
||||
{
|
||||
Name: dataVolumeName,
|
||||
MountPath: "/var/etcd",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Volumes: []api.Volume{
|
||||
{
|
||||
Name: credentialsName,
|
||||
VolumeSource: api.VolumeSource{
|
||||
Secret: &api.SecretVolumeSource{
|
||||
SecretName: credentialsName,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: dataVolumeName,
|
||||
VolumeSource: api.VolumeSource{
|
||||
PersistentVolumeClaim: &api.PersistentVolumeClaimVolumeSource{
|
||||
ClaimName: pvcName,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if dryRun {
|
||||
return dep, nil
|
||||
}
|
||||
|
||||
return clientset.Extensions().Deployments(namespace).Create(dep)
|
||||
}
|
||||
|
||||
func createControllerManager(clientset *client.Clientset, namespace, name, svcName, cmName, image, kubeconfigName, dnsZoneName, dnsProvider string, dryRun bool) (*extensions.Deployment, error) {
|
||||
dep := &extensions.Deployment{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: cmName,
|
||||
Namespace: namespace,
|
||||
Labels: componentLabel,
|
||||
},
|
||||
Spec: extensions.DeploymentSpec{
|
||||
Replicas: 1,
|
||||
Template: api.PodTemplateSpec{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: cmName,
|
||||
Labels: controllerManagerPodLabels,
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Name: "controller-manager",
|
||||
Image: image,
|
||||
Command: []string{
|
||||
"/hyperkube",
|
||||
"federation-controller-manager",
|
||||
fmt.Sprintf("--master=https://%s", svcName),
|
||||
"--kubeconfig=/etc/federation/controller-manager/kubeconfig",
|
||||
fmt.Sprintf("--dns-provider=%s", dnsProvider),
|
||||
"--dns-provider-config=",
|
||||
fmt.Sprintf("--federation-name=%s", name),
|
||||
fmt.Sprintf("--zone-name=%s", dnsZoneName),
|
||||
},
|
||||
VolumeMounts: []api.VolumeMount{
|
||||
{
|
||||
Name: kubeconfigName,
|
||||
MountPath: "/etc/federation/controller-manager",
|
||||
ReadOnly: true,
|
||||
},
|
||||
},
|
||||
Env: []api.EnvVar{
|
||||
{
|
||||
Name: "POD_NAMESPACE",
|
||||
ValueFrom: &api.EnvVarSource{
|
||||
FieldRef: &api.ObjectFieldSelector{
|
||||
FieldPath: "metadata.namespace",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Volumes: []api.Volume{
|
||||
{
|
||||
Name: kubeconfigName,
|
||||
VolumeSource: api.VolumeSource{
|
||||
Secret: &api.SecretVolumeSource{
|
||||
SecretName: kubeconfigName,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if dryRun {
|
||||
return dep, nil
|
||||
}
|
||||
return clientset.Extensions().Deployments(namespace).Create(dep)
|
||||
}
|
||||
|
||||
func waitForPods(clientset *client.Clientset, fedPods []string, namespace string) error {
|
||||
err := wait.PollInfinite(podWaitInterval, func() (bool, error) {
|
||||
podCheck := len(fedPods)
|
||||
podList, err := clientset.Core().Pods(namespace).List(api.ListOptions{})
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
for _, pod := range podList.Items {
|
||||
for _, fedPod := range fedPods {
|
||||
if strings.HasPrefix(pod.Name, fedPod) && pod.Status.Phase == "Running" {
|
||||
podCheck -= 1
|
||||
}
|
||||
}
|
||||
//ensure that all pods are in running state or keep waiting
|
||||
if podCheck == 0 {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
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 printSuccess(cmdOut io.Writer, ips, hostnames []string) error {
|
||||
svcEndpoints := append(ips, hostnames...)
|
||||
_, 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, 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
|
||||
}
|
1049
vendor/k8s.io/kubernetes/federation/pkg/kubefed/init/init_test.go
generated
vendored
Normal file
1049
vendor/k8s.io/kubernetes/federation/pkg/kubefed/init/init_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
238
vendor/k8s.io/kubernetes/federation/pkg/kubefed/join.go
generated
vendored
Normal file
238
vendor/k8s.io/kubernetes/federation/pkg/kubefed/join.go
generated
vendored
Normal file
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
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 kubefed
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/kubernetes/federation/pkg/kubefed/util"
|
||||
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
kubectlcmd "k8s.io/kubernetes/pkg/kubectl/cmd"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const (
|
||||
// defaultClusterCIDR is the default CIDR range accepted by the
|
||||
// joining API server. See `apis/federation.ClusterSpec` for
|
||||
// details.
|
||||
// TODO(madhusudancs): Make this value customizable.
|
||||
defaultClientCIDR = "0.0.0.0/0"
|
||||
)
|
||||
|
||||
var (
|
||||
join_long = templates.LongDesc(`
|
||||
Join a cluster to a federation.
|
||||
|
||||
Current context is assumed to be a federation API
|
||||
server. Please use the --context flag otherwise.`)
|
||||
join_example = templates.Examples(`
|
||||
# Join a cluster to a federation by specifying the
|
||||
# cluster name and the context name of the federation
|
||||
# control plane's host cluster. Cluster name must be
|
||||
# a valid RFC 1123 subdomain name. Cluster context
|
||||
# must be specified if the cluster name is different
|
||||
# than the cluster's context in the local kubeconfig.
|
||||
kubectl join foo --host-cluster-context=bar`)
|
||||
)
|
||||
|
||||
// NewCmdJoin defines the `join` command that joins a cluster to a
|
||||
// federation.
|
||||
func NewCmdJoin(f cmdutil.Factory, cmdOut io.Writer, config util.AdminConfig) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "join CLUSTER_NAME --host-cluster-context=HOST_CONTEXT",
|
||||
Short: "Join a cluster to a federation",
|
||||
Long: join_long,
|
||||
Example: join_example,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := joinFederation(f, cmdOut, config, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
},
|
||||
}
|
||||
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddGeneratorFlags(cmd, cmdutil.ClusterV1Beta1GeneratorName)
|
||||
util.AddSubcommandFlags(cmd)
|
||||
cmd.Flags().String("cluster-context", "", "Name of the cluster's context in the local kubeconfig. Defaults to cluster name if unspecified.")
|
||||
cmd.Flags().String("secret-name", "", "Name of the secret where the cluster's credentials will be stored in the host cluster. This name should be a valid RFC 1035 label. Defaults to cluster name if unspecified.")
|
||||
return cmd
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
clusterContext := cmdutil.GetFlagString(cmd, "cluster-context")
|
||||
secretName := cmdutil.GetFlagString(cmd, "secret-name")
|
||||
dryRun := cmdutil.GetDryRunFlag(cmd)
|
||||
|
||||
if clusterContext == "" {
|
||||
clusterContext = joinFlags.Name
|
||||
}
|
||||
if secretName == "" {
|
||||
secretName = joinFlags.Name
|
||||
}
|
||||
|
||||
glog.V(2).Infof("Args and flags: name %s, host: %s, host-system-namespace: %s, kubeconfig: %s, cluster-context: %s, secret-name: %s, dry-run: %s", joinFlags.Name, joinFlags.Host, joinFlags.FederationSystemNamespace, joinFlags.Kubeconfig, clusterContext, secretName, dryRun)
|
||||
|
||||
po := config.PathOptions()
|
||||
po.LoadingRules.ExplicitPath = joinFlags.Kubeconfig
|
||||
clientConfig, err := po.GetStartingConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
generator, err := clusterGenerator(clientConfig, joinFlags.Name, clusterContext, secretName)
|
||||
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, clusterContext, secretName, 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"),
|
||||
})
|
||||
}
|
||||
|
||||
// minifyConfig is a wrapper around `clientcmdapi.MinifyConfig()` that
|
||||
// sets the current context to the given context before calling
|
||||
// `clientcmdapi.MinifyConfig()`.
|
||||
func minifyConfig(clientConfig *clientcmdapi.Config, context string) (*clientcmdapi.Config, error) {
|
||||
// MinifyConfig inline-modifies the passed clientConfig. So we make a
|
||||
// copy of it before passing the config to it. A shallow copy is
|
||||
// sufficient because the underlying fields will be reconstructed by
|
||||
// MinifyConfig anyway.
|
||||
newClientConfig := *clientConfig
|
||||
newClientConfig.CurrentContext = context
|
||||
err := clientcmdapi.MinifyConfig(&newClientConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &newClientConfig, nil
|
||||
}
|
||||
|
||||
// createSecret extracts the kubeconfig for a given cluster and populates
|
||||
// a secret with that kubeconfig.
|
||||
func createSecret(hostFactory cmdutil.Factory, clientConfig *clientcmdapi.Config, namespace, 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)
|
||||
if err != nil {
|
||||
glog.V(2).Infof("Failed to minify the kubeconfig for the given context %q: %v", contextName, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Flatten the kubeconfig to ensure that all the referenced file
|
||||
// contents are inlined.
|
||||
err = clientcmdapi.FlattenConfig(newClientConfig)
|
||||
if err != nil {
|
||||
glog.V(2).Infof("Failed to flatten the kubeconfig for the given context %q: %v", contextName, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Boilerplate to create the secret in the host cluster.
|
||||
clientset, err := hostFactory.ClientSet()
|
||||
if err != nil {
|
||||
glog.V(2).Infof("Failed to serialize the kubeconfig for the given context %q: %v", contextName, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return util.CreateKubeconfigSecret(clientset, newClientConfig, namespace, secretName, dryRun)
|
||||
}
|
||||
|
||||
// clusterGenerator extracts the cluster information from the supplied
|
||||
// kubeconfig and builds a StructuredGenerator for the
|
||||
// `federation/cluster` API resource.
|
||||
func clusterGenerator(clientConfig *clientcmdapi.Config, name, contextName, secretName string) (kubectl.StructuredGenerator, error) {
|
||||
// Get the context from the config.
|
||||
ctx, found := clientConfig.Contexts[contextName]
|
||||
if !found {
|
||||
return nil, fmt.Errorf("cluster context %q not found", contextName)
|
||||
}
|
||||
|
||||
// Get the cluster object corresponding to the supplied context.
|
||||
cluster, found := clientConfig.Clusters[ctx.Cluster]
|
||||
if !found {
|
||||
return nil, fmt.Errorf("cluster endpoint not found for %q", name)
|
||||
}
|
||||
|
||||
// Extract the scheme portion of the cluster APIServer endpoint and
|
||||
// default it to `https` if it isn't specified.
|
||||
scheme := extractScheme(cluster.Server)
|
||||
serverAddress := cluster.Server
|
||||
if scheme == "" {
|
||||
// Use "https" as the default scheme.
|
||||
scheme := "https"
|
||||
serverAddress = strings.Join([]string{scheme, serverAddress}, "://")
|
||||
}
|
||||
|
||||
generator := &kubectl.ClusterGeneratorV1Beta1{
|
||||
Name: name,
|
||||
ClientCIDR: defaultClientCIDR,
|
||||
ServerAddress: serverAddress,
|
||||
SecretName: secretName,
|
||||
}
|
||||
return generator, nil
|
||||
}
|
||||
|
||||
// extractScheme parses the given URL to extract the scheme portion
|
||||
// out of it.
|
||||
func extractScheme(url string) string {
|
||||
scheme := ""
|
||||
segs := strings.SplitN(url, "://", 2)
|
||||
if len(segs) == 2 {
|
||||
scheme = segs[0]
|
||||
}
|
||||
return scheme
|
||||
}
|
295
vendor/k8s.io/kubernetes/federation/pkg/kubefed/join_test.go
generated
vendored
Normal file
295
vendor/k8s.io/kubernetes/federation/pkg/kubefed/join_test.go
generated
vendored
Normal file
|
@ -0,0 +1,295 @@
|
|||
/*
|
||||
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 kubefed
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
federationapi "k8s.io/kubernetes/federation/apis/federation/v1beta1"
|
||||
kubefedtesting "k8s.io/kubernetes/federation/pkg/kubefed/testing"
|
||||
"k8s.io/kubernetes/federation/pkg/kubefed/util"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/client/restclient/fake"
|
||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
||||
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
)
|
||||
|
||||
func TestJoinFederation(t *testing.T) {
|
||||
cmdErrMsg := ""
|
||||
cmdutil.BehaviorOnFatal(func(str string, code int) {
|
||||
cmdErrMsg = str
|
||||
})
|
||||
|
||||
fakeKubeFiles, err := kubefedtesting.FakeKubeconfigFiles()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
defer kubefedtesting.RemoveFakeKubeconfigFiles(fakeKubeFiles)
|
||||
|
||||
testCases := []struct {
|
||||
cluster string
|
||||
clusterCtx string
|
||||
secret string
|
||||
server string
|
||||
token string
|
||||
kubeconfigGlobal string
|
||||
kubeconfigExplicit string
|
||||
expectedServer string
|
||||
expectedErr string
|
||||
}{
|
||||
{
|
||||
cluster: "syndicate",
|
||||
clusterCtx: "",
|
||||
secret: "",
|
||||
server: "https://10.20.30.40",
|
||||
token: "badge",
|
||||
kubeconfigGlobal: fakeKubeFiles[0],
|
||||
kubeconfigExplicit: "",
|
||||
expectedServer: "https://10.20.30.40",
|
||||
expectedErr: "",
|
||||
},
|
||||
{
|
||||
cluster: "ally",
|
||||
clusterCtx: "",
|
||||
secret: "",
|
||||
server: "ally256.example.com:80",
|
||||
token: "souvenir",
|
||||
kubeconfigGlobal: fakeKubeFiles[0],
|
||||
kubeconfigExplicit: fakeKubeFiles[1],
|
||||
expectedServer: "https://ally256.example.com:80",
|
||||
expectedErr: "",
|
||||
},
|
||||
{
|
||||
cluster: "confederate",
|
||||
clusterCtx: "",
|
||||
secret: "",
|
||||
server: "10.8.8.8",
|
||||
token: "totem",
|
||||
kubeconfigGlobal: fakeKubeFiles[1],
|
||||
kubeconfigExplicit: fakeKubeFiles[2],
|
||||
expectedServer: "https://10.8.8.8",
|
||||
expectedErr: "",
|
||||
},
|
||||
{
|
||||
cluster: "associate",
|
||||
clusterCtx: "confederate",
|
||||
secret: "confidential",
|
||||
server: "10.8.8.8",
|
||||
token: "totem",
|
||||
kubeconfigGlobal: fakeKubeFiles[1],
|
||||
kubeconfigExplicit: fakeKubeFiles[2],
|
||||
expectedServer: "https://10.8.8.8",
|
||||
expectedErr: "",
|
||||
},
|
||||
{
|
||||
cluster: "affiliate",
|
||||
clusterCtx: "",
|
||||
secret: "",
|
||||
server: "https://10.20.30.40",
|
||||
token: "badge",
|
||||
kubeconfigGlobal: fakeKubeFiles[0],
|
||||
kubeconfigExplicit: "",
|
||||
expectedServer: "https://10.20.30.40",
|
||||
expectedErr: fmt.Sprintf("error: cluster context %q not found", "affiliate"),
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
cmdErrMsg = ""
|
||||
f := testJoinFederationFactory(tc.cluster, tc.secret, tc.expectedServer)
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
|
||||
hostFactory, err := fakeJoinHostFactory(tc.cluster, tc.clusterCtx, tc.secret, tc.server, tc.token)
|
||||
if err != nil {
|
||||
t.Fatalf("[%d] unexpected error: %v", i, err)
|
||||
}
|
||||
|
||||
adminConfig, err := kubefedtesting.NewFakeAdminConfig(hostFactory, tc.kubeconfigGlobal)
|
||||
if err != nil {
|
||||
t.Fatalf("[%d] unexpected error: %v", i, err)
|
||||
}
|
||||
|
||||
cmd := NewCmdJoin(f, buf, adminConfig)
|
||||
|
||||
cmd.Flags().Set("kubeconfig", tc.kubeconfigExplicit)
|
||||
cmd.Flags().Set("host-cluster-context", "substrate")
|
||||
if tc.clusterCtx != "" {
|
||||
cmd.Flags().Set("cluster-context", tc.clusterCtx)
|
||||
}
|
||||
if tc.secret != "" {
|
||||
cmd.Flags().Set("secret-name", tc.secret)
|
||||
}
|
||||
|
||||
cmd.Run(cmd, []string{tc.cluster})
|
||||
|
||||
if tc.expectedErr == "" {
|
||||
// uses the name from the cluster, not the response
|
||||
// Actual data passed are tested in the fake secret and cluster
|
||||
// REST clients.
|
||||
if msg := buf.String(); msg != fmt.Sprintf("cluster %q created\n", tc.cluster) {
|
||||
t.Errorf("[%d] unexpected output: %s", i, msg)
|
||||
if cmdErrMsg != "" {
|
||||
t.Errorf("[%d] unexpected error message: %s", i, cmdErrMsg)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if cmdErrMsg != tc.expectedErr {
|
||||
t.Errorf("[%d] expected error: %s, got: %s, output: %s", i, tc.expectedErr, cmdErrMsg, buf.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testJoinFederationFactory(clusterName, secretName, server string) cmdutil.Factory {
|
||||
if secretName == "" {
|
||||
secretName = clusterName
|
||||
}
|
||||
|
||||
want := fakeCluster(clusterName, secretName, server)
|
||||
f, tf, _, _ := cmdtesting.NewAPIFactory()
|
||||
codec := testapi.Federation.Codec()
|
||||
ns := dynamic.ContentConfig().NegotiatedSerializer
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
switch p, m := req.URL.Path, req.Method; {
|
||||
case p == "/clusters" && m == http.MethodPost:
|
||||
body, err := ioutil.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var got federationapi.Cluster
|
||||
_, _, err = codec.Decode(body, nil, &got)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !api.Semantic.DeepEqual(got, want) {
|
||||
return nil, fmt.Errorf("Unexpected cluster object\n\tDiff: %s", diff.ObjectGoPrintDiff(got, want))
|
||||
}
|
||||
return &http.Response{StatusCode: http.StatusCreated, Header: kubefedtesting.DefaultHeader(), Body: kubefedtesting.ObjBody(codec, &want)}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected request: %#v\n%#v", req.URL, req)
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
return f
|
||||
}
|
||||
|
||||
func fakeJoinHostFactory(clusterName, clusterCtx, secretName, server, token string) (cmdutil.Factory, error) {
|
||||
if clusterCtx == "" {
|
||||
clusterCtx = clusterName
|
||||
}
|
||||
if secretName == "" {
|
||||
secretName = clusterName
|
||||
}
|
||||
|
||||
kubeconfig := clientcmdapi.Config{
|
||||
Clusters: map[string]*clientcmdapi.Cluster{
|
||||
clusterCtx: {
|
||||
Server: server,
|
||||
},
|
||||
},
|
||||
AuthInfos: map[string]*clientcmdapi.AuthInfo{
|
||||
clusterCtx: {
|
||||
Token: token,
|
||||
},
|
||||
},
|
||||
Contexts: map[string]*clientcmdapi.Context{
|
||||
clusterCtx: {
|
||||
Cluster: clusterCtx,
|
||||
AuthInfo: clusterCtx,
|
||||
},
|
||||
},
|
||||
CurrentContext: clusterCtx,
|
||||
}
|
||||
configBytes, err := clientcmd.Write(kubeconfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
secretObject := v1.Secret{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Secret",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: secretName,
|
||||
Namespace: util.DefaultFederationSystemNamespace,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"kubeconfig": configBytes,
|
||||
},
|
||||
}
|
||||
|
||||
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
||||
ns := dynamic.ContentConfig().NegotiatedSerializer
|
||||
tf.ClientConfig = kubefedtesting.DefaultClientConfig()
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
switch p, m := req.URL.Path, req.Method; {
|
||||
case p == "/api/v1/namespaces/federation-system/secrets" && m == http.MethodPost:
|
||||
body, err := ioutil.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var got v1.Secret
|
||||
_, _, err = codec.Decode(body, nil, &got)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !api.Semantic.DeepEqual(got, secretObject) {
|
||||
return nil, fmt.Errorf("Unexpected secret object\n\tDiff: %s", diff.ObjectGoPrintDiff(got, secretObject))
|
||||
}
|
||||
return &http.Response{StatusCode: http.StatusCreated, Header: kubefedtesting.DefaultHeader(), Body: kubefedtesting.ObjBody(codec, &secretObject)}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected request: %#v\n%#v", req.URL, req)
|
||||
}
|
||||
}),
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func fakeCluster(clusterName, secretName, server string) federationapi.Cluster {
|
||||
return federationapi.Cluster{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: clusterName,
|
||||
},
|
||||
Spec: federationapi.ClusterSpec{
|
||||
ServerAddressByClientCIDRs: []federationapi.ServerAddressByClientCIDR{
|
||||
{
|
||||
ClientCIDR: defaultClientCIDR,
|
||||
ServerAddress: server,
|
||||
},
|
||||
},
|
||||
SecretRef: &v1.LocalObjectReference{
|
||||
Name: secretName,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
77
vendor/k8s.io/kubernetes/federation/pkg/kubefed/kubefed.go
generated
vendored
Normal file
77
vendor/k8s.io/kubernetes/federation/pkg/kubefed/kubefed.go
generated
vendored
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
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 kubefed
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
kubefedinit "k8s.io/kubernetes/federation/pkg/kubefed/init"
|
||||
"k8s.io/kubernetes/federation/pkg/kubefed/util"
|
||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
||||
kubectl "k8s.io/kubernetes/pkg/kubectl/cmd"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/util/flag"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// NewKubeFedCommand creates the `kubefed` command and its nested children.
|
||||
func NewKubeFedCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cobra.Command {
|
||||
// Parent command to which all subcommands are added.
|
||||
cmds := &cobra.Command{
|
||||
Use: "kubefed",
|
||||
Short: "kubefed controls a Kubernetes Cluster Federation",
|
||||
Long: templates.LongDesc(`
|
||||
kubefed controls a Kubernetes Cluster Federation.
|
||||
|
||||
Find more information at https://github.com/kubernetes/kubernetes.`),
|
||||
Run: runHelp,
|
||||
}
|
||||
|
||||
f.BindFlags(cmds.PersistentFlags())
|
||||
f.BindExternalFlags(cmds.PersistentFlags())
|
||||
|
||||
// From this point and forward we get warnings on flags that contain "_" separators
|
||||
cmds.SetGlobalNormalizationFunc(flag.WarnWordSepNormalizeFunc)
|
||||
|
||||
groups := templates.CommandGroups{
|
||||
{
|
||||
Message: "Basic Commands:",
|
||||
Commands: []*cobra.Command{
|
||||
kubefedinit.NewCmdInit(out, util.NewAdminConfig(clientcmd.NewDefaultPathOptions())),
|
||||
NewCmdJoin(f, out, util.NewAdminConfig(clientcmd.NewDefaultPathOptions())),
|
||||
NewCmdUnjoin(f, out, err, util.NewAdminConfig(clientcmd.NewDefaultPathOptions())),
|
||||
},
|
||||
},
|
||||
}
|
||||
groups.Add(cmds)
|
||||
|
||||
filters := []string{
|
||||
"options",
|
||||
}
|
||||
templates.ActsAsRootCommand(cmds, filters, groups...)
|
||||
|
||||
cmds.AddCommand(kubectl.NewCmdVersion(f, out))
|
||||
cmds.AddCommand(kubectl.NewCmdOptions(out))
|
||||
|
||||
return cmds
|
||||
}
|
||||
|
||||
func runHelp(cmd *cobra.Command, args []string) {
|
||||
cmd.Help()
|
||||
}
|
37
vendor/k8s.io/kubernetes/federation/pkg/kubefed/testing/BUILD
generated
vendored
Normal file
37
vendor/k8s.io/kubernetes/federation/pkg/kubefed/testing/BUILD
generated
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["testing.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/client/clientset_generated/federation_clientset:go_default_library",
|
||||
"//federation/pkg/kubefed/util:go_default_library",
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/client/restclient:go_default_library",
|
||||
"//pkg/client/unversioned/clientcmd:go_default_library",
|
||||
"//pkg/client/unversioned/clientcmd/api:go_default_library",
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//vendor:k8s.io/apimachinery/pkg/runtime",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
180
vendor/k8s.io/kubernetes/federation/pkg/kubefed/testing/testing.go
generated
vendored
Normal file
180
vendor/k8s.io/kubernetes/federation/pkg/kubefed/testing/testing.go
generated
vendored
Normal file
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
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 testing
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
fedclient "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset"
|
||||
"k8s.io/kubernetes/federation/pkg/kubefed/util"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/client/restclient"
|
||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
||||
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
)
|
||||
|
||||
type fakeAdminConfig struct {
|
||||
pathOptions *clientcmd.PathOptions
|
||||
hostFactory cmdutil.Factory
|
||||
}
|
||||
|
||||
func NewFakeAdminConfig(f cmdutil.Factory, kubeconfigGlobal string) (util.AdminConfig, error) {
|
||||
pathOptions := clientcmd.NewDefaultPathOptions()
|
||||
pathOptions.GlobalFile = kubeconfigGlobal
|
||||
pathOptions.EnvVar = ""
|
||||
|
||||
return &fakeAdminConfig{
|
||||
pathOptions: pathOptions,
|
||||
hostFactory: f,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f *fakeAdminConfig) PathOptions() *clientcmd.PathOptions {
|
||||
return f.pathOptions
|
||||
}
|
||||
|
||||
func (f *fakeAdminConfig) FederationClientset(context, kubeconfigPath string) (*fedclient.Clientset, error) {
|
||||
fakeRestClient, err := f.hostFactory.RESTClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// we ignore the function params and use the client from
|
||||
// the same fakefactory to create a federation clientset
|
||||
// our fake factory exposes only the healthz api for this client
|
||||
return fedclient.New(fakeRestClient), nil
|
||||
}
|
||||
|
||||
func (f *fakeAdminConfig) HostFactory(host, kubeconfigPath string) cmdutil.Factory {
|
||||
return f.hostFactory
|
||||
}
|
||||
|
||||
func FakeKubeconfigFiles() ([]string, error) {
|
||||
kubeconfigs := []clientcmdapi.Config{
|
||||
{
|
||||
Clusters: map[string]*clientcmdapi.Cluster{
|
||||
"syndicate": {
|
||||
Server: "https://10.20.30.40",
|
||||
},
|
||||
},
|
||||
AuthInfos: map[string]*clientcmdapi.AuthInfo{
|
||||
"syndicate": {
|
||||
Token: "badge",
|
||||
},
|
||||
},
|
||||
Contexts: map[string]*clientcmdapi.Context{
|
||||
"syndicate": {
|
||||
Cluster: "syndicate",
|
||||
AuthInfo: "syndicate",
|
||||
},
|
||||
},
|
||||
CurrentContext: "syndicate",
|
||||
},
|
||||
{
|
||||
Clusters: map[string]*clientcmdapi.Cluster{
|
||||
"ally": {
|
||||
Server: "ally256.example.com:80",
|
||||
},
|
||||
},
|
||||
AuthInfos: map[string]*clientcmdapi.AuthInfo{
|
||||
"ally": {
|
||||
Token: "souvenir",
|
||||
},
|
||||
},
|
||||
Contexts: map[string]*clientcmdapi.Context{
|
||||
"ally": {
|
||||
Cluster: "ally",
|
||||
AuthInfo: "ally",
|
||||
},
|
||||
},
|
||||
CurrentContext: "ally",
|
||||
},
|
||||
{
|
||||
Clusters: map[string]*clientcmdapi.Cluster{
|
||||
"ally": {
|
||||
Server: "https://ally64.example.com",
|
||||
},
|
||||
"confederate": {
|
||||
Server: "10.8.8.8",
|
||||
},
|
||||
},
|
||||
AuthInfos: map[string]*clientcmdapi.AuthInfo{
|
||||
"ally": {
|
||||
Token: "souvenir",
|
||||
},
|
||||
"confederate": {
|
||||
Token: "totem",
|
||||
},
|
||||
},
|
||||
Contexts: map[string]*clientcmdapi.Context{
|
||||
"ally": {
|
||||
Cluster: "ally",
|
||||
AuthInfo: "ally",
|
||||
},
|
||||
"confederate": {
|
||||
Cluster: "confederate",
|
||||
AuthInfo: "confederate",
|
||||
},
|
||||
},
|
||||
CurrentContext: "confederate",
|
||||
},
|
||||
}
|
||||
kubefiles := []string{}
|
||||
for _, cfg := range kubeconfigs {
|
||||
fakeKubeFile, _ := ioutil.TempFile("", "")
|
||||
err := clientcmd.WriteToFile(cfg, fakeKubeFile.Name())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
kubefiles = append(kubefiles, fakeKubeFile.Name())
|
||||
}
|
||||
return kubefiles, nil
|
||||
}
|
||||
|
||||
func RemoveFakeKubeconfigFiles(kubefiles []string) {
|
||||
for _, file := range kubefiles {
|
||||
os.Remove(file)
|
||||
}
|
||||
}
|
||||
|
||||
func DefaultHeader() http.Header {
|
||||
header := http.Header{}
|
||||
header.Set("Content-Type", runtime.ContentTypeJSON)
|
||||
return header
|
||||
}
|
||||
|
||||
func ObjBody(codec runtime.Codec, obj runtime.Object) io.ReadCloser {
|
||||
return ioutil.NopCloser(bytes.NewReader([]byte(runtime.EncodeOrDie(codec, obj))))
|
||||
}
|
||||
|
||||
func DefaultClientConfig() *restclient.Config {
|
||||
return &restclient.Config{
|
||||
APIPath: "/api",
|
||||
ContentConfig: restclient.ContentConfig{
|
||||
NegotiatedSerializer: api.Codecs,
|
||||
ContentType: runtime.ContentTypeJSON,
|
||||
GroupVersion: &api.Registry.GroupOrDie(api.GroupName).GroupVersion,
|
||||
},
|
||||
}
|
||||
}
|
152
vendor/k8s.io/kubernetes/federation/pkg/kubefed/unjoin.go
generated
vendored
Normal file
152
vendor/k8s.io/kubernetes/federation/pkg/kubefed/unjoin.go
generated
vendored
Normal file
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
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 kubefed
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
federationapi "k8s.io/kubernetes/federation/apis/federation"
|
||||
"k8s.io/kubernetes/federation/pkg/kubefed/util"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
unjoin_long = templates.LongDesc(`
|
||||
Unjoin removes a cluster from a federation.
|
||||
|
||||
Current context is assumed to be a federation endpoint.
|
||||
Please use the --context flag otherwise.`)
|
||||
unjoin_example = templates.Examples(`
|
||||
# Unjoin removes the specified cluster from a federation.
|
||||
# Federation control plane's host cluster context name
|
||||
# must be specified via the --host-cluster-context flag
|
||||
# to properly cleanup the credentials.
|
||||
kubectl unjoin foo --host-cluster-context=bar`)
|
||||
)
|
||||
|
||||
// NewCmdUnjoin defines the `unjoin` command that removes a cluster
|
||||
// from a federation.
|
||||
func NewCmdUnjoin(f cmdutil.Factory, cmdOut, cmdErr io.Writer, config util.AdminConfig) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "unjoin CLUSTER_NAME --host-cluster-context=HOST_CONTEXT",
|
||||
Short: "Unjoins a cluster from a federation",
|
||||
Long: unjoin_long,
|
||||
Example: unjoin_example,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := unjoinFederation(f, cmdOut, cmdErr, config, cmd, args)
|
||||
cmdutil.CheckErr(err)
|
||||
},
|
||||
}
|
||||
|
||||
util.AddSubcommandFlags(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// popCluster fetches the cluster object with the given name, deletes
|
||||
// it and returns the deleted cluster object.
|
||||
func popCluster(f cmdutil.Factory, name string) (*federationapi.Cluster, error) {
|
||||
// Boilerplate to create the secret in the host cluster.
|
||||
mapper, typer := f.Object()
|
||||
gvks, _, err := typer.ObjectKinds(&federationapi.Cluster{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gvk := gvks[0]
|
||||
mapping, err := mapper.RESTMapping(schema.GroupKind{Group: gvk.Group, Kind: gvk.Kind}, gvk.Version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err := f.ClientForMapping(mapping)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rh := resource.NewHelper(client, mapping)
|
||||
obj, err := rh.Get("", name, false)
|
||||
|
||||
if isNotFound(err) {
|
||||
// Cluster isn't registered, there isn't anything to be done here.
|
||||
return nil, nil
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cluster, ok := obj.(*federationapi.Cluster)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected object type: expected \"federation/v1beta1.Cluster\", got %T: obj: %#v", obj, obj)
|
||||
}
|
||||
|
||||
// Remove the cluster resource in the federation API server by
|
||||
// calling rh.Delete()
|
||||
return cluster, rh.Delete("", name)
|
||||
}
|
||||
|
||||
// deleteSecret deletes the secret with the given name from the host
|
||||
// cluster.
|
||||
func deleteSecret(hostFactory cmdutil.Factory, name, namespace string) error {
|
||||
clientset, err := hostFactory.ClientSet()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return clientset.Core().Secrets(namespace).Delete(name, &api.DeleteOptions{})
|
||||
}
|
||||
|
||||
// isNotFound checks if the given error is a NotFound status error.
|
||||
func isNotFound(err error) bool {
|
||||
statusErr := err
|
||||
if urlErr, ok := err.(*url.Error); ok {
|
||||
statusErr = urlErr.Err
|
||||
}
|
||||
return errors.IsNotFound(statusErr)
|
||||
}
|
226
vendor/k8s.io/kubernetes/federation/pkg/kubefed/unjoin_test.go
generated
vendored
Normal file
226
vendor/k8s.io/kubernetes/federation/pkg/kubefed/unjoin_test.go
generated
vendored
Normal file
|
@ -0,0 +1,226 @@
|
|||
/*
|
||||
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 kubefed
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
federationapi "k8s.io/kubernetes/federation/apis/federation"
|
||||
kubefedtesting "k8s.io/kubernetes/federation/pkg/kubefed/testing"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
"k8s.io/kubernetes/pkg/client/restclient/fake"
|
||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
)
|
||||
|
||||
func TestUnjoinFederation(t *testing.T) {
|
||||
cmdErrMsg := ""
|
||||
cmdutil.BehaviorOnFatal(func(str string, code int) {
|
||||
cmdErrMsg = str
|
||||
})
|
||||
|
||||
fakeKubeFiles, err := kubefedtesting.FakeKubeconfigFiles()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
defer kubefedtesting.RemoveFakeKubeconfigFiles(fakeKubeFiles)
|
||||
|
||||
testCases := []struct {
|
||||
cluster string
|
||||
wantCluster string
|
||||
wantSecret string
|
||||
kubeconfigGlobal string
|
||||
kubeconfigExplicit string
|
||||
expectedServer string
|
||||
expectedErr string
|
||||
}{
|
||||
// Tests that the contexts and credentials are read from the
|
||||
// global, default kubeconfig and the correct cluster resource
|
||||
// is deregisterd.
|
||||
{
|
||||
cluster: "syndicate",
|
||||
wantCluster: "syndicate",
|
||||
wantSecret: "",
|
||||
kubeconfigGlobal: fakeKubeFiles[0],
|
||||
kubeconfigExplicit: "",
|
||||
expectedServer: "https://10.20.30.40",
|
||||
expectedErr: "",
|
||||
},
|
||||
// Tests that the contexts and credentials are read from the
|
||||
// explicit kubeconfig file specified and the correct cluster
|
||||
// resource is deregisterd. kubeconfig contains a single
|
||||
// cluster and context.
|
||||
{
|
||||
cluster: "ally",
|
||||
wantCluster: "ally",
|
||||
wantSecret: "",
|
||||
kubeconfigGlobal: fakeKubeFiles[0],
|
||||
kubeconfigExplicit: fakeKubeFiles[1],
|
||||
expectedServer: "http://ally256.example.com:80",
|
||||
expectedErr: "",
|
||||
},
|
||||
// Tests that the contexts and credentials are read from the
|
||||
// explicit kubeconfig file specified and the correct cluster
|
||||
// resource is deregisterd. kubeconfig consists of multiple
|
||||
// clusters and contexts.
|
||||
{
|
||||
cluster: "confederate",
|
||||
wantCluster: "confederate",
|
||||
wantSecret: "",
|
||||
kubeconfigGlobal: fakeKubeFiles[1],
|
||||
kubeconfigExplicit: fakeKubeFiles[2],
|
||||
expectedServer: "https://10.8.8.8",
|
||||
expectedErr: "",
|
||||
},
|
||||
// Negative test to ensure that we get the right warning
|
||||
// when the specified cluster to deregister is not found.
|
||||
{
|
||||
cluster: "noexist",
|
||||
wantCluster: "affiliate",
|
||||
wantSecret: "",
|
||||
kubeconfigGlobal: fakeKubeFiles[0],
|
||||
kubeconfigExplicit: "",
|
||||
expectedServer: "https://10.20.30.40",
|
||||
expectedErr: fmt.Sprintf("WARNING: cluster %q not found in federation, so its credentials' secret couldn't be deleted", "affiliate"),
|
||||
},
|
||||
// Negative test to ensure that we get the right warning
|
||||
// when the specified cluster's credentials secret is not
|
||||
// found.
|
||||
{
|
||||
cluster: "affiliate",
|
||||
wantCluster: "affiliate",
|
||||
wantSecret: "noexist",
|
||||
kubeconfigGlobal: fakeKubeFiles[0],
|
||||
kubeconfigExplicit: "",
|
||||
expectedServer: "https://10.20.30.40",
|
||||
expectedErr: fmt.Sprintf("WARNING: secret %q not found in the host cluster, so it couldn't be deleted", "noexist"),
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
cmdErrMsg = ""
|
||||
f := testUnjoinFederationFactory(tc.cluster, tc.expectedServer, tc.wantSecret)
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
hostFactory := fakeUnjoinHostFactory(tc.cluster)
|
||||
adminConfig, err := kubefedtesting.NewFakeAdminConfig(hostFactory, tc.kubeconfigGlobal)
|
||||
if err != nil {
|
||||
t.Fatalf("[%d] unexpected error: %v", i, err)
|
||||
}
|
||||
|
||||
cmd := NewCmdUnjoin(f, buf, errBuf, adminConfig)
|
||||
|
||||
cmd.Flags().Set("kubeconfig", tc.kubeconfigExplicit)
|
||||
cmd.Flags().Set("host", "substrate")
|
||||
cmd.Run(cmd, []string{tc.wantCluster})
|
||||
|
||||
if tc.expectedErr == "" {
|
||||
// uses the name from the cluster, not the response
|
||||
// Actual data passed are tested in the fake secret and cluster
|
||||
// REST clients.
|
||||
if msg := buf.String(); msg != fmt.Sprintf("Successfully removed cluster %q from federation\n", tc.cluster) {
|
||||
t.Errorf("[%d] unexpected output: %s", i, msg)
|
||||
if cmdErrMsg != "" {
|
||||
t.Errorf("[%d] unexpected error message: %s", i, cmdErrMsg)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if errMsg := errBuf.String(); errMsg != tc.expectedErr {
|
||||
t.Errorf("[%d] expected warning: %s, got: %s, output: %s", i, tc.expectedErr, errMsg, buf.String())
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testUnjoinFederationFactory(name, server, secret string) cmdutil.Factory {
|
||||
urlPrefix := "/clusters/"
|
||||
|
||||
cluster := fakeCluster(name, name, server)
|
||||
if secret != "" {
|
||||
cluster.Spec.SecretRef.Name = secret
|
||||
}
|
||||
|
||||
f, tf, _, _ := cmdtesting.NewAPIFactory()
|
||||
codec := testapi.Federation.Codec()
|
||||
tf.ClientConfig = kubefedtesting.DefaultClientConfig()
|
||||
ns := testapi.Federation.NegotiatedSerializer()
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
GroupName: "federation",
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
switch p, m := req.URL.Path, req.Method; {
|
||||
case strings.HasPrefix(p, urlPrefix):
|
||||
got := strings.TrimPrefix(p, urlPrefix)
|
||||
if got != name {
|
||||
return nil, errors.NewNotFound(federationapi.Resource("clusters"), got)
|
||||
}
|
||||
|
||||
switch m {
|
||||
case http.MethodGet:
|
||||
return &http.Response{StatusCode: http.StatusOK, Header: kubefedtesting.DefaultHeader(), Body: kubefedtesting.ObjBody(codec, &cluster)}, nil
|
||||
case http.MethodDelete:
|
||||
status := metav1.Status{
|
||||
Status: "Success",
|
||||
}
|
||||
return &http.Response{StatusCode: http.StatusOK, Header: kubefedtesting.DefaultHeader(), Body: kubefedtesting.ObjBody(codec, &status)}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected method: %#v\n%#v", req.URL, req)
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected request: %#v\n%#v", req.URL, req)
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
return f
|
||||
}
|
||||
|
||||
func fakeUnjoinHostFactory(name string) cmdutil.Factory {
|
||||
urlPrefix := "/api/v1/namespaces/federation-system/secrets/"
|
||||
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
||||
ns := dynamic.ContentConfig().NegotiatedSerializer
|
||||
tf.ClientConfig = kubefedtesting.DefaultClientConfig()
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
switch p, m := req.URL.Path, req.Method; {
|
||||
case strings.HasPrefix(p, urlPrefix) && m == http.MethodDelete:
|
||||
got := strings.TrimPrefix(p, urlPrefix)
|
||||
if got != name {
|
||||
return nil, errors.NewNotFound(api.Resource("secrets"), got)
|
||||
}
|
||||
status := metav1.Status{
|
||||
Status: "Success",
|
||||
}
|
||||
return &http.Response{StatusCode: http.StatusOK, Header: kubefedtesting.DefaultHeader(), Body: kubefedtesting.ObjBody(codec, &status)}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected request: %#v\n%#v", req.URL, req)
|
||||
}
|
||||
}),
|
||||
}
|
||||
return f
|
||||
}
|
37
vendor/k8s.io/kubernetes/federation/pkg/kubefed/util/BUILD
generated
vendored
Normal file
37
vendor/k8s.io/kubernetes/federation/pkg/kubefed/util/BUILD
generated
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["util.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//federation/client/clientset_generated/federation_clientset:go_default_library",
|
||||
"//pkg/api: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:go_default_library",
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//vendor:github.com/spf13/cobra",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
151
vendor/k8s.io/kubernetes/federation/pkg/kubefed/util/util.go
generated
vendored
Normal file
151
vendor/k8s.io/kubernetes/federation/pkg/kubefed/util/util.go
generated
vendored
Normal file
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
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 util
|
||||
|
||||
import (
|
||||
fedclient "k8s.io/kubernetes/federation/client/clientset_generated/federation_clientset"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
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"
|
||||
kubectlcmd "k8s.io/kubernetes/pkg/kubectl/cmd"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const (
|
||||
// KubeconfigSecretDataKey is the key name used in the secret to
|
||||
// stores a cluster's credentials.
|
||||
KubeconfigSecretDataKey = "kubeconfig"
|
||||
|
||||
// DefaultFederationSystemNamespace is the namespace in which
|
||||
// federation system components are hosted.
|
||||
DefaultFederationSystemNamespace = "federation-system"
|
||||
)
|
||||
|
||||
// AdminConfig provides a filesystem based kubeconfig (via
|
||||
// `PathOptions()`) and a mechanism to talk to the federation
|
||||
// host cluster and the federation control plane api server.
|
||||
type AdminConfig interface {
|
||||
// PathOptions provides filesystem based kubeconfig access.
|
||||
PathOptions() *clientcmd.PathOptions
|
||||
// FedClientSet provides a federation API compliant clientset
|
||||
// to communicate with the federation control plane api server
|
||||
FederationClientset(context, kubeconfigPath string) (*fedclient.Clientset, error)
|
||||
// HostFactory provides a mechanism to communicate with the
|
||||
// cluster where federation control plane is hosted.
|
||||
HostFactory(hostcontext, kubeconfigPath string) cmdutil.Factory
|
||||
}
|
||||
|
||||
// adminConfig implements the AdminConfig interface.
|
||||
type adminConfig struct {
|
||||
pathOptions *clientcmd.PathOptions
|
||||
}
|
||||
|
||||
// NewAdminConfig creates an admin config for `kubefed` commands.
|
||||
func NewAdminConfig(pathOptions *clientcmd.PathOptions) AdminConfig {
|
||||
return &adminConfig{
|
||||
pathOptions: pathOptions,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *adminConfig) PathOptions() *clientcmd.PathOptions {
|
||||
return a.pathOptions
|
||||
}
|
||||
|
||||
func (a *adminConfig) FederationClientset(context, kubeconfigPath string) (*fedclient.Clientset, error) {
|
||||
fedConfig := a.getClientConfig(context, kubeconfigPath)
|
||||
fedClientConfig, err := fedConfig.ClientConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return fedclient.NewForConfigOrDie(fedClientConfig), nil
|
||||
}
|
||||
|
||||
func (a *adminConfig) HostFactory(hostcontext, kubeconfigPath string) cmdutil.Factory {
|
||||
hostClientConfig := a.getClientConfig(hostcontext, kubeconfigPath)
|
||||
return cmdutil.NewFactory(hostClientConfig)
|
||||
}
|
||||
|
||||
func (a *adminConfig) getClientConfig(context, kubeconfigPath string) clientcmd.ClientConfig {
|
||||
loadingRules := *a.pathOptions.LoadingRules
|
||||
loadingRules.Precedence = a.pathOptions.GetLoadingPrecedence()
|
||||
loadingRules.ExplicitPath = kubeconfigPath
|
||||
overrides := &clientcmd.ConfigOverrides{
|
||||
CurrentContext: context,
|
||||
}
|
||||
|
||||
return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(&loadingRules, overrides)
|
||||
}
|
||||
|
||||
// SubcommandFlags holds the flags required by the subcommands of
|
||||
// `kubefed`.
|
||||
type SubcommandFlags struct {
|
||||
Name string
|
||||
Host string
|
||||
FederationSystemNamespace string
|
||||
Kubeconfig string
|
||||
}
|
||||
|
||||
// AddSubcommandFlags adds the definition for `kubefed` subcommand
|
||||
// flags.
|
||||
func AddSubcommandFlags(cmd *cobra.Command) {
|
||||
cmd.Flags().String("kubeconfig", "", "Path to the kubeconfig file to use for CLI requests.")
|
||||
cmd.Flags().String("host-cluster-context", "", "Host cluster context")
|
||||
cmd.Flags().String("federation-system-namespace", DefaultFederationSystemNamespace, "Namespace in the host cluster where the federation system components are installed")
|
||||
}
|
||||
|
||||
// GetSubcommandFlags retrieves the command line flag values for the
|
||||
// `kubefed` subcommands.
|
||||
func GetSubcommandFlags(cmd *cobra.Command, args []string) (*SubcommandFlags, error) {
|
||||
name, err := kubectlcmd.NameFromCommandArgs(cmd, args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &SubcommandFlags{
|
||||
Name: name,
|
||||
Host: cmdutil.GetFlagString(cmd, "host-cluster-context"),
|
||||
FederationSystemNamespace: cmdutil.GetFlagString(cmd, "federation-system-namespace"),
|
||||
Kubeconfig: cmdutil.GetFlagString(cmd, "kubeconfig"),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func CreateKubeconfigSecret(clientset *client.Clientset, kubeconfig *clientcmdapi.Config, namespace, name string, dryRun bool) (*api.Secret, error) {
|
||||
configBytes, err := clientcmd.Write(*kubeconfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Build the secret object with the minified and flattened
|
||||
// kubeconfig content.
|
||||
secret := &api.Secret{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
KubeconfigSecretDataKey: configBytes,
|
||||
},
|
||||
}
|
||||
|
||||
if !dryRun {
|
||||
return clientset.Core().Secrets(namespace).Create(secret)
|
||||
}
|
||||
return secret, nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue