forked from yuuki/droot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
pull.go
98 lines (84 loc) · 2.79 KB
/
pull.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package commands
import (
"errors"
"fmt"
"io/ioutil"
"net/url"
"os"
"github.com/codegangsta/cli"
"github.com/yuuki1/droot/archive"
"github.com/yuuki1/droot/aws"
"github.com/yuuki1/droot/log"
"github.com/yuuki1/droot/osutil"
)
var CommandArgPull = "--dest DESTINATION_DIRECTORY --src S3_ENDPOINT [--user USER] [--grpup GROUP]"
var CommandPull = cli.Command{
Name: "pull",
Usage: "Pull an extracted docker image from s3",
Action: fatalOnError(doPull),
Flags: []cli.Flag{
cli.StringFlag{Name: "dest, d", Usage: "Local filesystem path (ex. /var/containers/app)"},
cli.StringFlag{Name: "src, s", Usage: "Amazon S3 endpoint (ex. s3://drootexample/app.tar.gz)"},
cli.StringFlag{Name: "user, u", Usage: "User (ID or name) to set after extracting archive (required superuser)"},
cli.StringFlag{Name: "group, g", Usage: "Group (ID or name) to set after extracting archive (required superuser)"},
},
}
func doPull(c *cli.Context) error {
destDir := c.String("dest")
srcURL := c.String("src")
if destDir == "" || srcURL == "" {
cli.ShowCommandHelp(c, "pull")
return errors.New("--src and --dest option required ")
}
s3URL, err := url.Parse(srcURL)
if err != nil {
return err
}
if s3URL.Scheme != "s3" {
return fmt.Errorf("Not s3 scheme %s", srcURL)
}
uid, gid := os.Getuid(), os.Getgid()
if group := c.String("group"); group != "" {
if gid, err = osutil.LookupGroup(group); err != nil {
return fmt.Errorf("Failed to lookup group:", err)
}
}
if user := c.String("user"); user != "" {
if uid, err = osutil.LookupUser(user); err != nil {
return fmt.Errorf("Failed to lookup user:", err)
}
}
tmp, err := ioutil.TempFile(os.TempDir(), "droot_gzip")
if err != nil {
return fmt.Errorf("Failed to create temporary file: %s", err)
}
defer func(f *os.File) {
f.Close()
os.Remove(f.Name())
}(tmp)
nBytes, err := aws.NewS3Client().Download(s3URL, tmp)
if err != nil {
return fmt.Errorf("Failed to download file(%s) from s3: %s", srcURL, err)
}
log.Info("downloaded", "from", s3URL, "to", tmp.Name(), nBytes, "bytes")
rawDir, err := ioutil.TempDir(os.TempDir(), "droot_raw")
if err != nil {
return fmt.Errorf("Failed to create temporary dir: %s", err)
}
defer os.RemoveAll(rawDir)
log.Info("Extract archive:", tmp.Name(), "to", rawDir)
if err := archive.ExtractTarGz(tmp, rawDir, uid, gid); err != nil {
return fmt.Errorf("Failed to extract archive: %s", err)
}
log.Info("Sync:", "from", rawDir, "to", destDir)
if err := archive.Rsync(rawDir, destDir); err != nil {
return fmt.Errorf("Failed to rsync: %s", err)
}
if err := os.Lchown(destDir, uid, gid); err != nil {
return fmt.Errorf("Failed to chown %d:%d: %s", uid, gid, err)
}
if err := os.Chmod(destDir, os.FileMode(0755)); err != nil {
return fmt.Errorf("Failed to chmod %s: %s", destDir, err)
}
return nil
}