add postgresql
[arvados.git] / services / boot / supervisor.go
1 package main
2
3 import (
4         "context"
5         "log"
6         "math/rand"
7         "os"
8
9         "github.com/hashicorp/consul/api"
10 )
11
12 type supervisor interface {
13         Running(ctx context.Context) (bool, error)
14         Start(ctx context.Context) error
15 }
16
17 func newSupervisor(ctx context.Context, name, cmd string, args ...string) supervisor {
18         if _, err := os.Stat("/run/systemd/system"); err == nil {
19                 return &systemdUnit{
20                         name: name,
21                         cmd:  cmd,
22                         args: args,
23                 }
24         }
25         return &runitService{
26                 name: name,
27                 cmd:  cmd,
28                 args: args,
29         }
30 }
31
32 // supervised by systemd/runit/etc and registered with consul
33 type supervisedService struct {
34         name string // name to register with consul
35         cmd  string // program to run (absolute path) -- if blank, use name
36         args []string
37 }
38
39 func (s *supervisedService) Boot(ctx context.Context) error {
40         bin := s.cmd
41         if bin == "" {
42                 bin = s.name
43         }
44         if _, err := os.Stat(bin); err != nil {
45                 return err
46         }
47         sup := newSupervisor(ctx, s.name, bin, s.args...)
48         if ok, err := sup.Running(ctx); err != nil {
49                 return err
50         } else if !ok {
51                 if err := sup.Start(ctx); err != nil {
52                         return err
53                 }
54         }
55         if err := consul.Boot(ctx); err != nil {
56                 return err
57         }
58         consul, err := api.NewClient(consulCfg)
59         if err != nil {
60                 return err
61         }
62         agent := consul.Agent()
63         svcs, err := agent.Services()
64         if err != nil {
65                 return err
66         }
67         if svc, ok := svcs[s.name]; ok {
68                 log.Printf("%s is registered: %#v", s.name, svc)
69                 return nil
70         }
71         return agent.ServiceRegister(&api.AgentServiceRegistration{
72                 ID:   s.name,
73                 Name: s.name,
74                 Port: availablePort(),
75         })
76 }
77
78 func availablePort() int {
79         return rand.Intn(10000) + 20000
80 }