diff options
-rw-r--r-- | TODO | 5 | ||||
-rw-r--r-- | api.py | 142 | ||||
-rwxr-xr-x | bootconf | 93 | ||||
-rw-r--r-- | check.py | 1 | ||||
-rw-r--r-- | config.py | 36 | ||||
-rw-r--r-- | msg.py | 15 | ||||
-rw-r--r-- | sync.py | 40 | ||||
-rw-r--r-- | test.py | 115 |
8 files changed, 284 insertions, 163 deletions
@@ -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... @@ -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 @@ -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(): @@ -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 = [] @@ -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 @@ -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. """, @@ -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) + @@ -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() |