Source code for cobbler.items.system

"""
All code belonging to Cobbler systems.

Changelog (System):

V3.4.0 (unreleased):
    * Added:
        * ``display_name``: str
        * ``redhat_management_org``: enums.VALUE_INHERITED
        * ``redhat_management_user``: enums.VALUE_INHERITED
        * ``redhat_management_password``: enums.VALUE_INHERITED
    * Changes:
        * Constructor: ``kwargs`` can now be used to seed the item during creation.
        * ``from_dict()``: The method was moved to the base class.
        * ``parent``: The property was moved to the base class.
V3.3.4 (unreleased):
    * Changed:
        * The network interface ``default`` is not created on object creation.
V3.3.3:
    * Changed:
        * ``boot_loaders``: Can now be set to ``<<inherit>>``
        * ``next_server_v4``: Can now be set to ``<<inhertit>>``
        * ``next_server_v6``: Can now be set to ``<<inhertit>>``
        * ``virt_cpus``: Can now be set to ``<<inhertit>>``
        * ``virt_file_size``: Can now be set to ``<<inhertit>>``
        * ``virt_disk_driver``: Can now be set to ``<<inhertit>>``
        * ``virt_auto_boot``: Can now be set to ``<<inhertit>>``
        * ``virt_ram``: Can now be set to ``<<inhertit>>``
        * ``virt_type``: Can now be set to ``<<inhertit>>``
        * ``virt_path``: Can now be set to ``<<inhertit>>``
V3.3.2:
    * No changes
V3.3.1:
    * Changed:
        * ``serial_device``: Default value is now ``-1``
V3.3.0:
    * This release switched from pure attributes to properties (getters/setters).
    * Added:
        * ``next_server_v4``
        * ``next_server_v6``
    * Changed:
        * ``virt_*``: Cannot be set to inherit anymore
        * ``enable_gpxe``: Renamed to ``enable_ipxe``
    * Removed:
        * ``get_fields()``
        * ``next_server`` - Please use one of ``next_server_v4`` or ``next_server_v6``
        * ``set_boot_loader()`` - Moved to ``boot_loader`` property
        * ``set_server()`` - Moved to ``server`` property
        * ``set_next_server()`` - Moved to ``next_server`` property
        * ``set_filename()`` - Moved to ``filename`` property
        * ``set_proxy()`` - Moved to ``proxy`` property
        * ``set_redhat_management_key()`` - Moved to ``redhat_management_key`` property
        * ``get_redhat_management_key()`` - Moved to ``redhat_management_key`` property
        * ``set_dhcp_tag()`` - Moved to ``NetworkInterface`` class property ``dhcp_tag``
        * ``set_cnames()`` - Moved to ``NetworkInterface`` class property ``cnames``
        * ``set_status()`` - Moved to ``status`` property
        * ``set_static()`` - Moved to ``NetworkInterface`` class property ``static``
        * ``set_management()`` - Moved to ``NetworkInterface`` class property ``management``
        * ``set_dns_name()`` - Moved to ``NetworkInterface`` class property ``dns_name``
        * ``set_hostname()`` - Moved to ``hostname`` property
        * ``set_ip_address()`` - Moved to ``NetworkInterface`` class property ``ip_address``
        * ``set_mac_address()`` - Moved to ``NetworkInterface`` class property ``mac_address``
        * ``set_gateway()`` - Moved to ``gateway`` property
        * ``set_name_servers()`` - Moved to ``name_servers`` property
        * ``set_name_servers_search()`` - Moved to ``name_servers_search`` property
        * ``set_netmask()`` - Moved to ``NetworkInterface`` class property ``netmask``
        * ``set_if_gateway()`` - Moved to ``NetworkInterface`` class property ``if_gateway``
        * ``set_virt_bridge()`` - Moved to ``NetworkInterface`` class property ``virt_bridge``
        * ``set_interface_type()`` - Moved to ``NetworkInterface`` class property ``interface_type``
        * ``set_interface_master()`` - Moved to ``NetworkInterface`` class property ``interface_master``
        * ``set_bonding_opts()`` - Moved to ``NetworkInterface`` class property ``bonding_opts``
        * ``set_bridge_opts()`` - Moved to ``NetworkInterface`` class property ``bridge_opts``
        * ``set_ipv6_autoconfiguration()`` - Moved to ``ipv6_autoconfiguration`` property
        * ``set_ipv6_default_device()`` - Moved to ``ipv6_default_device`` property
        * ``set_ipv6_address()`` - Moved to ``NetworkInterface`` class property ``ipv6_address``
        * ``set_ipv6_prefix()`` - Moved to ``NetworkInterface`` class property ``ipv6_prefix``
        * ``set_ipv6_secondaries()`` - Moved to ``NetworkInterface`` class property ``ipv6_secondaries``
        * ``set_ipv6_default_gateway()`` - Moved to ``NetworkInterface`` class property ``ipv6_default_gateway``
        * ``set_ipv6_static_routes()`` - Moved to ``NetworkInterface`` class property ``ipv6_static_routes``
        * ``set_ipv6_mtu()`` - Moved to ``NetworkInterface`` class property ``ipv6_mtu``
        * ``set_mtu()`` - Moved to ``NetworkInterface`` class property ``mtu``
        * ``set_connected_mode()`` - Moved to ``NetworkInterface`` class property ``connected_mode``
        * ``set_enable_gpxe()`` - Moved to ``enable_gpxe`` property
        * ``set_profile()`` - Moved to ``profile`` property
        * ``set_image()`` - Moved to ``image`` property
        * ``set_virt_cpus()`` - Moved to ``virt_cpus`` property
        * ``set_virt_file_size()`` - Moved to ``virt_file_size`` property
        * ``set_virt_disk_driver()`` - Moved to ``virt_disk_driver`` property
        * ``set_virt_auto_boot()`` - Moved to ``virt_auto_boot`` property
        * ``set_virt_pxe_boot()`` - Moved to ``virt_pxe_boot`` property
        * ``set_virt_ram()`` - Moved to ``virt_ram`` property
        * ``set_virt_type()`` - Moved to ``virt_type`` property
        * ``set_virt_path()`` - Moved to ``virt_path`` property
        * ``set_netboot_enabled()`` - Moved to ``netboot_enabled`` property
        * ``set_autoinstall()`` - Moved to ``autoinstall`` property
        * ``set_power_type()`` - Moved to ``power_type`` property
        * ``set_power_identity_file()`` - Moved to ``power_identity_file`` property
        * ``set_power_options()`` - Moved to ``power_options`` property
        * ``set_power_user()`` - Moved to ``power_user`` property
        * ``set_power_pass()`` - Moved to ``power_pass`` property
        * ``set_power_address()`` - Moved to ``power_address`` property
        * ``set_power_id()`` - Moved to ``power_id`` property
        * ``set_repos_enabled()`` - Moved to ``repos_enabled`` property
        * ``set_serial_device()`` - Moved to ``serial_device`` property
        * ``set_serial_baud_rate()`` - Moved to ``serial_baud_rate`` property
V3.2.2:
    * No changes
V3.2.1:
    * Added:
        * ``kickstart``: Resolves as a proxy to ``autoinstall``
V3.2.0:
    * No changes
V3.1.2:
    * Added:
        * ``filename``: str - Inheritable
        * ``set_filename()``
V3.1.1:
    * No changes
V3.1.0:
    * No changes
V3.0.1:
    * File was moved from ``cobbler/item_system.py`` to ``cobbler/items/system.py``.
V3.0.0:
    * Field definitions for network interfaces moved to own ``FIELDS`` array
    * Added:
        * ``boot_loader``: str - Inheritable
        * ``next_server``: str - Inheritable
        * ``power_options``: str
        * ``power_identity_file``: str
        * ``serial_device``: int
        * ``serial_baud_rate``: int - One of "", "2400", "4800", "9600", "19200", "38400", "57600", "115200"
        * ``set_next_server()``
        * ``set_serial_device()``
        * ``set_serial_baud_rate()``
        * ``get_config_filename()``
        * ``set_power_identity_file()``
        * ``set_power_options()``
    * Changed:
        * ``kickstart``: Renamed to ``autoinstall``
        * ``ks_meta``: Renamed to ``autoinstall_meta``
        * ``from_datastruct``: Renamed to ``from_dict()``
        * ``set_kickstart()``: Renamed to ``set_autoinstall()``
    * Removed:
        * ``redhat_management_server``
        * ``set_ldap_enabled()``
        * ``set_monit_enabled()``
        * ``set_template_remote_kickstarts()``
        * ``set_redhat_management_server()``
        * ``set_name()``
V2.8.5:
    * Inital tracking of changes for the changelog.
    * Network interface defintions part of this class
    * Added:
        * ``name``: str
        * ``uid``: str
        * ``owners``: List[str] - Inheritable
        * ``profile``: str - Name of the profile
        * ``image``: str - Name of the image
        * ``status``: str - One of "", "development", "testing", "acceptance", "production"
        * ``kernel_options``: Dict[str, Any]
        * ``kernel_options_post``: Dict[str, Any]
        * ``ks_meta``: Dict[str, Any]
        * ``enable_gpxe``: bool - Inheritable
        * ``proxy``: str - Inheritable
        * ``netboot_enabled``: bool
        * ``kickstart``: str - Inheritable
        * ``comment``: str
        * ``depth``: int
        * ``server``: str - Inheritable
        * ``virt_path``: str - Inheritable
        * ``virt_type``: str - Inheritable; One of "xenpv", "xenfv", "qemu", "kvm", "vmware", "openvz"
        * ``virt_cpus``: int - Inheritable
        * ``virt_file_size``: float - Inheritable
        * ``virt_disk_driver``: str - Inheritable; One of "<<inherit>>", "raw", "qcow", "qcow2", "aio", "vmdk", "qed"
        * ``virt_ram``: int - Inheritable
        * ``virt_auto_boot``: bool - Inheritable
        * ``virt_pxe_boot``: bool
        * ``ctime``: float
        * ``mtime``: float
        * ``power_type``: str - Default loaded from settings key ``power_management_default_type``
        * ``power_address``: str
        * ``power_user``: str
        * ``power_pass``: str
        * ``power_id``: str
        * ``hostname``: str
        * ``gateway``: str
        * ``name_servers``: List[str]
        * ``name_servers_search``: List[str]
        * ``ipv6_default_device``: str
        * ``ipv6_autoconfiguration``: bool
        * ``mgmt_classes``: List[Any] - Inheritable
        * ``mgmt_parameters``: str - Inheritable
        * ``boot_files``: Dict[str, Any]/List (Not reverse engineeriable) - Inheritable
        * ``fetchable_files``: Dict[str, Any] - Inheritable
        * ``template_files``: Dict[str, Any] - Inheritable
        * ``redhat_management_key``: str - Inheritable
        * ``redhat_management_server``: str - Inheritable
        * ``template_remote_kickstarts``: bool - Default loaded from settings key ``template_remote_kickstarts``
        * ``repos_enabled``: bool
        * ``ldap_enabled``: - bool
        * ``ldap_type``: str - Default loaded from settings key ``ldap_management_default_type``
        * ``monit_enabled``: bool

"""

