From 445ee81865d9764cbee5bf34429e61df7fbdbcfe Mon Sep 17 00:00:00 2001 From: Fedor Zhadaev Date: Thu, 3 Dec 2015 20:04:15 +0300 Subject: [PATCH] Refactored 'save_only' mode * Use common logic for 'normal' and 'save_only' modes - call modules logic in both cases Change-Id: I4ba533c1b7e9eb9e9e4538bec33b0565a8f8f2f0 Co-Authored-By: Fedor Zhadaev Baesed-On-Change-Id: Id54f1229915336b8aebdb36562e06e2596c003f1 Closes-Bug: #1502110 --- fuelmenu/common/network.py | 4 + fuelmenu/fuelmenu.py | 172 +++++++---------------------- fuelmenu/modules/bootstrapimg.py | 3 + fuelmenu/modules/cobblerconf.py | 5 +- fuelmenu/modules/dnsandhostname.py | 6 +- fuelmenu/modules/fueluser.py | 10 +- fuelmenu/modules/interfaces.py | 1 + fuelmenu/modules/ntpsetup.py | 20 +--- fuelmenu/modules/restore.py | 3 + fuelmenu/modules/rootpw.py | 4 + fuelmenu/modules/security.py | 13 +-- fuelmenu/settings.yaml | 9 -- 12 files changed, 81 insertions(+), 169 deletions(-) diff --git a/fuelmenu/common/network.py b/fuelmenu/common/network.py index c18b3c6..31be819 100644 --- a/fuelmenu/common/network.py +++ b/fuelmenu/common/network.py @@ -193,3 +193,7 @@ def upIface(iface): code, _, _ = execute(["ifconfig", iface, "up"]) if code != 0: raise NetworkException("Failed to up interface {0}".format(iface)) + + +def get_iface_info(iface, address_family=netifaces.AF_INET): + return netifaces.ifaddresses(iface)[address_family][0] diff --git a/fuelmenu/fuelmenu.py b/fuelmenu/fuelmenu.py index b336cf7..7c9225c 100755 --- a/fuelmenu/fuelmenu.py +++ b/fuelmenu/fuelmenu.py @@ -16,7 +16,6 @@ from __future__ import absolute_import from fuelmenu.common import dialog -from fuelmenu.common import errors from fuelmenu.common import network from fuelmenu.common import timeout from fuelmenu.common import urwidwrapper as widget @@ -44,12 +43,13 @@ log = logging.getLogger('fuelmenu.loader') class FuelSetup(object): - def __init__(self): + def __init__(self, save_only=False, managed_iface=None): + self.save_only = save_only self.footer = None self.frame = None self.screen = None - self.managediface = network.get_physical_ifaces()[0] self.dns_might_have_changed = False + self.managediface = managed_iface or network.get_physical_ifaces()[0] # Set to true to move all settings to end self.globalsave = True # Tasks to be executed on Apply @@ -122,6 +122,8 @@ class FuelSetup(object): self.draw_child_screen(self.child.screen) def refreshScreen(self): + if self.save_only: + return size = self.screen.get_cols_rows() self.screen.draw_screen(size, self.frame.render(size)) @@ -144,8 +146,8 @@ class FuelSetup(object): self.choices = [m.name for m in self.children] if len(self.children) == 0: - import sys sys.exit(1) + # Build list of choices excluding visible self.visiblechoices = [] for child, choice in zip(self.children, self.choices): @@ -221,7 +223,10 @@ class FuelSetup(object): widget.TextLabel("It is highly recommended to change default " "admin password."), "WARNING!") - self.mainloop.run() + if not self.save_only: + self.mainloop.run() + else: + self._save_only() def exit_program(self, button): # Fix /etc/hosts before quitting @@ -255,7 +260,7 @@ class FuelSetup(object): # Run invisible modules. They may not have screen methods if not module.visible: try: - module.apply(None) + self._save_module(module) except Exception as e: log.error("Unable to save module %s: %s" % (modulename, e)) continue @@ -267,7 +272,7 @@ class FuelSetup(object): % modulename) self.refreshScreen() module.refresh() - if module.apply(None): + if self._save_module(module): log.info("Saving module: %s" % modulename) else: return False, modulename @@ -284,6 +289,31 @@ class FuelSetup(object): return True, None + def _save_module(self, module): + if self.save_only: + if hasattr(module, 'check') and hasattr(module, 'save'): + resp = module.check(None) + module.save(resp) + return True + + return module.apply(None) + + def _save_only(self): + if utils.is_post_deployment(): + print( + "Not updating settings when invoked during post-deployment" + ".\nRun fuelmenu manually to make changes." + ) + sys.exit(0) + + success, module_name = self.global_save() + if not success: + msg = ("Problems with module '{}'." + " Settings have not been saved.".format(module_name)) + log.error(msg) + sys.stderr.write(msg + '\n') + sys.exit(1) + def reload_modules(self): for child in self.children: if hasattr(child, 'load') and callable(child.load): @@ -294,133 +324,12 @@ class FuelSetup(object): self.refreshScreen() -def setup(): +def setup(**kwargs): urwid.web_display.set_preferences("Fuel Setup") # try to handle short web requests quickly if urwid.web_display.handle_short_request(): return - FuelSetup() - - -def save_only(iface, settingsfile=consts.SETTINGS_FILE): - from fuelmenu.common import pwgen - import netifaces - - if utils.is_post_deployment(): - print("Not updating settings when invoked during post-deployment.\n" - "Run fuelmenu manually to make changes.") - sys.exit(0) - - # Calculate and set Static/DHCP pool fields - # Max IPs = net size - 2 (master node + bcast) - try: - ip = netifaces.ifaddresses(iface)[netifaces.AF_INET][0]['addr'] - netmask = netifaces.ifaddresses(iface)[netifaces.AF_INET][0]['netmask'] - mac = netifaces.ifaddresses(iface)[netifaces.AF_LINK][0]['addr'] - except Exception: - print("Interface %s is missing either IP address or netmask" - % (iface)) - sys.exit(1) - net_ip_list = network.getNetwork(ip, netmask) - try: - dhcp_pool = net_ip_list[1:] - dynamic_start = str(dhcp_pool[0]) - dynamic_end = str(dhcp_pool[-1]) - except Exception: - print("Unable to define DHCP pools") - sys.exit(1) - try: - hostname, sep, domain = os.uname()[1].partition('.') - except Exception: - print("Unable to calculate hostname and domain") - sys.exit(1) - try: - dhcptimeout = 5 - dhcp_server_data = network.search_external_dhcp(iface, dhcptimeout) - except errors.NetworkException: - log.error("DHCP scan failed") - dhcp_server_data = [] - - num_dhcp = len(dhcp_server_data) - if num_dhcp == 0: - log.debug("No DHCP servers found") - else: - # Problem exists, but permit user to continue - log.error("%s foreign DHCP server(s) found: %s" % - (num_dhcp, dhcp_server_data)) - print("ERROR: %s foreign DHCP server(s) found: %s" % - (num_dhcp, dhcp_server_data)) - if network.duplicateIPExists(ip, iface): - log.error("Duplicate host found with IP {0}".format(ip)) - print("ERROR: Duplicate host found with IP {0}".format(ip)) - - default_settings_file = os.path.join(os.path.dirname(__file__), - "settings.yaml") - mos_version = utils.get_fuel_version() - - settings = settings_module.Settings() - - settings.load( - default_settings_file, - template_kwargs={"mos_version": mos_version}) - - settings.load(settingsfile, template_kwargs={"mos_version": mos_version}) - - settings_upd = \ - { - "ADMIN_NETWORK/interface": iface, - "ADMIN_NETWORK/ipaddress": ip, - "ADMIN_NETWORK/netmask": netmask, - "ADMIN_NETWORK/mac": mac, - "ADMIN_NETWORK/dhcp_pool_start": dynamic_start, - "ADMIN_NETWORK/dhcp_pool_end": dynamic_end, - "ADMIN_NETWORK/dhcp_gateway": ip, - "ADMIN_NETWORK/ssh_network": network.getCidr(ip, netmask), - "HOSTNAME": hostname, - "DNS_DOMAIN": domain, - "DNS_SEARCH": domain, - "astute/user": "naily", - "astute/password": pwgen.password(), - "cobbler/user": "cobbler", - "cobbler/password": pwgen.password(), - "keystone/admin_token": pwgen.password(), - "keystone/ostf_user": "ostf", - "keystone/ostf_password": pwgen.password(), - "keystone/nailgun_user": "nailgun", - "keystone/nailgun_password": pwgen.password(), - "keystone/monitord_user": "monitord", - "keystone/monitord_password": pwgen.password(), - "mcollective/user": "mcollective", - "mcollective/password": pwgen.password(), - "postgres/keystone_dbname": "keystone", - "postgres/keystone_user": "keystone", - "postgres/keystone_password": pwgen.password(), - "postgres/nailgun_dbname": "nailgun", - "postgres/nailgun_user": "nailgun", - "postgres/nailgun_password": pwgen.password(), - "postgres/ostf_dbname": "ostf", - "postgres/ostf_user": "ostf", - "postgres/ostf_password": pwgen.password(), - "FUEL_ACCESS/user": "admin", - "FUEL_ACCESS/password": "admin", - } - for setting in settings_upd.keys(): - if "/" in setting: - part1, part2 = setting.split("/") - settings.setdefault(part1, {}) - # Keep old values for passwords if already set - if "password" in setting: - settings[part1].setdefault(part2, settings_upd[setting]) - else: - settings[part1][part2] = settings_upd[setting] - else: - if "password" in setting: - settings.setdefault(setting, settings_upd[setting]) - else: - settings[setting] = settings_upd[setting] - - # Write astute.yaml - settings.write(outfn=settingsfile) + FuelSetup(**kwargs) def main(*args, **kwargs): @@ -458,7 +367,8 @@ def main(*args, **kwargs): sys.exit(1) if options.save_only: - save_only(options.iface) + setup(save_only=True, + managed_iface=options.iface) else: setup() diff --git a/fuelmenu/modules/bootstrapimg.py b/fuelmenu/modules/bootstrapimg.py index 8324c61..90f96a4 100644 --- a/fuelmenu/modules/bootstrapimg.py +++ b/fuelmenu/modules/bootstrapimg.py @@ -138,6 +138,9 @@ class BootstrapImage(urwid.WidgetWrap): self.parent.refreshScreen() responses = self.responses + if self.parent.save_only: + return responses + errors = [] if not responses.get(BOOTSTRAP_SKIP_BUILD_KEY): errors.extend(self.check_apt_repos(responses)) diff --git a/fuelmenu/modules/cobblerconf.py b/fuelmenu/modules/cobblerconf.py index a0c986f..978bb71 100644 --- a/fuelmenu/modules/cobblerconf.py +++ b/fuelmenu/modules/cobblerconf.py @@ -37,8 +37,7 @@ class CobblerConfig(urwid.WidgetWrap): self.parent = parent self.getNetwork() self.gateway = self.get_default_gateway_linux() - self.activeiface = sorted(self.netsettings.keys())[0] - self.parent.managediface = self.activeiface + self.activeiface = self.parent.managediface # UI text text1 = "Settings for PXE booting of slave nodes." @@ -289,7 +288,7 @@ interface first.") settings = self.parent.settings ModuleHelper.load_to_defaults(settings, self.defaults) - iface = settings["ADMIN_NETWORK"]["interface"] + iface = settings.get("ADMIN_NETWORK", {}).get("interface") if iface in self.netsettings.keys(): self.activeiface = iface diff --git a/fuelmenu/modules/dnsandhostname.py b/fuelmenu/modules/dnsandhostname.py index f8c7ce7..f3ea9d0 100644 --- a/fuelmenu/modules/dnsandhostname.py +++ b/fuelmenu/modules/dnsandhostname.py @@ -109,6 +109,9 @@ is accessible"} else: responses[fieldname] = self.edits[index].get_edit_text() + if self.parent.save_only: + return responses + # Validate each field errors = [] @@ -305,7 +308,8 @@ is accessible"} except Exception: log.warning("Unable to look up system hostname") - oldsettings.update(self.resolv_conf_settings()) + if not self.parent.save_only: + oldsettings.update(self.resolv_conf_settings()) ModuleHelper.load_to_defaults(oldsettings, self.defaults, diff --git a/fuelmenu/modules/fueluser.py b/fuelmenu/modules/fueluser.py index 1312e79..eee9ed5 100644 --- a/fuelmenu/modules/fueluser.py +++ b/fuelmenu/modules/fueluser.py @@ -65,13 +65,17 @@ class FuelUser(urwid.WidgetWrap): responses[fieldname] = self.edits[index].get_edit_text() password = responses["FUEL_ACCESS/password"] + confirm_password = responses.pop("CONFIRM_PASSWORD") + + if self.parent.save_only: + return responses # Validate each field errors = [] warnings = [] # Passwords must match - if password != responses["CONFIRM_PASSWORD"] and \ + if password != confirm_password and \ password != self.defaults['FUEL_ACCESS/password']['value']: errors.append("Passwords do not match.") @@ -115,8 +119,6 @@ class FuelUser(urwid.WidgetWrap): else: self.parent.footer.set_text("No errors found.") - # Remove confirm from responses so it isn't saved - del responses["CONFIRM_PASSWORD"] return responses def apply(self, args): @@ -126,7 +128,7 @@ class FuelUser(urwid.WidgetWrap): log.error("%s" % (responses)) for index, fieldname in enumerate(self.fields): if fieldname == "FUEL_ACCESS/password": - return (self.edits[index].get_edit_text() == "") + return self.edits[index].get_edit_text() == "" return False self.save(responses) return True diff --git a/fuelmenu/modules/interfaces.py b/fuelmenu/modules/interfaces.py index 6c8eeb2..30e46cf 100644 --- a/fuelmenu/modules/interfaces.py +++ b/fuelmenu/modules/interfaces.py @@ -302,6 +302,7 @@ class Interfaces(urwid.WidgetWrap): l3ifconfig['params'] = params puppetclasses.append(l3ifconfig) self.log.info("Puppet data: %s" % (puppetclasses)) + try: self.parent.refreshScreen() result = puppet.puppetApply(puppetclasses) diff --git a/fuelmenu/modules/ntpsetup.py b/fuelmenu/modules/ntpsetup.py index 3f2b25d..d782468 100644 --- a/fuelmenu/modules/ntpsetup.py +++ b/fuelmenu/modules/ntpsetup.py @@ -70,6 +70,7 @@ class NtpSetup(urwid.WidgetWrap): self.parent.refreshScreen() # Get field information responses = dict() + ntp_enabled = False for index, fieldname in enumerate(self.fields): if fieldname == "blank": @@ -77,16 +78,17 @@ class NtpSetup(urwid.WidgetWrap): elif fieldname == "ntpenabled": rb_group = self.edits[index].rb_group if rb_group[0].state: - responses["ntpenabled"] = "Yes" - else: - responses["ntpenabled"] = "No" + ntp_enabled = True else: responses[fieldname] = self.edits[index].get_edit_text() + if self.parent.save_only: + return responses + # Validate each field errors = [] warnings = [] - if responses['ntpenabled'] == "No": + if not ntp_enabled: # Disabled NTP means passing no NTP servers to save method # Even though nodes will use Fuel Master, NTP[1,2,3] are empty so # Fuel Master can initialize itself as a time source. @@ -97,17 +99,7 @@ class NtpSetup(urwid.WidgetWrap): self.parent.footer.set_text("No errors found.") log.info("No errors found") return responses - if all(map(lambda f: (len(responses[f]) == 0), self.fields)): - pass - # We will allow empty if user doesn't need external networking - # and present a strongly worded warning - # msg = "If you continue without NTP, you may have issues with "\ - # + "deployment due to time synchronization issues. These "\ - # + "problems are exacerbated in virtualized deployments." - # dialog.display_dialog( - # self, widget.TextLabel(msg), "Empty NTP Warning") - del responses['ntpenabled'] for ntpfield, ntpvalue in responses.iteritems(): # NTP must be under 255 chars if len(ntpvalue) >= 255: diff --git a/fuelmenu/modules/restore.py b/fuelmenu/modules/restore.py index d8b5678..574d42b 100644 --- a/fuelmenu/modules/restore.py +++ b/fuelmenu/modules/restore.py @@ -183,6 +183,9 @@ class Restore(urwid.WidgetWrap): self.parent.settings, self.defaults, ignoredparams=('PATH',)) def save(self, responses): + if self.parent.save_only: + return + self.parent.settings.merge(responses) def screenUI(self): diff --git a/fuelmenu/modules/rootpw.py b/fuelmenu/modules/rootpw.py index f8644c5..7b36d35 100644 --- a/fuelmenu/modules/rootpw.py +++ b/fuelmenu/modules/rootpw.py @@ -97,6 +97,10 @@ class RootPassword(urwid.WidgetWrap): return True def save(self, password): + if self.parent.save_only: + # We shouldn't change root password in save_only mode + return True + hashed = crypt.crypt(password, utils.gensalt()) log.info("Changing root password") # clear any locks first diff --git a/fuelmenu/modules/security.py b/fuelmenu/modules/security.py index ce49aad..9a0d7f0 100644 --- a/fuelmenu/modules/security.py +++ b/fuelmenu/modules/security.py @@ -100,16 +100,15 @@ class Security(urwid.WidgetWrap): self.parent.settings.merge(newsettings) def load(self): + admin_network = network.get_iface_info(self.parent.managediface) + self.defaults[SSH_NETWORK]['value'] = network.getCidr( + admin_network["addr"], + admin_network["netmask"]) + helper.ModuleHelper.load_to_defaults( self.parent.settings, self.defaults, - ignoredparams=[SSH_NETWORK]) - admin_network = self.parent.settings["ADMIN_NETWORK"] - self.defaults[SSH_NETWORK]['value'] = network.getCidr( - admin_network["ipaddress"], - admin_network["netmask"]) - if 'ssh_network' in admin_network: - self.defaults[SSH_NETWORK]['value'] = admin_network["ssh_network"] + ) def refresh(self): pass diff --git a/fuelmenu/settings.yaml b/fuelmenu/settings.yaml index 6f22cab..c4ad0ea 100644 --- a/fuelmenu/settings.yaml +++ b/fuelmenu/settings.yaml @@ -5,15 +5,6 @@ DNS_UPSTREAM: "8.8.8.8" NTP1: "0.fuel.pool.ntp.org" NTP2: "1.fuel.pool.ntp.org" NTP3: "2.fuel.pool.ntp.org" -ADMIN_NETWORK: - interface: "eth0" - ipaddress: "10.20.0.2" - netmask: "255.255.255.0" - cidr: "10.20.0.0/24" - size: "256" - dhcp_gateway: "10.20.0.2" - dhcp_pool_start: "10.20.0.3" - dhcp_pool_end: "10.20.0.254" FUEL_ACCESS: user: "admin" password: "admin"