github.com/mkimuram/operator-sdk@v0.7.1-0.20190410172100-52ad33a4bda0/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 "k8s.io/client-go/tools/clientcmd" 30 31 "github.com/operator-framework/operator-sdk/internal/pkg/scaffold" 32 "github.com/operator-framework/operator-sdk/internal/util/projutil" 33 "github.com/operator-framework/operator-sdk/pkg/k8sutil" 34 log "github.com/sirupsen/logrus" 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 absProjectPath := projutil.MustGetwd() 68 projectName := filepath.Base(absProjectPath) 69 outputBinName := filepath.Join(scaffold.BuildBinDir, projectName+"-local") 70 args := []string{"build", "-o", outputBinName} 71 args = append(args, filepath.Join(scaffold.ManagerDir, scaffold.CmdFile)) 72 bc := exec.Command("go", args...) 73 if err := projutil.ExecCmd(bc); err != nil { 74 log.Fatalf("Failed to build local operator binary: %s", err) 75 } 76 localCmd = exec.Command(outputBinName) 77 localCmd.Stdout = &localCmdOutBuf 78 localCmd.Stderr = &localCmdErrBuf 79 c := make(chan os.Signal) 80 signal.Notify(c, os.Interrupt, syscall.SIGTERM) 81 go func() { 82 <-c 83 err := localCmd.Process.Signal(os.Interrupt) 84 if err != nil { 85 log.Fatalf("Failed to terminate the operator: (%v)", err) 86 } 87 os.Exit(0) 88 }() 89 if *kubeconfigPath != "" { 90 localCmd.Env = append(os.Environ(), fmt.Sprintf("%v=%v", k8sutil.KubeConfigEnvVar, *kubeconfigPath)) 91 } else { 92 // we can hardcode index 0 as that is the highest priority kubeconfig to be loaded and will always 93 // be populated by NewDefaultClientConfigLoadingRules() 94 localCmd.Env = append(os.Environ(), fmt.Sprintf("%v=%v", k8sutil.KubeConfigEnvVar, clientcmd.NewDefaultClientConfigLoadingRules().Precedence[0])) 95 } 96 localCmd.Env = append(localCmd.Env, fmt.Sprintf("%v=%v", k8sutil.WatchNamespaceEnvVar, Global.Namespace)) 97 } 98 // setup context to use when setting up crd 99 ctx := NewTestCtx(nil) 100 // os.Exit stops the program before the deferred functions run 101 // to fix this, we put the exit in the defer as well 102 defer func() { 103 // start local operator before running tests 104 if *localOperator { 105 err := localCmd.Start() 106 if err != nil { 107 log.Fatalf("Failed to run operator locally: (%v)", err) 108 } 109 log.Info("Started local operator") 110 } 111 exitCode := m.Run() 112 if *localOperator { 113 err := localCmd.Process.Kill() 114 if err != nil { 115 log.Warn("Failed to stop local operator process") 116 } 117 log.Infof("Local operator stdout: %s", string(localCmdOutBuf.Bytes())) 118 log.Infof("Local operator stderr: %s", string(localCmdErrBuf.Bytes())) 119 } 120 ctx.Cleanup() 121 os.Exit(exitCode) 122 }() 123 // create crd 124 if *kubeconfigPath != "incluster" { 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 } 134 }