Migrate Get Requests invocations(libraries)
[integration/test.git] / csit / libraries / Docker.py
1 """
2 Docker library for OpenDaylight project robot system test framework.
3 Authors: Marcus Williams - irc @ mgkwill - Intel Inc.
4 Updated: 2015-05-05
5
6 *Copyright (c) 2015 Intel Corp. and others.  All rights reserved.
7 *
8 * This program and the accompanying materials are made available under the
9 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
10 * and is available at http://www.eclipse.org/legal/epl-v10.html
11 """
12
13 import docker
14 from robot.api import logger
15
16
17 def docker_create(docker_image_name, passed_args_dict=None):
18     """
19     Args:
20         :param docker_image_name: A string that describes the docker image to use
21             example 'socketplane/openvswitch'
22
23         :param passed_args_dict: keyword docker-py create container args. defaults to command=None,
24             hostname=None, user=None, detach=False, stdin_open=False, tty=False,
25             mem_limit=0, ports=None, environment=None, dns=None, volumes=None,
26             volumes_from=None, network_disabled=False, name=None, entrypoint=None,
27             cpu_shares=None, working_dir=None, domainname=None, memswap_limit=0,
28             cpuset=None, host_config=None
29
30     Returns:
31         :returns dict: docker-info - identifying info about docker container created
32     """
33     logger.info("Creating docker %s" % docker_image_name)
34     logger.info(passed_args_dict)
35     docker_client = docker_get_client()
36
37     default_args_dict = dict(
38         command=None,
39         hostname=None,
40         user=None,
41         detach=False,
42         stdin_open=False,
43         tty=False,
44         mem_limit=0,
45         ports=None,
46         environment=None,
47         dns=None,
48         volumes=None,
49         volumes_from=None,
50         network_disabled=False,
51         name=None,
52         entrypoint=None,
53         cpu_shares=None,
54         working_dir=None,
55         domainname=None,
56         memswap_limit=0,
57         cpuset=None,
58         host_config=None,
59     )
60     args_dict = docker_process_args(
61         passed_args_dict, default_args_dict, "docker_create"
62     )
63
64     docker_client.images(name=docker_image_name)
65     docker_uid_dict = docker_client.create_container(docker_image_name, **args_dict)
66     docker_info = docker_client.inspect_container(docker_uid_dict.get("Id"))
67     return docker_info
68
69
70 def docker_start(docker_name, passed_args_dict=None):
71     """Start docker container.
72
73     Args:
74         :param docker_name: A string that describes the docker image to use.
75             Either the uid or docker container name must be used.
76
77         :param passed_args_dict: keyword docker-py start container args. defaults to binds=None,
78             port_bindings=None, lxc_conf=None, publish_all_ports=False,
79             links=None, privileged=False, dns=None, dns_search=None,
80             volumes_from=None, network_mode=None, restart_policy=None,
81             cap_add=None, cap_drop=None, devices=None, extra_hosts=None
82     Returns:
83         :returns bool: returns false if container fails to start
84             and true otherwise
85     """
86     logger.info("Starting docker %s" % docker_name)
87     logger.info(passed_args_dict)
88     docker_client = docker_get_client()
89
90     default_args_dict = dict(
91         binds=None,
92         port_bindings=None,
93         lxc_conf=None,
94         publish_all_ports=False,
95         links=None,
96         privileged=False,
97         dns=None,
98         dns_search=None,
99         volumes_from=None,
100         network_mode=None,
101         restart_policy=None,
102         cap_add=None,
103         cap_drop=None,
104         devices=None,
105         extra_hosts=None,
106     )
107     args_dict = docker_process_args(passed_args_dict, default_args_dict, "docker_start")
108
109     docker_client.start(docker_name, **args_dict)
110
111     if "True" in str(
112         docker_client.inspect_container(docker_name).get("State").get("Running")
113     ):
114         logger.info("Started docker %s successfully" % docker_name)
115         return True
116     else:
117         logger.info("Starting docker %s failed" % docker_name)
118         return False
119
120
121 def docker_remove(docker_name, passed_args_dict=None):
122     """Remove docker container.
123
124     Args:
125         :param docker_name: A string that describes the docker image to use
126             example 'socketplane/openvswitch'
127
128         :param passed_args_dict: keyword docker-py remove container args. defaults to v=False,
129             link=False, force=False
130
131     Returns:
132         :returns bool: True if container was removed false otherwise
133     """
134     logger.info("Removing docker %s" % docker_name)
135     logger.info(passed_args_dict)
136     docker_client = docker_get_client()
137
138     default_args_dict = dict(v=False, link=False, force=False)
139     args_dict = docker_process_args(
140         passed_args_dict, default_args_dict, "docker_remove"
141     )
142
143     docker_client.remove_container(docker_name, **args_dict)
144     docker_containers = docker_client.containers(all=True)
145     for container in docker_containers:
146         if docker_name in container.get("Id") or docker_name in container.get("Names"):
147             logger.info("Removing docker %s failed" % docker_name)
148             return False
149     logger.info("Removed docker %s successfully" % docker_name)
150     return True
151
152
153 def docker_stop(docker_name, timeout=10):
154     """Stop docker container.
155
156     Args:
157         :param docker_name: A string that describes the docker image to use.
158             Either the uid or docker container name must be used.
159
160         :param timeout: docker-py stop container args. defaults to timeout=10
161     Returns:
162         :returns bool: returns false if container fails to stop
163             and true otherwise
164     """
165     logger.info("Stopping docker %s with timeout %d" % (docker_name, timeout))
166     docker_client = docker_get_client()
167
168     docker_client.stop(docker_name, timeout)
169
170     if "False" in str(
171         docker_client.inspect_container(docker_name).get("State").get("Running")
172     ):
173         logger.info("Stopped docker %s successfully" % docker_name)
174         return True
175     else:
176         logger.debug("Stopping docker %s failed" % docker_name)
177         return False
178
179
180 def docker_return_logs(docker_name, passed_args_dict=None):
181     """Return docker container logs.
182
183     Args:
184         :param docker_name: A string that describes the docker image to use.
185             Either the uid or docker container name must be used.
186
187         :param passed_args_dict: keyword docker-py logs container args. defaults to
188             stdout=True, stderr=True, stream=False, timestamps=False, tail='all'
189     Returns:
190         :returns string: returns a string containing docker logs
191     """
192     logger.info("Returning logs for docker %s" % docker_name)
193     logger.info(passed_args_dict)
194     docker_client = docker_get_client()
195
196     default_args_dict = dict(
197         stdout=True, stderr=True, stream=False, timestamps=False, tail="all"
198     )
199     args_dict = docker_process_args(
200         passed_args_dict, default_args_dict, "docker_return_logs"
201     )
202
203     return docker_client.logs(docker_name, **args_dict)
204
205
206 def docker_execute(docker_name, cmd, passed_args_dict=None):
207     """Run a command on a docker container.
208
209     Args:
210         :param docker_name: A string that describes the docker image to use.
211             Either the uid or docker container name must be used.
212
213         :param cmd: A string of the command to run
214             Example 'ip a'
215
216         :param passed_args_dict: dictionary of key word
217         docker-py exec container args. defaults to detach=False,
218             stdout=True, stderr=True, stream=False, tty=False
219     Returns:
220         :returns string: returns string representing the results of the command
221
222     NOTE: In docker-py version >=1.2 execute will be deprecated in
223         favor of exec_create and exec_start
224     """
225     logger.info("Executing command %s on docker %s" % (cmd, docker_name))
226     logger.info(passed_args_dict)
227     docker_client = docker_get_client()
228
229     default_args_dict = dict(
230         detach=False, stdout=True, stderr=True, stream=False, tty=False
231     )
232     args_dict = docker_process_args(
233         passed_args_dict, default_args_dict, "docker_execute"
234     )
235
236     return docker_client.execute(docker_name, cmd, **args_dict)
237
238
239 def docker_get_ip4(docker_name):
240     """Inspects a docker container and returns its IP address.
241
242     Args:
243         :param docker_name: A string that describes the docker image to use.
244             Either the uid or docker container name must be used.
245
246     Returns:
247         :returns string: returns string of IP address
248     """
249     logger.info("Getting IP of docker %s" % docker_name)
250     docker_client = docker_get_client()
251     return str(
252         docker_client.inspect_container(docker_name)
253         .get("NetworkSettings")
254         .get("IPAddress")
255     )
256
257
258 def docker_ping(docker_name, ip, count=3):
259     """Pings from a docker container and returns results.
260
261     Args:
262         :param docker_name: A string that describes the docker image to use.
263             Either the uid or docker container name must be used.
264
265         :param ip: A string of the IP address to ping
266
267         :param count: An integer of the count to ping
268
269     Returns:
270         :returns string: returns string of results
271     """
272     logger.info("Pinging from docker %s to %s %d times" % (docker_name, ip, count))
273     ping_cmd = str(ip) + "ping -c " + str(count)
274     return docker_execute(docker_name, ping_cmd)
275
276
277 def docker_list_containers(passed_args_dict=None):
278     """Return a list of docker containers.
279
280     Returns:
281      :returns list: returns list of docker
282          containers in following format:
283          [{'Id': u'069a56ec06f965f98efa752467737faa58431ebb471bc51e9b2bd485fcc4916c'},
284          {'Id': u'769aff6170eec78e7c502fea4770cfbb7b7e53a2dc44070566d01e18b6d57c14'}]
285     """
286     logger.info("Listing docker containers")
287     logger.info(passed_args_dict)
288
289     default_args_dict = dict(
290         quiet=True,
291         all=True,
292         trunc=True,
293         latest=False,
294         since=None,
295         before=None,
296         limit=-1,
297         size=False,
298         filters=None,
299     )
300     args_dict = docker_process_args(
301         passed_args_dict, default_args_dict, "docker_list_containers"
302     )
303
304     return docker.Client(base_url="unix://var/run/docker.sock", timeout=10).containers(
305         **args_dict
306     )
307
308
309 def docker_create_host_config(passed_args_dict):
310     """Return a list of docker create host config for port bindings.
311
312     Parameters:
313      :param passed_args_dict: dictionary of the keyword values to use.
314
315     Returns:
316      :returns list: returns host config for a container
317          create command in following format:
318          {'PortBindings': {'6640/tcp': [{'HostIp': '', 'HostPort': '6640'}],
319          '6653/tcp': [{'HostIp': '', 'HostPort': '6653'}],
320          '9001/tcp': [{'HostIp': '', 'HostPort': '9001'}]}}
321     """
322     logger.info("Creating host config.")
323
324     default_args_dict = dict(
325         binds=None,
326         port_bindings=None,
327         lxc_conf=None,
328         publish_all_ports=False,
329         links=None,
330         privileged=False,
331         dns=None,
332         dns_search=None,
333         volumes_from=None,
334         network_mode=None,
335         restart_policy=None,
336         cap_add=None,
337         cap_drop=None,
338         devices=None,
339         extra_hosts=None,
340     )
341     args_dict = docker_process_args(
342         passed_args_dict, default_args_dict, "docker_create_host_config"
343     )
344
345     return docker.utils.create_host_config(**args_dict)
346
347
348 def docker_process_args(passed_args_dict, default_args_dict, method_name):
349     """Accepts two dicts and combines them preferring passed
350         args while filling unspecified args with default values.
351
352     Parameters:
353         :param passed_args_dict: A dict of the passed keyword args for the method.
354
355         :param default_args_dict: A dict of the default keyword args for the method.
356
357     Returns:
358         :returns dict: returns dict containing passed args, with
359         defaults for all other keyword args.
360     """
361     logger.info("Processing args for %s method" % method_name)
362     logger.info(passed_args_dict)
363     logger.info(default_args_dict)
364     processed_args_dict = {}
365
366     if passed_args_dict is None:
367         passed_args_dict = {}
368
369     try:
370         for key in default_args_dict:
371             if key in passed_args_dict:
372                 processed_args_dict[key] = passed_args_dict[key]
373             else:
374                 processed_args_dict[key] = default_args_dict[key]
375     except TypeError:
376         logger.debug("Error: One or both of the passed arguments is not a dictionary")
377
378     return processed_args_dict
379
380
381 def docker_get_client(*passed_args_dict):
382     """Returns docker-py client.
383
384     Parameters:
385         :param passed_args_dict: dictionary of the keyword values to use.
386
387     Returns:
388         :returns obj: returns docker-py client object.
389     """
390     default_args_dict = dict(
391         base_url="unix://var/run/docker.sock", version=None, timeout=10, tls=False
392     )
393     args_dict = docker_process_args(
394         passed_args_dict, default_args_dict, "docker_get_client"
395     )
396     return docker.Client(**args_dict)