summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cobbler.pod24
-rw-r--r--cobbler.spec7
-rw-r--r--cobbler/action_sync.py135
-rwxr-xr-xcobbler/cobbler.py9
-rw-r--r--cobbler/cobbler_msg.py5
-rw-r--r--cobbler/collection.py8
-rw-r--r--cobbler/collection_distros.py3
-rw-r--r--cobbler/collection_profiles.py3
-rw-r--r--cobbler/collection_systems.py3
-rw-r--r--cobbler/item.py14
-rw-r--r--cobbler/item_distro.py6
-rw-r--r--cobbler/item_profile.py14
-rw-r--r--cobbler/item_system.py6
-rw-r--r--tests/tests.py4
14 files changed, 194 insertions, 47 deletions
diff --git a/cobbler.pod b/cobbler.pod
index 949cf20..4d6b108 100644
--- a/cobbler.pod
+++ b/cobbler.pod
@@ -29,19 +29,23 @@ Any problems should be corrected, with the potential exception of DHCP related w
In the case of the DHCP server being on another machine, the "next-server" field in dhcpd.conf on that machine should be set to the IP of the boot server and "filename" field set to "pxelinux.0". In this case, DHCP errors coming from "cobbler check" should be ignored.
-B<cobbler distro add --name=<string> --kernel=<path> --initrd=<path> [--kopts=<string>]>
+B<cobbler distro add --name=<string> --kernel=<path> --initrd=<path> [--kopts=<string>] [--ksmeta=<string>]>
-Cobbler works in terms of distros, profiles, and systems. All three must define to get a working PXE configuration. "cobbler distro add" defines a distribution. Minimally, this is a named set (for instance, 'fc5-i386') of an initrd and a kernel. Kernel options from /var/lib/cobbler/settings can be overriden here by specifying a comma seperated list of key=value pairs.
+Cobbler works in terms of distros, profiles, and systems. All three must define to get a working PXE configuration. "cobbler distro add" defines a distribution. Minimally, this is a named set (for instance, 'fc5-i386') of an initrd and a kernel. Kernel options from /var/lib/cobbler/settings can be overriden here by specifying a space seperated list of options.
The kernel/initrd pairs used for "distro add" probably should be those that are used to boot Anaconda, but there are plenty of other uses. If Xen provisioning is desired, a Xen dom0 kernel and the matching Anaconda initrd is required.
-B<cobbler profile add --name=<string> --distro=<string> [--kickstart=<url>] [--kopts=<string>] [--xen-name=<string>] [--xen-file-size=<gigabytes>] [--xen-ram=<megabytes>]
+kopts is a string of space delimited key=value pairs such as --kopts="quiet rhgb=true". kopts are optional and reasonable defaults are provided in /var/lib/cobbler/settings
+
+ksmeta is an advanced feature to enable templating of kickstart files. See the 'KICKSTART TEMPLATING' section for more details. ksmeta requires a space delimited list of key=value pairs.
+
+B<cobbler profile add --name=<string> --distro=<string> [--kickstart=<url>] [--kopts=<string>] [--ksmeta=<string>] [--xen-name=<string>] [--xen-file-size=<gigabytes>] [--xen-ram=<megabytes>]
"cobbler profile add" defines a named provisioning profile, which must reference an already created distribution. Optional parameters can specify kickstart information or Xen parameters. Kickstarts are almost always desired, and can be nfs://, http://, or ftp:// -- or an absolute path. For file paths, cobbler will copy the kickstarts and serve them up as http -- so having servable kickstart paths as parameters to "cobbler profile add" is not required. In fact, it's probably a good idea to leave the kickstarts as absolute paths to avoid having yet another resource to manage.
For Xen parameters, koan may interpret some parameters as hints, not absolutes, if it has to resolve conflicts. All of these Xen parameters are optional, though as many as possible should be specified to avoid the risk koan making it's own decisions when run on the target dom0. See the documentation for koan for more details.
-B<cobbler system add --name=<ip|mac|hostname> --profile=<string> [--kopts=<string>]>
+B<cobbler system add --name=<ip|mac|hostname> --profile=<string> [--kopts=<string>] [--ksmeta=<string>]
Correlates a system name (an IP, hostname, or MAC address of a bare-metal system or a Xen dom0) with an already created profile. For koan (the tool used for Xen and auto-kickstart deployment), system configurations are *not* used -- system information is only used for PXE.
@@ -87,7 +91,17 @@ B<cobbler sync>
=head1 XEN EXAMPLE
-TBA
+For Xen, just add the optional Xen parameters above to customize a Xen profile. The Xen settings will assume
+reasonable defaults if they are not specified, but it is better to be explicit.
+
+=head1 KICKSTART TEMPLATING
+
+The --ksmeta option is an advanced feature which allows metadata to be assigned to a distro, profile, or system for the purposes of building kickstarts using templates. The arguments to --ksmeta are comma delimited key=value pairs such as "--ksmeta=a=1,b=2,c=3". When --ksmeta is used on a system, profile, or distribution, kickstarts can then be evaluated using the Cheetah templating language. This feature is entirely optional.
+
+Kickstarts do not have to use any templating, but if they do include Cheetah templating language, the ksmeta parameters to distros, profiles, and systems is the method used to pass variables into Cheetah. For example, using --ksmeta="a=1 b=2" sets the variables (a) and (b) as template variables, which can be used to add flexibility in the way kickstarts are built (such as conditional evaluation, loops, and variable substitution). Metadata can be added to a distro, a profile, or a system. System metadata is only relevant to PXE templating, though Distro and Profile metadata is relevant to all types. System metadata overrides Profile metadata when there are name collisions, and a profile will override Distro metadata. This is the same way prioritization works for kernel options (--kopts). Thus if a distribution sets "--ksmeta=alpha=bravo" and a profile sets "--ksmeta=alpha=delta", the value used for "alpha" will be "delta".
+
+For documentation on Cheetah's templating language for use inside kickstart, see http://cheetahtemplate.org.
+Note that if kickstarts are only passed through the templating engine if they are specified as file paths -- nfs:// and http:// kickstarts, by design, will be evaluated as is. The reason for this is that templates are only evaluated when 'cobbler sync' is run -- and we want nfs:// and http:// to be more dynamic. It is possible, for instance, to generate dynamic kickstarts through magic URLs (cgi, mod_python, etc). This type of dynamic generation would be incompatible with 'cobbler sync', which is based on static generation. We don't touch NFS kickstarts for similar reasons -- someone may manipulate the kickstarts on a remote system and not be able to run 'cobbler sync' on the boot server.
=head1 CONFIGURATION FILES
diff --git a/cobbler.spec b/cobbler.spec
index 10c3a9c..d5f8e46 100644
--- a/cobbler.spec
+++ b/cobbler.spec
@@ -1,13 +1,14 @@
Summary: Boot server configurator
Name: cobbler
-Version: 0.1.0
-Release: 2%{?dist}
+Version: 0.1.1
+Release: 3%{?dist}
Source0: %{name}-%{version}.tar.gz
License: GPL
Group: Applications/System
Requires: python >= 2.3
Requires: httpd
Requires: tftp-server
+Requires: python-cheetah
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot
BuildArch: noarch
Url: http://et.redhat.com/page/Cobbler_%26_Koan_Provisioning_Tools
@@ -39,6 +40,8 @@ rm -rf $RPM_BUILD_ROOT
%defattr(-,root,root)
%changelog
+* Wed Jul 12 2006 - 0.1.1-3
+- Added templating support using Cheetah
* Thu Jul 9 2006 - 0.1.0-2
- Fedora-Extras rpm spec tweaks
* Tue Jun 28 2006 - 0.1.0-1
diff --git a/cobbler/action_sync.py b/cobbler/action_sync.py
index 399a849..92f8491 100644
--- a/cobbler/action_sync.py
+++ b/cobbler/action_sync.py
@@ -16,16 +16,16 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
import os
import shutil
import yaml
+from Cheetah.Template import Template
import utils
import cobbler_msg
import cexceptions
-
-"""
-Handles conversion of internal state to the tftpboot tree layout
-"""
-
+
class BootSync:
+ """
+ Handles conversion of internal state to the tftpboot tree layout
+ """
def __init__(self,config):
"""
@@ -92,7 +92,7 @@ class BootSync:
"""
Delete any previously built pxelinux.cfg tree and xen tree info.
"""
- for x in ["pxelinux.cfg","images","systems","distros","profiles","kickstarts"]:
+ for x in ["pxelinux.cfg","images","systems","distros","profiles","kickstarts","kickstarts_sys"]:
path = os.path.join(self.settings.tftpboot,x)
self.rmtree(path)
self.mkdir(path)
@@ -129,23 +129,98 @@ class BootSync:
(http or ftp), can stay as is. kickstarts referenced by absolute
path (i.e. are files path) will be mirrored over http.
"""
- # ensure all referenced kickstarts exist
- # these are served by either NFS, Apache, or some ftpd, so we don't need to copy them
- # it's up to the user to make sure they are nicely served by their URLs
+
+ self.validate_kickstarts_per_profile()
+ self.validate_kickstarts_per_system()
+ return True
+
+ def validate_kickstarts_per_profile(self):
+ """
+ Koan provisioning (Xen + auto-ks) needs kickstarts
+ per profile. Validate them as needed. Local kickstarts
+ get template substitution. Since http:// kickstarts might
+ get generated via magic URLs, those are *not* substituted.
+ NFS kickstarts are also not substituted when referenced
+ by NFS URL's as we don't copy those files over to the cobbler
+ directories. They are supposed to be live such that an
+ admin can update those without needing to run 'sync' again.
+ """
for g in self.profiles:
+ distro = self.distros.find(g.distro)
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
- copy_path = os.path.join(self.settings.tftpboot, "kickstarts", g.name)
+ copy_path = os.path.join(
+ self.settings.tftpboot,
+ "kickstarts", # profile kickstarts go here
+ g.name
+ )
self.mkdir(copy_path)
dest = os.path.join(copy_path, "ks.cfg")
- try:
- self.copyfile(g.kickstart, dest)
- except:
- raise cexceptions.CobblerException("err_kickstart2")
-
+ # FIXME -- uncomment try for now
+ #try:
+ meta = self.blend_options(False, (
+ distro.ks_meta,
+ g.ks_meta,
+ ))
+ self.apply_template(kickstart_path, meta, dest)
+ #except:
+ #msg = "err_kickstart2" % (g.kickstart,dest)
+ #raise cexceptions.CobblerException(msg)
+
+ def validate_kickstarts_per_system(self):
+ """
+ PXE provisioning needs kickstarts evaluated per system.
+ Profiles would normally be sufficient, but not in cases
+ such as static IP, where we want to be able to do templating
+ on a system basis.
+
+ FIXME: be sure PXE configs reference the new kickstarts_sys path
+ instead.
+ """
+
+ for s in self.systems:
+ profile = self.profiles.find(s.profile)
+ distro = self.distros.find(profile.distro)
+ kickstart_path = utils.find_kickstart(profile.kickstart)
+ if kickstart_path and os.path.exists(kickstart_path):
+ copy_path = os.path.join(self.settings.tftpboot,
+ "kickstarts_sys", # system kickstarts go here
+ s.name
+ )
+ self.mkdir(copy_path)
+ dest = os.path.join(copy_path, "ks.cfg")
+ try:
+ meta = self.blend_options(False,(
+ distro.ks_meta,
+ profile.ks_meta,
+ s.ks_meta
+ ))
+ self.apply_template(kickstart_path, meta, dest)
+ except:
+ msg = "err_kickstart2" % (g.kickstart, dest)
+ raise cexpcetions.CobblerException(msg)
+
+ def apply_template(self, kickstart_input, metadata, out_path):
+ """
+ Take filesystem file kickstart_input, apply metadata using
+ Cheetah and save as out_path.
+ """
+ fd = open(kickstart_input)
+ data = fd.read()
+ fd.close()
+ print metadata # FIXME: temporary
+ t = Template(
+ "#errorCatcher Echo\n%s" % data,
+ searchList=[metadata],
+ )
+ computed = str(t)
+ fd = open(out_path, "w+")
+ fd.write(computed)
+ fd.close()
+
def build_trees(self):
"""
Now that kernels and initrds are copied and kickstarts are all valid,
@@ -161,7 +236,7 @@ class BootSync:
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((
+ d.kernel_options = self.blend_options(True,(
self.settings.kernel_options,
d.kernel_options
))
@@ -174,7 +249,7 @@ class BootSync:
filename = os.path.join(self.settings.tftpboot,"profiles",p.name)
distro = self.distros.find(p.distro)
if distro is not None:
- p.kernel_options = self.blend_kernel_options((
+ p.kernel_options = self.blend_options(True,(
self.settings.kernel_options,
distro.kernel_options,
p.kernel_options
@@ -230,7 +305,7 @@ class BootSync:
self.tee(fd,"timeout 1\n")
self.tee(fd,"label linux\n")
self.tee(fd," kernel %s\n" % kernel_path)
- kopts = self.blend_kernel_options((
+ kopts = self.blend_options(True,(
self.settings.kernel_options,
profile.kernel_options,
distro.kernel_options,
@@ -238,10 +313,10 @@ class BootSync:
))
nextline = " append %s initrd=%s" % (kopts,initrd_path)
if kickstart_path is not None and kickstart_path != "":
- # if kickstart path is local, we've already copied it into
+ # if kickstart path is on disk, 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_sys/%s/ks.cfg" % (self.settings.server, system.name)
nextline = nextline + " ks=%s" % kickstart_path
self.tee(fd, nextline)
self.close_file(fd)
@@ -367,15 +442,19 @@ class BootSync:
else:
print message
- def blend_kernel_options(self, list_of_opts):
+ def blend_options(self, is_for_kernel, list_of_opts):
"""
- Given a list of kernel options, take the values used by the
+ Given a list of options, take the values used by the
first argument in the list unless overridden by those in the
second (or further on), according to --key=value formats.
This is used such that we can have default kernel options
in /etc and then distro, profile, and system options with various
- levels of configurability.
+ levels of configurability overriding them. This also works
+ for template metadata (--ksopts)
+
+ The output when is_for_kernel is true is a space delimited list.
+ When is_for_kernel is false, it's just a hash (which Cheetah requires).
"""
internal = {}
results = []
@@ -390,17 +469,21 @@ class BootSync:
internal[key_value[0]] = ""
else:
internal[key_value[0]] = key_value[1]
- # now go back through the final list and render the single
+ if not is_for_kernel:
+ return internal
+ # the kernel requires a flat string for options, and we want
+ # to remove certain invalid options.
+ # go back through the final list and render the single
# items AND key/value items
for key in internal.keys():
data = internal[key]
- if key == "ks" or key == "initrd" or key == "append":
+ if (key == "ks" or key == "initrd" or key == "append"):
# the user REALLY doesn't want to do this...
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
+ # end result is a new fragment of an options string
return " ".join(results)
diff --git a/cobbler/cobbler.py b/cobbler/cobbler.py
index 22cb8d3..9949882 100755
--- a/cobbler/cobbler.py
+++ b/cobbler/cobbler.py
@@ -128,7 +128,8 @@ class BootCLI:
'--name' : lambda(a) : sys.set_name(a),
'--system' : lambda(a) : sys.set_name(a),
'--profile' : lambda(a) : sys.set_profile(a),
- '--kopts' : lambda(a) : sys.set_kernel_options(a)
+ '--kopts' : lambda(a) : sys.set_kernel_options(a),
+ '--ksmeta' : lambda(a) : sys.set_ksmeta(a)
}
on_ok = lambda: self.api.systems().add(sys)
return self.apply_args(args,commands,on_ok)
@@ -147,7 +148,8 @@ class BootCLI:
'--kopts' : lambda(a) : profile.set_kernel_options(a),
'--xen-name' : lambda(a) : profile.set_xen_name(a),
'--xen-file-size' : lambda(a) : profile.set_xen_file_size(a),
- '--xen-ram' : lambda(a) : profile.set_xen_ram(a)
+ '--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),
@@ -167,7 +169,8 @@ class BootCLI:
'--distro' : 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_kernel_options(a)
+ '--kopts' : lambda(a) : distro.set_kernel_options(a),
+ '--ksmeta' : lambda(a) : distro.set_ksmeta(a)
}
on_ok = lambda: self.api.distros().add(distro)
return self.apply_args(args,commands,on_ok)
diff --git a/cobbler/cobbler_msg.py b/cobbler/cobbler_msg.py
index f686f79..550cca7 100644
--- a/cobbler/cobbler_msg.py
+++ b/cobbler/cobbler_msg.py
@@ -15,6 +15,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
"""
_msg_table = {
+ "system" : "System",
+ "profile" : "Profile",
+ "distribution" : "Distribution",
"bad_server" : "The 'server' field in /var/lib/cobbler/settings must be set to something other than localhost, or kickstarting features will not work",
"parse_error" : "cobbler could not read %s, replacing...",
"no_create" : "cobbler could not create: %s",
@@ -39,7 +42,7 @@ _msg_table = {
"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",
"bad_param" : "at least one parameter is missing for this function",
- "empty_list" : "There are no configured items.",
+ "empty_list" : "There are no configured %s records.",
"err_resolv" : "The system name (%s) did not resolve",
"err_kickstart" : "The kickstart (%s) for item (%s) is not valid",
"err_kickstart2" : "Error while mirroring kickstart file (%s) to (%s)",
diff --git a/cobbler/collection.py b/cobbler/collection.py
index ad1ed27..2525d66 100644
--- a/cobbler/collection.py
+++ b/cobbler/collection.py
@@ -96,7 +96,7 @@ class Collection(serializable.Serializable):
if len(values) > 0:
return "\n\n".join(results)
else:
- return cobbler_msg.lookup("empty_list")
+ return cobbler_msg.lookup("empty_list" % cobbler_msg.lookup(self.collection_type()))
def __iter__(self):
"""
@@ -111,4 +111,10 @@ class Collection(serializable.Serializable):
"""
return len(self.listing.values())
+ def collection_type(self):
+ """
+ Returns the string key for the name of the collection (for use in messages for humans)
+ """
+ return exceptions.NotImplementedError
+
diff --git a/cobbler/collection_distros.py b/cobbler/collection_distros.py
index 9625b58..a687a6b 100644
--- a/cobbler/collection_distros.py
+++ b/cobbler/collection_distros.py
@@ -20,6 +20,9 @@ import cexceptions
class Distros(collection.Collection):
+ def collection_type(self):
+ return "distribution"
+
def factory_produce(self,config,seed_data):
"""
Return a Distro forged from seed_data
diff --git a/cobbler/collection_profiles.py b/cobbler/collection_profiles.py
index 152e1f8..93fb1c7 100644
--- a/cobbler/collection_profiles.py
+++ b/cobbler/collection_profiles.py
@@ -24,6 +24,9 @@ import cexceptions
class Profiles(collection.Collection):
+ def collection_type(self):
+ return "profile"
+
def factory_produce(self,config,seed_data):
return profile.Profile(config).from_datastruct(seed_data)
diff --git a/cobbler/collection_systems.py b/cobbler/collection_systems.py
index 39b3119..368c3f6 100644
--- a/cobbler/collection_systems.py
+++ b/cobbler/collection_systems.py
@@ -22,6 +22,9 @@ import cexceptions
class Systems(collection.Collection):
+ def collection_type(self):
+ return "system"
+
def factory_produce(self,config,seed_data):
"""
Return a system forged from seed_data
diff --git a/cobbler/item.py b/cobbler/item.py
index 9e8a5ba..6c55225 100644
--- a/cobbler/item.py
+++ b/cobbler/item.py
@@ -34,6 +34,20 @@ class Item(serializable.Serializable):
self.kernel_options = options_string
return True
+ def set_ksmeta(self,options_string):
+ """
+ A comma delimited list of key value pairs, like 'a=b,c=d,e=f'.
+ The meta tags are used as input to the Cheetah templating system
+ to preprocess kickstart files
+ """
+ self.ks_meta = options_string
+ tokens = self.ks_meta.split(",")
+ for t in tokens:
+ tokens2 = t.split("=")
+ if len(tokens2) != 2:
+ return False
+ return True
+
def to_datastruct(self):
"""
Returns an easily-marshalable representation of the collection.
diff --git a/cobbler/item_distro.py b/cobbler/item_distro.py
index 7491a98..e15c2b1 100644
--- a/cobbler/item_distro.py
+++ b/cobbler/item_distro.py
@@ -37,6 +37,7 @@ class Distro(item.Item):
self.kernel = None
self.initrd = None
self.kernel_options = ""
+ self.ks_meta = ""
def from_datastruct(self,seed_data):
"""
@@ -46,6 +47,7 @@ class Distro(item.Item):
self.kernel = seed_data['kernel']
self.initrd = seed_data['initrd']
self.kernel_options = seed_data['kernel_options']
+ self.ks_meta = seed_data['ks_meta']
return self
def set_kernel(self,kernel):
@@ -88,7 +90,8 @@ class Distro(item.Item):
'name': self.name,
'kernel': self.kernel,
'initrd' : self.initrd,
- 'kernel_options' : self.kernel_options
+ 'kernel_options' : self.kernel_options,
+ 'ks_meta' : self.ks_meta
}
def printable(self, id):
@@ -109,5 +112,6 @@ 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 + "ks metadata : %s\n" % self.ks_meta
return buf
diff --git a/cobbler/item_profile.py b/cobbler/item_profile.py
index 46c7929..e3cecfe 100644
--- a/cobbler/item_profile.py
+++ b/cobbler/item_profile.py
@@ -33,11 +33,12 @@ class Profile(item.Item):
self.distro = None # a name, not a reference
self.kickstart = None
self.kernel_options = ''
+ self.ks_meta = ''
self.xen_name = 'xenguest'
- self.xen_file_size = 5 # GB
- self.xen_ram = 2048 # MB
- self.xen_mac = ''
- self.xen_paravirt = True
+ self.xen_file_size = 5 # GB. 5 = Decent _minimum_ default for FC5.
+ self.xen_ram = 512 # MB. Install with 256 not likely to pass
+ self.xen_mac = '' # allow random generation as default
+ self.xen_paravirt = True # hvm support is *NOT* in Koan (now)
def from_datastruct(self,seed_data):
"""
@@ -47,6 +48,7 @@ class Profile(item.Item):
self.distro = seed_data['distro']
self.kickstart = seed_data['kickstart']
self.kernel_options = seed_data['kernel_options']
+ self.ks_meta = seed_data['ks_meta']
self.xen_name = seed_data['xen_name']
if not self.xen_name or self.xen_name == '':
self.xen_name = self.name
@@ -176,7 +178,8 @@ class Profile(item.Item):
'xen_file_size' : self.xen_file_size,
'xen_ram' : self.xen_ram,
'xen_mac' : self.xen_mac,
- 'xen_paravirt' : self.xen_paravirt
+ 'xen_paravirt' : self.xen_paravirt,
+ 'ks_meta' : self.ks_meta
}
def printable(self,id):
@@ -187,6 +190,7 @@ class Profile(item.Item):
buf = buf + "distro : %s\n" % self.distro
buf = buf + "kickstart : %s\n" % self.kickstart
buf = buf + "kernel options : %s\n" % self.kernel_options
+ buf = buf + "ks metadata : %s\n" % self.ks_meta
buf = buf + "xen name : %s\n" % self.xen_name
buf = buf + "xen file size : %s\n" % self.xen_file_size
buf = buf + "xen ram : %s\n" % self.xen_ram
diff --git a/cobbler/item_system.py b/cobbler/item_system.py
index ab4b520..68ba156 100644
--- a/cobbler/item_system.py
+++ b/cobbler/item_system.py
@@ -26,11 +26,13 @@ class System(item.Item):
self.name = None
self.profile = None # a name, not a reference
self.kernel_options = ""
+ self.ks_meta = ""
def from_datastruct(self,seed_data):
self.name = seed_data['name']
self.profile = seed_data['profile']
self.kernel_options = seed_data['kernel_options']
+ self.ks_meta = seed_data['ks_meta']
return self
def set_name(self,name):
@@ -69,12 +71,14 @@ class System(item.Item):
return {
'name' : self.name,
'profile' : self.profile,
- 'kernel_options' : self.kernel_options
+ 'kernel_options' : self.kernel_options,
+ 'ks_meta' : self.ks_meta
}
def printable(self,id):
buf = "system %-4s : %s\n" % (id, self.name)
buf = buf + "profile : %s\n" % self.profile
buf = buf + "kernel options : %s" % self.kernel_options
+ buf = buf + "ks metadata : %s" % self.ks_meta
return buf
diff --git a/tests/tests.py b/tests/tests.py
index 85ed0b9..11bf63f 100644
--- a/tests/tests.py
+++ b/tests/tests.py
@@ -286,8 +286,8 @@ class TestCLIBasic(BootTest):
# nothing major is broke at top level. Full CLI command testing
# is not included (yet) since the API tests hit that fairly throughly
# and it would easily double the length of the tests.
- app = "cobbler/cobbler.py"
- self.assertTrue(subprocess.call([app,"list"]) == 0)
+ app = "/usr/bin/python"
+ self.assertTrue(subprocess.call([app,"cobbler/cobbler.py","list"]) == 0)
if __name__ == "__main__":
if not os.path.exists("setup.py"):