summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Tantsur <dtantsur@protonmail.com>2020-05-06 15:21:05 +0200
committerDmitry Tantsur <dtantsur@protonmail.com>2020-05-06 16:22:51 +0200
commit50c81cdbc90c254957b32b854223845dc7a4adac (patch)
tree216ae4fa8a89798aab3c0072c22bb8925aa6daba
parentb889daccc232c56476ce2bb1c5190a276821b07b (diff)
downloadironic-50c81cdbc90c254957b32b854223845dc7a4adac.tar.gz
Mark more configuration options as reloadable
I have only checked the main configuration options and two generic drivers, leaving everything else untouched. Added are options that is possible and makes sense to reload. Change-Id: I74c629bcaf50da7f829f0ec8c526d936b9d40b36
-rw-r--r--ironic/conf/agent.py10
-rw-r--r--ironic/conf/api.py4
-rw-r--r--ironic/conf/conductor.py7
-rw-r--r--ironic/conf/default.py5
-rw-r--r--ironic/conf/deploy.py13
-rw-r--r--ironic/conf/ipmi.py6
-rw-r--r--ironic/conf/iscsi.py3
-rw-r--r--ironic/conf/neutron.py13
-rw-r--r--ironic/conf/nova.py1
-rw-r--r--ironic/conf/pxe.py7
-rw-r--r--ironic/conf/redfish.py4
-rw-r--r--ironic/drivers/modules/deploy_utils.py6
-rw-r--r--ironic/drivers/modules/iscsi_deploy.py2
-rw-r--r--releasenotes/notes/reloadable-301ec2aa421abf66.yaml48
14 files changed, 128 insertions, 1 deletions
diff --git a/ironic/conf/agent.py b/ironic/conf/agent.py
index f0cb7c820..64299742c 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 bda28d55a..80a30acfc 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 da98678a6..beab8ffcc 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 9621c2db5..b26e84abc 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 500324f1c..8be4758b0 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 9545bde17..3ca28054c 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 8b1a258e0..5e977e72c 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 377599636..d90395f52 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 9fc8c1c52..0ec1f2a77 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 a54beefa6..1a86237a7 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 af1b06451..7310b5a51 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 cb0af75c8..df369207a 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 c76d9e154..4d8bdd8d8 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 000000000..c952d473e
--- /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``.