func dockerEnv(boxEnv map[string]string, env *util.Environment) []string { s := []string{} for k, v := range boxEnv { s = append(s, fmt.Sprintf("%s=%s", strings.ToUpper(k), env.Interpolate(v))) } return s }
// NewGlobalOptions constructor func NewGlobalOptions(c util.Settings, e *util.Environment) (*GlobalOptions, error) { baseURL, _ := c.GlobalString("base-url", DEFAULT_BASE_URL) baseURL = strings.TrimRight(baseURL, "/") debug, _ := c.GlobalBool("debug") journal, _ := c.GlobalBool("journal") verbose, _ := c.GlobalBool("verbose") // TODO(termie): switch negative flag showColors, _ := c.GlobalBool("no-colors") showColors = !showColors authTokenStore, _ := c.GlobalString("auth-token-store") authTokenStore = util.ExpandHomePath(authTokenStore, e.Get("HOME")) authToken := guessAuthToken(c, e, authTokenStore) // If debug is true, than force verbose and do not use colors. if debug { verbose = true showColors = false } return &GlobalOptions{ BaseURL: baseURL, Debug: debug, Journal: journal, Verbose: verbose, ShowColors: showColors, AuthToken: authToken, AuthTokenStore: authTokenStore, }, nil }
func (d DockerAuth) ToAuthenticator(env *util.Environment) auth.Authenticator { opts := dockerauth.CheckAccessOptions{ Username: env.Interpolate(d.Username), Password: env.Interpolate(d.Password), Registry: env.Interpolate(d.Registry), } auth, _ := dockerauth.GetRegistryAuthenticator(opts) return auth }
func (b *DockerBox) binds(env *util.Environment) ([]string, error) { binds := []string{} // Make our list of binds for the Docker attach // NOTE(termie): we don't appear to need the "volumes" stuff, leaving // it commented out in case it actually does something // volumes := make(map[string]struct{}) entries, err := ioutil.ReadDir(b.options.HostPath()) if err != nil { return nil, err } for _, entry := range entries { if entry.IsDir() || entry.Mode()&os.ModeSymlink == os.ModeSymlink { // For local dev we can mount read-write and avoid a copy, so we'll mount // directly in the pipeline path if b.options.DirectMount { binds = append(binds, fmt.Sprintf("%s:%s:rw", b.options.HostPath(entry.Name()), b.options.GuestPath(entry.Name()))) } else { binds = append(binds, fmt.Sprintf("%s:%s:ro", b.options.HostPath(entry.Name()), b.options.MntPath(entry.Name()))) } // volumes[b.options.MntPath(entry.Name())] = struct{}{} } } if b.options.EnableVolumes { vols := util.SplitSpaceOrComma(b.config.Volumes) var interpolatedVols []string for _, vol := range vols { if strings.Contains(vol, ":") { pair := strings.SplitN(vol, ":", 2) interpolatedVols = append(interpolatedVols, env.Interpolate(pair[0])) interpolatedVols = append(interpolatedVols, env.Interpolate(pair[1])) } else { interpolatedVols = append(interpolatedVols, env.Interpolate(vol)) interpolatedVols = append(interpolatedVols, env.Interpolate(vol)) } } b.volumes = interpolatedVols for i := 0; i < len(b.volumes); i += 2 { binds = append(binds, fmt.Sprintf("%s:%s:rw", b.volumes[i], b.volumes[i+1])) } } return binds, nil }
// InitEnv sets up the internal state of the environment for the build func (b *DockerBuild) InitEnv(hostEnv *util.Environment) { env := b.Env() a := [][]string{ []string{"BUILD", "true"}, []string{"CI", "true"}, []string{"WERCKER_RUN_ID", b.options.RunID}, []string{"WERCKER_RUN_URL", b.options.WorkflowURL()}, []string{"WERCKER_GIT_DOMAIN", b.options.GitDomain}, []string{"WERCKER_GIT_OWNER", b.options.GitOwner}, []string{"WERCKER_GIT_REPOSITORY", b.options.GitRepository}, []string{"WERCKER_GIT_BRANCH", b.options.GitBranch}, []string{"WERCKER_GIT_COMMIT", b.options.GitCommit}, // Legacy env vars []string{"WERCKER_BUILD_ID", b.options.RunID}, []string{"WERCKER_BUILD_URL", b.options.WorkflowURL()}, } env.Update(b.CommonEnv()) env.Update(a) env.Update(hostEnv.GetMirror()) env.Update(hostEnv.GetPassthru().Ordered()) env.Hidden.Update(hostEnv.GetHiddenPassthru().Ordered()) }
// InitEnv sets up the internal state of the environment for the build func (d *DockerDeploy) InitEnv(hostEnv *util.Environment) { env := d.Env() a := [][]string{ []string{"DEPLOY", "true"}, []string{"WERCKER_RUN_ID", d.options.RunID}, []string{"WERCKER_RUN_URL", d.options.WorkflowURL()}, []string{"WERCKER_GIT_DOMAIN", d.options.GitDomain}, []string{"WERCKER_GIT_OWNER", d.options.GitOwner}, []string{"WERCKER_GIT_REPOSITORY", d.options.GitRepository}, []string{"WERCKER_GIT_BRANCH", d.options.GitBranch}, []string{"WERCKER_GIT_COMMIT", d.options.GitCommit}, // Legacy env vars []string{"WERCKER_DEPLOY_ID", d.options.RunID}, []string{"WERCKER_DEPLOY_URL", d.options.WorkflowURL()}, } if d.options.DeployTarget != "" { a = append(a, []string{"WERCKER_DEPLOYTARGET_NAME", d.options.DeployTarget}) } env.Update(d.CommonEnv()) env.Update(a) env.Update(hostEnv.GetMirror()) env.Update(hostEnv.GetPassthru().Ordered()) env.Hidden.Update(hostEnv.GetHiddenPassthru().Ordered()) }
// InitEnv sets up the internal state of the environment for the build func (b *DockerBuild) InitEnv(hostEnv *util.Environment) { env := b.Env() a := [][]string{ []string{"BUILD", "true"}, []string{"CI", "true"}, []string{"WERCKER_BUILD_ID", b.options.BuildID}, []string{"WERCKER_BUILD_URL", fmt.Sprintf("%s/#build/%s", b.options.BaseURL, b.options.BuildID)}, []string{"WERCKER_GIT_DOMAIN", b.options.GitDomain}, []string{"WERCKER_GIT_OWNER", b.options.GitOwner}, []string{"WERCKER_GIT_REPOSITORY", b.options.GitRepository}, []string{"WERCKER_GIT_BRANCH", b.options.GitBranch}, []string{"WERCKER_GIT_COMMIT", b.options.GitCommit}, } env.Update(b.CommonEnv()) env.Update(a) env.Update(hostEnv.GetMirror()) env.Update(hostEnv.GetPassthru().Ordered()) env.Hidden.Update(hostEnv.GetHiddenPassthru().Ordered()) }
// InitEnv parses our data into our config func (s *DockerPushStep) InitEnv(env *util.Environment) { if username, ok := s.data["username"]; ok { s.username = env.Interpolate(username) } if password, ok := s.data["password"]; ok { s.password = env.Interpolate(password) } if email, ok := s.data["email"]; ok { s.email = env.Interpolate(email) } if authServer, ok := s.data["auth-server"]; ok { s.authServer = env.Interpolate(authServer) } if repository, ok := s.data["repository"]; ok { s.repository = env.Interpolate(repository) } if tags, ok := s.data["tag"]; ok { splitTags := util.SplitSpaceOrComma(tags) interpolatedTags := make([]string, len(splitTags)) for i, tag := range splitTags { interpolatedTags[i] = env.Interpolate(tag) } s.tags = interpolatedTags } if author, ok := s.data["author"]; ok { s.author = env.Interpolate(author) } if message, ok := s.data["message"]; ok { s.message = env.Interpolate(message) } if ports, ok := s.data["ports"]; ok { iPorts := env.Interpolate(ports) parts := util.SplitSpaceOrComma(iPorts) portmap := make(map[docker.Port]struct{}) for _, port := range parts { port = strings.TrimSpace(port) if !strings.Contains(port, "/") { port = port + "/tcp" } portmap[docker.Port(port)] = struct{}{} } s.ports = portmap } if volumes, ok := s.data["volumes"]; ok { iVolumes := env.Interpolate(volumes) parts := util.SplitSpaceOrComma(iVolumes) volumemap := make(map[string]struct{}) for _, volume := range parts { volume = strings.TrimSpace(volume) volumemap[volume] = struct{}{} } s.volumes = volumemap } if workingDir, ok := s.data["working-dir"]; ok { s.workingDir = env.Interpolate(workingDir) } if registry, ok := s.data["registry"]; ok { // s.registry = env.Interpolate(registry) s.registry = normalizeRegistry(env.Interpolate(registry)) } else { // s.registry = "https://registry.hub.docker.com" s.registry = normalizeRegistry("https://registry.hub.docker.com") } if cmd, ok := s.data["cmd"]; ok { parts, err := shlex.Split(cmd) if err == nil { s.cmd = parts } } if entrypoint, ok := s.data["entrypoint"]; ok { parts, err := shlex.Split(entrypoint) if err == nil { s.entrypoint = parts } } if envi, ok := s.data["env"]; ok { parsedEnv, err := shlex.Split(envi) if err == nil { interpolatedEnv := make([]string, len(parsedEnv)) for i, envVar := range parsedEnv { interpolatedEnv[i] = env.Interpolate(envVar) } s.env = interpolatedEnv } } if stopsignal, ok := s.data["stopsignal"]; ok { s.stopSignal = env.Interpolate(stopsignal) } if labels, ok := s.data["labels"]; ok { parsedLabels, err := shlex.Split(labels) if err == nil { labelMap := make(map[string]string) for _, labelPair := range parsedLabels { pair := strings.Split(labelPair, "=") labelMap[env.Interpolate(pair[0])] = env.Interpolate(pair[1]) } s.labels = labelMap } } if user, ok := s.data["user"]; ok { s.user = env.Interpolate(user) } if forceTags, ok := s.data["force-tags"]; ok { ft, err := strconv.ParseBool(forceTags) if err == nil { s.forceTags = ft } } else { s.forceTags = true } }
// Fetch an image (or update the local) func (b *DockerBox) Fetch(ctx context.Context, env *util.Environment) (*docker.Image, error) { // TODO(termie): maybe move the container manipulation outside of here? client := b.client e, err := core.EmitterFromContext(ctx) if err != nil { return nil, err } // Shortcut to speed up local dev if b.dockerOptions.DockerLocal { image, err := client.InspectImage(env.Interpolate(b.Name)) if err != nil { return nil, err } b.image = image return image, nil } // Check for access to this image auth := docker.AuthConfiguration{ Username: env.Interpolate(b.config.Username), Password: env.Interpolate(b.config.Password), } checkOpts := CheckAccessOptions{ Auth: auth, Access: "read", Repository: env.Interpolate(b.repository), Registry: env.Interpolate(b.config.Registry), } check, err := client.CheckAccess(checkOpts) if err != nil { b.logger.Errorln("Error during check access") return nil, err } if !check { b.logger.Errorln("Not allowed to interact with this repository:", b.repository) return nil, fmt.Errorf("Not allowed to interact with this repository: %s", b.repository) } // Create a pipe since we want a io.Reader but Docker expects a io.Writer r, w := io.Pipe() defer w.Close() // emitStatusses in a different go routine go EmitStatus(e, r, b.options) options := docker.PullImageOptions{ // changeme if we have a private registry // Registry: "docker.tsuru.io", OutputStream: w, RawJSONStream: true, Repository: env.Interpolate(b.repository), Tag: env.Interpolate(b.tag), } err = client.PullImage(options, auth) if err != nil { return nil, err } image, err := client.InspectImage(env.Interpolate(b.Name)) if err != nil { return nil, err } b.image = image return nil, err }
// Run creates the container and runs it. func (b *DockerBox) Run(ctx context.Context, env *util.Environment) (*docker.Container, error) { err := b.RunServices(ctx, env) if err != nil { return nil, err } b.logger.Debugln("Starting base box:", b.Name) // TODO(termie): maybe move the container manipulation outside of here? client := b.client // Import the environment myEnv := dockerEnv(b.config.Env, env) var entrypoint []string if b.entrypoint != "" { entrypoint, err = shlex.Split(b.entrypoint) if err != nil { return nil, err } } cmd, err := shlex.Split(b.cmd) if err != nil { return nil, err } // Make and start the container container, err := client.CreateContainer( docker.CreateContainerOptions{ Name: b.getContainerName(), Config: &docker.Config{ Image: env.Interpolate(b.Name), Tty: false, OpenStdin: true, Cmd: cmd, Env: myEnv, AttachStdin: true, AttachStdout: true, AttachStderr: true, ExposedPorts: exposedPorts(b.options.PublishPorts), NetworkDisabled: b.networkDisabled, DNS: b.dockerOptions.DockerDNS, Entrypoint: entrypoint, // Volumes: volumes, }, }) if err != nil { return nil, err } b.logger.Debugln("Docker Container:", container.ID) binds, err := b.binds(env) if err != nil { return nil, err } client.StartContainer(container.ID, &docker.HostConfig{ Binds: binds, Links: b.links(), PortBindings: portBindings(b.options.PublishPorts), DNS: b.dockerOptions.DockerDNS, }) b.container = container return container, nil }
// Fetch an image (or update the local) func (b *DockerBox) Fetch(ctx context.Context, env *util.Environment) (*docker.Image, error) { // TODO(termie): maybe move the container manipulation outside of here? client := b.client e, err := core.EmitterFromContext(ctx) if err != nil { return nil, err } authenticator := b.config.Auth.ToAuthenticator(env) b.repository = authenticator.Repository(env.Interpolate(b.repository)) b.Name = fmt.Sprintf("%s:%s", b.repository, b.tag) // Shortcut to speed up local dev if b.dockerOptions.DockerLocal { image, err := client.InspectImage(env.Interpolate(b.Name)) if err != nil { return nil, err } b.image = image return image, nil } check, err := authenticator.CheckAccess(env.Interpolate(b.repository), auth.Pull) if err != nil { return nil, fmt.Errorf("Error interacting with this repository: %s %v", env.Interpolate(b.repository), err) } if !check { return nil, fmt.Errorf("Not allowed to interact with this repository: %s:", env.Interpolate(b.repository)) } // Create a pipe since we want a io.Reader but Docker expects a io.Writer r, w := io.Pipe() defer w.Close() // emitStatusses in a different go routine go EmitStatus(e, r, b.options) options := docker.PullImageOptions{ // changeme if we have a private registry // Registry: "docker.tsuru.io", OutputStream: w, RawJSONStream: true, Repository: b.repository, Tag: env.Interpolate(b.tag), } authConfig := docker.AuthConfiguration{ Username: authenticator.Username(), Password: authenticator.Password(), } err = client.PullImage(options, authConfig) if err != nil { return nil, err } image, err := client.InspectImage(env.Interpolate(b.Name)) if err != nil { return nil, err } b.image = image return nil, err }
// Run creates the container and runs it. func (b *DockerBox) Run(ctx context.Context, env *util.Environment) (*docker.Container, error) { err := b.RunServices(ctx, env) if err != nil { return nil, err } b.logger.Debugln("Starting base box:", b.Name) // TODO(termie): maybe move the container manipulation outside of here? client := b.client // Import the environment myEnv := dockerEnv(b.config.Env, env) var entrypoint []string if b.entrypoint != "" { entrypoint, err = shlex.Split(b.entrypoint) if err != nil { return nil, err } } cmd, err := shlex.Split(b.cmd) if err != nil { return nil, err } var ports map[docker.Port]struct{} if len(b.options.PublishPorts) > 0 { ports = exposedPorts(b.options.PublishPorts) } else if b.options.ExposePorts { ports = exposedPorts(b.config.Ports) } binds, err := b.binds(env) portsToBind := []string{""} if len(b.options.PublishPorts) >= 1 { b.logger.Warnln("--publish is deprecated, please use --expose-ports and define the ports for the boxes. See: https://github.com/wercker/wercker/pull/161") portsToBind = b.options.PublishPorts } else if b.options.ExposePorts { portsToBind = b.config.Ports } hostConfig := &docker.HostConfig{ Binds: binds, Links: b.links(), PortBindings: portBindings(portsToBind), DNS: b.dockerOptions.DockerDNS, } // Make and start the container container, err := client.CreateContainer( docker.CreateContainerOptions{ Name: b.getContainerName(), Config: &docker.Config{ Image: env.Interpolate(b.Name), Tty: false, OpenStdin: true, Cmd: cmd, Env: myEnv, AttachStdin: true, AttachStdout: true, AttachStderr: true, ExposedPorts: ports, NetworkDisabled: b.networkDisabled, DNS: b.dockerOptions.DockerDNS, Entrypoint: entrypoint, // Volumes: volumes, }, HostConfig: hostConfig, }) if err != nil { return nil, err } b.logger.Debugln("Docker Container:", container.ID) if err != nil { return nil, err } client.StartContainer(container.ID, hostConfig) b.container = container return container, nil }
// InitEnv parses our data into our config func (s *DockerPushStep) InitEnv(env *util.Environment) { if email, ok := s.data["email"]; ok { s.email = env.Interpolate(email) } if authServer, ok := s.data["auth-server"]; ok { s.authServer = env.Interpolate(authServer) } if repository, ok := s.data["repository"]; ok { s.repository = env.Interpolate(repository) } if tags, ok := s.data["tag"]; ok { splitTags := util.SplitSpaceOrComma(tags) interpolatedTags := make([]string, len(splitTags)) for i, tag := range splitTags { interpolatedTags[i] = env.Interpolate(tag) } s.tags = interpolatedTags } if author, ok := s.data["author"]; ok { s.author = env.Interpolate(author) } if message, ok := s.data["message"]; ok { s.message = env.Interpolate(message) } if ports, ok := s.data["ports"]; ok { iPorts := env.Interpolate(ports) parts := util.SplitSpaceOrComma(iPorts) portmap := make(map[docker.Port]struct{}) for _, port := range parts { port = strings.TrimSpace(port) if !strings.Contains(port, "/") { port = port + "/tcp" } portmap[docker.Port(port)] = struct{}{} } s.ports = portmap } if volumes, ok := s.data["volumes"]; ok { iVolumes := env.Interpolate(volumes) parts := util.SplitSpaceOrComma(iVolumes) volumemap := make(map[string]struct{}) for _, volume := range parts { volume = strings.TrimSpace(volume) volumemap[volume] = struct{}{} } s.volumes = volumemap } if workingDir, ok := s.data["working-dir"]; ok { s.workingDir = env.Interpolate(workingDir) } if cmd, ok := s.data["cmd"]; ok { parts, err := shlex.Split(cmd) if err == nil { s.cmd = parts } } if entrypoint, ok := s.data["entrypoint"]; ok { parts, err := shlex.Split(entrypoint) if err == nil { s.entrypoint = parts } } if envi, ok := s.data["env"]; ok { parsedEnv, err := shlex.Split(envi) if err == nil { interpolatedEnv := make([]string, len(parsedEnv)) for i, envVar := range parsedEnv { interpolatedEnv[i] = env.Interpolate(envVar) } s.env = interpolatedEnv } } if stopsignal, ok := s.data["stopsignal"]; ok { s.stopSignal = env.Interpolate(stopsignal) } if labels, ok := s.data["labels"]; ok { parsedLabels, err := shlex.Split(labels) if err == nil { labelMap := make(map[string]string) for _, labelPair := range parsedLabels { pair := strings.Split(labelPair, "=") labelMap[env.Interpolate(pair[0])] = env.Interpolate(pair[1]) } s.labels = labelMap } } if user, ok := s.data["user"]; ok { s.user = env.Interpolate(user) } if forceTags, ok := s.data["force-tags"]; ok { ft, err := strconv.ParseBool(forceTags) if err == nil { s.forceTags = ft } } else { s.forceTags = true } //build auther opts := dockerauth.CheckAccessOptions{} if username, ok := s.data["username"]; ok { opts.Username = env.Interpolate(username) } if password, ok := s.data["password"]; ok { opts.Password = env.Interpolate(password) } if awsAccessKey, ok := s.data["aws-access-key"]; ok { opts.AwsAccessKey = env.Interpolate(awsAccessKey) } if awsSecretKey, ok := s.data["aws-secret-key"]; ok { opts.AwsSecretKey = env.Interpolate(awsSecretKey) } if awsRegion, ok := s.data["aws-region"]; ok { opts.AwsRegion = env.Interpolate(awsRegion) } if awsAuth, ok := s.data["aws-strict-auth"]; ok { auth, err := strconv.ParseBool(awsAuth) if err == nil { opts.AwsStrictAuth = auth } } if awsRegistryID, ok := s.data["aws-registry-id"]; ok { opts.AwsRegistryID = env.Interpolate(awsRegistryID) } if registry, ok := s.data["registry"]; ok { opts.Registry = dockerauth.NormalizeRegistry(env.Interpolate(registry)) } auther, _ := dockerauth.GetRegistryAuthenticator(opts) s.authenticator = auther }
func guessAndUpdateDockerOptions(opts *DockerOptions, e *util.Environment) { if opts.DockerHost != "" { return } logger := util.RootLogger().WithField("Logger", "docker") // f := &util.Formatter{opts.GlobalOptions.ShowColors} f := &util.Formatter{false} // Check the unix socket, default on linux // This will fail instantly so don't bother with the goroutine unixSocket := "/var/run/docker.sock" logger.Println(f.Info("No Docker host specified, checking", unixSocket)) if _, err := os.Stat(unixSocket); err == nil { unixSocket = fmt.Sprintf("unix://%s", unixSocket) client, err := NewDockerClient(&DockerOptions{ DockerHost: unixSocket, }) if err == nil { _, err = client.Version() if err == nil { opts.DockerHost = unixSocket return } } } // Check the boot2docker port with default cert paths and such b2dCertPath := filepath.Join(e.Get("HOME"), ".boot2docker/certs/boot2docker-vm") b2dHost := "tcp://192.168.59.103:2376" logger.Printf(f.Info("No Docker host specified, checking for boot2docker", b2dHost)) client, err := NewDockerClient(&DockerOptions{ DockerHost: b2dHost, DockerCertPath: b2dCertPath, DockerTLSVerify: "1", }) if err == nil { // This can take a long time if it isn't up, so toss it in a // goroutine so we can time it out result := make(chan bool) go func() { _, err = client.Version() if err == nil { result <- true } else { result <- false } }() select { case success := <-result: if success { opts.DockerHost = b2dHost opts.DockerCertPath = b2dCertPath opts.DockerTLSVerify = "1" return } case <-time.After(1 * time.Second): } } // Pick a default localhost port and hope for the best :/ opts.DockerHost = "tcp://127.0.0.1:2375" logger.Println(f.Info("No Docker host found, falling back to default", opts.DockerHost)) }
func (a AmazonAuth) ToAuthenticator(env *util.Environment) auth.Authenticator { return auth.NewAmazonAuth(env.Interpolate(a.AWSRegistryID), env.Interpolate(a.AWSAccessKey), env.Interpolate(a.AWSSecretKey), env.Interpolate(a.AWSRegion), a.AWSStrictAuth) }