[ARVADOS] updated: 658183e2bca17f5aa281ab95068906c7150b2b73

Git user git at public.curoverse.com
Thu Feb 2 11:38:10 EST 2017


Summary of changes:
 services/boot/arvados_go.go       |  45 +++++++++----
 services/boot/arvados_packages.go |  33 ++++++++++
 services/boot/booter.go           |   9 ++-
 services/boot/command.go          |  13 ++++
 services/boot/config.go           |  35 +++++++++-
 services/boot/consul.go           |  63 ++++++++++++++++--
 services/boot/controller.go       |   7 +-
 services/boot/main.go             |   7 +-
 services/boot/os_package.go       |   5 +-
 services/boot/package.json        |   2 +-
 services/boot/supervisor.go       |  11 +++-
 services/boot/systemd.go          |   9 +--
 services/boot/vault.go            | 132 ++++++++++++++++++++++++++++++++++++++
 services/boot/write_file.go       |  46 +++++++++++++
 14 files changed, 376 insertions(+), 41 deletions(-)
 create mode 100644 services/boot/arvados_packages.go
 create mode 100644 services/boot/command.go
 create mode 100644 services/boot/vault.go
 create mode 100644 services/boot/write_file.go

       via  658183e2bca17f5aa281ab95068906c7150b2b73 (commit)
       via  315fb56f14fbef24204cc424f95ff49a9ee6149b (commit)
       via  55ce7e1b9befcde1a7a5be556bed7f6db8a1c098 (commit)
       via  eb459d42be239bd579634884292d3606896792fd (commit)
      from  a31038ebef04b7c8473222d90586ff8ae0a4a904 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.


commit 658183e2bca17f5aa281ab95068906c7150b2b73
Author: Tom Clegg <tom at curoverse.com>
Date:   Mon Jan 30 10:24:24 2017 -0500

    enable consul webgui on :18500

diff --git a/services/boot/arvados_go.go b/services/boot/arvados_go.go
index e23a1d1..3d60dde 100644
--- a/services/boot/arvados_go.go
+++ b/services/boot/arvados_go.go
@@ -28,10 +28,6 @@ type arvadosGoBooter struct {
 	tmpl string
 }
 
