--- /dev/null
+"""
+Docker library for OpenDaylight project robot system test framework.
+Authors: Marcus Williams - irc @ mgkwill - Intel Inc.
+Updated: 2015-05-05
+
+*Copyright (c) 2015 Intel Corp. and others. All rights reserved.
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License v1.0 which accompanies this distribution,
+* and is available at http://www.eclipse.org/legal/epl-v10.html
+"""
+
+import docker
+from robot.api import logger
+
+
+def docker_create(docker_image_name, passed_args_dict=None):
+ """
+ Args:
+ :param docker_image_name: A string that describes the docker image to use
+ example 'socketplane/openvswitch'
+
+ :param passed_args_dict: keyword docker-py create container args. defaults to command=None,
+ hostname=None, user=None, detach=False, stdin_open=False, tty=False,
+ mem_limit=0, ports=None, environment=None, dns=None, volumes=None,
+ volumes_from=None, network_disabled=False, name=None, entrypoint=None,
+ cpu_shares=None, working_dir=None, domainname=None, memswap_limit=0,
+ cpuset=None, host_config=None
+
+ Returns:
+ :returns dict: docker-info - identifying info about docker container created
+ """
+ logger.info("Creating docker %s" % docker_image_name)
+ logger.info(passed_args_dict)
+ docker_client = docker_get_client()
+
+ default_args_dict = dict(command=None,
+ hostname=None,
+ user=None,
+ detach=False,
+ stdin_open=False,
+ tty=False,
+ mem_limit=0,
+ ports=None,
+ environment=None,
+ dns=None,
+ volumes=None,
+ volumes_from=None,
+ network_disabled=False,
+ name=None,
+ entrypoint=None,
+ cpu_shares=None,
+ working_dir=None,
+ domainname=None,
+ memswap_limit=0,
+ cpuset=None,
+ host_config=None
+ )
+ args_dict = docker_process_args(passed_args_dict, default_args_dict, "docker_create")
+
+ docker_client.images(name=docker_image_name)
+ docker_uid_dict = docker_client\
+ .create_container(docker_image_name, **args_dict)
+ docker_info = docker_client.inspect_container(docker_uid_dict.get("Id"))
+ return docker_info
+
+
+def docker_start(docker_name, passed_args_dict=None):
+ """Start docker container.
+
+ Args:
+ :param docker_name: A string that describes the docker image to use.
+ Either the uid or docker container name must be used.
+
+ :param passed_args_dict: keyword docker-py start container args. defaults to binds=None,
+ port_bindings=None, lxc_conf=None, publish_all_ports=False,
+ links=None, privileged=False, dns=None, dns_search=None,
+ volumes_from=None, network_mode=None, restart_policy=None,
+ cap_add=None, cap_drop=None, devices=None, extra_hosts=None
+ Returns:
+ :returns bool: returns false if container fails to start
+ and true otherwise
+ """
+ logger.info("Starting docker %s" % docker_name)
+ logger.info(passed_args_dict)
+ docker_client = docker_get_client()
+
+ default_args_dict = dict(binds=None,
+ port_bindings=None,
+ lxc_conf=None,
+ publish_all_ports=False,
+ links=None,
+ privileged=False,
+ dns=None,
+ dns_search=None,
+ volumes_from=None,
+ network_mode=None,
+ restart_policy=None,
+ cap_add=None,
+ cap_drop=None,
+ devices=None,
+ extra_hosts=None
+ )
+ args_dict = docker_process_args(passed_args_dict, default_args_dict, "docker_start")
+
+ docker_client.start(docker_name, **args_dict)
+
+ if "True" in str(docker_client.inspect_container(docker_name)
+ .get("State").get("Running")):
+ logger.info("Started docker %s successfully" % docker_name)
+ return True
+ else:
+ logger.info("Starting docker %s failed" % docker_name)
+ return False
+
+
+def docker_remove(docker_name, passed_args_dict=None):
+ """Remove docker container.
+
+ Args:
+ :param docker_name: A string that describes the docker image to use
+ example 'socketplane/openvswitch'
+
+ :param passed_args_dict: keyword docker-py remove container args. defaults to v=False,
+ link=False, force=False
+
+ Returns:
+ :returns bool: True if container was removed false otherwise
+ """
+ logger.info("Removing docker %s" % docker_name)
+ logger.info(passed_args_dict)
+ docker_client = docker_get_client()
+
+ default_args_dict = dict(v=False,
+ link=False,
+ force=False
+ )
+ args_dict = docker_process_args(passed_args_dict, default_args_dict, "docker_remove")
+
+ docker_client.remove_container(docker_name, **args_dict)
+ docker_containers = docker_client.containers(all=True)
+ for container in docker_containers:
+ if docker_name in container.get("Id") or docker_name in container.get("Names"):
+ logger.info("Removing docker %s failed" % docker_name)
+ return False
+ logger.info("Removed docker %s successfully" % docker_name)
+ return True
+
+
+def docker_stop(docker_name, timeout=10):
+ """Stop docker container.
+
+ Args:
+ :param docker_name: A string that describes the docker image to use.
+ Either the uid or docker container name must be used.
+
+ :param timeout: docker-py stop container args. defaults to timeout=10
+ Returns:
+ :returns bool: returns false if container fails to stop
+ and true otherwise
+ """
+ logger.info("Stopping docker %s with timeout %d" % (docker_name, timeout))
+ docker_client = docker_get_client()
+
+ docker_client.stop(docker_name, timeout)
+
+ if "False" in str(docker_client.inspect_container(docker_name)
+ .get("State").get("Running")):
+ logger.info("Stopped docker %s successfully" % docker_name)
+ return True
+ else:
+ logger.debug("Stopping docker %s failed" % docker_name)
+ return False
+
+
+def docker_return_logs(docker_name, passed_args_dict=None):
+ """Return docker container logs.
+
+ Args:
+ :param docker_name: A string that describes the docker image to use.
+ Either the uid or docker container name must be used.
+
+ :param passed_args_dict: keyword docker-py logs container args. defaults to
+ stdout=True, stderr=True, stream=False, timestamps=False, tail='all'
+ Returns:
+ :returns string: returns a string containing docker logs
+ """
+ logger.info("Returning logs for docker %s" % docker_name)
+ logger.info(passed_args_dict)
+ docker_client = docker_get_client()
+
+ default_args_dict = dict(stdout=True,
+ stderr=True,
+ stream=False,
+ timestamps=False,
+ tail='all'
+ )
+ args_dict = docker_process_args(passed_args_dict, default_args_dict, "docker_return_logs")
+
+ return docker_client.logs(docker_name, **args_dict)
+
+
+def docker_execute(docker_name, cmd, passed_args_dict=None):
+ """Run a command on a docker container.
+
+ Args:
+ :param docker_name: A string that describes the docker image to use.
+ Either the uid or docker container name must be used.
+
+ :param cmd: A string of the command to run
+ Example 'ip a'
+
+ :param passed_args_dict: dictionary of key word
+ docker-py exec container args. defaults to detach=False,
+ stdout=True, stderr=True, stream=False, tty=False
+ Returns:
+ :returns string: returns string representing the results of the command
+
+ NOTE: In docker-py version >=1.2 execute will be deprecated in
+ favor of exec_create and exec_start
+ """
+ logger.info("Executing command %s on docker %s" % (cmd, docker_name))
+ logger.info(passed_args_dict)
+ docker_client = docker_get_client()
+
+ default_args_dict = dict(detach=False,
+ stdout=True,
+ stderr=True,
+ stream=False,
+ tty=False
+ )
+ args_dict = docker_process_args(passed_args_dict, default_args_dict, "docker_execute")
+
+ return docker_client.execute(docker_name, cmd, **args_dict)
+
+
+def docker_get_ip4(docker_name):
+ """Inspects a docker container and returns its IP address.
+
+ Args:
+ :param docker_name: A string that describes the docker image to use.
+ Either the uid or docker container name must be used.
+
+ Returns:
+ :returns string: returns string of IP address
+ """
+ logger.info("Getting IP of docker %s" % docker_name)
+ docker_client = docker_get_client()
+ return str(docker_client.inspect_container(docker_name)
+ .get("NetworkSettings")
+ .get("IPAddress"))
+
+
+def docker_ping(docker_name, ip, count=3):
+ """Pings from a docker container and returns results.
+
+ Args:
+ :param docker_name: A string that describes the docker image to use.
+ Either the uid or docker container name must be used.
+
+ :param ip: A string of the IP address to ping
+
+ :param count: An integer of the count to ping
+
+ Returns:
+ :returns string: returns string of results
+ """
+ logger.info("Pinging from docker %s to %s %d times" % (docker_name, ip, count))
+ ping_cmd = str(ip) + "ping -c " + str(count)
+ return docker_execute(docker_name, ping_cmd)
+
+
+def docker_list_containers(passed_args_dict=None):
+ """Return a list of docker containers.
+
+ Returns:
+ :returns list: returns list of docker
+ containers in following format:
+ [{'Id': u'069a56ec06f965f98efa752467737faa58431ebb471bc51e9b2bd485fcc4916c'},
+ {'Id': u'769aff6170eec78e7c502fea4770cfbb7b7e53a2dc44070566d01e18b6d57c14'}]
+ """
+ logger.info("Listing docker containers")
+ logger.info(passed_args_dict)
+
+ default_args_dict = dict(quiet=True,
+ all=True,
+ trunc=True,
+ latest=False,
+ since=None,
+ before=None,
+ limit=-1,
+ size=False,
+ filters=None
+ )
+ args_dict = docker_process_args(passed_args_dict, default_args_dict,
+ "docker_list_containers")
+
+ return docker.Client(
+ base_url='unix://var/run/docker.sock',
+ timeout=10)\
+ .containers(**args_dict)
+
+
+def docker_create_host_config(passed_args_dict):
+ """Return a list of docker create host config for port bindings.
+
+ Parameters:
+ :param passed_args_dict: dictionary of the keyword values to use.
+
+ Returns:
+ :returns list: returns host config for a container
+ create command in following format:
+ {'PortBindings': {'6640/tcp': [{'HostIp': '', 'HostPort': '6640'}],
+ '6653/tcp': [{'HostIp': '', 'HostPort': '6653'}],
+ '9001/tcp': [{'HostIp': '', 'HostPort': '9001'}]}}
+ """
+ logger.info("Creating host config.")
+
+ default_args_dict = dict(binds=None,
+ port_bindings=None,
+ lxc_conf=None,
+ publish_all_ports=False,
+ links=None,
+ privileged=False,
+ dns=None,
+ dns_search=None,
+ volumes_from=None,
+ network_mode=None,
+ restart_policy=None,
+ cap_add=None,
+ cap_drop=None,
+ devices=None,
+ extra_hosts=None
+ )
+ args_dict = docker_process_args(passed_args_dict, default_args_dict,
+ "docker_create_host_config")
+
+ return docker.utils.create_host_config(**args_dict)
+
+
+def docker_process_args(passed_args_dict, default_args_dict, method_name):
+ """Accepts two dicts and combines them preferring passed
+ args while filling unspecified args with default values.
+
+ Parameters:
+ :param passed_args_dict: A dict of the passed keyword args for the method.
+
+ :param default_args_dict: A dict of the default keyword args for the method.
+
+ Returns:
+ :returns dict: returns dict containing passed args, with
+ defaults for all other keyword args.
+ """
+ logger.info("Processing args for %s method" % method_name)
+ logger.info(passed_args_dict)
+ logger.info(default_args_dict)
+ processed_args_dict = {}
+
+ if passed_args_dict is None:
+ passed_args_dict = {}
+
+ try:
+ for key in default_args_dict:
+ if key in passed_args_dict:
+ processed_args_dict[key] = passed_args_dict[key]
+ else:
+ processed_args_dict[key] = default_args_dict[key]
+ except TypeError:
+ logger.debug("Error: One or both of the passed arguments is not a dictionary")
+
+ return processed_args_dict
+
+
+def docker_get_client(*passed_args_dict):
+ """Returns docker-py client.
+
+ Parameters:
+ :param passed_args_dict: dictionary of the keyword values to use.
+
+ Returns:
+ :returns obj: returns docker-py client object.
+ """
+ default_args_dict = dict(base_url="unix://var/run/docker.sock",
+ version=None,
+ timeout=10,
+ tls=False)
+ args_dict = docker_process_args(passed_args_dict, default_args_dict, "docker_get_client")
+ return docker.Client(**args_dict)