github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/daemon/cluster/convert/container.go (about)

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