Browse code

Use tdnf in iso installer.

Change-Id: Ie5a60155202fcab753c2559caa3d7ce7393a602c
Reviewed-on: http://photon-jenkins.eng.vmware.com/93
Tested-by: jenkins-photon <wangnan2015@hotmail.com>
Reviewed-by: Mahmoud Bassiouny <mbassiouny@vmware.com>

xiaolin-vmware authored on 2015/11/06 06:41:02
Showing 7 changed files
... ...
@@ -65,6 +65,7 @@ micro-iso: check $(PHOTON_STAGE) $(PHOTON_PACKAGES_MICRO)
65 65
                 -r $(PHOTON_STAGE)/RPMS \
66 66
                 -p $(PHOTON_GENERATED_DATA_DIR)/$(MICRO_PACKAGE_LIST_FILE) \
67 67
                 -o $(PHOTON_STAGE)/common/data \
68
+                -s $(PHOTON_DATA_DIR) \
68 69
                 -f > \
69 70
                 $(PHOTON_LOGS_DIR)/installer.log 2>&1
70 71
 
... ...
@@ -98,6 +99,7 @@ minimal-iso: check $(PHOTON_STAGE) $(PHOTON_PACKAGES_MINIMAL)
98 98
                 -r $(PHOTON_STAGE)/RPMS \
99 99
                 -p $(PHOTON_GENERATED_DATA_DIR)/$(MINIMAL_PACKAGE_LIST_FILE) \
100 100
                 -o $(PHOTON_STAGE)/common/data \
101
+                -s $(PHOTON_DATA_DIR) \
101 102
                 -f > \
102 103
                 $(PHOTON_LOGS_DIR)/installer.log 2>&1
103 104
 
... ...
@@ -111,6 +113,7 @@ ostree-host-iso: check $(PHOTON_STAGE) ostree-repo
111 111
                 -r $(PHOTON_STAGE)/RPMS \
112 112
                 -p $(PHOTON_GENERATED_DATA_DIR)/build_install_options_ostreehost.json \
113 113
                 -o $(PHOTON_STAGE)/common/data \
114
+		-s $(PHOTON_DATA_DIR) \
114 115
                 -f > \
115 116
                 $(PHOTON_LOGS_DIR)/installer.log 2>&1
116 117
 
... ...
@@ -124,6 +127,7 @@ live-iso: check $(PHOTON_STAGE) $(PHOTON_PACKAGES_MINIMAL) minimal-iso
124 124
                 -r $(PHOTON_STAGE)/RPMS \
125 125
                 -p $(PHOTON_GENERATED_DATA_DIR)/build_install_options_livecd.json \
126 126
                 -o $(PHOTON_STAGE)/common/data \
127
+                -s $(PHOTON_DATA_DIR) \
127 128
                 -f > \
128 129
                 $(PHOTON_LOGS_DIR)/installer.log 2>&1
129 130
 
... ...
@@ -154,6 +158,7 @@ iso: check $(PHOTON_STAGE) $(PHOTON_PACKAGES) ostree-repo
154 154
                 -r $(PHOTON_STAGE)/RPMS \
155 155
                 -p $(PHOTON_GENERATED_DATA_DIR)/$(FULL_PACKAGE_LIST_FILE) \
156 156
                 -o $(PHOTON_STAGE)/common/data \
157
+                -s $(PHOTON_DATA_DIR) \
157 158
                 -f > \
158 159
                 $(PHOTON_LOGS_DIR)/installer.log 2>&1
159 160
 
... ...
@@ -3,7 +3,7 @@
3 3
 #
4 4
 Summary:	dnf/yum equivalent using C libs
5 5
 Name:		tdnf
6
-Version:	1.0.4
6
+Version:	1.0.5
7 7
 Release:	1%{?dist}
8 8
 Vendor:		VMware, Inc.
9 9
 Distribution:	Photon
