github.com/docker/compose-on-kubernetes@v0.5.0/internal/conversions/v1alpha3.go (about)

     1  package conversions
     2  
     3  import (
     4  	"regexp"
     5  	"strconv"
     6  	"strings"
     7  
     8  	composetypes "github.com/docker/cli/cli/compose/types"
     9  	"github.com/docker/compose-on-kubernetes/api/compose/v1alpha3"
    10  	"github.com/docker/compose-on-kubernetes/internal/internalversion"
    11  	"github.com/docker/compose-on-kubernetes/internal/parsing"
    12  	"k8s.io/apimachinery/pkg/conversion"
    13  	"k8s.io/apimachinery/pkg/runtime"
    14  )
    15  
    16  // RegisterV1alpha3Conversions adds conversion functions to the given scheme.
    17  // Public to allow building arbitrary schemes.
    18  func RegisterV1alpha3Conversions(scheme *runtime.Scheme) error {
    19  	return scheme.AddConversionFuncs(
    20  		ownerToInternalV1alpha3,
    21  		ownerFromInternalV1alpha3,
    22  		stackToInternalV1alpha3,
    23  		stackFromInternalV1alpha3,
    24  		stackListToInternalV1alpha3,
    25  		stackListFromInternalV1alpha3,
    26  	)
    27  }
    28  
    29  func ownerToInternalV1alpha3(in *v1alpha3.Owner, out *internalversion.Owner, _ conversion.Scope) error {
    30  	out.ObjectMeta = in.ObjectMeta
    31  	out.Owner = in.Owner
    32  	return nil
    33  }
    34  
    35  func ownerFromInternalV1alpha3(in *internalversion.Owner, out *v1alpha3.Owner, _ conversion.Scope) error {
    36  	out.ObjectMeta = in.ObjectMeta
    37  	out.Owner = in.Owner
    38  	return nil
    39  }
    40  
    41  func stackToInternalV1alpha3(in *v1alpha3.Stack, out *internalversion.Stack, _ conversion.Scope) error {
    42  	out.ObjectMeta = in.ObjectMeta
    43  	out.Spec.Stack = in.Spec
    44  	if in.Status != nil {
    45  		out.Status = &internalversion.StackStatus{
    46  			Message: in.Status.Message,
    47  			Phase:   internalversion.StackPhase(in.Status.Phase),
    48  		}
    49  	} else {
    50  		out.Status = nil
    51  	}
    52  	return nil
    53  }
    54  
    55  func stackFromInternalV1alpha3(in *internalversion.Stack, out *v1alpha3.Stack, _ conversion.Scope) error {
    56  	out.ObjectMeta = in.ObjectMeta
    57  	out.Spec = in.Spec.Stack
    58  	if in.Spec.Stack == nil && in.Spec.ComposeFile != "" {
    59  		composeConfig, err := parsing.LoadStackData([]byte(in.Spec.ComposeFile), map[string]string{})
    60  		if err == nil {
    61  			return err
    62  		}
    63  		// This should only occur if old v1beta1-era objects are present in storage
    64  		// In that case we need to provide a Spec
    65  		config := FromComposeConfig(composeConfig)
    66  		out.Spec = config
    67  	}
    68  	if in.Status != nil {
    69  		out.Status = &v1alpha3.StackStatus{
    70  			Message: in.Status.Message,
    71  			Phase:   v1alpha3.StackPhase(in.Status.Phase),
    72  		}
    73  	} else {
    74  		out.Status = nil
    75  	}
    76  	return nil
    77  }
    78  
    79  // FromComposeConfig converts a cli/compose/types.Config to a v1alpha3 Config struct.
    80  // Use it only for backward compat between v1beta1 and later.
    81  func FromComposeConfig(c *composetypes.Config) *v1alpha3.StackSpec {
    82  	if c == nil {
    83  		return nil
    84  	}
    85  	serviceConfigs := make([]v1alpha3.ServiceConfig, len(c.Services))
    86  	for i, s := range c.Services {
    87  		serviceConfigs[i] = fromComposeServiceConfig(s)
    88  	}
    89  	return &v1alpha3.StackSpec{
    90  		Services: serviceConfigs,
    91  		Secrets:  fromComposeSecrets(c.Secrets),
    92  		Configs:  fromComposeConfigs(c.Configs),
    93  	}
    94  }
    95  
    96  func fromComposeSecrets(s map[string]composetypes.SecretConfig) map[string]v1alpha3.SecretConfig {
    97  	if s == nil {
    98  		return nil
    99  	}
   100  	m := map[string]v1alpha3.SecretConfig{}
   101  	for key, value := range s {
   102  		m[key] = v1alpha3.SecretConfig{
   103  			Name: value.Name,
   104  			File: value.File,
   105  			External: v1alpha3.External{
   106  				Name:     value.External.Name,
   107  				External: value.External.External,
   108  			},
   109  			Labels: value.Labels,
   110  		}
   111  	}
   112  	return m
   113  }
   114  
   115  func fromComposeConfigs(s map[string]composetypes.ConfigObjConfig) map[string]v1alpha3.ConfigObjConfig {
   116  	if s == nil {
   117  		return nil
   118  	}
   119  	m := map[string]v1alpha3.ConfigObjConfig{}
   120  	for key, value := range s {
   121  		m[key] = v1alpha3.ConfigObjConfig{
   122  			Name: value.Name,
   123  			File: value.File,
   124  			External: v1alpha3.External{
   125  				Name:     value.External.Name,
   126  				External: value.External.External,
   127  			},
   128  			Labels: value.Labels,
   129  		}
   130  	}
   131  	return m
   132  }
   133  
   134  func fromComposeServiceConfig(s composetypes.ServiceConfig) v1alpha3.ServiceConfig {
   135  	var userID *int64
   136  	if s.User != "" {
   137  		numerical, err := strconv.Atoi(s.User)
   138  		if err == nil {
   139  			unixUserID := int64(numerical)
   140  			userID = &unixUserID
   141  		}
   142  	}
   143  	return v1alpha3.ServiceConfig{
   144  		Name:    s.Name,
   145  		CapAdd:  s.CapAdd,
   146  		CapDrop: s.CapDrop,
   147  		Command: s.Command,
   148  		Configs: fromComposeServiceConfigs(s.Configs),
   149  		Deploy: v1alpha3.DeployConfig{
   150  			Mode:          s.Deploy.Mode,
   151  			Replicas:      s.Deploy.Replicas,
   152  			Labels:        s.Deploy.Labels,
   153  			UpdateConfig:  fromComposeUpdateConfig(s.Deploy.UpdateConfig),
   154  			Resources:     fromComposeResources(s.Deploy.Resources),
   155  			RestartPolicy: fromComposeRestartPolicy(s.Deploy.RestartPolicy),
   156  			Placement:     fromComposePlacement(s.Deploy.Placement),
   157  		},
   158  		Entrypoint:      s.Entrypoint,
   159  		Environment:     s.Environment,
   160  		ExtraHosts:      s.ExtraHosts,
   161  		Hostname:        s.Hostname,
   162  		HealthCheck:     fromComposeHealthcheck(s.HealthCheck),
   163  		Image:           s.Image,
   164  		Ipc:             s.Ipc,
   165  		Labels:          s.Labels,
   166  		Pid:             s.Pid,
   167  		Ports:           fromComposePorts(s.Ports),
   168  		Privileged:      s.Privileged,
   169  		ReadOnly:        s.ReadOnly,
   170  		Secrets:         fromComposeServiceSecrets(s.Secrets),
   171  		StdinOpen:       s.StdinOpen,
   172  		StopGracePeriod: composetypes.ConvertDurationPtr(s.StopGracePeriod),
   173  		Tmpfs:           s.Tmpfs,
   174  		Tty:             s.Tty,
   175  		User:            userID,
   176  		Volumes:         fromComposeServiceVolumeConfig(s.Volumes),
   177  		WorkingDir:      s.WorkingDir,
   178  	}
   179  }
   180  
   181  func fromComposePorts(ports []composetypes.ServicePortConfig) []v1alpha3.ServicePortConfig {
   182  	if ports == nil {
   183  		return nil
   184  	}
   185  	p := make([]v1alpha3.ServicePortConfig, len(ports))
   186  	for i, port := range ports {
   187  		p[i] = v1alpha3.ServicePortConfig{
   188  			Mode:      port.Mode,
   189  			Target:    port.Target,
   190  			Published: port.Published,
   191  			Protocol:  port.Protocol,
   192  		}
   193  	}
   194  	return p
   195  }
   196  
   197  func fromComposeServiceSecrets(secrets []composetypes.ServiceSecretConfig) []v1alpha3.ServiceSecretConfig {
   198  	if secrets == nil {
   199  		return nil
   200  	}
   201  	c := make([]v1alpha3.ServiceSecretConfig, len(secrets))
   202  	for i, secret := range secrets {
   203  		c[i] = v1alpha3.ServiceSecretConfig{
   204  			Source: secret.Source,
   205  			Target: secret.Target,
   206  			UID:    secret.UID,
   207  			Mode:   secret.Mode,
   208  		}
   209  	}
   210  	return c
   211  }
   212  
   213  func fromComposeServiceConfigs(configs []composetypes.ServiceConfigObjConfig) []v1alpha3.ServiceConfigObjConfig {
   214  	if configs == nil {
   215  		return nil
   216  	}
   217  	c := make([]v1alpha3.ServiceConfigObjConfig, len(configs))
   218  	for i, config := range configs {
   219  		c[i] = v1alpha3.ServiceConfigObjConfig{
   220  			Source: config.Source,
   221  			Target: config.Target,
   222  			UID:    config.UID,
   223  			Mode:   config.Mode,
   224  		}
   225  	}
   226  	return c
   227  }
   228  
   229  func fromComposeHealthcheck(h *composetypes.HealthCheckConfig) *v1alpha3.HealthCheckConfig {
   230  	if h == nil {
   231  		return nil
   232  	}
   233  	return &v1alpha3.HealthCheckConfig{
   234  		Test:     h.Test,
   235  		Timeout:  composetypes.ConvertDurationPtr(h.Timeout),
   236  		Interval: composetypes.ConvertDurationPtr(h.Interval),
   237  		Retries:  h.Retries,
   238  	}
   239  }
   240  
   241  func fromComposePlacement(p composetypes.Placement) v1alpha3.Placement {
   242  	return v1alpha3.Placement{
   243  		Constraints: fromComposeConstraints(p.Constraints),
   244  	}
   245  }
   246  
   247  var constraintEquals = regexp.MustCompile(`([\w\.]*)\W*(==|!=)\W*([\w\.]*)`)
   248  
   249  const (
   250  	swarmOs          = "node.platform.os"
   251  	swarmArch        = "node.platform.arch"
   252  	swarmHostname    = "node.hostname"
   253  	swarmLabelPrefix = "node.labels."
   254  )
   255  
   256  func fromComposeConstraints(s []string) *v1alpha3.Constraints {
   257  	if len(s) == 0 {
   258  		return nil
   259  	}
   260  	constraints := &v1alpha3.Constraints{}
   261  	for _, constraint := range s {
   262  		matches := constraintEquals.FindStringSubmatch(constraint)
   263  		if len(matches) == 4 {
   264  			key := matches[1]
   265  			operator := matches[2]
   266  			value := matches[3]
   267  			constraint := &v1alpha3.Constraint{
   268  				Operator: operator,
   269  				Value:    value,
   270  			}
   271  			switch {
   272  			case key == swarmOs:
   273  				constraints.OperatingSystem = constraint
   274  			case key == swarmArch:
   275  				constraints.Architecture = constraint
   276  			case key == swarmHostname:
   277  				constraints.Hostname = constraint
   278  			case strings.HasPrefix(key, swarmLabelPrefix):
   279  				if constraints.MatchLabels == nil {
   280  					constraints.MatchLabels = map[string]v1alpha3.Constraint{}
   281  				}
   282  				constraints.MatchLabels[strings.TrimPrefix(key, swarmLabelPrefix)] = *constraint
   283  			}
   284  		}
   285  	}
   286  	return constraints
   287  }
   288  
   289  func fromComposeResources(r composetypes.Resources) v1alpha3.Resources {
   290  	return v1alpha3.Resources{
   291  		Limits:       fromComposeResourcesResource(r.Limits),
   292  		Reservations: fromComposeResourcesResource(r.Reservations),
   293  	}
   294  }
   295  
   296  func fromComposeResourcesResource(r *composetypes.Resource) *v1alpha3.Resource {
   297  	if r == nil {
   298  		return nil
   299  	}
   300  	return &v1alpha3.Resource{
   301  		MemoryBytes: int64(r.MemoryBytes),
   302  		NanoCPUs:    r.NanoCPUs,
   303  	}
   304  }
   305  
   306  func fromComposeUpdateConfig(u *composetypes.UpdateConfig) *v1alpha3.UpdateConfig {
   307  	if u == nil {
   308  		return nil
   309  	}
   310  	return &v1alpha3.UpdateConfig{
   311  		Parallelism: u.Parallelism,
   312  	}
   313  }
   314  
   315  func fromComposeRestartPolicy(r *composetypes.RestartPolicy) *v1alpha3.RestartPolicy {
   316  	if r == nil {
   317  		return nil
   318  	}
   319  	return &v1alpha3.RestartPolicy{
   320  		Condition: r.Condition,
   321  	}
   322  }
   323  
   324  func fromComposeServiceVolumeConfig(vs []composetypes.ServiceVolumeConfig) []v1alpha3.ServiceVolumeConfig {
   325  	if vs == nil {
   326  		return nil
   327  	}
   328  	volumes := []v1alpha3.ServiceVolumeConfig{}
   329  	for _, v := range vs {
   330  		volumes = append(volumes, v1alpha3.ServiceVolumeConfig{
   331  			Type:     v.Type,
   332  			Source:   v.Source,
   333  			Target:   v.Target,
   334  			ReadOnly: v.ReadOnly,
   335  		})
   336  	}
   337  	return volumes
   338  }
   339  
   340  // StackFromInternalV1alpha3 converts an internal stack to v1alpha3 flavor
   341  func StackFromInternalV1alpha3(in *internalversion.Stack) (*v1alpha3.Stack, error) {
   342  	if in == nil {
   343  		return nil, nil
   344  	}
   345  	out := new(v1alpha3.Stack)
   346  	err := stackFromInternalV1alpha3(in, out, nil)
   347  	return out, err
   348  }
   349  
   350  func stackListToInternalV1alpha3(in *v1alpha3.StackList, out *internalversion.StackList, s conversion.Scope) error {
   351  	out.ListMeta = in.ListMeta
   352  	if in.Items != nil {
   353  		inSlice, outSlice := &in.Items, &out.Items
   354  		*outSlice = make([]internalversion.Stack, len(*inSlice))
   355  		for i := range *inSlice {
   356  			if err := stackToInternalV1alpha3(&(*inSlice)[i], &(*outSlice)[i], s); err != nil {
   357  				return err
   358  			}
   359  		}
   360  	} else {
   361  		out.Items = nil
   362  	}
   363  	return nil
   364  }
   365  
   366  func stackListFromInternalV1alpha3(in *internalversion.StackList, out *v1alpha3.StackList, s conversion.Scope) error {
   367  	out.ListMeta = in.ListMeta
   368  	if in.Items != nil {
   369  		inSlice, outSlice := &in.Items, &out.Items
   370  		*outSlice = make([]v1alpha3.Stack, len(*inSlice))
   371  		for i := range *inSlice {
   372  			if err := stackFromInternalV1alpha3(&(*inSlice)[i], &(*outSlice)[i], s); err != nil {
   373  				return err
   374  			}
   375  		}
   376  	} else {
   377  		out.Items = make([]v1alpha3.Stack, 0)
   378  	}
   379  	return nil
   380  }