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 }
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 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 (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) }