/
runner.go
169 lines (136 loc) · 3.79 KB
/
runner.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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
package cloud
import (
"context"
"fmt"
"io"
"log"
"os"
"strings"
"time"
"github.com/bramvdbogaerde/go-scp"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
tinycloud "github.com/kucicm/tiny-cloud/pkg"
"golang.org/x/crypto/ssh"
)
// check if docker image exists (do not create any resources if it does not exist)
// save docker image into a "file"
// push docker "file" in vm
// unpack docker image
// start docker container
// wait to finish?
func Run(task tinycloud.TaskDefinition) error {
signer, err := ssh.ParsePrivateKey(task.SSHKey)
if err != nil {
return err
}
cfg := &ssh.ClientConfig{
User: "ec2-user",
Auth: []ssh.AuthMethod{ssh.PublicKeys(signer)},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
url := fmt.Sprintf("%s:22", task.DNSName)
log.Printf("connecting to %s\n", url)
var conn *ssh.Client
for {
if conn, err = ssh.Dial("tcp", url, cfg); err == nil {
break
}
time.Sleep(time.Second)
}
defer conn.Close()
log.Printf("connected to %s\n", url)
client, err := scp.NewClientBySSH(conn)
if err != nil {
return err
}
img, err := GetDockerImage(task.DockerImageId)
if err != nil {
return err
}
defer img.Close()
imageName := fmt.Sprintf("tiny-cloud-docker-image-%s", task.DockerImageId)
log.Printf("pushing docker image %s\n", imageName)
err = client.CopyFilePassThru(
context.Background(),
img,
imageName,
"0655",
func(r io.Reader, total int64) io.Reader { return r })
if err != nil {
return err
}
client.Close()
log.Printf("pushed docker image %s\n", imageName)
script := "sudo yum install docker -y\n"
script += "sudo systemctl start docker\n"
script += "sudo usermod -a -G docker ec2-user\n"
script += fmt.Sprintf("sudo docker load --input %s\n", imageName)
script += fmt.Sprintf("sudo docker run --name tiny-cloud-container %s\n", task.DockerImageId)
script += "mkdir tiny_data\n"
script += "echo 'copy from docker to host...'\n"
script += fmt.Sprintf("sudo docker cp tiny-cloud-container:%s tiny_data/\n", task.DataOutPath)
script += "echo 'gzip...'\n"
script += "tar -czvf tiny_data.tar.gz tiny_data\n"
script += "echo 'copy to s3...'\n"
s3_path := fmt.Sprintf(`s3://%s/tiny_data_$(date +'%%Y%%m%%d%%H%%M%%S').tar.gz`, task.BucketName)
script += fmt.Sprintf(`aws s3 cp tiny_data.tar.gz "%s"`, s3_path)
script += "\necho 'all done'\nexit\n"
log.Printf("running script:\n %s\n", script)
// run docker image on vm
log.Println("create session")
session, err := conn.NewSession()
if err != nil {
return err
}
defer session.Close()
session.Stdout = os.Stdout
session.Stderr = os.Stderr
stdin, err := session.StdinPipe()
if err != nil {
return err
}
defer stdin.Close()
if err := session.Shell(); err != nil {
return err
}
log.Println("running script")
stdin.Write([]byte(script))
session.Wait()
return nil
}
func GetDockerImage(imageId string) (io.ReadCloser, error) {
if err := os.Setenv(client.EnvOverrideAPIVersion, "1.41"); err != nil {
return nil, err
}
cli, err := client.NewClientWithOpts(client.FromEnv)
if err != nil {
return nil, err
}
reader, err := cli.ImageSave(context.Background(), []string{imageId})
if err != nil {
return nil, err
}
return reader, nil
}
func DoseDockerImageExists(imageId string) (bool, error) {
if err := os.Setenv(client.EnvOverrideAPIVersion, "1.41"); err != nil {
return false, err
}
cli, err := client.NewClientWithOpts(client.FromEnv)
if err != nil {
return false, err
}
// todo add filter for imageId
images, err := cli.ImageList(context.TODO(), types.ImageListOptions{})
if err != nil {
return false, err
}
for _, img := range images {
id := strings.Split(img.ID, ":")[1]
if strings.HasPrefix(id, imageId) {
return true, nil
}
}
return false, nil
}