From 3efe03d91f0044f01b4a82ba6d3656c129275f29 Mon Sep 17 00:00:00 2001 From: Karan Goel Date: Tue, 1 May 2018 10:41:58 -0700 Subject: [PATCH 1/2] Add boilerplate for clusterctl --- clusterctl/.gitignore | 1 + clusterctl/CONTRIBUTING.md | 1 + clusterctl/README.md | 61 +++++++++++++++++++++++++++ clusterctl/cmd/create.go | 71 +++++++++++++++++++++++++++++++ clusterctl/cmd/delete.go | 56 +++++++++++++++++++++++++ clusterctl/cmd/register.go | 57 +++++++++++++++++++++++++ clusterctl/cmd/root.go | 85 ++++++++++++++++++++++++++++++++++++++ clusterctl/main.go | 23 +++++++++++ errors/deployer.go | 23 +++++++++++ 9 files changed, 378 insertions(+) create mode 100644 clusterctl/.gitignore create mode 100644 clusterctl/CONTRIBUTING.md create mode 100644 clusterctl/README.md create mode 100644 clusterctl/cmd/create.go create mode 100644 clusterctl/cmd/delete.go create mode 100644 clusterctl/cmd/register.go create mode 100644 clusterctl/cmd/root.go create mode 100644 clusterctl/main.go create mode 100644 errors/deployer.go diff --git a/clusterctl/.gitignore b/clusterctl/.gitignore new file mode 100644 index 000000000000..85d64d7de71e --- /dev/null +++ b/clusterctl/.gitignore @@ -0,0 +1 @@ +clusterctl \ No newline at end of file diff --git a/clusterctl/CONTRIBUTING.md b/clusterctl/CONTRIBUTING.md new file mode 100644 index 000000000000..33a12a74bf9f --- /dev/null +++ b/clusterctl/CONTRIBUTING.md @@ -0,0 +1 @@ +# Contributing Guidelines \ No newline at end of file diff --git a/clusterctl/README.md b/clusterctl/README.md new file mode 100644 index 000000000000..7c6a3e7a298b --- /dev/null +++ b/clusterctl/README.md @@ -0,0 +1,61 @@ +# clusterctl + +`clusterctl` is the SIG-cluster-lifecycle sponsored tool that implements the Cluster API. + +Read the [experience doc here](https://docs.google.com/document/d/1-sYb3EdkRga49nULH1kSwuQFf1o6GvAw_POrsNo5d8c/edit#). + +## Getting Started + +### Prerequisites + +Follow the steps listed at [CONTRIBUTING.md](https://github.com/kubernetes/kube-deploy/blob/master/cluster-api/clusterctl/CONTRIBUTING.md) to: + +1. Build the `clusterctl` tool +3. Create a `machines.yaml` file configured for your cluster. See the provided template for an example. + +### Limitation + + +### Creating a cluster + +**NOT YET SUPPORTED!** + +In order to create a cluster with the Cluster API, the user will supply these: + +* Cluster which defines the spec common across the entire cluster. +* Machine which defines the spec of a machine. Further abstractions of +MachineSets and MachineClass and MachineDeployments are supported as well. +* Extras (optional) spec extras.yaml file with specs of all controllers +(ConfigMaps) that the cluster needs. This would include the Machine controller, +MachineSet controller, Machine Setup ConfigMap etc. Note that this is not a new API +object. There will be defaults running. This will make the tool easily pluggage +(change the controller spec) instead of changing the tool or mucking with flags. + +1. Create a cluster: `./clusterctl create cluster -c cluster.yaml -m machines.yaml -e extras.yaml` + +### Interacting with your cluster + +Once you have created a cluster, you can interact with the cluster and machine +resources using kubectl: + +``` +$ kubectl get clusters +$ kubectl get machines +$ kubectl get machines -o yaml +``` + +#### Scaling your cluster + +**NOT YET SUPPORTED!** + +#### Upgrading your cluster + +**NOT YET SUPPORTED!** + +#### Node repair + +**NOT YET SUPPORTED!** + +### Deleting a cluster + +**NOT YET SUPPORTED!** diff --git a/clusterctl/cmd/create.go b/clusterctl/cmd/create.go new file mode 100644 index 000000000000..bcc1ee93a8b8 --- /dev/null +++ b/clusterctl/cmd/create.go @@ -0,0 +1,71 @@ +/* +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 ( + "os" + + //"fmt" + "github.com/golang/glog" + "github.com/spf13/cobra" + "sigs.k8s.io/cluster-api/errors" +) + +type CreateOptions struct { + Cluster string + Machine string + Extras string +} + +var co = &CreateOptions{} + +var createCmd = &cobra.Command{ + Use: "create", + Short: "Create kubernetes cluster", + Long: `Create a kubernetes cluster with one command`, + Run: func(cmd *cobra.Command, args []string) { + if co.Cluster == "" { + glog.Error("Please provide yaml file for cluster definition.") + cmd.Help() + os.Exit(1) + } + if co.Machine == "" { + glog.Error("Please provide yaml file for machine definition.") + cmd.Help() + os.Exit(1) + } + if co.Extras == "" { + glog.Error("Please provide a yaml file for extra definitions (controllers, Addons etc).") + cmd.Help() + os.Exit(1) + } + if err := RunCreate(co); err != nil { + glog.Exit(err) + } + }, +} + +func RunCreate(co *CreateOptions) error { + return errors.NotImplementedError +} +func init() { + createCmd.Flags().StringVarP(&co.Cluster, "cluster", "c", "", "cluster yaml file") + createCmd.Flags().StringVarP(&co.Machine, "machines", "m", "", "machine yaml file") + createCmd.Flags().StringVarP(&co.Extras, "extras", "e", "", "extras yaml file") + + RootCmd.AddCommand(createCmd) +} diff --git a/clusterctl/cmd/delete.go b/clusterctl/cmd/delete.go new file mode 100644 index 000000000000..be3fd91f0e43 --- /dev/null +++ b/clusterctl/cmd/delete.go @@ -0,0 +1,56 @@ +/* +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/golang/glog" + "github.com/spf13/cobra" + "os" + "sigs.k8s.io/cluster-api/errors" +) + +type DeleteOptions struct { + ClusterName string +} + +var do = &DeleteOptions{} + +var deleteCmd = &cobra.Command{ + Use: "delete", + Short: "Delete kubernetes cluster", + Long: `Delete a kubernetes cluster with one command`, + Run: func(cmd *cobra.Command, args []string) { + if do.ClusterName == "" { + glog.Error("Please provide cluster name.") + cmd.Help() + os.Exit(1) + } + if err := RunDelete(); err != nil { + glog.Exit(err) + } + }, +} + +func RunDelete() error { + return errors.NotImplementedError +} + +func init() { + deleteCmd.Flags().StringVarP(&do.ClusterName, "cluster-name", "n", "", "cluster name") + + RootCmd.AddCommand(deleteCmd) +} diff --git a/clusterctl/cmd/register.go b/clusterctl/cmd/register.go new file mode 100644 index 000000000000..59c4661b321a --- /dev/null +++ b/clusterctl/cmd/register.go @@ -0,0 +1,57 @@ +/* +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 ( + "os" + + "github.com/golang/glog" + "github.com/spf13/cobra" + "sigs.k8s.io/cluster-api/errors" +) + +type RegisterOptions struct { + RegistryEndpoint string +} + +var ro = &RegisterOptions{} + +var registerCmd = &cobra.Command{ + Use: "register", + Short: "Register a kubernetes cluster with a Cluster Registry", + Long: `Register a kubernetes cluster with a Cluster Registry`, + Run: func(cmd *cobra.Command, args []string) { + if ro.RegistryEndpoint == "" { + glog.Error("Please provide yaml file for cluster definition.") + cmd.Help() + os.Exit(1) + } + if err := RunRegister(ro); err != nil { + glog.Exit(err) + } + }, +} + +func RunRegister(co *RegisterOptions) error { + return errors.NotImplementedError +} + +func init() { + registerCmd.Flags().StringVarP(&ro.RegistryEndpoint, "registry-endpoint", "r", "", "registry endpoint") + + RootCmd.AddCommand(registerCmd) +} diff --git a/clusterctl/cmd/root.go b/clusterctl/cmd/root.go new file mode 100644 index 000000000000..72c6d30ae501 --- /dev/null +++ b/clusterctl/cmd/root.go @@ -0,0 +1,85 @@ +/* +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 ( + "flag" + "io/ioutil" + + "github.com/ghodss/yaml" + "github.com/golang/glog" + "github.com/spf13/cobra" + "k8s.io/apiserver/pkg/util/logs" + clusterv1 "sigs.k8s.io/cluster-api/pkg/apis/cluster/v1alpha1" + "sigs.k8s.io/cluster-api/util" +) + +var RootCmd = &cobra.Command{ + Use: "clusterctl", + Short: "cluster management", + Long: `Simple kubernetes cluster management`, + Run: func(cmd *cobra.Command, args []string) { + // Do Stuff Here + cmd.Help() + }, +} + +var ( + kubeConfig string +) + +func Execute() { + if err := RootCmd.Execute(); err != nil { + glog.Exit(err) + } +} + +func parseClusterYaml(file string) (*clusterv1.Cluster, error) { + bytes, err := ioutil.ReadFile(file) + if err != nil { + return nil, err + } + + cluster := &clusterv1.Cluster{} + err = yaml.Unmarshal(bytes, cluster) + if err != nil { + return nil, err + } + + return cluster, nil +} + +func parseMachinesYaml(file string) ([]*clusterv1.Machine, error) { + bytes, err := ioutil.ReadFile(file) + if err != nil { + return nil, err + } + + machines := &clusterv1.MachineList{} + err = yaml.Unmarshal(bytes, &machines) + if err != nil { + return nil, err + } + + return util.MachineP(machines.Items), nil +} + +func init() { + RootCmd.PersistentFlags().StringVarP(&kubeConfig, "kubeconfig", "k", "", "location for the kubernetes config file. If not provided, $HOME/.kube/config is used") + flag.CommandLine.Parse([]string{}) + logs.InitLogs() +} diff --git a/clusterctl/main.go b/clusterctl/main.go new file mode 100644 index 000000000000..736fcc0e1c57 --- /dev/null +++ b/clusterctl/main.go @@ -0,0 +1,23 @@ +/* +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 main + +import "sigs.k8s.io/cluster-api/clusterctl/cmd" + +func main() { + cmd.Execute() +} diff --git a/errors/deployer.go b/errors/deployer.go new file mode 100644 index 000000000000..8c7041dbfcfd --- /dev/null +++ b/errors/deployer.go @@ -0,0 +1,23 @@ +/* +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 errors + +import ( + "fmt" +) + +var NotImplementedError = fmt.Errorf("not implemented") From 0ec639a861d5aa6ee3d6b8e37b67c91071b48603 Mon Sep 17 00:00:00 2001 From: Karan Goel Date: Tue, 1 May 2018 13:15:19 -0700 Subject: [PATCH 2/2] remove flags from clusterctl boilerplate --- clusterctl/README.md | 26 +++----- clusterctl/cmd/create.go | 45 +------------- clusterctl/cmd/create_cluster.go | 59 +++++++++++++++++++ clusterctl/cmd/delete.go | 30 +--------- .../cmd/{register.go => delete_cluster.go} | 48 +++++++-------- clusterctl/cmd/root.go | 12 ++-- 6 files changed, 102 insertions(+), 118 deletions(-) create mode 100644 clusterctl/cmd/create_cluster.go rename clusterctl/cmd/{register.go => delete_cluster.go} (50%) diff --git a/clusterctl/README.md b/clusterctl/README.md index 7c6a3e7a298b..60a0a099cc13 100644 --- a/clusterctl/README.md +++ b/clusterctl/README.md @@ -8,31 +8,23 @@ Read the [experience doc here](https://docs.google.com/document/d/1-sYb3EdkRga49 ### Prerequisites -Follow the steps listed at [CONTRIBUTING.md](https://github.com/kubernetes/kube-deploy/blob/master/cluster-api/clusterctl/CONTRIBUTING.md) to: +Follow the steps listed at [CONTRIBUTING.md](https://github.com/kubernetes-sigs/cluster-api/blob/master/cluster-api/clusterctl/CONTRIBUTING.md) to: -1. Build the `clusterctl` tool -3. Create a `machines.yaml` file configured for your cluster. See the provided template for an example. +1. Build the `clusterctl` tool -### Limitation +``` +go build +``` + +2. Create a `machines.yaml` file configured for your cluster. See the provided template for an example. + +### Limitations ### Creating a cluster **NOT YET SUPPORTED!** -In order to create a cluster with the Cluster API, the user will supply these: - -* Cluster which defines the spec common across the entire cluster. -* Machine which defines the spec of a machine. Further abstractions of -MachineSets and MachineClass and MachineDeployments are supported as well. -* Extras (optional) spec extras.yaml file with specs of all controllers -(ConfigMaps) that the cluster needs. This would include the Machine controller, -MachineSet controller, Machine Setup ConfigMap etc. Note that this is not a new API -object. There will be defaults running. This will make the tool easily pluggage -(change the controller spec) instead of changing the tool or mucking with flags. - -1. Create a cluster: `./clusterctl create cluster -c cluster.yaml -m machines.yaml -e extras.yaml` - ### Interacting with your cluster Once you have created a cluster, you can interact with the cluster and machine diff --git a/clusterctl/cmd/create.go b/clusterctl/cmd/create.go index bcc1ee93a8b8..bb7e2890b762 100644 --- a/clusterctl/cmd/create.go +++ b/clusterctl/cmd/create.go @@ -17,55 +17,16 @@ limitations under the License. package cmd import ( - "os" - - //"fmt" - "github.com/golang/glog" "github.com/spf13/cobra" - "sigs.k8s.io/cluster-api/errors" ) -type CreateOptions struct { - Cluster string - Machine string - Extras string -} - -var co = &CreateOptions{} - var createCmd = &cobra.Command{ Use: "create", - Short: "Create kubernetes cluster", - Long: `Create a kubernetes cluster with one command`, - Run: func(cmd *cobra.Command, args []string) { - if co.Cluster == "" { - glog.Error("Please provide yaml file for cluster definition.") - cmd.Help() - os.Exit(1) - } - if co.Machine == "" { - glog.Error("Please provide yaml file for machine definition.") - cmd.Help() - os.Exit(1) - } - if co.Extras == "" { - glog.Error("Please provide a yaml file for extra definitions (controllers, Addons etc).") - cmd.Help() - os.Exit(1) - } - if err := RunCreate(co); err != nil { - glog.Exit(err) - } - }, + Short: "Create a cluster API resource", + Long: `Create a cluster API resource with one command`, } -func RunCreate(co *CreateOptions) error { - return errors.NotImplementedError -} func init() { - createCmd.Flags().StringVarP(&co.Cluster, "cluster", "c", "", "cluster yaml file") - createCmd.Flags().StringVarP(&co.Machine, "machines", "m", "", "machine yaml file") - createCmd.Flags().StringVarP(&co.Extras, "extras", "e", "", "extras yaml file") - + createCmd.AddCommand(NewCmdCreateCluster()) RootCmd.AddCommand(createCmd) } diff --git a/clusterctl/cmd/create_cluster.go b/clusterctl/cmd/create_cluster.go new file mode 100644 index 000000000000..47d3ecae0565 --- /dev/null +++ b/clusterctl/cmd/create_cluster.go @@ -0,0 +1,59 @@ +/* +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/golang/glog" + "github.com/spf13/cobra" + "sigs.k8s.io/cluster-api/errors" +) + +type CreateOptions struct { + Cluster string + Machine string + ProviderComponents string +} + +var co = &CreateOptions{} + +func NewCmdCreateCluster() *cobra.Command { + cmd := &cobra.Command{ + Use: "cluster", + Short: "Create kubernetes cluster", + Long: `Create a kubernetes cluster with one command`, + Run: func(cmd *cobra.Command, args []string) { + if co.Cluster == "" { + exitWithHelp(cmd, "Please provide yaml file for cluster definition.") + } + if co.Machine == "" { + exitWithHelp(cmd, "Please provide yaml file for machine definition.") + } + if co.ProviderComponents == "" { + exitWithHelp(cmd, "Please provide a yaml file for provider component definitions.") + } + if err := RunCreate(co); err != nil { + glog.Exit(err) + } + }, + } + + return cmd +} + +func RunCreate(co *CreateOptions) error { + return errors.NotImplementedError +} diff --git a/clusterctl/cmd/delete.go b/clusterctl/cmd/delete.go index be3fd91f0e43..690593ef057f 100644 --- a/clusterctl/cmd/delete.go +++ b/clusterctl/cmd/delete.go @@ -17,40 +17,16 @@ limitations under the License. package cmd import ( - "github.com/golang/glog" "github.com/spf13/cobra" - "os" - "sigs.k8s.io/cluster-api/errors" ) -type DeleteOptions struct { - ClusterName string -} - -var do = &DeleteOptions{} - var deleteCmd = &cobra.Command{ Use: "delete", - Short: "Delete kubernetes cluster", - Long: `Delete a kubernetes cluster with one command`, - Run: func(cmd *cobra.Command, args []string) { - if do.ClusterName == "" { - glog.Error("Please provide cluster name.") - cmd.Help() - os.Exit(1) - } - if err := RunDelete(); err != nil { - glog.Exit(err) - } - }, -} - -func RunDelete() error { - return errors.NotImplementedError + Short: "Delete a cluster API resource", + Long: `Delete a cluster API resource with one command`, } func init() { - deleteCmd.Flags().StringVarP(&do.ClusterName, "cluster-name", "n", "", "cluster name") - + deleteCmd.AddCommand(NewCmdDeleteCluster()) RootCmd.AddCommand(deleteCmd) } diff --git a/clusterctl/cmd/register.go b/clusterctl/cmd/delete_cluster.go similarity index 50% rename from clusterctl/cmd/register.go rename to clusterctl/cmd/delete_cluster.go index 59c4661b321a..b38fa4c9f2b6 100644 --- a/clusterctl/cmd/register.go +++ b/clusterctl/cmd/delete_cluster.go @@ -17,41 +17,35 @@ limitations under the License. package cmd import ( - "os" - "github.com/golang/glog" "github.com/spf13/cobra" "sigs.k8s.io/cluster-api/errors" ) -type RegisterOptions struct { - RegistryEndpoint string +type DeleteOptions struct { + ClusterName string } -var ro = &RegisterOptions{} - -var registerCmd = &cobra.Command{ - Use: "register", - Short: "Register a kubernetes cluster with a Cluster Registry", - Long: `Register a kubernetes cluster with a Cluster Registry`, - Run: func(cmd *cobra.Command, args []string) { - if ro.RegistryEndpoint == "" { - glog.Error("Please provide yaml file for cluster definition.") - cmd.Help() - os.Exit(1) - } - if err := RunRegister(ro); err != nil { - glog.Exit(err) - } - }, +var do = &DeleteOptions{} + +func NewCmdDeleteCluster() *cobra.Command { + cmd := &cobra.Command{ + Use: "delete", + 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) + } + }, + } + + return cmd } -func RunRegister(co *RegisterOptions) error { +func RunDelete() error { return errors.NotImplementedError } - -func init() { - registerCmd.Flags().StringVarP(&ro.RegistryEndpoint, "registry-endpoint", "r", "", "registry endpoint") - - RootCmd.AddCommand(registerCmd) -} diff --git a/clusterctl/cmd/root.go b/clusterctl/cmd/root.go index 72c6d30ae501..6e5279363d7a 100644 --- a/clusterctl/cmd/root.go +++ b/clusterctl/cmd/root.go @@ -19,6 +19,7 @@ package cmd import ( "flag" "io/ioutil" + "os" "github.com/ghodss/yaml" "github.com/golang/glog" @@ -38,10 +39,6 @@ var RootCmd = &cobra.Command{ }, } -var ( - kubeConfig string -) - func Execute() { if err := RootCmd.Execute(); err != nil { glog.Exit(err) @@ -78,8 +75,13 @@ func parseMachinesYaml(file string) ([]*clusterv1.Machine, error) { return util.MachineP(machines.Items), nil } +func exitWithHelp(cmd *cobra.Command, err string) { + glog.Error(err) + cmd.Help() + os.Exit(1) +} + func init() { - RootCmd.PersistentFlags().StringVarP(&kubeConfig, "kubeconfig", "k", "", "location for the kubernetes config file. If not provided, $HOME/.kube/config is used") flag.CommandLine.Parse([]string{}) logs.InitLogs() }