Merge "Refactored 'save_only' mode"

This commit is contained in:
Jenkins 2016-05-19 15:41:54 +00:00 committed by Gerrit Code Review
commit 1cb83a29fe
12 changed files with 81 additions and 169 deletions

View File

@ -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]

View File

@ -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()

View File

@ -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))

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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)

View File

@ -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:

View File

@ -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):

View File

@ -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

View File

@ -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

View File

@ -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"