Skip to content

Commit

Permalink
Adds popper check environments
Browse files Browse the repository at this point in the history
This adds the ability to run popper check in multiple environments.
Docker and the host are supported as of now but this can be extended.

fixes #167
  • Loading branch information
ivotron committed Oct 15, 2017
1 parent 25bac00 commit f7ecd32
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 54 deletions.
18 changes: 0 additions & 18 deletions popper/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,12 @@ package main
import (
"fmt"
"log"
"path"
"strings"

sh "github.com/codeskyblue/go-sh"
"github.com/spf13/cobra"
)

func getRepoInfo() (user, repo string, err error) {
remoteURL, err := sh.Command(
"git", "config", "--get", "remote.origin.url").Output()
if err != nil {
return
}
urlAndUser, repo := path.Split(string(remoteURL))

// get the user or org name
user = path.Base(strings.Replace(urlAndUser, ":", "/", -1))

// trim and remove .git extension, if present
repo = strings.TrimSuffix(strings.TrimSpace(repo), ".git")

return
}

func addExperiment(templateType string, templateName string, folder string) {
checkTemplateFolderExists(templateType)

Expand Down
117 changes: 84 additions & 33 deletions popper/check.go
Original file line number Diff line number Diff line change
@@ -1,62 +1,113 @@
package main

import (
"fmt"
"log"
"os"
"strings"

sh "github.com/codeskyblue/go-sh"
"github.com/spf13/cobra"
"github.com/theherk/viper"
)

var environment []string
var volumes []string
var volume []string
var skip string
var timeout string

func runOnHost(checkFlags []string) {
s := make([]interface{}, len(checkFlags))
for i, v := range checkFlags {
s[i] = v
}
if err := sh.Command(popperFolder+"/popper/_check/check.py", s...).Run(); err != nil {
log.Fatalln(err)
}
}

func runInDocker(checkFlags []string, checkEnv string) {
dockerFlags := ""
if len(environment) > 0 {
dockerFlags += " -e " + strings.Join(environment, " -e ")
}
if len(volume) > 0 {
dockerFlags += " -v " + strings.Join(volume, " -v ")
}
cmd_args := []string{"run", "--rm", "-i"}
cmd_args = append(cmd_args, strings.Fields(dockerFlags)...)
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:"+checkEnv)

s := make([]interface{}, len(cmd_args)+len(checkFlags))
for i, v := range cmd_args {
s[i] = v
}
for i, v := range checkFlags {
s[i+len(cmd_args)] = v
}
if err := sh.Command("docker", s...).Run(); err != nil {
log.Fatalln(err)
}
}

func runCheck() {
expName, err := getExperimentName()
if err != nil {
log.Fatalln(err)
}
err = readPopperConfig()
if err != nil {
log.Fatalln(err)
}

checkEnv := ""
if !viper.IsSet("envs." + expName) {
fmt.Println("No environment in .popper.yml, using default (alpine-3.4)")
checkEnv = "alpine-3.4"
} else {
checkEnv = viper.GetString("envs." + expName)
}

checkFlags := []string{"--timeout=" + timeout}
if len(skip) > 0 {
checkFlags = append(checkFlags, "--skip="+skip)
}

if checkEnv == "host" {
runOnHost(checkFlags)
} else {
runInDocker(checkFlags, checkEnv)
}
}

var checkCmd = &cobra.Command{
Use: "check",
Short: "Run experiment and report on its status",
Long: `Executes an experiment in its own isolated environment (docker container).
Environment variables and folders can be made available inside the experiment's environment
using -e and -v flags respectively. These are analogous to Docker's flags and are passed
down to the 'docker run' command. The experiment folder is always passed to the experiment
environment.`,
Long: `Executes an experiment in its corresponding environment (host or docker). If using docker,
environment variables and folders can be made available inside the container by using -e
and -v flags respectively. These flags are passed down to the 'docker run' command. The
experiment folder is bind-mounted. If the environment is 'host', the -v and -e flags are
ignored.`,
Run: func(cmd *cobra.Command, args []string) {

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
}
if err := sh.Command("docker", s...).Run(); err != nil {
log.Fatalln(err)
if len(args) != 0 {
log.Fatalln("This command doesn't take arguments.")
}
runCheck()
},
}

func init() {
RootCmd.AddCommand(checkCmd)

checkCmd.Flags().StringSliceVarP(&environment, "environment", "e", []string{}, "Environment variables available to the experiment.")
checkCmd.Flags().StringSliceVarP(&volumes, "volume", "v", []string{}, "Volumes available to the experiment.")
checkCmd.Flags().StringSliceVarP(&environment, "environment", "e", []string{}, `Environment variable available to the experiment. Can be
given multiple times. This flag is ignored when the environment
is 'host'.`)
checkCmd.Flags().StringSliceVarP(&volume, "volume", "v", []string{}, `Volume available to the experiment. Can be given multiple times
This flag is ignored when the environment is 'host'.`)
checkCmd.Flags().StringVarP(&skip, "skip", "s", "", "Comma-separated list of stages to skip.")
checkCmd.Flags().StringVarP(&timeout, "timeout", "t", "36000", "Timeout limit for experiment in seconds.")
}
19 changes: 18 additions & 1 deletion popper/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ import (

sh "github.com/codeskyblue/go-sh"
"github.com/spf13/cobra"
"github.com/theherk/viper"
)

var envFlagValue string

var setupSh = []byte(`#!/bin/bash
# Any setup required by the experiment goes here. Things like installing
# packages, allocating resources or deploying software on remote
Expand Down Expand Up @@ -86,10 +89,23 @@ func initExperiment(name string) {
log.Fatalln(err)
}

// add environment to .popper.yml
err := readPopperConfig()
if err != nil {
log.Fatalln(err)
}
values := map[string]string{}
if viper.IsSet("envs") {
values = viper.GetStringMapString("envs")
}
values[name] = envFlagValue
viper.Set("envs", values)
viper.WriteConfig()

// add README
readme := "# " + name + "\n"

err := ioutil.WriteFile("experiments/"+name+"/README.md", []byte(readme), 0644)
err = ioutil.WriteFile("experiments/"+name+"/README.md", []byte(readme), 0644)
if err != nil {
log.Fatalln(err)
}
Expand Down Expand Up @@ -127,5 +143,6 @@ name is 'paper', then a 'paper' folder is created. Otherwise, an experiment name
}

func init() {
initCmd.Flags().StringVarP(&envFlagValue, "env", "e", "alpine-3.4", "Environment where popper check will run.")
RootCmd.AddCommand(initCmd)
}
71 changes: 69 additions & 2 deletions popper/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@ import (
"fmt"
"log"
"os"
"path"
"strings"

"github.com/casimir/xdg-go"
"github.com/codeskyblue/go-sh"
sh "github.com/codeskyblue/go-sh"
"github.com/spf13/cobra"
"github.com/theherk/viper"
"github.com/casimir/xdg-go"
)

var showVersion bool
Expand Down Expand Up @@ -61,17 +64,81 @@ func getTemplates() (org_repo_branch string, err error) {
}

func ensureExperimentFolder() {
if sh.Test("file", ".popper.yml") {
log.Fatalln("File .popper.yml already exists")
}
if !sh.Test("dir", "../../experiments") {
log.Fatalln("Not inside an experiment folder, 'cd' into one first.")
}
}

func getExperimentPath() (dir string, err error) {
ensureExperimentFolder()
dir, err = os.Getwd()
if err != nil {
return
}
return
}

func getRepoInfo() (user, repo string, err error) {
remoteURL, err := sh.Command(
"git", "config", "--get", "remote.origin.url").Output()
if err != nil {
return
}
urlAndUser, repo := path.Split(string(remoteURL))

// get the user or org name
user = path.Base(strings.Replace(urlAndUser, ":", "/", -1))

// trim and remove .git extension, if present
repo = strings.TrimSuffix(strings.TrimSpace(repo), ".git")

return
}

func getProjectPath() (projectPath string, err error) {
if sh.Test("dir", "experiments") {
projectPath, err = os.Getwd()
} else if sh.Test("dir", "../../experiments") {
expPath, err := os.Getwd()
if err == nil {
projectPath = expPath + "/../../"
}
} else {
// TODO: create an error
log.Fatalln("Cannot identify project folder.")
}
return
}

func getExperimentName() (expName string, err error) {
dir, err := getExperimentPath()
expName = path.Base(dir)
return
}

func ensureRootFolder() {
if !sh.Test("dir", "experiments") {
log.Fatalln("Can't find experiments/ folder in current directory, 'cd' into project root folder first.")
}
}

func readPopperConfig() (err error) {
projectPath, err := getProjectPath()
if err != nil {
return
}
viper.AddConfigPath(projectPath)
viper.SetConfigName(".popper")
viper.SetConfigType("yaml")
if err = viper.ReadInConfig(); err != nil {
log.Fatalln(err)
}
return
}

func init() {
RootCmd.Flags().BoolVarP(
&showVersion, "version", "v", false,
Expand Down

0 comments on commit f7ecd32

Please sign in to comment.