blob: ad921ed334fd47d31fc4ecf0659557d0812cec14 [file] [log] [blame]
Bartek Grzybowskib9d8c4c2019-07-11 08:31:56 +02001#! /usr/bin/env python3
Mateusz Pilat84ef3b32019-06-17 07:45:24 +02002# -*- coding: utf-8 -*-
3
4# COPYRIGHT NOTICE STARTS HERE
5
6# Copyright 2019 . Samsung Electronics Co., Ltd.
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
20# COPYRIGHT NOTICE ENDS HERE
21
22from datetime import datetime
23import subprocess
24import argparse
25import logging
26import shutil
27import glob
28import json
29import sys
30import os
31
32import tarfile
33import git
34
35log = logging.getLogger(__name__)
36script_location = os.path.dirname(os.path.realpath(__file__))
37
38
39def prepare_application_repository(directory, url, refspec, patch_path):
40 """
41 Downloads git repository according to refspec, applies patch if provided
42 :param directory: path to repository
43 :param url: url to repository
44 :param refspec: refspec to fetch
45 :param patch_path: path git patch to be applied over repository
46 :return: repository - git repository object
47 """
48
49 try:
50 shutil.rmtree(directory)
51 except FileNotFoundError:
52 pass
53
54 log.info('Cloning {} with refspec {} '.format(url, refspec))
55 repository = git.Repo.init(directory)
56 origin = repository.create_remote('origin', url)
57 origin.pull(refspec)
58 repository.git.submodule('update', '--init')
59
60 if patch_path:
61 log.info('Applying {} over {} {}'.format(patch_path,
62 url,
63 refspec))
64 repository.git.apply(patch_path)
65 else:
66 log.info('No patch file provided, skipping patching')
67
68 return repository
69
70
Mateusz Pilatf7d2f572019-08-29 13:28:56 +020071def create_package_info_file(output_file, repository_list, tag):
Mateusz Pilat84ef3b32019-06-17 07:45:24 +020072 """
73 Generates text file in json format containing basic information about the build
74 :param output_file:
75 :param repository_list: list of repositories to be included in package info
76 :return:
77 """
78 log.info('Generating package.info file')
79 build_info = {
80 'Build_info': {
Mateusz Pilatf7d2f572019-08-29 13:28:56 +020081 'build_date': datetime.now().strftime('%Y-%m-%d_%H-%M'),
82 'Version': tag
Mateusz Pilat84ef3b32019-06-17 07:45:24 +020083 }
84 }
85 for repository in repository_list:
86 build_info['Build_info'][
87 repository.config_reader().get_value('remote "origin"', 'url')] = repository.head.commit.hexsha
88
89 with open(output_file, 'w') as outfile:
90 json.dump(build_info, outfile, indent=4)
91
92
93def create_package(tar_content, file_name):
94 """
95 Creates packages
96 :param tar_content: list of dictionaries defining src file and destination tar file
97 :param file_name: output file
98 """
99 log.info('Creating package {}'.format(file_name))
100 with tarfile.open(file_name, 'w') as output_tar_file:
101 for src, dst in tar_content.items():
Mateusz Pilatf7d2f572019-08-29 13:28:56 +0200102 if src != '':
103 output_tar_file.add(src, dst)
Mateusz Pilat84ef3b32019-06-17 07:45:24 +0200104
105
Mateusz Pilatf7d2f572019-08-29 13:28:56 +0200106def build_offline_deliverables(build_version,
107 application_repository_url,
Mateusz Pilat84ef3b32019-06-17 07:45:24 +0200108 application_repository_reference,
109 application_patch_file,
Mateusz Pilatf7d2f572019-08-29 13:28:56 +0200110 application_charts_dir,
111 application_configuration,
112 application_patch_role,
Mateusz Pilat84ef3b32019-06-17 07:45:24 +0200113 output_dir,
114 resources_directory,
Mateusz Pilatf7d2f572019-08-29 13:28:56 +0200115 aux_directory,
Mateusz Pilat84ef3b32019-06-17 07:45:24 +0200116 skip_sw,
117 skip_resources,
118 skip_aux,
119 overwrite):
120 """
121 Prepares offline deliverables
Mateusz Pilatf7d2f572019-08-29 13:28:56 +0200122 :param build_version: Version for packages tagging
Mateusz Pilat84ef3b32019-06-17 07:45:24 +0200123 :param application_repository_url: git repository hosting application helm charts
124 :param application_repository_reference: git refspec for repository hosting application helm charts
125 :param application_patch_file: git patch file to be applied over application repository
Mateusz Pilatf7d2f572019-08-29 13:28:56 +0200126 :param application_charts_dir: path to directory under application repository containing helm charts
127 :param application_configuration: path to application configuration file (helm override configuration)
128 :param application_patch_role: path to application patch role (executed just before helm deploy)
Mateusz Pilat84ef3b32019-06-17 07:45:24 +0200129 :param output_dir: Destination directory for saving packages
130 :param resources_directory: Path to resource directory
Mateusz Pilatf7d2f572019-08-29 13:28:56 +0200131 :param aux_directory: Path to aux binary directory
Mateusz Pilat84ef3b32019-06-17 07:45:24 +0200132 :param skip_sw: skip sw package generation
133 :param skip_resources: skip resources package generation
134 :param skip_aux: skip aux package generation
135 :param overwrite: overwrite files in output directory
136 :return:
137 """
138
139 if os.path.exists(output_dir) and os.listdir(output_dir):
140 if not overwrite:
141 log.error('Output directory is not empty, use overwrite to force build')
142 raise FileExistsError
Mateusz Pilatf7d2f572019-08-29 13:28:56 +0200143 shutil.rmtree(output_dir)
Mateusz Pilat84ef3b32019-06-17 07:45:24 +0200144
145 # Git
146 offline_repository_dir = os.path.join(script_location, '..')
147 offline_repository = git.Repo(offline_repository_dir)
148
149 application_dir = os.path.join(output_dir, 'application_repository')
150 application_repository = prepare_application_repository(application_dir,
151 application_repository_url,
152 application_repository_reference,
153 application_patch_file)
154
155 # Package info
156 info_file = os.path.join(output_dir, 'package.info')
Mateusz Pilatf7d2f572019-08-29 13:28:56 +0200157 create_package_info_file(info_file, [application_repository, offline_repository], build_version)
Mateusz Pilat84ef3b32019-06-17 07:45:24 +0200158
159 # packages layout as dictionaries. <file> : <file location under tar archive>
160 sw_content = {
161 os.path.join(offline_repository_dir, 'ansible'): 'ansible',
Mateusz Pilatf7d2f572019-08-29 13:28:56 +0200162 application_configuration: 'ansible/application/application_configuration.yml',
163 application_patch_role: 'ansible/application/onap-patch-role',
164 os.path.join(application_dir, application_charts_dir): 'ansible/application/helm_charts',
165 info_file: 'package.info'
Mateusz Pilat84ef3b32019-06-17 07:45:24 +0200166 }
167 resources_content = {
168 resources_directory: '',
Mateusz Pilatf7d2f572019-08-29 13:28:56 +0200169 info_file: 'package.info'
Mateusz Pilat84ef3b32019-06-17 07:45:24 +0200170 }
171 aux_content = {
Mateusz Pilatf7d2f572019-08-29 13:28:56 +0200172 aux_directory: '',
173 info_file: 'package.info'
Mateusz Pilat84ef3b32019-06-17 07:45:24 +0200174 }
175
176 if not skip_sw:
177 log.info('Building offline installer')
178 os.chdir(os.path.join(offline_repository_dir, 'ansible', 'docker'))
179 installer_build = subprocess.run(
180 os.path.join(offline_repository_dir, 'ansible', 'docker', 'build_ansible_image.sh'))
181 installer_build.check_returncode()
182 os.chdir(script_location)
Mateusz Pilatf7d2f572019-08-29 13:28:56 +0200183 sw_package_tar_path = os.path.join(output_dir, 'sw_package' + build_version + '.tar')
Mateusz Pilat84ef3b32019-06-17 07:45:24 +0200184 create_package(sw_content, sw_package_tar_path)
185
186 if not skip_resources:
187 log.info('Building own dns image')
188 dns_build = subprocess.run([
189 os.path.join(offline_repository_dir, 'build', 'creating_data', 'create_nginx_image', '01create-image.sh'),
190 os.path.join(resources_directory, 'offline_data', 'docker_images_infra')])
191 dns_build.check_returncode()
192
193 # Workaround for downloading without "flat" option
194 log.info('Binaries - workaround')
195 download_dir_path = os.path.join(resources_directory, 'downloads')
196 os.chdir(download_dir_path)
197 for file in os.listdir():
198 if os.path.islink(file):
199 os.unlink(file)
200
201 rke_files = glob.glob(os.path.join('.', '**/rke_linux-amd64'), recursive=True)
202 os.symlink(rke_files[0], os.path.join(download_dir_path, rke_files[0].split('/')[-1]))
203
204 helm_tar_files = glob.glob(os.path.join('.', '**/helm-*-linux-amd64.tar.gz'), recursive=True)
205 os.symlink(helm_tar_files[0], os.path.join(download_dir_path, helm_tar_files[0].split('/')[-1]))
206
207 kubectl_files = glob.glob(os.path.join('.', '**/kubectl'), recursive=True)
208 os.symlink(kubectl_files[0], os.path.join(download_dir_path, kubectl_files[0].split('/')[-1]))
209
210 os.chdir(script_location)
211 # End of workaround
212
Mateusz Pilatf7d2f572019-08-29 13:28:56 +0200213 resources_package_tar_path = os.path.join(output_dir, 'resources_package' + build_version + '.tar')
Mateusz Pilat84ef3b32019-06-17 07:45:24 +0200214 create_package(resources_content, resources_package_tar_path)
215
216 if not skip_aux:
Mateusz Pilatf7d2f572019-08-29 13:28:56 +0200217 aux_package_tar_path = os.path.join(output_dir, 'aux_package'+ build_version + '.tar')
Mateusz Pilat84ef3b32019-06-17 07:45:24 +0200218 create_package(aux_content, aux_package_tar_path)
219
220 shutil.rmtree(application_dir)
221
222
223def run_cli():
224 """
225 Run as cli tool
226 """
227 parser = argparse.ArgumentParser(description='Create Package For Offline Installer')
Mateusz Pilatf7d2f572019-08-29 13:28:56 +0200228 parser.add_argument('--build-version',
229 help='version of the build', default='custom')
Mateusz Pilat84ef3b32019-06-17 07:45:24 +0200230 parser.add_argument('application_repository_url', metavar='application-repository-url',
231 help='git repository hosting application helm charts')
232 parser.add_argument('--application-repository_reference', default='master',
233 help='git refspec for repository hosting application helm charts')
234 parser.add_argument('--application-patch_file',
235 help='git patch file to be applied over application repository', default='')
Mateusz Pilatf7d2f572019-08-29 13:28:56 +0200236 parser.add_argument('--application-charts_dir',
237 help='path to directory under application repository containing helm charts ', default='kubernetes')
238 parser.add_argument('--application-configuration',
239 help='path to application configuration file (helm override configuration)',
240 default='')
241 parser.add_argument('--application-patch-role',
242 help='path to application patch role file (ansible role) to be executed right before installation',
243 default='')
Mateusz Pilat84ef3b32019-06-17 07:45:24 +0200244 parser.add_argument('--output-dir', '-o', default=os.path.join(script_location, '..', '..'),
245 help='Destination directory for saving packages')
Mateusz Pilatf7d2f572019-08-29 13:28:56 +0200246 parser.add_argument('--resources-directory', default='',
Mateusz Pilat84ef3b32019-06-17 07:45:24 +0200247 help='Path to resource directory')
Mateusz Pilatf7d2f572019-08-29 13:28:56 +0200248 parser.add_argument('--aux-directory',
249 help='Path to aux binary directory', default='')
Mateusz Pilat84ef3b32019-06-17 07:45:24 +0200250 parser.add_argument('--skip-sw', action='store_true', default=False,
251 help='Set to skip sw package generation')
252 parser.add_argument('--skip-resources', action='store_true', default=False,
253 help='Set to skip resources package generation')
254 parser.add_argument('--skip-aux', action='store_true', default=False,
255 help='Set to skip aux package generation')
256 parser.add_argument('--overwrite', action='store_true', default=False,
257 help='overwrite files in output directory')
258 parser.add_argument('--debug', action='store_true', default=False,
259 help='Turn on debug output')
260 args = parser.parse_args()
261
262 if args.debug:
263 logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
264 else:
265 logging.basicConfig(stream=sys.stdout, level=logging.INFO, format='%(message)s')
266
Mateusz Pilatf7d2f572019-08-29 13:28:56 +0200267 build_offline_deliverables(args.build_version,
268 args.application_repository_url,
Mateusz Pilat84ef3b32019-06-17 07:45:24 +0200269 args.application_repository_reference,
270 args.application_patch_file,
Mateusz Pilatf7d2f572019-08-29 13:28:56 +0200271 args.application_charts_dir,
272 args.application_configuration,
273 args.application_patch_role,
Mateusz Pilat84ef3b32019-06-17 07:45:24 +0200274 args.output_dir,
275 args.resources_directory,
Mateusz Pilatf7d2f572019-08-29 13:28:56 +0200276 args.aux_directory,
Mateusz Pilat84ef3b32019-06-17 07:45:24 +0200277 args.skip_sw,
278 args.skip_resources,
279 args.skip_aux,
280 args.overwrite)
281
282
283if __name__ == '__main__':
284 run_cli()