// UpdateService updates existing service to match new properties. func (c *Cluster) UpdateService(serviceID string, version uint64, spec types.ServiceSpec) error { c.RLock() defer c.RUnlock() if !c.isActiveManager() { return ErrNoManager } serviceSpec, err := convert.ServiceSpecToGRPC(spec) if err != nil { return err } _, err = c.client.UpdateService( c.getRequestContext(), &swarmapi.UpdateServiceRequest{ ServiceID: serviceID, Spec: &serviceSpec, ServiceVersion: &swarmapi.Version{ Index: version, }, }, ) return err }
// CreateService creates a new service in a managed swarm cluster. func (c *Cluster) CreateService(s types.ServiceSpec) (string, error) { c.RLock() defer c.RUnlock() if !c.isActiveManager() { return "", ErrNoManager } ctx := c.getRequestContext() err := populateNetworkID(ctx, c.client, &s) if err != nil { return "", err } serviceSpec, err := convert.ServiceSpecToGRPC(s) if err != nil { return "", err } r, err := c.client.CreateService(ctx, &swarmapi.CreateServiceRequest{Spec: &serviceSpec}) if err != nil { return "", err } return r.Service.ID, nil }
// CreateService creates a new service in a managed swarm cluster. func (c *Cluster) CreateService(s types.ServiceSpec, encodedAuth string) (*apitypes.ServiceCreateResponse, error) { c.RLock() defer c.RUnlock() if !c.isActiveManager() { return nil, c.errNoManager() } ctx, cancel := c.getRequestContext() defer cancel() err := c.populateNetworkID(ctx, c.client, &s) if err != nil { return nil, err } serviceSpec, err := convert.ServiceSpecToGRPC(s) if err != nil { return nil, err } ctnr := serviceSpec.Task.GetContainer() if ctnr == nil { return nil, fmt.Errorf("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) } } 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()) resp.Warnings = append(resp.Warnings, fmt.Sprintf("unable to pin image %s to digest: %s", ctnr.Image, err.Error())) } else { logrus.Debugf("pinning image %s by digest: %s", ctnr.Image, digestImage) ctnr.Image = digestImage } } r, err := c.client.CreateService(ctx, &swarmapi.CreateServiceRequest{Spec: &serviceSpec}) if err != nil { return nil, err } resp.ID = r.Service.ID return resp, nil }
// CreateService creates a new service in a managed swarm cluster. func (c *Cluster) CreateService(s types.ServiceSpec, encodedAuth string) (string, error) { c.RLock() defer c.RUnlock() if !c.isActiveManager() { return "", c.errNoManager() } ctx := c.getRequestContext() err := populateNetworkID(ctx, c.client, &s) if err != nil { return "", err } serviceSpec, err := convert.ServiceSpecToGRPC(s) if err != nil { return "", err } if encodedAuth != "" { ctnr := serviceSpec.Task.GetContainer() if ctnr == nil { return "", fmt.Errorf("service does not use container tasks") } ctnr.PullOptions = &swarmapi.ContainerSpec_PullOptions{RegistryAuth: encodedAuth} } r, err := c.client.CreateService(ctx, &swarmapi.CreateServiceRequest{Spec: &serviceSpec}) if err != nil { return "", err } return r.Service.ID, nil }
// UpdateService updates existing service to match new properties. func (c *Cluster) UpdateService(serviceIDOrName string, version uint64, spec types.ServiceSpec, encodedAuth string) error { c.RLock() defer c.RUnlock() if !c.isActiveManager() { return c.errNoManager() } ctx, cancel := c.getRequestContext() defer cancel() err := c.populateNetworkID(ctx, c.client, &spec) if err != nil { return err } serviceSpec, err := convert.ServiceSpecToGRPC(spec) if err != nil { return err } currentService, err := getService(ctx, c.client, serviceIDOrName) if err != nil { return err } if encodedAuth != "" { ctnr := serviceSpec.Task.GetContainer() if ctnr == nil { return fmt.Errorf("service does not use container tasks") } ctnr.PullOptions = &swarmapi.ContainerSpec_PullOptions{RegistryAuth: encodedAuth} } else { // this is needed because if the encodedAuth isn't being updated then we // shouldn't lose it, and continue to use the one that was already present ctnr := currentService.Spec.Task.GetContainer() if ctnr == nil { return fmt.Errorf("service does not use container tasks") } serviceSpec.Task.GetContainer().PullOptions = ctnr.PullOptions } _, err = c.client.UpdateService( ctx, &swarmapi.UpdateServiceRequest{ ServiceID: currentService.ID, Spec: &serviceSpec, ServiceVersion: &swarmapi.Version{ Index: version, }, }, ) return err }
// UpdateService updates existing service to match new properties. func (c *Cluster) UpdateService(serviceIDOrName string, version uint64, spec types.ServiceSpec, encodedAuth string, registryAuthFrom string) error { c.RLock() defer c.RUnlock() if !c.isActiveManager() { return c.errNoManager() } ctx, cancel := c.getRequestContext() defer cancel() err := c.populateNetworkID(ctx, c.client, &spec) if err != nil { return err } serviceSpec, err := convert.ServiceSpecToGRPC(spec) if err != nil { return err } currentService, err := getService(ctx, c.client, serviceIDOrName) if err != nil { return err } newCtnr := serviceSpec.Task.GetContainer() if newCtnr == nil { return fmt.Errorf("service does not use container tasks") } if encodedAuth != "" { newCtnr.PullOptions = &swarmapi.ContainerSpec_PullOptions{RegistryAuth: encodedAuth} } else { // this is needed because if the encodedAuth isn't being updated then we // shouldn't lose it, and continue to use the one that was already present var ctnr *swarmapi.ContainerSpec switch registryAuthFrom { case apitypes.RegistryAuthFromSpec, "": ctnr = currentService.Spec.Task.GetContainer() case apitypes.RegistryAuthFromPreviousSpec: if currentService.PreviousSpec == nil { return fmt.Errorf("service does not have a previous spec") } ctnr = currentService.PreviousSpec.Task.GetContainer() default: return fmt.Errorf("unsupported registryAuthFromValue") } if ctnr == nil { return fmt.Errorf("service does not use container tasks") } newCtnr.PullOptions = ctnr.PullOptions // update encodedAuth so it can be used to pin image by digest if ctnr.PullOptions != nil { encodedAuth = ctnr.PullOptions.RegistryAuth } } // 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) } } // pin image by digest if os.Getenv("DOCKER_SERVICE_PREFER_OFFLINE_IMAGE") != "1" { digestImage, err := c.imageWithDigestString(ctx, newCtnr.Image, authConfig) if err != nil { logrus.Warnf("unable to pin image %s to digest: %s", newCtnr.Image, err.Error()) } else if newCtnr.Image != digestImage { logrus.Debugf("pinning image %s by digest: %s", newCtnr.Image, digestImage) newCtnr.Image = digestImage } } _, err = c.client.UpdateService( ctx, &swarmapi.UpdateServiceRequest{ ServiceID: currentService.ID, Spec: &serviceSpec, ServiceVersion: &swarmapi.Version{ Index: version, }, }, ) return err }