Browse code

Additional improvements to image builder

-Remove the use of photoninstaller.py
-Replace image builder script
-Enhance image builder config file
-Support image building using config files from Makefile
- make image IMG_NAME=<name>
- make image CONFIG=<config_file>
- or combination of both the above

Change-Id: I1a0db70969224826130c5e4c25a74e7217a8dace
Reviewed-on: http://photon-jenkins.eng.vmware.com:8082/6150
Reviewed-by: Anish Swaminathan <anishs@vmware.com>
Tested-by: Anish Swaminathan <anishs@vmware.com>

suezzelur authored on 2018/11/12 14:33:14
Showing 40 changed files
... ...
@@ -128,6 +128,7 @@ packages-minimal: check-tools $(PHOTON_STAGE) $(PHOTON_PUBLISH_RPMS) $(PHOTON_SO
128 128
 		--dist-tag $(PHOTON_DIST_TAG) \
129 129
 		--build-number $(PHOTON_BUILD_NUMBER) \
130 130
 		--release-version $(PHOTON_RELEASE_VERSION) \
131
+		--pkginfo-file $(PHOTON_PKGINFO_FILE) \
131 132
 		$(PHOTON_RPMCHECK_FLAGS) \
132 133
 		$(PUBLISH_BUILD_DEPENDENCIES) \
133 134
 		$(PACKAGE_WEIGHTS) \
... ...
@@ -152,7 +153,7 @@ packages: check-docker-py check-tools $(PHOTON_STAGE) $(PHOTON_PUBLISH_XRPMS) $(
152 152
 		--dist-tag $(PHOTON_DIST_TAG) \
153 153
 		--build-number $(PHOTON_BUILD_NUMBER) \
154 154
 		--release-version $(PHOTON_RELEASE_VERSION) \
155
-		--pkginfo-file $(PHOTON_STAGE)/pkg_info.json \
155
+		--pkginfo-file $(PHOTON_PKGINFO_FILE) \
156 156
 		$(PACKAGE_BUILD_OPTIONS) \
157 157
 		$(PHOTON_RPMCHECK_FLAGS) \
158 158
 		$(PHOTON_KAT_BUILD_FLAGS) \
... ...
@@ -179,7 +180,7 @@ packages-docker: check-docker-py check-docker-service check-tools $(PHOTON_STAGE
179 179
 		--dist-tag $(PHOTON_DIST_TAG) \
180 180
 		--build-number $(PHOTON_BUILD_NUMBER) \
181 181
 		--release-version $(PHOTON_RELEASE_VERSION) \
182
-		--pkginfo-file $(PHOTON_STAGE)/pkg_info.json \
182
+		--pkginfo-file $(PHOTON_PKGINFO_FILE) \
183 183
 		$(PACKAGE_BUILD_OPTIONS) \
184 184
 		$(PHOTON_RPMCHECK_FLAGS) \
185 185
 		$(PUBLISH_BUILD_DEPENDENCIES) \
... ...
@@ -296,7 +297,7 @@ check: packages
296 296
 		--dist-tag $(PHOTON_DIST_TAG) \
297 297
 		--build-number $(PHOTON_BUILD_NUMBER) \
298 298
 		--release-version $(PHOTON_RELEASE_VERSION) \
299
-		--pkginfo-file $(PHOTON_STAGE)/pkg_info.json \
299
+		--pkginfo-file $(PHOTON_PKGINFO_FILE) \
300 300
 		$(PACKAGE_BUILD_OPTIONS) \
301 301
 		--enable-rpmcheck \
302 302
 		$(rpmcheck_stop_on_error) \
... ...
@@ -310,89 +311,83 @@ all: iso photon-docker-image k8s-docker-images all-images src-iso
310 310
 
311 311
 iso: check-tools $(PHOTON_STAGE) $(PHOTON_PACKAGES)
312 312
 	@echo "Building Photon Full ISO..."
313
-	@cd $(PHOTON_INSTALLER_DIR) && \
314
-	sudo $(PHOTON_INSTALLER) \
313
+	@cd $(PHOTON_IMAGE_BUILDER_DIR) && \
314
+	sudo $(PHOTON_IMAGE_BUILDER) \
315 315
 		--iso-path $(PHOTON_STAGE)/photon-$(PHOTON_RELEASE_VERSION)-$(PHOTON_BUILD_NUMBER).iso \
316 316
 		--debug-iso-path $(PHOTON_STAGE)/photon-$(PHOTON_RELEASE_VERSION)-$(PHOTON_BUILD_NUMBER).debug.iso \
317
-		--working-directory $(PHOTON_STAGE)/photon_iso \
318 317
 		--log-path $(PHOTON_STAGE)/LOGS \
319 318
 		--log-level $(LOGLEVEL) \
320 319
 		--rpm-path $(PHOTON_STAGE)/RPMS \
321 320
 		--srpm-path $(PHOTON_STAGE)/SRPMS \
322 321
 		--package-list-file $(PHOTON_GENERATED_DATA_DIR)/$(FULL_PACKAGE_LIST_FILE) \
323
-		--output-data-path $(PHOTON_STAGE)/common/data \
324
-		--pkg-to-rpm-map-file $(PHOTON_STAGE)/pkg_info.json \
325
-		--json-data-path $(PHOTON_DATA_DIR) \
326
-		--force > \
322
+		--generated-data-path $(PHOTON_STAGE)/common/data \
323
+		--pkg-to-rpm-map-file $(PHOTON_PKGINFO_FILE) > \
327 324
 		$(PHOTON_LOGS_DIR)/installer.log 2>&1
328 325
 
329 326
 src-iso: check-tools $(PHOTON_STAGE) $(PHOTON_PACKAGES)
330 327
 	@echo "Building Photon Full Source ISO..."
331
-	@cd $(PHOTON_INSTALLER_DIR) && \
332
-	sudo $(PHOTON_INSTALLER) \
328
+	@cd $(PHOTON_IMAGE_BUILDER_DIR) && \
329
+	sudo $(PHOTON_IMAGE_BUILDER) \
333 330
 		--src-iso-path $(PHOTON_STAGE)/photon-$(PHOTON_RELEASE_VERSION)-$(PHOTON_BUILD_NUMBER).src.iso \
334
-		--working-directory $(PHOTON_STAGE)/photon_iso \
335 331
 		--log-path $(PHOTON_STAGE)/LOGS \
336 332
 		--log-level $(LOGLEVEL) \
337 333
 		--rpm-path $(PHOTON_STAGE)/RPMS \
338 334
 		--srpm-path $(PHOTON_STAGE)/SRPMS \
339 335
 		--package-list-file $(PHOTON_GENERATED_DATA_DIR)/$(FULL_PACKAGE_LIST_FILE) \
340
-		--output-data-path $(PHOTON_STAGE)/common/data \
341
-		--pkg-to-rpm-map-file $(PHOTON_STAGE)/pkg_info.json \
342
-		--json-data-path $(PHOTON_DATA_DIR) \
343
-		--force > \
336
+		--generated-data-path $(PHOTON_STAGE)/common/data \
337
+		--pkg-to-rpm-map-file $(PHOTON_PKGINFO_FILE) > \
344 338
 		$(PHOTON_LOGS_DIR)/sourceiso-installer.log 2>&1
345 339
 
346 340
 image: check-kpartx $(PHOTON_STAGE) $(VIXDISKUTIL) $(PHOTON_PACKAGES)
347
-	@echo "Building image $(IMG_NAME)..."
341
+	@echo "Building image using $(CONFIG)..."
348 342
 	@cd $(PHOTON_IMAGE_BUILDER_DIR)
349 343
 	$(PHOTON_IMAGE_BUILDER) \
350
-		--build-scripts-path=$(PHOTON_IMAGE_BUILDER_DIR) \
351
-	--img-name=$(IMG_NAME) \
352
-	--src-root=$(SRCROOT) \
353
-	--generated-data-path=$(PHOTON_GENERATED_DATA_DIR) \
354
-	--stage-path=$(PHOTON_STAGE) \
355
-	--additional-rpms-path=$(ADDITIONAL_RPMS_PATH)
356
-
344
+		--config-file=$(CONFIG) \
345
+		--img-name=$(IMG_NAME) \
346
+		--src-root=$(SRCROOT) \
347
+		--generated-data-path=$(PHOTON_GENERATED_DATA_DIR) \
348
+		--stage-path=$(PHOTON_STAGE) \
349
+		--rpm-path $(PHOTON_STAGE)/RPMS \
350
+		--additional-rpms-path=$(ADDITIONAL_RPMS_PATH)
357 351
 
358 352
 all-images: check-kpartx $(PHOTON_STAGE) $(VIXDISKUTIL) $(PHOTON_PACKAGES)
359 353
 	@echo "Building all images - gce, ami, azure, ova..."
360 354
 	@cd $(PHOTON_IMAGE_BUILDER_DIR)
361 355
 	$(PHOTON_IMAGE_BUILDER) \
362
-		--build-scripts-path=$(PHOTON_IMAGE_BUILDER_DIR) \
363
-		--img-name=ami \
364 356
 		--src-root=$(SRCROOT) \
365 357
 		--generated-data-path=$(PHOTON_GENERATED_DATA_DIR) \
366 358
 		--stage-path=$(PHOTON_STAGE) \
367
-		--additional-rpms-path=$(ADDITIONAL_RPMS_PATH)
359
+		--rpm-path $(PHOTON_STAGE)/RPMS \
360
+		--additional-rpms-path=$(ADDITIONAL_RPMS_PATH) \
361
+		--img-name=ami
368 362
 	$(PHOTON_IMAGE_BUILDER) \
369
-		--build-scripts-path=$(PHOTON_IMAGE_BUILDER_DIR) \
370
-		--img-name=azure \
371 363
 		--src-root=$(SRCROOT) \
372 364
 		--generated-data-path=$(PHOTON_GENERATED_DATA_DIR) \
373 365
 		--stage-path=$(PHOTON_STAGE) \
374
-		--additional-rpms-path=$(ADDITIONAL_RPMS_PATH)
366
+		--rpm-path $(PHOTON_STAGE)/RPMS \
367
+		--additional-rpms-path=$(ADDITIONAL_RPMS_PATH) \
368
+		--img-name=gce
375 369
 	$(PHOTON_IMAGE_BUILDER) \
376
-		--build-scripts-path=$(PHOTON_IMAGE_BUILDER_DIR) \
377
-		--img-name=gce \
378 370
 		--src-root=$(SRCROOT) \
379 371
 		--generated-data-path=$(PHOTON_GENERATED_DATA_DIR) \
380 372
 		--stage-path=$(PHOTON_STAGE) \
381
-		--additional-rpms-path=$(ADDITIONAL_RPMS_PATH)
373
+		--rpm-path $(PHOTON_STAGE)/RPMS \
374
+		--additional-rpms-path=$(ADDITIONAL_RPMS_PATH) \
375
+		--img-name=azure
382 376
 	$(PHOTON_IMAGE_BUILDER) \
383
-		--build-scripts-path=$(PHOTON_IMAGE_BUILDER_DIR) \
384
-		--img-name=ova \
385 377
 		--src-root=$(SRCROOT) \
386 378
 		--generated-data-path=$(PHOTON_GENERATED_DATA_DIR) \
387 379
 		--stage-path=$(PHOTON_STAGE) \
388
-		--additional-rpms-path=$(ADDITIONAL_RPMS_PATH)
380
+		--rpm-path $(PHOTON_STAGE)/RPMS \
381
+		--additional-rpms-path=$(ADDITIONAL_RPMS_PATH) \
382
+		--img-name=ova
389 383
 	$(PHOTON_IMAGE_BUILDER) \
390
-		--build-scripts-path=$(PHOTON_IMAGE_BUILDER_DIR) \
391
-		--img-name=ova_uefi \
392 384
 		--src-root=$(SRCROOT) \
393 385
 		--generated-data-path=$(PHOTON_GENERATED_DATA_DIR) \
394 386
 		--stage-path=$(PHOTON_STAGE) \
395
-		--additional-rpms-path=$(ADDITIONAL_RPMS_PATH)
387
+		--rpm-path $(PHOTON_STAGE)/RPMS \
388
+		--additional-rpms-path=$(ADDITIONAL_RPMS_PATH) \
389
+		--img-name=ova_uefi
396 390
 
397 391
 photon-docker-image:
398 392
 	$(PHOTON_REPO_TOOL) $(PHOTON_RPMS_DIR)
... ...
@@ -1,5 +1,4 @@
1 1
 #
2
-#    Copyright (C) 2015 vmware inc.
3 2
 #
4 3
 #    Author: Mahmoud Bassiouny <mbassiouny@vmware.com>
5 4
 
... ...
@@ -1,5 +1,4 @@
1 1
 #
2
-#    Copyright (C) 2015 vmware inc.
3 2
 #
4 3
 #    Author: Mahmoud Bassiouny <mbassiouny@vmware.com>
5 4
 
... ...
@@ -1,5 +1,4 @@
1 1
 #
2
-#    Copyright (C) 2015 vmware inc.
3 2
 #
4 3
 #    Author: Mahmoud Bassiouny <mbassiouny@vmware.com>
5 4
 
... ...
@@ -1,5 +1,4 @@
1 1
 #
2
-#    Copyright (C) 2015 vmware inc.
3 2
 #
4 3
 #    Author: Mahmoud Bassiouny <mbassiouny@vmware.com>
5 4
 
... ...
@@ -1,7 +1,6 @@
1 1
 """
2 2
 Photon installer
3 3
 """
4
-#    Copyright (C) 2015 vmware inc.
5 4
 #
6 5
 #    Author: Mahmoud Bassiouny <mbassiouny@vmware.com>
7 6
 
... ...
@@ -414,11 +413,10 @@ class Installer(object):
414 414
         """
415 415
         Execute the scripts in the modules folder
416 416
         """
417
-        sys.path.append("./modules")
418
-        modules_paths = glob.glob('modules/m_*.py')
417
+        sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "modules")))
418
+        modules_paths = glob.glob(os.path.abspath(os.path.join(os.path.dirname(__file__), 'modules')) + '/m_*.py')
419 419
         for mod_path in modules_paths:
420
-            module = mod_path.replace('/', '.', 1)
421
-            module = os.path.splitext(module)[0]
420
+            module = os.path.splitext(os.path.basename(mod_path))[0]
422 421
             try:
423 422
                 __import__(module)
424 423
                 mod = sys.modules[module]
... ...
@@ -445,7 +443,6 @@ class Installer(object):
445 445
                 modules.commons.log(modules.commons.LOG_ERROR,
446 446
                                     "Error: not able to execute module {}".format(module))
447 447
                 continue
448
-
449 448
             mod.execute(self.install_config, self.photon_root)
450 449
 
451 450
     def _adjust_packages_for_vmware_virt(self):
... ...
@@ -1,5 +1,4 @@
1 1
 #
2
-#    Copyright (C) 2015 vmware inc.
3 2
 #
4 3
 #    Author: Touseef Liaqat <tliaqat@vmware.com>
5 4
 
... ...
@@ -1,6 +1,5 @@
1 1
 #! /usr/bin/python3
2 2
 #
3
-#    Copyright (C) 2015 vmware inc.
4 3
 #
5 4
 #    Author: Mahmoud Bassiouny <mbassiouny@vmware.com>
6 5
 
... ...
@@ -1,5 +1,4 @@
1 1
 #
2
-#    Copyright (C) 2015 vmware inc.
3 2
 #
4 3
 #    Author: Sharath George <sharathg@vmware.com>
5 4
 
... ...
@@ -1,5 +1,4 @@
1 1
 #
2
-#    Copyright (C) 2015 vmware inc.
3 2
 #
