From b72b2d557fa4b4972ebb8d00571afd65a78bdec5 Mon Sep 17 00:00:00 2001 From: Ivo Jimenez Date: Sat, 9 Sep 2017 01:55:00 -0700 Subject: [PATCH] fixes #149 fixes #155 --- popper/_check/Dockerfile | 7 +++ popper/_check/check.py | 108 +++++++++++++++++++++++++++++++++++++++ popper/check.go | 83 +++++++++--------------------- popper/ci.go | 4 +- popper/update.go | 2 +- popper/version.go | 2 +- 6 files changed, 145 insertions(+), 61 deletions(-) create mode 100644 popper/_check/Dockerfile create mode 100755 popper/_check/check.py diff --git a/popper/_check/Dockerfile b/popper/_check/Dockerfile new file mode 100644 index 000000000..be6cd9de0 --- /dev/null +++ b/popper/_check/Dockerfile @@ -0,0 +1,7 @@ +FROM python:2.7-alpine +RUN apk add --no-cache curl bash && \ + curl -SL https://download.docker.com/linux/static/stable/x86_64/docker-17.06.2-ce.tgz | tar -xzv docker/docker && \ + mv docker/docker /usr/bin && \ + rm -r docker/ +ADD check.py / +ENTRYPOINT ["/check.py"] diff --git a/popper/_check/check.py b/popper/_check/check.py new file mode 100755 index 000000000..5bb20c77e --- /dev/null +++ b/popper/_check/check.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python + +import argparse +import os +import subprocess +import time +import signal +import sys + +from subprocess import check_output +from os import path + +stages = ['setup.sh', 'run.sh', 'post-run.sh', 'validate.sh', 'teardown.sh'] + + +def execute(stage, timeout): + time_limit = time.time() + timeout + + out_fname = 'popper_logs/{}.{}'.format(stage, 'out') + err_fname = 'popper_logs/{}.{}'.format(stage, 'err') + + sys.stdout.write('Running stage: ' + stage + ' ') + + with open(out_fname, "wb") as outf, open(err_fname, "wb") as errf: + p = subprocess.Popen('./' + stage, shell=True, stdout=outf, stderr=errf, + preexec_fn=os.setsid) + + while p.poll() is None: + sys.stdout.write('.') + + if time.time() > time_limit: + os.killpg(os.getpgid(p.pid), signal.SIGTERM) + sys.stdout.write(' time out!') + break + + time.sleep(20) + + sys.stdout.write('\n') + + return p.poll() + + +def check_experiment(skip, timeout): + check_output('rm -rf popper_logs/ popper_status', shell=True) + check_output('mkdir -p popper_logs/', shell=True) + + STATUS = "SUCCESS" + + for stage in stages: + + if not path.isfile(stage): + continue + + if skip and stage in skip.split(','): + continue + + ecode = execute(stage, timeout) + + if ecode != 0: + print("Stage {} failed. Check logs for details.".format(stage)) + STATUS = "FAIL" + break + + if stage == 'validate.sh': + STATUS = "GOLD" + with open('popper_logs/validate.sh.out', 'r') as f: + validate_output = f.readlines() + if len(validate_output) == 0: + STATUS = "SUCCESS" + for line in validate_output: + if '[true]' not in line: + STATUS = "SUCCESS" + + with open('popper_status', 'w') as f: + f.write(STATUS + '\n') + + print('status: ' + STATUS) + + +class Unbuffered(object): + def __init__(self, stream): + self.stream = stream + + def write(self, data): + self.stream.write(data) + self.stream.flush() + + def __getattr__(self, attr): + return getattr(self.stream, attr) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument('--timeout', default=10800, help='Timeout in seconds.') + parser.add_argument('--skip', default=None, required=False, + help='Comma-separated list of stages to skip.') + args = parser.parse_args() + sys.stdout = Unbuffered(sys.stdout) + + if path.isdir('./experiments'): + for f in os.listdir('experiments'): + if not f.startswith('.') and path.isdir('experiments/' + f): + print('\nChecking experiment ' + f) + os.chdir('experiments/' + f) + check_experiment(args.skip, int(args.timeout)) + os.chdir('../../') + else: + check_experiment(args.skip, int(args.timeout)) diff --git a/popper/check.go b/popper/check.go index 9ed2bc13f..132b7900c 100644 --- a/popper/check.go +++ b/popper/check.go @@ -1,9 +1,8 @@ package main import ( - "fmt" - "io/ioutil" "log" + "os" "strings" sh "github.com/codeskyblue/go-sh" @@ -14,68 +13,36 @@ var environment []string var volumes []string var skip string var timeout string -var checksh = `#!/bin/bash -set -e -type docker >/dev/null 2>&1 || { echo >&2 "Can't find docker command."; exit 1; } - -docker_path="" - -if [ $OSTYPE == "linux-gnu" ] ; then - docker_path=$(which docker) - libltdl_path=$(ldd $docker_path | grep libltdl | awk '{print $3}') - if [ -n "$libltdl_path" ] ; then - libltdl_path="--volume $libltdl_path:/usr/lib/$(basename $libltdl_path)" - fi -elif [[ $OSTYPE == *"darwin"* ]]; then - docker_path="/usr/bin/docker" - libltdl_path="" -else - echo "Unrecognized OS: $OSTYPE" - exit 1 -fi - -echo "Popper check started" -docker run --rm -i %s \ - $libltdl_path \ - --volume $PWD:$PWD \ - --volume $docker_path:/usr/bin/docker \ - --volume /var/run/docker.sock:/var/run/docker.sock \ - --workdir $PWD \ - ivotron/popperci-experimenter %s %s -echo "Popper check finished" -` - -func writePopperCheckScript() { - - env := "" - if len(environment) > 0 { - env += " -e " + strings.Join(environment, " -e ") - } - if len(volumes) > 0 { - env += " -v " + strings.Join(volumes, " -v ") - } - var content string - if len(skip) > 0 { - content = fmt.Sprintf(checksh, env, "--timeout "+timeout, "--skip "+skip) - } else { - content = fmt.Sprintf(checksh, env, "--timeout "+timeout, "") - } - err := ioutil.WriteFile("/tmp/poppercheck", []byte(content), 0755) - if err != nil { - log.Fatalln("Error writing bash script to /tmp") - } -} var checkCmd = &cobra.Command{ Use: "check", - Short: "Run experiment and check integrity (status) of experiment", + Short: "Run experiment and report on its integrity (status)", Long: ``, Run: func(cmd *cobra.Command, args []string) { - if len(args) > 0 { - log.Fatalln("This command doesn't take arguments") + + env := "" + if len(environment) > 0 { + env += " -e " + strings.Join(environment, " -e ") + } + if len(volumes) > 0 { + env += " -v " + strings.Join(volumes, " -v ") + } + cmd_args := []string{"run", "--rm", "-i"} + cmd_args = append(cmd_args, strings.Fields(env)...) + dir, err := os.Getwd() + if err != nil { + log.Fatal(err) + } + cmd_args = append(cmd_args, "--volume", dir+":"+dir, "--workdir", dir, "--volume", "/var/run/docker.sock:/var/run/docker.sock", "ivotron/poppercheck", "--timeout", timeout) + if len(skip) > 0 { + cmd_args = append(cmd_args, "--skip="+skip) + } + + s := make([]interface{}, len(cmd_args)) + for i, v := range cmd_args { + s[i] = v } - writePopperCheckScript() - if err := sh.Command("/tmp/poppercheck").Run(); err != nil { + if err := sh.Command("docker", s...).Run(); err != nil { log.Fatalln(err) } }, diff --git a/popper/ci.go b/popper/ci.go index 4c6818dd0..195bc5457 100644 --- a/popper/ci.go +++ b/popper/ci.go @@ -3,6 +3,7 @@ package main import ( "io/ioutil" "log" + "fmt" "github.com/spf13/cobra" ) @@ -39,10 +40,11 @@ var ciTravisCmd = &cobra.Command{ log.Fatalln("This command does not take arguments.") } ensureRootFolder() - err := ioutil.WriteFile("./.travis.yml", []byte(travisYaml), 0755) + err := ioutil.WriteFile("./.travis.yml", []byte(travisYaml), 0644) if err != nil { log.Fatalln("Error writing .travis.yml") } + fmt.Println("Created .travis.yml file.") }, } diff --git a/popper/update.go b/popper/update.go index 0c66bca67..d9b17dd8b 100644 --- a/popper/update.go +++ b/popper/update.go @@ -19,7 +19,7 @@ var updateCmd = &cobra.Command{ if err := updateTemplates(); err != nil { log.Fatalln(err) } - if err := sh.Command("docker", "pull", "ivotron/popperci-experimenter").Run(); err != nil { + if err := sh.Command("docker", "pull", "ivotron/poppercheck").Run(); err != nil { log.Fatalln(err) } fmt.Println("Updated Popper repository successfully.") diff --git a/popper/version.go b/popper/version.go index f2744552f..567c36b70 100644 --- a/popper/version.go +++ b/popper/version.go @@ -6,7 +6,7 @@ import ( "github.com/spf13/cobra" ) -var versionId = "0.4" +var versionId = "0.5-dev" var versionCmd = &cobra.Command{ Use: "version",