Browse code

Limit lines to a maximum of 99 characters, add more functions to installer.py.

Change-Id: Idad0f5e11a41c048ec8b187e1bf93a5ea29af918
Reviewed-on: http://photon-jenkins.eng.vmware.com:8082/4614
Tested-by: gerrit-photon <photon-checkins@vmware.com>
Reviewed-by: Divya Thaluru <dthaluru@vmware.com>

xiaolin-vmware authored on 2018/01/09 02:52:46
Showing 7 changed files
... ...
@@ -3,7 +3,6 @@
3 3
 #    Author: Mahmoud Bassiouny <mbassiouny@vmware.com>
4 4
 
5 5
 import subprocess
6
-import curses
7 6
 import os
8 7
 import shutil
9 8
 import signal
... ...
@@ -34,7 +33,7 @@ class Installer(object):
34 34
         else:
35 35
             self.working_directory = "/mnt/photon-root"
36 36
         self.photon_root = self.working_directory + "/photon-chroot"
37
-
37
+        self.rpms_tobeinstalled = None
38 38
         self.restart_command = "shutdown"
39 39
 
40 40
         if self.iso_installer:
... ...
@@ -62,7 +61,9 @@ class Installer(object):
62 62
         signal.signal(signal.SIGINT, self.exit_gracefully)
63 63
 
64 64
     # This will be called if the installer interrupted by Ctrl+C or exception
65
-    def exit_gracefully(self, signal, frame):
65
+    def exit_gracefully(self, signal1, frame1):
66
+        del signal1
67
+        del frame1
66 68
         if self.iso_installer:
67 69
             self.progress_bar.hide()
