eab8fb6671178b000a57d4796a26664271fe7d68
[apex.git] / apex / builders / overcloud_builder.py
1 ##############################################################################
2 # Copyright (c) 2017 Tim Rozet (trozet@redhat.com) and others.
3 #
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
9
10 # Used to modify overcloud qcow2 image
11
12 import logging
13 import os
14 import tarfile
15
16 import apex.builders.common_builder
17 from apex.common import constants as con
18 from apex.common import utils as utils
19 from apex.common.exceptions import ApexBuildException
20 from apex.virtual import utils as virt_utils
21
22
23 def inject_opendaylight(odl_version, image, tmp_dir, uc_ip,
24                         os_version, docker_tag=None):
25     assert odl_version in con.VALID_ODL_VERSIONS
26     # add repo
27     if odl_version == 'master':
28         # last version in the constants is "master" so select 2nd to last
29         # odl package version has no "master" version
30         odl_pkg_version = con.VALID_ODL_VERSIONS[-2]
31         # branch will be used to pull puppet-opendaylight. Since puppet-odl
32         # does not pull branch until later, we need to use master version of
33         # that if master ODL version is specified
34         branch = odl_version
35     else:
36         odl_pkg_version = odl_version
37         branch = "stable/{}".format(odl_version)
38     odl_url = "https://nexus.opendaylight.org/content/repositories" \
39               "/opendaylight-{}-epel-7-x86_64-devel/".format(odl_pkg_version)
40     repo_name = "opendaylight-{}".format(odl_pkg_version)
41     apex.builders.common_builder.add_repo(odl_url, repo_name, image, tmp_dir)
42     # download puppet-opendaylight
43     archive = apex.builders.common_builder.create_git_archive(
44         repo_url=con.PUPPET_ODL_URL, repo_name='puppet-opendaylight',
45         tmp_dir=tmp_dir, branch=branch, prefix='opendaylight/')
46     # install ODL, puppet-odl
47     virt_ops = [
48         {con.VIRT_UPLOAD: "{}:/etc/puppet/modules/".format(archive)},
49         {con.VIRT_RUN_CMD: 'rm -rf /etc/puppet/modules/opendaylight'},
50         {con.VIRT_RUN_CMD: "cd /etc/puppet/modules/ && tar xvf "
51                            "puppet-opendaylight.tar"},
52         {con.VIRT_INSTALL: "java-1.8.0-openjdk"}
53     ]
54     if docker_tag:
55         docker_cmds = [
56             "RUN yum remove opendaylight -y",
57             "RUN echo $'[opendaylight]\\n\\",
58             "baseurl={}\\n\\".format(odl_url),
59             "gpgcheck=0\\n\\",
60             "enabled=1' > /etc/yum.repos.d/opendaylight.repo",
61             "RUN yum -y install opendaylight"
62         ]
63         src_img_uri = "{}:8787/tripleo{}/centos-binary-{}:" \
64                       "{}".format(uc_ip, os_version, 'opendaylight',
65                                   docker_tag)
66         build_dockerfile('opendaylight', tmp_dir, docker_cmds, src_img_uri)
67     else:
68         virt_ops.append({con.VIRT_INSTALL: 'opendaylight'})
69     virt_utils.virt_customize(virt_ops, image)
70     logging.info("OpenDaylight injected into {}".format(image))
71
72
73 def inject_quagga(image, tmp_dir):
74     """
75     Downloads quagga tarball from artifacts.opnfv.org
76     and install it on the overcloud image on the fly.
77     :param image:
78     :param tmp_dir:
79     :return:
80     """
81     utils.fetch_upstream_and_unpack(tmp_dir,
82                                     os.path.split(con.QUAGGA_URL)[0] + "/",
83                                     [os.path.basename(con.QUAGGA_URL)])
84
85     virt_ops = [
86         {con.VIRT_UPLOAD: "{}/quagga-4.tar.gz:/root/".format(tmp_dir)},
87         {con.VIRT_RUN_CMD: "cd /root/ && tar xzf quagga-4.tar.gz"},
88         {con.VIRT_RUN_CMD: "cd /root/quagga;packages=$(ls |grep -vE 'debug"
89          "info|devel|contrib');yum -y install $packages"}
90     ]
91     virt_utils.virt_customize(virt_ops, image)
92     logging.info("Quagga injected into {}".format(image))
93
94
95 def inject_ovs_nsh(image, tmp_dir):
96     """
97     Downloads OpenVswitch, compiles it and installs it on the
98     overcloud image on the fly.
99     :param image:
100     :param tmp_dir:
101     :return:
102     """
103     ovs_filename = os.path.basename(con.OVS_URL)
104     ovs_folder = ovs_filename.replace(".tar.gz", "")
105     utils.fetch_upstream_and_unpack(tmp_dir,
106                                     os.path.split(con.OVS_URL)[0] + "/",
107                                     [ovs_filename])
108     (ovs_dist_name, ovs_version) = ovs_folder.split("-")
109
110     virt_ops = [
111         {con.VIRT_UPLOAD: "{}:/root/".format(tmp_dir + "/" + ovs_filename)},
112         {con.VIRT_INSTALL: "rpm-build,autoconf,automake,libtool,openssl,"
113          "openssl-devel,python,python-twisted-core,python-six,groff,graphviz,"
114          "python-zope-interface,desktop-file-utils,procps-ng,PyQt4,"
115          "libcap-ng,libcap-ng-devel,selinux-policy-devel,kernel-devel,"
116          "kernel-headers,kernel-tools,rpmdevtools,systemd-units,python-devel,"
117          "python-sphinx"},
118         {con.VIRT_RUN_CMD: "cd /root/ && tar xzf {}".format(ovs_filename)},
119         {con.VIRT_UPLOAD:
120          "{}/build_ovs_nsh.sh:/root/{}".format(tmp_dir, ovs_folder)},
121         {con.VIRT_RUN_CMD:
122          "cd /root/{0} && chmod -R 777 * && chown -R root:root * && "
123          "./build_ovs_nsh.sh && rpm -Uhv --force rpm/rpmbuild/RPMS/x86_64/{0}"
124          "-1.el7.x86_64.rpm && rpm -Uhv --force rpm/rpmbuild/RPMS/x86_64"
125          "/openvswitch-kmod-{1}-1.el7.x86_64.rpm".format(ovs_folder,
126                                                          ovs_version)}
127     ]
128     virt_utils.virt_customize(virt_ops, image)
129     logging.info("OVS injected into {}".format(image))
130
131
132 def build_dockerfile(service, tmp_dir, docker_cmds, src_image_uri):
133     """
134     Builds docker file per service and stores it in a
135     tmp_dir/containers/<service> directory.  If the Dockerfile already exists,
136     simply append the docker cmds to it.
137     :param service: name of sub-directory to store Dockerfile in
138     :param tmp_dir: Temporary directory to store the container's dockerfile in
139     :param docker_cmds: List of commands to insert into the dockerfile
140     :param src_image_uri: Docker URI format for where the source image exists
141     :return: None
142     """
143     logging.debug("Building Dockerfile for {} with docker_cmds: {}".format(
144         service, docker_cmds))
145     c_dir = os.path.join(tmp_dir, 'containers')
146     service_dir = os.path.join(c_dir, service)
147     if not os.path.isdir(service_dir):
148         os.makedirs(service_dir, exist_ok=True)
149     from_cmd = "FROM {}\n".format(src_image_uri)
150     service_file = os.path.join(service_dir, 'Dockerfile')
151     assert isinstance(docker_cmds, list)
152     if os.path.isfile(service_file):
153         append_cmds = True
154     else:
155         append_cmds = False
156     with open(service_file, "a+") as fh:
157         if not append_cmds:
158             fh.write(from_cmd)
159         fh.write('\n'.join(docker_cmds))
160
161
162 def archive_docker_patches(tmp_dir):
163     """
164     Archives Overcloud docker patches into a tar file for upload to Undercloud
165     :param tmp_dir: temporary directory where containers folder is stored
166     :return: None
167     """
168     container_path = os.path.join(tmp_dir, 'containers')
169     if not os.path.isdir(container_path):
170         raise ApexBuildException("Docker directory for patches not found: "
171                                  "{}".format(container_path))
172     archive_file = os.path.join(tmp_dir, 'docker_patches.tar.gz')
173     with tarfile.open(archive_file, "w:gz") as tar:
174         tar.add(container_path, arcname=os.path.basename(container_path))