blob: dcd5908c8f1c0b04162332adec48d31ea0e839e3 [file] [log] [blame]
Tommy Carpenter81b9ed72017-08-23 11:21:44 -04001# org.onap.dcae
2# ================================================================================
3# Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
4# ================================================================================
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# 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# ============LICENSE_END=========================================================
17#
18# ECOMP is a trademark and service mark of AT&T Intellectual Property.
19
20import json
21import docker
22import requests
23from dockering.exceptions import DockerError, DockerConnectionError
24from dockering import config_building as cb
25from dockering import utils
26
27
28# TODO: Replace default for logins to source it from Consul..perhaps
29
30def create_client(hostname, port, reauth=False, logins=[]):
31 """Create Docker client
32
33 Args:
34 -----
35 reauth: (boolean) Forces reauthentication e.g. Docker login
36 """
37 base_url = "tcp://{0}:{1}".format(hostname, port)
38 try:
39 client = docker.Client(base_url=base_url)
40
41 for dcl in logins:
42 dcl["reauth"] = reauth
43 client.login(**dcl)
44
45 return client
46 except requests.exceptions.ConnectionError as e:
47 raise DockerConnectionError(str(e))
48
49
50def create_container_using_config(client, service_component_name, container_config):
51 try:
52 image_name = container_config["Image"]
53
54 if not client.images(image_name):
55 def parse_pull_response(response):
56 """Pull response is a giant string of JSON messages concatentated
57 by `\r\n`. This method returns back those messages in the form of
58 list of dicts."""
59 # NOTE: There's a trailing `\r\n` so the last element is empty
60 # string. Remove that.
61 return list(map(json.loads, response.split("\r\n")[:-1]))
62
63 def get_error_message(response):
64 """Attempts to pull out and return an error message from parsed
65 response if it exists else return None"""
66 return response[-1].get("error", None)
67
68 # TODO: Implement this as verbose?
69 # for resp in client.pull(image, stream=True, decode=True):
70 response = parse_pull_response(client.pull(image_name))
71 error_message = get_error_message(response)
72
73 if error_message:
74 raise DockerError("Error pulling Docker image: {0}".format(error_message))
75 else:
76 utils.logger.info("Pulled Docker image: {0}".format(image_name))
77
78 return client.create_container_from_config(container_config,
79 service_component_name)
80 except requests.exceptions.ConnectionError as e:
81 # This separates connection failures so that caller can decide what to do.
82 # Underlying errors this inspired were socket.errors that are sourced
83 # from http://www.virtsync.com/c-error-codes-include-errno
84 raise DockerConnectionError(str(e))
85 except Exception as e:
86 raise DockerError(str(e))
87
88
89def create_container(client, image_name, service_component_name, envs,
90 host_config_params):
91 """Creates Docker container
92
93 Args:
94 -----
95 envs (dict): dict of environment variables to pass into the docker containers.
96 Gets passed into docker-py.create_container call
97 host_config_params (dict): Dict of input parameters to the docker-py
98 "create_host_config" method call
99 """
100 config = cb.create_container_config(client, image_name, envs, host_config_params)
101 return create_container_using_config(client, service_component_name, config)
102
103
104def start_container(client, container):
105 try:
106 # TODO: Have logic to inspect response and through NonRecoverableError
107 # when start fails. Docker-py docs don't quickly tell me what the
108 # response looks like.
109 response = client.start(container=container["Id"])
110 utils.logger.info("Container started: {0}".format(container["Id"]))
111
112 # TODO: Maybe check stats?
113 return container["Id"]
114 except Exception as e:
115 raise DockerError(str(e))
116
117
118def stop_then_remove_container(client, service_component_name):
119 try:
120 client.stop(service_component_name)
121 client.remove_container(service_component_name)
122 except docker.errors.NotFound as e:
123 raise DockerError("Container not found: {0}".format(service_component_name))
124 except Exception as e:
125 raise DockerError(str(e))
126
127
128def remove_image(client, image_name):
129 """Remove the Docker image"""
130 try:
131 client.remove_image(image_name)
132 return True
133 except:
134 # Failure to remove image is not classified as terrible..for now
135 return False
136