github.com/jmrodri/operator-sdk@v0.5.0/commands/operator-sdk/cmd/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 k8sInternal "github.com/operator-framework/operator-sdk/internal/util/k8sutil" 28 "github.com/operator-framework/operator-sdk/internal/util/projutil" 29 "github.com/operator-framework/operator-sdk/pkg/ansible" 30 aoflags "github.com/operator-framework/operator-sdk/pkg/ansible/flags" 31 "github.com/operator-framework/operator-sdk/pkg/helm" 32 hoflags "github.com/operator-framework/operator-sdk/pkg/helm/flags" 33 "github.com/operator-framework/operator-sdk/pkg/k8sutil" 34 "github.com/operator-framework/operator-sdk/pkg/log/zap" 35 "github.com/operator-framework/operator-sdk/pkg/scaffold" 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 t := projutil.GetOperatorType() 91 switch t { 92 case projutil.OperatorTypeGo: 93 return upLocal() 94 case projutil.OperatorTypeAnsible: 95 return upLocalAnsible() 96 case projutil.OperatorTypeHelm: 97 return upLocalHelm() 98 } 99 return fmt.Errorf("unknown operator type '%v'", t) 100 } 101 102 func upLocal() error { 103 projutil.MustInProjectRoot() 104 absProjectPath := projutil.MustGetwd() 105 projectName := filepath.Base(absProjectPath) 106 outputBinName := filepath.Join(scaffold.BuildBinDir, projectName+"-local") 107 if err := buildLocal(outputBinName); err != nil { 108 return fmt.Errorf("failed to build operator to run locally: (%v)", err) 109 } 110 111 args := []string{} 112 if operatorFlags != "" { 113 extraArgs := strings.Split(operatorFlags, " ") 114 args = append(args, extraArgs...) 115 } 116 dc := exec.Command(outputBinName, args...) 117 c := make(chan os.Signal) 118 signal.Notify(c, os.Interrupt, syscall.SIGTERM) 119 go func() { 120 <-c 121 err := dc.Process.Kill() 122 if err != nil { 123 log.Fatalf("Failed to terminate the operator: (%v)", err) 124 } 125 os.Exit(0) 126 }() 127 dc.Env = os.Environ() 128 // only set env var if user explicitly specified a kubeconfig path 129 if kubeConfig != "" { 130 dc.Env = append(dc.Env, fmt.Sprintf("%v=%v", k8sutil.KubeConfigEnvVar, kubeConfig)) 131 } 132 dc.Env = append(dc.Env, fmt.Sprintf("%v=%v", k8sutil.WatchNamespaceEnvVar, namespace)) 133 if err := projutil.ExecCmd(dc); err != nil { 134 return fmt.Errorf("failed to run operator locally: (%v)", err) 135 } 136 return nil 137 } 138 139 func upLocalAnsible() error { 140 logf.SetLogger(zap.Logger()) 141 if err := setupOperatorEnv(); err != nil { 142 return err 143 } 144 return ansible.Run(ansibleOperatorFlags) 145 } 146 147 func upLocalHelm() error { 148 logf.SetLogger(zap.Logger()) 149 if err := setupOperatorEnv(); err != nil { 150 return err 151 } 152 return helm.Run(helmOperatorFlags) 153 } 154 155 func setupOperatorEnv() error { 156 // Set the kubeconfig that the manager will be able to grab 157 // only set env var if user explicitly specified a kubeconfig path 158 if kubeConfig != "" { 159 if err := os.Setenv(k8sutil.KubeConfigEnvVar, kubeConfig); err != nil { 160 return fmt.Errorf("failed to set %s environment variable: (%v)", k8sutil.KubeConfigEnvVar, err) 161 } 162 } 163 // Set the namespace that the manager will be able to grab 164 if namespace != "" { 165 if err := os.Setenv(k8sutil.WatchNamespaceEnvVar, namespace); err != nil { 166 return fmt.Errorf("failed to set %s environment variable: (%v)", k8sutil.WatchNamespaceEnvVar, err) 167 } 168 } 169 // Set the operator name, if not already set 170 projutil.MustInProjectRoot() 171 if _, err := k8sutil.GetOperatorName(); err != nil { 172 operatorName := filepath.Base(projutil.MustGetwd()) 173 if err := os.Setenv(k8sutil.OperatorNameEnvVar, operatorName); err != nil { 174 return fmt.Errorf("failed to set %s environment variable: (%v)", k8sutil.OperatorNameEnvVar, err) 175 } 176 } 177 return nil 178 } 179 180 func buildLocal(outputBinName string) error { 181 args := []string{"build", "-o", outputBinName} 182 if ldFlags != "" { 183 args = append(args, "-ldflags", ldFlags) 184 } 185 args = append(args, filepath.Join(scaffold.ManagerDir, scaffold.CmdFile)) 186 187 bc := exec.Command("go", args...) 188 if err := projutil.ExecCmd(bc); err != nil { 189 return err 190 } 191 return nil 192 } 193 194 func printVersion() { 195 log.Infof("Go Version: %s", runtime.Version()) 196 log.Infof("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH) 197 log.Infof("Version of operator-sdk: %v", sdkVersion.Version) 198 }