runservice executor: add driver Setup method

Remote custom `copytoolbox` hack and use a generic `Setup` function in the
driver interface
This commit is contained in:
Simone Gotti 2019-04-22 18:17:55 +02:00
parent 7ebc436854
commit 7e9abbf529
4 changed files with 24 additions and 13 deletions

View File

@ -42,9 +42,10 @@ type DockerDriver struct {
logger *zap.Logger logger *zap.Logger
client *client.Client client *client.Client
initVolumeHostDir string initVolumeHostDir string
toolboxPath string
} }
func NewDockerDriver(logger *zap.Logger, initVolumeHostDir string) (*DockerDriver, error) { func NewDockerDriver(logger *zap.Logger, initVolumeHostDir, toolboxPath string) (*DockerDriver, error) {
cli, err := client.NewEnvClient() cli, err := client.NewEnvClient()
if err != nil { if err != nil {
return nil, err return nil, err
@ -53,13 +54,18 @@ func NewDockerDriver(logger *zap.Logger, initVolumeHostDir string) (*DockerDrive
logger: logger, logger: logger,
client: cli, client: cli,
initVolumeHostDir: initVolumeHostDir, initVolumeHostDir: initVolumeHostDir,
toolboxPath: toolboxPath,
}, nil }, nil
} }
func (d *DockerDriver) Setup(ctx context.Context) error {
return d.CopyToolbox(ctx)
}
// CopyToolbox is an hack needed when running the executor inside a docker // CopyToolbox is an hack needed when running the executor inside a docker
// container. It copies the agola-toolbox binaries from the container to an // container. It copies the agola-toolbox binaries from the container to an
// host path so it can be bind mounted to the other containers // host path so it can be bind mounted to the other containers
func (d *DockerDriver) CopyToolbox(ctx context.Context, toolboxPath string) error { func (d *DockerDriver) CopyToolbox(ctx context.Context) error {
// by default always try to pull the image so we are sure only authorized users can fetch them // by default always try to pull the image so we are sure only authorized users can fetch them
// see https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#alwayspullimages // see https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#alwayspullimages
reader, err := d.client.ImagePull(ctx, "busybox", types.ImagePullOptions{}) reader, err := d.client.ImagePull(ctx, "busybox", types.ImagePullOptions{})
@ -85,7 +91,7 @@ func (d *DockerDriver) CopyToolbox(ctx context.Context, toolboxPath string) erro
return err return err
} }
srcInfo, err := archive.CopyInfoSourcePath(toolboxPath, false) srcInfo, err := archive.CopyInfoSourcePath(d.toolboxPath, false)
if err != nil { if err != nil {
return err return err
} }
@ -288,9 +294,9 @@ func podLabelsFromContainer(containerLabels map[string]string) map[string]string
return labels return labels
} }
func (d *DockerDriver) GetPodByID(ctx context.Context, containerID string) (Pod, error) { func (d *DockerDriver) GetPodByID(ctx context.Context, podID string) (Pod, error) {
args := filters.NewArgs() args := filters.NewArgs()
args.Add(podIDKey, containerID) args.Add(podIDKey, podID)
containers, err := d.client.ContainerList(ctx, containers, err := d.client.ContainerList(ctx,
types.ContainerListOptions{ types.ContainerListOptions{
@ -300,7 +306,7 @@ func (d *DockerDriver) GetPodByID(ctx context.Context, containerID string) (Pod,
return nil, err return nil, err
} }
if len(containers) == 0 { if len(containers) == 0 {
return nil, errors.Errorf("no container with id %s", containerID) return nil, errors.Errorf("no pod with id %s", podID)
} }
return &DockerPod{ return &DockerPod{
@ -375,7 +381,7 @@ func (s *Stdin) Close() error {
return s.hresp.CloseWrite() return s.hresp.CloseWrite()
} }
func (dc *DockerPod) Exec(ctx context.Context, execConfig *ExecConfig) (ContainerExec, error) { func (dp *DockerPod) Exec(ctx context.Context, execConfig *ExecConfig) (ContainerExec, error) {
endCh := make(chan error) endCh := make(chan error)
dockerExecConfig := types.ExecConfig{ dockerExecConfig := types.ExecConfig{
@ -389,7 +395,7 @@ func (dc *DockerPod) Exec(ctx context.Context, execConfig *ExecConfig) (Containe
User: execConfig.User, User: execConfig.User,
} }
response, err := dc.client.ContainerExecCreate(ctx, dc.containers[0].ID, dockerExecConfig) response, err := dp.client.ContainerExecCreate(ctx, dp.containers[0].ID, dockerExecConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -397,7 +403,7 @@ func (dc *DockerPod) Exec(ctx context.Context, execConfig *ExecConfig) (Containe
Detach: dockerExecConfig.Detach, Detach: dockerExecConfig.Detach,
Tty: dockerExecConfig.Tty, Tty: dockerExecConfig.Tty,
} }
hresp, err := dc.client.ContainerExecAttach(ctx, response.ID, execStartCheck) hresp, err := dp.client.ContainerExecAttach(ctx, response.ID, execStartCheck)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -429,7 +435,7 @@ func (dc *DockerPod) Exec(ctx context.Context, execConfig *ExecConfig) (Containe
return &DockerContainerExec{ return &DockerContainerExec{
execID: response.ID, execID: response.ID,
hresp: &hresp, hresp: &hresp,
client: dc.client, client: dp.client,
stdin: stdin, stdin: stdin,
endCh: endCh, endCh: endCh,
}, nil }, nil

View File

@ -76,6 +76,10 @@ func TestPod(t *testing.T) {
if os.Getenv("SKIP_DOCKER_TESTS") == "1" { if os.Getenv("SKIP_DOCKER_TESTS") == "1" {
t.Skip("skipping since env var SKIP_DOCKER_TESTS is 1") t.Skip("skipping since env var SKIP_DOCKER_TESTS is 1")
} }
toolboxPath := os.Getenv("AGOLA_TOOLBOX_PATH")
if toolboxPath == "" {
t.Fatalf("env var AGOLA_TOOLBOX_PATH is undefined")
}
dir, err := ioutil.TempDir("", "agola") dir, err := ioutil.TempDir("", "agola")
if err != nil { if err != nil {
@ -83,7 +87,7 @@ func TestPod(t *testing.T) {
} }
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
d, err := NewDockerDriver(logger, dir) d, err := NewDockerDriver(logger, dir, toolboxPath)
if err != nil { if err != nil {
t.Fatalf("unexpected err: %v", err) t.Fatalf("unexpected err: %v", err)
} }

View File

@ -40,6 +40,7 @@ const (
// * Kubernetes pods // * Kubernetes pods
// * A Virtual Machine on which we execute multiple processes // * A Virtual Machine on which we execute multiple processes
type Driver interface { type Driver interface {
Setup(ctx context.Context) error
NewPod(ctx context.Context, podConfig *PodConfig, out io.Writer) (Pod, error) NewPod(ctx context.Context, podConfig *PodConfig, out io.Writer) (Pod, error)
GetPodsByLabels(ctx context.Context, labels map[string]string, all bool) ([]Pod, error) GetPodsByLabels(ctx context.Context, labels map[string]string, all bool) ([]Pod, error)
GetPodByID(ctx context.Context, containerID string) (Pod, error) GetPodByID(ctx context.Context, containerID string) (Pod, error)

View File

@ -1216,7 +1216,7 @@ func NewExecutor(c *config.RunServiceExecutor) (*Executor, error) {
c.ToolboxPath = path c.ToolboxPath = path
} }
dockerDriver, err := driver.NewDockerDriver(logger, "/tmp/agola/bin") dockerDriver, err := driver.NewDockerDriver(logger, "/tmp/agola/bin", c.ToolboxPath)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "failed to create docker client") return nil, errors.Wrapf(err, "failed to create docker client")
} }
@ -1269,7 +1269,7 @@ func NewExecutor(c *config.RunServiceExecutor) (*Executor, error) {
} }
func (e *Executor) Run(ctx context.Context) error { func (e *Executor) Run(ctx context.Context) error {
if err := e.driver.(*driver.DockerDriver).CopyToolbox(context.TODO(), e.c.ToolboxPath); err != nil { if err := e.driver.Setup(ctx); err != nil {
return err return err
} }