Merge branch '21766-disk-cache-size'
[arvados.git] / lib / boot / supervisor.go
index 143529487b315391aa07901427deb7cd19085491..67649e75de55132692767184e05cbb932b5f97e1 100644 (file)
@@ -61,8 +61,7 @@ type Supervisor struct {
        // explicitly configured in config file. If blank, use a
        // random port on ListenHost.
        ControllerAddr string
-       // Path to arvados-workbench2 source tree checkout.
-       Workbench2Source     string
+
        NoWorkbench1         bool
        NoWorkbench2         bool
        OwnTemporaryDatabase bool
@@ -112,29 +111,25 @@ func (super *Supervisor) Start(ctx context.Context) {
        super.ctx, super.cancel = context.WithCancel(ctx)
        super.done = make(chan struct{})
 
-       sigch := make(chan os.Signal)
-       signal.Notify(sigch, syscall.SIGINT, syscall.SIGTERM)
-       defer signal.Stop(sigch)
-       go func() {
-               for sig := range sigch {
-                       super.logger.WithField("signal", sig).Info("caught signal")
-                       if super.err == nil {
-                               super.err = fmt.Errorf("caught signal %s", sig)
-                       }
-                       super.cancel()
-               }
-       }()
-
-       hupch := make(chan os.Signal)
-       signal.Notify(hupch, syscall.SIGHUP)
-       defer signal.Stop(hupch)
+       sigch := make(chan os.Signal, 1)
+       signal.Notify(sigch, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
        go func() {
-               for sig := range hupch {
-                       super.logger.WithField("signal", sig).Info("caught signal")
-                       if super.err == nil {
-                               super.err = errNeedConfigReload
+               defer signal.Stop(sigch)
+               for {
+                       select {
+                       case <-ctx.Done():
+                               return
+                       case sig := <-sigch:
+                               super.logger.WithField("signal", sig).Info("caught signal")
+                               if super.err == nil {
+                                       if sig == syscall.SIGHUP {
+                                               super.err = errNeedConfigReload
+                                       } else {
+                                               super.err = fmt.Errorf("caught signal %s", sig)
+                                       }
+                               }
+                               super.cancel()
                        }
-                       super.cancel()
                }
        }()
 
@@ -209,15 +204,24 @@ func (super *Supervisor) Wait() error {
 func (super *Supervisor) startFederation(cfg *arvados.Config) {
        super.children = map[string]*Supervisor{}
        for id, cc := range cfg.Clusters {
-               super2 := *super
                yaml, err := json.Marshal(arvados.Config{Clusters: map[string]arvados.Cluster{id: cc}})
                if err != nil {
                        panic(fmt.Sprintf("json.Marshal partial config: %s", err))
                }
-               super2.ConfigYAML = string(yaml)
-               super2.ConfigPath = "-"
-               super2.children = nil
-
+               super2 := &Supervisor{
+                       ConfigPath:           "-",
+                       ConfigYAML:           string(yaml),
+                       SourcePath:           super.SourcePath,
+                       SourceVersion:        super.SourceVersion,
+                       ClusterType:          super.ClusterType,
+                       ListenHost:           super.ListenHost,
+                       ControllerAddr:       super.ControllerAddr,
+                       NoWorkbench1:         super.NoWorkbench1,
+                       NoWorkbench2:         super.NoWorkbench2,
+                       OwnTemporaryDatabase: super.OwnTemporaryDatabase,
+                       Stdin:                super.Stdin,
+                       Stderr:               super.Stderr,
+               }
                if super2.ClusterType == "test" {
                        super2.Stderr = &service.LogPrefixer{
                                Writer: super.Stderr,
@@ -225,7 +229,7 @@ func (super *Supervisor) startFederation(cfg *arvados.Config) {
                        }
                }
                super2.Start(super.ctx)
-               super.children[id] = &super2
+               super.children[id] = super2
        }
 }
 
@@ -251,13 +255,9 @@ func (super *Supervisor) runCluster() error {
        }
 
        if super.ListenHost == "" {
-               if urlhost := super.cluster.Services.Controller.ExternalURL.Host; urlhost != "" {
-                       if h, _, _ := net.SplitHostPort(urlhost); h != "" {
-                               super.ListenHost = h
-                       } else {
-                               super.ListenHost = urlhost
-                       }
-               } else {
+               u := url.URL(super.cluster.Services.Controller.ExternalURL)
+               super.ListenHost = u.Hostname()
+               if super.ListenHost == "" {
                        super.ListenHost = "0.0.0.0"
                }
        }
@@ -290,7 +290,7 @@ func (super *Supervisor) runCluster() error {
        if err != nil {
                return err
        }
-       conffile, err := os.OpenFile(filepath.Join(super.wwwtempdir, "config.yml"), os.O_CREATE|os.O_WRONLY, 0644)
+       conffile, err := os.OpenFile(filepath.Join(super.wwwtempdir, "config.yml"), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
        if err != nil {
                return err
        }
@@ -316,6 +316,7 @@ func (super *Supervisor) runCluster() error {
        if super.ClusterType != "production" {
                super.prependEnv("PATH", super.tempdir+"/bin:")
        }
+       super.setEnv("ARVADOS_SERVER_ADDRESS", super.ListenHost)
 
        // Now that we have the config, replace the bootstrap logger
        // with a new one according to the logging config.
@@ -332,13 +333,13 @@ func (super *Supervisor) runCluster() error {
        } else if super.SourceVersion == "" {
                // Find current source tree version.
                var buf bytes.Buffer
-               err = super.RunProgram(super.ctx, ".", runOptions{output: &buf}, "git", "diff", "--shortstat")
+               err = super.RunProgram(super.ctx, super.SourcePath, runOptions{output: &buf}, "git", "diff", "--shortstat")
                if err != nil {
                        return err
                }
                dirty := buf.Len() > 0
                buf.Reset()
-               err = super.RunProgram(super.ctx, ".", runOptions{output: &buf}, "git", "log", "-n1", "--format=%H")
+               err = super.RunProgram(super.ctx, super.SourcePath, runOptions{output: &buf}, "git", "log", "-n1", "--format=%H")
                if err != nil {
                        return err
                }
@@ -363,22 +364,22 @@ func (super *Supervisor) runCluster() error {
                createCertificates{},
                runPostgreSQL{},
                runNginx{},
-               runServiceCommand{name: "controller", svc: super.cluster.Services.Controller, depends: []supervisedTask{seedDatabase{}}},
-               runServiceCommand{name: "git-httpd", svc: super.cluster.Services.GitHTTP},
-               runGoProgram{src: "services/health", svc: super.cluster.Services.Health},
+               railsDatabase{},
+               runServiceCommand{name: "controller", svc: super.cluster.Services.Controller, depends: []supervisedTask{railsDatabase{}}},
+               runServiceCommand{name: "health", svc: super.cluster.Services.Health},
                runServiceCommand{name: "keepproxy", svc: super.cluster.Services.Keepproxy, depends: []supervisedTask{runPassenger{src: "services/api"}}},
                runServiceCommand{name: "keepstore", svc: super.cluster.Services.Keepstore},
                runServiceCommand{name: "keep-web", svc: super.cluster.Services.WebDAV},
-               runServiceCommand{name: "ws", svc: super.cluster.Services.Websocket, depends: []supervisedTask{seedDatabase{}}},
-               installPassenger{src: "services/api"},
-               runPassenger{src: "services/api", varlibdir: "railsapi", svc: super.cluster.Services.RailsAPI, depends: []supervisedTask{createCertificates{}, seedDatabase{}, installPassenger{src: "services/api"}}},
-               seedDatabase{},
+               runServiceCommand{name: "ws", svc: super.cluster.Services.Websocket, depends: []supervisedTask{railsDatabase{}}},
+               installPassenger{src: "services/api", varlibdir: "railsapi"},
+               runPassenger{src: "services/api", varlibdir: "railsapi", svc: super.cluster.Services.RailsAPI, depends: []supervisedTask{
+                       createCertificates{},
+                       installPassenger{src: "services/api", varlibdir: "railsapi"},
+                       railsDatabase{},
+               }},
        }
        if !super.NoWorkbench1 {
-               tasks = append(tasks,
-                       installPassenger{src: "apps/workbench", depends: []supervisedTask{seedDatabase{}}}, // dependency ensures workbench doesn't delay api install/startup
-                       runPassenger{src: "apps/workbench", varlibdir: "workbench1", svc: super.cluster.Services.Workbench1, depends: []supervisedTask{installPassenger{src: "apps/workbench"}}},
-               )
+               return errors.New("workbench1 is no longer supported")
        }
        if !super.NoWorkbench2 {
                tasks = append(tasks,
@@ -386,9 +387,13 @@ func (super *Supervisor) runCluster() error {
                )
        }
        if super.ClusterType != "test" {
+               tasks = append(tasks,
+                       runServiceCommand{name: "keep-balance", svc: super.cluster.Services.Keepbalance},
+               )
+       }
+       if super.cluster.Containers.CloudVMs.Enable {
                tasks = append(tasks,
                        runServiceCommand{name: "dispatch-cloud", svc: super.cluster.Services.DispatchCloud},
-                       runGoProgram{src: "services/keep-balance", svc: super.cluster.Services.Keepbalance},
                )
        }
        super.tasksReady = map[string]chan bool{}
@@ -467,6 +472,7 @@ func (super *Supervisor) WaitReady() bool {
                        super.logger.Infof("waiting for %s to be ready", id)
                        if !super2.WaitReady() {
                                super.logger.Infof("%s startup failed", id)
+                               super.Stop()
                                return false
                        }
                        super.logger.Infof("%s is ready", id)
@@ -480,6 +486,7 @@ func (super *Supervisor) WaitReady() bool {
                select {
                case <-ticker.C:
                case <-super.ctx.Done():
+                       super.Stop()
                        return false
                }
                if super.healthChecker == nil {
@@ -813,7 +820,6 @@ func (super *Supervisor) autofillConfig() error {
        for _, svc := range []*arvados.Service{
                &super.cluster.Services.Controller,
                &super.cluster.Services.DispatchCloud,
-               &super.cluster.Services.GitHTTP,
                &super.cluster.Services.Health,
                &super.cluster.Services.Keepproxy,
                &super.cluster.Services.Keepstore,
@@ -824,9 +830,6 @@ func (super *Supervisor) autofillConfig() error {
                &super.cluster.Services.Workbench1,
                &super.cluster.Services.Workbench2,
        } {
-               if svc == &super.cluster.Services.DispatchCloud && super.ClusterType == "test" {
-                       continue
-               }
                if svc.ExternalURL.Host == "" {
                        port, err := nextPort(defaultExtHost)
                        if err != nil {
@@ -834,7 +837,6 @@ func (super *Supervisor) autofillConfig() error {
                        }
                        host := net.JoinHostPort(defaultExtHost, port)
                        if svc == &super.cluster.Services.Controller ||
-                               svc == &super.cluster.Services.GitHTTP ||
                                svc == &super.cluster.Services.Health ||
                                svc == &super.cluster.Services.Keepproxy ||
                                svc == &super.cluster.Services.WebDAV ||
@@ -847,8 +849,9 @@ func (super *Supervisor) autofillConfig() error {
                        }
                }
                if super.NoWorkbench1 && svc == &super.cluster.Services.Workbench1 ||
-                       super.NoWorkbench2 && svc == &super.cluster.Services.Workbench2 {
-                       // When workbench1 is disabled, it gets an
+                       super.NoWorkbench2 && svc == &super.cluster.Services.Workbench2 ||
+                       !super.cluster.Containers.CloudVMs.Enable && svc == &super.cluster.Services.DispatchCloud {
+                       // When Workbench is disabled, it gets an
                        // ExternalURL (so we have a valid listening
                        // port to write in our Nginx config) but no
                        // InternalURLs (so health checker doesn't