upgrade libcompose to fbdac0a6a80837c63eb6c8f43514f7bb3f32df6c
This commit is contained in:
+34
-311
@@ -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, "~")
|
||||
|
||||
Reference in New Issue
Block a user