moving HostConfig into the ThinContainerExecRunner interface
[arvados.git] / lib / crunchrun / docker_adapter.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 package crunchrun
6
7 import (
8         "io"
9
10         dockertypes "github.com/docker/docker/api/types"
11         dockercontainer "github.com/docker/docker/api/types/container"
12         dockernetwork "github.com/docker/docker/api/types/network"
13         "golang.org/x/net/context"
14 )
15
16 type DockerAdapter struct {
17         docker          ThinDockerClient
18         containerConfig ContainerConfig
19         hostConfig      dockercontainer.HostConfig
20 }
21
22 func (a *DockerAdapter) ContainerAttach(ctx context.Context, container string, options ContainerAttachOptions) (HijackedResponse, error) {
23         dockerOptions := dockertypes.ContainerAttachOptions{
24                 Stream: options.Stream,
25                 Stdin:  options.Stdin,
26                 Stdout: options.Stdout,
27                 Stderr: options.Stderr}
28         dockerResponse, docker_err := a.docker.ContainerAttach(ctx, container, dockerOptions)
29
30         adapterResponse := HijackedResponse{
31                 Conn:   dockerResponse.Conn,
32                 Reader: dockerResponse.Reader,
33         }
34
35         return adapterResponse, docker_err
36 }
37
38 func (a *DockerAdapter) ContainerCreate(ctx context.Context, config ContainerConfig, hostConfig HostConfig, networkingConfig *NetworkingConfig, containerName string) (ContainerCreateResponse, error) {
39         var dockerEndpointsConfig map[string]*dockernetwork.EndpointSettings
40
41         var dockerNetworkConfig *dockernetwork.NetworkingConfig
42         if networkingConfig != nil {
43                 for k, v := range networkingConfig.EndpointsConfig {
44
45                         dockerIpamConfig := &dockernetwork.EndpointIPAMConfig{
46                                 IPv4Address:  v.IPAMConfig.IPv4Address,
47                                 IPv6Address:  v.IPAMConfig.IPv6Address,
48                                 LinkLocalIPs: v.IPAMConfig.LinkLocalIPs,
49                         }
50                         dockerEndpointsConfig[k] = &dockernetwork.EndpointSettings{
51                                 IPAMConfig:          dockerIpamConfig,
52                                 Links:               v.Links,
53                                 Aliases:             v.Aliases,
54                                 NetworkID:           v.NetworkID,
55                                 EndpointID:          v.EndpointID,
56                                 Gateway:             v.Gateway,
57                                 IPAddress:           v.IPAddress,
58                                 IPPrefixLen:         v.IPPrefixLen,
59                                 IPv6Gateway:         v.IPv6Gateway,
60                                 GlobalIPv6Address:   v.GlobalIPv6Address,
61                                 GlobalIPv6PrefixLen: v.GlobalIPv6PrefixLen,
62                                 MacAddress:          v.MacAddress,
63                                 DriverOpts:          v.DriverOpts,
64                         }
65
66                 }
67
68                 dockerNetworkConfig = &dockernetwork.NetworkingConfig{
69                         EndpointsConfig: dockerEndpointsConfig,
70                 }
71         }
72         dockerConfig := dockercontainer.Config{
73                 OpenStdin:    config.OpenStdin,
74                 StdinOnce:    config.StdinOnce,
75                 AttachStdin:  config.AttachStdin,
76                 AttachStdout: config.AttachStdout,
77                 AttachStderr: config.AttachStderr,
78                 Cmd:          config.Cmd,
79                 WorkingDir:   config.WorkingDir,
80                 Env:          config.Env,
81                 Volumes:      config.Volumes,
82         }
83         dockerHostConfig := dockercontainer.HostConfig{}
84
85         dockerResponse, dockerErr := a.docker.ContainerCreate(ctx,
86                 &dockerConfig,
87                 &dockerHostConfig, dockerNetworkConfig, containerName)
88         adapterResponse := ContainerCreateResponse{
89                 ID:       dockerResponse.ID,
90                 Warnings: dockerResponse.Warnings,
91         }
92         return adapterResponse, dockerErr
93 }
94
95 func (a *DockerAdapter) ContainerStart(ctx context.Context, container string, options ContainerStartOptions) error {
96         dockerContainerStartOptions := dockertypes.ContainerStartOptions{
97                 CheckpointID:  options.CheckpointID,
98                 CheckpointDir: options.CheckpointDir,
99         }
100
101         dockerErr := a.docker.ContainerStart(ctx, container, dockerContainerStartOptions)
102
103         return dockerErr
104 }
105
106 func (a *DockerAdapter) ContainerRemove(ctx context.Context, container string, options ContainerRemoveOptions) error {
107         dockerContainerRemoveOptions := dockertypes.ContainerRemoveOptions{Force: options.Force}
108
109         dockerErr := a.docker.ContainerRemove(ctx, container, dockerContainerRemoveOptions)
110
111         return dockerErr
112 }
113
114 func (a *DockerAdapter) ContainerInspect(ctx context.Context, id string) (ContainerInspectResponse, error) {
115
116         dockerContainerInspectResponse, dockerErr := a.docker.ContainerInspect(ctx, id)
117
118         containerState := &ContainerState{
119                 Running:    dockerContainerInspectResponse.State.Running,
120                 Paused:     dockerContainerInspectResponse.State.Paused,
121                 Restarting: dockerContainerInspectResponse.State.Restarting,
122                 OOMKilled:  dockerContainerInspectResponse.State.OOMKilled,
123                 Dead:       dockerContainerInspectResponse.State.Dead,
124                 Pid:        dockerContainerInspectResponse.State.Pid,
125                 ExitCode:   dockerContainerInspectResponse.State.ExitCode,
126                 Error:      dockerContainerInspectResponse.State.Error,
127                 StartedAt:  dockerContainerInspectResponse.State.StartedAt,
128                 FinishedAt: dockerContainerInspectResponse.State.FinishedAt,
129         }
130
131         adapterResponse := &ContainerInspectResponse{State: containerState}
132
133         return *adapterResponse, dockerErr
134 }
135
136 func (a *DockerAdapter) ContainerWait(ctx context.Context, container string, condition WaitCondition) (<-chan ContainerWaitOKBody, <-chan error) {
137
138         //var dockercontainerCondition dockercontainer.WaitCondition =
139         dockercontainerCondition := dockercontainer.WaitCondition(condition)
140
141         dockerContainerWaitOKBody, dockerErr := a.docker.ContainerWait(ctx, container, dockercontainerCondition)
142
143         // translate from <-chan dockercontainer.ContainerWaitOKBody to <-chan ContainerWaitOKBody,
144         adapterContainerWaitOKBody := make(chan ContainerWaitOKBody)
145         go func() {
146                 for dockerMsg := range dockerContainerWaitOKBody {
147                         var adapterBodyMsg *ContainerWaitOKBody
148                         var adapterError *ContainerWaitOKBodyError
149
150                         if dockerMsg.Error != nil {
151                                 adapterError = &ContainerWaitOKBodyError{
152                                         Message: dockerMsg.Error.Message,
153                                 }
154                         }
155
156                         adapterBodyMsg = &ContainerWaitOKBody{
157                                 Error:      adapterError,
158                                 StatusCode: dockerMsg.StatusCode,
159                         }
160
161                         adapterContainerWaitOKBody <- *adapterBodyMsg
162                 }
163         }()
164
165         return adapterContainerWaitOKBody, dockerErr
166 }
167
168 func (a *DockerAdapter) ImageInspectWithRaw(ctx context.Context, image string) (ImageInspectResponse, []byte, error) {
169         dockerImageInspectResponse, rawBytes, dockerErr := a.docker.ImageInspectWithRaw(ctx, image)
170
171         adapterImageInspectResponse := &ImageInspectResponse{
172                 ID: dockerImageInspectResponse.ID,
173         }
174         return *adapterImageInspectResponse, rawBytes, dockerErr
175 }
176
177 func (a *DockerAdapter) ImageLoad(ctx context.Context, input io.Reader, quiet bool) (ImageLoadResponse, error) {
178         dockerImageLoadResponse, dockerErr := a.docker.ImageLoad(ctx, input, quiet)
179
180         adapterImageLoadResponse := &ImageLoadResponse{
181                 Body: dockerImageLoadResponse.Body,
182                 JSON: dockerImageLoadResponse.JSON,
183         }
184
185         return *adapterImageLoadResponse, dockerErr
186 }
187
188 func (a *DockerAdapter) ImageRemove(ctx context.Context, image string, options ImageRemoveOptions) ([]ImageDeleteResponseItem, error) {
189
190         dockerOptions := &dockertypes.ImageRemoveOptions{
191                 Force:         options.Force,
192                 PruneChildren: options.PruneChildren,
193         }
194         dockerImageDeleteResponseItems, dockerErr := a.docker.ImageRemove(ctx, image, *dockerOptions)
195
196         var adapterResponses []ImageDeleteResponseItem
197         for _, dockerResponse := range dockerImageDeleteResponseItems {
198                 adapterResponse := &ImageDeleteResponseItem{
199                         Deleted:  dockerResponse.Deleted,
200                         Untagged: dockerResponse.Untagged,
201                 }
202                 adapterResponses = append(adapterResponses, *adapterResponse)
203         }
204         return adapterResponses, dockerErr
205 }
206
207 func (a *DockerAdapter) GetContainerConfig() (ContainerConfig, error) {
208         return a.containerConfig, nil
209 }
210
211 func (a *DockerAdapter) GetHostConfig() (HostConfig, error) {
212         adapterHostConfig := HostConfig{
213                 Binds: a.hostConfig.Binds,
214                 LogConfig: LogConfig{
215                         Type: a.hostConfig.LogConfig.Type,
216                 },
217                 Resources: Resources{
218                         CgroupParent: a.hostConfig.CgroupParent,
219                         NanoCPUs:     a.hostConfig.NanoCPUs,
220                         Memory:       a.hostConfig.Memory,
221                         MemorySwap:   a.hostConfig.MemorySwap,
222                         KernelMemory: a.hostConfig.KernelMemory,
223                 },
224         }
225         return adapterHostConfig, nil
226 }
227
228 func (a *DockerAdapter) SetHostConfig(adapterHostConfig HostConfig) error {
229         dockerHostConfig := dockercontainer.HostConfig{
230                 Binds: adapterHostConfig.Binds,
231                 LogConfig: dockercontainer.LogConfig{
232                         Type: adapterHostConfig.LogConfig.Type,
233                 },
234                 Resources: dockercontainer.Resources{
235                         CgroupParent: adapterHostConfig.CgroupParent,
236                         NanoCPUs:     adapterHostConfig.NanoCPUs,
237                         Memory:       adapterHostConfig.Memory,
238                         MemorySwap:   adapterHostConfig.MemorySwap,
239                         KernelMemory: adapterHostConfig.KernelMemory,
240                 },
241         }
242         a.hostConfig = dockerHostConfig
243         return nil
244 }
245
246 func (a *DockerAdapter) GetImage() (imageID string) {
247         return a.containerConfig.Image
248 }
249
250 func (a *DockerAdapter) SetImage(imageID string) {
251         a.containerConfig.Image = imageID
252 }
253 func (a *DockerAdapter) GetNetworkMode() (networkMode NetworkMode) {
254         return NetworkMode(a.hostConfig.NetworkMode)
255 }
256
257 func (a *DockerAdapter) SetNetworkMode(networkMode NetworkMode) {
258         a.hostConfig.NetworkMode = dockercontainer.NetworkMode(networkMode)
259 }
260
261 func adapter(docker ThinDockerClient) ThinContainerExecRunner {
262         return_object := &DockerAdapter{docker: docker}
263
264         return return_object
265 }