github.com/mkimuram/operator-sdk@v0.7.1-0.20190410172100-52ad33a4bda0/cmd/operator-sdk/up/local.go (about) 1 // Copyright 2018 The Operator-SDK Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package up 16 17 import ( 18 "fmt" 19 "os" 20 "os/exec" 21 "os/signal" 22 "path/filepath" 23 "runtime" 24 "strings" 25 "syscall" 26 27 "github.com/operator-framework/operator-sdk/internal/pkg/scaffold" 28 k8sInternal "github.com/operator-framework/operator-sdk/internal/util/k8sutil" 29 "github.com/operator-framework/operator-sdk/internal/util/projutil" 30 "github.com/operator-framework/operator-sdk/pkg/ansible" 31 aoflags "github.com/operator-framework/operator-sdk/pkg/ansible/flags" 32 "github.com/operator-framework/operator-sdk/pkg/helm" 33 hoflags "github.com/operator-framework/operator-sdk/pkg/helm/flags" 34 "github.com/operator-framework/operator-sdk/pkg/k8sutil" 35 "github.com/operator-framework/operator-sdk/pkg/log/zap" 36 sdkVersion "github.com/operator-framework/operator-sdk/version" 37 38 log "github.com/sirupsen/logrus" 39 "github.com/spf13/cobra" 40 logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" 41 ) 42 43 // newLocalCmd - up local command to run an operator loccally 44 func newLocalCmd() *cobra.Command { 45 upLocalCmd := &cobra.Command{ 46 Use: "local", 47 Short: "Launches the operator locally", 48 Long: `The operator-sdk up local command launches the operator on the local machine 49 by building the operator binary with the ability to access a 50 kubernetes cluster using a kubeconfig file. 51 `, 52 RunE: upLocalFunc, 53 } 54 55 upLocalCmd.Flags().StringVar(&kubeConfig, "kubeconfig", "", "The file path to kubernetes configuration file; defaults to location specified by $KUBECONFIG with a fallback to $HOME/.kube/config if not set") 56 upLocalCmd.Flags().StringVar(&operatorFlags, "operator-flags", "", "The flags that the operator needs. Example: \"--flag1 value1 --flag2=value2\"") 57 upLocalCmd.Flags().StringVar(&namespace, "namespace", "", "The namespace where the operator watches for changes.") 58 upLocalCmd.Flags().StringVar(&ldFlags, "go-ldflags", "", "Set Go linker options") 59 switch projutil.GetOperatorType() { 60 case projutil.OperatorTypeAnsible: 61 ansibleOperatorFlags = aoflags.AddTo(upLocalCmd.Flags(), "(ansible operator)") 62 case projutil.OperatorTypeHelm: 63 helmOperatorFlags = hoflags.AddTo(upLocalCmd.Flags(), "(helm operator)") 64 } 65 return upLocalCmd 66 } 67 68 var ( 69 kubeConfig string 70 operatorFlags string 71 namespace string 72 ldFlags string 73 ansibleOperatorFlags *aoflags.AnsibleOperatorFlags 74 helmOperatorFlags *hoflags.HelmOperatorFlags 75 ) 76 77 func upLocalFunc(cmd *cobra.Command, args []string) error { 78 log.Info("Running the operator locally.") 79 80 // get default namespace to watch if unset 81 if !cmd.Flags().Changed("namespace") { 82 _, defaultNamespace, err := k8sInternal.GetKubeconfigAndNamespace(kubeConfig) 83 if err != nil { 84 return fmt.Errorf("failed to get kubeconfig and default namespace: %v", err) 85 } 86 namespace = defaultNamespace 87 } 88 log.Infof("Using namespace %s.", namespace) 89 90 switch t := projutil.GetOperatorType(); t { 91 case projutil.OperatorTypeGo: 92 return upLocal() 93 case projutil.OperatorTypeAnsible: 94 return upLocalAnsible() 95 case projutil.OperatorTypeHelm: 96 return upLocalHelm() 97 } 98 return projutil.ErrUnknownOperatorType{} 99 } 100 101 func upLocal() error { 102 projutil.MustInProjectRoot() 103 absProjectPath := projutil.MustGetwd() 104 projectName := filepath.Base(absProjectPath) 105 outputBinName := filepath.Join(scaffold.BuildBinDir, projectName+"-local") 106 if err := buildLocal(outputBinName); err != nil { 107 return fmt.Errorf("failed to build operator to run locally: (%v)", err) 108 } 109 110 args := []string{} 111 if operatorFlags != "" { 112 extraArgs := strings.Split(operatorFlags, " ") 113 args = append(args, extraArgs...) 114 } 115 dc := exec.Command(outputBinName, args...) 116 c := make(chan os.Signal) 117 signal.Notify(c, os.Interrupt, syscall.SIGTERM) 118 go func() { 119 <-c 120 err := dc.Process.Kill() 121 if err != nil { 122 log.Fatalf("Failed to terminate the operator: (%v)", err) 123 } 124 os.Exit(0) 125 }() 126 dc.Env = os.Environ() 127 // only set env var if user explicitly specified a kubeconfig path 128 if kubeConfig != "" { 129 dc.Env = append(dc.Env, fmt.Sprintf("%v=%v", k8sutil.KubeConfigEnvVar, kubeConfig)) 130 } 131 dc.Env = append(dc.Env, fmt.Sprintf("%v=%v", k8sutil.WatchNamespaceEnvVar, namespace)) 132 if err := projutil.ExecCmd(dc); err != nil { 133 return fmt.Errorf("failed to run operator locally: (%v)", err) 134 } 135 return nil 136 } 137 138 func upLocalAnsible() error { 139 logf.SetLogger(zap.Logger()) 140 if err := setupOperatorEnv(); err != nil { 141 return err 142 } 143 return ansible.Run(ansibleOperatorFlags) 144 } 145 146 func upLocalHelm() error { 147 logf.SetLogger(zap.Logger()) 148 if err := setupOperatorEnv(); err != nil { 149 return err 150 } 151 return helm.Run(helmOperatorFlags) 152 } 153 154 func setupOperatorEnv() error { 155 // Set the kubeconfig that the manager will be able to grab 156 // only set env var if user explicitly specified a kubeconfig path 157 if kubeConfig != "" { 158 if err := os.Setenv(k8sutil.KubeConfigEnvVar, kubeConfig); err != nil { 159 return fmt.Errorf("failed to set %s environment variable: (%v)", k8sutil.KubeConfigEnvVar, err) 160 } 161 } 162 // Set the namespace that the manager will be able to grab 163 if namespace != "" { 164 if err := os.Setenv(k8sutil.WatchNamespaceEnvVar, namespace); err != nil { 165 return fmt.Errorf("failed to set %s environment variable: (%v)", k8sutil.WatchNamespaceEnvVar, err) 166 } 167 } 168 // Set the operator name, if not already set 169 projutil.MustInProjectRoot() 170 if _, err := k8sutil.GetOperatorName(); err != nil { 171 operatorName := filepath.Base(projutil.MustGetwd()) 172 if err := os.Setenv(k8sutil.OperatorNameEnvVar, operatorName); err != nil { 173 return fmt.Errorf("failed to set %s environment variable: (%v)", k8sutil.OperatorNameEnvVar, err) 174 } 175 } 176 return nil 177 } 178 179 func buildLocal(outputBinName string) error { 180 args := []string{"build", "-o", outputBinName} 181 if ldFlags != "" { 182 args = append(args, "-ldflags", ldFlags) 183 } 184 args = append(args, filepath.Join(scaffold.ManagerDir, scaffold.CmdFile)) 185 186 bc := exec.Command("go", args...) 187 if err := projutil.ExecCmd(bc); err != nil { 188 return err 189 } 190 return nil 191 } 192 193 func printVersion() { 194 log.Infof("Go Version: %s", runtime.Version()) 195 log.Infof("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH) 196 log.Infof("Version of operator-sdk: %v", sdkVersion.Version) 197 }