summaryrefslogtreecommitdiffstats
path: root/cobbler
diff options
context:
space:
mode:
authorMichael DeHaan <mdehaan@mdehaan.rdu.redhat.com>2007-06-13 18:03:33 -0400
committerMichael DeHaan <mdehaan@mdehaan.rdu.redhat.com>2007-06-13 18:03:33 -0400
commit5eaa46b5af9e89c881645eab69abfa787a6f7e29 (patch)
tree643767edc11cc71b7f84180c63142610daa2938f /cobbler
parent53fb6c70d0a869de623e4e4b02d78e2a2b6b9f63 (diff)
downloadthird_party-cobbler-5eaa46b5af9e89c881645eab69abfa787a6f7e29.tar.gz
third_party-cobbler-5eaa46b5af9e89c881645eab69abfa787a6f7e29.tar.xz
third_party-cobbler-5eaa46b5af9e89c881645eab69abfa787a6f7e29.zip
Keep track of depth of cobbler objects such that a pseudo-topological sort
can be done at deserialization time. The result of this is that full graph listing information can be reconstructed at time of config loading (up and down links), while only having to store the up links. This preserves the existing config file format while allowing for arbitrary inheritance and a reasonable measure of hand-editability. If changing profile relationships by hand, the cached depth info may be wrong, so some way to automatically resolve this could potentially be doable, but it's such a distinct corner case that I don't deem it neccessary at this point.
Diffstat (limited to 'cobbler')
-rw-r--r--cobbler/config.py14
-rw-r--r--cobbler/item_distro.py5
-rw-r--r--cobbler/item_profile.py12
-rw-r--r--cobbler/item_repo.py7
-rw-r--r--cobbler/item_system.py13
-rw-r--r--cobbler/serializer.py16
6 files changed, 52 insertions, 15 deletions
diff --git a/cobbler/config.py b/cobbler/config.py
index cd19d00..08bd770 100644
--- a/cobbler/config.py
+++ b/cobbler/config.py
@@ -59,10 +59,16 @@ class Config:
self._settings = settings.Settings() # not a true collection
self._repos = repos.Repos(weakref.proxy(self))
self._classes = [
+ self._settings,
+ self._distros,
+ self._profiles,
+ self._systems,
+ self._repos
+ ]
+ self._graph_classes = [
self._distros,
self._profiles,
self._systems,
- self._settings,
self._repos
]
self.file_check()
@@ -157,8 +163,10 @@ class Config:
"""
Load the object hierachy from disk, using the filenames referenced in each object.
"""
- for x in self._classes:
- if not serializer.deserialize(x):
+ if not serializer.deserialize(self._settings,topological=False):
+ return False
+ for x in self._graph_classes:
+ if not serializer.deserialize(x,topological=True):
return False
return True
diff --git a/cobbler/item_distro.py b/cobbler/item_distro.py
index b6a5bea..8fa7682 100644
--- a/cobbler/item_distro.py
+++ b/cobbler/item_distro.py
@@ -38,6 +38,7 @@ class Distro(item.Item):
self.arch = ('x86', '<<inherit>>')[is_subobject]
self.breed = ('redhat', '<<inherit>>')[is_subobject]
self.source_repos = ([], '<<inherit>>')[is_subobject]
+ self.depth = 0
def make_clone(self):
ds = self.to_datastruct()
@@ -69,6 +70,7 @@ class Distro(item.Item):
self.arch = self.load_item(seed_data,'arch','x86')
self.breed = self.load_item(seed_data,'breed','redhat')
self.source_repos = self.load_item(seed_data,'source_repos',[])
+ self.depth = self.load_item(seed_data,'depth',0)
# backwards compatibility -- convert string entries to dicts for storage
if type(self.kernel_options) != dict:
@@ -161,7 +163,8 @@ class Distro(item.Item):
'arch' : self.arch,
'breed' : self.breed,
'source_repos' : self.source_repos,
- 'parent' : self.parent
+ 'parent' : self.parent,
+ 'depth' : self.depth
}
def printable(self):
diff --git a/cobbler/item_profile.py b/cobbler/item_profile.py
index 79a7dcb..606c6f9 100644
--- a/cobbler/item_profile.py
+++ b/cobbler/item_profile.py
@@ -40,6 +40,7 @@ class Profile(item.Item):
self.virt_file_size = (5, '<<inherit>>')[is_subobject]
self.virt_ram = (512, '<<inherit>>')[is_subobject]
self.repos = ("", '<<inherit>>')[is_subobject]
+ self.depth = 1
def from_datastruct(self,seed_data):
"""
@@ -53,7 +54,8 @@ class Profile(item.Item):
self.kernel_options = self.load_item(seed_data,'kernel_options')
self.ks_meta = self.load_item(seed_data,'ks_meta')
self.repos = self.load_item(seed_data,'repos', [])
-
+ self.depth = self.load_item(seed_data,'depth', 1)
+
# backwards compatibility
if type(self.repos) != list:
self.set_repos(self.repos)
@@ -89,14 +91,17 @@ class Profile(item.Item):
if found is None:
raise CX(_("profile %s not found, inheritance not possible") % parent_name)
self.parent = parent_name
+ self.depth = found.depth + 1
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.config.distros().find(distro_name):
+ d = self.config.distros().find(distro_name)
+ if d is not None:
self.distro = distro_name
+ self.depth = d.depth +1 # reset depth if previously a subprofile and now top-level
return True
raise CX(_("distribution not found"))
@@ -217,7 +222,8 @@ class Profile(item.Item):
'virt_ram' : self.virt_ram,
'ks_meta' : self.ks_meta,
'repos' : self.repos,
- 'parent' : self.parent
+ 'parent' : self.parent,
+ 'depth' : self.depth
}
def printable(self):
diff --git a/cobbler/item_repo.py b/cobbler/item_repo.py
index c9846b1..19b2e3f 100644
--- a/cobbler/item_repo.py
+++ b/cobbler/item_repo.py
@@ -35,7 +35,8 @@ class Repo(item.Item):
self.local_filename = ("", '<<inherit>>')[is_subobject]
self.rpm_list = ("", '<<inherit>>')[is_subobject]
self.createrepo_flags = ("-c cache", '<<inherit>>')[is_subobject]
-
+ self.depth = 2 # arbitrary, as not really apart of the graph
+
def from_datastruct(self,seed_data):
self.parent = self.load_item(seed_data, 'parent')
self.name = self.load_item(seed_data, 'name')
@@ -44,6 +45,7 @@ class Repo(item.Item):
self.local_filename = self.load_item(seed_data, 'local_filename')
self.rpm_list = self.load_item(seed_data, 'rpm_list')
self.createrepo_flags = self.load_item(seed_data, 'createrepo_flags', '-c cache')
+ self.depth = self.load_item(seed_data, 'depth', 2)
return self
def set_name(self,name):
@@ -130,7 +132,8 @@ class Repo(item.Item):
'local_filename' : self.local_filename,
'rpm_list' : self.rpm_list,
'createrepo_flags' : self.createrepo_flags,
- 'parent' : self.parent
+ 'parent' : self.parent,
+ 'depth' : self.depth
}
def printable(self):
diff --git a/cobbler/item_system.py b/cobbler/item_system.py
index c2e8243..0152411 100644
--- a/cobbler/item_system.py
+++ b/cobbler/item_system.py
@@ -29,8 +29,6 @@ class System(item.Item):
return cloned
def clear(self,is_subobject=False):
- # names of cobbler repo definitions
-
self.name = None
self.profile = (None, '<<inherit>>')[is_subobject]
self.kernel_options = ({}, '<<inherit>>')[is_subobject]
@@ -39,6 +37,7 @@ class System(item.Item):
self.mac_address = ("", '<<inherit>>')[is_subobject]
self.netboot_enabled = (1, '<<inherit>>')[is_subobject]
self.hostname = ("", '<<inheirt>>')[is_subobject]
+ self.depth = 2
def from_datastruct(self,seed_data):
@@ -47,7 +46,8 @@ class System(item.Item):
self.profile = self.load_item(seed_data, 'profile')
self.kernel_options = self.load_item(seed_data, 'kernel_options')
self.ks_meta = self.load_item(seed_data, 'ks_meta')
-
+ self.depth = self.load_item(seed_data, 'depth')
+
# backwards compat, load --ip-address from two possible sources.
# the old --pxe-address was a bit of a misnomer, new value is --ip-address
@@ -175,8 +175,10 @@ class System(item.Item):
Set the system to use a certain named profile. The profile
must have already been loaded into the Profiles collection.
"""
- if self.config.profiles().find(profile_name):
+ p = self.config.profiles().find(profile_name)
+ if p is not None:
self.profile = profile_name
+ self.depth = p.depth + 1 # subprofiles have varying depths.
return True
raise CX(_("invalid profile name"))
@@ -223,7 +225,8 @@ class System(item.Item):
'netboot_enabled' : self.netboot_enabled,
'hostname' : self.hostname,
'mac_address' : self.mac_address,
- 'parent' : self.parent
+ 'parent' : self.parent,
+ 'depth' : self.depth
}
def printable(self):
diff --git a/cobbler/serializer.py b/cobbler/serializer.py
index 38a182d..39cb982 100644
--- a/cobbler/serializer.py
+++ b/cobbler/serializer.py
@@ -49,7 +49,7 @@ def serialize(obj):
fd.close()
return True
-def deserialize(obj):
+def deserialize(obj,topological=False):
"""
Populate an existing object with the contents of datastruct.
Object must "implement" Serializable. Returns True assuming
@@ -69,7 +69,21 @@ def deserialize(obj):
data = fd.read()
datastruct = yaml.load(data).next() # first record
fd.close()
+
+ if topological:
+ # in order to build the graph links from the flat list, sort by the
+ # depth of items in the graph. If an object doesn't have a depth, sort it as
+ # if the depth were 0. It will be assigned a proper depth at serialization
+ # time. This is a bit cleaner implementation wise than a topological sort,
+ # though that would make a shiny upgrade.
+ datastruct.sort(cmp=__depth_cmp)
obj.from_datastruct(datastruct)
return True
+def __depth_cmp(item1, item2):
+ if not item1.has_key("depth"):
+ return 1
+ if not item2.has_key("depth"):
+ return -1
+ return cmp(item1["depth"],item2["depth"])