774771efb07b8aba70cd32a8b6c0b6c1165125ab
[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         "errors"
10         "fmt"
11         "io"
12         "io/ioutil"
13         "os"
14         "os/exec"
15         "path/filepath"
16         "strings"
17
18         "github.com/docker/docker/api/types"
19         "github.com/docker/docker/client"
20 )
21
22 func testinstall(ctx context.Context, opts opts, stdin io.Reader, stdout, stderr io.Writer) error {
23         if opts.PackageVersion != "" {
24                 return errors.New("not implemented: package version was specified, but I only know how to test the latest version in pkgdir")
25         }
26         depsImageName := "arvados-package-deps-" + opts.TargetOS
27         depsCtrName := strings.Replace(depsImageName, ":", "-", -1)
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         sourcesFile := tmpdir + "/arvados-local.list"
37         err = ioutil.WriteFile(sourcesFile, []byte("deb [trusted=yes] file:///pkg ./\n"), 0644)
38         if err != nil {
39                 return fmt.Errorf("Write %s: %w", sourcesFile, err)
40         }
41
42         if exists, err := dockerImageExists(ctx, depsImageName); err != nil {
43                 return err
44         } else if !exists || opts.RebuildImage {
45                 err = dockerRm(ctx, depsCtrName)
46                 if err != nil {
47                         return err
48                 }
49                 defer dockerRm(ctx, depsCtrName)
50                 cmd := exec.CommandContext(ctx, "docker", "run",
51                         "--name", depsCtrName,
52                         "--tmpfs", "/tmp:exec,mode=01777",
53                         "-v", opts.PackageDir+":/pkg:ro",
54                         "-v", sourcesFile+":/etc/apt/sources.list.d/arvados-local.list:ro",
55                         "--env", "DEBIAN_FRONTEND=noninteractive",
56                         opts.TargetOS,
57                         "bash", "-c", `
58 set -e
59 apt-get update
60 apt-get install -y eatmydata
61 eatmydata apt-get install -y --no-install-recommends arvados-server-easy postgresql
62 eatmydata apt-get remove -y arvados-server-easy
63 `)
64                 cmd.Stdout = stdout
65                 cmd.Stderr = stderr
66                 err = cmd.Run()
67                 if err != nil {
68                         return fmt.Errorf("docker run: %w", err)
69                 }
70
71                 cmd = exec.CommandContext(ctx, "docker", "commit", depsCtrName, depsImageName)
72                 cmd.Stdout = stdout
73                 cmd.Stderr = stderr
74                 err = cmd.Run()
75                 if err != nil {
76                         return fmt.Errorf("docker commit: %w", err)
77                 }
78         }
79
80         cmd := exec.CommandContext(ctx, "docker", "run", "--rm",
81                 "--tmpfs", "/tmp:exec,mode=01777",
82                 "-v", opts.PackageDir+":/pkg:ro",
83                 "-v", sourcesFile+":/etc/apt/sources.list.d/arvados-local.list:ro",
84                 "--env", "DEBIAN_FRONTEND=noninteractive",
85                 depsImageName,
86                 "bash", "-c", `
87 set -e
88 PATH="/var/lib/arvados/bin:$PATH"
89 apt-get update
90 eatmydata apt-get install --reinstall -y --no-install-recommends arvados-server-easy
91 apt-get -y autoremove
92 /etc/init.d/postgresql start
93 arvados-server init -cluster-id x1234
94 exec arvados-server boot -listen-host 0.0.0.0 -shutdown
95 `)
96         cmd.Stdout = stdout
97         cmd.Stderr = stderr
98         err = cmd.Run()
99         if err != nil {
100                 return fmt.Errorf("docker run: %w", err)
101         }
102         return nil
103 }
104
105 func dockerImageExists(ctx context.Context, name string) (bool, error) {
106         cli, err := client.NewEnvClient()
107         if err != nil {
108                 return false, err
109         }
110         imgs, err := cli.ImageList(ctx, types.ImageListOptions{All: true})
111         if err != nil {
112                 return false, err
113         }
114         for _, img := range imgs {
115                 for _, tag := range img.RepoTags {
116                         if tag == name {
117                                 return true, nil
118                         }
119                 }
120         }
121         return false, nil
122 }