... ...
@@ -19,7 +19,7 @@ BuildRequires:	openssl-devel
19 19
 
20 20
 BuildRequires:	librepo-devel
21 21
 Source0:	%{name}-%{version}.tar.gz
22
-%define sha1 tdnf=e14364001db7102f541e230f3bb8934cfd9c1b9c
22
+%define sha1 tdnf=6337f9b4045b6a561d58db602a9f6fb127b0cd84
23 23
 
24 24
 %description
25 25
 tdnf is a yum/dnf equivalent
... ...
@@ -13,5 +13,6 @@
13 13
             "libtasn1-devel", "libarchive-devel", "cracklib-dicts", "findutils", "efivar", "grub2",
14 14
             "cpio", "shadow", "dbus", "python-requests", "pkg-config", "dosfstools", "sed", "json-glib",
15 15
             "python-hawkey", "libhif-devel", "grub2-efi", "linux", "cracklib-python", "gpgme-devel",
16
-            "grep", "ostree", "tar", "efibootmgr", "pciutils", "gnutls-devel", "e2fsprogs", "gzip", "gptfdisk"]
16
+            "grep", "ostree", "tar", "efibootmgr", "pciutils", "gnutls-devel", "e2fsprogs", "gzip", 
17
+            "gptfdisk", "tdnf"]
17 18
 }
... ...
@@ -16,7 +16,6 @@ import fnmatch
16 16
 import signal
17 17
 import sys
18 18
 import glob
19
-import urllib
20 19
 import modules.commons
21 20
 import xml.etree.ElementTree as ET
22 21
 from jsonwrapper import JsonWrapper
... ...
@@ -96,23 +95,40 @@ class Installer(object):
96 96
             self.window.show_window()
97 97
             self.progress_bar.initialize('Initializing installation...')
98 98
             self.progress_bar.show()
99
-
99
+            #self.rpm_path = "https://dl.bintray.com/vmware/photon_release_1.0_TP2_x86_64"
100
+            if self.rpm_path.startswith("https://") or self.rpm_path.startswith("http://"):
101
+                cmdoption = 's/baseurl.*/baseurl={}/g'.format(self.rpm_path.replace('/','\/'))
102
+                process = subprocess.Popen(['sed', '-i', cmdoption,'/etc/yum.repos.d/photon-iso.repo']) 
103
+                retval = process.wait()
104
+                if retval != 0:
105
+                    modules.commons.log(modules.commons.LOG_INFO, "Failed to reset repo")
106
+                    self.exit_gracefully(None, None)
100 107
         self.execute_modules(modules.commons.PRE_INSTALL)
101 108
 
102 109
         self.initialize_system()
103 110
 
111
+        if self.iso_installer:
112
+            self.get_size_of_packages()
113
+            selected_packages = self.install_config['packages']
114
+            for package in selected_packages:
115
+                self.progress_bar.update_message('Installing {0}...'.format(package))
116
+                process = subprocess.Popen(['tdnf', 'install', package, '--installroot', self.photon_root, '--nogpgcheck', '--assumeyes'], stdout=self.output, stderr=subprocess.STDOUT)
117
+                retval = process.wait()
118
+                # 0 : succeed; 137 : package already installed; 65 : package not found in repo.
119
+                if retval != 0 and retval != 137:
120
+                    modules.commons.log(modules.commons.LOG_ERROR, "Failed install: {} with error code {}".format(package, retval))
121
+                    self.exit_gracefully(None, None)
122
+                self.progress_bar.increment(self.size_of_packages[package])
123
+        else:
104 124
         #install packages
