github.com/blixtra/rkt@v0.8.1-0.20160204105720-ab0d1add1a43/tests/testutils/ctx.go (about) 1 // Copyright 2015 The rkt 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 testutils 16 17 import ( 18 "fmt" 19 "io/ioutil" 20 "os" 21 "os/exec" 22 "path/filepath" 23 "strings" 24 25 "github.com/coreos/gexpect" 26 "github.com/coreos/rkt/tests/testutils/logger" 27 ) 28 29 // dirDesc structure manages one directory and provides an option for 30 // rkt invocations 31 type dirDesc struct { 32 dir string // directory path 33 desc string // directory description, mostly for failure cases 34 prefix string // temporary directory prefix 35 option string // rkt option for given directory 36 } 37 38 // newDirDesc creates dirDesc instance managing a temporary directory. 39 func newDirDesc(prefix, desc, option string) *dirDesc { 40 dir := &dirDesc{ 41 dir: "", 42 desc: desc, 43 prefix: prefix, 44 option: option, 45 } 46 dir.reset() 47 return dir 48 } 49 50 // reset removes the managed directory and recreates it 51 func (d *dirDesc) reset() { 52 d.cleanup() 53 dir, err := ioutil.TempDir("", d.prefix) 54 if err != nil { 55 panic(fmt.Sprintf("Failed to create temporary %s directory: %v", d.desc, err)) 56 } 57 d.dir = dir 58 } 59 60 // cleanup removes the managed directory. After cleanup this instance 61 // cannot be used for anything, until it is reset. 62 func (d *dirDesc) cleanup() { 63 if d.dir == "" { 64 return 65 } 66 if err := os.RemoveAll(d.dir); err != nil && !os.IsNotExist(err) { 67 panic(fmt.Sprintf("Failed to remove temporary %s directory %q: %s", d.desc, d.dir, err)) 68 } 69 d.dir = "" 70 } 71 72 // rktOption returns option for rkt invocation 73 func (d *dirDesc) rktOption() string { 74 d.ensureValid() 75 return fmt.Sprintf("--%s=%s", d.option, d.dir) 76 } 77 78 func (d *dirDesc) ensureValid() { 79 if d.dir == "" { 80 panic(fmt.Sprintf("A temporary %s directory is not set up", d.desc)) 81 } 82 } 83 84 // TODO(emil): Document exported. 85 86 type RktRunCtx struct { 87 directories []*dirDesc 88 useDefaults bool 89 mds *exec.Cmd 90 children []*gexpect.ExpectSubprocess 91 } 92 93 func NewRktRunCtx() *RktRunCtx { 94 return &RktRunCtx{ 95 directories: []*dirDesc{ 96 newDirDesc("datadir-", "data", "dir"), 97 newDirDesc("localdir-", "local configuration", "local-config"), 98 newDirDesc("systemdir-", "system configuration", "system-config"), 99 }, 100 } 101 } 102 103 func (ctx *RktRunCtx) SetupDataDir() error { 104 return setupDataDir(ctx.DataDir()) 105 } 106 107 func (ctx *RktRunCtx) LaunchMDS() error { 108 ctx.mds = exec.Command(ctx.rktBin(), "metadata-service") 109 return ctx.mds.Start() 110 } 111 112 func (ctx *RktRunCtx) DataDir() string { 113 return ctx.dir(0) 114 } 115 116 func (ctx *RktRunCtx) LocalDir() string { 117 return ctx.dir(1) 118 } 119 120 func (ctx *RktRunCtx) SystemDir() string { 121 return ctx.dir(2) 122 } 123 124 func (ctx *RktRunCtx) dir(idx int) string { 125 ctx.ensureValid() 126 if idx < len(ctx.directories) { 127 return ctx.directories[idx].dir 128 } 129 panic("Directory index out of bounds") 130 } 131 132 func (ctx *RktRunCtx) Reset() { 133 ctx.cleanupChildren() 134 ctx.RunGC() 135 for _, d := range ctx.directories { 136 d.reset() 137 } 138 } 139 140 func (ctx *RktRunCtx) cleanupChildren() error { 141 for _, child := range ctx.children { 142 if child.Cmd.ProcessState.Exited() { 143 logger.Logf("Child %q already exited", child.Cmd.Path) 144 continue 145 } 146 logger.Logf("Shutting down child %q", child.Cmd.Path) 147 if err := child.Cmd.Process.Kill(); err != nil { 148 return err 149 } 150 if _, err := child.Cmd.Process.Wait(); err != nil { 151 return err 152 } 153 } 154 return nil 155 } 156 157 func (ctx *RktRunCtx) Cleanup() { 158 if ctx.mds != nil { 159 ctx.mds.Process.Kill() 160 ctx.mds.Wait() 161 os.Remove("/run/rkt/metadata-svc.sock") 162 } 163 if err := ctx.cleanupChildren(); err != nil { 164 logger.Logf("Error during child cleanup: %v", err) 165 } 166 ctx.RunGC() 167 for _, d := range ctx.directories { 168 d.cleanup() 169 } 170 } 171 172 func (ctx *RktRunCtx) RunGC() { 173 rktArgs := append(ctx.rktOptions(), 174 "gc", 175 "--grace-period=0s", 176 ) 177 if err := exec.Command(ctx.rktBin(), rktArgs...).Run(); err != nil { 178 panic(fmt.Sprintf("Failed to run gc: %v", err)) 179 } 180 } 181 182 func (ctx *RktRunCtx) Cmd() string { 183 return fmt.Sprintf("%s %s", 184 ctx.rktBin(), 185 strings.Join(ctx.rktOptions(), " "), 186 ) 187 } 188 189 // TODO(jonboulle): clean this up 190 func (ctx *RktRunCtx) CmdNoConfig() string { 191 return fmt.Sprintf("%s %s", 192 ctx.rktBin(), 193 ctx.directories[0].rktOption(), 194 ) 195 } 196 197 func (ctx *RktRunCtx) rktBin() string { 198 rkt := GetValueFromEnvOrPanic("RKT") 199 abs, err := filepath.Abs(rkt) 200 if err != nil { 201 abs = rkt 202 } 203 return abs 204 } 205 206 func (ctx *RktRunCtx) rktOptions() []string { 207 ctx.ensureValid() 208 opts := make([]string, 0, len(ctx.directories)) 209 for _, d := range ctx.directories { 210 opts = append(opts, d.rktOption()) 211 } 212 return opts 213 } 214 215 func (ctx *RktRunCtx) ensureValid() { 216 for _, d := range ctx.directories { 217 d.ensureValid() 218 } 219 } 220 221 func (ctx *RktRunCtx) RegisterChild(child *gexpect.ExpectSubprocess) { 222 ctx.children = append(ctx.children, child) 223 }