cleanup dhcp-checker, make fuelmenu optional
move fuelmenu to rpms directory cleanup fuelmenu files more fuelmenu cleanup
This commit is contained in:
parent
cc78e7ab4d
commit
fd9e9c8848
25
README
25
README
@ -1,25 +0,0 @@
|
||||
Fuel menu
|
||||
|
||||
This tool is used to perform setup of network interfaces, as well as configure
|
||||
Cobbler parameters. The framework is extensible.
|
||||
|
||||
Plugin guidelines:
|
||||
|
||||
Create a python class with a filename matching the class:
|
||||
class foo(urwid.Widget) and foo.py
|
||||
|
||||
Place this file in the Fuel Menu modules folder.
|
||||
|
||||
Plugin class should define the following functions:
|
||||
__init__(self, parent)
|
||||
check(self, args)
|
||||
apply(self, args)
|
||||
save(self) #Still need to complete
|
||||
load(self) #Still need to complete
|
||||
screenUI(self)
|
||||
|
||||
screenUI should use urwidwrapper class to define and set up all UI elements
|
||||
Note that you need to specify a function for buttons and radio button groups
|
||||
for them to work properly. Check and Apply buttons should point to check and
|
||||
apply functions, respectively.
|
||||
|
@ -1,74 +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 fuelmenu.settings import *
|
||||
from fuelmenu.common.urwidwrapper import *
|
||||
blank = urwid.Divider()
|
||||
|
||||
|
||||
class ModalDialog(urwid.WidgetWrap):
|
||||
signals = ['close']
|
||||
|
||||
title = None
|
||||
|
||||
def __init__(self, title, body, escape_key, previous_widget,loop=None):
|
||||
self.escape_key = escape_key
|
||||
self.previous_widget = previous_widget
|
||||
self.keep_open=True
|
||||
self.loop=loop
|
||||
logging.debug("start modal")
|
||||
logging.debug(type(body))
|
||||
|
||||
if type(body) in [str, unicode]:
|
||||
body = urwid.Text(body)
|
||||
logging.debug("Set text widget")
|
||||
self.title = title
|
||||
bodybox = urwid.LineBox(urwid.Pile([body,blank,Button("Close", self.close)]), title)
|
||||
#overlay = urwid.Overlay(urwid.Pile([bodybox]), previous_widget, 'center',
|
||||
overlay = urwid.Overlay(urwid.Filler(bodybox), previous_widget, 'center',
|
||||
('relative', 80), 'middle', ('relative', 80))
|
||||
#overlay = urwid.Overlay(body, previous_widget, 'center',
|
||||
#80, "top", 24, 80, 24,
|
||||
#0,0,0,0)
|
||||
#100, 'bottom',
|
||||
#100)
|
||||
#('relative', 100), 'bottom',
|
||||
#('relative', 100))
|
||||
overlay_attrmap = urwid.AttrMap(overlay, "body")
|
||||
#overlay_attrmap = urwid.AttrMap(overlay, "plugin.widget.dialog")
|
||||
super(ModalDialog, self).__init__(overlay_attrmap)
|
||||
logging.debug(overlay.contents[0])
|
||||
|
||||
def close(self,arg):
|
||||
urwid.emit_signal(self, "close")
|
||||
self.keep_open=False
|
||||
self.loop.widget=self.previous_widget
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s title='%s' at %s>" % (self.__class__.__name__, self.title,
|
||||
hex(id(self)))
|
||||
|
||||
def display_dialog(self, body, title, escape_key="esc"):
|
||||
filler = urwid.Pile([body])
|
||||
#dialog = urwid.Padding(ModalDialog(title, filler, escape_key,
|
||||
# self.parent.mainloop.widget))
|
||||
dialog = ModalDialog(title, filler, escape_key,
|
||||
self.parent.mainloop.widget,
|
||||
loop=self.parent.mainloop)
|
||||
#self.parent.frame.set_body(dialog)
|
||||
self.parent.mainloop.widget = dialog
|
||||
#self.parent.mainloop.widget = urwid.Padding(dialog,width=80)
|
||||
#self.__widget_stack.append(dialog)
|
||||
#self.force_redraw()
|
||||
#self.logger.debug("New Stack: %s" % self.__widget_stack)
|
||||
return dialog
|
||||
|
@ -1,173 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import urwid
|
||||
|
||||
# Exceptions to handle DialogDisplay exit codes
|
||||
|
||||
class DialogExit(Exception):
|
||||
def __init__(self, exitcode = 0):
|
||||
self.exitcode = exitcode
|
||||
|
||||
class ChildDialogExit(DialogExit):
|
||||
pass
|
||||
|
||||
class MainDialogExit(DialogExit):
|
||||
pass
|
||||
|
||||
class OffsetOverlay(urwid.Overlay):
|
||||
def calculate_padding_filler(self, size, focus):
|
||||
l, r, t, b = self.__super.calculate_padding_filler(size, focus)
|
||||
return l+1, max(0, r-1), t+1, max(0, b-1)
|
||||
# MyFrame makes urwid.Frame switch
|
||||
# focus between body and footer
|
||||
# when pressing 'tab'
|
||||
|
||||
class PopUpDialog(urwid.WidgetWrap):
|
||||
"""A dialog that appears with nothing but a close button """
|
||||
signals = ['close']
|
||||
def __init__(self):
|
||||
close_button = urwid.Button("that's pretty cool")
|
||||
urwid.connect_signal(close_button, 'click',
|
||||
lambda button:self._emit("close"))
|
||||
pile = urwid.Pile([urwid.Text(
|
||||
"^^ I'm attached to the widget that opened me. "
|
||||
"Try resizing the window!\n"), close_button])
|
||||
fill = urwid.Filler(pile)
|
||||
self.__super.__init__(urwid.AttrWrap(fill, 'popbg'))
|
||||
|
||||
class PopUp(urwid.PopUpLauncher):
|
||||
def __init__(self, original_widget, text):
|
||||
#self.__super.__init__(urwid.Button("click-me"))
|
||||
#urwid.connect_signal(self.original_widget, 'click',
|
||||
# lambda button: self.open_pop_up())
|
||||
pass
|
||||
def create_pop_up(self):
|
||||
pop_up = PopUpDialog()
|
||||
urwid.connect_signal(pop_up, 'close',
|
||||
lambda button: self.close_pop_up())
|
||||
return pop_up
|
||||
|
||||
def get_pop_up_parameters(self):
|
||||
return {'left':0, 'top':1, 'overlay_width':32, 'overlay_height':7}
|
||||
|
||||
|
||||
#class MyFrame(urwid.Frame):
|
||||
# def keypress(self, size, key):
|
||||
# if key == 'tab':
|
||||
# if self.focus_part == 'body':
|
||||
# self.set_focus('footer')
|
||||
# return None
|
||||
# elif self.focus_part == 'footer':
|
||||
# self.set_focus('body')
|
||||
# return None
|
||||
# else:
|
||||
# # do default action if
|
||||
# # focus_part is 'header'
|
||||
# self.__super.keypress(size, key)
|
||||
# return self.__super.keypress(size, key)
|
||||
#
|
||||
#class DialogDisplay(urwid.WidgetWrap):
|
||||
# palette = [
|
||||
# ('body','black','white'),
|
||||
# ('border','black','white'),
|
||||
# ('shadow','white','black'),
|
||||
# ('selectable','black', 'dark cyan'),
|
||||
# ('focus','black','dark cyan','bold'),
|
||||
# ('focustext','light gray','dark blue'),
|
||||
# ('button normal','light gray', 'dark blue', 'standout'),
|
||||
# ('button select','white', 'dark green'),
|
||||
# ]
|
||||
# parent = None
|
||||
# def __init__(self, text, width, height, body=None, loop=None):
|
||||
# width = int(width)
|
||||
# if width <= 0:
|
||||
# width = ('relative', 80)
|
||||
# height = int(height)
|
||||
# if height <= 0:
|
||||
# height = ('relative', 80)
|
||||
#
|
||||
# if body is None:
|
||||
# # fill space with nothing
|
||||
# self.body = urwid.SolidFill(' ')
|
||||
# fp = 'footer'
|
||||
# else:
|
||||
# self.body = body
|
||||
# fp = 'body'
|
||||
# self.frame = MyFrame(self.body, focus_part = fp)
|
||||
# if text is not None:
|
||||
# self.frame.header = urwid.Pile( [urwid.Text(text),
|
||||
# urwid.Divider(u'\u2550')] )
|
||||
# w = self.frame
|
||||
#
|
||||
# # pad area around listbox
|
||||
# w = urwid.Padding(w, ('fixed left',2), ('fixed right',2))
|
||||
# w = urwid.Filler(w, ('fixed top',1), ('fixed bottom',1))
|
||||
# w = urwid.AttrWrap(w, 'body')
|
||||
#
|
||||
# w = urwid.LineBox(w)
|
||||
#
|
||||
# # "shadow" effect
|
||||
# w = urwid.Columns( [w,('fixed', 1, urwid.AttrWrap(
|
||||
# urwid.Filler(urwid.Text(('border',' ')), "top")
|
||||
# ,'shadow'))])
|
||||
# w = urwid.Frame( w, footer =
|
||||
# urwid.AttrWrap(urwid.Text(('border',' ')),'shadow'))
|
||||
# if loop is None:
|
||||
# # this dialog is the main window
|
||||
# # create outermost border area
|
||||
# w = urwid.Padding(w, 'center', width )
|
||||
# w = urwid.Filler(w, 'middle', height )
|
||||
# w = urwid.AttrWrap( w, 'border' )
|
||||
# else:
|
||||
# # this dialog is a child window
|
||||
# # overlay it over the parent window
|
||||
# self.loop = loop
|
||||
# self.parent = self.loop.widget
|
||||
# w = urwid.Overlay(w, self.parent, 'center', width+2, 'middle', height+2)
|
||||
# self.view = w
|
||||
#
|
||||
# # Call WidgetWrap.__init__ to correctly initialize ourselves
|
||||
# urwid.WidgetWrap.__init__(self, self.view)
|
||||
#
|
||||
#
|
||||
# def add_buttons(self, buttons):
|
||||
# l = []
|
||||
# for name, exitcode in buttons:
|
||||
# b = urwid.Button( name, self.button_press )
|
||||
# b.exitcode = exitcode
|
||||
# b = urwid.AttrWrap( b, 'button normal','button select' )
|
||||
# l.append( b )
|
||||
# self.buttons = urwid.GridFlow(l, 10, 3, 1, 'center')
|
||||
# self.frame.footer = urwid.Pile( [ urwid.Divider(u'\u2500'),
|
||||
# self.buttons ], focus_item = 1)
|
||||
#
|
||||
# def button_press(self, button):
|
||||
# if self.parent is None:
|
||||
# # We are the main window,
|
||||
# # so raise an exception to
|
||||
# # quit the main loop
|
||||
# raise MainDialogExit(button.exitcode)
|
||||
# else:
|
||||
# # We are a child window,
|
||||
# # so restore the parent widget
|
||||
# # then raise a ChildDialogExit exception
|
||||
# self.loop.widget=self.parent
|
||||
# raise ChildDialogExit(button.exitcode)
|
||||
#
|
||||
# def show(self):
|
||||
# if self.loop is None:
|
||||
# self.loop = urwid.MainLoop(self.view, self.palette)
|
||||
# exited = False
|
||||
# while not exited:
|
||||
# try:
|
||||
# self.loop.run()
|
||||
# except ChildDialogExit as e:
|
||||
# # Determine which dialog has exited
|
||||
# # and act accordingly
|
||||
# pass
|
||||
# except MainDialogExit:
|
||||
# exited = True
|
||||
# else:
|
||||
# self.loop.widget = self.view
|
||||
#
|
@ -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,82 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
@since: 27 Jan 2012
|
||||
@author: oblivion
|
||||
'''
|
||||
import urwid
|
||||
import logging
|
||||
import window
|
||||
|
||||
|
||||
class PopUpDialog(window.Window):
|
||||
'''
|
||||
General purpose pop up dialog.
|
||||
'''
|
||||
signals = ['close', 'set']
|
||||
|
||||
def __init__(self, body=None):
|
||||
'''
|
||||
Constructor
|
||||
'''
|
||||
#log.logger.debug('Creating pop up dialog')
|
||||
if body == None:
|
||||
body = urwid.Filler(urwid.Text(''))
|
||||
#Buttons
|
||||
#Save
|
||||
save_button = urwid.Button('Set')
|
||||
self.save_button = urwid.AttrMap(save_button, 'body', 'focus')
|
||||
urwid.connect_signal(save_button, 'click',
|
||||
lambda button: self._emit("set"))
|
||||
#Back
|
||||
back_button = urwid.Button('Cancel')
|
||||
self.back_button = urwid.AttrMap(back_button, 'body', 'focus')
|
||||
urwid.connect_signal(back_button, 'click',
|
||||
lambda button: self._emit("close"))
|
||||
buttons = list()
|
||||
buttons.append(self.save_button)
|
||||
buttons.append(self.back_button)
|
||||
#Feed it to a GridFlow widget
|
||||
self.button_bar = urwid.GridFlow(buttons, 10, 3, 1, 'center')
|
||||
#Create a footer by piling the buttons with the divide
|
||||
widget = urwid.Pile([urwid.AttrMap(urwid.Divider(u'─', 1, 0),
|
||||
'frame'), self.button_bar])
|
||||
#Frame with buttons as footer.
|
||||
self.body = urwid.Frame(body, footer=widget, focus_part='body')
|
||||
widget = urwid.AttrWrap(self.body, 'body')
|
||||
|
||||
#log.logger.debug('Pop up created')
|
||||
#Window
|
||||
window.Window.__init__(self, widget)
|
||||
|
||||
def change_focus(self):
|
||||
'''
|
||||
Change the focus item in the dialog.
|
||||
'''
|
||||
#Focus on options
|
||||
if self.body.get_focus() == 'body':
|
||||
self.body.set_focus('footer')
|
||||
self.button_bar.set_focus(self.save_button)
|
||||
#log.logger.debug('Change focus: save')
|
||||
#Focus on buttons
|
||||
elif self.body.get_focus() == 'footer':
|
||||
if self.button_bar.get_focus() == self.save_button:
|
||||
self.button_bar.set_focus(self.back_button)
|
||||
#log.logger.debug('Change focus: back')
|
||||
else:
|
||||
self.body.set_focus('body')
|
||||
#log.logger.debug('Change focus: body')
|
||||
|
||||
def keypress(self, size, key):
|
||||
'''Handle tab key to change focus.'''
|
||||
self._w.keypress(size, key)
|
||||
if key == 'tab':
|
||||
#log.logger.debug('Handle key: tab')
|
||||
self.change_focus()
|
||||
return(None)
|
||||
if key == 'esc':
|
||||
#close
|
||||
self._emit('close')
|
||||
return # eat keypress
|
||||
return(key)
|
||||
|
||||
|
@ -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 )
|
||||
|
||||
|
@ -1,34 +0,0 @@
|
||||
'''
|
||||
@since: 8 Feb 2012
|
||||
@author: oblivion
|
||||
'''
|
||||
import urwid
|
||||
#import log
|
||||
|
||||
|
||||
class Window(urwid.WidgetWrap):
|
||||
'''
|
||||
A window with a line as frame.
|
||||
'''
|
||||
def __init__(self, w):
|
||||
'''
|
||||
Create the window.
|
||||
|
||||
@param w: The widget to display inside the window.
|
||||
@type w: urwid.Widget
|
||||
'''
|
||||
#log.logger.debug("Creating Window instance")
|
||||
|
||||
#Put a line around it
|
||||
widget = urwid.AttrMap(urwid.LineBox(w), 'frame')
|
||||
|
||||
#shadow
|
||||
widget = urwid.Columns([widget, ('fixed', 2,
|
||||
urwid.Filler(urwid.Text(('bg', ' ')
|
||||
), 'top'))])
|
||||
widget = urwid.Frame(widget, footer=urwid.Text(('bg', ' ')))
|
||||
widget = urwid.AttrMap(widget, 'shadow')
|
||||
|
||||
urwid.WidgetWrap.__init__(self, widget)
|
||||
|
||||
|
@ -1,2 +0,0 @@
|
||||
nameserver 8.8.8.8
|
||||
nameserver 8.8.8.8
|
@ -1,247 +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="%s/%s" \
|
||||
% (os.path.dirname(__file__),"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):
|
||||
if key == 'f8':
|
||||
raise urwid.ExitMainLoop()
|
||||
|
||||
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()
|
||||
|
@ -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
|
||||
from fuelmenu.settings import *
|
||||
from fuelmenu.common import network, puppet, replace, nailyfactersettings, \
|
||||
dialog
|
||||
from fuelmenu.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
|
||||
from fuelmenu.settings import *
|
||||
from fuelmenu.common import network, puppet, replace, \
|
||||
nailyfactersettings, dialog
|
||||
from fuelmenu.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,416 +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
|
||||
from fuelmenu.settings import *
|
||||
from fuelmenu.common import network, puppet, replace, dialog
|
||||
from fuelmenu.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,122 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import urwid
|
||||
import urwid.raw_display
|
||||
import urwid.web_display
|
||||
import logging
|
||||
import sys
|
||||
import copy
|
||||
from fuelmenu.settings import *
|
||||
from fuelmenu.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 fuelmenu.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 fuelmenu.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,12 +0,0 @@
|
||||
mnbs_internal_ipaddress=10.20.0.2
|
||||
mnbs_internal_netmask=255.255.255.0
|
||||
mnbs_static_pool_start=10.20.0.2
|
||||
mnbs_static_pool_end=10.20.0.127
|
||||
mnbs_dhcp_pool_start=10.20.0.128
|
||||
mnbs_dhcp_pool_end=10.20.0.254
|
||||
mnbs_internal_interface=vboxnet0
|
||||
mnbs_TEST_DNS=www.google.com
|
||||
mnbs_DNS_UPSTREAM=8.8.4.4
|
||||
mnbs_DNS_SEARCH=example.com
|
||||
mnbs_DNS_DOMAIN=example.com
|
||||
mnbs_HOSTNAME=fuel
|
@ -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
|
@ -1,3 +0,0 @@
|
||||
# Created by anaconda
|
||||
HOSTNAME=fuel
|
||||
NTPSERVERARGS=iburst
|
@ -1,14 +0,0 @@
|
||||
TEST_DNS: www.google.com
|
||||
DNS_UPSTREAM: 8.8.4.4
|
||||
DNS_DOMAIN: example.com
|
||||
DNS_SEARCH: example.com
|
||||
HOSTNAME: fuel
|
||||
ADMIN_NETWORK:
|
||||
interface: vboxnet0
|
||||
cidr: 10.20.0.0/24
|
||||
netmask: 255.255.255.0
|
||||
size: 256
|
||||
static_start: 10.20.0.2
|
||||
static_end: 10.20.0.127
|
||||
first: 10.20.0.128
|
||||
last: 10.20.0.254
|
@ -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"
|
||||
|
@ -1,74 +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.urwidwrapper import *
|
||||
blank = urwid.Divider()
|
||||
|
||||
|
||||
class ModalDialog(urwid.WidgetWrap):
|
||||
signals = ['close']
|
||||
|
||||
title = None
|
||||
|
||||
def __init__(self, title, body, escape_key, previous_widget,loop=None):
|
||||
self.escape_key = escape_key
|
||||
self.previous_widget = previous_widget
|
||||
self.keep_open=True
|
||||
self.loop=loop
|
||||
logging.debug("start modal")
|
||||
logging.debug(type(body))
|
||||
|
||||
if type(body) in [str, unicode]:
|
||||
body = urwid.Text(body)
|
||||
logging.debug("Set text widget")
|
||||
self.title = title
|
||||
bodybox = urwid.LineBox(urwid.Pile([body,blank,Button("Close", self.close)]), title)
|
||||
#overlay = urwid.Overlay(urwid.Pile([bodybox]), previous_widget, 'center',
|
||||
overlay = urwid.Overlay(urwid.Filler(bodybox), previous_widget, 'center',
|
||||
('relative', 80), 'middle', ('relative', 80))
|
||||
#overlay = urwid.Overlay(body, previous_widget, 'center',
|
||||
#80, "top", 24, 80, 24,
|
||||
#0,0,0,0)
|
||||
#100, 'bottom',
|
||||
#100)
|
||||
#('relative', 100), 'bottom',
|
||||
#('relative', 100))
|
||||
overlay_attrmap = urwid.AttrMap(overlay, "body")
|
||||
#overlay_attrmap = urwid.AttrMap(overlay, "plugin.widget.dialog")
|
||||
super(ModalDialog, self).__init__(overlay_attrmap)
|
||||
logging.debug(overlay.contents[0])
|
||||
|
||||
def close(self,arg):
|
||||
urwid.emit_signal(self, "close")
|
||||
self.keep_open=False
|
||||
self.loop.widget=self.previous_widget
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s title='%s' at %s>" % (self.__class__.__name__, self.title,
|
||||
hex(id(self)))
|
||||
|
||||
def display_dialog(self, body, title, escape_key="esc"):
|
||||
filler = urwid.Pile([body])
|
||||
#dialog = urwid.Padding(ModalDialog(title, filler, escape_key,
|
||||
# self.parent.mainloop.widget))
|
||||
dialog = ModalDialog(title, filler, escape_key,
|
||||
self.parent.mainloop.widget,
|
||||
loop=self.parent.mainloop)
|
||||
#self.parent.frame.set_body(dialog)
|
||||
self.parent.mainloop.widget = dialog
|
||||
#self.parent.mainloop.widget = urwid.Padding(dialog,width=80)
|
||||
#self.__widget_stack.append(dialog)
|
||||
#self.force_redraw()
|
||||
#self.logger.debug("New Stack: %s" % self.__widget_stack)
|
||||
return dialog
|
||||
|
BIN
dist/fuelmenu-0.1-py2.7.egg
vendored
BIN
dist/fuelmenu-0.1-py2.7.egg
vendored
Binary file not shown.
BIN
dist/fuelmenu-0.1.tar.gz
vendored
BIN
dist/fuelmenu-0.1.tar.gz
vendored
Binary file not shown.
@ -1,21 +0,0 @@
|
||||
Metadata-Version: 1.1
|
||||
Name: fuelmenu
|
||||
Version: 0.1
|
||||
Summary: Console util for pre-configuration of Fuel server
|
||||
Home-page: UNKNOWN
|
||||
Author: Matthew Mosesohn
|
||||
Author-email: mmosesohn@mirantis.com
|
||||
License: UNKNOWN
|
||||
Description: UNKNOWN
|
||||
Platform: UNKNOWN
|
||||
Classifier: License :: OSI Approved :: MIT License
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Environment :: Console
|
||||
Classifier: Environment :: Console :: Curses
|
||||
Classifier: Operating System :: POSIX
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Topic :: Security
|
||||
Classifier: Topic :: Internet
|
||||
Classifier: Topic :: Internet :: WWW/HTTP
|
||||
Classifier: Topic :: Internet :: Proxy Servers
|
||||
Classifier: Topic :: Software Development :: Testing
|
@ -1,55 +0,0 @@
|
||||
MANIFEST.in
|
||||
README
|
||||
setup.py
|
||||
fuelmenu/__init__.py
|
||||
fuelmenu/dnsmasq.upstream
|
||||
fuelmenu/fuelmenu.log
|
||||
fuelmenu/fuelmenu.py
|
||||
fuelmenu/loader.py
|
||||
fuelmenu/naily.facts
|
||||
fuelmenu/naily.facts.default
|
||||
fuelmenu/nailyfactersettings.pyc
|
||||
fuelmenu/network
|
||||
fuelmenu/newsettings.yaml
|
||||
fuelmenu/settings.py
|
||||
fuelmenu/settings.pyc
|
||||
fuelmenu/settings.yaml
|
||||
fuelmenu/urwidwrapper.pyc
|
||||
fuelmenu.egg-info/PKG-INFO
|
||||
fuelmenu.egg-info/SOURCES.txt
|
||||
fuelmenu.egg-info/dependency_links.txt
|
||||
fuelmenu.egg-info/entry_points.txt
|
||||
fuelmenu.egg-info/requires.txt
|
||||
fuelmenu.egg-info/top_level.txt
|
||||
fuelmenu/common/__init__.py
|
||||
fuelmenu/common/__init__.pyc
|
||||
fuelmenu/common/dialog.py
|
||||
fuelmenu/common/dialog.pyc
|
||||
fuelmenu/common/dialogdisplay.py
|
||||
fuelmenu/common/dialogdisplay.pyc
|
||||
fuelmenu/common/nailyfactersettings.py
|
||||
fuelmenu/common/nailyfactersettings.pyc
|
||||
fuelmenu/common/network.py
|
||||
fuelmenu/common/network.pyc
|
||||
fuelmenu/common/popupdialog.py
|
||||
fuelmenu/common/popupdialog.pyc
|
||||
fuelmenu/common/puppet.py
|
||||
fuelmenu/common/puppet.pyc
|
||||
fuelmenu/common/replace.py
|
||||
fuelmenu/common/replace.pyc
|
||||
fuelmenu/common/urwidwrapper.py
|
||||
fuelmenu/common/urwidwrapper.pyc
|
||||
fuelmenu/common/window.py
|
||||
fuelmenu/common/window.pyc
|
||||
fuelmenu/modules/cobblerconf.py
|
||||
fuelmenu/modules/cobblerconf.pyc
|
||||
fuelmenu/modules/dnsandhostname.py
|
||||
fuelmenu/modules/dnsandhostname.pyc
|
||||
fuelmenu/modules/interfaces.py
|
||||
fuelmenu/modules/interfaces.pyc
|
||||
fuelmenu/modules/mirrors.py
|
||||
fuelmenu/modules/mirrors.pyc
|
||||
fuelmenu/modules/shell.py
|
||||
fuelmenu/modules/shell.pyc
|
||||
fuelmenu/modules/welcome.py
|
||||
fuelmenu/modules/welcome.pyc
|
@ -1 +0,0 @@
|
||||
|
@ -1,3 +0,0 @@
|
||||
[console_scripts]
|
||||
fuelmenu = fuelmenu.fuelmenu:setup
|
||||
|
@ -1,6 +0,0 @@
|
||||
netaddr>=0.7.5
|
||||
OrderedDict>=1.1
|
||||
PyYAML>=3.10
|
||||
netifaces>=0.5
|
||||
ethtool>=0.6
|
||||
urwid>=1.1.1
|
@ -1 +0,0 @@
|
||||
fuelmenu
|
Loading…
Reference in New Issue
Block a user