upgrade libcompose to fbdac0a6a80837c63eb6c8f43514f7bb3f32df6c

This commit is contained in:
Tuna
2016-10-09 02:35:51 +02:00
parent 5a37bf0fb4
commit 592cc95907
567 changed files with 6730 additions and 44603 deletions
+34 -311
View File
@@ -3,6 +3,8 @@ package project
import (
"errors"
"fmt"
"os"
"path/filepath"
"strings"
"golang.org/x/net/context"
@@ -10,12 +12,15 @@ import (
log "github.com/Sirupsen/logrus"
"github.com/docker/libcompose/config"
"github.com/docker/libcompose/logger"
"github.com/docker/libcompose/lookup"
"github.com/docker/libcompose/project/events"
"github.com/docker/libcompose/project/options"
"github.com/docker/libcompose/utils"
"github.com/docker/libcompose/yaml"
)
// ComposeVersion is name of docker-compose.yml file syntax supported version
const ComposeVersion = "1.5.0"
type wrapperAction func(*serviceWrapper, map[string]*serviceWrapper)
type serviceAction func(service Service) error
@@ -55,6 +60,26 @@ func NewProject(context *Context, runtime RuntimeProject, parseOptions *config.P
context.LoggerFactory = &logger.NullLogger{}
}
if context.ResourceLookup == nil {
context.ResourceLookup = &lookup.FileResourceLookup{}
}
if context.EnvironmentLookup == nil {
cwd, err := os.Getwd()
if err != nil {
log.Errorf("Could not get the rooted path name to the current directory: %v", err)
return nil
}
context.EnvironmentLookup = &lookup.ComposableEnvLookup{
Lookups: []config.EnvironmentLookup{
&lookup.EnvfileLookup{
Path: filepath.Join(cwd, ".env"),
},
&lookup.OsEnvLookup{},
},
}
}
context.Project = p
p.listeners = []chan<- events.Event{NewDefaultListener(p)}
@@ -96,7 +121,7 @@ func (p *Project) Parse() error {
// CreateService creates a service with the specified name based. If there
// is no config in the project for this service, it will return an error.
func (p *Project) CreateService(name string) (Service, error) {
existing, ok := p.ServiceConfigs.Get(name)
existing, ok := p.GetServiceConfig(name)
if !ok {
return nil, fmt.Errorf("Failed to find service: %s", name)
}
@@ -109,7 +134,7 @@ func (p *Project) CreateService(name string) (Service, error) {
for _, env := range config.Environment {
parts := strings.SplitN(env, "=", 2)
if len(parts) > 1 && parts[1] != "" {
if len(parts) > 1 {
parsedEnv = append(parsedEnv, env)
continue
} else {
@@ -333,314 +358,6 @@ func (p *Project) loadWrappers(wrappers map[string]*serviceWrapper, servicesToCo
return nil
}
// Build builds the specified services (like docker build).
func (p *Project) Build(ctx context.Context, buildOptions options.Build, services ...string) error {
return p.perform(events.ProjectBuildStart, events.ProjectBuildDone, services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
wrapper.Do(wrappers, events.ServiceBuildStart, events.ServiceBuild, func(service Service) error {
return service.Build(ctx, buildOptions)
})
}), nil)
}
// Create creates the specified services (like docker create).
func (p *Project) Create(ctx context.Context, options options.Create, services ...string) error {
if options.NoRecreate && options.ForceRecreate {
return fmt.Errorf("no-recreate and force-recreate cannot be combined")
}
return p.perform(events.ProjectCreateStart, events.ProjectCreateDone, services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
wrapper.Do(wrappers, events.ServiceCreateStart, events.ServiceCreate, func(service Service) error {
return service.Create(ctx, options)
})
}), nil)
}
// Stop stops the specified services (like docker stop).
func (p *Project) Stop(ctx context.Context, timeout int, services ...string) error {
return p.perform(events.ProjectStopStart, events.ProjectStopDone, services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
wrapper.Do(nil, events.ServiceStopStart, events.ServiceStop, func(service Service) error {
return service.Stop(ctx, timeout)
})
}), nil)
}
// Down stops the specified services and clean related containers (like docker stop + docker rm).
func (p *Project) Down(ctx context.Context, opts options.Down, services ...string) error {
if !opts.RemoveImages.Valid() {
return fmt.Errorf("--rmi flag must be local, all or empty")
}
if err := p.Stop(ctx, 10, services...); err != nil {
return err
}
if opts.RemoveOrphans {
if err := p.runtime.RemoveOrphans(ctx, p.Name, p.ServiceConfigs); err != nil {
return err
}
}
if err := p.Delete(ctx, options.Delete{
RemoveVolume: opts.RemoveVolume,
}, services...); err != nil {
return err
}
networks, err := p.context.NetworksFactory.Create(p.Name, p.NetworkConfigs, p.ServiceConfigs, p.isNetworkEnabled())
if err != nil {
return err
}
if err := networks.Remove(ctx); err != nil {
return err
}
if opts.RemoveVolume {
volumes, err := p.context.VolumesFactory.Create(p.Name, p.VolumeConfigs, p.ServiceConfigs, p.isVolumeEnabled())
if err != nil {
return err
}
if err := volumes.Remove(ctx); err != nil {
return err
}
}
return p.forEach([]string{}, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
wrapper.Do(wrappers, events.NoEvent, events.NoEvent, func(service Service) error {
return service.RemoveImage(ctx, opts.RemoveImages)
})
}), func(service Service) error {
return service.Create(ctx, options.Create{})
})
}
// RemoveOrphans implements project.RuntimeProject.RemoveOrphans.
// It does nothing by default as it is supposed to be overriden by specific implementation.
func (p *Project) RemoveOrphans(ctx context.Context) error {
return nil
}
// Restart restarts the specified services (like docker restart).
func (p *Project) Restart(ctx context.Context, timeout int, services ...string) error {
return p.perform(events.ProjectRestartStart, events.ProjectRestartDone, services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
wrapper.Do(wrappers, events.ServiceRestartStart, events.ServiceRestart, func(service Service) error {
return service.Restart(ctx, timeout)
})
}), nil)
}
// Port returns the public port for a port binding of the specified service.
func (p *Project) Port(ctx context.Context, index int, protocol, serviceName, privatePort string) (string, error) {
service, err := p.CreateService(serviceName)
if err != nil {
return "", err
}
containers, err := service.Containers(ctx)
if err != nil {
return "", err
}
if index < 1 || index > len(containers) {
return "", fmt.Errorf("Invalid index %d", index)
}
return containers[index-1].Port(ctx, fmt.Sprintf("%s/%s", privatePort, protocol))
}
// Ps list containers for the specified services.
func (p *Project) Ps(ctx context.Context, onlyID bool, services ...string) (InfoSet, error) {
allInfo := InfoSet{}
for _, name := range p.ServiceConfigs.Keys() {
service, err := p.CreateService(name)
if err != nil {
return nil, err
}
info, err := service.Info(ctx, onlyID)
if err != nil {
return nil, err
}
allInfo = append(allInfo, info...)
}
return allInfo, nil
}
// Start starts the specified services (like docker start).
func (p *Project) Start(ctx context.Context, services ...string) error {
return p.perform(events.ProjectStartStart, events.ProjectStartDone, services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
wrapper.Do(wrappers, events.ServiceStartStart, events.ServiceStart, func(service Service) error {
return service.Start(ctx)
})
}), nil)
}
// Run executes a one off command (like `docker run image command`).
func (p *Project) Run(ctx context.Context, serviceName string, commandParts []string, opts options.Run) (int, error) {
if !p.ServiceConfigs.Has(serviceName) {
return 1, fmt.Errorf("%s is not defined in the template", serviceName)
}
if err := p.initialize(ctx); err != nil {
return 1, err
}
var exitCode int
err := p.forEach([]string{}, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
wrapper.Do(wrappers, events.ServiceRunStart, events.ServiceRun, func(service Service) error {
if service.Name() == serviceName {
code, err := service.Run(ctx, commandParts, opts)
exitCode = code
return err
}
return nil
})
}), func(service Service) error {
return service.Create(ctx, options.Create{})
})
return exitCode, err
}
// Up creates and starts the specified services (kinda like docker run).
func (p *Project) Up(ctx context.Context, options options.Up, services ...string) error {
if err := p.initialize(ctx); err != nil {
return err
}
return p.perform(events.ProjectUpStart, events.ProjectUpDone, services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
wrapper.Do(wrappers, events.ServiceUpStart, events.ServiceUp, func(service Service) error {
return service.Up(ctx, options)
})
}), func(service Service) error {
return service.Create(ctx, options.Create)
})
}
// Log aggregates and prints out the logs for the specified services.
func (p *Project) Log(ctx context.Context, follow bool, services ...string) error {
return p.forEach(services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
wrapper.Do(nil, events.NoEvent, events.NoEvent, func(service Service) error {
return service.Log(ctx, follow)
})
}), nil)
}
// Scale scales the specified services.
func (p *Project) Scale(ctx context.Context, timeout int, servicesScale map[string]int) error {
// This code is a bit verbose but I wanted to parse everything up front
order := make([]string, 0, 0)
services := make(map[string]Service)
for name := range servicesScale {
if !p.ServiceConfigs.Has(name) {
return fmt.Errorf("%s is not defined in the template", name)
}
service, err := p.CreateService(name)
if err != nil {
return fmt.Errorf("Failed to lookup service: %s: %v", service, err)
}
order = append(order, name)
services[name] = service
}
for _, name := range order {
scale := servicesScale[name]
log.Infof("Setting scale %s=%d...", name, scale)
err := services[name].Scale(ctx, scale, timeout)
if err != nil {
return fmt.Errorf("Failed to set the scale %s=%d: %v", name, scale, err)
}
}
return nil
}
// Pull pulls the specified services (like docker pull).
func (p *Project) Pull(ctx context.Context, services ...string) error {
return p.forEach(services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
wrapper.Do(nil, events.ServicePullStart, events.ServicePull, func(service Service) error {
return service.Pull(ctx)
})
}), nil)
}
// Containers lists the containers for the specified services. Can be filter using
// the Filter struct.
func (p *Project) Containers(ctx context.Context, filter Filter, services ...string) ([]string, error) {
containers := []string{}
err := p.forEach(services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
wrapper.Do(nil, events.NoEvent, events.NoEvent, func(service Service) error {
serviceContainers, innerErr := service.Containers(ctx)
if innerErr != nil {
return innerErr
}
for _, container := range serviceContainers {
running, innerErr := container.IsRunning(ctx)
if innerErr != nil {
log.Error(innerErr)
}
switch filter.State {
case Running:
if !running {
continue
}
case Stopped:
if running {
continue
}
case AnyState:
// Don't do a thing
default:
// Invalid state filter
return fmt.Errorf("Invalid container filter: %s", filter.State)
}
containerID, innerErr := container.ID()
if innerErr != nil {
log.Error(innerErr)
}
containers = append(containers, containerID)
}
return nil
})
}), nil)
if err != nil {
return nil, err
}
return containers, nil
}
// Delete removes the specified services (like docker rm).
func (p *Project) Delete(ctx context.Context, options options.Delete, services ...string) error {
return p.perform(events.ProjectDeleteStart, events.ProjectDeleteDone, services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
wrapper.Do(nil, events.ServiceDeleteStart, events.ServiceDelete, func(service Service) error {
return service.Delete(ctx, options)
})
}), nil)
}
// Kill kills the specified services (like docker kill).
func (p *Project) Kill(ctx context.Context, signal string, services ...string) error {
return p.perform(events.ProjectKillStart, events.ProjectKillDone, services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
wrapper.Do(nil, events.ServiceKillStart, events.ServiceKill, func(service Service) error {
return service.Kill(ctx, signal)
})
}), nil)
}
// Pause pauses the specified services containers (like docker pause).
func (p *Project) Pause(ctx context.Context, services ...string) error {
return p.perform(events.ProjectPauseStart, events.ProjectPauseDone, services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
wrapper.Do(nil, events.ServicePauseStart, events.ServicePause, func(service Service) error {
return service.Pause(ctx)
})
}), nil)
}
// Unpause pauses the specified services containers (like docker pause).
func (p *Project) Unpause(ctx context.Context, services ...string) error {
return p.perform(events.ProjectUnpauseStart, events.ProjectUnpauseDone, services, wrapperAction(func(wrapper *serviceWrapper, wrappers map[string]*serviceWrapper) {
wrapper.Do(nil, events.ServiceUnpauseStart, events.ServiceUnpause, func(service Service) error {
return service.Unpause(ctx)
})
}), nil)
}
func (p *Project) perform(start, done events.EventType, services []string, action wrapperAction, cycleAction serviceAction) error {
p.Notify(start, "", nil)
@@ -810,6 +527,12 @@ func (p *Project) Notify(eventType events.EventType, serviceName string, data ma
}
}
// GetServiceConfig looks up a service config for a given service name, returning the ServiceConfig
// object and a bool flag indicating whether it was found
func (p *Project) GetServiceConfig(name string) (*config.ServiceConfig, bool) {
return p.ServiceConfigs.Get(name)
}
// IsNamedVolume returns whether the specified volume (string) is a named volume or not.
func IsNamedVolume(volume string) bool {
return !strings.HasPrefix(volume, ".") && !strings.HasPrefix(volume, "/") && !strings.HasPrefix(volume, "~")