func containerToGRPC(c types.ContainerSpec) (*swarmapi.ContainerSpec, error) { containerSpec := &swarmapi.ContainerSpec{ Image: c.Image, Labels: c.Labels, Command: c.Command, Args: c.Args, Env: c.Env, Dir: c.Dir, User: c.User, Groups: c.Groups, } if c.StopGracePeriod != nil { containerSpec.StopGracePeriod = ptypes.DurationProto(*c.StopGracePeriod) } // Mounts for _, m := range c.Mounts { mount := swarmapi.Mount{ Target: m.Target, Source: m.Source, ReadOnly: m.ReadOnly, } if mountType, ok := swarmapi.Mount_MountType_value[strings.ToUpper(string(m.Type))]; ok { mount.Type = swarmapi.Mount_MountType(mountType) } else if string(m.Type) != "" { return nil, fmt.Errorf("invalid MountType: %q", m.Type) } if m.BindOptions != nil { if mountPropagation, ok := swarmapi.Mount_BindOptions_MountPropagation_value[strings.ToUpper(string(m.BindOptions.Propagation))]; ok { mount.BindOptions = &swarmapi.Mount_BindOptions{Propagation: swarmapi.Mount_BindOptions_MountPropagation(mountPropagation)} } else if string(m.BindOptions.Propagation) != "" { return nil, fmt.Errorf("invalid MountPropagation: %q", m.BindOptions.Propagation) } } if m.VolumeOptions != nil { mount.VolumeOptions = &swarmapi.Mount_VolumeOptions{ NoCopy: m.VolumeOptions.NoCopy, Labels: m.VolumeOptions.Labels, } if m.VolumeOptions.DriverConfig != nil { mount.VolumeOptions.DriverConfig = &swarmapi.Driver{ Name: m.VolumeOptions.DriverConfig.Name, Options: m.VolumeOptions.DriverConfig.Options, } } } containerSpec.Mounts = append(containerSpec.Mounts, mount) } return containerSpec, nil }
// parseTmpfs supports a simple tmpfs decl, similar to docker run. // // This should go away. func parseTmpfs(flags *pflag.FlagSet, spec *api.ServiceSpec) error { if flags.Changed("tmpfs") { tmpfss, err := flags.GetStringSlice("tmpfs") if err != nil { return err } container := spec.Task.GetContainer() // TODO(stevvooe): Nasty inline parsing code, replace with mount syntax. for _, tmpfs := range tmpfss { parts := strings.SplitN(tmpfs, ":", 2) if len(parts) < 1 { return errors.Errorf("invalid mount spec: %v", tmpfs) } if len(parts[0]) == 0 || !path.IsAbs(parts[0]) { return errors.Errorf("invalid mount spec: %v", tmpfs) } m := api.Mount{ Type: api.MountTypeTmpfs, Target: parts[0], } if len(parts) == 2 { if strings.Contains(parts[1], ":") { // repeated colon is illegal return errors.Errorf("invalid mount spec: %v", tmpfs) } // BUG(stevvooe): Cobra stringslice actually doesn't correctly // handle comma separated values, so multiple flags aren't // really supported. We'll have to replace StringSlice with a // type that doesn't use the csv parser. This is good enough // for now. flags := strings.Split(parts[1], ",") var opts api.Mount_TmpfsOptions for _, flag := range flags { switch { case strings.HasPrefix(flag, "size="): meat := strings.TrimPrefix(flag, "size=") // try to parse this into bytes i, err := strconv.ParseInt(meat, 10, 64) if err != nil { // remove suffux and try again suffix := meat[len(meat)-1] meat = meat[:len(meat)-1] var multiplier int64 = 1 switch suffix { case 'g': multiplier = 1 << 30 case 'm': multiplier = 1 << 20 case 'k': multiplier = 1 << 10 default: return errors.Errorf("invalid size format: %v", flag) } // reparse the meat var err error i, err = strconv.ParseInt(meat, 10, 64) if err != nil { return err } i *= multiplier } opts.SizeBytes = i case strings.HasPrefix(flag, "mode="): meat := strings.TrimPrefix(flag, "mode=") i, err := strconv.ParseInt(meat, 8, 32) if err != nil { return err } opts.Mode = os.FileMode(i) case flag == "ro": m.ReadOnly = true case flag == "rw": m.ReadOnly = false default: return errors.New("unsupported flag") } } m.TmpfsOptions = &opts } fmt.Println("mount", m) container.Mounts = append(container.Mounts, m) } } return nil }
func containerToGRPC(c types.ContainerSpec) (*swarmapi.ContainerSpec, error) { containerSpec := &swarmapi.ContainerSpec{ Image: c.Image, Labels: c.Labels, Command: c.Command, Args: c.Args, Hostname: c.Hostname, Env: c.Env, Dir: c.Dir, User: c.User, Groups: c.Groups, TTY: c.TTY, OpenStdin: c.OpenStdin, Hosts: c.Hosts, Secrets: secretReferencesToGRPC(c.Secrets), } if c.DNSConfig != nil { containerSpec.DNSConfig = &swarmapi.ContainerSpec_DNSConfig{ Nameservers: c.DNSConfig.Nameservers, Search: c.DNSConfig.Search, Options: c.DNSConfig.Options, } } if c.StopGracePeriod != nil { containerSpec.StopGracePeriod = ptypes.DurationProto(*c.StopGracePeriod) } // Mounts for _, m := range c.Mounts { mount := swarmapi.Mount{ Target: m.Target, Source: m.Source, ReadOnly: m.ReadOnly, } if mountType, ok := swarmapi.Mount_MountType_value[strings.ToUpper(string(m.Type))]; ok { mount.Type = swarmapi.Mount_MountType(mountType) } else if string(m.Type) != "" { return nil, fmt.Errorf("invalid MountType: %q", m.Type) } if m.BindOptions != nil { if mountPropagation, ok := swarmapi.Mount_BindOptions_MountPropagation_value[strings.ToUpper(string(m.BindOptions.Propagation))]; ok { mount.BindOptions = &swarmapi.Mount_BindOptions{Propagation: swarmapi.Mount_BindOptions_MountPropagation(mountPropagation)} } else if string(m.BindOptions.Propagation) != "" { return nil, fmt.Errorf("invalid MountPropagation: %q", m.BindOptions.Propagation) } } if m.VolumeOptions != nil { mount.VolumeOptions = &swarmapi.Mount_VolumeOptions{ NoCopy: m.VolumeOptions.NoCopy, Labels: m.VolumeOptions.Labels, } if m.VolumeOptions.DriverConfig != nil { mount.VolumeOptions.DriverConfig = &swarmapi.Driver{ Name: m.VolumeOptions.DriverConfig.Name, Options: m.VolumeOptions.DriverConfig.Options, } } } if m.TmpfsOptions != nil { mount.TmpfsOptions = &swarmapi.Mount_TmpfsOptions{ SizeBytes: m.TmpfsOptions.SizeBytes, Mode: m.TmpfsOptions.Mode, } } containerSpec.Mounts = append(containerSpec.Mounts, mount) } if c.Healthcheck != nil { containerSpec.Healthcheck = healthConfigToGRPC(c.Healthcheck) } return containerSpec, nil }