Change-Id: I33d4fe65b44a1479a40cc88ea2fff30e77e2b271
Reviewed-on: http://photon-jenkins.eng.vmware.com:8082/1659
Reviewed-by: Alexey Makhalov <amakhalov@vmware.com>
Tested-by: gerrit-photon <photon-checkins@vmware.com>
... | ... |
@@ -61,9 +61,10 @@ endif |
61 | 61 |
TOOLS_BIN := $(SRCROOT)/tools/bin |
62 | 62 |
CONTAIN := $(TOOLS_BIN)/contain |
63 | 63 |
VIXDISKUTIL := $(TOOLS_BIN)/vixdiskutil |
64 |
+IMGCONVERTER := $(TOOLS_BIN)/imgconverter |
|
64 | 65 |
|
65 | 66 |
.PHONY : all iso clean photon-build-machine photon-vagrant-build photon-vagrant-local cloud-image \ |
66 |
-check-tools check-docker check-bison check-g++ check-gawk check-createrepo check-vagrant check-packer check-packer-ovf-plugin check-sanity \ |
|
67 |
+check-tools check-docker check-bison check-g++ check-gawk check-createrepo check-kpartx check-vagrant check-packer check-packer-ovf-plugin check-sanity \ |
|
67 | 68 |
clean-install clean-chroot build-updated-packages check |
68 | 69 |
|
69 | 70 |
THREADS?=1 |
... | ... |
@@ -450,13 +451,13 @@ photon-vagrant-local: check-packer check-vagrant |
450 | 450 |
echo "Unable to find $(PHOTON_STAGE)/photon-$(PHOTON_RELEASE_VERSION)-$(PHOTON_BUILD_NUMBER).iso ... aborting build"; \ |
451 | 451 |
fi |
452 | 452 |
|
453 |
-cloud-image: $(PHOTON_STAGE) $(VIXDISKUTIL) iso |
|
453 |
+cloud-image: check-kpartx $(PHOTON_STAGE) $(VIXDISKUTIL) $(IMGCONVERTER) iso |
|
454 | 454 |
@echo "Building cloud image $(IMG_NAME)..." |
455 | 455 |
@cd $(PHOTON_CLOUD_IMAGE_BUILDER_DIR) |
456 | 456 |
$(PHOTON_CLOUD_IMAGE_BUILDER) $(PHOTON_CLOUD_IMAGE_BUILDER_DIR) $(IMG_NAME) $(SRCROOT) $(PHOTON_GENERATED_DATA_DIR) $(PHOTON_STAGE)/photon-$(PHOTON_RELEASE_VERSION)-$(PHOTON_BUILD_NUMBER).iso $(ADDITIONAL_RPMS_PATH) |
457 | 457 |
|
458 | 458 |
|
459 |
-cloud-image-all: $(PHOTON_STAGE) $(VIXDISKUTIL) iso |
|
459 |
+cloud-image-all: check-kpartx $(PHOTON_STAGE) $(VIXDISKUTIL) $(IMGCONVERTER) iso |
|
460 | 460 |
@echo "Building cloud images - gce, ami, azure and ova..." |
461 | 461 |
@cd $(PHOTON_CLOUD_IMAGE_BUILDER_DIR) |
462 | 462 |
$(PHOTON_CLOUD_IMAGE_BUILDER) $(PHOTON_CLOUD_IMAGE_BUILDER_DIR) gce $(SRCROOT) $(PHOTON_GENERATED_DATA_DIR) $(PHOTON_STAGE)/photon-$(PHOTON_RELEASE_VERSION)-$(PHOTON_BUILD_NUMBER).iso $(ADDITIONAL_RPMS_PATH) |
... | ... |
@@ -485,6 +486,9 @@ check-gawk: |
485 | 485 |
check-createrepo: |
486 | 486 |
@command -v createrepo >/dev/null 2>&1 || { echo "Package createrepo not installed. Aborting." >&2; exit 1; } |
487 | 487 |
|
488 |
+check-kpartx: |
|
489 |
+ @command -v kpartx >/dev/null 2>&1 || { echo "Package kpartx not installed. Aborting." >&2; exit 1; } |
|
490 |
+ |
|
488 | 491 |
check-vagrant: check-packer |
489 | 492 |
@command -v $(VAGRANT) >/dev/null 2>&1 || { echo "Vagrant not installed or wrong path, expecting $(VAGRANT). Aborting" >&2; exit 1; } |
490 | 493 |
|
... | ... |
@@ -558,3 +562,6 @@ $(VIXDISKUTIL): $(TOOLS_BIN) |
558 | 558 |
@cd $(SRCROOT)/tools/src/vixDiskUtil && \ |
559 | 559 |
make |
560 | 560 |
|
561 |
+$(IMGCONVERTER): $(TOOLS_BIN) |
|
562 |
+ @cd $(SRCROOT)/tools/src/imgconverter && \ |
|
563 |
+ make |
... | ... |
@@ -8,8 +8,11 @@ cd / |
8 | 8 |
echo "127.0.0.1 localhost" >> /etc/hosts |
9 | 9 |
|
10 | 10 |
# Update /etc/resolv.conf |
11 |
-rm /etc/resolv.conf |
|
12 |
-echo "nameserver 172.31.0.2" >> /etc/resolv.conf |
|
11 |
+if [ -f /etc/resolv.conf ] |
|
12 |
+ then |
|
13 |
+ rm /etc/resolv.conf |
|
14 |
+fi |
|
15 |
+echo "nameserver 169.254.169.253" >> /etc/resolv.conf |
|
13 | 16 |
echo "search ec2.internal" >> /etc/resolv.conf |
14 | 17 |
|
15 | 18 |
|
... | ... |
@@ -60,5 +63,7 @@ sed -i '/.*linux.*vmlinuz/ s/$/ console=ttyS0/' /boot/grub/grub.cfg |
60 | 60 |
echo 1 > /proc/sys/kernel/modules_disabled |
61 | 61 |
|
62 | 62 |
# Remove kernel symbols |
63 |
-rm /boot/system.map* |
|
64 |
- |
|
63 |
+if [ -f /boot/system.map* ] |
|
64 |
+ then |
|
65 |
+ rm /boot/system.map* |
|
66 |
+fi |
|
65 | 67 |
\ No newline at end of file |
... | ... |
@@ -1,12 +1,18 @@ |
1 | 1 |
{ |
2 |
- "hostname": "photon-machine", |
|
3 |
- "password": |
|
4 |
- { |
|
5 |
- "crypted": false, |
|
6 |
- "text": "PASSWORD" |
|
7 |
- }, |
|
8 |
- "type": "ami", |
|
9 |
- "size": {"root": "8", "swap": "0"}, |
|
10 |
- "public_key":"<ssh-key-here>" |
|
2 |
+ "hostname": "photon-machine", |
|
3 |
+ "password": |
|
4 |
+ { |
|
5 |
+ "crypted": false, |
|
6 |
+ "text": "PASSWORD" |
|
7 |
+ }, |
|
8 |
+ "type": "ami", |
|
9 |
+ "size": {"root": "16", "swap": "0"}, |
|
10 |
+ "public_key":"<ssh-key-here>", |
|
11 |
+ "postinstallscripts": [ "ami-patch.sh", "../password-expiry.sh" ], |
|
12 |
+ "additionalfiles": [ |
|
13 |
+ {"cloud-photon.cfg": "/etc/cloud/cloud.cfg"} |
|
14 |
+ ], |
|
15 |
+ "artifacttype": "tgz", |
|
16 |
+ "keeprawdisk": "false" |
|
11 | 17 |
} |
12 | 18 |
|
... | ... |
@@ -1,12 +1,18 @@ |
1 | 1 |
{ |
2 |
- "hostname": "photon-machine", |
|
3 |
- "password": |
|
4 |
- { |
|
5 |
- "crypted": false, |
|
6 |
- "text": "PASSWORD" |
|
7 |
- }, |
|
8 |
- "type": "azure", |
|
9 |
- "size": {"root": "8", "swap": "0"}, |
|
10 |
- "public_key":"<ssh-key-here>" |
|
2 |
+ "hostname": "photon-machine", |
|
3 |
+ "password": |
|
4 |
+ { |
|
5 |
+ "crypted": false, |
|
6 |
+ "text": "PASSWORD" |
|
7 |
+ }, |
|
8 |
+ "type": "azure", |
|
9 |
+ "size": {"root": "16", "swap": "0"}, |
|
10 |
+ "public_key":"<ssh-key-here>", |
|
11 |
+ "postinstallscripts": [ "azure-patch.sh", "../password-expiry.sh" ], |
|
12 |
+ "additionalfiles": [ |
|
13 |
+ {"cloud-photon.cfg": "/etc/cloud/cloud.cfg"} |
|
14 |
+ ], |
|
15 |
+ "artifacttype": "vhd", |
|
16 |
+ "keeprawdisk": "false" |
|
11 | 17 |
} |
12 | 18 |
|
... | ... |
@@ -18,22 +18,25 @@ GENERATED_DATA_PATH=$4 |
18 | 18 |
PHOTON_ISO_PATH=$5 |
19 | 19 |
PHOTON_STAGE_PATH=${PHOTON_ISO_PATH%/*} |
20 | 20 |
ADDITIONAL_RPMS_PATH=$6 |
21 |
-INSTALLER_PATH=$PHOTON_STAGE_PATH/$IMG_NAME |
|
22 |
-ISO_MOUNT_FOLDER=$PHOTON_STAGE_PATH/iso_mount |
|
21 |
+WORKING_DIR=$PHOTON_STAGE_PATH/$IMG_NAME |
|
23 | 22 |
|
24 | 23 |
PHOTON_IMG_OUTPUT_PATH=$PHOTON_STAGE_PATH/$IMG_NAME |
25 | 24 |
VMDK_CONFIG_FILE=${BUILD_SCRIPTS_PATH}/$IMG_NAME/vmdk_$IMG_NAME.json |
26 | 25 |
VMDK_CONFIG_SAFE_FILE=${BUILD_SCRIPTS_PATH}/$IMG_NAME/vmdk_safe_$IMG_NAME.json |
27 | 26 |
|
28 |
-mkdir -p $INSTALLER_PATH/installer |
|
29 |
-cp -R $SRC_ROOT/installer $INSTALLER_PATH/ |
|
27 |
+rm -rf $WORKING_DIR |
|
28 |
+mkdir -p $WORKING_DIR/installer |
|
29 |
+cp -R $SRC_ROOT/installer $WORKING_DIR/ |
|
30 | 30 |
|
31 |
-cd $INSTALLER_PATH/installer |
|
31 |
+cd $WORKING_DIR/installer |
|
32 | 32 |
cp $VMDK_CONFIG_FILE $VMDK_CONFIG_SAFE_FILE |
33 | 33 |
cp ${BUILD_SCRIPTS_PATH}/mk-setup-vmdk.sh . |
34 | 34 |
cp ${BUILD_SCRIPTS_PATH}/mk-clean-vmdk.sh . |
35 | 35 |
|
36 |
- |
|
36 |
+if [[ $IMG_NAME == ova* ]] |
|
37 |
+ then |
|
38 |
+ command -v ovftool >/dev/null 2>&1 || { echo "Ovftool not installed. Aborting." >&2; exit 1; } |
|
39 |
+fi |
|
37 | 40 |
if [[ $IMG_NAME != ova* ]] |
38 | 41 |
then |
39 | 42 |
cp ${BUILD_SCRIPTS_PATH}/mk-setup-grub.sh . |
... | ... |
@@ -49,105 +52,26 @@ sed -i "s/PASSWORD/$PASSWORD/" $VMDK_CONFIG_SAFE_FILE |
49 | 49 |
|
50 | 50 |
if [ -n "$ADDITIONAL_RPMS_PATH" ] |
51 | 51 |
then |
52 |
- mkdir $PHOTON_STAGE_PATH/RPMS/additonal |
|
53 |
- cp -f $ADDITIONAL_RPMS_PATH/* $PHOTON_STAGE_PATH/RPMS/additonal/ |
|
52 |
+ mkdir $PHOTON_STAGE_PATH/RPMS/additional |
|
53 |
+ cp -f $ADDITIONAL_RPMS_PATH/* $PHOTON_STAGE_PATH/RPMS/additional/ |
|
54 | 54 |
fi |
55 | 55 |
|
56 |
-./photonInstaller.py -p $GENERATED_DATA_PATH/build_install_options_$IMG_NAME.json -r $PHOTON_STAGE_PATH/RPMS -v $INSTALLER_PATH/photon-${IMG_NAME} -o $GENERATED_DATA_PATH -f $VMDK_CONFIG_SAFE_FILE |
|
56 |
+./photonInstaller.py -p $GENERATED_DATA_PATH/build_install_options_$IMG_NAME.json -r $PHOTON_STAGE_PATH/RPMS -v $WORKING_DIR/photon-${IMG_NAME} -o $GENERATED_DATA_PATH -f $VMDK_CONFIG_SAFE_FILE |
|
57 | 57 |
cat $VMDK_CONFIG_SAFE_FILE |
58 | 58 |
rm $VMDK_CONFIG_SAFE_FILE |
59 | 59 |
|
60 | 60 |
cd $BUILD_SCRIPTS_PATH |
61 | 61 |
|
62 |
-DISK_DEVICE=`losetup --show -f ${PHOTON_IMG_OUTPUT_PATH}/photon-${IMG_NAME}.raw` |
|
63 |
- |
|
64 |
-echo "Mapping device partition to loop device" |
|
65 |
-kpartx -av $DISK_DEVICE |
|
66 |
- |
|
67 |
-DEVICE_NAME=`echo $DISK_DEVICE|cut -c6- ` |
|
68 |
- |
|
69 |
-echo "DISK_DEVICE=$DISK_DEVICE" |
|
70 |
-echo "ROOT_PARTITION=/dev/mapper/${DEVICE_NAME}p2" |
|
71 |
- |
|
72 |
-rm -rf $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME} |
|
73 |
-mkdir $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME} |
|
74 |
- |
|
75 |
-UUID_VALUE=$(blkid -s UUID -o value /dev/mapper/${DEVICE_NAME}p2) |
|
76 |
-PARTUUID_VALUE=$(blkid -s PARTUUID -o value /dev/mapper/${DEVICE_NAME}p2) |
|
77 |
-if [ -z "$PARTUUID_VALUE" ] ; then |
|
78 |
- PARTUUID_VALUE=$(sgdisk -i 2 $DISK_DEVICE | grep "Partition unique GUID" | cut -d ' ' -f 4) |
|
79 |
-fi |
|
80 |
- |
|
81 |
-mkdir -p $ISO_MOUNT_FOLDER |
|
82 |
-mount -o loop $PHOTON_ISO_PATH $ISO_MOUNT_FOLDER |
|
83 |
-mount -v -t ext4 /dev/mapper/${DEVICE_NAME}p2 $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME} |
|
84 |
-rm -rf $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME}/installer |
|
85 |
-rm -rf $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME}/LOGS |
|
86 |
-cp $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME}/etc/shadow $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME}/etc/shadow.bak |
|
87 |
-sed -e "s/^\(root:\)[^:]*:/\1*:/" $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME}/etc/shadow.bak > $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME}/etc/shadow |
|
88 |
-rm -f $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME}/etc/shadow.bak |
|
89 |
-rm -f $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME}/etc/shadow- |
|
90 |
-rm -f $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME}/etc/machine-id |
|
91 |
-touch $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME}/etc/machine-id |
|
92 |
-rm -f $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME}/etc/fstab |
|
93 |
-echo "UUID=$UUID_VALUE / ext4 defaults 1 1" >> $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME}/etc/fstab |
|
94 |
-sed -i "s/rootpartition=PARTUUID=$/rootpartition=PARTUUID=$PARTUUID_VALUE/" $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME}/boot/grub/grub.cfg |
|
95 |
- |
|
96 |
-mount -o bind /proc $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME}/proc |
|
97 |
-mount -o bind /dev $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME}/dev |
|
98 |
-mount -o bind /dev/pts $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME}/dev/pts |
|
99 |
-mount -o bind /sys $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME}/sys |
|
100 |
-if [ -n "$ADDITIONAL_RPMS_PATH" ] |
|
101 |
- then |
|
102 |
- mkdir $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME}/additional_rpms |
|
103 |
- mkdir $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME}/var/run |
|
104 |
- cp -f $PHOTON_STAGE_PATH/RPMS/additonal/* $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME}/additional_rpms/ |
|
105 |
- chroot $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME} /bin/bash -c "rpm -i /additional_rpms/*" |
|
106 |
- rm -rf $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME}/additional_rpms/ |
|
107 |
-fi |
|
108 |
- |
|
109 |
-if [ $IMG_NAME != "ova" ] && [ $IMG_NAME != "ova_uefi" ] && [ $IMG_NAME != "ova_ovs" ] |
|
110 |
- then |
|
111 |
- cd $BUILD_SCRIPTS_PATH |
|
112 |
- if [ $IMG_NAME = "gce" ] |
|
113 |
- then |
|
114 |
- cp ntpd.service $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME}/lib/systemd/system/ |
|
115 |
- cp eth0.service $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME}/lib/systemd/system/ |
|
116 |
- fi |
|
117 |
- if [ $IMG_NAME != "ova_generic" ] |
|
118 |
- then |
|
119 |
- if [ -e $IMG_NAME/cloud-photon.cfg ] |
|
120 |
- then |
|
121 |
- cp -f $IMG_NAME/cloud-photon.cfg $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME}/etc/cloud/cloud.cfg |
|
122 |
- fi |
|
123 |
- cp $IMG_NAME/$IMG_NAME-patch.sh $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME}/ |
|
124 |
- cp /etc/resolv.conf $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME}/etc/ |
|
125 |
- echo "chrooting and running patch inside the chroot" |
|
126 |
- chroot $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME} /bin/bash -c "/$IMG_NAME-patch.sh" |
|
127 |
- rm -f $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME}/$IMG_NAME-patch.sh |
|
128 |
- # Change the max password days to 99999 |
|
129 |
- chroot $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME} /bin/bash -c "cat /etc/shadow | cut -d: -f1 | xargs -I {} chage -I -1 -m 0 -M 99999 -E -1 -W 7 {}" |
|
130 |
- sed -i 's/^PASS_MAX_DAYS.*/PASS_MAX_DAYS 99999/' $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME}/etc/login.defs |
|
131 |
- fi |
|
132 |
-fi |
|
133 |
-umount $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME}/sys |
|
134 |
-umount $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME}/dev/pts |
|
135 |
-umount $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME}/dev |
|
136 |
-umount $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME}/proc |
|
137 |
-umount $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME} |
|
138 |
-umount $ISO_MOUNT_FOLDER |
|
139 |
-rm -rf $ISO_MOUNT_FOLDER |
|
140 |
- |
|
141 |
-echo "Deleting device map partition" |
|
142 |
-kpartx -d $DISK_DEVICE |
|
143 |
- |
|
144 |
-rm -rf photon-${IMG_NAME} |
|
145 |
- |
|
146 |
-echo "Detaching loop device from raw disk" |
|
147 |
-losetup -d $DISK_DEVICE |
|
148 |
- |
|
149 |
- |
|
150 |
-cd $IMG_NAME |
|
151 |
-./mk-$IMG_NAME-image.sh $PHOTON_STAGE_PATH/$IMG_NAME $SRC_ROOT |
|
62 |
+./customize_cloud_image.py \ |
|
63 |
+ -r ${PHOTON_IMG_OUTPUT_PATH}/photon-${IMG_NAME}.raw \ |
|
64 |
+ -c $VMDK_CONFIG_FILE \ |
|
65 |
+ -w $WORKING_DIR \ |
|
66 |
+ -m $PHOTON_IMG_OUTPUT_PATH/photon-${IMG_NAME} \ |
|
67 |
+ -a $PHOTON_STAGE_PATH/RPMS/additional \ |
|
68 |
+ -i $IMG_NAME \ |
|
69 |
+ -t $SRC_ROOT/tools/bin/ \ |
|
70 |
+ -b $BUILD_SCRIPTS_PATH |
|
71 |
+ |
|
72 |
+rm -rf $WORKING_DIR/installer |
|
152 | 73 |
|
153 | 74 |
exit 0 |
154 | 75 |
new file mode 100755 |
... | ... |
@@ -0,0 +1,244 @@ |
0 |
+#!/usr/bin/python2 |
|
1 |
+ |
|
2 |
+import os |
|
3 |
+import re |
|
4 |
+import shutil |
|
5 |
+import tarfile |
|
6 |
+import fileinput |
|
7 |
+from optparse import OptionParser |
|
8 |
+from utils import Utils |
|
9 |
+ |
|
10 |
+def create_ova_image(raw_image_name, tools_path, build_scripts_path, config): |
|
11 |
+ output_path = os.path.dirname(os.path.realpath(raw_image_name)) |
|
12 |
+ utils = Utils() |
|
13 |
+ # Remove older artifacts |
|
14 |
+ files = os.listdir(output_path) |
|
15 |
+ for file in files: |
|
16 |
+ if file.endswith(".vmdk") or file.endswith(".ova"): |
|
17 |
+ os.remove(os.path.join(output_path, file)) |
|
18 |
+ |
|
19 |
+ vmx_path = output_path + '/photon-ova.vmx' |
|
20 |
+ utils.replaceandsaveasnewfile(build_scripts_path + '/vmx-template', vmx_path, 'VMDK_IMAGE', output_path + '/photon-ova.vmdk') |
|
21 |
+ vixdiskutil_path = tools_path + 'vixdiskutil' |
|
22 |
+ vmdk_path = output_path + '/photon-ova.vmdk' |
|
23 |
+ ovf_path = output_path + '/photon-ova.ovf' |
|
24 |
+ mf_path = output_path + '/photon-ova.mf' |
|
25 |
+ utils.runshellcommand("{} -convert {} -cap 16000 {}".format(vixdiskutil_path, raw_image_name, vmdk_path)) |
|
26 |
+ utils.runshellcommand("{} -wmeta toolsVersion 2147483647 {}".format(vixdiskutil_path, vmdk_path)) |
|
27 |
+ |
|
28 |
+ utils.runshellcommand("ovftool {} {}".format(vmx_path, ovf_path)) |
|
29 |
+ utils.replaceinfile(ovf_path, 'otherGuest', 'other3xLinux64Guest') |
|
30 |
+ |
|
31 |
+ #Add product info |
|
32 |
+ for line in fileinput.input(ovf_path, inplace=True): |
|
33 |
+ if line.strip() == '</VirtualSystem>': |
|
34 |
+ print ' \t<ProductSection> \n \t\t<Info>Information about the installed software</Info> \n \t\t<Product>Photon</Product> \n \t\t<Vendor>VMware Inc.</Vendor> \n \t\t<Version>1.0</Version> \n \t\t<FullVersion>1.0</FullVersion> \n \t</ProductSection> ' |
|
35 |
+ print line, |
|
36 |
+ |
|
37 |
+ if os.path.exists(mf_path): |
|
38 |
+ os.remove(mf_path) |
|
39 |
+ |
|
40 |
+ cwd = os.getcwd() |
|
41 |
+ os.chdir(output_path) |
|
42 |
+ out = utils.runshellcommand("openssl sha1 photon-ova-disk1.vmdk photon-ova.ovf") |
|
43 |
+ with open(mf_path, "w") as source: |
|
44 |
+ source.write(out) |
|
45 |
+ rawsplit = os.path.splitext(raw_image_name) |
|
46 |
+ ova_name = rawsplit[0] + '.ova' |
|
47 |
+ |
|
48 |
+ ovatar = tarfile.open(ova_name, "w:gz") |
|
49 |
+ for name in ["photon-ova.ovf", "photon-ova.mf", "photon-ova-disk1.vmdk"]: |
|
50 |
+ ovatar.add(name, arcname=os.path.basename(name)) |
|
51 |
+ ovatar.close() |
|
52 |
+ |
|
53 |
+ os.remove(vmx_path) |
|
54 |
+ os.remove(mf_path) |
|
55 |
+ |
|
56 |
+ if 'additionalhwversion' in config: |
|
57 |
+ for addlversion in config['additionalhwversion']: |
|
58 |
+ new_ovf_path = output_path + "photon-ova-hw{}.ovf".format(addlversion) |
|
59 |
+ mf_path = output_path + "photon-ova-hw{}.mf".format(addlversion) |
|
60 |
+ utils.replaceandsaveasnewfile(ovf_path, new_ovf_path, "vmx-.*<", "vmx-{}<".format(addlversion)) |
|
61 |
+ out = utils.runshellcommand("openssl sha1 photon-ova-disk1.vmdk {}".format(new_ovf_path)) |
|
62 |
+ with open(mf_path, "w") as source: |
|
63 |
+ source.write(out) |
|
64 |
+ temp_name_list = os.path.basename(ova_name).split('-') |
|
65 |
+ temp_name_list = temp_name_list[:2] + ["hw{}".format(addlversion)] + temp_name_list[2:] |
|
66 |
+ new_ova_name = '-'.join(temp_name_list) |
|
67 |
+ new_ova_path = output_path + new_ova_name |
|
68 |
+ ovatar = tarfile.open(new_ova_path, "w:gz") |
|
69 |
+ for name in [new_ovf_path, mf_path, "photon-ova-disk1.vmdk"]: |
|
70 |
+ ovatar.add(name, arcname=os.path.basename(name)) |
|
71 |
+ ovatar.close() |
|
72 |
+ |
|
73 |
+ os.remove(new_ovf_path) |
|
74 |
+ os.remove(mf_path) |
|
75 |
+ os.chdir(cwd) |
|
76 |
+ os.remove(ovf_path) |
|
77 |
+ os.remove(vmdk_path) |
|
78 |
+ |
|
79 |
+ |
|
80 |
+if __name__ == '__main__': |
|
81 |
+ usage = "Usage: %prog [options]" |
|
82 |
+ parser = OptionParser(usage) |
|
83 |
+ |
|
84 |
+ parser.add_option("-r", "--raw-image-path", dest="raw_image_path") |
|
85 |
+ parser.add_option("-c", "--vmdk-config-path", dest="vmdk_config_path") |
|
86 |
+ parser.add_option("-w", "--working-directory", dest="working_directory") |
|
87 |
+ parser.add_option("-m", "--mount-path", dest="mount_path") |
|
88 |
+ parser.add_option("-a", "--additional-rpms-path", dest="additional_rpms_path") |
|
89 |
+ parser.add_option("-i", "--image-name", dest="image_name") |
|
90 |
+ parser.add_option("-t", "--tools-bin-path", dest="tools_bin_path") |
|
91 |
+ parser.add_option("-b", "--build-scripts-path", dest="build_scripts_path") |
|
92 |
+ |
|
93 |
+ (options, args) = parser.parse_args() |
|
94 |
+ utils = Utils() |
|
95 |
+ config = utils.jsonread(options.vmdk_config_path) |
|
96 |
+ print options |
|
97 |
+ |
|
98 |
+ disk_device = (utils.runshellcommand("losetup --show -f {}".format(options.raw_image_path))).rstrip('\n') |
|
99 |
+ disk_partitions = utils.runshellcommand("kpartx -as {}".format(disk_device)) |
|
100 |
+ device_name = disk_device.split('/')[2] |
|
101 |
+ |
|
102 |
+ if not os.path.exists(options.mount_path): |
|
103 |
+ os.mkdir(options.mount_path) |
|
104 |
+ loop_device_path = "/dev/mapper/{}p2".format(device_name) |
|
105 |
+ |
|
106 |
+ try: |
|
107 |
+ print "Generating PARTUUID for the loop device ..." |
|
108 |
+ partuuidval = (utils.runshellcommand("blkid -s PARTUUID -o value {}".format(loop_device_path))).rstrip('\n') |
|
109 |
+ if (partuuidval == ''): |
|
110 |
+ sgdiskout = utils.runshellcommand("sgdisk -i 2 {} ".format(disk_device)) |
|
111 |
+ partuuidval = (re.findall(r'Partition unique GUID.*', sgdiskout))[0].split(':')[1].strip(' ') |
|
112 |
+ |
|
113 |
+ if (partuuidval == ''): |
|
114 |
+ raise RuntimeError("Cannot generate partuuid") |
|
115 |
+ |
|
116 |
+ # Mount the loop device |
|
117 |
+ print "Mounting the loop device for customization ..." |
|
118 |
+ utils.runshellcommand("mount -t ext4 {} {}".format(loop_device_path, options.mount_path)) |
|
119 |
+ shutil.rmtree(options.mount_path + "/installer", ignore_errors=True) |
|
120 |
+ shutil.rmtree(options.mount_path + "/LOGS", ignore_errors=True) |
|
121 |
+ # Clear the root password if not set explicitly from the config file |
|
122 |
+ if (config['password']['text'] != 'PASSWORD'): |
|
123 |
+ utils.replaceinfile(options.mount_path + "/etc/shadow",'root:.*?:','root:*:') |
|
124 |
+ # Clear machine-id so it gets regenerated on boot |
|
125 |
+ open(options.mount_path + "/etc/machine-id", "w").close() |
|
126 |
+ os.remove(options.mount_path + "/etc/fstab") |
|
127 |
+ |
|
128 |
+ f = open(options.mount_path + "/etc/fstab", "w") |
|
129 |
+ f.write("PARTUUID={} / ext4 defaults 1 1\n".format(partuuidval)) |
|
130 |
+ f.close() |
|
131 |
+ utils.replaceinfile(options.mount_path + "/boot/grub/grub.cfg", "rootpartition=PARTUUID=.*$", "rootpartition=PARTUUID={}".format(partuuidval)) |
|
132 |
+ |
|
133 |
+ if os.path.exists(options.additional_rpms_path): |
|
134 |
+ print "Installing additional rpms" |
|
135 |
+ os.mkdir(options.mount_path + "/additional_rpms") |
|
136 |
+ os.mkdir(options.mount_path + "/var/run") |
|
137 |
+ utils.copyallfiles(additional_rpms_path, options.mount_path + "/additional_rpms") |
|
138 |
+ utils.runshellcommand("chroot {} /bin/bash -c 'rpm -i /additional_rpms/*'".format(options.mount_path)) |
|
139 |
+ shutil.rmtree(options.mount_path + "/additional_rpms", ignore_errors=True) |
|
140 |
+ shutil.rmtree(additional_rpms_path, ignore_errors=True) |
|
141 |
+ |
|
142 |
+ utils.runshellcommand("mount -o bind /proc {}".format(options.mount_path + "/proc")) |
|
143 |
+ utils.runshellcommand("mount -o bind /dev {}".format(options.mount_path + "/dev")) |
|
144 |
+ utils.runshellcommand("mount -o bind /dev/pts {}".format(options.mount_path + "/dev/pts")) |
|
145 |
+ utils.runshellcommand("mount -o bind /sys {}".format(options.mount_path + "/sys")) |
|
146 |
+ |
|
147 |
+ if 'additionalfiles' in config: |
|
148 |
+ for filetuples in config['additionalfiles']: |
|
149 |
+ for src,dest in filetuples.iteritems(): |
|
150 |
+ shutil.copyfile(options.build_scripts_path + '/' + options.image_name + '/' + src, options.mount_path + '/' + dest) |
|
151 |
+ |
|
152 |
+ |
|
153 |
+ if 'postinstallscripts' in config: |
|
154 |
+ print "Running post install scripts ..." |
|
155 |
+ if not os.path.exists(options.mount_path + "/tempscripts"): |
|
156 |
+ os.mkdir(options.mount_path + "/tempscripts") |
|
157 |
+ for script in config['postinstallscripts']: |
|
158 |
+ shutil.copy(options.build_scripts_path + '/' + options.image_name + '/' + script, options.mount_path + "/tempscripts") |
|
159 |
+ for script in os.listdir(options.mount_path + "/tempscripts"): |
|
160 |
+ print " ...running script {}".format(script) |
|
161 |
+ utils.runshellcommand("chroot {} /bin/bash -c '/tempscripts/{}'".format(options.mount_path, script)) |
|
162 |
+ shutil.rmtree(options.mount_path + "/tempscripts", ignore_errors=True) |
|
163 |
+ |
|
164 |
+ utils.runshellcommand("umount -l {}".format(options.mount_path + "/sys")) |
|
165 |
+ utils.runshellcommand("umount -l {}".format(options.mount_path + "/dev/pts")) |
|
166 |
+ utils.runshellcommand("umount -l {}".format(options.mount_path + "/dev")) |
|
167 |
+ utils.runshellcommand("umount -l {}".format(options.mount_path + "/proc")) |
|
168 |
+ utils.runshellcommand("umount -l {}".format(options.mount_path)) |
|
169 |
+ |
|
170 |
+ finally: |
|
171 |
+ utils.runshellcommand("kpartx -d {}".format(disk_device)) |
|
172 |
+ utils.runshellcommand("losetup -d {}".format(disk_device)) |
|
173 |
+ |
|
174 |
+ shutil.rmtree(options.mount_path) |
|
175 |
+ |
|
176 |
+ photon_release_ver = os.environ['PHOTON_RELEASE_VER'] |
|
177 |
+ photon_build_num = os.environ['PHOTON_BUILD_NUM'] |
|
178 |
+ raw_image = options.raw_image_path |
|
179 |
+ new_name = "" |
|
180 |
+ img_path = os.path.dirname(os.path.realpath(raw_image)) |
|
181 |
+ # Rename gce image to disk.raw |
|
182 |
+ if options.image_name == "gce": |
|
183 |
+ print "Renaming the raw file to disk.raw ..." |
|
184 |
+ new_name = img_path + '/disk.raw' |
|
185 |
+ |
|
186 |
+ else: |
|
187 |
+ new_name = img_path + '/photon-' + options.image_name + '-' + photon_release_ver + '-' + photon_build_num + '.raw' |
|
188 |
+ |
|
189 |
+ shutil.move(raw_image, new_name) |
|
190 |
+ raw_image = new_name |
|
191 |
+ |
|
192 |
+ if config['artifacttype'] == 'tgz': |
|
193 |
+ print "Generating the tar.gz artifact ..." |
|
194 |
+ tarname = img_path + '/photon-' + options.image_name + '-' + photon_release_ver + '-' + photon_build_num + '.tar.gz' |
|
195 |
+ tgzout = tarfile.open(tarname, "w:gz") |
|
196 |
+ tgzout.add(raw_image, arcname=os.path.basename(raw_image)) |
|
197 |
+ tgzout.close() |
|
198 |
+ elif config['artifacttype'] == 'vhd': |
|
199 |
+ imgconverter = tools_bin_path + '/imgconverter' |
|
200 |
+ vhdname = img_path + '/photon-' + options.image_name + '-' + photon_release_ver + '-' + photon_build_num + '.vhd' |
|
201 |
+ utils.runshellcommand("{} -i {} -v vhd -o {}".format(imgconverter, raw_image, vhdname)) |
|
202 |
+ elif config['artifacttype'] == 'ova': |
|
203 |
+ create_ova_image(raw_image, options.tools_bin_path, options.build_scripts_path + '/' + options.image_name, config) |
|
204 |
+ if 'customartifacts' in config: |
|
205 |
+ if 'postinstallscripts' in config['customartifacts']: |
|
206 |
+ custom_path = img_path + '/photon-custom' |
|
207 |
+ if not os.path.exists(custom_path): |
|
208 |
+ os.mkdir(custom_path) |
|
209 |
+ index = 1 |
|
210 |
+ for script in config['customartifacts']['postinstallscripts']: |
|
211 |
+ print "Creating custom ova {}...".format(index) |
|
212 |
+ if index > 1: |
|
213 |
+ raw_image_custom = img_path + "/photon-custom-{}".format(index) + photon_release_ver + '-' + photon_build_num + '.raw' |
|
214 |
+ else: |
|
215 |
+ raw_image_custom = img_path + "/photon-custom-" + photon_release_ver + '-' + photon_build_num + '.raw' |
|
216 |
+ shutil.move(raw_image, raw_image_custom) |
|
217 |
+ disk_device = (utils.runshellcommand("losetup --show -f {}".format(raw_image_custom))).rstrip('\n') |
|
218 |
+ disk_partitions = utils.runshellcommand("kpartx -as {}".format(disk_device)) |
|
219 |
+ device_name = disk_device.split('/')[2] |
|
220 |
+ loop_device_path = "/dev/mapper/{}p2".format(device_name) |
|
221 |
+ |
|
222 |
+ print "Mounting the loop device for ova customization ..." |
|
223 |
+ utils.runshellcommand("mount -t ext4 {} {}".format(loop_device_path, custom_path)) |
|
224 |
+ if not os.path.exists(custom_path + "/tempscripts"): |
|
225 |
+ os.mkdir(custom_path + "/tempscripts") |
|
226 |
+ shutil.copy(options.build_scripts_path + '/' + options.image_name + '/' + script, custom_path + "/tempscripts") |
|
227 |
+ print "Running custom ova script {}".format(script) |
|
228 |
+ utils.runshellcommand("chroot {} /bin/bash -c '/tempscripts/{}'".format(custom_path, script)) |
|
229 |
+ shutil.rmtree(custom_path + "/tempscripts", ignore_errors=True) |
|
230 |
+ utils.runshellcommand("umount -l {}".format(custom_path)) |
|
231 |
+ utils.runshellcommand("kpartx -d {}".format(disk_device)) |
|
232 |
+ utils.runshellcommand("losetup -d {}".format(disk_device)) |
|
233 |
+ create_ova_image(raw_image_custom, options.tools_bin_path, options.build_scripts_path + '/' + options.image_name, config) |
|
234 |
+ raw_image = raw_image_custom |
|
235 |
+ index = index + 1 |
|
236 |
+ |
|
237 |
+ shutil.rmtree(custom_path) |
|
238 |
+ |
|
239 |
+ else: |
|
240 |
+ raise ValueError("Unknown output format") |
|
241 |
+ |
|
242 |
+ if config['keeprawdisk'] == 'false': |
|
243 |
+ os.remove(raw_image) |
|
0 | 244 |
\ No newline at end of file |
1 | 245 |
deleted file mode 100644 |
... | ... |
@@ -1,11 +0,0 @@ |
1 |
-[Unit] |
|
2 |
-Description=Network interface initialization |
|
3 |
-After=local-fs.target network-online.target network.target |
|
4 |
-Wants=local-fs.target network-online.target network.target |
|
5 |
- |
|
6 |
-[Service] |
|
7 |
-ExecStart=/usr/sbin/ifconfig eth0 mtu 1460 up |
|
8 |
-Type=oneshot |
|
9 |
- |
|
10 |
-[Install] |
|
11 |
-WantedBy=multi-user.target |
12 | 1 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,11 @@ |
0 |
+[Unit] |
|
1 |
+Description=Network interface initialization |
|
2 |
+After=local-fs.target network-online.target network.target |
|
3 |
+Wants=local-fs.target network-online.target network.target |
|
4 |
+ |
|
5 |
+[Service] |
|
6 |
+ExecStart=/usr/sbin/ifconfig eth0 mtu 1460 up |
|
7 |
+Type=oneshot |
|
8 |
+ |
|
9 |
+[Install] |
|
10 |
+WantedBy=multi-user.target |
... | ... |
@@ -115,6 +115,7 @@ else |
115 | 115 |
fi |
116 | 116 |
|
117 | 117 |
export menuentry_id_option |
118 |
+load_env -f "$BOOT_DIRECTORY"photon.cfg |
|
118 | 119 |
|
119 | 120 |
if [ "${prev_saved_entry}" ]; then |
120 | 121 |
set saved_entry="${prev_saved_entry}" |
... | ... |
@@ -164,11 +165,11 @@ menuentry 'GNU/Linux' --class gnu-linux --class gnu --class os $menuentry_id_opt |
164 | 164 |
else |
165 | 165 |
search --no-floppy --fs-uuid --set=root UUID_PLACEHOLDER |
166 | 166 |
fi |
167 |
- echo 'Loading Linux 4.4.8 ...' |
|
168 |
- linux /boot/vmlinuz-4.4.8 root=/dev/sda2 ro console=ttyS0,38400n8 |
|
167 |
+ echo 'Loading Linux $photon_linux ...' |
|
168 |
+ linux "$BOOT_DIRECTORY"\$photon_linux root=UUID_PLACEHOLDER ro console=ttyS0,38400n8 |
|
169 | 169 |
} |
170 | 170 |
submenu 'Advanced options for GNU/Linux' $menuentry_id_option 'gnulinux-advanced-UUID_PLACEHOLDER' { |
171 |
- menuentry 'GNU/Linux, with Linux 4.4.8' --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-4.4.8-advanced-UUID_PLACEHOLDER' { |
|
171 |
+ menuentry 'GNU/Linux, with Linux $photon_linux' --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-$photon_linux-advanced-UUID_PLACEHOLDER' { |
|
172 | 172 |
load_video |
173 | 173 |
set gfxpayload=keep |
174 | 174 |
insmod gzio |
... | ... |
@@ -180,10 +181,10 @@ submenu 'Advanced options for GNU/Linux' $menuentry_id_option 'gnulinux-advanced |
180 | 180 |
else |
181 | 181 |
search --no-floppy --fs-uuid --set=root UUID_PLACEHOLDER |
182 | 182 |
fi |
183 |
- echo 'Loading Linux 4.4.8 ...' |
|
184 |
- linux /boot/vmlinuz-4.4.8 root=/dev/sda2 ro console=ttyS0,38400n8 |
|
183 |
+ echo 'Loading Linux $photon_linux ...' |
|
184 |
+ linux "$BOOT_DIRECTORY"\$photon_linux root=UUID_PLACEHOLDER ro console=ttyS0,38400n8 |
|
185 | 185 |
} |
186 |
- menuentry 'GNU/Linux, with Linux 4.4.8 (recovery mode)' --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-4.4.8-recovery-UUID_PLACEHOLDER' { |
|
186 |
+ menuentry 'GNU/Linux, with Linux $photon_linux (recovery mode)' --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-$photon_linux-recovery-UUID_PLACEHOLDER' { |
|
187 | 187 |
load_video |
188 | 188 |
set gfxpayload=keep |
189 | 189 |
insmod gzio |
... | ... |
@@ -195,8 +196,8 @@ submenu 'Advanced options for GNU/Linux' $menuentry_id_option 'gnulinux-advanced |
195 | 195 |
else |
196 | 196 |
search --no-floppy --fs-uuid --set=root UUID_PLACEHOLDER |
197 | 197 |
fi |
198 |
- echo 'Loading Linux 4.4.8 ...' |
|
199 |
- linux /boot/vmlinuz-4.4.8 root=/dev/sda2 ro single console=ttyS0,38400n8 |
|
198 |
+ echo 'Loading Linux $photon_linux ...' |
|
199 |
+ linux "$BOOT_DIRECTORY"\$photon_linux root=/UUID_PLACEHOLDER ro single console=ttyS0,38400n8 |
|
200 | 200 |
} |
201 | 201 |
} |
202 | 202 |
|
203 | 203 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,12 @@ |
0 |
+[Unit] |
|
1 |
+Description=Network Time Service |
|
2 |
+After=network.target nss-lookup.target |
|
3 |
+ |
|
4 |
+[Service] |
|
5 |
+Type=forking |
|
6 |
+PrivateTmp=true |
|
7 |
+ExecStart=/usr/bin/ntpd -g -u ntp:ntp |
|
8 |
+Restart=always |
|
9 |
+ |
|
10 |
+[Install] |
|
11 |
+WantedBy=multi-user.target |
... | ... |
@@ -1,12 +1,20 @@ |
1 | 1 |
{ |
2 |
- "hostname": "photon-machine", |
|
3 |
- "password": |
|
4 |
- { |
|
5 |
- "crypted": false, |
|
6 |
- "text": "PASSWORD" |
|
7 |
- }, |
|
8 |
- "type": "gce", |
|
9 |
- "size": {"root": "8", "swap": "0"}, |
|
10 |
- "public_key":"<ssh-key-here>" |
|
2 |
+ "hostname": "photon-machine", |
|
3 |
+ "password": |
|
4 |
+ { |
|
5 |
+ "crypted": false, |
|
6 |
+ "text": "PASSWORD" |
|
7 |
+ }, |
|
8 |
+ "type": "gce", |
|
9 |
+ "size": {"root": "16", "swap": "0"}, |
|
10 |
+ "public_key":"<ssh-key-here>", |
|
11 |
+ "postinstallscripts": [ "gce-patch.sh", "../password-expiry.sh" ], |
|
12 |
+ "additionalfiles": [ |
|
13 |
+ {"cloud-photon.cfg": "/etc/cloud/cloud.cfg"}, |
|
14 |
+ {"ntpd.service": "/usr/lib/systemd/system/ntpd.service"}, |
|
15 |
+ {"eth0.service": "/usr/lib/systemd/system/eth0.service"} |
|
16 |
+ ], |
|
17 |
+ "artifacttype": "tgz", |
|
18 |
+ "keeprawdisk": "false" |
|
11 | 19 |
} |
12 | 20 |
|
... | ... |
@@ -96,6 +96,7 @@ set default=0 |
96 | 96 |
set timeout=5 |
97 | 97 |
set root=(hd0,2) |
98 | 98 |
loadfont /boot/grub2/unifont.pf2 |
99 |
+load_env -f "$BOOT_DIRECTORY"$photon.cfg |
|
99 | 100 |
|
100 | 101 |
insmod gfxterm |
101 | 102 |
insmod vbe |
... | ... |
@@ -112,7 +113,7 @@ set theme=/boot/grub2/themes/photon/theme.txt |
112 | 112 |
menuentry "Photon" { |
113 | 113 |
insmod ext2 |
114 | 114 |
insmod part_gpt |
115 |
- linux /boot/vmlinuz-4.4.8 init=/lib/systemd/systemd root=PARTUUID=UUID_PLACEHOLDER loglevel=3 ro |
|
115 |
+ linux "$BOOT_DIRECTORY"\$photon_linux init=/lib/systemd/systemd root=PARTUUID=UUID_PLACEHOLDER loglevel=3 ro |
|
116 | 116 |
initrd /boot/initrd.img-no-kmods |
117 | 117 |
} |
118 | 118 |
# End /boot/grub2/grub.cfg |
96 | 96 |
deleted file mode 100644 |
... | ... |
@@ -1,12 +0,0 @@ |
1 |
-[Unit] |
|
2 |
-Description=Network Time Service |
|
3 |
-After=network.target nss-lookup.target |
|
4 |
- |
|
5 |
-[Service] |
|
6 |
-Type=forking |
|
7 |
-PrivateTmp=true |
|
8 |
-ExecStart=/usr/bin/ntpd -g -u ntp:ntp |
|
9 |
-Restart=always |
|
10 |
- |
|
11 |
-[Install] |
|
12 |
-WantedBy=multi-user.target |
... | ... |
@@ -1,12 +1,16 @@ |
1 | 1 |
{ |
2 |
- "hostname": "photon-machine", |
|
3 |
- "password": |
|
4 |
- { |
|
5 |
- "crypted": false, |
|
6 |
- "text": "PASSWORD" |
|
7 |
- }, |
|
8 |
- "type": "minimal", |
|
9 |
- "size": {"root": "8", "swap": "0"}, |
|
10 |
- "public_key":"<ssh-key-here>" |
|
2 |
+ "hostname": "photon-machine", |
|
3 |
+ "password": |
|
4 |
+ { |
|
5 |
+ "crypted": false, |
|
6 |
+ "text": "PASSWORD" |
|
7 |
+ }, |
|
8 |
+ "type": "minimal", |
|
9 |
+ "size": { "root": "16", "swap": "0" }, |
|
10 |
+ "public_key":"<ssh-key-here>", |
|
11 |
+ "customartifacts": { "postinstallscripts": ["ova-custom-patch.sh"] }, |
|
12 |
+ "additionalhwversion": [ "10" ], |
|
13 |
+ "artifacttype": "ova", |
|
14 |
+ "keeprawdisk": "false" |
|
11 | 15 |
} |
12 | 16 |
|
... | ... |
@@ -6,7 +6,10 @@ |
6 | 6 |
"text": "PASSWORD" |
7 | 7 |
}, |
8 | 8 |
"type": "minimal", |
9 |
- "size": {"root": "8", "swap": "0"}, |
|
10 |
- "public_key":"<ssh-key-here>" |
|
9 |
+ "size": {"root": "16", "swap": "0"}, |
|
10 |
+ "public_key":"<ssh-key-here>", |
|
11 |
+ "customartifacts": { "postinstallscripts": ["ova_generic-custom-patch.sh"] }, |
|
12 |
+ "artifacttype": "ova", |
|
13 |
+ "keeprawdisk": "false" |
|
11 | 14 |
} |
12 | 15 |
|
... | ... |
@@ -6,8 +6,10 @@ |
6 | 6 |
"text": "PASSWORD" |
7 | 7 |
}, |
8 | 8 |
"type": "uefi", |
9 |
- "size": {"root": "8", "swap": "0"}, |
|
9 |
+ "size": {"root": "16", "swap": "0"}, |
|
10 | 10 |
"boot":"efi", |
11 |
- "public_key":"<ssh-key-here>" |
|
11 |
+ "public_key":"<ssh-key-here>", |
|
12 |
+ "artifacttype": "ova", |
|
13 |
+ "keeprawdisk": "false" |
|
12 | 14 |
} |
13 | 15 |
|
0 | 4 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,76 @@ |
0 |
+#!/usr/bin/python2 |
|
1 |
+ |
|
2 |
+import os |
|
3 |
+import ctypes |
|
4 |
+import ctypes.util |
|
5 |
+import json |
|
6 |
+import collections |
|
7 |
+import subprocess |
|
8 |
+import fileinput |
|
9 |
+import re |
|
10 |
+ |
|
11 |
+class Utils(object): |
|
12 |
+ def __init__(self): |
|
13 |
+ self.filesystems = [] |
|
14 |
+ with open('/proc/filesystems') as fs: |
|
15 |
+ for line in fs: |
|
16 |
+ self.filesystems.append(line.rstrip('\n').split('\t')[1]) |
|
17 |
+ |
|
18 |
+ self.libcloader = ctypes.CDLL(ctypes.util.find_library('c'), use_errno=True) |
|
19 |
+ |
|
20 |
+ def mount(self, source, destination, filesystem, flags): |
|
21 |
+ if not os.access(source, os.R_OK): |
|
22 |
+ raise Exception("Could not find path " + source) |
|
23 |
+ if not os.access(destination, os.F_OK): |
|
24 |
+ os.mkdir(destination) |
|
25 |
+ if not os.access(destination, os.W_OK): |
|
26 |
+ raise Exception("Could not write to path " + destination) |
|
27 |
+ if filesystem not in self.filesystems: |
|
28 |
+ raise ValueError("Filesystem unknown") |
|
29 |
+ ret = self.libcloader.mount(ctypes.c_char_p(source), |
|
30 |
+ ctypes.c_char_p(destination), |
|
31 |
+ ctypes.c_char_p(filesystem), |
|
32 |
+ ctypes.c_char_p(flags), |
|
33 |
+ 0) |
|
34 |
+ if ret != 0: |
|
35 |
+ raise RuntimeError("Cannot mount {} : {}".format(source, os.strerror(ctypes.get_errno()))) |
|
36 |
+ |
|
37 |
+ def umount(self, destination): |
|
38 |
+ ret = self.libcloader.umount(ctypes.c_char_p(destination)) |
|
39 |
+ if ret != 0: |
|
40 |
+ raise RuntimeError("Cannot umount {} : {}".format(destination, os.strerror(ctypes.get_errno()))) |
|
41 |
+ |
|
42 |
+ def jsonread(self, filename): |
|
43 |
+ json_data = open(filename) |
|
44 |
+ data = json.load(json_data, object_pairs_hook=collections.OrderedDict) |
|
45 |
+ json_data.close() |
|
46 |
+ return data |
|
47 |
+ |
|
48 |
+ def runshellcommand(self, cmd, ignore_errors=False): |
|
49 |
+ command=cmd.split() |
|
50 |
+ p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
|
51 |
+ output, err = p.communicate() |
|
52 |
+ rc = p.returncode |
|
53 |
+ if not ignore_errors: |
|
54 |
+ if rc != 0: |
|
55 |
+ print err |
|
56 |
+ raise RuntimeError("Cannot run command {}".format(cmd)) |
|
57 |
+ return output |
|
58 |
+ |
|
59 |
+ def replaceinfile(self, filename, pattern, sub): |
|
60 |
+ for line in fileinput.input(filename, inplace=True): |
|
61 |
+ line = re.sub(pattern, sub, line) |
|
62 |
+ print line, |
|
63 |
+ |
|
64 |
+ def replaceandsaveasnewfile(self, old_file, new_file, pattern, sub): |
|
65 |
+ with open(old_file, "r") as old, open(new_file, "w") as new: |
|
66 |
+ for line in old: |
|
67 |
+ line = re.sub(pattern, sub, line) |
|
68 |
+ new.write(line) |
|
69 |
+ |
|
70 |
+ def copyallfiles(self, src, target): |
|
71 |
+ files = os.listdir(src) |
|
72 |
+ for file in files: |
|
73 |
+ filename = os.path.join(src, file) |
|
74 |
+ if (os.path.isfile(filename)): |
|
75 |
+ shutil.copy(filename, target) |