4 3
 #    Author: Mahmoud Bassiouny <mbassiouny@vmware.com>
5 4
 
... ...
@@ -1,5 +1,4 @@
1 1
 #
2
-#    Copyright (C) 2015 vmware inc.
3 2
 #
4 3
 #    Author: Mahmoud Bassiouny <mbassiouny@vmware.com>
5 4
 
... ...
@@ -31,26 +31,25 @@ PACKAGE_LIST_FILE=$3
31 31
 RPM_LIST=$4
32 32
 STAGE_PATH=$5
33 33
 ADDITIONAL_FILES_TO_COPY_FROM_STAGE=$6
34
-LIVE_CD=$7
35
-OUTPUT_DATA_PATH=$8
34
+OUTPUT_DATA_PATH=$7
36 35
 PHOTON_COMMON_DIR=$(dirname "${PACKAGE_LIST_FILE}")
37 36
 PACKAGE_LIST_FILE_BASE_NAME=$(basename "${PACKAGE_LIST_FILE}")
38 37
 #- Step 3 Setting up the boot loader
39 38
 WORKINGDIR=${BUILDROOT}
40 39
 BUILDROOT=${BUILDROOT}/photon-chroot
41 40
 
42
-run_command "cp isolinux to working directory: ${WORKINGDIR}" "cp -r BUILD_DVD/isolinux ${WORKINGDIR}/" "${LOGFILE}"
43
-run_command "cp boot/grub2 to working directory: ${WORKINGDIR}" "cp -r BUILD_DVD/boot ${WORKINGDIR}/" "${LOGFILE}"
41
+run_command "cp isolinux to working directory: ${WORKINGDIR}" "cp -r $SCRIPT_PATH/BUILD_DVD/isolinux ${WORKINGDIR}/" "${LOGFILE}"
42
+run_command "cp boot/grub2 to working directory: ${WORKINGDIR}" "cp -r $SCRIPT_PATH/BUILD_DVD/boot ${WORKINGDIR}/" "${LOGFILE}"
44 43
 run_command "# 1" "mkdir ${WORKINGDIR}/boot/grub2/fonts/" "${LOGFILE}"
45
-run_command "# 2" "cp boot/ascii.pf2 ${WORKINGDIR}/boot/grub2/fonts/" "${LOGFILE}"
44
+run_command "# 2" "cp $SCRIPT_PATH/boot/ascii.pf2 ${WORKINGDIR}/boot/grub2/fonts/" "${LOGFILE}"
46 45
 run_command "# 3" "mkdir -p ${WORKINGDIR}/boot/grub2/themes/photon/" "${LOGFILE}"
47
-run_command "# 4" "cp boot/splash.png ${WORKINGDIR}/boot/grub2/themes/photon/photon.png" "${LOGFILE}"
48
-run_command "# 5" "cp boot/terminal_*.tga ${WORKINGDIR}/boot/grub2/themes/photon/" "${LOGFILE}"
49
-run_command "# 6" "cp boot/theme.txt ${WORKINGDIR}/boot/grub2/themes/photon/" "${LOGFILE}"
46
+run_command "# 4" "cp $SCRIPT_PATH/boot/splash.png ${WORKINGDIR}/boot/grub2/themes/photon/photon.png" "${LOGFILE}"
47
+run_command "# 5" "cp $SCRIPT_PATH/boot/terminal_*.tga ${WORKINGDIR}/boot/grub2/themes/photon/" "${LOGFILE}"
48
+run_command "# 6" "cp $SCRIPT_PATH/boot/theme.txt ${WORKINGDIR}/boot/grub2/themes/photon/" "${LOGFILE}"
50 49
 run_command "echo : ${WORKINGDIR}" "echo ${WORKINGDIR}" "${LOGFILE}"
51
-cp BUILD_DVD/isolinux/splash.png ${BUILDROOT}/installer/boot/.
50
+cp $SCRIPT_PATH/BUILD_DVD/isolinux/splash.png ${BUILDROOT}/installer/boot/.
52 51
 mkdir -p ${BUILDROOT}/installer/EFI/BOOT
53
-cp EFI_$(uname -m)/BOOT/* ${BUILDROOT}/installer/EFI/BOOT/
52
+cp $SCRIPT_PATH/EFI_$(uname -m)/BOOT/* ${BUILDROOT}/installer/EFI/BOOT/
54 53
 
55 54
 #Generate efiboot image
56 55
 # efiboot is a fat16 image that has at least EFI/BOOT/bootx64.efi
... ...
@@ -74,18 +73,14 @@ mkdir $EFI_FOLDER
74 74
 mount -o loop ${WORKINGDIR}/${EFI_IMAGE} $EFI_FOLDER
75 75
 mkdir $EFI_FOLDER/EFI
76 76
 mkdir ${WORKINGDIR}/EFI
77
-cp -r ./EFI_$(uname -m)/BOOT $EFI_FOLDER/EFI/
78
-cp -r ./EFI_$(uname -m)/BOOT ${WORKINGDIR}/EFI/
77
+cp -r $SCRIPT_PATH/EFI_$(uname -m)/BOOT $EFI_FOLDER/EFI/
78
+cp -r $SCRIPT_PATH/EFI_$(uname -m)/BOOT ${WORKINGDIR}/EFI/
79 79
 ls -lR $EFI_FOLDER
80 80
 umount $EFI_FOLDER
81 81
 rm -rf $EFI_FOLDER
82 82
 #mcopy -s -i ${WORKINGDIR}/${EFI_IMAGE} ./EFI '::/'
83 83
 
84
-if [ "$LIVE_CD" = true ] ; then
85
-    mv ${WORKINGDIR}/isolinux/live-menu.cfg ${WORKINGDIR}/isolinux/menu.cfg
86
-fi
87
-
88
-cp sample_ks.cfg ${WORKINGDIR}/isolinux/
84
+cp $SCRIPT_PATH/sample_ks.cfg ${WORKINGDIR}/isolinux/
89 85
 
90 86
 find ${BUILDROOT} -name linux-[0-9]*.rpm | head -1 | xargs rpm2cpio | cpio -iv --to-stdout ./boot/vmlinuz* > ${WORKINGDIR}/isolinux/vmlinuz
91 87
 
... ...
@@ -110,7 +105,7 @@ mkdir -p ${BUILDROOT}/etc/systemd/scripts
110 110
 
111 111
 # Step 6 create fstab
112 112
 
113
-cp BUILD_DVD/fstab ${BUILDROOT}/etc/fstab
113
+cp $SCRIPT_PATH/BUILD_DVD/fstab ${BUILDROOT}/etc/fstab
114 114
 
115 115
 mkdir -p ${BUILDROOT}/etc/yum.repos.d
116 116
 cat >> ${BUILDROOT}/etc/yum.repos.d/photon-iso.repo << EOF
... ...
@@ -124,8 +119,6 @@ skip_if_unavailable=True
124 124
 EOF
125 125
 
126 126
 #- Step 7 - Create installer script
127
-if [ "$LIVE_CD" = false ] ; then
128
-
129 127
 cat >> ${BUILDROOT}/bin/bootphotoninstaller << EOF
130 128
 #!/bin/bash
131 129
 cd /installer
... ...
@@ -135,8 +128,6 @@ EOF
135 135
 
136 136
 chmod 755 ${BUILDROOT}/bin/bootphotoninstaller
137 137
 
138
-fi
139
-
140 138
 cat >> ${BUILDROOT}/init << EOF
141 139
 mount -t proc proc /proc
142 140
 /lib/systemd/systemd
... ...
@@ -148,11 +139,7 @@ chmod 755 ${BUILDROOT}/init
148 148
 sed -i "s/ExecStart.*/ExecStart=-\/sbin\/agetty --autologin root --noclear %I linux/g" ${BUILDROOT}/lib/systemd/system/getty@.service
149 149
 
150 150
 #- Step 7 - Create installer script
151
-if [ "$LIVE_CD" = false ] ; then
152
-
153
-    sed -i "s/root:.*/root:x:0:0:root:\/root:\/bin\/bootphotoninstaller/g" ${BUILDROOT}/etc/passwd
154
-
155
-fi
151
+sed -i "s/root:.*/root:x:0:0:root:\/root:\/bin\/bootphotoninstaller/g" ${BUILDROOT}/etc/passwd
156 152
 
157 153
 mkdir -p ${BUILDROOT}/mnt/photon-root/photon-chroot
158 154
 rm -rf ${BUILDROOT}/RPMS
... ...
@@ -192,99 +179,96 @@ fi
192 192
 
193 193
 rm -rf ${BUILDROOT}/LOGS
194 194
 
