Browse code

installer: move partitioning to execution stage

Do not do partitioning in the very beginning of ui config
or at the end of ks config. Merge partitioning code and
move it to installer execution. Remove any partitioning
code from selectdisk ui screen.

Extras:
- deprecate 'vmdk_install' (it is same as 'not iso_installer')
- improve nsurses ui rendering. Avoid unnecessary refresh.
- removed unused param in display() and menu items handlers

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

Alexey Makhalov authored on 2019/09/24 09:18:44
Showing 16 changed files
... ...
@@ -80,11 +80,15 @@ class Installer(object):
80 80
             self.output = None
81 81
         signal.signal(signal.SIGINT, self.exit_gracefully)
82 82
 
83
-    def install(self, params):
83
+    def install(self):
84 84
         """
85 85
         Install photon system and handle exception
86 86
         """
87
-        del params
87
+        if self.install_config['iso_installer']:
88
+            self.window.show_window()
89
+            self.progress_bar.initialize('Initializing installation...')
90
+            self.progress_bar.show()
91
+
88 92
         try:
89 93
             return self._unsafe_install()
90 94
         except Exception as inst:
... ...
@@ -98,6 +102,7 @@ class Installer(object):
98 98
         """
99 99
         Install photon system
100 100
         """
101
+        self._format_disk()
101 102
         self._setup_install_repo()
102 103
         self._initialize_system()
103 104
         self._install_packages()
... ...
@@ -139,6 +144,8 @@ class Installer(object):
139 139
             self.window.addstr(0, 0, 'Congratulations, Photon has been installed in {0} secs.\n\n'
140 140
                                'Press any key to continue to boot...'
141 141
                                .format(self.progress_bar.time_elapsed))
142
+            if 'ui_install' in self.install_config:
143
+                self.window.content_window().getch()
142 144
             self._eject_cdrom()
143 145
 
144 146
     def _create_installrpms_list(self):
... ...
@@ -304,6 +311,7 @@ class Installer(object):
304 304
             self.exit_gracefully(None, None)
305 305
 
306 306
         if self.install_config['iso_installer']:
307
+            self.progress_bar.update_message('Initializing system...')
307 308
             self._bind_installer()
308 309
             self._bind_repo_dir()
