1
0
mirror of https://github.com/rancher/os.git synced 2025-07-02 01:31:48 +00:00

Merge pull request #288 from ibuildthecloud/rancher-compose-refactor

Rancher compose refactor
This commit is contained in:
Darren Shepherd 2015-05-05 13:40:50 -07:00
commit 605dfb085b
14 changed files with 150 additions and 129 deletions

12
Godeps/Godeps.json generated
View File

@ -171,14 +171,14 @@
"Rev": "166cde1ff3be90b9199a3703177668b647cbdcf4" "Rev": "166cde1ff3be90b9199a3703177668b647cbdcf4"
}, },
{ {
"ImportPath": "github.com/rancherio/rancher-compose/docker", "ImportPath": "github.com/rancherio/rancher-compose/librcompose/docker",
"Comment": "0.1.0-18-gac8e453", "Comment": "0.1.0-18-g14fef17",
"Rev": "ac8e4533c25f001e633ad85022235182601536dc" "Rev": "14fef170029bba5896269a3b592035b70ae3f2dc"
}, },
{ {
"ImportPath": "github.com/rancherio/rancher-compose/project", "ImportPath": "github.com/rancherio/rancher-compose/librcompose/project",
"Comment": "0.1.0-18-gac8e453", "Comment": "0.1.0-18-g14fef17",
"Rev": "ac8e4533c25f001e633ad85022235182601536dc" "Rev": "14fef170029bba5896269a3b592035b70ae3f2dc"
}, },
{ {
"ImportPath": "github.com/ryanuber/go-glob", "ImportPath": "github.com/ryanuber/go-glob",

View File

@ -5,7 +5,7 @@ import (
"github.com/docker/docker/nat" "github.com/docker/docker/nat"
"github.com/docker/docker/runconfig" "github.com/docker/docker/runconfig"
"github.com/rancherio/rancher-compose/project" "github.com/rancherio/rancher-compose/librcompose/project"
shlex "github.com/flynn/go-shlex" shlex "github.com/flynn/go-shlex"
) )
@ -42,17 +42,17 @@ func Convert(c *project.ServiceConfig) (*runconfig.Config, *runconfig.HostConfig
WorkingDir: c.WorkingDir, WorkingDir: c.WorkingDir,
} }
host_config := &runconfig.HostConfig{ host_config := &runconfig.HostConfig{
Memory: c.MemLimit,
CpuShares: c.CpuShares,
VolumesFrom: c.VolumesFrom, VolumesFrom: c.VolumesFrom,
CapAdd: c.CapAdd, CapAdd: c.CapAdd,
CapDrop: c.CapDrop, CapDrop: c.CapDrop,
CpuShares: c.CpuShares,
Privileged: c.Privileged, Privileged: c.Privileged,
Binds: c.Volumes, Binds: c.Volumes,
Dns: dns, Dns: dns,
LogConfig: runconfig.LogConfig{ LogConfig: runconfig.LogConfig{
Type: c.LogDriver, Type: c.LogDriver,
}, },
Memory: c.MemLimit,
NetworkMode: runconfig.NetworkMode(c.Net), NetworkMode: runconfig.NetworkMode(c.Net),
ReadonlyRootfs: c.ReadOnly, ReadonlyRootfs: c.ReadOnly,
PidMode: runconfig.PidMode(c.Pid), PidMode: runconfig.PidMode(c.Pid),

View File

@ -4,7 +4,6 @@ import (
"bytes" "bytes"
"errors" "errors"
"strings" "strings"
"sync"
log "github.com/Sirupsen/logrus" log "github.com/Sirupsen/logrus"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
@ -19,21 +18,20 @@ var (
) )
type ProjectEvent struct { type ProjectEvent struct {
Event Event Event Event
Service Service ServiceName string
Data map[string]string Data map[string]string
} }
func NewProject(name string, factory ServiceFactory) *Project { func NewProject(name string, factory ServiceFactory) *Project {
return &Project{ return &Project{
Name: name, Name: name,
configs: make(map[string]*ServiceConfig), configs: make(map[string]*ServiceConfig),
Services: make(map[string]Service), factory: factory,
factory: factory,
} }
} }
func (p *Project) createService(name string, config ServiceConfig) (Service, error) { func (p *Project) CreateService(name string, config ServiceConfig) (Service, error) {
if p.EnvironmentLookup != nil { if p.EnvironmentLookup != nil {
parsedEnv := make([]string, 0, len(config.Environment)) parsedEnv := make([]string, 0, len(config.Environment))
@ -55,17 +53,9 @@ func (p *Project) createService(name string, config ServiceConfig) (Service, err
} }
func (p *Project) AddConfig(name string, config *ServiceConfig) error { func (p *Project) AddConfig(name string, config *ServiceConfig) error {
service, err := p.createService(name, *config) p.Notify(SERVICE_ADD, name, nil)
if err != nil {
log.Errorf("Failed to create service for %s : %v", name, err)
return err
}
p.Notify(SERVICE_ADD, service, nil)
p.reload = append(p.reload, name)
p.configs[name] = config p.configs[name] = config
p.Services[name] = service
return nil return nil
} }
@ -88,24 +78,36 @@ func (p *Project) Load(bytes []byte) error {
} }
func (p *Project) Up() error { func (p *Project) Up() error {
wrappers := make(map[string]*ServiceWrapper) wrappers := make(map[string]*serviceWrapper)
p.Notify(PROJECT_UP_START, nil, nil) for name, _ := range p.configs {
wrapper, err := newServiceWrapper(name, p)
return p.startAll(wrappers) if err != nil {
} return err
}
func (p *Project) startAll(wrappers map[string]*ServiceWrapper) error { wrappers[name] = wrapper
for _, name := range p.reload {
wrappers[name] = NewServiceWrapper(name, p)
} }
p.reload = []string{} p.Notify(PROJECT_UP_START, "", nil)
err := p.startAll(wrappers, 0)
if err == nil {
p.Notify(PROJECT_UP_DONE, "", nil)
}
return err
}
func (p *Project) startAll(wrappers map[string]*serviceWrapper, level int) error {
restart := false restart := false
for _, wrapper := range wrappers { if level > 0 {
wrapper.Reset() for _, wrapper := range wrappers {
if err := wrapper.Reset(); err != nil {
return err
}
}
} }
for _, wrapper := range wrappers { for _, wrapper := range wrappers {
@ -132,85 +134,17 @@ func (p *Project) startAll(wrappers map[string]*ServiceWrapper) error {
log.Errorf("Failed calling callback: %v", err) log.Errorf("Failed calling callback: %v", err)
} }
} }
return p.startAll(wrappers) return p.startAll(wrappers, level+1)
} else { } else {
return firstError return firstError
} }
} }
type ServiceWrapper struct {
name string
services map[string]Service
service Service
done sync.WaitGroup
state ServiceState
err error
project *Project
}
func NewServiceWrapper(name string, p *Project) *ServiceWrapper {
wrapper := &ServiceWrapper{
name: name,
services: make(map[string]Service),
service: p.Services[name],
state: UNKNOWN,
project: p,
}
return wrapper
}
func (s *ServiceWrapper) Reset() {
if s.err == ErrRestart {
s.err = nil
}
s.done.Add(1)
}
func (s *ServiceWrapper) Start(wrappers map[string]*ServiceWrapper) {
defer s.done.Done()
if s.state == EXECUTED {
return
}
for _, link := range append(s.service.Config().Links, s.service.Config().VolumesFrom...) {
name := strings.Split(link, ":")[0]
if wrapper, ok := wrappers[name]; ok {
if wrapper.Wait() == ErrRestart {
s.project.Notify(PROJECT_RELOAD, wrapper.service, nil)
s.err = ErrRestart
return
}
} else {
log.Errorf("Failed to find %s", name)
}
}
s.state = EXECUTED
s.project.Notify(SERVICE_UP_START, s.service, nil)
s.err = s.service.Up()
if s.err == ErrRestart {
s.project.Notify(SERVICE_UP, s.service, nil)
s.project.Notify(PROJECT_RELOAD_TRIGGER, s.service, nil)
} else if s.err != nil {
log.Errorf("Failed to start %s : %v", s.name, s.err)
} else {
s.project.Notify(SERVICE_UP, s.service, nil)
}
}
func (s *ServiceWrapper) Wait() error {
s.done.Wait()
return s.err
}
func (p *Project) AddListener(c chan<- ProjectEvent) { func (p *Project) AddListener(c chan<- ProjectEvent) {
p.listeners = append(p.listeners, c) p.listeners = append(p.listeners, c)
} }
func (p *Project) Notify(event Event, service Service, data map[string]string) { func (p *Project) Notify(event Event, serviceName string, data map[string]string) {
buffer := bytes.NewBuffer(nil) buffer := bytes.NewBuffer(nil)
if data != nil { if data != nil {
for k, v := range data { for k, v := range data {
@ -233,17 +167,17 @@ func (p *Project) Notify(event Event, service Service, data map[string]string) {
logf = log.Infof logf = log.Infof
} }
if service == nil { if serviceName == "" {
logf("Project [%s]: %s %s", p.Name, event, buffer.Bytes()) logf("Project [%s]: %s %s", p.Name, event, buffer.Bytes())
} else { } else {
logf("[%d/%d] [%s]: %s %s", p.upCount, len(p.Services), service.Name(), event, buffer.Bytes()) logf("[%d/%d] [%s]: %s %s", p.upCount, len(p.configs), serviceName, event, buffer.Bytes())
} }
for _, l := range p.listeners { for _, l := range p.listeners {
projectEvent := ProjectEvent{ projectEvent := ProjectEvent{
Event: event, Event: event,
Service: service, ServiceName: serviceName,
Data: data, Data: data,
} }
// Don't ever block // Don't ever block
select { select {

View File

@ -0,0 +1,86 @@
package project
import (
"strings"
"sync"
log "github.com/Sirupsen/logrus"
)
type serviceWrapper struct {
name string
service Service
done sync.WaitGroup
state ServiceState
err error
project *Project
}
func newServiceWrapper(name string, p *Project) (*serviceWrapper, error) {
wrapper := &serviceWrapper{
name: name,
state: UNKNOWN,
project: p,
}
return wrapper, wrapper.Reset()
}
func (s *serviceWrapper) Reset() error {
if s.state != EXECUTED {
service, err := s.project.CreateService(s.name, *s.project.configs[s.name])
if err != nil {
log.Errorf("Failed to create service for %s : %v", s.name, err)
return err
}
s.service = service
}
if s.err == ErrRestart {
s.err = nil
}
s.done.Add(1)
return nil
}
func (s *serviceWrapper) Start(wrappers map[string]*serviceWrapper) {
defer s.done.Done()
if s.state == EXECUTED {
return
}
for _, link := range append(s.service.Config().Links, s.service.Config().VolumesFrom...) {
name := strings.Split(link, ":")[0]
if wrapper, ok := wrappers[name]; ok {
if wrapper.Wait() == ErrRestart {
s.project.Notify(PROJECT_RELOAD, wrapper.service.Name(), nil)
s.err = ErrRestart
return
}
} else {
log.Errorf("Failed to find %s", name)
}
}
s.state = EXECUTED
s.project.Notify(SERVICE_UP_START, s.service.Name(), nil)
s.err = s.service.Up()
if s.err == ErrRestart {
s.project.Notify(SERVICE_UP, s.service.Name(), nil)
s.project.Notify(PROJECT_RELOAD_TRIGGER, s.service.Name(), nil)
} else if s.err != nil {
log.Errorf("Failed to start %s : %v", s.name, s.err)
} else {
s.project.Notify(SERVICE_UP, s.service.Name(), nil)
}
}
func (s *serviceWrapper) Wait() error {
s.done.Wait()
return s.err
}

View File

@ -1,9 +1,10 @@
package project package project
import ( import (
"strings"
"github.com/rancherio/go-rancher/client" "github.com/rancherio/go-rancher/client"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
"strings"
) )
type Event string type Event string
@ -20,6 +21,7 @@ const (
SERVICE_UP = Event("Started") SERVICE_UP = Event("Started")
PROJECT_UP_START = Event("Starting project") PROJECT_UP_START = Event("Starting project")
PROJECT_UP_DONE = Event("Project started")
PROJECT_RELOAD = Event("Reloading project") PROJECT_RELOAD = Event("Reloading project")
PROJECT_RELOAD_TRIGGER = Event("Triggering project reload") PROJECT_RELOAD_TRIGGER = Event("Triggering project reload")
) )
@ -168,7 +170,6 @@ type Project struct {
Name string Name string
configs map[string]*ServiceConfig configs map[string]*ServiceConfig
reload []string reload []string
Services map[string]Service
file string file string
content []byte content []byte
client *client.RancherClient client *client.RancherClient

View File

@ -5,7 +5,7 @@ import (
"os" "os"
"strings" "strings"
"github.com/rancherio/rancher-compose/project" "github.com/rancherio/rancher-compose/librcompose/project"
log "github.com/Sirupsen/logrus" log "github.com/Sirupsen/logrus"
"github.com/rancherio/os/util" "github.com/rancherio/os/util"

View File

@ -1,7 +1,7 @@
package config package config
import ( import (
"github.com/rancherio/rancher-compose/project" "github.com/rancherio/rancher-compose/librcompose/project"
) )
func NewConfig() *Config { func NewConfig() *Config {
@ -179,7 +179,7 @@ func NewConfig() *Config {
SCOPE: SYSTEM, SCOPE: SYSTEM,
}), }),
Volumes: []string{ Volumes: []string{
"/var/lib/rancher:/var/lib/rancher", "/var/lib/rancher/conf:/var/lib/rancher/conf",
"/var/lib/docker:/var/lib/docker", "/var/lib/docker:/var/lib/docker",
"/var/lib/system-docker:/var/lib/system-docker", "/var/lib/system-docker:/var/lib/system-docker",
}, },

View File

@ -1,6 +1,6 @@
package config package config
import "github.com/rancherio/rancher-compose/project" import "github.com/rancherio/rancher-compose/librcompose/project"
const ( const (
DEFAULT_IMAGE_VERSION = "v0.3.0-rc2" DEFAULT_IMAGE_VERSION = "v0.3.0-rc2"

View File

@ -18,8 +18,8 @@ import (
dockerClient "github.com/fsouza/go-dockerclient" dockerClient "github.com/fsouza/go-dockerclient"
"github.com/rancherio/os/config" "github.com/rancherio/os/config"
"github.com/rancherio/os/util" "github.com/rancherio/os/util"
"github.com/rancherio/rancher-compose/docker" "github.com/rancherio/rancher-compose/librcompose/docker"
"github.com/rancherio/rancher-compose/project" "github.com/rancherio/rancher-compose/librcompose/project"
) )
type Container struct { type Container struct {
@ -209,7 +209,7 @@ func (c *Container) parseService() {
} }
if c.requiresUserDocker() { if c.requiresUserDocker() {
c.addLink("userdockerwait") c.addLink("dockerwait")
} else if c.ContainerCfg.Service.Image != "" { } else if c.ContainerCfg.Service.Image != "" {
client, err := NewClient(c.dockerHost) client, err := NewClient(c.dockerHost)
if err != nil { if err != nil {

View File

@ -5,7 +5,7 @@ import (
"github.com/rancherio/os/config" "github.com/rancherio/os/config"
"github.com/rancherio/os/util" "github.com/rancherio/os/util"
"github.com/rancherio/rancher-compose/project" "github.com/rancherio/rancher-compose/librcompose/project"
) )
type ContainerFactory struct { type ContainerFactory struct {
@ -39,7 +39,7 @@ func (c *containerBasedService) Up() error {
var event project.Event var event project.Event
c.project.Notify(project.CONTAINER_STARTING, c, map[string]string{}) c.project.Notify(project.CONTAINER_STARTING, c.name, map[string]string{})
if fakeCreate { if fakeCreate {
event = project.CONTAINER_CREATED event = project.CONTAINER_CREATED
@ -60,7 +60,7 @@ func (c *containerBasedService) Up() error {
} }
if container.Container != nil { if container.Container != nil {
c.project.Notify(event, c, map[string]string{ c.project.Notify(event, c.name, map[string]string{
project.CONTAINER_ID: container.Container.ID, project.CONTAINER_ID: container.Container.ID,
}) })
} }

View File

@ -7,7 +7,7 @@ import (
log "github.com/Sirupsen/logrus" log "github.com/Sirupsen/logrus"
"github.com/rancherio/os/config" "github.com/rancherio/os/config"
"github.com/rancherio/os/util" "github.com/rancherio/os/util"
"github.com/rancherio/rancher-compose/project" "github.com/rancherio/rancher-compose/librcompose/project"
) )
type configEnvironment struct { type configEnvironment struct {
@ -117,7 +117,7 @@ func RunServices(name string, cfg *config.Config, configs map[string]*project.Se
go func() { go func() {
for event := range projectEvents { for event := range projectEvents {
if event.Event == project.CONTAINER_STARTED && event.Service.Name() == "network" { if event.Event == project.CONTAINER_STARTED && event.ServiceName == "network" {
network = true network = true
} }
} }

View File

@ -10,7 +10,7 @@ import (
"github.com/rancherio/os/config" "github.com/rancherio/os/config"
"github.com/rancherio/os/docker" "github.com/rancherio/os/docker"
"github.com/rancherio/os/util" "github.com/rancherio/os/util"
"github.com/rancherio/rancher-compose/project" "github.com/rancherio/rancher-compose/librcompose/project"
) )
const boot2dockerMagic = "boot2docker, please format-me" const boot2dockerMagic = "boot2docker, please format-me"