summaryrefslogtreecommitdiffstats
path: root/python-dockering/dockering/core.py
diff options
context:
space:
mode:
Diffstat (limited to 'python-dockering/dockering/core.py')
-rw-r--r--python-dockering/dockering/core.py136
1 files changed, 136 insertions, 0 deletions
diff --git a/python-dockering/dockering/core.py b/python-dockering/dockering/core.py
new file mode 100644
index 0000000..dcd5908
--- /dev/null
+++ b/python-dockering/dockering/core.py
@@ -0,0 +1,136 @@
+# org.onap.dcae
+# ================================================================================
+# Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============LICENSE_END=========================================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+
+import json
+import docker
+import requests
+from dockering.exceptions import DockerError, DockerConnectionError
+from dockering import config_building as cb
+from dockering import utils
+
+
+# TODO: Replace default for logins to source it from Consul..perhaps
+
+def create_client(hostname, port, reauth=False, logins=[]):
+ """Create Docker client
+
+ Args:
+ -----
+ reauth: (boolean) Forces reauthentication e.g. Docker login
+ """
+ base_url = "tcp://{0}:{1}".format(hostname, port)
+ try:
+ client = docker.Client(base_url=base_url)
+
+ for dcl in logins:
+ dcl["reauth"] = reauth
+ client.login(**dcl)
+
+ return client
+ except requests.exceptions.ConnectionError as e:
+ raise DockerConnectionError(str(e))
+
+
+def create_container_using_config(client, service_component_name, container_config):
+ try:
+ image_name = container_config["Image"]
+
+ if not client.images(image_name):
+ def parse_pull_response(response):
+ """Pull response is a giant string of JSON messages concatentated
+ by `\r\n`. This method returns back those messages in the form of
+ list of dicts."""
+ # NOTE: There's a trailing `\r\n` so the last element is empty
+ # string. Remove that.
+ return list(map(json.loads, response.split("\r\n")[:-1]))
+
+ def get_error_message(response):
+ """Attempts to pull out and return an error message from parsed
+ response if it exists else return None"""
+ return response[-1].get("error", None)
+
+ # TODO: Implement this as verbose?
+ # for resp in client.pull(image, stream=True, decode=True):
+ response = parse_pull_response(client.pull(image_name))
+ error_message = get_error_message(response)
+
+ if error_message:
+ raise DockerError("Error pulling Docker image: {0}".format(error_message))
+ else:
+ utils.logger.info("Pulled Docker image: {0}".format(image_name))
+
+ return client.create_container_from_config(container_config,
+ service_component_name)
+ except requests.exceptions.ConnectionError as e:
+ # This separates connection failures so that caller can decide what to do.
+ # Underlying errors this inspired were socket.errors that are sourced
+ # from http://www.virtsync.com/c-error-codes-include-errno
+ raise DockerConnectionError(str(e))
+ except Exception as e:
+ raise DockerError(str(e))
+
+
+def create_container(client, image_name, service_component_name, envs,
+ host_config_params):
+ """Creates Docker container
+
+ Args:
+ -----
+ envs (dict): dict of environment variables to pass into the docker containers.
+ Gets passed into docker-py.create_container call
+ host_config_params (dict): Dict of input parameters to the docker-py
+ "create_host_config" method call
+ """
+ config = cb.create_container_config(client, image_name, envs, host_config_params)
+ return create_container_using_config(client, service_component_name, config)
+
+
+def start_container(client, container):
+ try:
+ # TODO: Have logic to inspect response and through NonRecoverableError
+ # when start fails. Docker-py docs don't quickly tell me what the
+ # response looks like.
+ response = client.start(container=container["Id"])
+ utils.logger.info("Container started: {0}".format(container["Id"]))
+
+ # TODO: Maybe check stats?
+ return container["Id"]
+ except Exception as e:
+ raise DockerError(str(e))
+
+
+def stop_then_remove_container(client, service_component_name):
+ try:
+ client.stop(service_component_name)
+ client.remove_container(service_component_name)
+ except docker.errors.NotFound as e:
+ raise DockerError("Container not found: {0}".format(service_component_name))
+ except Exception as e:
+ raise DockerError(str(e))
+
+
+def remove_image(client, image_name):
+ """Remove the Docker image"""
+ try:
+ client.remove_image(image_name)
+ return True
+ except:
+ # Failure to remove image is not classified as terrible..for now
+ return False
+