diff options
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | TODO | 13 | ||||
-rw-r--r-- | api.py | 41 | ||||
-rwxr-xr-x | bootconf | 8 | ||||
-rw-r--r-- | bootconf.pod | 45 | ||||
-rw-r--r-- | check.py | 2 | ||||
-rw-r--r-- | config.py | 10 | ||||
-rw-r--r-- | sync.py | 12 |
8 files changed, 94 insertions, 40 deletions
@@ -2,8 +2,9 @@ all: manpage manpage: pod2man bootconf.pod > bootconf.1 + -(\rm bootconf.1.gz) gzip bootconf.1 - cp bootconf.1.gz /usr/share/man/man1 + cp -f bootconf.1.gz /usr/share/man/man1 install: echo "(install not implemented)" @@ -11,22 +11,25 @@ T - Optional kernel parameter input to replace defaults resolved to give precendence to system, then group, then distro, then defaults. PARTIAL: input allowed and serialized but *NOT USED YET* - - dlutter mentions directories for kernels might not resolve - to full paths. Check into this and fix. NICE TO HAVE T - Move program writeable section of config to /var to conform with FS rules - - Make list show resolved values as currently set +D - Make list show resolved values as currently set for things like initrd, kernel, kickstart rather than just the directories or partial filenames. - Try pulling the kernel and initrd from the kickstart information? +RANDOM IDEAS + + - Support pxelinux's default directory + - Subnet creation shorthand LEGEND -T = DONE? BEING TESTED -D = DONE +T = DONE. SOME TESTING STILL TBA. +D = DONE. LOOKS FINE. P = PARTIAL I = IN PROGRESS + @@ -22,7 +22,7 @@ class BootAPI: self.utils = util.BootUtil(self,self.config) # if the file already exists, load real data now try: - if not self.config.files_exist(): + if self.config.files_exist(): self.config.deserialize() except: # traceback.print_exc() @@ -30,7 +30,7 @@ class BootAPI: try: self.config.serialize() except: - # traceback.print_exc() + traceback.print_exc() pass if not self.config.files_exist(): self.config.serialize() @@ -141,10 +141,9 @@ class Collection: """ def __str__(self): buf = "" - values = sorted(self.listing.values()) + values = map(lambda(a): str(a), sorted(self.listing.values())) if len(values) > 0: - for v in values: buf = buf + str(v) + "\n" - return buf + return "\n\n".join(values) else: return m("empty_list") @@ -253,6 +252,7 @@ class Item: def set_kernel_options(self,options_string): self.kernel_options = options_string + return True def to_datastruct(self): raise "not implemented" @@ -304,7 +304,22 @@ class Distro(Item): } def __str__(self): - return "%s : kernel=%s | initrd=%s | opts=%s" % (self.name,self.kernel,self.initrd,self.kernel_options) + kstr = self.api.utils.find_kernel(self.kernel) + istr = self.api.utils.find_initrd(self.initrd) + if kstr is None: + kstr = "%s (NOT FOUND!)" % self.kernel + elif os.path.isdir(self.kernel): + kstr = "%s (FOUND BY SEARCH)" % kstr + if istr is None: + istr = "%s (NOT FOUND)" % self.initrd + elif os.path.isdir(self.initrd): + istr = "%s (FOUND BY SEARCH)" % istr + buf = "" + buf = buf + "distro : %s\n" % self.name + buf = buf + "kernel : %s\n" % kstr + buf = buf + "initrd : %s\n" % istr + buf = buf + "kernel opts : %s" % self.kernel_options + return buf #--------------------------------------------- @@ -351,7 +366,12 @@ class Group(Item): } def __str__(self): - return "%s : distro=%s | kickstart=%s | opts=%s" % (self.name, self.distro, self.kickstart, self.kernel_options) + 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 + return buf #--------------------------------------------- @@ -402,6 +422,9 @@ class System(Item): } def __str__(self): - return "%s : group=%s | opts=%s" % (self.name,self.group,self.kernel_options) - + buf = "" + buf = buf + "system : %s\n" % self.name + buf = buf + "group : %s\n" % self.group + buf = buf + "kernel opts : %s" % self.kernel_options + return buf @@ -137,7 +137,7 @@ class BootCLI: commands = { '--name' : lambda(a) : sys.set_name(a), '--group' : lambda(a) : sys.set_group(a), - '--kopts' : lambda(a) : sys.set_kernel_opts(a) + '--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) @@ -151,7 +151,7 @@ class BootCLI: '--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_opts(a) + '--kopts' : lambda(a) : group.set_kernel_options(a) } on_ok = lambda: self.api.get_groups().add(group) return self.apply_args(args,commands,on_ok,True) @@ -165,7 +165,7 @@ class BootCLI: '--name' : lambda(a) : distro.set_name(a), '--kernel' : lambda(a) : distro.set_kernel(a), '--initrd' : lambda(a) : distro.set_initrd(a), - '--kopts' : lambda(a) : distro.set_kopts(a) + '--kopts' : lambda(a) : distro.set_kernel_options(a) } on_ok = lambda: self.api.get_distros().add(distro) return self.apply_args(args,commands,on_ok,True) @@ -180,7 +180,7 @@ class BootCLI: return False for x in args: try: - key, value = x.split("=") + key, value = x.split("=",1) value = value.replace('"','').replace("'",'') except: print m("bad_arg") % x diff --git a/bootconf.pod b/bootconf.pod index c4251af..f2d41c1 100644 --- a/bootconf.pod +++ b/bootconf.pod @@ -8,7 +8,7 @@ bootconf command [subcommand] [--arg1=] [--arg2=] =head1 DESCRIPTION -Configuration of a boot server involves a lot of things. Perhaps too many. These items include a tftpd server, a dhcpd server, syslinux, and a lot of copying files around and creating other config files. Bootconf makes these things simpler. +Configuration of a boot server involves a lot of things. Perhaps too many. These items include a tftpd server, a dhcpd server, syslinux, and a lot of copying files around and creating other config files. Bootconf makes these things simpler and more flexible. bootconf requires root access. @@ -17,9 +17,8 @@ bootconf requires root access. B<before you start...> First install dhcpd, tftpd, and syslinux. -You'll also need FTP, HTTP, or NFS to serve kickstarts (if you want them) -And you'll also have to edit dhcpd.conf for your particular DHCP environment. -Yes, DHCP is a required piece. +You'll also need FTP, HTTP, or NFS to serve kickstarts (if you want kickstarts).Finally, you'll also have to edit dhcpd.conf for your particular DHCP environment. + yum install dhcp tftp-server syslinux ... @@ -27,24 +26,24 @@ Yes, DHCP is a required piece. B<bootconf check> -This verifies that everything you need to set up is set up. +This verifies that everything you need to set up is properly set up. This will mention any missing services and obvious configuration errors. -Errors? Correct any problems reported, then run check until there are none. +Correct any problems reported, then run check until there are none. -Do not forget to look at /etc/bootconf.conf and modify all parameters to your liking. Of particular note: The kernel_opts field is the default kernel options list for all netbooting systems. It can be overriden by distro, group, or system specific settings. +Of particular note: The kernel_opts field in /etc/bootconf.conf is the default kernel options list for all netbooting systems. It can be overriden by distro, group, or system specific settings, though the defaults are probably good enough for most administrators. B<bootconf distro add --name=distro_name --kernel=path --initrd=path [--kopts="string"]> Defines a distribution as a matched pair of a kernel and an initrd, and -gives it a name. This could be 'fc5-i386' or 'foosball-73', it's your name. Kernel options are inherited from the kernel_opts parameter in /etc/bootconf.conf, though you can override them. +gives it a name. This could be 'fc5-i386' or 'foosball_rocks', it's your name. Kernel options are inherited from the kernel_opts parameter in /etc/bootconf.conf, though you can override some or all of them. B<bootconf group add --name=group_name --distro=distro_name [--kickstart=url] [--kopts="string"]> -Defines a provisioning group, which is a distro (you did define a distro, right?) and optionally a kickstart. Kickstarts are served up by URLs, so these need to be HTTP, NFS, or FTP URLs that point to a kickstart file. Kernel options are inherited from the distro, but you can optionally override them. If you don't want a kickstart, that's fine. +Defines a provisioning group, which is a distro (you did define a distro, right?) and optionally a kickstart. Kickstarts are served up by URLs, so these need to be HTTP, NFS, or FTP URLs that point to a kickstart file. If you don't want a kickstart, leave that parameter out. Kernel options are inherited from the distro, but you can optionally override some or all of them. B<bootconf system add --name=ip|mac|hostname --group=group_name [--kopts="string"]> -Defines a system. A system can't have a free form name, it has to be a hostname that resolves to an IP, a MAC address, or an actual IP. The group parameter is the group name you used with "group add". Kernel options are inherited from the group, you probably don't want to override them, but you can. +Defines a system, which is a representation of any netbootable system. A system can't have a free form name, it has to be a hostname that resolves to an IP, a MAC address, or an actual IP. Partial IP's (as in whole subnets) may be supported later. The group parameter is the group name you used with "group add", that is, what group the system belongs to. Kernel options are inherited from the group, and you probably don't want to override them, but you can override some or all of them. B<bootconf distro list> @@ -76,6 +75,32 @@ Applies the stored configuration to the system. If you have any configuration e Usage of the dryrun option will show you the pending changes without actually making them. +=head1 EXAMPLE + +B<bootconf check> + +B<bootconf distro add --name=rhel4u3 --kernel=/dir1/vmlinuz --initrd=/dir1/initrd.img> + +B<bootconf distro add --name=fc5 --kernel=/dir2/vmlinuz --initrd=/dir2/initrd.img> + +B<bootconf distro list> + +B<bootconf group add --name=fc5webservers --distro=fc5-i386 --kickstart=http://192.168.1.10/blah/fc5-webservers.ks --kopts="customization=blah"> + +B<bootconf group add --name=rhel4u3dbservers --distro=rhel4u3 --kickstart=http://192.168.1.10/blah/rhel4u3-dbservers.ks> + +B<bootconf group list> + +B<bootconf system add --name=AA:BB:CC:DD:EE:FF --group=fc5-webservers> + +B<bootconf system add --name=AA:BB:CC:DD:EE:FE --group=rhel4u3-dbservers> + +B<bootconf system list> + +B<bootconf sync --dryrun> + +B<bootconf sync> + =head1 CONFIGURATION_FILES bootconf uses /etc/bootconf.conf to store basic settings and /var/bootconf/bootconf.conf for it's internal state. @@ -102,7 +102,5 @@ class BootCheck: status.append(m("no_line") % (self.config.dhcpd_conf, 'filename "%s/pxelinux.0";' % self.config.tftpboot)) else: status.append(m("no_exist") % self.config.dhcpd_conf) - if not os.path.exists(self.config.kernel_root): - status.append(m("no_dir2") % (self.config.kernel_root, 'kernel_root')) @@ -42,7 +42,6 @@ class BootConfig: Set some reasonable defaults in case no values are available """ def set_defaults(self): - self.kernel_root = "/var/www/bootconf" self.tftpboot = "/tftpboot" self.dhcpd_conf = "/etc/dhcpd.conf" self.tftpd_conf = "/etc/xinetd.d/tftp" @@ -77,7 +76,6 @@ class BootConfig: # idea: add list of properties to self.properties # and use method_missing to write accessors??? data = {} - data['kernel_root'] = self.kernel_root data['tftpboot'] = self.tftpboot data['dhcpd_conf'] = self.dhcpd_conf data['tftpd_conf'] = self.tftpd_conf @@ -91,7 +89,6 @@ class BootConfig: """ def config_from_hash(self,hash): try: - self.kernel_root = hash['kernel_root'] self.tftpboot = hash['tftpboot'] self.dhcpd_conf = hash['dhcpd_conf'] self.tftpd_conf = hash['tftpd_conf'] @@ -113,6 +110,7 @@ class BootConfig: world['distros'] = self.get_distros().to_datastruct() world['groups'] = self.get_groups().to_datastruct() world['systems'] = self.get_systems().to_datastruct() + #print "DEBUG: %s" % (world) return world @@ -121,6 +119,7 @@ class BootConfig: There are seperate hashes for the /etc and /var portions. """ def from_hash(self,hash,is_etc): + #print "DEBUG: %s" % hash if is_etc: self.config_from_hash(hash['config']) else: @@ -171,6 +170,7 @@ class BootConfig: could use YAML later if we wanted. """ def deserialize(self): + #print "DEBUG: deserialize" # ----- # load global config (pathing, urls, etc)... @@ -179,6 +179,8 @@ class BootConfig: raw_data = settings.next() if raw_data is not None: self.from_hash(raw_data,True) + else: + print "WARNING: no %s data?" % self.settings_file except: self.api.last_error = m("parse_error") return False @@ -190,6 +192,8 @@ class BootConfig: raw_data = state.next() if raw_data is not None: self.from_hash(raw_data,False) + else: + print "WARNING: no %s data?" % self.state_file except: self.api.last_error = m("parse_error") return False @@ -101,8 +101,8 @@ class BootSync: # it's up to the user to make sure they are nicely served by their URLs for g in self.api.get_groups().contents(): kickstart_path = self.api.utils.find_kickstart(g.kickstart) - if kickstart_path is None or not os.path.isfile(kickstart_path): - self.api.last_error = "Kickstart for group (%s) cannot be found and needs to be fixed: %s" % (g.name, 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) raise "error" """ @@ -176,7 +176,7 @@ class BootSync: distro.kernel_options, system.kernel_options )) - nextline = " append %s initrd=%s" % (kopts,initrd_path) + nextline = " append %s initrd=%s" % (kopts,initrd_path) if kickstart_path is not None and kickstart_path != "": nextline = nextline + " ks=%s" % kickstart_path self.tee(file, nextline) @@ -246,7 +246,7 @@ class BootSync: tokens=items.split(" ") # deal with key/value pairs and single options alike for token in tokens: - key_value = tokens.split("=") + key_value = token.split("=") if len(key_value) == 1: internal[key_value[0]] = "" else: @@ -257,11 +257,11 @@ class BootSync: data = internal[key] if key == "ks" or key == "initrd" or key == "append": # the user REALLY doesn't want to do this... - next + continue if data == "": results.append(key) else: results.append("%s=%s" % (key,internal[key])) # end result is a new fragment of a kernel options string - return results.join(" ") + return " ".join(results) |