111 lines
2.7 KiB
Go
111 lines
2.7 KiB
Go
package jobrunner
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
|
|
"github.com/docker/docker/api/types"
|
|
"github.com/docker/docker/api/types/container"
|
|
"github.com/docker/docker/api/types/mount"
|
|
"github.com/docker/docker/client"
|
|
"github.com/docker/docker/pkg/stdcopy"
|
|
"github.com/op/go-logging"
|
|
)
|
|
|
|
var log = logging.MustGetLogger("cursorius-server")
|
|
|
|
type Job struct {
|
|
Id string
|
|
URL string
|
|
}
|
|
|
|
func RunJob(job Job, workingDir string) error {
|
|
jobFolder := filepath.Join(workingDir, job.Id)
|
|
|
|
log.Debugf("Job %v configured with URL \"%v\"", job.Id, job.URL)
|
|
|
|
log.Debugf("Job %v configured with folder \"%v\"", job.Id, jobFolder)
|
|
|
|
err := os.RemoveAll(jobFolder)
|
|
if err != nil {
|
|
return fmt.Errorf("could not delete existing folder %v", jobFolder)
|
|
}
|
|
|
|
err = os.MkdirAll(jobFolder, 0755)
|
|
if err != nil {
|
|
return fmt.Errorf("could not create working directory for job %v: %v", job.Id, err)
|
|
}
|
|
|
|
log.Infof("Cloning source from URL %v", job.URL)
|
|
cloneCmd := exec.Command("git", "clone", job.URL, jobFolder)
|
|
output, err := cloneCmd.CombinedOutput()
|
|
if err != nil {
|
|
log.Debugf("%s", output)
|
|
return fmt.Errorf("could not clone source: %v", err)
|
|
}
|
|
|
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
|
if err != nil {
|
|
return fmt.Errorf("Could not create docker client: %v", err)
|
|
}
|
|
|
|
ctx := context.Background()
|
|
|
|
resp, err := cli.ContainerCreate(ctx,
|
|
&container.Config{
|
|
Image: "cursorius:latest",
|
|
Cmd: []string{"/launcher.sh"},
|
|
Tty: false,
|
|
Env: []string{fmt.Sprintf("CURSORIUS_SRC_DIR=/job")},
|
|
},
|
|
// TODO: fix running the runner in docker (add VolumesFrom to HostConfig)
|
|
&container.HostConfig{
|
|
Mounts: []mount.Mount{{
|
|
Type: mount.TypeVolume,
|
|
Source: jobFolder,
|
|
Target: "/job",
|
|
ReadOnly: false,
|
|
Consistency: mount.ConsistencyDefault,
|
|
}},
|
|
},
|
|
nil, nil, "",
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("could not create container: %v", err)
|
|
}
|
|
|
|
log.Info("Launching container")
|
|
|
|
if err := cli.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{}); err != nil {
|
|
return fmt.Errorf("could not start container: %v", err)
|
|
}
|
|
statusCh, errCh := cli.ContainerWait(ctx, resp.ID, container.WaitConditionNotRunning)
|
|
select {
|
|
case err := <-errCh:
|
|
if err != nil {
|
|
return fmt.Errorf("container returned error: %v", err)
|
|
}
|
|
case retCode := <-statusCh:
|
|
log.Debugf("Container finished running with return code: %v", retCode)
|
|
}
|
|
|
|
out, err := cli.ContainerLogs(ctx, resp.ID, types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true})
|
|
if err != nil {
|
|
return fmt.Errorf("could not get container logs: %v", err)
|
|
}
|
|
|
|
var stdOut bytes.Buffer
|
|
var stdErr bytes.Buffer
|
|
|
|
stdcopy.StdCopy(&stdOut, &stdErr, out)
|
|
|
|
log.Debugf("%s", stdOut.Bytes())
|
|
log.Debugf("%s", stdErr.Bytes())
|
|
|
|
return nil
|
|
}
|