From 6041bf10c9b51560415a7f67d3b254ddb1e507de Mon Sep 17 00:00:00 2001 From: Matthew Mosesohn Date: Wed, 25 Sep 2013 15:24:06 +0400 Subject: [PATCH] rebase cleanup --- common/__init__.py | 0 common/nailyfactersettings.py | 42 --- common/network.py | 38 --- common/puppet.py | 62 ---- common/replace.py | 13 - common/urwidwrapper.py | 86 ------ fuelmenu.py | 249 ---------------- loader.py | 42 --- modules/cobblerconf.py | 527 ---------------------------------- modules/dnsandhostname.py | 382 ------------------------ modules/interfaces.py | 417 --------------------------- modules/mirrors.py | 123 -------- modules/shell.py | 39 --- modules/welcome.py | 102 ------- naily.facts.default | 7 - settings.py | 102 ------- settings.yaml | 15 - 17 files changed, 2246 deletions(-) delete mode 100644 common/__init__.py delete mode 100644 common/nailyfactersettings.py delete mode 100644 common/network.py delete mode 100644 common/puppet.py delete mode 100644 common/replace.py delete mode 100644 common/urwidwrapper.py delete mode 100755 fuelmenu.py delete mode 100644 loader.py delete mode 100644 modules/cobblerconf.py delete mode 100644 modules/dnsandhostname.py delete mode 100644 modules/interfaces.py delete mode 100644 modules/mirrors.py delete mode 100644 modules/shell.py delete mode 100644 modules/welcome.py delete mode 100644 naily.facts.default delete mode 100644 settings.py delete mode 100644 settings.yaml diff --git a/common/__init__.py b/common/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/common/nailyfactersettings.py b/common/nailyfactersettings.py deleted file mode 100644 index b55b4d9..0000000 --- a/common/nailyfactersettings.py +++ /dev/null @@ -1,42 +0,0 @@ -import yaml -import ConfigParser -import collections -import os -try: - from collections import OrderedDict -except: - # python 2.6 or earlier use backport - from ordereddict import OrderedDict - -class NailyFacterSettings(): - def __init__(self): - pass - def read(self, infile='naily.facts.default'): - config = OrderedDict() - fd=open(infile, 'r') - lines = fd.readlines() - for line in lines: - key = line.split('=')[0] - value = line.split('=')[1] - config[key]=value - fd.close() - return config - - def write(self, newvalues, prefix='mnbs_', defaultsfile='naily.facts.default', outfn='naily.facts'): - #Read outfn if it exists - if os.path.isfile(outfn): - config=self.read(outfn) - elif defaultsfile is not None: - #Get default config or start new - config=self.read(defaultsfile) - else: - config=OrderedDict() - #Insert newvalues with prefix into config - for key in newvalues.keys(): - config["%s%s" % (prefix,key)]="%s\n" %newvalues[key] - #Write out new file - outfile = open(outfn, 'w') - for key in config.keys(): - outfile.write("%s=%s" % (key, config[key])) - outfile.close() - return True diff --git a/common/network.py b/common/network.py deleted file mode 100644 index c88b8dd..0000000 --- a/common/network.py +++ /dev/null @@ -1,38 +0,0 @@ -import netaddr - -def inSameSubnet(ip1,ip2,netmask_or_cidr): - try: - cidr1=netaddr.IPNetwork("%s/%s" % (ip1,netmask_or_cidr)) - cidr2=netaddr.IPNetwork("%s/%s" % (ip2,netmask_or_cidr)) - return cidr1 == cidr2 - except: - return False - -def getCidr(ip, netmask): - try: - ipn = netaddr.IPNetwork("%s/%s" % (ip, netmask)) - return str(ipn.cidr) - except: - return False - -def getCidrSize(cidr): - try: - ipn = netaddr.IPNetwork(cidr) - return ipn.size - except: - return False - -def getNetwork(ip, netmask): - #Return a list excluding ip and broadcast IPs - try: - ipn = netaddr.IPNetwork("%s/%s" % (ip, netmask)) - ipn_list = list(ipn) - #Drop broadcast and network ip - ipn_list = ipn_list[1:-1] - #Drop ip - ipn_list[:] = [value for value in ipn_list if str(value) != ip] - - return ipn_list - except: - return False - diff --git a/common/puppet.py b/common/puppet.py deleted file mode 100644 index d976519..0000000 --- a/common/puppet.py +++ /dev/null @@ -1,62 +0,0 @@ -import subprocess -import sys -import logging - -#Python 2.6 hack to add check_output command - -if "check_output" not in dir( subprocess ): # duck punch it in! - def f(*popenargs, **kwargs): - if 'stdout' in kwargs: - raise ValueError('stdout argument not allowed, it will be overridden.') - process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs) - output, unused_err = process.communicate() - retcode = process.poll() - if retcode: - cmd = kwargs.get("args") - if cmd is None: - cmd = popenargs[0] - raise Exception(retcode, cmd) - return output - subprocess.check_output = f - -def puppetApply(classname, name=None, params=None): - '''Runs puppet apply -e "classname {'name': params}" ''' - log = logging - log.basicConfig(filename='./fuelmenu.log',level=logging.DEBUG) - log.info("Puppet start") - -#name should be a string -#params should be a dict -# command=["puppet","apply","-d","-v","--logdest","/tmp/puppet.log", "-e",'\'',classname,"{",'"%s":' % name] -# #Build params -# for key,value in params.items(): -# command.extend([key,"=>",'"%s",' % value]) -# command.append('{\'') - command=["puppet","apply","-d","-v","--logdest","/tmp/puppet.log",] - input=[classname,"{",'"%s":' % name] - #Build params - for key,value in params.items(): - input.extend([key,"=>",'"%s",' % value]) - input.append('}') - - log.debug(' '.join(command)) - log.debug(' '.join(input)) - output="" - try: - #output = subprocess.check_output(command) - process = subprocess.Popen(command, stdout=subprocess.PIPE, - stdin=subprocess.PIPE, stderr=subprocess.PIPE) - output, errout = process.communicate(input=' '.join(input))[0] - #output = subprocess.check_output(command) - except Exception, e: - import traceback - log.error(traceback.print_exc()) - log.error(e) - log.debug(output) - log.debug(e) - if "err:" in output: - log.error(e) - return False - else: - log.debug(output) - return True diff --git a/common/replace.py b/common/replace.py deleted file mode 100644 index 710905b..0000000 --- a/common/replace.py +++ /dev/null @@ -1,13 +0,0 @@ -import re - -def replaceInFile(filename, orig, new): - lines=open(filename).readlines() - for lineno,line in enumerate(lines): - lines[lineno]=re.sub(orig, new, line) - f=open(filename, 'w') - print ''.join(lines) - f.write("".join(lines)) - f.flush() - f.close() - - diff --git a/common/urwidwrapper.py b/common/urwidwrapper.py deleted file mode 100644 index 0c23a99..0000000 --- a/common/urwidwrapper.py +++ /dev/null @@ -1,86 +0,0 @@ -import urwid -import urwid.raw_display -import urwid.web_display - -def TextField(keyword, label, width, default_value=None, tooltip=None, toolbar=None, disabled=False): - """Returns an Urwid Edit object""" - if not tooltip: - edit_obj = urwid.Edit(('important', label.ljust(width)), default_value) - else: - edit_obj = TextWithTip(('important', label.ljust(width)), default_value, tooltip, toolbar) - wrapped_obj = urwid.AttrWrap(edit_obj, 'editbx', 'editfc') - if disabled: - wrapped_obj = urwid.WidgetDisable(urwid.AttrWrap(edit_obj, 'important', 'editfc')) - #Add get_edit_text and set_edit_text to wrapped_obj so we can use later - wrapped_obj.set_edit_text = edit_obj.set_edit_text - wrapped_obj.get_edit_text = edit_obj.get_edit_text - return wrapped_obj - -def ChoicesGroup(self, choices, default_value=None, fn=None): - """Returns list of RadioButtons and a horizontal Urwid GridFlow with - radio choices on one line.""" - rb_group = [] - - for txt in choices: - #if default_value == None: - # is_default = "first True" - #else: - # is_default = True if txt == default_value else False - is_default = True if txt == default_value else False - radio_button = urwid.AttrWrap(urwid.RadioButton(rb_group, txt, - is_default, on_state_change=fn, user_data=txt), - 'buttn','buttnf') - #txt, is_default, on_state_change=self.radioSelect, user_data=txt), 'buttn','buttnf') - wrapped_choices = urwid.GridFlow(rb_group, 13, 3, 0, 'left') - #Bundle rb_group so we can use it later easily - wrapped_choices.rb_group=rb_group - #setattr(wrapped_choices.rb_group, - #wrapped_choices = urwid.Padding(urwid.GridFlow(rb_group, 13, 3, 0, - # 'left'), left=4, right=3, min_width=13) - return wrapped_choices - -def TextLabel(text): - """Returns an Urwid text object""" - return urwid.Text(text) - -def HorizontalGroup(objects, cell_width, align="left"): - """Returns a padded Urwid GridFlow object that is left aligned""" - return urwid.Padding(urwid.GridFlow(objects, cell_width, 1, 0, align), - left=0,right=0,min_width=61) - -def Columns(objects): - """Returns a padded Urwid Columns object that is left aligned. - Objects is a list of widgets. Widgets may be optionally specified - as a tuple with ('weight', weight, widget) or (width, widget). - Tuples without a widget have a weight of 1.""" - return urwid.Padding(urwid.Columns(objects, 1), - left=0,right=0,min_width=61) - -def Button(text, fn): - """Returns a wrapped Button with reverse focus attribute""" - button = urwid.Button(text, fn) - return urwid.AttrMap(button, None, focus_map='reversed') - -class TextWithTip(urwid.Edit): - def __init__(self, label, default_value=None, tooltip=None, toolbar=None): - #def __init__(self, keyword, label, width, default_value=None, tooltip=None, toolbar=None): - #super(TextWithTip, self).__init__("") - urwid.Edit.__init__(self, caption=label, edit_text=default_value) - self.tip = tooltip - self.toolbar = toolbar - #def keypress(self, size, key): - # key = super(TextWithTip, self).keypress(size, key) - # self.toolbar.set_text(self.tip) - # return key - def render(self, size, focus=False): - if focus: - self.toolbar.set_text(self.tip) - canv = super(TextWithTip, self).render(size, focus) - return canv - #def mouse_event(self, size, event, button, x, y, focus): - # self.toolbar.set_text(self.tip) - # (maxcol,) = size - # if button==1: - # return self.move_cursor_to_coords( (maxcol,), x, y ) - - diff --git a/fuelmenu.py b/fuelmenu.py deleted file mode 100755 index 761188f..0000000 --- a/fuelmenu.py +++ /dev/null @@ -1,249 +0,0 @@ -import urwid -import urwid.raw_display -import urwid.web_display -import sys -import operator -import os -import sys - -# set up logging -import logging -#logging.basicConfig(filename='./fuelmenu.log') -#logging.basicConfig(level=logging.DEBUG) -logging.basicConfig(filename='./fuelmenu.log',level=logging.DEBUG) -log = logging.getLogger('fuelmenu.loader') - -class Loader: - - def __init__(self, parent): - self.modlist = [] - self.choices = [] - self.child = None - self.children = [] - self.childpage = None - self.parent = parent - - def load_modules(self, module_dir): - if not module_dir in sys.path: - sys.path.append(module_dir) - - modules = [os.path.splitext(f)[0] for f in os.listdir(module_dir) - if f.endswith('.py')] - - for module in modules: - log.info('loading module %s' % module) - try: - imported = __import__(module) - pass - #imported = process(module) - except ImportError as e: - log.error('module could not be imported: %s' % e) - continue - - clsobj = getattr(imported, module, None) - modobj = clsobj(self.parent) - - # add the module to the list - if modobj.visible: - self.modlist.append(modobj) - # sort modules - self.modlist.sort(key=operator.attrgetter('priority')) - for module in self.modlist: - self.choices.append(module.name) - return (self.modlist,self.choices) - - -version="3.2" -#choices= u"Status,Networking,OpenStack Setup,Terminal,Save & Quit".split(',') -class FuelSetup(): - - def __init__(self): - self.footer = None - self.frame = None - self.screen = None - self.defaultsettingsfile = "settings.yaml" - self.settingsfile = "newsettings.yaml" - self.main() - self.choices = [] - - def menu(self, title, choices): - body = [urwid.Text(title), urwid.Divider()] - for c in choices: - button = urwid.Button(c) - urwid.connect_signal(button, 'click', self.menu_chosen, c) - body.append(urwid.AttrMap(button, None, focus_map='reversed')) - return urwid.ListBox(urwid.SimpleListWalker(body)) - #return urwid.ListBox(urwid.SimpleFocusListWalker(body)) - - def menu_chosen(self, button, choice): - size = self.screen.get_cols_rows() - self.screen.draw_screen(size, self.frame.render(size)) - - - #Highlight menu item - #menulist=self.menuitems.original_widget - #log.info("%s" % self.menuitems) - #log.info("%s" % self.menuitems.contents()) - for item in self.menuitems.body.contents: - try: - log.info("inside loop %s" % item.original_widget.get_label()) - #self.footer.set_text("inside loop %s" % item.original_widget.get_label()) - if item.original_widget.get_label() == choice: - self.footer.set_text("Found choice %s" % choice) - item.set_attr_map({ None: 'header'}) - else: - item.set_attr_map({ None: None}) - except Exception, e: - self.footer.set_text("%s" % item) - log.info("%s" % item) - log.error("%s" % e) - #continue - self.setChildScreen(name=choice) - - - def setChildScreen(self, name=None): - if name is None: - child = self.children[0] - else: - child = self.children[int(self.choices.index(name))] - self.childpage = child.screenUI() - self.childfill = urwid.Filler(self.childpage, 'top', 40) - self.childbox = urwid.BoxAdapter(self.childfill, 40) - self.cols = urwid.Columns([ - ('fixed', 20, urwid.Pile([ - urwid.AttrMap(self.menubox, 'bright'), - urwid.Divider(" ")])), - ('weight', 3, urwid.Pile([ - urwid.Divider(" "), - self.childbox, - urwid.Divider(" ")])) - ], 1) - self.listwalker[:] = [self.cols] - - def refreshScreen(self): - size = self.screen.get_cols_rows() - self.screen.draw_screen(size, self.frame.render(size)) - - def refreshChildScreen(self, name): - child = self.children[int(self.choices.index(name))] - #Refresh child listwalker - child.listwalker[:]=child.listbox_content - - #reassign childpage top level objects - self.childpage = urwid.ListBox(child.listwalker) - self.childfill = urwid.Filler(self.childpage, 'middle', 22) - self.childbox = urwid.BoxAdapter(self.childfill, 22) - self.cols = urwid.Columns([ - ('fixed', 20, urwid.Pile([ - urwid.AttrMap(self.menubox, 'bright'), - urwid.Divider(" ")])), - ('weight', 3, urwid.Pile([ - urwid.Divider(" "), - self.childbox, - urwid.Divider(" ")])) - ], 1) - #Refresh top level listwalker - #self.listwalker[:] = [self.cols] - - - - def main(self): - - text_header = (u"Fuel %s setup " - u"UP / DOWN / PAGE UP / PAGE DOWN scroll. F8 exits." - % version) - text_footer = (u"Status messages go here.") - - blank = urwid.Divider() - - #Top and bottom lines of frame - self.header = urwid.AttrWrap(urwid.Text(text_header), 'header') - self.footer = urwid.AttrWrap(urwid.Text(text_footer), 'footer') - - #Prepare submodules - loader = Loader(self) - self.children, self.choices = loader.load_modules(module_dir="./modules") - if len(self.children) == 0: - import sys - sys.exit(1) - - self.menuitems=self.menu(u'Menu', self.choices) - menufill = urwid.Filler(self.menuitems, 'top', 40) - self.menubox = urwid.BoxAdapter(menufill, 40) - - - child = self.children[0] - self.childpage = child.screenUI() - self.childfill = urwid.Filler(self.childpage, 'top', 22) - self.childbox = urwid.BoxAdapter(self.childfill, 22) - self.cols = urwid.Columns([ - ('fixed', 20, urwid.Pile([ - urwid.AttrMap(self.menubox, 'bright'), - urwid.Divider(" ")])), - ('weight', 3, urwid.Pile([ - urwid.Divider(" "), - self.childbox, - urwid.Divider(" ")])) - ], 1) - - self.listwalker = urwid.SimpleListWalker([self.cols]) - #self.listwalker = urwid.TreeWalker([self.cols]) - self.listbox = urwid.ListBox(self.listwalker) - #listbox = urwid.ListBox(urwid.SimpleListWalker(listbox_content)) - - #frame = urwid.Frame(urwid.AttrWrap(cols, 'background'), header=header, footer=footer) - #frame = urwid.Frame(urwid.AttrWrap(cols, 'body'), header=header, footer=footer) - self.frame = urwid.Frame(urwid.AttrWrap(self.listbox, 'body'), header=self.header, footer=self.footer) - - palette = [ - ('body','black','light gray', 'standout'), - ('reverse','light gray','black'), - ('header','white','dark red', 'bold'), - ('important','dark blue','light gray',('standout','underline')), - ('editfc','white', 'dark blue', 'bold'), - ('editbx','light gray', 'dark blue'), - ('editcp','black','light gray', 'standout'), - ('bright','dark gray','light gray', ('bold','standout')), - ('buttn','black','dark cyan'), - ('buttnf','white','dark blue','bold'), - ('light gray','white', 'light gray','bold'), - ('red','dark red','light gray','bold'), - ('black','black','black','bold'), - ] - - - # use appropriate Screen class - if urwid.web_display.is_web_request(): - self.screen = urwid.web_display.Screen() - else: - self.screen = urwid.raw_display.Screen() - - def unhandled(key): - log.debug(key) - if key == 'f8': - raise urwid.ExitMainLoop() - if key == 'enter' and type(self.mainloop.widget) == urwid.Overlay: - log.debug("overlay enter key") - self.mainloop.widget = self.frame - - self.mainloop= urwid.MainLoop(self.frame, palette, self.screen, - unhandled_input=unhandled) - self.mainloop.run() - - def exit_program(self, button): - raise urwid.ExitMainLoop() - - -def setup(): - urwid.web_display.set_preferences("Fuel Setup") - # try to handle short web requests quickly - if urwid.web_display.handle_short_request(): - return - fm = FuelSetup() - - -if '__main__'==__name__ or urwid.web_display.is_web_request(): - if urwid.VERSION < (1,1,0): - print "This program requires urwid 1.1.0 or greater." - setup() - diff --git a/loader.py b/loader.py deleted file mode 100644 index 234bfd9..0000000 --- a/loader.py +++ /dev/null @@ -1,42 +0,0 @@ -import operator -import os -import sys - -from .constants import * -from .module import Module -from .moduleset import ModuleSet - -import ethtool - - -# set up logging -import logging -logging.basicConfig(level=logging.DEBUG) -log = logging.getLogger('fuelmenu.loader') - -class Loader: - - def __init__(self): - self.modlist = [] - - def load_modules(self, module_dir): - if not module_dir in sys.path: - sys.path.append(module_dir) - - modules = [os.path.splitext(f)[0] for f in os.listdir(module_dir) - if f.endswith('.py')] - - for module in modules: - log.info('loading module %s', module) - try: - imported = process(module) - except ImportError as e: - log.error('module could not be imported: %s', e) - continue - # add the module to the list - self.modlist.append(module) - # sort modules - self.modlist.sort(key=operator.attrgetter('priority')) - return self.modlist - - diff --git a/modules/cobblerconf.py b/modules/cobblerconf.py deleted file mode 100644 index 6ecc5b1..0000000 --- a/modules/cobblerconf.py +++ /dev/null @@ -1,527 +0,0 @@ -#!/usr/bin/env python - -import urwid -import urwid.raw_display -import urwid.web_display -import logging -import sys -import re -import copy -import socket, struct -import netaddr -import dhcp_checker.api -sys.path.append("/home/mmosesohn/git/fuel/iso/fuelmenu") -from settings import * -from common import network, puppet, replace, nailyfactersettings, dialog -from common.urwidwrapper import * -log = logging.getLogger('fuelmenu.pxe_setup') -blank = urwid.Divider() - -#Need to define fields in order so it will render correctly -#fields = ["hostname", "domain", "mgmt_if","dhcp_start","dhcp_end", -# "blank","ext_if","ext_dns"] -fields = ["static_label", - "ADMIN_NETWORK/static_start", "ADMIN_NETWORK/static_end", - "blank", "dynamic_label", "ADMIN_NETWORK/first", - "ADMIN_NETWORK/last"] -facter_translate = { - "ADMIN_NETWORK/interface" : "internal_interface", - #"ADMIN_NETWORK/ipaddr" : "internal_ipaddress", - "ADMIN_NETWORK/first" : "dhcp_pool_start", - "ADMIN_NETWORK/last" : "dhcp_pool_end", - "ADMIN_NETWORK/static_start" : "static_pool_start", - "ADMIN_NETWORK/static_end" : "static_pool_end", -} -mnbs_internal_ipaddress="10.20.0.2" -mnbs_internal_netmask="255.255.255.0" -mnbs_static_pool_start="10.20.0.130" -mnbs_static_pool_end="10.20.0.250" -mnbs_dhcp_pool_start="10.20.0.10" -mnbs_dhcp_pool_end="10.20.0.120" -mnbs_internal_interface="eth1" - -DEFAULTS = { - #"ADMIN_NETWORK/interface" : { "label" : "Management Interface", - # "tooltip": "This is the INTERNAL network for provisioning", - # "value" : "eth0"}, - "ADMIN_NETWORK/first" : { "label" : "DHCP Pool Start", - "tooltip": "Used for defining IPs for hosts and instance public addresses", - "value" : "10.0.0.130"}, - "ADMIN_NETWORK/last" : { "label" : "DHCP Pool End", - "tooltip": "Used for defining IPs for hosts and instance public addresses", - "value" : "10.0.0.254"}, - "static_label" : { "label" : "Static pool for installed nodes:", - "tooltip" : "", - "value" : "label"}, - "ADMIN_NETWORK/static_start" : { "label" : "Static Pool Start", - "tooltip": "Static pool for installed nodes", - "value" : "10.0.0.10"}, - "ADMIN_NETWORK/static_end": { "label" : "Static Pool End", - "tooltip": "Static pool for installed nodes", - "value" : "10.0.0.120"}, - "dynamic_label" : { "label" : "DHCP pool for node discovery:", - "tooltip" : "", - "value" : "label"}, - #"ADMIN_NETWORK/dynamic_start" : { "label" : "Static Pool Start", - # "tooltip": "DHCP pool for node discovery", - # "value" : "10.0.0.10"}, - #"ADMIN_NETWORK/dynamic_end": { "label" : "Static Pool End", - # "tooltip": "DHCP pool for node discovery", - # "value" : "10.0.0.120"}, -} - -class cobblerconf(urwid.WidgetWrap): - def __init__(self, parent): - self.name="PXE Setup" - self.priority=20 - self.visible=True - self.netsettings = dict() - self.deployment="pre" - self.getNetwork() - self.gateway=self.get_default_gateway_linux() - self.activeiface = sorted(self.netsettings.keys())[0] - self.extdhcp=True - self.parent = parent - self.oldsettings= self.load() - #self.screen = self.screenUI() - - def check(self, args): - """Validates that all fields have valid values and some sanity checks""" - self.parent.footer.set_text("Checking data...") - self.parent.refreshScreen() - - #Get field information - responses=dict() - - for index, fieldname in enumerate(fields): - if fieldname == "blank" or "label" in fieldname: - pass - else: - responses[fieldname]=self.edits[index].get_edit_text() - responses["ADMIN_NETWORK/interface"]=self.activeiface - ###Validate each field - errors=[] - - #ensure management interface is valid - if responses["ADMIN_NETWORK/interface"] not in self.netsettings.keys(): - errors.append("Management interface not valid") - else: - self.parent.footer.set_text("Scanning for DHCP servers. Please wait...") - self.parent.refreshScreen() - - ###Start DHCP check on this interface - #dhcp_server_data=[{'server_id': '192.168.200.2', 'iface': 'eth2', 'yiaddr': '192.168.200.15', 'mac': '52:54:00:12:35:02', 'server_ip': '192.168.200.2', 'dport': 67, 'message': 'offer', 'gateway': '0.0.0.0'}] - dhcp_server_data=dhcp_checker.api.check_dhcp_on_eth(\ - self.activeiface,timeout=5) - - num_dhcp=len(dhcp_server_data) - if num_dhcp == 0: - log.debug("No DHCP servers found") - else: - #We have a problem and will report it, but permit it to continue - log.error("%s foreign DHCP server(s) found: %s" % (num_dhcp, dhcp_server_data)) - - #Build dialog elements - dhcp_info=[] - dhcp_info.append(urwid.Padding(\ - urwid.Text(("header","!!! WARNING !!!"))\ - ,"center")) - dhcp_info.append(TextLabel("You have selected an interface that \ -contains one or more DHCP servers. This will impact provisioning. You should \ - disable these DHCP servers before you continue, or else deployment will \ -likely fail.")) - dhcp_info.append(TextLabel("")) - for index, dhcp_server in enumerate(dhcp_server_data): - dhcp_info.append(TextLabel("DHCP Server # %s:" % (index+1))) - dhcp_info.append(TextLabel("IP address: %-10s" % dhcp_server['server_ip'])) - dhcp_info.append(TextLabel("MAC address: %-10s" % dhcp_server['mac'])) - dhcp_info.append(TextLabel("")) - dialog.display_dialog(self,urwid.Pile(dhcp_info),"DHCP Servers Found on %s" \ -% self.activeiface) - ###Ensure pool start and end are on the same subnet as mgmt_if - #Ensure mgmt_if has an IP first - if len(self.netsettings[responses["ADMIN_NETWORK/interface"]]["addr"]) == 0: - errors.append("Go to Interfaces to configure management interface first.") - else: - #Ensure ADMIN_NETWORK/interface is not running DHCP - if self.netsettings[responses["ADMIN_NETWORK/interface"]]["bootproto"] == "dhcp": - errors.append("%s is running DHCP. Change it to static first." - % self.activeiface) - - #Ensure Static Pool Start and Static Pool are valid IPs - try: - if netaddr.valid_ipv4(responses["ADMIN_NETWORK/static_start"]): - static_start=netaddr.IPAddress(responses["ADMIN_NETWORK/static_start"]) - else: - raise Exception("") - except Exception, e: - errors.append("Not a valid IP address for Static Pool Start: %s" - % e) - #% responses["ADMIN_NETWORK/first"]) - try: - if netaddr.valid_ipv4(responses["ADMIN_NETWORK/static_end"]): - static_end=netaddr.IPAddress(responses["ADMIN_NETWORK/static_end"]) - else: - raise Exception("") - except: - errors.append("Not a valid IP address for Static Pool end: %s" - % responses["ADMIN_NETWORK/static_end"]) - #Ensure DHCP Pool Start and DHCP Pool are valid IPs - try: - if netaddr.valid_ipv4(responses["ADMIN_NETWORK/first"]): - dhcp_start=netaddr.IPAddress(responses["ADMIN_NETWORK/first"]) - else: - raise Exception("") - except Exception, e: - errors.append("Not a valid IP address for DHCP Pool Start: %s" - % e) - #% responses["ADMIN_NETWORK/first"]) - try: - if netaddr.valid_ipv4(responses["ADMIN_NETWORK/last"]): - dhcp_end=netaddr.IPAddress(responses["ADMIN_NETWORK/last"]) - else: - raise Exception("") - except: - errors.append("Not a valid IP address for DHCP Pool end: %s" - % responses["ADMIN_NETWORK/last"]) - - #Ensure pool start and end are in the same subnet of each other - netmask=self.netsettings[responses["ADMIN_NETWORK/interface"]]["netmask"] - if network.inSameSubnet(responses["ADMIN_NETWORK/first"],responses["ADMIN_NETWORK/last"], - netmask) is False: - errors.append("DHCP Pool start and end are not in the same subnet.") - - #Ensure pool start and end are in the netmask of ADMIN_NETWORK/interface - mgmt_if_ipaddr=self.netsettings[responses["ADMIN_NETWORK/interface"]]["addr"] - if network.inSameSubnet(responses["ADMIN_NETWORK/first"],mgmt_if_ipaddr, - netmask) is False: - errors.append("DHCP Pool start does not match management network.") - if network.inSameSubnet(responses["ADMIN_NETWORK/last"],mgmt_if_ipaddr, - netmask) is False: - errors.append("DHCP Pool end is not in the same subnet as management interface.") - - if len(errors) > 0: - self.parent.footer.set_text("Errors: %s First error: %s" % (len(errors), errors[0])) - return False - else: - self.parent.footer.set_text("No errors found.") - return responses - - def apply(self, args): - responses = self.check(args) - if responses is False: - log.error("Check failed. Not applying") - log.error("%s" % (responses)) - return False - - #Always save even if "post" - self.save(responses) - #Need to decide if we are pre-deployment or post-deployment - if self.deployment == "post": - self.updateCobbler(responses) - services.restart("cobbler") - - def updateCobbler(self, params): - patterns={ - 'cblr_server' : '^server: .*', - 'cblr_next_server' : '^next_server: .*', - 'mgmt_if' : '^interface=.*', - 'domain' : '^domain=.*', - 'server' : '^server=.*', - 'dhcp-range' : '^dhcp-range=', - 'dhcp-option' : '^dhcp-option=', - 'pxe-service' : '^pxe-service=(^,)', - 'dhcp-boot' : '^dhcp-boot=([^,],{3}),' - } - def cancel(self, button): - for index, fieldname in enumerate(fields): - if fieldname == "blank" or "label" in fieldname: - pass - else: - self.edits[index].set_edit_text(DEFAULTS[fieldname]['value']) - self.setNetworkDetails() - def load(self): - #Read in yaml - defaultsettings=Settings().read(self.parent.defaultsettingsfile) - oldsettings=defaultsettings - oldsettings.update(Settings().read(self.parent.settingsfile)) - log.debug("Old settings %s" % oldsettings) - for setting in DEFAULTS.keys(): - if "label" in setting: - continue - elif "/" in setting: - part1, part2 = setting.split("/") - DEFAULTS[setting]["value"] = oldsettings[part1][part2] - else: - DEFAULTS[setting]["value"] = oldsettings[setting] - if oldsettings["ADMIN_NETWORK"]["interface"] in self.netsettings.keys(): - self.activeiface=oldsettings["ADMIN_NETWORK"]["interface"] - - return oldsettings - def save(self, responses): - ## Generic settings start ## - newsettings = dict() - for setting in responses.keys(): - if "/" in setting: - part1, part2 = setting.split("/") - if not newsettings.has_key(part1): - #We may not touch all settings, so copy oldsettings first - newsettings[part1]=self.oldsettings[part1] - newsettings[part1][part2] = responses[setting] - else: - newsettings[setting] = responses[setting] - ## Generic settings end ## - - ## Need to calculate and set cidr, netmask, size - newsettings['ADMIN_NETWORK']['netmask'] = \ - self.netsettings[newsettings['ADMIN_NETWORK']['interface']]["netmask"] - newsettings['ADMIN_NETWORK']['cidr'] = network.getCidr( - self.netsettings[newsettings['ADMIN_NETWORK']['interface']]["addr"], - newsettings['ADMIN_NETWORK']['netmask']) - newsettings['ADMIN_NETWORK']['size']=network.getCidrSize( - newsettings['ADMIN_NETWORK']['cidr']) - - - log.debug(str(newsettings)) - Settings().write(newsettings,defaultsfile=self.parent.settingsfile, - outfn="newsettings.yaml") - #Write naily.facts - factsettings=dict() - #for key in newsettings.keys(): - log.debug(str(facter_translate)) - log.debug(str(newsettings)) - for key in facter_translate.keys(): - factsettings[facter_translate[key]]=responses[key] - n=nailyfactersettings.NailyFacterSettings() - log.debug("Facts to write: %s" % factsettings) - n.write(factsettings) - - #Set oldsettings to reflect new settings - self.oldsettings = newsettings - #Update DEFAULTS - for index, fieldname in enumerate(fields): - if fieldname != "blank" and "label" not in fieldname: - DEFAULTS[fieldname]['value']= responses[fieldname] - - self.parent.footer.set_text("Changes saved successfully.") - - def getNetwork(self): - """Uses netifaces module to get addr, broadcast, netmask about - network interfaces""" - import netifaces - for iface in netifaces.interfaces(): - if 'lo' in iface or 'vir' in iface: - #if 'lo' in iface or 'vir' in iface or 'vbox' in iface: - if iface != "virbr2-nic": - continue - try: - self.netsettings.update({iface: netifaces.ifaddresses(iface)[netifaces.AF_INET][0]}) - self.netsettings[iface]["onboot"]="Yes" - except: - self.netsettings.update({iface: {"addr": "", "netmask": "", - "onboot": "no"}}) - self.netsettings[iface]['mac'] = netifaces.ifaddresses(iface)[netifaces.AF_LINK][0]['addr'] - - #Set link state - try: - with open("/sys/class/net/%s/operstate" % iface) as f: - content = f.readlines() - self.netsettings[iface]["link"]=content[0].strip() - except: - self.netsettings[iface]["link"]="unknown" - #Change unknown link state to up if interface has an IP - if self.netsettings[iface]["link"] == "unknown": - if self.netsettings[iface]["addr"] != "": - self.netsettings[iface]["link"]="up" - - #We can try to get bootproto from /etc/sysconfig/network-scripts/ifcfg-DEV - try: - with open("/etc/sysconfig/network-scripts/ifcfg-%s" % iface) as fh: - for line in fh: - if re.match("^BOOTPROTO=", line): - self.netsettings[iface]['bootproto']=line.split('=').strip() - break - except: - #Let's try checking for dhclient process running for this interface - if self.getDHCP(iface): - self.netsettings[iface]['bootproto']="dhcp" - else: - self.netsettings[iface]['bootproto']="none" - - def getDHCP(self, iface): - """Returns True if the interface has a dhclient process running""" - import subprocess - noout=open('/dev/null','w') - dhclient_running = subprocess.call(["pgrep","-f","dhclient.*%s" % (iface)], - stdout=noout, stderr=noout) - if dhclient_running == 0: - return True - else: - return False - - - def get_default_gateway_linux(self): - """Read the default gateway directly from /proc.""" - with open("/proc/net/route") as fh: - for line in fh: - fields = line.strip().split() - if fields[1] != '00000000' or not int(fields[3], 16) & 2: - continue - - return socket.inet_ntoa(struct.pack("= 60: - errors.append("Hostname must be under 60 chars.") - - #hostname must not be empty - if len(responses["HOSTNAME"]) == 0: - errors.append("Hostname must not be empty.") - - #hostname needs to have valid chars - if not re.match('[a-z0-9-]',responses["HOSTNAME"]): - errors.append("Hostname must contain only alphanumeric and hyphen.") - - #domain must be under 180 chars - if len(responses["DNS_DOMAIN"]) >= 180: - errors.append("Domain must be under 180 chars.") - - #domain must not be empty - if len(responses["DNS_DOMAIN"]) == 0: - errors.append("Domain must not be empty.") - - #domain needs to have valid chars - if not re.match('[a-z0-9-.]',responses["DNS_DOMAIN"]): - errors.append("Domain must contain only alphanumeric, period and hyphen.") - #ensure external DNS is valid - if len(responses["DNS_UPSTREAM"]) == 0: - #We will allow empty if user doesn't need external networking - #and present a strongly worded warning - msg="If you continue without DNS, you may not be able to access \ -external data necessary for installation needed for some OpenStack \ -Releases." - - diag=dialog.display_dialog(self,TextLabel(msg), "Empty DNS Warning") - - else: - #external DNS must contain only numbers, periods, and commas - #TODO: More serious ip address checking - if not re.match('[0-9.,]',responses["DNS_UPSTREAM"]): - errors.append("External DNS must contain only IP addresses and commas.") - #ensure test DNS name isn't empty - if len(responses["TEST_DNS"]) == 0: - errors.append("Test DNS must not be empty.") - #Validate first IP address - try: - if netaddr.valid_ipv4(responses["DNS_UPSTREAM"].split(",")[0]): - DNS_UPSTREAM=responses["DNS_UPSTREAM"].split(",")[0] - else: - errors.append("Not a valid IP address for External DNS: %s" - % responses["DNS_UPSTREAM"]) - - #Try to resolve with first address - #Note: Python's internal resolver caches negative answers. - #Therefore, we should call dig externally to be sure. - import subprocess - noout=open('/dev/null','w') - dns_works = subprocess.call(["dig","+short","+time=3", - "+retries=1",responses["TEST_DNS"], - "@%s" % DNS_UPSTREAM],stdout=noout, stderr=noout) - if dns_works != 0: - errors.append("Domain Name server %s unable to resolve host." - % DNS_UPSTREAM) - #from twisted.names import client - #for nameserver in responses["ext_dns"].split(","): - # resolver = client.createResolver(servers=[(nameserver,53)) - # if resolver.getHostByName('wikipedia.org') - except Exception, e: - - errors.append(e) - errors.append("Not a valid IP address for External DNS: %s" - % responses["DNS_UPSTREAM"]) - - if len(errors) > 0: - self.parent.footer.set_text("Errors: %s First error: %s" % (len(errors), errors[0])) - return False - else: - self.parent.footer.set_text("No errors found.") - return responses - - def apply(self, args): - responses = self.check(args) - if responses is False: - log.error("Check failed. Not applying") - log.error("%s" % (responses)) - return False - - self.save(responses) - #Apply hostname - expr='HOSTNAME=.*' - replace.replaceInFile("/etc/sysconfig/network",expr,"HOSTNAME=%s" - % (responses["HOSTNAME"])) - #Write dnsmasq upstream server - with open('/etc/dnsmasq.upstream','a') as f: - nameservers=responses['DNS_UPSTREAM'].replace(',',' ') - f.write("nameserver %s\n" % nameservers) - f.close() - - ###Future feature to apply post-deployment - #Need to decide if we are pre-deployment or post-deployment - #if self.deployment == "post": - # self.updateCobbler(responses) - # services.restart("cobbler") - -# def updateCobbler(self, params): -# patterns={ -# 'cblr_server' : '^server: .*', -# 'cblr_next_server' : '^next_server: .*', -# 'mgmt_if' : '^interface=.*', -# 'domain' : '^domain=.*', -# 'server' : '^server=.*', -# 'dhcp-range' : '^dhcp-range=', -# 'dhcp-option' : '^dhcp-option=', -# 'pxe-service' : '^pxe-service=(^,)', -# 'dhcp-boot' : '^dhcp-boot=([^,],{3}),' -# } - def cancel(self, button): - for index, fieldname in enumerate(fields): - if fieldname == "blank": - pass - else: - self.edits[index].set_edit_text(DEFAULTS[fieldname]['value']) - - def load(self): - #Read in yaml - defaultsettings=Settings().read(self.parent.defaultsettingsfile) - oldsettings=defaultsettings - oldsettings.update(Settings().read(self.parent.settingsfile)) - - oldsettings=Settings().read(self.parent.settingsfile) - for setting in DEFAULTS.keys(): - try: - if "/" in setting: - part1, part2 = setting.split("/") - DEFAULTS[setting]["value"] = oldsettings[part1][part2] - else: - DEFAULTS[setting]["value"] = oldsettings[setting] - except: - log.warning("No setting named %s found." % setting) - continue - #Read hostname if it's already set - try: - import os - oldsettings["HOSTNAME"]=os.uname()[1] - except: - log.warning("Unable to look up system hostname") - return oldsettings - def save(self, responses): - ## Generic settings start ## - newsettings = dict() - for setting in responses.keys(): - if "/" in setting: - part1, part2 = setting.split("/") - if not newsettings.has_key(part1): - #We may not touch all settings, so copy oldsettings first - newsettings[part1]=self.oldsettings[part1] - newsettings[part1][part2] = responses[setting] - else: - newsettings[setting] = responses[setting] - ## Generic settings end ## - - #log.debug(str(newsettings)) - Settings().write(newsettings,defaultsfile=self.parent.settingsfile, - outfn="newsettings.yaml") - #Write naily.facts - factsettings=dict() - #log.debug(newsettings) - for key in newsettings.keys(): - if key != "blank": - factsettings[key]=newsettings[key] - n=nailyfactersettings.NailyFacterSettings() - n.write(factsettings) - - #Set oldsettings to reflect new settings - self.oldsettings = newsettings - #Update DEFAULTS - for index, fieldname in enumerate(fields): - if fieldname != "blank": - DEFAULTS[fieldname]['value']= newsettings[fieldname] - - def getNetwork(self): - """Uses netifaces module to get addr, broadcast, netmask about - network interfaces""" - import netifaces - for iface in netifaces.interfaces(): - if 'lo' in iface or 'vir' in iface: - #if 'lo' in iface or 'vir' in iface or 'vbox' in iface: - if iface != "virbr2-nic": - continue - try: - self.netsettings.update({iface: netifaces.ifaddresses(iface)[netifaces.AF_INET][0]}) - self.netsettings[iface]["onboot"]="Yes" - except: - self.netsettings.update({iface: {"addr": "", "netmask": "", - "onboot": "no"}}) - self.netsettings[iface]['mac'] = netifaces.ifaddresses(iface)[netifaces.AF_LINK][0]['addr'] - - #Set link state - try: - with open("/sys/class/net/%s/operstate" % iface) as f: - content = f.readlines() - self.netsettings[iface]["link"]=content[0].strip() - except: - self.netsettings[iface]["link"]="unknown" - #Change unknown link state to up if interface has an IP - if self.netsettings[iface]["link"] == "unknown": - if self.netsettings[iface]["addr"] != "": - self.netsettings[iface]["link"]="up" - - #We can try to get bootproto from /etc/sysconfig/network-scripts/ifcfg-DEV - try: - with open("/etc/sysconfig/network-scripts/ifcfg-%s" % iface) as fh: - for line in fh: - if re.match("^BOOTPROTO=", line): - self.netsettings[iface]['bootproto']=line.split('=').strip() - break - except: - #Let's try checking for dhclient process running for this interface - if self.getDHCP(iface): - self.netsettings[iface]['bootproto']="dhcp" - else: - self.netsettings[iface]['bootproto']="none" - - def getDHCP(self, iface): - """Returns True if the interface has a dhclient process running""" - import subprocess - noout=open('/dev/null','w') - dhclient_running = subprocess.call(["pgrep","-f","dhclient.*%s" % (iface)], - stdout=noout, stderr=noout) - - - def get_default_gateway_linux(self): - """Read the default gateway directly from /proc.""" - with open("/proc/net/route") as fh: - for line in fh: - fields = line.strip().split() - if fields[1] != '00000000' or not int(fields[3], 16) & 2: - continue - - return socket.inet_ntoa(struct.pack(" 0: - gateway=netaddr.IPAddress(responses["netmask"]) - #Check if gateway is valid - if gateway.valid_ipv4 is False: - raise Exception("Gateway IP address is not valid") - #Check if gateway is in same subnet - if network.inSameSubnet(responses["ipaddr"],responses["gateway"], - responses["netmask"]) is False: - raise Exception("Gateway IP address is not in the same subnet as\ -IP address") - except Exception, e: - errors.append(e) - if len(errors) > 0: - self.parent.footer.set_text("Errors: %s First error: %s" % (len(errors), errors[0])) - return False - else: - self.parent.footer.set_text("No errors found.") - return responses - - def apply(self, args): - responses = self.check(args) - if responses is False: - self.log.error("Check failed. Not applying") - self.parent.footer.set_text("Check failed. Not applying.") - self.log.error("%s" % (responses)) - return False - - self.parent.footer.set_text("Applying changes...") - puppetclass="l23network::l3::ifconfig" - if responses["onboot"].lower() == "no": - params={"ipaddr": "none"} - elif responses["bootproto"] == "dhcp": - params={"ipaddr": "dhcp"} - else: - params={"ipaddr": responses["ipaddr"], - "netmask": responses["netmask"]} - if len(responses["gateway"]) > 1: - params["gateway"]=responses["gateway"] - self.log.info("Puppet data: %s %s %s" % (puppetclass, self.activeiface, params)) - try: - self.parent.refreshScreen() - puppet.puppetApply(puppetclass,self.activeiface, params) - except Exception, e: - self.log.error(e) - self.parent.footer.set_text("Error applying changes. Check logs for details.") - self.getNetwork() - self.setNetworkDetails() - return False - self.parent.footer.set_text("Changes successfully applied.") - self.getNetwork() - self.setNetworkDetails() - - return True - - #leftover from network. we let puppet save everything - def save(self, args): - newsettings = dict() - newsettings['common'] = { YAMLTREE : { "domain" : DEFAULTS['domain']['value']}} - for key, widget in self.edits.items(): - text = widget.original_widget.get_edit_text() - newsettings['common'][YAMLTREE][key] = text - log.warning(str(newsettings)) - Settings().write(newsettings, tree=YAMLTREE) - logging.warning('And this, too') - - - def getNetwork(self): - """Uses netifaces module to get addr, broadcast, netmask about - network interfaces""" - import netifaces - for iface in netifaces.interfaces(): - if 'lo' in iface or 'vir' in iface: - #if 'lo' in iface or 'vir' in iface or 'vbox' in iface: - if iface != "virbr2-nic": - continue - try: - self.netsettings.update({iface: netifaces.ifaddresses(iface)[netifaces.AF_INET][0]}) - self.netsettings[iface]["onboot"]="Yes" - except: - #Interface is down, so mark it onboot=no - self.netsettings.update({iface: {"addr": "", "netmask": "", - "onboot": "no"}}) - - self.netsettings[iface]['mac'] = netifaces.ifaddresses(iface)[netifaces.AF_LINK][0]['addr'] - - #Set link state - try: - with open("/sys/class/net/%s/operstate" % iface) as f: - content = f.readlines() - self.netsettings[iface]["link"]=content[0].strip() - except: - self.netsettings[iface]["link"]="unknown" - #Change unknown link state to up if interface has an IP - if self.netsettings[iface]["link"] == "unknown": - if self.netsettings[iface]["addr"] != "": - self.netsettings[iface]["link"]="up" - - - #We can try to get bootproto from /etc/sysconfig/network-scripts/ifcfg-DEV - #default to static - self.netsettings[iface]['bootproto']="none" - try: - with open("/etc/sysconfig/network-scripts/ifcfg-%s" % iface) as fh: - for line in fh: - if re.match("^BOOTPROTO=", line): - self.netsettings[iface]['bootproto']=line.split('=').strip() - break - - except: - #Let's try checking for dhclient process running for this interface - if self.getDHCP(iface): - self.netsettings[iface]['bootproto']="dhcp" - else: - self.netsettings[iface]['bootproto']="none" - - - def getDHCP(self, iface): - """Returns True if the interface has a dhclient process running""" - import subprocess - noout=open('/dev/null','w') - dhclient_running = subprocess.call(["pgrep","-f","dhclient.*%s" % (iface)], - stdout=noout, stderr=noout) - #self.log.info("Interface %s: %s" % (iface, dhclient_running)) - if dhclient_running != 0: - return False - else: - return True - - def get_default_gateway_linux(self): - """Read the default gateway directly from /proc.""" - with open("/proc/net/route") as fh: - for line in fh: - fields = line.strip().split() - if fields[1] != '00000000' or not int(fields[3], 16) & 2: - continue - - return socket.inet_ntoa(struct.pack("