github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/daemon/cluster/convert/container.go (about)

     1  package convert // import "github.com/docker/docker/daemon/cluster/convert"
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/docker/docker/api/types/container"
     8  	mounttypes "github.com/docker/docker/api/types/mount"
     9  	types "github.com/docker/docker/api/types/swarm"
    10  	swarmapi "github.com/docker/swarmkit/api"
    11  	gogotypes "github.com/gogo/protobuf/types"
    12  	"github.com/pkg/errors"
    13  	"github.com/sirupsen/logrus"
    14  )
    15  
    16  func containerSpecFromGRPC(c *swarmapi.ContainerSpec) *types.ContainerSpec {
    17  	if c == nil {
    18  		return nil
    19  	}
    20  	containerSpec := &types.ContainerSpec{
    21  		Image:        c.Image,
    22  		Labels:       c.Labels,
    23  		Command:      c.Command,
    24  		Args:         c.Args,
    25  		Hostname:     c.Hostname,
    26  		Env:          c.Env,
    27  		Dir:          c.Dir,
    28  		User:         c.User,
    29  		Groups:       c.Groups,
    30  		StopSignal:   c.StopSignal,
    31  		TTY:          c.TTY,
    32  		OpenStdin:    c.OpenStdin,
    33  		ReadOnly:     c.ReadOnly,
    34  		Hosts:        c.Hosts,
    35  		Secrets:      secretReferencesFromGRPC(c.Secrets),
    36  		Configs:      configReferencesFromGRPC(c.Configs),
    37  		Isolation:    IsolationFromGRPC(c.Isolation),
    38  		Init:         initFromGRPC(c.Init),
    39  		Sysctls:      c.Sysctls,
    40  		Capabilities: c.Capabilities,
    41  	}
    42  
    43  	if c.DNSConfig != nil {
    44  		containerSpec.DNSConfig = &types.DNSConfig{
    45  			Nameservers: c.DNSConfig.Nameservers,
    46  			Search:      c.DNSConfig.Search,
    47  			Options:     c.DNSConfig.Options,
    48  		}
    49  	}
    50  
    51  	// Privileges
    52  	if c.Privileges != nil {
    53  		containerSpec.Privileges = &types.Privileges{}
    54  
    55  		if c.Privileges.CredentialSpec != nil {
    56  			containerSpec.Privileges.CredentialSpec = credentialSpecFromGRPC(c.Privileges.CredentialSpec)
    57  		}
    58  
    59  		if c.Privileges.SELinuxContext != nil {
    60  			containerSpec.Privileges.SELinuxContext = &types.SELinuxContext{
    61  				Disable: c.Privileges.SELinuxContext.Disable,
    62  				User:    c.Privileges.SELinuxContext.User,
    63  				Type:    c.Privileges.SELinuxContext.Type,
    64  				Role:    c.Privileges.SELinuxContext.Role,
    65  				Level:   c.Privileges.SELinuxContext.Level,
    66  			}
    67  		}
    68  	}
    69  
    70  	// Mounts
    71  	for _, m := range c.Mounts {
    72  		mount := mounttypes.Mount{
    73  			Target:   m.Target,
    74  			Source:   m.Source,
    75  			Type:     mounttypes.Type(strings.ToLower(swarmapi.Mount_MountType_name[int32(m.Type)])),
    76  			ReadOnly: m.ReadOnly,
    77  		}
    78  
    79  		if m.BindOptions != nil {
    80  			mount.BindOptions = &mounttypes.BindOptions{
    81  				Propagation:  mounttypes.Propagation(strings.ToLower(swarmapi.Mount_BindOptions_MountPropagation_name[int32(m.BindOptions.Propagation)])),
    82  				NonRecursive: m.BindOptions.NonRecursive,
    83  			}
    84  		}
    85  
    86  		if m.VolumeOptions != nil {
    87  			mount.VolumeOptions = &mounttypes.VolumeOptions{
    88  				NoCopy: m.VolumeOptions.NoCopy,
    89  				Labels: m.VolumeOptions.Labels,
    90  			}
    91  			if m.VolumeOptions.DriverConfig != nil {
    92  				mount.VolumeOptions.DriverConfig = &mounttypes.Driver{
    93  					Name:    m.VolumeOptions.DriverConfig.Name,
    94  					Options: m.VolumeOptions.DriverConfig.Options,
    95  				}
    96  			}
    97  		}
    98  
    99  		if m.TmpfsOptions != nil {
   100  			mount.TmpfsOptions = &mounttypes.TmpfsOptions{
   101  				SizeBytes: m.TmpfsOptions.SizeBytes,
   102  				Mode:      m.TmpfsOptions.Mode,
   103  			}
   104  		}
   105  		containerSpec.Mounts = append(containerSpec.Mounts, mount)
   106  	}
   107  
   108  	if c.StopGracePeriod != nil {
   109  		grace, _ := gogotypes.DurationFromProto(c.StopGracePeriod)
   110  		containerSpec.StopGracePeriod = &grace
   111  	}
   112  
   113  	if c.Healthcheck != nil {
   114  		containerSpec.Healthcheck = healthConfigFromGRPC(c.Healthcheck)
   115  	}
   116  
   117  	return containerSpec
   118  }
   119  
   120  func initFromGRPC(v *gogotypes.BoolValue) *bool {
   121  	if v == nil {
   122  		return nil
   123  	}
   124  	value := v.GetValue()
   125  	return &value
   126  }
   127  
   128  func initToGRPC(v *bool) *gogotypes.BoolValue {
   129  	if v == nil {
   130  		return nil
   131  	}
   132  	return &gogotypes.BoolValue{Value: *v}
   133  }
   134  
   135  func secretReferencesToGRPC(sr []*types.SecretReference) []*swarmapi.SecretReference {
   136  	refs := make([]*swarmapi.SecretReference, 0, len(sr))
   137  	for _, s := range sr {
   138  		ref := &swarmapi.SecretReference{
   139  			SecretID:   s.SecretID,
   140  			SecretName: s.SecretName,
   141  		}
   142  		if s.File != nil {
   143  			ref.Target = &swarmapi.SecretReference_File{
   144  				File: &swarmapi.FileTarget{
   145  					Name: s.File.Name,
   146  					UID:  s.File.UID,
   147  					GID:  s.File.GID,
   148  					Mode: s.File.Mode,
   149  				},
   150  			}
   151  		}
   152  
   153  		refs = append(refs, ref)
   154  	}
   155  
   156  	return refs
   157  }
   158  
   159  func secretReferencesFromGRPC(sr []*swarmapi.SecretReference) []*types.SecretReference {
   160  	refs := make([]*types.SecretReference, 0, len(sr))
   161  	for _, s := range sr {
   162  		target := s.GetFile()
   163  		if target == nil {
   164  			// not a file target
   165  			logrus.Warnf("secret target not a file: secret=%s", s.SecretID)
   166  			continue
   167  		}
   168  		refs = append(refs, &types.SecretReference{
   169  			File: &types.SecretReferenceFileTarget{
   170  				Name: target.Name,
   171  				UID:  target.UID,
   172  				GID:  target.GID,
   173  				Mode: target.Mode,
   174  			},
   175  			SecretID:   s.SecretID,
   176  			SecretName: s.SecretName,
   177  		})
   178  	}
   179  
   180  	return refs
   181  }
   182  
   183  func configReferencesToGRPC(sr []*types.ConfigReference) ([]*swarmapi.ConfigReference, error) {
   184  	refs := make([]*swarmapi.ConfigReference, 0, len(sr))
   185  	for _, s := range sr {
   186  		ref := &swarmapi.ConfigReference{
   187  			ConfigID:   s.ConfigID,
   188  			ConfigName: s.ConfigName,
   189  		}
   190  		switch {
   191  		case s.Runtime == nil && s.File == nil:
   192  			return nil, errors.New("either File or Runtime should be set")
   193  		case s.Runtime != nil && s.File != nil:
   194  			return nil, errors.New("cannot specify both File and Runtime")
   195  		case s.Runtime != nil:
   196  			// Runtime target was added in API v1.40 and takes precedence over
   197  			// File target. However, File and Runtime targets are mutually exclusive,
   198  			// so we should never have both.
   199  			ref.Target = &swarmapi.ConfigReference_Runtime{
   200  				Runtime: &swarmapi.RuntimeTarget{},
   201  			}
   202  		case s.File != nil:
   203  			ref.Target = &swarmapi.ConfigReference_File{
   204  				File: &swarmapi.FileTarget{
   205  					Name: s.File.Name,
   206  					UID:  s.File.UID,
   207  					GID:  s.File.GID,
   208  					Mode: s.File.Mode,
   209  				},
   210  			}
   211  		}
   212  
   213  		refs = append(refs, ref)
   214  	}
   215  
   216  	return refs, nil
   217  }
   218  
   219  func configReferencesFromGRPC(sr []*swarmapi.ConfigReference) []*types.ConfigReference {
   220  	refs := make([]*types.ConfigReference, 0, len(sr))
   221  	for _, s := range sr {
   222  
   223  		r := &types.ConfigReference{
   224  			ConfigID:   s.ConfigID,
   225  			ConfigName: s.ConfigName,
   226  		}
   227  		if target := s.GetRuntime(); target != nil {
   228  			r.Runtime = &types.ConfigReferenceRuntimeTarget{}
   229  		} else if target := s.GetFile(); target != nil {
   230  			r.File = &types.ConfigReferenceFileTarget{
   231  				Name: target.Name,
   232  				UID:  target.UID,
   233  				GID:  target.GID,
   234  				Mode: target.Mode,
   235  			}
   236  		} else {
   237  			// not a file target
   238  			logrus.Warnf("config target not known: config=%s", s.ConfigID)
   239  			continue
   240  		}
   241  		refs = append(refs, r)
   242  	}
   243  
   244  	return refs
   245  }
   246  
   247  func containerToGRPC(c *types.ContainerSpec) (*swarmapi.ContainerSpec, error) {
   248  	containerSpec := &swarmapi.ContainerSpec{
   249  		Image:        c.Image,
   250  		Labels:       c.Labels,
   251  		Command:      c.Command,
   252  		Args:         c.Args,
   253  		Hostname:     c.Hostname,
   254  		Env:          c.Env,
   255  		Dir:          c.Dir,
   256  		User:         c.User,
   257  		Groups:       c.Groups,
   258  		StopSignal:   c.StopSignal,
   259  		TTY:          c.TTY,
   260  		OpenStdin:    c.OpenStdin,
   261  		ReadOnly:     c.ReadOnly,
   262  		Hosts:        c.Hosts,
   263  		Secrets:      secretReferencesToGRPC(c.Secrets),
   264  		Isolation:    isolationToGRPC(c.Isolation),
   265  		Init:         initToGRPC(c.Init),
   266  		Sysctls:      c.Sysctls,
   267  		Capabilities: c.Capabilities,
   268  	}
   269  
   270  	if c.DNSConfig != nil {
   271  		containerSpec.DNSConfig = &swarmapi.ContainerSpec_DNSConfig{
   272  			Nameservers: c.DNSConfig.Nameservers,
   273  			Search:      c.DNSConfig.Search,
   274  			Options:     c.DNSConfig.Options,
   275  		}
   276  	}
   277  
   278  	if c.StopGracePeriod != nil {
   279  		containerSpec.StopGracePeriod = gogotypes.DurationProto(*c.StopGracePeriod)
   280  	}
   281  
   282  	// Privileges
   283  	if c.Privileges != nil {
   284  		containerSpec.Privileges = &swarmapi.Privileges{}
   285  
   286  		if c.Privileges.CredentialSpec != nil {
   287  			cs, err := credentialSpecToGRPC(c.Privileges.CredentialSpec)
   288  			if err != nil {
   289  				return nil, errors.Wrap(err, "invalid CredentialSpec")
   290  			}
   291  			containerSpec.Privileges.CredentialSpec = cs
   292  		}
   293  
   294  		if c.Privileges.SELinuxContext != nil {
   295  			containerSpec.Privileges.SELinuxContext = &swarmapi.Privileges_SELinuxContext{
   296  				Disable: c.Privileges.SELinuxContext.Disable,
   297  				User:    c.Privileges.SELinuxContext.User,
   298  				Type:    c.Privileges.SELinuxContext.Type,
   299  				Role:    c.Privileges.SELinuxContext.Role,
   300  				Level:   c.Privileges.SELinuxContext.Level,
   301  			}
   302  		}
   303  	}
   304  
   305  	if c.Configs != nil {
   306  		configs, err := configReferencesToGRPC(c.Configs)
   307  		if err != nil {
   308  			return nil, errors.Wrap(err, "invalid Config")
   309  		}
   310  		containerSpec.Configs = configs
   311  	}
   312  
   313  	// Mounts
   314  	for _, m := range c.Mounts {
   315  		mount := swarmapi.Mount{
   316  			Target:   m.Target,
   317  			Source:   m.Source,
   318  			ReadOnly: m.ReadOnly,
   319  		}
   320  
   321  		if mountType, ok := swarmapi.Mount_MountType_value[strings.ToUpper(string(m.Type))]; ok {
   322  			mount.Type = swarmapi.Mount_MountType(mountType)
   323  		} else if string(m.Type) != "" {
   324  			return nil, fmt.Errorf("invalid MountType: %q", m.Type)
   325  		}
   326  
   327  		if m.BindOptions != nil {
   328  			if mountPropagation, ok := swarmapi.Mount_BindOptions_MountPropagation_value[strings.ToUpper(string(m.BindOptions.Propagation))]; ok {
   329  				mount.BindOptions = &swarmapi.Mount_BindOptions{Propagation: swarmapi.Mount_BindOptions_MountPropagation(mountPropagation)}
   330  			} else if string(m.BindOptions.Propagation) != "" {
   331  				return nil, fmt.Errorf("invalid MountPropagation: %q", m.BindOptions.Propagation)
   332  			}
   333  
   334  			if m.BindOptions.NonRecursive {
   335  				if mount.BindOptions == nil {
   336  					// the propagation defaults to rprivate
   337  					mount.BindOptions = &swarmapi.Mount_BindOptions{}
   338  				}
   339  				mount.BindOptions.NonRecursive = m.BindOptions.NonRecursive
   340  			}
   341  		}
   342  
   343  		if m.VolumeOptions != nil {
   344  			mount.VolumeOptions = &swarmapi.Mount_VolumeOptions{
   345  				NoCopy: m.VolumeOptions.NoCopy,
   346  				Labels: m.VolumeOptions.Labels,
   347  			}
   348  			if m.VolumeOptions.DriverConfig != nil {
   349  				mount.VolumeOptions.DriverConfig = &swarmapi.Driver{
   350  					Name:    m.VolumeOptions.DriverConfig.Name,
   351  					Options: m.VolumeOptions.DriverConfig.Options,
   352  				}
   353  			}
   354  		}
   355  
   356  		if m.TmpfsOptions != nil {
   357  			mount.TmpfsOptions = &swarmapi.Mount_TmpfsOptions{
   358  				SizeBytes: m.TmpfsOptions.SizeBytes,
   359  				Mode:      m.TmpfsOptions.Mode,
   360  			}
   361  		}
   362  
   363  		containerSpec.Mounts = append(containerSpec.Mounts, mount)
   364  	}
   365  
   366  	if c.Healthcheck != nil {
   367  		containerSpec.Healthcheck = healthConfigToGRPC(c.Healthcheck)
   368  	}
   369  
   370  	return containerSpec, nil
   371  }
   372  
   373  func credentialSpecFromGRPC(c *swarmapi.Privileges_CredentialSpec) *types.CredentialSpec {
   374  	cs := &types.CredentialSpec{}
   375  	switch c.Source.(type) {
   376  	case *swarmapi.Privileges_CredentialSpec_Config:
   377  		cs.Config = c.GetConfig()
   378  	case *swarmapi.Privileges_CredentialSpec_File:
   379  		cs.File = c.GetFile()
   380  	case *swarmapi.Privileges_CredentialSpec_Registry:
   381  		cs.Registry = c.GetRegistry()
   382  	}
   383  	return cs
   384  }
   385  
   386  func credentialSpecToGRPC(c *types.CredentialSpec) (*swarmapi.Privileges_CredentialSpec, error) {
   387  	var opts []string
   388  
   389  	if c.Config != "" {
   390  		opts = append(opts, `"config"`)
   391  	}
   392  	if c.File != "" {
   393  		opts = append(opts, `"file"`)
   394  	}
   395  	if c.Registry != "" {
   396  		opts = append(opts, `"registry"`)
   397  	}
   398  	l := len(opts)
   399  	switch {
   400  	case l == 0:
   401  		return nil, errors.New(`must either provide "file", "registry", or "config" for credential spec`)
   402  	case l == 2:
   403  		return nil, fmt.Errorf("cannot specify both %s and %s credential specs", opts[0], opts[1])
   404  	case l > 2:
   405  		return nil, fmt.Errorf("cannot specify both %s, and %s credential specs", strings.Join(opts[:l-1], ", "), opts[l-1])
   406  	}
   407  
   408  	spec := &swarmapi.Privileges_CredentialSpec{}
   409  	switch {
   410  	case c.Config != "":
   411  		spec.Source = &swarmapi.Privileges_CredentialSpec_Config{
   412  			Config: c.Config,
   413  		}
   414  	case c.File != "":
   415  		spec.Source = &swarmapi.Privileges_CredentialSpec_File{
   416  			File: c.File,
   417  		}
   418  	case c.Registry != "":
   419  		spec.Source = &swarmapi.Privileges_CredentialSpec_Registry{
   420  			Registry: c.Registry,
   421  		}
   422  	}
   423  
   424  	return spec, nil
   425  }
   426  
   427  func healthConfigFromGRPC(h *swarmapi.HealthConfig) *container.HealthConfig {
   428  	interval, _ := gogotypes.DurationFromProto(h.Interval)
   429  	timeout, _ := gogotypes.DurationFromProto(h.Timeout)
   430  	startPeriod, _ := gogotypes.DurationFromProto(h.StartPeriod)
   431  	return &container.HealthConfig{
   432  		Test:        h.Test,
   433  		Interval:    interval,
   434  		Timeout:     timeout,
   435  		Retries:     int(h.Retries),
   436  		StartPeriod: startPeriod,
   437  	}
   438  }
   439  
   440  func healthConfigToGRPC(h *container.HealthConfig) *swarmapi.HealthConfig {
   441  	return &swarmapi.HealthConfig{
   442  		Test:        h.Test,
   443  		Interval:    gogotypes.DurationProto(h.Interval),
   444  		Timeout:     gogotypes.DurationProto(h.Timeout),
   445  		Retries:     int32(h.Retries),
   446  		StartPeriod: gogotypes.DurationProto(h.StartPeriod),
   447  	}
   448  }
   449  
   450  // IsolationFromGRPC converts a swarm api container isolation to a moby isolation representation
   451  func IsolationFromGRPC(i swarmapi.ContainerSpec_Isolation) container.Isolation {
   452  	switch i {
   453  	case swarmapi.ContainerIsolationHyperV:
   454  		return container.IsolationHyperV
   455  	case swarmapi.ContainerIsolationProcess:
   456  		return container.IsolationProcess
   457  	case swarmapi.ContainerIsolationDefault:
   458  		return container.IsolationDefault
   459  	}
   460  	return container.IsolationEmpty
   461  }
   462  
   463  func isolationToGRPC(i container.Isolation) swarmapi.ContainerSpec_Isolation {
   464  	if i.IsHyperV() {
   465  		return swarmapi.ContainerIsolationHyperV
   466  	}
   467  	if i.IsProcess() {
   468  		return swarmapi.ContainerIsolationProcess
   469  	}
   470  	return swarmapi.ContainerIsolationDefault
   471  }