diff options
32 files changed, 1903 insertions, 950 deletions
diff --git a/doc/source/deploy/install-guide.rst b/doc/source/deploy/install-guide.rst index 4d5737343..2907ad54b 100644 --- a/doc/source/deploy/install-guide.rst +++ b/doc/source/deploy/install-guide.rst @@ -1099,6 +1099,19 @@ by an operator. There are two kinds of inspection supported by Ironic: being run on a separate host from the ironic-conductor service, or is using non-standard port. + In order to ensure that ports in Ironic are synchronized with NIC ports on + the node, the following settings in the ironic-discoverd configuration file + must be set:: + + [discoverd] + add_ports = all + keep_ports = present + + (requires ironic-discoverd of version 1.1.0 or higher). Note that in this + case an operator is responsible for deleting ports that can't be actually + used by Ironic, see `bug 1405131 + <https://bugs.launchpad.net/ironic/+bug/1405131>`_ for explanation. + .. _ironic-discoverd: https://github.com/stackforge/ironic-discoverd diff --git a/doc/source/dev/dev-quickstart.rst b/doc/source/dev/dev-quickstart.rst index 01b27d644..223052651 100644 --- a/doc/source/dev/dev-quickstart.rst +++ b/doc/source/dev/dev-quickstart.rst @@ -366,11 +366,11 @@ Source credentials, create a key, and spawn an instance:: .. note:: Because devstack create multiple networks, we need to pass an additional parameter - `--nic net-id` to the nova boot command when using the admin account, for example: + ``--nic net-id`` to the nova boot command when using the admin account, for example:: - net_id=$(neutron net-list | egrep "$PRIVATE_NETWORK_NAME"'[^-]' | awk '{ print $2 }') + net_id=$(neutron net-list | egrep "$PRIVATE_NETWORK_NAME"'[^-]' | awk '{ print $2 }') - nova boot --flavor baremetal --nic net-id=$net_id --image $image --key-name default testing + nova boot --flavor baremetal --nic net-id=$net_id --image $image --key-name default testing As the demo tenant, you should now see a Nova instance building:: diff --git a/etc/ironic/ironic.conf.sample b/etc/ironic/ironic.conf.sample index bc38835b5..a8a1501a6 100644 --- a/etc/ironic/ironic.conf.sample +++ b/etc/ironic/ironic.conf.sample @@ -824,8 +824,9 @@ # (integer value) #glance_num_retries=0 -# Default protocol to use when connecting to glance. Set to -# https for SSL. (string value) +# Authentication strategy to use when connecting to glance. +# Only "keystone" and "noauth" are currently supported by +# ironic. (string value) #auth_strategy=keystone @@ -1190,6 +1191,23 @@ #cleaning_network_uuid=<None> +[oslo_concurrency] + +# +# Options defined in oslo.concurrency +# + +# Enables or disables inter-process locks. (boolean value) +#disable_process_locking=false + +# Directory to use for lock files. For security, the +# specified directory should only be writable by the user +# running the processes that need locking. Defaults to +# environment variable OSLO_LOCK_PATH. If external locks are +# used, a lock path must be set. (string value) +#lock_path=<None> + + [oslo_messaging_amqp] # @@ -1374,11 +1392,42 @@ # value) #rabbit_ha_queues=false +# Number of seconds after which the Rabbit broker is +# considered down if heartbeat's keep-alive fails (0 disable +# the heartbeat). (integer value) +#heartbeat_timeout_threshold=60 + +# How often times during the heartbeat_timeout_threshold we +# check the heartbeat. (integer value) +#heartbeat_rate=2 + # Deprecated, use rpc_backend=kombu+memory or rpc_backend=fake # (boolean value) #fake_rabbit=false +[oslo_policy] + +# +# Options defined in oslo.policy +# + +# The JSON file that defines policies. (string value) +#policy_file=policy.json + +# Default rule. Enforced when a requested rule is not found. +# (string value) +#policy_default_rule=default + +# Directories where policy configuration files are stored. +# They can be relative to any directory in the search path +# defined by the config_dir option, or absolute paths. The +# file defined by policy_file must exist for these directories +# to be searched. Missing or empty directories are ignored. +# (multi valued) +#policy_dirs=policy.d + + [pxe] # diff --git a/ironic/api/controllers/v1/node.py b/ironic/api/controllers/v1/node.py index 4712d62d2..ce48e0916 100644 --- a/ironic/api/controllers/v1/node.py +++ b/ironic/api/controllers/v1/node.py @@ -391,6 +391,11 @@ class NodeStatesController(rest.RestController): raise exception.NodeLocked(node=rpc_node.uuid, host=rpc_node.reservation) + if (target in (ir_states.ACTIVE, ir_states.REBUILD) + and rpc_node.maintenance): + raise exception.NodeInMaintenance(op=_('provisioning'), + node=rpc_node.uuid) + m = ir_states.machine.copy() m.initialize(rpc_node.provision_state) if not m.is_valid_event(ir_states.VERBS.get(target, target)): diff --git a/ironic/common/image_service.py b/ironic/common/image_service.py index 57ab194d7..e4bef4ae3 100644 --- a/ironic/common/image_service.py +++ b/ironic/common/image_service.py @@ -65,8 +65,9 @@ glance_opts = [ 'glance.'), cfg.StrOpt('auth_strategy', default='keystone', - help='Default protocol to use when connecting to glance. ' - 'Set to https for SSL.'), + help='Authentication strategy to use when connecting to ' + 'glance. Only "keystone" and "noauth" are currently ' + 'supported by ironic.'), ] CONF.register_opts(glance_opts, group='glance') diff --git a/ironic/common/pxe_utils.py b/ironic/common/pxe_utils.py index 8174eccc4..a125da034 100644 --- a/ironic/common/pxe_utils.py +++ b/ironic/common/pxe_utils.py @@ -23,6 +23,7 @@ from ironic.common import dhcp_factory from ironic.common import exception from ironic.common.i18n import _ from ironic.common import utils +from ironic.drivers.modules import deploy_utils from ironic.drivers import utils as driver_utils from ironic.openstack.common import fileutils from ironic.openstack.common import log as logging @@ -191,7 +192,7 @@ def create_pxe_config(task, pxe_options, template=None): pxe_config = _build_pxe_config(pxe_options, template) utils.write_to_file(pxe_config_file_path, pxe_config) - if driver_utils.get_boot_mode_for_deploy(task.node) == 'uefi': + if deploy_utils.get_boot_mode_for_deploy(task.node) == 'uefi': _link_ip_address_pxe_configs(task) else: _link_mac_pxe_configs(task) @@ -205,7 +206,7 @@ def clean_up_pxe_config(task): """ LOG.debug("Cleaning up PXE config for node %s", task.node.uuid) - if driver_utils.get_boot_mode_for_deploy(task.node) == 'uefi': + if deploy_utils.get_boot_mode_for_deploy(task.node) == 'uefi': api = dhcp_factory.DHCPFactory().provider ip_addresses = api.get_ip_addresses(task) if not ip_addresses: @@ -252,7 +253,7 @@ def dhcp_options_for_instance(task): dhcp_opts.append({'opt_name': 'bootfile-name', 'opt_value': ipxe_script_url}) else: - if driver_utils.get_boot_mode_for_deploy(task.node) == 'uefi': + if deploy_utils.get_boot_mode_for_deploy(task.node) == 'uefi': boot_file = CONF.pxe.uefi_pxe_bootfile_name else: boot_file = CONF.pxe.pxe_bootfile_name diff --git a/ironic/drivers/modules/deploy_utils.py b/ironic/drivers/modules/deploy_utils.py index 7a8aff5f9..79fcaecd3 100644 --- a/ironic/drivers/modules/deploy_utils.py +++ b/ironic/drivers/modules/deploy_utils.py @@ -751,8 +751,14 @@ def _iscsi_setup_and_handle_errors(address, port, iqn, lun, delete_iscsi(address, port, iqn) -def notify_deploy_complete(address): - """Notifies the completion of deployment to the baremetal node. +def notify_ramdisk_to_proceed(address): + """Notifies the ramdisk waiting for instructions from Ironic. + + DIB ramdisk (from init script) makes vendor passhthrus and listens + on port 10000 for Ironic to notify back the completion of the task. + This method connects to port 10000 of the bare metal running the + ramdisk and then sends some data to notify the ramdisk to proceed + with it's next task. :param address: The IP address of the node. """ @@ -964,7 +970,7 @@ def try_set_boot_device(task, device, persistent=True): manager_utils.node_set_boot_device(task, device, persistent=persistent) except exception.IPMIFailure: - if driver_utils.get_boot_mode_for_deploy(task.node) == 'uefi': + if get_boot_mode_for_deploy(task.node) == 'uefi': LOG.warning(_LW("ipmitool is unable to set boot device while " "the node %s is in UEFI boot mode. Please set " "the boot device manually.") % task.node.uuid) @@ -1035,3 +1041,35 @@ def is_secure_boot_requested(node): sec_boot = capabilities.get('secure_boot', 'false').lower() return sec_boot == 'true' + + +def get_boot_mode_for_deploy(node): + """Returns the boot mode that would be used for deploy. + + This method returns boot mode to used for deploy using following order: + It returns 'uefi' if 'secure_boot' is set to 'true' in + 'instance_info/capabilities' of node. + It returns value of 'boot_mode' in 'properties/capabilities' of node. + It returns boot mode specified in 'instance_info/deploy_boot_mode' of + node. + It would return None if boot mode is present neither in 'capabilities' of + node 'properties' nor in node's 'instance_info'. + + :param node: an ironic node object. + :returns: 'bios', 'uefi' or None + """ + + if is_secure_boot_requested(node): + boot_mode = 'uefi' + LOG.debug('Deploy boot mode is %(boot_mode)s for %(node)s.', + {'boot_mode': boot_mode, 'node': node.uuid}) + return boot_mode + + boot_mode = driver_utils.get_node_capability(node, 'boot_mode') + if boot_mode is None: + instance_info = node.instance_info + boot_mode = instance_info.get('deploy_boot_mode') + + LOG.debug('Deploy boot mode is %(boot_mode)s for %(node)s.', + {'boot_mode': boot_mode, 'node': node.uuid}) + return boot_mode diff --git a/ironic/drivers/modules/ilo/common.py b/ironic/drivers/modules/ilo/common.py index f2281c671..02085ea5d 100644 --- a/ironic/drivers/modules/ilo/common.py +++ b/ironic/drivers/modules/ilo/common.py @@ -30,7 +30,7 @@ from ironic.common.i18n import _LI from ironic.common import images from ironic.common import swift from ironic.common import utils -from ironic.drivers import utils as driver_utils +from ironic.drivers.modules import deploy_utils from ironic.openstack.common import log as logging ilo_client = importutils.try_import('proliantutils.ilo.client') @@ -343,7 +343,7 @@ def update_boot_mode(task): """ node = task.node - boot_mode = driver_utils.get_boot_mode_for_deploy(node) + boot_mode = deploy_utils.get_boot_mode_for_deploy(node) if boot_mode is not None: LOG.debug("Node %(uuid)s boot mode is being set to %(boot_mode)s", @@ -360,7 +360,7 @@ def update_boot_mode(task): boot_mode = 'legacy' if boot_mode != 'UNKNOWN': - boot_mode = BOOT_MODE_ILO_TO_GENERIC[boot_mode.lower()] + boot_mode = BOOT_MODE_ILO_TO_GENERIC[boot_mode.lower()] if boot_mode == 'UNKNOWN': # NOTE(faizan) ILO will return this in remote cases and mostly on diff --git a/ironic/drivers/modules/ilo/deploy.py b/ironic/drivers/modules/ilo/deploy.py index af79ca93f..dbd9d7340 100644 --- a/ironic/drivers/modules/ilo/deploy.py +++ b/ironic/drivers/modules/ilo/deploy.py @@ -160,7 +160,7 @@ def _get_boot_iso(task, root_uuid): # Option 3 - Create boot_iso from kernel/ramdisk, upload to Swift # and provide its name. deploy_iso_uuid = deploy_info['ilo_deploy_iso'] - boot_mode = driver_utils.get_boot_mode_for_deploy(task.node) + boot_mode = deploy_utils.get_boot_mode_for_deploy(task.node) boot_iso_object_name = _get_boot_iso_object_name(task.node) kernel_params = CONF.pxe.pxe_append_params container = CONF.ilo.swift_ilo_container @@ -332,13 +332,17 @@ def _prepare_node_for_deploy(task): if _disable_secure_boot(task): change_boot_mode = False - # Set boot_mode capability to uefi for secure boot - if deploy_utils.is_secure_boot_requested(task.node): - LOG.debug('Secure boot deploy requested for node %s', task.node.uuid) - _enable_uefi_capability(task) - if change_boot_mode: ilo_common.update_boot_mode(task) + else: + # Need to update boot mode that would used during deploy, if one is not + # provided. + # Since secure boot was disabled, we are in 'uefi' boot mode. + if deploy_utils.get_boot_mode_for_deploy(task.node) is None: + instance_info = task.node.instance_info + instance_info['deploy_boot_mode'] = 'uefi' + task.node.instance_info = instance_info + task.node.save() def _update_secure_boot_mode(task, mode): @@ -363,15 +367,6 @@ def _update_secure_boot_mode(task, mode): {'mode': mode, 'node': task.node.uuid}) -def _enable_uefi_capability(task): - """Adds capability boot_mode='uefi' into Node property. - - :param task: a TaskManager instance containing the node to act on. - """ - driver_utils.rm_node_capability(task, 'boot_mode') - driver_utils.add_node_capability(task, 'boot_mode', 'uefi') - - class IloVirtualMediaIscsiDeploy(base.DeployInterface): def get_properties(self): @@ -624,6 +619,10 @@ class IloVirtualMediaAgentVendorInterface(agent.AgentVendorInterface): error = self.check_deploy_success(node) if error is None: + # Set boot mode + ilo_common.update_boot_mode(task) + + # Need to enable secure boot, if being requested _update_secure_boot_mode(task, True) super(IloVirtualMediaAgentVendorInterface, @@ -730,6 +729,8 @@ class VendorPassthru(agent_base_vendor.BaseAgentVendor): """ if method == 'pass_deploy_info': iscsi_deploy.get_deploy_info(task.node, **kwargs) + elif method == 'pass_bootloader_install_info': + iscsi_deploy.validate_pass_bootloader_info_input(task, kwargs) def _configure_vmedia_boot(self, task, root_uuid): """Configure vmedia boot for the node.""" @@ -754,6 +755,29 @@ class VendorPassthru(agent_base_vendor.BaseAgentVendor): @base.passthru(['POST']) @task_manager.require_exclusive_lock + def pass_bootloader_install_info(self, task, **kwargs): + """Accepts the results of bootloader installation. + + This method acts as a vendor passthru and accepts the result of + bootloader installation. If the bootloader installation was + successful, then it notifies the baremetal to proceed to reboot + and makes the instance active. If bootloader installation failed, + then it sets provisioning as failed and powers off the node. + + :param task: A TaskManager object. + :param kwargs: The arguments sent with vendor passthru. The expected + kwargs are:: + 'key': The deploy key for authorization + 'status': 'SUCCEEDED' or 'FAILED' + 'error': The error message if status == 'FAILED' + 'address': The IP address of the ramdisk + """ + task.process_event('resume') + iscsi_deploy.validate_bootloader_install_status(task, kwargs) + iscsi_deploy.finish_deploy(task, kwargs['address']) + + @base.passthru(['POST']) + @task_manager.require_exclusive_lock def pass_deploy_info(self, task, **kwargs): """Continues the iSCSI deployment from where ramdisk left off. @@ -782,30 +806,36 @@ class VendorPassthru(agent_base_vendor.BaseAgentVendor): 'root uuid', uuid_dict.get('disk identifier')) try: - # For iscsi_ilo driver, we boot from disk every time if the image - # deployed is a whole disk image. - if iscsi_deploy.get_boot_option(node) == "local" or iwdi: - manager_utils.node_set_boot_device(task, boot_devices.DISK, - persistent=True) - else: - self._configure_vmedia_boot(task, root_uuid_or_disk_id) - # Set boot mode ilo_common.update_boot_mode(task) # Need to enable secure boot, if being requested _update_secure_boot_mode(task, True) - deploy_utils.notify_deploy_complete(kwargs.get('address')) + # For iscsi_ilo driver, we boot from disk every time if the image + # deployed is a whole disk image. + if iscsi_deploy.get_boot_option(node) == "local" or iwdi: + manager_utils.node_set_boot_device(task, boot_devices.DISK, + persistent=True) - LOG.info(_LI('Deployment to node %s done'), node.uuid) - task.process_event('done') + # Ask the ramdisk to install bootloader and + # wait for the call-back through the vendor passthru + # 'pass_bootloader_install_info', if it's not a whole + # disk image. + if not iwdi: + deploy_utils.notify_ramdisk_to_proceed(kwargs['address']) + task.process_event('wait') + return + else: + self._configure_vmedia_boot(task, root_uuid_or_disk_id) except Exception as e: LOG.error(_LE('Deploy failed for instance %(instance)s. ' 'Error: %(error)s'), {'instance': node.instance_uuid, 'error': e}) msg = _('Failed to continue iSCSI deployment.') deploy_utils.set_failed_state(task, msg) + else: + iscsi_deploy.finish_deploy(task, kwargs.get('address')) @task_manager.require_exclusive_lock def continue_deploy(self, task, **kwargs): diff --git a/ironic/drivers/modules/iscsi_deploy.py b/ironic/drivers/modules/iscsi_deploy.py index 858412944..57df4a7d6 100644 --- a/ironic/drivers/modules/iscsi_deploy.py +++ b/ironic/drivers/modules/iscsi_deploy.py @@ -22,9 +22,13 @@ from six.moves.urllib import parse from ironic.common import exception from ironic.common.glance_service import service_utils as glance_service_utils from ironic.common.i18n import _ +from ironic.common.i18n import _LE +from ironic.common.i18n import _LI from ironic.common import image_service as service from ironic.common import keystone +from ironic.common import states from ironic.common import utils +from ironic.conductor import utils as manager_utils from ironic.drivers.modules import deploy_utils from ironic.drivers.modules import image_cache from ironic.drivers import utils as driver_utils @@ -416,7 +420,7 @@ def _get_boot_mode(node): :param node: A single Node. :returns: A string representing the boot mode type. Defaults to 'bios'. """ - boot_mode = driver_utils.get_boot_mode_for_deploy(node) + boot_mode = deploy_utils.get_boot_mode_for_deploy(node) if boot_mode: return boot_mode.lower() return "bios" @@ -539,3 +543,87 @@ def validate(task): # Validate the root device hints deploy_utils.parse_root_device_hints(node) + + +def validate_pass_bootloader_info_input(task, input_params): + """Validates the input sent with bootloader install info passthru. + + This method validates the input sent with bootloader install info + passthru. + + :param task: A TaskManager object. + :param input_params: A dictionary of params sent as input to passthru. + :raises: InvalidParameterValue, if deploy key passed doesn't match the + one stored in instance_info. + :raises: MissingParameterValue, if some input is missing. + """ + params = {'address': input_params.get('address'), + 'key': input_params.get('key'), + 'status': input_params.get('status')} + msg = _("Some mandatory input missing in 'pass_bootloader_info' " + "vendor passthru from ramdisk.") + deploy_utils.check_for_missing_params(params, msg) + + deploy_key = task.node.instance_info['deploy_key'] + if deploy_key != input_params.get('key'): + raise exception.InvalidParameterValue( + _("Deploy key %(key_sent)s does not match " + "with %(expected_key)s") % + {'key_sent': input_params.get('key'), 'expected_key': deploy_key}) + + +def validate_bootloader_install_status(task, input_params): + """Validate if bootloader was installed. + + This method first validates if deploy key sent in vendor passthru + was correct one, and then validates whether bootloader installation + was successful or not. + + :param task: A TaskManager object. + :param input_params: A dictionary of params sent as input to passthru. + :raises: InstanceDeployFailure, if bootloader installation was + reported from ramdisk as failure. + """ + if input_params['status'] != 'SUCCEEDED': + msg = (_('Failed to install bootloader on node %(node)s. ' + 'Error: %(error)s.') % + {'node': task.node.uuid, 'error': input_params.get('error')}) + LOG.error(msg) + deploy_utils.set_failed_state(task, msg) + raise exception.InstanceDeployFailure(msg) + + +def finish_deploy(task, address): + """Notifies the ramdisk to reboot the node and makes the instance active. + + This method notifies the ramdisk to proceed to reboot and then + makes the instance active. + + :param task: a TaskManager object. + :param address: The IP address of the bare metal node. + :raises: InstanceDeployFailure, if notifying ramdisk failed. + """ + node = task.node + try: + deploy_utils.notify_ramdisk_to_proceed(address) + except Exception as e: + LOG.error(_LE('Deploy failed for instance %(instance)s. ' + 'Error: %(error)s'), + {'instance': node.instance_uuid, 'error': e}) + msg = (_('Failed to notify ramdisk to reboot after bootloader ' + 'installation. Error: %s') % e) + deploy_utils.set_failed_state(task, msg) + raise exception.InstanceDeployFailure(msg) + + # TODO(lucasagomes): When deploying a node with the DIB ramdisk + # Ironic will not power control the node at the end of the deployment, + # it's the DIB ramdisk that reboots the node. But, for the SSH driver + # some changes like setting the boot device only gets applied when the + # machine is powered off and on again. So the code below is enforcing + # it. For Liberty we need to change the DIB ramdisk so that Ironic + # always controls the power state of the node for all drivers. + if get_boot_option(node) == "local" and 'ssh' in node.driver: + manager_utils.node_power_action(task, states.REBOOT) + + LOG.info(_LI('Deployment to node %s done'), node.uuid) + task.process_event('done') diff --git a/ironic/drivers/modules/pxe.py b/ironic/drivers/modules/pxe.py index 9a63c7af5..9ab3fc32c 100644 --- a/ironic/drivers/modules/pxe.py +++ b/ironic/drivers/modules/pxe.py @@ -28,7 +28,6 @@ from ironic.common import exception from ironic.common.glance_service import service_utils from ironic.common.i18n import _ from ironic.common.i18n import _LE -from ironic.common.i18n import _LI from ironic.common.i18n import _LW from ironic.common import image_service as service from ironic.common import keystone @@ -243,7 +242,7 @@ def validate_boot_option_for_uefi(node): :raises: InvalidParameterValue """ - boot_mode = driver_utils.get_boot_mode_for_deploy(node) + boot_mode = deploy_utils.get_boot_mode_for_deploy(node) boot_option = iscsi_deploy.get_boot_option(node) if (boot_mode == 'uefi' and node.driver_internal_info.get('is_whole_disk_image') and @@ -354,7 +353,7 @@ class PXEDeploy(base.DeployInterface): driver_utils.validate_boot_mode_capability(node) driver_utils.validate_boot_option_capability(node) - boot_mode = driver_utils.get_boot_mode_for_deploy(task.node) + boot_mode = deploy_utils.get_boot_mode_for_deploy(task.node) if CONF.pxe.ipxe_enabled: if not CONF.pxe.http_url or not CONF.pxe.http_root: @@ -448,7 +447,7 @@ class PXEDeploy(base.DeployInterface): pxe_options = _build_pxe_config_options(task.node, pxe_info, task.context) - if driver_utils.get_boot_mode_for_deploy(task.node) == 'uefi': + if deploy_utils.get_boot_mode_for_deploy(task.node) == 'uefi': pxe_config_template = CONF.pxe.uefi_pxe_config_template else: pxe_config_template = CONF.pxe.pxe_config_template @@ -486,7 +485,7 @@ class PXEDeploy(base.DeployInterface): task.node.uuid) deploy_utils.switch_pxe_config( pxe_config_path, root_uuid_or_disk_id, - driver_utils.get_boot_mode_for_deploy(task.node), + deploy_utils.get_boot_mode_for_deploy(task.node), iwdi) def clean_up(self, task): @@ -544,6 +543,7 @@ class VendorPassthru(agent_base_vendor.BaseAgentVendor): Valid methods: * pass_deploy_info + * pass_bootloader_install_info :param task: a TaskManager instance containing the node to act on. :param method: method to be validated. @@ -553,6 +553,30 @@ class VendorPassthru(agent_base_vendor.BaseAgentVendor): if method == 'pass_deploy_info': driver_utils.validate_boot_option_capability(task.node) iscsi_deploy.get_deploy_info(task.node, **kwargs) + elif method == 'pass_bootloader_install_info': + iscsi_deploy.validate_pass_bootloader_info_input(task, kwargs) + + @base.passthru(['POST']) + @task_manager.require_exclusive_lock + def pass_bootloader_install_info(self, task, **kwargs): + """Accepts the results of bootloader installation. + + This method acts as a vendor passthru and accepts the result of + the bootloader installation. If bootloader installation was + successful, then it notifies the bare metal to proceed to reboot + and makes the instance active. If the bootloader installation failed, + then it sets provisioning as failed and powers off the node. + :param task: A TaskManager object. + :param kwargs: The arguments sent with vendor passthru. The expected + kwargs are:: + 'key': The deploy key for authorization + 'status': 'SUCCEEDED' or 'FAILED' + 'error': The error message if status == 'FAILED' + 'address': The IP address of the ramdisk + """ + task.process_event('resume') + iscsi_deploy.validate_bootloader_install_status(task, kwargs) + iscsi_deploy.finish_deploy(task, kwargs['address']) @base.passthru(['POST']) @task_manager.require_exclusive_lock @@ -587,25 +611,34 @@ class VendorPassthru(agent_base_vendor.BaseAgentVendor): try: if iscsi_deploy.get_boot_option(node) == "local": deploy_utils.try_set_boot_device(task, boot_devices.DISK) + # If it's going to boot from the local disk, get rid of # the PXE configuration files used for the deployment pxe_utils.clean_up_pxe_config(task) + + # Ask the ramdisk to install bootloader and + # wait for the call-back through the vendor passthru + # 'pass_bootloader_install_info', if it's not a + # whole disk image. + if not is_whole_disk_image: + deploy_utils.notify_ramdisk_to_proceed(kwargs['address']) + task.process_event('wait') + return else: pxe_config_path = pxe_utils.get_pxe_config_file_path(node.uuid) - boot_mode = driver_utils.get_boot_mode_for_deploy(node) + boot_mode = deploy_utils.get_boot_mode_for_deploy(node) deploy_utils.switch_pxe_config(pxe_config_path, root_uuid_or_disk_id, boot_mode, is_whole_disk_image) - deploy_utils.notify_deploy_complete(kwargs['address']) - LOG.info(_LI('Deployment to node %s done'), node.uuid) - task.process_event('done') except Exception as e: LOG.error(_LE('Deploy failed for instance %(instance)s. ' 'Error: %(error)s'), {'instance': node.instance_uuid, 'error': e}) msg = _('Failed to continue iSCSI deployment.') deploy_utils.set_failed_state(task, msg) + else: + iscsi_deploy.finish_deploy(task, kwargs.get('address')) @task_manager.require_exclusive_lock def continue_deploy(self, task, **kwargs): @@ -648,7 +681,7 @@ class VendorPassthru(agent_base_vendor.BaseAgentVendor): root_uuid_or_disk_id = uuid_dict.get( 'root uuid', uuid_dict.get('disk identifier')) pxe_config_path = pxe_utils.get_pxe_config_file_path(node.uuid) - boot_mode = driver_utils.get_boot_mode_for_deploy(node) + boot_mode = deploy_utils.get_boot_mode_for_deploy(node) deploy_utils.switch_pxe_config(pxe_config_path, root_uuid_or_disk_id, boot_mode, is_whole_disk_image) diff --git a/ironic/drivers/utils.py b/ironic/drivers/utils.py index 9c34a49ac..7caa6cabe 100644 --- a/ironic/drivers/utils.py +++ b/ironic/drivers/utils.py @@ -144,33 +144,6 @@ def get_node_capability(node, capability): "Format should be 'key:val'."), node_capability) -def rm_node_capability(task, capability): - """Remove 'capability' from node's 'capabilities' property. - - :param task: Task object. - :param capability: Capability key. - - """ - node = task.node - properties = node.properties - capabilities = properties.get('capabilities') - - if not capabilities: - return - - caps = [] - for cap in capabilities.split(','): - parts = cap.split(':') - if len(parts) == 2 and parts[0] and parts[1]: - if parts[0] == capability: - continue - caps.append(cap) - new_cap_str = ",".join(caps) - properties['capabilities'] = new_cap_str if new_cap_str else None - node.properties = properties - node.save() - - def add_node_capability(task, capability, value): """Add 'capability' to node's 'capabilities' property. @@ -250,28 +223,3 @@ def validate_secure_boot_capability(node): """ validate_capability(node, 'secure_boot', ('true', 'false')) - - -def get_boot_mode_for_deploy(node): - """Returns the boot mode that would be used for deploy. - - This method returns deploy_boot_mode available in node field - boot_mode from 'capabilities' of node 'properties'. - Otherwise returns boot mode specified in node's 'instance_info'. - - :param node: an ironic node object. - :returns: Value of boot mode that would be used for deploy. - Possible values are 'bios', 'uefi'. - It would return None if boot mode is present neither - in 'capabilities' of node 'properties' nor in node's - 'instance_info'. - - """ - boot_mode = get_node_capability(node, 'boot_mode') - if boot_mode is None: - instance_info = node.instance_info - boot_mode = instance_info.get('deploy_boot_mode', None) - - LOG.debug('Deploy boot mode is %(boot_mode)s for %(node)s.', - {'boot_mode': boot_mode, 'node': node.uuid}) - return boot_mode diff --git a/ironic/locale/ironic-log-error.pot b/ironic/locale/ironic-log-error.pot index ec19ab67e..1e63a60d5 100644 --- a/ironic/locale/ironic-log-error.pot +++ b/ironic/locale/ironic-log-error.pot @@ -6,9 +6,9 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: ironic 2015.1.dev31\n" +"Project-Id-Version: ironic 2015.1.dev139\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2015-02-18 06:15+0000\n" +"POT-Creation-Date: 2015-04-08 06:27+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -26,40 +26,48 @@ msgstr "" msgid "Exception in string format operation" msgstr "" -#: ironic/common/images.py:132 +#: ironic/common/images.py:148 #, python-format msgid "vfat image creation failed. Error: %s" msgstr "" -#: ironic/common/images.py:200 +#: ironic/common/images.py:218 ironic/common/images.py:284 msgid "Creating the filesystem root failed." msgstr "" -#: ironic/common/images.py:214 +#: ironic/common/images.py:233 ironic/common/images.py:310 msgid "Creating ISO image failed." msgstr "" -#: ironic/common/service.py:89 +#: ironic/common/images.py:540 +msgid "mounting the deploy iso failed." +msgstr "" + +#: ironic/common/images.py:554 +msgid "examining the deploy iso failed." +msgstr "" + +#: ironic/common/service.py:92 #, python-format msgid "Service error occurred when stopping the RPC server. Error: %s" msgstr "" -#: ironic/common/service.py:94 +#: ironic/common/service.py:97 #, python-format msgid "Service error occurred when cleaning up the RPC manager. Error: %s" msgstr "" -#: ironic/common/utils.py:398 +#: ironic/common/utils.py:401 #, python-format msgid "Could not remove tmpdir: %s" msgstr "" -#: ironic/common/utils.py:429 +#: ironic/common/utils.py:432 #, python-format msgid "Failed to make file system. File system %s is not supported." msgstr "" -#: ironic/common/utils.py:433 +#: ironic/common/utils.py:436 #, python-format msgid "Failed to create a file system in %(path)s. Error: %(error)s" msgstr "" @@ -71,7 +79,7 @@ msgid "" "attempt %(attempt)s of %(num_attempts)s failed." msgstr "" -#: ironic/conductor/manager.py:224 +#: ironic/conductor/manager.py:256 #, python-format msgid "" "Conductor %s cannot be started because no drivers were loaded. This " @@ -79,110 +87,128 @@ msgid "" "option." msgstr "" -#: ironic/conductor/manager.py:1029 +#: ironic/conductor/manager.py:799 +#, python-format +msgid "Error in tear_down of node %(node)s: %(err)s" +msgstr "" + +#: ironic/conductor/manager.py:1284 #, python-format msgid "Failed to stop console while deleting the node %(node)s: %(err)s." msgstr "" -#: ironic/conductor/manager.py:1510 +#: ironic/conductor/manager.py:1911 #, python-format msgid "Unexpected state %(state)s returned while deploying node %(node)s." msgstr "" -#: ironic/conductor/manager.py:1637 +#: ironic/conductor/manager.py:2011 #, python-format msgid "" "Failed to change power state of node %(node)s to '%(state)s'. Attempts " "left: %(left)s." msgstr "" -#: ironic/dhcp/neutron.py:124 +#: ironic/conductor/manager.py:2043 +#, python-format +msgid "Failed to inspect node %(node)s: %(err)s" +msgstr "" + +#: ironic/dhcp/neutron.py:128 #, python-format msgid "Failed to update Neutron port %s." msgstr "" -#: ironic/dhcp/neutron.py:139 +#: ironic/dhcp/neutron.py:143 #, python-format msgid "Failed to update MAC address on Neutron port %s." msgstr "" -#: ironic/dhcp/neutron.py:206 +#: ironic/dhcp/neutron.py:216 #, python-format msgid "Failed to Get IP address on Neutron port %s." msgstr "" -#: ironic/dhcp/neutron.py:222 +#: ironic/dhcp/neutron.py:232 #, python-format msgid "Neutron returned invalid IPv4 address %s." msgstr "" -#: ironic/dhcp/neutron.py:226 +#: ironic/dhcp/neutron.py:236 #, python-format msgid "No IP address assigned to Neutron port %s." msgstr "" -#: ironic/drivers/base.py:407 +#: ironic/dhcp/neutron.py:379 +#, python-format +msgid "Failed to rollback cleaning port changes for node %s" +msgstr "" + +#: ironic/drivers/base.py:511 #, python-format msgid "vendor_passthru failed with method %s" msgstr "" -#: ironic/drivers/modules/agent_base_vendor.py:168 +#: ironic/drivers/modules/agent.py:188 #, python-format -msgid "Async exception for %(node)s: %(msg)s" +msgid "" +"Agent deploy supports only HTTP(S) URLs as instance_info['image_source']." +" Either %s is not a valid HTTP(S) URL or is not reachable." msgstr "" -#: ironic/drivers/modules/agent_base_vendor.py:282 +#: ironic/drivers/modules/agent_base_vendor.py:374 #, python-format msgid "Could not find matching node for the provided MACs %s." msgstr "" -#: ironic/drivers/modules/deploy_utils.py:354 +#: ironic/drivers/modules/deploy_utils.py:449 #, python-format msgid "" "Failed to erase beginning of disk for node %(node)s. Command: " "%(command)s. Error: %(error)s." msgstr "" -#: ironic/drivers/modules/deploy_utils.py:366 +#: ironic/drivers/modules/deploy_utils.py:461 #, python-format msgid "" "Failed to get disk block count for node %(node)s. Command: %(command)s. " "Error: %(error)s." msgstr "" -#: ironic/drivers/modules/deploy_utils.py:379 +#: ironic/drivers/modules/deploy_utils.py:474 #, python-format msgid "" "Failed to erase the end of the disk on node %(node)s. Command: " "%(command)s. Error: %(error)s." msgstr "" -#: ironic/drivers/modules/deploy_utils.py:530 -msgid "Failed to detect root device UUID." +#: ironic/drivers/modules/deploy_utils.py:646 +#, python-format +msgid "Failed to detect %s" msgstr "" -#: ironic/drivers/modules/deploy_utils.py:572 -#: ironic/drivers/modules/deploy_utils.py:578 +#: ironic/drivers/modules/deploy_utils.py:741 +#: ironic/drivers/modules/deploy_utils.py:747 #, python-format msgid "Deploy to address %s failed." msgstr "" -#: ironic/drivers/modules/deploy_utils.py:573 +#: ironic/drivers/modules/deploy_utils.py:742 #, python-format msgid "Command: %s" msgstr "" -#: ironic/drivers/modules/deploy_utils.py:574 +#: ironic/drivers/modules/deploy_utils.py:743 #, python-format msgid "StdOut: %r" msgstr "" -#: ironic/drivers/modules/deploy_utils.py:575 +#: ironic/drivers/modules/deploy_utils.py:744 #, python-format msgid "StdErr: %r" msgstr "" -#: ironic/drivers/modules/deploy_utils.py:659 +#: ironic/drivers/modules/deploy_utils.py:832 #, python-format msgid "" "Node %s failed to power off while handling deploy failure. This may be a " @@ -190,56 +216,74 @@ msgid "" "maintenance mode until the problem is resolved." msgstr "" -#: ironic/drivers/modules/ipminative.py:263 +#: ironic/drivers/modules/discoverd.py:160 +#, python-format +msgid "" +"Exception during contacting ironic-discoverd for inspection of node " +"%(node)s: %(err)s" +msgstr "" + +#: ironic/drivers/modules/discoverd.py:191 +#, python-format +msgid "" +"Unexpected exception while getting inspection status for node %s, will " +"retry later" +msgstr "" + +#: ironic/drivers/modules/discoverd.py:197 +#, python-format +msgid "Inspection failed for node %(uuid)s with error: %(err)s" +msgstr "" + +#: ironic/drivers/modules/ipminative.py:268 #, python-format msgid "" "IPMI get sensor data failed for node %(node_id)s with the following " "error: %(error)s" msgstr "" -#: ironic/drivers/modules/ipminative.py:414 +#: ironic/drivers/modules/ipminative.py:419 #, python-format msgid "" "IPMI set boot device failed for node %(node_id)s with the following " "error: %(error)s" msgstr "" -#: ironic/drivers/modules/ipminative.py:449 +#: ironic/drivers/modules/ipminative.py:454 #, python-format msgid "" "IPMI get boot device failed for node %(node_id)s with the following " "error: %(error)s" msgstr "" -#: ironic/drivers/modules/ipmitool.py:413 +#: ironic/drivers/modules/ipmitool.py:424 #, python-format msgid "" "IPMI power %(state)s timed out after %(tries)s retries on node " "%(node_id)s." msgstr "" -#: ironic/drivers/modules/ipmitool.py:573 +#: ironic/drivers/modules/ipmitool.py:584 #, python-format msgid "IPMI \"raw bytes\" failed for node %(node_id)s with error: %(error)s." msgstr "" -#: ironic/drivers/modules/ipmitool.py:879 +#: ironic/drivers/modules/ipmitool.py:890 #, python-format msgid "IPMI \"bmc reset\" failed for node %(node_id)s with error: %(error)s." msgstr "" -#: ironic/drivers/modules/iscsi_deploy.py:266 +#: ironic/drivers/modules/iscsi_deploy.py:610 ironic/drivers/modules/pxe.py:635 +#: ironic/drivers/modules/ilo/deploy.py:833 #, python-format -msgid "Error returned from deploy ramdisk: %s" +msgid "Deploy failed for instance %(instance)s. Error: %(error)s" msgstr "" -#: ironic/drivers/modules/iscsi_deploy.py:279 ironic/drivers/modules/pxe.py:515 -#: ironic/drivers/modules/ilo/deploy.py:525 -#, python-format -msgid "Deploy failed for instance %(instance)s. Error: %(error)s" +#: ironic/drivers/modules/pxe.py:250 +msgid "Whole disk image with netboot is not supported in UEFI boot mode." msgstr "" -#: ironic/drivers/modules/pxe.py:328 +#: ironic/drivers/modules/pxe.py:365 msgid "UEFI boot mode is not supported with iPXE boot enabled." msgstr "" @@ -281,8 +325,8 @@ msgstr "" #: ironic/drivers/modules/virtualbox.py:160 #, python-format msgid "" -"Failed while creating a VirtualMachine object for node %(node)s. Error: " -"%(error)s." +"Failed while creating a VirtualMachine object for node %(node_id)s. " +"Error: %(error)s." msgstr "" #: ironic/drivers/modules/virtualbox.py:176 @@ -305,6 +349,42 @@ msgstr "" msgid "'set_boot_device' failed for node %(node_id)s with error: %(error)s" msgstr "" +#: ironic/drivers/modules/amt/common.py:105 +#, python-format +msgid "Call to AMT with URI %(uri)s failed: got Fault %(fault)s" +msgstr "" + +#: ironic/drivers/modules/amt/common.py:129 +#, python-format +msgid "" +"Call to AMT with URI %(uri)s and method %(method)s failed: return value " +"was %(value)s" +msgstr "" + +#: ironic/drivers/modules/amt/management.py:62 +#, python-format +msgid "" +"Failed to set boot device %(boot_device)s for node %(node_id)s with " +"error: %(error)s." +msgstr "" + +#: ironic/drivers/modules/amt/management.py:95 +#, python-format +msgid "Failed to enable boot config for node %(node_id)s with error: %(error)s." +msgstr "" + +#: ironic/drivers/modules/amt/power.py:112 +#, python-format +msgid "" +"Failed to set power state %(state)s for node %(node_id)s with error: " +"%(error)s." +msgstr "" + +#: ironic/drivers/modules/amt/power.py:136 +#, python-format +msgid "Failed to get power state for node %(node_id)s with error: %(error)s." +msgstr "" + #: ironic/drivers/modules/drac/management.py:82 #, python-format msgid "" @@ -361,59 +441,67 @@ msgid "" "%(target_power_state)s. Reason: %(error)s." msgstr "" -#: ironic/drivers/modules/ilo/common.py:412 +#: ironic/drivers/modules/ilo/common.py:450 #, python-format msgid "Error while deleting %(object_name)s from %(container)s. Error: %(error)s" msgstr "" -#: ironic/drivers/modules/ilo/common.py:422 +#: ironic/drivers/modules/ilo/common.py:460 #, python-format msgid "" "Error while ejecting virtual media %(device)s from node %(uuid)s. Error: " "%(error)s" msgstr "" -#: ironic/drivers/modules/ilo/deploy.py:109 +#: ironic/drivers/modules/ilo/deploy.py:122 #, python-format msgid "" -"Unable to find boot_iso in Glance, required to deploy node %(node)s in " -"UEFI boot mode." +"Virtual media deploy accepts only Glance images or HTTP(S) URLs as " +"instance_info['ilo_boot_iso']. Either %s is not a valid HTTP(S) URL or is" +" not reachable." msgstr "" -#: ironic/drivers/modules/ilo/deploy.py:115 +#: ironic/drivers/modules/ilo/deploy.py:149 #, python-format msgid "" -"Unable to find 'kernel_id' and 'ramdisk_id' in Glance image %(image)s for" -" generating boot ISO for %(node)s" +"Unable to find kernel or ramdisk for image %(image)s to generate boot ISO" +" for %(node)s" msgstr "" -#: ironic/drivers/modules/ilo/deploy.py:156 +#: ironic/drivers/modules/ilo/deploy.py:197 #, python-format msgid "Failed to clean up boot ISO for %(node)s.Error: %(error)s." msgstr "" -#: ironic/drivers/modules/ilo/deploy.py:509 +#: ironic/drivers/modules/ilo/deploy.py:741 #, python-format msgid "Cannot get boot ISO for node %s" msgstr "" -#: ironic/drivers/modules/ilo/power.py:85 +#: ironic/drivers/modules/ilo/power.py:92 #, python-format msgid "iLO get_power_state failed for node %(node_id)s with error: %(error)s." msgstr "" -#: ironic/drivers/modules/ilo/power.py:157 +#: ironic/drivers/modules/ilo/power.py:164 #, python-format msgid "" "iLO set_power_state failed to set state to %(tstate)s for node " "%(node_id)s with error: %(error)s" msgstr "" -#: ironic/drivers/modules/ilo/power.py:170 +#: ironic/drivers/modules/ilo/power.py:177 #, python-format msgid "iLO failed to change state to %(tstate)s within %(timeout)s sec" msgstr "" +#: ironic/drivers/modules/irmc/management.py:60 +#, python-format +msgid "" +"SCCI get sensor data failed for node %(node_id)s with the following " +"error: %(error)s" +msgstr "" + #: ironic/drivers/modules/irmc/power.py:65 #, python-format msgid "" @@ -431,16 +519,6 @@ msgstr "" msgid "Unable to instantiate unregistered object type %(objtype)s" msgstr "" -#: ironic/openstack/common/excutils.py:76 -#, python-format -msgid "Original exception being dropped: %s" -msgstr "" - -#: ironic/openstack/common/excutils.py:105 -#, python-format -msgid "Unexpected exception occurred %d time(s)... retrying." -msgstr "" - #: ironic/openstack/common/loopingcall.py:95 msgid "in fixed duration looping call" msgstr "" @@ -454,21 +532,11 @@ msgstr "" msgid "Error during %(full_task_name)s: %(e)s" msgstr "" -#: ironic/openstack/common/policy.py:563 ironic/openstack/common/policy.py:843 -#, python-format -msgid "Failed to understand rule %s" -msgstr "" - -#: ironic/openstack/common/policy.py:573 -#, python-format -msgid "No handler for matches of kind %s" -msgstr "" - -#: ironic/openstack/common/service.py:269 +#: ironic/openstack/common/service.py:276 msgid "Unhandled exception" msgstr "" -#: ironic/tests/db/sqlalchemy/test_migrations.py:174 +#: ironic/tests/db/sqlalchemy/test_migrations.py:168 #, python-format msgid "Failed to migrate to version %(version)s on engine %(engine)s" msgstr "" diff --git a/ironic/locale/ironic-log-info.pot b/ironic/locale/ironic-log-info.pot index 1316e7925..7472171e5 100644 --- a/ironic/locale/ironic-log-info.pot +++ b/ironic/locale/ironic-log-info.pot @@ -6,9 +6,9 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: ironic 2015.1.dev15\n" +"Project-Id-Version: ironic 2015.1.dev139\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2015-02-13 06:14+0000\n" +"POT-Creation-Date: 2015-04-08 06:27+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -31,115 +31,235 @@ msgstr "" msgid "Loaded the following drivers: %s" msgstr "" -#: ironic/common/service.py:80 +#: ironic/common/service.py:83 #, python-format msgid "Created RPC server for service %(service)s on host %(host)s." msgstr "" -#: ironic/common/service.py:98 +#: ironic/common/service.py:101 #, python-format msgid "Stopped RPC server for service %(service)s on host %(host)s." msgstr "" -#: ironic/conductor/manager.py:260 +#: ironic/common/service.py:106 #, python-format -msgid "Successfuly started conductor with hostname %(hostname)s." +msgid "" +"Got signal SIGUSR1. Not deregistering on next shutdown of service " +"%(service)s on host %(host)s." +msgstr "" + +#: ironic/conductor/manager.py:292 +#, python-format +msgid "Successfully started conductor with hostname %(hostname)s." msgstr "" -#: ironic/conductor/manager.py:279 +#: ironic/conductor/manager.py:313 #, python-format msgid "Successfully stopped conductor with hostname %(hostname)s." msgstr "" -#: ironic/conductor/manager.py:827 +#: ironic/conductor/manager.py:319 +#, python-format +msgid "Not deregistering conductor with hostname %(hostname)s." +msgstr "" + +#: ironic/conductor/manager.py:807 +#, python-format +msgid "Successfully unprovisioned node %(node)s with instance %(instance)s." +msgstr "" + +#: ironic/conductor/manager.py:877 +#, python-format +msgid "" +"Cleaning is disabled, node %s has been successfully moved to AVAILABLE " +"state." +msgstr "" + +#: ironic/conductor/manager.py:936 +#, python-format +msgid "Executing %(state)s on node %(node)s, remaining steps: %(steps)s" +msgstr "" + +#: ironic/conductor/manager.py:946 +#, python-format +msgid "Executing %(step)s on node %(node)s" +msgstr "" + +#: ironic/conductor/manager.py:965 +#, python-format +msgid "" +"Clean step %(step)s on node %(node)s being executed asynchronously, " +"waiting for driver." +msgstr "" + +#: ironic/conductor/manager.py:975 +#, python-format +msgid "Node %(node)s finished clean step %(step)s" +msgstr "" + +#: ironic/conductor/manager.py:990 +#, python-format +msgid "Node %s cleaning complete" +msgstr "" + +#: ironic/conductor/manager.py:1085 #, python-format msgid "" "During sync_power_state, node %(node)s was not found and presumed deleted" " by another process." msgstr "" -#: ironic/conductor/manager.py:831 +#: ironic/conductor/manager.py:1089 #, python-format msgid "" "During sync_power_state, node %(node)s was already locked by another " "process. Skip." msgstr "" -#: ironic/conductor/manager.py:1026 +#: ironic/conductor/manager.py:1288 #, python-format msgid "Successfully deleted node %(node)s." msgstr "" -#: ironic/conductor/manager.py:1095 +#: ironic/conductor/manager.py:1307 #, python-format -msgid "No console action was triggered because the console is already %s" +msgid "" +"Successfully deleted port %(port)s. The node associated with the port was" +" %(node)s" msgstr "" -#: ironic/conductor/manager.py:1497 +#: ironic/conductor/manager.py:1378 #, python-format -msgid "Successfully deployed node %(node)s with instance %(instance)s." +msgid "No console action was triggered because the console is already %s" msgstr "" -#: ironic/conductor/manager.py:1526 +#: ironic/conductor/manager.py:1905 #, python-format -msgid "Successfully unprovisioned node %(node)s with instance %(instance)s." +msgid "Successfully deployed node %(node)s with instance %(instance)s." msgstr "" -#: ironic/conductor/manager.py:1601 +#: ironic/conductor/manager.py:1981 #, python-format msgid "" "During sync_power_state, node %(node)s has no previous known state. " "Recording current state '%(state)s'." msgstr "" +#: ironic/conductor/manager.py:2056 +#, python-format +msgid "Successfully inspected node %(node)s" +msgstr "" + #: ironic/conductor/utils.py:124 #, python-format -msgid "Succesfully set node %(node)s power state to %(state)s." +msgid "Successfully set node %(node)s power state to %(state)s." msgstr "" -#: ironic/drivers/modules/image_cache.py:128 +#: ironic/drivers/modules/agent_base_vendor.py:448 +#: ironic/drivers/modules/iscsi_deploy.py:628 +#, python-format +msgid "Deployment to node %s done" +msgstr "" + +#: ironic/drivers/modules/discoverd.py:71 +#, python-format +msgid "" +"Inspection via ironic-discoverd is disabled in configuration for driver " +"%s. To enable, change [discoverd] enabled = True." +msgstr "" + +#: ironic/drivers/modules/discoverd.py:169 +#, python-format +msgid "Node %s was sent to inspection to ironic-discoverd" +msgstr "" + +#: ironic/drivers/modules/discoverd.py:204 +#, python-format +msgid "Inspection finished successfully for node %s" +msgstr "" + +#: ironic/drivers/modules/image_cache.py:138 #, python-format msgid "Master cache miss for image %(uuid)s, starting download" msgstr "" -#: ironic/drivers/modules/image_cache.py:269 +#: ironic/drivers/modules/image_cache.py:279 #, python-format msgid "" "After cleaning up cache dir %(dir)s cache size %(actual)d is still larger" " than threshold %(expected)d" msgstr "" -#: ironic/drivers/modules/iscsi_deploy.py:272 +#: ironic/drivers/modules/amt/management.py:67 #, python-format -msgid "Continuing deployment for node %(node)s, params %(params)s" +msgid "Successfully set boot device %(boot_device)s for node %(node_id)s" msgstr "" -#: ironic/drivers/modules/pxe.py:478 ironic/drivers/modules/ilo/deploy.py:518 +#: ironic/drivers/modules/amt/management.py:99 #, python-format -msgid "Deployment to node %s done" +msgid "Successfully enabled boot config for node %(node_id)s." +msgstr "" + +#: ironic/drivers/modules/amt/power.py:117 +#, python-format +msgid "Power state set to %(state)s for node %(node_id)s" msgstr "" -#: ironic/drivers/modules/ilo/common.py:293 +#: ironic/drivers/modules/ilo/common.py:300 #, python-format msgid "Attached virtual media %s successfully." msgstr "" -#: ironic/drivers/modules/ilo/common.py:311 +#: ironic/drivers/modules/ilo/common.py:318 #, python-format msgid "Node %(uuid)s pending boot mode is %(boot_mode)s." msgstr "" -#: ironic/drivers/modules/ilo/common.py:323 +#: ironic/drivers/modules/ilo/common.py:330 #, python-format msgid "Node %(uuid)s boot mode is set to %(boot_mode)s." msgstr "" -#: ironic/drivers/modules/ilo/common.py:371 +#: ironic/drivers/modules/ilo/common.py:410 #, python-format msgid "Setting up node %s to boot from virtual media" msgstr "" -#: ironic/openstack/common/eventlet_backdoor.py:140 +#: ironic/drivers/modules/ilo/deploy.py:362 +#, python-format +msgid "Changed secure boot to %(mode)s for node %(node)s" +msgstr "" + +#: ironic/drivers/modules/ilo/inspect.py:57 +#, python-format +msgid "Port created for MAC address %(address)s for node %(node)s" +msgstr "" + +#: ironic/drivers/modules/ilo/inspect.py:254 +#, python-format +msgid "The node %s is not powered on. Powering on the node for inspection." +msgstr "" + +#: ironic/drivers/modules/ilo/inspect.py:293 +#, python-format +msgid "Node %s inspected." +msgstr "" + +#: ironic/drivers/modules/ilo/inspect.py:296 +#, python-format +msgid "" +"The node %s was powered on for inspection. Powered off the node as " +"inspection completed." +msgstr "" + +#: ironic/drivers/modules/ilo/management.py:252 +#, python-format +msgid "" +"Missing 'ilo_change_password' parameter in driver_info. Clean step " +"'reset_ilo_credential' is not performed on node %s." +msgstr "" + +#: ironic/openstack/common/eventlet_backdoor.py:146 #, python-format msgid "Eventlet backdoor listening on %(port)s for process %(pid)d" msgstr "" @@ -154,59 +274,54 @@ msgstr "" msgid "Skipping periodic task %(task)s because it is disabled" msgstr "" -#: ironic/openstack/common/policy.py:275 -#, python-format -msgid "Can not find policy directory: %s" -msgstr "" - -#: ironic/openstack/common/service.py:174 +#: ironic/openstack/common/service.py:173 #, python-format msgid "Caught %s, exiting" msgstr "" -#: ironic/openstack/common/service.py:232 +#: ironic/openstack/common/service.py:239 msgid "Parent process has died unexpectedly, exiting" msgstr "" -#: ironic/openstack/common/service.py:263 +#: ironic/openstack/common/service.py:270 #, python-format msgid "Child caught %s, exiting" msgstr "" -#: ironic/openstack/common/service.py:302 +#: ironic/openstack/common/service.py:309 msgid "Forking too fast, sleeping" msgstr "" -#: ironic/openstack/common/service.py:321 +#: ironic/openstack/common/service.py:328 #, python-format msgid "Started child %d" msgstr "" -#: ironic/openstack/common/service.py:331 +#: ironic/openstack/common/service.py:338 #, python-format msgid "Starting %d workers" msgstr "" -#: ironic/openstack/common/service.py:348 +#: ironic/openstack/common/service.py:355 #, python-format msgid "Child %(pid)d killed by signal %(sig)d" msgstr "" -#: ironic/openstack/common/service.py:352 +#: ironic/openstack/common/service.py:359 #, python-format msgid "Child %(pid)s exited with status %(code)d" msgstr "" -#: ironic/openstack/common/service.py:391 +#: ironic/openstack/common/service.py:398 #, python-format msgid "Caught %s, stopping children" msgstr "" -#: ironic/openstack/common/service.py:400 +#: ironic/openstack/common/service.py:413 msgid "Wait called after thread killed. Cleaning up." msgstr "" -#: ironic/openstack/common/service.py:416 +#: ironic/openstack/common/service.py:429 #, python-format msgid "Waiting on %d children to exit" msgstr "" diff --git a/ironic/locale/ironic-log-warning.pot b/ironic/locale/ironic-log-warning.pot index 5c1982c39..c1c0126b8 100644 --- a/ironic/locale/ironic-log-warning.pot +++ b/ironic/locale/ironic-log-warning.pot @@ -6,9 +6,9 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: ironic 2015.1.dev31\n" +"Project-Id-Version: ironic 2015.1.dev139\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2015-02-18 06:15+0000\n" +"POT-Creation-Date: 2015-04-08 06:27+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -29,100 +29,100 @@ msgid "" "expected format: %(line)s" msgstr "" -#: ironic/common/utils.py:445 +#: ironic/common/utils.py:448 #, python-format msgid "Failed to unlink %(path)s, error: %(e)s" msgstr "" -#: ironic/common/utils.py:454 +#: ironic/common/utils.py:457 #, python-format msgid "Failed to remove dir %(path)s, error: %(e)s" msgstr "" -#: ironic/common/utils.py:470 +#: ironic/common/utils.py:473 #, python-format msgid "Failed to create symlink from %(source)s to %(link)s, error: %(e)s" msgstr "" -#: ironic/common/utils.py:484 +#: ironic/common/utils.py:487 #, python-format msgid "" "Failed to remove trailing character. Returning original object. Supplied " "object is not a string: %s," msgstr "" -#: ironic/conductor/manager.py:249 +#: ironic/conductor/manager.py:281 #, python-format msgid "" "A conductor with hostname %(hostname)s was previously registered. " "Updating registration" msgstr "" -#: ironic/conductor/manager.py:315 +#: ironic/conductor/manager.py:353 msgid "Conductor could not connect to database while heartbeating." msgstr "" -#: ironic/conductor/manager.py:446 +#: ironic/conductor/manager.py:484 msgid "" "Drivers implementing their own version of vendor_passthru() has been " "deprecated. Please update the code to use the @passthru decorator." msgstr "" -#: ironic/conductor/manager.py:539 +#: ironic/conductor/manager.py:577 msgid "" "Drivers implementing their own version of driver_vendor_passthru() has " "been deprecated. Please update the code to use the @driver_passthru " "decorator." msgstr "" -#: ironic/conductor/manager.py:1164 +#: ironic/conductor/manager.py:1440 #, python-format msgid "" "No VIF found for instance %(instance)s port %(port)s when attempting to " "update port MAC address." msgstr "" -#: ironic/conductor/manager.py:1221 +#: ironic/conductor/manager.py:1492 #, python-format msgid "" "get_sensors_data is not implemented for driver %(driver)s, node_uuid is " "%(node)s" msgstr "" -#: ironic/conductor/manager.py:1225 +#: ironic/conductor/manager.py:1496 #, python-format msgid "" "During get_sensors_data, could not parse sensor data for node %(node)s. " "Error: %(err)s." msgstr "" -#: ironic/conductor/manager.py:1229 +#: ironic/conductor/manager.py:1500 #, python-format msgid "" "During get_sensors_data, could not get sensor data for node %(node)s. " "Error: %(err)s." msgstr "" -#: ironic/conductor/manager.py:1233 +#: ironic/conductor/manager.py:1504 #, python-format msgid "" "During send_sensor_data, node %(node)s was not found and presumed deleted" " by another process." msgstr "" -#: ironic/conductor/manager.py:1237 +#: ironic/conductor/manager.py:1508 #, python-format msgid "Failed to get sensor data for node %(node)s. Error: %(error)s" msgstr "" -#: ironic/conductor/manager.py:1378 +#: ironic/conductor/manager.py:1779 #, python-format msgid "" "No free conductor workers available to perform an action on node " "%(node)s, setting node's power state back to %(power_state)s." msgstr "" -#: ironic/conductor/manager.py:1406 +#: ironic/conductor/manager.py:1807 #, python-format msgid "" "No free conductor workers available to perform an action on node " @@ -130,41 +130,36 @@ msgid "" "target_provision_state to %(tgt_prov_state)s." msgstr "" -#: ironic/conductor/manager.py:1474 +#: ironic/conductor/manager.py:1875 #, python-format msgid "Error while uploading the configdrive for %(node)s to Swift" msgstr "" -#: ironic/conductor/manager.py:1484 +#: ironic/conductor/manager.py:1885 #, python-format msgid "Error while preparing to deploy to node %(node)s: %(err)s" msgstr "" -#: ironic/conductor/manager.py:1493 +#: ironic/conductor/manager.py:1894 #, python-format msgid "Error in deploy of node %(node)s: %(err)s" msgstr "" -#: ironic/conductor/manager.py:1525 -#, python-format -msgid "Error in tear_down of node %(node)s: %(err)s" -msgstr "" - -#: ironic/conductor/manager.py:1598 +#: ironic/conductor/manager.py:1971 #, python-format msgid "" "During sync_power_state, could not get power state for node %(node)s. " "Error: %(err)s." msgstr "" -#: ironic/conductor/manager.py:1625 +#: ironic/conductor/manager.py:1999 #, python-format msgid "" "During sync_power_state, node %(node)s state '%(actual)s' does not match " "expected state. Changing hardware state to '%(state)s'." msgstr "" -#: ironic/conductor/manager.py:1643 +#: ironic/conductor/manager.py:2017 #, python-format msgid "" "During sync_power_state, node %(node)s state does not match expected " @@ -188,24 +183,24 @@ msgstr "" msgid "Driver returns ERROR power state for node %s." msgstr "" -#: ironic/db/sqlalchemy/api.py:583 +#: ironic/db/sqlalchemy/api.py:584 #, python-format msgid "Cleared reservations held by %(hostname)s: %(nodes)s" msgstr "" -#: ironic/dhcp/neutron.py:179 +#: ironic/dhcp/neutron.py:189 #, python-format msgid "" "Some errors were encountered when updating the DHCP BOOT options for node" " %(node)s on the following ports: %(ports)s." msgstr "" -#: ironic/dhcp/neutron.py:243 +#: ironic/dhcp/neutron.py:253 #, python-format msgid "No VIFs found for node %(node)s when attempting to get port IP address." msgstr "" -#: ironic/dhcp/neutron.py:272 +#: ironic/dhcp/neutron.py:282 #, python-format msgid "" "Some errors were encountered on node %(node)s while retrieving IP address" @@ -217,12 +212,12 @@ msgstr "" msgid "Ignoring malformed capability '%s'. Format should be 'key:val'." msgstr "" -#: ironic/drivers/modules/agent_base_vendor.py:259 +#: ironic/drivers/modules/agent_base_vendor.py:351 #, python-format msgid "Malformed MAC: %s" msgstr "" -#: ironic/drivers/modules/agent_base_vendor.py:302 +#: ironic/drivers/modules/agent_base_vendor.py:394 #, python-format msgid "MAC address %s not found in database" msgstr "" @@ -239,6 +234,13 @@ msgstr "" msgid "No console pid found for node %s while trying to stop shellinabox console." msgstr "" +#: ironic/drivers/modules/deploy_utils.py:974 +#, python-format +msgid "" +"ipmitool is unable to set boot device while the node %s is in UEFI boot " +"mode. Please set the boot device manually." +msgstr "" + #: ironic/drivers/modules/iboot.py:113 #, python-format msgid "" @@ -246,86 +248,100 @@ msgid "" "get_relays() failed." msgstr "" -#: ironic/drivers/modules/image_cache.py:194 +#: ironic/drivers/modules/image_cache.py:204 #, python-format msgid "" "Cache clean up was unable to reclaim %(required)d MiB of disk space, " "still %(left)d MiB required" msgstr "" -#: ironic/drivers/modules/image_cache.py:221 -#: ironic/drivers/modules/image_cache.py:260 +#: ironic/drivers/modules/image_cache.py:231 +#: ironic/drivers/modules/image_cache.py:270 #, python-format msgid "Unable to delete file %(name)s from master image cache: %(exc)s" msgstr "" -#: ironic/drivers/modules/ipminative.py:133 +#: ironic/drivers/modules/ipminative.py:138 #, python-format msgid "" "IPMI power on failed for node %(node_id)s with the following error: " "%(error)s" msgstr "" -#: ironic/drivers/modules/ipminative.py:163 +#: ironic/drivers/modules/ipminative.py:168 #, python-format msgid "" "IPMI power off failed for node %(node_id)s with the following error: " "%(error)s" msgstr "" -#: ironic/drivers/modules/ipminative.py:195 +#: ironic/drivers/modules/ipminative.py:200 #, python-format msgid "" "IPMI power reboot failed for node %(node_id)s with the following error: " "%(error)s" msgstr "" -#: ironic/drivers/modules/ipminative.py:230 +#: ironic/drivers/modules/ipminative.py:235 #, python-format msgid "" "IPMI get power state failed for node %(node_id)s with the following " "error: %(error)s" msgstr "" -#: ironic/drivers/modules/ipminative.py:244 +#: ironic/drivers/modules/ipminative.py:249 #, python-format msgid "" "IPMI get power state for node %(node_id)s returns the following details: " "%(detail)s" msgstr "" -#: ironic/drivers/modules/ipmitool.py:402 +#: ironic/drivers/modules/ipmitool.py:413 #, python-format msgid "IPMI power %(state)s failed for node %(node)s." msgstr "" -#: ironic/drivers/modules/ipmitool.py:467 +#: ironic/drivers/modules/ipmitool.py:478 #, python-format msgid "IPMI power status failed for node %(node_id)s with error: %(error)s." msgstr "" -#: ironic/drivers/modules/ipmitool.py:742 +#: ironic/drivers/modules/ipmitool.py:753 #, python-format msgid "" "IPMI set boot device failed for node %(node)s when executing \"ipmitool " "%(cmd)s\". Error: %(error)s" msgstr "" -#: ironic/drivers/modules/ipmitool.py:773 +#: ironic/drivers/modules/ipmitool.py:784 #, python-format msgid "" "IPMI get boot device failed for node %(node)s when executing \"ipmitool " "%(cmd)s\". Error: %(error)s" msgstr "" -#: ironic/drivers/modules/pxe.py:282 +#: ironic/drivers/modules/pxe.py:132 #, python-format msgid "" -"ipmitool is unable to set boot device while the node %s is in UEFI boot " -"mode. Please set the boot device manually." +"The \"%(old_param)s\" parameter is deprecated. Please update the node " +"%(node)s to use \"%(new_param)s\" instead." +msgstr "" + +#: ironic/drivers/modules/pxe.py:474 +#, python-format +msgid "" +"The UUID for the root partition can't be found, unable to switch the pxe " +"config from deployment mode to service (boot) mode for node %(node)s" +msgstr "" + +#: ironic/drivers/modules/pxe.py:479 +#, python-format +msgid "" +"The disk id for the whole disk image can't be found, unable to switch the" +" pxe config from deployment mode to service (boot) mode for node %(node)s" msgstr "" -#: ironic/drivers/modules/pxe.py:429 +#: ironic/drivers/modules/pxe.py:504 #, python-format msgid "Could not get image info to clean up images for node %(node)s: %(err)s" msgstr "" @@ -364,6 +380,46 @@ msgid "" " support this operation" msgstr "" +#: ironic/drivers/modules/amt/power.py:179 +#, python-format +msgid "" +"AMT failed to set power state %(state)s after %(tries)s retries on node " +"%(node_id)s." +msgstr "" + +#: ironic/drivers/modules/amt/power.py:189 +#, python-format +msgid "" +"AMT set power state %(state)s for node %(node)s - Attempt %(attempt)s " +"times of %(max_attempt)s failed." +msgstr "" + +#: ironic/drivers/modules/drac/client.py:73 +#, python-format +msgid "" +"Empty response on calling %(action)s on client. Last error (cURL error " +"code): %(last_error)s, fault string: \"%(fault_string)s\" response_code: " +"%(response_code)s. Retry attempt %(count)d" +msgstr "" + +#: ironic/drivers/modules/ilo/deploy.py:456 +#: ironic/drivers/modules/ilo/deploy.py:536 +#, python-format +msgid "Secure boot mode is not supported for node %s" +msgstr "" + +#: ironic/drivers/modules/ilo/inspect.py:60 +#, python-format +msgid "Port already exists for MAC address %(address)s for node %(node)s" +msgstr "" + +#: ironic/drivers/modules/ilo/management.py:98 +#, python-format +msgid "" +"'%(step)s' clean step is not supported on node %(uuid)s. Skipping the " +"clean step." +msgstr "" + #: ironic/nova/scheduler/ironic_host_manager.py:35 msgid "" "This class (ironic.nova.scheduler.ironic_host_manager.IronicHostManager) " @@ -381,22 +437,10 @@ msgstr "" #: ironic/openstack/common/loopingcall.py:87 #, python-format -msgid "task %(func_name)s run outlasted interval by %(delay).2f sec" -msgstr "" - -#: ironic/openstack/common/network_utils.py:149 -msgid "tcp_keepidle not available on your system" -msgstr "" - -#: ironic/openstack/common/network_utils.py:156 -msgid "tcp_keepintvl not available on your system" -msgstr "" - -#: ironic/openstack/common/network_utils.py:163 -msgid "tcp_keepknt not available on your system" +msgid "task %(func_name)r run outlasted interval by %(delay).2f sec" msgstr "" -#: ironic/openstack/common/service.py:356 +#: ironic/openstack/common/service.py:363 #, python-format msgid "pid %d not in child list" msgstr "" diff --git a/ironic/locale/ironic.pot b/ironic/locale/ironic.pot index bfd7b3f3e..38f3bff0e 100644 --- a/ironic/locale/ironic.pot +++ b/ironic/locale/ironic.pot @@ -6,9 +6,9 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: ironic 2015.1.dev31\n" +"Project-Id-Version: ironic 2015.1.dev139\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2015-02-18 06:14+0000\n" +"POT-Creation-Date: 2015-04-08 06:27+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -17,96 +17,105 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 1.3\n" -#: ironic/api/controllers/base.py:92 -msgid "Invalid value for X-OpenStack-Ironic-API-Version header." +#: ironic/api/controllers/base.py:102 +#, python-format +msgid "Invalid value for %s header" msgstr "" -#: ironic/api/controllers/v1/__init__.py:164 +#: ironic/api/controllers/v1/__init__.py:173 #, python-format msgid "" "Mutually exclusive versions requested. Version %(ver)s requested but not " -"supported by this service." +"supported by this service. The supported version range is: [%(min)s, " +"%(max)s]." msgstr "" -#: ironic/api/controllers/v1/__init__.py:170 +#: ironic/api/controllers/v1/__init__.py:180 #, python-format msgid "" -"Unsupported minor version requested. This API service supports the " -"following version range: [%(min)s, %(max)s]." +"Version %(ver)s was requested but the minor version is not supported by " +"this service. The supported version range is: [%(min)s, %(max)s]." msgstr "" #: ironic/api/controllers/v1/driver.py:146 -#: ironic/api/controllers/v1/node.py:716 +#: ironic/api/controllers/v1/node.py:703 msgid "Method not specified" msgstr "" -#: ironic/api/controllers/v1/node.py:423 +#: ironic/api/controllers/v1/node.py:402 #, python-format msgid "Adding a config drive is only supported when setting provision state to %s" msgstr "" -#: ironic/api/controllers/v1/node.py:446 +#: ironic/api/controllers/v1/node.py:428 #, python-format msgid "The requested action \"%(action)s\" could not be understood." msgstr "" -#: ironic/api/controllers/v1/node.py:801 +#: ironic/api/controllers/v1/node.py:788 msgid "Chassis id not specified." msgstr "" -#: ironic/api/controllers/v1/node.py:975 +#: ironic/api/controllers/v1/node.py:963 #, python-format msgid "Cannot create node with invalid name %(name)s" msgstr "" -#: ironic/api/controllers/v1/node.py:1003 +#: ironic/api/controllers/v1/node.py:1002 #, python-format msgid "Node %s can not be updated while a state transition is in progress." msgstr "" -#: ironic/api/controllers/v1/node.py:1013 +#: ironic/api/controllers/v1/node.py:1012 #, python-format msgid "Node %(node)s: Cannot change name to invalid name '%(name)s'" msgstr "" -#: ironic/api/controllers/v1/port.py:182 -msgid "Node id not specified." +#: ironic/api/controllers/v1/node.py:1060 +#, python-format +msgid "" +"Node %s can not update the driver while the console is enabled. Please " +"stop the console first." msgstr "" -#: ironic/api/controllers/v1/types.py:171 +#: ironic/api/controllers/v1/port.py:183 +msgid "Node identifier not specified." +msgstr "" + +#: ironic/api/controllers/v1/types.py:173 #, python-format msgid "%s is not JSON serializable" msgstr "" -#: ironic/api/controllers/v1/types.py:222 +#: ironic/api/controllers/v1/types.py:224 #, python-format msgid "'%s' is an internal attribute and can not be updated" msgstr "" -#: ironic/api/controllers/v1/types.py:226 +#: ironic/api/controllers/v1/types.py:228 #, python-format msgid "'%s' is a mandatory attribute and can not be removed" msgstr "" -#: ironic/api/controllers/v1/types.py:231 +#: ironic/api/controllers/v1/types.py:233 msgid "'add' and 'replace' operations needs value" msgstr "" -#: ironic/api/controllers/v1/utils.py:32 +#: ironic/api/controllers/v1/utils.py:38 msgid "Limit must be positive" msgstr "" -#: ironic/api/controllers/v1/utils.py:39 +#: ironic/api/controllers/v1/utils.py:45 #, python-format msgid "Invalid sort direction: %s. Acceptable values are 'asc' or 'desc'" msgstr "" -#: ironic/api/controllers/v1/utils.py:49 +#: ironic/api/controllers/v1/utils.py:55 #, python-format msgid "Adding a new attribute (%s) to the root of the resource is not allowed" msgstr "" -#: ironic/api/middleware/auth_token.py:41 +#: ironic/api/middleware/auth_token.py:43 #, python-format msgid "Cannot compile public API routes: %s" msgstr "" @@ -134,510 +143,551 @@ msgstr "" msgid "An unknown exception occurred." msgstr "" -#: ironic/common/exception.py:99 +#: ironic/common/exception.py:106 msgid "Not authorized." msgstr "" -#: ironic/common/exception.py:104 +#: ironic/common/exception.py:111 msgid "Operation not permitted." msgstr "" -#: ironic/common/exception.py:108 +#: ironic/common/exception.py:115 msgid "Unacceptable parameters." msgstr "" -#: ironic/common/exception.py:113 +#: ironic/common/exception.py:120 msgid "Conflict." msgstr "" -#: ironic/common/exception.py:118 +#: ironic/common/exception.py:125 msgid "Resource temporarily unavailable, please retry." msgstr "" -#: ironic/common/exception.py:124 +#: ironic/common/exception.py:131 msgid "Request not acceptable." msgstr "" -#: ironic/common/exception.py:129 +#: ironic/common/exception.py:136 msgid "Invalid resource state." msgstr "" -#: ironic/common/exception.py:133 +#: ironic/common/exception.py:140 #, python-format msgid "A node with UUID %(uuid)s already exists." msgstr "" -#: ironic/common/exception.py:137 +#: ironic/common/exception.py:144 #, python-format msgid "A port with MAC address %(mac)s already exists." msgstr "" -#: ironic/common/exception.py:141 +#: ironic/common/exception.py:148 #, python-format msgid "A chassis with UUID %(uuid)s already exists." msgstr "" -#: ironic/common/exception.py:145 +#: ironic/common/exception.py:152 #, python-format msgid "A port with UUID %(uuid)s already exists." msgstr "" -#: ironic/common/exception.py:149 +#: ironic/common/exception.py:156 #, python-format msgid "" "Instance %(instance_uuid)s is already associated with a node, it cannot " "be associated with this other node %(node)s" msgstr "" -#: ironic/common/exception.py:154 +#: ironic/common/exception.py:161 #, python-format msgid "A node with name %(name)s already exists." msgstr "" -#: ironic/common/exception.py:158 +#: ironic/common/exception.py:165 #, python-format msgid "Expected a uuid but received %(uuid)s." msgstr "" -#: ironic/common/exception.py:162 +#: ironic/common/exception.py:169 #, python-format msgid "Expected a logical name or uuid but received %(name)s." msgstr "" -#: ironic/common/exception.py:166 +#: ironic/common/exception.py:173 #, python-format msgid "Expected a logical name but received %(name)s." msgstr "" -#: ironic/common/exception.py:170 +#: ironic/common/exception.py:177 #, python-format msgid "Expected an uuid or int but received %(identity)s." msgstr "" -#: ironic/common/exception.py:174 +#: ironic/common/exception.py:181 #, python-format msgid "Expected a MAC address but received %(mac)s." msgstr "" -#: ironic/common/exception.py:178 +#: ironic/common/exception.py:185 #, python-format msgid "" "The requested action \"%(action)s\" can not be performed on node " "\"%(node)s\" while it is in state \"%(state)s\"." msgstr "" -#: ironic/common/exception.py:183 +#: ironic/common/exception.py:190 #, python-format msgid "Couldn't apply patch '%(patch)s'. Reason: %(reason)s" msgstr "" -#: ironic/common/exception.py:187 +#: ironic/common/exception.py:194 #, python-format msgid "Failed to deploy instance: %(reason)s" msgstr "" -#: ironic/common/exception.py:191 ironic/common/exception.py:195 +#: ironic/common/exception.py:198 ironic/common/exception.py:202 #, python-format msgid "Image %(image_id)s is unacceptable: %(reason)s" msgstr "" -#: ironic/common/exception.py:201 ironic/common/exception.py:205 +#: ironic/common/exception.py:208 ironic/common/exception.py:212 #, python-format msgid "%(err)s" msgstr "" -#: ironic/common/exception.py:209 +#: ironic/common/exception.py:216 msgid "Resource already exists." msgstr "" -#: ironic/common/exception.py:213 +#: ironic/common/exception.py:220 msgid "Resource could not be found." msgstr "" -#: ironic/common/exception.py:218 +#: ironic/common/exception.py:225 #, python-format msgid "Failed to load DHCP provider %(dhcp_provider_name)s." msgstr "" -#: ironic/common/exception.py:222 +#: ironic/common/exception.py:229 #, python-format msgid "Could not find the following driver(s): %(driver_name)s." msgstr "" -#: ironic/common/exception.py:226 +#: ironic/common/exception.py:233 #, python-format msgid "Image %(image_id)s could not be found." msgstr "" -#: ironic/common/exception.py:230 +#: ironic/common/exception.py:237 #, python-format msgid "No valid host was found. Reason: %(reason)s" msgstr "" -#: ironic/common/exception.py:234 +#: ironic/common/exception.py:241 #, python-format msgid "Instance %(instance)s could not be found." msgstr "" -#: ironic/common/exception.py:238 +#: ironic/common/exception.py:245 #, python-format msgid "Node %(node)s could not be found." msgstr "" -#: ironic/common/exception.py:242 +#: ironic/common/exception.py:249 #, python-format msgid "Node %(node)s is associated with instance %(instance)s." msgstr "" -#: ironic/common/exception.py:246 +#: ironic/common/exception.py:253 #, python-format msgid "Port %(port)s could not be found." msgstr "" -#: ironic/common/exception.py:250 +#: ironic/common/exception.py:257 #, python-format msgid "Update DHCP options on port: %(port_id)s failed." msgstr "" -#: ironic/common/exception.py:254 +#: ironic/common/exception.py:261 #, python-format msgid "Retrieve IP address on port: %(port_id)s failed." msgstr "" -#: ironic/common/exception.py:258 +#: ironic/common/exception.py:265 #, python-format msgid "Invalid IPv4 address %(ip_address)s." msgstr "" -#: ironic/common/exception.py:262 +#: ironic/common/exception.py:269 #, python-format msgid "Update MAC address on port: %(port_id)s failed." msgstr "" -#: ironic/common/exception.py:266 +#: ironic/common/exception.py:273 #, python-format msgid "Chassis %(chassis)s could not be found." msgstr "" -#: ironic/common/exception.py:270 +#: ironic/common/exception.py:277 #, python-format msgid "Conductor %(conductor)s cannot be started because no drivers were loaded." msgstr "" -#: ironic/common/exception.py:275 +#: ironic/common/exception.py:282 #, python-format msgid "Conductor %(conductor)s could not be found." msgstr "" -#: ironic/common/exception.py:279 +#: ironic/common/exception.py:286 #, python-format msgid "Conductor %(conductor)s already registered." msgstr "" -#: ironic/common/exception.py:283 +#: ironic/common/exception.py:290 #, python-format msgid "Failed to set node power state to %(pstate)s." msgstr "" -#: ironic/common/exception.py:287 +#: ironic/common/exception.py:294 msgid "An exclusive lock is required, but the current context has a shared lock." msgstr "" -#: ironic/common/exception.py:292 +#: ironic/common/exception.py:299 #, python-format msgid "Failed to toggle maintenance-mode flag for node %(node)s: %(reason)s" msgstr "" -#: ironic/common/exception.py:297 +#: ironic/common/exception.py:304 #, python-format msgid "Console access is not enabled on node %(node)s" msgstr "" -#: ironic/common/exception.py:301 +#: ironic/common/exception.py:308 #, python-format msgid "" "The %(op)s operation can't be performed on node %(node)s because it's in " "maintenance mode." msgstr "" -#: ironic/common/exception.py:306 +#: ironic/common/exception.py:313 #, python-format msgid "" "Can not change instance association while node %(node)s is in power state" " %(pstate)s." msgstr "" -#: ironic/common/exception.py:311 +#: ironic/common/exception.py:318 #, python-format msgid "" "Cannot complete the requested action because chassis %(chassis)s contains" " nodes." msgstr "" -#: ironic/common/exception.py:316 +#: ironic/common/exception.py:323 #, python-format msgid "IPMI call failed: %(cmd)s." msgstr "" -#: ironic/common/exception.py:320 +#: ironic/common/exception.py:327 +msgid "Failed to connect to AMT service." +msgstr "" + +#: ironic/common/exception.py:331 +#, python-format +msgid "AMT call failed: %(cmd)s." +msgstr "" + +#: ironic/common/exception.py:335 #, python-format msgid "Failed to establish SSH connection to host %(host)s." msgstr "" -#: ironic/common/exception.py:324 +#: ironic/common/exception.py:339 #, python-format msgid "Failed to execute command via SSH: %(cmd)s." msgstr "" -#: ironic/common/exception.py:328 +#: ironic/common/exception.py:343 #, python-format msgid "Unsupported object type %(objtype)s" msgstr "" -#: ironic/common/exception.py:332 +#: ironic/common/exception.py:347 #, python-format msgid "Cannot call %(method)s on orphaned %(objtype)s object" msgstr "" -#: ironic/common/exception.py:336 +#: ironic/common/exception.py:351 #, python-format -msgid "Driver %(driver)s does not support %(extension)s." +msgid "" +"Driver %(driver)s does not support %(extension)s (disabled or not " +"implemented)." msgstr "" -#: ironic/common/exception.py:340 +#: ironic/common/exception.py:356 #, python-format msgid "Version %(objver)s of %(objname)s is not supported" msgstr "" -#: ironic/common/exception.py:344 +#: ironic/common/exception.py:360 #, python-format msgid "Connection to glance host %(host)s:%(port)s failed: %(reason)s" msgstr "" -#: ironic/common/exception.py:349 +#: ironic/common/exception.py:365 #, python-format msgid "Not authorized for image %(image_id)s." msgstr "" -#: ironic/common/exception.py:353 +#: ironic/common/exception.py:369 #, python-format msgid "Invalid image href %(image_href)s." msgstr "" -#: ironic/common/exception.py:357 +#: ironic/common/exception.py:373 +#, python-format +msgid "Validation of image href %(image_href)s failed, reason: %(reason)s" +msgstr "" + +#: ironic/common/exception.py:378 +#, python-format +msgid "Failed to download image %(image_href)s, reason: %(reason)s" +msgstr "" + +#: ironic/common/exception.py:382 msgid "Not authorized in Keystone." msgstr "" -#: ironic/common/exception.py:370 +#: ironic/common/exception.py:395 #, python-format msgid "" "Service type %(service_type)s with endpoint type %(endpoint_type)s not " "found in keystone service catalog." msgstr "" -#: ironic/common/exception.py:375 +#: ironic/common/exception.py:400 msgid "Connection failed" msgstr "" -#: ironic/common/exception.py:379 +#: ironic/common/exception.py:404 msgid "Requested OpenStack Images API is forbidden" msgstr "" -#: ironic/common/exception.py:387 +#: ironic/common/exception.py:412 msgid "The provided endpoint is invalid" msgstr "" -#: ironic/common/exception.py:391 +#: ironic/common/exception.py:416 msgid "Unable to communicate with the server." msgstr "" -#: ironic/common/exception.py:407 +#: ironic/common/exception.py:432 #, python-format msgid "Could not find config at %(path)s" msgstr "" -#: ironic/common/exception.py:411 +#: ironic/common/exception.py:436 #, python-format msgid "" "Node %(node)s is locked by host %(host)s, please retry after the current " "operation is completed." msgstr "" -#: ironic/common/exception.py:416 +#: ironic/common/exception.py:441 #, python-format msgid "Node %(node)s found not to be locked on release" msgstr "" -#: ironic/common/exception.py:420 +#: ironic/common/exception.py:445 msgid "" "Requested action cannot be performed due to lack of free conductor " "workers." msgstr "" -#: ironic/common/exception.py:430 +#: ironic/common/exception.py:455 #, python-format msgid "Invalid configuration file. %(error_msg)s" msgstr "" -#: ironic/common/exception.py:434 +#: ironic/common/exception.py:459 #, python-format msgid "Driver %(driver)s could not be loaded. Reason: %(reason)s." msgstr "" -#: ironic/common/exception.py:442 +#: ironic/common/exception.py:467 #, python-format msgid "Could not find pid in pid file %(pid_path)s" msgstr "" -#: ironic/common/exception.py:446 +#: ironic/common/exception.py:471 #, python-format msgid "Console subprocess failed to start. %(error)s" msgstr "" -#: ironic/common/exception.py:450 +#: ironic/common/exception.py:475 #, python-format msgid "Failed to create the password file. %(error)s" msgstr "" -#: ironic/common/exception.py:458 +#: ironic/common/exception.py:483 #, python-format msgid "%(operation)s failed, error: %(error)s" msgstr "" -#: ironic/common/exception.py:466 +#: ironic/common/exception.py:487 +#, python-format +msgid "%(operation)s not supported. error: %(error)s" +msgstr "" + +#: ironic/common/exception.py:495 #, python-format msgid "" "DRAC client failed. Last error (cURL error code): %(last_error)s, fault " "string: \"%(fault_string)s\" response_code: %(response_code)s" msgstr "" -#: ironic/common/exception.py:473 +#: ironic/common/exception.py:502 #, python-format msgid "DRAC operation failed. Message: %(message)s" msgstr "" -#: ironic/common/exception.py:477 +#: ironic/common/exception.py:506 #, python-format msgid "" "DRAC operation yielded return value %(actual_return_value)s that is " "neither error nor expected %(expected_return_value)s" msgstr "" -#: ironic/common/exception.py:482 +#: ironic/common/exception.py:511 #, python-format msgid "" "Another job with ID %(job_id)s is already created to configure " "%(target)s. Wait until existing job is completed or is canceled" msgstr "" -#: ironic/common/exception.py:488 +#: ironic/common/exception.py:517 #, python-format msgid "" "Invalid filter dialect '%(invalid_filter)s'. Supported options are " "%(supported)s" msgstr "" -#: ironic/common/exception.py:493 +#: ironic/common/exception.py:522 #, python-format msgid "Failed to get sensor data for node %(node)s. Error: %(error)s" msgstr "" -#: ironic/common/exception.py:498 +#: ironic/common/exception.py:527 #, python-format msgid "Failed to parse sensor data for node %(node)s. Error: %(error)s" msgstr "" -#: ironic/common/exception.py:503 +#: ironic/common/exception.py:532 #, python-format msgid "" "Disk volume where '%(path)s' is located doesn't have enough disk space. " "Required %(required)d MiB, only %(actual)d MiB available space present." msgstr "" -#: ironic/common/exception.py:509 +#: ironic/common/exception.py:538 #, python-format msgid "Creating %(image_type)s image failed: %(error)s" msgstr "" -#: ironic/common/exception.py:513 +#: ironic/common/exception.py:542 #, python-format msgid "Swift operation '%(operation)s' failed: %(error)s" msgstr "" -#: ironic/common/exception.py:517 +#: ironic/common/exception.py:546 #, python-format msgid "SNMP operation '%(operation)s' failed: %(error)s" msgstr "" -#: ironic/common/exception.py:521 +#: ironic/common/exception.py:550 #, python-format msgid "Failed to create a file system. File system %(fs)s is not supported." msgstr "" -#: ironic/common/exception.py:526 +#: ironic/common/exception.py:555 #, python-format msgid "iRMC %(operation)s failed. Reason: %(error)s" msgstr "" -#: ironic/common/exception.py:530 +#: ironic/common/exception.py:559 #, python-format msgid "VirtualBox operation '%(operation)s' failed. Error: %(error)s" msgstr "" -#: ironic/common/fsm.py:84 +#: ironic/common/exception.py:564 +#, python-format +msgid "Failed to inspect hardware. Reason: %(error)s" +msgstr "" + +#: ironic/common/exception.py:568 +#, python-format +msgid "Failed to clean node %(node)s: %(reason)s" +msgstr "" + +#: ironic/common/fsm.py:94 #, python-format msgid "State '%s' already defined" msgstr "" -#: ironic/common/fsm.py:87 +#: ironic/common/fsm.py:97 msgid "On enter callback must be callable" msgstr "" -#: ironic/common/fsm.py:90 +#: ironic/common/fsm.py:100 msgid "On exit callback must be callable" msgstr "" -#: ironic/common/fsm.py:92 +#: ironic/common/fsm.py:102 #, python-format msgid "Target state '%s' does not exist" msgstr "" -#: ironic/common/fsm.py:108 +#: ironic/common/fsm.py:106 +#, python-format +msgid "Target state '%s' is not a 'stable' state" +msgstr "" + +#: ironic/common/fsm.py:122 #, python-format msgid "" "Can not add a transition on event '%(event)s' that starts in a undefined " "state '%(state)s'" msgstr "" -#: ironic/common/fsm.py:113 +#: ironic/common/fsm.py:127 #, python-format msgid "" "Can not add a transition on event '%(event)s' that ends in a undefined " "state '%(state)s'" msgstr "" -#: ironic/common/fsm.py:124 +#: ironic/common/fsm.py:138 msgid "Can only process events after being initialized (not before)" msgstr "" -#: ironic/common/fsm.py:128 +#: ironic/common/fsm.py:142 #, python-format msgid "Can not transition from terminal state '%(state)s' on event '%(event)s'" msgstr "" -#: ironic/common/fsm.py:133 +#: ironic/common/fsm.py:147 #, python-format msgid "" "Can not transition from state '%(state)s' on event '%(event)s' (no " "defined transition)" msgstr "" -#: ironic/common/fsm.py:171 +#: ironic/common/fsm.py:185 #, python-format msgid "Can not start from an undefined state '%s'" msgstr "" -#: ironic/common/fsm.py:174 +#: ironic/common/fsm.py:188 #, python-format msgid "Can not start from a terminal state '%s'" msgstr "" @@ -655,20 +705,49 @@ msgstr "" msgid "The driver '%s' is unknown." msgstr "" -#: ironic/common/images.py:257 +#: ironic/common/image_service.py:137 +#, python-format +msgid "Got HTTP code %s instead of 200 in response to HEAD request." +msgstr "" + +#: ironic/common/image_service.py:159 +#, python-format +msgid "Got HTTP code %s instead of 200 in response to GET request." +msgstr "" + +#: ironic/common/image_service.py:181 +msgid "" +"Cannot determine image size as there is no Content-Length header " +"specified in response to HEAD request." +msgstr "" + +#: ironic/common/image_service.py:204 +msgid "Specified image file not found." +msgstr "" + +#: ironic/common/image_service.py:280 +#, python-format +msgid "Image download protocol %s is not supported." +msgstr "" + +#: ironic/common/images.py:357 msgid "'qemu-img info' parsing failed." msgstr "" -#: ironic/common/images.py:263 +#: ironic/common/images.py:363 #, python-format msgid "fmt=%(fmt)s backed by: %(backing_file)s" msgstr "" -#: ironic/common/images.py:278 +#: ironic/common/images.py:378 #, python-format msgid "Converted to raw, but format is now %s" msgstr "" +#: ironic/common/images.py:561 +msgid "Deploy iso didn't contain efiboot.img or grub.cfg" +msgstr "" + #: ironic/common/keystone.py:52 msgid "Keystone API endpoint is missing" msgstr "" @@ -682,7 +761,7 @@ msgstr "" msgid "No Keystone service catalog loaded" msgstr "" -#: ironic/common/pxe_utils.py:100 +#: ironic/common/pxe_utils.py:102 #, python-format msgid "Failed to get IP address for any port on node %s." msgstr "" @@ -711,7 +790,7 @@ msgstr "" msgid "post object" msgstr "" -#: ironic/common/utils.py:117 +#: ironic/common/utils.py:116 msgid "Invalid private key" msgstr "" @@ -748,92 +827,144 @@ msgid "" "swift_store_multiple_containers_seed." msgstr "" -#: ironic/conductor/manager.py:338 +#: ironic/conductor/manager.py:376 msgid "Invalid method call: update_node can not change node state." msgstr "" -#: ironic/conductor/manager.py:463 ironic/conductor/manager.py:555 +#: ironic/conductor/manager.py:501 ironic/conductor/manager.py:593 #: ironic/drivers/utils.py:84 #, python-format msgid "No handler for method %s" msgstr "" -#: ironic/conductor/manager.py:468 ironic/conductor/manager.py:560 +#: ironic/conductor/manager.py:506 ironic/conductor/manager.py:598 #, python-format msgid "The method %(method)s does not support HTTP %(http)s" msgstr "" -#: ironic/conductor/manager.py:657 +#: ironic/conductor/manager.py:695 msgid "provisioning" msgstr "" -#: ironic/conductor/manager.py:664 +#: ironic/conductor/manager.py:730 #, python-format msgid "RPC do_node_deploy failed to validate deploy or power info. Error: %(msg)s" msgstr "" -#: ironic/conductor/manager.py:724 +#: ironic/conductor/manager.py:777 #, python-format msgid "" "Failed to validate power driver interface. Can not delete instance. " "Error: %(msg)s" msgstr "" -#: ironic/conductor/manager.py:994 +#: ironic/conductor/manager.py:802 +#, python-format +msgid "Failed to tear down. Error: %s" +msgstr "" + +#: ironic/conductor/manager.py:851 +#, python-format +msgid "" +"Cannot continue cleaning on %(node)s, node is in %(state)s state, should " +"be %(clean_state)s" +msgstr "" + +#: ironic/conductor/manager.py:887 +#, python-format +msgid "" +"Failed to validate power driver interface. Can not clean node %(node)s. " +"Error: %(msg)s" +msgstr "" + +#: ironic/conductor/manager.py:897 +#, python-format +msgid "Failed to prepare node %(node)s for cleaning: %(e)s" +msgstr "" + +#: ironic/conductor/manager.py:929 +#, python-format +msgid "Node %(node)s got an invalid last step for %(state)s: %(step)s." +msgstr "" + +#: ironic/conductor/manager.py:951 +#, python-format +msgid "Node %(node)s failed step %(step)s: %(exc)s" +msgstr "" + +#: ironic/conductor/manager.py:970 +#, python-format +msgid "" +"While executing step %(step)s on node %(node)s, step returned invalid " +"value: %(val)s" +msgstr "" + +#: ironic/conductor/manager.py:986 +#, python-format +msgid "Failed to tear down from cleaning for node %s" +msgstr "" + +#: ironic/conductor/manager.py:1249 msgid "not supported" msgstr "" -#: ironic/conductor/manager.py:1022 +#: ironic/conductor/manager.py:1277 #, python-format msgid "Node %s can't be deleted because it's not powered off" msgstr "" -#: ironic/conductor/manager.py:1101 +#: ironic/conductor/manager.py:1377 msgid "enabled" msgstr "" -#: ironic/conductor/manager.py:1101 +#: ironic/conductor/manager.py:1377 msgid "disabled" msgstr "" -#: ironic/conductor/manager.py:1124 +#: ironic/conductor/manager.py:1400 msgid "enabling" msgstr "" -#: ironic/conductor/manager.py:1124 +#: ironic/conductor/manager.py:1400 msgid "disabling" msgstr "" -#: ironic/conductor/manager.py:1125 +#: ironic/conductor/manager.py:1401 #, python-format msgid "Error %(op)s the console on node %(node)s. Reason: %(error)s" msgstr "" -#: ironic/conductor/manager.py:1376 ironic/conductor/manager.py:1404 +#: ironic/conductor/manager.py:1660 +#, python-format +msgid "" +"RPC inspect_hardware failed to validate inspection or power info. Error: " +"%(msg)s" +msgstr "" + +#: ironic/conductor/manager.py:1692 +msgid "timeout reached while inspecting the node" +msgstr "" + +#: ironic/conductor/manager.py:1777 ironic/conductor/manager.py:1805 msgid "No free conductor workers available" msgstr "" -#: ironic/conductor/manager.py:1476 +#: ironic/conductor/manager.py:1877 #, python-format msgid "Failed to upload the configdrive to Swift. Error: %s" msgstr "" -#: ironic/conductor/manager.py:1486 +#: ironic/conductor/manager.py:1887 #, python-format msgid "Failed to prepare to deploy. Error: %s" msgstr "" -#: ironic/conductor/manager.py:1494 +#: ironic/conductor/manager.py:1895 #, python-format msgid "Failed to deploy. Error: %s" msgstr "" -#: ironic/conductor/manager.py:1528 -#, python-format -msgid "Failed to tear down. Error: %s" -msgstr "" - -#: ironic/conductor/manager.py:1548 +#: ironic/conductor/manager.py:1921 #, python-format msgid "" "During sync_power_state, max retries exceeded for node %(node)s, node " @@ -841,11 +972,16 @@ msgid "" "state to '%(actual)s' Switching node to maintenance mode." msgstr "" -#: ironic/conductor/manager.py:1594 +#: ironic/conductor/manager.py:1967 msgid "Power driver returned ERROR state while trying to sync power state." msgstr "" -#: ironic/conductor/rpcapi.py:105 +#: ironic/conductor/manager.py:2059 +#, python-format +msgid "During inspection, driver returned unexpected state %(state)s" +msgstr "" + +#: ironic/conductor/rpcapi.py:108 #, python-format msgid "No conductor service registered which supports driver %s." msgstr "" @@ -871,69 +1007,98 @@ msgid "" "aborting. More info may be found in the log file." msgstr "" -#: ironic/db/sqlalchemy/api.py:338 +#: ironic/db/sqlalchemy/api.py:334 msgid "Cannot overwrite UUID for an existing Node." msgstr "" -#: ironic/db/sqlalchemy/api.py:425 +#: ironic/db/sqlalchemy/api.py:431 msgid "Cannot overwrite UUID for an existing Port." msgstr "" -#: ironic/db/sqlalchemy/api.py:488 +#: ironic/db/sqlalchemy/api.py:489 msgid "Cannot overwrite UUID for an existing Chassis." msgstr "" -#: ironic/dhcp/neutron.py:70 +#: ironic/dhcp/neutron.py:74 msgid "Neutron auth_strategy should be either \"noauth\" or \"keystone\"." msgstr "" -#: ironic/dhcp/neutron.py:161 +#: ironic/dhcp/neutron.py:171 #, python-format msgid "" "No VIFs found for node %(node)s when attempting to update DHCP BOOT " "options." msgstr "" -#: ironic/dhcp/neutron.py:175 +#: ironic/dhcp/neutron.py:185 #, python-format msgid "Failed to set DHCP BOOT options for any port on node %s." msgstr "" -#: ironic/drivers/agent.py:103 ironic/drivers/fake.py:197 -#: ironic/drivers/pxe.py:231 +#: ironic/dhcp/neutron.py:297 +msgid "Valid cleaning network UUID not provided" +msgstr "" + +#: ironic/dhcp/neutron.py:313 +#, python-format +msgid "Could not create cleaning port on network %(net)s from %(node)s. %(exc)s" +msgstr "" + +#: ironic/dhcp/neutron.py:322 +#, python-format +msgid "Failed to create cleaning ports for node %(node)s" +msgstr "" + +#: ironic/dhcp/neutron.py:343 +#, python-format +msgid "" +"Could not get cleaning network vif for %(node)s from Neutron, possible " +"network issue. %(exc)s" +msgstr "" + +#: ironic/dhcp/neutron.py:357 +#, python-format +msgid "" +"Could not remove cleaning ports on network %(net)s from %(node)s, " +"possible network issue. %(exc)s" +msgstr "" + +#: ironic/drivers/agent.py:103 ironic/drivers/fake.py:205 +#: ironic/drivers/pxe.py:244 msgid "Unable to import pyremotevbox library" msgstr "" -#: ironic/drivers/drac.py:34 ironic/drivers/fake.py:159 +#: ironic/drivers/drac.py:35 ironic/drivers/fake.py:166 +#: ironic/drivers/fake.py:233 ironic/drivers/pxe.py:264 msgid "Unable to import pywsman library" msgstr "" -#: ironic/drivers/fake.py:96 +#: ironic/drivers/fake.py:102 msgid "Unable to import pyghmi IPMI library" msgstr "" -#: ironic/drivers/fake.py:110 ironic/drivers/pxe.py:114 +#: ironic/drivers/fake.py:116 ironic/drivers/pxe.py:126 msgid "Unable to import seamicroclient library" msgstr "" -#: ironic/drivers/fake.py:134 ironic/drivers/pxe.py:142 +#: ironic/drivers/fake.py:140 ironic/drivers/pxe.py:154 msgid "Unable to import iboot library" msgstr "" -#: ironic/drivers/fake.py:146 ironic/drivers/ilo.py:43 ironic/drivers/ilo.py:66 -#: ironic/drivers/pxe.py:162 +#: ironic/drivers/fake.py:152 ironic/drivers/ilo.py:43 ironic/drivers/ilo.py:67 +#: ironic/drivers/pxe.py:174 msgid "Unable to import proliantutils library" msgstr "" -#: ironic/drivers/fake.py:173 ironic/drivers/pxe.py:184 +#: ironic/drivers/fake.py:180 ironic/drivers/pxe.py:197 msgid "Unable to import pysnmp library" msgstr "" -#: ironic/drivers/fake.py:185 ironic/drivers/pxe.py:207 +#: ironic/drivers/fake.py:192 ironic/drivers/pxe.py:220 msgid "Unable to import python-scciclient library" msgstr "" -#: ironic/drivers/pxe.py:91 +#: ironic/drivers/pxe.py:101 msgid "Unable to import pyghmi library" msgstr "" @@ -948,62 +1113,136 @@ msgid "" "%(valid_values)s." msgstr "" -#: ironic/drivers/modules/agent.py:182 +#: ironic/drivers/modules/agent.py:71 ironic/drivers/modules/pxe.py:102 +msgid "UUID (from Glance) of the deployment kernel. Required." +msgstr "" + +#: ironic/drivers/modules/agent.py:73 +msgid "" +"UUID (from Glance) of the ramdisk with agent that is used at deploy time." +" Required." +msgstr "" + +#: ironic/drivers/modules/agent.py:260 #, python-format msgid "Node %s failed to validate deploy image info. Some parameters were missing" msgstr "" -#: ironic/drivers/modules/agent.py:336 +#: ironic/drivers/modules/agent.py:266 +#, python-format +msgid "" +"image_source's image_checksum must be provided in instance_info for node " +"%s" +msgstr "" + +#: ironic/drivers/modules/agent.py:274 +#, python-format +msgid "" +"Node %(node)s is configured to use the %(driver)s driver which currently " +"does not support deploying partition images." +msgstr "" + +#: ironic/drivers/modules/agent.py:483 #, python-format msgid "node %(node)s command status errored: %(error)s" msgstr "" -#: ironic/drivers/modules/agent_base_vendor.py:119 +#: ironic/drivers/modules/agent_base_vendor.py:124 msgid "Missing parameter version" msgstr "" -#: ironic/drivers/modules/agent_base_vendor.py:122 +#: ironic/drivers/modules/agent_base_vendor.py:127 #, python-format msgid "Unknown lookup payload version: %s" msgstr "" -#: ironic/drivers/modules/agent_base_vendor.py:149 +#: ironic/drivers/modules/agent_base_vendor.py:160 +#, python-format +msgid "Agent returned error for clean step %(step)s on node %(node)s : %(err)s." +msgstr "" + +#: ironic/drivers/modules/agent_base_vendor.py:172 +#, python-format +msgid "Could not restart cleaning on node %(node)s: %(err)s." +msgstr "" + +#: ironic/drivers/modules/agent_base_vendor.py:184 +#, python-format +msgid "" +"Agent returned unknown status for clean step %(step)s on node %(node)s : " +"%(err)s." +msgstr "" + +#: ironic/drivers/modules/agent_base_vendor.py:215 msgid "For heartbeat operation, \"agent_url\" must be specified." msgstr "" -#: ironic/drivers/modules/agent_base_vendor.py:158 +#: ironic/drivers/modules/agent_base_vendor.py:224 msgid "Failed checking if deploy is done." msgstr "" -#: ironic/drivers/modules/agent_base_vendor.py:161 +#: ironic/drivers/modules/agent_base_vendor.py:232 msgid "Node failed to get image for deploy." msgstr "" -#: ironic/drivers/modules/agent_base_vendor.py:165 +#: ironic/drivers/modules/agent_base_vendor.py:236 msgid "Node failed to move to active state." msgstr "" -#: ironic/drivers/modules/agent_base_vendor.py:245 +#: ironic/drivers/modules/agent_base_vendor.py:249 +#, python-format +msgid "Asynchronous exception for node %(node)s: %(msg)s exception: %(e)s" +msgstr "" + +#: ironic/drivers/modules/agent_base_vendor.py:337 #, python-format msgid "Malformed network interfaces lookup: %s" msgstr "" -#: ironic/drivers/modules/agent_base_vendor.py:274 +#: ironic/drivers/modules/agent_base_vendor.py:366 #, python-format msgid "No ports matching the given MAC addresses %sexist in the database." msgstr "" -#: ironic/drivers/modules/agent_base_vendor.py:322 +#: ironic/drivers/modules/agent_base_vendor.py:414 #, python-format msgid "" "Ports matching mac addresses match multiple nodes. MACs: %(macs)s. Port " "ids: %(port_ids)s" msgstr "" +#: ironic/drivers/modules/agent_base_vendor.py:443 +#, python-format +msgid "Error rebooting node %(node)s. Error: %(error)s" +msgstr "" + +#: ironic/drivers/modules/agent_base_vendor.py:475 +#, python-format +msgid "" +"Failed to install a bootloader when deploying node %(node)s. Error: " +"%(error)s" +msgstr "" + +#: ironic/drivers/modules/agent_base_vendor.py:484 +#, python-format +msgid "" +"Failed to change the boot device to %(boot_dev)s when deploying node " +"%(node)s. Error: %(error)s" +msgstr "" + #: ironic/drivers/modules/agent_client.py:48 msgid "Agent driver requires agent_url in driver_internal_info" msgstr "" +#: ironic/drivers/modules/agent_client.py:79 +#, python-format +msgid "" +"Unable to decode response as JSON.\n" +"Request URL: %(url)s\n" +"Request body: \"%(body)s\"\n" +"Response: \"%(response)s\"" +msgstr "" + #: ironic/drivers/modules/console_utils.py:89 #, python-format msgid "" @@ -1037,74 +1276,125 @@ msgstr "" msgid "Could not stop the console for node '%(node)s'. Reason: %(err)s." msgstr "" -#: ironic/drivers/modules/deploy_utils.py:117 +#: ironic/drivers/modules/deploy_utils.py:129 #, python-format msgid "" "iSCSI connection was not seen by the file system after attempting to " "verify %d times." msgstr "" -#: ironic/drivers/modules/deploy_utils.py:140 +#: ironic/drivers/modules/deploy_utils.py:152 #, python-format msgid "" "iSCSI connection did not become active after attempting to verify %d " "times." msgstr "" -#: ironic/drivers/modules/deploy_utils.py:406 +#: ironic/drivers/modules/deploy_utils.py:303 +#, python-format +msgid "" +"Unable to stat device %(dev)s after attempting to verify %(attempts)d " +"times." +msgstr "" + +#: ironic/drivers/modules/deploy_utils.py:501 #, python-format msgid "" "Can't download the configdrive content for node %(node)s from '%(url)s'. " "Reason: %(reason)s" msgstr "" -#: ironic/drivers/modules/deploy_utils.py:415 +#: ironic/drivers/modules/deploy_utils.py:510 #, python-format msgid "" "Config drive for node %s is not base64 encoded or the content is " "malformed." msgstr "" -#: ironic/drivers/modules/deploy_utils.py:418 +#: ironic/drivers/modules/deploy_utils.py:513 #, python-format msgid " Downloaded from \"%s\"." msgstr "" -#: ironic/drivers/modules/deploy_utils.py:431 +#: ironic/drivers/modules/deploy_utils.py:526 #, python-format msgid "" "Encountered error while decompressing and writing config drive for node " "%(node)s. Error: %(exc)s" msgstr "" -#: ironic/drivers/modules/deploy_utils.py:468 +#: ironic/drivers/modules/deploy_utils.py:597 #, python-format -msgid "Parent device '%s' not found" +msgid "Root device '%s' not found" msgstr "" -#: ironic/drivers/modules/deploy_utils.py:496 +#: ironic/drivers/modules/deploy_utils.py:607 #, python-format -msgid "Root device '%s' not found" +msgid "'%(partition)s' device '%(part_device)s' not found" msgstr "" -#: ironic/drivers/modules/deploy_utils.py:505 +#: ironic/drivers/modules/deploy_utils.py:735 #, python-format -msgid "'%(partition)s' device '%(part_device)s' not found" +msgid "Parent device '%s' not found" msgstr "" -#: ironic/drivers/modules/deploy_utils.py:613 +#: ironic/drivers/modules/deploy_utils.py:786 #, python-format msgid "%(error_msg)s. Missing are: %(missing_info)s" msgstr "" -#: ironic/drivers/modules/deploy_utils.py:701 +#: ironic/drivers/modules/deploy_utils.py:875 #, python-format msgid "" "Error parsing capabilities from Node %s instance_info field. A dictionary" -" or a dictionary string is expected." +" or a \"jsonified\" dictionary is expected." +msgstr "" + +#: ironic/drivers/modules/deploy_utils.py:909 +#, python-format +msgid "get_clean_steps for node %(node)s returned invalid result: %(result)s" +msgstr "" + +#: ironic/drivers/modules/deploy_utils.py:945 +#, python-format +msgid "Agent on node %(node)s returned bad command result: %(result)s" +msgstr "" + +#: ironic/drivers/modules/deploy_utils.py:1002 +#, python-format +msgid "" +"The hints \"%(invalid_hints)s\" are invalid. Valid hints are: " +"\"%(valid_hints)s\"" +msgstr "" + +#: ironic/drivers/modules/deploy_utils.py:1012 +msgid "Root device hint \"size\" is not an integer value." +msgstr "" + +#: ironic/drivers/modules/discoverd.py:78 +msgid "ironic-discoverd support is disabled" +msgstr "" + +#: ironic/drivers/modules/discoverd.py:82 +msgid "ironic-discoverd Python module not found" +msgstr "" + +#: ironic/drivers/modules/discoverd.py:88 +#, python-format +msgid "ironic-discoverd version is too old: required >= 1.0.0, got %s" +msgstr "" + +#: ironic/drivers/modules/discoverd.py:166 +#, python-format +msgid "Failed to start inspection: %s" +msgstr "" + +#: ironic/drivers/modules/discoverd.py:200 +#, python-format +msgid "ironic-discoverd inspection failed: %s" msgstr "" -#: ironic/drivers/modules/fake.py:48 ironic/drivers/modules/ipminative.py:338 +#: ironic/drivers/modules/fake.py:48 ironic/drivers/modules/ipminative.py:343 #, python-format msgid "set_power_state called with an invalid power state: %s." msgstr "" @@ -1130,11 +1420,12 @@ msgstr "" msgid "Test if the value of bar is meow" msgstr "" -#: ironic/drivers/modules/fake.py:163 ironic/drivers/modules/ipminative.py:404 -#: ironic/drivers/modules/ipmitool.py:723 +#: ironic/drivers/modules/fake.py:163 ironic/drivers/modules/ipminative.py:409 +#: ironic/drivers/modules/ipmitool.py:734 #: ironic/drivers/modules/seamicro.py:571 ironic/drivers/modules/ssh.py:644 #: ironic/drivers/modules/virtualbox.py:338 -#: ironic/drivers/modules/ilo/management.py:132 +#: ironic/drivers/modules/ilo/management.py:198 +#: ironic/drivers/modules/irmc/management.py:142 #, python-format msgid "Invalid boot device %s specified." msgstr "" @@ -1177,100 +1468,100 @@ msgstr "" msgid "Cannot get power status for node '%(node)s'. iBoot get_relays() failed." msgstr "" -#: ironic/drivers/modules/iboot.py:185 ironic/drivers/modules/ipmitool.py:642 +#: ironic/drivers/modules/iboot.py:185 ironic/drivers/modules/ipmitool.py:653 #: ironic/drivers/modules/snmp.py:672 ironic/drivers/modules/ssh.py:561 #, python-format msgid "set_power_state called with invalid power state %s." msgstr "" -#: ironic/drivers/modules/ipminative.py:63 +#: ironic/drivers/modules/ipminative.py:68 msgid "IP of the node's BMC. Required." msgstr "" -#: ironic/drivers/modules/ipminative.py:64 +#: ironic/drivers/modules/ipminative.py:69 msgid "IPMI password. Required." msgstr "" -#: ironic/drivers/modules/ipminative.py:65 +#: ironic/drivers/modules/ipminative.py:70 msgid "IPMI username. Required." msgstr "" -#: ironic/drivers/modules/ipminative.py:68 -#: ironic/drivers/modules/ipmitool.py:96 ironic/drivers/modules/seamicro.py:80 -#: ironic/drivers/modules/ilo/common.py:72 +#: ironic/drivers/modules/ipminative.py:73 +#: ironic/drivers/modules/ipmitool.py:95 ironic/drivers/modules/seamicro.py:80 +#: ironic/drivers/modules/ilo/common.py:75 msgid "node's UDP port to connect to. Only required for console access." msgstr "" -#: ironic/drivers/modules/ipminative.py:92 -#: ironic/drivers/modules/ipmitool.py:212 +#: ironic/drivers/modules/ipminative.py:97 +#: ironic/drivers/modules/ipmitool.py:223 #, python-format msgid "Missing the following IPMI credentials in node's driver_info: %s." msgstr "" -#: ironic/drivers/modules/ipminative.py:110 -#: ironic/drivers/modules/ipmitool.py:232 +#: ironic/drivers/modules/ipminative.py:115 +#: ironic/drivers/modules/ipmitool.py:243 msgid "IPMI terminal port is not an integer." msgstr "" -#: ironic/drivers/modules/ipminative.py:494 -#: ironic/drivers/modules/ipmitool.py:940 +#: ironic/drivers/modules/ipminative.py:499 +#: ironic/drivers/modules/ipmitool.py:951 msgid "Missing 'ipmi_terminal_port' parameter in node's driver_info." msgstr "" -#: ironic/drivers/modules/ipmitool.py:70 +#: ironic/drivers/modules/ipmitool.py:69 msgid "IP address or hostname of the node. Required." msgstr "" -#: ironic/drivers/modules/ipmitool.py:73 +#: ironic/drivers/modules/ipmitool.py:72 msgid "password. Optional." msgstr "" -#: ironic/drivers/modules/ipmitool.py:74 +#: ironic/drivers/modules/ipmitool.py:73 #, python-format msgid "privilege level; default is ADMINISTRATOR. One of %s. Optional." msgstr "" -#: ironic/drivers/modules/ipmitool.py:76 +#: ironic/drivers/modules/ipmitool.py:75 msgid "username; default is NULL user. Optional." msgstr "" -#: ironic/drivers/modules/ipmitool.py:77 +#: ironic/drivers/modules/ipmitool.py:76 msgid "" "bridging_type; default is \"no\". One of \"single\", \"dual\", \"no\". " "Optional." msgstr "" -#: ironic/drivers/modules/ipmitool.py:79 +#: ironic/drivers/modules/ipmitool.py:78 msgid "" "transit channel for bridged request. Required only if ipmi_bridging is " "set to \"dual\"." msgstr "" -#: ironic/drivers/modules/ipmitool.py:81 +#: ironic/drivers/modules/ipmitool.py:80 msgid "" "transit address for bridged request. Required only if ipmi_bridging is " "set to \"dual\"." msgstr "" -#: ironic/drivers/modules/ipmitool.py:83 +#: ironic/drivers/modules/ipmitool.py:82 msgid "" "destination channel for bridged request. Required only if ipmi_bridging " "is set to \"single\" or \"dual\"." msgstr "" -#: ironic/drivers/modules/ipmitool.py:86 +#: ironic/drivers/modules/ipmitool.py:85 msgid "" "destination address for bridged request. Required only if ipmi_bridging " "is set to \"single\" or \"dual\"." msgstr "" -#: ironic/drivers/modules/ipmitool.py:89 +#: ironic/drivers/modules/ipmitool.py:88 msgid "" "local IPMB address for bridged requests. Used only if ipmi_bridging is " "set to \"single\" or \"dual\". Optional." msgstr "" -#: ironic/drivers/modules/ipmitool.py:243 +#: ironic/drivers/modules/ipmitool.py:254 #, python-format msgid "" "Value for ipmi_bridging is provided as %s, but IPMI bridging is not " @@ -1278,152 +1569,206 @@ msgid "" "is > 1.8.11" msgstr "" -#: ironic/drivers/modules/ipmitool.py:266 +#: ironic/drivers/modules/ipmitool.py:277 #, python-format msgid "%(param)s not provided" msgstr "" -#: ironic/drivers/modules/ipmitool.py:269 +#: ironic/drivers/modules/ipmitool.py:280 #, python-format msgid "" "Invalid value for ipmi_bridging: %(bridging_type)s, the valid value can " "be one of: %(bridging_types)s" msgstr "" -#: ironic/drivers/modules/ipmitool.py:277 +#: ironic/drivers/modules/ipmitool.py:288 #, python-format msgid "" "Invalid privilege level value:%(priv_level)s, the valid value can be one " "of %(valid_levels)s" msgstr "" -#: ironic/drivers/modules/ipmitool.py:507 +#: ironic/drivers/modules/ipmitool.py:518 #, python-format msgid "parse ipmi sensor data failed, unknown sensor type data: %(sensors_data)s" msgstr "" -#: ironic/drivers/modules/ipmitool.py:545 +#: ironic/drivers/modules/ipmitool.py:556 #, python-format msgid "" "parse ipmi sensor data failed, get nothing with input data: " "%(sensors_data)s" msgstr "" -#: ironic/drivers/modules/ipmitool.py:587 -#: ironic/drivers/modules/ipmitool.py:678 -#: ironic/drivers/modules/ipmitool.py:830 -#: ironic/drivers/modules/ipmitool.py:922 +#: ironic/drivers/modules/ipmitool.py:598 +#: ironic/drivers/modules/ipmitool.py:689 +#: ironic/drivers/modules/ipmitool.py:841 +#: ironic/drivers/modules/ipmitool.py:933 msgid "" "Unable to locate usable ipmitool command in the system path when checking" " ipmitool version" msgstr "" -#: ironic/drivers/modules/ipmitool.py:906 +#: ironic/drivers/modules/ipmitool.py:917 msgid "Parameter raw_bytes (string of bytes) was not specified." msgstr "" -#: ironic/drivers/modules/iscsi_deploy.py:119 +#: ironic/drivers/modules/iscsi_deploy.py:127 msgid "" "Cannot validate iSCSI deploy. Some parameters were missing in node's " "instance_info" msgstr "" -#: ironic/drivers/modules/iscsi_deploy.py:131 +#: ironic/drivers/modules/iscsi_deploy.py:136 #, python-format msgid "" "Cannot validate parameter for iSCSI deploy. Invalid parameter %(param)s. " "Reason: %(reason)s" msgstr "" -#: ironic/drivers/modules/iscsi_deploy.py:137 +#: ironic/drivers/modules/iscsi_deploy.py:142 #, python-format -msgid "'%s' is not an integer value." +msgid "%s is not an integer value." +msgstr "" + +#: ironic/drivers/modules/iscsi_deploy.py:149 +msgid "Cannot deploy whole disk image with swap or ephemeral size set" msgstr "" -#: ironic/drivers/modules/iscsi_deploy.py:166 +#: ironic/drivers/modules/iscsi_deploy.py:182 #, python-format msgid "" "Root partition is too small for requested image. Image size: %(image_mb)d" " MB, Root size: %(root_mb)d MB" msgstr "" -#: ironic/drivers/modules/iscsi_deploy.py:221 +#: ironic/drivers/modules/iscsi_deploy.py:236 msgid "Deploy key does not match" msgstr "" -#: ironic/drivers/modules/iscsi_deploy.py:237 +#: ironic/drivers/modules/iscsi_deploy.py:257 #, python-format msgid "Parameters %s were not passed to ironic for deploy." msgstr "" -#: ironic/drivers/modules/iscsi_deploy.py:268 -msgid "Failure in deploy ramdisk." +#: ironic/drivers/modules/iscsi_deploy.py:304 +#, python-format +msgid "Error returned from deploy ramdisk: %s" msgstr "" -#: ironic/drivers/modules/iscsi_deploy.py:282 ironic/drivers/modules/pxe.py:518 -#: ironic/drivers/modules/ilo/deploy.py:528 -msgid "Failed to continue iSCSI deployment." +#: ironic/drivers/modules/iscsi_deploy.py:325 +#, python-format +msgid "Deploy failed for instance %(instance)s. Error: %(error)s" msgstr "" -#: ironic/drivers/modules/iscsi_deploy.py:389 +#: ironic/drivers/modules/iscsi_deploy.py:333 +#, python-format +msgid "" +"Couldn't determine the UUID of the root partition or the disk identifier " +"after deploying node %s" +msgstr "" + +#: ironic/drivers/modules/iscsi_deploy.py:371 +#, python-format +msgid "" +"Failed to start the iSCSI target to deploy the node %(node)s. Error: " +"%(error)s" +msgstr "" + +#: ironic/drivers/modules/iscsi_deploy.py:495 #, python-format msgid "Failed to connect to Glance to get the properties of the image %s" msgstr "" -#: ironic/drivers/modules/iscsi_deploy.py:393 +#: ironic/drivers/modules/iscsi_deploy.py:499 #, python-format -msgid "Image %s not found in Glance" +msgid "Image %s can not be found." msgstr "" -#: ironic/drivers/modules/iscsi_deploy.py:403 +#: ironic/drivers/modules/iscsi_deploy.py:511 #, python-format msgid "Image %(image)s is missing the following properties: %(properties)s" msgstr "" -#: ironic/drivers/modules/iscsi_deploy.py:423 ironic/drivers/modules/ssh.py:508 +#: ironic/drivers/modules/iscsi_deploy.py:531 ironic/drivers/modules/ssh.py:508 #, python-format msgid "Node %s does not have any port associated with it." msgstr "" -#: ironic/drivers/modules/iscsi_deploy.py:432 +#: ironic/drivers/modules/iscsi_deploy.py:540 #, python-format msgid "" "Couldn't get the URL of the Ironic API service from the configuration " "file or keystone catalog. Keystone error: %s" msgstr "" -#: ironic/drivers/modules/pxe.py:100 -msgid "UUID (from Glance) of the deployment kernel. Required." +#: ironic/drivers/modules/iscsi_deploy.py:563 +msgid "" +"Some mandatory input missing in 'pass_bootloader_info' vendor passthru " +"from ramdisk." +msgstr "" + +#: ironic/drivers/modules/iscsi_deploy.py:570 +#, python-format +msgid "Deploy key %(key_sent)s does not match with %(expected_key)s" +msgstr "" + +#: ironic/drivers/modules/iscsi_deploy.py:588 +#, python-format +msgid "Failed to install bootloader on node %(node)s. Error: %(error)s." msgstr "" -#: ironic/drivers/modules/pxe.py:102 +#: ironic/drivers/modules/iscsi_deploy.py:613 +#, python-format +msgid "" +"Failed to notify ramdisk to reboot after bootloader installation. Error: " +"%s" +msgstr "" + +#: ironic/drivers/modules/pxe.py:104 msgid "UUID (from Glance) of the ramdisk that is mounted at boot time. Required." msgstr "" -#: ironic/drivers/modules/pxe.py:124 +#: ironic/drivers/modules/pxe.py:106 +msgid "" +"DEPRECATED: Use deploy_kernel instead. UUID (from Glance) of the " +"deployment kernel. Required." +msgstr "" + +#: ironic/drivers/modules/pxe.py:109 +msgid "" +"DEPRECATED: Use deploy_ramdisk instead. UUID (from Glance) of the ramdisk" +" that is mounted at boot time. Required." +msgstr "" + +#: ironic/drivers/modules/pxe.py:147 msgid "" "Cannot validate PXE bootloader. Some parameters were missing in node's " "driver_info" msgstr "" -#: ironic/drivers/modules/pxe.py:315 +#: ironic/drivers/modules/pxe.py:252 #, python-format msgid "" -"Local boot is requested, but can't be used with node %s because it's " -"configured to use UEFI boot" +"Conflict: Whole disk image being used for deploy, but cannot be used with" +" node %(node_uuid)s configured to use UEFI boot with netboot option" msgstr "" -#: ironic/drivers/modules/pxe.py:323 +#: ironic/drivers/modules/pxe.py:360 msgid "iPXE boot is enabled but no HTTP URL or HTTP root was specified." msgstr "" -#: ironic/drivers/modules/pxe.py:330 +#: ironic/drivers/modules/pxe.py:367 #, python-format msgid "" "Conflict: iPXE is enabled, but cannot be used with node%(node_uuid)s " "configured to use UEFI boot" msgstr "" +#: ironic/drivers/modules/pxe.py:638 ironic/drivers/modules/ilo/deploy.py:836 +msgid "Failed to continue iSCSI deployment." +msgstr "" + #: ironic/drivers/modules/seamicro.py:68 msgid "API endpoint. Required." msgstr "" @@ -1667,6 +2012,46 @@ msgstr "" msgid "'set_power_state' called with invalid power state '%s'" msgstr "" +#: ironic/drivers/modules/amt/common.py:37 +msgid "IP address or host name of the node. Required." +msgstr "" + +#: ironic/drivers/modules/amt/common.py:38 +msgid "Password. Required." +msgstr "" + +#: ironic/drivers/modules/amt/common.py:39 +msgid "Username to log into AMT system. Required." +msgstr "" + +#: ironic/drivers/modules/amt/common.py:42 +msgid "" +"Protocol used for AMT endpoint. one of http, https; default is \"http\". " +"Optional." +msgstr "" + +#: ironic/drivers/modules/amt/common.py:159 +#, python-format +msgid "AMT driver requires the following to be set in node's driver_info: %s." +msgstr "" + +#: ironic/drivers/modules/amt/common.py:167 +#, python-format +msgid "Invalid protocol %s." +msgstr "" + +#: ironic/drivers/modules/amt/management.py:144 +#, python-format +msgid "" +"set_boot_device called with invalid device %(device)s for node " +"%(node_id)s." +msgstr "" + +#: ironic/drivers/modules/amt/power.py:165 +#, python-format +msgid "Unsupported target_state: %s" +msgstr "" + #: ironic/drivers/modules/drac/common.py:26 msgid "IP address or hostname of the DRAC card. Required." msgstr "" @@ -1722,138 +2107,222 @@ msgid "" "%s" msgstr "" -#: ironic/drivers/modules/ilo/common.py:62 +#: ironic/drivers/modules/ilo/common.py:65 msgid "IP address or hostname of the iLO. Required." msgstr "" -#: ironic/drivers/modules/ilo/common.py:63 +#: ironic/drivers/modules/ilo/common.py:66 msgid "username for the iLO with administrator privileges. Required." msgstr "" -#: ironic/drivers/modules/ilo/common.py:65 +#: ironic/drivers/modules/ilo/common.py:68 msgid "password for ilo_username. Required." msgstr "" -#: ironic/drivers/modules/ilo/common.py:68 +#: ironic/drivers/modules/ilo/common.py:71 msgid "port to be used for iLO operations. Optional." msgstr "" -#: ironic/drivers/modules/ilo/common.py:69 +#: ironic/drivers/modules/ilo/common.py:72 msgid "timeout (in seconds) for iLO operations. Optional." msgstr "" -#: ironic/drivers/modules/ilo/common.py:108 +#: ironic/drivers/modules/ilo/common.py:79 +msgid "" +"new password for iLO. Required if the clean step 'reset_ilo_credential' " +"is enabled." +msgstr "" + +#: ironic/drivers/modules/ilo/common.py:115 #, python-format msgid "" "The following required iLO parameters are missing from the node's " "driver_info: %s" msgstr "" -#: ironic/drivers/modules/ilo/common.py:129 +#: ironic/drivers/modules/ilo/common.py:136 #, python-format msgid "" "The following iLO parameters from the node's driver_info should be " "integers: %s" msgstr "" -#: ironic/drivers/modules/ilo/common.py:177 +#: ironic/drivers/modules/ilo/common.py:184 msgid "iLO license check" msgstr "" -#: ironic/drivers/modules/ilo/common.py:289 +#: ironic/drivers/modules/ilo/common.py:296 #, python-format msgid "Inserting virtual media %s" msgstr "" -#: ironic/drivers/modules/ilo/common.py:319 +#: ironic/drivers/modules/ilo/common.py:326 +#: ironic/drivers/modules/ilo/common.py:375 #, python-format msgid "Setting %s as boot mode" msgstr "" -#: ironic/drivers/modules/ilo/deploy.py:47 +#: ironic/drivers/modules/ilo/common.py:479 +#, python-format +msgid "Get secure boot mode for node %s." +msgstr "" + +#: ironic/drivers/modules/ilo/common.py:512 +#, python-format +msgid "Setting secure boot to %(flag)s for node %(node)s." +msgstr "" + +#: ironic/drivers/modules/ilo/deploy.py:61 msgid "UUID (from Glance) of the deployment ISO. Required." msgstr "" -#: ironic/drivers/modules/ilo/deploy.py:177 +#: ironic/drivers/modules/ilo/deploy.py:218 msgid "" "Error validating iLO virtual media deploy. Some parameters were missing " "in node's driver_info" msgstr "" -#: ironic/drivers/modules/ilo/deploy.py:446 +#: ironic/drivers/modules/ilo/deploy.py:695 msgid "Missing 'console_port' parameter in node's driver_info." msgstr "" -#: ironic/drivers/modules/ilo/management.py:100 +#: ironic/drivers/modules/ilo/inspect.py:101 +#, python-format +msgid "Server didn't return the key(s): %(key)s" +msgstr "" + +#: ironic/drivers/modules/ilo/inspect.py:106 +#, python-format +msgid "" +"Essential properties are expected to be in dictionary format, received " +"%(properties)s from node %(node)s." +msgstr "" + +#: ironic/drivers/modules/ilo/inspect.py:112 +#, python-format +msgid "The node %s didn't return 'properties' as the key with inspection." +msgstr "" + +#: ironic/drivers/modules/ilo/inspect.py:118 +#, python-format +msgid "Node %(node)s didn't return MACs %(macs)s in dictionary format." +msgstr "" + +#: ironic/drivers/modules/ilo/inspect.py:123 +#, python-format +msgid "The node %s didn't return 'macs' as the key with inspection." +msgstr "" + +#: ironic/drivers/modules/ilo/inspect.py:172 +#, python-format +msgid "" +"Node %(node)s has invalid capabilities string %(capabilities)s, unable to" +" modify the node properties['capabilities'] string" +msgstr "" + +#: ironic/drivers/modules/ilo/inspect.py:180 +#, python-format +msgid "" +"The expected format of capabilities from inspection is dictionary while " +"node %(node)s returned %(capabilities)s." +msgstr "" + +#: ironic/drivers/modules/ilo/inspect.py:249 +#, python-format +msgid "Inspecting hardware (get_power_state) on %s" +msgstr "" + +#: ironic/drivers/modules/ilo/management.py:91 +#, python-format +msgid "Clean step '%s' not found. 'proliantutils' package needs to be updated." +msgstr "" + +#: ironic/drivers/modules/ilo/management.py:102 +#, python-format +msgid "Clean step %(step)s failed on node %(node)s with error: %(err)s" +msgstr "" + +#: ironic/drivers/modules/ilo/management.py:166 msgid "Get boot device" msgstr "" -#: ironic/drivers/modules/ilo/management.py:143 +#: ironic/drivers/modules/ilo/management.py:209 #, python-format msgid "Setting %s as boot device" msgstr "" -#: ironic/drivers/modules/ilo/power.py:88 +#: ironic/drivers/modules/ilo/power.py:95 msgid "iLO get_power_status" msgstr "" -#: ironic/drivers/modules/ilo/power.py:152 +#: ironic/drivers/modules/ilo/power.py:159 #: ironic/drivers/modules/irmc/power.py:60 #, python-format msgid "_set_power_state called with invalid power state '%s'" msgstr "" -#: ironic/drivers/modules/ilo/power.py:161 +#: ironic/drivers/modules/ilo/power.py:168 msgid "iLO set_power_state" msgstr "" -#: ironic/drivers/modules/irmc/common.py:46 +#: ironic/drivers/modules/irmc/common.py:50 msgid "IP address or hostname of the iRMC. Required." msgstr "" -#: ironic/drivers/modules/irmc/common.py:47 +#: ironic/drivers/modules/irmc/common.py:51 msgid "Username for the iRMC with administrator privileges. Required." msgstr "" -#: ironic/drivers/modules/irmc/common.py:49 +#: ironic/drivers/modules/irmc/common.py:53 msgid "Password for irmc_username. Required." msgstr "" -#: ironic/drivers/modules/irmc/common.py:52 +#: ironic/drivers/modules/irmc/common.py:56 msgid "" "Port to be used for iRMC operations; either 80 or 443. The default value " "is 443. Optional." msgstr "" -#: ironic/drivers/modules/irmc/common.py:54 +#: ironic/drivers/modules/irmc/common.py:58 msgid "" "Authentication method for iRMC operations; either 'basic' or 'digest'. " -"The default value is 'digest'. Optional." +"The default value is 'basic'. Optional." msgstr "" -#: ironic/drivers/modules/irmc/common.py:57 +#: ironic/drivers/modules/irmc/common.py:61 msgid "" "Timeout (in seconds) for iRMC operations. The default value is 60. " "Optional." msgstr "" -#: ironic/drivers/modules/irmc/common.py:82 +#: ironic/drivers/modules/irmc/common.py:63 +msgid "" +"Sensor data retrieval method; either 'ipmitool' or 'scci'. The default " +"value is 'ipmitool'. Optional." +msgstr "" + +#: ironic/drivers/modules/irmc/common.py:89 #, python-format msgid "Missing the following iRMC parameters in node's driver_info: %s." msgstr "" -#: ironic/drivers/modules/irmc/common.py:96 -#: ironic/drivers/modules/irmc/common.py:99 -#, python-format -msgid "'%s' has unsupported value." +#: ironic/drivers/modules/irmc/common.py:103 +msgid "'irmc_auth_method' has unsupported value." msgstr "" -#: ironic/drivers/modules/irmc/common.py:102 -#, python-format -msgid "'%s' is not integer type." +#: ironic/drivers/modules/irmc/common.py:106 +msgid "'irmc_port' has unsupported value." msgstr "" -#: ironic/drivers/modules/irmc/common.py:104 +#: ironic/drivers/modules/irmc/common.py:109 +msgid "'irmc_client_timeout' is not integer type." +msgstr "" + +#: ironic/drivers/modules/irmc/common.py:112 +msgid "'irmc_sensor_method' has unsupported value." +msgstr "" + +#: ironic/drivers/modules/irmc/common.py:114 #, python-format msgid "" "The following type errors were encountered while parsing driver_info:\n" @@ -1900,18 +2369,6 @@ msgstr "" msgid "An object of class %s is required here" msgstr "" -#: ironic/openstack/common/cliutils.py:271 -#, python-format -msgid "No %(name)s with a name or ID of '%(name_or_id)s' exists." -msgstr "" - -#: ironic/openstack/common/cliutils.py:279 -#, python-format -msgid "" -"Multiple %(name)s matches found for '%(name_or_id)s', use an ID to be " -"more specific." -msgstr "" - #: ironic/openstack/common/gettextutils.py:301 msgid "Message objects do not support addition." msgstr "" @@ -1922,16 +2379,17 @@ msgid "" "characters. Please use unicode() or translate() instead." msgstr "" -#: ironic/openstack/common/imageutils.py:75 +#: ironic/openstack/common/imageutils.py:76 #, python-format msgid "Invalid input value \"%s\"." msgstr "" -#: ironic/openstack/common/imageutils.py:104 +#: ironic/openstack/common/imageutils.py:105 msgid "Snapshot list encountered but no header found!" msgstr "" #: ironic/openstack/common/log.py:298 +#: ironic/openstack/common/versionutils.py:241 #, python-format msgid "Deprecated: %s" msgstr "" @@ -1947,6 +2405,7 @@ msgid "syslog facility must be one of: %s" msgstr "" #: ironic/openstack/common/log.py:715 +#: ironic/openstack/common/versionutils.py:259 #, python-format msgid "Fatal call to deprecated config: %(msg)s" msgstr "" @@ -1956,225 +2415,27 @@ msgstr "" msgid "Unexpected argument for periodic task creation: %(arg)s." msgstr "" -#: ironic/openstack/common/policy.py:111 -msgid "The JSON file that defines policies." -msgstr "" - -#: ironic/openstack/common/policy.py:114 -msgid "Default rule. Enforced when a requested rule is not found." -msgstr "" - -#: ironic/openstack/common/policy.py:118 -msgid "" -"Directories where policy configuration files are stored. They can be " -"relative to any directory in the search path defined by the config_dir " -"option, or absolute paths. The file defined by policy_file must exist for" -" these directories to be searched." -msgstr "" - -#: ironic/openstack/common/policy.py:142 -#, python-format -msgid "Policy doesn't allow %s to be performed." -msgstr "" - -#: ironic/openstack/common/policy.py:239 -#, python-format -msgid "Rules must be an instance of dict or Rules, got %s instead" -msgstr "" - -#: ironic/openstack/common/strutils.py:114 -#, python-format -msgid "Unrecognized value '%(val)s', acceptable values are: %(acceptable)s" -msgstr "" - -#: ironic/openstack/common/strutils.py:219 -#, python-format -msgid "Invalid unit system: \"%s\"" -msgstr "" - -#: ironic/openstack/common/strutils.py:228 -#, python-format -msgid "Invalid string format: %s" -msgstr "" - -#: ironic/openstack/common/versionutils.py:88 +#: ironic/openstack/common/versionutils.py:108 #, python-format msgid "" "%(what)s is deprecated as of %(as_of)s in favor of %(in_favor_of)s and " "may be removed in %(remove_in)s." msgstr "" -#: ironic/openstack/common/versionutils.py:92 +#: ironic/openstack/common/versionutils.py:112 #, python-format msgid "" "%(what)s is deprecated as of %(as_of)s and may be removed in " "%(remove_in)s. It will not be superseded." msgstr "" -#: ironic/openstack/common/versionutils.py:96 +#: ironic/openstack/common/versionutils.py:116 #, python-format msgid "%(what)s is deprecated as of %(as_of)s in favor of %(in_favor_of)s." msgstr "" -#: ironic/openstack/common/versionutils.py:99 +#: ironic/openstack/common/versionutils.py:119 #, python-format msgid "%(what)s is deprecated as of %(as_of)s. It will not be superseded." msgstr "" -#: ironic/openstack/common/apiclient/base.py:224 -#: ironic/openstack/common/apiclient/base.py:381 -#, python-format -msgid "No %(name)s matching %(args)s." -msgstr "" - -#: ironic/openstack/common/apiclient/client.py:233 -msgid "Cannot find endpoint or token for request" -msgstr "" - -#: ironic/openstack/common/apiclient/client.py:356 -#, python-format -msgid "" -"Invalid %(api_name)s client version '%(version)s'. Must be one of: " -"%(version_map)s" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:41 -#, python-format -msgid "Missing arguments: %s" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:74 -#, python-format -msgid "Authentication failed. Missing options: %s" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:83 -#, python-format -msgid "AuthSystemNotFound: %s" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:106 -#, python-format -msgid "AmbiguousEndpoints: %s" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:114 -msgid "HTTP Error" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:134 -msgid "HTTP Redirection" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:142 -msgid "HTTP Client Error" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:151 -msgid "HTTP Server Error" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:161 -msgid "Multiple Choices" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:170 -msgid "Bad Request" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:180 -msgid "Unauthorized" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:189 -msgid "Payment Required" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:199 -msgid "Forbidden" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:209 -msgid "Not Found" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:219 -msgid "Method Not Allowed" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:229 -msgid "Not Acceptable" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:238 -msgid "Proxy Authentication Required" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:247 -msgid "Request Timeout" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:257 -msgid "Conflict" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:267 -msgid "Gone" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:277 -msgid "Length Required" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:287 -msgid "Precondition Failed" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:296 -msgid "Request Entity Too Large" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:313 -msgid "Request-URI Too Long" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:323 -msgid "Unsupported Media Type" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:333 -msgid "Requested Range Not Satisfiable" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:342 -msgid "Expectation Failed" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:352 -msgid "Unprocessable Entity" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:361 -msgid "Internal Server Error" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:372 -msgid "Not Implemented" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:382 -msgid "Bad Gateway" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:391 -msgid "Service Unavailable" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:401 -msgid "Gateway Timeout" -msgstr "" - -#: ironic/openstack/common/apiclient/exceptions.py:410 -msgid "HTTP Version Not Supported" -msgstr "" - diff --git a/ironic/locale/pt_BR/LC_MESSAGES/ironic-log-critical.po b/ironic/locale/pt_BR/LC_MESSAGES/ironic-log-critical.po new file mode 100644 index 000000000..712adbb10 --- /dev/null +++ b/ironic/locale/pt_BR/LC_MESSAGES/ironic-log-critical.po @@ -0,0 +1,25 @@ +# Translations template for ironic. +# Copyright (C) 2015 ORGANIZATION +# This file is distributed under the same license as the ironic project. +# +# Translators: +# Lucas Alvares Gomes <lucasagomes@gmail.com>, 2015 +msgid "" +msgstr "" +"Project-Id-Version: Ironic\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2015-04-08 06:27+0000\n" +"PO-Revision-Date: 2015-03-30 09:01+0000\n" +"Last-Translator: Lucas Alvares Gomes <lucasagomes@gmail.com>\n" +"Language-Team: Portuguese (Brazil) (http://www.transifex.com/projects/p/" +"ironic/language/pt_BR/)\n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 1.3\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: ironic/conductor/manager.py:297 +msgid "Failed to start keepalive" +msgstr "Falha ao inicar o keep alive" diff --git a/ironic/openstack/common/service.py b/ironic/openstack/common/service.py index e4eed8a2e..694edf271 100644 --- a/ironic/openstack/common/service.py +++ b/ironic/openstack/common/service.py @@ -199,18 +199,30 @@ class ServiceWrapper(object): class ProcessLauncher(object): - def __init__(self): - """Constructor.""" + _signal_handlers_set = set() + + @classmethod + def _handle_class_signals(cls, *args, **kwargs): + for handler in cls._signal_handlers_set: + handler(*args, **kwargs) + def __init__(self, wait_interval=0.01): + """Constructor. + + :param wait_interval: The interval to sleep for between checks + of child process exit. + """ self.children = {} self.sigcaught = None self.running = True + self.wait_interval = wait_interval rfd, self.writepipe = os.pipe() self.readpipe = eventlet.greenio.GreenPipe(rfd, 'r') self.handle_signal() def handle_signal(self): - _set_signals_handler(self._handle_signal) + self._signal_handlers_set.add(self._handle_signal) + _set_signals_handler(self._handle_class_signals) def _handle_signal(self, signo, frame): self.sigcaught = signo @@ -329,8 +341,8 @@ class ProcessLauncher(object): def _wait_child(self): try: - # Block while any of child processes have exited - pid, status = os.waitpid(0, 0) + # Don't block if no child processes have exited + pid, status = os.waitpid(0, os.WNOHANG) if not pid: return None except OSError as exc: @@ -359,6 +371,10 @@ class ProcessLauncher(object): while self.running: wrap = self._wait_child() if not wrap: + # Yield to other threads if no children have exited + # Sleep for a short time to avoid excessive CPU usage + # (see bug #1095346) + eventlet.greenthread.sleep(self.wait_interval) continue while self.running and len(wrap.children) < wrap.workers: self._start_child(wrap) @@ -383,8 +399,14 @@ class ProcessLauncher(object): if not _is_sighup_and_daemon(self.sigcaught): break + cfg.CONF.reload_config_files() + for service in set( + [wrap.service for wrap in self.children.values()]): + service.reset() + for pid in self.children: os.kill(pid, signal.SIGHUP) + self.running = True self.sigcaught = None except eventlet.greenlet.GreenletExit: diff --git a/ironic/openstack/common/versionutils.py b/ironic/openstack/common/versionutils.py index dce07a82e..83bc04eac 100644 --- a/ironic/openstack/common/versionutils.py +++ b/ironic/openstack/common/versionutils.py @@ -17,6 +17,7 @@ Helpers for comparing version strings. """ +import copy import functools import inspect import logging @@ -32,13 +33,19 @@ LOG = logging.getLogger(__name__) CONF = cfg.CONF -opts = [ +deprecated_opts = [ cfg.BoolOpt('fatal_deprecations', default=False, help='Enables or disables fatal status of deprecations.'), ] +def list_opts(): + """Entry point for oslo.config-generator. + """ + return [(None, copy.deepcopy(deprecated_opts))] + + class deprecated(object): """A decorator to mark callables as deprecated. @@ -232,7 +239,7 @@ def report_deprecated_feature(logger, msg, *args, **kwargs): fatal deprecations. """ stdmsg = _("Deprecated: %s") % msg - CONF.register_opts(opts) + CONF.register_opts(deprecated_opts) if CONF.fatal_deprecations: logger.critical(stdmsg, *args, **kwargs) raise DeprecatedConfig(msg=stdmsg) diff --git a/ironic/tests/api/v1/test_nodes.py b/ironic/tests/api/v1/test_nodes.py index c2b510173..dbb95daaf 100644 --- a/ironic/tests/api/v1/test_nodes.py +++ b/ironic/tests/api/v1/test_nodes.py @@ -1813,17 +1813,14 @@ class TestPut(test_api_base.FunctionalTest): True, 'test-topic') def test_provision_node_in_maintenance_fail(self): - with mock.patch.object(rpcapi.ConductorAPI, 'do_node_deploy') as dnd: - self.node.maintenance = True - self.node.save() - dnd.side_effect = exception.NodeInMaintenance(op='provisioning', - node=self.node.uuid) + self.node.maintenance = True + self.node.save() - ret = self.put_json('/nodes/%s/states/provision' % self.node.uuid, - {'target': states.ACTIVE}, - expect_errors=True) - self.assertEqual(400, ret.status_code) - self.assertTrue(ret.json['error_message']) + ret = self.put_json('/nodes/%s/states/provision' % self.node.uuid, + {'target': states.ACTIVE}, + expect_errors=True) + self.assertEqual(400, ret.status_code) + self.assertTrue(ret.json['error_message']) @mock.patch.object(rpcapi.ConductorAPI, 'set_boot_device') def test_set_boot_device(self, mock_sbd): diff --git a/ironic/tests/db/sqlalchemy/test_migrations.py b/ironic/tests/db/sqlalchemy/test_migrations.py index 8ddd3382f..37b539e02 100644 --- a/ironic/tests/db/sqlalchemy/test_migrations.py +++ b/ironic/tests/db/sqlalchemy/test_migrations.py @@ -15,15 +15,9 @@ # under the License. """ -Tests for database migrations. This test case reads the configuration -file test_migrations.conf for database connection settings -to use in the tests. For each connection found in the config file, -the test case runs a series of test cases to ensure that migrations work -properly. - -There are also "opportunistic" tests for both mysql and postgresql in here, -which allows testing against all 3 databases (sqlite in memory, mysql, pg) in -a properly configured unit test environment. +Tests for database migrations. There are "opportunistic" tests for both mysql +and postgresql in here, which allows testing against these databases in a +properly configured unit test environment. For the opportunistic testing you need to set up a db named 'openstack_citest' with user 'openstack_citest' and password 'openstack_citest' on localhost. diff --git a/ironic/tests/db/test_conductor.py b/ironic/tests/db/test_conductor.py index d93aad120..1ff182615 100644 --- a/ironic/tests/db/test_conductor.py +++ b/ironic/tests/db/test_conductor.py @@ -64,7 +64,7 @@ class DbConductorTestCase(base.DbTestCase): self.dbapi.unregister_conductor, c.hostname) - @mock.patch.object(timeutils, 'utcnow') + @mock.patch.object(timeutils, 'utcnow', autospec=True) def test_touch_conductor(self, mock_utcnow): test_time = datetime.datetime(2000, 1, 1, 0, 0) mock_utcnow.return_value = test_time @@ -110,7 +110,7 @@ class DbConductorTestCase(base.DbTestCase): self.assertEqual('hostname2', node2.reservation) self.assertIsNone(node3.reservation) - @mock.patch.object(timeutils, 'utcnow') + @mock.patch.object(timeutils, 'utcnow', autospec=True) def test_get_active_driver_dict_one_host_no_driver(self, mock_utcnow): h = 'fake-host' expected = {} @@ -120,7 +120,7 @@ class DbConductorTestCase(base.DbTestCase): result = self.dbapi.get_active_driver_dict() self.assertEqual(expected, result) - @mock.patch.object(timeutils, 'utcnow') + @mock.patch.object(timeutils, 'utcnow', autospec=True) def test_get_active_driver_dict_one_host_one_driver(self, mock_utcnow): h = 'fake-host' d = 'fake-driver' @@ -131,7 +131,7 @@ class DbConductorTestCase(base.DbTestCase): result = self.dbapi.get_active_driver_dict() self.assertEqual(expected, result) - @mock.patch.object(timeutils, 'utcnow') + @mock.patch.object(timeutils, 'utcnow', autospec=True) def test_get_active_driver_dict_one_host_many_drivers(self, mock_utcnow): h = 'fake-host' d1 = 'driver-one' @@ -143,7 +143,7 @@ class DbConductorTestCase(base.DbTestCase): result = self.dbapi.get_active_driver_dict() self.assertEqual(expected, result) - @mock.patch.object(timeutils, 'utcnow') + @mock.patch.object(timeutils, 'utcnow', autospec=True) def test_get_active_driver_dict_many_hosts_one_driver(self, mock_utcnow): h1 = 'host-one' h2 = 'host-two' @@ -156,7 +156,7 @@ class DbConductorTestCase(base.DbTestCase): result = self.dbapi.get_active_driver_dict() self.assertEqual(expected, result) - @mock.patch.object(timeutils, 'utcnow') + @mock.patch.object(timeutils, 'utcnow', autospec=True) def test_get_active_driver_dict_many_hosts_and_drivers(self, mock_utcnow): h1 = 'host-one' h2 = 'host-two' @@ -172,7 +172,7 @@ class DbConductorTestCase(base.DbTestCase): result = self.dbapi.get_active_driver_dict() self.assertEqual(expected, result) - @mock.patch.object(timeutils, 'utcnow') + @mock.patch.object(timeutils, 'utcnow', autospec=True) def test_get_active_driver_dict_with_old_conductor(self, mock_utcnow): past = datetime.datetime(2000, 1, 1, 0, 0) present = past + datetime.timedelta(minutes=2) diff --git a/ironic/tests/db/test_nodes.py b/ironic/tests/db/test_nodes.py index 7e3450345..be44943b4 100644 --- a/ironic/tests/db/test_nodes.py +++ b/ironic/tests/db/test_nodes.py @@ -136,7 +136,7 @@ class DbNodeTestCase(base.DbTestCase): res = self.dbapi.get_node_list(filters={'maintenance': False}) self.assertEqual([node1.id], [r.id for r in res]) - @mock.patch.object(timeutils, 'utcnow') + @mock.patch.object(timeutils, 'utcnow', autospec=True) def test_get_nodeinfo_list_provision(self, mock_utcnow): past = datetime.datetime(2000, 1, 1, 0, 0) next = past + datetime.timedelta(minutes=8) @@ -161,7 +161,7 @@ class DbNodeTestCase(base.DbTestCase): states.DEPLOYWAIT}) self.assertEqual([node2.id], [r[0] for r in res]) - @mock.patch.object(timeutils, 'utcnow') + @mock.patch.object(timeutils, 'utcnow', autospec=True) def test_get_nodeinfo_list_inspection(self, mock_utcnow): past = datetime.datetime(2000, 1, 1, 0, 0) next = past + datetime.timedelta(minutes=8) @@ -354,7 +354,7 @@ class DbNodeTestCase(base.DbTestCase): node2.id, {'instance_uuid': new_i_uuid}) - @mock.patch.object(timeutils, 'utcnow') + @mock.patch.object(timeutils, 'utcnow', autospec=True) def test_update_node_provision(self, mock_utcnow): mocked_time = datetime.datetime(2000, 1, 1, 0, 0) mock_utcnow.return_value = mocked_time @@ -378,7 +378,7 @@ class DbNodeTestCase(base.DbTestCase): self.assertIsNone(res['provision_updated_at']) self.assertIsNone(res['inspection_started_at']) - @mock.patch.object(timeutils, 'utcnow') + @mock.patch.object(timeutils, 'utcnow', autospec=True) def test_update_node_inspection_started_at(self, mock_utcnow): mocked_time = datetime.datetime(2000, 1, 1, 0, 0) mock_utcnow.return_value = mocked_time @@ -390,7 +390,7 @@ class DbNodeTestCase(base.DbTestCase): timeutils.normalize_time(result)) self.assertIsNone(res['inspection_finished_at']) - @mock.patch.object(timeutils, 'utcnow') + @mock.patch.object(timeutils, 'utcnow', autospec=True) def test_update_node_inspection_finished_at(self, mock_utcnow): mocked_time = datetime.datetime(2000, 1, 1, 0, 0) mock_utcnow.return_value = mocked_time diff --git a/ironic/tests/drivers/amt/test_vendor.py b/ironic/tests/drivers/amt/test_vendor.py index f16079349..a6ddfc769 100644 --- a/ironic/tests/drivers/amt/test_vendor.py +++ b/ironic/tests/drivers/amt/test_vendor.py @@ -37,7 +37,8 @@ class AMTPXEVendorPassthruTestCase(db_base.DbTestCase): driver='pxe_amt', driver_info=INFO_DICT) def test_vendor_routes(self): - expected = ['heartbeat', 'pass_deploy_info'] + expected = ['heartbeat', 'pass_deploy_info', + 'pass_bootloader_install_info'] with task_manager.acquire(self.context, self.node.uuid, shared=True) as task: vendor_routes = task.driver.vendor.vendor_routes diff --git a/ironic/tests/drivers/ilo/test_deploy.py b/ironic/tests/drivers/ilo/test_deploy.py index 300e582fd..f44e532b9 100644 --- a/ironic/tests/drivers/ilo/test_deploy.py +++ b/ironic/tests/drivers/ilo/test_deploy.py @@ -124,7 +124,7 @@ class IloDeployPrivateMethodsTestCase(db_base.DbTestCase): boot_iso_expected = 'boot-iso-uuid' self.assertEqual(boot_iso_expected, boot_iso_actual) - @mock.patch.object(driver_utils, 'get_boot_mode_for_deploy') + @mock.patch.object(deploy_utils, 'get_boot_mode_for_deploy') @mock.patch.object(images, 'get_image_properties') @mock.patch.object(ilo_deploy, '_parse_deploy_info') def test__get_boot_iso_uefi_no_glance_image(self, @@ -293,19 +293,6 @@ class IloDeployPrivateMethodsTestCase(db_base.DbTestCase): ilo_deploy._update_secure_boot_mode(task, False) self.assertFalse(func_set_secure_boot_mode.called) - @mock.patch.object(driver_utils, 'add_node_capability') - @mock.patch.object(driver_utils, 'rm_node_capability') - def test__enable_uefi_capability(self, func_rm_node_capability, - func_add_node_capability): - with task_manager.acquire(self.context, self.node.uuid, - shared=False) as task: - ilo_deploy._enable_uefi_capability(task) - func_rm_node_capability.assert_called_once_with(task, - 'boot_mode') - func_add_node_capability.assert_called_once_with(task, - 'boot_mode', - 'uefi') - @mock.patch.object(ilo_common, 'set_secure_boot_mode') @mock.patch.object(ilo_common, 'get_secure_boot_mode') def test__disable_secure_boot_false(self, @@ -349,67 +336,86 @@ class IloDeployPrivateMethodsTestCase(db_base.DbTestCase): self.assertFalse(returned_state) @mock.patch.object(ilo_common, 'update_boot_mode') - @mock.patch.object(deploy_utils, 'is_secure_boot_requested') @mock.patch.object(ilo_deploy, '_disable_secure_boot') @mock.patch.object(manager_utils, 'node_power_action') def test__prepare_node_for_deploy(self, func_node_power_action, func_disable_secure_boot, - func_is_secure_boot_requested, func_update_boot_mode): with task_manager.acquire(self.context, self.node.uuid, shared=False) as task: func_disable_secure_boot.return_value = False - func_is_secure_boot_requested.return_value = False ilo_deploy._prepare_node_for_deploy(task) func_node_power_action.assert_called_once_with(task, states.POWER_OFF) func_disable_secure_boot.assert_called_once_with(task) - func_is_secure_boot_requested.assert_called_once_with(task.node) func_update_boot_mode.assert_called_once_with(task) + bootmode = driver_utils.get_node_capability(task.node, "boot_mode") + self.assertIsNone(bootmode) @mock.patch.object(ilo_common, 'update_boot_mode') - @mock.patch.object(deploy_utils, 'is_secure_boot_requested') @mock.patch.object(ilo_deploy, '_disable_secure_boot') @mock.patch.object(manager_utils, 'node_power_action') def test__prepare_node_for_deploy_sec_boot_on(self, func_node_power_action, func_disable_secure_boot, - func_is_secure_boot_req, func_update_boot_mode): with task_manager.acquire(self.context, self.node.uuid, shared=False) as task: func_disable_secure_boot.return_value = True - func_is_secure_boot_req.return_value = False ilo_deploy._prepare_node_for_deploy(task) func_node_power_action.assert_called_once_with(task, states.POWER_OFF) func_disable_secure_boot.assert_called_once_with(task) - func_is_secure_boot_req.assert_called_once_with(task.node) self.assertFalse(func_update_boot_mode.called) + ret_boot_mode = task.node.instance_info['deploy_boot_mode'] + self.assertEqual('uefi', ret_boot_mode) + bootmode = driver_utils.get_node_capability(task.node, "boot_mode") + self.assertIsNone(bootmode) + + @mock.patch.object(ilo_common, 'update_boot_mode') + @mock.patch.object(ilo_deploy, '_disable_secure_boot') + @mock.patch.object(manager_utils, 'node_power_action') + def test__prepare_node_for_deploy_inst_info(self, + func_node_power_action, + func_disable_secure_boot, + func_update_boot_mode): + instance_info = {'capabilities': '{"secure_boot": "true"}'} + with task_manager.acquire(self.context, self.node.uuid, + shared=False) as task: + func_disable_secure_boot.return_value = False + task.node.instance_info = instance_info + ilo_deploy._prepare_node_for_deploy(task) + func_node_power_action.assert_called_once_with(task, + states.POWER_OFF) + func_disable_secure_boot.assert_called_once_with(task) + func_update_boot_mode.assert_called_once_with(task) + bootmode = driver_utils.get_node_capability(task.node, "boot_mode") + self.assertIsNone(bootmode) + deploy_boot_mode = task.node.instance_info.get('deploy_boot_mode') + self.assertIsNone(deploy_boot_mode) @mock.patch.object(ilo_common, 'update_boot_mode') - @mock.patch.object(ilo_deploy, '_enable_uefi_capability') - @mock.patch.object(deploy_utils, 'is_secure_boot_requested') @mock.patch.object(ilo_deploy, '_disable_secure_boot') @mock.patch.object(manager_utils, 'node_power_action') - def test__prepare_node_for_deploy_sec_boot_req(self, - func_node_power_action, - func_disable_secure_boot, - func_is_secure_boot_req, - func_enable_uefi_cap, - func_update_boot_mode): + def test__prepare_node_for_deploy_sec_boot_on_inst_info(self, + func_node_power_action, + func_disable_secure_boot, + func_update_boot_mode): + instance_info = {'capabilities': '{"secure_boot": "true"}'} with task_manager.acquire(self.context, self.node.uuid, shared=False) as task: func_disable_secure_boot.return_value = True - func_is_secure_boot_req.return_value = True + task.node.instance_info = instance_info ilo_deploy._prepare_node_for_deploy(task) func_node_power_action.assert_called_once_with(task, states.POWER_OFF) func_disable_secure_boot.assert_called_once_with(task) - func_is_secure_boot_req.assert_called_once_with(task.node) - func_enable_uefi_cap.assert_called_once_with(task) self.assertFalse(func_update_boot_mode.called) + bootmode = driver_utils.get_node_capability(task.node, "boot_mode") + self.assertIsNone(bootmode) + deploy_boot_mode = task.node.instance_info.get('deploy_boot_mode') + self.assertIsNone(deploy_boot_mode) class IloVirtualMediaIscsiDeployTestCase(db_base.DbTestCase): @@ -744,6 +750,18 @@ class VendorPassthruTestCase(db_base.DbTestCase): get_deploy_info_mock.assert_called_once_with(task.node, foo='bar') + @mock.patch.object(iscsi_deploy, 'validate_pass_bootloader_info_input', + autospec=True) + def test_validate_pass_bootloader_install_info(self, + validate_mock): + with task_manager.acquire(self.context, self.node.uuid, + shared=True) as task: + kwargs = {'address': '1.2.3.4', 'key': 'fake-key', + 'status': 'SUCCEEDED', 'error': ''} + task.driver.vendor.validate( + task, method='pass_bootloader_install_info', **kwargs) + validate_mock.assert_called_once_with(task, kwargs) + @mock.patch.object(iscsi_deploy, 'get_deploy_info') def test_validate_heartbeat(self, get_deploy_info_mock): with task_manager.acquire(self.context, self.node.uuid, @@ -752,7 +770,22 @@ class VendorPassthruTestCase(db_base.DbTestCase): vendor.validate(task, method='heartbeat', foo='bar') self.assertFalse(get_deploy_info_mock.called) - @mock.patch.object(deploy_utils, 'notify_deploy_complete') + @mock.patch.object(iscsi_deploy, 'validate_bootloader_install_status', + autospec=True) + @mock.patch.object(iscsi_deploy, 'finish_deploy', autospec=True) + def test_pass_bootloader_install_info(self, finish_deploy_mock, + validate_input_mock): + kwargs = {'method': 'pass_deploy_info', 'address': '123456'} + self.node.provision_state = states.DEPLOYWAIT + self.node.target_provision_state = states.ACTIVE + self.node.save() + with task_manager.acquire(self.context, self.node.uuid, + shared=False) as task: + task.driver.vendor.pass_bootloader_install_info(task, **kwargs) + finish_deploy_mock.assert_called_once_with(task, '123456') + validate_input_mock.assert_called_once_with(task, kwargs) + + @mock.patch.object(deploy_utils, 'notify_ramdisk_to_proceed') @mock.patch.object(ilo_deploy, '_update_secure_boot_mode') @mock.patch.object(ilo_common, 'update_boot_mode') @mock.patch.object(manager_utils, 'node_set_boot_device') @@ -765,7 +798,7 @@ class VendorPassthruTestCase(db_base.DbTestCase): setup_vmedia_mock, set_boot_device_mock, func_update_boot_mode, func_update_secure_boot_mode, - notify_deploy_complete_mock): + notify_ramdisk_to_proceed_mock): kwargs = {'method': 'pass_deploy_info', 'address': '123456'} continue_deploy_mock.return_value = {'root uuid': 'root-uuid'} get_boot_iso_mock.return_value = 'boot-iso' @@ -791,7 +824,7 @@ class VendorPassthruTestCase(db_base.DbTestCase): self.assertEqual('boot-iso', task.node.instance_info['ilo_boot_iso']) - notify_deploy_complete_mock.assert_called_once_with('123456') + notify_ramdisk_to_proceed_mock.assert_called_once_with('123456') @mock.patch.object(ilo_common, 'cleanup_vmedia_boot') def test_pass_deploy_info_bad(self, cleanup_vmedia_boot_mock): @@ -810,16 +843,19 @@ class VendorPassthruTestCase(db_base.DbTestCase): self.assertEqual(states.NOSTATE, task.node.target_provision_state) self.assertFalse(cleanup_vmedia_boot_mock.called) + @mock.patch.object(ilo_deploy, '_update_secure_boot_mode', autospec=True) + @mock.patch.object(ilo_common, 'update_boot_mode', autospec=True) @mock.patch.object(manager_utils, 'node_power_action') @mock.patch.object(iscsi_deploy, 'continue_deploy') @mock.patch.object(ilo_common, 'cleanup_vmedia_boot') @mock.patch.object(ilo_deploy, '_get_boot_iso') def test_pass_deploy_info_create_boot_iso_fail(self, get_iso_mock, - cleanup_vmedia_boot_mock, continue_deploy_mock, node_power_mock): + cleanup_vmedia_boot_mock, continue_deploy_mock, node_power_mock, + update_boot_mode_mock, update_secure_boot_mode_mock): kwargs = {'address': '123456'} continue_deploy_mock.return_value = {'root uuid': 'root-uuid'} get_iso_mock.side_effect = exception.ImageCreationFailed( - image_type='iso', error="error") + image_type='iso', error="error") self.node.provision_state = states.DEPLOYWAIT self.node.target_provision_state = states.ACTIVE self.node.save() @@ -829,6 +865,8 @@ class VendorPassthruTestCase(db_base.DbTestCase): task.driver.vendor.pass_deploy_info(task, **kwargs) cleanup_vmedia_boot_mock.assert_called_once_with(task) + update_boot_mode_mock.assert_called_once_with(task) + update_secure_boot_mode_mock.assert_called_once_with(task, True) continue_deploy_mock.assert_called_once_with(task, **kwargs) get_iso_mock.assert_called_once_with(task, 'root-uuid') node_power_mock.assert_called_once_with(task, states.POWER_OFF) @@ -836,22 +874,57 @@ class VendorPassthruTestCase(db_base.DbTestCase): self.assertEqual(states.ACTIVE, task.node.target_provision_state) self.assertIsNotNone(task.node.last_error) - @mock.patch.object(deploy_utils, 'notify_deploy_complete') + @mock.patch.object(iscsi_deploy, 'finish_deploy', autospec=True) + @mock.patch.object(deploy_utils, 'notify_ramdisk_to_proceed', + autospec=True) @mock.patch.object(manager_utils, 'node_set_boot_device') @mock.patch.object(ilo_deploy, '_update_secure_boot_mode') @mock.patch.object(ilo_common, 'update_boot_mode') @mock.patch.object(iscsi_deploy, 'continue_deploy') @mock.patch.object(ilo_common, 'cleanup_vmedia_boot') - def _test_pass_deploy_info_localboot(self, cleanup_vmedia_boot_mock, - continue_deploy_mock, - func_update_boot_mode, - func_update_secure_boot_mode, - set_boot_device_mock, - notify_deploy_complete_mock): + def test_pass_deploy_info_boot_option_local( + self, cleanup_vmedia_boot_mock, continue_deploy_mock, + func_update_boot_mode, func_update_secure_boot_mode, + set_boot_device_mock, notify_ramdisk_to_proceed_mock, + finish_deploy_mock): + kwargs = {'method': 'pass_deploy_info', 'address': '123456'} + continue_deploy_mock.return_value = {'root uuid': '<some-uuid>'} + self.node.instance_info = {'capabilities': '{"boot_option": "local"}'} + self.node.provision_state = states.DEPLOYWAIT + self.node.target_provision_state = states.ACTIVE + self.node.save() + with task_manager.acquire(self.context, self.node.uuid, + shared=False) as task: + vendor = task.driver.vendor + vendor.pass_deploy_info(task, **kwargs) + + cleanup_vmedia_boot_mock.assert_called_once_with(task) + continue_deploy_mock.assert_called_once_with(task, **kwargs) + set_boot_device_mock.assert_called_once_with(task, + boot_devices.DISK, + persistent=True) + func_update_boot_mode.assert_called_once_with(task) + func_update_secure_boot_mode.assert_called_once_with(task, True) + notify_ramdisk_to_proceed_mock.assert_called_once_with('123456') + self.assertEqual(states.DEPLOYWAIT, task.node.provision_state) + self.assertEqual(states.ACTIVE, task.node.target_provision_state) + self.assertFalse(finish_deploy_mock.called) + + @mock.patch.object(iscsi_deploy, 'finish_deploy', autospec=True) + @mock.patch.object(manager_utils, 'node_set_boot_device', autospec=True) + @mock.patch.object(ilo_deploy, '_update_secure_boot_mode', autospec=True) + @mock.patch.object(ilo_common, 'update_boot_mode', autospec=True) + @mock.patch.object(iscsi_deploy, 'continue_deploy', autospec=True) + @mock.patch.object(ilo_common, 'cleanup_vmedia_boot', autospec=True) + def _test_pass_deploy_info_whole_disk_image( + self, cleanup_vmedia_boot_mock, continue_deploy_mock, + func_update_boot_mode, func_update_secure_boot_mode, + set_boot_device_mock, notify_ramdisk_to_proceed_mock): kwargs = {'method': 'pass_deploy_info', 'address': '123456'} continue_deploy_mock.return_value = {'root uuid': '<some-uuid>'} + self.node.driver_internal_info = {'is_whole_disk_image': True} self.node.provision_state = states.DEPLOYWAIT self.node.target_provision_state = states.ACTIVE self.node.save() @@ -867,19 +940,15 @@ class VendorPassthruTestCase(db_base.DbTestCase): persistent=True) func_update_boot_mode.assert_called_once_with(task) func_update_secure_boot_mode.assert_called_once_with(task, True) - notify_deploy_complete_mock.assert_called_once_with('123456') - self.assertEqual(states.ACTIVE, task.node.provision_state) - self.assertEqual(states.NOSTATE, task.node.target_provision_state) + iscsi_deploy.finish_deploy.assert_called_once_with(task, '123456') - def test_pass_deploy_info_boot_option_local(self): + def test_pass_deploy_info_whole_disk_image_local(self): self.node.instance_info = {'capabilities': '{"boot_option": "local"}'} self.node.save() - self._test_pass_deploy_info_localboot() + self._test_pass_deploy_info_whole_disk_image() def test_pass_deploy_info_whole_disk_image(self): - self.node.driver_internal_info = {'is_whole_disk_image': True} - self.node.save() - self._test_pass_deploy_info_localboot() + self._test_pass_deploy_info_whole_disk_image() @mock.patch.object(ilo_deploy, '_update_secure_boot_mode') @mock.patch.object(ilo_common, 'update_boot_mode') @@ -1075,7 +1144,8 @@ class IloPXEVendorPassthruTestCase(db_base.DbTestCase): driver='pxe_ilo', driver_info=INFO_DICT) def test_vendor_routes(self): - expected = ['heartbeat', 'pass_deploy_info'] + expected = ['heartbeat', 'pass_deploy_info', + 'pass_bootloader_install_info'] with task_manager.acquire(self.context, self.node.uuid, shared=True) as task: vendor_routes = task.driver.vendor.vendor_routes @@ -1115,8 +1185,10 @@ class IloVirtualMediaAgentVendorInterfaceTestCase(db_base.DbTestCase): @mock.patch.object(agent.AgentVendorInterface, 'reboot_to_instance') @mock.patch.object(agent.AgentVendorInterface, 'check_deploy_success') + @mock.patch.object(ilo_common, 'update_boot_mode') @mock.patch.object(ilo_deploy, '_update_secure_boot_mode') def test_reboot_to_instance(self, func_update_secure_boot_mode, + func_update_boot_mode, check_deploy_success_mock, agent_reboot_to_instance_mock): kwargs = {'address': '123456'} @@ -1125,14 +1197,17 @@ class IloVirtualMediaAgentVendorInterfaceTestCase(db_base.DbTestCase): shared=False) as task: task.driver.vendor.reboot_to_instance(task, **kwargs) check_deploy_success_mock.called_once_with(task.node) + func_update_boot_mode.assert_called_once_with(task) func_update_secure_boot_mode.assert_called_once_with(task, True) agent_reboot_to_instance_mock.assert_called_once_with(task, **kwargs) @mock.patch.object(agent.AgentVendorInterface, 'reboot_to_instance') @mock.patch.object(agent.AgentVendorInterface, 'check_deploy_success') + @mock.patch.object(ilo_common, 'update_boot_mode') @mock.patch.object(ilo_deploy, '_update_secure_boot_mode') def test_reboot_to_instance_deploy_fail(self, func_update_secure_boot_mode, + func_update_boot_mode, check_deploy_success_mock, agent_reboot_to_instance_mock): kwargs = {'address': '123456'} @@ -1141,6 +1216,7 @@ class IloVirtualMediaAgentVendorInterfaceTestCase(db_base.DbTestCase): shared=False) as task: task.driver.vendor.reboot_to_instance(task, **kwargs) check_deploy_success_mock.called_once_with(task.node) + self.assertFalse(func_update_boot_mode.called) self.assertFalse(func_update_secure_boot_mode.called) agent_reboot_to_instance_mock.assert_called_once_with(task, **kwargs) diff --git a/ironic/tests/drivers/test_deploy_utils.py b/ironic/tests/drivers/test_deploy_utils.py index f86719028..fdb6653a3 100644 --- a/ironic/tests/drivers/test_deploy_utils.py +++ b/ironic/tests/drivers/test_deploy_utils.py @@ -1470,6 +1470,27 @@ class ParseInstanceInfoCapabilitiesTestCase(tests_base.TestCase): self.node.instance_info = {'capabilities': {"secure_boot": "invalid"}} self.assertFalse(utils.is_secure_boot_requested(self.node)) + def test_get_boot_mode_for_deploy_using_capabilities(self): + properties = {'capabilities': 'boot_mode:uefi,cap2:value2'} + self.node.properties = properties + + result = utils.get_boot_mode_for_deploy(self.node) + self.assertEqual('uefi', result) + + def test_get_boot_mode_for_deploy_using_instance_info_cap(self): + instance_info = {'capabilities': {'secure_boot': 'True'}} + self.node.instance_info = instance_info + + result = utils.get_boot_mode_for_deploy(self.node) + self.assertEqual('uefi', result) + + def test_get_boot_mode_for_deploy_using_instance_info(self): + instance_info = {'deploy_boot_mode': 'bios'} + self.node.instance_info = instance_info + + result = utils.get_boot_mode_for_deploy(self.node) + self.assertEqual('bios', result) + class TrySetBootDeviceTestCase(db_base.DbTestCase): diff --git a/ironic/tests/drivers/test_iscsi_deploy.py b/ironic/tests/drivers/test_iscsi_deploy.py index 0899f1702..a0b1f40ba 100644 --- a/ironic/tests/drivers/test_iscsi_deploy.py +++ b/ironic/tests/drivers/test_iscsi_deploy.py @@ -778,3 +778,118 @@ class IscsiDeployMethodsTestCase(db_base.DbTestCase): self.assertEqual(states.DEPLOYFAIL, self.node.provision_state) self.assertEqual(states.ACTIVE, self.node.target_provision_state) self.assertIsNotNone(self.node.last_error) + + def test_validate_pass_bootloader_info_input(self): + params = {'key': 'some-random-key', 'address': '1.2.3.4', + 'error': '', 'status': 'SUCCEEDED'} + with task_manager.acquire(self.context, self.node.uuid, + shared=False) as task: + task.node.instance_info['deploy_key'] = 'some-random-key' + # Assert that the method doesn't raise + iscsi_deploy.validate_pass_bootloader_info_input(task, params) + + def test_validate_pass_bootloader_info_missing_status(self): + params = {'key': 'some-random-key', 'address': '1.2.3.4'} + with task_manager.acquire(self.context, self.node.uuid, + shared=False) as task: + self.assertRaises(exception.MissingParameterValue, + iscsi_deploy.validate_pass_bootloader_info_input, + task, params) + + def test_validate_pass_bootloader_info_missing_key(self): + params = {'status': 'SUCCEEDED', 'address': '1.2.3.4'} + with task_manager.acquire(self.context, self.node.uuid, + shared=False) as task: + self.assertRaises(exception.MissingParameterValue, + iscsi_deploy.validate_pass_bootloader_info_input, + task, params) + + def test_validate_pass_bootloader_info_missing_address(self): + params = {'status': 'SUCCEEDED', 'key': 'some-random-key'} + with task_manager.acquire(self.context, self.node.uuid, + shared=False) as task: + self.assertRaises(exception.MissingParameterValue, + iscsi_deploy.validate_pass_bootloader_info_input, + task, params) + + def test_validate_pass_bootloader_info_input_invalid_key(self): + params = {'key': 'some-other-key', 'address': '1.2.3.4', + 'status': 'SUCCEEDED'} + with task_manager.acquire(self.context, self.node.uuid, + shared=False) as task: + task.node.instance_info['deploy_key'] = 'some-random-key' + self.assertRaises(exception.InvalidParameterValue, + iscsi_deploy.validate_pass_bootloader_info_input, + task, params) + + def test_validate_bootloader_install_status(self): + kwargs = {'key': 'abcdef', 'status': 'SUCCEEDED', 'error': ''} + with task_manager.acquire(self.context, self.node.uuid, + shared=False) as task: + task.node.instance_info['deploy_key'] = 'abcdef' + # Nothing much to assert except that it shouldn't raise. + iscsi_deploy.validate_bootloader_install_status(task, kwargs) + + @mock.patch.object(deploy_utils, 'set_failed_state', autospec=True) + def test_validate_bootloader_install_status_install_failed( + self, set_fail_state_mock): + kwargs = {'key': 'abcdef', 'status': 'FAILED', 'error': 'some-error'} + with task_manager.acquire(self.context, self.node.uuid, + shared=False) as task: + task.node.provision_state = states.DEPLOYING + task.node.target_provision_state = states.ACTIVE + task.node.instance_info['deploy_key'] = 'abcdef' + self.assertRaises(exception.InstanceDeployFailure, + iscsi_deploy.validate_bootloader_install_status, + task, kwargs) + set_fail_state_mock.assert_called_once_with(task, mock.ANY) + + @mock.patch.object(deploy_utils, 'notify_ramdisk_to_proceed', + autospec=True) + def test_finish_deploy(self, notify_mock): + self.node.provision_state = states.DEPLOYING + self.node.target_provision_state = states.ACTIVE + self.node.save() + with task_manager.acquire(self.context, self.node.uuid, + shared=False) as task: + iscsi_deploy.finish_deploy(task, '1.2.3.4') + notify_mock.assert_called_once_with('1.2.3.4') + self.assertEqual(states.ACTIVE, task.node.provision_state) + self.assertEqual(states.NOSTATE, task.node.target_provision_state) + + @mock.patch.object(deploy_utils, 'set_failed_state', autospec=True) + @mock.patch.object(deploy_utils, 'notify_ramdisk_to_proceed', + autospec=True) + def test_finish_deploy_notify_fails(self, notify_mock, + set_fail_state_mock): + with task_manager.acquire(self.context, self.node.uuid, + shared=False) as task: + notify_mock.side_effect = RuntimeError() + self.assertRaises(exception.InstanceDeployFailure, + iscsi_deploy.finish_deploy, task, '1.2.3.4') + set_fail_state_mock.assert_called_once_with(task, mock.ANY) + + @mock.patch.object(manager_utils, 'node_power_action') + @mock.patch.object(deploy_utils, 'notify_ramdisk_to_proceed', + autospec=True) + def test_finish_deploy_ssh_with_local_boot(self, notify_mock, + node_power_mock): + instance_info = dict(INST_INFO_DICT) + instance_info['capabilities'] = {'boot_option': 'local'} + n = { + 'uuid': uuidutils.generate_uuid(), + 'driver': 'fake_ssh', + 'instance_info': instance_info, + 'provision_state': states.DEPLOYING, + 'target_provision_state': states.ACTIVE, + } + mgr_utils.mock_the_extension_manager(driver="fake_ssh") + node = obj_utils.create_test_node(self.context, **n) + + with task_manager.acquire(self.context, node.uuid, + shared=False) as task: + iscsi_deploy.finish_deploy(task, '1.2.3.4') + notify_mock.assert_called_once_with('1.2.3.4') + self.assertEqual(states.ACTIVE, task.node.provision_state) + self.assertEqual(states.NOSTATE, task.node.target_provision_state) + node_power_mock.assert_called_once_with(task, states.REBOOT) diff --git a/ironic/tests/drivers/test_pxe.py b/ironic/tests/drivers/test_pxe.py index a8ed19c86..0c6168c86 100644 --- a/ironic/tests/drivers/test_pxe.py +++ b/ironic/tests/drivers/test_pxe.py @@ -681,6 +681,33 @@ class PXEDriverTestCase(db_base.DbTestCase): address='123456', iqn='aaa-bbb', key='fake-12345') + @mock.patch.object(iscsi_deploy, 'validate_pass_bootloader_info_input', + autospec=True) + def test_vendor_passthru_pass_bootloader_install_info(self, + validate_mock): + with task_manager.acquire(self.context, self.node.uuid, + shared=True) as task: + kwargs = {'address': '1.2.3.4', 'key': 'fake-key', + 'status': 'SUCCEEDED', 'error': ''} + task.driver.vendor.validate( + task, method='pass_bootloader_install_info', **kwargs) + validate_mock.assert_called_once_with(task, kwargs) + + @mock.patch.object(iscsi_deploy, 'validate_bootloader_install_status', + autospec=True) + @mock.patch.object(iscsi_deploy, 'finish_deploy', autospec=True) + def test_pass_bootloader_install_info(self, finish_deploy_mock, + validate_input_mock): + kwargs = {'method': 'pass_deploy_info', 'address': '123456'} + self.node.provision_state = states.DEPLOYWAIT + self.node.target_provision_state = states.ACTIVE + self.node.save() + with task_manager.acquire(self.context, self.node.uuid, + shared=False) as task: + task.driver.vendor.pass_bootloader_install_info(task, **kwargs) + finish_deploy_mock.assert_called_once_with(task, '123456') + validate_input_mock.assert_called_once_with(task, kwargs) + @mock.patch.object(pxe, '_get_image_info') @mock.patch.object(pxe, '_cache_ramdisk_kernel') @mock.patch.object(pxe, '_build_pxe_config_options') @@ -901,7 +928,7 @@ class PXEDriverTestCase(db_base.DbTestCase): @mock.patch.object(pxe_utils, 'clean_up_pxe_config') @mock.patch.object(manager_utils, 'node_set_boot_device') - @mock.patch.object(deploy_utils, 'notify_deploy_complete') + @mock.patch.object(deploy_utils, 'notify_ramdisk_to_proceed') @mock.patch.object(deploy_utils, 'switch_pxe_config') @mock.patch.object(iscsi_deploy, 'InstanceImageCache') @mock.patch.object(deploy_utils, 'deploy_partition_image') @@ -932,8 +959,6 @@ class PXEDriverTestCase(db_base.DbTestCase): task, address='123456', iqn='aaa-bbb', key='fake-56789') self.node.refresh() - self.assertEqual(states.ACTIVE, self.node.provision_state) - self.assertEqual(states.NOSTATE, self.node.target_provision_state) self.assertEqual(states.POWER_ON, self.node.power_state) self.assertIn('root_uuid_or_disk_id', self.node.driver_internal_info) self.assertIsNone(self.node.last_error) @@ -957,7 +982,7 @@ class PXEDriverTestCase(db_base.DbTestCase): @mock.patch.object(pxe_utils, 'clean_up_pxe_config') @mock.patch.object(manager_utils, 'node_set_boot_device') - @mock.patch.object(deploy_utils, 'notify_deploy_complete') + @mock.patch.object(deploy_utils, 'notify_ramdisk_to_proceed') @mock.patch.object(deploy_utils, 'switch_pxe_config') @mock.patch.object(iscsi_deploy, 'InstanceImageCache') @mock.patch.object(deploy_utils, 'deploy_disk_image') @@ -993,8 +1018,6 @@ class PXEDriverTestCase(db_base.DbTestCase): key='fake-56789') self.node.refresh() - self.assertEqual(states.ACTIVE, self.node.provision_state) - self.assertEqual(states.NOSTATE, self.node.target_provision_state) self.assertEqual(states.POWER_ON, self.node.power_state) self.assertIsNone(self.node.last_error) self.assertFalse(os.path.exists(token_path)) @@ -1017,15 +1040,23 @@ class PXEDriverTestCase(db_base.DbTestCase): def test_pass_deploy_info_deploy(self): self._test_pass_deploy_info_deploy(False) + self.assertEqual(states.ACTIVE, self.node.provision_state) + self.assertEqual(states.NOSTATE, self.node.target_provision_state) def test_pass_deploy_info_localboot(self): self._test_pass_deploy_info_deploy(True) + self.assertEqual(states.DEPLOYWAIT, self.node.provision_state) + self.assertEqual(states.ACTIVE, self.node.target_provision_state) def test_pass_deploy_info_whole_disk_image(self): self._test_pass_deploy_info_whole_disk_image(False) + self.assertEqual(states.ACTIVE, self.node.provision_state) + self.assertEqual(states.NOSTATE, self.node.target_provision_state) def test_pass_deploy_info_whole_disk_image_localboot(self): self._test_pass_deploy_info_whole_disk_image(True) + self.assertEqual(states.ACTIVE, self.node.provision_state) + self.assertEqual(states.NOSTATE, self.node.target_provision_state) def test_pass_deploy_info_invalid(self): self.node.power_state = states.POWER_ON @@ -1056,7 +1087,8 @@ class PXEDriverTestCase(db_base.DbTestCase): "pass_deploy_info was not called once.") def test_vendor_routes(self): - expected = ['heartbeat', 'pass_deploy_info'] + expected = ['heartbeat', 'pass_deploy_info', + 'pass_bootloader_install_info'] with task_manager.acquire(self.context, self.node.uuid, shared=True) as task: vendor_routes = task.driver.vendor.vendor_routes diff --git a/ironic/tests/drivers/test_utils.py b/ironic/tests/drivers/test_utils.py index 5eb9b5ace..cd14b464f 100644 --- a/ironic/tests/drivers/test_utils.py +++ b/ironic/tests/drivers/test_utils.py @@ -112,27 +112,6 @@ class UtilsTestCase(db_base.DbTestCase): self.assertEqual('a:b,c:d,a:b', task.node.properties['capabilities']) - def test_rm_node_capability(self): - with task_manager.acquire(self.context, self.node.uuid, - shared=False) as task: - task.node.properties['capabilities'] = 'a:b' - driver_utils.rm_node_capability(task, 'a') - self.assertIsNone(task.node.properties['capabilities']) - - def test_rm_node_capability_exists(self): - with task_manager.acquire(self.context, self.node.uuid, - shared=False) as task: - task.node.properties['capabilities'] = 'a:b,c:d,x:y' - self.assertIsNone(driver_utils.rm_node_capability(task, 'c')) - self.assertEqual('a:b,x:y', task.node.properties['capabilities']) - - def test_rm_node_capability_non_existent(self): - with task_manager.acquire(self.context, self.node.uuid, - shared=False) as task: - task.node.properties['capabilities'] = 'a:b' - self.assertIsNone(driver_utils.rm_node_capability(task, 'x')) - self.assertEqual('a:b', task.node.properties['capabilities']) - def test_validate_capability(self): properties = {'capabilities': 'cat:meow,cap2:value2'} self.node.properties = properties @@ -191,17 +170,3 @@ class UtilsTestCase(db_base.DbTestCase): self.assertRaises(exception.InvalidParameterValue, driver_utils.validate_secure_boot_capability, self.node) - - def test_get_boot_mode_for_deploy_using_capabilities(self): - properties = {'capabilities': 'boot_mode:uefi,cap2:value2'} - self.node.properties = properties - - result = driver_utils.get_boot_mode_for_deploy(self.node) - self.assertEqual('uefi', result) - - def test_get_boot_mode_for_deploy_using_instance_info(self): - instance_info = {'deploy_boot_mode': 'uefi'} - self.node.instance_info = instance_info - - result = driver_utils.get_boot_mode_for_deploy(self.node) - self.assertEqual('uefi', result) diff --git a/ironic/tests/test_glance_service.py b/ironic/tests/test_glance_service.py index 266b86f12..8482ed751 100644 --- a/ironic/tests/test_glance_service.py +++ b/ironic/tests/test_glance_service.py @@ -18,6 +18,7 @@ import datetime import filecmp import os import tempfile +import time import mock from oslo_context import context @@ -458,7 +459,8 @@ class TestGlanceImageService(base.TestCase): self.assertEqual(self.NOW_DATETIME, image_meta['created_at']) self.assertEqual(self.NOW_DATETIME, image_meta['updated_at']) - def test_download_with_retries(self): + @mock.patch.object(time, 'sleep', autospec=True) + def test_download_with_retries(self, mock_sleep): tries = [0] class MyGlanceStubClient(stubs.StubGlanceClient): @@ -487,6 +489,7 @@ class TestGlanceImageService(base.TestCase): tries = [0] self.config(glance_num_retries=1, group='glance') stub_service.download(image_id, writer) + self.assertTrue(mock_sleep.called) def test_download_file_url(self): # NOTE: only in v2 API diff --git a/tools/config/oslo.config.generator.rc b/tools/config/oslo.config.generator.rc index e224cf753..84c865ab5 100644 --- a/tools/config/oslo.config.generator.rc +++ b/tools/config/oslo.config.generator.rc @@ -1,2 +1,2 @@ -export IRONIC_CONFIG_GENERATOR_EXTRA_LIBRARIES='oslo.db oslo.messaging keystonemiddleware.auth_token' +export IRONIC_CONFIG_GENERATOR_EXTRA_LIBRARIES='oslo.db oslo.messaging keystonemiddleware.auth_token oslo.concurrency oslo.policy' export IRONIC_CONFIG_GENERATOR_EXTRA_MODULES= @@ -43,6 +43,7 @@ commands = bash tools/config/generate_sample.sh -b . -p ironic -o etc/ironic [testenv:gendocs] +setenv = PYTHONHASHSEED=0 sitepackages = False envdir = {toxworkdir}/venv commands = |