Skip to content

Commit

Permalink
Add 'cluster', 'namespace', and 'user' options to delete command. Enh…
Browse files Browse the repository at this point in the history
…ance delete to load provider components from cluster. (#384)
  • Loading branch information
spew authored and k8s-ci-robot committed Jun 25, 2018
1 parent 3d9767c commit 3784fb3
Show file tree
Hide file tree
Showing 10 changed files with 98 additions and 71 deletions.
2 changes: 1 addition & 1 deletion clusterctl/clusterdeployer/clientfactory.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,5 @@ func (f *clientFactory) NewClusterClientFromKubeconfig(kubeconfig string) (Clust
}

func (f *clientFactory) NewCoreClientsetFromKubeconfigFile(kubeconfigPath string) (*kubernetes.Clientset, error) {
return clientcmd.NewCoreClientSetForDefaultSearchPath(kubeconfigPath)
return clientcmd.NewCoreClientSetForDefaultSearchPath(kubeconfigPath, clientcmd.NewConfigOverrides())
}
49 changes: 33 additions & 16 deletions clusterctl/clusterdeployer/clusterclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/golang/glog"
apiv1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
tcmd "k8s.io/client-go/tools/clientcmd"
clusterv1 "sigs.k8s.io/cluster-api/pkg/apis/cluster/v1alpha1"
"sigs.k8s.io/cluster-api/pkg/client/clientset_generated/clientset"
"sigs.k8s.io/cluster-api/pkg/clientcmd"
Expand All @@ -44,9 +45,10 @@ const (
)

type clusterClient struct {
clientSet clientset.Interface
kubeconfigFile string
closeFn func() error
clientSet clientset.Interface
kubeconfigFile string
configOverrides tcmd.ConfigOverrides
closeFn func() error
}

// NewClusterClient creates and returns the address of a clusterClient, the kubeconfig argument is expected to be the string represenattion
Expand All @@ -57,7 +59,7 @@ func NewClusterClient(kubeconfig string) (*clusterClient, error) {
return nil, err
}
defer ifErrRemove(&err, f)
c, err := NewClusterClientFromFile(f)
c, err := NewClusterClientFromDefaultSearchPath(f, clientcmd.NewConfigOverrides())
if err != nil {
return nil, err
}
Expand All @@ -69,17 +71,18 @@ func (c *clusterClient) removeKubeconfigFile() error {
return os.Remove(c.kubeconfigFile)
}

// NewClusterClientFromFile creates and returns the address of a clusterClient, the kubeconfigFile argument is expected to be the path to a
// NewClusterClientFromDefaultSearchPath creates and returns the address of a clusterClient, the kubeconfigFile argument is expected to be the path to a
// valid kubeconfig file.
func NewClusterClientFromFile(kubeconfigFile string) (*clusterClient, error) {
c, err := clientcmd.NewClusterApiClientForDefaultSearchPath(kubeconfigFile)
func NewClusterClientFromDefaultSearchPath(kubeconfigFile string, overrides tcmd.ConfigOverrides) (*clusterClient, error) {
c, err := clientcmd.NewClusterApiClientForDefaultSearchPath(kubeconfigFile, overrides)
if err != nil {
return nil, err
}

return &clusterClient{
kubeconfigFile: kubeconfigFile,
clientSet: c,
kubeconfigFile: kubeconfigFile,
clientSet: c,
configOverrides: overrides,
}, nil
}

Expand Down Expand Up @@ -169,16 +172,30 @@ func (c *clusterClient) WaitForClusterV1alpha1Ready() error {
}

func (c *clusterClient) kubectlApply(manifest string) error {
r := strings.NewReader(manifest)
cmd := exec.Command("kubectl", "apply", "--kubeconfig", c.kubeconfigFile, "-f", "-")
cmd.Stdin = r

cmd := exec.Command("kubectl", c.buildKubectlArgs("apply")...)
cmd.Stdin = strings.NewReader(manifest)
out, err := cmd.CombinedOutput()
if err == nil {
return nil
} else {
if err != nil {
return fmt.Errorf("couldn't kubectl apply: %v, output: %s", err, string(out))
}
return nil
}

func (c *clusterClient) buildKubectlArgs(commandName string) []string {
args := []string{commandName}
if c.kubeconfigFile != "" {
args = append(args, "--kubeconfig", c.kubeconfigFile)
}
if c.configOverrides.Context.Cluster != "" {
args = append(args, "--cluster", c.configOverrides.Context.Cluster)
}
if c.configOverrides.Context.Namespace != "" {
args = append(args, "--namespace", c.configOverrides.Context.Namespace)
}
if c.configOverrides.Context.AuthInfo != "" {
args = append(args, "--user", c.configOverrides.Context.AuthInfo)
}
return append(args, "-f", "-")
}

func (c *clusterClient) waitForKubectlApply(manifest string) error {
Expand Down
40 changes: 34 additions & 6 deletions clusterctl/cmd/delete_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,22 @@ limitations under the License.
package cmd

import (
"fmt"

"k8s.io/api/core/v1"
tcmd "k8s.io/client-go/tools/clientcmd"
"sigs.k8s.io/cluster-api/clusterctl/providercomponents"
"sigs.k8s.io/cluster-api/pkg/clientcmd"
"sigs.k8s.io/cluster-api/pkg/errors"

"github.com/golang/glog"
"github.com/spf13/cobra"
"sigs.k8s.io/cluster-api/pkg/errors"
)

type DeleteOptions struct {
ClusterName string
ProviderComponents string
KubeconfigPath string
ProviderComponents string
KubeconfigOverrides tcmd.ConfigOverrides
}

var do = &DeleteOptions{}
Expand All @@ -34,20 +42,40 @@ var deleteClusterCmd = &cobra.Command{
Short: "Delete kubernetes cluster",
Long: `Delete a kubernetes cluster with one command`,
Run: func(cmd *cobra.Command, args []string) {
if do.ClusterName == "" {
exitWithHelp(cmd, "Please provide cluster name.")
}
if err := RunDelete(); err != nil {
glog.Exit(err)
}
},
}

func init() {
deleteClusterCmd.Flags().StringVarP(&do.KubeconfigPath, "kubeconfig", "", "", "Path to the kubeconfig file to use for connecting to the cluster to be deleted, if empty, the default KUBECONFIG load path is used.")
deleteClusterCmd.Flags().StringVarP(&do.ProviderComponents, "provider-components", "p", "", "A yaml file containing cluster api provider controllers and supporting objects, if empty the value is loaded from the cluster's configuration store.")
// BindContextFlags will bind the flags cluster, namespace, and user
tcmd.BindContextFlags(&do.KubeconfigOverrides.Context, deleteClusterCmd.Flags(), tcmd.RecommendedContextOverrideFlags(""))
deleteCmd.AddCommand(deleteClusterCmd)
}

func RunDelete() error {
_, err := loadProviderComponents()
if err != nil {
return err
}
return errors.NotImplementedError
}

func loadProviderComponents() (string, error) {
coreClients, err := clientcmd.NewCoreClientSetForDefaultSearchPath(do.KubeconfigPath, do.KubeconfigOverrides)
if err != nil {
return "", fmt.Errorf("error creating core clients: %v", err)
}
pcStore := providercomponents.Store{
ExplicitPath: do.ProviderComponents,
ConfigMap: coreClients.CoreV1().ConfigMaps(v1.NamespaceDefault),
}
providerComponents, err := pcStore.Load()
if err != nil {
return "", fmt.Errorf("error when loading provider components: %v", err)
}
return providerComponents, nil
}
1 change: 0 additions & 1 deletion clusterctl/main_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ func TestEmptyAndInvalidArgs(t *testing.T) {
{"create cluster with no arguments with invalid flag", []string{"create", "cluster", "--invalid-flag"}, 1, "create-cluster-no-args-invalid-flag.golden"},
{"delete with no arguments", []string{"delete"}, 0, "delete-no-args.golden"},
{"delete with no arguments with invalid flag", []string{"delete", "--invalid-flag"}, 1, "delete-no-args-invalid-flag.golden"},
{"delete cluster with no arguments", []string{"delete", "cluster"}, 1, "delete-cluster-no-args.golden"},
{"delete cluster with no arguments with invalid flag", []string{"delete", "cluster", "--invalid-flag"}, 1, "delete-cluster-no-args-invalid-flag.golden"},
{"validate with no arguments", []string{"validate"}, 0, "validate-no-args.golden"},
{"validate with no arguments with invalid flag", []string{"validate", "--invalid-flag"}, 1, "validate-no-args-invalid-flag.golden"},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ Usage:
clusterctl delete cluster [flags]

Flags:
--cluster string The name of the kubeconfig cluster to use
-h, --help help for cluster
--kubeconfig string Path to the kubeconfig file to use for connecting to the cluster to be deleted, if empty, the default KUBECONFIG load path is used.
-n, --namespace string If present, the namespace scope for this CLI request
-p, --provider-components string A yaml file containing cluster api provider controllers and supporting objects, if empty the value is loaded from the cluster's configuration store.
--user string The name of the kubeconfig user to use

Global Flags:
--alsologtostderr log to standard error as well as files
Expand Down
19 changes: 0 additions & 19 deletions clusterctl/testdata/delete-cluster-no-args.golden

This file was deleted.

6 changes: 1 addition & 5 deletions gcp-deployer/deploy/deploy_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,11 +258,7 @@ func (d *deployer) copyKubeConfig(cluster *clusterv1.Cluster, master *clusterv1.
}

func (d *deployer) initApiClient() error {
c, err := clientcmd.NewClusterApiClientForDefaultSearchPath(d.configPath)
if err != nil {
return err
}
kubernetesClientSet, err := clientcmd.NewCoreClientSetForDefaultSearchPath(d.configPath)
kubernetesClientSet, c, err := clientcmd.NewClientsForDefaultSearchpath(d.configPath, clientcmd.NewConfigOverrides())
if err != nil {
return err
}
Expand Down
44 changes: 23 additions & 21 deletions pkg/clientcmd/configutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,16 @@ import (
"sigs.k8s.io/cluster-api/pkg/client/clientset_generated/clientset"
)

// This is a convienience method to prevent the need of importing both this version of clientcmd and the client-go version
func NewConfigOverrides() clientcmd.ConfigOverrides {
return clientcmd.ConfigOverrides{}
}

// NewCoreClientSetForDefaultSearchPath creates a core kubernetes clientset. If the kubeconfigPath is specified then the configuration is loaded from that path.
// Otherwise the default kubeconfig search path is used.
func NewCoreClientSetForDefaultSearchPath(kubeconfigPath string) (*kubernetes.Clientset, error) {
config, err := newRestConfigForDefaultSearchPath(kubeconfigPath)
// The overrides parameter is used to select a specific context of the config, for example, select the context with a given cluster name or namespace.
func NewCoreClientSetForDefaultSearchPath(kubeconfigPath string, overrides clientcmd.ConfigOverrides) (*kubernetes.Clientset, error) {
config, err := newRestConfigForDefaultSearchPath(kubeconfigPath, overrides)
if err != nil {
return nil, err
}
Expand All @@ -48,8 +54,9 @@ func NewCoreClientSetForKubeconfig(kubeconfig string) (*kubernetes.Clientset, er

// NewClusterApiClientForDefaultSearchPath creates a Cluster API clientset. If the kubeconfigPath is specified then the configuration is loaded from that path.
// Otherwise the default kubeconfig search path is used.
func NewClusterApiClientForDefaultSearchPath(kubeconfigPath string) (*clientset.Clientset, error) {
config, err := newRestConfigForDefaultSearchPath(kubeconfigPath)
// The overrides parameter is used to select a specific context of the config, for example, select the context with a given cluster name or namespace.
func NewClusterApiClientForDefaultSearchPath(kubeconfigPath string, overrides clientcmd.ConfigOverrides) (*clientset.Clientset, error) {
config, err := newRestConfigForDefaultSearchPath(kubeconfigPath, overrides)
if err != nil {
return nil, err
}
Expand All @@ -67,17 +74,9 @@ func NewClusterApiClientForKubeconfig(kubeconfig string) (*clientset.Clientset,

// NewClientsForDefaultSearchpath creates both a core kubernetes clientset and a cluster-api clientset. If the kubeconfigPath
// is specified then the configuration is loaded from that path. Otherwise the default kubeconfig search path is used.
func NewClientsForDefaultSearchpath(kubeconfigPath string) (*kubernetes.Clientset, *clientset.Clientset, error) {
config, err := newRestConfigForDefaultSearchPath(kubeconfigPath)
if err != nil {
return nil, nil, err
}
return newClientsFromRestConfig(config)
}

// NewClientsForKubeconfig creates both a core kubernetes clientset and a cluster-api clientset.
func NewClientsForKubeconfig(kubeconfig string) (*kubernetes.Clientset, *clientset.Clientset, error) {
config, err := newRestConfigForKubeconfig(kubeconfig)
// The overrides parameter is used to select a specific context of the config, for example, select the context with a given cluster name or namespace.
func NewClientsForDefaultSearchpath(kubeconfigPath string, overrides clientcmd.ConfigOverrides) (*kubernetes.Clientset, *clientset.Clientset, error) {
config, err := newRestConfigForDefaultSearchPath(kubeconfigPath, overrides)
if err != nil {
return nil, nil, err
}
Expand All @@ -98,14 +97,17 @@ func newClientsFromRestConfig(config *rest.Config) (*kubernetes.Clientset, *clie
}

// newRestConfig creates a rest.Config for the given apiConfig
func newRestConfig(apiConfig *api.Config) (*rest.Config, error) {
return clientcmd.NewDefaultClientConfig(*apiConfig, &clientcmd.ConfigOverrides{}).ClientConfig()
// The overrides parameter is used to select a specific context of the config, for example, select the context with a given cluster name or namespace.
func newRestConfig(apiConfig *api.Config, overrides clientcmd.ConfigOverrides) (*rest.Config, error) {
return clientcmd.NewDefaultClientConfig(*apiConfig, &overrides).ClientConfig()
}

// newRestConfigForDefaultSearchPath creates a rest.Config by searching for the kubeconfig on the default search path. If an override 'kubeconfigPath' is
// given then that path is used instead of the default path. If no override is given, an attempt is made to load the
// 'in cluster' config. If this fails, then the default search path is used.
func newRestConfigForDefaultSearchPath(kubeconfigPath string) (*rest.Config, error) {
//
// The overrides parameter is used to select a specific context of the config, for example, select the context with a given cluster name or namespace.
func newRestConfigForDefaultSearchPath(kubeconfigPath string, overrides clientcmd.ConfigOverrides) (*rest.Config, error) {
if kubeconfigPath == "" {
config, err := rest.InClusterConfig()
// if there is no err, continue because InClusterConfig is only expected to succeed if running inside of a pod.
Expand All @@ -117,16 +119,16 @@ func newRestConfigForDefaultSearchPath(kubeconfigPath string) (*rest.Config, err
if err != nil {
return nil, err
}
return newRestConfig(apiConfig)
return newRestConfig(apiConfig, overrides)
}

// newRestConfigForKubeconfig creates a rest.Config for a given kubeconfig string.
func newRestConfigForKubeconfig(kubeconfig string) (*rest.Config, error) {
apiConfig, err := newApiConfigForDefaultSearchPath(kubeconfig)
apiConfig, err := newApiConfigForKubeconfig(kubeconfig)
if err != nil {
return nil, err
}
return newRestConfig(apiConfig)
return newRestConfig(apiConfig, clientcmd.ConfigOverrides{})
}

// newApiConfigForDefaultSearchPath creates an api.Config by searching for the kubeconfig on the default search path. If an override 'kubeconfigPath' is
Expand Down
2 changes: 1 addition & 1 deletion tools/repair/util/repair.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func NewRepairer(dryRun bool, configPath string) (*repairer, error) {
configPath = util.GetDefaultKubeConfigPath()
}

c, err := clientcmd.NewClusterApiClientForDefaultSearchPath(configPath)
c, err := clientcmd.NewClusterApiClientForDefaultSearchPath(configPath, clientcmd.NewConfigOverrides())
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion tools/upgrader/util/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func initClient(kubeconfig string) error {
if kubeconfig == "" {
kubeconfig = util.GetDefaultKubeConfigPath()
}
coreClientset, clusterapiClientset, err := clientcmd.NewClientsForDefaultSearchpath(kubeconfig)
coreClientset, clusterapiClientset, err := clientcmd.NewClientsForDefaultSearchpath(kubeconfig, clientcmd.NewConfigOverrides())
if err != nil {
glog.Fatalf("Error creating rest config: %v", err)
return err
Expand Down

0 comments on commit 3784fb3

Please sign in to comment.