105
-        for rpm in self.rpms_tobeinstalled:
106
-            # We already installed the filesystem in the preparation
107
-            if rpm['package'] == 'filesystem':
108
-                continue
109
-            if self.iso_installer:
110
-                self.progress_bar.update_message('Installing {0}...'.format(rpm['package']))
111
-            return_value = self.install_package(rpm['filename'])
112
-            if return_value != 0:
113
-                self.exit_gracefully(None, None)
114
-            if self.iso_installer:
115
-                self.progress_bar.increment(rpm['size'] * self.install_factor)
125
+            for rpm in self.rpms_tobeinstalled:
126
+                # We already installed the filesystem in the preparation
127
+                if rpm['package'] == 'filesystem':
128
+                    continue
129
+                return_value = self.install_package(rpm['filename'])
130
+                if return_value != 0:
131
+                    self.exit_gracefully(None, None)
132
+
116 133
 
117 134
         if self.iso_installer:
118 135
             self.progress_bar.show_loading('Finalizing installation')
... ...
@@ -150,75 +166,9 @@ class Installer(object):
150 150
                 self.window.content_window().getch()
151 151
 
152 152
         return ActionResult(True, None)
153
-
154
-    def download_file(self, url, directory):
155
-        # TODO: Add errors handling
156
-        urlopener = urllib.URLopener()
157
-        urlopener.retrieve(url, os.path.join(directory, os.path.basename(url)))
158
-
159
-    def download_rpms(self):
160
-        repodata_dir = os.path.join(self.photon_root, 'RPMS/repodata')
161
-        process = subprocess.Popen(['mkdir', '-p', repodata_dir], stdout=self.output)
162
-        retval = process.wait()
163
-
164
-        import hawkey
165
-        self.install_factor = 1
166
-        # Load the repo data
167
-        sack = hawkey.Sack()
168
-        
169
-        repomd_filename = "repomd.xml"
170
-        repomd_url = os.path.join(self.rpm_path, "repodata/repomd.xml")
171
-
172
-        self.download_file(repomd_url, repodata_dir)
173
-
174
-        # parse to the xml to get the primary and files list
175
-        tree = ET.parse(os.path.join(repodata_dir, repomd_filename))
176
-        # TODO: Get the namespace dynamically from the xml file
177
-        ns = {'ns': 'http://linux.duke.edu/metadata/repo'}
178
-
179
-        primary_location = tree.find("./ns:data[@type='primary']/ns:location", ns).get("href");
180
-        filelists_location = tree.find("./ns:data[@type='filelists']/ns:location", ns).get("href");
181
-        primary_filename = os.path.basename(primary_location);
182
-        filelists_filename = os.path.basename(filelists_location);
183
-
184
-        self.download_file(os.path.join(self.rpm_path, primary_location), repodata_dir)
185
-        self.download_file(os.path.join(self.rpm_path, filelists_location), repodata_dir)
186
-        
187
-        repo = hawkey.Repo("installrepo")
188
-        repo.repomd_fn = os.path.join(repodata_dir, repomd_filename)
189
-        repo.primary_fn = os.path.join(repodata_dir, primary_filename)
190
-        repo.filelists_fn = os.path.join(repodata_dir, filelists_filename)
191
-        
192
-        sack.load_yum_repo(repo, load_filelists=True)
193
-
194
-        progressbar_num_items = 0
195
-        self.rpms_tobeinstalled = []
196
-        selected_packages = self.install_config['packages']
197
-        for package in selected_packages:
198
-            # Locate the package
199
-            q = hawkey.Query(sack).filter(name=package)
200
-            if (len(q) > 0):
201
-                progressbar_num_items +=  q[0].size + q[0].size * self.install_factor
202
-                self.rpms_tobeinstalled.append({'package': package, 'size': q[0].size, 'location': q[0].location, 'filename': os.path.basename(q[0].location)})
203
-            else:
204
-                modules.commons.log(modules.commons.LOG_WARNING, "Package {} not found in the repo".format(package))
205
-                #self.exit_gracefully(None, None)
206
-
207
-        self.progress_bar.update_num_items(progressbar_num_items)
208
-
209
-        # Download the rpms
210
-        for rpm in self.rpms_tobeinstalled:
211
-            message = 'Downloading {0}...'.format(rpm['filename'])
212
-            self.progress_bar.update_message(message)
213
-            self.download_file(os.path.join(self.rpm_path, rpm['location']), os.path.join(self.photon_root, "RPMS"))
214
-            self.progress_bar.increment(rpm['size'])
215 153
         
