github.com/masahide/goansible@v0.0.0-20160116054156-01eac649e9f2/goansible.go (about) 1 package goansible 2 3 /* 4 import ( 5 "bufio" 6 "bytes" 7 "fmt" 8 "io" 9 "os" 10 "os/exec" 11 "path/filepath" 12 "strconv" 13 "strings" 14 ) 15 16 var cUpdateScript = []byte(`#!/bin/bash 17 18 cd .goansible 19 20 REL=$TACHYON_RELEASE 21 BIN=goansible-$TACHYON_OS-$TACHYON_ARCH 22 23 if test -f goansible; then 24 CUR=$(< release) 25 if test "$REL" != "$CUR"; then 26 echo "Detected goansible of old release ($CUR), removing." 27 rm goansible 28 fi 29 fi 30 31 if which curl > /dev/null; then 32 DL="curl -O" 33 elif which wget > /dev/null; then 34 DL="wget" 35 else 36 echo "No curl or wget, unable to pull a release" 37 exit 1 38 fi 39 40 if ! test -f goansible; then 41 echo "Downloading $REL/$BIN..." 42 43 $DL https://s3-us-west-2.amazonaws.com/goansible.vektra.io/$REL/sums 44 if which gpg > /dev/null; then 45 gpg --keyserver keys.gnupg.net --recv-key A408199F & 46 $DL https://s3-us-west-2.amazonaws.com/goansible.vektra.io/$REL/sums.asc & 47 fi 48 49 $DL https://s3-us-west-2.amazonaws.com/goansible.vektra.io/$REL/$BIN 50 51 wait 52 53 if which gpg > /dev/null; then 54 if ! gpg --verify sums.asc; then 55 echo "Signature verification failed! Aborting!" 56 exit 1 57 fi 58 fi 59 60 mv $BIN $BIN.gz 61 62 # If gunzip fails, it's because the file isn't gzip'd, so we 63 # assume it's already in the correct format. 64 if ! gunzip $BIN.gz; then 65 mv $BIN.gz $BIN 66 fi 67 68 if which shasum > /dev/null; then 69 if ! (grep $BIN sums | shasum -c); then 70 echo "Sum verification failed!" 71 exit 1 72 fi 73 else 74 echo "No shasum available to verify files" 75 fi 76 77 echo $REL > release 78 79 chmod a+x $BIN 80 ln -s $BIN goansible 81 fi 82 `) 83 84 func normalizeArch(arch string) string { 85 switch arch { 86 case "x86_64": 87 return "amd64" 88 default: 89 return arch 90 } 91 } 92 93 type Tachyon struct { 94 Target string `goansible:"target"` 95 Debug bool `goansible:"debug"` 96 Output bool `goansible:"output"` 97 Clean bool `goansible:"clean"` 98 Dev bool `goansible:"dev"` 99 Playbook string `goansible:"playbook"` 100 Release string `goansible:"release"` 101 NoJSON bool `goansible:"no_json"` 102 InstallOnly bool `goansible:"install_only"` 103 } 104 105 func (t *Tachyon) ShowOutput() bool { return t.Output } 106 func (t *Tachyon) ShowDebug() bool { return t.Debug } 107 108 func (t *Tachyon) Run(env *CommandEnv) (*Result, error) { 109 if t.Release == "" { 110 t.Release = Release 111 } 112 113 ssh := NewSSH(t.Target) 114 ssh.Debug = t.Debug 115 116 defer ssh.Cleanup() 117 118 // err := ssh.Start() 119 // if err != nil { 120 // return nil, fmt.Errorf("Error starting persistent SSH connection: %s\n", err) 121 // } 122 123 var bootstrap string 124 125 if t.Clean { 126 bootstrap = "rm -rf .goansible && mkdir -p .goansible" 127 } else { 128 bootstrap = "mkdir -p .goansible" 129 } 130 131 out, err := ssh.RunAndCapture(bootstrap + " && uname && uname -m") 132 if err != nil { 133 return nil, fmt.Errorf("Error creating remote .goansible dir: %s (%s)", err, string(out)) 134 } 135 136 tos, arch, ok := split2(string(out), "\n") 137 if !ok { 138 return nil, fmt.Errorf("Unable to figure out os and arch of remote machine\n") 139 } 140 141 tos = strings.ToLower(tos) 142 arch = normalizeArch(strings.TrimSpace(arch)) 143 144 binary := fmt.Sprintf("goansible-%s-%s", tos, arch) 145 146 if t.Dev { 147 env.Progress("Copying development goansible...") 148 149 path := filepath.Dir(Arg0) 150 151 err = ssh.CopyToHost(filepath.Join(path, binary), ".goansible/"+binary+".new") 152 if err != nil { 153 return nil, fmt.Errorf("Error copying goansible to vagrant: %s\n", err) 154 } 155 156 ssh.Run(fmt.Sprintf("cd .goansible && mv %[1]s.new %[1]s && ln -fs %[1]s goansible", binary)) 157 } else { 158 env.Progress("Updating goansible release...") 159 160 c := ssh.Command("cat > .goansible/update && chmod a+x .goansible/update") 161 162 c.Stdout = os.Stdout 163 c.Stdin = bytes.NewReader(cUpdateScript) 164 err = c.Run() 165 if err != nil { 166 return nil, fmt.Errorf("Error updating, well, the updater: %s\n", err) 167 } 168 169 cmd := fmt.Sprintf("TACHYON_RELEASE=%s TACHYON_OS=%s TACHYON_ARCH=%s ./.goansible/update", t.Release, tos, arch) 170 err = ssh.Run(cmd) 171 if err != nil { 172 return nil, fmt.Errorf("Error running updater: %s", err) 173 } 174 } 175 176 if t.InstallOnly { 177 res := NewResult(true) 178 res.Add("target", t.Target) 179 res.Add("install_only", true) 180 181 return res, nil 182 } 183 184 var src string 185 186 var main string 187 188 fi, err := os.Stat(t.Playbook) 189 if err != nil { 190 return nil, err 191 } 192 193 if fi.IsDir() { 194 src, err = filepath.Abs(t.Playbook) 195 if err != nil { 196 return nil, fmt.Errorf("Unable to resolve %s: %s", t.Playbook, err) 197 } 198 main = "site.yml" 199 } else { 200 abs, err := filepath.Abs(t.Playbook) 201 if err != nil { 202 return nil, fmt.Errorf("Unable to resolve %s: %s", t.Playbook, err) 203 } 204 205 main = filepath.Base(abs) 206 src = filepath.Dir(abs) 207 } 208 209 src += "/" 210 211 env.Progress("Syncing playbook...") 212 213 c := exec.Command("rsync", "-av", "-e", ssh.RsyncCommand(), src, ssh.Host+":.goansible/playbook") 214 215 if t.Debug { 216 c.Stdout = os.Stdout 217 } 218 219 err = c.Run() 220 221 if err != nil { 222 return nil, fmt.Errorf("Error copying playbook to vagrant: %s\n", err) 223 } 224 225 env.Progress("Running playbook...") 226 227 var format string 228 229 if !t.NoJSON { 230 format = "--json" 231 } 232 233 startCmd := fmt.Sprintf("cd .goansible && sudo ./goansible %s playbook/%s", format, main) 234 235 c = ssh.Command(startCmd) 236 237 if t.Debug { 238 fmt.Fprintf(os.Stderr, "Run: %#v\n", c.Args) 239 } 240 241 stream, err := c.StdoutPipe() 242 if err != nil { 243 return nil, err 244 } 245 246 c.Stderr = os.Stderr 247 248 c.Start() 249 250 input := bufio.NewReader(stream) 251 252 for { 253 str, err := input.ReadString('\n') 254 if err != nil { 255 break 256 } 257 258 sz, err := strconv.Atoi(strings.TrimSpace(str)) 259 if err != nil { 260 break 261 } 262 263 data := make([]byte, sz) 264 265 _, err = input.Read(data) 266 if err != nil { 267 break 268 } 269 270 _, err = input.ReadByte() 271 if err != nil { 272 break 273 } 274 275 env.progress.JSONProgress(data) 276 } 277 278 if err != nil { 279 if err != io.EOF { 280 fmt.Printf("error: %s\n", err) 281 } 282 } 283 284 err = c.Wait() 285 if err != nil { 286 return nil, fmt.Errorf("Error running playbook remotely: %s", err) 287 } 288 289 res := NewResult(true) 290 res.Add("target", t.Target) 291 res.Add("playbook", t.Playbook) 292 293 return res, nil 294 } 295 296 func init() { 297 RegisterCommand("goansible", &Tachyon{}) 298 } 299 */