diff --git a/.gitignore b/.gitignore index 550e1f965e3a..9d2a74ed9d4d 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,6 @@ bazel-cluster-api bazel-genfiles bazel-out bazel-testlogs + +# kubeconfigs +minikube.kubeconfig \ No newline at end of file diff --git a/cmd/clusterctl/clusterdeployer/bootstrap/minikube/minikube.go b/cmd/clusterctl/clusterdeployer/bootstrap/minikube/minikube.go index 29c039c9f0f5..e5ae03ca8ca1 100644 --- a/cmd/clusterctl/clusterdeployer/bootstrap/minikube/minikube.go +++ b/cmd/clusterctl/clusterdeployer/bootstrap/minikube/minikube.go @@ -18,11 +18,12 @@ package minikube import ( "fmt" - "github.com/golang/glog" "io/ioutil" "os" "os/exec" "strings" + + "github.com/golang/glog" ) type Minikube struct { @@ -37,11 +38,18 @@ func New() *Minikube { } func WithOptions(options []string) *Minikube { - return &Minikube{ - minikubeExec: minikubeExec, - options: options, + return WithOptionsAndKubeConfigPath(options, "") +} + +func WithOptionsAndKubeConfigPath(options []string, kubeconfigpath string) *Minikube { + if kubeconfigpath == "" { // Arbitrary file name. Can potentially be randomly generated. - kubeconfigpath: "minikube.kubeconfig", + kubeconfigpath = "minikube.kubeconfig" + } + return &Minikube{ + minikubeExec: minikubeExec, + options: options, + kubeconfigpath: kubeconfigpath, } } diff --git a/cmd/clusterctl/clusterdeployer/bootstrap/provisioner.go b/cmd/clusterctl/clusterdeployer/bootstrap/provisioner.go new file mode 100644 index 000000000000..03865ebd789e --- /dev/null +++ b/cmd/clusterctl/clusterdeployer/bootstrap/provisioner.go @@ -0,0 +1,24 @@ +/* +Copyright 2018 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 bootstrap + +// Can provision a kubernetes cluster +type ClusterProvisioner interface { + Create() error + Delete() error + GetKubeconfig() (string, error) +} diff --git a/cmd/clusterctl/clusterdeployer/clusterdeployer.go b/cmd/clusterctl/clusterdeployer/clusterdeployer.go index f4cd4c3df590..d9aff152a0ed 100644 --- a/cmd/clusterctl/clusterdeployer/clusterdeployer.go +++ b/cmd/clusterctl/clusterdeployer/clusterdeployer.go @@ -23,12 +23,15 @@ import ( "strings" "time" + "sigs.k8s.io/cluster-api/cmd/clusterctl/phases" + + "github.com/golang/glog" "k8s.io/client-go/kubernetes" + + "sigs.k8s.io/cluster-api/cmd/clusterctl/clusterdeployer/bootstrap" "sigs.k8s.io/cluster-api/cmd/clusterctl/clusterdeployer/clusterclient" clusterv1 "sigs.k8s.io/cluster-api/pkg/apis/cluster/v1alpha1" "sigs.k8s.io/cluster-api/pkg/util" - - "github.com/golang/glog" ) // Deprecated interface for Provider specific logic. Please do not extend or add. This interface should be removed @@ -40,13 +43,6 @@ type ProviderDeployer interface { GetKubeConfig(cluster *clusterv1.Cluster, master *clusterv1.Machine) (string, error) } -// Can provision a kubernetes cluster -type ClusterProvisioner interface { - Create() error - Delete() error - GetKubeconfig() (string, error) -} - type ProviderComponentsStore interface { Save(providerComponents string) error Load() (string, error) @@ -57,7 +53,7 @@ type ProviderComponentsStoreFactory interface { } type ClusterDeployer struct { - bootstrapProvisioner ClusterProvisioner + bootstrapProvisioner bootstrap.ClusterProvisioner clientFactory clusterclient.Factory providerComponents string addonComponents string @@ -65,7 +61,7 @@ type ClusterDeployer struct { } func New( - bootstrapProvisioner ClusterProvisioner, + bootstrapProvisioner bootstrap.ClusterProvisioner, clientFactory clusterclient.Factory, providerComponents string, addonComponents string, @@ -91,8 +87,7 @@ func (d *ClusterDeployer) Create(cluster *clusterv1.Cluster, machines []*cluster return fmt.Errorf("unable to separate master machines from node machines: %v", err) } - glog.Info("Creating bootstrap cluster") - bootstrapClient, cleanupBootstrapCluster, err := d.createBootstrapCluster() + bootstrapClient, cleanupBootstrapCluster, err := phases.CreateBootstrapCluster(d.bootstrapProvisioner, d.cleanupBootstrapCluster, d.clientFactory) defer cleanupBootstrapCluster() if err != nil { return fmt.Errorf("could not create bootstrap cluster: %v", err) @@ -179,7 +174,7 @@ func (d *ClusterDeployer) Create(cluster *clusterv1.Cluster, machines []*cluster func (d *ClusterDeployer) Delete(targetClient clusterclient.Client, namespace string) error { glog.Info("Creating bootstrap cluster") - bootstrapClient, cleanupBootstrapCluster, err := d.createBootstrapCluster() + bootstrapClient, cleanupBootstrapCluster, err := phases.CreateBootstrapCluster(d.bootstrapProvisioner, d.cleanupBootstrapCluster, d.clientFactory) defer cleanupBootstrapCluster() if err != nil { return fmt.Errorf("could not create bootstrap cluster: %v", err) @@ -212,31 +207,6 @@ func (d *ClusterDeployer) Delete(targetClient clusterclient.Client, namespace st return nil } -func (d *ClusterDeployer) createBootstrapCluster() (clusterclient.Client, func(), error) { - cleanupFn := func() {} - if err := d.bootstrapProvisioner.Create(); err != nil { - return nil, cleanupFn, fmt.Errorf("could not create bootstrap control plane: %v", err) - } - - if d.cleanupBootstrapCluster { - cleanupFn = func() { - glog.Info("Cleaning up bootstrap cluster.") - d.bootstrapProvisioner.Delete() - } - } - - bootstrapKubeconfig, err := d.bootstrapProvisioner.GetKubeconfig() - if err != nil { - return nil, cleanupFn, fmt.Errorf("unable to get bootstrap cluster kubeconfig: %v", err) - } - bootstrapClient, err := d.clientFactory.NewClientFromKubeconfig(bootstrapKubeconfig) - if err != nil { - return nil, cleanupFn, fmt.Errorf("unable to create bootstrap client: %v", err) - } - - return bootstrapClient, cleanupFn, nil -} - func (d *ClusterDeployer) createTargetClusterClient(bootstrapClient clusterclient.Client, provider ProviderDeployer, kubeconfigOutput string, clusterName, namespace string) (clusterclient.Client, error) { cluster, master, _, err := getClusterAPIObject(bootstrapClient, clusterName, namespace) if err != nil { diff --git a/cmd/clusterctl/cmd/alpha.go b/cmd/clusterctl/cmd/alpha.go new file mode 100644 index 000000000000..128c6c92256f --- /dev/null +++ b/cmd/clusterctl/cmd/alpha.go @@ -0,0 +1,31 @@ +/* +Copyright 2018 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 cmd + +import ( + "github.com/spf13/cobra" +) + +var alphaCmd = &cobra.Command{ + Use: "alpha", + Short: "Alpha/Experimental features", + Long: `Alpha/Experimental features`, +} + +func init() { + RootCmd.AddCommand(alphaCmd) +} diff --git a/cmd/clusterctl/cmd/alpha_phase_create_bootstrap_cluster.go b/cmd/clusterctl/cmd/alpha_phase_create_bootstrap_cluster.go new file mode 100644 index 000000000000..c85e945fb63c --- /dev/null +++ b/cmd/clusterctl/cmd/alpha_phase_create_bootstrap_cluster.go @@ -0,0 +1,72 @@ +/* +Copyright 2018 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 cmd + +import ( + "fmt" + + "sigs.k8s.io/cluster-api/cmd/clusterctl/phases" + + "github.com/golang/glog" + "github.com/spf13/cobra" + "sigs.k8s.io/cluster-api/cmd/clusterctl/clusterdeployer/bootstrap/minikube" + "sigs.k8s.io/cluster-api/cmd/clusterctl/clusterdeployer/clusterclient" +) + +type AlphaPhaseCreateBootstrapClusterOptions struct { + MiniKube []string + VmDriver string + KubeconfigOutput string +} + +var pcbco = &AlphaPhaseCreateBootstrapClusterOptions{} + +var alphaPhaseCreateBootstrapClusterCmd = &cobra.Command{ + Use: "create-bootstrap-cluster", + Short: "Create a bootstrap cluster", + Long: `Create a bootstrap cluster`, + Run: func(cmd *cobra.Command, args []string) { + if err := RunAlphaPhaseCreateBootstrapCluster(pcbco); err != nil { + glog.Exit(err) + } + }, +} + +func RunAlphaPhaseCreateBootstrapCluster(pcbco *AlphaPhaseCreateBootstrapClusterOptions) error { + if pcbco.VmDriver != "" { + pcbco.MiniKube = append(pcbco.MiniKube, fmt.Sprintf("vm-driver=%s", pcbco.VmDriver)) + } + + bootstrapProvider := minikube.WithOptionsAndKubeConfigPath(pcbco.MiniKube, pcbco.KubeconfigOutput) + + _, _, err := phases.CreateBootstrapCluster(bootstrapProvider, false, clusterclient.NewFactory()) + if err != nil { + return fmt.Errorf("failed to create bootstrap cluster: %v", err) + } + + glog.Infof("Created bootstrap cluster, path to kubeconfig: %q", pcbco.KubeconfigOutput) + return nil +} + +func init() { + // Optional flags + alphaPhaseCreateBootstrapClusterCmd.Flags().StringSliceVarP(&pcbco.MiniKube, "minikube", "", []string{}, "Minikube options") + alphaPhaseCreateBootstrapClusterCmd.Flags().StringVarP(&pcbco.VmDriver, "vm-driver", "", "", "Which vm driver to use for minikube") + alphaPhaseCreateBootstrapClusterCmd.Flags().StringVarP(&pcbco.KubeconfigOutput, "kubeconfig-out", "", "minikube.kubeconfig", "Where to output the kubeconfig for the bootstrap cluster") + + alphaPhasesCmd.AddCommand(alphaPhaseCreateBootstrapClusterCmd) +} diff --git a/cmd/clusterctl/cmd/alpha_phases.go b/cmd/clusterctl/cmd/alpha_phases.go new file mode 100644 index 000000000000..2506fbdebcdc --- /dev/null +++ b/cmd/clusterctl/cmd/alpha_phases.go @@ -0,0 +1,31 @@ +/* +Copyright 2018 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 cmd + +import ( + "github.com/spf13/cobra" +) + +var alphaPhasesCmd = &cobra.Command{ + Use: "phases", + Short: "Run an individual phase", + Long: `Run an individual phase`, +} + +func init() { + alphaCmd.AddCommand(alphaPhasesCmd) +} diff --git a/cmd/clusterctl/cmd/create_cluster.go b/cmd/clusterctl/cmd/create_cluster.go index aced2814e8af..d0610100c655 100644 --- a/cmd/clusterctl/cmd/create_cluster.go +++ b/cmd/clusterctl/cmd/create_cluster.go @@ -24,6 +24,7 @@ import ( "github.com/golang/glog" "github.com/spf13/cobra" "sigs.k8s.io/cluster-api/cmd/clusterctl/clusterdeployer" + "sigs.k8s.io/cluster-api/cmd/clusterctl/clusterdeployer/bootstrap" "sigs.k8s.io/cluster-api/cmd/clusterctl/clusterdeployer/bootstrap/existing" "sigs.k8s.io/cluster-api/cmd/clusterctl/clusterdeployer/bootstrap/minikube" "sigs.k8s.io/cluster-api/cmd/clusterctl/clusterdeployer/clusterclient" @@ -77,7 +78,7 @@ func RunCreate(co *CreateOptions) error { return err } - var bootstrapProvider clusterdeployer.ClusterProvisioner + var bootstrapProvider bootstrap.ClusterProvisioner if co.ExistingClusterKubeconfigPath != "" { bootstrapProvider, err = existing.NewExistingCluster(co.ExistingClusterKubeconfigPath) if err != nil { diff --git a/cmd/clusterctl/phases/createbootstrapcluster.go b/cmd/clusterctl/phases/createbootstrapcluster.go new file mode 100644 index 000000000000..6b89542207c5 --- /dev/null +++ b/cmd/clusterctl/phases/createbootstrapcluster.go @@ -0,0 +1,53 @@ +/* +Copyright 2018 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 phases + +import ( + "fmt" + + "github.com/golang/glog" + + "sigs.k8s.io/cluster-api/cmd/clusterctl/clusterdeployer/bootstrap" + "sigs.k8s.io/cluster-api/cmd/clusterctl/clusterdeployer/clusterclient" +) + +func CreateBootstrapCluster(provisioner bootstrap.ClusterProvisioner, cleanupBootstrapCluster bool, clientFactory clusterclient.Factory) (clusterclient.Client, func(), error) { + glog.Info("Creating bootstrap cluster") + + cleanupFn := func() {} + if err := provisioner.Create(); err != nil { + return nil, cleanupFn, fmt.Errorf("could not create bootstrap control plane: %v", err) + } + + if cleanupBootstrapCluster { + cleanupFn = func() { + glog.Info("Cleaning up bootstrap cluster.") + provisioner.Delete() + } + } + + bootstrapKubeconfig, err := provisioner.GetKubeconfig() + if err != nil { + return nil, cleanupFn, fmt.Errorf("unable to get bootstrap cluster kubeconfig: %v", err) + } + bootstrapClient, err := clientFactory.NewClientFromKubeconfig(bootstrapKubeconfig) + if err != nil { + return nil, cleanupFn, fmt.Errorf("unable to create bootstrap client: %v", err) + } + + return bootstrapClient, cleanupFn, nil +} diff --git a/cmd/clusterctl/testdata/no-args-invalid-flag.golden b/cmd/clusterctl/testdata/no-args-invalid-flag.golden index c39d44869e0b..790cb815864e 100644 --- a/cmd/clusterctl/testdata/no-args-invalid-flag.golden +++ b/cmd/clusterctl/testdata/no-args-invalid-flag.golden @@ -4,6 +4,7 @@ Usage: clusterctl [command] Available Commands: + alpha Alpha/Experimental features create Create a cluster API resource delete Delete a cluster API resource help Help about any command diff --git a/cmd/clusterctl/testdata/no-args.golden b/cmd/clusterctl/testdata/no-args.golden index 112ceec72860..7f7462bb8474 100644 --- a/cmd/clusterctl/testdata/no-args.golden +++ b/cmd/clusterctl/testdata/no-args.golden @@ -5,6 +5,7 @@ Usage: clusterctl [command] Available Commands: + alpha Alpha/Experimental features create Create a cluster API resource delete Delete a cluster API resource help Help about any command