216
-        # update the rpms path
217
-        self.rpm_path = os.path.join(self.photon_root, "RPMS")
218
-
219 154
     def copy_rpms(self):
220 155
         # prepare the RPMs list
221
-        self.install_factor = 3
222 156
         rpms = []
223 157
         for root, dirs, files in os.walk(self.rpm_path):
224 158
             for name in files:
... ...
@@ -226,7 +176,6 @@ class Installer(object):
226 226
                 size = os.path.getsize(file)
227 227
                 rpms.append({'filename': name, 'path': file, 'size': size})
228 228
 
229
-        progressbar_num_items = 0
230 229
         self.rpms_tobeinstalled = []
231 230
         selected_packages = self.install_config['packages']
232 231
         for package in selected_packages:
... ...
@@ -236,20 +185,10 @@ class Installer(object):
236 236
                 if fnmatch.fnmatch(rpm['filename'], pattern) or fnmatch.fnmatch(rpm['filename'], pattern2):
237 237
                     rpm['package'] = package
238 238
                     self.rpms_tobeinstalled.append(rpm)
239
-                    progressbar_num_items += rpm['size'] + rpm['size'] * self.install_factor
240 239
                     break
241
-
242
-        if self.iso_installer:
243
-            self.progress_bar.update_num_items(progressbar_num_items)
244
-
245 240
         # Copy the rpms
246 241
         for rpm in self.rpms_tobeinstalled:
247
-            if self.iso_installer:
248
-                message = 'Copying {0}...'.format(rpm['filename'])
249
-                self.progress_bar.update_message(message)
250 242
             shutil.copy(rpm['path'], self.photon_root + '/RPMS/')
251
-            if self.iso_installer:
252
-                self.progress_bar.increment(rpm['size'])
253 243
 
254 244
     def copy_files(self):
255 245
         # Make the photon_root directory if not exits
... ...
@@ -263,11 +202,17 @@ class Installer(object):
263 263
         # Create the rpms directory
264 264
         process = subprocess.Popen(['mkdir', '-p', self.photon_root + '/RPMS'], stdout=self.output)
265 265
         retval = process.wait()
266
+        self.copy_rpms()
266 267
 
267
-        if self.rpm_path.startswith("http://"):
268
-            self.download_rpms()
269
-        else:
270
-            self.copy_rpms()
268
+    def bind_installer(self):
269
+        # Make the photon_root/installer directory if not exits
270
+        process = subprocess.Popen(['mkdir', '-p', os.path.join(self.photon_root, "installer")], stdout=self.output)
271
+        retval = process.wait()
272
+        # The function finalize_system will access the file /installer/mk-finalize-system.sh after chroot to photon_root. 
273
+        # Bind the /installer folder to self.photon_root/installer, so that after chroot to photon_root,
274
+        # the file can still be accessed as /installer/mk-finalize-system.sh.
275
+        process = subprocess.Popen(['mount', '--bind', '/installer', os.path.join(self.photon_root, "installer")], stdout=self.output)
276
+        retval = process.wait()
271 277
 
272 278
     def update_fstab(self):
273 279
         fstab_file = open(os.path.join(self.photon_root, "etc/fstab"), "w")
... ...
@@ -321,12 +266,16 @@ class Installer(object):
321 321
             process = subprocess.Popen(command, stdout=self.output)
322 322
             retval = process.wait()
323 323
         
