|
@@ -40,18 +40,21 @@ func (c *Cluster) GetServices(options apitypes.ServiceListOptions) ([]types.Serv
|
|
|
// be good to have accepted file check in the same file as
|
|
|
// the filter processing (in the for loop below).
|
|
|
accepted := map[string]bool{
|
|
|
- "name": true,
|
|
|
- "id": true,
|
|
|
- "label": true,
|
|
|
- "mode": true,
|
|
|
+ "name": true,
|
|
|
+ "id": true,
|
|
|
+ "label": true,
|
|
|
+ "mode": true,
|
|
|
+ "runtime": true,
|
|
|
}
|
|
|
if err := options.Filters.Validate(accepted); err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
+
|
|
|
filters := &swarmapi.ListServicesRequest_Filters{
|
|
|
NamePrefixes: options.Filters.Get("name"),
|
|
|
IDPrefixes: options.Filters.Get("id"),
|
|
|
Labels: runconfigopts.ConvertKVStringsToMap(options.Filters.Get("label")),
|
|
|
+ Runtimes: options.Filters.Get("runtime"),
|
|
|
}
|
|
|
|
|
|
ctx, cancel := c.getRequestContext()
|
|
@@ -80,7 +83,11 @@ func (c *Cluster) GetServices(options apitypes.ServiceListOptions) ([]types.Serv
|
|
|
continue
|
|
|
}
|
|
|
}
|
|
|
- services = append(services, convert.ServiceFromGRPC(*service))
|
|
|
+ svcs, err := convert.ServiceFromGRPC(*service)
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ services = append(services, svcs)
|
|
|
}
|
|
|
|
|
|
return services, nil
|
|
@@ -99,7 +106,11 @@ func (c *Cluster) GetService(input string, insertDefaults bool) (types.Service,
|
|
|
}); err != nil {
|
|
|
return types.Service{}, err
|
|
|
}
|
|
|
- return convert.ServiceFromGRPC(*service), nil
|
|
|
+ svc, err := convert.ServiceFromGRPC(*service)
|
|
|
+ if err != nil {
|
|
|
+ return types.Service{}, err
|
|
|
+ }
|
|
|
+ return svc, nil
|
|
|
}
|
|
|
|
|
|
// CreateService creates a new service in a managed swarm cluster.
|
|
@@ -116,58 +127,65 @@ func (c *Cluster) CreateService(s types.ServiceSpec, encodedAuth string) (*apity
|
|
|
return apierrors.NewBadRequestError(err)
|
|
|
}
|
|
|
|
|
|
- ctnr := serviceSpec.Task.GetContainer()
|
|
|
- if ctnr == nil {
|
|
|
- return errors.New("service does not use container tasks")
|
|
|
- }
|
|
|
+ resp = &apitypes.ServiceCreateResponse{}
|
|
|
|
|
|
- if encodedAuth != "" {
|
|
|
- ctnr.PullOptions = &swarmapi.ContainerSpec_PullOptions{RegistryAuth: encodedAuth}
|
|
|
- }
|
|
|
+ switch serviceSpec.Task.Runtime.(type) {
|
|
|
+ // handle other runtimes here
|
|
|
+ case *swarmapi.TaskSpec_Container:
|
|
|
+ ctnr := serviceSpec.Task.GetContainer()
|
|
|
+ if ctnr == nil {
|
|
|
+ return errors.New("service does not use container tasks")
|
|
|
+ }
|
|
|
+ if encodedAuth != "" {
|
|
|
+ ctnr.PullOptions = &swarmapi.ContainerSpec_PullOptions{RegistryAuth: encodedAuth}
|
|
|
+ }
|
|
|
|
|
|
- // retrieve auth config from encoded auth
|
|
|
- authConfig := &apitypes.AuthConfig{}
|
|
|
- if encodedAuth != "" {
|
|
|
- if err := json.NewDecoder(base64.NewDecoder(base64.URLEncoding, strings.NewReader(encodedAuth))).Decode(authConfig); err != nil {
|
|
|
- logrus.Warnf("invalid authconfig: %v", err)
|
|
|
+ // retrieve auth config from encoded auth
|
|
|
+ authConfig := &apitypes.AuthConfig{}
|
|
|
+ if encodedAuth != "" {
|
|
|
+ if err := json.NewDecoder(base64.NewDecoder(base64.URLEncoding, strings.NewReader(encodedAuth))).Decode(authConfig); err != nil {
|
|
|
+ logrus.Warnf("invalid authconfig: %v", err)
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- resp = &apitypes.ServiceCreateResponse{}
|
|
|
+ // pin image by digest
|
|
|
+ if os.Getenv("DOCKER_SERVICE_PREFER_OFFLINE_IMAGE") != "1" {
|
|
|
+ digestImage, err := c.imageWithDigestString(ctx, ctnr.Image, authConfig)
|
|
|
+ if err != nil {
|
|
|
+ logrus.Warnf("unable to pin image %s to digest: %s", ctnr.Image, err.Error())
|
|
|
+ // warning in the client response should be concise
|
|
|
+ resp.Warnings = append(resp.Warnings, digestWarning(ctnr.Image))
|
|
|
|
|
|
- // pin image by digest
|
|
|
- if os.Getenv("DOCKER_SERVICE_PREFER_OFFLINE_IMAGE") != "1" {
|
|
|
- digestImage, err := c.imageWithDigestString(ctx, ctnr.Image, authConfig)
|
|
|
- if err != nil {
|
|
|
- logrus.Warnf("unable to pin image %s to digest: %s", ctnr.Image, err.Error())
|
|
|
- // warning in the client response should be concise
|
|
|
- resp.Warnings = append(resp.Warnings, digestWarning(ctnr.Image))
|
|
|
- } else if ctnr.Image != digestImage {
|
|
|
- logrus.Debugf("pinning image %s by digest: %s", ctnr.Image, digestImage)
|
|
|
- ctnr.Image = digestImage
|
|
|
- } else {
|
|
|
- logrus.Debugf("creating service using supplied digest reference %s", ctnr.Image)
|
|
|
+ } else if ctnr.Image != digestImage {
|
|
|
+ logrus.Debugf("pinning image %s by digest: %s", ctnr.Image, digestImage)
|
|
|
+ ctnr.Image = digestImage
|
|
|
+
|
|
|
+ } else {
|
|
|
+ logrus.Debugf("creating service using supplied digest reference %s", ctnr.Image)
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // Replace the context with a fresh one.
|
|
|
+ // If we timed out while communicating with the
|
|
|
+ // registry, then "ctx" will already be expired, which
|
|
|
+ // would cause UpdateService below to fail. Reusing
|
|
|
+ // "ctx" could make it impossible to create a service
|
|
|
+ // if the registry is slow or unresponsive.
|
|
|
+ var cancel func()
|
|
|
+ ctx, cancel = c.getRequestContext()
|
|
|
+ defer cancel()
|
|
|
}
|
|
|
|
|
|
- // Replace the context with a fresh one.
|
|
|
- // If we timed out while communicating with the
|
|
|
- // registry, then "ctx" will already be expired, which
|
|
|
- // would cause UpdateService below to fail. Reusing
|
|
|
- // "ctx" could make it impossible to create a service
|
|
|
- // if the registry is slow or unresponsive.
|
|
|
- var cancel func()
|
|
|
- ctx, cancel = c.getRequestContext()
|
|
|
- defer cancel()
|
|
|
- }
|
|
|
+ r, err := state.controlClient.CreateService(ctx, &swarmapi.CreateServiceRequest{Spec: &serviceSpec})
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
|
|
|
- r, err := state.controlClient.CreateService(ctx, &swarmapi.CreateServiceRequest{Spec: &serviceSpec})
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
+ resp.ID = r.Service.ID
|
|
|
}
|
|
|
-
|
|
|
- resp.ID = r.Service.ID
|
|
|
return nil
|
|
|
})
|
|
|
+
|
|
|
return resp, err
|
|
|
}
|
|
|
|