X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/41dec55a4b007a79c58f77d36ad0940b5354b453..9acc8cb9cd9ca4429712b0d31b647e9a6ecf2d96:/lib/install/deps.go diff --git a/lib/install/deps.go b/lib/install/deps.go index 6902688253..62b295a1f1 100644 --- a/lib/install/deps.go +++ b/lib/install/deps.go @@ -8,12 +8,15 @@ import ( "bufio" "bytes" "context" + _ "embed" "errors" "flag" "fmt" "io" "os" "os/exec" + "os/user" + "path/filepath" "strconv" "strings" "syscall" @@ -24,13 +27,33 @@ import ( "github.com/lib/pq" ) -var Command cmd.Handler = installCommand{} +var Command cmd.Handler = &installCommand{} -const devtestDatabasePassword = "insecure_arvados_test" +const goversion = "1.17.7" -type installCommand struct{} +const ( + rubyversion = "2.7.5" + bundlerversion = "2.2.19" + singularityversion = "3.7.4" + pjsversion = "1.9.8" + geckoversion = "0.24.0" + gradleversion = "5.3.1" + nodejsversion = "v12.22.11" + devtestDatabasePassword = "insecure_arvados_test" + workbench2version = "5e020488f67b5bc919796e0dc8b0b9f3b3ff23b0" +) + +//go:embed arvados.service +var arvadosServiceFile []byte -func (installCommand) RunCommand(prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) int { +type installCommand struct { + ClusterType string + SourcePath string + PackageVersion string + EatMyData bool +} + +func (inst *installCommand) RunCommand(prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) int { logger := ctxlog.New(stderr, "text", "info") ctx := ctxlog.Context(context.Background(), logger) ctx, cancel := context.WithCancel(ctx) @@ -46,27 +69,29 @@ func (installCommand) RunCommand(prog string, args []string, stdin io.Reader, st flags := flag.NewFlagSet(prog, flag.ContinueOnError) flags.SetOutput(stderr) versionFlag := flags.Bool("version", false, "Write version information to stdout and exit 0") - clusterType := flags.String("type", "production", "cluster `type`: development, test, or production") - err = flags.Parse(args) - if err == flag.ErrHelp { - err = nil - return 0 - } else if err != nil { - return 2 + flags.StringVar(&inst.ClusterType, "type", "production", "cluster `type`: development, test, production, or package") + flags.StringVar(&inst.SourcePath, "source", "/arvados", "source tree location (required for -type=package)") + flags.StringVar(&inst.PackageVersion, "package-version", "0.0.0", "version string to embed in executable files") + flags.BoolVar(&inst.EatMyData, "eatmydata", false, "use eatmydata to speed up install") + + if ok, code := cmd.ParseFlags(flags, prog, args, "", stderr); !ok { + return code } else if *versionFlag { return cmd.Version.RunCommand(prog, args, stdin, stdout, stderr) } - var dev, test, prod bool - switch *clusterType { + var dev, test, prod, pkg bool + switch inst.ClusterType { case "development": dev = true case "test": test = true case "production": prod = true + case "package": + pkg = true default: - err = fmt.Errorf("invalid cluster type %q (must be 'development', 'test', or 'production')", *clusterType) + err = fmt.Errorf("invalid cluster type %q (must be 'development', 'test', 'production', or 'package')", inst.ClusterType) return 2 } @@ -96,34 +121,44 @@ func (installCommand) RunCommand(prog string, args []string, stdin io.Reader, st } } - if dev || test { - debs := []string{ + if inst.EatMyData { + cmd := exec.CommandContext(ctx, "apt-get", "install", "--yes", "--no-install-recommends", "eatmydata") + cmd.Env = append(os.Environ(), "DEBIAN_FRONTEND=noninteractive") + cmd.Stdout = stdout + cmd.Stderr = stderr + err = cmd.Run() + if err != nil { + return 1 + } + } + + pkgs := prodpkgs(osv) + + if pkg { + pkgs = append(pkgs, + "dpkg-dev", + "eatmydata", // install it for later steps, even if we're not using it now + "rsync", + ) + } + + if dev || test || pkg { + pkgs = append(pkgs, + "automake", "bison", "bsdmainutils", "build-essential", - "ca-certificates", "cadaver", "curl", "cython3", - "daemontools", // lib/boot uses setuidgid to drop privileges when running as root "default-jdk-headless", "default-jre-headless", - "fuse", "gettext", - "git", - "gitolite3", - "graphviz", - "haveged", - "iceweasel", "libattr1-dev", "libcrypt-ssleay-perl", - "libcrypt-ssleay-perl", - "libcurl3-gnutls", - "libcurl4-openssl-dev", "libfuse-dev", "libgnutls28-dev", "libjson-perl", - "libjson-perl", "libpam-dev", "libpcre3-dev", "libpq-dev", @@ -131,13 +166,12 @@ func (installCommand) RunCommand(prog string, args []string, stdin io.Reader, st "libssl-dev", "libwww-perl", "libxml2-dev", - "libxslt1.1", + "libxslt1-dev", "linkchecker", "lsof", + "make", "net-tools", - "nginx", "pandoc", - "perl-modules", "pkg-config", "postgresql", "postgresql-contrib", @@ -152,18 +186,34 @@ func (installCommand) RunCommand(prog string, args []string, stdin io.Reader, st "r-cran-roxygen2", "r-cran-xml", "sudo", + "uuid-dev", "wget", "xvfb", - "zlib1g-dev", + ) + if test { + if osv.Debian && osv.Major <= 10 { + pkgs = append(pkgs, "iceweasel") + } else { + pkgs = append(pkgs, "firefox") + } + } + if dev || test { + pkgs = append(pkgs, "squashfs-tools") // for singularity } switch { + case osv.Debian && osv.Major >= 11: + pkgs = append(pkgs, "libcurl4", "perl-modules-5.32") case osv.Debian && osv.Major >= 10: - debs = append(debs, "libcurl4") + pkgs = append(pkgs, "libcurl4", "perl-modules") default: - debs = append(debs, "libcurl3") + pkgs = append(pkgs, "libcurl3", "perl-modules") } - cmd := exec.CommandContext(ctx, "apt-get", "install", "--yes", "--no-install-recommends") - cmd.Args = append(cmd.Args, debs...) + cmd := exec.CommandContext(ctx, "apt-get") + if inst.EatMyData { + cmd = exec.CommandContext(ctx, "eatmydata", "apt-get") + } + cmd.Args = append(cmd.Args, "install", "--yes", "--no-install-recommends") + cmd.Args = append(cmd.Args, pkgs...) cmd.Env = append(os.Environ(), "DEBIAN_FRONTEND=noninteractive") cmd.Stdout = stdout cmd.Stderr = stderr @@ -174,21 +224,34 @@ func (installCommand) RunCommand(prog string, args []string, stdin io.Reader, st } os.Mkdir("/var/lib/arvados", 0755) - rubyversion := "2.5.7" + os.Mkdir("/var/lib/arvados/tmp", 0700) + if prod || pkg { + u, er := user.Lookup("www-data") + if er != nil { + err = fmt.Errorf("user.Lookup(%q): %w", "www-data", er) + return 1 + } + uid, _ := strconv.Atoi(u.Uid) + gid, _ := strconv.Atoi(u.Gid) + os.Mkdir("/var/lib/arvados/wwwtmp", 0700) + err = os.Chown("/var/lib/arvados/wwwtmp", uid, gid) + if err != nil { + return 1 + } + } + rubymajorversion := rubyversion[:strings.LastIndex(rubyversion, ".")] if haverubyversion, err := exec.Command("/var/lib/arvados/bin/ruby", "-v").CombinedOutput(); err == nil && bytes.HasPrefix(haverubyversion, []byte("ruby "+rubyversion)) { logger.Print("ruby " + rubyversion + " already installed") } else { - err = runBash(` -mkdir -p /var/lib/arvados/tmp -tmp=/var/lib/arvados/tmp/ruby-`+rubyversion+` -trap "rm -r ${tmp}" ERR -wget --progress=dot:giga -O- https://cache.ruby-lang.org/pub/ruby/2.5/ruby-`+rubyversion+`.tar.gz | tar -C /var/lib/arvados/tmp -xzf - -cd ${tmp} -./configure --disable-install-doc --prefix /var/lib/arvados -make -j4 + err = inst.runBash(` +tmp="$(mktemp -d)" +trap 'rm -r "${tmp}"' ERR EXIT +wget --progress=dot:giga -O- https://cache.ruby-lang.org/pub/ruby/`+rubymajorversion+`/ruby-`+rubyversion+`.tar.gz | tar -C "${tmp}" -xzf - +cd "${tmp}/ruby-`+rubyversion+`" +./configure --disable-install-static-library --enable-shared --disable-install-doc --prefix /var/lib/arvados +make -j8 make install -/var/lib/arvados/bin/gem install bundler -rm -r ${tmp} +/var/lib/arvados/bin/gem install bundler --no-document `, stdout, stderr) if err != nil { return 1 @@ -196,74 +259,58 @@ rm -r ${tmp} } if !prod { - goversion := "1.14" if havegoversion, err := exec.Command("/usr/local/bin/go", "version").CombinedOutput(); err == nil && bytes.HasPrefix(havegoversion, []byte("go version go"+goversion+" ")) { logger.Print("go " + goversion + " already installed") } else { - err = runBash(` + err = inst.runBash(` cd /tmp +rm -rf /var/lib/arvados/go/ wget --progress=dot:giga -O- https://storage.googleapis.com/golang/go`+goversion+`.linux-amd64.tar.gz | tar -C /var/lib/arvados -xzf - -ln -sf /var/lib/arvados/go/bin/* /usr/local/bin/ +ln -sfv /var/lib/arvados/go/bin/* /usr/local/bin/ `, stdout, stderr) if err != nil { return 1 } } + } - pjsversion := "1.9.8" + if !prod && !pkg { if havepjsversion, err := exec.Command("/usr/local/bin/phantomjs", "--version").CombinedOutput(); err == nil && string(havepjsversion) == "1.9.8\n" { logger.Print("phantomjs " + pjsversion + " already installed") } else { - err = runBash(` + err = inst.runBash(` PJS=phantomjs-`+pjsversion+`-linux-x86_64 -wget --progress=dot:giga -O- https://bitbucket.org/ariya/phantomjs/downloads/$PJS.tar.bz2 | tar -C /var/lib/arvados -xjf - -ln -sf /var/lib/arvados/$PJS/bin/phantomjs /usr/local/bin/ +wget --progress=dot:giga -O- https://cache.arvados.org/$PJS.tar.bz2 | tar -C /var/lib/arvados -xjf - +ln -sfv /var/lib/arvados/$PJS/bin/phantomjs /usr/local/bin/ `, stdout, stderr) if err != nil { return 1 } } - geckoversion := "0.24.0" if havegeckoversion, err := exec.Command("/usr/local/bin/geckodriver", "--version").CombinedOutput(); err == nil && strings.Contains(string(havegeckoversion), " "+geckoversion+" ") { logger.Print("geckodriver " + geckoversion + " already installed") } else { - err = runBash(` + err = inst.runBash(` GD=v`+geckoversion+` wget --progress=dot:giga -O- https://github.com/mozilla/geckodriver/releases/download/$GD/geckodriver-$GD-linux64.tar.gz | tar -C /var/lib/arvados/bin -xzf - geckodriver -ln -sf /var/lib/arvados/bin/geckodriver /usr/local/bin/ +ln -sfv /var/lib/arvados/bin/geckodriver /usr/local/bin/ `, stdout, stderr) if err != nil { return 1 } } - nodejsversion := "v10.23.1" - if havenodejsversion, err := exec.Command("/usr/local/bin/node", "--version").CombinedOutput(); err == nil && string(havenodejsversion) == nodejsversion+"\n" { - logger.Print("nodejs " + nodejsversion + " already installed") - } else { - err = runBash(` -NJS=`+nodejsversion+` -wget --progress=dot:giga -O- https://nodejs.org/dist/${NJS}/node-${NJS}-linux-x64.tar.xz | sudo tar -C /var/lib/arvados -xJf - -ln -sf /var/lib/arvados/node-${NJS}-linux-x64/bin/{node,npm} /usr/local/bin/ -`, stdout, stderr) - if err != nil { - return 1 - } - } - - gradleversion := "5.3.1" if havegradleversion, err := exec.Command("/usr/local/bin/gradle", "--version").CombinedOutput(); err == nil && strings.Contains(string(havegradleversion), "Gradle "+gradleversion+"\n") { logger.Print("gradle " + gradleversion + " already installed") } else { - err = runBash(` + err = inst.runBash(` G=`+gradleversion+` -mkdir -p /var/lib/arvados/tmp zip=/var/lib/arvados/tmp/gradle-${G}-bin.zip trap "rm ${zip}" ERR wget --progress=dot:giga -O${zip} https://services.gradle.org/distributions/gradle-${G}-bin.zip unzip -o -d /var/lib/arvados ${zip} -ln -sf /var/lib/arvados/gradle-${G}/bin/gradle /usr/local/bin/ +ln -sfv /var/lib/arvados/gradle-${G}/bin/gradle /usr/local/bin/ rm ${zip} `, stdout, stderr) if err != nil { @@ -271,6 +318,26 @@ rm ${zip} } } + if havesingularityversion, err := exec.Command("/var/lib/arvados/bin/singularity", "--version").CombinedOutput(); err == nil && strings.Contains(string(havesingularityversion), singularityversion) { + logger.Print("singularity " + singularityversion + " already installed") + } else if dev || test { + err = inst.runBash(` +S=`+singularityversion+` +tmp=/var/lib/arvados/tmp/singularity +trap "rm -r ${tmp}" ERR EXIT +cd /var/lib/arvados/tmp +git clone https://github.com/sylabs/singularity +cd singularity +git checkout v${S} +./mconfig --prefix=/var/lib/arvados +make -C ./builddir +make -C ./builddir install +`, stdout, stderr) + if err != nil { + return 1 + } + } + // The entry in /etc/locale.gen is "en_US.UTF-8"; once // it's installed, locale -a reports it as // "en_US.utf8". @@ -278,7 +345,7 @@ rm ${zip} if havelocales, err := exec.Command("locale", "-a").CombinedOutput(); err == nil && bytes.Contains(havelocales, []byte(strings.Replace(wantlocale+"\n", "UTF-", "utf", 1))) { logger.Print("locale " + wantlocale + " already installed") } else { - err = runBash(`sed -i 's/^# *\(`+wantlocale+`\)/\1/' /etc/locale.gen && locale-gen`, stdout, stderr) + err = inst.runBash(`sed -i 's/^# *\(`+wantlocale+`\)/\1/' /etc/locale.gen && locale-gen`, stdout, stderr) if err != nil { return 1 } @@ -357,7 +424,7 @@ rm ${zip} // locales. Otherwise, it might need a // restart, so we attempt to restart it with // systemd. - if err = runBash(`sudo systemctl restart postgresql`, stdout, stderr); err != nil { + if err = inst.runBash(`sudo systemctl restart postgresql`, stdout, stderr); err != nil { logger.Warn("`systemctl restart postgresql` failed; hoping postgresql does not need to be restarted") } else if err = waitPostgreSQLReady(); err != nil { return 1 @@ -392,12 +459,213 @@ rm ${zip} } } + if !prod { + if havenodejsversion, err := exec.Command("/usr/local/bin/node", "--version").CombinedOutput(); err == nil && string(havenodejsversion) == nodejsversion+"\n" { + logger.Print("nodejs " + nodejsversion + " already installed") + } else { + err = inst.runBash(` +NJS=`+nodejsversion+` +wget --progress=dot:giga -O- https://nodejs.org/dist/${NJS}/node-${NJS}-linux-x64.tar.xz | sudo tar -C /var/lib/arvados -xJf - +ln -sfv /var/lib/arvados/node-${NJS}-linux-x64/bin/{node,npm} /usr/local/bin/ +`, stdout, stderr) + if err != nil { + return 1 + } + } + + if haveyarnversion, err := exec.Command("/usr/local/bin/yarn", "--version").CombinedOutput(); err == nil && len(haveyarnversion) > 0 { + logger.Print("yarn " + strings.TrimSpace(string(haveyarnversion)) + " already installed") + } else { + err = inst.runBash(` +npm install -g yarn +ln -sfv /var/lib/arvados/node-`+nodejsversion+`-linux-x64/bin/{yarn,yarnpkg} /usr/local/bin/ +`, stdout, stderr) + if err != nil { + return 1 + } + } + + if havewb2version, err := exec.Command("git", "--git-dir=/var/lib/arvados/arvados-workbench2/.git", "log", "-n1", "--format=%H").CombinedOutput(); err == nil && string(havewb2version) == workbench2version+"\n" { + logger.Print("workbench2 repo is already at " + workbench2version) + } else { + err = inst.runBash(` +V=`+workbench2version+` +cd /var/lib/arvados +if [[ ! -e arvados-workbench2 ]]; then + git clone https://git.arvados.org/arvados-workbench2.git + cd arvados-workbench2 + git checkout $V +else + cd arvados-workbench2 + if ! git checkout $V; then + git fetch + git checkout yarn.lock + git checkout $V + fi +fi +rm -rf build +`, stdout, stderr) + if err != nil { + return 1 + } + } + + if err = inst.runBash(` +cd /var/lib/arvados/arvados-workbench2 +yarn install +`, stdout, stderr); err != nil { + return 1 + } + } + + if prod || pkg { + // Install Go programs to /var/lib/arvados/bin/ + for _, srcdir := range []string{ + "cmd/arvados-client", + "cmd/arvados-server", + "services/crunch-dispatch-local", + "services/crunch-dispatch-slurm", + "services/health", + "services/keep-balance", + "services/keepstore", + "services/ws", + } { + fmt.Fprintf(stderr, "building %s...\n", srcdir) + cmd := exec.Command("go", "install", "-ldflags", "-X git.arvados.org/arvados.git/lib/cmd.version="+inst.PackageVersion+" -X main.version="+inst.PackageVersion+" -s -w") + cmd.Env = append(cmd.Env, os.Environ()...) + cmd.Env = append(cmd.Env, "GOBIN=/var/lib/arvados/bin") + cmd.Dir = filepath.Join(inst.SourcePath, srcdir) + cmd.Stdout = stdout + cmd.Stderr = stderr + err = cmd.Run() + if err != nil { + return 1 + } + } + + // Symlink user-facing Go programs /usr/bin/x -> + // /var/lib/arvados/bin/x + for _, prog := range []string{"arvados-client", "arvados-server"} { + err = os.Remove("/usr/bin/" + prog) + if err != nil && !errors.Is(err, os.ErrNotExist) { + return 1 + } + err = os.Symlink("/var/lib/arvados/bin/"+prog, "/usr/bin/"+prog) + if err != nil { + return 1 + } + } + + // Copy assets from source tree to /var/lib/arvados/share + cmd := exec.Command("install", "-v", "-t", "/var/lib/arvados/share", filepath.Join(inst.SourcePath, "sdk/python/tests/nginx.conf")) + cmd.Stdout = stdout + cmd.Stderr = stderr + err = cmd.Run() + if err != nil { + return 1 + } + + // Install Rails apps to /var/lib/arvados/{railsapi,workbench1}/ + for dstdir, srcdir := range map[string]string{ + "railsapi": "services/api", + "workbench1": "apps/workbench", + } { + fmt.Fprintf(stderr, "building %s...\n", srcdir) + cmd := exec.Command("rsync", + "-a", "--no-owner", "--no-group", "--delete-after", "--delete-excluded", + "--exclude", "/coverage", + "--exclude", "/log", + "--exclude", "/node_modules", + "--exclude", "/tmp", + "--exclude", "/public/assets", + "--exclude", "/vendor", + "--exclude", "/config/environments", + "./", "/var/lib/arvados/"+dstdir+"/") + cmd.Dir = filepath.Join(inst.SourcePath, srcdir) + cmd.Stdout = stdout + cmd.Stderr = stderr + err = cmd.Run() + if err != nil { + return 1 + } + for _, cmdline := range [][]string{ + {"mkdir", "-p", "log", "public/assets", "tmp", "vendor", ".bundle", "/var/www/.bundle", "/var/www/.gem", "/var/www/.npm", "/var/www/.passenger"}, + {"touch", "log/production.log"}, + {"chown", "-R", "--from=root", "www-data:www-data", "/var/www/.bundle", "/var/www/.gem", "/var/www/.npm", "/var/www/.passenger", "log", "tmp", "vendor", ".bundle", "Gemfile.lock", "config.ru", "config/environment.rb"}, + {"sudo", "-u", "www-data", "/var/lib/arvados/bin/gem", "install", "--user", "--conservative", "--no-document", "bundler:" + bundlerversion}, + {"sudo", "-u", "www-data", "/var/lib/arvados/bin/bundle", "install", "--deployment", "--jobs", "8", "--path", "/var/www/.gem", "--without", "development test diagnostics performance"}, + + {"chown", "www-data:www-data", ".", "public/assets"}, + // {"sudo", "-u", "www-data", "/var/lib/arvados/bin/bundle", "config", "set", "--local", "system", "true"}, + {"sudo", "-u", "www-data", "ARVADOS_CONFIG=none", "RAILS_GROUPS=assets", "RAILS_ENV=production", "/var/lib/arvados/bin/bundle", "exec", "rake", "npm:install"}, + {"sudo", "-u", "www-data", "ARVADOS_CONFIG=none", "RAILS_GROUPS=assets", "RAILS_ENV=production", "/var/lib/arvados/bin/bundle", "exec", "rake", "assets:precompile"}, + {"chown", "root:root", "."}, + {"chown", "-R", "root:root", "public/assets", "vendor"}, + + {"sudo", "-u", "www-data", "/var/lib/arvados/bin/bundle", "exec", "passenger-config", "build-native-support"}, + {"sudo", "-u", "www-data", "/var/lib/arvados/bin/bundle", "exec", "passenger-config", "install-standalone-runtime"}, + } { + if cmdline[len(cmdline)-2] == "rake" && dstdir != "workbench1" { + continue + } + cmd = exec.Command(cmdline[0], cmdline[1:]...) + cmd.Dir = "/var/lib/arvados/" + dstdir + cmd.Stdout = stdout + cmd.Stderr = stderr + fmt.Fprintf(stderr, "... %s\n", cmd.Args) + err = cmd.Run() + if err != nil { + return 1 + } + } + cmd = exec.Command("sudo", "-u", "www-data", "/var/lib/arvados/bin/bundle", "exec", "passenger-config", "validate-install") + cmd.Dir = "/var/lib/arvados/" + dstdir + cmd.Stdout = stdout + cmd.Stderr = stderr + err = cmd.Run() + if err != nil && !strings.Contains(err.Error(), "exit status 2") { + // Exit code 2 indicates there were warnings (like + // "other passenger installations have been detected", + // which we can't expect to avoid) but no errors. + // Other non-zero exit codes (1, 9) indicate errors. + return 1 + } + } + + // Install workbench2 app to /var/lib/arvados/workbench2/ + if err = inst.runBash(` +cd /var/lib/arvados/arvados-workbench2 +VERSION="`+inst.PackageVersion+`" BUILD_NUMBER=1 GIT_COMMIT="`+workbench2version[:9]+`" yarn build +rsync -a --delete-after build/ /var/lib/arvados/workbench2/ +`, stdout, stderr); err != nil { + return 1 + } + + err = os.WriteFile("/lib/systemd/system/arvados.service", arvadosServiceFile, 0777) + if err != nil { + return 1 + } + // This is equivalent to "systemd enable", but does + // not depend on the systemctl program being + // available. + symlink := "/etc/systemd/system/multi-user.target.wants/arvados.service" + err = os.Remove(symlink) + if err != nil && !errors.Is(err, os.ErrNotExist) { + return 1 + } + err = os.Symlink("/lib/systemd/system/arvados.service", symlink) + if err != nil { + return 1 + } + } + return 0 } type osversion struct { Debian bool Ubuntu bool + Centos bool Major int } @@ -435,6 +703,8 @@ func identifyOS() (osversion, error) { osv.Ubuntu = true case "debian": osv.Debian = true + case "centos": + osv.Centos = true default: return osv, fmt.Errorf("unsupported ID in /etc/os-release: %q", kv["ID"]) } @@ -462,10 +732,64 @@ func waitPostgreSQLReady() error { } } -func runBash(script string, stdout, stderr io.Writer) error { +func (inst *installCommand) runBash(script string, stdout, stderr io.Writer) error { cmd := exec.Command("bash", "-") + if inst.EatMyData { + cmd = exec.Command("eatmydata", "bash", "-") + } cmd.Stdin = bytes.NewBufferString("set -ex -o pipefail\n" + script) cmd.Stdout = stdout cmd.Stderr = stderr return cmd.Run() } + +func prodpkgs(osv osversion) []string { + pkgs := []string{ + "ca-certificates", + "curl", + "fuse", + "git", + "gitolite3", + "graphviz", + "haveged", + "libcurl3-gnutls", + "libxslt1.1", + "nginx", + "python", + "sudo", + } + if osv.Debian || osv.Ubuntu { + if osv.Debian && osv.Major == 8 { + pkgs = append(pkgs, "libgnutls-deb0-28") // sdk/cwl + } else if osv.Debian && osv.Major >= 10 || osv.Ubuntu && osv.Major >= 16 { + pkgs = append(pkgs, "python3-distutils") // sdk/cwl + } + return append(pkgs, + "g++", + "libcurl4-openssl-dev", // services/api + "libpq-dev", + "libpython2.7", // services/fuse + "mime-support", // keep-web + "zlib1g-dev", // services/api + ) + } else if osv.Centos { + return append(pkgs, + "fuse-libs", // services/fuse + "gcc", + "gcc-c++", + "libcurl-devel", // services/api + "mailcap", // keep-web + "postgresql-devel", // services/api + ) + } else { + panic("os version not supported") + } +} + +func ProductionDependencies() ([]string, error) { + osv, err := identifyOS() + if err != nil { + return nil, err + } + return prodpkgs(osv), nil +}