Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upstart Support #16

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM alpine:3.1
FROM alpine:3.2
ENTRYPOINT ["/bin/resolvable"]

COPY ./config /config
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile.dev
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM gliderlabs/alpine:3.1
FROM gliderlabs/alpine:3.2

ENV GOPATH /go
RUN apk-install go git mercurial
Expand Down
20 changes: 15 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,24 @@ 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

build:
Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 `<hostname>` and `<name>.docker` for each container. Containers are automatically registered when they start, and removed when they die.
Expand Down
36 changes: 36 additions & 0 deletions resolver/resolvconf.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"os"
"regexp"
"strings"

"github.com/gliderlabs/resolvable/upstart"
)

const RESOLVCONF_COMMENT = "# added by resolvable"
Expand Down Expand Up @@ -83,5 +85,39 @@ func updateResolvConf(insert, path string) error {
if err != nil {
return err
}

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()
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
}
175 changes: 175 additions & 0 deletions upstart/upstart.go
Original file line number Diff line number Diff line change
@@ -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
}