diff options
-rw-r--r-- | cobbler/action_litesync.py | 6 | ||||
-rw-r--r-- | cobbler/action_sync.py | 73 | ||||
-rwxr-xr-x | cobbler/cobbler.py | 7 | ||||
-rw-r--r-- | cobbler/item_system.py | 120 | ||||
-rw-r--r-- | cobbler/utils.py | 30 |
5 files changed, 148 insertions, 88 deletions
diff --git a/cobbler/action_litesync.py b/cobbler/action_litesync.py index e3d63e6..8828daa 100644 --- a/cobbler/action_litesync.py +++ b/cobbler/action_litesync.py @@ -106,13 +106,15 @@ class BootLiteSync: self.sync.validate_kickstart_for_specific_system(system) def remove_single_system(self, name): + system_record = self.systems.find(name) # rebuild system_list file in webdir self.sync.write_listings() # delete system YAML file in systems/$name in webdir self.sync.rmfile(os.path.join(self.settings.webdir, "systems", name)) # 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)) + if system_record.is_pxe_supported(): + filename = self.sync.get_config_filename(system_record) + self.sync.rmtree(os.path.join(self.settings.webdir, "kickstarts_sys", filename)) # delete PXE Linux configuration file (which might be in one of two places) itanic = False diff --git a/cobbler/action_sync.py b/cobbler/action_sync.py index d828f11..fa2f0a4 100644 --- a/cobbler/action_sync.py +++ b/cobbler/action_sync.py @@ -150,15 +150,11 @@ class BootSync: system_definitions = "" counter = 0 for system in self.systems: - if not utils.is_mac(system.name): - # can't do per-system dhcp features if the system - # hostname is not a MAC, therefore the templating - # gets to be pretty lame. The general rule here is - # if you want to PXE IA64 boxes, you need to use - # the MAC as the system name. - continue - - + if not system.get_mac_address() != "": + # can't write a DHCP entry for this system + # FIXME: should this be a warning? + pass + counter = counter + 1 systxt = "" if mode == "isc": @@ -169,9 +165,9 @@ class BootSync: if distro.arch == "ia64": # can't use pxelinux.0 anymore systxt = systxt + " filename \"/%s\";\n" % elilo - systxt = systxt + " hardware ethernet %s;\n" % system.name - if system.pxe_address != "": - systxt = systxt + " fixed-address %s;\n" % system.pxe_address + systxt = systxt + " hardware ethernet %s;\n" % system.get_mac_address() + if system.get_ip_address() != None: + systxt = systxt + " fixed-address %s;\n" % system.get_ip_address() systxt = systxt + " next-server %s;\n" % self.settings.next_server systxt = systxt + "}\n" @@ -184,9 +180,9 @@ class BootSync: profile = self.profiles.find(system.profile) distro = self.distros.find(profile.distro) - if system.pxe_address != "": + if system.get_ip_address() != None: if distro.arch.lower() == "ia64": - systxt = "dhcp-host=net:ia64," + system.pxe_address + "\n" + systxt = "dhcp-host=net:ia64," + system.get_ip_address() + "\n" # support for other arches needs modifications here else: systxt = "" @@ -208,12 +204,12 @@ class BootSync: # read 'man ethers' for format info fh = open("/etc/ethers","w+") for sys in self.systems: - if not utils.is_mac(sys.name): - # hopefully no one uses non-mac system ID's anymore, but I'm not sure. - # these need to be deprecated + if sys.get_mac_address() == None: + # can't write this w/o a MAC address + # FIXME -- should this raise a warning? continue - if sys.pxe_address != "": - fh.write(sys.name.upper() + "\t" + sys.pxe_address + "\n") + if sys.get_ip_address() != None: + fh.write(sys.get_mac_address().upper() + "\t" + sys.get_ip_address() + "\n") fh.close() def regen_hosts(self): @@ -221,10 +217,10 @@ class BootSync: # (other things may also make use of this later) fh = open("/var/lib/cobbler/cobbler_hosts","w+") for sys in self.systems: - if not utils.is_mac(sys.name): + if sys.get_mac_address() == None: continue - if sys.hostname != "" and sys.pxe_address != "": - fh.write(sys.pxe_address + "\t" + sys.hostname + "\n") + if sys.hostname != "" and sys.get_ip_address() != None: + fh.write(sys.get_ip_address() + "\t" + sys.hostname + "\n") fh.close() @@ -428,7 +424,7 @@ class BootSync: distro = self.distros.find(profile.distro) kickstart_path = utils.find_kickstart(profile.kickstart) if kickstart_path and os.path.exists(kickstart_path): - pxe_fn = self.get_pxe_filename(s.name) + pxe_fn = utils.get_config_filename(s) copy_path = os.path.join(self.settings.webdir, "kickstarts_sys", # system kickstarts go here pxe_fn @@ -510,7 +506,7 @@ class BootSync: distro = self.distros.find(profile.distro) if distro is None: raise CX(_("profile %s references a missing distro %s") % { "profile" : system.profile, "distro" : profile.distro}) - f1 = self.get_pxe_filename(system.name) + f1 = utils.get_config_filename(system) # tftp only @@ -521,17 +517,17 @@ class BootSync: if distro.arch == "ia64": # elilo expects files to be named "$name.conf" in the root # and can not do files based on the MAC address - if system.pxe_address == "" or system.pxe_address is None or not utils.is_ip(system.pxe_address): - raise CX(_("Itanium system object names must be MAC addresses")) + if system.get_ip_address() == None: + print _("Warning: Itanium system object (%s) needs an IP address to PXE") % system.name - filename = "%s.conf" % self.get_pxe_filename(system.pxe_address) + filename = "%s.conf" % self.utils_config_filename(system) f2 = os.path.join(self.settings.tftpboot, filename) f3 = os.path.join(self.settings.webdir, "systems", f1) - if system.netboot_enabled: + if system.netboot_enabled and system.is_pxe_supported(): if distro.arch in [ "x86", "x86_64", "standard"]: self.write_pxe_file(f2,system,profile,distro,False) if distro.arch == "ia64": @@ -541,25 +537,6 @@ class BootSync: self.rmfile(f2) self.write_system_file(f3,system) - - - def get_pxe_filename(self,name_input): - """ - The configuration file for each system pxe uses is either - a form of the MAC address of the hex version of the IP. Not sure - about ipv6 (or if that works). The system name in the config file - is either a system name, an IP, or the MAC, so figure it out, resolve - the host if needed, and return the pxe directory name. - """ - if name_input == "default": - return "default" - name = utils.find_system_identifier(name_input) - if utils.is_ip(name): - return utils.get_host_ip(name) - elif utils.is_mac(name): - return "01-" + "-".join(name.split(":")).lower() - else: - raise CX(_("System name for %s is not an MAC, IP, or resolvable host") % name) def make_pxe_menu(self): # only do this if there is NOT a system named default. @@ -659,7 +636,7 @@ class BootSync: if kickstart_path is not None and kickstart_path != "": if system is not None and kickstart_path.startswith("/"): - pxe_fn = self.get_pxe_filename(system.name) + pxe_fn = self.utils_config_filename(system) kickstart_path = "http://%s/cblr/kickstarts_sys/%s/ks.cfg" % (self.settings.server, pxe_fn) elif kickstart_path.startswith("/") or kickstart_path.find("/cobbler/kickstarts/") != -1: kickstart_path = "http://%s/cblr/kickstarts/%s/ks.cfg" % (self.settings.server, profile.name) diff --git a/cobbler/cobbler.py b/cobbler/cobbler.py index fda1772..0daaf85 100755 --- a/cobbler/cobbler.py +++ b/cobbler/cobbler.py @@ -471,8 +471,11 @@ class BootCLI: '--kopts' : lambda(a) : sys.set_kernel_options(a), '--ksmeta' : lambda(a) : sys.set_ksmeta(a), '--hostname' : lambda(a) : sys.set_hostname(a), - '--pxe-address' : lambda(a) : sys.set_ip_address(a), - '--ip-address' : lambda(a) : sys.set_ip_address(a) + '--pxe-address' : lambda(a) : sys.set_ip_address(a), # deprecated + '--ip-address' : lambda(a) : sys.set_ip_address(a), + '--ip' : lambda(a) : sys.set_ip_address(a), # alias + '--mac-address' : lambda(a) : sys.set_mac_address(a), + '--mac' : lambda(a) : sys.set_mac_address(a) # alias } def on_ok(): self.api.systems().add(sys, with_copy=self.api.sync_flag) diff --git a/cobbler/item_system.py b/cobbler/item_system.py index cb6b5c8..ebfa03c 100644 --- a/cobbler/item_system.py +++ b/cobbler/item_system.py @@ -31,7 +31,8 @@ class System(item.Item): self.profile = None # a name, not a reference self.kernel_options = {} self.ks_meta = {} - self.pxe_address = "" + self.ip_address = "" # bad naming here, to the UI, this is usually 'ip-address' + self.mac_address = "" self.netboot_enabled = 1 self.hostname = "" @@ -40,31 +41,94 @@ 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.pxe_address = self.load_item(seed_data, 'pxe_address') + + # backwards compat, load --ip-address from two possible sources. + # the old --pxe-address was a bit of a misnomer, new value is --ip-address + + oldvar = self.load_item(seed_data, 'pxe_address') + if oldvar == "": # newer version, yay + self.ip_address = self.load_item(seed_data, 'ip_address') + else: + self.ip_address = oldvar + self.netboot_enabled = self.load_item(seed_data, 'netboot_enabled', 1) self.hostname = self.load_item(seed_data, 'hostname') + self.mac_address = self.load_item(seed_data, 'mac_address') # backwards compatibility -- convert string entries to dicts for storage + # this allows for better usage from the API. + if type(self.kernel_options) != dict: self.set_kernel_options(self.kernel_options) if type(self.ks_meta) != dict: self.set_ksmeta(self.ks_meta) + # backwards compatibility -- if name is an IP or a MAC, set appropriate fields + # this will only happen once, as part of an upgrade path ... + # Explanation -- older cobbler's figured out the MAC and IP + # from the system name, newer cobblers allow arbitrary naming but can tell when the + # name is an IP or a MAC and use that if that info is not supplied. + + if self.mac_address == "" and utils.is_mac(self.name): + self.mac_address = self.name + elif self.ip_address == "" and utils.is_ip(self.name): + self.ip_address = self.name + return self def set_name(self,name): """ - A name can be a resolvable hostname (it instantly resolved and replaced with the IP), - any legal ipv4 address, or any legal mac address. ipv6 is not supported yet but _should_ be. - See utils.py + In Cobbler 0.4.9, any name given is legal, but if it's not an IP or MAC, --ip-address of --mac-address must + be given for PXE options to work. """ - if name == "default": - self.name="default" - return True - new_name = utils.find_system_identifier(name) - if not new_name: - raise CX(_("system name must be an MAC address, IP, or resolvable host")) - self.name = name # we check it add time, but store the original value. + + # set appropriate fields if the name implicitly is a MAC or IP. + # if the name is a hostname though, don't intuit that, as that's hard to determine + + if utils.is_mac(self.name): + self.mac_address = self.name + elif utils.is_ip(self.name): + self.ip_address = self.name + self.name = name + + return True + + def get_mac_address(self): + """ + Get the mac address, which may be implicit in the object name or explicit with --mac-address. + Use the explicit location first. + """ + if self.mac_address != "": + return self.mac_address + elif utils.is_mac(self.name): + return self.name + else: + # no one ever set it, but that might be ok depending on usage. + return None + + def get_ip_address(self): + """ + Get the IP address, which may be implicit in the object name or explict with --ip-address. + Use the explicit location first. + """ + if self.ip_address != "": # misnomer + return self.ip_address + elif utils.is_ip(self.name): + return self.name + else: + # no one ever set it, but that might be ok depending on usage. + return None + + def is_pxe_supported(self): + """ + Can only add system PXE records if a MAC or IP address is available, else it's a koan + only record. Actually Itanium goes beyond all this and needs the IP all of the time + though this is enforced elsewhere (action_sync.py). + """ + mac = self.get_mac_address() + ip = self.get_ip_address() + if mac is None or ip is None: + return False return True def set_hostname(self,hostname): @@ -72,21 +136,24 @@ class System(item.Item): return True def set_ip_address(self,address): - # allow function to use more sensical name - return self.set_pxe_address(address) - - 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 - # by cobbler (since elilo can't do MAC addresses) -- this is - # covered in the man page. - self.pxe_address = address - return True + if utils.is_ip(address): + self.ip_address = address + return True + raise CX(_("invalid format for IP address")) + + def set_mac_address(self,address): + if utils.is_mac(address): + self.mac_address = address + return True + raise CX(_("invalid format for MAC address")) + + def set_ip_address(self,address): + # backwards compatibility for API users: + return self.set_ip_address(address) def set_profile(self,profile_name): """ @@ -135,7 +202,7 @@ class System(item.Item): 'profile' : self.profile, 'kernel_options' : self.kernel_options, 'ks_meta' : self.ks_meta, - 'pxe_address' : self.pxe_address, + 'ip_address' : self.ip_address, 'netboot_enabled' : self.netboot_enabled, 'hostname' : self.hostname, } @@ -145,7 +212,10 @@ class System(item.Item): buf = buf + _("profile : %s\n") % self.profile buf = buf + _("kernel options : %s\n") % self.kernel_options buf = buf + _("ks metadata : %s\n") % self.ks_meta - buf = buf + _("ip address : %s\n") % self.pxe_address + buf = buf + _("ip address : %s\n") % self.get_ip_address() + buf = buf + _("mac address : %s\n") % self.get_mac_address() + buf = buf + _("pxe info set? : %s\n") % self.is_pxe_supported() + buf = buf + _("pxe id : %s\n") % self.get_system_identifier() buf = buf + _("hostname : %s\n") % self.hostname return buf diff --git a/cobbler/utils.py b/cobbler/utils.py index 9868975..de810be 100644 --- a/cobbler/utils.py +++ b/cobbler/utils.py @@ -40,17 +40,25 @@ def get_host_ip(ip): results = out.read() return results.split(" ")[-1][0:8] -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. - pxe bootloaders don't work in hostnames - """ - if is_mac(strdata): - return strdata.upper() - if is_ip(strdata): - return strdata - return resolve_ip(strdata) +def get_config_filename(sys): + """ + The configuration file for each system pxe uses is either + a form of the MAC address of the hex version of the IP. If none + of that is available, just use the given name, though the name + given will be unsuitable for PXE configuration (For this, check + system.is_pxe_supported()). This same file is used to store + system config information in the Apache tree, so it's still relevant. + """ + if sys.name == "default": + return "default" + mac = sys.get_mac_address() + ip = sys.get_ip_address() + if mac != None: + return "01-" + "-".join(mac.split(":")).lower() + elif ip != None: + return utils.get_host_ip(ip) + else: + return sys.name def is_ip(strdata): |