309 310
             process = subprocess.Popen([self.prepare_command, '-w',
... ...
@@ -471,15 +479,35 @@ class Installer(object):
471 471
         except KeyError:
472 472
             pass
473 473
 
474
+    def _format_disk(self):
475
+        """
476
+        Partition and format the disk
477
+        """
478
+        # skip partitioning if installer was called from image
479
+        if not self.install_config['iso_installer']:
480
+            return
481
+
482
+        self.progress_bar.update_message('Partitioning...')
483
+
484
+        if 'partitions' in self.install_config:
485
+            partitions = self.install_config['partitions']
486
+        else:
487
+            partitions = modules.commons.default_partitions
488
+
489
+        # do partitioning
490
+        partitions_data = modules.commons.partition_disk(self.install_config['disk'], partitions)
491
+
492
+        if partitions_data == None:
493
+            raise Exception("Partitioning failed.")
494
+        self.install_config['disk'] = partitions_data
495
+
496
+
474 497
     def _setup_install_repo(self):
475 498
         """
476 499
         Setup the tdnf repo for installation
477 500
         """
478 501
         if self.install_config['iso_installer']:
479 502
             keepcache = False
480
-            self.window.show_window()
481
-            self.progress_bar.initialize('Initializing installation...')
482
-            self.progress_bar.show()
483 503
             with open(self.tdnf_repo_path, "w") as repo_file:
484 504
                 repo_file.write("[photon-local]\n")
485 505
                 repo_file.write("name=VMWare Photon installer repo\n")
... ...
@@ -611,8 +639,6 @@ class Installer(object):
611 611
         Eject the cdrom on request
612 612
         """
613 613
         eject_cdrom = True
614
-        if 'ui_install' in self.install_config:
615
-            self.window.content_window().getch()
616 614
         if 'eject_cdrom' in self.install_config and not self.install_config['eject_cdrom']:
617 615
             eject_cdrom = False
618 616
         if eject_cdrom:
... ...
@@ -18,7 +18,7 @@ class InstallerContainer(object):
18 18
         self.log_path = log_path
19 19
         self.log_level = log_level
20 20
 
21
-    def install(self, params):
21
+    def install(self):
22 22
         installer = None
23 23
 
24 24
         if self.install_config.get('type', '') == "ostree_host":
... ...
@@ -28,4 +28,4 @@ class InstallerContainer(object):
28 28
             installer = Installer(self.install_config, self.maxy, self.maxx,
29 29
                               self.iso_installer, self.rpm_path, self.log_path, self.log_level)
30 30
 
31
-        return installer.install(params)
31
+        return installer.install()
... ...
@@ -26,7 +26,7 @@ class IsoInstaller(object):
26 26
         config = IsoConfig()
27 27
         rpm_path, install_config = config.Configure(options_file, rpms_path, self.maxy, self.maxx)
28 28
 
29
-        self.screen.clear()
29
+        self.screen.erase()
30 30
         installer = InstallerContainer(
31 31
             install_config,
32 32
             self.maxy, self.maxx,
... ...
@@ -34,7 +34,7 @@ class IsoInstaller(object):
34 34
             rpm_path=rpm_path,
35 35
             log_path="/var/log")
36 36
 
37
-        installer.install(None)
37
+        installer.install()
38 38
 
39 39
 if __name__ == '__main__':
40 40
     usage = "Usage: %prog [options]"
... ...
@@ -15,6 +15,7 @@ import modules.commons
15 15
 from partitionISO import PartitionISO
16 16
 from packageselector import PackageSelector
17 17
 from windowstringreader import WindowStringReader
18
+from confirmwindow import ConfirmWindow
18 19
 from jsonwrapper import JsonWrapper
19 20
 from selectdisk import SelectDisk
20 21
 from license import License
... ...
@@ -70,6 +71,13 @@ class IsoConfig(object):
70 70
             install_config = self.ks_config(options_file, ks_config)
71 71
         else:
72 72
             install_config = self.ui_config(options_file, maxy, maxx)
73
+
74
+        self._add_default(install_config)
75
+
76
+        issue = self._check_install_config(install_config)
77
+        if issue:
78
+            raise Exception(issue)
79
+
73 80
         return rpm_path, install_config
74 81
 
75 82
     @staticmethod
... ...
@@ -172,18 +180,9 @@ class IsoConfig(object):
172 172
             package_list.extend(install_config['additional_packages'])
173 173
         install_config['packages'] = package_list
174 174
 
175
-        if 'partitions' in install_config:
176
-            partitions = install_config['partitions']
177
-        else:
178
-            partitions = modules.commons.default_partitions
179
-
180
-        install_config['disk'] = modules.commons.partition_disk(install_config['disk'], partitions)
181
-
182 175
         if "hostname" in install_config:
183 176
             evalhostname = os.popen('printf ' + install_config["hostname"].strip(" ")).readlines()
184 177
             install_config['hostname'] = evalhostname[0]
185
-        if "hostname" not in install_config or install_config['hostname'] == "":
186
-            install_config['hostname'] = "photon-" + self.random_id.strip()
187 178
 
188 179
         # crypt the password if needed
189 180
         if install_config['password']['crypted']:
... ...
@@ -306,15 +305,19 @@ class IsoConfig(object):
306 306
         # I can go back to this window or not
307 307
         install_config = {}
308 308
         install_config['ui_install'] = True
309
-        items, select_linux_index = self.add_ui_pages(options_file, maxy, maxx,
309
+        items = self.add_ui_pages(options_file, maxy, maxx,
310 310
                                                       install_config)
311 311
         index = 0
312 312
         while True:
313
-            result = items[index][0](None)
313
+            result = items[index][0]()
314 314
             if result.success:
315 315
                 index += 1
316 316
                 if index == len(items):
317
-                    break
317
+                    # confirm window
318
+                    if result.result['yes']:
319
+                        break
320
+                    else:
321
+                        exit(0)
318 322
             else:
319 323
                 index -= 1
320 324
                 while index >= 0 and items[index][1] is False:
... ...
@@ -380,23 +383,51 @@ class IsoConfig(object):
380 380
             None, # post processing of the input field
381 381
             'Please provide the Refspec in OSTree repo', 'OSTree Repo Refspec:', 2, install_config,
382 382
             "photon/3.0/x86_64/minimal")
383
+        confirm_window = ConfirmWindow(11, 60, maxy, maxx,
384
+                                      (maxy - 11) // 2 + 7,
385
+                                      'Start installation? All data on the selected disk will be lost.\n\n'
386
+                                      'Press <Yes> to confirm, or <No> to quit')
383 387
 
384 388
         items.append((license_agreement.display, False))
385 389
         items.append((select_disk.display, True))
386 390
         items.append((select_partition.display, False))
387
-        items.append((select_disk.guided_partitions, False))
388 391
         items.append((package_selector.display, True))
389
-        select_linux_index = -1
390 392
         if self.is_vmware_virtualization():
391 393
             linux_selector = LinuxSelector(maxy, maxx, install_config)
392 394
             items.append((linux_selector.display, True))
393
-            select_linux_index = items.index((linux_selector.display, True))
394 395
         items.append((hostname_reader.get_user_string, True))
395 396
         items.append((root_password_reader.get_user_string, True))
396 397
         items.append((confirm_password_reader.get_user_string, False))
397 398
         items.append((ostree_server_selector.display, True))
398 399
         items.append((ostree_url_reader.get_user_string, True))
399 400
         items.append((ostree_ref_reader.get_user_string, True))
401
+        items.append((confirm_window.do_action, True))
402
+
403
+        return items
404
+
405
+    def _add_default(self, install_config):
406
+        """
407
+        Add default install_config settings if not specified
408
+        """
409
+        # 'boot' mode
410
+        if 'boot' not in install_config:
411
+            arch = subprocess.check_output(['uname', '-m'], universal_newlines=True)
412
+            if "x86" in arch:
413
+                install_config['boot'] = 'dualboot'
414
+            else:
415
+                install_config['boot'] = 'efi'
416
+
417
+        # define 'hostname' as 'photon-<RANDOM STRING>'
418
+        if "hostname" not in install_config or install_config['hostname'] == "":
419
+            install_config['hostname'] = "photon-" + self.random_id.strip()
420
+
421
+    def _check_install_config(self, install_config):
422
+        """
423
+        Sanity check of install_config before its execution.
424
+        Return error string or None
425
+        """
426
+        if not 'disk' in install_config:
427
+            return "No disk configured"
400 428
 
401
-        return items, select_linux_index
429
+        return None
402 430
 
... ...
@@ -23,7 +23,7 @@ class License(object):
23 23
         self.window = Window(self.win_height, self.win_width, self.maxy, self.maxx,
24 24
                              'Welcome to the Photon installer', False)
25 25
 
26
-    def display(self, params):
26
+    def display(self):
27 27
         accept_decline_items = [('<Accept>', self.accept_function),
28 28
                                 ('<Cancel>', self.exit_function)]
29 29
 
... ...
@@ -36,7 +36,7 @@ class LinuxSelector(object):
36 36
         self.install_config['install_linux_esx'] = is_linux_esx
37 37
         return ActionResult(True, None)
38 38
 
39
-    def display(self, params):
39
+    def display(self):
40 40
         self.window.addstr(0, 0, 'The installer has detected that you are installing')
41 41
         self.window.addstr(1, 0, 'Photon OS on a VMware hypervisor.')
42 42
         self.window.addstr(2, 0, 'Which type of Linux kernel would you like to install?')
... ...
@@ -121,7 +121,7 @@ class Menu(Action):
121 121
                 self.window.addch(index + up + self.filled, self.width - 2, curses.ACS_CKBOARD)
122 122
 
123 123
     def refresh(self, highligh=True):
124
-        self.window.clear()
124
+#        self.window.clear()
125 125
         for index, item in enumerate(self.items_strings):
126 126
             if index < self.head_position:
127 127
                 continue
... ...
@@ -35,7 +35,7 @@ class OSTreeServerSelector(object):
35 35
         self.install_config['default_repo'] = is_default_repo
36 36
         return ActionResult(True, None)
37 37
 
38
-    def display(self, params):
38
+    def display(self):
39 39
         if self.install_config['type'] == 'ostree_host':
40 40
             return self.window.do_action()
41 41
         return ActionResult(True, None)
... ...
@@ -11,7 +11,7 @@ class OSTreeWindowStringReader(WindowStringReader):
11 11
     def __init__(self, maxy, maxx, height, width, field, confirmation_err_msg, echo_char, accepted_chars, validation_fn, conversion_fn, title, display_string, inputy, install_config, default_string = None):
12 12
         WindowStringReader.__init__(self, maxy, maxx, height, width, field, confirmation_err_msg, echo_char, accepted_chars, validation_fn, conversion_fn, title, display_string, inputy, install_config, default_string)
13 13
 
14
-    def get_user_string(self, params):
14
+    def get_user_string(self):
15 15
         if self.install_config['type'] == 'ostree_host' and not self.install_config['default_repo']:
16 16
             return self.window.do_action()
17 17
         return ActionResult(True, None)
... ...
@@ -81,8 +81,8 @@ class PackageSelector(object):
81 81
         self.install_config['additional-files'] = selected_item_params[2]
82 82
         return ActionResult(True, {'custom': False})
83 83
 
84
-    def custom_packages(self, params):
84
+    def custom_packages(self):
85 85
         return ActionResult(True, {'custom': True})
86 86
 
87
-    def display(self, params):
87
+    def display(self):
88 88
         return self.window.do_action()
... ...
@@ -35,10 +35,7 @@ class PartitionISO(object):
35 35
                              'Welcome to the Photon installer', False, can_go_next=False)
36 36
         Device.refresh_devices()
37 37
 
38
-    def display(self, params):
39
-        if 'skipPrevs' in self.install_config and self.install_config['skipPrevs'] == True:
40
-            self.delete()
41
-            return ActionResult(False, {'goBack':True})
38
+    def display(self):
42 39
         if 'autopartition' in self.install_config and self.install_config['autopartition'] == True:
43 40
             return ActionResult(True, None)
44 41
         if ('delete_partition' in self.install_config and
... ...
@@ -162,11 +159,11 @@ class PartitionISO(object):
162 162
             self.install_config['partitionsnumber'] = self.install_config['partitionsnumber'] + 1
163 163
 
164 164
         #parse the input in install config
165
-        return self.display(False)
165
+        return self.display()
166 166
 
167 167
     def delete_function(self):
168 168
         self.delete()
169
-        return self.display(False)
169
+        return self.display()
170 170
 
171 171
     def go_back(self):
172 172
         self.delete()
... ...
@@ -184,7 +181,7 @@ class PartitionISO(object):
184 184
                                            'Partition information cannot be empty',
185 185
                                            info=True)
186 186
             confirm_window.do_action()
187
-            return self.display(False)
187
+            return self.display()
188 188
         #must have /
189 189
         if not self.has_slash:
190 190
             window_height = 9
... ...
@@ -194,10 +191,25 @@ class PartitionISO(object):
194 194
                                            self.maxx, window_starty, 'Missing /',
195 195
                                            info=True)
196 196
             confirm_window.do_action()
197
-            return self.display(False)
197
+            return self.display()
198 198
 
199 199
         self.window.hide_window()
200 200
         self.text_pane.hide()
201
+
202
+        partitions = []
203
+        for i in range(int(self.install_config['partitionsnumber'])):
204
+            if len(self.install_config[str(i)+'partition_info'+str(0)]) == 0:
205
+                sizedata = 0
206
+            else:
207
+                sizedata = int(self.install_config[str(i) + 'partition_info' + str(0)])
208
+            mtdata = self.install_config[str(i) + 'partition_info' + str(2)]
209
+            typedata = self.install_config[str(i) + 'partition_info'+str(1)]
210
+
211
+            partitions = partitions + [{"mountpoint": mtdata,
212
+                                        "size": sizedata,
213
+                                        "filesystem": typedata},]
214
+        self.install_config['partitions'] = partitions
215
+
201 216
         return ActionResult(True, {'goNext':True})
202 217
 
203 218
     def delete(self):
... ...
@@ -6,9 +6,7 @@ from device import Device
6 6
 from window import Window
7 7
 from actionresult import ActionResult
8 8
 from menu import Menu
9
-from confirmwindow import ConfirmWindow
10 9
 import modules.commons
11
-from progressbar import ProgressBar
12 10
 import subprocess
13 11
 
14 12
 class SelectDisk(object):
... ...
@@ -26,11 +24,6 @@ class SelectDisk(object):
26 26
 
27 27
         self.menu_starty = self.win_starty + 6
28 28
         self.menu_height = 5
29
-        self.progress_padding = 5
30
-        self.progress_width = self.win_width - self.progress_padding
31
-        self.progress_bar = ProgressBar(self.win_starty + 6,
32
-                                        self.win_startx + (self.progress_padding // 2),
33
-                                        self.progress_width, new_win=True)
34 29
 
35 30
         self.disk_buttom_items = []
36 31
         self.disk_buttom_items.append(('<Custom>', self.custom_function, False))
... ...
@@ -40,74 +33,9 @@ class SelectDisk(object):
40 40
                              'Select a disk', True,
41 41
                              items=self.disk_buttom_items, menu_helper=self.save_index,
42 42
                              position=2, tab_enabled=False)
43
-        self.partition_window = Window(self.win_height, self.win_width, self.maxy,
44
-                                       self.maxx, 'Partition', True)
45 43
         self.devices = Device.refresh_devices()
46 44
 
47
-    def guided_partitions(self, params):
48
-        if not 'diskindex' in self.install_config:
49
-            return ActionResult(False, None)
50
-
51
-        device_index = self.install_config['diskindex']
52
-
53
-        menu_height = 9
54
-        menu_width = 40
55
-        menu_starty = (self.maxy - menu_height) // 2 + 5
56
-        self.install_config['delete_partition'] = True
57
-        confrim_window = ConfirmWindow(menu_height, menu_width, self.maxy,
58
-                                       self.maxx, menu_starty,
59
-                                       'This will erase the disk.\nAre you sure?')
60
-        confirmed = confrim_window.do_action().result['yes']
61
-
62
-        if confirmed == False:
63
-            self.install_config['skipPrevs'] = True
64
-            return ActionResult(False, {'goBack':True})
65
-
66
-        self.install_config['skipPrevs'] = False
67
-        self.progress_bar.initialize('Partitioning...')
68
-        self.progress_bar.show()
69
-        self.progress_bar.show_loading('Partitioning')
70
-
71
-        # Do the partitioning
72
-        if 'partitionsnumber' in self.install_config:
73
-            if int(self.install_config['partitionsnumber']) == 0:
74
-                partitions_data = modules.commons.partition_disk(
75
-                    self.devices[device_index].path, modules.commons.default_partitions)
76
-            else:
77
-                partitions = []
78
-                for i in range(int(self.install_config['partitionsnumber'])):
79
-                    if len(self.install_config[str(i)+'partition_info'+str(0)]) == 0:
80
-                        sizedata = 0
81
-                    else:
82
-                        sizedata = int(self.install_config[str(i) + 'partition_info' + str(0)])
83
-                    mtdata = self.install_config[str(i) + 'partition_info' + str(2)]
84
-                    typedata = self.install_config[str(i) + 'partition_info'+str(1)]
85
-
86
-                    partitions = partitions + [{"mountpoint": mtdata,
87
-                                                "size": sizedata,
88
-                                                "filesystem": typedata},]
89
-                partitions_data = modules.commons.partition_disk(
90
-                    self.devices[device_index].path, partitions)
91
-        else:
92
-            partitions_data = modules.commons.partition_disk(
93
-                self.devices[device_index].path, modules.commons.default_partitions)
94
-
95
-        if partitions_data == None:
96
-            self.partition_window.adderror('Partitioning failed, you may try again')
97
-        else:
98
-            self.install_config['disk'] = partitions_data
99
-            arch = subprocess.check_output(['uname', '-m'], universal_newlines=True)
100
-            if "x86" in arch:
101
-                self.install_config['boot'] = 'dualboot'
102
-            else:
103
-                self.install_config['boot'] = 'efi'
104
-
105
-        self.progress_bar.hide()
106
-        return ActionResult(partitions_data != None, None)
107
-
108
-    def display(self, params):
109
-        if 'skipPrevs' in self.install_config:
110
-            self.install_config['skipPrevs'] = False
45
+    def display(self):
111 46
         self.window.addstr(0, 0, 'Please select a disk and a method how to partition it:\n' +
112 47
                            'Auto - single partition for /, no swap partition.\n' +
113 48
                            'Custom - for customized partitioning')
... ...
@@ -133,13 +61,14 @@ class SelectDisk(object):
133 133
 
134 134
     def save_index(self, device_index):
135 135
         self.install_config['diskindex'] = device_index
136
+        self.install_config['disk'] = self.devices[device_index].path
136 137
         return ActionResult(True, None)
137 138
 
138
-    def auto_function(self, params):    #default is no partition
139
+    def auto_function(self):    #default is no partition
139 140
         self.install_config['autopartition'] = True
140 141
         self.install_config['partitionsnumber'] = 0
141 142
         return ActionResult(True, None)
142 143
 
143
-    def custom_function(self, params):  #custom minimize partition number is 1
144
+    def custom_function(self):  #custom minimize partition number is 1
144 145
         self.install_config['autopartition'] = False
145 146
         return ActionResult(True, None)
... ...
@@ -173,7 +173,7 @@ class TextPane(Action):
173 173
                 self.window.addch(index + up + self.filled, self.width - 2, curses.ACS_CKBOARD)
174 174
 
175 175
     def refresh(self):
176
-        self.window.clear()
176
+        self.window.erase()
177 177
         for index, line in enumerate(self.lines):
178 178
             if index < self.head_position:
179 179
                 continue
... ...
@@ -71,7 +71,7 @@ class Window(Action):
71 71
         self.shadowpanel = curses.panel.new_panel(self.shadowwin)
72 72
 
73 73
         self.action_panel = action_panel
74
-        self.refresh(0, True)
74
+#        self.refresh(0, True)
75 75
         self.hide_window()
76 76
 
77 77
     def update_next_item(self):
... ...
@@ -80,7 +80,7 @@ class Window(Action):
80 80
         self.tab_enabled = False
81 81
 
82 82
 
83
-    def next_function(self, params):
83
+    def next_function(self):
84 84
         return ActionResult(True, None)
85 85
 
86 86
     def set_action_panel(self, action_panel):
... ...
@@ -104,7 +104,7 @@ class Window(Action):
104 104
                 if self.menu_helper:
105 105
                     self.menu_helper(params)
106 106
 
107
-            result = self.items[self.position-1][1](None)
107
+            result = self.items[self.position-1][1]()
108 108
             if result.success:
109 109
                 self.hide_window()
110 110
                 self.action_panel.hide()
... ...
@@ -130,7 +130,7 @@ class Window(Action):
130 130
                     action_result.result['goNext']):
131 131
                 return ActionResult(True, None)
132 132
             if self.position != 0:    #saving the disk index
133
-                self.items[self.position-1][1](None)
133
+                self.items[self.position-1][1]()
134 134
             if self.items:
135 135
                 return self.update_menu(action_result)
136 136
             self.hide_window()
... ...
@@ -184,7 +184,7 @@ class Window(Action):
184 184
                             params = action_result.result['diskIndex']
185 185
                             if self.menu_helper:
186 186
                                 self.menu_helper(params)
187
-                        result = self.items[self.position-1][1](None)
187
+                        result = self.items[self.position-1][1]()
188 188
                         if result.success:
189 189
                             self.hide_window()
190 190
                             self.action_panel.hide()
... ...
@@ -36,5 +36,5 @@ class WindowStringReader(object):
36 36
         self.window.set_action_panel(self.read_text)
37 37
         self.window.addstr(0, 0, self.display_string)
38 38
 
39
-    def get_user_string(self, params):
39
+    def get_user_string(self, params=None):
40 40
         return self.window.do_action()
... ...
@@ -43,7 +43,7 @@ def runInstaller(options, config):
43 43
     # Run the installer
44 44
     package_installer = Installer(config, rpm_path=options.rpm_path,
45 45
                                   log_path=options.log_path, log_level=options.log_level)
46
-    return package_installer.install(None)
46
+    return package_installer.install()
47 47
 
48 48
 def get_file_name_with_last_folder(filename):
49 49
     basename = os.path.basename(filename)
... ...
@@ -292,7 +292,6 @@ def createImage(options):
292 292
     if not success:
293 293
         raise Exception("Unexpected failure in creating disk, please check the logs")
294 294
         sys.exit(1)
295
-    config['vmdk_install'] = True
296 295
     result = runInstaller(options, config)
297 296
     process = subprocess.Popen([disk_cleanup_script, config['disk']['disk']])
298 297
     process.wait()