diff --git a/ironic/conf/agent.py b/ironic/conf/agent.py index f0cb7c8208..64299742c4 100644 --- a/ironic/conf/agent.py +++ b/ironic/conf/agent.py @@ -28,6 +28,7 @@ opts = [ 'ramdisk.')), cfg.IntOpt('memory_consumed_by_agent', default=0, + mutable=True, help=_('The memory size in MiB consumed by agent when it is ' 'booted on a bare metal node. This is used for ' 'checking if the image can be downloaded and deployed ' @@ -36,6 +37,7 @@ opts = [ 'the agent ramdisk image.')), cfg.BoolOpt('stream_raw_images', default=True, + mutable=True, help=_('Whether the agent ramdisk should stream raw images ' 'directly onto the disk or not. By streaming raw ' 'images directly onto the disk the agent ramdisk will ' @@ -63,6 +65,7 @@ opts = [ 'failure')), ('never', _('never collect logs'))], default='on_failure', + mutable=True, help=_('Whether Ironic should collect the deployment logs on ' 'deployment failure (on_failure), always or never.')), cfg.StrOpt('deploy_logs_storage_backend', @@ -70,20 +73,24 @@ opts = [ ('swift', _('store the logs in Object Storage ' 'service'))], default='local', + mutable=True, help=_('The name of the storage backend where the logs ' 'will be stored.')), cfg.StrOpt('deploy_logs_local_path', default='/var/log/ironic/deploy', + mutable=True, help=_('The path to the directory where the logs should be ' 'stored, used when the deploy_logs_storage_backend ' 'is configured to "local".')), cfg.StrOpt('deploy_logs_swift_container', default='ironic_deploy_logs_container', + mutable=True, help=_('The name of the Swift container to store the logs, ' 'used when the deploy_logs_storage_backend is ' 'configured to "swift".')), cfg.IntOpt('deploy_logs_swift_days_to_expire', default=30, + mutable=True, help=_('Number of days before a log object is marked as ' 'expired in Swift. If None, the logs will be kept ' 'forever or until manually deleted. Used when the ' @@ -96,6 +103,7 @@ opts = [ 'from HTTP service served at conductor ' 'nodes.'))], default='swift', + mutable=True, help=_('Specifies whether direct deploy interface should try ' 'to use the image source directly or if ironic should ' 'cache the image on the conductor and serve it from ' @@ -104,6 +112,7 @@ opts = [ 'service.')), cfg.IntOpt('command_timeout', default=60, + mutable=True, help=_('Timeout (in seconds) for IPA commands. ' 'Please note, the bootloader installation command ' 'to the agent is permitted a timeout of twice the ' @@ -116,6 +125,7 @@ opts = [ 'problems.')), cfg.IntOpt('neutron_agent_poll_interval', default=2, + mutable=True, help=_('The number of seconds Neutron agent will wait between ' 'polling for device changes. This value should be ' 'the same as CONF.AGENT.polling_interval in Neutron ' diff --git a/ironic/conf/api.py b/ironic/conf/api.py index bda28d55ab..80a30acfc0 100644 --- a/ironic/conf/api.py +++ b/ironic/conf/api.py @@ -28,9 +28,11 @@ opts = [ help=_('The TCP port on which ironic-api listens.')), cfg.IntOpt('max_limit', default=1000, + mutable=True, help=_('The maximum number of items returned in a single ' 'response from a collection resource.')), cfg.StrOpt('public_endpoint', + mutable=True, help=_("Public URL to use when building the links to the API " "resources (for example, \"https://ironic.rocks:6384\")." " If None the links will be built using the request's " @@ -57,10 +59,12 @@ opts = [ "to set URLs in responses to the SSL terminated one.")), cfg.BoolOpt('restrict_lookup', default=True, + mutable=True, help=_('Whether to restrict the lookup API to only nodes ' 'in certain states.')), cfg.IntOpt('ramdisk_heartbeat_timeout', default=300, + mutable=True, help=_('Maximum interval (in seconds) for agent heartbeats.')), ] diff --git a/ironic/conf/conductor.py b/ironic/conf/conductor.py index da98678a6c..beab8ffccd 100644 --- a/ironic/conf/conductor.py +++ b/ironic/conf/conductor.py @@ -46,6 +46,7 @@ opts = [ # We're using timedelta which can overflow if somebody sets this # too high, so limit to a sane value of 10 years. max=315576000, + mutable=True, help=_('Maximum time (in seconds) since the last check-in ' 'of a conductor. A conductor is considered inactive ' 'when this time has been exceeded.')), @@ -74,6 +75,7 @@ opts = [ 'a deploy ramdisk. Set to 0 to disable timeout.')), cfg.BoolOpt('force_power_state_during_sync', default=True, + mutable=True, help=_('During sync_power_state, should the hardware power ' 'state be set to the state recorded in the database ' '(True) or should the database be updated based on ' @@ -162,6 +164,7 @@ opts = [ '0 - unlimited.')), cfg.BoolOpt('automated_clean', default=True, + mutable=True, help=_('Enables or disables automated cleaning. Automated ' 'cleaning is a configurable set of steps, ' 'such as erasing disk drives, that are performed on ' @@ -206,10 +209,12 @@ opts = [ cfg.IntOpt('soft_power_off_timeout', default=600, min=1, + mutable=True, help=_('Timeout (in seconds) of soft reboot and soft power ' 'off operation. This value always has to be positive.')), cfg.IntOpt('power_state_change_timeout', min=2, default=60, + mutable=True, help=_('Number of seconds to wait for power operations to ' 'complete, i.e., so that a baremetal node is in the ' 'desired power state. If timed out, the power operation ' @@ -255,11 +260,13 @@ opts = [ cfg.StrOpt('rescue_password_hash_algorithm', default='sha256', choices=['sha256', 'sha512'], + mutable=True, help=_('Password hash algorithm to be used for the rescue ' 'password.')), cfg.BoolOpt('require_rescue_password_hashed', # TODO(TheJulia): Change this to True in Victoria. default=False, + mutable=True, help=_('Option to cause the conductor to not fallback to ' 'an un-hashed version of the rescue password, ' 'permitting rescue with older ironic-python-agent ' diff --git a/ironic/conf/default.py b/ironic/conf/default.py index 9621c2db56..b26e84abce 100644 --- a/ironic/conf/default.py +++ b/ironic/conf/default.py @@ -72,6 +72,7 @@ api_opts = [ help=_('Enable pecan debug mode. WARNING: this is insecure ' 'and should not be used in a production environment.')), cfg.StrOpt('default_resource_class', + mutable=True, help=_('Resource class to use for new nodes when no resource ' 'class is provided in the creation request.')), ] @@ -191,6 +192,7 @@ hash_opts = [ image_opts = [ cfg.BoolOpt('force_raw_images', default=True, + mutable=True, help=_('If True, convert backing images to "raw" disk image ' 'format.')), cfg.StrOpt('isolinux_bin', @@ -231,6 +233,7 @@ image_opts = [ img_cache_opts = [ cfg.BoolOpt('parallel_image_downloads', default=False, + mutable=True, help=_('Run image downloads and raw format conversions in ' 'parallel.')), ] @@ -304,6 +307,7 @@ path_opts = [ portgroup_opts = [ cfg.StrOpt( 'default_portgroup_mode', default='active-backup', + mutable=True, help=_( 'Default mode for portgroups. Allowed values can be found in the ' 'linux kernel documentation on bonding: ' @@ -340,6 +344,7 @@ service_opts = [ 'conductor and API services')), cfg.BoolOpt('require_agent_token', default=False, + mutable=True, help=_('Used to require the use of agent tokens. These ' 'tokens are used to guard the api lookup endpoint and ' 'conductor heartbeat processing logic to authenticate ' diff --git a/ironic/conf/deploy.py b/ironic/conf/deploy.py index 500324f1c5..8be4758b0a 100644 --- a/ironic/conf/deploy.py +++ b/ironic/conf/deploy.py @@ -29,15 +29,18 @@ opts = [ help=_("ironic-conductor node's HTTP root path.")), cfg.BoolOpt('enable_ata_secure_erase', default=True, + mutable=True, help=_('Whether to support the use of ATA Secure Erase ' 'during the cleaning process. Defaults to True.')), cfg.IntOpt('erase_devices_priority', + mutable=True, help=_('Priority to run in-band erase devices via the Ironic ' 'Python Agent ramdisk. If unset, will use the priority ' 'set in the ramdisk (defaults to 10 for the ' 'GenericHardwareManager). If set to 0, will not run ' 'during cleaning.')), cfg.IntOpt('erase_devices_metadata_priority', + mutable=True, help=_('Priority to run in-band clean step that erases ' 'metadata from devices, via the Ironic Python Agent ' 'ramdisk. If unset, will use the priority set in the ' @@ -47,11 +50,13 @@ opts = [ cfg.IntOpt('shred_random_overwrite_iterations', default=1, min=0, + mutable=True, help=_('During shred, overwrite all block devices N times with ' 'random data. This is only used if a device could not ' 'be ATA Secure Erased. Defaults to 1.')), cfg.BoolOpt('shred_final_overwrite_with_zeros', default=True, + mutable=True, help=_("Whether to write zeros to a node's block devices " "after writing random data. This will write zeros to " "the device even when " @@ -60,6 +65,7 @@ opts = [ "Secure Erased. Defaults to True.")), cfg.BoolOpt('continue_if_disk_secure_erase_fails', default=False, + mutable=True, help=_('Defines what to do if an ATA secure erase operation ' 'fails during cleaning in the Ironic Python Agent. ' 'If False, the cleaning operation will fail and the ' @@ -69,18 +75,21 @@ opts = [ cfg.IntOpt('disk_erasure_concurrency', default=1, min=1, + mutable=True, help=_('Defines the target pool size used by Ironic Python ' 'Agent ramdisk to erase disk devices. The number of ' 'threads created to erase disks will not exceed this ' 'value or the number of disks to be erased.')), cfg.BoolOpt('power_off_after_deploy_failure', default=True, + mutable=True, help=_('Whether to power off a node after deploy failure. ' 'Defaults to True.')), cfg.StrOpt('default_boot_option', choices=[('netboot', _('boot from a network')), ('local', _('local boot'))], default='local', + mutable=True, help=_('Default boot option to use when no boot option is ' 'requested in node\'s driver_info. Defaults to ' '"local". Prior to the Ussuri release, the default ' @@ -89,6 +98,7 @@ opts = [ choices=[(boot_modes.UEFI, _('UEFI boot mode')), (boot_modes.LEGACY_BIOS, _('Legacy BIOS boot mode'))], default=boot_modes.LEGACY_BIOS, + mutable=True, help=_('Default boot mode to use when no boot mode is ' 'requested in node\'s driver_info, capabilities or ' 'in the `instance_info` configuration. Currently the ' @@ -103,6 +113,7 @@ opts = [ default=False, deprecated_group='conductor', deprecated_name='configdrive_use_swift', + mutable=True, help=_('Whether to upload the config drive to object store. ' 'Set this option to True to store config drive ' 'in a swift endpoint.')), @@ -115,6 +126,7 @@ opts = [ 'instead of swift tempurls.')), cfg.BoolOpt('fast_track', default=False, + mutable=True, help=_('Whether to allow deployment agents to perform lookup, ' 'heartbeat operations during initial states of a ' 'machine lifecycle and by-pass the normal setup ' @@ -127,6 +139,7 @@ opts = [ default=300, min=0, max=300, + mutable=True, help=_('Seconds for which the last heartbeat event is to be ' 'considered valid for the purpose of a fast ' 'track sequence. This setting should generally be ' diff --git a/ironic/conf/ipmi.py b/ironic/conf/ipmi.py index 9545bde179..3ca28054cc 100644 --- a/ironic/conf/ipmi.py +++ b/ironic/conf/ipmi.py @@ -22,6 +22,7 @@ from ironic.common.i18n import _ opts = [ cfg.IntOpt('command_retry_timeout', default=60, + mutable=True, help=_('Maximum time in seconds to retry retryable IPMI ' 'operations. (An operation is retryable, for ' 'example, if the requested operation fails ' @@ -31,18 +32,21 @@ opts = [ 'unresponsive BMCs.')), cfg.IntOpt('min_command_interval', default=5, + mutable=True, help=_('Minimum time, in seconds, between IPMI operations ' 'sent to a server. There is a risk with some hardware ' 'that setting this too low may cause the BMC to crash. ' 'Recommended setting is 5 seconds.')), cfg.BoolOpt('kill_on_timeout', default=True, + mutable=True, help=_('Kill `ipmitool` process invoked by ironic to read ' 'node power state if `ipmitool` process does not exit ' 'after `command_retry_timeout` timeout expires. ' 'Recommended setting is True')), cfg.BoolOpt('disable_boot_timeout', default=True, + mutable=True, help=_('Default timeout behavior whether ironic sends a raw ' 'IPMI command to disable the 60 second timeout for ' 'booting. Setting this option to False will NOT send ' @@ -51,10 +55,12 @@ opts = [ 'option in node\'s \'driver_info\' field.')), cfg.MultiStrOpt('additional_retryable_ipmi_errors', default=[], + mutable=True, help=_('Additional errors ipmitool may encounter, ' 'specific to the environment it is run in.')), cfg.BoolOpt('debug', default=False, + mutable=True, help=_('Enables all ipmi commands to be executed with an ' 'additional debugging output. This is a separate ' 'option as ipmitool can log a substantial amount ' diff --git a/ironic/conf/iscsi.py b/ironic/conf/iscsi.py index 8b1a258e0a..5e977e72c4 100644 --- a/ironic/conf/iscsi.py +++ b/ironic/conf/iscsi.py @@ -21,9 +21,11 @@ from ironic.common.i18n import _ opts = [ cfg.PortOpt('portal_port', default=3260, + mutable=True, help=_('The port number on which the iSCSI portal listens ' 'for incoming connections.')), cfg.StrOpt('conv_flags', + mutable=True, help=_('Flags that need to be sent to the dd command, ' 'to control the conversion of the original file ' 'when copying to the host. It can contain several ' @@ -31,6 +33,7 @@ opts = [ cfg.IntOpt('verify_attempts', default=3, min=1, + mutable=True, help=_('Maximum attempts to verify an iSCSI connection is ' 'active, sleeping 1 second between attempts. Defaults ' 'to 3.')), diff --git a/ironic/conf/neutron.py b/ironic/conf/neutron.py index 3775996366..d90395f52c 100644 --- a/ironic/conf/neutron.py +++ b/ironic/conf/neutron.py @@ -23,12 +23,15 @@ opts = [ cfg.IntOpt('port_setup_delay', default=0, min=0, + mutable=True, help=_('Delay value to wait for Neutron agents to setup ' 'sufficient DHCP configuration for port.')), cfg.IntOpt('retries', default=3, + mutable=True, help=_('Client retries in the case of a failed request.')), cfg.StrOpt('cleaning_network', + mutable=True, help=_('Neutron network UUID or name for the ramdisk to be ' 'booted into for cleaning nodes. Required for "neutron" ' 'network interface. It is also required if cleaning ' @@ -37,6 +40,7 @@ opts = [ 'unique among all networks or cleaning will fail.'), deprecated_name='cleaning_network_uuid'), cfg.StrOpt('provisioning_network', + mutable=True, help=_('Neutron network UUID or name for the ramdisk to be ' 'booted into for provisioning nodes. Required for ' '"neutron" network interface. If a name is provided, ' @@ -45,6 +49,7 @@ opts = [ deprecated_name='provisioning_network_uuid'), cfg.ListOpt('provisioning_network_security_groups', default=[], + mutable=True, help=_('List of Neutron Security Group UUIDs to be ' 'applied during provisioning of the nodes. ' 'Optional for the "neutron" network interface and not ' @@ -53,6 +58,7 @@ opts = [ 'is used.')), cfg.ListOpt('cleaning_network_security_groups', default=[], + mutable=True, help=_('List of Neutron Security Group UUIDs to be ' 'applied during cleaning of the nodes. ' 'Optional for the "neutron" network interface and not ' @@ -60,6 +66,7 @@ opts = [ 'If not specified, default security group ' 'is used.')), cfg.StrOpt('rescuing_network', + mutable=True, help=_('Neutron network UUID or name for booting the ramdisk ' 'for rescue mode. This is not the network that the ' 'rescue ramdisk will use post-boot -- the tenant ' @@ -70,6 +77,7 @@ opts = [ 'among all networks or rescue will fail.')), cfg.ListOpt('rescuing_network_security_groups', default=[], + mutable=True, help=_('List of Neutron Security Group UUIDs to be applied ' 'during the node rescue process. Optional for the ' '"neutron" network interface and not used for the ' @@ -77,6 +85,7 @@ opts = [ 'specified, the default security group is used.')), cfg.IntOpt('request_timeout', default=45, + mutable=True, help=_('Timeout for request processing when interacting ' 'with Neutron. This value should be increased if ' 'neutron port action timeouts are observed as neutron ' @@ -85,18 +94,21 @@ opts = [ 'client/server interactions.')), cfg.BoolOpt('add_all_ports', default=False, + mutable=True, help=_('Option to enable transmission of all ports ' 'to neutron when creating ports for provisioning, ' 'cleaning, or rescue. This is done without IP ' 'addresses assigned to the port, and may be useful ' 'in some bonded network configurations.')), cfg.StrOpt('inspection_network', + mutable=True, help=_('Neutron network UUID or name for the ramdisk to be ' 'booted into for in-band inspection of nodes. ' 'If a name is provided, it must be unique among all ' 'networks or inspection will fail.')), cfg.ListOpt('inspection_network_security_groups', default=[], + mutable=True, help=_('List of Neutron Security Group UUIDs to be applied ' 'during the node inspection process. Optional for the ' '"neutron" network interface and not used for the ' @@ -104,6 +116,7 @@ opts = [ 'specified, the default security group is used.')), cfg.IntOpt('dhcpv6_stateful_address_count', default=4, + mutable=True, help=_('Number of IPv6 addresses to allocate for ports created ' 'for provisioning, cleaning, rescue or inspection on ' 'DHCPv6-stateful networks. Different stages of the ' diff --git a/ironic/conf/nova.py b/ironic/conf/nova.py index 9fc8c1c52e..0ec1f2a77c 100644 --- a/ironic/conf/nova.py +++ b/ironic/conf/nova.py @@ -18,6 +18,7 @@ from ironic.conf import auth opts = [ cfg.BoolOpt('send_power_notifications', default=True, + mutable=True, help=_('When set to True, it will enable the support ' 'for power state change callbacks to nova. This ' 'option should be set to False in deployments ' diff --git a/ironic/conf/pxe.py b/ironic/conf/pxe.py index a54beefa66..1a86237a7e 100644 --- a/ironic/conf/pxe.py +++ b/ironic/conf/pxe.py @@ -23,9 +23,11 @@ from ironic.common.i18n import _ opts = [ cfg.StrOpt('pxe_append_params', default='nofb nomodeset vga=normal', + mutable=True, help=_('Additional append parameters for baremetal PXE boot.')), cfg.StrOpt('default_ephemeral_format', default='ext4', + mutable=True, help=_('Default file system format for ephemeral partition, ' 'if one is created.')), cfg.StrOpt('images_path', @@ -50,16 +52,19 @@ opts = [ cfg.StrOpt('pxe_config_template', default=os.path.join( '$pybasedir', 'drivers/modules/pxe_config.template'), + mutable=True, help=_('On ironic-conductor node, template file for PXE ' 'configuration.')), cfg.StrOpt('uefi_pxe_config_template', default=os.path.join( '$pybasedir', 'drivers/modules/pxe_grub_config.template'), + mutable=True, help=_('On ironic-conductor node, template file for PXE ' 'configuration for UEFI boot loader.')), cfg.DictOpt('pxe_config_template_by_arch', default={}, + mutable=True, help=_('On ironic-conductor node, template file for PXE ' 'configuration per node architecture. ' 'For example: ' @@ -129,10 +134,12 @@ opts = [ default='4', choices=[('4', _('IPv4')), ('6', _('IPv6'))], + mutable=True, help=_('The IP version that will be used for PXE booting. ' 'Defaults to 4. EXPERIMENTAL')), cfg.BoolOpt('ipxe_use_swift', default=False, + mutable=True, help=_("Download deploy and rescue images directly from swift " "using temporary URLs. " "If set to false (default), images are downloaded " diff --git a/ironic/conf/redfish.py b/ironic/conf/redfish.py index af1b064515..7310b5a517 100644 --- a/ironic/conf/redfish.py +++ b/ironic/conf/redfish.py @@ -46,6 +46,7 @@ opts = [ help=_('Redfish HTTP client authentication method.')), cfg.BoolOpt('use_swift', default=True, + mutable=True, help=_('Upload generated ISO images for virtual media boot to ' 'Swift, then pass temporary URL to BMC for booting the ' 'node. If set to false, images are placed on the ' @@ -53,15 +54,18 @@ opts = [ 'local HTTP server.')), cfg.StrOpt('swift_container', default='ironic_redfish_container', + mutable=True, help=_('The Swift container to store Redfish driver data. ' 'Applies only when `use_swift` is enabled.')), cfg.IntOpt('swift_object_expiry_timeout', default=900, + mutable=True, help=_('Amount of time in seconds for Swift objects to ' 'auto-expire. Applies only when `use_swift` is ' 'enabled.')), cfg.StrOpt('kernel_append_params', default='nofb nomodeset vga=normal', + mutable=True, help=_('Additional kernel parameters to pass down to the ' 'instance kernel. These parameters can be consumed by ' 'the kernel or by the applications by reading ' diff --git a/ironic/drivers/modules/deploy_utils.py b/ironic/drivers/modules/deploy_utils.py index cb0af75c8e..df369207a8 100644 --- a/ironic/drivers/modules/deploy_utils.py +++ b/ironic/drivers/modules/deploy_utils.py @@ -838,7 +838,7 @@ class InstanceImageCache(image_cache.ImageCache): @METRICS.timer('cache_instance_image') -def cache_instance_image(ctx, node, force_raw=CONF.force_raw_images): +def cache_instance_image(ctx, node, force_raw=None): """Fetch the instance's image from Glance This method pulls the AMI and writes them to the appropriate place @@ -850,6 +850,10 @@ def cache_instance_image(ctx, node, force_raw=CONF.force_raw_images): :returns: a tuple containing the uuid of the image and the path in the filesystem where image is cached. """ + # NOTE(dtantsur): applying the default here to make the option mutable + if force_raw is None: + force_raw = CONF.force_raw_images + i_info = parse_instance_info(node) fileutils.ensure_tree(_get_image_dir_path(node.uuid)) image_path = _get_image_file_path(node.uuid) diff --git a/ironic/drivers/modules/iscsi_deploy.py b/ironic/drivers/modules/iscsi_deploy.py index c76d9e1543..4d8bdd8d80 100644 --- a/ironic/drivers/modules/iscsi_deploy.py +++ b/ironic/drivers/modules/iscsi_deploy.py @@ -283,6 +283,8 @@ def deploy_partition_image( NOTE: If key exists but value is None, it means partition doesn't exist. """ + # NOTE(dtantsur): CONF.default_boot_option is mutable, don't use it in + # the function signature! boot_option = boot_option or deploy_utils.get_default_boot_option() image_mb = disk_utils.get_image_mb(image_path) if image_mb > root_mb: diff --git a/releasenotes/notes/reloadable-301ec2aa421abf66.yaml b/releasenotes/notes/reloadable-301ec2aa421abf66.yaml new file mode 100644 index 0000000000..c952d473e2 --- /dev/null +++ b/releasenotes/notes/reloadable-301ec2aa421abf66.yaml @@ -0,0 +1,48 @@ +--- +other: + - | + The following configuration options can now be reloaded without restarting + ironic: + + From ``[agent]``: ``memory_consumed_by_agent``, ``stream_raw_images``, + ``deploy_logs_*``, ``image_download_source``, ``command_timeout`` + and ``neutron_agent_poll_interval``. + + From ``[api]``: ``max_limit``, ``public_endpoint`` + and ``ramdisk_heartbeat_timeout``. + + From ``[conductor]``: ``heartbeat_timeout``, + ``force_power_state_during_sync``, ``automated_clean``, + ``soft_power_off_timeout``, ``power_state_change_timeout``, + ``rescue_password_hash_algorithm`` and ``require_rescue_password_hashed``. + + From ``[DEFAULT]``: ``default_resource_class``, ``force_raw_images``, + ``parallel_image_downloads``, ``default_portgroup_mode`` + and ``require_agent_token``. + + From ``[deploy]``: ``enable_ata_secure_erase``, ``erase_devices_priority``, + ``erase_devices_metadata_priority``, ``shred_random_overwrite_iterations``, + ``shred_final_overwrite_with_zeros``, + ``continue_if_disk_secure_erase_fails``, ``disk_erasure_concurrency``, + ``power_off_after_deploy_failure``, ``default_boot_option``, + ``default_boot_mode``, ``configdrive_use_object_store``, ``fast_track``, + and ``fast_track_timeout``. + + From ``[ipmi]``: ``kill_on_timeout``, ``disable_boot_timeout``, + ``command_retry_interval``, ``min_command_interval``, ``debug`` + and ``additional_retryable_ipmi_errors``. + + From ``[iscsi]``: ``portal_port``, ``conv_flags`` and ``verify_attempts``. + + From ``[neutron]``: ``port_setup_delay``, ``*_network``, + ``*_network_security_groups``, ``request_timeout``, ``add_all_ports`` + and ``dhcpv6_stateful_address_count``. + + From ``[nova]``: ``send_power_notifications``. + + From ``[pxe]``: ``pxe_append_params``, ``default_ephemeral_format``, + ``pxe_config_template``, ``uefi_pxe_config_template``, + ``pxe_config_template_by_arch``, ``ip_version`` and ``ipxe_use_swift``. + + From ``[redfish]``: ``use_swift``, ``swift_container``, + ``swift_object_expiry_timeout`` and ``kernel_append_params``.