324
-        self.copy_files()
325
-        
326
-        #Setup the filesystem basics
327
-        process = subprocess.Popen([self.prepare_command, '-w', self.photon_root], stdout=self.output)
328
-        retval = process.wait()
329
-
324
+        if self.iso_installer:
325
+            self.bind_installer()
326
+            process = subprocess.Popen([self.prepare_command, '-w', self.photon_root, 'install'], stdout=self.output)
327
+            retval = process.wait()
328
+        else:
329
+            self.copy_files()
330
+            #Setup the filesystem basics
331
+            process = subprocess.Popen([self.prepare_command, '-w', self.photon_root], stdout=self.output)
332
+            retval = process.wait()
333
+    
330 334
     def finalize_system(self):
331 335
         #Setup the disk
332 336
         process = subprocess.Popen([self.chroot_command, '-w', self.photon_root, self.finalize_command, '-w', self.photon_root], stdout=self.output)
... ...
@@ -336,6 +285,9 @@ class Installer(object):
336 336
         if self.iso_installer:
337 337
             # just copy the initramfs /boot -> /photon_mnt/boot
338 338
             shutil.copy(os.path.join(initrd_dir, initrd_file_name), self.photon_root + '/boot/')
339
+            # unmount the installer directory
340
+            process = subprocess.Popen(['umount', os.path.join(self.photon_root, "installer")], stdout=self.output)
341
+            retval = process.wait()
339 342
             # remove the installer directory
340 343
             process = subprocess.Popen(['rm', '-rf', os.path.join(self.photon_root, "installer")], stdout=self.output)
341 344
             retval = process.wait()
... ...
@@ -416,6 +368,32 @@ class Installer(object):
416 416
                 continue
417 417
             mod.execute(module, self.ks_config, self.install_config, self.photon_root)
418 418
 
419
+    def get_install_size_of_a_package(self, name_size_pairs, package):
420
+        modules.commons.log(modules.commons.LOG_INFO, "Find the install size of: {} ".format(package))
421
+        for index, name in enumerate(name_size_pairs, start=0):
422
+            if name[name.find(":") + 1:].strip() == package.strip():  
423
+                item = name_size_pairs[index + 1] 
424
+                size = item[item.find("(") + 1:item.find(")")]
425
+                return int(size)
426
+
427
+    def get_size_of_packages(self):
428
+        #call tdnf info to get the install size of all the packages.
429
+        process = subprocess.Popen(['tdnf', 'info', '--installroot', self.photon_root], stdout=subprocess.PIPE)
430
+        out,err = process.communicate()
431
+        if err != None and err != 0:
432
+            modules.commons.log(modules.commons.LOG_ERROR, "Failed to get infomation from : {} with error code {}".format(package, err))
433
+
434
+        name_size_pairs = re.findall("(?:^Name.*$)|(?:^.*Install Size.*$)", out, re.M)
435
+        selected_packages = self.install_config['packages']
436
+        self.size_of_packages = {}
437
+        progressbar_num_items = 0
438
+        for package in selected_packages:
439
+            size = self.get_install_size_of_a_package(name_size_pairs, package)
440
+            progressbar_num_items += size;
441
+            self.size_of_packages[package] = size;
442
+        self.progress_bar.update_num_items(progressbar_num_items)    
443
+
444
+
419 445
     def run(self, command, comment = None):
420 446
         if comment != None:
421 447
             modules.commons.log(modules.commons.LOG_INFO, "Installer: {} ".format(comment))
... ...
@@ -71,6 +71,17 @@ mkdir -p ${BUILDROOT}/etc/systemd/scripts
71 71
 
72 72
 cp BUILD_DVD/fstab ${BUILDROOT}/etc/fstab
73 73
 
74
+mkdir -p ${BUILDROOT}/etc/yum.repos.d
75
+cat >> ${BUILDROOT}/etc/yum.repos.d/photon-iso.repo <<EOF
76
+[photon-iso]
77
+name=VMWare Photon Linux 1.0(x86_64)
78
+baseurl=file:///mnt/cdrom/RPMS
79
+gpgkey=file:///etc/pki/rpm-gpg/VMWARE-RPM-GPG-KEY
80
+gpgcheck=1
81
+enabled=1
82
+skip_if_unavailable=True​
83
+EOF
84
+
74 85
 #- Step 7 - Create installer script
