-type Booter struct {
- SourcePath string // e.g., /home/username/src/arvados
- LibPath string // e.g., /var/lib/arvados
- ClusterType string // e.g., production
- Stderr io.Writer
-
- logger logrus.FieldLogger
- cluster *arvados.Cluster
-
- ctx context.Context
- cancel context.CancelFunc
- done chan struct{}
- healthChecker *health.Aggregator
-
- tempdir string
- configfile string
- environ []string // for child processes
-
- setupRubyOnce sync.Once
- setupRubyErr error
- goMutex sync.Mutex
-}
-
-func (boot *Booter) Start(ctx context.Context, loader *config.Loader) {
- boot.ctx, boot.cancel = context.WithCancel(ctx)
- boot.done = make(chan struct{})
- go func() {
- err := boot.run(loader)
- if err != nil {
- fmt.Fprintln(boot.Stderr, err)
- }
- close(boot.done)
- }()
-}
-
-func (boot *Booter) run(loader *config.Loader) error {
- cwd, err := os.Getwd()
- if err != nil {
- return err
- }
- if !strings.HasPrefix(boot.SourcePath, "/") {
- boot.SourcePath = filepath.Join(cwd, boot.SourcePath)
- }
- boot.SourcePath, err = filepath.EvalSymlinks(boot.SourcePath)
- if err != nil {
- return err
- }
-
- boot.tempdir, err = ioutil.TempDir("", "arvados-server-boot-")
- if err != nil {
- return err
- }
- defer os.RemoveAll(boot.tempdir)
-
- loader.SkipAPICalls = true
- cfg, err := loader.Load()
- if err != nil {
- return err
- }
-
- // Fill in any missing config keys, and write the resulting
- // config in the temp dir for child services to use.
- err = boot.autofillConfig(cfg, boot.logger)
- if err != nil {
- return err
- }
- conffile, err := os.OpenFile(filepath.Join(boot.tempdir, "config.yml"), os.O_CREATE|os.O_WRONLY, 0777)
- if err != nil {
- return err
- }
- defer conffile.Close()
- err = json.NewEncoder(conffile).Encode(cfg)
- if err != nil {
- return err
- }
- err = conffile.Close()
- if err != nil {
- return err
- }
- boot.configfile = conffile.Name()
-
- boot.environ = os.Environ()
- boot.setEnv("ARVADOS_CONFIG", boot.configfile)
- boot.setEnv("RAILS_ENV", boot.ClusterType)
- boot.prependEnv("PATH", filepath.Join(boot.LibPath, "bin")+":")
-
- boot.cluster, err = cfg.GetCluster("")
- if err != nil {
- return err
- }
- // Now that we have the config, replace the bootstrap logger
- // with a new one according to the logging config.
- boot.logger = ctxlog.New(boot.Stderr, boot.cluster.SystemLogs.Format, boot.cluster.SystemLogs.LogLevel).WithFields(logrus.Fields{
- "PID": os.Getpid(),
- })
- boot.healthChecker = &health.Aggregator{Cluster: boot.cluster}
-
- for _, dir := range []string{boot.LibPath, filepath.Join(boot.LibPath, "bin")} {
- if _, err = os.Stat(filepath.Join(dir, ".")); os.IsNotExist(err) {
- err = os.Mkdir(dir, 0755)
- if err != nil {
- return err
- }
- } else if err != nil {
- return err
- }
- }
- err = boot.installGoProgram(boot.ctx, "cmd/arvados-server")
- if err != nil {
- return err
- }
- err = boot.setupRubyEnv()
- if err != nil {
- return err
- }
-
- var wg sync.WaitGroup
- for _, cmpt := range []component{
- {name: "nginx", runFunc: runNginx},
- {name: "controller", cmdHandler: controller.Command},
- {name: "dispatchcloud", cmdHandler: dispatchcloud.Command, notIfTest: true},
- {name: "git-httpd", goProg: "services/arv-git-httpd"},
- {name: "health", goProg: "services/health"},
- {name: "keep-balance", goProg: "services/keep-balance", notIfTest: true},
- {name: "keepproxy", goProg: "services/keepproxy"},
- {name: "keepstore", goProg: "services/keepstore", svc: boot.cluster.Services.Keepstore},
- {name: "keep-web", goProg: "services/keep-web"},
- {name: "railsAPI", svc: boot.cluster.Services.RailsAPI, railsApp: "services/api"},
- {name: "workbench1", svc: boot.cluster.Services.Workbench1, railsApp: "apps/workbench"},
- {name: "ws", goProg: "services/ws"},
- } {
- cmpt := cmpt
- wg.Add(1)
- go func() {
- defer wg.Done()
- defer boot.cancel()
- boot.logger.WithField("component", cmpt.name).Info("starting")
- err := cmpt.Run(boot.ctx, boot)
- if err != nil && err != context.Canceled {
- boot.logger.WithError(err).WithField("component", cmpt.name).Error("exited")
- }
- }()
- }
- wg.Wait()
- return nil
-}