1
0
mirror of https://github.com/rancher/os.git synced 2025-06-30 08:41: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"
},
{
"ImportPath": "github.com/rancherio/rancher-compose/docker",
"Comment": "0.1.0-18-gac8e453",
"Rev": "ac8e4533c25f001e633ad85022235182601536dc"
"ImportPath": "github.com/rancherio/rancher-compose/librcompose/docker",
"Comment": "0.1.0-18-g14fef17",
"Rev": "14fef170029bba5896269a3b592035b70ae3f2dc"
},
{
"ImportPath": "github.com/rancherio/rancher-compose/project",
"Comment": "0.1.0-18-gac8e453",
"Rev": "ac8e4533c25f001e633ad85022235182601536dc"
"ImportPath": "github.com/rancherio/rancher-compose/librcompose/project",
"Comment": "0.1.0-18-g14fef17",
"Rev": "14fef170029bba5896269a3b592035b70ae3f2dc"
},
{
"ImportPath": "github.com/ryanuber/go-glob",

View File

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

View File

@ -4,7 +4,6 @@ import (
"bytes"
"errors"
"strings"
"sync"
log "github.com/Sirupsen/logrus"
"gopkg.in/yaml.v2"
@ -19,21 +18,20 @@ var (
)
type ProjectEvent struct {
Event Event
Service Service
Data map[string]string
Event Event
ServiceName string
Data map[string]string
}
func NewProject(name string, factory ServiceFactory) *Project {
return &Project{
Name: name,
configs: make(map[string]*ServiceConfig),
Services: make(map[string]Service),
factory: factory,
Name: name,
configs: make(map[string]*ServiceConfig),
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 {
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 {
service, err := p.createService(name, *config)
if err != nil {
log.Errorf("Failed to create service for %s : %v", name, err)
return err
}
p.Notify(SERVICE_ADD, name, nil)
p.Notify(SERVICE_ADD, service, nil)
p.reload = append(p.reload, name)
p.configs[name] = config
p.Services[name] = service
return nil
}
@ -88,24 +78,36 @@ func (p *Project) Load(bytes []byte) error {
}
func (p *Project) Up() error {
wrappers := make(map[string]*ServiceWrapper)
wrappers := make(map[string]*serviceWrapper)
p.Notify(PROJECT_UP_START, nil, nil)
return p.startAll(wrappers)
}
func (p *Project) startAll(wrappers map[string]*ServiceWrapper) error {
for _, name := range p.reload {
wrappers[name] = NewServiceWrapper(name, p)
for name, _ := range p.configs {
wrapper, err := newServiceWrapper(name, p)
if err != nil {
return err
}
wrappers[name] = wrapper
}
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
for _, wrapper := range wrappers {
wrapper.Reset()
if level > 0 {
for _, wrapper := range wrappers {
if err := wrapper.Reset(); err != nil {
return err
}
}
}
for _, wrapper := range wrappers {
@ -132,85 +134,17 @@ func (p *Project) startAll(wrappers map[string]*ServiceWrapper) error {
log.Errorf("Failed calling callback: %v", err)
}
}
return p.startAll(wrappers)
return p.startAll(wrappers, level+1)
} else {
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) {
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)
if data != nil {
for k, v := range data {
@ -233,17 +167,17 @@ func (p *Project) Notify(event Event, service Service, data map[string]string) {
logf = log.Infof
}
if service == nil {
if serviceName == "" {
logf("Project [%s]: %s %s", p.Name, event, buffer.Bytes())
} 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 {
projectEvent := ProjectEvent{
Event: event,
Service: service,
Data: data,
Event: event,
ServiceName: serviceName,
Data: data,
}
// Don't ever block
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
import (
"strings"
"github.com/rancherio/go-rancher/client"
"gopkg.in/yaml.v2"
"strings"
)
type Event string
@ -20,6 +21,7 @@ const (
SERVICE_UP = Event("Started")
PROJECT_UP_START = Event("Starting project")
PROJECT_UP_DONE = Event("Project started")
PROJECT_RELOAD = Event("Reloading project")
PROJECT_RELOAD_TRIGGER = Event("Triggering project reload")
)
@ -168,7 +170,6 @@ type Project struct {
Name string
configs map[string]*ServiceConfig
reload []string
Services map[string]Service
file string
content []byte
client *client.RancherClient

View File

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

View File

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

View File

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

View File

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

View File

@ -5,7 +5,7 @@ import (
"github.com/rancherio/os/config"
"github.com/rancherio/os/util"
"github.com/rancherio/rancher-compose/project"
"github.com/rancherio/rancher-compose/librcompose/project"
)
type ContainerFactory struct {
@ -39,7 +39,7 @@ func (c *containerBasedService) Up() error {
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 {
event = project.CONTAINER_CREATED
@ -60,7 +60,7 @@ func (c *containerBasedService) Up() error {
}
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,
})
}

View File

@ -7,7 +7,7 @@ import (
log "github.com/Sirupsen/logrus"
"github.com/rancherio/os/config"
"github.com/rancherio/os/util"
"github.com/rancherio/rancher-compose/project"
"github.com/rancherio/rancher-compose/librcompose/project"
)
type configEnvironment struct {
@ -117,7 +117,7 @@ func RunServices(name string, cfg *config.Config, configs map[string]*project.Se
go func() {
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
}
}

View File

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