func addServices(p *project.Project, enabled map[interface{}]interface{}, configs map[string]*composeConfig.ServiceConfigV1) map[interface{}]interface{} { serviceConfigsV2, _ := composeConfig.ConvertServices(configs) // Note: we ignore errors while loading services unchanged := true for name, serviceConfig := range serviceConfigsV2 { hash := composeConfig.GetServiceHash(name, serviceConfig) if enabled[name] == hash { continue } if err := p.AddConfig(name, serviceConfig); err != nil { log.Infof("Failed loading service %s", name) continue } if unchanged { enabled = util.MapCopy(enabled) unchanged = false } enabled[name] = hash } return enabled }
func (s *Service) createContainer(ctx context.Context, namer Namer, oldContainer string, configOverride *config.ServiceConfig, oneOff bool) (*composecontainer.Container, error) { serviceConfig := s.serviceConfig if configOverride != nil { serviceConfig.Command = configOverride.Command serviceConfig.Tty = configOverride.Tty serviceConfig.StdinOpen = configOverride.StdinOpen } configWrapper, err := ConvertToAPI(serviceConfig, s.context.Context, s.clientFactory) if err != nil { return nil, err } configWrapper.Config.Image = s.imageName() containerName, containerNumber := namer.Next() configWrapper.Config.Labels[labels.SERVICE.Str()] = s.name configWrapper.Config.Labels[labels.PROJECT.Str()] = s.project.Name configWrapper.Config.Labels[labels.HASH.Str()] = config.GetServiceHash(s.name, serviceConfig) configWrapper.Config.Labels[labels.ONEOFF.Str()] = strings.Title(strconv.FormatBool(oneOff)) configWrapper.Config.Labels[labels.NUMBER.Str()] = fmt.Sprintf("%d", containerNumber) configWrapper.Config.Labels[labels.VERSION.Str()] = project.ComposeVersion err = s.populateAdditionalHostConfig(configWrapper.HostConfig) if err != nil { return nil, err } // FIXME(vdemeester): oldContainer should be a Container instead of a string client := s.clientFactory.Create(s) if oldContainer != "" { info, err := client.ContainerInspect(ctx, oldContainer) if err != nil { return nil, err } configWrapper.HostConfig.Binds = util.Merge(configWrapper.HostConfig.Binds, volumeBinds(configWrapper.Config.Volumes, &info)) } logrus.Debugf("Creating container %s %#v", containerName, configWrapper) // FIXME(vdemeester): long-term will be container.Create(…) container, err := composecontainer.Create(ctx, client, containerName, configWrapper.Config, configWrapper.HostConfig, configWrapper.NetworkingConfig) if err != nil { return nil, err } s.project.Notify(events.ContainerCreated, s.name, map[string]string{ "name": containerName, }) return container, nil }
// OutOfSync checks if the container is out of sync with the service definition. // It looks if the the service hash container label is the same as the computed one. func (s *Service) OutOfSync(ctx context.Context, c *container.Container) (bool, error) { if c.ImageConfig() != s.serviceConfig.Image { logrus.Debugf("Images for %s do not match %s!=%s", c.Name(), c.ImageConfig(), s.serviceConfig.Image) return true, nil } expectedHash := config.GetServiceHash(s.name, s.Config()) if c.Hash() != expectedHash { logrus.Debugf("Hashes for %s do not match %s!=%s", c.Name(), c.Hash(), expectedHash) return true, nil } image, err := image.InspectImage(ctx, s.clientFactory.Create(s), c.ImageConfig()) if err != nil { if client.IsErrImageNotFound(err) { logrus.Debugf("Image %s do not exist, do not know if it's out of sync", c.Image()) return false, nil } return false, err } logrus.Debugf("Checking existing image name vs id: %s == %s", image.ID, c.Image()) return image.ID != c.Image(), err }
func (c *Container) getHash() string { return config.GetServiceHash(c.service.Name(), c.service.Config()) }