75 86
 if [ "$LIVE_CD" = false ] ; then
76 87
 
... ...
@@ -35,10 +35,16 @@ cd ${BUILDROOT} || fail "${PRGNAME}: Change directory: ${BUILDROOT}: FAILURE"
35 35
 #
36 36
 #	Setup the filesystem for chapter 06
37 37
 #
38
-RPMPKG="$(find RPMS -name 'filesystem-[0-9]*.rpm' -print)"
39
-[ -z ${RPMPKG} ] && fail "	Filesystem rpm package missing: Can not continue"
40
-run_command "	Installing filesystem" "rpm -Uvh --nodeps --root ${BUILDROOT} --dbpath /var/lib/rpm ${RPMPKG}" "${LOGFILE}"
41
-
38
+if [[	$# -gt 0 ]] && [[ $1 == 'install' ]]; then
39
+	mkdir -p ${BUILDROOT}/var/lib/rpm
40
+	rpm   --root ${BUILDROOT} --initdb
41
+    tdnf install filesystem --installroot ${BUILDROOT} --nogpgcheck --assumeyes
42
+else
43
+	RPMPKG="$(find RPMS -name 'filesystem-[0-9]*.rpm' -print)"
44
+	[ -z ${RPMPKG} ] && fail "	Filesystem rpm package missing: Can not continue"
45
+	run_command "	Installing filesystem" "rpm -Uvh --nodeps --root ${BUILDROOT} --dbpath /var/lib/rpm ${RPMPKG}" "${LOGFILE}"
46
+fi
47
+ 
42 48
 # 	Ommited in the filesystem.spec file - not needed for booting
43 49
 [ -e ${BUILDROOT}/dev/console ]	|| mknod -m 600 ${BUILDROOT}/dev/console c 5 1
44 50
 [ -e ${BUILDROOT}/dev/null ]    || mknod -m 666 ${BUILDROOT}/dev/null c 1 3
... ...
@@ -134,7 +134,7 @@ if __name__ == '__main__':
134 134
     parser.add_option("-p", "--package-list-file", dest="package_list_file", default="../common/data/build_install_options_all.json")
135 135
     parser.add_option("-m", "--stage-path", dest="stage_path", default="../stage")
136 136
     parser.add_option("-c", "--dracut-configuration", dest="dracut_configuration_file", default="../common/data/dracut_configuration.json")
137
-
137
+    parser.add_option("-s", "--json-data-path", dest="json_data_path", default="../stage/common/data/")
138 138
     (options,  args) = parser.parse_args()
139 139
     if options.iso_path:
140 140
         # Check the arguments
... ...
@@ -231,7 +231,7 @@ if __name__ == '__main__':
231 231
         rpm_list = " ".join(create_rpm_list_to_copy_in_iso(options.package_list_file, options.output_data_path))
232 232
         files_to_copy = " ".join(create_additional_file_list_to_copy_in_iso(os.path.abspath(options.stage_path), options.package_list_file))
233 233
         live_cd = get_live_cd_status_string(options.package_list_file)
234
-        process = subprocess.Popen(['./mk-install-iso.sh', '-w', options.working_directory, options.iso_path, options.rpm_path, options.package_list_file, rpm_list, options.stage_path, files_to_copy, live_cd, options.output_data_path])
234
+        process = subprocess.Popen(['./mk-install-iso.sh', '-w', options.working_directory, options.iso_path, options.rpm_path, options.package_list_file, rpm_list, options.stage_path, files_to_copy, live_cd, options.json_data_path])
235 235
         retval = process.wait()
236 236
 
237 237
     # Cleaning up for vmdk