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