summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--TODO5
-rw-r--r--api.py142
-rwxr-xr-xbootconf93
-rw-r--r--check.py1
-rw-r--r--config.py36
-rw-r--r--msg.py15
-rw-r--r--sync.py40
-rw-r--r--test.py115
8 files changed, 284 insertions, 163 deletions
diff --git a/TODO b/TODO
index c0dc5f5..f1a9628 100644
--- a/TODO
+++ b/TODO
@@ -1,5 +1,10 @@
+
bootconf TODO list
+P - Unified options and nomenclature for Xen.
+P - Group is a "Profile", not a Group
+ - Bootconf 'trace' command to show what a system would be provisioned to
+ - Actually write xen-net-install
T - Do kernel copying into directories named after each distro
to resolve name conflicts
I - Manpage (in progress) .. continuously...
diff --git a/api.py b/api.py
index f0c2a5a..0d0e422 100644
--- a/api.py
+++ b/api.py
@@ -36,7 +36,7 @@ class BootAPI:
self.config.serialize()
"""
- Forget about current list of groups, distros, and systems
+ Forget about current list of profiles, distros, and systems
"""
def clear(self):
self.config.clear()
@@ -48,10 +48,10 @@ class BootAPI:
return self.config.get_systems()
"""
- Return the current list of groups
+ Return the current list of profiles
"""
- def get_groups(self):
- return self.config.get_groups()
+ def get_profiles(self):
+ return self.config.get_profiles()
"""
Return the current list of distributions
@@ -72,10 +72,10 @@ class BootAPI:
return Distro(self,None)
"""
- Create a blank, unconfigured group
+ Create a blank, unconfigured profile
"""
- def new_group(self):
- return Group(self,None)
+ def new_profile(self):
+ return Profile(self,None)
"""
See if all preqs for network booting are operational
@@ -169,9 +169,9 @@ class Distros(Collection):
"""
def remove(self,name):
# first see if any Groups use this distro
- for k,v in self.api.get_groups().listing.items():
+ for k,v in self.api.get_profiles().listing.items():
if v.distro == name:
- self.api.last_error = m("orphan_group")
+ self.api.last_error = m("orphan_profiles")
return False
if self.find(name):
del self.listing[name]
@@ -183,24 +183,25 @@ class Distros(Collection):
#--------------------------------------------
"""
-A group represents a distro paired with a kickstart file.
+A profile represents a distro paired with a kickstart file.
For instance, FC5 with a kickstart file specifying OpenOffice
-might represent a 'desktop' group.
+might represent a 'desktop' profile. For Xen, there are many
+additional options, with client-side defaults (not kept here).
"""
-class Groups(Collection):
+class Profiles(Collection):
def __init__(self,api,seed_data):
self.api = api
self.listing = {}
if seed_data is not None:
for x in seed_data:
- self.add(Group(self.api,x))
+ self.add(Profile(self.api,x))
"""
Remove element named 'name' from the collection
"""
def remove(self,name):
for k,v in self.api.get_systems().listing.items():
- if v.group == name:
+ if v.profile == name:
self.api.last_error = m("orphan_system")
return False
if self.find(name):
@@ -213,7 +214,7 @@ class Groups(Collection):
#--------------------------------------------
"""
-Systems are hostnames/MACs/IP names and the associated groups
+Systems are hostnames/MACs/IP names and the associated profile
they belong to.
"""
class Systems(Collection):
@@ -323,19 +324,30 @@ class Distro(Item):
#---------------------------------------------
-class Group(Item):
+class Profile(Item):
def __init__(self,api,seed_data):
self.api = api
self.name = None
self.distro = None # a name, not a reference
self.kickstart = None
- self.kernel_options = ""
+ self.kernel_options = ''
+ self.xen_name_prefix = 'xen'
+ self.xen_file_path = '/var/xen-files'
+ self.xen_file_size = 10240
+ self.xen_ram = 2048
+ self.xen_mac = ''
+ self.xen_paravirt = True
if seed_data is not None:
- self.name = seed_data['name']
- self.distro = seed_data['distro']
- self.kickstart = seed_data['kickstart']
- self.kernel_options = seed_data['kernel_options']
+ self.name = seed_data['name']
+ self.distro = seed_data['distro']
+ self.kickstart = seed_data['kickstart']
+ self.kernel_options = seed_data['kernel_options']
+ self.xen_name_prefix = seed_data['xen_name_prefix']
+ self.xen_file_path = seed_data['xen_file_path']
+ self.xen_file_size = seed_data['xen_ram']
+ self.xen_mac = seed_data['xen_mac']
+ self.xen_paravirt = seed_data['xen_paravirt']
def set_distro(self,distro_name):
if self.api.get_distros().find(distro_name):
@@ -351,6 +363,56 @@ class Group(Item):
self.last_error = m("no_kickstart")
return False
+ def set_xen_name_prefix(self,str):
+ # no slashes or wildcards
+ for bad in [ '/', '*', '?' ]:
+ if str.find(bad) != -1:
+ return False
+ self.xen_name_prefix = str
+ return True
+
+ def set_xen_file_path(self,str):
+ # path must look absolute
+ if len(str) < 1 or str[0] != "/":
+ return False
+ self.xen_file_path = str
+ return True
+
+ def set_xen_file_size(self,num):
+ # num is a non-negative integer (0 means default)
+ try:
+ inum = int(num)
+ if inum != float(num):
+ return False
+ self.xen_file_size = inum
+ if inum >= 0:
+ return True
+ return False
+ except:
+ return False
+
+ def set_xen_mac(self,mac):
+ # mac needs to be in mac format AA:BB:CC:DD:EE:FF or a range
+ # ranges currently *not* supported, so we'll fail them
+ if self.api.utils.is_mac(mac):
+ self.xen_mac = mac
+ return True
+ else:
+ return False
+
+ def set_xen_paravirt(self,truthiness):
+ # truthiness needs to be True or False, or (lcased) string equivalents
+ try:
+ if (truthiness == False or truthiness.lower() == 'false'):
+ self.xen_paravirt = False
+ elif (truthiness == True or truthiness.lower() == 'true'):
+ self.xen_paravirt = True
+ else:
+ return False
+ except:
+ return False
+ return True
+
def is_valid(self):
for x in (self.name, self.distro):
if x is None:
@@ -362,15 +424,27 @@ class Group(Item):
'name' : self.name,
'distro' : self.distro,
'kickstart' : self.kickstart,
- 'kernel_options' : self.kernel_options
+ 'kernel_options' : self.kernel_options,
+ 'xen_name_prefix' : self.xen_name_prefix,
+ 'xen_file_path' : self.xen_file_path,
+ 'xen_file_size' : self.xen_file_size,
+ 'xen_ram' : self.xen_ram,
+ 'xen_mac' : self.xen_mac,
+ 'xen_paravirt' : self.xen_paravirt
}
def __str__(self):
buf = ""
- buf = buf + "group : %s\n" % self.name
- buf = buf + "distro : %s\n" % self.distro
- buf = buf + "kickstart : %s\n" % self.kickstart
- buf = buf + "kernel opts : %s" % self.kernel_options
+ buf = buf + "profile : %s\n" % self.name
+ buf = buf + "distro : %s\n" % self.distro
+ buf = buf + "kickstart : %s\n" % self.kickstart
+ buf = buf + "kernel opts : %s" % self.kernel_options
+ buf = buf + "xen name prefix : %s" % self.xen_name_prefix
+ buf = buf + "xen file path : %s" % self.xen_file_path
+ buf = buf + "xen file size : %s" % self.xen_file_size
+ buf = buf + "xen ram : %s" % self.xen_ram
+ buf = buf + "xen mac : %s" % self.xen_mac
+ buf = buf + "xen paravirt : %s" % self.xen_paravirt
return buf
#---------------------------------------------
@@ -380,11 +454,11 @@ class System(Item):
def __init__(self,api,seed_data):
self.api = api
self.name = None
- self.group = None # a name, not a reference
+ self.profile = None # a name, not a reference
self.kernel_options = ""
if seed_data is not None:
self.name = seed_data['name']
- self.group = seed_data['group']
+ self.profile = seed_data['profile']
self.kernel_options = seed_data['kernel_options']
"""
@@ -400,9 +474,9 @@ class System(Item):
self.name = name # we check it add time, but store the original value.
return True
- def set_group(self,group_name):
- if self.api.get_groups().find(group_name):
- self.group = group_name
+ def set_profile(self,profile_name):
+ if self.api.get_profiles().find(profile_name):
+ self.profile = profile_name
return True
return False
@@ -410,21 +484,21 @@ class System(Item):
if self.name is None:
self.api.last_error = m("bad_sys_name")
return False
- if self.group is None:
+ if self.profile is None:
return False
return True
def to_datastruct(self):
return {
'name' : self.name,
- 'group' : self.group,
+ 'profile' : self.profile,
'kernel_options' : self.kernel_options
}
def __str__(self):
buf = ""
buf = buf + "system : %s\n" % self.name
- buf = buf + "group : %s\n" % self.group
+ buf = buf + "profile : %s\n" % self.profile
buf = buf + "kernel opts : %s" % self.kernel_options
return buf
diff --git a/bootconf b/bootconf
index 2a77dc0..78b9a19 100755
--- a/bootconf
+++ b/bootconf
@@ -24,44 +24,45 @@ class BootCLI:
def __init__(self,args):
self.args = args
self.api = api.BootAPI()
- self.distro_commands = {
+ self.commands = {}
+ self.commands['distro'] = {
'add' : self.distro_edit,
'edit' : self.distro_edit,
'delete' : self.distro_remove,
'remove' : self.distro_remove,
'list' : self.distro_list
}
- self.group_commands = {
- 'add' : self.group_edit,
- 'edit' : self.group_edit,
- 'delete' : self.group_remove,
- 'remove' : self.group_remove,
- 'list' : self.group_list
+ self.commands['profile'] = {
+ 'add' : self.profile_edit,
+ 'edit' : self.profile_edit,
+ 'delete' : self.profile_remove,
+ 'remove' : self.profile_remove,
+ 'list' : self.profile_list
}
- self.system_commands = {
+ self.commands['system'] = {
'add' : self.system_edit,
'edit' : self.system_edit,
'delete' : self.system_remove,
'remove' : self.system_remove,
'list' : self.system_list
}
- self.toplevel_commands = {
- 'check' : self.check,
- 'distros' : self.distro,
- 'distro' : self.distro,
- 'groups' : self.group,
- 'group' : self.group,
- 'systems' : self.system,
- 'system' : self.system,
- 'sync' : self.sync,
- 'help' : self.help
+ self.commands['toplevel'] = {
+ 'check' : self.check,
+ 'distros' : self.distro,
+ 'distro' : self.distro,
+ 'profiles' : self.profile,
+ 'profile' : self.profile,
+ 'systems' : self.system,
+ 'system' : self.system,
+ 'sync' : self.sync,
+ 'help' : self.help
}
"""
Run the command line
"""
def run(self):
- rc = self.curry_args(self.args[1:], self.toplevel_commands)
+ rc = self.curry_args(self.args[1:], self.commands['toplevel'])
if not rc:
print self.api.last_error
return rc
@@ -88,10 +89,10 @@ class BootCLI:
print str(self.api.get_systems())
"""
- Print out the list of groups: 'bootconf group list'
+ Print out the list of profiles: 'bootconf profile list'
"""
- def group_list(self,args):
- print str(self.api.get_groups())
+ def profile_list(self,args):
+ print str(self.api.get_profiles())
"""
Print out the list of distros: 'bootconf distro list'
@@ -110,11 +111,11 @@ class BootCLI:
return self.apply_args(args,commands,on_ok,True)
"""
- Delete a group: 'bootconf group remove --name=foo'
+ Delete a profile: 'bootconf profile remove --name=foo'
"""
- def group_remove(self,args):
+ def profile_remove(self,args):
commands = {
- '--name' : lambda(a): self.api.get_groups().remove(a)
+ '--name' : lambda(a): self.api.get_profiles().remove(a)
}
on_ok = lambda: True
return self.apply_args(args,commands,on_ok,True)
@@ -136,24 +137,32 @@ class BootCLI:
sys = self.api.new_system()
commands = {
'--name' : lambda(a) : sys.set_name(a),
- '--group' : lambda(a) : sys.set_group(a),
+ '--profile' : lambda(a) : sys.set_profile(a),
+ '--profiles' : lambda(a) : sys.set_profile(a), # alias
'--kopts' : lambda(a) : sys.set_kernel_options(a)
}
on_ok = lambda: self.api.get_systems().add(sys)
return self.apply_args(args,commands,on_ok,True)
"""
- Create/Edit a group: 'bootconf group edit --name='foo' ...
+ Create/Edit a profile: 'bootconf profile edit --name='foo' ...
"""
- def group_edit(self,args):
- group = self.api.new_group()
+ def profile_edit(self,args):
+ profile = self.api.new_profile()
commands = {
- '--name' : lambda(a) : group.set_name(a),
- '--distro' : lambda(a) : group.set_distro(a),
- '--kickstart' : lambda(a) : group.set_kickstart(a),
- '--kopts' : lambda(a) : group.set_kernel_options(a)
+ '--name' : lambda(a) : profile.set_name(a),
+ '--distro' : lambda(a) : profile.set_distro(a),
+ '--kickstart' : lambda(a) : profile.set_kickstart(a),
+ '--kopts' : lambda(a) : profile.set_kernel_options(a),
+ '--xen-name-prefix' : lambda(a) : profile.set_xen_name(a),
+ '--xen-file-path' : lambda(a) : profile.set_xen_file(a),
+ '--xen-file-size' : lambda(a) : profile.set_xen_file_size(a),
+ '--xen-ram' : lambda(a) : profile.set_xen_ram(a),
+ '--xen-mac' : lambda(a) : profile.set_xen_mac(a),
+ '--xen-paravirt' : lambda(a) : profile.set_xen_paravirt(a),
+ # FIXME: more Xen opts that xen-guest-install needs
}
- on_ok = lambda: self.api.get_groups().add(group)
+ on_ok = lambda: self.api.get_profiles().add(profile)
return self.apply_args(args,commands,on_ok,True)
"""
@@ -172,7 +181,7 @@ class BootCLI:
"""
Instead of getopt...
- Parses arguments of the form --foo=bar, see group_edit for example
+ Parses arguments of the form --foo=bar, see profile_edit for example
"""
def apply_args(self,args,input_routines,on_ok,serialize):
if len(args) == 0:
@@ -199,7 +208,7 @@ class BootCLI:
"""
Helper function to make subcommands a bit more friendly.
- See group(), system(), or distro() for examples
+ See profiles(), system(), or distro() for examples
"""
def curry_args(self, args, commands):
if args is None or len(args) == 0:
@@ -245,22 +254,22 @@ class BootCLI:
Handles any of the 'bootconf distro' subcommands
"""
def distro(self,args):
- return self.curry_args(args, self.distro_commands)
+ return self.curry_args(args, self.commands['distro'])
"""
- Handles any of the 'bootconf group' subcommands
+ Handles any of the 'bootconf profile' subcommands
"""
- def group(self,args):
- return self.curry_args(args, self.group_commands)
+ def profile(self,args):
+ return self.curry_args(args, self.commands['profile'])
"""
Handles any of the 'bootconf system' subcommands
"""
def system(self,args):
- return self.curry_args(args, self.system_commands)
+ return self.curry_args(args, self.commands['system'])
if __name__ == "__main__":
- if os.getuid() != 0:
+ if os.getuid() != 0: # FIXME
print m("need_root")
sys.exit(1)
if BootCLI(sys.argv).run():
diff --git a/check.py b/check.py
index 18fe178..cdfdba0 100644
--- a/check.py
+++ b/check.py
@@ -20,7 +20,6 @@ class BootCheck:
"""
Returns None if there are no errors, otherwise returns a list
of things to correct prior to running bootconf 'for real'.
- FIXME: this needs to be more tolerant of non-default paths
"""
def run(self):
status = []
diff --git a/config.py b/config.py
index cf93214..9aded94 100644
--- a/config.py
+++ b/config.py
@@ -31,10 +31,10 @@ class BootConfig:
return os.path.exists(self.settings_file) and os.path.exists(self.state_file)
"""
- Establish an empty list of groups, distros, and systems.
+ Establish an empty list of profiles distros, and systems.
"""
def clear(self):
- self.groups = api.Groups(self.api,None)
+ self.profiles = api.Profiles(self.api,None)
self.distros = api.Distros(self.api,None)
self.systems = api.Systems(self.api,None)
@@ -51,10 +51,10 @@ class BootConfig:
self.kernel_options = "append devfs=nomount ramdisk_size=16438 lang= vga=788 ksdevice=eth0 console=ttyS0,38400n8" #initrd and ks added programmatically
"""
- Access the current groups list
+ Access the current profiles list
"""
- def get_groups(self):
- return self.groups
+ def get_profiles(self):
+ return self.profiles
"""
Access the current distros list
@@ -72,9 +72,6 @@ class BootConfig:
Save all global config options in hash form (for serialization)
"""
def config_to_hash(self):
- # FIXME: this duplication NEEDS to go away.
- # idea: add list of properties to self.properties
- # and use method_missing to write accessors???
data = {}
data['tftpboot'] = self.tftpboot
data['dhcpd_conf'] = self.dhcpd_conf
@@ -105,11 +102,11 @@ class BootConfig:
def to_hash(self,is_etc):
world = {}
if is_etc:
- world['config'] = self.config_to_hash()
+ world['config'] = self.config_to_hash()
else:
- world['distros'] = self.get_distros().to_datastruct()
- world['groups'] = self.get_groups().to_datastruct()
- world['systems'] = self.get_systems().to_datastruct()
+ world['distros'] = self.get_distros().to_datastruct()
+ world['profiles'] = self.get_profiles().to_datastruct()
+ world['systems'] = self.get_systems().to_datastruct()
#print "DEBUG: %s" % (world)
return world
@@ -123,9 +120,9 @@ class BootConfig:
if is_etc:
self.config_from_hash(hash['config'])
else:
- self.distros = api.Distros(self.api, hash['distros'])
- self.groups = api.Groups(self.api, hash['groups'])
- self.systems = api.Systems(self.api, hash['systems'])
+ self.distros = api.Distros(self.api, hash['distros'])
+ self.profiles = api.Profiles(self.api, hash['profiles'])
+ self.systems = api.Systems(self.api, hash['systems'])
# ------------------------------------------------------
# we don't care about file formats until below this line
@@ -151,7 +148,7 @@ class BootConfig:
settings.write(yaml.dump(data))
# ------
- # dump internal state (distros, groups, systems...)
+ # dump internal state (distros, profiles, systems...)
if not os.path.isdir(os.path.dirname(self.state_file)):
os.mkdir(os.path.dirname(self.state_file))
try:
@@ -186,7 +183,7 @@ class BootConfig:
return False
# -----
- # load internal state(distros, systems, groups...)
+ # load internal state(distros, systems, profiles...)
try:
state = yaml.loadFile(self.state_file)
raw_data = state.next()
@@ -195,8 +192,9 @@ class BootConfig:
else:
print "WARNING: no %s data?" % self.state_file
except:
- self.api.last_error = m("parse_error")
- return False
+ traceback.print_exc()
+ self.api.last_error = m("parse_error")
+ return False
# all good
return True
diff --git a/msg.py b/msg.py
index ed9147e..609597e 100644
--- a/msg.py
+++ b/msg.py
@@ -14,9 +14,8 @@ msg_table = {
"reject_arg" : "the value of parameter '%s' is not valid",
"weird_arg" : "this command doesn't take a parameter named '%s'",
"bad_sys_name" : "system name must be a MAC, IP, or resolveable host",
- "run_check" : "run 'bootconf check' and fix errors before running sync",
"usage" : "for help, run 'bootconf help'",
- "need_to_fix" : "the following items need to be corrected:",
+ "need_to_fix" : "the following potential problems were detected:",
"need_root" : "bootconf must be run as root",
"no_dhcpd" : "can't find dhcpd, try 'yum install dhcpd'",
"no_pxelinux" : "can't find pxelinux, try 'yum install pxelinux'",
@@ -29,18 +28,22 @@ msg_table = {
"no_cfg" : "could not find bootconf.conf, recreating",
"bad_param" : "at least one parameter is missing for this function",
"empty_list" : "(Empty)",
- "orphan_group" : "could not delete, distro is referenced by a group",
- "orphan_system" : "could not delete, group is referenced by a system",
+ "err_resolv" : "system (%s) did not resolve",
+ "err_kickstart" : "kickstart (%s) for item (%s) is not valid",
+ "orphan_profile2" : "profile does not reference a distro",
+ "orphan_system2" : "system does not reference a profile",
+ "orphan_profile" : "removing this distro would break a profile",
+ "orphan_system" : "removing this profile would break a system",
"delete_nothing" : "can't delete something that doesn't exist",
"no_distro" : "distro does not exist",
- "no_group" : "group does not exist",
+ "no_profile" : "profile does not exist",
"no_kickstart" : "kickstart must be an http://, ftp:// or nfs:// URL",
"no_kernel" : "the kernel needs to be a directory containing a kernel, or a full path. Kernels must be named just 'vmlinuz' or in the form 'vmlinuz-AA.BB.CC-something'",
"no_initrd" : "the initrd needs to be a directory containing an initrd, or a full path. Initrds must be named just 'initrd.img' or in the form 'initrd-AA.BB.CC-something.img",
"check_ok" : """
No setup problems found.
-Manual editing of /etc/dhcpd.conf and /etc/bootconf.conf is suggested to tailor them to your specific configuration. Kickstarts will not work without editing the URL in /etc/bootconf.conf, for instance. Your dhcpd.conf has some PXE related information in it, but it's imposible to tell automatically that it's totally correct in a general sense. We'll leave this up to you.
+Manual editing of /etc/dhcpd.conf and /etc/bootconf.conf is suggested to tailor them to your specific configuration. Your dhcpd.conf has some PXE related information in it, but it's imposible to tell automatically that it's totally correct in a general sense. We'll leave this up to you.
Good luck.
""",
diff --git a/sync.py b/sync.py
index 6ad9eb9..dfbfa4c 100644
--- a/sync.py
+++ b/sync.py
@@ -22,15 +22,14 @@ class BootSync:
"""
Syncs the current bootconf configuration.
- Automatically runs the 'check' function first to eliminate likely failures.
- FUTURE: make dryrun work.
+ Using the Check().run_ functions previously is recommended
"""
def sync(self,dry_run=False,verbose=True):
self.dry_run = dry_run
- results = self.api.check()
- if results != []:
- self.api.last_error = m("run_check")
- return False
+ #results = self.api.check()
+ #if results != []:
+ # self.api.last_error = m("run_check")
+ # return False
try:
self.copy_pxelinux()
self.clean_pxelinux_tree()
@@ -99,10 +98,10 @@ class BootSync:
# ensure all referenced kickstarts exist
# these are served by either NFS, Apache, or some ftpd, so we don't need to copy them
# it's up to the user to make sure they are nicely served by their URLs
- for g in self.api.get_groups().contents():
+ for g in self.api.get_profiles().contents():
kickstart_path = self.api.utils.find_kickstart(g.kickstart)
if kickstart_path is None:
- self.api.last_error = "Kickstart for group (%s) is not valid and needs to be fixed: %s" % (g.name, g.kickstart)
+ self.api.last_error = m("err_kickstart") % (g.name, g.kickstart)
raise "error"
"""
@@ -114,21 +113,21 @@ class BootSync:
# create pxelinux.cfg under tftpboot
# and file for each MAC or IP (hex encoded 01-XX-XX-XX-XX-XX-XX)
systems = self.api.get_systems()
- groups = self.api.get_groups()
+ profiles = self.api.get_profiles()
distros = self.api.get_distros()
self.mkdir(os.path.join(self.api.config.tftpboot,"pxelinux.cfg"))
for system in self.api.get_systems().contents():
- group = groups.find(system.group)
- if group is None:
- self.api.last_error = "System %s is orphaned (no group), was the configuration edited manually?" % system.name
+ profile = profiles.find(system.profile)
+ if profile is None:
+ self.api.last_error = m("orphan_profile2")
raise "error"
- distro = distros.find(group.distro)
+ distro = distros.find(profile.distro)
if distro is None:
- self.api.last_error = "Group %s is orphaned (no distro), was the configuration edited manually?" % group.name
+ self.api.last_error = m("orphan_system2")
raise "error"
filename = self.get_pxelinux_filename(system.name)
filename = os.path.join(self.api.config.tftpboot, "pxelinux.cfg", filename)
- self.write_pxelinux_file(filename,system,group,distro)
+ self.write_pxelinux_file(filename,system,profile,distro)
"""
The configuration file for each system pxelinux uses is either
@@ -144,7 +143,7 @@ class BootSync:
elif self.api.utils.is_mac(name):
return "01-" + "-".join(name.split(":")).lower()
else:
- self.api.last_error = "system name (%s) couldn't resolve and is not an IP or a MAC address." % name
+ self.api.last_error = m("err_resolv") % name
raise "error"
"""
@@ -152,10 +151,10 @@ class BootSync:
More system-specific configuration may come in later, if so
that would appear inside the system object in api.py
"""
- def write_pxelinux_file(self,filename,system,group,distro):
+ def write_pxelinux_file(self,filename,system,profile,distro):
kernel_path = os.path.join("/images",distro.name,os.path.basename(distro.kernel))
initrd_path = os.path.join("/images",distro.name,os.path.basename(distro.initrd))
- kickstart_path = group.kickstart
+ kickstart_path = profile.kickstart
self.sync_log("writing: %s" % filename)
self.sync_log("---------------------------------")
if self.dry_run:
@@ -172,7 +171,7 @@ class BootSync:
# booting we *could* try to detect it and warn them.
kopts = self.blend_kernel_options((
self.api.config.kernel_options,
- group.kernel_options,
+ profile.kernel_options,
distro.kernel_options,
system.kernel_options
))
@@ -234,7 +233,7 @@ class BootSync:
second (or further on), according to --key=value formats.
This is used such that we can have default kernel options
- in /etc and then distro, group, and system options with various
+ in /etc and then distro, profile, and system options with various
levels of configurability.
"""
def blend_kernel_options(self, list_of_opts):
@@ -265,3 +264,4 @@ class BootSync:
# end result is a new fragment of a kernel options string
return " ".join(results)
+
diff --git a/test.py b/test.py
index afb6d88..0dc1f3a 100644
--- a/test.py
+++ b/test.py
@@ -6,7 +6,7 @@
# Michael DeHaan <mdehaan@redhat.com>
import api
-
+import sys
import unittest
import os
@@ -37,7 +37,6 @@ class BootTest(unittest.TestCase):
self.api = None
def make_basic_config(self):
- self.assertTrue(os.getuid() == 0)
distro = self.api.new_distro()
self.assertTrue(distro.set_name("testdistro0"))
self.assertTrue(distro.set_kernel(FAKE_KERNEL))
@@ -45,16 +44,16 @@ class BootTest(unittest.TestCase):
self.assertTrue(self.api.get_distros().add(distro))
self.assertTrue(self.api.get_distros().find("testdistro0"))
- group = self.api.new_group()
- self.assertTrue(group.set_name("testgroup0"))
- self.assertTrue(group.set_distro("testdistro0"))
- self.assertTrue(group.set_kickstart(FAKE_KICKSTART))
- self.assertTrue(self.api.get_groups().add(group))
- self.assertTrue(self.api.get_groups().find("testgroup0"))
+ profile = self.api.new_profile()
+ self.assertTrue(profile.set_name("testprofile0"))
+ self.assertTrue(profile.set_distro("testdistro0"))
+ self.assertTrue(profile.set_kickstart(FAKE_KICKSTART))
+ self.assertTrue(self.api.get_profiles().add(profile))
+ self.assertTrue(self.api.get_profiles().find("testprofile0"))
system = self.api.new_system()
self.assertTrue(system.set_name(self.hostname))
- self.assertTrue(system.set_group("testgroup0"))
+ self.assertTrue(system.set_profile("testprofile0"))
self.assertTrue(self.api.get_systems().add(system))
self.assertTrue(self.api.get_systems().find(self.hostname))
@@ -113,32 +112,63 @@ class Additions(BootTest):
self.assertFalse(self.api.get_distros().add(distro))
self.assertFalse(self.api.get_distros().find("testdistro3"))
- def test_invalid_group_non_referenced_distro(self):
- group = self.api.new_group()
- self.assertTrue(group.set_name("testgroup11"))
- self.assertFalse(group.set_distro("distrodoesntexist"))
- self.assertTrue(group.set_kickstart(FAKE_KICKSTART))
- self.assertFalse(self.api.get_groups().add(group))
- self.assertFalse(self.api.get_groups().find("testgroup2"))
-
- def test_invalid_group_kickstart_not_url(self):
- group = self.api.new_group()
- self.assertTrue(group.set_name("testgroup12"))
- self.assertTrue(group.set_distro("testdistro0"))
- self.assertFalse(group.set_kickstart("kickstartdoesntexist"))
+ def test_invalid_profile_non_referenced_distro(self):
+ profile = self.api.new_profile()
+ self.assertTrue(profile.set_name("testprofile11"))
+ self.assertFalse(profile.set_distro("distrodoesntexist"))
+ self.assertTrue(profile.set_kickstart(FAKE_KICKSTART))
+ self.assertFalse(self.api.get_profiles().add(profile))
+ self.assertFalse(self.api.get_profiles().find("testprofile2"))
+
+ def test_invalid_profile_kickstart_not_url(self):
+ profile = self.api.new_profile()
+ self.assertTrue(profile.set_name("testprofile12"))
+ self.assertTrue(profile.set_distro("testdistro0"))
+ self.assertFalse(profile.set_kickstart("kickstartdoesntexist"))
# since kickstarts are optional, you can still add it
- self.assertTrue(self.api.get_groups().add(group))
- self.assertTrue(self.api.get_groups().find("testgroup12"))
+ self.assertTrue(self.api.get_profiles().add(profile))
+ self.assertTrue(self.api.get_profiles().find("testprofile12"))
# now verify the other kickstart forms would still work
- self.assertTrue(group.set_kickstart("http://bar"))
- self.assertTrue(group.set_kickstart("ftp://bar"))
- self.assertTrue(group.set_kickstart("nfs://bar"))
+ self.assertTrue(profile.set_kickstart("http://bar"))
+ self.assertTrue(profile.set_kickstart("ftp://bar"))
+ self.assertTrue(profile.set_kickstart("nfs://bar"))
+
+ def test_profile_xen_parameter_checking(self):
+ profile = self.api.new_profile()
+ self.assertTrue(profile.set_name("testprofile12b"))
+ self.assertTrue(profile.set_distro("testdistro0"))
+ self.assertTrue(profile.set_kickstart("http://127.0.0.1/foo"))
+ # no slashes or wildcards in prefixes
+ self.assertTrue(profile.set_xen_name_prefix("xen"))
+ self.assertTrue(profile.set_xen_name_prefix("xen"))
+ self.assertFalse(profile.set_xen_name_prefix("xen/foo"))
+ self.assertFalse(profile.set_xen_name_prefix("xen*foo"))
+ self.assertFalse(profile.set_xen_name_prefix("xen?foo"))
+ # paths must be absolute
+ self.assertFalse(profile.set_xen_file_path("tmp"))
+ self.assertTrue(profile.set_xen_file_path("/tmp"))
+ # sizes must be integers
+ self.assertTrue(profile.set_xen_file_size("54321"))
+ self.assertFalse(profile.set_xen_file_size("huge"))
+ self.assertFalse(profile.set_xen_file_size("54321.23"))
+ # macs must be properly formatted
+ self.assertTrue(profile.set_xen_mac("AA:BB:CC:DD:EE:FF"))
+ self.assertFalse(profile.set_xen_mac("AA-BB-CC-DD-EE-FF"))
+ # paravirt must be 'true' or 'false'
+ self.assertFalse(profile.set_xen_mac("cowbell"))
+ self.assertTrue(profile.set_xen_paravirt('true'))
+ self.assertTrue(profile.set_xen_paravirt('fALsE'))
+ self.assertFalse(profile.set_xen_paravirt('sputnik'))
+ self.assertFalse(profile.set_xen_paravirt(11))
+ # each item should be 'true' now, so we can add it
+ # since the failed items don't affect status
+ self.assertTrue(self.api.get_profiles().add(profile))
def test_invalid_system_bad_name_host(self):
system = self.api.new_system()
name = "hostnamewontresolveanyway"
self.assertFalse(system.set_name(name))
- self.assertTrue(system.set_group("testgroup0"))
+ self.assertTrue(system.set_profile("testprofile0"))
self.assertFalse(self.api.get_systems().add(system))
self.assertFalse(self.api.get_systems().find(name))
@@ -146,7 +176,7 @@ class Additions(BootTest):
system = self.api.new_system()
name = "00:16:41:14:B7:71"
self.assertTrue(system.set_name(name))
- self.assertTrue(system.set_group("testgroup0"))
+ self.assertTrue(system.set_profile("testprofile0"))
self.assertTrue(self.api.get_systems().add(system))
self.assertTrue(self.api.get_systems().find(name))
@@ -154,24 +184,24 @@ class Additions(BootTest):
system = self.api.new_system()
name = "192.168.1.54"
self.assertTrue(system.set_name(name))
- self.assertTrue(system.set_group("testgroup0"))
+ self.assertTrue(system.set_profile("testprofile0"))
self.assertTrue(self.api.get_systems().add(system))
self.assertTrue(self.api.get_systems().find(name))
- def test_invalid_system_non_referenced_group(self):
+ def test_invalid_system_non_referenced_profile(self):
system = self.api.new_system()
self.assertTrue(system.set_name(self.hostname))
- self.assertFalse(system.set_group("groupdoesntexist"))
+ self.assertFalse(system.set_profile("profiledoesntexist"))
self.assertFalse(self.api.get_systems().add(system))
class Deletions(BootTest):
- def test_invalid_delete_group_doesnt_exist(self):
- self.assertFalse(self.api.get_groups().remove("doesnotexist"))
+ def test_invalid_delete_profile_doesnt_exist(self):
+ self.assertFalse(self.api.get_profiles().remove("doesnotexist"))
- def test_invalid_delete_group_would_orphan_systems(self):
+ def test_invalid_delete_profile_would_orphan_systems(self):
self.make_basic_config()
- self.assertFalse(self.api.get_groups().remove("testgroup0"))
+ self.assertFalse(self.api.get_profiles().remove("testprofile0"))
def test_invalid_delete_system_doesnt_exist(self):
self.assertFalse(self.api.get_systems().remove("doesnotexist"))
@@ -179,7 +209,7 @@ class Deletions(BootTest):
def test_invalid_delete_distro_doesnt_exist(self):
self.assertFalse(self.api.get_distros().remove("doesnotexist"))
- def test_invalid_delete_distro_would_orphan_group(self):
+ def test_invalid_delete_distro_would_orphan_profile(self):
self.make_basic_config()
self.assertFalse(self.api.get_distros().remove("testdistro0"))
@@ -188,10 +218,10 @@ class Deletions(BootTest):
self.make_basic_config()
self.assertTrue(self.api.get_systems().remove(self.hostname))
self.api.serialize()
- self.assertTrue(self.api.get_groups().remove("testgroup0"))
+ self.assertTrue(self.api.get_profiles().remove("testprofile0"))
self.assertTrue(self.api.get_distros().remove("testdistro0"))
self.assertFalse(self.api.get_systems().find(self.hostname))
- self.assertFalse(self.api.get_groups().find("testgroup0"))
+ self.assertFalse(self.api.get_profiles().find("testprofile0"))
self.assertFalse(self.api.get_distros().find("testdistro0"))
class TestSerialization(BootTest):
@@ -201,11 +231,11 @@ class TestSerialization(BootTest):
self.api.serialize()
self.api.clear()
self.assertFalse(self.api.get_systems().find(self.hostname))
- self.assertFalse(self.api.get_groups().find("testgroup0"))
+ self.assertFalse(self.api.get_profiles().find("testprofile0"))
self.assertFalse(self.api.get_distros().find("testdistro0"))
self.api.deserialize()
self.assertTrue(self.api.get_systems().find(self.hostname))
- self.assertTrue(self.api.get_groups().find("testgroup0"))
+ self.assertTrue(self.api.get_profiles().find("testprofile0"))
self.assertTrue(self.api.get_distros().find("testdistro0"))
@@ -231,5 +261,8 @@ class TestSync(BootTest):
pass
if __name__ == "__main__":
+ if os.getuid()!=0:
+ print "root would be nice"
+ sys.exit(1)
unittest.main()