1
0
mirror of https://github.com/rancher/os.git synced 2025-05-03 05:36:19 +00:00
os/docker/service.go

223 lines
5.6 KiB
Go
Raw Normal View History

2015-08-04 21:45:38 +00:00
package docker
import (
"github.com/Sirupsen/logrus"
2016-05-24 00:21:28 +00:00
dockerclient "github.com/docker/engine-api/client"
"github.com/docker/engine-api/types"
composeConfig "github.com/docker/libcompose/config"
2015-08-04 21:45:38 +00:00
"github.com/docker/libcompose/docker"
"github.com/docker/libcompose/project"
2016-05-24 00:21:28 +00:00
"github.com/docker/libcompose/project/options"
"github.com/rancher/os/config"
2016-05-24 00:21:28 +00:00
"golang.org/x/net/context"
2015-08-04 21:45:38 +00:00
)
type Service struct {
*docker.Service
deps map[string][]string
context *docker.Context
project *project.Project
2015-08-04 21:45:38 +00:00
}
2016-05-24 00:21:28 +00:00
func NewService(factory *ServiceFactory, name string, serviceConfig *composeConfig.ServiceConfig, context *docker.Context, project *project.Project) *Service {
2015-08-04 21:45:38 +00:00
return &Service{
Service: docker.NewService(name, serviceConfig, context),
deps: factory.Deps,
context: context,
project: project,
2015-08-04 21:45:38 +00:00
}
}
func (s *Service) DependentServices() []project.ServiceRelationship {
rels := s.Service.DependentServices()
for _, dep := range s.deps[s.Name()] {
rels = appendLink(rels, dep, true, s.project)
2015-08-04 21:45:38 +00:00
}
if s.requiresSyslog() {
rels = appendLink(rels, "syslog", false, s.project)
2015-08-04 21:45:38 +00:00
}
if s.requiresUserDocker() {
// Linking to cloud-init is a hack really. The problem is we need to link to something
// that will trigger a reload
rels = appendLink(rels, "cloud-init", false, s.project)
2015-08-04 21:45:38 +00:00
} else if s.missingImage() {
rels = appendLink(rels, "network", false, s.project)
2015-08-04 21:45:38 +00:00
}
return rels
}
func (s *Service) missingImage() bool {
image := s.Config().Image
if image == "" {
return false
}
client := s.context.ClientFactory.Create(s)
2016-05-24 00:21:28 +00:00
_, _, err := client.ImageInspectWithRaw(context.Background(), s.Config().Image, false)
return err != nil
2015-08-04 21:45:38 +00:00
}
func (s *Service) requiresSyslog() bool {
2016-05-24 00:21:28 +00:00
return s.Config().Logging.Driver == "syslog"
2015-08-04 21:45:38 +00:00
}
func (s *Service) requiresUserDocker() bool {
2016-05-24 00:21:28 +00:00
return s.Config().Labels[config.SCOPE] != config.SYSTEM
2015-08-04 21:45:38 +00:00
}
func appendLink(deps []project.ServiceRelationship, name string, optional bool, p *project.Project) []project.ServiceRelationship {
2016-05-24 00:21:28 +00:00
if _, ok := p.ServiceConfigs.Get(name); !ok {
return deps
}
rel := project.NewServiceRelationship(name, project.RelTypeLink)
2015-08-04 21:45:38 +00:00
rel.Optional = optional
return append(deps, rel)
}
2016-05-24 00:21:28 +00:00
func (s *Service) shouldRebuild(ctx context.Context) (bool, error) {
containers, err := s.Containers(ctx)
if err != nil {
return false, err
}
2016-06-02 01:41:55 +00:00
cfg := config.LoadConfig()
for _, c := range containers {
2016-05-24 00:21:28 +00:00
outOfSync, err := c.(*docker.Container).OutOfSync(ctx, s.Service.Config().Image)
if err != nil {
return false, err
}
2016-05-24 00:21:28 +00:00
_, containerInfo, err := s.getContainer(ctx)
if err != nil {
return false, err
}
name := containerInfo.Name[1:]
origRebuildLabel := containerInfo.Config.Labels[config.REBUILD]
2016-05-24 00:21:28 +00:00
newRebuildLabel := s.Config().Labels[config.REBUILD]
rebuildLabelChanged := newRebuildLabel != origRebuildLabel
logrus.WithFields(logrus.Fields{
"origRebuildLabel": origRebuildLabel,
"newRebuildLabel": newRebuildLabel,
"rebuildLabelChanged": rebuildLabelChanged,
"outOfSync": outOfSync}).Debug("Rebuild values")
rebuilding := false
if outOfSync {
if cfg.Rancher.ForceConsoleRebuild && s.Name() == "console" {
2016-05-31 21:34:04 +00:00
if err := config.Set("rancher.force_console_rebuild", false); err != nil {
return false, err
}
rebuilding = true
} else if origRebuildLabel == "always" || rebuildLabelChanged || origRebuildLabel != "false" {
rebuilding = true
} else {
logrus.Warnf("%s needs rebuilding", name)
}
}
if rebuilding {
logrus.Infof("Rebuilding %s", name)
return true, nil
}
}
return false, nil
}
2016-05-24 00:21:28 +00:00
func (s *Service) Up(ctx context.Context, options options.Up) error {
labels := s.Config().Labels
2015-08-04 21:45:38 +00:00
2016-05-24 00:21:28 +00:00
if err := s.Service.Create(ctx, options.Create); err != nil {
2015-08-04 21:45:38 +00:00
return err
}
2016-05-24 00:21:28 +00:00
shouldRebuild, err := s.shouldRebuild(ctx)
if err != nil {
return err
}
if shouldRebuild {
2016-05-24 00:21:28 +00:00
cs, err := s.Service.Containers(ctx)
if err != nil {
return err
}
for _, c := range cs {
2016-05-24 00:21:28 +00:00
if _, err := c.(*docker.Container).Recreate(ctx, s.Config().Image); err != nil {
return err
}
}
2016-05-24 00:21:28 +00:00
s.rename(ctx)
}
if labels[config.CREATE_ONLY] == "true" {
return s.checkReload(labels)
}
2016-05-24 00:21:28 +00:00
if err := s.Service.Up(ctx, options); err != nil {
2015-08-04 21:45:38 +00:00
return err
}
if labels[config.DETACH] == "false" {
2016-05-24 00:21:28 +00:00
if err := s.wait(ctx); err != nil {
2015-08-04 21:45:38 +00:00
return err
}
}
return s.checkReload(labels)
}
func (s *Service) checkReload(labels map[string]string) error {
if labels[config.RELOAD_CONFIG] == "true" {
return project.ErrRestart
}
return nil
}
2016-05-24 00:21:28 +00:00
func (s *Service) Create(ctx context.Context, options options.Create) error {
return s.Service.Create(ctx, options)
2015-08-04 21:45:38 +00:00
}
2016-05-24 00:21:28 +00:00
func (s *Service) getContainer(ctx context.Context) (dockerclient.APIClient, types.ContainerJSON, error) {
containers, err := s.Service.Containers(ctx)
2015-08-04 21:45:38 +00:00
if err != nil {
2016-05-24 00:21:28 +00:00
return nil, types.ContainerJSON{}, err
2015-08-04 21:45:38 +00:00
}
if len(containers) == 0 {
2016-05-24 00:21:28 +00:00
return nil, types.ContainerJSON{}, nil
2015-08-04 21:45:38 +00:00
}
id, err := containers[0].ID()
2015-08-04 21:45:38 +00:00
if err != nil {
2016-05-24 00:21:28 +00:00
return nil, types.ContainerJSON{}, err
2015-08-04 21:45:38 +00:00
}
client := s.context.ClientFactory.Create(s)
2016-05-24 00:21:28 +00:00
info, err := client.ContainerInspect(context.Background(), id)
2015-08-04 21:45:38 +00:00
return client, info, err
}
2016-05-24 00:21:28 +00:00
func (s *Service) wait(ctx context.Context) error {
client, info, err := s.getContainer(ctx)
if err != nil {
2015-08-04 21:45:38 +00:00
return err
}
2016-05-24 00:21:28 +00:00
if _, err := client.ContainerWait(context.Background(), info.ID); err != nil {
2015-08-04 21:45:38 +00:00
return err
}
return nil
2015-08-04 21:45:38 +00:00
}
2016-05-24 00:21:28 +00:00
func (s *Service) rename(ctx context.Context) error {
client, info, err := s.getContainer(ctx)
if err != nil {
return err
}
if len(info.Name) > 0 && info.Name[1:] != s.Name() {
logrus.Debugf("Renaming container %s => %s", info.Name[1:], s.Name())
2016-05-24 00:21:28 +00:00
return client.ContainerRename(context.Background(), info.ID, s.Name())
} else {
return nil
}
}