From 01dcb4989747b44c24b8ce6dc2dad9a43ffcdf2e Mon Sep 17 00:00:00 2001 From: Erik Kristensen Date: Mon, 7 Dec 2015 15:27:05 -0700 Subject: [PATCH 1/2] working on upstart --- Dockerfile | 2 +- Dockerfile.dev | 2 +- Makefile | 20 +++-- README.md | 9 +++ resolver/resolvconf.go | 27 +++++++ upstart/upstart.go | 175 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 228 insertions(+), 7 deletions(-) create mode 100644 upstart/upstart.go diff --git a/Dockerfile b/Dockerfile index acbbdf5..f62477a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.1 +FROM alpine:3.2 ENTRYPOINT ["/bin/resolvable"] COPY ./config /config diff --git a/Dockerfile.dev b/Dockerfile.dev index e4096ac..b2a93ee 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -1,4 +1,4 @@ -FROM gliderlabs/alpine:3.1 +FROM gliderlabs/alpine:3.2 ENV GOPATH /go RUN apk-install go git mercurial diff --git a/Makefile b/Makefile index 02efb9d..bff9717 100644 --- a/Makefile +++ b/Makefile @@ -2,16 +2,26 @@ NAME=resolvable VERSION=$(shell cat VERSION) dev: - @docker history $(NAME):dev &> /dev/null \ - || docker build -f Dockerfile.dev -t $(NAME):dev . + #@docker history $(NAME):dev &> /dev/null \ + # || docker build -f Dockerfile.dev -t $(NAME):dev . + docker build -f Dockerfile.dev -t $(NAME):dev . @docker run --rm \ --hostname $(NAME) \ - -v $(PWD):/go/src/github.com/gliderlabs/resolvable \ - -v $(PWD)/config:/config \ -v /var/run/docker.sock:/tmp/docker.sock \ - -v /etc/resolv.conf:/tmp/resolv.conf \ + -v /etc/resolvconf/resolv.conf.d/head:/tmp/resolv.conf \ + -v /var/run/dbus/system_bus_socket:/var/run/dbus/system_bus_socket \ $(NAME):dev +devupstart: + docker build -f Dockerfile.dev -t $(NAME):dev . + @docker run --rm -it \ + --hostname $(NAME) \ + --privileged \ + -v /var/run/docker.sock:/tmp/docker.sock \ + -v /etc/resolvconf/resolv.conf.d/head:/tmp/resolv.conf \ + -v /var/run/dbus/system_bus_socket:/var/run/dbus/system_bus_socket \ + $(NAME):dev /bin/ash + build: mkdir -p build docker build -t $(NAME):$(VERSION) . diff --git a/README.md b/README.md index 9681200..6c6f062 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,15 @@ On systems using systemd, `resolvable` can integrate with the systemd DNS config `resolvable` will generate a systemd network config, and then use the DBUS socket to reload `systemd-networkd` to regenerate the host's `/etc/resolv.conf`. +## Upstart integration + + docker run -d \ + --hostname resolvable \ + -v /var/run/docker.sock:/tmp/docker.sock \ + -v /etc/resolvconf/resolv.conf.d/head:/tmp/resolv.conf \ + -v /var/run/dbus/system_bus_socket:/var/run/dbus/system_bus_socket \ + mgood/resolvable + ## Container Registration `resolvable` provides DNS entries `` and `.docker` for each container. Containers are automatically registered when they start, and removed when they die. diff --git a/resolver/resolvconf.go b/resolver/resolvconf.go index af6e507..adc01c4 100644 --- a/resolver/resolvconf.go +++ b/resolver/resolvconf.go @@ -7,6 +7,8 @@ import ( "os" "regexp" "strings" + + "github.com/gliderlabs/resolvable/upstart" ) const RESOLVCONF_COMMENT = "# added by resolvable" @@ -82,6 +84,31 @@ func updateResolvConf(insert, path string) error { pos, err := f.Seek(0, os.SEEK_CUR) if err != nil { return err + } else { + reload("resolvconf") } + return f.Truncate(pos) } + +func reload(name string) error { + log.Printf("upstart: %s: starting reload...", name) + + conn, err := upstart.Dial() + if err != nil { + fmt.Fprintln(os.Stderr, "Failed to connect to session bus:", err) + os.Exit(1) + } + + j, err := conn.Job(name) + if err != nil { + return err + } + + err2 := j.Restart() + if err2 != nil { + return err2 + } + + return nil +} diff --git a/upstart/upstart.go b/upstart/upstart.go new file mode 100644 index 0000000..1be01e0 --- /dev/null +++ b/upstart/upstart.go @@ -0,0 +1,175 @@ +package upstart + +import ( + "fmt" + "github.com/guelfey/go.dbus" +) + +type Conn struct { + conn *dbus.Conn +} + +type Job struct { + u *Conn + path dbus.ObjectPath +} + +const BusName = "com.ubuntu.Upstart" + +func (u *Conn) object(path dbus.ObjectPath) *dbus.Object { + return u.conn.Object(BusName, path) +} + +func Dial() (*Conn, error) { + conn, err := dbus.SystemBus() + if err != nil { + return nil, err + } + + return &Conn{conn}, nil +} + +func (u *Conn) Job(name string) (*Job, error) { + obj := u.object("/com/ubuntu/Upstart") + + var s dbus.ObjectPath + err := obj.Call("com.ubuntu.Upstart0_6.GetJobByName", 0, name).Store(&s) + if err != nil { + return nil, err + } + + return &Job{u, s}, nil +} + +type Instance struct { + j *Job + path dbus.ObjectPath +} + +func (j *Job) obj() *dbus.Object { + return j.u.object(j.path) +} + +func (i *Instance) obj() *dbus.Object { + return i.j.u.object(i.path) +} + +func (j *Job) Instances() ([]*Instance, error) { + var instances []dbus.ObjectPath + + err := j.obj().Call("com.ubuntu.Upstart0_6.Job.GetAllInstances", 0).Store(&instances) + if err != nil { + return nil, err + } + + var out []*Instance + + for _, inst := range instances { + out = append(out, &Instance{j, inst}) + } + + return out, nil +} + +func (j *Job) Name() (string, error) { + val, err := j.obj().GetProperty("com.ubuntu.Upstart0_6.Job.name") + if err != nil { + return "", err + } + + if str, ok := val.Value().(string); ok { + return str, nil + } + + return "", fmt.Errorf("Name was not a string") +} + +func (j *Job) Pid() (int32, error) { + insts, err := j.Instances() + if err != nil { + return 0, err + } + + switch len(insts) { + default: + return 0, fmt.Errorf("More than 1 instances running, no single pid") + case 0: + return 0, fmt.Errorf("No instances of job available") + case 1: + procs, err := insts[0].Processes() + if err != nil { + return 0, err + } + + switch len(procs) { + default: + return 0, fmt.Errorf("More than 1 processes running, no single pid") + case 0: + return 0, fmt.Errorf("No process running of any instances") + case 1: + return procs[0].Pid, nil + } + } +} + +func (j *Job) Pids() ([]int32, error) { + insts, err := j.Instances() + if err != nil { + return nil, err + } + + var pids []int32 + + for _, inst := range insts { + procs, err := inst.Processes() + if err != nil { + return nil, err + } + + for _, proc := range procs { + pids = append(pids, proc.Pid) + } + } + + return pids, nil +} + +func (j *Job) Restart() error { + wait := false + c := j.obj().Call("com.ubuntu.Upstart0_6.Job.Restart", 0, []string{}, wait) + + var inst dbus.ObjectPath + return c.Store(&inst) +} + +func (j *Job) Stop() error { + wait := false + c := j.obj().Call("com.ubuntu.Upstart0_6.Job.Stop", 0, []string{}, wait) + + return c.Store() +} + +type Process struct { + Name string + Pid int32 +} + +func (i *Instance) Processes() ([]Process, error) { + val, err := i.obj().GetProperty("com.ubuntu.Upstart0_6.Instance.processes") + + if err != nil { + return nil, err + } + + var out []Process + + if ary, ok := val.Value().([][]interface{}); ok { + for _, elem := range ary { + out = append(out, Process{elem[0].(string), elem[1].(int32)}) + } + } else { + return nil, fmt.Errorf("Unable to decode processes property") + } + + return out, nil +} From c37c74002bf6a82e978c3c21b481112ca29a088c Mon Sep 17 00:00:00 2001 From: Erik Kristensen Date: Mon, 7 Dec 2015 16:13:31 -0700 Subject: [PATCH 2/2] upstart reload support --- Makefile | 2 +- resolver/resolvconf.go | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index bff9717..1528d4b 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ devupstart: -v /var/run/docker.sock:/tmp/docker.sock \ -v /etc/resolvconf/resolv.conf.d/head:/tmp/resolv.conf \ -v /var/run/dbus/system_bus_socket:/var/run/dbus/system_bus_socket \ - $(NAME):dev /bin/ash + $(NAME):dev build: mkdir -p build diff --git a/resolver/resolvconf.go b/resolver/resolvconf.go index adc01c4..002bf50 100644 --- a/resolver/resolvconf.go +++ b/resolver/resolvconf.go @@ -84,14 +84,23 @@ func updateResolvConf(insert, path string) error { pos, err := f.Seek(0, os.SEEK_CUR) if err != nil { return err - } else { - reload("resolvconf") + } + + err2 := reload("resolvconf") + if err2 != nil { + return err2 } return f.Truncate(pos) } func reload(name string) error { + upstartDbusPath := getopt("UPSTART_DBUS_PATH", "/var/run/dbus/system_bus_socket") + if _, err := os.Stat(upstartDbusPath); err != nil { + log.Printf("upstart: disabled, cannot read %s: %s", upstartDbusPath, err) + return nil + } + log.Printf("upstart: %s: starting reload...", name) conn, err := upstart.Dial()