68 70
             self.window.addstr(0, 0, 'Oops, Installer got interrupted.\n\n' +
... ...
@@ -73,8 +74,9 @@ class Installer(object):
73 73
         sys.exit(1)
74 74
 
75 75
     def install(self, params):
76
+        del params
76 77
         try:
77
-            return self.unsafe_install(params)
78
+            return self.unsafe_install()
78 79
         except Exception as inst:
79 80
             if self.iso_installer:
80 81
                 modules.commons.log(modules.commons.LOG_ERROR, repr(inst))
... ...
@@ -82,105 +84,13 @@ class Installer(object):
82 82
             else:
83 83
                 raise
84 84
 
85
-    def unsafe_install(self, params):
86
-
87
-        if self.iso_installer:
88
-            self.window.show_window()
89
-            self.progress_bar.initialize('Initializing installation...')
90
-            self.progress_bar.show()
91
-            #self.rpm_path = "https://dl.bintray.com/vmware/photon_release_1.0_TP2_x86_64"
92
-            if self.rpm_path.startswith("https://") or self.rpm_path.startswith("http://"):
93
-                cmdoption = 's/baseurl.*/baseurl={}/g'.format(self.rpm_path.replace('/', '\/'))
94
-                process = subprocess.Popen(['sed', '-i', cmdoption,
95
-                                            '/etc/yum.repos.d/photon-iso.repo'])
96
-                retval = process.wait()
97
-                if retval != 0:
98
-                    modules.commons.log(modules.commons.LOG_INFO, "Failed to reset repo")
99
-                    self.exit_gracefully(None, None)
100
-
101
-            cmdoption = ('s/cachedir=\/var/cachedir={}/g'
102
-                         .format(self.photon_root.replace('/', '\/')))
103
-            process = subprocess.Popen(['sed', '-i', cmdoption, '/etc/tdnf/tdnf.conf'])
104
-            retval = process.wait()
105
-            if retval != 0:
106
-                modules.commons.log(modules.commons.LOG_INFO, "Failed to reset tdnf cachedir")
107
-                self.exit_gracefully(None, None)
85
+    def unsafe_install(self):
86
+        self.setup_install_repo()
108 87
         self.execute_modules(modules.commons.PRE_INSTALL)
109 88
 
110 89
         self.initialize_system()
111
-
112
-        if self.iso_installer:
113
-            self.adjust_packages_for_vmware_virt()
114
-            selected_packages = self.install_config['packages']
115
-            state = 0
116
-            packages_to_install = {}
117
-            total_size = 0
118
-            with open(modules.commons.TDNF_CMDLINE_FILE_NAME, "w") as tdnf_cmdline_file:
119
-                tdnf_cmdline_file.write("tdnf install --installroot {0} --nogpgcheck {1}"
120
-                                        .format(self.photon_root, " ".join(selected_packages)))
121
-            with open(modules.commons.TDNF_LOG_FILE_NAME, "w") as tdnf_errlog:
122
-                process = subprocess.Popen(['tdnf', 'install'] + selected_packages +
123
-                                           ['--installroot', self.photon_root, '--nogpgcheck',
124
-                                            '--assumeyes'], stdout=subprocess.PIPE,
125
-                                           stderr=tdnf_errlog)
126
-                while True:
127
-                    output = process.stdout.readline().decode()
128
-                    if output == '':
129
-                        retval = process.poll()
130
-                        if retval is not None:
131
-                            break
132
-                    if state == 0:
133
-                        if output == 'Installing:\n':
134
-                            state = 1
135
-                    elif state == 1: #N A EVR Size(readable) Size(in bytes)
136
-                        if output == '\n':
137
-                            state = 2
138
-                            self.progress_bar.update_num_items(total_size)
139
-                        else:
140
-                            info = output.split()
141
-                            package = '{0}-{1}.{2}'.format(info[0], info[2], info[1])
142
-                            packages_to_install[package] = int(info[5])
143
-                            total_size += int(info[5])
144
-                    elif state == 2:
145
-                        if output == 'Downloading:\n':
146
-                            self.progress_bar.update_message('Preparing ...')
147
-                            state = 3
148
-                    elif state == 3:
149
-                        self.progress_bar.update_message(output)
150
-                        if output == 'Running transaction\n':
151
-                            state = 4
152
-                    else:
153
-                        modules.commons.log(modules.commons.LOG_INFO, "[tdnf] {0}".format(output))
154
-                        prefix = 'Installing/Updating: '
155
-                        if output.startswith(prefix):
156
-                            package = output[len(prefix):].rstrip('\n')
157
-                            self.progress_bar.increment(packages_to_install[package])
158
-
159
-                        self.progress_bar.update_message(output)
160
-                # 0 : succeed; 137 : package already installed; 65 : package not found in repo.
161
-                if retval != 0 and retval != 137:
162
-                    modules.commons.log(modules.commons.LOG_ERROR,
163
-                                        "Failed to install some packages, refer to {0}"
164
-                                        .format(modules.commons.TDNF_LOG_FILE_NAME))
165
-                    self.exit_gracefully(None, None)
166
-        else:
167
-        #install packages
168
-            rpms = []
169
-            for rpm in self.rpms_tobeinstalled:
170
-                # We already installed the filesystem in the preparation
171
-                if rpm['package'] == 'filesystem':
172
-                    continue
173
-                rpms.append(rpm['filename'])
174
-            return_value = self.install_package(rpms)
175
-            if return_value != 0:
176
-                self.exit_gracefully(None, None)
177
-
178
-
179
-        if self.iso_installer:
180
-            self.progress_bar.show_loading('Finalizing installation')
181
-
182
-        if os.path.exists("/etc/resolv.conf"):
183
-            shutil.copy("/etc/resolv.conf", self.photon_root + '/etc/.')
90
+        self.install_packages()
91
+        self.enable_network_in_chroot()
184 92
         self.finalize_system()
185 93
 
186 94
         if not self.install_config['iso_system']:
... ...
@@ -228,9 +138,7 @@ class Installer(object):
228 228
             retval = process.wait()
229 229
 
230 230
             self.update_fstab()
231
-
232
-        if os.path.exists(self.photon_root + '/etc/resolv.conf'):
233
-            os.remove(self.photon_root + '/etc/resolv.conf')
231
+        self.disable_network_in_chroot()
234 232
 
235 233
         command = [self.unmount_disk_command, '-w', self.photon_root]
236 234
         if not self.install_config['iso_system']:
... ...
@@ -240,17 +148,10 @@ class Installer(object):
240 240
 
241 241
         if self.iso_installer:
242 242
             self.progress_bar.hide()
243
-            self.window.addstr(0, 0, 'Congratulations, Photon has been installed in {0} secs.\n\n' +
243
+            self.window.addstr(0, 0, 'Congratulations, Photon has been installed in {0} secs.\n\n'
244 244
                                'Press any key to continue to boot...'
245 245
                                .format(self.progress_bar.time_elapsed))
246
-            eject_cdrom = True
247
-            if 'ui_install' in self.install_config:
248
-                self.window.content_window().getch()
249
-            if 'eject_cdrom' in self.install_config and not self.install_config['eject_cdrom']:
250
-                eject_cdrom = False
251
-            if eject_cdrom:
252
-                process = subprocess.Popen(['eject', '-r'], stdout=self.output)
253
-                process.wait()
246
+            self.eject_cdrom()
254 247
         return ActionResult(True, None)
255 248
 
256 249
     def copy_rpms(self):
... ...
@@ -263,7 +164,7 @@ class Installer(object):
263 263
 
264 264
         for pkg in selected_packages:
265 265
             if pkg in pkg_to_rpm_map:
266
-                if not pkg_to_rpm_map[pkg]['rpm'] is None:
266
+                if pkg_to_rpm_map[pkg]['rpm'] is not None:
267 267
                     name = pkg_to_rpm_map[pkg]['rpm']
268 268
                     basename = os.path.basename(name)
269 269
                     self.rpms_tobeinstalled.append({'filename': basename, 'path': name,
... ...
@@ -421,7 +322,7 @@ class Installer(object):
421 421
 
422 422
         rpms = set(rpm_file_names)
423 423
         rpm_paths = []
424
-        for root, dirs, files in os.walk(self.rpm_path):
424
+        for root, _, files in os.walk(self.rpm_path):
425 425
             for f in files:
426 426
                 if f in rpms:
427 427
                     rpm_paths.append(os.path.join(root, f))
... ...
@@ -457,7 +358,7 @@ class Installer(object):
457 457
                 continue
458 458
 
459 459
             # the module default is disabled
460
-            if not hasattr(mod, 'enabled') or mod.enabled == False:
460
+            if not hasattr(mod, 'enabled') or mod.enabled is False:
461 461
                 modules.commons.log(modules.commons.LOG_INFO,
462 462
                                     "module {} is not enabled".format(module))
463 463
                 continue
... ...
@@ -475,7 +376,7 @@ class Installer(object):
475 475
                                     "Error: not able to execute module {}".format(module))
476 476
                 continue
477 477
 
478
-            mod.execute(module, self.install_config, self.photon_root)
478
+            mod.execute(self.install_config, self.photon_root)
479 479
 
480 480
     def adjust_packages_for_vmware_virt(self):
481 481
         try:
... ...
@@ -492,3 +393,115 @@ class Installer(object):
492 492
                 selected_packages.append('linux-esx')
493 493
         except KeyError:
494 494
             pass
495
+
496
+    def setup_install_repo(self):
497
+        if self.iso_installer:
498
+            self.window.show_window()
499
+            self.progress_bar.initialize('Initializing installation...')
500
+            self.progress_bar.show()
501
+            #self.rpm_path = "https://dl.bintray.com/vmware/photon_release_1.0_TP2_x86_64"
502
+            if self.rpm_path.startswith("https://") or self.rpm_path.startswith("http://"):
503
+                cmdoption = 's/baseurl.*/baseurl={}/g'.format(self.rpm_path.replace('/', '\/'))
504
+                process = subprocess.Popen(['sed', '-i', cmdoption,
505
+                                            '/etc/yum.repos.d/photon-iso.repo'])
506
+                retval = process.wait()
507
+                if retval != 0:
508
+                    modules.commons.log(modules.commons.LOG_INFO, "Failed to reset repo")
509
+                    self.exit_gracefully(None, None)
510
+
511
+            cmdoption = ('s/cachedir=\/var/cachedir={}/g'
512
+                         .format(self.photon_root.replace('/', '\/')))
513
+            process = subprocess.Popen(['sed', '-i', cmdoption, '/etc/tdnf/tdnf.conf'])
514
+            retval = process.wait()
515
+            if retval != 0:
516
+                modules.commons.log(modules.commons.LOG_INFO, "Failed to reset tdnf cachedir")
517
+                self.exit_gracefully(None, None)
518
+
519
+    def install_packages(self):
520
+        if self.iso_installer:
521
+            self.tdnf_install_packages()
522
+        else:
523
+        #install packages
524
+            rpms = []
525
+            for rpm in self.rpms_tobeinstalled:
526
+                # We already installed the filesystem in the preparation
527
+                if rpm['package'] == 'filesystem':
528
+                    continue
529
+                rpms.append(rpm['filename'])
530
+            return_value = self.install_package(rpms)
531
+            if return_value != 0:
532
+                self.exit_gracefully(None, None)
533
+
534
+    def tdnf_install_packages(self):
535
+        self.adjust_packages_for_vmware_virt()
536
+        selected_packages = self.install_config['packages']
537
+        state = 0
538
+        packages_to_install = {}
539
+        total_size = 0
540
+        with open(modules.commons.TDNF_CMDLINE_FILE_NAME, "w") as tdnf_cmdline_file:
541
+            tdnf_cmdline_file.write("tdnf install --installroot {0} --nogpgcheck {1}"
542
+                                    .format(self.photon_root, " ".join(selected_packages)))
543
+        with open(modules.commons.TDNF_LOG_FILE_NAME, "w") as tdnf_errlog:
544
+            process = subprocess.Popen(['tdnf', 'install'] + selected_packages +
545
+                                       ['--installroot', self.photon_root, '--nogpgcheck',
546
+                                        '--assumeyes'], stdout=subprocess.PIPE,
547
+                                       stderr=tdnf_errlog)
548
+            while True:
549
+                output = process.stdout.readline().decode()
550
+                if output == '':
551
+                    retval = process.poll()
552
+                    if retval is not None:
553
+                        break
554
+                if state == 0:
555
+                    if output == 'Installing:\n':
556
+                        state = 1
557
+                elif state == 1: #N A EVR Size(readable) Size(in bytes)
558
+                    if output == '\n':
559
+                        state = 2
560
+                        self.progress_bar.update_num_items(total_size)
561
+                    else:
562
+                        info = output.split()
563
+                        package = '{0}-{1}.{2}'.format(info[0], info[2], info[1])
564
+                        packages_to_install[package] = int(info[5])
565
+                        total_size += int(info[5])
566
+                elif state == 2:
567
+                    if output == 'Downloading:\n':
568
+                        self.progress_bar.update_message('Preparing ...')
569
+                        state = 3
570
+                elif state == 3:
571
+                    self.progress_bar.update_message(output)
572
+                    if output == 'Running transaction\n':
573
+                        state = 4
574
+                else:
575
+                    modules.commons.log(modules.commons.LOG_INFO, "[tdnf] {0}".format(output))
576
+                    prefix = 'Installing/Updating: '
577
+                    if output.startswith(prefix):
578
+                        package = output[len(prefix):].rstrip('\n')
579
+                        self.progress_bar.increment(packages_to_install[package])
580
+
581
+                    self.progress_bar.update_message(output)
582
+            # 0 : succeed; 137 : package already installed; 65 : package not found in repo.
583
+            if retval != 0 and retval != 137:
584
+                modules.commons.log(modules.commons.LOG_ERROR,
585
+                                    "Failed to install some packages, refer to {0}"
586
+                                    .format(modules.commons.TDNF_LOG_FILE_NAME))
587
+                self.exit_gracefully(None, None)
588
+        self.progress_bar.show_loading('Finalizing installation')
589
+
590
+    def eject_cdrom(self):
591
+        eject_cdrom = True
592
+        if 'ui_install' in self.install_config:
593
+            self.window.content_window().getch()
594
+        if 'eject_cdrom' in self.install_config and not self.install_config['eject_cdrom']:
595
+            eject_cdrom = False
596
+        if eject_cdrom:
597
+            process = subprocess.Popen(['eject', '-r'], stdout=self.output)
598
+            process.wait()
599
+
600
+    def enable_network_in_chroot(self):
601
+        if os.path.exists("/etc/resolv.conf"):
602
+            shutil.copy("/etc/resolv.conf", self.photon_root + '/etc/.')
603
+
604
+    def disable_network_in_chroot(self):
605
+        if os.path.exists(self.photon_root + '/etc/resolv.conf'):
606
+            os.remove(self.photon_root + '/etc/resolv.conf')
... ...
@@ -18,24 +18,35 @@ from license import License
18 18
 from linuxselector import LinuxSelector
19 19
 
20 20
 class IsoConfig(object):
21
-    def Configure(self,options_file, maxy, maxx):
21
+    """This class handles iso installer configuration."""
22
+    def __init__(self):
22 23
         self.cd_path = None
24
+        self.alpha_chars = list(range(65, 91))
25
+        self.alpha_chars.extend(range(97, 123))
26
+        self.hostname_accepted_chars = self.alpha_chars
27
+        # Adding the numeric chars
28
+        self.hostname_accepted_chars.extend(range(48, 58))
29
+        # Adding the . and -
30
+        self.hostname_accepted_chars.extend([ord('.'), ord('-')])
31
+        self.random_id = '%12x' % random.randrange(16**12)
32
+        self.random_hostname = "photon-" + self.random_id.strip()
23 33
 
34
+    def Configure(self, options_file, maxy, maxx):
24 35
         kernel_params = subprocess.check_output(['cat', '/proc/cmdline'])
25 36
 
26 37
         # check for the repo param
27 38
         m = re.match(r".*repo=(\S+)\s*.*\s*", kernel_params.decode())
28
-        if m != None:
39
+        if m is not None:
29 40
             rpm_path = m.group(1)
30 41
         else:
31 42
             # the rpms should be in the cd
32
-            self.mount_RPMS_cd()
43
+            self.mount_cd()
33 44
             rpm_path = os.path.join(self.cd_path, "RPMS")
34 45
 
35 46
         # check the kickstart param
36 47
         ks_config = None
37 48
         m = re.match(r".*ks=(\S+)\s*.*\s*", kernel_params.decode())
38
-        if m != None:
49
+        if m is not None:
39 50
             ks_config = self.get_config(m.group(1))
40 51
 
41 52
         install_config = None
... ...
@@ -45,21 +56,23 @@ class IsoConfig(object):
45 45
             install_config = self.ui_config(options_file, maxy, maxx)
46 46
         return rpm_path, install_config
47 47
 
48
-    def is_vmware_virtualization(self):
48
+    @staticmethod
49
+    def is_vmware_virtualization():
50
+        """Detect vmware vm"""
49 51
         process = subprocess.Popen(['systemd-detect-virt'], stdout=subprocess.PIPE)
50 52
         out, err = process.communicate()
51 53
         if err is not None and err != 0:
52 54
             return False
53
-        else:
54
-            return out == 'vmware\n'
55
+        return out == 'vmware\n'
55 56
 
56 57
     def get_config(self, path):
58
+        """kick start configuration"""
57 59
         if path.startswith("http://"):
58 60
             # Do 5 trials to get the kick start
59 61
             # TODO: make sure the installer run after network is up
60 62
             ks_file_error = "Failed to get the kickstart file at {0}".format(path)
61 63
             wait = 1
62
-            for x in range(0, 5):
64
+            for _ in range(0, 5):
63 65
                 err_msg = ""
64 66
                 try:
65 67
                     response = requests.get(path, timeout=3)
... ...
@@ -70,9 +83,9 @@ class IsoConfig(object):
70 70
                     err_msg = e
71 71
 
72 72
                 modules.commons.log(modules.commons.LOG_ERROR,
73
-                    ks_file_error)
73
+                                    ks_file_error)
74 74
                 modules.commons.log(modules.commons.LOG_ERROR,
75
-                    "error msg: {0}".format(err_msg))
75
+                                    "error msg: {0}".format(err_msg))
76 76
                 print(ks_file_error)
77 77
                 print("retry in a second")
78 78
                 time.sleep(wait)
... ...
@@ -84,11 +97,12 @@ class IsoConfig(object):
84 84
             raise Exception(err_msg)
85 85
         else:
86 86
             if path.startswith("cdrom:/"):
87
-                self.mount_RPMS_cd()
87
+                self.mount_cd()
88 88
                 path = os.path.join(self.cd_path, path.replace("cdrom:/", "", 1))
89 89
             return (JsonWrapper(path)).read()
90 90
 
91
-    def mount_RPMS_cd(self):
91
+    def mount_cd(self):
92
+        """Mount the cd with RPMS"""
92 93
         # check if the cd is already mounted
93 94
         if self.cd_path:
94 95
             return
... ...
@@ -98,7 +112,7 @@ class IsoConfig(object):
98 98
         retval = process.wait()
99 99
 
100 100
         # Retry mount the CD
101
-        for i in range(0, 3):
101
+        for _ in range(0, 3):
102 102
             process = subprocess.Popen(['mount', '/dev/cdrom', '/mnt/cdrom'])
103 103
             retval = process.wait()
104 104
             if retval == 0:
... ...
@@ -111,6 +125,8 @@ class IsoConfig(object):
111 111
         raise Exception("Can not mount the cd")
112 112
 
113 113
     def ks_config(self, options_file, ks_config):
114
+        """Load configuration from file"""
115
+        del options_file
114 116
         install_config = ks_config
115 117
         install_config['iso_system'] = False
116 118
         if self.is_vmware_virtualization() and 'install_linux_esx' not in install_config:
... ...
@@ -123,7 +139,9 @@ class IsoConfig(object):
123 123
         base_path = os.path.dirname("build_install_options_all.json")
124 124
         package_list = []
125 125
 
126
-        package_list = PackageSelector.get_packages_to_install(options_sorted, install_config['type'], base_path)
126
+        package_list = PackageSelector.get_packages_to_install(options_sorted,
127
+                                                               install_config['type'],
128
+                                                               base_path)
127 129
         if 'additional_packages' in install_config:
128 130
             package_list.extend(install_config['additional_packages'])
129 131
         install_config['packages'] = package_list
... ...
@@ -139,77 +157,103 @@ class IsoConfig(object):
139 139
             evalhostname = os.popen('printf ' + install_config["hostname"].strip(" ")).readlines()
140 140
             install_config['hostname'] = evalhostname[0]
141 141
         if "hostname" not in install_config or install_config['hostname'] == "":
142
-            random_id = '%12x' % random.randrange(16**12)
143
-            install_config['hostname'] = "photon-" + random_id.strip()
142
+            install_config['hostname'] = "photon-" + self.random_id.strip()
144 143
 
145 144
         # crypt the password if needed
146 145
         if install_config['password']['crypted']:
147 146
             install_config['password'] = install_config['password']['text']
148 147
         else:
149
-            install_config['password'] = crypt.crypt(install_config['password']['text'],
150
-                "$6$" + "".join([random.choice(string.ascii_letters + string.digits) for _ in range(16)]))
148
+            install_config['password'] = crypt.crypt(
149
+                install_config['password']['text'],
150
+                "$6$" + "".join([random.choice(
151
+                    string.ascii_letters + string.digits) for _ in range(16)]))
151 152
         return install_config
152 153
 
153
-    def validate_hostname(self, hostname):
154
+    @staticmethod
155
+    def validate_hostname(hostname):
156
+        """A valid hostname must start with a letter"""
154 157
         error_empty = "Empty hostname or domain is not allowed"
155 158
         error_dash = "Hostname or domain should not start or end with '-'"
156 159
         error_hostname = "Hostname should start with alpha char and <= 64 chars"
157 160
 
158
-        if hostname is None or len(hostname) == 0:
161
+        if hostname is None or not hostname:
159 162
             return False, error_empty
160 163
 
161 164
         fields = hostname.split('.')
162 165
         for field in fields:
163
-            if len(field) == 0:
166
+            if not field:
164 167
                 return False, error_empty
165 168
             if field[0] == '-' or field[-1] == '-':
166 169
                 return False, error_dash
167 170
 
168 171
         machinename = fields[0]
169
-        return (len(machinename) <= 64) and (ord(machinename[0]) in self.alpha_chars), error_hostname
172
+        return (len(machinename) <= 64 and
173
+                machinename[0].isalpha(), error_hostname)
170 174
 
171 175
     @staticmethod
172 176
     def validate_password(text):
177
+        """Validate password with cracklib"""
173 178
         try:
174
-            p = cracklib.VeryFascistCheck(text)
179
+            password = cracklib.VeryFascistCheck(text)
175 180
         except ValueError as message:
176
-            p = str(message)
177
-        return p == text, "Error: " + p
181
+            password = str(message)
182
+        return password == text, "Error: " + password
178 183
 
179 184
     @staticmethod
180 185
     def generate_password_hash(password):
181
-        shadow_password = crypt.crypt(password, "$6$" + "".join([random.choice(string.ascii_letters + string.digits) for _ in range(16)]))
186
+        """Generate hash for the password"""
187
+        shadow_password = crypt.crypt(
188
+            password, "$6$" + "".join(
189
+                [random.choice(
190
+                    string.ascii_letters + string.digits) for _ in range(16)]))
182 191
         return shadow_password
183 192
 
184 193
     def ui_config(self, options_file, maxy, maxx):
185
-        # This represents the installer screen, the bool indicated if I can go back to this window or not
186
-        items = []
187
-        random_id = '%12x' % random.randrange(16**12)
188
-        random_hostname = "photon-" + random_id.strip()
194
+        """Configuration through UI"""
195
+        # This represents the installer screen, the bool indicated if
196
+        # I can go back to this window or not
189 197
         install_config = {'iso_system': False}
190 198
         install_config['ui_install'] = True
199
+        items, select_linux_index = self.add_ui_pages(options_file, maxy, maxx,
200
+                                                      install_config)
201
+        index = 0
202
+        while True:
203
+            result = items[index][0](None)
204
+            if result.success:
205
+                index += 1
206
+                if index == len(items):
207
+                    break
208
+                #Skip linux select screen for ostree installation.
209
+                if index == select_linux_index:
210
+                    if install_config['type'] == 'ostree_server':
211
+                        index += 1
212
+            else:
213
+                index -= 1
214
+                while index >= 0 and items[index][1] is False:
215
+                    index -= 1
216
+                if index < 0:
217
+                    index = 0
218
+                #Skip linux select screen for ostree installation.
219
+                if index == select_linux_index:
220
+                    if install_config['type'] == 'ostree_server':
221
+                        index -= 1
222
+        return install_config
223
+    def add_ui_pages(self, options_file, maxy, maxx, install_config):
224
+        items = []
191 225
         license_agreement = License(maxy, maxx)
192 226
         select_disk = SelectDisk(maxy, maxx, install_config)
193 227
         select_partition = PartitionISO(maxy, maxx, install_config)
194 228
         package_selector = PackageSelector(maxy, maxx, install_config, options_file)
195
-        self.alpha_chars = list(range(65, 91))
196
-        self.alpha_chars.extend(range(97, 123))
197
-        hostname_accepted_chars = self.alpha_chars
198
-        # Adding the numeric chars
199
-        hostname_accepted_chars.extend(range(48, 58))
200
-        # Adding the . and -
201
-        hostname_accepted_chars.extend([ord('.'), ord('-')])
202
-
203 229
         hostname_reader = WindowStringReader(
204 230
             maxy, maxx, 10, 70,
205 231
             'hostname',
206 232
             None, # confirmation error msg if it's a confirmation text
207 233
             None, # echo char
208
-            hostname_accepted_chars, # set of accepted chars
209
-            self.validate_hostname, # validation function of the input
234
+            self.hostname_accepted_chars, # set of accepted chars
235
+            IsoConfig.validate_hostname, # validation function of the input
210 236
             None, # post processing of the input field
211 237
             'Choose the hostname for your system', 'Hostname:', 2, install_config,
212
-            random_hostname,
238
+            self.random_hostname,
213 239
             True)
214 240
         root_password_reader = WindowStringReader(
215 241
             maxy, maxx, 10, 70,
... ...
@@ -223,7 +267,8 @@ class IsoConfig(object):
223 223
         confirm_password_reader = WindowStringReader(
224 224
             maxy, maxx, 10, 70,
225 225
             'password',
226
-            "Passwords don't match, please try again.", # confirmation error msg if it's a confirmation text
226
+            # confirmation error msg if it's a confirmation text
227
+            "Passwords don't match, please try again.",
227 228
             '*', # echo char
228 229
             None, # set of accepted chars
229 230
             None, # validation function of the input
... ...
@@ -243,27 +288,4 @@ class IsoConfig(object):
243 243
         items.append((hostname_reader.get_user_string, True))
244 244
         items.append((root_password_reader.get_user_string, True))
245 245
         items.append((confirm_password_reader.get_user_string, False))
246
-        index = 0
247
-        params = None
248
-        while True:
249
-            result = items[index][0](params)
250
-            if result.success:
251
-                index += 1
252
-                params = result.result
253
-                if index == len(items):
254
-                    break
255
-                #Skip linux select screen for ostree installation.
256
-                if index == select_linux_index:
257
-                    if install_config['type'] == 'ostree_server':
258
-                        index += 1
259
-            else:
260
-                index -= 1
261
-                while index >= 0 and items[index][1] is False:
262
-                    index -= 1
263
-                if index < 0:
264
-                    index = 0
265
-                #Skip linux select screen for ostree installation.
266
-                if index == select_linux_index:
267
-                    if install_config['type'] == 'ostree_server':
268
-                        index -= 1
269
-        return install_config
246
+        return items, select_linux_index
... ...
@@ -6,8 +6,8 @@ PRE_INSTALL = "pre-install"
6 6
 POST_INSTALL = "post-install"
7 7
 
8 8
 LOG_LEVEL_DESC = ["emerg", "alert", "crit", "err", "warning", "notice", "info", "debug"]
9
-LOG_FILE_NAME  = "/var/log/installer.log"
10
-TDNF_LOG_FILE_NAME  = "/var/log/tdnf.log"
9
+LOG_FILE_NAME = "/var/log/installer.log"
10
+TDNF_LOG_FILE_NAME = "/var/log/tdnf.log"
11 11
 TDNF_CMDLINE_FILE_NAME = "/var/log/tdnf.cmdline"
12 12
 KS_POST_INSTALL_LOG_FILE_NAME = "/var/log/installer-kickstart.log"
13 13
 SIGNATURE   = "localhost echo"
... ...
@@ -21,8 +21,8 @@ LOG_INFO    = 6
21 21
 LOG_DEBUG   = 7
22 22
 
23 23
 default_partitions = [
24
-                        {"mountpoint": "/", "size": 0, "filesystem": "ext4"},
25
-                     ]
24
+    {"mountpoint": "/", "size": 0, "filesystem": "ext4"},
25
+    ]
26 26
 
27 27
 def partition_compare(p):
28 28
     if 'mountpoint' in p:
... ...
@@ -36,7 +36,7 @@ def partition_disk(disk, partitions):
36 36
     output = open(os.devnull, 'w')
37 37
 
38 38
     # Clear the disk
39
-    process = subprocess.Popen(['sgdisk', '-o', '-g', disk], stderr = output, stdout = output)
39
+    process = subprocess.Popen(['sgdisk', '-o', '-g', disk], stderr=output, stdout=output)
40 40
     retval = process.wait()
41 41
     if retval != 0:
42 42
         log(LOG_ERROR, "Failed clearing disk {0}".format(disk))
... ...
@@ -58,7 +58,7 @@ def partition_disk(disk, partitions):
58 58
     # Adding the known size partitions
59 59
     for partition in partitions:
60 60
         if partition['size'] == 0:
61
-            # Can not have more than 1 extensible partition 
61
+            # Can not have more than 1 extensible partition
62 62
             if extensible_partition != None:
63 63
                 log(LOG_ERROR, "Can not have more than 1 extensible partition")
64 64
                 return None
... ...
@@ -80,13 +80,13 @@ def partition_disk(disk, partitions):
80 80
     partition_cmd.extend(['-p', disk])
81 81
 
82 82
     # Run the partitioning command
83
-    process = subprocess.Popen(partition_cmd, stderr = output, stdout = output)
83
+    process = subprocess.Popen(partition_cmd, stderr=output, stdout=output)
84 84
     retval = process.wait()
85 85
     if retval != 0:
86 86
         log(LOG_ERROR, "Faild partition disk, command: {0}". format(partition_cmd))
87 87
         return None
88 88
 
89
-    process = subprocess.Popen(['sgdisk', '-t1' + grub_flag, disk], stderr = output, stdout = output)
89
+    process = subprocess.Popen(['sgdisk', '-t1' + grub_flag, disk], stderr=output, stdout=output)
90 90
     retval = process.wait()
91 91
     if retval != 0:
92 92
         log(LOG_ERROR, "Failed to setup grub partition")
... ...
@@ -103,25 +103,27 @@ def partition_disk(disk, partitions):
103 103
                 partitions_data['boot_partition_number'] = partition['partition_number']
104 104
                 partitions_data['bootdirectory'] = '/'
105 105
         if partition['filesystem'] == "swap":
106
-            process = subprocess.Popen(['mkswap', partition['path']], stderr = output, stdout = output)
106
+            process = subprocess.Popen(['mkswap', partition['path']], stderr=output, stdout=output)
107 107
             retval = process.wait()
108 108
             if retval != 0:
109 109
                 log(LOG_ERROR, "Failed to create swap partition @ {}".format(partition['path']))
110 110
                 return None
111 111
         else:
112 112
             mkfs_cmd = ['mkfs', '-t', partition['filesystem'], partition['path']]
113
-            process = subprocess.Popen(mkfs_cmd, stderr = output, stdout = output)
113
+            process = subprocess.Popen(mkfs_cmd, stderr=output, stdout=output)
114 114
             retval = process.wait()
115 115
             if retval != 0:
116
-                log(LOG_ERROR, "Failed to format {} partition @ {}".format(partition['filesystem'], partition['path']))
116
+                log(LOG_ERROR,
117
+                    "Failed to format {} partition @ {}".format(partition['filesystem'],
118
+                                                                partition['path']))
117 119
                 return None
118 120
 
119 121
     # Check if there is no root partition
120
-    if not 'root' in partitions_data:
122
+    if 'root' not in partitions_data:
121 123
         log(LOG_ERROR, "There is no partition assigned to root '/'")
122 124
         return None
123 125
 
124
-    if not 'boot' in partitions_data:
126
+    if 'boot' not in partitions_data:
125 127
         partitions_data['boot'] = partitions_data['root']
126 128
         partitions_data['boot_partition_number'] = partitions_data['root_partition_number']
127 129
         partitions_data['bootdirectory'] = '/boot/'
... ...
@@ -130,9 +132,9 @@ def partition_disk(disk, partitions):
130 130
 
131 131
     return partitions_data
132 132
 
133
-def replace_string_in_file(filename,  search_string,  replace_string):
133
+def replace_string_in_file(filename, search_string, replace_string):
134 134
     with open(filename, "r") as source:
135
-        lines=source.readlines()
135
+        lines = source.readlines()
136 136
 
137 137
     with open(filename, "w") as destination:
138 138
         for line in lines:
... ...
@@ -145,7 +147,8 @@ def log(type, message):
145 145
     return retval
146 146
 
147 147
 def dump(type, filename):
148
-    command = "journalctl -p {0} | grep --line-buffered \"{1}\" > {2}".format(LOG_LEVEL_DESC[type], SIGNATURE, filename)
148
+    command = ("journalctl -p {0} | grep --line-buffered \"{1}\" > {2}"
149
+               .format(LOG_LEVEL_DESC[type], SIGNATURE, filename))
149 150
     process = subprocess.Popen([command], shell=True)
150 151
     retval = process.wait()
151 152
     return retval
... ...
@@ -153,5 +156,5 @@ def dump(type, filename):
153 153
 def dump(filename):
154 154
     command = "journalctl | grep --line-buffered \"{0}\" > {1}".format(SIGNATURE, filename)
155 155
     process = subprocess.Popen([command], shell=True)
156
-    retval = process.wait()    
156
+    retval = process.wait()
157 157
     return retval
... ...
@@ -5,7 +5,7 @@ import commons
5 5
 install_phase = commons.POST_INSTALL
6 6
 enabled = True
7 7
 
8
-def execute(name, config, root):
8
+def execute(config, root):
9 9
     if 'postinstall' not in config:
10 10
         return
11 11
     # run the script in the chroot environment
... ...
@@ -13,14 +13,15 @@ def execute(name, config, root):
13 13
 
14 14
     script_file = os.path.join(root, 'etc/tmpfiles.d/postinstall.sh')
15 15
 
16
-    with open(script_file,  'wb') as outfile:
16
+    with open(script_file, 'wb') as outfile:
17 17
         outfile.write("\n".join(script).encode())
18 18
 
19
-    os.chmod(script_file, 0o700);
20
-    with open(commons.KS_POST_INSTALL_LOG_FILE_NAME,"w") as logfile:
21
-        process = subprocess.Popen(["./mk-run-chroot.sh", '-w', root, "/etc/tmpfiles.d/postinstall.sh"],
22
-            stdout=logfile,stderr=logfile)
19
+    os.chmod(script_file, 0o700)
20
+    with open(commons.KS_POST_INSTALL_LOG_FILE_NAME, "w") as logfile:
21
+        process = subprocess.Popen(["./mk-run-chroot.sh", '-w', root,
22
+                                    "/etc/tmpfiles.d/postinstall.sh"],
23
+                                   stdout=logfile, stderr=logfile)
23 24
         retval = process.wait()
24
-        if retval==0:
25
+        if retval == 0:
25 26
             return True
26 27
         return False
... ...
@@ -1,11 +1,11 @@
1 1
 import os
2
-import commons
3 2
 import random
3
+import commons
4 4
 
5 5
 install_phase = commons.POST_INSTALL
6 6
 enabled = True
7 7
 
8
-def execute(name, config, root):
8
+def execute(config, root):
9 9
     hostname = config['hostname']
10 10
 
11 11
     hostname_file = os.path.join(root, 'etc/hostname')
... ...
@@ -1,26 +1,25 @@
1 1
 import os
2
-import commons
3 2
 import crypt
4 3
 import random
5 4
 import string
5
+import commons
6 6
 
7 7
 install_phase = commons.POST_INSTALL
8 8
 enabled = True
9 9
 
10
-def execute(name, config, root):
10
+def execute(config, root):
11 11
     shadow_password = config['password']
12 12
 
13 13
     passwd_filename = os.path.join(root, 'etc/passwd')
14 14
     shadow_filename = os.path.join(root, 'etc/shadow')
15
-    
15
+
16 16
     #replace root blank password in passwd file to point to shadow file
17
-    commons.replace_string_in_file(passwd_filename,  "root::", "root:x:")
17
+    commons.replace_string_in_file(passwd_filename, "root::", "root:x:")
18 18
 
19 19
     if os.path.isfile(shadow_filename) == False:
20 20
         with open(shadow_filename, "w") as destination:
21
-            destination.write("root:"+shadow_password+":")
21
+            destination.write("root:" + shadow_password + ":")
22 22
     else:
23 23
         #add password hash in shadow file
24 24
         commons.replace_string_in_file(shadow_filename, "root::", "root:"+shadow_password+":")
25 25
         commons.replace_string_in_file(shadow_filename, "root:x:", "root:"+shadow_password+":")
26
-
... ...
@@ -5,7 +5,7 @@ import commons
5 5
 install_phase = commons.POST_INSTALL
6 6
 enabled = True
7 7
 
8
-def execute(name, config, root):
8
+def execute(config, root):
9 9
     if 'public_key' not in config:
10 10
         return
11 11
 
... ...
@@ -21,5 +21,6 @@ def execute(name, config, root):
21 21
     os.chmod(authorized_keys_filename, 0o600)
22 22
 
23 23
     # Change the sshd config to allow root login
24
-    process = subprocess.Popen(["sed", "-i", "s/^\\s*PermitRootLogin\s\+no/PermitRootLogin yes/", sshd_config_filename])
24
+    process = subprocess.Popen(["sed", "-i", "s/^\\s*PermitRootLogin\s\+no/PermitRootLogin yes/",
25
+                                sshd_config_filename])
25 26
     return process.wait()