Apache Mesos
docker.hpp
Go to the documentation of this file.
1 // Licensed to the Apache Software Foundation (ASF) under one
2 // or more contributor license agreements. See the NOTICE file
3 // distributed with this work for additional information
4 // regarding copyright ownership. The ASF licenses this file
5 // to you under the Apache License, Version 2.0 (the
6 // "License"); you may not use this file except in compliance
7 // with the License. You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 
17 #ifndef __DOCKER_HPP__
18 #define __DOCKER_HPP__
19 
20 #include <map>
21 #include <mutex>
22 #include <string>
23 #include <utility>
24 #include <vector>
25 
26 #include <process/future.hpp>
27 #include <process/owned.hpp>
28 #include <process/subprocess.hpp>
29 
30 #include <stout/duration.hpp>
31 #include <stout/json.hpp>
32 #include <stout/none.hpp>
33 #include <stout/nothing.hpp>
34 #include <stout/option.hpp>
35 #include <stout/path.hpp>
36 #include <stout/version.hpp>
37 
38 #include <stout/os/rm.hpp>
39 
40 #include "mesos/resources.hpp"
41 
42 #include "messages/flags.hpp"
43 
44 // OS-specific default prefix to be used for the DOCKER_HOST environment
45 // variable. Note that on Linux, the default prefix is the only prefix
46 // available; only Windows supports multiple prefixes.
47 // TODO(hausdorff): Add support for the Windows `tcp://` prefix as well.
48 #ifdef __WINDOWS__
49 constexpr char DEFAULT_DOCKER_HOST_PREFIX[] = "npipe://";
50 #else
51 constexpr char DEFAULT_DOCKER_HOST_PREFIX[] = "unix://";
52 #endif // __WINDOWS__
53 
54 // Abstraction for working with Docker (modeled on CLI).
55 //
56 // TODO(benh): Make futures returned by functions be discardable.
57 class Docker
58 {
59 public:
60  // Create Docker abstraction and optionally validate docker.
62  const std::string& path,
63  const std::string& socket,
64  bool validate = true,
65  const Option<JSON::Object>& config = None());
66 
67  virtual ~Docker() {}
68 
69  struct Device
70  {
73 
74  struct Access
75  {
76  Access() : read(false), write(false), mknod(false) {}
77 
78  bool read;
79  bool write;
80  bool mknod;
81  } access;
82  };
83 
84  struct PortMapping
85  {
86  uint32_t hostPort;
87  uint32_t containerPort;
89  };
90 
91  class Container
92  {
93  public:
94  static Try<Container> create(
95  const std::string& output);
96 
97  // Returns the docker inspect output.
98  const std::string output;
99 
100  // Returns the ID of the container.
101  const std::string id;
102 
103  // Returns the name of the container.
104  const std::string name;
105 
106  // Returns the pid of the container, or None if the container is
107  // not running.
109 
110  // Returns if the container has already started. This field is
111  // needed since pid is empty when the container terminates.
112  const bool started;
113 
114  // Returns the IPv4 address of the container, or `None()` if no
115  // IPv4 address has been assigned.
117 
118  // Returns the IPv6 address of the container, or `None()` if no
119  // IPv6 address has been assigned.
121 
122  const std::vector<Device> devices;
123 
124  // Returns the DNS nameservers set by "--dns" option.
125  const std::vector<std::string> dns;
126 
127  // Returns the DNS options set by "--dns-option" option.
128  const std::vector<std::string> dnsOptions;
129 
130  // Returns the DNS search domains set by "--dns-search" option.
131  const std::vector<std::string> dnsSearch;
132 
133  private:
134  Container(
135  const std::string& _output,
136  const std::string& _id,
137  const std::string& _name,
138  const Option<pid_t>& _pid,
139  bool _started,
140  const Option<std::string>& _ipAddress,
141  const Option<std::string>& _ip6Address,
142  const std::vector<Device>& _devices,
143  const std::vector<std::string>& _dns,
144  const std::vector<std::string>& _dnsOptions,
145  const std::vector<std::string>& _dnsSearch)
146  : output(_output),
147  id(_id),
148  name(_name),
149  pid(_pid),
150  started(_started),
151  ipAddress(_ipAddress),
152  ip6Address(_ip6Address),
153  devices(_devices),
154  dns(_dns),
155  dnsOptions(_dnsOptions),
156  dnsSearch(_dnsSearch) {}
157  };
158 
159  class Image
160  {
161  public:
162  static Try<Image> create(const JSON::Object& json);
163 
165 
167 
168  private:
169  Image(const Option<std::vector<std::string>>& _entrypoint,
170  const Option<std::map<std::string, std::string>>& _environment)
171  : entrypoint(_entrypoint),
172  environment(_environment) {}
173  };
174 
175  // See https://docs.docker.com/engine/reference/run for a complete
176  // explanation of each option.
178  {
179  public:
180  static Try<RunOptions> create(
181  const mesos::ContainerInfo& containerInfo,
182  const mesos::CommandInfo& commandInfo,
183  const std::string& containerName,
184  const std::string& sandboxDirectory,
185  const std::string& mappedDirectory,
186  const Option<mesos::Resources>& resources = None(),
187  bool enableCfsQuota = false,
188  const Option<std::map<std::string, std::string>>& env = None(),
189  const Option<std::vector<Device>>& devices = None(),
190  const Option<mesos::internal::ContainerDNSInfo>& defaultContainerDNS = None()); // NOLINT(whitespace/line_length)
191 
192  // "--privileged" option.
194 
195  // "--cpu-shares" option.
197 
198  // "--cpu-quota" option.
200 
201  // "--memory" option.
203 
204  // Environment variable overrides. These overrides will be passed
205  // to docker container through "--env-file" option.
206  std::map<std::string, std::string> env;
207 
208  // "--volume" option.
209  std::vector<std::string> volumes;
210 
211  // "--volume-driver" option.
213 
214  // "--network" option.
216 
217  // "--hostname" option.
219 
220  // "--dns" option.
221  std::vector<std::string> dns;
222 
223  // "--dns-search" option.
224  std::vector<std::string> dnsSearch;
225 
226  // "--dns-opt" option.
227  std::vector<std::string> dnsOpt;
228 
229  // Port mappings for "-p" option.
230  std::vector<PortMapping> portMappings;
231 
232  // "--device" option.
233  std::vector<Device> devices;
234 
235  // "--entrypoint" option.
237 
238  // "--name" option.
240 
241  // Additional docker options passed through containerizer.
242  std::vector<std::string> additionalOptions;
243 
244  // "IMAGE[:TAG|@DIGEST]" part of docker run.
245  std::string image;
246 
247  // Arguments for docker run.
248  std::vector<std::string> arguments;
249  };
250 
251  // Performs 'docker run IMAGE'. Returns the exit status of the
252  // container. Note that currently the exit status may correspond
253  // to the exit code from a failure of the docker client or daemon
254  // rather than the container. Docker >= 1.10 [1] uses the following
255  // exit statuses inherited from 'chroot':
256  // 125 if the error is with Docker daemon itself.
257  // 126 if the contained command cannot be invoked.
258  // 127 if the contained command cannot be found.
259  // Exit code of contained command otherwise.
260  //
261  // [1]: https://github.com/docker/docker/pull/14012
263  const RunOptions& options,
264  const process::Subprocess::IO& _stdout =
266  const process::Subprocess::IO& _stderr =
268 
269  // Returns the current docker version.
270  virtual process::Future<Version> version() const;
271 
272  // Performs 'docker stop -t TIMEOUT CONTAINER'. If remove is true then a rm -f
273  // will be called when stop failed, otherwise a failure is returned. The
274  // timeout parameter will be passed through to docker and is the amount of
275  // time for docker to wait after stopping a container before killing it.
276  // A value of zero (the default value) is the same as issuing a
277  // 'docker kill CONTAINER'.
279  const std::string& containerName,
280  const Duration& timeout = Seconds(0),
281  bool remove = false) const;
282 
283  // Performs 'docker kill --signal=<signal> CONTAINER'.
285  const std::string& containerName,
286  int signal) const;
287 
288  // Performs 'docker rm (-f) CONTAINER'.
290  const std::string& containerName,
291  bool force = false) const;
292 
293  // Performs 'docker inspect CONTAINER'. If retryInterval is set,
294  // we will keep retrying inspect until the container is started or
295  // the future is discarded.
297  const std::string& containerName,
298  const Option<Duration>& retryInterval = None()) const;
299 
300  // Performs 'docker ps (-a)'.
302  bool all = false,
303  const Option<std::string>& prefix = None()) const;
304 
306  const std::string& directory,
307  const std::string& image,
308  bool force = false) const;
309 
310  // Validate current docker version is not less than minVersion.
311  virtual Try<Nothing> validateVersion(const Version& minVersion) const;
312 
313  virtual std::string getPath()
314  {
315  return path;
316  }
317 
318  virtual std::string getSocket()
319  {
320  return socket;
321  }
322 
323 protected:
324  // Uses the specified path to the Docker CLI tool.
325  Docker(const std::string& _path,
326  const std::string& _socket,
327  const Option<JSON::Object>& _config)
328  : path(_path),
329  socket(DEFAULT_DOCKER_HOST_PREFIX + _socket),
330  config(_config) {}
331 
332 private:
333  static process::Future<Version> _version(
334  const std::string& cmd,
335  const process::Subprocess& s);
336 
337  static process::Future<Version> __version(
338  const process::Future<std::string>& output);
339 
340  static process::Future<Nothing> _stop(
341  const Docker& docker,
342  const std::string& containerName,
343  const std::string& cmd,
344  const process::Subprocess& s,
345  bool remove);
346 
347  static void _inspect(
348  const std::string& cmd,
350  const Option<Duration>& retryInterval,
351  std::shared_ptr<std::pair<lambda::function<void()>, std::mutex>>
352  callback);
353 
354  static void __inspect(
355  const std::string& cmd,
357  const Option<Duration>& retryInterval,
359  const process::Subprocess& s,
360  std::shared_ptr<std::pair<lambda::function<void()>, std::mutex>>
361  callback);
362 
363  static void ___inspect(
364  const std::string& cmd,
366  const Option<Duration>& retryInterval,
367  const process::Future<std::string>& output,
368  std::shared_ptr<std::pair<lambda::function<void()>, std::mutex>>
369  callback);
370 
372  const Docker& docker,
373  const std::string& cmd,
374  const process::Subprocess& s,
377 
379  const Docker& docker,
380  const Option<std::string>& prefix,
381  const std::string& output);
382 
383  static void inspectBatches(
384  process::Owned<std::vector<Docker::Container>> containers,
385  process::Owned<std::vector<std::string>> lines,
386  process::Owned<process::Promise<std::vector<Docker::Container>>> promise,
387  const Docker& docker,
388  const Option<std::string>& prefix);
389 
390  static std::vector<process::Future<Docker::Container>> createInspectBatch(
391  process::Owned<std::vector<std::string>> lines,
392  const Docker& docker,
393  const Option<std::string>& prefix);
394 
395  static process::Future<Image> _pull(
396  const Docker& docker,
397  const process::Subprocess& s,
398  const std::string& directory,
399  const std::string& image,
400  const std::string& path,
401  const std::string& socket,
402  const Option<JSON::Object>& config,
404 
405  static process::Future<Image> __pull(
406  const Docker& docker,
407  const std::string& directory,
408  const std::string& image,
409  const std::string& path,
410  const std::string& socket,
411  const Option<JSON::Object>& config);
412 
413  static process::Future<Image> ___pull(
414  const Docker& docker,
415  const process::Subprocess& s,
416  const std::string& cmd,
417  const std::string& directory,
418  const std::string& image);
419 
420  static process::Future<Image> ____pull(
421  const std::string& output);
422 
423  static void pullDiscarded(
424  const process::Subprocess& s,
425  const std::string& cmd);
426 
427  const std::string path;
428  const std::string socket;
429  const Option<JSON::Object> config;
430 };
431 
432 #endif // __DOCKER_HPP__
Option< std::vector< std::string > > entrypoint
Definition: docker.hpp:164
Definition: docker.hpp:74
Definition: path.hpp:26
struct Docker::Device::Access access
Option< Error > validate(const std::string &imageDir)
std::string image
Definition: docker.hpp:245
const Option< pid_t > pid
Definition: docker.hpp:108
std::vector< std::string > arguments
Definition: docker.hpp:248
std::vector< std::string > dnsOpt
Definition: docker.hpp:227
virtual process::Future< Version > version() const
Definition: check.hpp:33
Option< Bytes > memory
Definition: docker.hpp:202
Option< uint64_t > cpuShares
Definition: docker.hpp:196
bool privileged
Definition: docker.hpp:193
Option< std::string > network
Definition: docker.hpp:215
uint32_t containerPort
Definition: docker.hpp:87
constexpr const char * prefix
Definition: os.hpp:94
std::vector< Device > devices
Definition: docker.hpp:233
virtual process::Future< std::vector< Container > > ps(bool all=false, const Option< std::string > &prefix=None()) const
Option< uint64_t > cpuQuota
Definition: docker.hpp:199
Option< std::map< std::string, std::string > > environment
Definition: docker.hpp:166
const std::vector< std::string > dnsSearch
Definition: docker.hpp:131
const bool started
Definition: docker.hpp:112
virtual process::Future< Image > pull(const std::string &directory, const std::string &image, bool force=false) const
constexpr char DEFAULT_DOCKER_HOST_PREFIX[]
Definition: docker.hpp:51
Option< std::string > hostname
Definition: docker.hpp:218
#define STDERR_FILENO
Definition: windows.hpp:155
Definition: duration.hpp:32
std::vector< std::string > dns
Definition: docker.hpp:221
virtual process::Future< Nothing > kill(const std::string &containerName, int signal) const
virtual process::Future< Container > inspect(const std::string &containerName, const Option< Duration > &retryInterval=None()) const
Access()
Definition: docker.hpp:76
Definition: json.hpp:158
Docker(const std::string &_path, const std::string &_socket, const Option< JSON::Object > &_config)
Definition: docker.hpp:325
Definition: docker.hpp:91
Definition: docker.hpp:69
Represents a fork() exec()ed subprocess.
Definition: subprocess.hpp:43
static IO FD(int_fd fd, IO::FDType type=IO::DUPLICATED)
bool write
Definition: docker.hpp:79
const std::vector< std::string > dns
Definition: docker.hpp:125
const Option< std::string > ipAddress
Definition: docker.hpp:116
#define STDOUT_FILENO
Definition: windows.hpp:154
const std::vector< std::string > dnsOptions
Definition: docker.hpp:128
bool mknod
Definition: docker.hpp:80
Represents a POSIX or Windows file system path and offers common path manipulations.
Definition: path.hpp:145
Definition: duration.hpp:207
Describes how the I/O is redirected for stdin/stdout/stderr.
Definition: subprocess.hpp:61
std::vector< std::string > dnsSearch
Definition: docker.hpp:224
std::vector< std::string > additionalOptions
Definition: docker.hpp:242
void json(JSON::ObjectWriter *writer, const Task &task)
Definition: future.hpp:74
const std::string output
Definition: docker.hpp:98
static Try< process::Owned< Docker > > create(const std::string &path, const std::string &socket, bool validate=true, const Option< JSON::Object > &config=None())
Protocol< PromiseRequest, PromiseResponse > promise
uint32_t hostPort
Definition: docker.hpp:86
std::vector< PortMapping > portMappings
Definition: docker.hpp:230
Option< std::string > protocol
Definition: docker.hpp:88
Definition: docker.hpp:57
std::map< std::string, std::string > env
Definition: docker.hpp:206
URI image(const std::string &repository, const std::string &reference, const std::string &registry, const Option< std::string > &scheme=None(), const Option< int > &port=None())
Definition: docker.hpp:30
Definition: none.hpp:27
Option< std::string > volumeDriver
Definition: docker.hpp:212
const std::vector< Device > devices
Definition: docker.hpp:122
Definition: version.hpp:41
virtual Try< Nothing > validateVersion(const Version &minVersion) const
const std::string id
Definition: docker.hpp:101
virtual std::string getSocket()
Definition: docker.hpp:318
virtual std::string getPath()
Definition: docker.hpp:313
virtual ~Docker()
Definition: docker.hpp:67
Path hostPath
Definition: docker.hpp:71
Definition: docker.hpp:84
const std::string name
Definition: docker.hpp:104
bool read
Definition: docker.hpp:78
virtual process::Future< Option< int > > run(const RunOptions &options, const process::Subprocess::IO &_stdout=process::Subprocess::FD(STDOUT_FILENO), const process::Subprocess::IO &_stderr=process::Subprocess::FD(STDERR_FILENO)) const
std::vector< std::string > volumes
Definition: docker.hpp:209
Definition: spec.hpp:34
Definition: owned.hpp:36
Option< std::string > entrypoint
Definition: docker.hpp:236
Option< std::string > name
Definition: docker.hpp:239
const Option< std::string > ip6Address
Definition: docker.hpp:120
Definition: docker.hpp:177
Path containerPath
Definition: docker.hpp:72
virtual process::Future< Nothing > rm(const std::string &containerName, bool force=false) const
virtual process::Future< Nothing > stop(const std::string &containerName, const Duration &timeout=Seconds(0), bool remove=false) const
Definition: docker.hpp:159
Definition: future.hpp:58