Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[Federation][(Un)join-01] Refactor common functions and structs into a util package. #35592

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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 18 additions & 0 deletions federation/cmd/kubefed/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package(default_visibility = ["//visibility:public"])

licenses(["notice"])

load(
"@io_bazel_rules_go//go:def.bzl",
"go_binary",
"go_library",
"go_test",
"cgo_library",
)

go_binary(
name = "kubefed",
srcs = ["kubefed.go"],
tags = ["automanaged"],
deps = ["//federation/cmd/kubefed/app:go_default_library"],
)
24 changes: 24 additions & 0 deletions federation/cmd/kubefed/app/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package(default_visibility = ["//visibility:public"])

licenses(["notice"])

load(
"@io_bazel_rules_go//go:def.bzl",
"go_binary",
"go_library",
"go_test",
"cgo_library",
)

go_library(
name = "go_default_library",
srcs = ["kubefed.go"],
tags = ["automanaged"],
deps = [
"//federation/pkg/kubefed:go_default_library",
"//pkg/client/metrics/prometheus:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/util/logs:go_default_library",
"//pkg/version/prometheus:go_default_library",
],
)
35 changes: 35 additions & 0 deletions federation/cmd/kubefed/app/kubefed.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
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 app

import (
"os"

"k8s.io/kubernetes/federation/pkg/kubefed"
_ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/util/logs"
_ "k8s.io/kubernetes/pkg/version/prometheus" // for version metric registration
)

func Run() error {
logs.InitLogs()
defer logs.FlushLogs()

cmd := kubefed.NewKubeFedCommand(cmdutil.NewFactory(nil), os.Stdin, os.Stdout, os.Stderr)
return cmd.Execute()
}
30 changes: 30 additions & 0 deletions federation/cmd/kubefed/kubefed.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
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 main

import (
"os"

"k8s.io/kubernetes/federation/cmd/kubefed/app"
)

