15954: Ignore warnings from passenger-config validate-install.
[arvados.git] / lib / boot / passenger.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 package boot
6
7 import (
8         "bytes"
9         "context"
10         "fmt"
11         "os"
12         "path/filepath"
13         "strings"
14         "sync"
15
16         "git.arvados.org/arvados.git/sdk/go/arvados"
17 )
18
19 // Don't trust "passenger-config" (or "bundle install") to handle
20 // concurrent installs.
21 var passengerInstallMutex sync.Mutex
22
23 // Install a Rails application's dependencies, including phusion
24 // passenger.
25 type installPassenger struct {
26         src     string
27         depends []supervisedTask
28 }
29
30 func (runner installPassenger) String() string {
31         return "installPassenger:" + runner.src
32 }
33
34 func (runner installPassenger) Run(ctx context.Context, fail func(error), super *Supervisor) error {
35         err := super.wait(ctx, runner.depends...)
36         if err != nil {
37                 return err
38         }
39
40         passengerInstallMutex.Lock()
41         defer passengerInstallMutex.Unlock()
42
43         var buf bytes.Buffer
44         err = super.RunProgram(ctx, runner.src, &buf, nil, "gem", "list", "--details", "bundler")
45         if err != nil {
46                 return err
47         }
48         for _, version := range []string{"1.11.0", "1.17.3", "2.0.2"} {
49                 if !strings.Contains(buf.String(), "("+version+")") {
50                         err = super.RunProgram(ctx, runner.src, nil, nil, "gem", "install", "--user", "bundler:1.11", "bundler:1.17.3", "bundler:2.0.2")
51                         if err != nil {
52                                 return err
53                         }
54                         break
55                 }
56         }
57         err = super.RunProgram(ctx, runner.src, nil, nil, "bundle", "install", "--jobs", "4", "--path", filepath.Join(os.Getenv("HOME"), ".gem"))
58         if err != nil {
59                 return err
60         }
61         err = super.RunProgram(ctx, runner.src, nil, nil, "bundle", "exec", "passenger-config", "build-native-support")
62         if err != nil {
63                 return err
64         }
65         err = super.RunProgram(ctx, runner.src, nil, nil, "bundle", "exec", "passenger-config", "install-standalone-runtime")
66         if err != nil {
67                 return err
68         }
69         err = super.RunProgram(ctx, runner.src, nil, nil, "bundle", "exec", "passenger-config", "validate-install")
70         if err != nil && !strings.Contains(err.Error(), "exit status 2") {
71                 // Exit code 2 indicates there were warnings (like
72                 // "other passenger installations have been detected",
73                 // which we can't expect to avoid) but no errors.
74                 // Other non-zero exit codes (1, 9) indicate errors.
75                 return err
76         }
77         return nil
78 }
79
80 type runPassenger struct {
81         src     string
82         svc     arvados.Service
83         depends []supervisedTask
84 }
85
86 func (runner runPassenger) String() string {
87         return "runPassenger:" + runner.src
88 }
89
90 func (runner runPassenger) Run(ctx context.Context, fail func(error), super *Supervisor) error {
91         err := super.wait(ctx, runner.depends...)
92         if err != nil {
93                 return err
94         }
95         port, err := internalPort(runner.svc)
96         if err != nil {
97                 return fmt.Errorf("bug: no internalPort for %q: %v (%#v)", runner, err, runner.svc)
98         }
99         loglevel := "4"
100         if lvl, ok := map[string]string{
101                 "debug":   "5",
102                 "info":    "4",
103                 "warn":    "2",
104                 "warning": "2",
105                 "error":   "1",
106                 "fatal":   "0",
107                 "panic":   "0",
108         }[super.cluster.SystemLogs.LogLevel]; ok {
109                 loglevel = lvl
110         }
111         super.waitShutdown.Add(1)
112         go func() {
113                 defer super.waitShutdown.Done()
114                 err = super.RunProgram(ctx, runner.src, nil, []string{"ARVADOS_RAILS_LOG_TO_STDOUT=1"}, "bundle", "exec",
115                         "passenger", "start",
116                         "-p", port,
117                         "--log-file", "/dev/stderr",
118                         "--log-level", loglevel,
119                         "--no-friendly-error-pages",
120                         "--pid-file", filepath.Join(super.tempdir, "passenger."+strings.Replace(runner.src, "/", "_", -1)+".pid"))
121                 fail(err)
122         }()
123         return nil
124 }