summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael DeHaan <mdehaan@redhat.com>2006-05-05 17:48:01 -0400
committerJim Meyering <jim@meyering.net>2006-05-05 17:48:01 -0400
commit8e434ed6574a5b391d9b57f3cbb10f73e62a403c (patch)
tree0ccf20785615db6ae452a674959451a77af8eebc
parent297525dcb3c500d086bb4a5006a5839d98f8522b (diff)
downloadthird_party-cobbler-8e434ed6574a5b391d9b57f3cbb10f73e62a403c.tar.gz
third_party-cobbler-8e434ed6574a5b391d9b57f3cbb10f73e62a403c.tar.xz
third_party-cobbler-8e434ed6574a5b391d9b57f3cbb10f73e62a403c.zip
Interim commit
-rw-r--r--cobbler/.serializable.py.swp0
-rw-r--r--cobbler/api.py16
-rwxr-xr-xcobbler/cobbler.py32
-rw-r--r--cobbler/collection.py26
-rw-r--r--cobbler/config.py65
-rw-r--r--cobbler/distro.py27
-rw-r--r--cobbler/distros.py19
-rw-r--r--cobbler/item.py5
-rw-r--r--cobbler/msg.py3
-rw-r--r--cobbler/profile.py39
-rw-r--r--cobbler/profiles.py19
-rw-r--r--cobbler/serializable.py5
-rw-r--r--cobbler/serializer.py17
-rw-r--r--cobbler/settings.py8
-rw-r--r--cobbler/sync.py19
-rw-r--r--cobbler/system.py27
-rw-r--r--cobbler/systems.py15
-rw-r--r--cobbler/utils.py (renamed from cobbler/util.py)50
-rw-r--r--tests/tests.py46
19 files changed, 285 insertions, 153 deletions
diff --git a/cobbler/.serializable.py.swp b/cobbler/.serializable.py.swp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cobbler/.serializable.py.swp
diff --git a/cobbler/api.py b/cobbler/api.py
index d93bf54..4d93da2 100644
--- a/cobbler/api.py
+++ b/cobbler/api.py
@@ -10,14 +10,14 @@ import os
import traceback
import config
-import util
+import utils
import sync
import check
-from msg import *
+
+_config = config.Config()
class BootAPI:
- _config = config.Config()
def __init__(self):
"""
@@ -61,22 +61,21 @@ class BootAPI:
"""
Return a blank, unconfigured system, unattached to a collection
"""
- return system.System(self,None)
+ return _config.new_system()
def new_distro(self):
"""
Create a blank, unconfigured distro, unattached to a collection.
"""
- return distro.Distro(self,None)
+ return _config.new_distro()
def new_profile(self):
"""
Create a blank, unconfigured profile, unattached to a collection
"""
- return profile.Profile(self,None)
-
+ return _config.new_profile()
def check(self):
"""
@@ -113,3 +112,6 @@ class BootAPI:
"""
_config.deserialize()
+ def last_error(self):
+ return utils.last_error()
+
diff --git a/cobbler/cobbler.py b/cobbler/cobbler.py
index fb58ff7..f170aee 100755
--- a/cobbler/cobbler.py
+++ b/cobbler/cobbler.py
@@ -80,21 +80,21 @@ class BootCLI:
"""
Print out the list of systems: 'cobbler system list'
"""
- print self.api.get_systems().printable()
+ print self.api.systems().printable()
return True
def profile_list(self,args):
"""
Print out the list of profiles: 'cobbler profile list'
"""
- print self.api.get_profiles().printable()
+ print self.api.profiles().printable()
return True
def distro_list(self,args):
"""
Print out the list of distros: 'cobbler distro list'
"""
- print self.api.get_distros().printable()
+ print self.api.distros().printable()
return True
def system_remove(self,args):
@@ -102,7 +102,7 @@ class BootCLI:
Delete a system: 'cobbler system remove --name=foo'
"""
commands = {
- '--name' : lambda(a): self.api.get_systems().remove(a)
+ '--name' : lambda(a): self.api.systems().remove(a)
}
on_ok = lambda: True
return self.apply_args(args,commands,on_ok,True)
@@ -113,7 +113,7 @@ class BootCLI:
Delete a profile: 'cobbler profile remove --name=foo'
"""
commands = {
- '--name' : lambda(a): self.api.get_profiles().remove(a)
+ '--name' : lambda(a): self.api.profiles().remove(a)
}
on_ok = lambda: True
return self.apply_args(args,commands,on_ok,True)
@@ -124,7 +124,7 @@ class BootCLI:
Delete a distro: 'cobbler distro remove --name='foo'
"""
commands = {
- '--name' : lambda(a): self.api.get_distros().remove(a)
+ '--name' : lambda(a): self.api.distros().remove(a)
}
on_ok = lambda: True
return self.apply_args(args,commands,on_ok,True)
@@ -141,7 +141,7 @@ class BootCLI:
'--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)
+ on_ok = lambda: self.api.systems().add(sys)
return self.apply_args(args,commands,on_ok,True)
@@ -163,7 +163,7 @@ class BootCLI:
# '--xen-mac' : lambda(a) : profile.set_xen_mac(a),
# '--xen-paravirt' : lambda(a) : profile.set_xen_paravirt(a),
}
- on_ok = lambda: self.api.get_profiles().add(profile)
+ on_ok = lambda: self.api.profiles().add(profile)
return self.apply_args(args,commands,on_ok,True)
@@ -178,7 +178,7 @@ class BootCLI:
'--initrd' : lambda(a) : distro.set_initrd(a),
'--kopts' : lambda(a) : distro.set_kernel_options(a)
}
- on_ok = lambda: self.api.get_distros().add(distro)
+ on_ok = lambda: self.api.distros().add(distro)
return self.apply_args(args,commands,on_ok,True)
@@ -298,18 +298,14 @@ def main():
raise Exception("needs a more-recent PySyck")
if os.getuid() != 0:
- # while it's true that we don't technically need root, we do need
- # permissions on a relatively long list of files that ordinarily
- # only root has access to, and we don't know specifically what
- # files are where (other distributions in play, etc). It's
- # fairly safe to assume root is required. This might be patched
- # later.
+ # FIXME: don't require root
print m("need_root")
sys.exit(1)
try:
cli = BootCLI(sys.argv)
except Exception, e:
- if not str(e) or not str(e).startswith("parse_error"):
- traceback.print_exc()
- sys.exit(3)
+ traceback.print_exc()
+ sys.exit(1)
sys.exit(cli.run())
+
+
diff --git a/cobbler/collection.py b/cobbler/collection.py
index 5a008f7..708bb98 100644
--- a/cobbler/collection.py
+++ b/cobbler/collection.py
@@ -1,15 +1,25 @@
+import serializable
"""
Base class for any serializable lists of things...
"""
-class Collection(Serializable):
- _item_factory = None
- _filename = None
+class Collection(serializable.Serializable):
- def __init__(self):
+ def class_container(self):
+ raise exceptions.NotImplementedError
+
+ def filename(self):
+ raise exceptions.NotImplementedError
+
+ def __init__(self,config):
"""
Constructor.
"""
+ self.config = config
+ self.clear()
+
+
+ def clear(self):
self.listing = {}
def find(self,name):
@@ -29,8 +39,10 @@ class Collection(Serializable):
datastruct = [x.to_datastruct() for x in self.listing.values()]
def from_datastruct(self,datastruct):
+ container = self.class_container()
for x in datastruct:
- self._item_factory(x)
+ item = container(x,self.config)
+ self.add(item)
def add(self,ref):
"""
@@ -40,8 +52,8 @@ class Collection(Serializable):
won't be added to the collection).
"""
if ref is None or not ref.is_valid():
- if runtime.last_error() is None or runtime.last_error() == "":
- runtime.set_error("bad_param")
+ if utils.last_error() is None or utils.last_error() == "":
+ utils.set_error("bad_param")
return False
self.listing[ref.name] = ref
return True
diff --git a/cobbler/config.py b/cobbler/config.py
new file mode 100644
index 0000000..27c33bd
--- /dev/null
+++ b/cobbler/config.py
@@ -0,0 +1,65 @@
+"""
+Config.py is a repository of the Cobbler object model
+"""
+import weakref
+
+import distro
+import profile
+import system
+
+import distros
+import profiles
+import systems
+
+import settings
+import serializer
+
+class Config:
+
+ def __init__(self):
+ # manage a definitive copy of all data collections with weakrefs
+ # back here so they can understand each other
+ self._distros = distros.Distros(weakref.proxy(self))
+ self._profiles = profiles.Profiles(weakref.proxy(self))
+ self._systems = systems.Systems(weakref.proxy(self))
+ self._settings = settings.Settings() # not a true collection
+ self._classes = [
+ self._distros,
+ self._profiles,
+ self._systems,
+ self._settings,
+ ]
+
+ def distros(self):
+ return self._distros
+
+ def profiles(self):
+ return self._profiles
+
+ def systems(self):
+ return self._systems
+
+ def settings(self):
+ return self._app_settings
+
+ def new_distro(self):
+ return distro.Distro(weakref.proxy(self))
+
+ def new_system(self):
+ return system.System(weakref.proxy(self))
+
+ def new_profile(self):
+ return profile.Profile(weakref.proxy(self))
+
+ def clear(self):
+ for x in self._classes:
+ x.clear()
+
+ def serialize(self):
+ for x in self._classes:
+ serializer.serialize(x)
+
+ def deserialize(self):
+ for x in self._classes:
+ serializer.deserialize(x)
+
diff --git a/cobbler/distro.py b/cobbler/distro.py
index ddfed2b..ef2f1df 100644
--- a/cobbler/distro.py
+++ b/cobbler/distro.py
@@ -1,15 +1,24 @@
-class Distro(Item):
+import utils
+import item
+import weakref
- def __init__(self,seed_data):
+class Distro(item.Item):
+
+ def __init__(self,config):
+ self.config = config
+ self.clear()
+
+ def clear(self):
self.name = None
self.kernel = None
self.initrd = None
self.kernel_options = ""
- if seed_data is not None:
- self.name = seed_data['name']
- self.kernel = seed_data['kernel']
- self.initrd = seed_data['initrd']
- self.kernel_options = seed_data['kernel_options']
+
+ def from_datastruct(seed_data):
+ self.name = seed_data['name']
+ self.kernel = seed_data['kernel']
+ self.initrd = seed_data['initrd']
+ self.kernel_options = seed_data['kernel_options']
def set_kernel(self,kernel):
"""
@@ -22,7 +31,7 @@ class Distro(Item):
if utils.find_kernel(kernel):
self.kernel = kernel
return True
- runtime.set_error("no_kernel")
+ utils.set_error("no_kernel")
return False
def set_initrd(self,initrd):
@@ -33,7 +42,7 @@ class Distro(Item):
if utils.find_initrd(initrd):
self.initrd = initrd
return True
- runtime.set_error("no_initrd")
+ utils.set_error("no_initrd")
return False
def is_valid(self):
diff --git a/cobbler/distros.py b/cobbler/distros.py
index a510fd0..f60f776 100644
--- a/cobbler/distros.py
+++ b/cobbler/distros.py
@@ -1,27 +1,32 @@
import distro
-import runtime
+import utils
import profiles
+import collection
"""
A distro represents a network bootable matched set of kernels
and initrd files
"""
-class Distros(Collection):
- _item_factory = distro.Distro
- _filename = "/var/lib/cobbler/distros"
+class Distros(collection.Collection):
+
+ def class_container(self):
+ return distro.Distro
+
+ def filename(self):
+ return "/var/lib/cobbler/distros"
def remove(self,name):
"""
Remove element named 'name' from the collection
"""
# first see if any Groups use this distro
- for k,v in profile.profiles().listing.items():
+ for k,v in self.config.profiles().listing.items():
if v.distro == name:
- runtime.set_error("orphan_files")
+ utils.set_error("orphan_files")
return False
if self.find(name):
del self.listing[name]
return True
- runtime.set_error("delete_nothing")
+ utils.set_error("delete_nothing")
return False
diff --git a/cobbler/item.py b/cobbler/item.py
index 0d43d9f..a881b40 100644
--- a/cobbler/item.py
+++ b/cobbler/item.py
@@ -1,7 +1,10 @@
+
+import serializable
+
"""
An Item is a serializable thing that can appear in a Collection
"""
-class Item:
+class Item(serializable.Serializable):
"""
constructor must be of format:
diff --git a/cobbler/msg.py b/cobbler/msg.py
index a9e1676..dc6211a 100644
--- a/cobbler/msg.py
+++ b/cobbler/msg.py
@@ -8,8 +8,7 @@ be reused and potentially translated.
msg_table = {
"bad_server" : "server field in /etc/cobbler.conf must be set to something other than localhost, or kickstarts will fail",
- "parse_error" : "could not parse /etc/cobbler.conf, must fix manually",
- "parse_error2" : "could not parse /var/lib/cobbler/cobbler.conf, replacing...",
+ "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",
diff --git a/cobbler/profile.py b/cobbler/profile.py
index 09c91bf..592cbcb 100644
--- a/cobbler/profile.py
+++ b/cobbler/profile.py
@@ -1,6 +1,12 @@
+import utils
+
class Profile(Item):
- def __init__(self,seed_data):
+ def __init__(self,config):
+ self.config = config
+ self.clear()
+
+ def clear(self):
self.name = None
self.distro = None # a name, not a reference
self.kickstart = None
@@ -10,25 +16,26 @@ class Profile(Item):
self.xen_ram = 2048 # MB
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.xen_name = seed_data['xen_name']
- if not self.xen_name or self.xen_name == '':
- self.xen_name = self.name
- self.xen_ram = seed_data['xen_ram']
- self.xen_file_size = seed_data['xen_file_size']
- self.xen_mac = seed_data['xen_mac']
- self.xen_paravirt = seed_data['xen_paravirt']
+
+ def from_datastruct(seed_data)
+ 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 = seed_data['xen_name']
+ if not self.xen_name or self.xen_name == '':
+ self.xen_name = self.name
+ self.xen_ram = seed_data['xen_ram']
+ self.xen_file_size = seed_data['xen_file_size']
+ self.xen_mac = seed_data['xen_mac']
+ self.xen_paravirt = seed_data['xen_paravirt']
def set_distro(self,distro_name):
"""
Sets the distro. This must be the name of an existing
Distro object in the Distros collection.
"""
- if self.api.get_distros().find(distro_name):
+ if self.api.distros().find(distro_name):
self.distro = distro_name
return True
self.last_error = m("no_distro")
@@ -39,7 +46,7 @@ class Profile(Item):
Sets the kickstart. This must be a NFS, HTTP, or FTP URL.
Minor checking of the URL is performed here.
"""
- if self.api.utils.find_kickstart(kickstart):
+ if utils.find_kickstart(kickstart):
self.kickstart = kickstart
return True
self.last_error = m("no_kickstart")
@@ -94,7 +101,7 @@ class Profile(Item):
"""
# 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):
+ if utils.is_mac(mac):
self.xen_mac = mac
return True
else:
diff --git a/cobbler/profiles.py b/cobbler/profiles.py
index 9fb2d92..972ba23 100644
--- a/cobbler/profiles.py
+++ b/cobbler/profiles.py
@@ -1,5 +1,6 @@
import profile
-import runtime
+import utils
+import collection
#--------------------------------------------
@@ -9,21 +10,25 @@ For instance, FC5 with a kickstart file specifying OpenOffice
might represent a 'desktop' profile. For Xen, there are many
additional options, with client-side defaults (not kept here).
"""
-class Profiles(Collection):
- _item_factory = profile.Profile
- _filename = "/var/lib/cobbler/profiles"
+class Profiles(collection.Collection):
+
+ def class_container(self):
+ return profile.Profile
+
+ def filename(self):
+ return "/var/lib/cobbler/profiles"
def remove(self,name):
"""
Remove element named 'name' from the collection
"""
- for k,v in self.api.get_systems().listing.items():
+ for k,v in self.config.systems().listing.items():
if v.profile == name:
- runtime.set_error("orphan_system")
+ utils.set_error("orphan_system")
return False
if self.find(name):
del self.listing[name]
return True
- runtime.set_error("delete_nothing")
+ utils.set_error("delete_nothing")
return False
diff --git a/cobbler/serializable.py b/cobbler/serializable.py
index e03b88f..de1d171 100644
--- a/cobbler/serializable.py
+++ b/cobbler/serializable.py
@@ -1,3 +1,4 @@
+import exceptions
class Serializable:
@@ -5,8 +6,8 @@ class Serializable:
return None
def from_datastruct(datastruct):
- raise "not implemented"
+ raise exceptions.NotImplementedError
def to_datastruct():
- raise "not implemented"
+ raise exceptions.NotImplementedError
diff --git a/cobbler/serializer.py b/cobbler/serializer.py
index 847be6e..112025e 100644
--- a/cobbler/serializer.py
+++ b/cobbler/serializer.py
@@ -1,9 +1,13 @@
# Michael DeHaan <mdehaan@redhat.com>
import api
-import util
+import utils
+import syck # PySyck 0.61 or greater, not syck-python 0.55
+import msg
def serialize(obj):
+ if obj.filename() is None:
+ raise Exception("not serializable")
fd = open(obj.filename(),"w+")
datastruct = obj.to_datastruct()
yaml = syck.dump(datastruct)
@@ -12,8 +16,15 @@ def serialize(obj):
return True
def deserialize(obj):
- fd = open(obj.filename(),"r")
+ 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 = yaml.load(data)
fd.close()
- return obj.from_datastruct(datastruct)
+ obj.from_datastruct(datastruct)
+ return True
diff --git a/cobbler/settings.py b/cobbler/settings.py
index 2a7553f..79b09e1 100644
--- a/cobbler/settings.py
+++ b/cobbler/settings.py
@@ -1,14 +1,18 @@
+import serializable
+
"""
Cobbler app-wide settings
"""
-class Settings(Serializable)
+class Settings(serializable.Serializable):
def filename(self):
return "/var/lib/cobbler/settings"
def __init__(self):
+ self.clear()
+ def clear(self):
self._attributes = {
"httpd_bin" : "/usr/sbin/httpd",
"pxelinux" : "/usr/lib/syslinux/pxelinux.0",
@@ -20,6 +24,7 @@ class Settings(Serializable)
"tftpd_conf" : "/etc/xinetd.d/tftp",
"tftpboot" : "/tftpboot",
}
+
def to_datastruct():
return self._attributes()
@@ -32,3 +37,4 @@ class Settings(Serializable)
return self._attributes[name]
else:
raise AttributeError, name
+
diff --git a/cobbler/sync.py b/cobbler/sync.py
index c768b57..76dfb38 100644
--- a/cobbler/sync.py
+++ b/cobbler/sync.py
@@ -10,7 +10,6 @@ import traceback
import re
import shutil
import syck
-import IPy
import weakref
from msg import *
@@ -104,11 +103,11 @@ 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):
- runtime.set_error("Kernel for distro (%s) cannot be found and needs to be fixed: %s" % (d.name, d.kernel))
- print runtime.last_error()
+ 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")
if initrd is None or not os.path.isfile(initrd):
- runtime.last_error("Initrd for distro (%s) cannot be found and needs to be fixed: %s" % (d.name, d.initrd))
+ utils.last_error("Initrd for distro (%s) cannot be found and needs to be fixed: %s" % (d.name, d.initrd))
raise Exception("error")
b_kernel = os.path.basename(kernel)
b_initrd = os.path.basename(initrd)
@@ -138,7 +137,7 @@ class BootSync:
try:
self.copyfile(g.kickstart, dest)
except:
- runtime.set_error("err_kickstart2")
+ utils.set_error("err_kickstart2")
raise "error"
def build_trees(self):
@@ -180,11 +179,11 @@ class BootSync:
self.sync_log("processing system: %s" % system.name)
profile = self.profiles.find(system.profile)
if profile is None:
- runtime.set_error("orphan_profile2")
+ utils.set_error("orphan_profile2")
raise "error"
distro = self.distros.find(profile.distro)
if distro is None:
- runtime.set_error("orphan_system2")
+ utils.set_error("orphan_system2")
raise "error"
f1 = self.get_pxelinux_filename(system.name)
f2 = os.path.join(self.settings.tftpboot, "pxelinux.cfg", f1)
@@ -203,11 +202,11 @@ class BootSync:
"""
name = utils.find_system_identifier(name_input)
if utils.is_ip(name):
- return IPy.IP(name).strHex()[2:]
+ return utils.get_host_ip(name)
elif utils.is_mac(name):
return "01-" + "-".join(name.split(":")).lower()
else:
- runtime.set_error(m("err_resolv" % name)
+ utils.set_error(m("err_resolv" % name))
raise "error"
@@ -239,7 +238,7 @@ class BootSync:
# if kickstart path is local, we've already copied it into
# the HTTP mirror, so make it something anaconda can get at
if kickstart_path.startswith("/"):
- kickstart_path = "http://%s/cobbler/kickstarts/%s/ks.cfg" % self.settings.server, profile.name)
+ kickstart_path = "http://%s/cobbler/kickstarts/%s/ks.cfg" % (self.settings.server, profile.name)
nextline = nextline + " ks=%s" % kickstart_path
self.tee(fd, nextline)
self.close_file(fd)
diff --git a/cobbler/system.py b/cobbler/system.py
index dc1a2f7..9e5e5c6 100644
--- a/cobbler/system.py
+++ b/cobbler/system.py
@@ -1,16 +1,21 @@
+import utils
+import item
-class System(Item):
+class System(item.Item):
- def __init__(self,api,seed_data):
- self.api = api
+ def __init__(self,config):
+ self.config = config
+ self.clear()
+
+ def clear(self):
self.name = None
self.profile = None # a name, not a reference
self.kernel_options = ""
- if seed_data is not None:
- self.name = seed_data['name']
- self.profile = seed_data['profile']
- self.kernel_options = seed_data['kernel_options']
+ def from_datastruct(seed_data):
+ self.name = seed_data['name']
+ self.profile = seed_data['profile']
+ self.kernel_options = seed_data['kernel_options']
def set_name(self,name):
"""
@@ -18,9 +23,9 @@ class System(Item):
any legal ipv4 address, or any legal mac address. ipv6 is not supported yet but _should_ be.
See utils.py
"""
- new_name = self.api.utils.find_system_identifier(name)
+ new_name = utils.find_system_identifier(name)
if new_name is None or new_name == False:
- self.api.last_error = m("bad_sys_name")
+ utils.last_error = m("bad_sys_name")
return False
self.name = name # we check it add time, but store the original value.
return True
@@ -30,7 +35,7 @@ class System(Item):
Set the system to use a certain named profile. The profile
must have already been loaded into the Profiles collection.
"""
- if self.api.get_profiles().find(profile_name):
+ if self.config.profiles().find(profile_name):
self.profile = profile_name
return True
return False
@@ -40,7 +45,7 @@ class System(Item):
A system is valid when it contains a valid name and a profile.
"""
if self.name is None:
- self.api.last_error = m("bad_sys_name")
+ utils.last_error = m("bad_sys_name")
return False
if self.profile is None:
return False
diff --git a/cobbler/systems.py b/cobbler/systems.py
index 9c48c00..dc25096 100644
--- a/cobbler/systems.py
+++ b/cobbler/systems.py
@@ -1,5 +1,6 @@
import system
-import runtime
+import utils
+import collection
#--------------------------------------------
@@ -7,9 +8,13 @@ import runtime
Systems are hostnames/MACs/IP names and the associated profile
they belong to.
"""
-class Systems(Collection):
- _item_factory = system.System
- _filename = "/var/lib/cobbler/systems"
+class Systems(collection.Collection):
+
+ def class_container(self):
+ return system.System
+
+ def filename(self):
+ return "/var/lib/cobbler/systems"
def remove(self,name):
"""
@@ -18,6 +23,6 @@ class Systems(Collection):
if self.find(name):
del self.listing[name]
return True
- runtime.set_error("delete_nothing")
+ utils.set_error("delete_nothing")
return False
diff --git a/cobbler/util.py b/cobbler/utils.py
index a851440..5a5f6fe 100644
--- a/cobbler/util.py
+++ b/cobbler/utils.py
@@ -2,40 +2,42 @@
#
# Michael DeHaan <mdehaan@redhat.com>
-import config
-
import os
import re
import socket
import glob
-import weakref
import subprocess
re_kernel = re.compile(r'vmlinuz-(\d+)\.(\d+)\.(\d+)-(.*)')
re_initrd = re.compile(r'initrd-(\d+)\.(\d+)\.(\d+)-(.*).img')
+_last_error = ""
+
+def last_error():
+ return _last_error
+
+def set_error(strmsg):
+ _last_error = msg.m(strmsg)
def get_host_ip(ip):
- handle = subprocess.Popen("/usr/bin/gethostip %s" % ip,
- shell=True
- stdout=PIPE)
+ handle = subprocess.Popen("/usr/bin/gethostip %s" % ip, shell=True, stdout=subprocess.PIPE)
out = handle.stdout
results = out.read()
return results.split(" ")[-1]
-def find_system_identifier(self,strdata):
+def find_system_identifier(strdata):
"""
If the input is a MAC or an IP, return that.
If it's not, resolve the hostname and return the IP.
pxelinux doesn't work in hostnames
"""
- if self.is_mac(strdata):
+ if is_mac(strdata):
return strdata
- if self.is_ip(strdata):
+ if is_ip(strdata):
return strdata
- return self.resolve_ip(strdata)
+ return resolve_ip(strdata)
-def is_ip(self,strdata):
+def is_ip(strdata):
"""
Return whether the argument is an IP address. ipv6 needs
to be added...
@@ -46,7 +48,7 @@ def is_ip(self,strdata):
return False
-def is_mac(self,strdata):
+def is_mac(strdata):
"""
Return whether the argument is a mac address.
"""
@@ -56,7 +58,7 @@ def is_mac(self,strdata):
return False
-def resolve_ip(self,strdata):
+def resolve_ip(strdata):
"""
Resolve the IP address and handle errors...
"""
@@ -66,7 +68,7 @@ def resolve_ip(self,strdata):
return None
-def find_matching_files(self,directory,regex):
+def find_matching_files(directory,regex):
"""
Find all files in a given directory that match a given regex.
Can't use glob directly as glob doesn't take regexen.
@@ -79,13 +81,13 @@ def find_matching_files(self,directory,regex):
return results
-def find_highest_files(self,directory,unversioned,regex):
+def find_highest_files(directory,unversioned,regex):
"""
Find the highest numbered file (kernel or initrd numbering scheme)
in a given directory that matches a given pattern. Used for
auto-booting the latest kernel in a directory.
"""
- files = self.find_matching_files(directory, regex)
+ files = find_matching_files(directory, regex)
get_numbers = re.compile(r'(\d+).(\d+).(\d+)')
def max2(a, b):
"""Returns the larger of the two values"""
@@ -108,23 +110,23 @@ def find_highest_files(self,directory,unversioned,regex):
return None
-def find_kernel(self,path):
+def find_kernel(path):
"""
Given a directory or a filename, find if the path can be made
to resolve into a kernel, and return that full path if possible.
"""
if os.path.isfile(path):
filename = os.path.basename(path)
- if self.re_kernel.match(filename):
+ if re_kernel.match(filename):
return path
elif filename == "vmlinuz":
return path
elif os.path.isdir(path):
- return self.find_highest_files(path,"vmlinuz",self.re_kernel)
- return None
+ return find_highest_files(path,"vmlinuz",re_kernel)
+ return None
-def find_initrd(self,path):
+def find_initrd(path):
"""
Given a directory or a filename, see if the path can be made
to resolve into an intird, return that full path if possible.
@@ -132,16 +134,16 @@ def find_initrd(self,path):
# FUTURE: try to match kernel/initrd pairs?
if os.path.isfile(path):
filename = os.path.basename(path)
- if self.re_initrd.match(filename):
+ if re_initrd.match(filename):
return path
if filename == "initrd.img" or filename == "initrd":
return path
elif os.path.isdir(path):
- return self.find_highest_files(path,"initrd.img",self.re_initrd)
+ return find_highest_files(path,"initrd.img",re_initrd)
return None
-def find_kickstart(self,url):
+def find_kickstart(url):
"""
Check if a kickstart url looks like an http, ftp, nfs or local path.
If a local path is used, cobbler will copy the kickstart and serve
diff --git a/tests/tests.py b/tests/tests.py
index 1db0ba3..e5bcb54 100644
--- a/tests/tests.py
+++ b/tests/tests.py
@@ -80,37 +80,37 @@ class Utilities(BootTest):
"Expected: %s; actual: %s" % (expected, actual))
def test_kernel_scan(self):
- self.assertTrue(self.api.utils.find_kernel(self.fk_kernel))
- self.assertFalse(self.api.utils.find_kernel("/etc/fstab"))
- self.assertFalse(self.api.utils.find_kernel("filedoesnotexist"))
- self._expeq(self.fk_kernel, self.api.utils.find_kernel(self.topdir))
+ self.assertTrue(utils.find_kernel(self.fk_kernel))
+ self.assertFalse(utils.find_kernel("/etc/fstab"))
+ self.assertFalse(utils.find_kernel("filedoesnotexist"))
+ self._expeq(self.fk_kernel, utils.find_kernel(self.topdir))
def test_initrd_scan(self):
- self.assertTrue(self.api.utils.find_initrd(self.fk_initrd))
- self.assertFalse(self.api.utils.find_kernel("/etc/fstab"))
- self.assertFalse(self.api.utils.find_initrd("filedoesnotexist"))
- self._expeq(self.fk_initrd, self.api.utils.find_initrd(self.topdir))
+ self.assertTrue(utils.find_initrd(self.fk_initrd))
+ self.assertFalse(utils.find_kernel("/etc/fstab"))
+ self.assertFalse(utils.find_initrd("filedoesnotexist"))
+ self._expeq(self.fk_initrd, utils.find_initrd(self.topdir))
def test_kickstart_scan(self):
# we don't check to see if kickstart files look like anything
# so this will pass
- self.assertTrue(self.api.utils.find_kickstart(self.fk_initrd) is None)
- self.assertTrue(self.api.utils.find_kickstart("filedoesnotexist") is None)
- self.assertTrue(self.api.utils.find_kickstart(self.topdir) == None)
- self.assertTrue(self.api.utils.find_kickstart("http://bar"))
- self.assertTrue(self.api.utils.find_kickstart("ftp://bar"))
- self.assertTrue(self.api.utils.find_kickstart("nfs://bar"))
- self.assertFalse(self.api.utils.find_kickstart("gopher://bar"))
+ self.assertTrue(utils.find_kickstart(self.fk_initrd) is None)
+ self.assertTrue(utils.find_kickstart("filedoesnotexist") is None)
+ self.assertTrue(utils.find_kickstart(self.topdir) == None)
+ self.assertTrue(utils.find_kickstart("http://bar"))
+ self.assertTrue(utils.find_kickstart("ftp://bar"))
+ self.assertTrue(utils.find_kickstart("nfs://bar"))
+ self.assertFalse(utils.find_kickstart("gopher://bar"))
def test_matching(self):
- self.assertTrue(self.api.utils.is_mac("00:C0:B7:7E:55:50"))
- self.assertFalse(self.api.utils.is_mac("00:c0:b7:7E:55:50"))
- self.assertFalse(self.api.utils.is_mac("00.D0.B7.7E.55.50"))
- self.assertFalse(self.api.utils.is_mac(self.hostname))
- self.assertTrue(self.api.utils.is_ip("127.0.0.1"))
- self.assertTrue(self.api.utils.is_ip("192.168.1.1"))
- self.assertFalse(self.api.utils.is_ip("00:C0:B7:7E:55:50"))
- self.assertFalse(self.api.utils.is_ip(self.hostname))
+ self.assertTrue(utils.is_mac("00:C0:B7:7E:55:50"))
+ self.assertFalse(utils.is_mac("00:c0:b7:7E:55:50"))
+ self.assertFalse(utils.is_mac("00.D0.B7.7E.55.50"))
+ self.assertFalse(utils.is_mac(self.hostname))
+ self.assertTrue(utils.is_ip("127.0.0.1"))
+ self.assertTrue(utils.is_ip("192.168.1.1"))
+ self.assertFalse(utils.is_ip("00:C0:B7:7E:55:50"))
+ self.assertFalse(utils.is_ip(self.hostname))
class Additions(BootTest):