# SPDX-License-Identifier: GPL-2.0-or-later
# SPDX-FileCopyrightText: Copyright 2006-2008, Red Hat, Inc and Others
# SPDX-FileCopyrightText: Michael DeHaan <michael.dehaan AT gmail>

import copy
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Set, Union

from cobbler import enums, utils, validate
from cobbler.cexceptions import CX
from cobbler.items.abstract.bootable_item import BootableItem, KernelOptionsDict
from cobbler.items.network_interface import NetworkInterface
from cobbler.items.options.dns import DNSOption
from cobbler.items.options.power import PowerOption
from cobbler.items.options.tftp import TFTPOption
from cobbler.items.options.virt import VirtOption
from cobbler.items.profile import Profile
from cobbler.utils import input_converters

if TYPE_CHECKING:
    from cobbler.api import CobblerAPI
    from cobbler.items.system_group import SystemGroup
    from cobbler.items.template import Template

    InheritableProperty = property
    LazyProperty = property
else:
    from cobbler.decorator import InheritableProperty, LazyProperty


[docs] class System(BootableItem): """ A Cobbler system object. """ # Constants TYPE_NAME = "system" COLLECTION_TYPE = "system" def __init__(self, api: "CobblerAPI", *args: Any, **kwargs: Any) -> None: """ Constructor :param api: The Cobbler API """ super().__init__(api) # Prevent attempts to clear the to_dict cache before the object is initialized. self._has_initialized = False self._ipv6_autoconfiguration = False self._repos_enabled = False self._autoinstall = enums.VALUE_INHERITED self._boot_loaders = [enums.BootLoader.INHERITED] self._dns = DNSOption(api=api, item=self) self._enable_ipxe: Union[bool, str] = enums.VALUE_INHERITED self._gateway = "" self._hostname = "" self._image = "" self._ipv6_default_device = "" self._netboot_enabled = False self._tftp = TFTPOption(api=api, item=self) self._filename = enums.VALUE_INHERITED self._power = PowerOption(api=api, item=self) self._profile = "" self._proxy = enums.VALUE_INHERITED self._redhat_management_key = enums.VALUE_INHERITED self._redhat_management_org = enums.VALUE_INHERITED self._redhat_management_user = enums.VALUE_INHERITED self._redhat_management_password = enums.VALUE_INHERITED self._server = enums.VALUE_INHERITED self._status = "" self._virt = VirtOption(api=api, item=self) self._serial_device = -1 self._serial_baud_rate = enums.BaudRates.DISABLED self._display_name = "" # Overwrite defaults from bootable_item.py self._owners = enums.VALUE_INHERITED self._autoinstall_meta = enums.VALUE_INHERITED self._kernel_options: Union[KernelOptionsDict, str] = enums.VALUE_INHERITED self._kernel_options_post: Union[KernelOptionsDict, str] = enums.VALUE_INHERITED if len(kwargs) > 0: self.from_dict(kwargs) if not self._has_initialized: self._has_initialized = True def __getattr__(self, name: str) -> Any: if name == "kickstart": return self.autoinstall if name == "ks_meta": return self.autoinstall_meta raise AttributeError(f'Attribute "{name}" did not exist on object type System.') # # override some base class methods first (BootableItem) #
[docs] def make_clone(self): _dict = copy.deepcopy(self.to_dict()) _dict.pop("uid", None) if isinstance(_dict.get("autoinstall"), dict): # This is a concrete dict object, not inherited. autoinstall = _dict.pop("autoinstall") _dict["autoinstall"] = autoinstall["uid"] return System(self.api, **_dict)
[docs] def check_if_valid(self): """ Checks if the current item passes logical validation. :raises CX: In case name is missing. Additionally either image or profile is required. """ super().check_if_valid() if not self.inmemory: return # System specific validation if self.profile == "": if self.image == "": raise CX( f"Error with system {self.name} - profile or image is required" )
# # specific methods for item.System # @property def interfaces(self) -> Dict[str, NetworkInterface]: r""" Represents all interfaces owned by the system. :getter: The interfaces present. Has at least the ``default`` one. :setter: Accepts not only the correct type but also a dict with dicts which will then be converted by the setter. """ search_result = self.api.find_network_interface( return_list=True, system_uid=self.uid ) result: Dict[str, NetworkInterface] = {} if search_result is None: return result if not isinstance(search_result, list): raise TypeError("Result must be of type list!") for item in search_result: result[item.name] = item return result @property def tftp(self) -> TFTPOption: """ Property for the TFTPOptions. :getter: The TFTPOptions of the System. """ return self._tftp @property def power(self) -> PowerOption: """ Property for the PowerOptions. :getter: The PowerOptions of the System. """ return self._power @property def virt(self) -> VirtOption: """ Property for the VirtOptions. :getter: The VirtOptions of the System. """ return self._virt @property def dns(self) -> DNSOption: """ Property for the DNSOptions. :getter: The DNSOptions of the System. """ return self._dns @LazyProperty def hostname(self) -> str: """ hostname property. :getter: Returns the value for ``hostname``. :setter: Sets the value for the property ``hostname``. """ return self._hostname @hostname.setter def hostname(self, value: str): """ Setter for the hostname of the System class. :param value: The new hostname """ if not isinstance(value, str): # type: ignore raise TypeError("Field hostname of object system needs to be of type str!") self._hostname = value @LazyProperty def status(self) -> str: """ status property. :getter: Returns the value for ``status``. :setter: Sets the value for the property ``status``. """ return self._status @status.setter def status(self, status: str): """ Setter for the status of the System class. :param status: The new system status. """ if not isinstance(status, str): # type: ignore raise TypeError("Field status of object system needs to be of type str!") self._status = status @InheritableProperty def boot_loaders(self) -> List[enums.BootLoader]: """ boot_loaders property. .. note:: This property can be set to ``<<inherit>>``. :getter: Returns the value for ``boot_loaders``. :setter: Sets the value for the property ``boot_loaders``. """ return self._resolve_enum(["boot_loaders"], enums.BootLoader) @boot_loaders.setter def boot_loaders( self, boot_loaders: Union[str, List[str], List[enums.BootLoader]], ): """ Setter of the boot loaders. :param boot_loaders: The boot loaders for the system. :raises CX: This is risen in case the bootloaders set are not valid ones. """ boot_loaders_split: List[enums.BootLoader] = [] if isinstance(boot_loaders, list): if all([isinstance(value, str) for value in boot_loaders]): boot_loaders_split = [ enums.BootLoader.to_enum(value) for value in boot_loaders ] elif all([isinstance(value, enums.BootLoader) for value in boot_loaders]): boot_loaders_split = boot_loaders # type: ignore else: raise TypeError( "The items inside the list of boot_loaders must all be of type str or cobbler.enums.BootLoader" ) elif isinstance(boot_loaders, str): # type: ignore if boot_loaders == "": self._boot_loaders = [] return if boot_loaders == enums.VALUE_INHERITED: self._boot_loaders = [enums.BootLoader.INHERITED] return boot_loaders_split = [ enums.BootLoader.to_enum(value) for value in input_converters.input_string_or_list_no_inherit( boot_loaders ) ] else: raise TypeError("The bootloaders need to be either a str or list") parent = self.logical_parent if parent is not None: # This can only be an item type that has the boot loaders property parent_boot_loaders: List[enums.BootLoader] = parent.boot_loaders # type: ignore else: self.logger.warning( 'Parent of System "%s" could not be found for resolving the parent bootloaders.', self.name, ) parent_boot_loaders = [] if ( len(boot_loaders_split) == 1 and boot_loaders_split[0] == enums.BootLoader.INHERITED ): self._boot_loaders = [enums.BootLoader.INHERITED] return if not set(boot_loaders_split).issubset(parent_boot_loaders): raise CX( f'Error with system "{self.name}" - not all boot_loaders are supported (given:' f'"{str(boot_loaders_split)}"; supported: "{str(parent_boot_loaders)}")' ) self._boot_loaders = boot_loaders_split @InheritableProperty def server(self) -> str: """ server property. .. note:: This property can be set to ``<<inherit>>``. :getter: Returns the value for ``server``. :setter: Sets the value for the property ``server``. """ return self._resolve(["server"]) @server.setter def server(self, server: str): """ If a system can't reach the boot server at the value configured in settings because it doesn't have the same name on it's subnet this is there for an override. :param server: The new value for the ``server`` property. :raises TypeError: In case server is no string. """ if not isinstance(server, str): # type: ignore raise TypeError("Field server of object system needs to be of type str!") if server == "": server = enums.VALUE_INHERITED self._server = server @InheritableProperty def filename(self) -> str: """ filename property. :getter: Returns the value for ``filename``. :setter: Sets the value for the property ``filename``. """ if self.image != "": return "" return self._resolve(["filename"]) @filename.setter def filename(self, filename: str): """ Setter for the filename of the System class. :param filename: The new value for the ``filename`` property. :raises TypeError: In case filename is no string. """ if not isinstance(filename, str): # type: ignore raise TypeError("Field filename of object system needs to be of type str!") if not filename: self._filename = enums.VALUE_INHERITED else: self._filename = filename.strip() @InheritableProperty def proxy(self) -> str: """ proxy property. This corresponds per default to the setting``proxy_url_int``. .. note:: This property can be set to ``<<inherit>>``. :getter: Returns the value for ``proxy``. :setter: Sets the value for the property ``proxy``. """ if self.profile != "": return self._resolve(["proxy"]) return self._resolve(["proxy_url_int"]) @proxy.setter def proxy(self, proxy: str): """ Setter for the proxy of the System class. :param proxy: The new value for the proxy. :raises TypeError: In case proxy is no string. """ if not isinstance(proxy, str): # type: ignore raise TypeError("Field proxy of object system needs to be of type str!") self._proxy = proxy @InheritableProperty def redhat_management_key(self) -> str: """ redhat_management_key property. .. note:: This property can be set to ``<<inherit>>``. :getter: Returns the value for ``redhat_management_key``. :setter: Sets the value for the property ``redhat_management_key``. """ return self._resolve(["redhat_management_key"]) @redhat_management_key.setter def redhat_management_key(self, management_key: str): """ Setter for the redhat_management_key of the System class. :param management_key: The new value for the redhat management key :raises TypeError: In case management_key is no string. """ if not isinstance(management_key, str): # type: ignore raise TypeError( "Field redhat_management_key of object system needs to be of type str!" ) if management_key == "": self._redhat_management_key = enums.VALUE_INHERITED self._redhat_management_key = management_key @InheritableProperty def redhat_management_org(self) -> str: """ redhat_management_org property. .. note:: This property can be set to ``<<inherit>>``. :getter: Returns the value for ``redhat_management_org``. :setter: Sets the value for the property ``redhat_management_org``. """ return self._resolve(["redhat_management_org"]) @redhat_management_org.setter # type: ignore[no-redef] def redhat_management_org(self, management_org: str): """ Setter for the redhat_management_org of the System class. :param management_org: The new value for the redhat management org :raises TypeError: In case management_org is no string. """ if not isinstance(management_org, str): # type: ignore raise TypeError( "Field redhat_management_org of object system needs to be of type str!" ) if management_org == "": self._redhat_management_org = enums.VALUE_INHERITED self._redhat_management_org = management_org @InheritableProperty def redhat_management_user(self) -> str: """ redhat_management_user property. .. note:: This property can be set to ``<<inherit>>``. :getter: Returns the value for ``redhat_management_user``. :setter: Sets the value for the property ``redhat_management_user``. """ return self._resolve(["redhat_management_user"]) @redhat_management_user.setter # type: ignore[no-redef] def redhat_management_user(self, management_user: str): """ Setter for the redhat_management_user of the System class. :param management_user: The new value for the redhat management user :raises TypeError: In case management_user is no string. """ if not isinstance(management_user, str): # type: ignore raise TypeError( "Field redhat_management_user of object system needs to be of type str!" ) if management_user == "": self._redhat_management_user = enums.VALUE_INHERITED self._redhat_management_user = management_user @InheritableProperty def redhat_management_password(self) -> str: """ redhat_management_password property. .. note:: This property can be set to ``<<inherit>>``. :getter: Returns the value for ``redhat_management_password``. :setter: Sets the value for the property ``redhat_management_password``. """ return self._resolve(["redhat_management_password"]) @redhat_management_password.setter # type: ignore[no-redef] def redhat_management_password(self, management_password: str): """ Setter for the redhat_management_password of the System class. :param management_password: The new value for the redhat management password :raises TypeError: In case management_password is no string. """ if not isinstance(management_password, str): # type: ignore raise TypeError( "Field redhat_management_password of object system needs to be of type str!" ) if management_password == "": self._redhat_management_password = enums.VALUE_INHERITED self._redhat_management_password = management_password
[docs] def get_mac_address(self, interface: str = "default"): """ Get the mac address, which may be implicit in the object name or explicit with --mac-address. Use the explicit location first. :param interface: The name of the interface to get the MAC of. """ search_result = self.api.find_network_interface( False, False, system_uid=self.uid, name=interface ) if search_result is None or isinstance(search_result, list): return None if search_result.mac_address != "": return search_result.mac_address.strip() return None
@property def get_mac_addresses(self) -> Set[str]: """ Get the set of system mac addresses. """ macs: Set[str] = set() for intf in self.interfaces.values(): mac = intf.mac_address if mac: mac = mac.strip() macs.add(mac) return macs
[docs] def get_ip_address(self, interface: str) -> str: """ Get the IP address for the given interface. :param interface: The name of the interface to get the IP address of. """ search_result = self.api.find_network_interface( False, False, system_uid=self.uid, name=interface ) if search_result is None or isinstance(search_result, list): return "" if search_result.ipv4.address: return search_result.ipv4.address.strip() return ""
[docs] def is_management_supported(self, cidr_ok: bool = True) -> bool: """ Can only add system PXE records if a MAC or IP address is available, else it's a koan only record. :param cidr_ok: Deprecated parameter which is not used anymore. """ if self.name == "default": return True for interface in self.interfaces.values(): mac = interface.mac_address ip_v4 = interface.ipv4.address ip_v6 = interface.ipv6.address if mac or ip_v4 or ip_v6: return True return False
@LazyProperty def gateway(self): """ gateway property. :getter: Returns the value for ``gateway``. :setter: Sets the value for the property ``gateway``. """ return self._gateway @gateway.setter def gateway(self, gateway: str): """ Set a gateway IPv4 address. :param gateway: IP address :returns: True or CX """ self._gateway = validate.ipv4_address(gateway) @LazyProperty def ipv6_autoconfiguration(self) -> bool: """ ipv6_autoconfiguration property. :getter: Returns the value for ``ipv6_autoconfiguration``. :setter: Sets the value for the property ``ipv6_autoconfiguration``. """ return self._ipv6_autoconfiguration @ipv6_autoconfiguration.setter def ipv6_autoconfiguration(self, value: bool): """ Setter for the ipv6_autoconfiguration of the System class. :param value: The new value for the ``ipv6_autoconfiguration`` property. """ value = input_converters.input_boolean(value) if not isinstance(value, bool): # type: ignore raise TypeError("ipv6_autoconfiguration needs to be of type bool") self._ipv6_autoconfiguration = value @LazyProperty def ipv6_default_device(self) -> str: """ ipv6_default_device property. :getter: Returns the value for ``ipv6_default_device``. :setter: Sets the value for the property ``ipv6_default_device``. """ return self._ipv6_default_device @ipv6_default_device.setter def ipv6_default_device(self, interface_name: str): """ Setter for the ipv6_default_device of the System class. :param interface_name: The new value for the ``ipv6_default_device`` property. """ if not isinstance(interface_name, str): # type: ignore raise TypeError( "Field ipv6_default_device of object system needs to be of type str!" ) self._ipv6_default_device = interface_name @InheritableProperty def enable_ipxe(self) -> bool: """ enable_ipxe property. .. note:: This property can be set to ``<<inherit>>``. :getter: Returns the value for ``enable_ipxe``. :setter: Sets the value for the property ``enable_ipxe``. """ return self._resolve(["enable_ipxe"]) @enable_ipxe.setter def enable_ipxe(self, enable_ipxe: Union[str, bool]): """ Sets whether the system will use iPXE for booting. :param enable_ipxe: If ipxe should be enabled or not. :raises TypeError: In case enable_ipxe is not a boolean. """ if enable_ipxe == enums.VALUE_INHERITED: self._enable_ipxe = enums.VALUE_INHERITED return enable_ipxe = input_converters.input_boolean(enable_ipxe) if not isinstance(enable_ipxe, bool): # type: ignore raise TypeError("enable_ipxe needs to be of type bool") self._enable_ipxe = enable_ipxe @LazyProperty def profile(self) -> str: """ profile property. :getter: Returns the value for ``profile``. :setter: Sets the value for the property ``profile``. """ return self._profile @profile.setter def profile(self, profile_uid: Union["Profile", str]): """ Set the system to use a certain named profile. The profile must have already been loaded into the profiles collection. :param uid: The uid of the profile which the system is underneath. :raises TypeError: In case profile_uid is no string. :raises ValueError: In case profile_uid does not exist. """ profile = None if isinstance(profile_uid, Profile): profile = profile_uid profile_uid = profile.uid elif not isinstance(profile_uid, str): # type: ignore raise TypeError("The name of a profile needs to be of type str.") items = self.api.systems() old_profile = self._profile if profile_uid in ["delete", "None", "~", ""]: self._profile = "" items.update_index_value(self, "profile", old_profile, "") return if profile is None: profile = self.api.profiles().find(uid=profile_uid, return_list=False) # type: ignore if isinstance(profile, list): raise ValueError("Search returned ambigous match!") if profile is None: raise ValueError(f'Profile with the uid "{profile_uid}" is not existing') self.image = "" # mutual exclusion rule self._profile = profile_uid self.depth = profile.depth + 1 # subprofiles have varying depths. items.update_index_value(self, "profile", old_profile, profile_uid) @LazyProperty def image(self) -> str: """ image property. :getter: Returns the value for ``image``. :setter: Sets the value for the property ``image``. """ return self._image @image.setter def image(self, image_uid: str): """ Set the system to use a certain named image. Works like ``set_profile()`` but cannot be used at the same time. It's one or the other. :param image_uid: The uid of the image which will act as a parent. :raises ValueError: In case the image name was invalid. :raises TypeError: In case image_name is no string. """ if not isinstance(image_uid, str): # type: ignore raise TypeError("The uid of an image must be of type str.") items = self.api.systems() old_image = self._image if image_uid in ["delete", "None", "~", ""]: self._image = "" items.update_index_value(self, "image", old_image, "") return img = self.api.images().find(uid=image_uid) if isinstance(img, list): raise ValueError("Search returned ambigous match!") if img is None: raise ValueError(f'Image with the name "{image_uid}" is not existing') self.profile = "" # mutual exclusion rule self._image = image_uid self.depth = img.depth + 1 items.update_index_value(self, "image", old_image, image_uid) @LazyProperty def netboot_enabled(self) -> bool: """ netboot_enabled property. :getter: Returns the value for ``netboot_enabled``. :setter: Sets the value for the property ``netboot_enabled``. """ return self._netboot_enabled @netboot_enabled.setter def netboot_enabled(self, netboot_enabled: bool): """ 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 automatic installation file's %post section. 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. :param: netboot_enabled: :raises TypeError: In case netboot_enabled is not a boolean. """ netboot_enabled = input_converters.input_boolean(netboot_enabled) if not isinstance(netboot_enabled, bool): # type: ignore raise TypeError("netboot_enabled needs to be a bool") self._netboot_enabled = netboot_enabled @InheritableProperty def autoinstall(self) -> Optional["Template"]: """ Represents the automatic OS installation template object. :getter: The template object that is configured. :setter: The name, UID or Template object. This property may be set to ``<<inherit>>``. """ if self._autoinstall == "": return None autoinstall = self._resolve(["autoinstall"]) if validate.validate_uuid(autoinstall): search_result = self.api.find_template(False, False, uid=autoinstall) elif hasattr(autoinstall, "TYPE_NAME"): return autoinstall else: # Built-In Templates save the names to survive serialization. search_result = self.api.find_template(False, False, name=autoinstall) if search_result is None: raise ValueError("No search result for given template UID/Name!") if isinstance(search_result, list): raise ValueError("Ambigous template match name detected!") return search_result @autoinstall.setter def autoinstall(self, autoinstall: Union[str, "Template"]): """ Setter for the ``autoinstall`` property. :param autoinstall: local automatic installation template name, UID or Template object. """ self._autoinstall = validate.validate_template(self.api, autoinstall) @LazyProperty def repos_enabled(self) -> bool: """ repos_enabled property. :getter: Returns the value for ``repos_enabled``. :setter: Sets the value for the property ``repos_enabled``. """ return self._repos_enabled @repos_enabled.setter def repos_enabled(self, repos_enabled: bool): """ Setter for the repos_enabled of the System class. :param repos_enabled: The new value for the ``repos_enabled`` property. :raises TypeError: In case is no string. """ repos_enabled = input_converters.input_boolean(repos_enabled) if not isinstance(repos_enabled, bool): # type: ignore raise TypeError( "Field repos_enabled of object system needs to be of type bool!" ) self._repos_enabled = repos_enabled @LazyProperty def serial_device(self) -> int: """ serial_device property. "-1" disables the serial device functionality completely. :getter: Returns the value for ``serial_device``. :setter: Sets the value for the property ``serial_device``. """ return self._serial_device @serial_device.setter def serial_device(self, device_number: int): """ Setter for the serial_device of the System class. :param device_number: The number of the device which is going """ self._serial_device = validate.validate_serial_device(device_number) @LazyProperty def serial_baud_rate(self) -> enums.BaudRates: """ serial_baud_rate property. The value "disabled" will disable the functionality completely. :getter: Returns the value for ``serial_baud_rate``. :setter: Sets the value for the property ``serial_baud_rate``. """ return self._serial_baud_rate @serial_baud_rate.setter def serial_baud_rate(self, baud_rate: int): """ Setter for the serial_baud_rate of the System class. :param baud_rate: The new value for the ``baud_rate`` property. """ self._serial_baud_rate = validate.validate_serial_baud_rate(baud_rate)
[docs] def get_config_filename( self, interface: str, loader: Optional[enums.BootLoader] = None ) -> Optional[str]: """ The configuration file for each system pxe uses is either a form of the MAC address or the hex version or the IP address. 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_management_supported()). This same file is used to store system config information in the Apache tree, so it's still relevant. :param interface: Name of the interface. :param loader: Bootloader type. """ boot_loaders = self.boot_loaders if loader is None: if ( enums.BootLoader.GRUB in boot_loaders or len(boot_loaders) < 1 ): # pylint: disable=unsupported-membership-test loader = enums.BootLoader.GRUB else: loader = boot_loaders[0] # pylint: disable=unsubscriptable-object if interface not in self.interfaces: self.logger.warning( 'System "%s" did not have an interface with the name "%s" attached to it.', self.name, interface, ) return None if self.name == "default": if loader == enums.BootLoader.GRUB: return None return "default" mac = self.get_mac_address(interface) ip_address = self.get_ip_address(interface) if mac is not None and mac != "": if loader == enums.BootLoader.GRUB: return mac.lower() return "01-" + "-".join(mac.split(":")).lower() if ip_address != "": return utils.get_host_ip(ip_address) return self.name
@LazyProperty def display_name(self) -> str: """ Returns the display name. :getter: Returns the display name for the boot menu. :setter: Sets the display name for the boot menu. """ return self._display_name @display_name.setter def display_name(self, display_name: str): """ Setter for the display_name of the item. :param display_name: The new display_name. If ``None`` the display_name will be set to an emtpy string. """ self._display_name = display_name @property def system_groups(self) -> List["SystemGroup"]: """ Finds all SystemGroups that this system is a member of. """ groups: List["SystemGroup"] = [] group_collection = self.api.system_groups() for group in group_collection.listing.values(): if self.uid in getattr(group, "members", []): groups.append(group) return groups