github.phpd.cn/cilium/cilium@v1.6.12/test/helpers/vagrant.go (about) 1 // Copyright 2017 Authors of Cilium 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 helpers 16 17 import ( 18 "bytes" 19 "fmt" 20 "io" 21 "os" 22 "os/exec" 23 "strings" 24 25 "github.com/cilium/cilium/test/config" 26 ginkgoext "github.com/cilium/cilium/test/ginkgo-ext" 27 28 "github.com/onsi/ginkgo" 29 "github.com/sirupsen/logrus" 30 ) 31 32 // CreateVM creates a new vagrant server.Receives a scope which indicates the 33 // target server that needs to be created. In case of any error on vagrant 34 // [provision|up|ssh-config] error will be returned. 35 func CreateVM(scope string) error { 36 createCMD := "vagrant up %s --provision" 37 38 for _, v := range Status(scope) { 39 switch v { 40 case "running": 41 createCMD = "vagrant provision %s" 42 case "not_created": 43 createCMD = "vagrant up %s --provision" 44 default: 45 // Sometimes servers are stoped and not destroyed. Destroy VM just in case 46 DestroyVM(scope) 47 } 48 } 49 createCMD = fmt.Sprintf(createCMD, scope) 50 log.Infof("Vagrant:Create: running '%s'", createCMD) 51 cmd := getCmd(createCMD) 52 stdout, err := cmd.StdoutPipe() 53 if err != nil { 54 return fmt.Errorf("error getting stdout: %s", err) 55 } 56 stderr, err := cmd.StderrPipe() 57 if err != nil { 58 return fmt.Errorf("error getting stderr: %s", err) 59 } 60 61 globalWriter := ginkgoext.NewWriter(ginkgo.GinkgoWriter) 62 63 go io.Copy(globalWriter, stderr) 64 go io.Copy(globalWriter, stdout) 65 66 if err := cmd.Start(); err != nil { 67 log.WithFields(logrus.Fields{ 68 "command": createCMD, 69 "err": err, 70 }).Fatalf("Create error on start") 71 return err 72 } 73 result := cmd.Wait() 74 io.Copy(ginkgoext.GinkgoWriter, globalWriter.Buffer) 75 return result 76 } 77 78 // GetVagrantSSHMetadata returns a string containing the output of `vagrant ssh-config` 79 // for the provided Vagrant of name vmName. Returns an error if 80 // `vagrant ssh-config` fails to execute. 81 func GetVagrantSSHMetadata(vmName string) ([]byte, error) { 82 // debugVMs is used when ssh-config returns error and be able to debug the 83 // virtual machines status. 84 debugVms := func() { 85 cmd := getCmd("vagrant status --machine-readable") 86 output, _ := cmd.CombinedOutput() 87 fmt.Fprintf(&config.TestLogWriter, "Vagrant status on failure:\n%s\n", output) 88 } 89 90 var stdout, stderr bytes.Buffer 91 cmd := getCmd(fmt.Sprintf("vagrant ssh-config %s", vmName)) 92 if config.CiliumTestConfig.SSHConfig != "" { 93 cmd = getCmd(config.CiliumTestConfig.SSHConfig) 94 debugVms = func() {} // not apply the debug helper due is a dev env. 95 } 96 cmd.Stdout = &stdout 97 cmd.Stderr = &stderr 98 99 err := cmd.Run() 100 if err != nil { 101 fmt.Fprintf(&config.TestLogWriter, "cmd='%s %s'\noutput:\n%s\nstderr:\n%s\n", 102 cmd.Path, strings.Join(cmd.Args, " "), stdout.String(), stderr.String()) 103 debugVms() 104 return nil, err 105 } 106 return stdout.Bytes(), nil 107 } 108 109 //DestroyVM destroys all running Vagrant VMs in the provided scope. It returns an 110 //error if deletion of either the VMs fails 111 func DestroyVM(scope string) error { 112 command := fmt.Sprintf("vagrant destroy -f %s ", scope) 113 cmd := getCmd(command) 114 _, err := cmd.CombinedOutput() 115 if err != nil { 116 return err 117 } 118 return nil 119 } 120 121 func getCmd(vmCommand string) *exec.Cmd { 122 log.Infof("Vagrant: running command '%v'", vmCommand) 123 cmd := exec.Command(getPath("bash"), "-c", vmCommand) 124 cmd.Dir = getDir() 125 return cmd 126 } 127 128 func getDir() string { 129 dir, err := os.Getwd() 130 if err != nil { 131 return "/tmp/" 132 } 133 return fmt.Sprintf("%s/", dir) 134 } 135 136 func getPath(prog string) string { 137 path, err := exec.LookPath(prog) 138 if err != nil { 139 return "" 140 } 141 return path 142 } 143 144 //Status returns a mapping of Vagrant VM name to its status 145 func Status(key string) map[string]string { 146 result := map[string]string{} 147 148 cmd := getCmd(fmt.Sprintf("vagrant status %s --machine-readable", key)) 149 data, err := cmd.CombinedOutput() 150 if err != nil { 151 return result 152 } 153 for _, line := range strings.Split(string(data), "\n") { 154 val := strings.Split(line, ",") 155 if len(val) > 2 && val[2] == "state" { 156 result[val[1]] = val[3] 157 } 158 } 159 return result 160 }