def status(self): """ Where we are in the process """ if self.errors: return _("Error checking software selection") if not self.ready: return _("Processing...") if not self.txid_valid: return _("Source changed - please verify") ## FIXME: # quite ugly, but env isn't getting set to gnome (or anything) by # default, and it really should be so we can maintain consistency # with graphical behavior if self._selection >= 0 and not self.environment \ and not self._kickstarted: self.apply() if not self.environment: # Ks installs with %packages will have an env selected, unless # they did an install without a desktop environment. This should # catch that one case. if self._kickstarted: return _("Custom software selected") return _("Nothing selected") return self.payload.environmentDescription(self.environment)[0]
def _main_loop_handleException(self, dump_info): """ Helper method with one argument only so that it can be registered with GLib.idle_add() to run on idle or called from a handler. :type dump_info: an instance of the meh.DumpInfo class """ ty = dump_info.exc_info.type value = dump_info.exc_info.value if (issubclass(ty, blivet.errors.StorageError) and value.hardware_fault) or ( issubclass(ty, OSError) and value.errno == errno.EIO ): # hardware fault or '[Errno 5] Input/Output error' hw_error_msg = _( "The installation was stopped due to what " "seems to be a problem with your hardware. " "The exact error message is:\n\n%s.\n\n " "The installer will now terminate." ) % str(value) self.intf.messageWindow(_("Hardware error occured"), hw_error_msg) sys.exit(0) elif isinstance(value, blivet.errors.UnusableConfigurationError): sys.exit(0) else: super(AnacondaExceptionHandler, self).handleException(dump_info) return False
def _update_summary(self): """ Update the summary based on the UI. """ count = 0 capacity = 0 free = Size(0) # pass in our disk list so hidden disks' free space is available free_space = self.storage.getFreeSpace(disks=self.disks) selected = [d for d in self.disks if d.name in self.selected_disks] for disk in selected: capacity += disk.size free += free_space[disk.name][0] count += 1 summary = (P_(("%d disk selected; %s capacity; %s free ..."), ("%d disks selected; %s capacity; %s free ..."), count) % (count, str(Size(capacity)), free)) if len(self.disks) == 0: summary = _("No disks detected. Please shut down the computer, connect at least one disk, and restart to complete installation.") elif count == 0: summary = (_("No disks selected; please select at least one disk to install to.")) # Append storage errors to the summary if self.errors: summary = summary + "\n" + "\n".join(self.errors) elif self.warnings: summary = summary + "\n" + "\n".join(self.warnings) return summary
def initialize(self, actions): for (i, action) in enumerate(actions, start=1): mountpoint = "" if action.type in [ACTION_TYPE_DESTROY, ACTION_TYPE_RESIZE]: typeString = """<span foreground='red'>%s</span>""" % \ escape_markup(action.type_desc.title()) else: typeString = """<span foreground='green'>%s</span>""" % \ escape_markup(action.type_desc.title()) if action.obj == ACTION_OBJECT_FORMAT: mountpoint = getattr(action.device.format, "mountpoint", "") if hasattr(action.device, "description"): desc = _("%(description)s (%(deviceName)s)") % {"deviceName": action.device.name, "description": action.device.description} serial = action.device.serial elif hasattr(action.device, "disk"): desc = _("%(deviceName)s on %(container)s") % {"deviceName": action.device.name, "container": action.device.disk.description} serial = action.device.disk.serial else: desc = action.device.name serial = action.device.serial self._store.append([i, typeString, action.object_type_string, desc, mountpoint, serial])
def refresh(self, args=None): NormalTUISpoke.refresh(self, args) # Join the initialization thread to block on it # This print is foul. Need a better message display print(_(PAYLOAD_STATUS_PROBING_STORAGE)) threadMgr.wait(THREAD_STORAGE_WATCHER) # synchronize our local data store with the global ksdata # Commment out because there is no way to select a disk right # now without putting it in ksdata. Seems wrong? #self.selected_disks = self.data.ignoredisk.onlyuse[:] self.autopart = self.data.autopart.autopart message = self._update_summary() # loop through the disks and present them. for disk in self.disks: disk_info = self._format_disk_info(disk) c = CheckboxWidget(title="%i) %s" % (self.disks.index(disk) + 1, disk_info), completed=(disk.name in self.selected_disks)) self._window += [c, ""] # if we have more than one disk, present an option to just # select all disks if len(self.disks) > 1: c = CheckboxWidget(title="%i) %s" % (len(self.disks) + 1, _("Select all")), completed=(self.selection == len(self.disks))) self._window += [c, ""] self._window += [TextWidget(message), ""] return True
def refresh(self, args=None): """ Refresh screen. """ self._load_new_devices() EditTUISpoke.refresh(self, args) summary = self._summary_text() self._window += [TextWidget(summary), ""] hostname = _("Host Name: %s\n") % self.data.network.hostname self._window += [TextWidget(hostname), ""] current_hostname = _("Current host name: %s\n") % network.current_hostname() self._window += [TextWidget(current_hostname), ""] # if we have any errors, display them while len(self.errors) > 0: self._window += [TextWidget(self.errors.pop()), ""] def _prep(i, w): """ Mangle our text to make it look pretty on screen. """ number = TextWidget("%2d)" % (i + 1)) return ColumnWidget([(4, [number]), (None, [w])], 1) _opts = [_("Set host name")] for devname in self.supported_devices: _opts.append(_("Configure device %s") % devname) text = [TextWidget(o) for o in _opts] # make everything presentable on screen choices = [_prep(i, w) for i, w in enumerate(text)] displayed = ColumnWidget([(78, choices)], 1) self._window += [displayed, ""] return True
def status(self): if len(self.data.user.userList) == 0: return _("No user will be created") elif self._wheel.name in self.data.user.userList[0].groups: return _("Administrator %s will be created") % self.data.user.userList[0].name else: return _("User %s will be created") % self.data.user.userList[0].name
def status(self): if self.errors: return _("Error setting up software source") elif not self._ready: return _("Processing...") else: return self._repo_status()
def _activated_device_msg(self, devname): msg = _("Wired (%(interface_name)s) connected\n") \ % {"interface_name": devname} ipv4config = nm.nm_device_ip_config(devname, version=4) ipv6config = nm.nm_device_ip_config(devname, version=6) if ipv4config and ipv4config[0]: addr_str, prefix, gateway_str = ipv4config[0][0] netmask_str = network.prefix2netmask(prefix) dnss_str = ",".join(ipv4config[1]) else: addr_str = dnss_str = gateway_str = netmask_str = "" msg += _(" IPv4 Address: %(addr)s Netmask: %(netmask)s Gateway: %(gateway)s\n") % \ {"addr": addr_str, "netmask": netmask_str, "gateway": gateway_str} msg += _(" DNS: %s\n") % dnss_str if ipv6config and ipv6config[0]: for ipv6addr in ipv6config[0]: addr_str, prefix, gateway_str = ipv6addr # Do not display link-local addresses if not addr_str.startswith("fe80:"): msg += _(" IPv6 Address: %(addr)s/%(prefix)d\n") % \ {"addr": addr_str, "prefix": prefix} dnss_str = ",".join(ipv6config[1]) return msg
def refresh(self, args=None): """args is None if we want a list of zones or "zone" to show all timezones in that zone.""" NormalTUISpoke.refresh(self, args) if args and args in self._timezones: self._window += [TextWidget(_("Available timezones in region %s") % args)] displayed = [TextWidget(z) for z in self._timezones[args]] else: self._window += [TextWidget(_("Available regions"))] displayed = [TextWidget(z) for z in self._regions] def _prep(i, w): number = TextWidget("%2d)" % (i + 1)) return ColumnWidget([(4, [number]), (None, [w])], 1) # split zones to three columns middle = len(displayed) / 3 left = [_prep(i, w) for i, w in enumerate(displayed) if i <= middle] center = [_prep(i, w) for i, w in enumerate(displayed) if i > middle and i <= 2*middle] right = [_prep(i, w) for i, w in enumerate(displayed) if i > 2*middle] c = ColumnWidget([(24, left), (24, center), (24, right)], 3) self._window.append(c) return True
def check_password_empty(self, inputcheck): """Check whether a password has been specified at all. This check is used for both the password and the confirmation. """ # If the password was set by kickstart, skip the strength check # pylint: disable=no-member if self.input_kickstarted and not self.policy.changesok: return InputCheck.CHECK_OK # Skip the check if no password is required if (not self.input_enabled) or self.input_kickstarted: return InputCheck.CHECK_OK # Also skip the check if the policy says that an empty password is fine # pylint: disable=no-member elif self.policy.emptyok: return InputCheck.CHECK_OK elif not self.get_input(inputcheck.input_obj): # pylint: disable=no-member if self.policy.strict: return _(constants.PASSWORD_EMPTY_ERROR) else: if self.waive_clicks > 1: return InputCheck.CHECK_OK else: return "%s %s" % (_(constants.PASSWORD_EMPTY_ERROR), _(constants.PASSWORD_DONE_TWICE)) else: return InputCheck.CHECK_OK
def on_info_bar_clicked(self, *args): if self.errors: label = _("The following errors were encountered when checking your storage " "configuration. You can modify your storage layout or quit the " "installer.") dialog = DetailedErrorDialog(self.data, buttons=[_("_Quit"), _("_Modify Storage Layout")], label=label) with enlightbox(self.window, dialog.window): errors = "\n".join(self.errors) dialog.refresh(errors) rc = dialog.run() dialog.window.destroy() if rc == 0: # Quit. sys.exit(0) elif self.warnings: label = _("The following warnings were encountered when checking your storage " "configuration. These are not fatal, but you may wish to make " "changes to your storage layout.") dialog = DetailedErrorDialog(self.data, buttons=[_("_OK")], label=label) with enlightbox(self.window, dialog.window): warnings = "\n".join(self.warnings) dialog.refresh(warnings) rc = dialog.run() dialog.window.destroy()
def connectToView(self): """Attempt to connect to self.vncconnecthost""" maxTries = 10 self.log.info(_("Attempting to connect to vnc client on host %s..."), self.vncconnecthost) if self.vncconnectport != "": hostarg = self.vncconnecthost + ":" + self.vncconnectport else: hostarg = self.vncconnecthost vncconfigcommand = [self.root+"/usr/bin/vncconfig", "-display", ":%s" % constants.X_DISPLAY_NUMBER, "-connect", hostarg] for _i in range(maxTries): vncconfp = iutil.startProgram(vncconfigcommand, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # vncconfig process err = vncconfp.communicate()[1].decode("utf-8") if err == '': self.log.info(_("Connected!")) return True elif err.startswith("connecting") and err.endswith("failed\n"): self.log.info(_("Will try to connect again in 15 seconds...")) time.sleep(15) continue else: log.critical(err) iutil.ipmi_abort(scripts=self.anaconda.ksdata.scripts) sys.exit(1) self.log.error(P_("Giving up attempting to connect after %d try!\n", "Giving up attempting to connect after %d tries!\n", maxTries), maxTries) return False
def refresh(self): self.disks = getDisks(self.storage.devicetree) # synchronize our local data store with the global ksdata disk_names = [d.name for d in self.disks] # don't put disks with hidden formats in selected_disks self.selected_disks = [d for d in self.data.ignoredisk.onlyuse if d in disk_names] self.autopart = self.data.autopart.autopart self.autoPartType = self.data.autopart.type if self.autoPartType is None: # nkwin7 add begin # keywords: default partitioning; defaultFS; autopart type; # add combo; delete refresh button #reset autopart type to be AUTOPART_TYPE_PLAIN #self.autoPartType = AUTOPART_TYPE_LVM self.autoPartType = AUTOPART_TYPE_PLAIN # nkwin7 end self.encrypted = self.data.autopart.encrypted self.passphrase = self.data.autopart.passphrase self._previous_autopart = self.autopart # First, remove all non-button children. for child in self.localOverviews + self.advancedOverviews: child.destroy() # Then deal with local disks, which are really easy. They need to be # handled here instead of refresh to take into account the user pressing # the rescan button on custom partitioning. for disk in filter(isLocalDisk, self.disks): self._add_disk_overview(disk, self.local_disks_box) # Advanced disks are different. Because there can potentially be a lot # of them, we do not display them in the box by default. Instead, only # those selected in the filter UI are displayed. This means refresh # needs to know to create and destroy overviews as appropriate. for name in self.data.ignoredisk.onlyuse: obj = self.storage.devicetree.getDeviceByName(name, hidden=True) if isLocalDisk(obj): continue self._add_disk_overview(obj, self.specialized_disks_box) # update the selections in the ui for overview in self.localOverviews + self.advancedOverviews: name = overview.get_property("name") # nkwin7 add begin # keywords:indirect and direct; default selected disks; show correctly messages #overview.set_chosen(name in self.selected_disks) # we default select all disks. overview.set_chosen(True) # nkwin7 end self._update_summary() if self.errors: self.set_warning(_("Error checking storage configuration. Click for details.")) elif self.warnings: self.set_warning(_("Warning checking storage configuration. Click for details."))
def _update_summary(self): """ Update the summary based on the UI. """ count = 0 capacity = 0 free = Size(bytes=0) # pass in our disk list so hidden disks' free space is available free_space = self.storage.getFreeSpace(disks=self.disks) selected = [d for d in self.disks if d.name in self.selected_disks] for disk in selected: capacity += disk.size free += free_space[disk.name][0] count += 1 summary = (P_("%d disk selected; %s capacity; %s free", "%d disks selected; %s capacity; %s free", count) % (count, str(Size(spec="%s MB" % capacity)), free)) summary_label = self.builder.get_object("summary_label") summary_label.set_text(summary) summary_label.set_sensitive(count > 0) summary_button = self.builder.get_object("summary_button") summary_button.set_visible(count > 0) if len(self.disks) == 0: self.set_warning(_("No disks detected. Please shut down the computer, connect at least one disk, and restart to complete installation.")) elif count == 0: self.set_warning(_("No disks selected; please select at least one disk to install to.")) else: self.clear_info()
def status(self): if self.data.rootpw.password: return _("Root password is set") elif self.data.rootpw.lock: return _("Root account is disabled") else: return _("Root password is not set")
def refresh(self, required_space, auto_swap, disk_free, fs_free, autoPartType, encrypted): self.autoPartType = autoPartType self.autoPartTypeCombo = self.builder.get_object("options2_combo") self.autoPartTypeCombo.set_active(self.autoPartType) self.encrypted = encrypted self.encryptCheckbutton = self.builder.get_object("encryption2_checkbutton") self.encryptCheckbutton.set_active(self.encrypted) sw_text = self._get_sw_needs_text(required_space, auto_swap) label_text = _("%s The disks you've selected have the following " "amounts of free space:") % sw_text label = self.builder.get_object("options2_label1") label.set_markup(label_text) label.set_tooltip_text(_("Please wait... software metadata still loading.")) label.connect("activate-link", self._modify_sw_link_clicked) self.disk_free_label = self.builder.get_object("options2_disk_free_label") self.fs_free_label = self.builder.get_object("options2_fs_free_label") self._set_free_space_labels(disk_free, fs_free) label_text = _("<b>You don't have enough space available to install " "%s</b>. You can shrink or remove existing partitions " "via our guided reclaim space tool, or you can adjust your " "partitions on your own in the custom partitioning " "interface.") % productName self.builder.get_object("options2_label2").set_markup(label_text) self._add_modify_watcher("options2_label1")
def _do_check(self): self.clear_errors() StorageCheckHandler.errors = [] StorageCheckHandler.warnings = [] # We can't overwrite the main Storage instance because all the other # spokes have references to it that would get invalidated, but we can # achieve the same effect by updating/replacing a few key attributes. self.storage.devicetree._devices = self._storage_playground.devicetree._devices self.storage.devicetree._actions = self._storage_playground.devicetree._actions self.storage.devicetree._hidden = self._storage_playground.devicetree._hidden self.storage.devicetree.names = self._storage_playground.devicetree.names self.storage.roots = self._storage_playground.roots # set up bootloader and check the configuration try: self.storage.set_up_bootloader() except BootLoaderError as e: log.error("storage configuration failed: %s", e) StorageCheckHandler.errors = str(e).split("\n") self.data.bootloader.bootDrive = "" StorageCheckHandler.checkStorage(self) if self.errors: self.set_warning(_("Error checking storage configuration. <a href=\"\">Click for details</a> or press Done again to continue.")) elif self.warnings: self.set_warning(_("Warning checking storage configuration. <a href=\"\">Click for details</a> or press Done again to continue.")) # on_info_bar_clicked requires self._error to be set, so set it to the # list of all errors and warnings that storage checking found. self._error = "\n".join(self.errors + self.warnings) return self._error == ""
def install(self): progressQ.send_message(_('Starting package installation process')) # Add the rpm macros to the global transaction environment for macro in self.rpmMacros: rpm.addMacro(macro[0], macro[1]) if self.install_device: self._setupMedia(self.install_device) try: self.checkSoftwareSelection() self._download_location = self._pick_download_location() except packaging.PayloadError as e: if errors.errorHandler.cb(e) == errors.ERROR_RAISE: _failure_limbo() pkgs_to_download = self._base.transaction.install_set log.info('Downloading packages.') progressQ.send_message(_('Downloading packages')) progress = DownloadProgress() try: self._base.download_packages(pkgs_to_download, progress) except dnf.exceptions.DownloadError as e: msg = 'Failed to download the following packages: %s' % str(e) exc = packaging.PayloadInstallError(msg) if errors.errorHandler.cb(exc) == errors.ERROR_RAISE: _failure_limbo() log.info('Downloading packages finished.') pre_msg = _("Preparing transaction from installation source") progressQ.send_message(pre_msg) queue_instance = multiprocessing.Queue() process = multiprocessing.Process(target=do_transaction, args=(self._base, queue_instance)) process.start() (token, msg) = queue_instance.get() while token not in ('post', 'quit'): if token == 'install': msg = _("Installing %s") % msg progressQ.send_message(msg) (token, msg) = queue_instance.get() if token == 'quit': _failure_limbo() post_msg = _("Performing post-installation setup tasks") progressQ.send_message(post_msg) process.join() self._base.close() if os.path.exists(self._download_location): log.info("Cleaning up downloaded packages: %s", self._download_location) shutil.rmtree(self._download_location) else: # Some installation sources, such as NFS, don't need to download packages to # local storage, so the download location might not always exist. So for now # warn about this, at least until the RFE in bug 1193121 is implemented and # we don't have to care about clearing the download location ourselves. log.warning("Can't delete nonexistent download location: %s", self._download_location)
def refresh(self, args=None): NormalTUISpoke.refresh(self, args) # check if the storage refresh thread is running if threadMgr.get(THREAD_STORAGE_WATCHER): # storage refresh is running - just report it # so that the user can refresh until it is done # TODO: refresh once the thread is done ? message = _(PAYLOAD_STATUS_PROBING_STORAGE) self._window += [TextWidget(message), ""] return True # check if there are any mountable devices if self._mountable_devices: def _prep(i, w): """ Mangle our text to make it look pretty on screen. """ number = TextWidget("%2d)" % (i + 1)) return ColumnWidget([(4, [number]), (None, [w])], 1) devices = [TextWidget(d[1]) for d in self._mountable_devices] # gnarl and mangle all of our widgets so things look pretty on # screen choices = [_prep(i, w) for i, w in enumerate(devices)] displayed = ColumnWidget([(78, choices)], 1) self._window.append(displayed) else: message = _("No mountable devices found") self._window += [TextWidget(message), ""] return True
def retranslate(self, lang): # Change the translations on labels and buttons that do not have # substitution text. for name in ["pickLanguageLabel", "betaWarnTitle", "betaWarnDesc", "quitButton", "continueButton"]: self._retranslate_one(name) # The welcome label is special - it has text that needs to be # substituted. welcomeLabel = self.builder.get_object("welcomeLabel") if not welcomeLabel in self._origStrings: self._origStrings[welcomeLabel] = welcomeLabel.get_label() before = self._origStrings[welcomeLabel] # pylint: disable-msg=E1103 xlated = _(before) % {"name" : productName.upper(), "version" : productVersion} welcomeLabel.set_label(xlated) # Retranslate the language (filtering) entry's placeholder text languageEntry = self.builder.get_object("languageEntry") if not languageEntry in self._origStrings: self._origStrings[languageEntry] = languageEntry.get_placeholder_text() languageEntry.set_placeholder_text(_(self._origStrings[languageEntry])) # And of course, don't forget the underlying window. self.window.set_property("distribution", distributionText().upper()) self.window.retranslate(lang)
def refresh(self, args=None): """ args is None if we want a list of languages; or, it is a list of all locales for a language. """ NormalTUISpoke.refresh(self, args) if args: self._window += [TextWidget(_("Available locales"))] displayed = [TextWidget(localization.get_english_name(z)) for z in args] else: self._window += [TextWidget(_("Available languages"))] displayed = [TextWidget(z) for z in self._langs] def _prep(i, w): """ make everything look nice """ number = TextWidget("%2d)" % (i + 1)) return ColumnWidget([(4, [number]), (None, [w])], 1) # split zones to three columns middle = len(displayed) / 3 left = [_prep(i, w) for i, w in enumerate(displayed) if i <= middle] center = [_prep(i, w) for i, w in enumerate(displayed) if i > middle and i <= 2*middle] right = [_prep(i, w) for i, w in enumerate(displayed) if i > 2*middle] c = ColumnWidget([(24, left), (24, center), (24, right)], 3) self._window += [c, ""] return True
def verify_partition_format_sizes(storage, constraints, report_error, report_warning): """ Verify that the size of the device is allowed by the format used. :param storage: a storage to check :param constraints: a dictionary of constraints :param report_error: a function for error reporting :param report_warning: a function for warning reporting """ # storage.mountpoints is a property that returns a new dict each time, so # iterating over it is thread-safe. filesystems = storage.mountpoints for (mount, device) in filesystems.items(): problem = filesystems[mount].check_size() if problem < 0: report_error(_("Your %(mount)s partition is too small for " "%(format)s formatting (allowable size is " "%(minSize)s to %(maxSize)s)") % {"mount": mount, "format": device.format.name, "minSize": device.min_size, "maxSize": device.max_size}) elif problem > 0: report_error(_("Your %(mount)s partition is too large for " "%(format)s formatting (allowable size is " "%(minSize)s to %(maxSize)s)") % {"mount": mount, "format": device.format.name, "minSize": device.min_size, "maxSize": device.max_size})
def input(self, args, key): """Override input so that we can launch the VNC password spoke""" try: keyid = int(key) - 1 if 0 <= keyid < len(self._choices): choice = self._choices[keyid] if choice == _(USETEXT): self._usevnc = False else: self._usevnc = True newspoke = VNCPassSpoke(self.app, self.data, self.storage, self.payload, self.instclass) self.app.switch_screen_modal(newspoke) self.apply() self.close() return INPUT_PROCESSED except ValueError: pass # TRANSLATORS: 'q' to quit if key.lower() == C_('TUI|Spoke Navigation', 'q'): d = YesNoDialog(self.app, _(self.app.quit_message)) self.app.switch_screen_modal(d) if d.answer: iutil.ipmi_report(IPMI_ABORTED) if can_touch_runtime_system("Quit and Reboot"): execWithRedirect("systemctl", ["--no-wall", "reboot"]) else: exit(1) else: return key
def verify_root(storage, constraints, report_error, report_warning): """ Verify the root. :param storage: a storage to check :param constraints: a dictionary of constraints :param report_error: a function for error reporting :param report_warning: a function for warning reporting """ root = storage.fsset.root_device if root: if root.size < constraints[STORAGE_MIN_ROOT]: report_warning(_("Your root partition is less than %(size)s " "which is usually too small to install " "%(product)s.") % {'size': constraints[STORAGE_MIN_ROOT], 'product': productName}) else: report_error(_("You have not defined a root partition (/), " "which is required for installation of %s" " to continue.") % (productName,)) if storage.root_device and storage.root_device.format.exists: e = storage.must_format(storage.root_device) if e: report_error(e)
def validate_mountpoint(mountpoint, used_mountpoints, strict=True): if strict: fake_mountpoints = [] else: fake_mountpoints = ["swap", "biosboot", "prepboot"] if mountpoint in used_mountpoints: return _("That mount point is already in use. Try something else?") elif not mountpoint: return _("Please enter a valid mount point.") elif mountpoint in system_mountpoints: return _("That mount point is invalid. Try something else?") elif (lowerASCII(mountpoint) not in fake_mountpoints and ((len(mountpoint) > 1 and mountpoint.endswith("/")) or not mountpoint.startswith("/") or " " in mountpoint or re.search(r'/\.*/', mountpoint) or re.search(r'/\.+$', mountpoint))): # - does not end with '/' unless mountpoint _is_ '/' # - starts with '/' except for "swap", &c # - does not contain spaces # - does not contain pairs of '/' enclosing zero or more '.' # - does not end with '/' followed by one or more '.' return _("That mount point is invalid. Try something else?") else: return ""
def _update_action_buttons(self, row): obj = PartStoreRow(*row) device = self.storage.devicetree.get_device_by_id(obj.id) # Disks themselves may be editable in certain ways, but they are never # shrinkable. self._preserveButton.set_sensitive(obj.editable) self._shrinkButton.set_sensitive(obj.editable and not device.is_disk) self._deleteButton.set_sensitive(obj.editable) self._resizeSlider.set_visible(False) if not obj.editable: return # If the selected filesystem does not support shrinking, make that # button insensitive. self._shrinkButton.set_sensitive(device.resizable) if device.resizable: self._setup_slider(device, Size(obj.target)) # Then, disable the button for whatever action is currently selected. # It doesn't make a lot of sense to allow clicking that. if obj.action == _(PRESERVE): self._preserveButton.set_sensitive(False) elif obj.action == _(SHRINK): self._shrinkButton.set_sensitive(False) self._resizeSlider.set_visible(True) elif obj.action == _(DELETE): self._deleteButton.set_sensitive(False)
def prompt(self, args=None): """ Customize default prompt. """ prompt = NormalTUISpoke.prompt(self, args) prompt.set_message(_("Please select language support to install")) # TRANSLATORS: 'b' to go back prompt.add_option(C_("TUI|Spoke Navigation|Language Support", "b"), _("to return to language list")) return prompt
def _doExecute(self): self._ready = False hubQ.send_not_ready(self.__class__.__name__) # on the off-chance dasdfmt is running, we can't proceed further threadMgr.wait(constants.THREAD_DASDFMT) hubQ.send_message(self.__class__.__name__, _("Saving storage configuration...")) try: doKickstartStorage(self.storage, self.data, self.instclass) except (StorageError, KickstartValueError) as e: log.error("storage configuration failed: %s", e) StorageChecker.errors = str(e).split("\n") hubQ.send_message(self.__class__.__name__, _("Failed to save storage configuration...")) self.data.bootloader.bootDrive = "" self.data.ignoredisk.drives = [] self.data.ignoredisk.onlyuse = [] self.storage.config.update(self.data) self.storage.reset() self.disks = getDisks(self.storage.devicetree) # now set ksdata back to the user's specified config applyDiskSelection(self.storage, self.data, self.selected_disks) except BootLoaderError as e: log.error("BootLoader setup failed: %s", e) StorageChecker.errors = str(e).split("\n") hubQ.send_message(self.__class__.__name__, _("Failed to save storage configuration...")) self.data.bootloader.bootDrive = "" else: if self.autopart: self.run() finally: resetCustomStorageData(self.data) self._ready = True hubQ.send_ready(self.__class__.__name__, True)
def retranslate(self): # Change the translations on labels and buttons that do not have # substitution text. for name in ["pickLanguageLabel", "betaWarnTitle", "betaWarnDesc"]: self._retranslate_one(name) # It would be nice to be able to read the translation context from the # widget, but we live in an imperfect world. # See also: https://bugzilla.gnome.org/show_bug.cgi?id=729066 for name in ["quitButton", "continueButton"]: self._retranslate_one(name, "GUI|Welcome|Beta Warn Dialog") # The welcome label is special - it has text that needs to be # substituted. welcomeLabel = self.builder.get_object("welcomeLabel") welcomeLabel.set_text( _("WELCOME TO %(name)s %(version)s.") % {"name": productName.upper(), "version": productVersion} ) # Retranslate the language (filtering) entry's placeholder text languageEntry = self.builder.get_object("languageEntry") if not languageEntry in self._origStrings: self._origStrings[languageEntry] = languageEntry.get_placeholder_text() languageEntry.set_placeholder_text(_(self._origStrings[languageEntry])) # And of course, don't forget the underlying window. self.window.set_property("distribution", distributionText().upper()) self.window.retranslate()
def _checkStrength(self, inputcheck): if self._pwq_error: return ("dialog-error", _(ERROR_WEAK) % self._pwq_error) else: return InputCheck.CHECK_OK
class TUIHub(TUIObject, common.Hub): """Base Hub class implementing the pyanaconda.ui.common.Hub interface. It uses text based categories to look for relevant Spokes and manages all the spokes it finds to have the proper category. :param categories: list all the spoke categories to be displayed in this Hub :type categories: list of strings :param title: title for this Hub :type title: unicode """ categories = [] title = _("Default HUB title") def __init__(self, app, data, storage, payload, instclass): TUIObject.__init__(self, app, data) common.Hub.__init__(self, data, storage, payload, instclass) self._spokes = {} # holds spokes referenced by their class name self._keys = {} # holds spokes referenced by their user input key self._spoke_count = 0 def setup(self, environment="anaconda"): # look for spokes having category present in self.categories for c in self.categories: spokes = collect_spokes(self.paths["spokes"], c) # sort them according to their priority for s in sorted(spokes, key=lambda s: s.title): # Check if this spoke is to be shown in anaconda if not s.should_run(environment, self.data): continue spoke = s(self.app, self.data, self.storage, self.payload, self.instclass) spoke.initialize() if not spoke.showable: spoke.teardown() del spoke continue if spoke.indirect: continue self._spoke_count += 1 self._keys[self._spoke_count] = spoke self._spokes[spoke.__class__.__name__] = spoke # only schedule the hub if it has some spokes return self._spoke_count != 0 def refresh(self, args=None): """This methods fills the self._window list by all the objects we want shown on this screen. Title and Spokes mostly.""" TUIObject.refresh(self, args) def _prep(i, w): number = tui.TextWidget("%2d)" % i) return tui.ColumnWidget([(3, [number]), (None, [w])], 1) # split spokes to two columns left = [_prep(i, w) for i, w in self._keys.iteritems() if i % 2 == 1] right = [_prep(i, w) for i, w in self._keys.iteritems() if i % 2 == 0] c = tui.ColumnWidget([(39, left), (39, right)], 2) self._window.append(c) return True def input(self, args, key): """Handle user input. Numbers are used to show a spoke, the rest is passed to the higher level for processing.""" try: number = int(key) self.app.switch_screen_with_return(self._keys[number]) return None except (ValueError, KeyError): # If we get a continue, check for unfinished spokes. If unfinished # don't continue # TRANSLATORS: 'c' to continue if key == _('c'): for spoke in self._spokes.values(): if not spoke.completed and spoke.mandatory: print( _("Please complete all spokes before continuing")) return False return key
def startServer(self): self.log.info(_("Starting VNC...")) network.wait_for_connectivity() # Lets call it from here for now. try: self.initialize() except (socket.herror, dbus.DBusException, ValueError) as e: stdoutLog.critical("Could not initialize the VNC server: %s", e) iutil.ipmi_report(constants.IPMI_ABORTED) sys.exit(1) if self.password and (len(self.password) < 6 or len(self.password) > 8): self.changeVNCPasswdWindow() if not self.password: SecurityTypes = "None" rfbauth = "0" else: SecurityTypes = "VncAuth" rfbauth = self.pw_file # Create the password file. self.setVNCPassword() # Lets start the xvnc. xvnccommand = [ XVNC_BINARY_NAME, ":%s" % constants.X_DISPLAY_NUMBER, "-depth", "16", "-br", "IdleTimeout=0", "-auth", "/dev/null", "-once", "DisconnectClients=false", "desktop=%s" % (self.desktop, ), "SecurityTypes=%s" % SecurityTypes, "rfbauth=%s" % rfbauth ] try: iutil.startX(xvnccommand, output_redirect=self.openlogfile()) except OSError: stdoutLog.critical("Could not start the VNC server. Aborting.") iutil.ipmi_report(constants.IPMI_ABORTED) sys.exit(1) self.log.info(_("The VNC server is now running.")) # Lets tell the user what we are going to do. if self.vncconnecthost != "": self.log.warning( _("\n\nYou chose to connect to a listening vncviewer. \n" "This does not require a password to be set. If you \n" "set a password, it will be used in case the connection \n" "to the vncviewer is unsuccessful\n\n")) elif self.password == "": self.log.warning( _("\n\nWARNING!!! VNC server running with NO PASSWORD!\n" "You can use the vncpassword=<password> boot option\n" "if you would like to secure the server.\n\n")) elif self.password != "": self.log.warning( _("\n\nYou chose to execute vnc with a password. \n\n")) else: self.log.warning(_("\n\nUnknown Error. Aborting. \n\n")) iutil.ipmi_report(constants.IPMI_ABORTED) sys.exit(1) # Lets try to configure the vnc server to whatever the user specified if self.vncconnecthost != "": connected = self.connectToView() if not connected: self.VNCListen() else: self.VNCListen() # Start vncconfig for copy/paste self.startVncConfig()
def _show_no_ntp_server_warning(self): self.set_warning(_("You have no working NTP server configured"))
def _show_no_network_warning(self): self.set_warning(_("You need to set up networking first if you "\ "want to use NTP"))
def doConfiguration(storage, payload, ksdata, instClass): willWriteNetwork = not flags.flags.imageInstall and not flags.flags.dirInstall willRunRealmd = ksdata.realm.discovered # configure base, create users, configure addons, initramfs, post-install step_count = 5 # network, maybe if willWriteNetwork: step_count += 1 # if a realm was discovered, # increment the counter as the # real joining step will be executed if willRunRealmd: step_count += 1 if ksdata.snapshot and ksdata.snapshot.has_snapshot(SNAPSHOT_WHEN_POST_INSTALL): step_count += 1 progress_init(step_count) # Now run the execute methods of ksdata that require an installed system # to be present first. with progress_report(_("Configuring installed system")): ksdata.authconfig.execute(storage, ksdata, instClass) ksdata.selinux.execute(storage, ksdata, instClass) ksdata.firstboot.execute(storage, ksdata, instClass) ksdata.services.execute(storage, ksdata, instClass) ksdata.keyboard.execute(storage, ksdata, instClass) ksdata.timezone.execute(storage, ksdata, instClass) ksdata.lang.execute(storage, ksdata, instClass) ksdata.firewall.execute(storage, ksdata, instClass) ksdata.xconfig.execute(storage, ksdata, instClass) ksdata.skipx.execute(storage, ksdata, instClass) if willWriteNetwork: with progress_report(_("Writing network configuration")): ksdata.network.execute(storage, ksdata, instClass) # Creating users and groups requires some pre-configuration. with progress_report(_("Creating users")): createLuserConf(iutil.getSysroot(), algoname=getPassAlgo(ksdata.authconfig.authconfig)) u = Users() ksdata.rootpw.execute(storage, ksdata, instClass, u) ksdata.group.execute(storage, ksdata, instClass, u) ksdata.user.execute(storage, ksdata, instClass, u) ksdata.sshkey.execute(storage, ksdata, instClass, u) with progress_report(_("Configuring addons")): ksdata.addons.execute(storage, ksdata, instClass, u, payload) with progress_report(_("Generating initramfs")): payload.recreateInitrds(force=True) if willRunRealmd: with progress_report(_("Joining realm: %s") % ksdata.realm.discovered): ksdata.realm.execute(storage, ksdata, instClass) with progress_report(_("Running post-installation scripts")): runPostScripts(ksdata.scripts) # setup kexec reboot if requested if flags.flags.kexec: setup_kexec() # Write the kickstart file to the installed system (or, copy the input # kickstart file over if one exists). if flags.flags.nosave_output_ks: # don't write the kickstart file to the installed system if this has # been disabled by the nosave option log.warning("Writing of the output kickstart to installed system has been disabled" " by the nosave option.") else: _writeKS(ksdata) # write out the user interaction config file screen_access.sam.write_out_config_file() if ksdata.snapshot and ksdata.snapshot.has_snapshot(SNAPSHOT_WHEN_POST_INSTALL): with progress_report(N_("Creating snapshots")): ksdata.snapshot.execute(storage, ksdata, instClass) progress_complete()
def doInstall(storage, payload, ksdata, instClass): """Perform an installation. This method takes the ksdata as prepared by the UI (the first hub, in graphical mode) and applies it to the disk. The two main tasks for this are putting filesystems onto disks and installing packages onto those filesystems. """ willRunRealmd = ksdata.realm.join_realm willInstallBootloader = not flags.flags.dirInstall and (not ksdata.bootloader.disabled and ksdata.bootloader != "none") # First save system time to HW clock. if flags.can_touch_runtime_system("save system time to HW clock"): timezone.save_hw_clock(ksdata.timezone) # We really only care about actions that affect filesystems, since # those are the ones that take the most time. steps = len(storage.devicetree.findActions(action_type="create", object_type="format")) + \ len(storage.devicetree.findActions(action_type="resize", object_type="format")) # pre setup phase, pre install, post install steps += 3 # realmd, maybe if willRunRealmd: steps += 1 # bootloader, maybe if willInstallBootloader: steps += 1 # This should be the only thread running, wait for the others to finish if not. if threadMgr.running > 1: progress_init(steps+1) with progress_report(_("Waiting for %s threads to finish") % (threadMgr.running-1)): map(log.debug, ("Thread %s is running" % n for n in threadMgr.names)) threadMgr.wait_all() else: progress_init(steps) with progress_report(_("Setting up the installation environment")): ksdata.firstboot.setup(storage, ksdata, instClass) ksdata.addons.setup(storage, ksdata, instClass, payload) # put custom storage info into ksdata, but not if just assigning mount points if not ksdata.mount.dataList(): storage.updateKSData() # Do partitioning. payload.preStorage() # callbacks for blivet message_clbk = lambda clbk_data: progress_message(clbk_data.msg) step_clbk = lambda clbk_data: progress_step(clbk_data.msg) entropy_wait_clbk = lambda clbk_data: wait_for_entropy(clbk_data.msg, clbk_data.min_entropy, ksdata) callbacks_reg = callbacks.create_new_callbacks_register(create_format_pre=message_clbk, create_format_post=step_clbk, resize_format_pre=message_clbk, resize_format_post=step_clbk, wait_for_entropy=entropy_wait_clbk) turnOnFilesystems(storage, mountOnly=flags.flags.dirInstall, callbacks=callbacks_reg) write_storage_late = (flags.flags.livecdInstall or ksdata.ostreesetup.seen or ksdata.method.method == "liveimg") if not write_storage_late and not flags.flags.dirInstall: storage.write() # # STACKI # # Check to see if we're running as a frontend # import os file = open('/proc/cmdline', 'r') args = file.readline().split() file.close() if 'frontend' in args: # If /export does not exist, create a symlink # to /state/partition1. If /state/partition1 doesn't # exist either, just ignore if not os.path.exists('/mnt/sysimage/export'): if os.path.exists('/mnt/sysimage/state/partition1'): pwd = os.getcwd() os.chdir('/mnt/sysimage') os.symlink('state/partition1', 'export') os.chdir(pwd) # Enable all known repos for repo in payload._yum.repos.repos.values(): payload.enableRepo(repo.id) log.debug('STACKI: repo.id (%s) - %s' % (repo.id, repo.isEnabled())) else: # # need to setup a symbolic link in order to store all the packages # downloaded by lighttpd # cmd = 'rm -rf /install ; ' cmd += 'mkdir -p /mnt/sysimage/install ; ' cmd += 'ln -s /mnt/sysimage/install /install' os.system(cmd) # STACKI # Run %pre-install scripts with the filesystem mounted and no packages with progress_report(_("Running pre-installation scripts")): runPreInstallScripts(ksdata.scripts) # Do packaging. # Discover information about realms to join, # to determine additional packages if willRunRealmd: with progress_report(_("Discovering realm to join")): ksdata.realm.setup() # make name resolution work for rpm scripts in chroot if flags.can_touch_runtime_system("copy /etc/resolv.conf to sysroot"): network.copyFileToPath("/etc/resolv.conf", iutil.getSysroot()) # Check for additional packages ksdata.authconfig.setup() ksdata.firewall.setup() # Setup timezone and add chrony as package if timezone was set in KS # and "-chrony" wasn't in packages section and/or --nontp wasn't set. ksdata.timezone.setup(ksdata) # anaconda requires storage packages in order to make sure the target # system is bootable and configurable, and some other packages in order # to finish setting up the system. packages = storage.packages + ksdata.realm.packages packages += ksdata.authconfig.packages + ksdata.firewall.packages if willInstallBootloader: packages += storage.bootloader.packages if network.is_using_team_device(): packages.append("teamd") # don't try to install packages from the install class' ignored list and the # explicitly excluded ones (user takes the responsibility) packages = [p for p in packages if p not in instClass.ignoredPackages and p not in ksdata.packages.excludedList] payload.preInstall(packages=packages, groups=payload.languageGroups()) payload.install() if write_storage_late and not flags.flags.dirInstall: if iutil.getSysroot() != iutil.getTargetPhysicalRoot(): blivet.setSysroot(iutil.getTargetPhysicalRoot(), iutil.getSysroot()) # Note this changed for RHEL 7.5; see comments in rpmostreepayload.py. payload.prepareMountTargets(storage) storage.write() # Do bootloader. if willInstallBootloader: with progress_report(_("Installing boot loader")): writeBootLoader(storage, payload, instClass, ksdata) with progress_report(_("Performing post-installation setup tasks")): payload.postInstall() progress_complete()
def progress_message(message): progressQ.send_message(_(message)) log.info(message)
def install(self): progress_message(N_('Starting package installation process')) # Add the rpm macros to the global transaction environment for macro in self.rpmMacros: rpm.addMacro(macro[0], macro[1]) if self.install_device: self._setupMedia(self.install_device) try: self.checkSoftwareSelection() self._download_location = self._pick_download_location() except payload.PayloadError as e: if errors.errorHandler.cb(e) == errors.ERROR_RAISE: log.error("Installation failed: %r", e) _failure_limbo() pkgs_to_download = self._base.transaction.install_set log.info('Downloading packages to %s.', self._download_location) progressQ.send_message(_('Downloading packages')) progress = DownloadProgress() try: self._base.download_packages(pkgs_to_download, progress) except dnf.exceptions.DownloadError as e: msg = 'Failed to download the following packages: %s' % str(e) exc = payload.PayloadInstallError(msg) if errors.errorHandler.cb(exc) == errors.ERROR_RAISE: log.error("Installation failed: %r", exc) _failure_limbo() log.info('Downloading packages finished.') pre_msg = (N_("Preparing transaction from installation source")) progress_message(pre_msg) queue_instance = multiprocessing.Queue() process = multiprocessing.Process(target=do_transaction, args=(self._base, queue_instance)) process.start() (token, msg) = queue_instance.get() # When the installation works correctly it will get 'install' updates # followed by a 'post' message and then a 'quit' message. # If the installation fails it will send 'quit' without 'post' while token: if token == 'install': msg = _("Installing %s") % msg progressQ.send_message(msg) elif token == 'log': log.info(msg) elif token == 'post': break # Installation finished successfully elif token == 'quit': msg = ( "Payload error - DNF installation has ended up abruptly: %s" % msg) raise payload.PayloadError(msg) elif token == 'error': exc = payload.PayloadInstallError("DNF error: %s" % msg) if errors.errorHandler.cb(exc) == errors.ERROR_RAISE: log.error("Installation failed: %r", exc) _failure_limbo() (token, msg) = queue_instance.get() post_msg = (N_("Performing post-installation setup tasks")) progress_message(post_msg) process.join() self._base.close() if os.path.exists(self._download_location): log.info("Cleaning up downloaded packages: %s", self._download_location) shutil.rmtree(self._download_location) else: # Some installation sources, such as NFS, don't need to download packages to # local storage, so the download location might not always exist. So for now # warn about this, at least until the RFE in bug 1193121 is implemented and # we don't have to care about clearing the download location ourselves. log.warning("Can't delete nonexistent download location: %s", self._download_location)
def install(self): mainctx = GLib.MainContext.new() mainctx.push_thread_default() cancellable = None gi.require_version("OSTree", "1.0") gi.require_version("RpmOstree", "1.0") from gi.repository import OSTree, RpmOstree ostreesetup = self.data.ostreesetup log.info("executing ostreesetup=%r", ostreesetup) # Initialize the filesystem - this will create the repo as well self._safeExecWithRedirect("ostree", [ "admin", "--sysroot=" + iutil.getTargetPhysicalRoot(), "init-fs", iutil.getTargetPhysicalRoot() ]) # Here, we use the physical root as sysroot, because we haven't # yet made a deployment. sysroot_file = Gio.File.new_for_path(iutil.getTargetPhysicalRoot()) sysroot = OSTree.Sysroot.new(sysroot_file) sysroot.load(cancellable) repo = sysroot.get_repo(None)[1] # We don't support resuming from interrupted installs repo.set_disable_fsync(True) self._remoteOptions = {} if hasattr(ostreesetup, 'nogpg') and ostreesetup.nogpg: self._remoteOptions['gpg-verify'] = GLib.Variant('b', False) if flags.noverifyssl: self._remoteOptions['tls-permissive'] = GLib.Variant('b', True) repo.remote_change(None, OSTree.RepoRemoteChange.ADD_IF_NOT_EXISTS, ostreesetup.remote, ostreesetup.url, GLib.Variant('a{sv}', self._remoteOptions), cancellable) # Variable substitute the ref: https://pagure.io/atomic-wg/issue/299 ref = RpmOstree.varsubst_basearch(ostreesetup.ref) progressQ.send_message(_("Starting pull of %(branchName)s from %(source)s") % \ {"branchName": ref, "source": ostreesetup.remote}) progress = OSTree.AsyncProgress.new() progress.connect('changed', self._pullProgressCb) pull_opts = {'refs': GLib.Variant('as', [ref])} # If we're doing a kickstart, we can at least use the content as a reference: # See <https://github.com/rhinstaller/anaconda/issues/1117> # The first path here is used by <https://pagure.io/fedora-lorax-templates> # and the second by <https://github.com/projectatomic/rpm-ostree-toolbox/> if OSTree.check_version(2017, 8): for path in ['/ostree/repo', '/install/ostree/repo']: if os.path.isdir(path + '/objects'): pull_opts['localcache-repos'] = GLib.Variant('as', [path]) break try: repo.pull_with_options(ostreesetup.remote, GLib.Variant('a{sv}', pull_opts), progress, cancellable) except GLib.GError as e: exn = PayloadInstallError("Failed to pull from repository: %s" % e) log.error(str(exn)) if errors.errorHandler.cb(exn) == errors.ERROR_RAISE: progressQ.send_quit(1) iutil.ipmi_abort(scripts=self.data.scripts) sys.exit(1) log.info("ostree pull: " + (progress.get_status() or "")) progressQ.send_message(_("Preparing deployment of %s") % (ref, )) # Now that we have the data pulled, delete the remote for now. # This will allow a remote configuration defined in the tree # (if any) to override what's in the kickstart. Otherwise, # we'll re-add it in post. Ideally, ostree would support a # pull without adding a remote, but that would get quite # complex. repo.remote_delete(self.data.ostreesetup.remote, None) self._safeExecWithRedirect("ostree", [ "admin", "--sysroot=" + iutil.getTargetPhysicalRoot(), "os-init", ostreesetup.osname ]) admin_deploy_args = [ "admin", "--sysroot=" + iutil.getTargetPhysicalRoot(), "deploy", "--os=" + ostreesetup.osname ] admin_deploy_args.append(ostreesetup.remote + ':' + ref) log.info("ostree admin deploy starting") progressQ.send_message(_("Deployment starting: %s") % (ref, )) self._safeExecWithRedirect("ostree", admin_deploy_args) log.info("ostree admin deploy complete") progressQ.send_message(_("Deployment complete: %s") % (ref, )) # Reload now that we've deployed, find the path to the new deployment sysroot.load(None) deployments = sysroot.get_deployments() assert len(deployments) > 0 deployment = deployments[0] deployment_path = sysroot.get_deployment_directory(deployment) iutil.setSysroot(deployment_path.get_path()) try: self._copyBootloaderData() except (OSError, RuntimeError) as e: exn = PayloadInstallError("Failed to copy bootloader data: %s" % e) log.error(str(exn)) if errors.errorHandler.cb(exn) == errors.ERROR_RAISE: progressQ.send_quit(1) iutil.ipmi_abort(scripts=self.data.scripts) sys.exit(1) mainctx.pop_thread_default()
def preInstall(self, packages=None, groups=None): """ Perform pre-installation tasks. """ super(LiveImagePayload, self).preInstall(packages=packages, groups=groups) progressQ.send_message(_("Installing software") + (" %d%%") % (0, ))
# common string needs to be easy to change import product productName = product.productName productVersion = product.productVersion productArch = product.productArch bugzillaUrl = product.bugUrl isFinal = product.isFinal eulaLocation = "/usr/share/redhat-release/EULA" # for use in device names, eg: "fedora", "rhel" shortProductName = productName.lower() if productName.count(" "): shortProductName = ''.join(s[0] for s in shortProductName.split()) exceptionText = _("An unhandled exception has occurred. This " "is most likely a bug. Please save a copy of " "the detailed exception and file a bug report") if not bugzillaUrl: # this string will be combined with "An unhandled exception"... # the leading space is not a typo. exceptionText += _(" with the provider of this software.") else: # this string will be combined with "An unhandled exception"... # the leading space is not a typo. exceptionText += _(" against anaconda at %s") %(bugzillaUrl,) # DriverDisc Paths DD_ALL = "/tmp/DD" DD_EXTRACTED = re.compile("/lib/modules/[^/]+/updates/DD/(?P<moduledir>.*/)?(?P<modulename>[^/.]+).ko.*") DD_FIRMWARE = "/tmp/DD/lib/firmware" DD_RPMS = "/tmp/DD-*"
def prompt(self, args = None): return(_("\tUse of this product is subject to the license agreement found at %s\n\n\tInstallation complete. Press return to quit") % eulaLocation)
def refresh(self, args=None): """ Refresh window. """ EditTUISpoke.refresh(self, args) message = _("Configuring device %s.") % self.args.device self._window += [TextWidget(message), ""] return True
def __init__(self, *args, **kwargs): # these are all absolutely required. not getting them is fatal. self._disks = kwargs.pop("disks") free = kwargs.pop("free") self.selected = kwargs.pop("selected")[:] self.name = kwargs.pop("name") or "" # make sure it's a string self.device_type = kwargs.pop("device_type") self.storage = kwargs.pop("storage") # these are less critical self.raid_level = kwargs.pop("raid_level", None) or None # not "" self.encrypted = kwargs.pop("encrypted", False) self.exists = kwargs.pop("exists", False) self.size_policy = kwargs.pop("size_policy", SIZE_POLICY_AUTO) self.size = kwargs.pop("size", Size(0)) self._error = None GUIObject.__init__(self, *args, **kwargs) self._grabObjects() GUIDialogInputCheckHandler.__init__(self, self._save_button) # set up the dialog labels with device-type-specific text container_type = get_container_type(self.device_type) title_text = _(CONTAINER_DIALOG_TITLE) % { "container_type": container_type.name.upper() } self._title_label.set_text(title_text) dialog_text = _(CONTAINER_DIALOG_TEXT) % { "container_type": container_type.name.lower() } self._dialog_label.set_text(dialog_text) # populate the dialog widgets self._name_entry.set_text(self.name) # populate the store for disk in self._disks: self._store.append([ disk.description, str(disk.size), str(free[disk.name][0]), disk.serial, disk.id ]) model = self._treeview.get_model() itr = model.get_iter_first() selected_ids = [d.id for d in self.selected] selection = self._treeview.get_selection() while itr: disk_id = model.get_value(itr, 4) if disk_id in selected_ids: selection.select_iter(itr) itr = model.iter_next(itr) # XXX how will this be related to the device encryption setting? self._encryptCheckbutton.set_active(self.encrypted) # set up the raid level combo # XXX how will this be related to the device raid level setting? self._raidStoreFilter.set_visible_func(self._raid_level_visible) self._raidStoreFilter.refilter() self._populate_raid() self._original_size = self.size self._original_size_text = self.size.humanReadable(max_places=2) self._sizeEntry.set_text(self._original_size_text) if self.size_policy == SIZE_POLICY_AUTO: self._sizeCombo.set_active(0) elif self.size_policy == SIZE_POLICY_MAX: self._sizeCombo.set_active(1) else: self._sizeCombo.set_active(2) if self.exists: fancy_set_sensitive(self._name_entry, False) self._treeview.set_sensitive(False) fancy_set_sensitive(self._encryptCheckbutton, False) fancy_set_sensitive(self._sizeCombo, False) self._sizeEntry.set_sensitive(False) # Check that the container name configured is valid self.add_check(self._name_entry, self._checkNameEntry)
def preInstall(self, *args, **kwargs): """ Get image and loopback mount it. This is called after partitioning is setup, we now have space to grab the image. If it is a network source Download it to sysroot and provide feedback during the download (using urlgrabber callback). If it is a file:// source then use the file directly. """ error = None if self.data.method.url.startswith("file://"): self.image_path = self.data.method.url[7:] else: error = self._preInstall_url_image() if error: exn = PayloadInstallError(str(error)) if errorHandler.cb(exn) == ERROR_RAISE: raise exn # Used to make install progress % look correct self._adj_size = os.stat(self.image_path)[stat.ST_SIZE] if self.data.method.checksum: progressQ.send_message(_("Checking image checksum")) sha256 = hashlib.sha256() with open(self.image_path, "rb") as f: while True: data = f.read(1024 * 1024) if not data: break sha256.update(data) filesum = sha256.hexdigest() log.debug("sha256 of %s is %s", self.data.method.url, filesum) if lowerASCII(self.data.method.checksum) != filesum: log.error("%s does not match checksum.", self.data.method.checksum) exn = PayloadInstallError("Checksum of image does not match") if errorHandler.cb(exn) == ERROR_RAISE: raise exn # If this looks like a tarfile, skip trying to mount it if self.is_tarfile: return # Mount the image and check to see if it is a LiveOS/*.img # style squashfs image. If so, move it to IMAGE_DIR and mount the real # root image on INSTALL_TREE rc = blivet.util.mount(self.image_path, INSTALL_TREE, fstype="auto", options="ro") if rc != 0: log.error("mount error (%s) with %s", rc, self.image_path) exn = PayloadInstallError("mount error %s" % rc) if errorHandler.cb(exn) == ERROR_RAISE: raise exn # Nothing more to mount if not os.path.exists(INSTALL_TREE + "/LiveOS"): return # Mount the first .img in the directory on INSTALL_TREE img_files = glob.glob(INSTALL_TREE + "/LiveOS/*.img") if img_files: # move the mount to IMAGE_DIR os.makedirs(IMAGE_DIR, 0o755) # work around inability to move shared filesystems rc = iutil.execWithRedirect("mount", ["--make-rprivate", "/"]) if rc == 0: rc = iutil.execWithRedirect( "mount", ["--move", INSTALL_TREE, IMAGE_DIR]) if rc != 0: log.error("error %s moving mount", rc) exn = PayloadInstallError("mount error %s" % rc) if errorHandler.cb(exn) == ERROR_RAISE: raise exn img_file = IMAGE_DIR + "/LiveOS/" + os.path.basename( sorted(img_files)[0]) rc = blivet.util.mount(img_file, INSTALL_TREE, fstype="auto", options="ro") if rc != 0: log.error("mount error (%s) with %s", rc, img_file) exn = PayloadInstallError("mount error %s with %s" % (rc, img_file)) if errorHandler.cb(exn) == ERROR_RAISE: raise exn source = iutil.eintr_retry_call(os.statvfs, INSTALL_TREE) self.source_size = source.f_frsize * (source.f_blocks - source.f_bfree)
def prompt(self, args=None): return _("Press Enter to exit.")
def initialize(self): NormalSpoke.initialize(self) self.initialize_start() # get object references from the builders self._password_entry = self.builder.get_object("password_entry") self._password_confirmation_entry = self.builder.get_object("password_confirmation_entry") self._password_bar = self.builder.get_object("password_bar") self._password_label = self.builder.get_object("password_label") # set state based on kickstart self.password_kickstarted = self.data.rootpw.seen # Install the password checks: # - Has a password been specified? # - If a password has been specified and there is data in the confirm box, do they match? # - How strong is the password? # - Does the password contain non-ASCII characters? # Setup the password checker for password checking self._checker = input_checking.PasswordChecker( initial_password_content = self.password, initial_password_confirmation_content = self.password_confirmation, policy = input_checking.get_policy(self.data, "root") ) # configure the checker for password checking self.checker.name_of_password = _(constants.NAME_OF_PASSWORD) self.checker.name_of_password_plural = _(constants.NAME_OF_PASSWORD_PLURAL) # remove any placeholder texts if either password or confirmation field changes content from initial state self.checker.password.changed_from_initial_state.connect(self.remove_placeholder_texts) self.checker.password_confirmation.changed_from_initial_state.connect(self.remove_placeholder_texts) # connect UI updates to check results self.checker.checks_done.connect(self._checks_done) # check that the password is not empty self._empty_check = input_checking.PasswordEmptyCheck() # check that the content of the password field & the conformation field are the same self._confirm_check = input_checking.PasswordConfirmationCheck() # regards both fields empty as success to let the user escape self._confirm_check.success_if_confirmation_empty = True # check password validity, quality and strength self._validity_check = input_checking.PasswordValidityCheck() # connect UI updates to validity check results self._validity_check.result.password_score_changed.connect(self.set_password_score) self._validity_check.result.status_text_changed.connect(self.set_password_status) # check if the password contains non-ascii characters self._ascii_check = input_checking.PasswordASCIICheck() # register the individual checks with the checker in proper order # 1) is the password non-empty ? # 2) are both entered passwords the same ? # 3) is the password valid according to the current password checking policy ? # 4) is the password free of non-ASCII characters ? self.checker.add_check(self._empty_check) self.checker.add_check(self._confirm_check) self.checker.add_check(self._validity_check) self.checker.add_check(self._ascii_check) # set placeholders if the password has been kickstarted as we likely don't know # nothing about it and can't really show it in the UI in any meaningful way password_set_message = _("The password was set by kickstart.") if self.password_kickstarted: self.password_entry.set_placeholder_text(password_set_message) self.password_confirmation_entry.set_placeholder_text(password_set_message) # Configure levels for the password bar self._password_bar.add_offset_value("low", 2) self._password_bar.add_offset_value("medium", 3) self._password_bar.add_offset_value("high", 4) # Send ready signal to main event loop hubQ.send_ready(self.__class__.__name__, False) # report that we are done self.initialize_done()
def distributionText(): return _("%(productName)s %(productVersion)s INSTALLATION") % \ {"productName": productName, "productVersion": productVersion}
def get_container_type(device_type): return CONTAINER_TYPES.get(device_type, ContainerType(_("container"), _("container")))
def _downloading_package_md(self): # Reset the error state from previous payloads self._error = False hubQ.send_message(self.__class__.__name__, _(constants.PAYLOAD_STATUS_PACKAGE_MD))
def translated_new_install_name(): return _("New %(name)s %(version)s Installation") % \ {"name" : productName, "version" : productVersion}
def refresh(self): self._back_clicked = False self.disks = getDisks(self.storage.devicetree) # synchronize our local data store with the global ksdata disk_names = [d.name for d in self.disks] self.selected_disks = [ d for d in self.data.ignoredisk.onlyuse if d in disk_names ] # unhide previously hidden disks so that they don't look like being # empty (because of all child devices hidden) self._unhide_disks() self.autopart = self.data.autopart.autopart self.autoPartType = self.data.autopart.type if self.autoPartType is None: self.autoPartType = AUTOPART_TYPE_LVM self.encrypted = self.data.autopart.encrypted self.passphrase = self.data.autopart.passphrase self._previous_autopart = self.autopart # First, remove all non-button children. for child in self.localOverviews + self.advancedOverviews: child.destroy() # Then deal with local disks, which are really easy. They need to be # handled here instead of refresh to take into account the user pressing # the rescan button on custom partitioning. for disk in filter(isLocalDisk, self.disks): # While technically local disks, zFCP devices are specialized # storage and should not be shown here. if disk.type is not "zfcp": self._add_disk_overview(disk, self.local_disks_box) # Advanced disks are different. Because there can potentially be a lot # of them, we do not display them in the box by default. Instead, only # those selected in the filter UI are displayed. This means refresh # needs to know to create and destroy overviews as appropriate. for name in self.data.ignoredisk.onlyuse: if name not in disk_names: continue obj = self.storage.devicetree.getDeviceByName(name, hidden=True) # since zfcp devices may be detected as local disks when added # manually, specifically check the disk type here to make sure # we won't accidentally bypass adding zfcp devices to the disk # overview if isLocalDisk(obj) and obj.type is not "zfcp": continue self._add_disk_overview(obj, self.specialized_disks_box) # update the selections in the ui for overview in self.localOverviews + self.advancedOverviews: name = overview.get_property("name") overview.set_chosen(name in self.selected_disks) # if encrypted is specified in kickstart, select the encryptionCheckbox in the GUI if self.encrypted: self._encrypted.set_active(True) self._customPart.set_active(not self.autopart) self._update_summary() if self.errors: self.set_warning( _("Error checking storage configuration. <a href=\"\">Click for details.</a>" )) elif self.warnings: self.set_warning( _("Warning checking storage configuration. <a href=\"\">Click for details.</a>" ))
def _downloading_group_md(self): hubQ.send_message(self.__class__.__name__, _(constants.PAYLOAD_STATUS_GROUP_MD))
def populate(self, disks): totalDisks = 0 totalReclaimableSpace = Size(0) self._initialFreeSpace = Size(0) self._selectedReclaimableSpace = Size(0) canShrinkSomething = False free_space = self.storage.getFreeSpace(disks=disks) for disk in disks: # First add the disk itself. editable = not disk.protected if disk.partitioned: fstype = "" diskReclaimableSpace = Size(0) else: fstype = disk.format.name diskReclaimableSpace = disk.size itr = self._diskStore.append(None, [ disk.id, "%s %s" % (disk.size.humanReadable(max_places=1), disk.description), fstype, "<span foreground='grey' style='italic'>%s total</span>", _(PRESERVE), editable, TY_NORMAL, self._get_tooltip(disk), int(disk.size), disk.name ]) if disk.partitioned: # Then add all its partitions. for dev in self.storage.devicetree.getChildren(disk): if dev.isExtended and disk.format.logicalPartitions: continue # Devices that are not resizable are still deletable. if dev.resizable: freeSize = dev.size - dev.minSize resizeString = _("%(freeSize)s of %(devSize)s") \ % {"freeSize": freeSize.humanReadable(max_places=1), "devSize": dev.size.humanReadable(max_places=1)} if not dev.protected: canShrinkSomething = True else: freeSize = dev.size resizeString = "<span foreground='grey'>%s</span>" % \ escape_markup(_("Not resizeable")) if dev.protected: ty = TY_PROTECTED else: ty = TY_NORMAL self._diskStore.append(itr, [ dev.id, self._description(dev), dev.format.name, resizeString, _(PRESERVE), not dev.protected, ty, self._get_tooltip(dev), int(dev.size), dev.name ]) diskReclaimableSpace += freeSize # And then add another uneditable line that lists how much space is # already free in the disk. diskFree = free_space[disk.name][0] if diskFree >= Size("1MiB"): freeSpaceString = "<span foreground='grey' style='italic'>%s</span>" % \ escape_markup(_("Free space")) self._diskStore.append(itr, [ disk.id, freeSpaceString, "", "<span foreground='grey' style='italic'>%s</span>" % escape_markup(diskFree.humanReadable(max_places=1)), NOTHING, False, TY_FREE_SPACE, self._get_tooltip(disk), diskFree, "" ]) self._initialFreeSpace += diskFree # And then go back and fill in the total reclaimable space for the # disk, now that we know what each partition has reclaimable. self._diskStore[itr][RECLAIMABLE_COL] = self._diskStore[itr][ RECLAIMABLE_COL] % diskReclaimableSpace totalDisks += 1 totalReclaimableSpace += diskReclaimableSpace self._update_labels(totalDisks, totalReclaimableSpace, 0) description = _( "You can remove existing file systems you no longer need to free up space " "for this installation. Removing a file system will permanently delete all " "of the data it contains.") if canShrinkSomething: description += "\n\n" description += _( "There is also free space available in pre-existing file systems. " "While it's risky and we recommend you back up your data first, you " "can recover that free disk space and make it available for this " "installation below.") self._reclaimDescLabel.set_text(description) self._update_reclaim_button(Size(0))
def on_back_clicked(self, button): # We can't exit early if it looks like nothing has changed because the # user might want to change settings presented in the dialogs shown from # within this method. # Do not enter this method multiple times if user clicking multiple times # on back button if self._back_clicked: return else: self._back_clicked = True # make sure the snapshot of unmodified on-disk-storage model is created if not on_disk_storage.created: on_disk_storage.create_snapshot(self.storage) if self.autopart_missing_passphrase: self._setup_passphrase() NormalSpoke.on_back_clicked(self, button) return # No disks selected? The user wants to back out of the storage spoke. if not self.selected_disks: NormalSpoke.on_back_clicked(self, button) return disk_selection_changed = False if self._last_selected_disks: disk_selection_changed = (self._last_selected_disks != set( self.selected_disks)) # remember the disk selection for future decisions self._last_selected_disks = set(self.selected_disks) if disk_selection_changed: # Changing disk selection is really, really complicated and has # always been causing numerous hard bugs. Let's not play the hero # game and just revert everything and start over again. on_disk_storage.reset_to_snapshot(self.storage) self.disks = getDisks(self.storage.devicetree) else: # Remove all non-existing devices if autopart was active when we last # refreshed. if self._previous_autopart: self._previous_autopart = False self._remove_nonexistant_partitions() # hide disks as requested self._hide_disks() # make sure no containers were split up by the user's disk selection self.clear_info() # if there are some disk selection errors we don't let user to leave the # spoke, so these errors don't have to go to self.errors self.disks_errors = checkDiskSelection(self.storage, self.selected_disks) if self.disks_errors: # The disk selection has to make sense before we can proceed. self.set_error( _("There was a problem with your disk selection. " "Click here for details.")) self._back_clicked = False return if arch.isS390(): # check for unformatted DASDs and launch dasdfmt if any discovered rc = self._check_dasd_formats() if rc == DASD_FORMAT_NO_CHANGE: pass elif rc == DASD_FORMAT_REFRESH: # User hit OK on the dialog self.refresh() elif rc == DASD_FORMAT_RETURN_TO_HUB: # User clicked uri to return to hub. NormalSpoke.on_back_clicked(self, button) return else: # User either hit cancel on the dialog or closed it via escape, # there was no formatting done. self._back_clicked = False return # even if they're not doing autopart, setting autopart.encrypted # establishes a default of encrypting new devices self.encrypted = self._encrypted.get_active() # We might first need to ask about an encryption passphrase. if self.encrypted and not self._setup_passphrase(): self._back_clicked = False return # At this point there are three possible states: # 1) user chose custom part => just send them to the CustomPart spoke # 2) user wants to reclaim some more space => run the ResizeDialog # 3) we are just asked to do autopart => check free space and see if we need # user to do anything more self.autopart = not self._customPart.get_active() disks = [d for d in self.disks if d.name in self.selected_disks] dialog = None if not self.autopart: self.skipTo = "CustomPartitioningSpoke" elif self._reclaim.get_active(): # HINT: change the logic of this 'if' statement if we are asked to # support "reclaim before custom partitioning" # respect disk selection and other choices in the ReclaimDialog self.apply() dialog = ResizeDialog(self.data, self.storage, self.payload) dialog.refresh(disks) else: dialog = self._check_space_and_get_dialog(disks) if dialog: # more dialogs may need to be run based on user choices, but we are # only interested in the final result rc = self._run_dialogs(disks, start_with=dialog) if rc == RESPONSE_OK: # nothing special needed pass elif rc == RESPONSE_CANCEL: # A cancel button was clicked on one of the dialogs. Stay on this # spoke. Generally, this is because the user wants to add more disks. self._back_clicked = False return elif rc == RESPONSE_MODIFY_SW: # The "Fedora software selection" link was clicked on one of the # dialogs. Send the user to the software spoke. self.skipTo = "SoftwareSelectionSpoke" elif rc == RESPONSE_QUIT: # Not enough space, and the user can't do anything about it so # they chose to quit. raise SystemExit("user-selected exit") else: # I don't know how we'd get here, but might as well have a # catch-all. Just stay on this spoke. self._back_clicked = False return if self.autopart: refreshAutoSwapSize(self.storage) self.applyOnSkip = True NormalSpoke.on_back_clicked(self, button)
def run_dasdfmt(self, to_format=None): """ This generates the list of DASDs requiring dasdfmt and runs dasdfmt against them. to_format is an optional list of DASDs to format. This shouldn't be passed if run_dasdfmt is called during a ks installation, and if called during a manual installation, a list of DASDs needs to be passed. """ if not to_format: # go ahead and initialize this to_format = [] # if the storage thread is running, wait on it to complete before taking # any further actions on devices; most likely to occur if user has # zerombr in their ks file threadMgr.wait(THREAD_STORAGE) if flags.automatedInstall: # automated install case unformatted = [] ldl = [] if self.data.zerombr.zerombr: # unformatted DASDs unformatted += make_unformatted_dasd_list( [d.name for d in getDisks(self.storage.devicetree)]) if self.data.clearpart.cdl: # LDL DASDs ldl += [ d.name for d in self.storage.devicetree.dasd if is_ldl_dasd(d.name) ] # combine into one nice list to_format = list(set(unformatted + ldl)) else: # manual install; ask to verify they want to run dasdfmt # prepare our msg strings; copied directly from dasdfmt.glade summary = _( "The following unformatted or LDL DASDs have been " "detected on your system. You can choose to format them " "now with dasdfmt or cancel to leave them unformatted. " "Unformatted DASDs cannot be used during installation.\n\n") warntext = _( "Warning: All storage changes made using the installer will be lost when you choose to format.\n\nProceed to run dasdfmt?\n" ) displaytext = summary + "\n".join( "/dev/" + d for d in to_format) + "\n" + warntext # now show actual prompt; note -- in cmdline mode, auto-answer for # this is 'no', so unformatted and ldl DASDs will remain so unless # zerombr or cdl are added to the ks file question_window = YesNoDialog(self._app, displaytext) self._app.switch_screen_modal(question_window) if not question_window.answer: # no? well fine then, back to the storage spoke with you; return None for disk in to_format: try: print(_("Formatting /dev/%s. This may take a moment.") % disk) format_dasd(disk) except DasdFormatError as err: # Log errors if formatting fails, but don't halt the installer log.error("dasdfmt /dev/%s failed: %s", disk, err) continue # need to make devicetree aware of disk changes self.storage.devicetree.populate() if not flags.automatedInstall: # reinit storage threadMgr.add( AnacondaThread( name=THREAD_STORAGE, target=storageInitialize, args=(self.storage, self.data, self.storage.devicetree.protectedDevNames))) # update the summary screen with the changes self._initialize()
def on_info_bar_clicked(self, *args): if self.disks_errors: label = _( "The following errors were encountered when checking your disk " "selection. You can modify your selection or quit the " "installer.") dialog = DetailedErrorDialog(self.data, buttons=[ C_("GUI|Storage|Error Dialog", "_Quit"), C_("GUI|Storage|Error Dialog", "_Modify Disk Selection") ], label=label) with self.main_window.enlightbox(dialog.window): errors = "\n".join(self.disks_errors) dialog.refresh(errors) rc = dialog.run() dialog.window.destroy() if rc == 0: # Quit. iutil.ipmi_report(constants.IPMI_ABORTED) sys.exit(0) elif self.errors: label = _( "The following errors were encountered when checking your storage " "configuration. You can modify your storage layout or quit the " "installer.") dialog = DetailedErrorDialog(self.data, buttons=[ C_("GUI|Storage|Error Dialog", "_Quit"), C_("GUI|Storage|Error Dialog", "_Modify Storage Layout") ], label=label) with self.main_window.enlightbox(dialog.window): errors = "\n".join(self.errors) dialog.refresh(errors) rc = dialog.run() dialog.window.destroy() if rc == 0: # Quit. iutil.ipmi_report(constants.IPMI_ABORTED) sys.exit(0) elif self.warnings: label = _( "The following warnings were encountered when checking your storage " "configuration. These are not fatal, but you may wish to make " "changes to your storage layout.") dialog = DetailedErrorDialog( self.data, buttons=[C_("GUI|Storage|Warning Dialog", "_OK")], label=label) with self.main_window.enlightbox(dialog.window): warnings = "\n".join(self.warnings) dialog.refresh(warnings) rc = dialog.run() dialog.window.destroy()
def _check_nfs_server(self, user_input, report_func): if ":" not in user_input or len(user_input.split(":")) != 2: report_func(_("Server must be specified as SERVER:/PATH")) return False return True
def _get_tooltip(self, device): if device.protected: return _("This device contains the installation source.") else: return None