// EnsureItExists make sure the volume exists and return an error if it does not exists // and cannot be created. func (v *Volume) EnsureItExists(ctx context.Context) error { volumeResource, err := v.Inspect(ctx) if v.external { if client.IsErrVolumeNotFound(err) { // FIXME(shouze) introduce some libcompose error type return fmt.Errorf("Volume %s declared as external, but could not be found. Please create the volume manually using docker volume create %s and try again", v.name, v.name) } return err } if err != nil && client.IsErrVolumeNotFound(err) { return v.create(ctx) } if volumeResource.Driver != v.driver { return fmt.Errorf("Volume %q needs to be recreated - driver has changed", v.name) } return err }
// Run starts the test instance containers as well as any // containers which will manage the tests and waits for // the results. func (r *runner) Run(cli DockerClient) error { var ( failedTests int runTests int runnerStart = time.Now() ctx = context.Background() ) // TODO: Run in parallel // TODO: validate namespace when in parallel mode for _, suite := range r.config.Suites { for _, instance := range suite.Instances { // TODO: Add configuration for nocache nocache := false contName := "golem-" + instance.Name // TODO: Use image ID and not image name imageName := r.imageName(instance.Name) logFields := logrus.Fields{ "instance": instance.Name, "image": imageName, "container": contName, } logrus.WithFields(logFields).Info("running instance") hc := &container.HostConfig{ Privileged: true, VolumeDriver: "local", } args := []string{} if suite.DockerInDocker { args = append(args, "-docker") } if r.debug { args = append(args, "-debug") } // TODO: Add argument for instance name config := &container.Config{ Image: imageName, Cmd: append([]string{r.config.ExecutableName}, args...), WorkingDir: "/runner", Volumes: map[string]struct{}{ "/var/log/docker": {}, }, } if suite.DockerInDocker { config.Env = append(config.Env, "DOCKER_GRAPHDRIVER="+getGraphDriver()) // TODO: In parallel mode, do not use a cached volume volumeName := contName + "-graph" cont, err := cli.ContainerInspect(ctx, contName) if err == nil { removeOptions := types.ContainerRemoveOptions{ RemoveVolumes: true, } if err := cli.ContainerRemove(ctx, cont.ID, removeOptions); err != nil { return fmt.Errorf("error removing existing container %s: %v", contName, err) } } var createVolume bool vol, err := cli.VolumeInspect(ctx, volumeName) if err == nil { if nocache { if err := cli.VolumeRemove(ctx, vol.Name); err != nil { return fmt.Errorf("error removing volume %s: %v", vol.Name, err) } createVolume = true } } else if client.IsErrVolumeNotFound(err) { createVolume = true } else { return fmt.Errorf("error inspecting volume: %v", err) } if createVolume { createOptions := types.VolumeCreateRequest{ Name: volumeName, Driver: "local", } vol, err = cli.VolumeCreate(ctx, createOptions) if err != nil { return fmt.Errorf("error creating volume: %v", err) } } // TODO: Use volume name instead of mountpoint logrus.Debugf("Mounting %s to %s", vol.Mountpoint, "/var/lib/docker") hc.Binds = append(hc.Binds, fmt.Sprintf("%s:/var/lib/docker", vol.Mountpoint)) } nc := &network.NetworkingConfig{} container, err := cli.ContainerCreate(ctx, config, hc, nc, contName) if err != nil { return fmt.Errorf("error creating container: %s", err) } for _, warning := range container.Warnings { logrus.Warnf("Container %q create warning: %v", contName, warning) } if err := cli.ContainerStart(ctx, container.ID); err != nil { return fmt.Errorf("error starting container: %s", err) } attachOptions := types.ContainerAttachOptions{ Stream: true, Stdout: true, Stderr: true, } resp, err := cli.ContainerAttach(ctx, container.ID, attachOptions) if err != nil { return fmt.Errorf("Error attaching to container: %v", err) } // TODO: Capture output for parallel mode if _, err := stdcopy.StdCopy(os.Stdout, os.Stderr, resp.Reader); err != nil { return fmt.Errorf("Error copying output stream: %v", err) } inspectedContainer, err := cli.ContainerInspect(ctx, container.ID) if err != nil { return fmt.Errorf("Error inspecting container: %v", err) } runTests = runTests + 1 if inspectedContainer.State.ExitCode > 0 { logrus.Errorf("Test failed with exit code %d", inspectedContainer.State.ExitCode) failedTests = failedTests + 1 } } } logFields := logrus.Fields{ timerKey: time.Since(runnerStart), "ran": runTests, "failed": failedTests, } logrus.WithFields(logFields).Info("test runner complete") if failedTests > 0 { return fmt.Errorf("test failure: %d of %d tests failed", failedTests, runTests) } return nil }