diff --git a/commands/operator-sdk/cmd/build.go b/commands/operator-sdk/cmd/build.go index 69364c5fbdc..e67dae1a7e3 100644 --- a/commands/operator-sdk/cmd/build.go +++ b/commands/operator-sdk/cmd/build.go @@ -16,15 +16,14 @@ package cmd import ( "fmt" - "io/ioutil" "os" "os/exec" + "github.com/operator-framework/operator-sdk/commands/operator-sdk/cmd/cmdutil" cmdError "github.com/operator-framework/operator-sdk/commands/operator-sdk/error" "github.com/operator-framework/operator-sdk/pkg/generator" "github.com/spf13/cobra" - yaml "gopkg.in/yaml.v2" ) func NewBuildCmd() *cobra.Command { @@ -74,14 +73,7 @@ func buildFunc(cmd *cobra.Command, args []string) { } fmt.Fprintln(os.Stdout, string(o)) - c := &generator.Config{} - fp, err := ioutil.ReadFile(configYaml) - if err != nil { - cmdError.ExitWithError(cmdError.ExitError, fmt.Errorf("failed to read config file %v: (%v)", configYaml, err)) - } - if err = yaml.Unmarshal(fp, c); err != nil { - cmdError.ExitWithError(cmdError.ExitError, fmt.Errorf("failed to unmarshal config file %v: (%v)", configYaml, err)) - } + c := cmdutil.GetConfig() if err = generator.RenderOperatorYaml(c, image); err != nil { cmdError.ExitWithError(cmdError.ExitError, fmt.Errorf("failed to generate deploy/operator.yaml: (%v)", err)) } diff --git a/commands/operator-sdk/cmd/cmdutil/util.go b/commands/operator-sdk/cmd/cmdutil/util.go new file mode 100644 index 00000000000..cd9137fc81f --- /dev/null +++ b/commands/operator-sdk/cmd/cmdutil/util.go @@ -0,0 +1,36 @@ +package cmdutil + +import ( + "fmt" + "io/ioutil" + "os" + + cmdError "github.com/operator-framework/operator-sdk/commands/operator-sdk/error" + "github.com/operator-framework/operator-sdk/pkg/generator" + yaml "gopkg.in/yaml.v2" +) + +const configYaml = "./config/config.yaml" + +// MustInProjectRoot checks if the current dir is the project root. +func MustInProjectRoot() { + // if the current directory has the "./config/config.yaml" file, then it is safe to say + // we are at the project root. + _, err := os.Stat(configYaml) + if err != nil && os.IsNotExist(err) { + cmdError.ExitWithError(cmdError.ExitError, fmt.Errorf("must in project root dir: %v", err)) + } +} + +// GetConfig gets the values from ./config/config.yaml and parses them into a Config struct. +func GetConfig() *generator.Config { + c := &generator.Config{} + fp, err := ioutil.ReadFile(configYaml) + if err != nil { + cmdError.ExitWithError(cmdError.ExitError, fmt.Errorf("failed to read config file %v: (%v)", configYaml, err)) + } + if err = yaml.Unmarshal(fp, c); err != nil { + cmdError.ExitWithError(cmdError.ExitError, fmt.Errorf("failed to unmarshal config file %v: (%v)", configYaml, err)) + } + return c +} diff --git a/commands/operator-sdk/cmd/root.go b/commands/operator-sdk/cmd/root.go index 2f09596d755..4424872b0d3 100644 --- a/commands/operator-sdk/cmd/root.go +++ b/commands/operator-sdk/cmd/root.go @@ -25,6 +25,7 @@ func NewRootCmd() *cobra.Command { cmd.AddCommand(NewNewCmd()) cmd.AddCommand(NewBuildCmd()) cmd.AddCommand(NewGenerateCmd()) + cmd.AddCommand(NewUpCmd()) return cmd } diff --git a/commands/operator-sdk/cmd/up.go b/commands/operator-sdk/cmd/up.go new file mode 100644 index 00000000000..3549f4f8968 --- /dev/null +++ b/commands/operator-sdk/cmd/up.go @@ -0,0 +1,19 @@ +package cmd + +import ( + "github.com/operator-framework/operator-sdk/commands/operator-sdk/cmd/up" + + "github.com/spf13/cobra" +) + +func NewUpCmd() *cobra.Command { + upCmd := &cobra.Command{ + Use: "up", + Short: "Launches the operator", + Long: `The up command has subcommands that can launch the operator in various ways. +`, + } + + upCmd.AddCommand(up.NewLocalCmd()) + return upCmd +} diff --git a/commands/operator-sdk/cmd/up/local.go b/commands/operator-sdk/cmd/up/local.go new file mode 100644 index 00000000000..95f2a3780d2 --- /dev/null +++ b/commands/operator-sdk/cmd/up/local.go @@ -0,0 +1,77 @@ +package up + +import ( + "fmt" + "os" + "os/exec" + "os/user" + "path/filepath" + + "github.com/operator-framework/operator-sdk/commands/operator-sdk/cmd/cmdutil" + cmdError "github.com/operator-framework/operator-sdk/commands/operator-sdk/error" + + "github.com/spf13/cobra" +) + +func NewLocalCmd() *cobra.Command { + upCmd := &cobra.Command{ + Use: "local", + Short: "Launches the operator locally", + Long: `The operator-sdk up local command launches the operator on the local machine +by building the operator binary with the ability to access a +kubernetes cluster using a Kubernete config file. +`, + Run: upFunc, + } + + upCmd.Flags().StringVar(&kubeConfig, "kubeconfig", "", "The file path to kubernetes configuration file; defaults to $HOME/.kube/config") + + return upCmd +} + +var ( + kubeConfig string +) + +const ( + gocmd = "go" + run = "run" + cmd = "cmd" + main = "main.go" + defaultConfigPath = ".kube/config" +) + +func upFunc(cmd *cobra.Command, args []string) { + mustKubeConfig() + cmdutil.MustInProjectRoot() + c := cmdutil.GetConfig() + up(c.ProjectName) +} + +// mustKubeConfig checks if the kubeconfig file exists. +func mustKubeConfig() { + // if kubeConfig is not specified, search for the default kubeconfig file under the $HOME/.kube/config. + if len(kubeConfig) == 0 { + usr, err := user.Current() + if err != nil { + cmdError.ExitWithError(cmdError.ExitError, fmt.Errorf("failed to determine user's home dir: %v", err)) + } + kubeConfig = filepath.Join(usr.HomeDir, defaultConfigPath) + } + + _, err := os.Stat(kubeConfig) + if err != nil && os.IsNotExist(err) { + cmdError.ExitWithError(cmdError.ExitError, fmt.Errorf("failed to fine the Kubernetes config file (%v): %v", kubeConfig, err)) + } +} + +func up(projectName string) { + dc := exec.Command(gocmd, run, filepath.Join(cmd, projectName, main)) + dc.Stdout = os.Stdout + dc.Stderr = os.Stderr + dc.Env = append(os.Environ(), fmt.Sprintf("KUBERNETES_CONFIG=%v", kubeConfig)) + err := dc.Run() + if err != nil { + cmdError.ExitWithError(cmdError.ExitError, fmt.Errorf("failed to run operator locally: %v", err)) + } +}