40 |
40 |
41 from solaris_install import run, CalledProcessError |
41 from solaris_install import run, CalledProcessError |
42 from solaris_install.engine import InstallEngine |
42 from solaris_install.engine import InstallEngine |
43 from solaris_install.gui_install.base_screen import BaseScreen, \ |
43 from solaris_install.gui_install.base_screen import BaseScreen, \ |
44 NotOkToProceedError |
44 NotOkToProceedError |
45 from solaris_install.gui_install.gui_install_common import \ |
45 from solaris_install.gui_install.gui_install_common import _, \ |
46 is_discovery_complete, modal_dialog, queue_td_iscsi, \ |
46 is_discovery_complete, modal_dialog, queue_td_iscsi, \ |
47 set_td_results_state, start_td_iscsi, GLADE_ERROR_MSG, \ |
47 set_td_results_state, start_td_iscsi, GLADE_ERROR_MSG, \ |
48 ISCSI_LABEL |
48 ISCSI_LABEL |
49 from solaris_install.gui_install.install_profile import InstallProfile |
49 from solaris_install.gui_install.install_profile import InstallProfile |
50 from solaris_install.logger import INSTALL_LOGGER_NAME |
50 from solaris_install.logger import INSTALL_LOGGER_NAME |
54 from solaris_install.sysconfig.profile.ip_address import IPAddress |
54 from solaris_install.sysconfig.profile.ip_address import IPAddress |
55 |
55 |
56 |
56 |
57 LOGGER = None |
57 LOGGER = None |
58 |
58 |
59 # Strings displayed in GUI |
|
60 INTERNAL_ERROR_MSG = _("Internal error") |
|
61 DISK_DISCOVERY_TITLE = _("Disk Discovery") |
|
62 DISK_DISCOVERY_SUBTITLE = _("What types of disks would you like the " |
|
63 "Installer to discover?") |
|
64 NO_DISK_TYPE_SELECTED_MSG = _("No disk types selected.") |
|
65 SELECT_DISK_TYPE_MSG = _("You must select at least one of the disk types " |
|
66 "to search for.") |
|
67 TARGET_IP_1_FIELD = _("Target IP (#1)") |
|
68 TARGET_IP_2_FIELD = _("Target IP (#2)") |
|
69 TARGET_IP_3_FIELD = _("Target IP (#3)") |
|
70 TARGET_IP_4_FIELD = _("Target IP (#4)") |
|
71 TARGET_LUN_FIELD = _("LUN") |
|
72 NO_INITIATOR_NODE_MSG = _("Could not obtain Initiator Node Name for this host") |
|
73 REQUIRED_FIELD_MISSING_MSG = _("Required field not entered") |
|
74 ENTER_REQUIRED_FIELD_MSG = _("You must enter a value for : ") |
|
75 INVALID_IP_MSG = _("Invalid Target IP address") |
|
76 INVALID_TARGET_IQN_MSG = _("Invalid Target IQN string") |
|
77 INVALID_INITIATOR_IQN_MSG = _("Invalid Initiator IQN string") |
|
78 ENTER_VALID_VALUE_MSG = _("Enter a valid value") |
|
79 CHAP_PASSWORD_INVALID_LENGTH = _("CHAP password must be between 12 and 16 " |
|
80 "characters") |
|
81 CHAP_USERNAME_MISSING = _("CHAP username not specified") |
|
82 CHAP_PASSWORD_MISSING = _("CHAP password not specified") |
|
83 MAPPING_TARGET_MSG = _("Mapping iSCSI Target...") |
|
84 MAPPING_LUN_MSG = _("Mapping iSCSI LUN...") |
|
85 CANNOT_MAP_LUN_MSG = _("Unable to map iSCSI LUN") |
|
86 |
|
87 # Regex for iSCSI Qualified Names |
59 # Regex for iSCSI Qualified Names |
88 IQN_RE = re.compile("iqn\.\d{4}\-\d{2}\.\w+\.\w+", re.I) |
60 IQN_RE = re.compile("iqn\.\d{4}\-\d{2}\.\w+\.\w+", re.I) |
89 |
61 |
90 |
62 |
91 class DiskDiscoveryScreen(BaseScreen): |
63 class DiskDiscoveryScreen(BaseScreen): |
92 ''' |
64 ''' |
93 The Disk Discovery screen. |
65 The Disk Discovery screen. |
94 ''' |
66 ''' |
|
67 |
|
68 # Strings displayed in GUI |
|
69 INTERNAL_ERROR_MSG = _("Internal error") |
|
70 DISK_DISCOVERY_TITLE = _("Disk Discovery") |
|
71 DISK_DISCOVERY_SUBTITLE = _("What types of disks would you like the " |
|
72 "Installer to discover?") |
|
73 NO_DISK_TYPE_SELECTED_MSG = _("No disk types selected.") |
|
74 SELECT_DISK_TYPE_MSG = _("You must select at least one of the disk types " |
|
75 "to search for.") |
|
76 TARGET_IP_1_FIELD = _("Target IP (#1)") |
|
77 TARGET_IP_2_FIELD = _("Target IP (#2)") |
|
78 TARGET_IP_3_FIELD = _("Target IP (#3)") |
|
79 TARGET_IP_4_FIELD = _("Target IP (#4)") |
|
80 TARGET_LUN_FIELD = _("LUN") |
|
81 NO_INITIATOR_NODE_MSG = _("Could not obtain Initiator Node Name for " |
|
82 "this host") |
|
83 REQUIRED_FIELD_MISSING_MSG = _("Required field not entered") |
|
84 ENTER_REQUIRED_FIELD_MSG = _("You must enter a value for : ") |
|
85 INVALID_IP_MSG = _("Invalid Target IP address") |
|
86 INVALID_TARGET_IQN_MSG = _("Invalid Target IQN string") |
|
87 INVALID_INITIATOR_IQN_MSG = _("Invalid Initiator IQN string") |
|
88 ENTER_VALID_VALUE_MSG = _("Enter a valid value") |
|
89 CHAP_PASSWORD_INVALID_LENGTH = _("CHAP password must be between 12 and 16 " |
|
90 "characters") |
|
91 CHAP_USERNAME_MISSING = _("CHAP username not specified") |
|
92 CHAP_PASSWORD_MISSING = _("CHAP password not specified") |
|
93 MAPPING_TARGET_MSG = _("Mapping iSCSI Target...") |
|
94 MAPPING_LUN_MSG = _("Mapping iSCSI LUN...") |
|
95 CANNOT_MAP_LUN_MSG = _("Unable to map iSCSI LUN") |
95 |
96 |
96 def __init__(self, builder): |
97 def __init__(self, builder): |
97 ''' Initializer method - called from constructor. |
98 ''' Initializer method - called from constructor. |
98 |
99 |
99 Params: |
100 Params: |
316 log_pw = None |
319 log_pw = None |
317 LOGGER.info("CHAP Password: %s", log_pw) |
320 LOGGER.info("CHAP Password: %s", log_pw) |
318 |
321 |
319 # ERROR - required fields must be entered |
322 # ERROR - required fields must be entered |
320 required_fields = { |
323 required_fields = { |
321 self._discovery_target_ip_1_entry: TARGET_IP_1_FIELD, |
324 self._discovery_target_ip_1_entry: self.TARGET_IP_1_FIELD, |
322 self._discovery_target_ip_2_entry: TARGET_IP_2_FIELD, |
325 self._discovery_target_ip_2_entry: self.TARGET_IP_2_FIELD, |
323 self._discovery_target_ip_3_entry: TARGET_IP_3_FIELD, |
326 self._discovery_target_ip_3_entry: self.TARGET_IP_3_FIELD, |
324 self._discovery_target_ip_4_entry: TARGET_IP_4_FIELD, |
327 self._discovery_target_ip_4_entry: self.TARGET_IP_4_FIELD, |
325 } |
328 } |
326 # self._discovery_lun_entry: TARGET_LUN_FIELD, |
329 # self._discovery_lun_entry: self.TARGET_LUN_FIELD, |
327 for field in required_fields: |
330 for field in required_fields: |
328 if not field.get_text(): |
331 if not field.get_text(): |
329 msg = REQUIRED_FIELD_MISSING_MSG |
332 msg = self.REQUIRED_FIELD_MISSING_MSG |
330 LOGGER.error(msg + " : " + required_fields[field]) |
333 LOGGER.error(msg + " : " + required_fields[field]) |
331 modal_dialog(msg, |
334 modal_dialog(msg, |
332 ENTER_REQUIRED_FIELD_MSG + required_fields[field]) |
335 self.ENTER_REQUIRED_FIELD_MSG + required_fields[field]) |
333 field.grab_focus() |
336 field.grab_focus() |
334 raise NotOkToProceedError(msg) |
337 raise NotOkToProceedError(msg) |
335 |
338 |
336 # ERROR - IP must be proper IP address |
339 # ERROR - IP must be proper IP address |
337 try: |
340 try: |
338 IPAddress.convert_address(self._target_ip) |
341 IPAddress.convert_address(self._target_ip) |
339 except ValueError as error: |
342 except ValueError as error: |
340 msg = INVALID_IP_MSG |
343 msg = self.INVALID_IP_MSG |
341 LOGGER.error(msg + " : " + str(error)) |
344 LOGGER.error(msg + " : " + str(error)) |
342 modal_dialog(msg, str(error)) |
345 modal_dialog(msg, str(error)) |
343 self._discovery_target_ip_1_entry.grab_focus() |
346 self._discovery_target_ip_1_entry.grab_focus() |
344 raise NotOkToProceedError(msg) |
347 raise NotOkToProceedError(msg) |
345 |
348 |
346 # ERROR - Initiator Name must match regular expression |
349 # ERROR - Initiator Name must match regular expression |
347 if self._initiator_name is not None: |
350 if self._initiator_name is not None: |
348 if IQN_RE.match(self._initiator_name) is None: |
351 if IQN_RE.match(self._initiator_name) is None: |
349 msg = INVALID_INITIATOR_IQN_MSG |
352 msg = self.INVALID_INITIATOR_IQN_MSG |
350 LOGGER.error(msg) |
353 LOGGER.error(msg) |
351 modal_dialog(msg, ENTER_VALID_VALUE_MSG) |
354 modal_dialog(msg, self.ENTER_VALID_VALUE_MSG) |
352 self._discovery_initiator_name_entry.grab_focus() |
355 self._discovery_initiator_name_entry.grab_focus() |
353 raise NotOkToProceedError(msg) |
356 raise NotOkToProceedError(msg) |
354 |
357 |
355 # ERROR - Target name name must match regular expression |
358 # ERROR - Target name name must match regular expression |
356 if self._target_name is not None: |
359 if self._target_name is not None: |
357 if IQN_RE.match(self._target_name) is None: |
360 if IQN_RE.match(self._target_name) is None: |
358 msg = INVALID_TARGET_IQN_MSG |
361 msg = self.INVALID_TARGET_IQN_MSG |
359 LOGGER.error(msg) |
362 LOGGER.error(msg) |
360 modal_dialog(msg, ENTER_VALID_VALUE_MSG) |
363 modal_dialog(msg, self.ENTER_VALID_VALUE_MSG) |
361 self._discovery_target_name_entry.grab_focus() |
364 self._discovery_target_name_entry.grab_focus() |
362 raise NotOkToProceedError(msg) |
365 raise NotOkToProceedError(msg) |
363 |
366 |
364 # ERROR - if CHAP name is given, password must also |
367 # ERROR - if CHAP name is given, password must also |
365 # be given, and vice versa |
368 # be given, and vice versa |
366 if self._chap_name and not self._chap_password: |
369 if self._chap_name and not self._chap_password: |
367 msg = CHAP_PASSWORD_MISSING |
370 msg = self.CHAP_PASSWORD_MISSING |
368 LOGGER.error(msg) |
371 LOGGER.error(msg) |
369 modal_dialog(msg, ENTER_VALID_VALUE_MSG) |
372 modal_dialog(msg, self.ENTER_VALID_VALUE_MSG) |
370 self._discovery_chap_pass_entry.grab_focus() |
373 self._discovery_chap_pass_entry.grab_focus() |
371 raise NotOkToProceedError(msg) |
374 raise NotOkToProceedError(msg) |
372 if self._chap_password and not self._chap_name: |
375 if self._chap_password and not self._chap_name: |
373 msg = CHAP_USERNAME_MISSING |
376 msg = self.CHAP_USERNAME_MISSING |
374 LOGGER.error(msg) |
377 LOGGER.error(msg) |
375 modal_dialog(msg, ENTER_VALID_VALUE_MSG) |
378 modal_dialog(msg, self.ENTER_VALID_VALUE_MSG) |
376 self._discovery_chap_name_entry.grab_focus() |
379 self._discovery_chap_name_entry.grab_focus() |
377 raise NotOkToProceedError(msg) |
380 raise NotOkToProceedError(msg) |
378 |
381 |
379 # ERROR - CHAP password must be correct length |
382 # ERROR - CHAP password must be correct length |
380 if self._chap_password is not None: |
383 if self._chap_password is not None: |
381 if not 12 <= len(self._chap_password) <= 16: |
384 if not 12 <= len(self._chap_password) <= 16: |
382 msg = CHAP_PASSWORD_INVALID_LENGTH |
385 msg = self.CHAP_PASSWORD_INVALID_LENGTH |
383 LOGGER.error(msg) |
386 LOGGER.error(msg) |
384 modal_dialog(msg, ENTER_VALID_VALUE_MSG) |
387 modal_dialog(msg, self.ENTER_VALID_VALUE_MSG) |
385 self._discovery_chap_pass_entry.grab_focus() |
388 self._discovery_chap_pass_entry.grab_focus() |
386 raise NotOkToProceedError(msg) |
389 raise NotOkToProceedError(msg) |
387 |
390 |
388 # ERROR - must be able to connect to LUN to verify iSCSI disk |
391 # ERROR - must be able to connect to LUN to verify iSCSI disk |
389 # teardown any currently-configured Iscsis before trying |
392 # teardown any currently-configured Iscsis before trying |
424 # in a separate thread (otherwise the GUI would appear |
427 # in a separate thread (otherwise the GUI would appear |
425 # unresponsive and the user may think it has hung). |
428 # unresponsive and the user may think it has hung). |
426 self.set_back_next(back_sensitive=False, next_sensitive=False) |
429 self.set_back_next(back_sensitive=False, next_sensitive=False) |
427 if iscsi.target_lun is not None: |
430 if iscsi.target_lun is not None: |
428 self._discovery_status_label.set_markup( |
431 self._discovery_status_label.set_markup( |
429 '<span font_desc="Bold">%s</span>' % MAPPING_LUN_MSG) |
432 '<span font_desc="Bold">%s</span>' % self.MAPPING_LUN_MSG) |
430 else: |
433 else: |
431 self._discovery_status_label.set_markup( |
434 self._discovery_status_label.set_markup( |
432 '<span font_desc="Bold">%s</span>' % MAPPING_TARGET_MSG) |
435 '<span font_desc="Bold">%s</span>' % |
|
436 self.MAPPING_TARGET_MSG) |
433 self._discovery_status_label.show() |
437 self._discovery_status_label.show() |
434 thread = SetupIscsiThread(iscsi) |
438 thread = SetupIscsiThread(iscsi) |
435 # Keep passing control back to Gtk+ to process its event queue |
439 # Keep passing control back to Gtk+ to process its event queue |
436 # until SetupIscsiThread has completed. |
440 # until SetupIscsiThread has completed. |
437 while thread.is_alive(): |
441 while thread.is_alive(): |