summaryrefslogtreecommitdiffstats
path: root/contrail-analytics/hooks/docker_utils.py
diff options
context:
space:
mode:
authorStuart Mackie <wsmackie@juniper.net>2017-07-25 10:37:57 -0700
committerStuart Mackie <wsmackie@juniper.net>2017-07-25 10:37:57 -0700
commit711967ae9639095ce41500bb0e6f80c8b80fab95 (patch)
tree07f598b35664ddbd269b76f21cf587f5679cab86 /contrail-analytics/hooks/docker_utils.py
parentefd4f1414b79dd51c6316a73893ade33bc9f668e (diff)
Contrail charms
Change-Id: I2d259d03f63fce38348b8384e26ac23e3fce44a8 Signed-off-by: Stuart Mackie <wsmackie@juniper.net>
Diffstat (limited to 'contrail-analytics/hooks/docker_utils.py')
-rw-r--r--contrail-analytics/hooks/docker_utils.py185
1 files changed, 185 insertions, 0 deletions
diff --git a/contrail-analytics/hooks/docker_utils.py b/contrail-analytics/hooks/docker_utils.py
new file mode 100644
index 0000000..92605f0
--- /dev/null
+++ b/contrail-analytics/hooks/docker_utils.py
@@ -0,0 +1,185 @@
+import functools
+from time import sleep, time
+
+from subprocess import (
+ CalledProcessError,
+ check_call,
+ check_output
+)
+from charmhelpers.core.hookenv import (
+ resource_get,
+ config,
+ log,
+ ERROR,
+)
+
+
+config = config()
+
+
+DOCKER_PACKAGES = ["docker.engine"]
+DOCKER_CLI = "/usr/bin/docker"
+
+
+def retry(f=None, timeout=10, delay=2):
+ """Retry decorator.
+
+ Provides a decorator that can be used to retry a function if it raises
+ an exception.
+
+ :param timeout: timeout in seconds (default 10)
+ :param delay: retry delay in seconds (default 2)
+
+ Examples::
+
+ # retry fetch_url function
+ @retry
+ def fetch_url():
+ # fetch url
+
+ # retry fetch_url function for 60 secs
+ @retry(timeout=60)
+ def fetch_url():
+ # fetch url
+ """
+ if not f:
+ return functools.partial(retry, timeout=timeout, delay=delay)
+
+ @functools.wraps(f)
+ def func(*args, **kwargs):
+ start = time()
+ error = None
+ while True:
+ try:
+ return f(*args, **kwargs)
+ except Exception as e:
+ error = e
+ elapsed = time() - start
+ if elapsed >= timeout:
+ raise error
+ remaining = timeout - elapsed
+ sleep(delay if delay <= remaining else remaining)
+ return func
+
+
+# NOTE: this code assumes that name of container is the part of the
+# name of docker image
+
+def add_docker_repo():
+ import platform
+ cmd = 'curl -fsSL https://apt.dockerproject.org/gpg | sudo apt-key add -'
+ check_output(cmd, shell=True)
+ dist = platform.linux_distribution()[2].strip()
+ cmd = "add-apt-repository " + \
+ "\"deb https://apt.dockerproject.org/repo/ " + \
+ "ubuntu-%s " % (dist) + \
+ "main\""
+ check_output(cmd, shell=True)
+
+
+def is_container_launched(name):
+ # NOTE: 'paused' state is not getting into account if someone paused it
+ # NOTE: assume that this cmd is the same as inspect of state:
+ # [DOCKER_CLI, "inspect", "-f", "{{.State.Running}}", name]
+ cmd = DOCKER_CLI + ' ps | grep -w ' + name
+ try:
+ check_output(cmd, shell=True)
+ return True
+ except CalledProcessError:
+ return False
+
+
+def is_container_present(name):
+ cmd = DOCKER_CLI + ' ps --all | grep -w ' + name
+ try:
+ check_output(cmd, shell=True)
+ return True
+ except CalledProcessError:
+ return False
+
+
+def dpkg_version(name, pkg):
+ try:
+ return check_output([DOCKER_CLI,
+ "exec",
+ name,
+ "dpkg-query",
+ "-f", "${Version}\\n", "-W", pkg]).rstrip()
+ except CalledProcessError:
+ return None
+
+
+def load_docker_image(name):
+ img_path = resource_get(name)
+ if not img_path:
+ return None
+ image_id = get_docker_image_id(name)
+ if image_id:
+ # remove previous image
+ check_call([DOCKER_CLI, "rmi", image_id])
+ check_call([DOCKER_CLI, "load", "-i", img_path])
+ return get_docker_image_id(name)
+
+
+def get_docker_image_id(name):
+ try:
+ output = check_output(DOCKER_CLI + ' images | grep -w ' + name,
+ shell=True)
+ except CalledProcessError:
+ return None
+ output = output.decode('UTF-8').split('\n')
+ for line in output:
+ parts = line.split()
+ if name in parts[0]:
+ return parts[2].strip()
+ return None
+
+
+def launch_docker_image(name, additional_args=[]):
+ image_id = get_docker_image_id(name)
+ if not image_id:
+ log(name + " docker image is not available", level=ERROR)
+ return
+
+ orchestrator = config.get("cloud_orchestrator")
+ args = [DOCKER_CLI,
+ "run",
+ "--net=host",
+ "--cap-add=AUDIT_WRITE",
+ "--privileged",
+ "--restart=unless-stopped",
+ "--env='CLOUD_ORCHESTRATOR=%s'" % (orchestrator),
+ "--volume=/etc/contrailctl:/etc/contrailctl",
+ "--name=%s" % name]
+ args.extend(additional_args)
+ args.extend(["-itd", image_id])
+ log("Run container with cmd: " + ' '.join(args))
+ check_call(args)
+
+
+def docker_cp(name, src, dst):
+ check_call([DOCKER_CLI, "cp", name + ":" + src, dst])
+
+
+def docker_exec(name, cmd):
+ cli = [DOCKER_CLI, "exec", name]
+ if isinstance(cmd, list):
+ cli.extend(cmd)
+ else:
+ cli.append(cmd)
+ output = check_output(cli)
+ return output.decode('UTF-8')
+
+
+@retry(timeout=32, delay=10)
+def apply_config_in_container(name, cfg_name):
+ try:
+ cmd = (DOCKER_CLI + ' exec ' + name + ' contrailctl config sync -v'
+ + ' -c ' + cfg_name)
+ check_call(cmd, shell=True)
+ return True
+ except CalledProcessError as e:
+ if e.returncode == 137:
+ log("Container was restarted. " + str(e.output), level=ERROR)
+ return False
+ raise