195
-if [ "$LIVE_CD" = false ] ; then
196
-    # Cleaning up
197
-    #Remove our rpm database as it fills up the ramdisk
198
-    for filename in ${BUILDROOT}/usr/lib/*; do 
199
-        #run_command " echo ${filename}" "echo ${filename}" "${LOGFILE}"
200
-        if [[ -f ${filename} ]]; then
201
-            file ${filename} | grep ELF >/dev/null 2>&1
202
-            #run_command " file ${filename}" "echo ${filename}" "${LOGFILE}"
203
-            if [[ $? -eq 0 ]]; then
204
-                run_command " strip ${filename}" "strip ${filename}" "${LOGFILE}"
205
-            fi;
195
+# Cleaning up
196
+#Remove our rpm database as it fills up the ramdisk
197
+for filename in ${BUILDROOT}/usr/lib/*; do 
198
+    #run_command " echo ${filename}" "echo ${filename}" "${LOGFILE}"
199
+    if [[ -f ${filename} ]]; then
200
+        file ${filename} | grep ELF >/dev/null 2>&1
201
+        #run_command " file ${filename}" "echo ${filename}" "${LOGFILE}"
202
+        if [[ $? -eq 0 ]]; then
203
+            run_command " strip ${filename}" "strip ${filename}" "${LOGFILE}"
206 204
         fi;
207
-    done
208
-
209
-    #Remove our rpm database as it fills up the ramdisk
210
-    for filename in $(find ${BUILDROOT}/usr/lib/modules); do 
211
-        #run_command " echo ${filename}" "echo ${filename}" "${LOGFILE}"
212
-        if [[ -f ${filename} ]]; then
213
-            file ${filename} | grep ELF >/dev/null 2>&1
214
-            #run_command " file ${filename}" "echo ${filename}" "${LOGFILE}"
215
-            if [[ $? -eq 0 ]]; then
216
-                run_command " strip ${filename}" "strip ${filename}" "${LOGFILE}"
217
-            fi;
205
+    fi;
206
+done
207
+
208
+#Remove our rpm database as it fills up the ramdisk
209
+for filename in $(find ${BUILDROOT}/usr/lib/modules); do 
210
+    #run_command " echo ${filename}" "echo ${filename}" "${LOGFILE}"
211
+    if [[ -f ${filename} ]]; then
212
+        file ${filename} | grep ELF >/dev/null 2>&1
213
+        #run_command " file ${filename}" "echo ${filename}" "${LOGFILE}"
214
+        if [[ $? -eq 0 ]]; then
215
+            run_command " strip ${filename}" "strip ${filename}" "${LOGFILE}"
218 216
         fi;
219
-    done
220
-    rm -rf ${BUILDROOT}/home/*
221
-    rm -rf ${BUILDROOT}/var/lib/rpm
222
-
223
-    # Remove the boot directory
224
-    rm -rf ${BUILDROOT}/boot
225
-
226
-    #Remove the include files.
227
-    rm -rf ${BUILDROOT}/usr/include
228
-
229
-    rm ${BUILDROOT}/lib64/libmvec*
230
-    rm ${BUILDROOT}/usr/sbin/sln
231
-    rm ${BUILDROOT}/usr/bin/oldfind
232
-
233
-    rm ${BUILDROOT}/usr/bin/localedef
234
-    rm ${BUILDROOT}/usr/bin/systemd-nspawn
235
-    rm ${BUILDROOT}/usr/bin/systemd-analyze
236
-    rm -rf ${BUILDROOT}/usr/lib64/gconv
237
-    rm ${BUILDROOT}/usr/bin/sqlite3
238
-
239
-    rm ${BUILDROOT}/usr/bin/bsdcpio
240
-    rm ${BUILDROOT}/usr/bin/bsdtar
241
-    rm ${BUILDROOT}/usr/bin/networkctl
242
-    rm ${BUILDROOT}/usr/bin/machinectl
243
-    rm ${BUILDROOT}/usr/bin/pkg-config
244
-    rm ${BUILDROOT}/usr/bin/openssl
245
-    rm ${BUILDROOT}/usr/bin/timedatectl
246
-    rm ${BUILDROOT}/usr/bin/localectl
247
-    rm ${BUILDROOT}/usr/bin/systemd-cgls
248
-    rm ${BUILDROOT}/usr/bin/systemd-inhibit
249
-    rm ${BUILDROOT}/usr/bin/systemd-studio-bridge
250
-    rm ${BUILDROOT}/usr/bin/iconv
251
-
252
-    rm -rf ${BUILDROOT}/usr/lib/python2.7/lib2to3
253
-    rm -rf ${BUILDROOT}/usr/lib/python2.7/lib-tk
254
-    rm -rf ${BUILDROOT}/usr/lib/python2.7/ensurepip
255
-    rm -rf ${BUILDROOT}/usr/lib/python2.7/distutils
256
-    rm -rf ${BUILDROOT}/usr/lib/python2.7/pydoc_data
257
-    rm -rf ${BUILDROOT}/usr/lib/python2.7/idlelib
258
-    rm -rf ${BUILDROOT}/usr/lib/python2.7/unittest 
259
-
260
-    rm ${BUILDROOT}/usr/lib/librpmbuild.so*
261
-    rm ${BUILDROOT}/usr/lib/libdb_cxx*
262
-    rm ${BUILDROOT}/usr/lib/libnss_compat*
263
-
264
-    rm ${BUILDROOT}/usr/bin/grub2-*
265
-    rm ${BUILDROOT}/usr/lib/grub/i386-pc/*.module
266
-    rm ${BUILDROOT}/usr/lib/grub/x86_64-efi/*.module
267
-
268
-    for j in `ls ${BUILDROOT}/usr/sbin/grub2*`; do
269
-        bsname=$(basename "$j")
270
-        if [ $bsname != 'grub2-install' ]; then
271
-            rm $j
272
-        fi
273
-    done
274
-
275
-    # TODO: mbassiouny, Find a clean way to do that
276
-    for i in `ls ${BUILDROOT}/usr/share/`; do
277
-        if [ $i != 'terminfo' -a $i != 'cracklib' -a $i != 'grub' -a $i != 'factory' -a $i != 'dbus-1' ]; then
278
-            rm -rf ${BUILDROOT}/usr/share/$i
279
-        fi
280
-    done
217
+    fi;
218
+done
219
+rm -rf ${BUILDROOT}/home/*
220
+rm -rf ${BUILDROOT}/var/lib/rpm
221
+
222
+# Remove the boot directory
223
+rm -rf ${BUILDROOT}/boot
224
+
225
+#Remove the include files.
226
+rm -rf ${BUILDROOT}/usr/include
227
+
228
+rm ${BUILDROOT}/lib64/libmvec*
229
+rm ${BUILDROOT}/usr/sbin/sln
230
+rm ${BUILDROOT}/usr/bin/oldfind
231
+
232
+rm ${BUILDROOT}/usr/bin/localedef
233
+rm ${BUILDROOT}/usr/bin/systemd-nspawn
234
+rm ${BUILDROOT}/usr/bin/systemd-analyze
235
+rm -rf ${BUILDROOT}/usr/lib64/gconv
236
+rm ${BUILDROOT}/usr/bin/sqlite3
237
+
238
+rm ${BUILDROOT}/usr/bin/bsdcpio
239
+rm ${BUILDROOT}/usr/bin/bsdtar
240
+rm ${BUILDROOT}/usr/bin/networkctl
241
+rm ${BUILDROOT}/usr/bin/machinectl
242
+rm ${BUILDROOT}/usr/bin/pkg-config
243
+rm ${BUILDROOT}/usr/bin/openssl
244
+rm ${BUILDROOT}/usr/bin/timedatectl
245
+rm ${BUILDROOT}/usr/bin/localectl
246
+rm ${BUILDROOT}/usr/bin/systemd-cgls
247
+rm ${BUILDROOT}/usr/bin/systemd-inhibit
248
+rm ${BUILDROOT}/usr/bin/systemd-studio-bridge
249
+rm ${BUILDROOT}/usr/bin/iconv
250
+
251
+rm -rf ${BUILDROOT}/usr/lib/python2.7/lib2to3
252
+rm -rf ${BUILDROOT}/usr/lib/python2.7/lib-tk
253
+rm -rf ${BUILDROOT}/usr/lib/python2.7/ensurepip
254
+rm -rf ${BUILDROOT}/usr/lib/python2.7/distutils
255
+rm -rf ${BUILDROOT}/usr/lib/python2.7/pydoc_data
256
+rm -rf ${BUILDROOT}/usr/lib/python2.7/idlelib
257
+rm -rf ${BUILDROOT}/usr/lib/python2.7/unittest 
258
+
259
+rm ${BUILDROOT}/usr/lib/librpmbuild.so*
260
+rm ${BUILDROOT}/usr/lib/libdb_cxx*
261
+rm ${BUILDROOT}/usr/lib/libnss_compat*
262
+
263
+rm ${BUILDROOT}/usr/bin/grub2-*
264
+rm ${BUILDROOT}/usr/lib/grub/i386-pc/*.module
265
+rm ${BUILDROOT}/usr/lib/grub/x86_64-efi/*.module
266
+
267
+for j in `ls ${BUILDROOT}/usr/sbin/grub2*`; do
268
+    bsname=$(basename "$j")
269
+    if [ $bsname != 'grub2-install' ]; then
270
+        rm $j
271
+    fi
272
+done
281 273
 
282
-fi
274
+# TODO: mbassiouny, Find a clean way to do that
275
+for i in `ls ${BUILDROOT}/usr/share/`; do
276
+    if [ $i != 'terminfo' -a $i != 'cracklib' -a $i != 'grub' -a $i != 'factory' -a $i != 'dbus-1' ]; then
277
+        rm -rf ${BUILDROOT}/usr/share/$i
278
+    fi
279
+done
283 280
 
284 281
 # Set password max days to 99999 (disable aging)
285 282
 chroot ${BUILDROOT} /bin/bash -c "chage -M 99999 root"
286 283
 
287
-# Generate the intird
284
+# Generate the initrd
288 285
 pushd $BUILDROOT
289 286
 (find . | cpio -o -H newc --quiet | gzip -9 ) > ${WORKINGDIR}/isolinux/initrd.img
290 287
 popd
... ...
@@ -27,7 +27,9 @@ LOGFILE=/var/log/"${PRGNAME}-${LOGFILE}"    #   set log file name
27 27
 if mountpoint ${BUILDROOT}/run  >/dev/null 2>&1; then umount ${BUILDROOT}/run; fi
28 28
 if mountpoint ${BUILDROOT}/sys  >/dev/null 2>&1; then umount ${BUILDROOT}/sys; fi
29 29
 if mountpoint ${BUILDROOT}/proc >/dev/null 2>&1; then umount ${BUILDROOT}/proc; fi
30
-if mountpoint ${BUILDROOT}/dev  >/dev/null 2>&1; then umount -R ${BUILDROOT}/dev; fi
30
+if mountpoint ${BUILDROOT}/dev/pts  >/dev/null 2>&1; then umount ${BUILDROOT}/dev/pts; fi
31
+if mountpoint ${BUILDROOT}/dev  >/dev/null 2>&1; then umount ${BUILDROOT}/dev; fi
32
+sync
31 33
 [ ${EUID} -eq 0 ]   || fail "${PRGNAME}: Need to be root user: FAILURE"
32 34
 
33 35
 cd ${BUILDROOT} || fail "${PRGNAME}: Change directory: ${BUILDROOT}: FAILURE"
... ...
@@ -59,7 +61,8 @@ fi
59 59
 
60 60
 #   Mount kernel filesystem
61 61
 #
62
-if ! mountpoint ${BUILDROOT}/dev    >/dev/null 2>&1; then mount --rbind /dev ${BUILDROOT}/dev; mount --make-rslave ${BUILDROOT}/dev; fi
62
+if ! mountpoint ${BUILDROOT}/dev    >/dev/null 2>&1; then mount --bind /dev ${BUILDROOT}/dev; fi
63
+if ! mountpoint ${BUILDROOT}/dev/pts    >/dev/null 2>&1; then mount -t devpts devpts ${BUILDROOT}/dev/pts -o gid=5,mode=620; fi
63 64
 if ! mountpoint ${BUILDROOT}/proc   >/dev/null 2>&1; then mount -t proc proc ${BUILDROOT}/proc; fi
64 65
 if ! mountpoint ${BUILDROOT}/sys    >/dev/null 2>&1; then mount -t sysfs sysfs ${BUILDROOT}/sys; fi
65 66
 if ! mountpoint ${BUILDROOT}/run    >/dev/null 2>&1; then mount -t tmpfs tmpfs ${BUILDROOT}/run; fi
... ...
@@ -21,11 +21,12 @@ LOGFILE=/var/log/"${PRGNAME}-${LOGFILE}"    #   set log file name
21 21
 [ ${EUID} -eq 0 ]   || fail "${PRGNAME}: Need to be root user: FAILURE"
22 22
 [ -z ${BUILDROOT} ]     && fail "${PRGNAME}: BUILDROOT not set: FAILURE"
23 23
 
24
-if mountpoint ${BUILDROOT}/run >/dev/null 2>&1; then umount ${BUILDROOT}/run; fi
25
-if mountpoint ${BUILDROOT}/sys >/dev/null 2>&1; then umount ${BUILDROOT}/sys; fi
26
-if mountpoint ${BUILDROOT}/proc    >/dev/null 2>&1; then umount ${BUILDROOT}/proc; fi
27
-if mountpoint ${BUILDROOT}/dev >/dev/null 2>&1; then umount -R ${BUILDROOT}/dev; fi
28
-
24
+if mountpoint ${BUILDROOT}/run >/dev/null 2>&1; then umount -l ${BUILDROOT}/run; fi
25
+if mountpoint ${BUILDROOT}/sys >/dev/null 2>&1; then umount -l ${BUILDROOT}/sys; fi
26
+if mountpoint ${BUILDROOT}/proc    >/dev/null 2>&1; then umount -l ${BUILDROOT}/proc; fi
27
+if mountpoint ${BUILDROOT}/dev/pts >/dev/null 2>&1; then umount ${BUILDROOT}/dev/pts; fi
28
+if mountpoint ${BUILDROOT}/dev >/dev/null 2>&1; then umount ${BUILDROOT}/dev; fi
29
+sync
29 30
 while [[ $# > 0 ]]
30 31
 do
31 32
     key="$1"
... ...
@@ -38,7 +39,8 @@ do
38 38
         shift 2
39 39
 
40 40
         # make sure the directory exists
41
-        if mountpoint ${BUILDROOT}${MOUNTPOINT} >/dev/null 2>&1; then umount ${BUILDROOT}${MOUNTPOINT}; fi
41
+        if mountpoint ${BUILDROOT}${MOUNTPOINT} >/dev/null 2>&1; then umount -l ${BUILDROOT}${MOUNTPOINT}; fi
42
+        sync
42 43
     ;;
43 44
     *)
44 45
         # unknown option
... ...
@@ -1,5 +1,4 @@
1 1
 #
2
-#    Copyright (C) 2015 vmware inc.
3 2
 #
4 3
 #    Author: Mahmoud Bassiouny <mbassiouny@vmware.com>
5 4
 
6 5
deleted file mode 100755
... ...
@@ -1,345 +0,0 @@
1
-#! /usr/bin/python3
2
-#
3
-#    Copyright (C) 2015 vmware inc.
4
-#
5
-#    Author: Mahmoud Bassiouny <mbassiouny@vmware.com>
6
-
7
-from argparse import ArgumentParser
8
-from installer import Installer
9
-import crypt
10
-import random
11
-import string
12
-import subprocess
13
-import sys
14
-import os
15
-from jsonwrapper import JsonWrapper
16
-from packageselector import PackageSelector
17
-
18
-def query_yes_no(question, default="no"):
19
-    valid = {"yes": True, "y": True, "ye": True,
20
-             "no": False, "n": False}
21
-    if default is None:
22
-        prompt = " [y/n] "
23
-    elif default == "yes":
24
-        prompt = " [Y/n] "
25
-    elif default == "no":
26
-        prompt = " [y/N] "
27
-    else:
28
-        raise ValueError("invalid default answer: '%s'" % default)
29
-
30
-    while True:
31
-        sys.stdout.write(question + prompt)
32
-        choice = raw_input().lower().strip()
33
-        if default is not None and choice == '':
34
-            return valid[default]
35
-        elif choice in valid:
36
-            return valid[choice]
37
-        else:
38
-            sys.stdout.write("Please respond with 'yes' or 'no' "
39
-                             "(or 'y' or 'n').\n")
40
-
41
-def create_vmdk_and_partition(config, vmdk_path, disk_setup_script):
42
-    partitions_data = {}
43
-
44
-    firmware = "bios"
45
-    if 'boot' in config and config['boot'] == 'efi':
46
-        firmware = "efi"
47
-    process = subprocess.Popen([disk_setup_script, '-rp', config['size']['root'], '-sp',
48
-                                config['size']['swap'], '-n', vmdk_path, '-fm', firmware],
49
-                               stdout=subprocess.PIPE)
50
-    count = 0
51
-
52
-    while True:
53
-        line = process.stdout.readline().decode()
54
-        if line == '':
55
-            retval = process.poll()
56
-            if retval is not None:
57
-                break
58
-        sys.stdout.write(line)
59
-        if line.startswith("DISK_DEVICE="):
60
-            partitions_data['disk'] = line.replace("DISK_DEVICE=", "").strip()
61
-            count += 1
62
-        elif line.startswith("ROOT_PARTITION="):
63
-            partitions_data['root'] = line.replace("ROOT_PARTITION=", "").strip()
64
-            partitions_data['boot'] = partitions_data['root']
65
-            partitions_data['bootdirectory'] = '/boot/'
66
-            partitions_data['partitions'] = [{'path': partitions_data['root'], 'mountpoint': '/',
67
-                                          'filesystem': 'ext4'}]
68
-            count += 1
69
-        elif line.startswith("ESP_PARTITION="):
70
-            partitions_data['esp'] = line.replace("ESP_PARTITION=", "").strip()
71
-            partitions_data['partitions'].append({'path': partitions_data['esp'], 'mountpoint': '/boot/esp',
72
-                                          'filesystem': 'vfat'})
73
-            count += 1
74
-    return partitions_data, count == 2 or count == 3
75
-
76
-def get_file_name_with_last_folder(filename):
77
-    basename = os.path.basename(filename)
78
-    dirname = os.path.dirname(filename)
79
-    lastfolder = os.path.basename(dirname)
80
-    name = os.path.join(lastfolder, basename)
81
-    return name
82
-def create_pkg_list_to_copy_to_iso(build_install_option, output_data_path):
83
-    json_wrapper_option_list = JsonWrapper(build_install_option)
84
-    option_list_json = json_wrapper_option_list.read()
85
-    options_sorted = option_list_json.items()
86
-    packages = []
87
-    for install_option in options_sorted:
88
-        if install_option[0] != "iso":
89
-            file_path = os.path.join(output_data_path, install_option[1]["file"])
90
-            json_wrapper_package_list = JsonWrapper(file_path)
91
-            package_list_json = json_wrapper_package_list.read()
92
-            packages = packages + package_list_json["packages"]
93
-    return packages
94
-
95
-    #copy_flags 1: add the rpm file for the package
96
-    #           2: add debuginfo rpm file for the package.
97
-    #           4: add src rpm file for the package
98
-def create_rpm_list_to_be_copied_to_iso(pkg_to_rpm_map_file, build_install_option, copy_flags,
99
-                                        output_data_path):
100
-    packages = []
101
-    if build_install_option is None:
102
-        packages = []
103
-    else:
104
-        packages = create_pkg_list_to_copy_to_iso(build_install_option, output_data_path)
105
-
106
-    rpm_list = []
107
-    json_pkg_to_rpm_map = JsonWrapper(pkg_to_rpm_map_file)
108
-    pkg_to_rpm_map = json_pkg_to_rpm_map.read()
109
-    for k in pkg_to_rpm_map:
110
-        if build_install_option is None or k in packages:
111
-            if not pkg_to_rpm_map[k]['rpm'] is None and bool(copy_flags & 1):
112
-                filename = pkg_to_rpm_map[k]['rpm']
113
-                rpm_list.append(get_file_name_with_last_folder(filename))
114
-            if not pkg_to_rpm_map[k]['debugrpm'] is None and bool(copy_flags & 2):
115
-                filename = pkg_to_rpm_map[k]['debugrpm']
116
-                rpm_list.append(pkg_to_rpm_map[k]['debugrpm'])
117
-            if not pkg_to_rpm_map[k]['sourcerpm'] is None and bool(copy_flags & 4):
118
-                rpm_list.append(pkg_to_rpm_map[k]['sourcerpm'])
119
-    return rpm_list
120
-
121
-def create_additional_file_list_to_copy_in_iso(base_path, build_install_option):
122
-    json_wrapper_option_list = JsonWrapper(build_install_option)
123
-    option_list_json = json_wrapper_option_list.read()
124
-    options_sorted = option_list_json.items()
125
-    file_list = []
126
-    for install_option in options_sorted:
127
-        if "additional-files" in install_option[1]:
128
-            file_list = file_list + list(map(
129
-                lambda filename: os.path.join(base_path, filename),
130
-                install_option[1].get("additional-files")))
131
-    return file_list
132
-
133
-def get_live_cd_status_string(build_install_option):
134
-    json_wrapper_option_list = JsonWrapper(build_install_option)
135
-    option_list_json = json_wrapper_option_list.read()
136
-    options_sorted = option_list_json.items()
137
-    file_list = []
138
-    for install_option in options_sorted:
139
-        if "live-cd" in install_option[1]:
140
-            if install_option[1].get("live-cd") == True:
141
-                return "true"
142
-    return "false"
143
-
144
-def make_src_iso(working_directory, src_iso_path, rpm_list):
145
-    if os.path.isdir(working_directory):
146
-        process = subprocess.Popen(['rm', '-rf', working_directory])
147
-        retval = process.wait()
148
-    process = subprocess.Popen(['mkdir', '-p', os.path.join(working_directory, "SRPMS")])
149
-    retval = process.wait()
150
-    for aaa in rpm_list:
151
-        if os.path.isfile(aaa):
152
-            process = subprocess.Popen(['cp', aaa, os.path.join(working_directory, "SRPMS")])
153
-            retval = process.wait()
154
-    process = subprocess.Popen(['mkisofs', '-r', '-o', src_iso_path, working_directory])
155
-    retval = process.wait()
156
-    process = subprocess.Popen(['rm', '-rf', options.working_directory])
157
-    retval = process.wait()
158
-
159
-def make_debug_iso(working_directory, debug_iso_path, rpm_list):
160
-    if os.path.isdir(working_directory):
161
-        process = subprocess.Popen(['rm', '-rf', working_directory])
162
-        retval = process.wait()
163
-    process = subprocess.Popen(['mkdir', '-p', os.path.join(working_directory, "DEBUGRPMS")])
164
-    retval = process.wait()
165
-    for aaa in rpm_list:
166
-        if os.path.isfile(aaa):
167
-            dirname = os.path.dirname(aaa)
168
-            lastfolder = os.path.basename(dirname)
169
-            dest_working_directory = os.path.join(working_directory, "DEBUGRPMS", lastfolder)
170
-            if not os.path.isdir(dest_working_directory):
171
-                process = subprocess.Popen(['mkdir', dest_working_directory])
172
-                retval = process.wait()
173
-            process = subprocess.Popen(['cp', aaa, dest_working_directory])
174
-            retval = process.wait()
175
-    process = subprocess.Popen(['mkisofs', '-r', '-o', debug_iso_path, working_directory])
176
-    retval = process.wait()
177
-    process = subprocess.Popen(['rm', '-rf', options.working_directory])
178
-    retval = process.wait()
179
-
180
-if __name__ == '__main__':
181
-    usage = "Usage: %prog [options] <config file> <tools path>"
182
-    parser = ArgumentParser(usage)
183
-    parser.add_argument("-i", "--iso-path", dest="iso_path")
184
-    parser.add_argument("-j", "--src-iso-path", dest="src_iso_path")
185
-    parser.add_argument("-k", "--debug-iso-path", dest="debug_iso_path")
186
-    parser.add_argument("-v", "--vmdk-path", dest="vmdk_path")
187
-    parser.add_argument("-w", "--working-directory", dest="working_directory",
188
-                        default="/mnt/photon-root")
189
-    parser.add_argument("-l", "--log-path", dest="log_path",
190
-                        default=os.path.dirname(__file__)+"/../stage/LOGS")
191
-    parser.add_argument("-y", "--log-level", dest="log_level")
192
-    parser.add_argument("-r", "--rpm-path", dest="rpm_path", default=os.path.dirname(__file__)+"/../stage/RPMS")
193
-    parser.add_argument("-x", "--srpm-path", dest="srpm_path", default=os.path.dirname(__file__)+"/../stage/SRPMS")
194
-    parser.add_argument("-o", "--output-data-path", dest="output_data_path",
195
-                        default=os.path.dirname(__file__)+"/../stage/common/data/")
196
-    parser.add_argument("-f", "--force", action="store_true", dest="force", default=False)
197
-    parser.add_argument("-p", "--package-list-file", dest="package_list_file",
198
-                        default=os.path.dirname(__file__)+"/../common/data/build_install_options_all.json")
199
-    parser.add_argument("-m", "--stage-path", dest="stage_path", default=os.path.dirname(__file__)+"../stage")
200
-    parser.add_argument("-s", "--json-data-path", dest="json_data_path",
201
-                        default=os.path.dirname(__file__)+"/../stage/common/data/")
202
-    parser.add_argument("-d", "--pkg-to-rpm-map-file", dest="pkg_to_rpm_map_file",
203
-                        default=os.path.dirname(__file__)+"/../stage/pkg_info.json")
204
-    parser.add_argument("-c", "--pkg-to-be-copied-conf-file", dest="pkg_to_be_copied_conf_file")
205
-    parser.add_argument("-ds", "--disk-setup-script", dest="disk_setup_script",
206
-                        default=os.path.dirname(__file__)+"/../support/image-builder/mk-setup-vmdk.sh")
207
-    parser.add_argument("-dc", "--disk-cleanup-script", dest="disk_cleanup_script",
208
-                        default=os.path.dirname(__file__)+"/../support/image-builder/mk-clean-vmdk.sh")
209
-    parser.add_argument("-ps", "--prepare-script", dest="prepare_system_script",
210
-                        default=os.path.dirname(__file__)+"/mk-prepare-system.sh")
211
-    parser.add_argument("-sg", "--setup-grub-script", dest="setup_grub_script",
212
-                        default=os.path.dirname(__file__)+"/mk-setup-grub.sh")
213
-    parser.add_argument('configfile', nargs='?')
214
-    options = parser.parse_args()
215
-    # Cleanup the working directory
216
-    if not options.force:
217
-        proceed = query_yes_no("This will remove everything under {0}. " +
218
-                               "Are you sure?".format(options.working_directory))
219
-        if not proceed:
220
-            sys.exit(0)
221
-
222
-    if options.src_iso_path:
223
-        rpm_list = create_rpm_list_to_be_copied_to_iso(options.pkg_to_rpm_map_file,
224
-                                                       options.pkg_to_be_copied_conf_file, 4,
225
-                                                       options.output_data_path)
226
-        make_src_iso(options.working_directory, options.src_iso_path, rpm_list)
227
-
228
-    else:
229
-        if options.iso_path:
230
-            # Check the arguments
231
-            if options.configfile:
232
-                parser.error("Incorrect arguments")
233
-            config = {}
234
-            config['iso_system'] = True
235
-            config['vmdk_install'] = False
236
-            config['type'] = 'iso'
237
-
238
-        elif options.vmdk_path:
239
-            # Check the arguments
240
-            if not options.configfile:
241
-                parser.error("Incorrect arguments")
242
-
243
-            # Read the conf file
244
-            config = (JsonWrapper(options.configfile)).read()
245
-            config['disk'], success = create_vmdk_and_partition(config, options.vmdk_path, options.disk_setup_script)
246
-            if not success:
247
-                print("Unexpected failure, please check the logs")
248
-                sys.exit(1)
249
-
250
-            config['iso_system'] = False
251
-            config['vmdk_install'] = True
252
-        else:
253
-            # Check the arguments
254
-            if not options.configfile:
255
-                parser.error("Incorrect arguments")
256
-
257
-            # Read the conf file
258
-            config = (JsonWrapper(options.configfile)).read()
259
-
260
-            config['iso_system'] = False
261
-            config['vmdk_install'] = False
262
-
263
-        config["pkg_to_rpm_map_file"] = options.pkg_to_rpm_map_file
264
-
265
-        if 'password' in config:
266
-            # crypt the password if needed
267
-            if config['password']['crypted']:
268
-                config['password'] = config['password']['text']
269
-            else:
270
-                config['password'] = crypt.crypt(
271
-                    config['password']['text'],
272
-                    "$6$" + "".join([random.choice(
273
-                        string.ascii_letters + string.digits) for _ in range(16)]))
274
-
275
-        # Check the installation type
276
-        json_wrapper_option_list = JsonWrapper(options.package_list_file)
277
-        option_list_json = json_wrapper_option_list.read()
278
-        options_sorted = option_list_json.items()
279
-
280
-        packages = []
281
-        if 'type' in config:
282
-            for install_option in options_sorted:
283
-                if install_option[0] == config['type']:
284
-                    packages = PackageSelector.get_packages_to_install(install_option[1]['packagelist_file'],
285
-                                                                   options.output_data_path)
286
-                    break
287
-        else:
288
-            if 'packagelist_file' in config:
289
-                packages = PackageSelector.get_packages_to_install(config['packagelist_file'],
290
-                                                                   options.output_data_path)
291
-            if 'additional_packages' in config:
292
-                packages = packages.extend(config['additional_packages'])
293
-
294
-        config['packages'] = packages
295
-
296
-        if os.path.isdir(options.working_directory):
297
-            process = subprocess.Popen(['rm', '-rf', options.working_directory])
298
-            retval = process.wait()
299
-
300
-        process = subprocess.Popen(['mkdir', '-p',
301
-                                    os.path.join(options.working_directory, "photon-chroot")])
302
-        retval = process.wait()
303
-
304
-        config['working_directory'] = options.working_directory
305
-        config['prepare_script'] = options.prepare_system_script
306
-        config['setup_grub_script'] = options.setup_grub_script
307
-
308
-        # Run the installer
309
-        package_installer = Installer(config, rpm_path=options.rpm_path,
310
-                                      log_path=options.log_path, log_level=options.log_level)
311
-        package_installer.install(None)
312
-
313
-        # Making the iso if needed
314
-        if options.iso_path:
315
-            rpm_list = " ".join(
316
-                create_rpm_list_to_be_copied_to_iso(
317
-                    options.pkg_to_rpm_map_file,
318
-                    options.pkg_to_be_copied_conf_file, 1, options.output_data_path))
319
-            files_to_copy = " ".join(
320
-                create_additional_file_list_to_copy_in_iso(
321
-                    os.path.abspath(options.stage_path), options.package_list_file))
322
-
323
-            live_cd = get_live_cd_status_string(options.package_list_file)
324
-            process = subprocess.Popen(['./mk-install-iso.sh', '-w',
325
-                                        options.working_directory, options.iso_path,
326
-                                        options.rpm_path, options.package_list_file,
327
-                                        rpm_list, options.stage_path, files_to_copy,
328
-                                        live_cd, options.json_data_path])
329
-            retval = process.wait()
330
-
331
-        if options.debug_iso_path:
332
-            debug_rpm_list = create_rpm_list_to_be_copied_to_iso(
333
-                options.pkg_to_rpm_map_file, options.pkg_to_be_copied_conf_file, 2,
334
-                options.output_data_path)
335
-            make_debug_iso(options.working_directory, options.debug_iso_path, debug_rpm_list)
336
-
337
-        # Cleaning up for vmdk
338
-        if 'vmdk_install' in config and config['vmdk_install']:
339
-            process = subprocess.Popen([options.disk_cleanup_script, config['disk']['disk']])
340
-            process.wait()
341
-
342
-        #Clean up the working directories
343
-        if options.iso_path or options.vmdk_path or options.debug_iso_path:
344
-            process = subprocess.Popen(['rm', '-rf', options.working_directory])
345
-            retval = process.wait()
... ...
@@ -1,5 +1,4 @@
1 1
 #
2
-#    Copyright (C) 2015 vmware inc.
3 2
 #
4 3
 #    Author: Mahmoud Bassiouny <mbassiouny@vmware.com>
5 4
 
... ...
@@ -1,5 +1,4 @@
1 1
 #
2
-#    Copyright (C) 2015 vmware inc.
3 2
 #
4 3
 #    Author: Yang Yao <yaoyang@vmware.com>
5 4
 
... ...
@@ -1,5 +1,4 @@
1 1
 #
2
-#    Copyright (C) 2015 vmware inc.
3 2
 #
4 3
 #    Author: Mahmoud Bassiouny <mbassiouny@vmware.com>
5 4
 
... ...
@@ -1,5 +1,4 @@
1 1
 #
2
-#    Copyright (C) 2015 vmware inc.
3 2
 #
4 3
 #    Author: Mahmoud Bassiouny <mbassiouny@vmware.com>
5 4
 
... ...
@@ -1,4 +1,3 @@
1
-#    Copyright (C) 2015 vmware inc.
2 1
 #
3 2
 #    Author: Mahmoud Bassiouny <mbassiouny@vmware.com>
4 3
 import curses
... ...
@@ -1,5 +1,4 @@
1 1
 #
2
-#    Copyright (C) 2015 vmware inc.
3 2
 #
4 3
 #    Author: Mahmoud Bassiouny <mbassiouny@vmware.com>
5 4
 
... ...
@@ -1,5 +1,4 @@
1 1
 #
2
-#    Copyright (C) 2015 vmware inc.
3 2
 #
4 3
 #    Author: Mahmoud Bassiouny <mbassiouny@vmware.com>
5 4
 
... ...
@@ -1,4 +1,5 @@
1 1
 {
2
+    "image_type": "ami",
2 3
     "hostname": "photon-machine",
3 4
     "password": 
4 5
         {
... ...
@@ -6,13 +7,13 @@
6 6
             "text": "PASSWORD"
7 7
         },
8 8
     "packagelist_file": "packages_ami.json",
9
-    "size": {"root": "8", "swap": "0"},
9
+    "size": {"root": "16", "swap": "0"},
10 10
     "public_key":"<ssh-key-here>",
11 11
     "postinstallscripts": [ "ami-patch.sh", "../password-expiry.sh" ],
12 12
     "additionalfiles": [
13 13
                             {"cloud-photon.cfg": "/etc/cloud/cloud.cfg"}
14 14
                        ],
15 15
     "artifacttype": "tgz",
16
-    "keeprawdisk": "false"
16
+    "keeprawdisk": false
17 17
 }
18 18
 
... ...
@@ -1,4 +1,5 @@
1 1
 {
2
+    "image_type": "azure",
2 3
     "hostname": "photon-machine",
3 4
     "password": 
4 5
         {
... ...
@@ -13,6 +14,6 @@
13 13
                             {"cloud-photon.cfg": "/etc/cloud/cloud.cfg"}
14 14
                        ],
15 15
     "artifacttype": "vhd",
16
-    "keeprawdisk": "false"
16
+    "keeprawdisk": false
17 17
 }
18 18
 
19 19
deleted file mode 100755
... ...
@@ -1,341 +0,0 @@
1
-#!/usr/bin/python3
2
-
3
-import os
4
-import re
5
-import shutil
6
-import tarfile
7
-import fileinput
8
-from argparse import ArgumentParser
9
-import json
10
-from utils import Utils
11
-
12
-def create_ova_image(raw_image_name, tools_path, build_scripts_path, config):
13
-    output_path = os.path.dirname(os.path.realpath(raw_image_name))
14
-    utils = Utils()
15
-    # Remove older artifacts
16
-    files = os.listdir(output_path)
17
-    for file in files:
18
-        if file.endswith(".vmdk"):
19
-            os.remove(os.path.join(output_path, file))
20
-
21
-    vmx_path = output_path + '/photon-ova.vmx'
22
-    utils.replaceandsaveasnewfile(build_scripts_path + '/vmx-template',
23
-                                  vmx_path, 'VMDK_IMAGE',
24
-                                  output_path + '/photon-ova.vmdk')
25
-    vixdiskutil_path = tools_path + 'vixdiskutil'
26
-    vmdk_path = output_path + '/photon-ova.vmdk'
27
-    ovf_path = output_path + '/photon-ova.ovf'
28
-    mf_path = output_path + '/photon-ova.mf'
29
-    ovfinfo_path = build_scripts_path + '/ovfinfo.txt'
30
-    vmdk_capacity = (int(config['size']['root']) +
31
-                     int(config['size']['swap'])) * 1024
32
-    utils.runshellcommand(
33
-        "{} -convert {} -cap {} {}".format(vixdiskutil_path,
34
-                                           raw_image_name,
35
-                                           vmdk_capacity,
36
-                                           vmdk_path))
37
-    utils.runshellcommand(
38
-        "{} -wmeta toolsVersion 2147483647 {}".format(vixdiskutil_path, vmdk_path))
39
-
40
-    utils.runshellcommand("ovftool {} {}".format(vmx_path, ovf_path))
41
-    utils.replaceinfile(ovf_path, 'otherGuest', 'other3xLinux64Guest')
42
-
43
-    #Add product info
44
-    if os.path.exists(ovfinfo_path):
45
-        with open(ovfinfo_path) as f:
46
-            lines = f.readlines()
47
-            for line in fileinput.input(ovf_path, inplace=True):
48
-                if line.strip() == '</VirtualHardwareSection>':
49
-                    for ovfinfoline in lines:
50
-                        print(ovfinfoline)
51
-                else:
52
-                    print(line)
53
-
54
-    if os.path.exists(mf_path):
55
-        os.remove(mf_path)
56
-
57
-    cwd = os.getcwd()
58
-    os.chdir(output_path)
59
-    out = utils.runshellcommand("openssl sha1 photon-ova-disk1.vmdk photon-ova.ovf")
60
-    with open(mf_path, "w") as source:
61
-        source.write(out)
62
-    rawsplit = os.path.splitext(raw_image_name)
63
-    ova_name = rawsplit[0] + '.ova'
64
-
65
-    ovatar = tarfile.open(ova_name, "w", format=tarfile.USTAR_FORMAT)
66
-    for name in ["photon-ova.ovf", "photon-ova.mf", "photon-ova-disk1.vmdk"]:
67
-        ovatar.add(name, arcname=os.path.basename(name))
68
-    ovatar.close()
69
-    os.remove(vmx_path)
70
-    os.remove(mf_path)
71
-
72
-    if 'additionalhwversion' in config:
73
-        for addlversion in config['additionalhwversion']:
74
-            new_ovf_path = output_path + "/photon-ova-hw{}.ovf".format(addlversion)
75
-            mf_path = output_path + "/photon-ova-hw{}.mf".format(addlversion)
76
-            utils.replaceandsaveasnewfile(
77
-                ovf_path, new_ovf_path, "vmx-.*<", "vmx-{}<".format(addlversion))
78
-            out = utils.runshellcommand("openssl sha1 photon-ova-disk1.vmdk "
79
-                                        "photon-ova-hw{}.ovf".format(addlversion))
80
-            with open(mf_path, "w") as source:
81
-                source.write(out)
82
-            temp_name_list = os.path.basename(ova_name).split('-')
83
-            temp_name_list = temp_name_list[:2] + ["hw{}".format(addlversion)] + temp_name_list[2:]
84
-            new_ova_name = '-'.join(temp_name_list)
85
-            new_ova_path = output_path + '/' + new_ova_name
86
-            ovatar = tarfile.open(new_ova_path, "w", format=tarfile.USTAR_FORMAT)
87
-            for name in [new_ovf_path, mf_path, "photon-ova-disk1.vmdk"]:
88
-                ovatar.add(name, arcname=os.path.basename(name))
89
-            ovatar.close()
90
-
91
-            os.remove(new_ovf_path)
92
-            os.remove(mf_path)
93
-    os.chdir(cwd)
94
-    os.remove(ovf_path)
95
-    os.remove(vmdk_path)
96
-    files = os.listdir(output_path)
97
-    for file in files:
98
-        if file.endswith(".vmdk"):
99
-            os.remove(os.path.join(output_path, file))
100
-
101
-
102
-if __name__ == '__main__':
103
-    usage = "Usage: %prog [options]"
104
-    parser = ArgumentParser(usage)
105
-
106
-    parser.add_argument("-r", "--raw-image-path", dest="raw_image_path")
107
-    parser.add_argument("-c", "--vmdk-config-path", dest="vmdk_config_path")
108
-    parser.add_argument("-w", "--working-directory", dest="working_directory")
109
-    parser.add_argument("-m", "--mount-path", dest="mount_path")
110
-    parser.add_argument("-a", "--additional-rpms-path", dest="additional_rpms_path")
111
-    parser.add_argument("-i", "--image-name", dest="image_name")
112
-    parser.add_argument("-t", "--tools-bin-path", dest="tools_bin_path")
113
-    parser.add_argument("-b", "--build-scripts-path", dest="build_scripts_path")
114
-    parser.add_argument("-s", "--src-root", dest="src_root")
115
-
116
-    options = parser.parse_args()
117
-    utils = Utils()
118
-    config = utils.jsonread(options.vmdk_config_path)
119
-    print(options)
120
-
121
-    disk_device = (utils.runshellcommand(
122
-        "losetup --show -f {}".format(options.raw_image_path))).rstrip('\n')
123
-    disk_partitions = utils.runshellcommand("kpartx -as {}".format(disk_device))
124
-    device_name = disk_device.split('/')[2]
125
-
126
-    if not os.path.exists(options.mount_path):
127
-        os.mkdir(options.mount_path)
128
-    loop_device_path = "/dev/mapper/{}p2".format(device_name)
129
-
130
-    try:
131
-        print("Generating PARTUUID for the loop device ...")
132
-        partuuidval = (utils.runshellcommand(
133
-            "blkid -s PARTUUID -o value {}".format(loop_device_path))).rstrip('\n')
134
-        uuidval = (utils.runshellcommand(
135
-            "blkid -s UUID -o value {}".format(loop_device_path))).rstrip('\n')
136
-        if partuuidval == '':
137
-            sgdiskout = utils.runshellcommand(
138
-                "sgdisk -i 2 {} ".format(disk_device))
139
-            partuuidval = (re.findall(r'Partition unique GUID.*',
140
-                                      sgdiskout))[0].split(':')[1].strip(' ').lower()
141
-
142
-        if partuuidval == '':
143
-            raise RuntimeError("Cannot generate partuuid")
144
-
145
-        # Mount the loop device
146
-        print("Mounting the loop device for customization ...")
147
-        utils.runshellcommand(
148
-            "mount -t ext4 {} {}".format(loop_device_path, options.mount_path))
149
-        shutil.rmtree(options.mount_path + "/installer", ignore_errors=True)
150
-        shutil.rmtree(options.mount_path + "/LOGS", ignore_errors=True)
151
-        # Clear the root password if not set explicitly from the config file
152
-        if config['password']['text'] != 'PASSWORD':
153
-            utils.replaceinfile(options.mount_path + "/etc/shadow",
154
-                                'root:.*?:', 'root:*:')
155
-        # Clear machine-id so it gets regenerated on boot
156
-        open(options.mount_path + "/etc/machine-id", "w").close()
157
-        os.remove(options.mount_path + "/etc/fstab")
158
-
159
-        f = open(options.mount_path + "/etc/fstab", "w")
160
-        if uuidval != '':
161
-            f.write("UUID={}    /    ext4    defaults 1 1\n".format(uuidval))
162
-        else:
163
-            f.write("PARTUUID={}    /    ext4    defaults 1 1\n".format(partuuidval))
164
-        f.close()
165
-        utils.replaceinfile(options.mount_path + "/boot/grub/grub.cfg",
166
-                            "rootpartition=PARTUUID=.*$",
167
-                            "rootpartition=PARTUUID={}".format(partuuidval))
168
-
169
-        if os.path.exists(options.additional_rpms_path):
170
-            print("Installing additional rpms")
171
-            os.mkdir(options.mount_path + "/additional_rpms")
172
-            os.mkdir(options.mount_path + "/var/run")
173
-            utils.copyallfiles(options.additional_rpms_path,
174
-                               options.mount_path + "/additional_rpms")
175
-            utils.runshellcommand(
176
-                "chroot {} /bin/bash -c 'rpm -i /additional_rpms/*'".format(options.mount_path))
177
-            shutil.rmtree(options.mount_path + "/additional_rpms", ignore_errors=True)
178
-            shutil.rmtree(options.additional_rpms_path, ignore_errors=True)
179
-
180
-        utils.runshellcommand("mount -o bind /proc {}".format(options.mount_path + "/proc"))
181
-        utils.runshellcommand("mount -o bind /dev {}".format(options.mount_path + "/dev"))
182
-        utils.runshellcommand("mount -o bind /dev/pts {}".format(options.mount_path + "/dev/pts"))
183
-        utils.runshellcommand("mount -o bind /sys {}".format(options.mount_path + "/sys"))
184
-
185
-        if 'additionalfiles' in config:
186
-            print("  Copying additional files into the raw image ...")
187
-            for filetuples in config['additionalfiles']:
188
-                for src, dest in filetuples.items():
189
-                    if (os.path.isdir(options.build_scripts_path + '/' +
190
-                                      options.image_name + '/' + src)):
191
-                        shutil.copytree(options.build_scripts_path + '/' +
192
-                                        options.image_name + '/' + src,
193
-                                        options.mount_path + dest, True)
194
-                    else:
195
-                        shutil.copyfile(options.build_scripts_path + '/' +
196
-                                        options.image_name + '/' + src,
197
-                                        options.mount_path + dest)
198
-
199
-
200
-        if 'postinstallscripts' in config:
201
-            print("  Running post install scripts ...")
202
-            if not os.path.exists(options.mount_path + "/tempscripts"):
203
-                os.mkdir(options.mount_path + "/tempscripts")
204
-            for script in config['postinstallscripts']:
205
-                shutil.copy(options.build_scripts_path + '/' +
206
-                            options.image_name + '/' + script,
207
-                            options.mount_path + "/tempscripts")
208
-            for script in os.listdir(options.mount_path + "/tempscripts"):
209
-                print("     ...running script {}".format(script))
210
-                utils.runshellcommand(
211
-                    "chroot {} /bin/bash -c '/tempscripts/{}'".format(options.mount_path, script))
212
-            shutil.rmtree(options.mount_path + "/tempscripts", ignore_errors=True)
213
-
214
-    except Exception as e:
215
-        print(e)
216
-
217
-    finally:
218
-        utils.runshellcommand("umount -l {}".format(options.mount_path + "/sys"))
219
-        utils.runshellcommand("umount -l {}".format(options.mount_path + "/dev/pts"))
220
-        utils.runshellcommand("umount -l {}".format(options.mount_path + "/dev"))
221
-        utils.runshellcommand("umount -l {}".format(options.mount_path + "/proc"))
222
-
223
-        utils.runshellcommand("sync")
224
-        utils.runshellcommand("umount -l {}".format(options.mount_path))
225
-
226
-        utils.runshellcommand("kpartx -d {}".format(disk_device))
227
-        utils.runshellcommand("losetup -d {}".format(disk_device))
228
-
229
-        shutil.rmtree(options.mount_path)
230
-
231
-        photon_release_ver = os.environ['PHOTON_RELEASE_VER']
232
-        photon_build_num = os.environ['PHOTON_BUILD_NUM']
233
-        raw_image = options.raw_image_path
234
-        new_name = ""
235
-        img_path = os.path.dirname(os.path.realpath(raw_image))
236
-        # Rename gce image to disk.raw
237
-        if options.image_name == "gce":
238
-            print("Renaming the raw file to disk.raw ...")
239
-            new_name = img_path + '/disk.raw'
240
-
241
-        else:
242
-            new_name = (img_path + '/photon-' + options.image_name +
243
-                        '-' + photon_release_ver + '-' +
244
-                        photon_build_num + '.raw')
245
-
246
-        shutil.move(raw_image, new_name)
247
-        raw_image = new_name
248
-
249
-        if config['artifacttype'] == 'tgz':
250
-            print("Generating the tar.gz artifact ...")
251
-            tarname = (img_path + '/photon-' + options.image_name +
252
-                       '-' + photon_release_ver + '-' +
253
-                       photon_build_num + '.tar.gz')
254
-
255
-            tgzout = tarfile.open(tarname, "w:gz")
256
-            tgzout.add(raw_image, arcname=os.path.basename(raw_image))
257
-            tgzout.close()
258
-        elif config['artifacttype'] == 'xz':
259
-            print("Generating the xz artifact ...")
260
-            utils.runshellcommand("xz -z -k {}".format(raw_image))
261
-#            tarname = img_path + '/photon-' + options.image_name +
262
-#            '-' + photon_release_ver + '-' + photon_build_num +
263
-#            '.xz'
264
-#            tgzout = tarfile.open(tarname, "w:xz")
265
-#            tgzout.add(raw_image, arcname=os.path.basename(raw_image))
266
-#            tgzout.close()
267
-        elif config['artifacttype'] == 'vhd':
268
-            relrawpath = os.path.relpath(raw_image, options.src_root)
269
-            vhdname = (os.path.dirname(relrawpath) + '/photon-' +
270
-                       options.image_name + '-' + photon_release_ver + '-' +
271
-                       photon_build_num + '.vhd')
272
-            print("Converting raw disk to vhd ...")
273
-            info_output = utils.runshellcommand(
274
-                "docker run -v {}:/mnt:rw anishs/qemu-img info -f raw --output json {}"
275
-                .format(options.src_root, '/mnt/' + relrawpath))
276
-            mbsize = 1024 * 1024
277
-            mbroundedsize = ((int(json.loads(info_output)["virtual-size"])/mbsize + 1) * mbsize)
278
-            utils.runshellcommand(
279
-                "docker run -v {}:/mnt:rw anishs/qemu-img resize -f raw {} {}"
280
-                .format(options.src_root, '/mnt/' + relrawpath, mbroundedsize))
281
-            utils.runshellcommand(
282
-                "docker run -v {}:/mnt:rw anishs/qemu-img convert {} -O "
283
-                "vpc -o subformat=fixed,force_size {}"
284
-                .format(options.src_root, '/mnt/' + relrawpath, '/mnt/' + vhdname))
285
-        elif config['artifacttype'] == 'ova':
286
-            create_ova_image(raw_image, options.tools_bin_path,
287
-                             options.build_scripts_path + '/' + options.image_name, config)
288
-            if 'customartifacts' in config:
289
-                if 'postinstallscripts' in config['customartifacts']:
290
-                    custom_path = img_path + '/photon-custom'
291
-                    if not os.path.exists(custom_path):
292
-                        os.mkdir(custom_path)
293
-                    index = 1
294
-                    for script in config['customartifacts']['postinstallscripts']:
295
-                        print("Creating custom ova {}...".format(index))
296
-                        if index > 1:
297
-                            raw_image_custom = (img_path + "/photon-custom-{}".format(index) +
298
-                                                photon_release_ver + '-' +
299
-                                                photon_build_num + '.raw')
300
-                        else:
301
-                            raw_image_custom = (img_path + "/photon-custom-" +
302
-                                                photon_release_ver + '-' +
303
-                                                photon_build_num + '.raw')
304
-                        shutil.move(raw_image, raw_image_custom)
305
-                        disk_device = (
306
-                            utils.runshellcommand(
307
-                                "losetup --show -f {}".format(raw_image_custom))).rstrip('\n')
308
-                        disk_partitions = utils.runshellcommand(
309
-                            "kpartx -as {}".format(disk_device))
310
-                        device_name = disk_device.split('/')[2]
311
-                        loop_device_path = "/dev/mapper/{}p2".format(device_name)
312
-
313
-                        print("Mounting the loop device for ova customization ...")
314
-                        utils.runshellcommand(
315
-                            "mount -t ext4 {} {}".format(loop_device_path, custom_path))
316
-                        if not os.path.exists(custom_path + "/tempscripts"):
317
-                            os.mkdir(custom_path + "/tempscripts")
318
-                        shutil.copy(options.build_scripts_path + '/' + options.image_name +
319
-                                    '/' + script, custom_path + "/tempscripts")
320
-                        print("Running custom ova script {}".format(script))
321
-                        utils.runshellcommand("chroot {} /bin/bash -c '/tempscripts/{}'"
322
-                                              .format(custom_path, script))
323
-                        shutil.rmtree(custom_path + "/tempscripts", ignore_errors=True)
324
-                        utils.runshellcommand("umount -l {}".format(custom_path))
325
-
326
-                        utils.runshellcommand("sync")
327
-                        utils.runshellcommand("kpartx -d {}".format(disk_device))
328
-                        utils.runshellcommand("losetup -d {}".format(disk_device))
329
-                        create_ova_image(raw_image_custom, options.tools_bin_path,
330
-                                         options.build_scripts_path + '/' + options.image_name,
331
-                                         config)
332
-                        raw_image = raw_image_custom
333
-                        index = index + 1
334
-
335
-                    shutil.rmtree(custom_path)
336
-
337
-        else:
338
-            raise ValueError("Unknown output format")
339
-
340
-        if config['keeprawdisk'] == 'false':
341
-            os.remove(raw_image)
... ...
@@ -1,4 +1,5 @@
1 1
 {
2
+    "image_type": "gce",
2 3
     "hostname": "photon-machine",
3 4
     "password": 
4 5
         {
... ...
@@ -14,6 +15,6 @@
14 14
                             {"ntpd.service": "/usr/lib/systemd/system/ntpd.service"}
15 15
                        ],
16 16
     "artifacttype": "tgz",
17
-    "keeprawdisk": "false"
17
+    "keeprawdisk": false
18 18
 }
19 19
 
20 20
deleted file mode 100755
... ...
@@ -1,114 +0,0 @@
1
-#!/bin/bash
2
-
3
-#################################################
4
-#	Title:	image-builder.sh		            #
5
-#   Date:	2015-07-22        	 		        #
6
-#   Version:	1.1				                #
7
-#   Author:	anishs@vmware.com    		        #
8
-#################################################
9
-#	Overview
10
-#		Create images like ami, azure, gce, ova, rpi3
11
-#	End
12
-#
13
-
14
-for i in "$@"
15
-do
16
-    case $i in
17
-        -b=*|--build-scripts-path=*)
18
-        BUILD_SCRIPTS_PATH="${i#*=}"
19
-        shift
20
-        ;;
21
-        -i=*|--img-name=*)
22
-        IMG_NAME="${i#*=}"
23
-        shift
24
-        ;;
25
-        -s=*|--src-root=*)
26
-        SRC_ROOT="${i#*=}"
27
-        shift
28
-        ;;
29
-        -g=*|--generated-data-path=*)
30
-        GENERATED_DATA_PATH="${i#*=}"
31
-        shift
32
-        ;;
33
-        -s=*|--stage-path=*)
34
-        PHOTON_STAGE_PATH="${i#*=}"
35
-        shift
36
-        ;;
37
-        -r=*|--additional-rpms-path=*)
38
-        ADDITIONAL_RPMS_PATH="${i#*=}"
39
-        shift
40
-        ;;
41
-        *)
42
-        ;;
43
-    esac
44
-done
45
-
46
-WORKING_DIR=$PHOTON_STAGE_PATH/$IMG_NAME
47
-
48
-PHOTON_IMG_OUTPUT_PATH=$PHOTON_STAGE_PATH/$IMG_NAME
49
-IMAGE_CONFIG_FILE=${BUILD_SCRIPTS_PATH}/$IMG_NAME/config_$IMG_NAME.json
50
-IMAGE_CONFIG_SAFE_FILE=${BUILD_SCRIPTS_PATH}/$IMG_NAME/config_safe_$IMG_NAME.json
51
-
52
-cd $BUILD_SCRIPTS_PATH
53
-image_list=`for i in $(ls -d */); do echo ${i%%/}; done`
54
-if ! [[ $image_list =~ (^|[[:space:]])$IMG_NAME($|[[:space:]]) ]] ; then
55
-    echo "Input image name not supported. Aborting."; exit 1;
56
-fi
57
-if [[ $IMG_NAME == ova* ]] ; then
58
-    command -v ovftool >/dev/null 2>&1 || { echo "Ovftool not installed. Aborting." >&2; exit 1; }
59
-fi
60
-
61
-rm -rf $WORKING_DIR
62
-mkdir -p $WORKING_DIR
63
-INSTALLER_PATH=$SRC_ROOT/installer
64
-
65
-cd $WORKING_DIR
66
-cp $IMAGE_CONFIG_FILE $IMAGE_CONFIG_SAFE_FILE
67
-
68
-DISK_SETUP="--disk-setup-script ${BUILD_SCRIPTS_PATH}/mk-setup-vmdk.sh"
69
-if [ -f ${BUILD_SCRIPTS_PATH}/$IMG_NAME/mk-setup-vmdk.sh ]; then
70
-    DISK_SETUP="--disk-setup-script ${BUILD_SCRIPTS_PATH}/$IMG_NAME/mk-setup-vmdk.sh"
71
-fi
72
-
73
-DISK_CLEANUP="--disk-cleanup-script ${BUILD_SCRIPTS_PATH}/mk-clean-vmdk.sh"
74
-if [ -f ${BUILD_SCRIPTS_PATH}/$IMG_NAME/mk-clean-vmdk.sh ]; then
75
-    DISK_CLEANUP="--disk-cleanup-script ${BUILD_SCRIPTS_PATH}/$IMG_NAME/mk-clean-vmdk.sh"
76
-fi
77
-
78
-PREPARE_SYSTEM="--prepare-script ${INSTALLER_PATH}/mk-prepare-system.sh"
79
-if [ -f ${BUILD_SCRIPTS_PATH}/$IMG_NAME/mk-prepare-system.sh ]; then
80
-    PREPARE_SYSTEM="--prepare-script ${BUILD_SCRIPTS_PATH}/$IMG_NAME/mk-prepare-system.sh"
81
-fi
82
-
83
-GRUB_SCRIPT="--setup-grub-script ${INSTALLER_PATH}/mk-setup-grub.sh"
84
-if [ -f ${BUILD_SCRIPTS_PATH}/$IMG_NAME/mk-setup-grub.sh ]; then
85
-    GRUB_SCRIPT="--setup-grub-script ${BUILD_SCRIPTS_PATH}/$IMG_NAME/mk-setup-grub.sh"
86
-fi
87
-
88
-PASSWORD=`date | md5sum | cut -f 1 -d ' '`
89
-sed -i "s/PASSWORD/$PASSWORD/" $IMAGE_CONFIG_SAFE_FILE
90
-
91
-if [ -n "$ADDITIONAL_RPMS_PATH" ]
92
-  then
93
-    mkdir -p $PHOTON_STAGE_PATH/RPMS/additional
94
-    cp -f $ADDITIONAL_RPMS_PATH/* $PHOTON_STAGE_PATH/RPMS/additional/
95
-fi
96
-
97
-${INSTALLER_PATH}/photonInstaller.py -r $PHOTON_STAGE_PATH/RPMS -v $WORKING_DIR/photon-${IMG_NAME} $GRUB_SCRIPT $PREPARE_SYSTEM $DISK_CLEANUP $DISK_SETUP -o $GENERATED_DATA_PATH -d $PHOTON_STAGE_PATH/pkg_info.json -f $IMAGE_CONFIG_SAFE_FILE
98
-status=$?
99
-rm $IMAGE_CONFIG_SAFE_FILE
100
-
101
-cd $BUILD_SCRIPTS_PATH
102
-
103
-[ $status -eq 0 ] && ./customize_image.py \
104
- -r ${PHOTON_IMG_OUTPUT_PATH}/photon-${IMG_NAME}.raw \
105
- -c $IMAGE_CONFIG_FILE \
106
- -w $WORKING_DIR \
107
- -m $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME} \
108
- -a $PHOTON_STAGE_PATH/RPMS/additional \
109
- -i $IMG_NAME \
110
- -t $SRC_ROOT/tools/bin/ \
111
- -b $BUILD_SCRIPTS_PATH \
112
- -s $SRC_ROOT
113
-
114
-exit 0
115 1
new file mode 100755
... ...
@@ -0,0 +1,349 @@
0
+#!/usr/bin/python3
1
+
2
+import os
3
+import shutil
4
+import random
5
+import string
6
+import json
7
+from utils import Utils
8
+import sys
9
+import crypt
10
+import subprocess
11
+from argparse import ArgumentParser
12
+import imagegenerator
13
+
14
+def runInstaller(options, config):
15
+    try:
16
+        sys.path.insert(0, options.installer_path)
17
+        from installer import Installer
18
+        from packageselector import PackageSelector
19
+    except:
20
+        raise ImportError('Installer path incorrect!')
21
+    config["pkg_to_rpm_map_file"] = options.pkg_to_rpm_map_file
22
+    
23
+    # Check the installation type
24
+    option_list_json = Utils.jsonread(options.package_list_file)
25
+    options_sorted = option_list_json.items()
26
+
27
+    packages = []
28
+    if 'type' in config:
29
+        for install_option in options_sorted:
30
+            if install_option[0] == config['type']:
31
+                packages = PackageSelector.get_packages_to_install(install_option[1]['packagelist_file'],
32
+                                                               options.generated_data_path)
33
+                break
34
+    else:
35
+        if 'packagelist_file' in config:
36
+            packages = PackageSelector.get_packages_to_install(config['packagelist_file'],
37
+                                                               options.generated_data_path)
38
+        if 'additional_packages' in config:
39
+            packages = packages.extend(config['additional_packages'])
40
+
41
+    config['packages'] = packages
42
+    # Run the installer
43
+    package_installer = Installer(config, rpm_path=options.rpm_path,
44
+                                  log_path=options.log_path, log_level=options.log_level)
45
+    return package_installer.install(None)
46
+
47
+def get_file_name_with_last_folder(filename):
48
+    basename = os.path.basename(filename)
49
+    dirname = os.path.dirname(filename)
50
+    lastfolder = os.path.basename(dirname)
51
+    name = os.path.join(lastfolder, basename)
52
+    return name
53
+
54
+def create_pkg_list_to_copy_to_iso(build_install_option, output_data_path):
55
+    option_list_json = Utils.jsonread(build_install_option)
56
+    options_sorted = option_list_json.items()
57
+    packages = []
58
+    for install_option in options_sorted:
59
+        if install_option[0] != "iso":
60
+            file_path = os.path.join(output_data_path, install_option[1]["file"])
61
+            package_list_json = Utils.jsonread(file_path)
62
+            packages = packages + package_list_json["packages"]
63
+    return packages
64
+
65
+def create_additional_file_list_to_copy_in_iso(base_path, build_install_option):
66
+    option_list_json = Utils.jsonread(build_install_option)
67
+    options_sorted = option_list_json.items()
68
+    file_list = []
69
+    for install_option in options_sorted:
70
+        if "additional-files" in install_option[1]:
71
+            file_list = file_list + list(map(
72
+                lambda filename: os.path.join(base_path, filename),
73
+                install_option[1].get("additional-files")))
74
+    return file_list
75
+
76
+    #copy_flags 1: add the rpm file for the package
77
+    #           2: add debuginfo rpm file for the package.
78
+    #           4: add src rpm file for the package
79
+def create_rpm_list_to_be_copied_to_iso(pkg_to_rpm_map_file, build_install_option, copy_flags,
80
+                                        output_data_path):
81
+    packages = []
82
+    if build_install_option is None:
83
+        packages = []
84
+    else:
85
+        packages = create_pkg_list_to_copy_to_iso(build_install_option, output_data_path)
86
+
87
+    rpm_list = []
88
+    pkg_to_rpm_map = Utils.jsonread(pkg_to_rpm_map_file)
89
+    for k in pkg_to_rpm_map:
90
+        if build_install_option is None or k in packages:
91
+            if not pkg_to_rpm_map[k]['rpm'] is None and bool(copy_flags & 1):
92
+                filename = pkg_to_rpm_map[k]['rpm']
93
+                rpm_list.append(get_file_name_with_last_folder(filename))
94
+            if not pkg_to_rpm_map[k]['debugrpm'] is None and bool(copy_flags & 2):
95
+                filename = pkg_to_rpm_map[k]['debugrpm']
96
+                rpm_list.append(pkg_to_rpm_map[k]['debugrpm'])
97
+            if not pkg_to_rpm_map[k]['sourcerpm'] is None and bool(copy_flags & 4):
98
+                rpm_list.append(pkg_to_rpm_map[k]['sourcerpm'])
99
+    return rpm_list
100
+
101
+def make_debug_iso(working_directory, debug_iso_path, rpm_list):
102
+    if os.path.exists(working_directory) and os.path.isdir(working_directory):
103
+        shutil.rmtree(working_directory)
104
+    process = subprocess.Popen(['mkdir', '-p', os.path.join(working_directory, "DEBUGRPMS")])
105
+    retval = process.wait()
106
+    for rpmfile in rpm_list:
107
+        if os.path.isfile(rpmfile):
108
+            dirname = os.path.dirname(rpmfile)
109
+            lastfolder = os.path.basename(dirname)
110
+            dest_working_directory = os.path.join(working_directory, "DEBUGRPMS", lastfolder)
111
+            if not os.path.isdir(dest_working_directory):
112
+                process = subprocess.Popen(['mkdir', dest_working_directory])
113
+                retval = process.wait()
114
+            shutil.copy2(rpmfile, dest_working_directory)
115
+    process = subprocess.Popen(['mkisofs', '-r', '-o', debug_iso_path, working_directory])
116
+    retval = process.wait()
117
+    shutil.rmtree(working_directory)
118
+
119
+def make_src_iso(working_directory, src_iso_path, rpm_list):
120
+    if os.path.exists(working_directory) and os.path.isdir(working_directory):
121
+        shutil.rmtree(working_directory)
122
+    process = subprocess.Popen(['mkdir', '-p', os.path.join(working_directory, "SRPMS")])
123
+    retval = process.wait()
124
+    for rpmfile in rpm_list:
125
+        if os.path.isfile(rpmfile):
126
+            shutil.copy2(rpmfile, os.path.join(working_directory, "SRPMS"))
127
+    process = subprocess.Popen(['mkisofs', '-r', '-o', src_iso_path, working_directory])
128
+    retval = process.wait()
129
+    shutil.rmtree(working_directory)
130
+
131
+def createIso(options):
132
+    working_directory = os.path.abspath(os.path.join(options.stage_path, "photon_iso"))
133
+    config = {}
134
+    config['iso_system'] = True
135
+    config['vmdk_install'] = False
136
+    config['type'] = 'iso'
137
+    config['working_directory'] = working_directory
138
+
139
+    result = runInstaller(options, config)
140
+    if not result:
141
+        raise Exception("Installation process failed")
142
+    # Making the iso if needed
143
+    if options.iso_path:
144
+        rpm_list = " ".join(
145
+            create_rpm_list_to_be_copied_to_iso(
146
+                options.pkg_to_rpm_map_file,
147
+                options.pkg_to_be_copied_conf_file, 1, options.generated_data_path))
148
+        files_to_copy = " ".join(
149
+            create_additional_file_list_to_copy_in_iso(
150
+                os.path.abspath(options.stage_path), options.package_list_file))
151
+
152
+        process = subprocess.Popen([options.installer_path + '/mk-install-iso.sh', '-w',
153
+                                    working_directory, options.iso_path,
154
+                                    options.rpm_path, options.package_list_file,
155
+                                    rpm_list, options.stage_path, files_to_copy,
156
+                                    options.generated_data_path])
157
+        retval = process.wait()
158
+
159
+    if options.debug_iso_path:
160
+        debug_rpm_list = create_rpm_list_to_be_copied_to_iso(
161
+            options.pkg_to_rpm_map_file, options.pkg_to_be_copied_conf_file, 2,
162
+            options.generated_data_path)
163
+        make_debug_iso(working_directory, options.debug_iso_path, debug_rpm_list)
164
+
165
+    if options.src_iso_path:
166
+        rpm_list = create_rpm_list_to_be_copied_to_iso(options.pkg_to_rpm_map_file,
167
+                                                       options.pkg_to_be_copied_conf_file, 4,
168
+                                                       options.generated_data_path)
169
+        make_src_iso(working_directory, options.src_iso_path, rpm_list)
170
+    if os.path.exists(working_directory) and os.path.isdir(working_directory):
171
+        shutil.rmtree(working_directory) 
172
+
173
+def cryptPassword(config, passwordtext):
174
+    config['passwordtext'] = passwordtext
175
+    crypted = config['password']['crypted']
176
+    if config['password']['text'] == 'PASSWORD':
177
+        config['password'] = "".join([random.SystemRandom().choice(
178
+                string.ascii_letters + string.digits) for _ in range(16)])
179
+        if crypted:
180
+            config['password'] = crypt.crypt(
181
+                config['password'],
182
+                "$6$" + "".join([random.SystemRandom().choice(
183
+                    string.ascii_letters + string.digits) for _ in range(16)]))
184
+    else:
185
+        config['password'] = crypt.crypt(passwordtext, '$6$saltsalt$')
186
+
187
+def replaceScript(script_dir, img, script_name, parent_script_dir=None):
188
+    if not parent_script_dir:
189
+        parent_script_dir = script_dir
190
+    script = parent_script_dir + '/' + script_name
191
+    if os.path.isfile(script_dir + '/' + img + '/' + script_name):
192
+        script = script_dir + '/' + img + '/' + script_name
193
+    return script
194
+
195
+def verifyImageTypeAndConfig(config_file, img_name):
196
+    # All of the below combinations are supported
197
+    # 1. make image IMG_NAME=<name>
198
+    # 2. make image IMG_NAME=<name> CONFIG=<config_file_path>
199
+    # 3. make image CONFIG=<config_file_path>
200
+    config = None
201
+    if img_name and img_name != '':
202
+        # Verify there is a directory corresponding to image
203
+        if img_name not in next(os.walk('.'))[1]:
204
+            return (False, config)
205
+        if config_file and config_file != '' and os.path.isfile(config_file):
206
+            config = Utils.jsonread(config_file)
207
+            if 'image_type' in config and config['image_type'] != img_name:
208
+                return (False, config)
209
+        else:
210
+            config_file = img_name + "/config_" + img_name + ".json"
211
+            if os.path.isfile(config_file):
212
+                config = Utils.jsonread(config_file)
213
+                if 'image_type' not in config:
214
+                    config['image_type'] = img_name
215
+            else:
216
+                return (False, config)
217
+        return (True, config)
218
+    else:
219
+        if not config_file or config_file == '':
220
+            return (False, config)
221
+        else:
222
+            config = Utils.jsonread(config_file)
223
+            if 'image_type' not in config:
224
+                return (False, config)
225
+            else:
226
+                return (True, config)
227
+
228
+def create_vmdk_and_partition(config, vmdk_path, disk_setup_script):
229
+    partitions_data = {}
230
+
231
+    firmware = "bios"
232
+    if 'boot' in config and config['boot'] == 'efi':
233
+        firmware = "efi"
234
+    process = subprocess.Popen([disk_setup_script, '-rp', config['size']['root'], '-sp',
235
+                                config['size']['swap'], '-n', vmdk_path, '-fm', firmware],
236
+                               stdout=subprocess.PIPE)
237
+    count = 0
238
+
239
+    while True:
240
+        line = process.stdout.readline().decode()
241
+        if line == '':
242
+            retval = process.poll()
243
+            if retval is not None:
244
+                break
245
+        sys.stdout.write(line)
246
+        if line.startswith("DISK_DEVICE="):
247
+            partitions_data['disk'] = line.replace("DISK_DEVICE=", "").strip()
248
+            count += 1
249
+        elif line.startswith("ROOT_PARTITION="):
250
+            partitions_data['root'] = line.replace("ROOT_PARTITION=", "").strip()
251
+            partitions_data['boot'] = partitions_data['root']
252
+            partitions_data['bootdirectory'] = '/boot/'
253
+            partitions_data['partitions'] = [{'path': partitions_data['root'], 'mountpoint': '/',
254
+                                          'filesystem': 'ext4'}]
255
+            count += 1
256
+        elif line.startswith("ESP_PARTITION="):
257
+            partitions_data['esp'] = line.replace("ESP_PARTITION=", "").strip()
258
+            partitions_data['partitions'].append({'path': partitions_data['esp'], 'mountpoint': '/boot/esp',
259
+                                          'filesystem': 'vfat'})
260
+            count += 1
261
+    return partitions_data, count == 2 or count == 3
262
+
263
+def createImage(options):
264
+    (validImage, config) = verifyImageTypeAndConfig(options.config_file, options.img_name)
265
+    if not validImage:
266
+        raise Exception("Image type/config not supported")
267
+    
268
+    if 'ova' in config['image_type'] and shutil.which("ovftool") is None:
269
+        raise Exception("ovftool is not available")
270
+    workingDir = os.path.abspath(options.stage_path + "/" + config['image_type'])
271
+    if os.path.exists(workingDir) and os.path.isdir(workingDir):
272
+        shutil.rmtree(workingDir)
273
+    os.mkdir(workingDir)
274
+    if 'password' in config:
275
+        cryptPassword(config, config['password']['text'])
276
+    script_dir = os.path.dirname(os.path.realpath(__file__))
277
+    # Use image specific scripts
278
+    disk_setup_script = replaceScript(script_dir, config['image_type'], "mk-setup-vmdk.sh")
279
+    disk_cleanup_script = replaceScript(script_dir, config['image_type'], "mk-clean-vmdk.sh")
280
+    grub_script = replaceScript(script_dir, config['image_type'], "mk-setup-grub.sh", options.installer_path)
281
+    prepare_script = replaceScript(script_dir, config['image_type'], "mk-prepare-system.sh", options.installer_path)
282
+    config['prepare_script'] = prepare_script
283
+    config['setup_grub_script'] = grub_script
284
+    
285
+    if options.additional_rpms_path:
286
+        os.mkdir(options.rpm_path + '/additional')
287
+        for item in os.listdir(options.additional_rpms_path):
288
+            s = os.path.join(options.additional_rpms_path, item)
289
+            d = os.path.join(options.rpm_path + '/additional', item)
290
+            shutil.copy2(s, d)
291
+
292
+    os.chdir(workingDir)
293
+    vmdk_path = workingDir + "/photon-" + config['image_type']
294
+    config['disk'], success = create_vmdk_and_partition(config, vmdk_path, disk_setup_script)
295
+    if not success:
296
+        raise Exception("Unexpected failure in creating disk, please check the logs")
297
+        sys.exit(1)
298
+    config['iso_system'] = False
299
+    config['vmdk_install'] = True
300
+    result = runInstaller(options, config)
301
+    process = subprocess.Popen([disk_cleanup_script, config['disk']['disk']])
302
+    process.wait()
303
+    if not result:
304
+        raise Exception("Installation process failed")
305
+    os.chdir(script_dir)
306
+    imagegenerator.generateImage(
307
+                                vmdk_path + '.raw',
308
+                                options.rpm_path + '/additional/',
309
+                                options.src_root + '/tools/bin/',
310
+                                options.src_root,
311
+                                config
312
+                              )
313
+
314
+if __name__ == '__main__':
315
+    parser = ArgumentParser()
316
+
317
+    # Common args
318
+    parser.add_argument("-e", "--src-root", dest="src_root", default="../..")
319
+    parser.add_argument("-f", "--installer-path", dest="installer_path", default="../../installer")
320
+    parser.add_argument("-g", "--generated-data-path", dest="generated_data_path", default="../../stage/common/data")
321
+    parser.add_argument("-s", "--stage-path", dest="stage_path", default="../../stage")
322
+    parser.add_argument("-l", "--log-path", dest="log_path", default="../../stage/LOGS")
323
+    parser.add_argument("-y", "--log-level", dest="log_level")
324
+    # Image builder args for ami, gce, azure, ova, rpi3 etc.
325
+    parser.add_argument("-c", "--config-file", dest="config_file")
326
+    parser.add_argument("-a", "--additional-rpms-path", dest="additional_rpms_path")
327
+    parser.add_argument("-i", "--img-name", dest="img_name")
328
+    # ISO builder args
329
+    parser.add_argument("-j", "--iso-path", dest="iso_path")
330
+    parser.add_argument("-k", "--debug-iso-path", dest="debug_iso_path")
331
+    parser.add_argument("-m", "--src-iso-path", dest="src_iso_path")
332
+    parser.add_argument("-r", "--rpm-path", dest="rpm_path", default="../../stage/RPMS")
333
+    parser.add_argument("-x", "--srpm-path", dest="srpm_path", default="../../stage/SRPMS")
334
+    parser.add_argument("-p", "--package-list-file", dest="package_list_file", default="../../common/data/build_install_options_all.json")
335
+    parser.add_argument("-d", "--pkg-to-rpm-map-file", dest="pkg_to_rpm_map_file", default="../../stage/pkg_info.json")
336
+    parser.add_argument("-z", "--pkg-to-be-copied-conf-file", dest="pkg_to_be_copied_conf_file")
337
+
338
+    options = parser.parse_args()
339
+    if options.config_file and options.config_file != '':
340
+        options.config_file = os.path.abspath(options.config_file)
341
+    # Create ISO
342
+    os.chdir(os.path.dirname(os.path.realpath(__file__)))
343
+    if options.iso_path or options.debug_iso_path or options.src_iso_path:
344
+        createIso(options)
345
+    elif options.config_file or options.img_name:
346
+        createImage(options)
347
+    else:
348
+        raise Exception("No supported image type defined") 
0 349
new file mode 100755
... ...
@@ -0,0 +1,229 @@
0
+#!/usr/bin/python3
1
+
2
+import os
3
+import re
4
+import shutil
5
+import tarfile
6
+import fileinput
7
+from argparse import ArgumentParser
8
+import json
9
+from utils import Utils
10
+import ovagenerator
11
+
12
+def prepLoopDevice(loop_device_path, mount_path):
13
+    Utils.runshellcommand(
14
+            "mount -t ext4 {} {}".format(loop_device_path, mount_path))
15
+    Utils.runshellcommand("mount -o bind /proc {}".format(mount_path + "/proc"))
16
+    Utils.runshellcommand("mount -o bind /dev {}".format(mount_path + "/dev"))
17
+    Utils.runshellcommand("mount -o bind /dev/pts {}".format(mount_path + "/dev/pts"))
18
+    Utils.runshellcommand("mount -o bind /sys {}".format(mount_path + "/sys"))        
19
+
20
+def cleanupMountPoints(mount_path):
21
+    Utils.runshellcommand("umount -l {}".format(mount_path + "/sys"))
22
+    Utils.runshellcommand("umount -l {}".format(mount_path + "/dev/pts"))
23
+    Utils.runshellcommand("umount -l {}".format(mount_path + "/dev"))
24
+    Utils.runshellcommand("umount -l {}".format(mount_path + "/proc"))
25
+
26
+    Utils.runshellcommand("sync")
27
+    Utils.runshellcommand("umount -l {}".format(mount_path))
28
+
29
+def installAdditionalRpms(mount_path, additional_rpms_path):
30
+    os.mkdir(mount_path + "/additional_rpms")
31
+    Utils.copyallfiles(additional_rpms_path,
32
+                       mount_path + "/additional_rpms")
33
+    Utils.runshellcommand(
34
+        "chroot {} /bin/bash -c 'rpm -i /additional_rpms/*'".format(mount_path))
35
+    shutil.rmtree(mount_path + "/additional_rpms", ignore_errors=True)
36
+    shutil.rmtree(additional_rpms_path, ignore_errors=True)
37
+
38
+def writefstabandgrub(mount_path, uuidval, partuuidval):
39
+    os.remove(mount_path + "/etc/fstab")
40
+    f = open(mount_path + "/etc/fstab", "w")
41
+    if uuidval != '':
42
+        f.write("UUID={}    /    ext4    defaults 1 1\n".format(uuidval))
43
+    else:
44
+        f.write("PARTUUID={}    /    ext4    defaults 1 1\n".format(partuuidval))
45
+    f.close()
46
+    Utils.replaceinfile(mount_path + "/boot/grub/grub.cfg",
47
+                        "rootpartition=PARTUUID=.*$",
48
+                        "rootpartition=PARTUUID={}".format(partuuidval))
49
+
50
+def generateUuid(loop_device_path):
51
+    partuuidval = (Utils.runshellcommand(
52
+        "blkid -s PARTUUID -o value {}".format(loop_device_path))).rstrip('\n')
53
+    uuidval = (Utils.runshellcommand(
54
+        "blkid -s UUID -o value {}".format(loop_device_path))).rstrip('\n')
55
+    if partuuidval == '':
56
+        sgdiskout = Utils.runshellcommand(
57
+            "sgdisk -i 2 {} ".format(disk_device))
58
+        partuuidval = (re.findall(r'Partition unique GUID.*',
59
+                                  sgdiskout))[0].split(':')[1].strip(' ').lower()
60
+
61
+    if partuuidval == '':
62
+        raise RuntimeError("Cannot generate partuuid")
63
+
64
+    return (uuidval, partuuidval)
65
+
66
+def customizeImage(config, mount_path):
67
+    build_scripts_path = os.path.dirname(os.path.abspath(__file__))
68
+    image_name = config['image_type']
69
+    if 'additionalfiles' in config:
70
+        for filetuples in config['additionalfiles']:
71
+            for src, dest in filetuples.items():
72
+                if (os.path.isdir(build_scripts_path + '/' +
73
+                                  image_name + '/' + src)):
74
+                    shutil.copytree(build_scripts_path + '/' +
75
+                                    image_name + '/' + src,
76
+                                    mount_path + dest, True)
77
+                else:
78
+                    shutil.copyfile(build_scripts_path + '/' +
79
+                                    image_name + '/' + src,
80
+                                    mount_path + dest)
81
+    if 'postinstallscripts' in config:
82
+        if not os.path.exists(mount_path + "/tempscripts"):
83
+            os.mkdir(mount_path + "/tempscripts")
84
+        for script in config['postinstallscripts']:
85
+            shutil.copy(build_scripts_path + '/' +
86
+                        image_name + '/' + script,
87
+                        mount_path + "/tempscripts")
88
+        for script in os.listdir(mount_path + "/tempscripts"):
89
+            print("     ...running script {}".format(script))
90
+            Utils.runshellcommand(
91
+                "chroot {} /bin/bash -c '/tempscripts/{}'".format(mount_path, script))
92
+        shutil.rmtree(mount_path + "/tempscripts", ignore_errors=True)
93
+    if 'expirepassword' in config and config['expirepassword']:
94
+        Utils.runshellcommand("chage -R {} -d 0 root".format(mount_path))
95
+
96
+def createOutputArtifact(raw_image_path, config, src_root, tools_bin_path):
97
+    photon_release_ver = os.environ['PHOTON_RELEASE_VER']
98
+    photon_build_num = os.environ['PHOTON_BUILD_NUM']
99
+    new_name = ""
100
+    img_path = os.path.dirname(os.path.realpath(raw_image_path))
101
+    # Rename gce image to disk.raw
102
+    if config['image_type'] == "gce":
103
+        new_name = img_path + '/disk.raw'
104
+
105
+    else:
106
+        new_name = (img_path + '/photon-' + config['image_type'] +
107
+                    '-' + photon_release_ver + '-' +
108
+                    photon_build_num + '.raw')
109
+
110
+    shutil.move(raw_image_path, new_name)
111
+    raw_image = new_name
112
+
113
+    if config['artifacttype'] == 'tgz':
114
+        print("Generating the tar.gz artifact ...")
115
+        outputfile = (img_path + '/photon-' + config['image_type'] +
116
+                      '-' + photon_release_ver + '-' +
117
+                      photon_build_num + '.tar.gz')
118
+        generateCompressedFile(raw_image, outputfile, "w:gz")
119
+    elif config['artifacttype'] == 'xz':
120
+        print("Generating the xz artifact ...")
121
+        outputfile = (img_path + '/photon-' + config['image_type'] +
122
+                      '-' + photon_release_ver + '-' +
123
+                      photon_build_num + '.xz')
124
+        generateCompressedFile(raw_image, outputfile, "w:xz")
125
+    elif 'vhd' in config['artifacttype']:
126
+        relrawpath = os.path.relpath(raw_image, src_root)
127
+        vhdname = (os.path.dirname(relrawpath) + '/photon-' +
128
+                   config['image_type'] + '-' + photon_release_ver + '-' +
129
+                   photon_build_num + '.vhd')
130
+        print("Converting raw disk to vhd ...")
131
+        info_output = Utils.runshellcommand(
132
+            "docker run -v {}:/mnt:rw anishs/qemu-img info -f raw --output json {}"
133
+            .format(src_root, '/mnt/' + relrawpath))
134
+        mbsize = 1024 * 1024
135
+        mbroundedsize = ((int(json.loads(info_output)["virtual-size"])/mbsize + 1) * mbsize)
136
+        Utils.runshellcommand(
137
+            "docker run -v {}:/mnt:rw anishs/qemu-img resize -f raw {} {}"
138
+            .format(src_root, '/mnt/' + relrawpath, mbroundedsize))
139
+        Utils.runshellcommand(
140
+            "docker run -v {}:/mnt:rw anishs/qemu-img convert {} -O "
141
+            "vpc -o subformat=fixed,force_size {}"
142
+            .format(src_root, '/mnt/' + relrawpath, '/mnt/' + vhdname))
143
+        if config['artifacttype'] == 'vhd.gz':
144
+            outputfile = (img_path + '/photon-' + config['image_type'] +
145
+                          '-' + photon_release_ver + '-' +
146
+                          photon_build_num + '.vhd.tar.gz')
147
+            generateCompressedFile(vhdname, outputfile, "w:gz")
148
+    elif config['artifacttype'] == 'ova':
149
+        ovagenerator.create_ova_image(raw_image, tools_bin_path, config)
150
+    elif config['artifacttype'] == 'raw':
151
+        pass
152
+    else:
153
+        raise ValueError("Unknown output format")
154
+
155
+    if not config['keeprawdisk']:
156
+        os.remove(raw_image)
157
+
158
+def generateCompressedFile(inputfile, outputfile, formatstring):
159
+    tarout = tarfile.open(outputfile, formatstring)
160
+    tarout.add(inputfile, arcname=os.path.basename(inputfile))
161
+    tarout.close()
162
+
163
+def generateImage(raw_image_path, additional_rpms_path, tools_bin_path, src_root, config):
164
+    working_directory = os.path.dirname(raw_image_path)
165
+    mount_path = os.path.splitext(raw_image_path)[0]
166
+    build_scripts_path = os.path.dirname(os.path.abspath(__file__))
167
+
168
+    if os.path.exists(mount_path) and os.path.isdir(mount_path):
169
+        shutil.rmtree(mount_path)
170
+    os.mkdir(mount_path)
171
+    disk_device = (Utils.runshellcommand(
172
+        "losetup --show -f {}".format(raw_image_path))).rstrip('\n')
173
+    disk_partitions = Utils.runshellcommand("kpartx -as {}".format(disk_device))
174
+    device_name = disk_device.split('/')[2]
175
+    if not device_name:
176
+        raise Exception("Could not create loop device and partition")
177
+    loop_device_path = "/dev/mapper/{}p2".format(device_name)
178
+    
179
+    try:
180
+        (uuidval, partuuidval) = generateUuid(loop_device_path)
181
+        # Prep the loop device
182
+        prepLoopDevice(loop_device_path, mount_path)
183
+        # Clear the root password if not set explicitly from the config file
184
+        if config['passwordtext'] == 'PASSWORD':
185
+            Utils.replaceinfile(mount_path + "/etc/shadow",
186
+                                'root:.*?:', 'root:*:')
187
+        # Clear machine-id so it gets regenerated on boot
188
+        open(mount_path + "/etc/machine-id", "w").close()
189
+        # Write fstab
190
+        writefstabandgrub(mount_path, uuidval, partuuidval)
191
+        if additional_rpms_path and os.path.exists(additional_rpms_path):
192
+            installAdditionalRpms(mount_path, additional_rpms_path)
193
+        # Perform additional steps defined in installer config
194
+        customizeImage(config, mount_path)
195
+    except Exception as e:
196
+        print(e)
197
+    finally:
198
+        cleanupMountPoints(mount_path)
199
+        Utils.runshellcommand("kpartx -d {}".format(disk_device))
200
+        Utils.runshellcommand("losetup -d {}".format(disk_device))
201
+
202
+        shutil.rmtree(mount_path)
203
+        createOutputArtifact(raw_image_path, config, src_root, tools_bin_path)
204
+    
205
+if __name__ == '__main__':
206
+    parser = ArgumentParser()
207
+
208
+    parser.add_argument("-r", "--raw-image-path", dest="raw_image_path")
209
+    parser.add_argument("-c", "--config-path", dest="config_path")
210
+    parser.add_argument("-a", "--additional-rpms-path", dest="additional_rpms_path")
211
+    parser.add_argument("-t", "--tools-bin-path", dest="tools_bin_path")
212
+    parser.add_argument("-s", "--src-root", dest="src_root")
213
+
214
+    options = parser.parse_args()
215
+    if config_path:
216
+        config = Utils.jsonread(options.config_path)
217
+    else:
218
+        raise Exception("No config file defined")
219
+
220
+    generateImage(
221
+                options.raw_image_path,
222
+                options.working_directory,
223
+                options.additional_rpms_path,
224
+                options.tools_bin_path,
225
+                options.src_root,
226
+                config
227
+                )
228
+
... ...
@@ -18,7 +18,6 @@ SCRIPT_PATH=$(dirname $(realpath -s $0))
18 18
 INSTALLER_PATH=$SCRIPT_PATH/../../installer
19 19
 source ${INSTALLER_PATH}/config.inc		#	configuration parameters
20 20
 LOGFILE="/var/log/${PRGNAME}-${LOGFILE}"	#	set log file name
21
-LFS_DISK="/mnt/photon-disk"
22 21
 [ ${EUID} -eq 0 ]	|| { echo "${PRGNAME}: Need to be root user: FAILURE"; exit 1; }
23 22
 > ${LOGFILE}		#	clear/initialize logfile
24 23
 
... ...
@@ -1,15 +1,16 @@
1 1
 {
2
+    "image_type": "ova",
2 3
     "hostname": "photon-machine",
3 4
     "password": 
4 5
         {
5
-            "crypted": false,
6
-            "text": "PASSWORD"
6
+            "crypted": true,
7
+            "text": "changeme"
7 8
         },
8 9
     "packagelist_file": "packages_ova.json",
9 10
     "size": { "root": "16", "swap": "0" },
10 11
     "public_key":"<ssh-key-here>",
11
-    "customartifacts": { "postinstallscripts": ["ova-custom-patch.sh"] },
12
+    "expirepassword": true,
12 13
     "artifacttype": "ova",
13
-    "keeprawdisk": "false"
14
+    "keeprawdisk": false
14 15
 }
15 16
 
16 17
deleted file mode 100755
... ...
@@ -1,3 +0,0 @@
1
-#!/bin/bash
2
-echo -e "changeme\nchangeme" | passwd root
3
-chage -d 0 root
4 1
\ No newline at end of file
... ...
@@ -1,16 +1,17 @@
1 1
 {
2
+    "image_type": "ova_uefi",
2 3
 	"hostname": "photon-machine",
3 4
 	"password": 
4 5
 		{
5
-			"crypted": false,
6
-			"text": "PASSWORD"
6
+			"crypted": true,
7
+			"text": "changeme"
7 8
 		},
8 9
 	"packagelist_file": "packages_ova.json",
9 10
     "size": {"root": "16", "swap": "0"},
10 11
     "boot":"efi",
11 12
     "public_key":"<ssh-key-here>",
12
-    "customartifacts": { "postinstallscripts": ["ova_uefi-custom-patch.sh"] },
13
+    "expirepassword": true,
13 14
     "artifacttype": "ova",
14
-    "keeprawdisk": "false"
15
+    "keeprawdisk": false
15 16
 }
16 17
 
17 18
deleted file mode 100755
... ...
@@ -1,3 +0,0 @@
1
-#!/bin/bash
2
-echo -e "changeme\nchangeme" | passwd root
3
-chage -d 0 root
4 1
new file mode 100755
... ...
@@ -0,0 +1,108 @@
0
+#!/usr/bin/python3
1
+
2
+import os
3
+import fileinput
4
+import tarfile
5
+from argparse import ArgumentParser
6
+from utils import Utils
7
+
8
+def create_ova_image(raw_image_name, tools_path, config):
9
+    build_scripts_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), config['image_type'])
10
+    output_path = os.path.dirname(os.path.realpath(raw_image_name))
11
+    utils = Utils()
12
+    # Remove older artifacts
13
+    files = os.listdir(output_path)
14
+    for file in files:
15
+        if file.endswith(".vmdk"):
16
+            os.remove(os.path.join(output_path, file))
17
+
18
+    vmx_path = os.path.join(output_path, 'photon-ova.vmx')
19
+    utils.replaceandsaveasnewfile(os.path.join(build_scripts_path, 'vmx-template'),
20
+                                  vmx_path, 'VMDK_IMAGE',
21
+                                  os.path.join(output_path, 'photon-ova.vmdk'))
22
+    vixdiskutil_path = os.path.join(tools_path, 'vixdiskutil')
23
+    vmdk_path = os.path.join(output_path, 'photon-ova.vmdk')
24
+    ovf_path = os.path.join(output_path, 'photon-ova.ovf')
25
+    mf_path = os.path.join(output_path, 'photon-ova.mf')
26
+    ovfinfo_path = os.path.join(build_scripts_path, 'ovfinfo.txt')
27
+    vmdk_capacity = (int(config['size']['root']) +
28
+                     int(config['size']['swap'])) * 1024
29
+    utils.runshellcommand(
30
+        "{} -convert {} -cap {} {}".format(vixdiskutil_path,
31
+                                           raw_image_name,
32
+                                           vmdk_capacity,
33
+                                           vmdk_path))
34
+    utils.runshellcommand(
35
+        "{} -wmeta toolsVersion 2147483647 {}".format(vixdiskutil_path, vmdk_path))
36
+
37
+    utils.runshellcommand("ovftool {} {}".format(vmx_path, ovf_path))
38
+    utils.replaceinfile(ovf_path, 'otherGuest', 'other3xLinux64Guest')
39
+
40
+    #Add product info
41
+    if os.path.exists(ovfinfo_path):
42
+        with open(ovfinfo_path) as f:
43
+            lines = f.readlines()
44
+            for line in fileinput.input(ovf_path, inplace=True):
45
+                if line.strip() == '</VirtualHardwareSection>':
46
+                    for ovfinfoline in lines:
47
+                        print(ovfinfoline)
48
+                else:
49
+                    print(line)
50
+
51
+    if os.path.exists(mf_path):
52
+        os.remove(mf_path)
53
+
54
+    cwd = os.getcwd()
55
+    os.chdir(output_path)
56
+    out = utils.runshellcommand("openssl sha1 photon-ova-disk1.vmdk photon-ova.ovf")
57
+    with open(mf_path, "w") as source:
58
+        source.write(out)
59
+    rawsplit = os.path.splitext(raw_image_name)
60
+    ova_name = rawsplit[0] + '.ova'
61
+
62
+    ovatar = tarfile.open(ova_name, "w", format=tarfile.USTAR_FORMAT)
63
+    for name in ["photon-ova.ovf", "photon-ova.mf", "photon-ova-disk1.vmdk"]:
64
+        ovatar.add(name, arcname=os.path.basename(name))
65
+    ovatar.close()
66
+    os.remove(vmx_path)
67
+    os.remove(mf_path)
68
+
69
+    if 'additionalhwversion' in config:
70
+        for addlversion in config['additionalhwversion']:
71
+            new_ovf_path = output_path + "/photon-ova-hw{}.ovf".format(addlversion)
72
+            mf_path = output_path + "/photon-ova-hw{}.mf".format(addlversion)
73
+            utils.replaceandsaveasnewfile(
74
+                ovf_path, new_ovf_path, "vmx-.*<", "vmx-{}<".format(addlversion))
75
+            out = utils.runshellcommand("openssl sha1 photon-ova-disk1.vmdk "
76
+                                        "photon-ova-hw{}.ovf".format(addlversion))
77
+            with open(mf_path, "w") as source:
78
+                source.write(out)
79
+            temp_name_list = os.path.basename(ova_name).split('-')
80
+            temp_name_list = temp_name_list[:2] + ["hw{}".format(addlversion)] + temp_name_list[2:]
81
+            new_ova_name = '-'.join(temp_name_list)
82
+            new_ova_path = output_path + '/' + new_ova_name
83
+            ovatar = tarfile.open(new_ova_path, "w", format=tarfile.USTAR_FORMAT)
84
+            for name in [new_ovf_path, mf_path, "photon-ova-disk1.vmdk"]:
85
+                ovatar.add(name, arcname=os.path.basename(name))
86
+            ovatar.close()
87
+
88
+            os.remove(new_ovf_path)
89
+            os.remove(mf_path)
90
+    os.chdir(cwd)
91
+    os.remove(ovf_path)
92
+    os.remove(vmdk_path)
93
+    files = os.listdir(output_path)
94
+    for file in files:
95
+        if file.endswith(".vmdk"):
96
+            os.remove(os.path.join(output_path, file))
97
+
98
+if __name__ == '__main__':
99
+    parser = ArgumentParser()
100
+
101
+    parser.add_argument("-r", "--raw-image-path", dest="raw_image_path")
102
+    parser.add_argument("-c", "--config-path", dest="config_path")
103
+    parser.add_argument("-t", "--tools-bin-path", dest="tools_bin_path")
104
+
105
+    options = parser.parse_args()
106
+
107
+    create_ova_image(options.raw_image_path, options.tools_bin_path, config)
... ...
@@ -1,7 +1,3 @@
1
-#
2
-# Copyright VMware, Inc 2015
3
-#
4
-
5 1
 MKDIR=/bin/mkdir
6 2
 RM=/bin/rm
7 3
 RMDIR=/bin/rm -rf
... ...
@@ -47,7 +43,8 @@ PHOTON_PULLSOURCES_CONFIG?=$(PHOTON_PKG_BUILDER_DIR)/bintray.conf
47 47
 endif
48 48
 PHOTON_PULL_PUBLISH_RPMS=$(PHOTON_PULL_PUBLISH_RPMS_DIR)/pullpublishrpms.sh
49 49
 PHOTON_PULL_PUBLISH_X_RPMS=$(PHOTON_PULL_PUBLISH_RPMS_DIR)/pullpublishXrpms.sh
50
-PHOTON_IMAGE_BUILDER=$(PHOTON_IMAGE_BUILDER_DIR)/image-builder.sh
50
+PHOTON_IMAGE_BUILDER=$(PHOTON_IMAGE_BUILDER_DIR)/imagebuilder.py
51
+PHOTON_PKGINFO_FILE=$(PHOTON_STAGE)/pkg_info.json
51 52
 
52 53
 PHOTON_CHROOT_CLEANER=$(PHOTON_PKG_BUILDER_DIR)/clean-up-chroot.py
53 54
 PHOTON_RPMS_DIR_NOARCH=$(PHOTON_RPMS_DIR)/noarch
... ...
@@ -1,4 +1,3 @@
1
-#    Copyright (C) 2015-2017 VMware, Inc. All rights reserved.
2 1
 #    pullsources.py
3 2
 #    Allows pulling packages'sources from a source repository.
4 3
 #
... ...
@@ -1,7 +1,5 @@
1 1
 #! /usr/bin/python3
2 2
 #
3
-#    Copyright (C) 2015 vmware inc.
4
-#
5 3
 #    Author: Harish Udaiya Kumar <hudaiyakumar@vmware.com>
6 4
 import sys
7 5
 import os
... ...
@@ -1,8 +1,7 @@
1
-#    Copyright (C) 2015 vmware inc.
1
+#!/usr/bin/python3
2 2
 #
3 3
 #    Author: Sharath George <sharathg@vmware.com>
4 4
 
5
-
6 5
 import json
7 6
 import collections
8 7