From 6e84895b828b4fa5e3c45464dd08949fa382dfa5 Mon Sep 17 00:00:00 2001 From: Michael DeHaan Date: Thu, 12 Oct 2006 18:04:08 -0400 Subject: Initial code behind an import feature for directory trees, i.e. to transform something like /mnt/redhat (containing a lot of OS builds with trees) into distributions and profiles directly. --- cobbler/action_enchant.py | 4 +- cobbler/action_import.py | 101 ++++++++++++++++++++++++++++++++++++++++++++++ cobbler/api.py | 7 ++-- cobbler/cobbler.py | 49 +++++++++++++++------- cobbler/cobbler_msg.py | 2 - 5 files changed, 143 insertions(+), 20 deletions(-) create mode 100644 cobbler/action_import.py (limited to 'cobbler') diff --git a/cobbler/action_enchant.py b/cobbler/action_enchant.py index ce28f0c..03ad987 100644 --- a/cobbler/action_enchant.py +++ b/cobbler/action_enchant.py @@ -24,12 +24,14 @@ class Enchant: def __init__(self,config,sysname,password=''): """ - Constructor. All arguments required. + Constructor. If password is None it should rely on SSH key auth. """ self.config = config self.settings = self.config.settings() self.username = "root" self.sysname = sysname + if sysname is None: + raise cexception.CobblerException("enchant_failed","no system name specified") self.profile = '' self.password = password diff --git a/cobbler/action_import.py b/cobbler/action_import.py new file mode 100644 index 0000000..456f358 --- /dev/null +++ b/cobbler/action_import.py @@ -0,0 +1,101 @@ +""" +Enables the "cobbler distro import" command to seed cobbler +information with available distributions. A minimal (kickstartless) +profile will also be created with the same name as the distro. + +Copyright 2006, Red Hat, Inc +Michael DeHaan + +This software may be freely redistributed under the terms of the GNU +general public license. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +""" + +import cexceptions +import os +import os.path +import traceback + +class Importer: + + def __init__(self,config,path): + # FIXME: consider a basename for the import + self.config = config + self.path = path + if path is None: + raise cexceptions.CobblerException("import_failed","no path specified") + self.distros = config.distros() + self.profiles = config.profiles() + self.systems = config.systems() + + def run(self): + 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 + + 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): + return + 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 + if self.profiles.find(name) is not None: + print "already registered: %s" % name + else: + print "adding: %s" % name + # FIXME + + def get_proposed_name(self,dirname): + # FIXME + str = "_".join(dirname.split("/")) + if str.startswith("_"): + return str[1:-1] + return str + + def get_pxe_arch(self,dirname): + # FIXME + return "x86" + + def is_pxe_dir(self,dirname): + tokens = os.path.split(dirname) + for x in tokens: + if x.lower() == "pxe" or x.lower() == "pxeboot": + 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/api.py b/cobbler/api.py index 186eca6..f4387eb 100644 --- a/cobbler/api.py +++ b/cobbler/api.py @@ -19,6 +19,7 @@ import utils import action_sync import action_check import action_enchant +import action_import import cexceptions class BootAPI: @@ -115,12 +116,12 @@ class BootAPI: enchant = action_enchant.Enchant(self._config,sysname,password) return enchant.run() - def import_distros(self,tree_path): + def import_tree(self,tree_path): """ Automatically import a directory tree full of distribution files. """ - print "STUB: NOT IMPLEMENTED YET" - return False + importer = action_import.Importer(self._config, tree_path) + return importer.run() def serialize(self): """ diff --git a/cobbler/cobbler.py b/cobbler/cobbler.py index 73a5688..c991ece 100755 --- a/cobbler/cobbler.py +++ b/cobbler/cobbler.py @@ -22,6 +22,7 @@ import os.path import cobbler_msg import cexceptions +LOCKING_ENABLED = False LOCKFILE="/var/lib/cobbler/lock" class BootCLI: @@ -63,7 +64,8 @@ class BootCLI: 'systems' : self.system, 'system' : self.system, 'sync' : self.sync, - '--help' : self.usage, + 'import' : self.import_tree, + 'help' : self.usage, '/?' : self.usage } @@ -143,6 +145,25 @@ class BootCLI: on_ok = lambda: go_enchant() return self.apply_args(args,commands,on_ok) + def import_tree(self,args): + """ + Import a directory tree and auto-create distros & profiles. + 'cobbler + """ + self.temp_path = None + 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) + commands = { + '--path' : lambda(a): set_path(a) + } + on_ok = lambda: go_import() + return self.apply_args(args,commands,on_ok) + def system_edit(self,args): """ Create/Edit a system: 'cobbler system edit --name='foo' ... @@ -175,8 +196,6 @@ class BootCLI: '--xen-ram' : lambda(a) : profile.set_xen_ram(a), '--ksmeta' : lambda(a) : profile.set_ksmeta(a) # the following options are most likely not useful for profiles (yet) - # primarily due to not being implemented in koan. - # '--xen-mac' : lambda(a) : profile.set_xen_mac(a), # '--xen-paravirt' : lambda(a) : profile.set_xen_paravirt(a), } on_ok = lambda: self.api.profiles().add(profile) @@ -288,21 +307,23 @@ def main(): """ exitcode = 0 try: - if os.path.exists(LOCKFILE): - raise cexceptions.CobblerException("lock") - try: - lockfile = open(LOCKFILE,"w+") - except: - raise cexceptions.CobblerException("no_create",LOCKFILE) - lockfile.close() + if LOCKING_ENABLED: + if os.path.exists(LOCKFILE): + raise cexceptions.CobblerException("lock") + try: + lockfile = open(LOCKFILE,"w+") + except: + raise cexceptions.CobblerException("no_create",LOCKFILE) + lockfile.close() BootCLI(sys.argv).run() except cexceptions.CobblerException, exc: print str(exc)[1:-1] # remove framing air quotes exitcode = 1 - try: - os.remove(LOCKFILE) - except: - pass + if LOCKING_ENABLED: + try: + os.remove(LOCKFILE) + except: + pass return exitcode if __name__ == "__main__": diff --git a/cobbler/cobbler_msg.py b/cobbler/cobbler_msg.py index dbcdfff..dee3611 100644 --- a/cobbler/cobbler_msg.py +++ b/cobbler/cobbler_msg.py @@ -27,9 +27,7 @@ _msg_table = { "no_delete" : "cobbler could not delete: %s", "no_args" : "this command requires arguments.", "missing_options" : "cannot perform this action, more arguments are required", - "enchant_args" : "usage: cobbler enchant --name= --profile= --password=", "enchant_failed" : "enchant failed (%s)", - "import_args" : "usage: cobbler import --path=", "import_failed" : "import failed (%s)", "unknown_cmd" : "cobbler doesn't understand '%s'", "bad_arg" : "cobbler was expecting an equal sign in argument '%s'", -- cgit