grim/convey

2c339dc89014
Parents 310962069a9a
Children aaf0c394ff02
Clean up the complexity of docker/run.go
  • +143 -121
    docker/run.go
  • --- a/docker/run.go Sun Jan 14 04:07:43 2018 -0600
    +++ b/docker/run.go Sun Jan 14 04:39:16 2018 -0600
    @@ -95,7 +95,28 @@
    {{.Image}}{{if .Command}} {{.Command}}{{end}}`
    // writeScript will write a shell script to the given tempfile for the given commands
    -func (r *Run) writeScript(st *state.State, script *os.File, fullEnv []string) (string, string, string, error) {
    +func (r *Run) writeScript(st *state.State, fullEnv []string) (string, string, string, error) {
    + // figure out the current working directory
    + pwd, err := os.Getwd()
    + if err != nil {
    + return "", "", "", err
    + }
    +
    + // now get the absolute path
    + absPwd, err := filepath.Abs(pwd)
    + if err != nil {
    + return "", "", "", err
    + }
    +
    + // create the temp file to write the script to
    + script, err := ioutil.TempFile(absPwd, "convey-script-")
    + if err != nil {
    + return "", "", "", err
    + }
    +
    + // set scriptFile to the name of the temp file
    + scriptFile := script.Name()
    +
    entryPoint := r.Shell
    if entryPoint == "" {
    entryPoint = "/bin/sh"
    @@ -108,12 +129,10 @@
    // bash if you need that kind of control.
    scripts, err := environment.SliceMapper(r.Script, fullEnv)
    if err != nil {
    + os.Remove(scriptFile)
    return "", "", "", err
    }
    - // set scriptFile to the name of the temp file
    - scriptFile := script.Name()
    -
    // set the run command argument to the script file
    commandArg := scriptFile
    @@ -128,6 +147,115 @@
    return scriptFile, entryPoint, commandArg, nil
    }
    +// detach will run the container detached
    +func (r *Run) detach(name, runTemplate string, params map[string]interface{}, st *state.State, logger *gomol.LogAdapter) error {
    + stdout, stderr, err := DockerOutput(name, runTemplate, params, st)
    + if err != nil {
    + logger.Errorf("%s", stderr)
    +
    + return err
    + }
    +
    + cid := strings.TrimSpace(stdout)
    + st.MarkDetached(cid)
    +
    + logger.Infof("started detached container %s", cid)
    +
    + logger.Infof("checking for healthcheck")
    +
    + // check if the container has a health check
    + hasHealth, err := containerHasHealthCheck(name, cid, st, logger)
    + if err != nil {
    + return err
    + }
    +
    + if hasHealth {
    + healthChan := make(chan error)
    +
    + logger.Infof("waiting for container to go healthy")
    +
    + go func() {
    + duration := 5 * time.Second
    +
    + for {
    + // check the health
    + healthy, err := containerIsHealthy(name, cid, st, logger)
    + if err != nil {
    + healthChan <- err
    + }
    +
    + if healthy {
    + healthChan <- nil
    + }
    +
    + logger.Infof("container still not healthy, waiting %v", duration)
    +
    + time.Sleep(duration)
    + }
    + }()
    +
    + err := <-healthChan
    + if err != nil {
    + return err
    + }
    +
    + logger.Infof("container is ready")
    + } else {
    + logger.Infof("no healthcheck found")
    + }
    +
    + return nil
    +}
    +
    +func (r *Run) mapVariables(fullEnv []string, st *state.State, workSpace string) (map[string]interface{}, error) {
    + dockerWorkspace := st.Workspace.(*Workspace)
    +
    + username, err := environment.Mapper(r.User, fullEnv)
    + if err != nil {
    + return nil, err
    + }
    +
    + image, err := environment.Mapper(r.Image, fullEnv)
    + if err != nil {
    + return nil, err
    + }
    +
    + hostname, err := environment.Mapper(r.Hostname, fullEnv)
    + if err != nil {
    + return nil, err
    + }
    +
    + labels, err := st.MapSlice(r.Labels, fullEnv)
    + if err != nil {
    + return nil, err
    + }
    +
    + workdir, err := environment.Mapper(r.WorkDir, fullEnv)
    + if err != nil {
    + return nil, err
    + }
    +
    + workspacePath, err := environment.Mapper(dockerWorkspace.mountPoint, fullEnv)
    + if err != nil {
    + return nil, err
    + }
    +
    + workspaceMount, err := environment.Mapper(workSpace, fullEnv)
    + if err != nil {
    + return nil, err
    + }
    +
    + return map[string]interface{}{
    + "username": username,
    + "image": image,
    + "hostname": hostname,
    + "labels": labels,
    + "workdir": workdir,
    + "workspacePath": workspacePath,
    + "workspaceMount": workspaceMount,
    + }, nil
    +}
    +
    // Execute runs the run task.
    func (r *Run) Execute(name string, logger *gomol.LogAdapter, env []string, st *state.State) error {
    fullEnv := environment.Merge(env, r.Environment)
    @@ -165,77 +293,26 @@
    // if we're using a script defined in the yaml, create it and override
    // some variables
    if len(r.Script) > 0 {
    - // figure out the current working directory
    - pwd, err := os.Getwd()
    - if err != nil {
    - return err
    - }
    -
    - // now get the absolute path
    - absPwd, err := filepath.Abs(pwd)
    - if err != nil {
    - return err
    - }
    -
    - // create the temp file to write the script to
    - script, err := ioutil.TempFile(absPwd, "convey-script-")
    + scriptFile, entryPoint, commandArg, err = r.writeScript(st, fullEnv)
    if err != nil {
    return err
    }
    // Be sure to clean up the script on app exit
    - cleanupFn := st.CleanupList.Add(func() { os.Remove(script.Name()) })
    + cleanupFn := st.CleanupList.Add(func() { os.Remove(scriptFile) })
    // Call cleanup function on defer, which may instead be called
    // if the cleanup thread traps a signal.
    defer cleanupFn()
    -
    - scriptFile, entryPoint, commandArg, err = r.writeScript(st, script, fullEnv)
    - if err != nil {
    - return err
    - }
    }
    taskLabel := normalize.Normalize(
    fmt.Sprintf("convey-%d-task=%s", os.Getpid(), name),
    )
    - dockerWorkspace := st.Workspace.(*Workspace)
    -
    //
    // Map variables
    -
    - username, err := environment.Mapper(r.User, fullEnv)
    - if err != nil {
    - return err
    - }
    -
    - image, err := environment.Mapper(r.Image, fullEnv)
    - if err != nil {
    - return err
    - }
    -
    - hostname, err := environment.Mapper(r.Hostname, fullEnv)
    - if err != nil {
    - return err
    - }
    -
    - labels, err := st.MapSlice(r.Labels, fullEnv)
    - if err != nil {
    - return err
    - }
    -
    - workdir, err := environment.Mapper(r.WorkDir, fullEnv)
    - if err != nil {
    - return err
    - }
    -
    - workspacePath, err := environment.Mapper(dockerWorkspace.mountPoint, fullEnv)
    - if err != nil {
    - return err
    - }
    -
    - workspaceMount, err := environment.Mapper(workSpace, fullEnv)
    + vars, err := r.mapVariables(fullEnv, st, workSpace)
    if err != nil {
    return err
    }
    @@ -248,84 +325,29 @@
    "Command": commandArg,
    "CPUShares": st.CPUShares,
    "Detach": r.Detach,
    - "Hostname": hostname,
    + "Hostname": vars["hostname"],
    "Environment": environment.Prune(fullEnv),
    "EntryPoint": entryPoint,
    - "Username": username,
    + "Username": vars["username"],
    "UID": user.Uid,
    "GID": user.Gid,
    "HealthCheck": r.HealthCheck,
    - "Image": image,
    - "Labels": labels,
    + "Image": vars["image"],
    + "Labels": vars["labels"],
    "Memory": st.Memory,
    "Network": st.Network.Name(),
    "ScriptFile": scriptFile,
    "SSHAgent": st.EnableSSHAgent,
    "SSHAuthSock": os.Getenv("SSH_AUTH_SOCK"),
    - "WorkDir": workdir,
    - "WorkspacePath": workspacePath,
    - "WorkspaceMount": workspaceMount,
    + "WorkDir": vars["workdir"],
    + "WorkspacePath": vars["workspacePath"],
    + "WorkspaceMount": vars["workspaceMount"],
    "TaskLabel": taskLabel,
    "Name": runID,
    }
    if r.Detach {
    - stdout, stderr, err := DockerOutput(name, runTemplate, params, st)
    - if err != nil {
    - logger.Errorf("%s", stderr)
    -
    - return err
    - }
    -
    - cid := strings.TrimSpace(stdout)
    - st.MarkDetached(cid)
    -
    - logger.Infof("started detached container %s", cid)
    -
    - logger.Infof("checking for healthcheck")
    -
    - // check if the container has a health check
    - hasHealth, err := containerHasHealthCheck(name, cid, st, logger)
    - if err != nil {
    - return err
    - }
    -
    - if hasHealth {
    - healthChan := make(chan error)
    -
    - logger.Infof("waiting for container to go healthy")
    -
    - go func() {
    - duration := 5 * time.Second
    -
    - for {
    - // check the health
    - healthy, err := containerIsHealthy(name, cid, st, logger)
    - if err != nil {
    - healthChan <- err
    - }
    -
    - if healthy {
    - healthChan <- nil
    - }
    -
    - logger.Infof("container still not healthy, waiting %v", duration)
    -
    - time.Sleep(duration)
    - }
    - }()
    -
    - err := <-healthChan
    - if err != nil {
    - return err
    - }
    -
    - logger.Infof("container is ready")
    - } else {
    - logger.Infof("no healthcheck found")
    - }
    -
    - return nil
    + return r.detach(name, runTemplate, params, st, logger)
    }
    // Mark running so we can detach this container form the network