github.com/jiasir/docker@v1.3.3-0.20170609024000-252e610103e7/daemon/cluster/convert/service.go (about)

     1  package convert
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strings"
     7  
     8  	types "github.com/docker/docker/api/types/swarm"
     9  	"github.com/docker/docker/pkg/namesgenerator"
    10  	swarmapi "github.com/docker/swarmkit/api"
    11  	gogotypes "github.com/gogo/protobuf/types"
    12  )
    13  
    14  var (
    15  	// ErrUnsupportedRuntime returns an error if the runtime is not supported by the daemon
    16  	ErrUnsupportedRuntime = errors.New("unsupported runtime")
    17  )
    18  
    19  // ServiceFromGRPC converts a grpc Service to a Service.
    20  func ServiceFromGRPC(s swarmapi.Service) (types.Service, error) {
    21  	curSpec, err := serviceSpecFromGRPC(&s.Spec)
    22  	if err != nil {
    23  		return types.Service{}, err
    24  	}
    25  	prevSpec, err := serviceSpecFromGRPC(s.PreviousSpec)
    26  	if err != nil {
    27  		return types.Service{}, err
    28  	}
    29  	service := types.Service{
    30  		ID:           s.ID,
    31  		Spec:         *curSpec,
    32  		PreviousSpec: prevSpec,
    33  
    34  		Endpoint: endpointFromGRPC(s.Endpoint),
    35  	}
    36  
    37  	// Meta
    38  	service.Version.Index = s.Meta.Version.Index
    39  	service.CreatedAt, _ = gogotypes.TimestampFromProto(s.Meta.CreatedAt)
    40  	service.UpdatedAt, _ = gogotypes.TimestampFromProto(s.Meta.UpdatedAt)
    41  
    42  	// UpdateStatus
    43  	if s.UpdateStatus != nil {
    44  		service.UpdateStatus = &types.UpdateStatus{}
    45  		switch s.UpdateStatus.State {
    46  		case swarmapi.UpdateStatus_UPDATING:
    47  			service.UpdateStatus.State = types.UpdateStateUpdating
    48  		case swarmapi.UpdateStatus_PAUSED:
    49  			service.UpdateStatus.State = types.UpdateStatePaused
    50  		case swarmapi.UpdateStatus_COMPLETED:
    51  			service.UpdateStatus.State = types.UpdateStateCompleted
    52  		case swarmapi.UpdateStatus_ROLLBACK_STARTED:
    53  			service.UpdateStatus.State = types.UpdateStateRollbackStarted
    54  		case swarmapi.UpdateStatus_ROLLBACK_PAUSED:
    55  			service.UpdateStatus.State = types.UpdateStateRollbackPaused
    56  		case swarmapi.UpdateStatus_ROLLBACK_COMPLETED:
    57  			service.UpdateStatus.State = types.UpdateStateRollbackCompleted
    58  		}
    59  
    60  		startedAt, _ := gogotypes.TimestampFromProto(s.UpdateStatus.StartedAt)
    61  		if !startedAt.IsZero() && startedAt.Unix() != 0 {
    62  			service.UpdateStatus.StartedAt = &startedAt
    63  		}
    64  
    65  		completedAt, _ := gogotypes.TimestampFromProto(s.UpdateStatus.CompletedAt)
    66  		if !completedAt.IsZero() && completedAt.Unix() != 0 {
    67  			service.UpdateStatus.CompletedAt = &completedAt
    68  		}
    69  
    70  		service.UpdateStatus.Message = s.UpdateStatus.Message
    71  	}
    72  
    73  	return service, nil
    74  }
    75  
    76  func serviceSpecFromGRPC(spec *swarmapi.ServiceSpec) (*types.ServiceSpec, error) {
    77  	if spec == nil {
    78  		return nil, nil
    79  	}
    80  
    81  	serviceNetworks := make([]types.NetworkAttachmentConfig, 0, len(spec.Networks))
    82  	for _, n := range spec.Networks {
    83  		netConfig := types.NetworkAttachmentConfig{Target: n.Target, Aliases: n.Aliases, DriverOpts: n.DriverAttachmentOpts}
    84  		serviceNetworks = append(serviceNetworks, netConfig)
    85  
    86  	}
    87  
    88  	taskTemplate := taskSpecFromGRPC(spec.Task)
    89  
    90  	switch t := spec.Task.GetRuntime().(type) {
    91  	case *swarmapi.TaskSpec_Container:
    92  		containerConfig := t.Container
    93  		taskTemplate.ContainerSpec = containerSpecFromGRPC(containerConfig)
    94  		taskTemplate.Runtime = types.RuntimeContainer
    95  	case *swarmapi.TaskSpec_Generic:
    96  		switch t.Generic.Kind {
    97  		case string(types.RuntimePlugin):
    98  			taskTemplate.Runtime = types.RuntimePlugin
    99  		default:
   100  			return nil, fmt.Errorf("unknown task runtime type: %s", t.Generic.Payload.TypeUrl)
   101  		}
   102  
   103  	default:
   104  		return nil, fmt.Errorf("error creating service; unsupported runtime %T", t)
   105  	}
   106  
   107  	convertedSpec := &types.ServiceSpec{
   108  		Annotations:  annotationsFromGRPC(spec.Annotations),
   109  		TaskTemplate: taskTemplate,
   110  		Networks:     serviceNetworks,
   111  		EndpointSpec: endpointSpecFromGRPC(spec.Endpoint),
   112  	}
   113  
   114  	// UpdateConfig
   115  	convertedSpec.UpdateConfig = updateConfigFromGRPC(spec.Update)
   116  	convertedSpec.RollbackConfig = updateConfigFromGRPC(spec.Rollback)
   117  
   118  	// Mode
   119  	switch t := spec.GetMode().(type) {
   120  	case *swarmapi.ServiceSpec_Global:
   121  		convertedSpec.Mode.Global = &types.GlobalService{}
   122  	case *swarmapi.ServiceSpec_Replicated:
   123  		convertedSpec.Mode.Replicated = &types.ReplicatedService{
   124  			Replicas: &t.Replicated.Replicas,
   125  		}
   126  	}
   127  
   128  	return convertedSpec, nil
   129  }
   130  
   131  // ServiceSpecToGRPC converts a ServiceSpec to a grpc ServiceSpec.
   132  func ServiceSpecToGRPC(s types.ServiceSpec) (swarmapi.ServiceSpec, error) {
   133  	name := s.Name
   134  	if name == "" {
   135  		name = namesgenerator.GetRandomName(0)
   136  	}
   137  
   138  	serviceNetworks := make([]*swarmapi.NetworkAttachmentConfig, 0, len(s.Networks))
   139  	for _, n := range s.Networks {
   140  		netConfig := &swarmapi.NetworkAttachmentConfig{Target: n.Target, Aliases: n.Aliases, DriverAttachmentOpts: n.DriverOpts}
   141  		serviceNetworks = append(serviceNetworks, netConfig)
   142  	}
   143  
   144  	taskNetworks := make([]*swarmapi.NetworkAttachmentConfig, 0, len(s.TaskTemplate.Networks))
   145  	for _, n := range s.TaskTemplate.Networks {
   146  		netConfig := &swarmapi.NetworkAttachmentConfig{Target: n.Target, Aliases: n.Aliases, DriverAttachmentOpts: n.DriverOpts}
   147  		taskNetworks = append(taskNetworks, netConfig)
   148  
   149  	}
   150  
   151  	spec := swarmapi.ServiceSpec{
   152  		Annotations: swarmapi.Annotations{
   153  			Name:   name,
   154  			Labels: s.Labels,
   155  		},
   156  		Task: swarmapi.TaskSpec{
   157  			Resources:   resourcesToGRPC(s.TaskTemplate.Resources),
   158  			LogDriver:   driverToGRPC(s.TaskTemplate.LogDriver),
   159  			Networks:    taskNetworks,
   160  			ForceUpdate: s.TaskTemplate.ForceUpdate,
   161  		},
   162  		Networks: serviceNetworks,
   163  	}
   164  
   165  	switch s.TaskTemplate.Runtime {
   166  	case types.RuntimeContainer, "": // if empty runtime default to container
   167  		containerSpec, err := containerToGRPC(s.TaskTemplate.ContainerSpec)
   168  		if err != nil {
   169  			return swarmapi.ServiceSpec{}, err
   170  		}
   171  		spec.Task.Runtime = &swarmapi.TaskSpec_Container{Container: containerSpec}
   172  	case types.RuntimePlugin:
   173  		spec.Task.Runtime = &swarmapi.TaskSpec_Generic{
   174  			Generic: &swarmapi.GenericRuntimeSpec{
   175  				Kind: string(types.RuntimePlugin),
   176  				Payload: &gogotypes.Any{
   177  					TypeUrl: string(types.RuntimeURLPlugin),
   178  				},
   179  			},
   180  		}
   181  	default:
   182  		return swarmapi.ServiceSpec{}, ErrUnsupportedRuntime
   183  	}
   184  
   185  	restartPolicy, err := restartPolicyToGRPC(s.TaskTemplate.RestartPolicy)
   186  	if err != nil {
   187  		return swarmapi.ServiceSpec{}, err
   188  	}
   189  	spec.Task.Restart = restartPolicy
   190  
   191  	if s.TaskTemplate.Placement != nil {
   192  		var preferences []*swarmapi.PlacementPreference
   193  		for _, pref := range s.TaskTemplate.Placement.Preferences {
   194  			if pref.Spread != nil {
   195  				preferences = append(preferences, &swarmapi.PlacementPreference{
   196  					Preference: &swarmapi.PlacementPreference_Spread{
   197  						Spread: &swarmapi.SpreadOver{
   198  							SpreadDescriptor: pref.Spread.SpreadDescriptor,
   199  						},
   200  					},
   201  				})
   202  			}
   203  		}
   204  		var platforms []*swarmapi.Platform
   205  		for _, plat := range s.TaskTemplate.Placement.Platforms {
   206  			platforms = append(platforms, &swarmapi.Platform{
   207  				Architecture: plat.Architecture,
   208  				OS:           plat.OS,
   209  			})
   210  		}
   211  		spec.Task.Placement = &swarmapi.Placement{
   212  			Constraints: s.TaskTemplate.Placement.Constraints,
   213  			Preferences: preferences,
   214  			Platforms:   platforms,
   215  		}
   216  	}
   217  
   218  	spec.Update, err = updateConfigToGRPC(s.UpdateConfig)
   219  	if err != nil {
   220  		return swarmapi.ServiceSpec{}, err
   221  	}
   222  	spec.Rollback, err = updateConfigToGRPC(s.RollbackConfig)
   223  	if err != nil {
   224  		return swarmapi.ServiceSpec{}, err
   225  	}
   226  
   227  	if s.EndpointSpec != nil {
   228  		if s.EndpointSpec.Mode != "" &&
   229  			s.EndpointSpec.Mode != types.ResolutionModeVIP &&
   230  			s.EndpointSpec.Mode != types.ResolutionModeDNSRR {
   231  			return swarmapi.ServiceSpec{}, fmt.Errorf("invalid resolution mode: %q", s.EndpointSpec.Mode)
   232  		}
   233  
   234  		spec.Endpoint = &swarmapi.EndpointSpec{}
   235  
   236  		spec.Endpoint.Mode = swarmapi.EndpointSpec_ResolutionMode(swarmapi.EndpointSpec_ResolutionMode_value[strings.ToUpper(string(s.EndpointSpec.Mode))])
   237  
   238  		for _, portConfig := range s.EndpointSpec.Ports {
   239  			spec.Endpoint.Ports = append(spec.Endpoint.Ports, &swarmapi.PortConfig{
   240  				Name:          portConfig.Name,
   241  				Protocol:      swarmapi.PortConfig_Protocol(swarmapi.PortConfig_Protocol_value[strings.ToUpper(string(portConfig.Protocol))]),
   242  				PublishMode:   swarmapi.PortConfig_PublishMode(swarmapi.PortConfig_PublishMode_value[strings.ToUpper(string(portConfig.PublishMode))]),
   243  				TargetPort:    portConfig.TargetPort,
   244  				PublishedPort: portConfig.PublishedPort,
   245  			})
   246  		}
   247  	}
   248  
   249  	// Mode
   250  	if s.Mode.Global != nil && s.Mode.Replicated != nil {
   251  		return swarmapi.ServiceSpec{}, fmt.Errorf("cannot specify both replicated mode and global mode")
   252  	}
   253  
   254  	if s.Mode.Global != nil {
   255  		spec.Mode = &swarmapi.ServiceSpec_Global{
   256  			Global: &swarmapi.GlobalService{},
   257  		}
   258  	} else if s.Mode.Replicated != nil && s.Mode.Replicated.Replicas != nil {
   259  		spec.Mode = &swarmapi.ServiceSpec_Replicated{
   260  			Replicated: &swarmapi.ReplicatedService{Replicas: *s.Mode.Replicated.Replicas},
   261  		}
   262  	} else {
   263  		spec.Mode = &swarmapi.ServiceSpec_Replicated{
   264  			Replicated: &swarmapi.ReplicatedService{Replicas: 1},
   265  		}
   266  	}
   267  
   268  	return spec, nil
   269  }
   270  
   271  func annotationsFromGRPC(ann swarmapi.Annotations) types.Annotations {
   272  	a := types.Annotations{
   273  		Name:   ann.Name,
   274  		Labels: ann.Labels,
   275  	}
   276  
   277  	if a.Labels == nil {
   278  		a.Labels = make(map[string]string)
   279  	}
   280  
   281  	return a
   282  }
   283  
   284  func resourcesFromGRPC(res *swarmapi.ResourceRequirements) *types.ResourceRequirements {
   285  	var resources *types.ResourceRequirements
   286  	if res != nil {
   287  		resources = &types.ResourceRequirements{}
   288  		if res.Limits != nil {
   289  			resources.Limits = &types.Resources{
   290  				NanoCPUs:    res.Limits.NanoCPUs,
   291  				MemoryBytes: res.Limits.MemoryBytes,
   292  			}
   293  		}
   294  		if res.Reservations != nil {
   295  			resources.Reservations = &types.Resources{
   296  				NanoCPUs:    res.Reservations.NanoCPUs,
   297  				MemoryBytes: res.Reservations.MemoryBytes,
   298  			}
   299  		}
   300  	}
   301  
   302  	return resources
   303  }
   304  
   305  func resourcesToGRPC(res *types.ResourceRequirements) *swarmapi.ResourceRequirements {
   306  	var reqs *swarmapi.ResourceRequirements
   307  	if res != nil {
   308  		reqs = &swarmapi.ResourceRequirements{}
   309  		if res.Limits != nil {
   310  			reqs.Limits = &swarmapi.Resources{
   311  				NanoCPUs:    res.Limits.NanoCPUs,
   312  				MemoryBytes: res.Limits.MemoryBytes,
   313  			}
   314  		}
   315  		if res.Reservations != nil {
   316  			reqs.Reservations = &swarmapi.Resources{
   317  				NanoCPUs:    res.Reservations.NanoCPUs,
   318  				MemoryBytes: res.Reservations.MemoryBytes,
   319  			}
   320  
   321  		}
   322  	}
   323  	return reqs
   324  }
   325  
   326  func restartPolicyFromGRPC(p *swarmapi.RestartPolicy) *types.RestartPolicy {
   327  	var rp *types.RestartPolicy
   328  	if p != nil {
   329  		rp = &types.RestartPolicy{}
   330  
   331  		switch p.Condition {
   332  		case swarmapi.RestartOnNone:
   333  			rp.Condition = types.RestartPolicyConditionNone
   334  		case swarmapi.RestartOnFailure:
   335  			rp.Condition = types.RestartPolicyConditionOnFailure
   336  		case swarmapi.RestartOnAny:
   337  			rp.Condition = types.RestartPolicyConditionAny
   338  		default:
   339  			rp.Condition = types.RestartPolicyConditionAny
   340  		}
   341  
   342  		if p.Delay != nil {
   343  			delay, _ := gogotypes.DurationFromProto(p.Delay)
   344  			rp.Delay = &delay
   345  		}
   346  		if p.Window != nil {
   347  			window, _ := gogotypes.DurationFromProto(p.Window)
   348  			rp.Window = &window
   349  		}
   350  
   351  		rp.MaxAttempts = &p.MaxAttempts
   352  	}
   353  	return rp
   354  }
   355  
   356  func restartPolicyToGRPC(p *types.RestartPolicy) (*swarmapi.RestartPolicy, error) {
   357  	var rp *swarmapi.RestartPolicy
   358  	if p != nil {
   359  		rp = &swarmapi.RestartPolicy{}
   360  
   361  		switch p.Condition {
   362  		case types.RestartPolicyConditionNone:
   363  			rp.Condition = swarmapi.RestartOnNone
   364  		case types.RestartPolicyConditionOnFailure:
   365  			rp.Condition = swarmapi.RestartOnFailure
   366  		case types.RestartPolicyConditionAny:
   367  			rp.Condition = swarmapi.RestartOnAny
   368  		default:
   369  			if string(p.Condition) != "" {
   370  				return nil, fmt.Errorf("invalid RestartCondition: %q", p.Condition)
   371  			}
   372  			rp.Condition = swarmapi.RestartOnAny
   373  		}
   374  
   375  		if p.Delay != nil {
   376  			rp.Delay = gogotypes.DurationProto(*p.Delay)
   377  		}
   378  		if p.Window != nil {
   379  			rp.Window = gogotypes.DurationProto(*p.Window)
   380  		}
   381  		if p.MaxAttempts != nil {
   382  			rp.MaxAttempts = *p.MaxAttempts
   383  
   384  		}
   385  	}
   386  	return rp, nil
   387  }
   388  
   389  func placementFromGRPC(p *swarmapi.Placement) *types.Placement {
   390  	if p == nil {
   391  		return nil
   392  	}
   393  	r := &types.Placement{
   394  		Constraints: p.Constraints,
   395  	}
   396  
   397  	for _, pref := range p.Preferences {
   398  		if spread := pref.GetSpread(); spread != nil {
   399  			r.Preferences = append(r.Preferences, types.PlacementPreference{
   400  				Spread: &types.SpreadOver{
   401  					SpreadDescriptor: spread.SpreadDescriptor,
   402  				},
   403  			})
   404  		}
   405  	}
   406  
   407  	for _, plat := range p.Platforms {
   408  		r.Platforms = append(r.Platforms, types.Platform{
   409  			Architecture: plat.Architecture,
   410  			OS:           plat.OS,
   411  		})
   412  	}
   413  
   414  	return r
   415  }
   416  
   417  func driverFromGRPC(p *swarmapi.Driver) *types.Driver {
   418  	if p == nil {
   419  		return nil
   420  	}
   421  
   422  	return &types.Driver{
   423  		Name:    p.Name,
   424  		Options: p.Options,
   425  	}
   426  }
   427  
   428  func driverToGRPC(p *types.Driver) *swarmapi.Driver {
   429  	if p == nil {
   430  		return nil
   431  	}
   432  
   433  	return &swarmapi.Driver{
   434  		Name:    p.Name,
   435  		Options: p.Options,
   436  	}
   437  }
   438  
   439  func updateConfigFromGRPC(updateConfig *swarmapi.UpdateConfig) *types.UpdateConfig {
   440  	if updateConfig == nil {
   441  		return nil
   442  	}
   443  
   444  	converted := &types.UpdateConfig{
   445  		Parallelism:     updateConfig.Parallelism,
   446  		MaxFailureRatio: updateConfig.MaxFailureRatio,
   447  	}
   448  
   449  	converted.Delay = updateConfig.Delay
   450  	if updateConfig.Monitor != nil {
   451  		converted.Monitor, _ = gogotypes.DurationFromProto(updateConfig.Monitor)
   452  	}
   453  
   454  	switch updateConfig.FailureAction {
   455  	case swarmapi.UpdateConfig_PAUSE:
   456  		converted.FailureAction = types.UpdateFailureActionPause
   457  	case swarmapi.UpdateConfig_CONTINUE:
   458  		converted.FailureAction = types.UpdateFailureActionContinue
   459  	case swarmapi.UpdateConfig_ROLLBACK:
   460  		converted.FailureAction = types.UpdateFailureActionRollback
   461  	}
   462  
   463  	switch updateConfig.Order {
   464  	case swarmapi.UpdateConfig_STOP_FIRST:
   465  		converted.Order = types.UpdateOrderStopFirst
   466  	case swarmapi.UpdateConfig_START_FIRST:
   467  		converted.Order = types.UpdateOrderStartFirst
   468  	}
   469  
   470  	return converted
   471  }
   472  
   473  func updateConfigToGRPC(updateConfig *types.UpdateConfig) (*swarmapi.UpdateConfig, error) {
   474  	if updateConfig == nil {
   475  		return nil, nil
   476  	}
   477  
   478  	converted := &swarmapi.UpdateConfig{
   479  		Parallelism:     updateConfig.Parallelism,
   480  		Delay:           updateConfig.Delay,
   481  		MaxFailureRatio: updateConfig.MaxFailureRatio,
   482  	}
   483  
   484  	switch updateConfig.FailureAction {
   485  	case types.UpdateFailureActionPause, "":
   486  		converted.FailureAction = swarmapi.UpdateConfig_PAUSE
   487  	case types.UpdateFailureActionContinue:
   488  		converted.FailureAction = swarmapi.UpdateConfig_CONTINUE
   489  	case types.UpdateFailureActionRollback:
   490  		converted.FailureAction = swarmapi.UpdateConfig_ROLLBACK
   491  	default:
   492  		return nil, fmt.Errorf("unrecognized update failure action %s", updateConfig.FailureAction)
   493  	}
   494  	if updateConfig.Monitor != 0 {
   495  		converted.Monitor = gogotypes.DurationProto(updateConfig.Monitor)
   496  	}
   497  
   498  	switch updateConfig.Order {
   499  	case types.UpdateOrderStopFirst, "":
   500  		converted.Order = swarmapi.UpdateConfig_STOP_FIRST
   501  	case types.UpdateOrderStartFirst:
   502  		converted.Order = swarmapi.UpdateConfig_START_FIRST
   503  	default:
   504  		return nil, fmt.Errorf("unrecognized update order %s", updateConfig.Order)
   505  	}
   506  
   507  	return converted, nil
   508  }
   509  
   510  func taskSpecFromGRPC(taskSpec swarmapi.TaskSpec) types.TaskSpec {
   511  	taskNetworks := make([]types.NetworkAttachmentConfig, 0, len(taskSpec.Networks))
   512  	for _, n := range taskSpec.Networks {
   513  		netConfig := types.NetworkAttachmentConfig{Target: n.Target, Aliases: n.Aliases, DriverOpts: n.DriverAttachmentOpts}
   514  		taskNetworks = append(taskNetworks, netConfig)
   515  	}
   516  
   517  	c := taskSpec.GetContainer()
   518  	cSpec := types.ContainerSpec{}
   519  	if c != nil {
   520  		cSpec = containerSpecFromGRPC(c)
   521  	}
   522  
   523  	return types.TaskSpec{
   524  		ContainerSpec: cSpec,
   525  		Resources:     resourcesFromGRPC(taskSpec.Resources),
   526  		RestartPolicy: restartPolicyFromGRPC(taskSpec.Restart),
   527  		Placement:     placementFromGRPC(taskSpec.Placement),
   528  		LogDriver:     driverFromGRPC(taskSpec.LogDriver),
   529  		Networks:      taskNetworks,
   530  		ForceUpdate:   taskSpec.ForceUpdate,
   531  	}
   532  }