15370: Fix unspecified docker API version requirement.
[arvados.git] / cmd / arvados-package / install.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 package main
6
7 import (
8         "context"
9         "fmt"
10         "io"
11         "io/ioutil"
12         "os"
13         "os/exec"
14         "path/filepath"
15         "strings"
16
17         "github.com/docker/docker/api/types"
18         "github.com/docker/docker/client"
19 )
20
21 func testinstall(ctx context.Context, opts opts, stdin io.Reader, stdout, stderr io.Writer) error {
22         depsImageName := "arvados-package-deps-" + opts.TargetOS
23         depsCtrName := strings.Replace(depsImageName, ":", "-", -1)
24         absPackageDir, err := filepath.Abs(opts.PackageDir)
25         if err != nil {
26                 return fmt.Errorf("error resolving PackageDir %q: %w", opts.PackageDir, err)
27         }
28
29         _, prog := filepath.Split(os.Args[0])
30         tmpdir, err := ioutil.TempDir("", prog+".")
31         if err != nil {
32                 return fmt.Errorf("TempDir: %w", err)
33         }
34         defer os.RemoveAll(tmpdir)
35
36         if exists, err := dockerImageExists(ctx, depsImageName); err != nil {
37                 return err
38         } else if !exists || opts.RebuildImage {
39                 err = dockerRm(ctx, depsCtrName)
40                 if err != nil {
41                         return err
42                 }
43                 defer dockerRm(ctx, depsCtrName)
44                 cmd := exec.CommandContext(ctx, "docker", "run",
45                         "--name", depsCtrName,
46                         "--tmpfs", "/tmp:exec,mode=01777",
47                         "-v", absPackageDir+":/pkg:ro",
48                         "--env", "DEBIAN_FRONTEND=noninteractive",
49                         opts.TargetOS,
50                         "bash", "-c", `
51 set -e -o pipefail
52 apt-get --allow-releaseinfo-change update
53 apt-get install -y --no-install-recommends dpkg-dev eatmydata
54
55 mkdir /tmp/pkg
56 ln -s /pkg/*.deb /tmp/pkg/
57 (cd /tmp/pkg; dpkg-scanpackages --multiversion . | gzip > Packages.gz)
58 echo >/etc/apt/sources.list.d/arvados-local.list "deb [trusted=yes] file:///tmp/pkg ./"
59 apt-get --allow-releaseinfo-change update
60
61 eatmydata apt-get install -y --no-install-recommends arvados-server-easy postgresql
62 eatmydata apt-get remove -y dpkg-dev
63 SUDO_FORCE_REMOVE=yes apt-get autoremove -y
64 eatmydata apt-get remove -y arvados-server-easy
65 rm /etc/apt/sources.list.d/arvados-local.list
66 `)
67                 cmd.Stdout = stdout
68                 cmd.Stderr = stderr
69                 err = cmd.Run()
70                 if err != nil {
71                         return fmt.Errorf("%v: %w", cmd.Args, err)
72                 }
73
74                 cmd = exec.CommandContext(ctx, "docker", "commit", depsCtrName, depsImageName)
75                 cmd.Stdout = stdout
76                 cmd.Stderr = stderr
77                 err = cmd.Run()
78                 if err != nil {
79                         return fmt.Errorf("%v: %w", cmd.Args, err)
80                 }
81         }
82
83         versionsuffix := ""
84         if opts.PackageVersion != "" {
85                 versionsuffix = "=" + opts.PackageVersion
86         }
87         cmd := exec.CommandContext(ctx, "docker", "run", "--rm",
88                 "--tmpfs=/tmp:exec,mode=01777",
89                 "--volume="+absPackageDir+":/pkg:ro",
90                 "--env=DEBIAN_FRONTEND=noninteractive")
91         if opts.Live != "" {
92                 cmd.Args = append(cmd.Args,
93                         "--env=domain="+opts.Live,
94                         "--env=bootargs=",
95                         "--publish=:443:443",
96                         "--publish=:4440-4460:4440-4460",
97                         "--publish=:9000-9020:9000-9020",
98                         "--add-host="+opts.Live+":0.0.0.0",
99                         "--volume=/var/lib/acme:/var/lib/acme:ro")
100         } else {
101                 cmd.Args = append(cmd.Args,
102                         "--env=domain=localhost",
103                         "--env=bootargs=-shutdown")
104         }
105         cmd.Args = append(cmd.Args,
106                 depsImageName,
107                 "bash", "-c", `
108 set -e -o pipefail
109 PATH="/var/lib/arvados/bin:$PATH"
110 apt-get --allow-releaseinfo-change update
111 apt-get install -y --no-install-recommends dpkg-dev
112 mkdir /tmp/pkg
113 ln -s /pkg/*.deb /tmp/pkg/
114 (cd /tmp/pkg; dpkg-scanpackages --multiversion . | gzip > Packages.gz)
115 apt-get remove -y dpkg-dev
116 echo
117
118 echo >/etc/apt/sources.list.d/arvados-local.list "deb [trusted=yes] file:///tmp/pkg ./"
119 apt-get --allow-releaseinfo-change update
120 eatmydata apt-get install --reinstall -y --no-install-recommends arvados-server-easy`+versionsuffix+`
121 SUDO_FORCE_REMOVE=yes apt-get autoremove -y
122
123 /etc/init.d/postgresql start
124 arvados-server init -cluster-id x1234 -domain=$domain -login=test -insecure
125 exec arvados-server boot -listen-host=0.0.0.0 -no-workbench2=false $bootargs
126 `)
127         cmd.Stdout = stdout
128         cmd.Stderr = stderr
129         err = cmd.Run()
130         if err != nil {
131                 return fmt.Errorf("%v: %w", cmd.Args, err)
132         }
133         return nil
134 }
135
136 func dockerImageExists(ctx context.Context, name string) (bool, error) {
137         cli, err := client.NewClient(client.DefaultDockerHost, "1.21", nil, nil)
138         if err != nil {
139                 return false, err
140         }
141         imgs, err := cli.ImageList(ctx, types.ImageListOptions{All: true})
142         if err != nil {
143                 return false, err
144         }
145         for _, img := range imgs {
146                 for _, tag := range img.RepoTags {
147                         if tag == name {
148                                 return true, nil
149                         }
150                 }
151         }
152         return false, nil
153 }