rebase cleanup
This commit is contained in:
parent
fd9e9c8848
commit
6041bf10c9
@ -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
|
@ -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
|
||||
|
@ -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
|
@ -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()
|
||||
|
||||
|
@ -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 )
|
||||
|
||||
|
249
fuelmenu.py
249
fuelmenu.py
@ -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()
|
||||
|
42
loader.py
42
loader.py
@ -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
|
||||
|
||||
|
@ -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("<L", int(fields[2], 16)))
|
||||
|
||||
def radioSelectIface(self, current, state, user_data=None):
|
||||
"""Update network details and display information"""
|
||||
### This makes no sense, but urwid returns the previous object.
|
||||
### The previous object has True state, which is wrong..
|
||||
### Somewhere in current.group a RadioButton is set to True.
|
||||
### Our quest is to find it.
|
||||
for rb in current.group:
|
||||
if rb.get_label() == current.get_label():
|
||||
continue
|
||||
if rb.base_widget.state == True:
|
||||
self.activeiface = rb.base_widget.get_label()
|
||||
break
|
||||
self.gateway=self.get_default_gateway_linux()
|
||||
self.getNetwork()
|
||||
self.setNetworkDetails()
|
||||
return
|
||||
|
||||
def radioSelectExtIf(self, current, state, user_data=None):
|
||||
"""Update network details and display information"""
|
||||
### This makes no sense, but urwid returns the previous object.
|
||||
### The previous object has True state, which is wrong..
|
||||
### Somewhere in current.group a RadioButton is set to True.
|
||||
### Our quest is to find it.
|
||||
for rb in current.group:
|
||||
if rb.get_label() == current.get_label():
|
||||
continue
|
||||
if rb.base_widget.state == True:
|
||||
if rb.base_widget.get_label() == "Yes":
|
||||
self.extdhcp=True
|
||||
else:
|
||||
self.extdhcp=False
|
||||
break
|
||||
self.setExtIfaceFields(self.extdhcp)
|
||||
return
|
||||
|
||||
def setNetworkDetails(self):
|
||||
#condensed mode:
|
||||
self.net_text1.set_text("Interface: %-13s Link: %s" % (self.activeiface, self.netsettings[self.activeiface]['link'].upper()))
|
||||
self.net_text2.set_text("IP: %-15s MAC: %s" % (self.netsettings[self.activeiface]['addr'],
|
||||
self.netsettings[self.activeiface]['mac']))
|
||||
self.net_text3.set_text("Netmask: %-15s Gateway: %s" %
|
||||
(self.netsettings[self.activeiface]['netmask'],
|
||||
self.gateway))
|
||||
log.debug("bootproto for %s: %s" % (self.netsettings[self.activeiface],
|
||||
self.netsettings[self.activeiface]['bootproto']))
|
||||
if self.netsettings[self.activeiface]['link'].upper() == "UP":
|
||||
if self.netsettings[self.activeiface]['bootproto'] == "dhcp":
|
||||
self.net_text4.set_text("WARNING: Cannot use interface running DHCP.\n\
|
||||
Reconfigure as static in Network Setup screen.")
|
||||
else:
|
||||
self.net_text4.set_text("")
|
||||
else:
|
||||
self.net_text4.set_text("WARNING: This interface is DOWN. Configure it first.")
|
||||
|
||||
#Calculate and set Static/DHCP pool fields
|
||||
#Max IPs = net size - 2 (master node + bcast)
|
||||
net_ip_list = network.getNetwork(self.netsettings[self.activeiface]['addr'],
|
||||
self.netsettings[self.activeiface]['netmask'])
|
||||
try:
|
||||
half = int(len(net_ip_list)/2)
|
||||
static_pool = list(net_ip_list[:half])
|
||||
dhcp_pool = list(net_ip_list[half:])
|
||||
static_start = str(static_pool[0])
|
||||
static_end = str(static_pool[-1])
|
||||
dynamic_start = str(dhcp_pool[0])
|
||||
dynamic_end = str(dhcp_pool[-1])
|
||||
if self.net_text4.get_text() == "":
|
||||
self.net_text4.set_text("This network configuration can support %s \
|
||||
nodes." % len(dhcp_pool))
|
||||
except:
|
||||
#We don't have valid values, so mark all fields empty
|
||||
static_start = ""
|
||||
static_end = ""
|
||||
dynamic_start = ""
|
||||
dynamic_end = ""
|
||||
for index, key in enumerate(fields):
|
||||
if key == "ADMIN_NETWORK/static_start":
|
||||
self.edits[index].set_edit_text(static_start)
|
||||
elif key == "ADMIN_NETWORK/static_end":
|
||||
self.edits[index].set_edit_text(static_end)
|
||||
elif key == "ADMIN_NETWORK/first":
|
||||
self.edits[index].set_edit_text(dynamic_start)
|
||||
elif key == "ADMIN_NETWORK/last":
|
||||
self.edits[index].set_edit_text(dynamic_end)
|
||||
|
||||
|
||||
#def setExtIfaceFields(self, enabled=True):
|
||||
# ###TODO: Define ext iface fields as disabled and then toggle
|
||||
# pass
|
||||
def screenUI(self):
|
||||
#Define your text labels, text fields, and buttons first
|
||||
text1 = urwid.Text("Settings for PXE booting of slave nodes.")
|
||||
text2 = urwid.Text("Select the interface where PXE will run:")
|
||||
#Current network settings
|
||||
self.net_text1 = TextLabel("")
|
||||
self.net_text2 = TextLabel("")
|
||||
self.net_text3 = TextLabel("")
|
||||
self.net_text4 = TextLabel("")
|
||||
log.debug("Default iface %s" % self.activeiface)
|
||||
self.net_choices = ChoicesGroup(self, sorted(self.netsettings.keys()),
|
||||
default_value=self.activeiface,
|
||||
fn=self.radioSelectIface)
|
||||
|
||||
self.edits = []
|
||||
toolbar = self.parent.footer
|
||||
for key in fields:
|
||||
#for key, values in DEFAULTS.items():
|
||||
#Example: key = hostname, label = Hostname, value = fuel-pm
|
||||
if key == "blank":
|
||||
self.edits.append(blank)
|
||||
elif DEFAULTS[key]["value"] == "radio":
|
||||
label = TextLabel(DEFAULTS[key]["label"])
|
||||
choices = ChoicesGroup(self,["Yes", "No"],
|
||||
default_value="Yes", fn=self.radioSelectExtIf)
|
||||
self.edits.append(Columns([label,choices]))
|
||||
elif DEFAULTS[key]["value"] == "label":
|
||||
self.edits.append(TextLabel(DEFAULTS[key]["label"]))
|
||||
else:
|
||||
caption = DEFAULTS[key]["label"]
|
||||
default = DEFAULTS[key]["value"]
|
||||
tooltip = DEFAULTS[key]["tooltip"]
|
||||
self.edits.append(TextField(key, caption, 23, default, tooltip, toolbar))
|
||||
|
||||
|
||||
#Button to check
|
||||
button_check = Button("Check", self.check)
|
||||
#Button to revert to previously saved settings
|
||||
button_cancel = Button("Cancel", self.cancel)
|
||||
#Button to apply (and check again)
|
||||
button_apply = Button("Apply", self.apply)
|
||||
|
||||
#Wrap buttons into Columns so it doesn't expand and look ugly
|
||||
check_col = Columns([button_check, button_cancel,
|
||||
button_apply,('weight',2,blank)])
|
||||
|
||||
self.listbox_content = [text1, blank, text2]
|
||||
self.listbox_content.extend([self.net_choices, self.net_text1,
|
||||
self.net_text2, self.net_text3,
|
||||
self.net_text4, blank])
|
||||
self.listbox_content.extend(self.edits)
|
||||
self.listbox_content.append(blank)
|
||||
self.listbox_content.append(check_col)
|
||||
|
||||
#Add listeners
|
||||
|
||||
#Build all of these into a list
|
||||
#self.listbox_content = [ text1, blank, blank, edit1, edit2, \
|
||||
# edit3, edit4, edit5, edit6, button_check ]
|
||||
self.setNetworkDetails()
|
||||
|
||||
#Add everything into a ListBox and return it
|
||||
self.listwalker=urwid.SimpleListWalker(self.listbox_content)
|
||||
screen = urwid.ListBox(self.listwalker)
|
||||
return screen
|
||||
|
@ -1,382 +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
|
||||
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.mirrors')
|
||||
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 = ["HOSTNAME", "DNS_DOMAIN", "DNS_SEARCH","DNS_UPSTREAM","blank", "TEST_DNS"]
|
||||
|
||||
DEFAULTS = {
|
||||
"HOSTNAME" : { "label" : "Hostname",
|
||||
"tooltip": "Hostname to use for Fuel master node",
|
||||
"value" : "fuel"},
|
||||
"DNS_UPSTREAM" : { "label" : "External DNS",
|
||||
"tooltip": "DNS server(s) (comma separated) to handle DNS\
|
||||
requests (example 8.8.8.8)",
|
||||
"value" : "8.8.8.8"},
|
||||
"DNS_DOMAIN" : { "label" : "Domain",
|
||||
"tooltip": "Domain suffix to user for all nodes in your cluster",
|
||||
"value" : "example.com"},
|
||||
"DNS_SEARCH" : { "label" : "Search Domain",
|
||||
"tooltip": "Domains to search when looking up DNS\
|
||||
(space separated)",
|
||||
"value" : "example.com"},
|
||||
"TEST_DNS" : { "label" : "Hostname to test DNS:",
|
||||
"value" : "www.google.com",
|
||||
"tooltip": "DNS record to resolve to see if DNS is \
|
||||
accessible",}
|
||||
}
|
||||
|
||||
|
||||
|
||||
class dnsandhostname(urwid.WidgetWrap):
|
||||
def __init__(self, parent):
|
||||
self.name="DNS & Hostname"
|
||||
self.priority=15
|
||||
self.visible=True
|
||||
self.netsettings = dict()
|
||||
self.deployment="pre"
|
||||
self.getNetwork()
|
||||
self.gateway=self.get_default_gateway_linux()
|
||||
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":
|
||||
pass
|
||||
else:
|
||||
responses[fieldname]=self.edits[index].get_edit_text()
|
||||
|
||||
###Validate each field
|
||||
errors=[]
|
||||
|
||||
#hostname must be under 60 chars
|
||||
if len(responses["HOSTNAME"]) >= 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("<L", int(fields[2], 16)))
|
||||
|
||||
def radioSelectIface(self, current, state, user_data=None):
|
||||
"""Update network details and display information"""
|
||||
### This makes no sense, but urwid returns the previous object.
|
||||
### The previous object has True state, which is wrong..
|
||||
### Somewhere in current.group a RadioButton is set to True.
|
||||
### Our quest is to find it.
|
||||
for rb in current.group:
|
||||
if rb.get_label() == current.get_label():
|
||||
continue
|
||||
if rb.base_widget.state == True:
|
||||
self.activeiface = rb.base_widget.get_label()
|
||||
break
|
||||
self.gateway=self.get_default_gateway_linux()
|
||||
self.getNetwork()
|
||||
self.setNetworkDetails()
|
||||
return
|
||||
|
||||
def screenUI(self):
|
||||
#Define your text labels, text fields, and buttons first
|
||||
text1 = urwid.Text("DNS and hostname setup")
|
||||
text2 = urwid.Text("Note: Leave External DNS blank if you do not have"\
|
||||
" Internet access.")
|
||||
|
||||
self.edits = []
|
||||
toolbar = self.parent.footer
|
||||
for key in fields:
|
||||
#for key, values in DEFAULTS.items():
|
||||
#Example: key = hostname, label = Hostname, value = fuel-pm
|
||||
if key == "blank":
|
||||
self.edits.append(blank)
|
||||
elif DEFAULTS[key]["value"] == "radio":
|
||||
label = TextLabel(DEFAULTS[key]["label"])
|
||||
choices = ChoicesGroup(self,["Yes", "No"],
|
||||
default_value="Yes", fn=self.radioSelectExtIf)
|
||||
self.edits.append(Columns([label,choices]))
|
||||
else:
|
||||
caption = DEFAULTS[key]["label"]
|
||||
default = DEFAULTS[key]["value"]
|
||||
tooltip = DEFAULTS[key]["tooltip"]
|
||||
self.edits.append(TextField(key, caption, 23, default, tooltip, toolbar))
|
||||
|
||||
#Button to check
|
||||
button_check = Button("Check", self.check)
|
||||
#Button to revert to previously saved settings
|
||||
button_cancel = Button("Cancel", self.cancel)
|
||||
#Button to apply (and check again)
|
||||
button_apply = Button("Apply", self.apply)
|
||||
|
||||
#Wrap buttons into Columns so it doesn't expand and look ugly
|
||||
check_col = Columns([button_check, button_cancel,
|
||||
button_apply,('weight',2,blank)])
|
||||
|
||||
self.listbox_content = [text1,blank,text2, blank]
|
||||
self.listbox_content.extend(self.edits)
|
||||
self.listbox_content.append(blank)
|
||||
self.listbox_content.append(check_col)
|
||||
|
||||
#Add listeners
|
||||
|
||||
#Build all of these into a list
|
||||
#self.listbox_content = [ text1, blank, blank, edit1, edit2, \
|
||||
# edit3, edit4, edit5, edit6, button_check ]
|
||||
|
||||
#Add everything into a ListBox and return it
|
||||
self.listwalker=urwid.SimpleListWalker(self.listbox_content)
|
||||
screen = urwid.ListBox(self.listwalker)
|
||||
return screen
|
||||
|
@ -1,417 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import urwid
|
||||
import urwid.raw_display
|
||||
import urwid.web_display
|
||||
import logging
|
||||
import sys
|
||||
import copy
|
||||
import socket, struct
|
||||
import re
|
||||
import netaddr
|
||||
sys.path.append("/home/mmosesohn/git/fuel/iso/fuelmenu")
|
||||
from settings import *
|
||||
from common import network, puppet, replace, dialog
|
||||
from common.urwidwrapper import *
|
||||
blank = urwid.Divider()
|
||||
|
||||
|
||||
#Need to define fields in order so it will render correctly
|
||||
fields = ["blank", "ifname", "onboot", "bootproto", "ipaddr", "netmask", "gateway"]
|
||||
|
||||
DEFAULTS = {
|
||||
"ifname" : { "label" : "Interface name:",
|
||||
"tooltip": "Interface system identifier",
|
||||
"value" : "locked"},
|
||||
"onboot" : { "label" : "Enabled on boot:",
|
||||
"tooltip": "",
|
||||
"value" : "radio"},
|
||||
"bootproto" : { "label" : "Configuration via DHCP:",
|
||||
"tooltip": "",
|
||||
"value" : "radio",
|
||||
"choices": ["DHCP", "Static"]},
|
||||
"ipaddr" : { "label" : "IP address:",
|
||||
"tooltip": "Manual IP address (example 192.168.1.2)",
|
||||
"value" : ""},
|
||||
"netmask" : { "label" : "Netmask:",
|
||||
"tooltip": "Manual netmask (example 255.255.255.0)",
|
||||
"value" : "255.255.255.0"},
|
||||
"gateway" : { "label" : "Default Gateway:",
|
||||
"tooltip": "Manual gateway to access Internet (example 192.168.1.1)",
|
||||
"value" : ""},
|
||||
}
|
||||
YAMLTREE = "cobbler_common"
|
||||
|
||||
|
||||
|
||||
class interfaces(urwid.WidgetWrap):
|
||||
def __init__(self, parent):
|
||||
|
||||
self.name="Network Setup"
|
||||
self.priority=5
|
||||
self.visible=True
|
||||
self.netsettings = dict()
|
||||
logging.basicConfig(filename='./fuelmenu.log',level=logging.DEBUG)
|
||||
self.log = logging
|
||||
self.log.basicConfig(filename='./fuelmenu.log',level=logging.DEBUG)
|
||||
self.log.info("init Interfaces")
|
||||
self.getNetwork()
|
||||
self.gateway=self.get_default_gateway_linux()
|
||||
self.activeiface = sorted(self.netsettings.keys())[0]
|
||||
self.extdhcp=True
|
||||
self.parent = parent
|
||||
self.screen = None
|
||||
|
||||
def check(self, args):
|
||||
"""Validates that all fields have valid values and some sanity checks"""
|
||||
#self.popup(msg="Test",buttons=None)
|
||||
#self.popup(msg="Test",buttons=None)
|
||||
#diag=dialog.display_dialog(self,TextLabel("Test"), "Test")
|
||||
#Test pop up
|
||||
#dd = popupdialog.PopUpDialog(self.screen)
|
||||
#dd = dialogdisplay.PopUp(self.screen,"Test")
|
||||
#dd.open_pop_up()
|
||||
#dd = dialogdisplay.PopUpDialog("Test")
|
||||
|
||||
#Get field information
|
||||
responses=dict()
|
||||
self.parent.footer.set_text("Checking data...")
|
||||
for index, fieldname in enumerate(fields):
|
||||
if fieldname == "blank" or fieldname == "ifname":
|
||||
pass
|
||||
elif fieldname == "bootproto":
|
||||
rb_group = self.edits[index].rb_group
|
||||
if rb_group[0].state:
|
||||
responses["bootproto"]="dhcp"
|
||||
else:
|
||||
responses["bootproto"]="none"
|
||||
elif fieldname == "onboot":
|
||||
rb_group = self.edits[index].rb_group
|
||||
if rb_group[0].state:
|
||||
responses["onboot"]="yes"
|
||||
else:
|
||||
responses["onboot"]="no"
|
||||
else:
|
||||
responses[fieldname]=self.edits[index].get_edit_text()
|
||||
|
||||
###Validate each field
|
||||
errors=[]
|
||||
#Perform checks only if enabled
|
||||
if responses["onboot"] == "no":
|
||||
return responses
|
||||
#No checks yet for DHCP, just return
|
||||
|
||||
if responses["bootproto"] == "dhcp":
|
||||
return responses
|
||||
#Check ipaddr, netmask, gateway only if static
|
||||
if responses["bootproto"] == "none":
|
||||
try:
|
||||
if netaddr.valid_ipv4(responses["ipaddr"]):
|
||||
ipaddr=netaddr.IPAddress(responses["ipaddr"])
|
||||
else:
|
||||
raise Exception("")
|
||||
except:
|
||||
errors.append("Not a valid IP address: %s" % responses["ipaddr"])
|
||||
try:
|
||||
if netaddr.valid_ipv4(responses["netmask"]):
|
||||
netmask=netaddr.IPAddress(responses["netmask"])
|
||||
if netmask.is_netmask is False:
|
||||
raise Exception("")
|
||||
else:
|
||||
raise Exception("")
|
||||
except:
|
||||
errors.append("Not a valid netmask: %s" % responses["netmask"])
|
||||
try:
|
||||
if len(responses["gateway"]) > 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("<L", int(fields[2], 16)))
|
||||
|
||||
def radioSelectIface(self, current, state, user_data=None):
|
||||
"""Update network details and display information"""
|
||||
### This makes no sense, but urwid returns the previous object.
|
||||
### The previous object has True state, which is wrong..
|
||||
### Somewhere in current.group a RadioButton is set to True.
|
||||
### Our quest is to find it.
|
||||
for rb in current.group:
|
||||
if rb.get_label() == current.get_label():
|
||||
continue
|
||||
if rb.base_widget.state == True:
|
||||
self.activeiface = rb.base_widget.get_label()
|
||||
break
|
||||
self.gateway=self.get_default_gateway_linux()
|
||||
self.getNetwork()
|
||||
self.setNetworkDetails()
|
||||
return
|
||||
|
||||
def radioSelectExtIf(self, current, state, user_data=None):
|
||||
"""Update network details and display information"""
|
||||
### This makes no sense, but urwid returns the previous object.
|
||||
### The previous object has True state, which is wrong..
|
||||
### Somewhere in current.group a RadioButton is set to True.
|
||||
### Our quest is to find it.
|
||||
for rb in current.group:
|
||||
if rb.get_label() == current.get_label():
|
||||
continue
|
||||
if rb.base_widget.state == True:
|
||||
if rb.base_widget.get_label() == "Yes":
|
||||
self.extdhcp=True
|
||||
else:
|
||||
self.extdhcp=False
|
||||
break
|
||||
self.setExtIfaceFields(self.extdhcp)
|
||||
return
|
||||
|
||||
def setNetworkDetails(self):
|
||||
#condensed mode:
|
||||
self.net_text1.set_text("Interface: %-13s Link: %s" % (self.activeiface, self.netsettings[self.activeiface]['link'].upper()))
|
||||
|
||||
self.net_text2.set_text("IP: %-15s MAC: %s" % (self.netsettings[self.activeiface]['addr'],
|
||||
self.netsettings[self.activeiface]['mac']))
|
||||
self.net_text3.set_text("Netmask: %-15s Gateway: %s" %
|
||||
(self.netsettings[self.activeiface]['netmask'],
|
||||
self.gateway))
|
||||
# #Old spread out method
|
||||
# self.net_text1.set_text("Current network settings for %s" % self.activeiface)
|
||||
# self.net_text2.set_text("MAC address: %s" % self.netsettings[self.activeiface]['mac'])
|
||||
# self.net_text3.set_text("IP address: %s" % self.netsettings[self.activeiface]['addr'])
|
||||
# self.net_text4.set_text("Netmask: %s" % self.netsettings[self.activeiface]['netmask'])
|
||||
# self.net_text5.set_text("Default gateway: %s" % (self.gateway))
|
||||
#
|
||||
#Set text fields to current netsettings
|
||||
for index, fieldname in enumerate(fields):
|
||||
if fieldname == "ifname":
|
||||
self.edits[index].base_widget.set_edit_text(self.activeiface)
|
||||
elif fieldname == "bootproto":
|
||||
rb_group = self.edits[index].rb_group
|
||||
for rb in rb_group:
|
||||
if self.netsettings[self.activeiface]["bootproto"].lower() == "dhcp":
|
||||
rb_group[0].set_state(True)
|
||||
rb_group[1].set_state(False)
|
||||
else:
|
||||
rb_group[0].set_state(False)
|
||||
rb_group[1].set_state(True)
|
||||
elif fieldname == "onboot":
|
||||
rb_group = self.edits[index].rb_group
|
||||
for rb in rb_group:
|
||||
if self.netsettings[self.activeiface]["onboot"].lower() == "yes":
|
||||
rb_group[0].set_state(True)
|
||||
rb_group[1].set_state(False)
|
||||
else:
|
||||
rb_group[0].set_state(False)
|
||||
rb_group[1].set_state(True)
|
||||
elif fieldname == "ipaddr":
|
||||
self.edits[index].set_edit_text(self.netsettings[self.activeiface]['addr'])
|
||||
elif fieldname == "netmask":
|
||||
self.edits[index].set_edit_text(self.netsettings[self.activeiface]['netmask'])
|
||||
elif fieldname == "gateway":
|
||||
#This is gateway for iface only if self.gateway is in same subnet
|
||||
if network.inSameSubnet(self.netsettings[self.activeiface]['addr'],
|
||||
self.gateway,
|
||||
self.netsettings[self.activeiface]['netmask']):
|
||||
self.edits[index].set_edit_text(self.gateway)
|
||||
else:
|
||||
self.edits[index].set_edit_text("")
|
||||
def setExtIfaceFields(self, enabled=True):
|
||||
###TODO: Define ext iface fields as disabled and then toggle
|
||||
pass
|
||||
def screenUI(self):
|
||||
#Define your text labels, text fields, and buttons first
|
||||
text1 = TextLabel("Network interface setup")
|
||||
|
||||
#Current network settings
|
||||
self.net_text1 = TextLabel("")
|
||||
self.net_text2 = TextLabel("")
|
||||
self.net_text3 = TextLabel("")
|
||||
self.net_choices = ChoicesGroup(self, sorted(self.netsettings.keys()),
|
||||
default_value=self.activeiface, fn=self.radioSelectIface)
|
||||
|
||||
self.edits = []
|
||||
toolbar = self.parent.footer
|
||||
for key in fields:
|
||||
#Example: key = hostname, label = Hostname, value = fuel
|
||||
if key == "blank":
|
||||
self.edits.append(blank)
|
||||
elif DEFAULTS[key]["value"] == "radio":
|
||||
label = TextLabel(DEFAULTS[key]["label"])
|
||||
if DEFAULTS[key].has_key("choices"):
|
||||
choices_list = DEFAULTS[key]["choices"]
|
||||
else:
|
||||
choices_list = ["Yes", "No"]
|
||||
choices = ChoicesGroup(self,choices_list,
|
||||
default_value="Yes", fn=self.radioSelectExtIf)
|
||||
columns=Columns([('weight',2,label),('weight',3,choices)])
|
||||
#Attach choices rb_group so we can use it later
|
||||
columns.rb_group = choices.rb_group
|
||||
self.edits.append(columns)
|
||||
else:
|
||||
caption = DEFAULTS[key]["label"]
|
||||
default = DEFAULTS[key]["value"]
|
||||
tooltip = DEFAULTS[key]["tooltip"]
|
||||
disabled = True if key == "ifname" else False
|
||||
self.edits.append(TextField(key, caption, 23, default, tooltip,
|
||||
toolbar, disabled=disabled))
|
||||
|
||||
|
||||
#Button to check
|
||||
button_check = Button("Check", self.check)
|
||||
#Button to apply (and check again)
|
||||
button_apply = Button("Apply", self.apply)
|
||||
|
||||
#Wrap buttons into Columns so it doesn't expand and look ugly
|
||||
check_col = Columns([button_check, button_apply,('weight',3,blank)])
|
||||
|
||||
self.listbox_content = [text1, blank]
|
||||
self.listbox_content.extend([self.net_choices, self.net_text1,
|
||||
self.net_text2, self.net_text3,
|
||||
blank])
|
||||
self.listbox_content.extend(self.edits)
|
||||
self.listbox_content.append(blank)
|
||||
self.listbox_content.append(check_col)
|
||||
|
||||
#Add listeners
|
||||
|
||||
#Build all of these into a list
|
||||
#self.listbox_content = [ text1, blank, blank, edit1, edit2, \
|
||||
# edit3, edit4, edit5, edit6, button_check ]
|
||||
|
||||
#Add everything into a ListBox and return it
|
||||
self.listwalker=urwid.SimpleListWalker(self.listbox_content)
|
||||
screen = urwid.ListBox(self.listwalker)
|
||||
self.setNetworkDetails()
|
||||
self.screen = screen
|
||||
return screen
|
||||
|
@ -1,123 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import urwid
|
||||
import urwid.raw_display
|
||||
import urwid.web_display
|
||||
import logging
|
||||
import sys
|
||||
import copy
|
||||
sys.path.append("/home/mmosesohn/git/fuel/iso/fuelmenu")
|
||||
from settings import *
|
||||
from common.urwidwrapper import *
|
||||
log = logging.getLogger('fuelmenu.mirrors')
|
||||
log.info("test")
|
||||
blank = urwid.Divider()
|
||||
|
||||
DEFAULTS = {
|
||||
"custom_mirror" : "http://mirror.your-company-name.com/",
|
||||
"parent_proxy" : "",
|
||||
"port" : "3128"
|
||||
}
|
||||
|
||||
class mirrors(urwid.WidgetWrap):
|
||||
def __init__(self, parent):
|
||||
self.name="Repo Mirrors"
|
||||
self.priority=25
|
||||
self.visible=False
|
||||
self.parent = parent
|
||||
self.listbox_content = []
|
||||
self.settings = copy.deepcopy(DEFAULTS)
|
||||
self.screen = self.screenUI()
|
||||
|
||||
def apply(self, args):
|
||||
if not self.check(args):
|
||||
log.error("Check failed. Not applying")
|
||||
return False
|
||||
conf = Settings()
|
||||
conf.write(module="mirrors",values=self.settings)
|
||||
|
||||
def check(self, args):
|
||||
log = logging.getLogger('fuelmenu.mirrors')
|
||||
|
||||
customurl = self.edit1.get_edit_text()
|
||||
self.parent.footer.set_text("Checking %s" % customurl)
|
||||
log.info("Checking %s" % customurl)
|
||||
if self.repochoice == "Defult":
|
||||
self.parent.footer.set_text("")
|
||||
pass
|
||||
else:
|
||||
#Ensure host can connect
|
||||
import subprocess
|
||||
reachable = subprocess.call(["curl","-o","/dev/null","--silent","--head","--write-out","'%{http_code}\n'",customurl])
|
||||
error_msg = None
|
||||
if reachable == 0:
|
||||
pass
|
||||
elif reachable == 1 or reachable == 3:
|
||||
error_msg = u"Unrecognized protocol. Did you spell it right?"
|
||||
elif reachable == 6:
|
||||
error_msg = u"Couldn't resolve host."
|
||||
elif reachable == 7:
|
||||
error_msg = u"Couldn't connect to host."
|
||||
elif reachable == 6:
|
||||
error_msg = u"Couldn't resolve host."
|
||||
if error_msg:
|
||||
self.parent.footer.set_text("Could not reach custom mirror. Error: %s" % (error_msg))
|
||||
return False
|
||||
self.parent.footer.set_text("Reached custom mirror!")
|
||||
|
||||
#Ensure valid page with 2XX or 3XX return code
|
||||
status_code = subprocess.check_output(["curl","-o","/dev/null","--silent","--head","--write-out","'\%{http_code}'",customurl])
|
||||
import re
|
||||
regexp = re.compile(r'[23]\d\d')
|
||||
if regexp.search(status_code) is not None:
|
||||
error_msg = "URL not reachable on server. Error %s" % status_code
|
||||
log.error("Could not reach custom url %s. Error code: %s" % (customurl, reachable))
|
||||
self.parent.footer.set_text("Could not reach custom url %s. Error code: %s" % (customurl, reachable))
|
||||
return False
|
||||
|
||||
self.parent.footer.set_text("Repo mirror OK!")
|
||||
return True
|
||||
|
||||
def radioSelect(self, current, state, user_data=None):
|
||||
for rb in current.group:
|
||||
if rb.get_label() == current.get_label():
|
||||
continue
|
||||
if rb.base_widget.state == True:
|
||||
self.repochoice = rb.base_widget.get_label()
|
||||
break
|
||||
|
||||
#def keypress(self, size, key):
|
||||
# self.parent.footer.set_text("keypress")
|
||||
#def displayTooltip(self, obj):
|
||||
# focus = obj.get_focus()[0].content
|
||||
# self.parent.footer.set_text(focus.get_label())
|
||||
|
||||
def screenUI(self):
|
||||
#Define your text labels, text fields, and buttons first
|
||||
text1 = TextLabel(u"Choose repo mirrors to use.\n"
|
||||
u"Note: Refer to Fuel documentation on how to set up a custom mirror.")
|
||||
choice_list = [u"Default", u"Custom"]
|
||||
self.choices = ChoicesGroup(self, choice_list)
|
||||
self.repochoice = "Default"
|
||||
#self.edit1 = TextField("custom_mirror", "Custom URL:", 15, DEFAULTS["custom_mirror"], "URL goes here", self.parent.footer)
|
||||
self.edit1 = TextField("custom_mirror", "Custom URL:", 15, DEFAULTS["custom_mirror"], "URL goes here", self.parent.footer)
|
||||
self.edit2 = TextField("parent_proxy", "Squid parent proxy:", 20, DEFAULTS["parent_proxy"], "Squid proxy URL (include http://)", self.parent.footer)
|
||||
self.edit3 = TextField("port", "Port:", 5, DEFAULTS["parent_proxy"], "Squid Proxy port (usually 3128)", self.parent.footer)
|
||||
self.proxyedits = Columns([('weight', 3, self.edit2), self.edit3])
|
||||
|
||||
#Button to check
|
||||
button_check = Button("Check", self.check)
|
||||
#Button to apply (and check again)
|
||||
button_apply = Button("Apply", self.apply)
|
||||
#Wrap into Columns so it doesn't expand and look ugly
|
||||
check_col = Columns([button_check, button_apply,('weight',7,blank)])
|
||||
|
||||
#Build all of these into a list
|
||||
self.listbox_content = [ text1, blank, blank, self.choices, blank, self.edit1, blank, self.proxyedits, blank, blank, check_col ]
|
||||
|
||||
#Add everything into a ListBox and return it
|
||||
walker = urwid.SimpleListWalker(self.listbox_content)
|
||||
#urwid.connect_signal(walker, 'modified', self.displayTooltip)
|
||||
self.myscreen = urwid.ListBox(walker)
|
||||
return self.myscreen
|
||||
|
@ -1,39 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import urwid
|
||||
import urwid.raw_display
|
||||
import urwid.web_display
|
||||
from common.urwidwrapper import *
|
||||
import subprocess
|
||||
|
||||
blank = urwid.Divider()
|
||||
|
||||
|
||||
class shell():
|
||||
def __init__(self, parent):
|
||||
self.name="Shell Login"
|
||||
self.priority=99
|
||||
self.visible=True
|
||||
self.parent=parent
|
||||
#self.screen = self.screenUI()
|
||||
def check(self):
|
||||
#TODO: Ensure all params are filled out and sensible
|
||||
return True
|
||||
|
||||
def start_shell(self, args):
|
||||
self.parent.mainloop.screen.stop()
|
||||
message="Type exit to return to the main UI."
|
||||
subprocess.call("clear ; echo '%s';echo; bash" % message, shell=True)
|
||||
self.parent.mainloop.screen.start()
|
||||
|
||||
def screenUI(self):
|
||||
#Define your text labels, text fields, and buttons first
|
||||
text1 = urwid.Text("Press the button below to enter a shell login.")
|
||||
login_button = Button("Shell Login",self.start_shell)
|
||||
#Build all of these into a list
|
||||
listbox_content = [ text1, blank, login_button ]
|
||||
|
||||
#Add everything into a ListBox and return it
|
||||
screen = urwid.ListBox(urwid.SimpleListWalker(listbox_content))
|
||||
return screen
|
||||
|
@ -1,102 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
import urwid
|
||||
import urwid.raw_display
|
||||
import urwid.web_display
|
||||
from common.urwidwrapper import *
|
||||
|
||||
|
||||
blank = urwid.Divider()
|
||||
|
||||
|
||||
class welcome():
|
||||
def __init__(self, parent):
|
||||
self.name="Welcome"
|
||||
self.priority=1
|
||||
self.visible=False
|
||||
self.screen = self.screenUI()
|
||||
|
||||
def check(self):
|
||||
#TODO: Ensure all params are filled out and sensible
|
||||
return True
|
||||
|
||||
def screenUI(self):
|
||||
#Define your text labels, text fields, and buttons first
|
||||
text1 = urwid.Text("Welcome to Fuel! Use the menu on the left")
|
||||
fuellogo_huge=[
|
||||
[('light gray','YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY')],
|
||||
[('light gray','YYYY'),('red','YYYYYYYYYYYYYYYYYYYY'),('light gray','YYYYYYYYYY'),('red','YYYY'),('light gray','YYYYYYYYYYYY'),('red','YYYY'),('light gray','YYYYYYYYYYYY'),('red','YYYYYYYYYYYYYYYYYYYY'),('light gray','YYYYYYYYYY'),('red','YYYY'),('light gray','YYYYYYYYYYYYYYYYYYYY')],
|
||||
[('light gray','YY'),('red','YYYYYYYYYYYYYYYYYYYYYYYY'),('light gray','YYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYYYYYYYYYYYYYYYYYY'),('light gray','YYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYY')],
|
||||
[('light gray','YY'),('red','YYYYYYYYYYYYYYYYYYYYYYYY'),('light gray','YYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYYYYYYYYYYYYYYYYYY'),('light gray','YYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYY')],
|
||||
[('light gray','YY'),('red','YYYYYYYYYYYYYYYYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYYYYYYYYYYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYY')],
|
||||
[('light gray','YY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYY')],
|
||||
[('light gray','YY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYY')],
|
||||
[('light gray','YY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYY')],
|
||||
[('light gray','YY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYY')],
|
||||
[('light gray','YY'),('red','YYYYYYYYYYYYYYYY'),('light gray','YYYYYYYYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYYYYYYYYYY'),('light gray','YYYYYYYYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYY')],
|
||||
[('light gray','YY'),('red','YYYYYYYYYYYYYYYYYY'),('light gray','YYYYYYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYYYYYYYYYYYY'),('light gray','YYYYYYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYY')],
|
||||
[('light gray','YY'),('red','YYYYYYYYYYYYYYYYYY'),('light gray','YYYYYYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYYYYYYYYYYYY'),('light gray','YYYYYYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYY')],
|
||||
[('light gray','YY'),('red','YYYYYYYYYYYYYYYY'),('light gray','YYYYYYYYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYYYYYYYYYY'),('light gray','YYYYYYYYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYY')],
|
||||
[('light gray','YY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYY')],
|
||||
[('light gray','YY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYY')],
|
||||
[('light gray','YY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYY')],
|
||||
[('light gray','YY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYY')],
|
||||
[('light gray','YY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYYYYYYYY'),('red','YYYYYYYY'),('light gray','YYYY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYY'),('red','YYYYYYYYYYYYYYYYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYYYYYYYYYYYYYYYY'),('light gray','YYYY')],
|
||||
[('light gray','YY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYYYYYYYY'),('red','YYYYYYYYYYYYYYYYYYYY'),('light gray','YYYYYYYYYY'),('red','YYYYYYYYYYYYYYYYYYYYYYYY'),('light gray','YYYYYY'),('red','YYYYYYYYYYYYYYYYYYYYYYYY'),('light gray','YY')],
|
||||
[('light gray','YY'),('red','YYYYYYYY'),('light gray','YYYYYYYYYYYYYYYYYYYYYYYYYY'),('red','YYYYYYYYYYYYYYYY'),('light gray','YYYYYYYYYYYY'),('red','YYYYYYYYYYYYYYYYYYYYYYYY'),('light gray','YYYYYY'),('red','YYYYYYYYYYYYYYYYYYYYYYYY'),('light gray','YY')],
|
||||
[('light gray','YYYY'),('red','YYYY'),('light gray','YYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'),('red','YYYYYYYYYYYY'),('light gray','YYYYYYYYYYYYYYYY'),('red','YYYYYYYYYYYYYYYYYYYY'),('light gray','YYYYYYYY'),('red','YYYYYYYYYYYYYYYYYYYYYY'),('light gray','YYYY')],
|
||||
[('light gray','YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY')],
|
||||
[('light gray','YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY')],
|
||||
[('light gray','YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY')],
|
||||
[('light gray','YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY')],
|
||||
[('light gray','YYYYYY'),('black','YYYY'),('light gray','YYYYYYYYYYYYYYYYYYYYYYYYYY'),('black','YYYYYY'),('light gray','YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'),('black','YYYYYY'),('light gray','YYYYYYYYYYYYYYYYYYYYYYYYYY'),('black','YY'),('light gray','YYYYYYYY')],
|
||||
[('light gray','YYYY'),('black','YY'),('light gray','YYYYYYYYYYYYYYYYYYYYYYYYYYYY'),('black','YY'),('light gray','YYYYYY'),('black','YY'),('light gray','YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'),('black','YY'),('light gray','YYYYYYYY'),('black','YY'),('light gray','YYYYYYYYYYYYYYYYYYYYYY'),('black','YY'),('light gray','YYYYYYYY')],
|
||||
[('light gray','YY'),('black','YYYYYY'),('light gray','YYYY'),('black','YYYY'),('light gray','YYYY'),('black','YYYY'),('light gray','YYYYYYYYYY'),('black','YY'),('light gray','YYYYYY'),('black','YY'),('light gray','YY'),('black','YYYYYY'),('light gray','YYYYYY'),('black','YYYY'),('light gray','YYYY'),('black','YYYYYY'),('light gray','YYYY'),('black','YY'),('light gray','YYYYYY'),('black','YYYYYY'),('light gray','YY'),('black','YYYYYY'),('light gray','YYYYYY'),('black','YYYY'),('light gray','YY'),('black','YY'),('light gray','YYYY'),('black','YY'),('light gray','YY')],
|
||||
[('light gray','YYYY'),('black','YY'),('light gray','YYYY'),('black','YY'),('light gray','YYYY'),('black','YY'),('light gray','YY'),('black','YY'),('light gray','YYYYYYYYYYYY'),('black','YY'),('light gray','YYYYYY'),('black','YY'),('light gray','YY'),('black','YY'),('light gray','YYYY'),('black','YY'),('light gray','YY'),('black','YY'),('light gray','YYYY'),('black','YY'),('light gray','YY'),('black','YY'),('light gray','YYYY'),('black','YY'),('light gray','YYYY'),('black','YY'),('light gray','YYYYYY'),('black','YY'),('light gray','YYYYYYYYYY'),('black','YY'),('light gray','YY'),('black','YY'),('light gray','YYYYYY'),('black','YY'),('light gray','YY'),('black','YY'),('light gray','YYYY')],
|
||||
[('light gray','YYYY'),('black','YY'),('light gray','YYYY'),('black','YY'),('light gray','YYYY'),('black','YY'),('light gray','YY'),('black','YY'),('light gray','YYYYYYYYYYYY'),('black','YY'),('light gray','YYYYYY'),('black','YY'),('light gray','YY'),('black','YY'),('light gray','YYYY'),('black','YY'),('light gray','YY'),('black','YYYYYYYY'),('light gray','YY'),('black','YY'),('light gray','YYYY'),('black','YY'),('light gray','YYYYYY'),('black','YY'),('light gray','YYYY'),('black','YY'),('light gray','YYYYYY'),('black','YYYYYY'),('light gray','YY'),('black','YY'),('light gray','YYYYYY'),('black','YYYY'),('light gray','YYYYYY')],
|
||||
[('light gray','YYYY'),('black','YY'),('light gray','YYYY'),('black','YY'),('light gray','YYYY'),('black','YY'),('light gray','YY'),('black','YY'),('light gray','YYYYYYYYYYYY'),('black','YY'),('light gray','YYYYYY'),('black','YY'),('light gray','YY'),('black','YY'),('light gray','YYYY'),('black','YY'),('light gray','YY'),('black','YY'),('light gray','YYYYYYYY'),('black','YY'),('light gray','YYYY'),('black','YY'),('light gray','YYYYYYYY'),('black','YY'),('light gray','YY'),('black','YY'),('light gray','YYYY'),('black','YY'),('light gray','YYYY'),('black','YY'),('light gray','YY'),('black','YY'),('light gray','YYYYYY'),('black','YY'),('light gray','YY'),('black','YY'),('light gray','YYYY')],
|
||||
[('light gray','YYYY'),('black','YY'),('light gray','YYYY'),('black','YY'),('light gray','YYYY'),('black','YY'),('light gray','YY'),('black','YY'),('light gray','YYYYYYYYYYYY'),('black','YY'),('light gray','YYYYYY'),('black','YY'),('light gray','YY'),('black','YY'),('light gray','YYYY'),('black','YY'),('light gray','YY'),('black','YY'),('light gray','YYYYYYYY'),('black','YY'),('light gray','YYYY'),('black','YY'),('light gray','YYYYYYYY'),('black','YY'),('light gray','YY'),('black','YY'),('light gray','YYYY'),('black','YY'),('light gray','YYYY'),('black','YY'),('light gray','YY'),('black','YY'),('light gray','YYYYYY'),('black','YY'),('light gray','YY'),('black','YY'),('light gray','YYYY')],
|
||||
[('light gray','YYYY'),('black','YY'),('light gray','YYYYYY'),('black','YYYY'),('light gray','YYYY'),('black','YY'),('light gray','YYYYYYYYYYYYYY'),('black','YYYYYY'),('light gray','YYYY'),('black','YYYYYY'),('light gray','YYYYYY'),('black','YYYYYY'),('light gray','YY'),('black','YY'),('light gray','YYYY'),('black','YY'),('light gray','YY'),('black','YYYYYY'),('light gray','YYYYYY'),('black','YY'),('light gray','YYYY'),('black','YYYYYY'),('light gray','YYYY'),('black','YYYY'),('light gray','YY'),('black','YY'),('light gray','YYYY'),('black','YY'),('light gray','YY')],
|
||||
[('light gray','YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'),('black','YY'),('light gray','YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY')],
|
||||
[('light gray','YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY'),('black','YY'),('light gray','YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY')],
|
||||
[('light gray','YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY')],
|
||||
]
|
||||
fuellogo_small=[
|
||||
[('red',u'±ÛÛÛÛÛÛÛÛÛÛ± ±ÛÛ± ±ÛÛ± ±ÛÛÛÛÛÛÛÛÛ± ±ÛÛ± TM')],
|
||||
[('red',u'Û²²²²²²²²²²Û Û²²² Û²²² Û²²²²²²²²²² Û²²²')],
|
||||
[('red',u'Û²²²²²²²²²²° Û²²² Û²²² Û²²²²²²²²²± Û²²²')],
|
||||
#[('red',u'Û²²² Û²²² Û²²² Û²²² Û²²²')],
|
||||
#[('red',u'Û²²² Û²²² Û²²² Û²²² Û²²²')],
|
||||
[('red',u'Û²²² Û²²² Û²²² Û²²² Û²²²')],
|
||||
[('red',u'Û²²² Û²²² Û²²² Û²²² Û²²²')],
|
||||
[('red',u'Û²²²ÛÛÛÛÛ Û²²² Û²²² Û²²²ÛÛÛÛÛ Û²²²')],
|
||||
[('red',u'Û²²²²²²²² Û²²² Û²²² Û²²²²²²²² Û²²²')],
|
||||
#[('red',u'Û²²² Û²²² Û²²² Û²²² Û²²²')],
|
||||
#[('red',u'Û²²² Û²²² Û²²² Û²²² Û²²²')],
|
||||
[('red',u'Û²²² Û²²² Û²²² Û²²² Û²²²')],
|
||||
[('red',u'Û²²² Û²²²Û Û²²²² Û²²² Û²²²')],
|
||||
[('red',u'Û²²² ±²²²²ÛÛÛ²²²²° Û²²²ÛÛÛÛÛÛ° Û²²²ÛÛÛÛÛÛÛ°')],
|
||||
[('red',u'Û²²² ²²²²²²²²²²² Û²²²²²²²²²Û Û²²²²²²²²²²Û')],
|
||||
[('red',u'±²²° °²²²²²²²° ±²²²²²²²²²° ±²²²²²²²²²²°')],
|
||||
#[''],
|
||||
#[''],
|
||||
[('light gray',u' ÛÛ ÛÛÛ ÛÛÛ Û R')],
|
||||
[('light gray',u' Û Û Û Û Û Û ')],
|
||||
[('light gray',u'ÛÛÛ ÛÛ ÛÛÛ Û Û ÛÛÛ ÛÛÛÛ ÛÛÛÛ Û ÛÛÛ ÛÛ ÛÛ Û Û')],
|
||||
[('light gray',u' Û Û Û Û Û Û Û Û Û Û Û Û ÛÛ Û Û Û Û Û')],
|
||||
[('light gray',u' Û Û Û Û Û Û Û Û ÛÛÛÛ Û Û Û Û ÛÛÛ Û ÛÛ')],
|
||||
[('light gray',u' Û Û Û Û Û Û Û Û Û Û Û Û Û Û Û Û Û Û')],
|
||||
[('light gray',u' Û ÛÛ Û ÛÛÛ ÛÛÛ ÛÛÛÛ Û Û ÛÛÛ ÛÛ ÛÛÛ ÛÛ Û Û')],
|
||||
[('light gray',u' Û')],
|
||||
[('light gray',u' Û')],
|
||||
]
|
||||
logotexts=[]
|
||||
for line in fuellogo_small:
|
||||
logotexts.append(TextLabel(line))
|
||||
#Build all of these into a list
|
||||
listbox_content = [ text1 ] + logotexts
|
||||
|
||||
#Add everything into a ListBox and return it
|
||||
screen = urwid.ListBox(urwid.SimpleListWalker(listbox_content))
|
||||
return screen
|
||||
|
@ -1,7 +0,0 @@
|
||||
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
|
102
settings.py
102
settings.py
@ -1,102 +0,0 @@
|
||||
import yaml
|
||||
import collections
|
||||
try:
|
||||
from collections import OrderedDict
|
||||
except:
|
||||
# python 2.6 or earlier use backport
|
||||
from ordereddict import OrderedDict
|
||||
def construct_ordered_mapping(self, node, deep=False):
|
||||
if not isinstance(node, yaml.MappingNode):
|
||||
raise ConstructorError(None, None,
|
||||
"expected a mapping node, but found %s" % node.id,
|
||||
node.start_mark)
|
||||
mapping = OrderedDict()
|
||||
for key_node, value_node in node.value:
|
||||
key = self.construct_object(key_node, deep=deep)
|
||||
if not isinstance(key, collections.Hashable):
|
||||
raise ConstructorError("while constructing a mapping", node.start_mark,
|
||||
"found unhashable key", key_node.start_mark)
|
||||
value = self.construct_object(value_node, deep=deep)
|
||||
mapping[key] = value
|
||||
return mapping
|
||||
yaml.constructor.BaseConstructor.construct_mapping = construct_ordered_mapping
|
||||
def construct_yaml_map_with_ordered_dict(self, node):
|
||||
data = OrderedDict()
|
||||
yield data
|
||||
value = self.construct_mapping(node)
|
||||
data.update(value)
|
||||
yaml.constructor.Constructor.add_constructor(
|
||||
'tag:yaml.org,2002:map',
|
||||
construct_yaml_map_with_ordered_dict)
|
||||
def represent_ordered_mapping(self, tag, mapping, flow_style=None):
|
||||
value = []
|
||||
node = yaml.MappingNode(tag, value, flow_style=flow_style)
|
||||
if self.alias_key is not None:
|
||||
self.represented_objects[self.alias_key] = node
|
||||
best_style = True
|
||||
if hasattr(mapping, 'items'):
|
||||
mapping = list(mapping.items())
|
||||
for item_key, item_value in mapping:
|
||||
node_key = self.represent_data(item_key)
|
||||
node_value = self.represent_data(item_value)
|
||||
if not (isinstance(node_key, yaml.ScalarNode) and not node_key.style):
|
||||
best_style = False
|
||||
if not (isinstance(node_value, yaml.ScalarNode) and not node_value.style):
|
||||
best_style = False
|
||||
value.append((node_key, node_value))
|
||||
if flow_style is None:
|
||||
if self.default_flow_style is not None:
|
||||
node.flow_style = self.default_flow_style
|
||||
else:
|
||||
node.flow_style = best_style
|
||||
return node
|
||||
yaml.representer.BaseRepresenter.represent_mapping = represent_ordered_mapping
|
||||
yaml.representer.Representer.add_representer(OrderedDict,
|
||||
yaml.representer.SafeRepresenter.represent_dict)
|
||||
|
||||
|
||||
class Settings():
|
||||
def __init__(self):
|
||||
pass
|
||||
def read(self, yamlfile):
|
||||
try:
|
||||
infile = file(yamlfile, 'r')
|
||||
settings = yaml.load(infile)
|
||||
return settings
|
||||
except:
|
||||
import logging
|
||||
logging.error("Unable to read YAML: %s" % yamlfile)
|
||||
return OrderedDict()
|
||||
|
||||
def write(self, newvalues, tree=None, defaultsfile='settings.yaml', outfn='mysettings.yaml'):
|
||||
settings = self.read(defaultsfile)
|
||||
settings.update(self.read(outfn))
|
||||
settings.update(newvalues)
|
||||
outfile = file(outfn, 'w')
|
||||
yaml.dump(settings, outfile, default_flow_style=False)
|
||||
return True
|
||||
|
||||
if __name__ == '__main__':
|
||||
import textwrap
|
||||
|
||||
sample = """
|
||||
one:
|
||||
two: fish
|
||||
red: fish
|
||||
blue: fish
|
||||
two:
|
||||
a: yes
|
||||
b: no
|
||||
c: null
|
||||
"""
|
||||
infile = file('settings.yaml', 'r')
|
||||
data = yaml.load(infile)
|
||||
#data = yaml.load(infile, OrderedDictYAMLLoader)
|
||||
#data = yaml.load(textwrap.dedent(sample), OrderedDictYAMLLoader)
|
||||
outfile = file("testout", 'w')
|
||||
yaml.dump(data, outfile, default_flow_style=False)
|
||||
|
||||
|
||||
#assert type(data) is OrderedDict
|
||||
print data.items()
|
||||
|
@ -1,15 +0,0 @@
|
||||
HOSTNAME: "fuel"
|
||||
DNS_DOMAIN: "example.com"
|
||||
DNS_SEARCH: "example.com"
|
||||
DNS_UPSTREAM: "8.8.8.8"
|
||||
|
||||
ADMIN_NETWORK:
|
||||
interface: "eth0"
|
||||
cidr: "10.20.0.0/24"
|
||||
netmask: "255.255.255.0"
|
||||
size: "256"
|
||||
static_start: "10.20.0.10"
|
||||
static_end: "10.20.0.120"
|
||||
first: "10.20.0.130"
|
||||
last: "10.20.0.254"
|
||||
|
Loading…
Reference in New Issue
Block a user