-func availablePort() int {
-	return rand.Intn(10000) + 20000
-}
-
 func (agb *arvadosGoBooter) Boot(ctx context.Context) error {
 	cfg := cfg(ctx)
 
@@ -58,7 +54,9 @@ func (agb *arvadosGoBooter) Boot(ctx context.Context) error {
 	if err := os.MkdirAll(path.Dir(cfgPath), 0755); err != nil {
 		return err
 	}
-	if err := atomicWriteFile(cfgPath+".ctmpl", []byte("{}"), 0644); err != nil {
+	// ctmpl := []byte(fmt.Sprintf(`{{tree %q | explode | toJSONPretty}}`, agb.name))
+	ctmpl := []byte(`{}`)
+	if err := atomicWriteFile(cfgPath+".ctmpl", ctmpl, 0644); err != nil {
 		return err
 	}
 	return Series{
diff --git a/services/boot/consul.go b/services/boot/consul.go
index d5e6301..f51d694 100644
--- a/services/boot/consul.go
+++ b/services/boot/consul.go
@@ -61,10 +61,12 @@ func (cb *consulBooter) Boot(ctx context.Context) error {
 	{
 		cf := path.Join(cfg.DataDir, "consul-ports.json")
 		err = atomicWriteJSON(cf, map[string]interface{}{
+			"client_addr":      "0.0.0.0",
 			"bootstrap_expect": len(cfg.ControlHosts),
 			"data_dir":         dataDir,
 			"datacenter":       cfg.SiteID,
 			"server":           true,
+			"ui":               true,
 			"ports": map[string]int{
 				"dns":      cfg.Ports.ConsulDNS,
 				"http":     cfg.Ports.ConsulHTTP,
diff --git a/services/boot/package.json b/services/boot/package.json
index 6e2be8a..7c30502 100644
--- a/services/boot/package.json
+++ b/services/boot/package.json
@@ -14,7 +14,7 @@
   "scripts": {
     "dev": "WEBPACK_FLAGS=-d go generate && go get ./... && $GOPATH/bin/boot",
     "dev-as-root": "WEBPACK_FLAGS=-d go generate && go get ./... && sudo $GOPATH/bin/boot",
-    "dev-docker": "WEBPACK_FLAGS=-d go generate && go get ./... && docker build --tag=arvados-boot-test-runit testimage_runit && docker run -it --cap-add=IPC_LOCK --rm --volume=${GOPATH}/bin/boot:/usr/bin/arvados-boot:ro arvados-boot-test-runit",
+    "dev-docker": "WEBPACK_FLAGS=-d go generate && go get ./... && docker build --tag=arvados-boot-test-runit testimage_runit && docker run --rm -it --publish=18500:18500 --cap-add=IPC_LOCK --volume=${GOPATH}/bin/boot:/usr/bin/arvados-boot:ro arvados-boot-test-runit",
     "test": "./node_modules/.bin/tap 'js/**/*_test.js'",
     "build": "go generate && go get ./...",
     "start": "npm run build && $GOPATH/bin/boot",
diff --git a/services/boot/supervisor.go b/services/boot/supervisor.go
index 9ac2532..a8d8a8c 100644
--- a/services/boot/supervisor.go
+++ b/services/boot/supervisor.go
@@ -28,9 +28,10 @@ func newSupervisor(ctx context.Context, name, cmd string, args ...string) superv
 	}
 }
 
+// supervised by systemd/runit/etc and registered with consul
 type supervisedService struct {
-	name string
-	cmd  string
+	name string		// name to register with consul
+	cmd  string		// program to run (absolute path)
 	args []string
 }
 
@@ -72,3 +73,7 @@ func (s *supervisedService) Boot(ctx context.Context) error {
 		Port: availablePort(),
 	})
 }
+
+func availablePort() int {
+	return rand.Intn(10000) + 20000
+}

commit 315fb56f14fbef24204cc424f95ff49a9ee6149b
Author: Tom Clegg <tom at curoverse.com>
Date:   Sun Jan 29 14:01:38 2017 -0500

    fix templated services

diff --git a/services/boot/arvados_go.go b/services/boot/arvados_go.go
index 8a4a10d..e23a1d1 100644
--- a/services/boot/arvados_go.go
+++ b/services/boot/arvados_go.go
@@ -2,6 +2,7 @@ package main
 
 import (
 	"context"
+	"fmt"
 	"log"
 	"math/rand"
 	"os"
@@ -12,15 +13,19 @@ import (
 var (
 	dispatchLocal = &arvadosGoBooter{name: "crunch-dispatch-local"}
 	dispatchSLURM = &arvadosGoBooter{name: "crunch-dispatch-slurm"}
-	gitHTTP       = &arvadosGoBooter{name: "arvados-git-httpd"}
-	keepbalance   = &arvadosGoBooter{name: "keep-balance"}
+	gitHTTP       = &arvadosGoBooter{name: "arvados-git-httpd", conf: "git-httpd"}
+	keepbalance   = &arvadosGoBooter{name: "keep-balance", tmpl: keepbalanceTmpl}
 	keepproxy     = &arvadosGoBooter{name: "keepproxy"}
 	keepstore     = &arvadosGoBooter{name: "keepstore"}
-	websocket     = &arvadosGoBooter{name: "arvados-ws"}
+	websocket     = &arvadosGoBooter{name: "arvados-ws", conf: "ws"}
+
+	keepbalanceTmpl = `{"RunPeriod":"1m"}`
 )
 
 type arvadosGoBooter struct {
 	name string
+	conf string
+	tmpl string
 }
 
 func availablePort() int {
@@ -29,6 +34,14 @@ func availablePort() int {
 
 func (agb *arvadosGoBooter) Boot(ctx context.Context) error {
 	cfg := cfg(ctx)
+
+	if agb.conf == "" {
+		agb.conf = agb.name
+	}
+	if agb.tmpl == "" {
+		agb.tmpl = "{}"
+	}
+
 	cmd := path.Join(cfg.UsrDir, "bin", agb.name)
 	if _, err := os.Stat(cmd); err != nil {
 		if found, err := filepath.Glob(path.Join(cfg.UsrDir, "pkg", agb.name+"_*.deb")); err == nil && len(found) > 0 {
@@ -41,8 +54,13 @@ func (agb *arvadosGoBooter) Boot(ctx context.Context) error {
 			}
 		}
 	}
-	cfgPath := path.Join("/etc/arvados", agb.name, agb.name+".yml")
-	atomicWriteFile(cfgPath+".ctmpl", []byte("{}"), 0644)
+	cfgPath := path.Join("/etc/arvados", agb.conf, agb.conf+".yml")
+	if err := os.MkdirAll(path.Dir(cfgPath), 0755); err != nil {
+		return err
+	}
+	if err := atomicWriteFile(cfgPath+".ctmpl", []byte("{}"), 0644); err != nil {
+		return err
+	}
 	return Series{
 		&osPackage{
 			Debian: agb.name,
@@ -51,8 +69,8 @@ func (agb *arvadosGoBooter) Boot(ctx context.Context) error {
 			name: agb.name,
 			cmd:  path.Join(cfg.UsrDir, "bin", "consul-template"),
 			args: []string{
-				"-consul-addr=127.0.0.1:8500",
-				"-template="+cfgPath+".ctmpl:"+cfgPath,
+				"-consul-addr=" + fmt.Sprintf("0.0.0.0:%d", cfg.Ports.ConsulHTTP),
+				"-template=" + cfgPath + ".ctmpl:" + cfgPath,
 				"-exec",
 				agb.name,
 			},
diff --git a/services/boot/booter.go b/services/boot/booter.go
index 3ca800d..ee37fd0 100644
--- a/services/boot/booter.go
+++ b/services/boot/booter.go
@@ -45,7 +45,14 @@ func (cb Concurrent) Boot(ctx context.Context) error {
 		i, b := i, b
 		go func() {
 			defer wg.Done()
-			errs[i] = b.Boot(ctx)
+			err := b.Boot(ctx)
+			switch err.(type) {
+			case nil:
+			case *MultipleError:
+			default:
+				err = fmt.Errorf("%T: %s", b, err)
+			}
+			errs[i] = err
 		}()
 	}
 	wg.Wait()
diff --git a/services/boot/consul.go b/services/boot/consul.go
index 6ad5e6e..d5e6301 100644
--- a/services/boot/consul.go
+++ b/services/boot/consul.go
@@ -80,7 +80,7 @@ func (cb *consulBooter) Boot(ctx context.Context) error {
 		}
 		args = append(args, "-config-file="+cf)
 	}
-	supervisor := newSupervisor(ctx, "consul", bin, args...)
+	supervisor := newSupervisor(ctx, "arvados-consul", bin, args...)
 	running, err := supervisor.Running(ctx)
 	if err != nil {
 		return err
diff --git a/services/boot/supervisor.go b/services/boot/supervisor.go
index 2fcb336..9ac2532 100644
--- a/services/boot/supervisor.go
+++ b/services/boot/supervisor.go
@@ -42,7 +42,7 @@ func (s *supervisedService) Boot(ctx context.Context) error {
 	if _, err := os.Stat(bin); err != nil {
 		return err
 	}
-	sup := newSupervisor(ctx, s.name, bin)
+	sup := newSupervisor(ctx, s.name, bin, s.args...)
 	if ok, err := sup.Running(ctx); err != nil {
 		return err
 	} else if !ok {
diff --git a/services/boot/vault.go b/services/boot/vault.go
index 85b062a..de9cfb3 100644
--- a/services/boot/vault.go
+++ b/services/boot/vault.go
@@ -53,7 +53,7 @@ func (vb *vaultBooter) Boot(ctx context.Context) error {
 	}
 
 	args := []string{"server", "-config=" + cfgPath}
-	supervisor := newSupervisor(ctx, "vault", bin, args...)
+	supervisor := newSupervisor(ctx, "arvados-vault", bin, args...)
 	running, err := supervisor.Running(ctx)
 	if err != nil {
 		return err

commit 55ce7e1b9befcde1a7a5be556bed7f6db8a1c098
Author: Tom Clegg <tom at curoverse.com>
Date:   Sun Jan 29 05:54:30 2017 -0500

    unseal vault

diff --git a/services/boot/consul.go b/services/boot/consul.go
index e1015ae..6ad5e6e 100644
--- a/services/boot/consul.go
+++ b/services/boot/consul.go
@@ -5,6 +5,8 @@ import (
 	"fmt"
 	"os"
 	"os/exec"
+	"path"
+	"strings"
 	"sync"
 
 	"github.com/hashicorp/consul/api"
@@ -38,16 +40,46 @@ func (cb *consulBooter) Boot(ctx context.Context) error {
 	if err := os.MkdirAll(dataDir, 0700); err != nil {
 		return err
 	}
-	args := []string{
-		"agent",
-		"-server",
-		"-datacenter=" + cfg.SiteID,
-		"-dns-port=" + fmt.Sprintf("%d", cfg.Ports.ConsulDNS),
-		"-http-port=" + fmt.Sprintf("%d", cfg.Ports.ConsulHTTP),
-		"-serf-lan-bind=0.0.0.0:" + fmt.Sprintf("%d", cfg.Ports.ConsulSerfLAN),
-		"-serf-wan-bind=0.0.0.0:" + fmt.Sprintf("%d", cfg.Ports.ConsulSerfWAN),
-		"-data-dir", dataDir,
-		"-bootstrap-expect", fmt.Sprintf("%d", len(cfg.ControlHosts))}
+	args := []string{"agent"}
+	{
+		cf := path.Join(cfg.DataDir, "consul-encrypt.json")
+		_, err := os.Stat(cf)
+		if os.IsNotExist(err) {
+			key, err := exec.Command(bin, "keygen").CombinedOutput()
+			if err != nil {
+				return err
+			}
+			err = atomicWriteJSON(cf, map[string]interface{}{
+				"encrypt": strings.TrimSpace(string(key)),
+			}, 0400)
+		}
+		if err != nil {
+			return err
+		}
+		args = append(args, "-config-file="+cf)
+	}
+	{
+		cf := path.Join(cfg.DataDir, "consul-ports.json")
+		err = atomicWriteJSON(cf, map[string]interface{}{
+			"bootstrap_expect": len(cfg.ControlHosts),
+			"data_dir":         dataDir,
+			"datacenter":       cfg.SiteID,
+			"server":           true,
+			"ports": map[string]int{
+				"dns":      cfg.Ports.ConsulDNS,
+				"http":     cfg.Ports.ConsulHTTP,
+				"https":    cfg.Ports.ConsulHTTPS,
+				"rpc":      cfg.Ports.ConsulRPC,
+				"serf_lan": cfg.Ports.ConsulSerfLAN,
+				"serf_wan": cfg.Ports.ConsulSerfWAN,
+				"server":   cfg.Ports.ConsulServer,
+			},
+		}, 0644)
+		if err != nil {
+			return err
+		}
+		args = append(args, "-config-file="+cf)
+	}
 	supervisor := newSupervisor(ctx, "consul", bin, args...)
 	running, err := supervisor.Running(ctx)
 	if err != nil {
@@ -88,3 +120,13 @@ func (cb *consulBooter) check(ctx context.Context) error {
 	}
 	return nil
 }
+
+// OnlyNode returns true if this is the only consul node.
+func (cb *consulBooter) OnlyNode() (bool, error) {
+	c, err := api.NewClient(consulCfg)
+	if err != nil {
+		return false, err
+	}
+	nodes, _, err := c.Catalog().Nodes(nil)
+	return len(nodes) == 1, err
+}
diff --git a/services/boot/controller.go b/services/boot/controller.go
index 06de1d3..953507f 100644
--- a/services/boot/controller.go
+++ b/services/boot/controller.go
@@ -10,22 +10,22 @@ type controller struct{}
 func (c *controller) Boot(ctx context.Context) error {
 	cfg := cfg(ctx)
 	return Series{
+		cfg,
 		Concurrent{
-			cfg,
 			installCerts,
 			arvadosRepo,
 		},
 		Concurrent{
-			consul,
 			&download{
 				URL:  "https://releases.hashicorp.com/consul-template/0.18.0/consul-template_0.18.0_linux_amd64.zip",
 				Dest: path.Join(cfg.UsrDir, "bin", "consul-template"),
 				Size: 6912352,
 				Mode: 0755,
 			},
+			consul,
 		},
+		vault,
 		Concurrent{
-			vault,
 			dispatchLocal,
 			dispatchSLURM,
 			gitHTTP,
diff --git a/services/boot/vault.go b/services/boot/vault.go
index 1b0d38a..85b062a 100644
--- a/services/boot/vault.go
+++ b/services/boot/vault.go
@@ -3,6 +3,7 @@ package main
 import (
 	"context"
 	"fmt"
+	"io/ioutil"
 	"log"
 	"path"
 	"sync"
@@ -10,7 +11,10 @@ import (
 	"github.com/hashicorp/vault/api"
 )
 
-var vault = &vaultBooter{}
+var (
+	vault    = &vaultBooter{}
+	vaultCfg = api.DefaultConfig()
+)
 
 type vaultBooter struct {
 	sync.Mutex
@@ -34,6 +38,7 @@ func (vb *vaultBooter) Boot(ctx context.Context) error {
 	if err != nil {
 		return err
 	}
+
 	cfgPath := path.Join(cfg.DataDir, "vault.hcl")
 	err = atomicWriteFile(cfgPath, []byte(fmt.Sprintf(`backend "consul" {
 		address = "127.0.0.1:%d"
@@ -60,22 +65,68 @@ func (vb *vaultBooter) Boot(ctx context.Context) error {
 			return fmt.Errorf("starting vault: %s", err)
 		}
 	}
+
+	vb.tryInit(ctx)
 	return vb.check(ctx)
 }
 
-var vaultCfg = api.DefaultConfig()
+func (vb *vaultBooter) tryInit(ctx context.Context) {
+	cfg := cfg(ctx)
+	vault, err := vb.client(ctx)
+	if err != nil {
+		return
+	}
+	if init, err := vault.Sys().InitStatus(); err != nil {
+		log.Printf("error: vault InitStatus: %s", err)
+		return
+	} else if init {
+		return
+	}
+	resp, err := vault.Sys().Init(&api.InitRequest{
+		SecretShares:    5,
+		SecretThreshold: 3,
+	})
+	if err != nil {
+		log.Printf("vault-init: %s", err)
+		return
+	}
+	atomicWriteJSON(path.Join(cfg.DataDir, "vault-keys.json"), resp, 0400)
+	atomicWriteFile(path.Join(cfg.DataDir, "vault-root-token.txt"), []byte(resp.RootToken), 0400)
 
-func (vb *vaultBooter) check(ctx context.Context) error {
+	for _, key := range resp.Keys {
+		resp, err := vault.Sys().Unseal(key)
+		if err != nil {
+			log.Printf("error: unseal: %s", err)
+			continue
+		}
+		if !resp.Sealed {
+			log.Printf("unseal successful")
+			break
+		}
+	}
+}
+
+func (vb *vaultBooter) client(ctx context.Context) (*api.Client, error) {
 	cfg := cfg(ctx)
 	vaultCfg.Address = fmt.Sprintf("http://0.0.0.0:%d", cfg.Ports.VaultServer)
-	vault, err := api.NewClient(vaultCfg)
+	return api.NewClient(vaultCfg)
+}
+
+func (vb *vaultBooter) check(ctx context.Context) error {
+	cfg := cfg(ctx)
+	vault, err := vb.client(ctx)
 	if err != nil {
 		return err
 	}
-	help, err := vault.Help("help")
+	token, err := ioutil.ReadFile(path.Join(cfg.DataDir, "vault-root-token.txt"))
 	if err != nil {
 		return err
 	}
-	log.Printf("%#v", help)
+	vault.SetToken(string(token))
+	if init, err := vault.Sys().InitStatus(); err != nil {
+		return err
+	} else if !init {
+		return fmt.Errorf("vault is not initialized")
+	}
 	return nil
 }
diff --git a/services/boot/write_file.go b/services/boot/write_file.go
index 24374dd..d482f16 100644
--- a/services/boot/write_file.go
+++ b/services/boot/write_file.go
@@ -1,6 +1,7 @@
 package main
 
 import (
+	"encoding/json"
 	"io/ioutil"
 	"os"
 	"path"
@@ -35,3 +36,11 @@ func atomicWriteFile(name string, data []byte, mode os.FileMode) error {
 	tmp = nil
 	return nil
 }
+
+func atomicWriteJSON(name string, data interface{}, mode os.FileMode) error {
+	j, err := json.MarshalIndent(data, "", "  ")
+	if err != nil {
+		return err
+	}
+	return atomicWriteFile(name, j, mode)
+}

commit eb459d42be239bd579634884292d3606896792fd
Author: Tom Clegg <tom at curoverse.com>
Date:   Sun Jan 29 02:15:12 2017 -0500

    add vault, consul-template, arvados pkgs

diff --git a/services/boot/arvados_go.go b/services/boot/arvados_go.go
index b95f7c0..8a4a10d 100644
--- a/services/boot/arvados_go.go
+++ b/services/boot/arvados_go.go
@@ -5,7 +5,6 @@ import (
 	"log"
 	"math/rand"
 	"os"
-	"os/exec"
 	"path"
 	"path/filepath"
 )
@@ -33,9 +32,7 @@ func (agb *arvadosGoBooter) Boot(ctx context.Context) error {
 	cmd := path.Join(cfg.UsrDir, "bin", agb.name)
 	if _, err := os.Stat(cmd); err != nil {
 		if found, err := filepath.Glob(path.Join(cfg.UsrDir, "pkg", agb.name+"_*.deb")); err == nil && len(found) > 0 {
-			cmd := exec.Command("dpkg", "-i", found[0])
-			cmd.Stdout = os.Stderr
-			cmd.Stderr = os.Stderr
+			cmd := command("dpkg", "-i", found[0])
 			osPackageMutex.Lock()
 			err = cmd.Run()
 			osPackageMutex.Unlock()
@@ -44,13 +41,21 @@ func (agb *arvadosGoBooter) Boot(ctx context.Context) error {
 			}
 		}
 	}
+	cfgPath := path.Join("/etc/arvados", agb.name, agb.name+".yml")
+	atomicWriteFile(cfgPath+".ctmpl", []byte("{}"), 0644)
 	return Series{
 		&osPackage{
 			Debian: agb.name,
 		},
 		&supervisedService{
+			name: agb.name,
 			cmd:  path.Join(cfg.UsrDir, "bin", "consul-template"),
-			args: []string{"blah"},
+			args: []string{
+				"-consul-addr=127.0.0.1:8500",
+				"-template="+cfgPath+".ctmpl:"+cfgPath,
+				"-exec",
+				agb.name,
+			},
 		},
 	}.Boot(ctx)
 }
diff --git a/services/boot/arvados_packages.go b/services/boot/arvados_packages.go
new file mode 100644
index 0000000..5115b46
--- /dev/null
+++ b/services/boot/arvados_packages.go
@@ -0,0 +1,33 @@
+package main
+
+import (
+	"context"
+	"io/ioutil"
+	"os"
+	"sync"
+)
+
+var arvadosRepo = &arvadosRepoBooter{}
+
+type arvadosRepoBooter struct {
+	sync.Mutex
+}
+
+func (*arvadosRepoBooter) Boot(ctx context.Context) error {
+	cfg := cfg(ctx)
+	repo := cfg.ArvadosAptRepo
+	if !repo.Enabled {
+		return nil
+	}
+	srcPath := "/etc/apt/sources.list.d/arvados.list"
+	if _, err := os.Stat(srcPath); err == nil {
+		return nil
+	}
+	if err := command("apt-key", "adv", "--keyserver", "pool.sks-keyservers.net", "--recv", "1078ECD7").Run(); err != nil {
+		return err
+	}
+	if err := ioutil.WriteFile(srcPath, []byte("deb "+repo.URL+" "+repo.Release+" main\n"), 0644); err != nil {
+		return err
+	}
+	return command("apt-get", "update").Run()
+}
diff --git a/services/boot/command.go b/services/boot/command.go
new file mode 100644
index 0000000..c080918
--- /dev/null
+++ b/services/boot/command.go
@@ -0,0 +1,13 @@
+package main
+
+import (
+	"os"
+	"os/exec"
+)
+
+func command(prog string, args ...string) *exec.Cmd {
+	cmd := exec.Command(prog, args...)
+	cmd.Stderr = os.Stderr
+	cmd.Stdout = os.Stderr
+	return cmd
+}
diff --git a/services/boot/config.go b/services/boot/config.go
index 2eeac01..3ee981d 100644
--- a/services/boot/config.go
+++ b/services/boot/config.go
@@ -3,7 +3,9 @@ package main
 import (
 	"context"
 	"fmt"
+	"io/ioutil"
 	"os"
+	"strings"
 )
 
 type Config struct {
@@ -20,6 +22,8 @@ type Config struct {
 	DataDir      string
 	UsrDir       string
 	RunitSvDir   string
+
+	ArvadosAptRepo aptRepoConfig
 }
 
 type portsConfig struct {
@@ -27,9 +31,10 @@ type portsConfig struct {
 	ConsulHTTP    int
 	ConsulHTTPS   int
 	ConsulRPC     int
-	ConsulSerfLAN int `json:"Serf_LAN"`
-	ConsulSerfWAN int `json:"Serf_WAN"`
+	ConsulSerfLAN int
+	ConsulSerfWAN int
 	ConsulServer  int
+	VaultServer   int
 }
 
 type webguiConfig struct {
@@ -38,6 +43,12 @@ type webguiConfig struct {
 	Listen string
 }
 
+type aptRepoConfig struct {
+	Enabled bool
+	URL     string
+	Release string
+}
+
 func (c *Config) Boot(ctx context.Context) error {
 	for _, path := range []string{c.DataDir, c.UsrDir, c.UsrDir + "/bin"} {
 		if fi, err := os.Stat(path); err != nil {
@@ -53,8 +64,25 @@ func (c *Config) Boot(ctx context.Context) error {
 }
 
 func DefaultConfig() *Config {
+	var repoConf aptRepoConfig
+	if rel, err := ioutil.ReadFile("/etc/os-release"); err == nil {
+		rel := string(rel)
+		for _, try := range []string{"jessie", "precise", "xenial"} {
+			if !strings.Contains(rel, try) {
+				continue
+			}
+			repoConf = aptRepoConfig{
+				Enabled: true,
+				URL:     "http://apt.arvados.org/",
+				Release: try,
+			}
+			break
+		}
+	}
 	return &Config{
-		ControlHosts: []string{"127.0.0.1"},
+		SiteID:         "zzzzz",
+		ArvadosAptRepo: repoConf,
+		ControlHosts:   []string{"127.0.0.1"},
 		Ports: portsConfig{
 			ConsulDNS:     18600,
 			ConsulHTTP:    18500,
@@ -63,6 +91,7 @@ func DefaultConfig() *Config {
 			ConsulSerfLAN: 18301,
 			ConsulSerfWAN: 18302,
 			ConsulServer:  18300,
+			VaultServer:   18200,
 		},
 		DataDir:    "/var/lib/arvados",
 		UsrDir:     "/usr/local/arvados",
diff --git a/services/boot/consul.go b/services/boot/consul.go
index a536d1a..e1015ae 100644
--- a/services/boot/consul.go
+++ b/services/boot/consul.go
@@ -41,7 +41,11 @@ func (cb *consulBooter) Boot(ctx context.Context) error {
 	args := []string{
 		"agent",
 		"-server",
-		"-advertise=127.0.0.1",
+		"-datacenter=" + cfg.SiteID,
+		"-dns-port=" + fmt.Sprintf("%d", cfg.Ports.ConsulDNS),
+		"-http-port=" + fmt.Sprintf("%d", cfg.Ports.ConsulHTTP),
+		"-serf-lan-bind=0.0.0.0:" + fmt.Sprintf("%d", cfg.Ports.ConsulSerfLAN),
+		"-serf-wan-bind=0.0.0.0:" + fmt.Sprintf("%d", cfg.Ports.ConsulSerfWAN),
 		"-data-dir", dataDir,
 		"-bootstrap-expect", fmt.Sprintf("%d", len(cfg.ControlHosts))}
 	supervisor := newSupervisor(ctx, "consul", bin, args...)
@@ -72,6 +76,7 @@ var consulCfg = api.DefaultConfig()
 
 func (cb *consulBooter) check(ctx context.Context) error {
 	cfg := cfg(ctx)
+	consulCfg.Address = fmt.Sprintf("127.0.0.1:%d", cfg.Ports.ConsulHTTP)
 	consulCfg.Datacenter = cfg.SiteID
 	consul, err := api.NewClient(consulCfg)
 	if err != nil {
diff --git a/services/boot/controller.go b/services/boot/controller.go
index cc996bf..06de1d3 100644
--- a/services/boot/controller.go
+++ b/services/boot/controller.go
@@ -13,16 +13,19 @@ func (c *controller) Boot(ctx context.Context) error {
 		Concurrent{
 			cfg,
 			installCerts,
+			arvadosRepo,
 		},
 		Concurrent{
 			consul,
 			&download{
 				URL:  "https://releases.hashicorp.com/consul-template/0.18.0/consul-template_0.18.0_linux_amd64.zip",
 				Dest: path.Join(cfg.UsrDir, "bin", "consul-template"),
+				Size: 6912352,
 				Mode: 0755,
 			},
 		},
 		Concurrent{
+			vault,
 			dispatchLocal,
 			dispatchSLURM,
 			gitHTTP,
diff --git a/services/boot/main.go b/services/boot/main.go
index 86846b3..ebab009 100644
--- a/services/boot/main.go
+++ b/services/boot/main.go
@@ -2,6 +2,7 @@ package main
 
 import (
 	"context"
+	"encoding/json"
 	"flag"
 	"log"
 	"os"
@@ -22,6 +23,11 @@ func main() {
 	} else if err != nil {
 		log.Fatal(err)
 	}
+
+	enc := json.NewEncoder(os.Stderr)
+	enc.SetIndent("", "  ")
+	enc.Encode(cfg)
+
 	go runWebGUI(cfg)
 	go func() {
 		var ctl Booter = &controller{}
@@ -38,4 +44,3 @@ func main() {
 	}()
 	<-(chan struct{})(nil)
 }
-
diff --git a/services/boot/os_package.go b/services/boot/os_package.go
index db953a1..dc5cd18 100644
--- a/services/boot/os_package.go
+++ b/services/boot/os_package.go
@@ -4,7 +4,6 @@ import (
 	"context"
 	"fmt"
 	"os"
-	"os/exec"
 	"strings"
 	"sync"
 )
@@ -56,9 +55,7 @@ func (pkg *osPackage) Boot(ctx context.Context) error {
 }
 
 func (*osPackage) aptGet(args ...string) error {
-	cmd := exec.Command("apt-get", args...)
-	cmd.Stdout = os.Stderr
-	cmd.Stderr = os.Stderr
+	cmd := command("apt-get", args...)
 	for _, kv := range os.Environ() {
 		if !strings.HasPrefix(kv, "DEBIAN_FRONTEND=") {
 			cmd.Env = append(cmd.Env, kv)
diff --git a/services/boot/package.json b/services/boot/package.json
index 340c69f..6e2be8a 100644
--- a/services/boot/package.json
+++ b/services/boot/package.json
@@ -14,7 +14,7 @@
   "scripts": {
     "dev": "WEBPACK_FLAGS=-d go generate && go get ./... && $GOPATH/bin/boot",
     "dev-as-root": "WEBPACK_FLAGS=-d go generate && go get ./... && sudo $GOPATH/bin/boot",
-    "dev-docker": "WEBPACK_FLAGS=-d go generate && go get ./... && docker build --tag=arvados-boot-test-runit testimage_runit && docker run -it --rm --volume=${GOPATH}/bin/boot:/usr/bin/arvados-boot:ro arvados-boot-test-runit",
+    "dev-docker": "WEBPACK_FLAGS=-d go generate && go get ./... && docker build --tag=arvados-boot-test-runit testimage_runit && docker run -it --cap-add=IPC_LOCK --rm --volume=${GOPATH}/bin/boot:/usr/bin/arvados-boot:ro arvados-boot-test-runit",
     "test": "./node_modules/.bin/tap 'js/**/*_test.js'",
     "build": "go generate && go get ./...",
     "start": "npm run build && $GOPATH/bin/boot",
diff --git a/services/boot/systemd.go b/services/boot/systemd.go
index 4cde7a9..18d123e 100644
--- a/services/boot/systemd.go
+++ b/services/boot/systemd.go
@@ -3,7 +3,6 @@ package main
 import (
 	"context"
 	"fmt"
-	"os"
 	"os/exec"
 )
 
@@ -14,9 +13,7 @@ type systemdUnit struct {
 }
 
 func (u *systemdUnit) Start(ctx context.Context) error {
-	cmd := exec.Command("systemd-run", append([]string{"--unit=arvados-" + u.name, u.cmd}, u.args...)...)
-	cmd.Stdout = os.Stderr
-	cmd.Stderr = os.Stderr
+	cmd := command("systemd-run", append([]string{"--unit=arvados-" + u.name, u.cmd}, u.args...)...)
 	err := cmd.Run()
 	if err != nil {
 		err = fmt.Errorf("systemd-run: %s", err)
@@ -29,9 +26,7 @@ func (u *systemdUnit) Running(ctx context.Context) (bool, error) {
 }
 
 func runStatusCmd(prog string, args ...string) (bool, error) {
-	cmd := exec.Command(prog, args...)
-	cmd.Stdout = os.Stderr
-	cmd.Stderr = os.Stderr
+	cmd := command(prog, args...)
 	err := cmd.Run()
 	switch err.(type) {
 	case *exec.ExitError:
diff --git a/services/boot/vault.go b/services/boot/vault.go
new file mode 100644
index 0000000..1b0d38a
--- /dev/null
+++ b/services/boot/vault.go
@@ -0,0 +1,81 @@
+package main
+
+import (
+	"context"
+	"fmt"
+	"log"
+	"path"
+	"sync"
+
+	"github.com/hashicorp/vault/api"
+)
+
+var vault = &vaultBooter{}
+
+type vaultBooter struct {
+	sync.Mutex
+}
+
+func (vb *vaultBooter) Boot(ctx context.Context) error {
+	vb.Lock()
+	defer vb.Unlock()
+
+	if vb.check(ctx) == nil {
+		return nil
+	}
+	cfg := cfg(ctx)
+	bin := cfg.UsrDir + "/bin/vault"
+	err := (&download{
+		URL:  "https://releases.hashicorp.com/vault/0.6.4/vault_0.6.4_linux_amd64.zip",
+		Dest: bin,
+		Size: 52518022,
+		Mode: 0755,
+	}).Boot(ctx)
+	if err != nil {
+		return err
+	}
+	cfgPath := path.Join(cfg.DataDir, "vault.hcl")
+	err = atomicWriteFile(cfgPath, []byte(fmt.Sprintf(`backend "consul" {
+		address = "127.0.0.1:%d"
+		path = "vault"
+	}
+	listener "tcp" {
+		address = "127.0.0.1:%d"
+		tls_disable = 1
+	}`, cfg.Ports.ConsulHTTP, cfg.Ports.VaultServer)), 0644)
+	if err != nil {
+		return err
+	}
+
+	args := []string{"server", "-config=" + cfgPath}
+	supervisor := newSupervisor(ctx, "vault", bin, args...)
+	running, err := supervisor.Running(ctx)
+	if err != nil {
+		return err
+	}
+	if !running {
+		defer feedbackf(ctx, "starting vault service")()
+		err = supervisor.Start(ctx)
+		if err != nil {
+			return fmt.Errorf("starting vault: %s", err)
+		}
+	}
+	return vb.check(ctx)
+}
+
+var vaultCfg = api.DefaultConfig()
+
+func (vb *vaultBooter) check(ctx context.Context) error {
+	cfg := cfg(ctx)
+	vaultCfg.Address = fmt.Sprintf("http://0.0.0.0:%d", cfg.Ports.VaultServer)
+	vault, err := api.NewClient(vaultCfg)
+	if err != nil {
+		return err
+	}
+	help, err := vault.Help("help")
+	if err != nil {
+		return err
+	}
+	log.Printf("%#v", help)
+	return nil
+}
diff --git a/services/boot/write_file.go b/services/boot/write_file.go
new file mode 100644
index 0000000..24374dd
--- /dev/null
+++ b/services/boot/write_file.go
@@ -0,0 +1,37 @@
+package main
+
+import (
+	"io/ioutil"
+	"os"
+	"path"
+)
+
+func atomicWriteFile(name string, data []byte, mode os.FileMode) error {
+	tmp, err := ioutil.TempFile(path.Dir(name), path.Base(name)+"~")
+	if err != nil {
+		return err
+	}
+	defer func() {
+		if tmp != nil {
+			os.Remove(tmp.Name())
+		}
+	}()
+	_, err = tmp.Write(data)
+	if err != nil {
+		return err
+	}
+	err = tmp.Close()
+	if err != nil {
+		return err
+	}
+	err = os.Chmod(tmp.Name(), mode)
+	if err != nil {
+		return err
+	}
+	err = os.Rename(tmp.Name(), name)
+	if err != nil {
+		return err
+	}
+	tmp = nil
+	return nil
+}

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list