func main() {
if err := app.Run(); err != nil {
os.Exit(1)
}
os.Exit(0)
}
20 changes: 18 additions & 2 deletions federation/pkg/kubefed/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,46 @@ load(

go_library(
name = "go_default_library",
srcs = ["join.go"],
srcs = [
"join.go",
"kubefed.go",
"unjoin.go",
],
tags = ["automanaged"],
deps = [
"//federation/apis/federation:go_default_library",
"//federation/pkg/kubefed/util:go_default_library",
"//pkg/api:go_default_library",
"//pkg/api/errors:go_default_library",
"//pkg/api/unversioned: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/runtime:go_default_library",
"//pkg/util/flag:go_default_library",
"//vendor:github.com/golang/glog",
"//vendor:github.com/spf13/cobra",
],
)

go_test(
name = "go_default_test",
srcs = ["join_test.go"],
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/util:go_default_library",
"//pkg/api:go_default_library",
"//pkg/api/errors:go_default_library",
"//pkg/api/testapi:go_default_library",
"//pkg/api/unversioned:go_default_library",
"//pkg/api/v1:go_default_library",
Expand Down
110 changes: 17 additions & 93 deletions federation/pkg/kubefed/join.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ import (
"io"
"strings"

"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
"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"
Expand All @@ -35,10 +34,6 @@ import (
)

const (
// KubeconfigSecretDataKey is the key name used in the secret to
// stores a cluster's credentials.
KubeconfigSecretDataKey = "kubeconfig"

// defaultClusterCIDR is the default CIDR range accepted by the
// joining API server. See `apis/federation.ClusterSpec` for
// details.
Expand All @@ -56,57 +51,14 @@ var (
# Join a cluster to a federation by specifying the
# cluster context name and the context name of the
# federation control plane's host cluster.
kubectl join foo --host=bar`)
kubectl join foo --host-cluster-context=bar`)
)

// JoinFederationConfig provides a filesystem based kubeconfig (via
// `PathOptions()`) and a mechanism to talk to the federation host
// cluster.
type JoinFederationConfig interface {
// PathOptions provides filesystem based kubeconfig access.
PathOptions() *clientcmd.PathOptions
// HostFactory provides a mechanism to communicate with the
// cluster where federation control plane is hosted.
HostFactory(host, kubeconfigPath string) cmdutil.Factory
}

// joinFederationConfig implements JoinFederationConfig interface.
type joinFederationConfig struct {
pathOptions *clientcmd.PathOptions
}

// Assert that `joinFederationConfig` implements the
// `JoinFederationConfig` interface.
var _ JoinFederationConfig = &joinFederationConfig{}

func NewJoinFederationConfig(pathOptions *clientcmd.PathOptions) JoinFederationConfig {
return &joinFederationConfig{
pathOptions: pathOptions,
}
}

func (j *joinFederationConfig) PathOptions() *clientcmd.PathOptions {
return j.pathOptions
}

func (j *joinFederationConfig) HostFactory(host, kubeconfigPath string) cmdutil.Factory {
loadingRules := *j.pathOptions.LoadingRules
loadingRules.Precedence = j.pathOptions.GetLoadingPrecedence()
loadingRules.ExplicitPath = kubeconfigPath
overrides := &clientcmd.ConfigOverrides{
CurrentContext: host,
}

hostClientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(&loadingRules, overrides)

return cmdutil.NewFactory(hostClientConfig)
}

// NewCmdJoin defines the `join` command that joins a cluster to a
// federation.
func NewCmdJoin(f cmdutil.Factory, cmdOut io.Writer, config JoinFederationConfig) *cobra.Command {
func NewCmdJoin(f cmdutil.Factory, cmdOut io.Writer, config util.AdminConfig) *cobra.Command {
cmd := &cobra.Command{
Use: "join CLUSTER_CONTEXT --host=HOST_CONTEXT",
Use: "join CLUSTER_CONTEXT --host-cluster-context=HOST_CONTEXT",
Short: "Join a cluster to a federation",
Long: join_long,
Example: join_example,
Expand All @@ -120,36 +72,35 @@ func NewCmdJoin(f cmdutil.Factory, cmdOut io.Writer, config JoinFederationConfig
cmdutil.AddValidateFlags(cmd)
cmdutil.AddPrinterFlags(cmd)
cmdutil.AddGeneratorFlags(cmd, cmdutil.ClusterV1Beta1GeneratorName)
addJoinFlags(cmd)
util.AddSubcommandFlags(cmd)
return cmd
}

// joinFederation is the implementation of the `join federation` command.
func joinFederation(f cmdutil.Factory, cmdOut io.Writer, config JoinFederationConfig, cmd *cobra.Command, args []string) error {
name, err := kubectlcmd.NameFromCommandArgs(cmd, args)
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
}
host := cmdutil.GetFlagString(cmd, "host")
hostSystemNamespace := cmdutil.GetFlagString(cmd, "host-system-namespace")
kubeconfig := cmdutil.GetFlagString(cmd, "kubeconfig")
dryRun := cmdutil.GetDryRunFlag(cmd)

glog.V(2).Infof("Args and flags: name %s, host: %s, host-system-namespace: %s, kubeconfig: %s, dry-run: %s", name, host, hostSystemNamespace, kubeconfig, dryRun)
glog.V(2).Infof("Args and flags: name %s, host: %s, host-system-namespace: %s, kubeconfig: %s, dry-run: %s", joinFlags.Name, joinFlags.Host, joinFlags.HostSystemNamespace, joinFlags.Kubeconfig, dryRun)

po := config.PathOptions()
po.LoadingRules.ExplicitPath = kubeconfig
po.LoadingRules.ExplicitPath = joinFlags.Kubeconfig
clientConfig, err := po.GetStartingConfig()
if err != nil {
return err
}
generator, err := clusterGenerator(clientConfig, name)
generator, err := clusterGenerator(clientConfig, joinFlags.Name)
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
Expand All @@ -165,28 +116,21 @@ func joinFederation(f cmdutil.Factory, cmdOut io.Writer, config JoinFederationCo
// 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.
hostFactory := config.HostFactory(host, kubeconfig)
_, err = createSecret(hostFactory, clientConfig, hostSystemNamespace, name, dryRun)
_, err = createSecret(hostFactory, clientConfig, joinFlags.HostSystemNamespace, joinFlags.Name, 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: name,
Name: joinFlags.Name,
StructuredGenerator: generator,
DryRun: dryRun,
OutputFormat: cmdutil.GetFlagString(cmd, "output"),
})
}

func addJoinFlags(cmd *cobra.Command) {
cmd.Flags().String("kubeconfig", "", "Path to the kubeconfig file to use for CLI requests.")
cmd.Flags().String("host", "", "Host cluster context")
cmd.Flags().String("host-system-namespace", "federation-system", "Namespace in the host cluster where the federation system components are installed")
}

// minifyConfig is a wrapper around `clientcmdapi.MinifyConfig()` that
// sets the current context to the given context before calling
// `clientcmdapi.MinifyConfig()`.
Expand Down Expand Up @@ -223,34 +167,14 @@ func createSecret(hostFactory cmdutil.Factory, clientConfig *clientcmdapi.Config
return nil, err
}

configBytes, err := clientcmd.Write(*newClientConfig)
// 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", name, err)
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 {
// Boilerplate to create the secret in the host cluster.
clientset, err := hostFactory.ClientSet()
if err != nil {
glog.V(2).Infof("Failed to retrieve the cluster clientset: %v", err)
return nil, err
}
return clientset.Core().Secrets(namespace).Create(secret)
}
return secret, nil
return util.CreateKubeconfigSecret(clientset, newClientConfig, namespace, name, dryRun)
}

// clusterGenerator extracts the cluster information from the supplied
Expand Down