// dockerRun mimics the 'docker run --rm' CLI command. It uses the Docker Remote // API to create and start a container and stream its logs. The container is // removed after it terminates. func dockerRun(client DockerClient, createOpts docker.CreateContainerOptions, logsOpts docker.LogsOptions) error { // Create a new container. glog.V(4).Infof("Creating container with options {Name:%q Config:%+v HostConfig:%+v} ...", createOpts.Name, createOpts.Config, createOpts.HostConfig) c, err := client.CreateContainer(createOpts) if err != nil { return fmt.Errorf("create container %q: %v", createOpts.Name, err) } containerName := containerNameOrID(c) removeContainer := func() { glog.V(4).Infof("Removing container %q ...", containerName) if err := client.RemoveContainer(docker.RemoveContainerOptions{ID: c.ID}); err != nil { glog.V(0).Infof("warning: Failed to remove container %q: %v", containerName, err) } else { glog.V(4).Infof("Removed container %q", containerName) } } startWaitContainer := func() error { // Start the container. glog.V(4).Infof("Starting container %q ...", containerName) if err := client.StartContainer(c.ID, nil); err != nil { return fmt.Errorf("start container %q: %v", containerName, err) } // Stream container logs. logsOpts.Container = c.ID glog.V(4).Infof("Streaming logs of container %q with options %+v ...", containerName, logsOpts) if err := client.Logs(logsOpts); err != nil { return fmt.Errorf("streaming logs of %q: %v", containerName, err) } // Return an error if the exit code of the container is non-zero. glog.V(4).Infof("Waiting for container %q to stop ...", containerName) exitCode, err := client.WaitContainer(c.ID) if err != nil { return fmt.Errorf("waiting for container %q to stop: %v", containerName, err) } if exitCode != 0 { return fmt.Errorf("container %q returned non-zero exit code: %d", containerName, exitCode) } return nil } // the interrupt handler acts as a super-defer which will guarantee removeContainer is executed // either when startWaitContainer finishes, or when a SIGQUIT/SIGINT/SIGTERM is received. return interrupt.New(nil, removeContainer).Run(startWaitContainer) }
// dockerRun mimics the 'docker run --rm' CLI command. It uses the Docker Remote // API to create and start a container and stream its logs. The container is // removed after it terminates. func dockerRun(client DockerClient, createOpts docker.CreateContainerOptions, logsOpts docker.LogsOptions) error { // Create a new container. glog.V(4).Infof("Creating container with options {Name:%q Config:%+v HostConfig:%+v} ...", createOpts.Name, createOpts.Config, createOpts.HostConfig) c, err := client.CreateContainer(createOpts) if err != nil { return fmt.Errorf("create container %q: %v", createOpts.Name, err) } containerName := containerNameOrID(c) // Container was created, so we defer its removal. defer func() { glog.V(4).Infof("Removing container %q ...", containerName) if err := client.RemoveContainer(docker.RemoveContainerOptions{ID: c.ID}); err != nil { glog.Warningf("Failed to remove container %q: %v", containerName, err) } else { glog.V(4).Infof("Removed container %q", containerName) } }() // Start the container. glog.V(4).Infof("Starting container %q ...", containerName) if err := client.StartContainer(c.ID, nil); err != nil { return fmt.Errorf("start container %q: %v", containerName, err) } // Stream container logs. logsOpts.Container = c.ID glog.V(4).Infof("Streaming logs of container %q with options %+v ...", containerName, logsOpts) if err := client.Logs(logsOpts); err != nil { return fmt.Errorf("streaming logs of %q: %v", containerName, err) } // Return an error if the exit code of the container is non-zero. glog.V(4).Infof("Waiting for container %q to stop ...", containerName) exitCode, err := client.WaitContainer(c.ID) if err != nil { return fmt.Errorf("waiting for container %q to stop: %v", containerName, err) } if exitCode != 0 { return fmt.Errorf("container %q returned non-zero exit code: %d", containerName, exitCode) } return nil }