From d4f71b4318fedf374844030095c6c8dd544f0e92 Mon Sep 17 00:00:00 2001 From: Michael DeHaan Date: Mon, 8 May 2006 15:02:06 -0400 Subject: Interim checkin while straightening out exceptions. The last_error bit reminded me of the thing I hated most about Microsoft SDK/DDK programming (that being, last_error and inconsistant error handling), so it had to go. --- Makefile | 6 ++-- cobbler/action_check.py | 29 ++++++++-------- cobbler/action_sync.py | 46 +++++++++++-------------- cobbler/api.py | 6 ---- cobbler/cobbler.py | 52 +++++++++++++++++----------- cobbler/cobbler_exception.py | 20 +++++++++++ cobbler/cobbler_msg.py | 67 ++++++++++++++++++++++++++++++++++++ cobbler/collection.py | 8 ++--- cobbler/collection_distros.py | 6 ++-- cobbler/collection_profiles.py | 7 ++-- cobbler/collection_systems.py | 4 +-- cobbler/item_distro.py | 7 ++-- cobbler/item_profile.py | 8 ++--- cobbler/item_system.py | 7 ++-- cobbler/msg.py | 66 ----------------------------------- cobbler/serializer.py | 78 ++++++++++++++++++++++++++++++------------ cobbler/utils.py | 16 --------- 17 files changed, 232 insertions(+), 201 deletions(-) create mode 100644 cobbler/cobbler_exception.py create mode 100644 cobbler/cobbler_msg.py delete mode 100644 cobbler/msg.py diff --git a/Makefile b/Makefile index ef8922d..2a2560a 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,13 @@ clean: - \rm -f cobbler*.gz cobbler*.rpm MANIFEST - \rm -rf cobbler-* dist build + -rm -f cobbler*.gz cobbler*.rpm MANIFEST + -rm -rf cobbler-* dist build manpage: pod2man --center="cobbler" --release="" cobbler.pod | gzip -c > cobbler.1.gz test: python tests/tests.py - \rm -rf /tmp/_cobbler-* + -rm -rf /tmp/_cobbler-* install: clean manpage python setup.py sdist diff --git a/cobbler/action_check.py b/cobbler/action_check.py index 05718b3..fdcc5d5 100644 --- a/cobbler/action_check.py +++ b/cobbler/action_check.py @@ -7,8 +7,7 @@ Michael DeHaan import os import re - -from msg import * +import cobbler_msg class BootCheck: @@ -43,14 +42,14 @@ class BootCheck: parameters. """ if self.settings.server == "localhost": - status.append(m("bad_server")) + status.append(cobbler_msg.lookup("bad_server")) def check_httpd(self,status): """ Check if Apache is installed. """ if not os.path.exists(self.settings.httpd_bin): - status.append(m("no_httpd")) + status.append(cobbler_msg.lookup("no_httpd")) def check_dhcpd_bin(self,status): @@ -58,28 +57,28 @@ class BootCheck: Check if dhcpd is installed """ if not os.path.exists(self.settings.dhcpd_bin): - status.append(m("no_dhcpd")) + status.append(cobbler_msg.lookup("no_dhcpd")) def check_pxelinux_bin(self,status): """ Check if pxelinux (part of syslinux) is installed """ if not os.path.exists(self.settings.pxelinux): - status.append(m("no_pxelinux")) + status.append(cobbler_msg.lookup("no_pxelinux")) def check_tftpd_bin(self,status): """ Check if tftpd is installed """ if not os.path.exists(self.settings.tftpd_bin): - status.append(m("no_tftpd")) + status.append(cobbler_msg.lookup("no_tftpd")) def check_tftpd_dir(self,status): """ Check if cobbler.conf's tftpboot directory exists """ if not os.path.exists(self.settings.tftpboot): - status.append(m("no_dir") % self.settings.tftpboot) + status.append(cobbler_msg.lookup("no_dir") % self.settings.tftpboot) def check_tftpd_conf(self,status): @@ -94,15 +93,15 @@ class BootCheck: found_bootdir = False for line in f.readlines(): if re_1.search(line): - status.append(m("chg_attrib") % ('default','on',self.settings.tftpd_conf)) + status.append(cobbler_msg.lookup("chg_attrib") % ('default','on',self.settings.tftpd_conf)) if re_2.search(line): - status.append(m("chg_attrib") % ('disable','no',self.settings.tftpd_conf)) + status.append(cobbler_msg.lookup("chg_attrib") % ('disable','no',self.settings.tftpd_conf)) if line.find("-s %s" % self.settings.tftpboot) != -1: found_bootdir = True if not found_bootdir: - status.append(m("chg_attrib") % ('server_args',"-s %s" % self.settings.tftpboot, self.settings.tftpd_conf)) + status.append(cobbler_msg.lookup("chg_attrib") % ('server_args',"-s %s" % self.settings.tftpboot, self.settings.tftpd_conf)) else: - status.append(m("no_exist") % self.settings.tftpd_conf) + status.append(cobbler_msg.lookup("no_exist") % self.settings.tftpd_conf) def check_dhcpd_conf(self,status): @@ -122,10 +121,10 @@ class BootCheck: if line.find("filename") != -1: match_file = True if not match_next: - status.append(m("no_line") % (self.settings.dhcpd_conf, 'next-server ip-address')) + status.append(cobbler_msg.lookup("no_line") % (self.settings.dhcpd_conf, 'next-server ip-address')) if not match_file: - status.append(m("no_line") % (self.settings.dhcpd_conf, 'filename "%s/pxelinux.0";' % self.settings.tftpboot)) + status.append(cobbler_msg.lookup("no_line") % (self.settings.dhcpd_conf, 'filename "%s/pxelinux.0";' % self.settings.tftpboot)) else: - status.append(m("no_exist") % self.settings.dhcpd_conf) + status.append(cobbler_msg.lookup("no_exist") % self.settings.dhcpd_conf) diff --git a/cobbler/action_sync.py b/cobbler/action_sync.py index fede994..6fc3c6b 100644 --- a/cobbler/action_sync.py +++ b/cobbler/action_sync.py @@ -11,7 +11,8 @@ import shutil import syck import utils -from msg import * +import cobbler_msg +from cobbler_exception import CobblerException """ Handles conversion of internal state to the tftpboot tree layout @@ -63,7 +64,7 @@ class BootSync: cobbler infrastructure available over TFTP over HTTP also. """ if not os.path.exists("/etc/httpd/conf.d"): - self.sync_log(m("no_httpd")) + self.sync_log(cobbler_msg.lookup("no_httpd")) return f = self.open_file("/etc/httpd/conf.d/cobbler.conf","w+") config_data = """ @@ -107,12 +108,9 @@ class BootSync: kernel = utils.find_kernel(d.kernel) # full path initrd = utils.find_initrd(d.initrd) # full path if kernel is None or not os.path.isfile(kernel): - utils.set_error("Kernel for distro (%s) cannot be found and needs to be fixed: %s" % (d.name, d.kernel)) - print utils.last_error() - raise Exception, "error" + raise CobblerException("sync_kernel", (d.name, d.kernel)) if initrd is None or not os.path.isfile(initrd): - utils.set_error("Initrd for distro (%s) cannot be found and needs to be fixed: %s" % (d.name, d.initrd)) - raise Exception, "error" + raise CobblerException("sync_initrd", (d.name, d.initrd)) b_kernel = os.path.basename(kernel) b_initrd = os.path.basename(initrd) self.copyfile(kernel, os.path.join(distro_dir, b_kernel)) @@ -131,7 +129,7 @@ class BootSync: # it's up to the user to make sure they are nicely served by their URLs for g in self.profiles: - self.sync_log("mirroring any local kickstarts: %s" % g.name) + self.sync_log(cobbler_msg.lookup("sync_mirror_ks")) kickstart_path = utils.find_kickstart(g.kickstart) if kickstart_path and os.path.exists(kickstart_path): # the input is an *actual* file, hence we have to copy it @@ -141,8 +139,7 @@ class BootSync: try: self.copyfile(g.kickstart, dest) except: - utils.set_error("err_kickstart2") - raise Exception, "error" + raise CobblerException("err_kickstart2") def build_trees(self): """ @@ -151,12 +148,12 @@ class BootSync: configured IP or MAC address. Also build a parallel 'xeninfo' tree for xen-net-install info. """ - self.sync_log("building trees...") + self.sync_log(cobbler_msg.lookup("sync_buildtree")) # create pxelinux.cfg under tftpboot # and file for each MAC or IP (hex encoded 01-XX-XX-XX-XX-XX-XX) for d in self.distros: - self.sync_log("processing distro: %s" % d.name) + self.sync_log(cobbler_msg.lookup("sync_processing") % d.name) # TODO: add check to ensure all distros have profiles (=warning) filename = os.path.join(self.settings.tftpboot,"distros",d.name) d.kernel_options = self.blend_kernel_options(( @@ -166,7 +163,7 @@ class BootSync: self.write_distro_file(filename,d) for p in self.profiles: - self.sync_log("processing profile: %s" % p.name) + self.sync_log(cobbler_msg.lookup("sync_processing") % p.name) # TODO: add check to ensure all profiles have distros (=error) # TODO: add check to ensure all profiles have systems (=warning) filename = os.path.join(self.settings.tftpboot,"profiles",p.name) @@ -180,15 +177,13 @@ class BootSync: self.write_profile_file(filename,p) for system in self.systems: - self.sync_log("processing system: %s" % system.name) + self.sync_log(cobbler_msg.lookup("sync_processing") % system.name) profile = self.profiles.find(system.profile) if profile is None: - utils.set_error("orphan_profile2") - raise Exception, "error" + raise CobblerException("orphan_profile2") distro = self.distros.find(profile.distro) if distro is None: - utils.set_error("orphan_system2") - raise Exception, "error" + raise CobblerException("orphan_system2") f1 = self.get_pxelinux_filename(system.name) f2 = os.path.join(self.settings.tftpboot, "pxelinux.cfg", f1) f3 = os.path.join(self.settings.tftpboot, "systems", f1) @@ -210,8 +205,7 @@ class BootSync: elif utils.is_mac(name): return "01-" + "-".join(name.split(":")).lower() else: - utils.set_error(m("err_resolv" % name)) - raise Exception, "error" + raise CobblerException("err_resolv", name) def write_pxelinux_file(self,filename,system,profile,distro): @@ -223,7 +217,7 @@ class BootSync: 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 = profile.kickstart - self.sync_log("writing: %s" % filename) + self.sync_log(cobbler_msg.lookup("writing") % filename) self.sync_log("---------------------------------") fd = self.open_file(filename,"w+") self.tee(fd,"default linux\n") @@ -309,7 +303,7 @@ class BootSync: """ For dry_run support: potentially copy a file. """ - self.sync_log("copy %s to %s" % (src,dst)) + self.sync_log(cobbler_msg.lookup("copying") % (src,dst)) if self.dry_run: return True return shutil.copyfile(src,dst) @@ -318,7 +312,7 @@ class BootSync: """ For dry_run support: potentially copy a file. """ - self.sync_log("copy %s to %s" % (src,dst)) + self.sync_log(cobbler_msg.lookup("copying") % (src,dst)) if self.dry_run: return True return shutil.copy(src,dst) @@ -327,7 +321,7 @@ class BootSync: """ For dry_run support: potentially delete a tree. """ - self.sync_log("removing dir %s" % (path)) + self.sync_log(cobbler_msg.lookup("removing") % (path)) if self.dry_run: return True return shutil.rmtree(path,ignore) @@ -336,7 +330,7 @@ class BootSync: """ For dry_run support: potentially make a directory. """ - self.sync_log("creating dir %s" % (path)) + self.sync_log(cobbler_msg.lookup("mkdir") % (path)) if self.dry_run: return True return os.mkdir(path,mode) @@ -348,7 +342,7 @@ class BootSync: """ if self.verbose: if self.dry_run: - print "dry_run | %s" % message + print cobbler_msg.lookup("dry_run") % message else: print message diff --git a/cobbler/api.py b/cobbler/api.py index d3ea377..a7dbe8b 100644 --- a/cobbler/api.py +++ b/cobbler/api.py @@ -109,9 +109,3 @@ class BootAPI: """ return _config.deserialize() - def last_error(self): - """ - In the event of failure, what went wrong? - """ - return utils.last_error() - diff --git a/cobbler/cobbler.py b/cobbler/cobbler.py index a8de380..33f2253 100755 --- a/cobbler/cobbler.py +++ b/cobbler/cobbler.py @@ -11,7 +11,9 @@ import sys import api import syck import traceback -from msg import * + +import cobbler_msg +from cobbler_exception import CobblerException class BootCLI: @@ -58,13 +60,27 @@ class BootCLI: } + def deserialize(self): + """ + Load data from file(s) + """ + return self.api.deserialize() + + def serialize(self): + """ + Save data to file(s) + """ + return self.api.serialize() + def run(self): """ Run the command line and return system exit code """ - rc = self.curry_args(self.args[1:], self.commands['toplevel']) + rc = self.deserialize() + if rc: + rc = self.curry_args(self.args[1:], self.commands['toplevel']) if not rc: - print self.api.last_error + print self.api.last_error() return 1 return 0 @@ -72,7 +88,7 @@ class BootCLI: """ Print out abbreviated help if user gives bad syntax """ - print m("usage") + print cobbler_msg.lookup("usage") return False @@ -187,7 +203,7 @@ class BootCLI: Parses arguments of the form --foo=bar, see profile_edit for example """ if len(args) == 0: - print m("no_args") + print cobbler_msg.lookup("no_args") return False for x in args: try: @@ -195,25 +211,25 @@ class BootCLI: key, value = x.split("=",1) value = value.replace('"','').replace("'",'') except: - print m("bad_arg") % x + print cobbler_msg.lookup("bad_arg") % x return False if key in input_routines: # --argument is recognized, so run the loader # attached to it in the dispatch table if not input_routines[key](value): # loader does not like passed value - print m("reject_arg") % key + print cobbler_msg.lookup("reject_arg") % key return False else: # --argument is not recognized - print m("weird_arg") % key + print cobbler_msg.lookup("weird_arg") % key return False # success thus far, so run the success routine for the set of # arguments. Configuration will only be written to file if the # final routine succeeds. rc = on_ok() if rc and serialize: - self.api.serialize() + return self.serialize() return rc @@ -223,7 +239,7 @@ class BootCLI: See profiles(), system(), or distro() for examples """ if args is None or len(args) == 0: - print m("help") + print cobbler_msg.lookup("help") return False if args[0] in commands: # if the subargument is in the dispatch table, run @@ -233,7 +249,7 @@ class BootCLI: if not rc: return False else: - print m("unknown_cmd") % args[0] + print cobbler_msg.lookup("unknown_cmd") % args[0] return False return True @@ -258,10 +274,10 @@ class BootCLI: if status is None: return False elif len(status) == 0: - print m("check_ok") + print cobbler_msg.lookup("check_ok") return True else: - print m("need_to_fix") + print cobbler_msg.lookup("need_to_fix") for i,x in enumerate(status): print "#%d: %s" % (i,x) return False @@ -294,16 +310,12 @@ def main(): # verify syck isn't busted (old syck bindings were) if not hasattr(syck,"dump"): - raise Exception("needs a more-recent PySyck module") + raise CobblerException("needs a more-recent PySyck module") - if os.getuid() != 0: - # FIXME: don't require root - print m("need_root") - sys.exit(1) try: cli = BootCLI(sys.argv) - except Exception: - traceback.print_exc() + except Exception, exc: + print exc sys.exit(1) sys.exit(cli.run()) diff --git a/cobbler/cobbler_exception.py b/cobbler/cobbler_exception.py new file mode 100644 index 0000000..c6abfce --- /dev/null +++ b/cobbler/cobbler_exception.py @@ -0,0 +1,20 @@ +""" +Custom error for fatal cobbler exceptions that come with human readable error messages. +These can be caught and printed without stack traces. + +Michael DeHaan +""" + +import exceptions +import cobbler_msg + +class CobblerException(exceptions.Exception): + + def __init__(self, value, args=[]): + if type(args) == str or type(args) == int: + args = (args) + self.value = cobbler_msg.lookup(value) % args + + def __str__(self): + return repr(self.value) + diff --git a/cobbler/cobbler_msg.py b/cobbler/cobbler_msg.py new file mode 100644 index 0000000..69a5dbd --- /dev/null +++ b/cobbler/cobbler_msg.py @@ -0,0 +1,67 @@ +""" +Messages used by cobbler. +This module encapsulates strings so they can +be reused and potentially translated. + +Michael DeHaan +""" + +_msg_table = { + "bad_server" : "server field in /var/lib/cobbler/settings must be set to something other than localhost, or kickstarts will fail", + "parse_error" : "could not read %s, replacing...", + "no_create" : "cannot create: %s", + "no_args" : "this command requires arguments.", + "missing_options" : "cannot add, all parameters have not been set", + "unknown_cmd" : "cobbler doesn't understand '%s'", + "bad_arg" : "expecting an equal sign in argument '%s'", + "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", + "usage" : "for help, see 'man cobbler'", + "need_to_fix" : "the following potential problems were detected:", + "need_perms" : "cobbler cannot access %s", + "no_dhcpd" : "can't find dhcpd, try 'yum install dhcpd'", + "no_pxelinux" : "can't find pxelinux, try 'yum install pxelinux'", + "no_tftpd" : "can't find tftpd, try 'yum install tftpd'", + "no_dir" : "can't find %s, need to create it", + "chg_attrib" : "need to change '%s' to '%s' in '%s'", + "no_exist" : "%s does not exist", + "no_line" : "file '%s' should have a line '%s' somewhere", + "no_dir2" : "can't find %s for %s as referenced in /var/lib/cobbler/settings", + "no_cfg" : "could not find a valid /var/lib/cobbler/settings, rebuilding", + "bad_param" : "at least one parameter is missing for this function", + "empty_list" : "(Empty)", + "err_resolv" : "system (%s) did not resolve", + "err_kickstart" : "kickstart (%s) for item (%s) is not valid", + "err_kickstart2" : "error mirroring kickstart file (%s) to (%s)", + "orphan_profile2" : "system references a non-existant profile", + "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_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'", + "sync_kernel" : "the kernel (%s) for distro (%s) cannot be found and must be fixed", + "sync_initrd" : "the initrd (%s) for distro (%s) cannot be found and must be fixed", + "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 /var/lib/cobbler/settings and dhcpd.conf is suggested to tailor them to your specific configuration. Furthermore, it's important to know that cobbler can't completely understnad what you intend to do with dhcpd.conf, but it looks like there is at least some PXE related information in it. We'll leave this up to you. + +Good luck. +""", + "help" : "see 'man cobbler'" +} + +def lookup(key): + """ + Return the lookup of a string key. + """ + if _msg_table.has_key(key): + return _msg_table[key] + else: + return key + diff --git a/cobbler/collection.py b/cobbler/collection.py index 24a2691..607b344 100644 --- a/cobbler/collection.py +++ b/cobbler/collection.py @@ -8,7 +8,7 @@ import exceptions import serializable import utils -import msg +import cobbler_msg class Collection(serializable.Serializable): @@ -70,9 +70,7 @@ class Collection(serializable.Serializable): won't be added to the collection). """ if ref is None or not ref.is_valid(): - if utils.last_error() is None or utils.last_error() == "": - utils.set_error("bad_param") - return False + raise CobblerException("bad_param") self.listing[ref.name] = ref return True @@ -87,7 +85,7 @@ class Collection(serializable.Serializable): if len(values) > 0: return "\n\n".join(values) else: - return msg.m("empty_list") + return cobbler_msg.lookup("empty_list") def __iter__(self): """ diff --git a/cobbler/collection_distros.py b/cobbler/collection_distros.py index be024fc..5f49d16 100644 --- a/cobbler/collection_distros.py +++ b/cobbler/collection_distros.py @@ -30,11 +30,9 @@ class Distros(collection.Collection): # first see if any Groups use this distro for v in self.config.profiles(): if v.distro == name: - utils.set_error("orphan_files") - return False + raise CobblerException("orphan_files") if self.find(name): del self.listing[name] return True - utils.set_error("delete_nothing") - return False + raise CobblerException("delete_nothing") diff --git a/cobbler/collection_profiles.py b/cobbler/collection_profiles.py index a5b1996..b1c92dd 100644 --- a/cobbler/collection_profiles.py +++ b/cobbler/collection_profiles.py @@ -10,6 +10,7 @@ Michael DeHaan import item_profile as profile import utils import collection +from cobbler_exception import CobblerException #-------------------------------------------- @@ -27,11 +28,9 @@ class Profiles(collection.Collection): """ for k,v in self.config.systems().listing.items(): if v.profile == name: - utils.set_error("orphan_system") - return False + raise CobblerException("orphan_system") if self.find(name): del self.listing[name] return True - utils.set_error("delete_nothing") - return False + raise CobblerException("delete_nothing") diff --git a/cobbler/collection_systems.py b/cobbler/collection_systems.py index 5d201bc..3147a67 100644 --- a/cobbler/collection_systems.py +++ b/cobbler/collection_systems.py @@ -8,6 +8,7 @@ Michael DeHaan import item_system as system import utils import collection +from cobbler_exception import CobblerException #-------------------------------------------- @@ -32,6 +33,5 @@ class Systems(collection.Collection): if self.find(name): del self.listing[name] return True - utils.set_error("delete_nothing") - return False + raise CobblerException("delete_nothing") diff --git a/cobbler/item_distro.py b/cobbler/item_distro.py index aa2d463..59250af 100644 --- a/cobbler/item_distro.py +++ b/cobbler/item_distro.py @@ -10,6 +10,7 @@ import utils import item import weakref import os +from cobbler_exception import CobblerException class Distro(item.Item): @@ -50,8 +51,7 @@ class Distro(item.Item): if utils.find_kernel(kernel): self.kernel = kernel return True - utils.set_error("no_kernel") - return False + raise CobblerException("no_kernel") def set_initrd(self,initrd): """ @@ -61,8 +61,7 @@ class Distro(item.Item): if utils.find_initrd(initrd): self.initrd = initrd return True - utils.set_error("no_initrd") - return False + raise CobblerException("no_initrd") def is_valid(self): """ diff --git a/cobbler/item_profile.py b/cobbler/item_profile.py index 9fd308a..c344fc3 100644 --- a/cobbler/item_profile.py +++ b/cobbler/item_profile.py @@ -7,7 +7,7 @@ Michael DeHaan import utils import item -from msg import * +from cobbler_exception import CobblerException class Profile(item.Item): @@ -57,8 +57,7 @@ class Profile(item.Item): if self.config.distros().find(distro_name): self.distro = distro_name return True - utils.set_error("no_distro") - return False + raise CobblerException("no_distro") def set_kickstart(self,kickstart): """ @@ -68,8 +67,7 @@ class Profile(item.Item): if utils.find_kickstart(kickstart): self.kickstart = kickstart return True - utils.set_error("no_kickstart") - return False + raise CobblerException("no_kickstart") def set_xen_name(self,str): """ diff --git a/cobbler/item_system.py b/cobbler/item_system.py index 0819781..fef3743 100644 --- a/cobbler/item_system.py +++ b/cobbler/item_system.py @@ -6,6 +6,7 @@ Michael DeHaan import utils import item +from cobbler_exception import CobblerException class System(item.Item): @@ -32,8 +33,7 @@ class System(item.Item): """ new_name = utils.find_system_identifier(name) if not new_name: - utils.set_error("bad_sys_name") - return False + raise CobblerException("bad_sys_name") self.name = name # we check it add time, but store the original value. return True @@ -52,8 +52,7 @@ class System(item.Item): A system is valid when it contains a valid name and a profile. """ if self.name is None: - utils.set_error("bad_sys_name") - return False + raise CobblerException("bad_sys_name") if self.profile is None: return False return True diff --git a/cobbler/msg.py b/cobbler/msg.py deleted file mode 100644 index e617e58..0000000 --- a/cobbler/msg.py +++ /dev/null @@ -1,66 +0,0 @@ -""" -Messages used by cobbler. -This module encapsulates strings so they can -be reused and potentially translated. - -Michael DeHaan -""" - -msg_table = { - "bad_server" : "server field in /var/lib/cobbler/settings must be set to something other than localhost, or kickstarts will fail", - "parse_error" : "could not read %s, replacing...", - "no_create" : "cannot create: %s", - "no_args" : "this command requires arguments.", - "missing_options" : "cannot add, all parameters have not been set", - "unknown_cmd" : "cobbler doesn't understand '%s'", - "bad_arg" : "expecting an equal sign in argument '%s'", - "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", - "usage" : "for help, see 'man cobbler'", - "need_to_fix" : "the following potential problems were detected:", - "need_root" : "cobbler 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'", - "no_tftpd" : "can't find tftpd, try 'yum install tftpd'", - "no_dir" : "can't find %s, need to create it", - "chg_attrib" : "need to change '%s' to '%s' in '%s'", - "no_exist" : "%s does not exist", - "no_line" : "file '%s' should have a line '%s' somewhere", - "no_dir2" : "can't find %s for %s as referenced in /var/lib/cobbler/settings", - "no_cfg" : "could not find a valid /var/lib/cobbler/settings, rebuilding", - "bad_param" : "at least one parameter is missing for this function", - "empty_list" : "(Empty)", - "err_resolv" : "system (%s) did not resolve", - "err_kickstart" : "kickstart (%s) for item (%s) is not valid", - "err_kickstart2" : "error mirroring kickstart file (%s) to (%s)", - "orphan_profile2" : "system references a non-existant profile", - "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_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 /var/lib/cobbler/settings and dhcpd.conf is suggested to tailor them to your specific configuration. Furthermore, it's important to know that cobbler can't completely understnad what you intend to do with dhcpd.conf, but it looks like there is at least some PXE related information in it. We'll leave this up to you. - -Good luck. -""", - "help" : "see 'man cobbler'" -} - -def m(key): - """ - Return the lookup of a string key. - """ - if key in msg_table: - # localization could use different tables or just gettext. - return msg_table[key] - else: - return key - diff --git a/cobbler/serializer.py b/cobbler/serializer.py index da4c684..a63cd6e 100644 --- a/cobbler/serializer.py +++ b/cobbler/serializer.py @@ -1,28 +1,64 @@ # Michael DeHaan import syck # PySyck 0.61 or greater, not syck-python 0.55 -import msg +import errno +import os + +import utils def serialize(obj): - if obj.filename() is None: - raise Exception("not serializable") - fd = open(obj.filename(),"w+") - datastruct = obj.to_datastruct() - encoded = syck.dump(datastruct) - fd.write(encoded) - fd.close() - return True + """ + Save an object to disk. Object must "implement" Serializable. + Will create intermediate paths if it can. Returns True on Success, + False on permission errors. + """ + filename = obj.filename() + try: + fd = open(filename,"w+") + except IOError, ioe: + basename = os.path.basename(filename) + if not os.path.exists(basename): + try: + os.makedirs(basename) + except: + raise CobblerException("need_perms", basename) + return False + try: + fd = open(filename,"w+") + except: + raise CobblerException("need_perms", filename) + return False + datastruct = obj.to_datastruct() + encoded = syck.dump(datastruct) + fd.write(encoded) + fd.close() + return True def deserialize(obj): - if obj.filename() is None: - raise Exception("not serializable") - try: - fd = open(obj.filename(),"r") - except: - print msg.m("parse_error") % obj.filename() - return - data = fd.read() - datastruct = syck.load(data) - fd.close() - obj.from_datastruct(datastruct) - return True + """ + Populate an existing object with the contents of datastruct. + Object must "implement" Serializable. Returns True assuming + files could be read and contained decent YAML. Otherwise returns + False. + """ + filename = obj.filename() + try: + fd = open(filename,"r") + except IOError, ioe: + # if it doesn't exist, that's cool -- it's not a bug until we try + # to write the file and can't create it. + if not os.path.exists(filename): + return True + else: + raise CobblerException("need_perms",obj.filename()) + data = fd.read() + datastruct = syck.load(data) + if type(datastruct) == str: + # PySyck returns strings when it chokes on data + # it doesn't really throw exceptions + raise CobblerException("parse_error",filename) + fd.close() + obj.from_datastruct(datastruct) + return True + + diff --git a/cobbler/utils.py b/cobbler/utils.py index c6cc019..3c82044 100644 --- a/cobbler/utils.py +++ b/cobbler/utils.py @@ -10,24 +10,8 @@ import socket import glob import subprocess -import msg - _re_kernel = re.compile(r'vmlinuz-(\d+)\.(\d+)\.(\d+)-(.*)') _re_initrd = re.compile(r'initrd-(\d+)\.(\d+)\.(\d+)-(.*).img') -_utils_last_error = "" - -def last_error(): - """ - Return the last error message set with set_error - """ - return _utils_last_error - -def set_error(strmsg): - """ - Set the error message for the last failed operation - """ - global _utils_last_error - _utils_last_error = msg.m(strmsg) def get_host_ip(ip): """ -- cgit