github.skymusic.top/operator-framework/operator-sdk@v0.8.2/pkg/test/main_entry.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 test 16 17 import ( 18 "bytes" 19 "flag" 20 "fmt" 21 "io/ioutil" 22 "os" 23 "os/exec" 24 "os/signal" 25 "path/filepath" 26 "syscall" 27 "testing" 28 29 "github.com/operator-framework/operator-sdk/internal/pkg/scaffold" 30 "github.com/operator-framework/operator-sdk/internal/util/projutil" 31 "github.com/operator-framework/operator-sdk/pkg/k8sutil" 32 33 log "github.com/sirupsen/logrus" 34 "k8s.io/client-go/tools/clientcmd" 35 ) 36 37 const ( 38 ProjRootFlag = "root" 39 KubeConfigFlag = "kubeconfig" 40 NamespacedManPathFlag = "namespacedMan" 41 GlobalManPathFlag = "globalMan" 42 SingleNamespaceFlag = "singleNamespace" 43 TestNamespaceEnv = "TEST_NAMESPACE" 44 LocalOperatorFlag = "localOperator" 45 ) 46 47 func MainEntry(m *testing.M) { 48 projRoot := flag.String(ProjRootFlag, "", "path to project root") 49 kubeconfigPath := flag.String(KubeConfigFlag, "", "path to kubeconfig") 50 globalManPath := flag.String(GlobalManPathFlag, "", "path to operator manifest") 51 namespacedManPath := flag.String(NamespacedManPathFlag, "", "path to rbac manifest") 52 singleNamespace = flag.Bool(SingleNamespaceFlag, false, "enable single namespace mode") 53 localOperator := flag.Bool(LocalOperatorFlag, false, "enable if operator is running locally (not in cluster)") 54 flag.Parse() 55 // go test always runs from the test directory; change to project root 56 err := os.Chdir(*projRoot) 57 if err != nil { 58 log.Fatalf("Failed to change directory to project root: %v", err) 59 } 60 if err := setup(kubeconfigPath, namespacedManPath, *localOperator); err != nil { 61 log.Fatalf("Failed to set up framework: %v", err) 62 } 63 // setup local operator command, but don't start it yet 64 var localCmd *exec.Cmd 65 var localCmdOutBuf, localCmdErrBuf bytes.Buffer 66 if *localOperator { 67 projectName := filepath.Base(projutil.MustGetwd()) 68 outputBinName := filepath.Join(scaffold.BuildBinDir, projectName+"-local") 69 opts := projutil.GoCmdOptions{ 70 BinName: outputBinName, 71 PackagePath: filepath.Join(scaffold.ManagerDir, scaffold.CmdFile), 72 GoMod: projutil.IsDepManagerGoMod(), 73 } 74 if err := projutil.GoBuild(opts); err != nil { 75 log.Fatalf("Failed to build local operator binary: %s", err) 76 } 77 localCmd = exec.Command(outputBinName) 78 localCmd.Stdout = &localCmdOutBuf 79 localCmd.Stderr = &localCmdErrBuf 80 c := make(chan os.Signal) 81 signal.Notify(c, os.Interrupt, syscall.SIGTERM) 82 go func() { 83 <-c 84 err := localCmd.Process.Signal(os.Interrupt) 85 if err != nil { 86 log.Fatalf("Failed to terminate the operator: (%v)", err) 87 } 88 os.Exit(0) 89 }() 90 if *kubeconfigPath != "" { 91 localCmd.Env = append(os.Environ(), fmt.Sprintf("%v=%v", k8sutil.KubeConfigEnvVar, *kubeconfigPath)) 92 } else { 93 // we can hardcode index 0 as that is the highest priority kubeconfig to be loaded and will always 94 // be populated by NewDefaultClientConfigLoadingRules() 95 localCmd.Env = append(os.Environ(), fmt.Sprintf("%v=%v", k8sutil.KubeConfigEnvVar, clientcmd.NewDefaultClientConfigLoadingRules().Precedence[0])) 96 } 97 localCmd.Env = append(localCmd.Env, fmt.Sprintf("%v=%v", k8sutil.WatchNamespaceEnvVar, Global.Namespace)) 98 } 99 // setup context to use when setting up crd 100 ctx := NewTestCtx(nil) 101 // os.Exit stops the program before the deferred functions run 102 // to fix this, we put the exit in the defer as well 103 defer func() { 104 // start local operator before running tests 105 if *localOperator { 106 err := localCmd.Start() 107 if err != nil { 108 log.Fatalf("Failed to run operator locally: (%v)", err) 109 } 110 log.Info("Started local operator") 111 } 112 exitCode := m.Run() 113 if *localOperator { 114 err := localCmd.Process.Kill() 115 if err != nil { 116 log.Warn("Failed to stop local operator process") 117 } 118 log.Infof("Local operator stdout: %s", string(localCmdOutBuf.Bytes())) 119 log.Infof("Local operator stderr: %s", string(localCmdErrBuf.Bytes())) 120 } 121 ctx.Cleanup() 122 os.Exit(exitCode) 123 }() 124 // create crd 125 globalYAML, err := ioutil.ReadFile(*globalManPath) 126 if err != nil { 127 log.Fatalf("Failed to read global resource manifest: %v", err) 128 } 129 err = ctx.createFromYAML(globalYAML, true, &CleanupOptions{TestContext: ctx}) 130 if err != nil { 131 log.Fatalf("Failed to create resource(s) in global resource manifest: %v", err) 132 } 133 }