From 817962be5ff44c685eae4d7fe9e9247c2ca49fe0 Mon Sep 17 00:00:00 2001 From: Michael DeHaan Date: Tue, 20 Feb 2007 13:16:58 -0500 Subject: Adding disable_netboot option for cobbler, which can be programatically exercised by API users to prevent install-loop scenarios by taking action as a result of some event in post. Also making syncless code modifications work with IA64 tftp locations. --- cobbler/action_litesync.py | 17 ++++++++++++--- cobbler/action_sync.py | 44 +++++++++++++++++---------------------- cobbler/collection_systems.py | 2 +- cobbler/item_system.py | 48 ++++++++++++++++++++++++++++++++++--------- 4 files changed, 72 insertions(+), 39 deletions(-) (limited to 'cobbler') diff --git a/cobbler/action_litesync.py b/cobbler/action_litesync.py index 4f9195c..fddea9d 100644 --- a/cobbler/action_litesync.py +++ b/cobbler/action_litesync.py @@ -109,7 +109,18 @@ class BootLiteSync: # delete contents of kickstarts_sys/$name in webdir filename = self.sync.get_pxe_filename(name) self.sync.rmtree(os.path.join(self.settings.webdir, "kickstarts_sys", filename)) - # delete pxelinux.cfg/$foo where $foo is either the *encoded* IP - # or the MAC or default - self.sync.rmfile(os.path.join(self.settings.tftpboot, "pxelinux.cfg", filename)) + + # delete PXE Linux configuration file (which might be in one of two places) + itanic = False + system_record = self.systems.find(name) + profile = self.profiles.find(system_record.profile) + # allow cobbler deletes to still work in the cobbler config is discombobulated + if profile is not None: + distro = self.distros.find(profile.distro) + if distro is not None and distro in [ "ia64", "IA64"]: + itanic = True + if not itanic: + self.sync.rmfile(os.path.join(self.settings.tftpboot, "pxelinux.cfg", filename)) + else: + self.sync.rmfile(os.path.join(self.settings.tftpboot, filename)) diff --git a/cobbler/action_sync.py b/cobbler/action_sync.py index e243afa..be6d02c 100644 --- a/cobbler/action_sync.py +++ b/cobbler/action_sync.py @@ -264,7 +264,7 @@ class BootSync: a solution. *Otherwise* duplication is minimal. """ - # clean out all of /tftpboot + # clean out parts of webdir and all of /tftpboot/images and /tftpboot/pxelinux.cfg for x in os.listdir(self.settings.webdir): path = os.path.join(self.settings.webdir,x) if os.path.isfile(path): @@ -279,9 +279,6 @@ class BootSync: self.rmtree_contents(path) self.rmtree_contents(os.path.join(self.settings.tftpboot, "pxelinux.cfg")) self.rmtree_contents(os.path.join(self.settings.tftpboot, "images")) - # no real reason to delete these - # self.rmfile(os.path.join(self.settings.tftpboot, "pxelinux.0")) - # self.rmfile(os.path.join(self.settings.tftpboot, "elilo-3.6-ia64.efi")) def copy_distros(self): """ @@ -492,23 +489,8 @@ class BootSync: self.write_distro_file(d) for p in self.profiles: - # TODO: add check to ensure all profiles have distros (=error) - # TODO: add check to ensure all profiles have systems (=warning) self.write_profile_file(p) - # Copy default PXE file if it exists; if there's none, ignore - # FIXME: Log something inobtrusive ifthe default file is missing - # src = "/etc/cobbler/default.pxe" - # if os.path.exists(src): - # nocopy = False - # for system in self.systems: - # if system.name == "default": - # nocopy = True - # break - # if not nocopy: - # dst = os.path.join(self.settings.tftpboot, "pxelinux.cfg", "default") - # self.copyfile(src, dst) - for system in self.systems: self.write_all_system_files(system) @@ -540,10 +522,16 @@ class BootSync: f3 = os.path.join(self.settings.webdir, "systems", f1) - if distro.arch in [ "x86", "x86_64", "standard"]: - self.write_pxe_file(f2,system,profile,distro,False) - if distro.arch == "ia64": - self.write_pxe_file(f2,system,profile,distro,True) + + if system.netboot_enabled: + if distro.arch in [ "x86", "x86_64", "standard"]: + self.write_pxe_file(f2,system,profile,distro,False) + if distro.arch == "ia64": + self.write_pxe_file(f2,system,profile,distro,True) + else: + # ensure the file doesn't exist + self.rmfile(f2) + self.write_system_file(f3,system) @@ -600,8 +588,9 @@ class BootSync: # bits and pieces relevant to the profile. distro = self.distros.find(profile.distro) contents = self.write_pxe_file(None,None,profile,distro,False,include_header=False) - defaults.write(contents + "\n") - defaults.write("\n") + if contents is not None: + defaults.write(contents + "\n") + defaults.write("\n") defaults.close() @@ -614,6 +603,11 @@ class BootSync: NOTE: relevant to tftp only """ + # system might have netboot_enabled set to False (see item_system.py), if so, + # don't do anything else and flag the error condition. + if system is not None and not system.netboot_enabled: + return None + buffer = "" kernel_path = os.path.join("/images",distro.name,os.path.basename(distro.kernel)) diff --git a/cobbler/collection_systems.py b/cobbler/collection_systems.py index 8d90eb5..7b6191b 100644 --- a/cobbler/collection_systems.py +++ b/cobbler/collection_systems.py @@ -48,10 +48,10 @@ class Systems(collection.Collection): Remove element named 'name' from the collection """ if self.find(name): - del self.listing[name] if with_delete: lite_sync = action_litesync.BootLiteSync(self.config) lite_sync.remove_single_system(name) + del self.listing[name] return True raise cexceptions.CobblerException("delete_nothing") diff --git a/cobbler/item_system.py b/cobbler/item_system.py index 7409f11..5f23be6 100644 --- a/cobbler/item_system.py +++ b/cobbler/item_system.py @@ -28,13 +28,15 @@ class System(item.Item): self.kernel_options = {} self.ks_meta = {} self.pxe_address = "" + self.netboot_enabled = 1 def from_datastruct(self,seed_data): - self.name = self.load_item(seed_data,'name') - 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.pxe_address = self.load_item(seed_data,'pxe_address') + self.name = self.load_item(seed_data, 'name') + 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.pxe_address = self.load_item(seed_data, 'pxe_address') + self.netboot_enabled = self.load_item(seed_data, 'netboot_enabled', 1) # backwards compatibility -- convert string entries to dicts for storage if type(self.kernel_options) != dict: @@ -60,6 +62,10 @@ class System(item.Item): return True def set_pxe_address(self,address): + """ + Assign a IP or hostname in DHCP when this MAC boots. + Only works if manage_dhcp is set in /var/lib/cobbler/settings + """ # restricting to address as IP only in dhcpd.conf is probably # incorrect ... some people may want to pin the hostname instead. # doing so, however, doesn't allow dhcpd.conf to be managed @@ -78,6 +84,27 @@ class System(item.Item): return True raise cexceptions.CobblerException("exc_profile") + def set_netboot_enabled(self,netboot_enabled): + """ + If true, allows per-system PXE files to be generated on sync (or add). If false, + these files are not generated, thus eliminating the potential for an infinite install + loop when systems are set to PXE boot first in the boot order. In general, users + who are PXE booting first in the boot order won't create system definitions, so this + feature primarily comes into play for programmatic users of the API, who want to + initially create a system with netboot enabled and then disable it after the system installs, + as triggered by some action in kickstart %post. For this reason, this option is not + surfaced in the CLI, output, or documentation (yet). + + Use of this option does not affect the ability to use PXE menus. If an admin has machines + set up to PXE only after local boot fails, this option isn't even relevant. + """ + if netboot_enabled in [ True, "True", "true", 1, "on", "yes", "y", "ON", "YES", "Y" ]: + # this is a bit lame, though we don't know what the user will enter YAML wise... + self.netboot_enabled = 1 + else: + self.netboot_enabled = 0 + return True + def is_valid(self): """ A system is valid when it contains a valid name and a profile. @@ -90,11 +117,12 @@ class System(item.Item): def to_datastruct(self): return { - 'name' : self.name, - 'profile' : self.profile, - 'kernel_options' : self.kernel_options, - 'ks_meta' : self.ks_meta, - 'pxe_address' : self.pxe_address + 'name' : self.name, + 'profile' : self.profile, + 'kernel_options' : self.kernel_options, + 'ks_meta' : self.ks_meta, + 'pxe_address' : self.pxe_address, + 'netboot_enabled' : self.netboot_enabled } def printable(self): -- cgit