| package convert // import "github.com/docker/docker/daemon/cluster/convert" |
| |
| import ( |
| "errors" |
| "fmt" |
| "strings" |
| |
| "github.com/docker/docker/api/types/container" |
| mounttypes "github.com/docker/docker/api/types/mount" |
| types "github.com/docker/docker/api/types/swarm" |
| swarmapi "github.com/docker/swarmkit/api" |
| gogotypes "github.com/gogo/protobuf/types" |
| "github.com/sirupsen/logrus" |
| ) |
| |
| func containerSpecFromGRPC(c *swarmapi.ContainerSpec) *types.ContainerSpec { |
| if c == nil { |
| return nil |
| } |
| containerSpec := &types.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, |
| StopSignal: c.StopSignal, |
| TTY: c.TTY, |
| OpenStdin: c.OpenStdin, |
| ReadOnly: c.ReadOnly, |
| Hosts: c.Hosts, |
| Secrets: secretReferencesFromGRPC(c.Secrets), |
| Configs: configReferencesFromGRPC(c.Configs), |
| Isolation: IsolationFromGRPC(c.Isolation), |
| Init: initFromGRPC(c.Init), |
| } |
| |
| if c.DNSConfig != nil { |
| containerSpec.DNSConfig = &types.DNSConfig{ |
| Nameservers: c.DNSConfig.Nameservers, |
| Search: c.DNSConfig.Search, |
| Options: c.DNSConfig.Options, |
| } |
| } |
| |
| // Privileges |
| if c.Privileges != nil { |
| containerSpec.Privileges = &types.Privileges{} |
| |
| if c.Privileges.CredentialSpec != nil { |
| containerSpec.Privileges.CredentialSpec = &types.CredentialSpec{} |
| switch c.Privileges.CredentialSpec.Source.(type) { |
| case *swarmapi.Privileges_CredentialSpec_File: |
| containerSpec.Privileges.CredentialSpec.File = c.Privileges.CredentialSpec.GetFile() |
| case *swarmapi.Privileges_CredentialSpec_Registry: |
| containerSpec.Privileges.CredentialSpec.Registry = c.Privileges.CredentialSpec.GetRegistry() |
| } |
| } |
| |
| if c.Privileges.SELinuxContext != nil { |
| containerSpec.Privileges.SELinuxContext = &types.SELinuxContext{ |
| Disable: c.Privileges.SELinuxContext.Disable, |
| User: c.Privileges.SELinuxContext.User, |
| Type: c.Privileges.SELinuxContext.Type, |
| Role: c.Privileges.SELinuxContext.Role, |
| Level: c.Privileges.SELinuxContext.Level, |
| } |
| } |
| } |
| |
| // Mounts |
| for _, m := range c.Mounts { |
| mount := mounttypes.Mount{ |
| Target: m.Target, |
| Source: m.Source, |
| Type: mounttypes.Type(strings.ToLower(swarmapi.Mount_MountType_name[int32(m.Type)])), |
| ReadOnly: m.ReadOnly, |
| } |
| |
| if m.BindOptions != nil { |
| mount.BindOptions = &mounttypes.BindOptions{ |
| Propagation: mounttypes.Propagation(strings.ToLower(swarmapi.Mount_BindOptions_MountPropagation_name[int32(m.BindOptions.Propagation)])), |
| } |
| } |
| |
| if m.VolumeOptions != nil { |
| mount.VolumeOptions = &mounttypes.VolumeOptions{ |
| NoCopy: m.VolumeOptions.NoCopy, |
| Labels: m.VolumeOptions.Labels, |
| } |
| if m.VolumeOptions.DriverConfig != nil { |
| mount.VolumeOptions.DriverConfig = &mounttypes.Driver{ |
| Name: m.VolumeOptions.DriverConfig.Name, |
| Options: m.VolumeOptions.DriverConfig.Options, |
| } |
| } |
| } |
| |
| if m.TmpfsOptions != nil { |
| mount.TmpfsOptions = &mounttypes.TmpfsOptions{ |
| SizeBytes: m.TmpfsOptions.SizeBytes, |
| Mode: m.TmpfsOptions.Mode, |
| } |
| } |
| containerSpec.Mounts = append(containerSpec.Mounts, mount) |
| } |
| |
| if c.StopGracePeriod != nil { |
| grace, _ := gogotypes.DurationFromProto(c.StopGracePeriod) |
| containerSpec.StopGracePeriod = &grace |
| } |
| |
| if c.Healthcheck != nil { |
| containerSpec.Healthcheck = healthConfigFromGRPC(c.Healthcheck) |
| } |
| |
| return containerSpec |
| } |
| |
| func initFromGRPC(v *gogotypes.BoolValue) *bool { |
| if v == nil { |
| return nil |
| } |
| value := v.GetValue() |
| return &value |
| } |
| |
| func initToGRPC(v *bool) *gogotypes.BoolValue { |
| if v == nil { |
| return nil |
| } |
| return &gogotypes.BoolValue{Value: *v} |
| } |
| |
| func secretReferencesToGRPC(sr []*types.SecretReference) []*swarmapi.SecretReference { |
| refs := make([]*swarmapi.SecretReference, 0, len(sr)) |
| for _, s := range sr { |
| ref := &swarmapi.SecretReference{ |
| SecretID: s.SecretID, |
| SecretName: s.SecretName, |
| } |
| if s.File != nil { |
| ref.Target = &swarmapi.SecretReference_File{ |
| File: &swarmapi.FileTarget{ |
| Name: s.File.Name, |
| UID: s.File.UID, |
| GID: s.File.GID, |
| Mode: s.File.Mode, |
| }, |
| } |
| } |
| |
| refs = append(refs, ref) |
| } |
| |
| return refs |
| } |
| |
| func secretReferencesFromGRPC(sr []*swarmapi.SecretReference) []*types.SecretReference { |
| refs := make([]*types.SecretReference, 0, len(sr)) |
| for _, s := range sr { |
| target := s.GetFile() |
| if target == nil { |
| // not a file target |
| logrus.Warnf("secret target not a file: secret=%s", s.SecretID) |
| continue |
| } |
| refs = append(refs, &types.SecretReference{ |
| File: &types.SecretReferenceFileTarget{ |
| Name: target.Name, |
| UID: target.UID, |
| GID: target.GID, |
| Mode: target.Mode, |
| }, |
| SecretID: s.SecretID, |
| SecretName: s.SecretName, |
| }) |
| } |
| |
| return refs |
| } |
| |
| func configReferencesToGRPC(sr []*types.ConfigReference) []*swarmapi.ConfigReference { |
| refs := make([]*swarmapi.ConfigReference, 0, len(sr)) |
| for _, s := range sr { |
| ref := &swarmapi.ConfigReference{ |
| ConfigID: s.ConfigID, |
| ConfigName: s.ConfigName, |
| } |
| if s.File != nil { |
| ref.Target = &swarmapi.ConfigReference_File{ |
| File: &swarmapi.FileTarget{ |
| Name: s.File.Name, |
| UID: s.File.UID, |
| GID: s.File.GID, |
| Mode: s.File.Mode, |
| }, |
| } |
| } |
| |
| refs = append(refs, ref) |
| } |
| |
| return refs |
| } |
| |
| func configReferencesFromGRPC(sr []*swarmapi.ConfigReference) []*types.ConfigReference { |
| refs := make([]*types.ConfigReference, 0, len(sr)) |
| for _, s := range sr { |
| target := s.GetFile() |
| if target == nil { |
| // not a file target |
| logrus.Warnf("config target not a file: config=%s", s.ConfigID) |
| continue |
| } |
| refs = append(refs, &types.ConfigReference{ |
| File: &types.ConfigReferenceFileTarget{ |
| Name: target.Name, |
| UID: target.UID, |
| GID: target.GID, |
| Mode: target.Mode, |
| }, |
| ConfigID: s.ConfigID, |
| ConfigName: s.ConfigName, |
| }) |
| } |
| |
| return refs |
| } |
| |
| 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, |
| StopSignal: c.StopSignal, |
| TTY: c.TTY, |
| OpenStdin: c.OpenStdin, |
| ReadOnly: c.ReadOnly, |
| Hosts: c.Hosts, |
| Secrets: secretReferencesToGRPC(c.Secrets), |
| Configs: configReferencesToGRPC(c.Configs), |
| Isolation: isolationToGRPC(c.Isolation), |
| Init: initToGRPC(c.Init), |
| } |
| |
| 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 = gogotypes.DurationProto(*c.StopGracePeriod) |
| } |
| |
| // Privileges |
| if c.Privileges != nil { |
| containerSpec.Privileges = &swarmapi.Privileges{} |
| |
| if c.Privileges.CredentialSpec != nil { |
| containerSpec.Privileges.CredentialSpec = &swarmapi.Privileges_CredentialSpec{} |
| |
| if c.Privileges.CredentialSpec.File != "" && c.Privileges.CredentialSpec.Registry != "" { |
| return nil, errors.New("cannot specify both \"file\" and \"registry\" credential specs") |
| } |
| if c.Privileges.CredentialSpec.File != "" { |
| containerSpec.Privileges.CredentialSpec.Source = &swarmapi.Privileges_CredentialSpec_File{ |
| File: c.Privileges.CredentialSpec.File, |
| } |
| } else if c.Privileges.CredentialSpec.Registry != "" { |
| containerSpec.Privileges.CredentialSpec.Source = &swarmapi.Privileges_CredentialSpec_Registry{ |
| Registry: c.Privileges.CredentialSpec.Registry, |
| } |
| } else { |
| return nil, errors.New("must either provide \"file\" or \"registry\" for credential spec") |
| } |
| } |
| |
| if c.Privileges.SELinuxContext != nil { |
| containerSpec.Privileges.SELinuxContext = &swarmapi.Privileges_SELinuxContext{ |
| Disable: c.Privileges.SELinuxContext.Disable, |
| User: c.Privileges.SELinuxContext.User, |
| Type: c.Privileges.SELinuxContext.Type, |
| Role: c.Privileges.SELinuxContext.Role, |
| Level: c.Privileges.SELinuxContext.Level, |
| } |
| } |
| } |
| |
| // 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 |
| } |
| |
| func healthConfigFromGRPC(h *swarmapi.HealthConfig) *container.HealthConfig { |
| interval, _ := gogotypes.DurationFromProto(h.Interval) |
| timeout, _ := gogotypes.DurationFromProto(h.Timeout) |
| startPeriod, _ := gogotypes.DurationFromProto(h.StartPeriod) |
| return &container.HealthConfig{ |
| Test: h.Test, |
| Interval: interval, |
| Timeout: timeout, |
| Retries: int(h.Retries), |
| StartPeriod: startPeriod, |
| } |
| } |
| |
| func healthConfigToGRPC(h *container.HealthConfig) *swarmapi.HealthConfig { |
| return &swarmapi.HealthConfig{ |
| Test: h.Test, |
| Interval: gogotypes.DurationProto(h.Interval), |
| Timeout: gogotypes.DurationProto(h.Timeout), |
| Retries: int32(h.Retries), |
| StartPeriod: gogotypes.DurationProto(h.StartPeriod), |
| } |
| } |
| |
| // IsolationFromGRPC converts a swarm api container isolation to a moby isolation representation |
| func IsolationFromGRPC(i swarmapi.ContainerSpec_Isolation) container.Isolation { |
| switch i { |
| case swarmapi.ContainerIsolationHyperV: |
| return container.IsolationHyperV |
| case swarmapi.ContainerIsolationProcess: |
| return container.IsolationProcess |
| case swarmapi.ContainerIsolationDefault: |
| return container.IsolationDefault |
| } |
| return container.IsolationEmpty |
| } |
| |
| func isolationToGRPC(i container.Isolation) swarmapi.ContainerSpec_Isolation { |
| if i.IsHyperV() { |
| return swarmapi.ContainerIsolationHyperV |
| } |
| if i.IsProcess() { |
| return swarmapi.ContainerIsolationProcess |
| } |
| return swarmapi.ContainerIsolationDefault |
| } |