From cd9b923b946c45c5a732fa6e053a59c0f9fcb40e Mon Sep 17 00:00:00 2001 From: Michael DeHaan Date: Fri, 13 Oct 2006 12:30:43 -0400 Subject: Import feature added (usable for things like /mnt/redhat) --- cobbler/action_import.py | 89 ++++++++++++++++++++++++++---------------------- cobbler/action_sync.py | 14 +++++--- cobbler/api.py | 6 ++-- cobbler/cobbler.py | 9 +++-- cobbler/item.py | 4 +-- cobbler/item_distro.py | 28 ++++++++++++++- cobbler/item_system.py | 20 ----------- 7 files changed, 98 insertions(+), 72 deletions(-) (limited to 'cobbler') diff --git a/cobbler/action_import.py b/cobbler/action_import.py index 456f358..e50ffd8 100644 --- a/cobbler/action_import.py +++ b/cobbler/action_import.py @@ -19,12 +19,15 @@ import os import os.path import traceback +import api + class Importer: - def __init__(self,config,path): + def __init__(self,config,path,mirror): # FIXME: consider a basename for the import self.config = config self.path = path + self.mirror = mirror if path is None: raise cexceptions.CobblerException("import_failed","no path specified") self.distros = config.distros() @@ -32,70 +35,76 @@ class Importer: self.systems = config.systems() def run(self): + if self.path is None and self.mirror is None: + raise cexceptions.CobblerException("import_failed","no path specified") if not os.path.isdir(self.path): raise cexceptions.CobblerException("import_failed","bad path") - arg = None - os.path.walk(self.path, self.walker, arg) - return True + if self.path is not None: + arg = None + os.path.walk(self.path, self.walker, arg) + return True + return False def walker(self,arg,dirname,fnames): # FIXME: requires getting an arch out of the path # FIXME: requires making sure the path contains "pxe" somewhere print "dirname: %s" % dirname - if self.is_leaf(dirname,fnames): - print "is_leaf" - initrd = None - kernel = None - for x in fnames: - if x.startswith("initrd"): - initrd = os.path.join(dirname,x) - if x.startswith("vmlinuz"): - kernel = os.path.join(dirname,x) - if initrd is not None and kernel is not None: - print "kernel: %s" % kernel - print "initrd: %s" % initrd - self.consider(dirname,kernel,initrd) - - def consider(self,dirname,kernel,initrd): - if not self.is_pxe_dir(dirname): + initrd = None + kernel = None + if not self.is_pxe_or_xen_dir(dirname): return + for x in fnames: + if x.startswith("initrd"): + initrd = os.path.join(dirname,x) + if x.startswith("vmlinuz"): + kernel = os.path.join(dirname,x) + if initrd is not None and kernel is not None: + self.add_entry(dirname,kernel,initrd) + + def add_entry(self,dirname,kernel,initrd): pxe_arch = self.get_pxe_arch(dirname) name = self.get_proposed_name(dirname) if self.distros.find(name) is not None: print "already registered: %s" % name else: - print "adding: %s" % name - # FIXME + distro = self.config.new_distro() + distro.set_name(name) + distro.set_kernel(kernel) + distro.set_initrd(initrd) + distro.set_arch(pxe_arch) + self.distros.add(distro) + print "*** DISTRO ADDED ***" if self.profiles.find(name) is not None: print "already registered: %s" % name else: - print "adding: %s" % name - # FIXME - + profile = self.config.new_profile() + profile.set_name(name) + profile.set_distro(name) + self.profiles.add(profile) + print "*** PROFILE ADDED ***" + def get_proposed_name(self,dirname): - # FIXME + # FIXME: how can this name be nicer? str = "_".join(dirname.split("/")) if str.startswith("_"): - return str[1:-1] + return str[1:] return str def get_pxe_arch(self,dirname): - # FIXME + tokens = os.path.split(dirname) + tokens = [x.lower() for x in tokens] + for t in tokens: + if t == "i386" or t == "386" or t == "x86": + return "x86" + if t == "x86_64": + return "x86_64" + if t == "ia64": + return "ia64" return "x86" - def is_pxe_dir(self,dirname): + def is_pxe_or_xen_dir(self,dirname): tokens = os.path.split(dirname) for x in tokens: - if x.lower() == "pxe" or x.lower() == "pxeboot": + if x.lower() == "pxe" or x.lower() == "pxeboot" or x.lower() == "xen": return True - print "not a pxe directory: %s" % dirname return False - - def is_leaf(self,dirname,fnames): - for x in fnames: - if os.path.isdir(x): - print "not a leaf directory: %s" % dirname - return False - return True - - diff --git a/cobbler/action_sync.py b/cobbler/action_sync.py index 11d60d8..4fda5b3 100644 --- a/cobbler/action_sync.py +++ b/cobbler/action_sync.py @@ -126,7 +126,9 @@ class BootSync: systxt = "" counter = counter + 1 systxt = "\nhost label%d {\n" % counter - if system.pxe_arch == "ia64": + profile = self.profiles.find(system.profile) + distro = self.distros.find(profile.distro) + if distro.arch == "ia64": # can't use pxelinux.0 anymore systxt = systxt + " filename \"/%s\";\n" % elilo systxt = systxt + " hardware ethernet %s;\n" % system.name @@ -388,10 +390,12 @@ class BootSync: f1 = self.get_pxe_filename(system.name) # tftp only - if system.pxe_arch == "standard": + + + if distro.arch in [ "x86", "x86_64", "standard"]: # pxelinux wants a file named $name under pxelinux.cfg f2 = os.path.join(self.settings.tftpboot, "pxelinux.cfg", f1) - if system.pxe_arch == "ia64": + if distro.arch == "ia64": # elilo expects files to be named "$name.conf" in the root # and can not do files based on the MAC address if system.pxe_address == "" or system.pxe_address is None or not utils.is_ip(system.pxe_address): @@ -403,9 +407,9 @@ class BootSync: f3 = os.path.join(self.settings.webdir, "systems", f1) - if system.pxe_arch == "standard": + if distro.arch in [ "x86", "x86_64", "standard"]: self.write_pxe_file(f2,system,profile,distro,False) - if system.pxe_arch == "ia64": + if distro.arch == "ia64": self.write_pxe_file(f2,system,profile,distro,True) self.write_system_file(f3,system) diff --git a/cobbler/api.py b/cobbler/api.py index f4387eb..18ed9e0 100644 --- a/cobbler/api.py +++ b/cobbler/api.py @@ -116,11 +116,13 @@ class BootAPI: enchant = action_enchant.Enchant(self._config,sysname,password) return enchant.run() - def import_tree(self,tree_path): + def import_tree(self,tree_path,mirror_url): """ Automatically import a directory tree full of distribution files. + Imports either a tree (path) or mirror (ftp/http). + Mirror support really doesn't exist yet... TBA. """ - importer = action_import.Importer(self._config, tree_path) + importer = action_import.Importer(self._config, tree_path, mirror_url) return importer.run() def serialize(self): diff --git a/cobbler/cobbler.py b/cobbler/cobbler.py index c991ece..e7a512c 100755 --- a/cobbler/cobbler.py +++ b/cobbler/cobbler.py @@ -151,15 +151,19 @@ class BootCLI: 'cobbler """ self.temp_path = None + self.temp_mirror = None + def set_mirror(a): + self.temp_mirror = a def set_path(a): if os.path.isdir(a): self.temp_path = a return True return False def go_import(): - return self.api.import_tree(self.temp_path) + return self.api.import_tree(self.temp_path,self.temp_mirror) commands = { - '--path' : lambda(a): set_path(a) + '--path' : lambda(a): set_path(a), + '--mirror' : lambda(a): set_mirror(a) } on_ok = lambda: go_import() return self.apply_args(args,commands,on_ok) @@ -213,6 +217,7 @@ class BootCLI: '--kernel' : lambda(a) : distro.set_kernel(a), '--initrd' : lambda(a) : distro.set_initrd(a), '--kopts' : lambda(a) : distro.set_kernel_options(a), + '--arch' : lambda(a) : distro.set_arch(a), '--ksmeta' : lambda(a) : distro.set_ksmeta(a) } on_ok = lambda: self.api.distros().add(distro) diff --git a/cobbler/item.py b/cobbler/item.py index 0bec45f..6dad205 100644 --- a/cobbler/item.py +++ b/cobbler/item.py @@ -48,7 +48,7 @@ class Item(serializable.Serializable): return False return True - def load_item(self,datastruct,key): + def load_item(self,datastruct,key,default=''): """ Used in subclass from_datastruct functions to load items from a hash. Intented to ease backwards compatibility of config @@ -56,7 +56,7 @@ class Item(serializable.Serializable): """ if datastruct.has_key(key): return datastruct[key] - return '' + return default def to_datastruct(self): """ diff --git a/cobbler/item_distro.py b/cobbler/item_distro.py index 0d0f26d..9af47f4 100644 --- a/cobbler/item_distro.py +++ b/cobbler/item_distro.py @@ -38,6 +38,7 @@ class Distro(item.Item): self.initrd = None self.kernel_options = "" self.ks_meta = "" + self.arch = "x86" def from_datastruct(self,seed_data): """ @@ -48,6 +49,7 @@ class Distro(item.Item): self.initrd = self.load_item(seed_data,'initrd') self.kernel_options = self.load_item(seed_data,'kernel_options') self.ks_meta = self.load_item(seed_data,'ks_meta') + self.arch = self.load_item(seed_data,'arch',"x86") return self def set_kernel(self,kernel): @@ -73,6 +75,28 @@ class Distro(item.Item): return True raise cexceptions.CobblerException("no_initrd") + def set_arch(self,arch): + """ + The field is mainly relevant to PXE provisioning. + + Should someone have Itanium machines on a network, having + syslinux (pxelinux.0) be the only option in the config file causes + problems. + + Using an alternative distro type allows for dhcpd.conf templating + to "do the right thing" with those systems -- this also relates to + bootloader configuration files which have different syntax for different + distro types (because of the bootloaders). + + This field is named "arch" because mainly on Linux, we only care about + the architecture, though if (in the future) new provisioning types + are added, an arch value might be something like "bsd_x86". + """ + if arch in [ "standard", "ia64", "x86", "x86_64" ]: + self.arch = arch + return True + raise cexceptions.CobblerException("exc_pxe_arch") + def is_valid(self): """ A distro requires that the kernel and initrd be set. All @@ -91,7 +115,8 @@ class Distro(item.Item): 'kernel': self.kernel, 'initrd' : self.initrd, 'kernel_options' : self.kernel_options, - 'ks_meta' : self.ks_meta + 'ks_meta' : self.ks_meta, + 'arch' : self.arch } def printable(self, id): @@ -112,6 +137,7 @@ class Distro(item.Item): buf = buf + "kernel : %s\n" % kstr buf = buf + "initrd : %s\n" % istr buf = buf + "kernel options : %s\n" % self.kernel_options + buf = buf + "architecture : %s\n" % self.arch buf = buf + "ks metadata : %s\n" % self.ks_meta return buf diff --git a/cobbler/item_system.py b/cobbler/item_system.py index 2568959..74ea7c7 100644 --- a/cobbler/item_system.py +++ b/cobbler/item_system.py @@ -27,7 +27,6 @@ class System(item.Item): self.profile = None # a name, not a reference self.kernel_options = "" self.ks_meta = "" - self.pxe_arch = "standard" self.pxe_address = "" def from_datastruct(self,seed_data): @@ -35,7 +34,6 @@ class System(item.Item): self.profile = self.load_item(seed_data,'profile') self.kernel_options = self.load_item(seed_data,'kernel_options') self.ks_meta = self.load_item(seed_data,'ks_meta') - self.pxe_arch = self.load_item(seed_data,'pxe_arch') self.pxe_address = self.load_item(seed_data,'pxe_address') return self @@ -75,22 +73,6 @@ class System(item.Item): return True raise cexceptions.CobblerException("exc_profile") - def set_pxe_arch(self,new_arch): - """ - The PXE architecture field is naturally relevant to PXE only. - Should someone have Itanium machines on a network, having - pxelinux.0 be the only option in the config file causes - problems. Using an alternative architecture here allows - for dhcpd.conf templating to "do the right thing" with - those systems. If manage_dhcp is off in /var/lib/cobbler/settings - this parameter is meaningless. It only has value when - generating a dhcp file. - """ - if new_arch == "standard" or new_arch == "ia64": - self.pxe_arch = new_arch - return True - raise cexceptions.CobblerException("exc_pxe_arch") - def is_valid(self): """ A system is valid when it contains a valid name and a profile. @@ -107,7 +89,6 @@ class System(item.Item): 'profile' : self.profile, 'kernel_options' : self.kernel_options, 'ks_meta' : self.ks_meta, - 'pxe_arch' : self.pxe_arch, 'pxe_address' : self.pxe_address } @@ -116,7 +97,6 @@ class System(item.Item): buf = buf + "profile : %s\n" % self.profile buf = buf + "kernel options : %s\n" % self.kernel_options buf = buf + "ks metadata : %s\n" % self.ks_meta - buf = buf + "pxe arch : %s\n" % self.pxe_arch buf = buf + "pxe address : %s\n" % self.pxe_address return buf -- cgit