Enable Adapter to work behind proxy
[dcaegen2/platform.git] / adapter / acumos / aoconversion / docker_gen.py
1 # ============LICENSE_START====================================================
2 # org.onap.dcae
3 # =============================================================================
4 # Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
5 # =============================================================================
6 # Copyright (c) 2021 highstreet technologies GmbH. All rights reserved.
7 # =============================================================================
8 # Licensed under the Apache License, Version 2.0 (the "License");
9 # you may not use this file except in compliance with the License.
10 # You may obtain a copy of the License at
11 #
12 #      http://www.apache.org/licenses/LICENSE-2.0
13 #
14 # Unless required by applicable law or agreed to in writing, software
15 # distributed under the License is distributed on an "AS IS" BASIS,
16 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 # See the License for the specific language governing permissions and
18 # limitations under the License.
19 # ============LICENSE_END======================================================
20
21 import os
22 from docker import APIClient
23 from aoconversion import exceptions, utils
24
25
26 def _generate_dockerfile(meta, model_name, http_proxy, https_proxy, no_proxy):
27     """
28     bind the templated docker string
29     """
30     python_version = meta["runtime"]["version"]
31     docker_template = f'''
32     FROM python:{python_version}
33
34     ENV MODELNAME {model_name}
35     RUN mkdir /app
36     WORKDIR /app
37
38     ADD ./{model_name} /app/{model_name}
39     ADD ./requirements.txt /app
40     ENV http_proxy={http_proxy}
41     ENV https_proxy={https_proxy}
42     ENV HTTP_PROXY={http_proxy}
43     ENV HTTPS_PROXY={https_proxy}
44     ENV no_proxy={no_proxy}
45     ENV NO_PROXY={no_proxy}
46     RUN pip install -r /app/requirements.txt && \
47         pip install acumos_dcae_model_runner
48
49     ENV DCAEPORT=10000
50     EXPOSE $DCAEPORT
51
52     ENTRYPOINT ["acumos_dcae_model_runner"]
53     CMD ["/app/{model_name}"]
54     '''
55
56     return docker_template
57
58
59 # Public
60
61
62 def build_and_push_docker(config, model_name, model_version="latest"):
63     """
64     build and push the dcae docker container
65     Returns the docker uri so this can be pipelined into specgen
66     """
67     model_repo_path = config.tmpdir
68     dockerfile_path = "{0}/Dockerfile".format(model_repo_path)
69     reqs_path = "{0}/requirements.txt".format(model_repo_path)
70
71     # get the metadata
72     meta = utils.get_metadata(model_repo_path, model_name)
73
74     # write the reqs file, will be removed later
75     reqs = meta["runtime"]["dependencies"]["pip"]["requirements"]
76     with open(reqs_path, "w") as f:
77         for r in reqs:
78             f.write("{0}=={1}\n".format(r["name"], r["version"]))
79
80     # generate the dockerfile
81     print("Http_Proxy: {} & Https_Proxy: {}".format(config.http_proxy, config.https_proxy))
82     dockerfile = _generate_dockerfile(meta, model_name, config.http_proxy, config.https_proxy, config.no_proxy)
83
84     # write the dockerfile, will be removed later
85     with open("{0}/Dockerfile".format(model_repo_path), "w") as f:
86         f.write(dockerfile)
87
88     docker_uri = "{0}/{1}:{2}".format(config.dockerregistry, model_name, model_version)
89
90     # do the docker build
91     cli = APIClient(base_url=config.dockerhost, user_agent="Docker-Client-xx.yy")
92     response = [line.decode() for line in cli.build(path=model_repo_path, rm=True, tag=docker_uri)]
93
94     # clean up the files
95     os.remove(dockerfile_path)
96     os.remove(reqs_path)
97
98     # parse the Docker response to see whether we succeeded
99     for r in response:
100         # In some scenarios, for example a non-existing Dockerfile, docker build raises a native exception, see:
101         # https://docker-py.readthedocs.io/en/stable/api.html#module-docker.api.build
102         # However, if something fails such as a non-existing directory referenced in the dockerfile, NO exception is raised.
103         # In this case, one of the console output lines is "errorDetail"....
104         if "errorDetail" in r:
105             raise exceptions.DockerBuildFail(r)
106
107     # if the above succeeded, we can push
108     # push. same problem as above; e.g., "no basic auth credentials" does not throw an exception!
109     response = [
110         line.decode()
111         for line in cli.push(
112             repository=docker_uri, auth_config={"username": config.dockeruser, "password": config.dockerpass()}, stream=True
113         )
114     ]
115     for r in response:
116         if "errorDetail" in r:
117             raise exceptions.DockerPushFail(r)
118
119     return docker_uri