diff options
41 files changed, 1942 insertions, 1025 deletions
diff --git a/doc/source/deploy/cleaning.rst b/doc/source/deploy/cleaning.rst index b19b88a1b..8897bf46b 100644 --- a/doc/source/deploy/cleaning.rst +++ b/doc/source/deploy/cleaning.rst @@ -13,9 +13,14 @@ the tenant will get a consistent baremetal node deployed every time. Ironic implements cleaning by collecting a list of steps to perform on a node from each Power, Deploy, and Management driver assigned to the node. These steps are then arranged by priority and executed on the node when it is moved -to CLEANING state, if cleaning is enabled. +to cleaning state, if cleaning is enabled. -Ironic added support for cleaning used nodes in the Kilo release. +Typically, nodes move to cleaning state when moving from active -> available. +Nodes also traverse cleaning when going from manageable -> available. For a +full understanding of all state transitions into cleaning, please see +:ref:`states`. + +Ironic added support for cleaning nodes in the Kilo release. Enabling Cleaning @@ -41,8 +46,8 @@ In-band steps are performed by Ironic making API calls to a ramdisk running on the node using a Deploy driver. Currently, only the ironic-python-agent ramdisk used with an agent_* driver supports in-band cleaning. By default, ironic-python-agent ships with a minimal cleaning configuration, only erasing -disks. However, with this ramdisk, you can add your own clean_steps and/or -override default clean_steps with a custom Hardware Manager. +disks. However, with this ramdisk, you can add your own cleaning steps and/or +override default cleaning steps with a custom Hardware Manager. There is currently no support for in-band cleaning using the Ironic pxe ramdisk. @@ -81,12 +86,14 @@ to disable erase_devices, you'd use the following config:: agent_erase_devices_priority=0 -What clean_step is running? ---------------------------- -To check what clean_step the node is performing or attempted to perform and +What cleaning step is running? +------------------------------ +To check what cleaning step the node is performing or attempted to perform and failed, either query the node endpoint for the node or run ``ironic node-show -$node_ident`` and look at the 'clean_step' field. This will tell you which -step for which driver is or was (if in CLEANFAIL state) being executed. +$node_ident`` and look in the `internal_driver_info` field. The `clean_steps` +field will contain a list of all remaining steps with their priority, and the +first one listed is the step currently in progress or that the node failed +before going into cleanfail state. Should I disable cleaning? -------------------------- @@ -107,17 +114,17 @@ cleaning. Troubleshooting =============== -If cleaning fails on a node, the node will be put into CLEANFAIL state and +If cleaning fails on a node, the node will be put into cleanfail state and placed in maintenance mode, to prevent Ironic from taking actions on the node. -Nodes in CLEANFAIL will not be powered off, as the node might be in a state +Nodes in cleanfail will not be powered off, as the node might be in a state such that powering it off could damage the node or remove useful information about the nature of the cleaning failure. -A CLEANFAIL node can be moved to MANAGEABLE state, where they cannot be +A cleanfail node can be moved to manageable state, where they cannot be scheduled by Nova and you can safely attempt to fix the node. To move a node -from CLEANFAIL to MANAGEABLE: ``ironic node-set-provision-state manage``. +from cleanfail to manageable: ``ironic node-set-provision-state manage``. You can now take actions on the node, such as replacing a bad disk drive. Strategies for determining why a cleaning step failed include checking the @@ -125,7 +132,7 @@ Ironic conductor logs, viewing logs on the still-running ironic-python-agent (if an in-band step failed), or performing general hardware troubleshooting on the node. -When the node is repaired, you can move the node back to AVAILABLE state, to +When the node is repaired, you can move the node back to available state, to allow it to be scheduled by Nova. :: @@ -136,5 +143,5 @@ allow it to be scheduled by Nova. # Now, make the node available for scheduling by Nova ironic node-set-provision-state $node_ident provide -The node will begin cleaning from the start, and move to AVAILABLE state +The node will begin cleaning from the start, and move to available state when complete. diff --git a/doc/source/deploy/install-guide.rst b/doc/source/deploy/install-guide.rst index 2907ad54b..5e253746e 100644 --- a/doc/source/deploy/install-guide.rst +++ b/doc/source/deploy/install-guide.rst @@ -4,8 +4,9 @@ Bare Metal Service Installation Guide ===================================== -This document pertains to the Juno (2014.2) release of OpenStack. Users of -earlier releases may encounter some differences in configuration of services. +This document pertains to the Kilo (2015.1) release of OpenStack Ironic. Users +of earlier releases may encounter differences, and are encouraged to look at +earlier versions of this document for guidance. Service Overview @@ -14,23 +15,33 @@ Service Overview The Bare Metal Service is a collection of components that provides support to manage and provision physical machines. -Also known as the ``ironic`` project, the Bare Metal Service interacts with -several other OpenStack services such as: +Also known as the ``Ironic`` project, the Bare Metal Service may, depending +upon configuration, interact with several other OpenStack services. This +includes: -- the Identity Service (keystone) for request authentication and to +- the Telemetry (Ceilometer) for consuming the IPMI metrics +- the Identity Service (Keystone) for request authentication and to locate other OpenStack services -- the Image Service (glance) from which to retrieve images -- the Networking Service (neutron) for DHCP and network configuration -- the Compute Service (nova), which leverages the Bare Metal Service to - manage compute instances on bare metal. +- the Image Service (Glance) from which to retrieve images and image meta-data +- the Networking Service (Neutron) for DHCP and network configuration +- the Compute Service (Nova) works with Ironic and acts as a user-facing API + for instance management, while Ironic provides the admin/operator API for + hardware management. Nova also provides scheduling facilities (matching + flavors <-> images <-> hardware), tenant quotas, IP assignment, and other + services which Ironic does not, in and of itself, provide. + +- the Block Storage (Cinder) will provide volumes, but the aspect is not yet available. The Bare Metal Service includes the following components: -- ironic-api. A RESTful API that processes application requests by sending +- ironic-api: A RESTful API that processes application requests by sending them to the ironic-conductor over RPC. -- ironic-conductor. Adds/edits/deletes nodes; powers on/off nodes with +- ironic-conductor: Adds/edits/deletes nodes; powers on/off nodes with ipmi or ssh; provisions/deploys/decommissions bare metal nodes. -- Ironic client. A command-line interface (CLI) for interacting with +- ironic-python-agent: A python service which is run in a temporary ramdisk to + provide ironic-conductor service(s) with remote access and in-band hardware + control. +- python-ironicclient: A command-line interface (CLI) for interacting with the Bare Metal Service. Additionally, the Bare Metal Service has certain external dependencies, which are @@ -44,6 +55,20 @@ very similar to other OpenStack Services: - A queue. A central hub for passing messages. It should use the same implementation as that of the Compute Service (typically RabbitMQ). +Optionally, one may wish to utilize the following associated projects for +additional functionality: + +- ironic-discoverd_; An associated service which performs in-band hardware + introspection by PXE booting unregistered hardware into a "discovery ramdisk". +- diskimage-builder_; May be used to customize machine images, create and + discovery deploy ramdisks, if necessary. +.. _ironic-discoverd: https://github.com/stackforge/ironic-discoverd +.. _diskimage-builder: https://github.com/openstack/diskimage-builder + + +.. todo: include coreos-image-builder reference here, once the split is done + + Install and Configure Prerequisites =================================== @@ -676,21 +701,6 @@ steps on the Ironic conductor node to configure PXE UEFI environment. ironic node-update <node-uuid> add properties/capabilities='boot_mode:uefi' -#. For deploying signed images, update the Ironic node with ``secure_boot`` - capability in node's properties. - field:: - - ironic node-update <node-uuid> add properties/capabilities='secure_boot:true' - -#. Ensure the public key of the signed image is loaded into baremetal to deploy - signed images. - For HP Proliant Gen9 servers, one can enroll public key using iLO System - Utilities UI. Please refer to section ``Accessing Secure Boot options`` in - HP UEFI System Utilities User Guide http://www.hp.com/ctg/Manual/c04398276.pdf. - Also, one can refer to white paper on Secure Boot on Linux for HP Proliant - Servers at http://h20195.www2.hp.com/V2/getpdf.aspx/4AA5-4496ENW.pdf for - more details. - #. Make sure that bare metal node is configured to boot in UEFI boot mode and boot device is set to network/pxe. diff --git a/doc/source/deploy/upgrade-guide.rst b/doc/source/deploy/upgrade-guide.rst new file mode 100644 index 000000000..2ce9e0952 --- /dev/null +++ b/doc/source/deploy/upgrade-guide.rst @@ -0,0 +1,36 @@ +.. _upgrade-guide: + +===================================== +Bare Metal Service Upgrade Guide +===================================== + +This document outlines various steps and notes for operators to consider when +upgrading their Ironic-driven clouds from previous versions of OpenStack. + +The Ironic service is tightly coupled with the Ironic driver that is shipped +with Nova. Currently, some special considerations must be taken into account +when upgrading your cloud from previous versions of OpenStack. + +Upgrading from Juno to Kilo +=========================== + +When upgrading a cloud from Juno to Kilo, users must ensure the Nova +service is upgraded prior to upgrading the Ironic service. Additionally, +users need to set a special config flag in Nova prior to upgrading to ensure +the newer version of Nova is not attempting to take advantage of new Ironic +features until the Ironic service has been upgraded. The steps for upgrading +your Nova and Ironic services are as follows: + +- Edit nova.conf and ensure force_config_drive=False is set in the [DEFAULT] + group. Restart nova-compute if necessary. +- Install new Nova code, run database migrations +- Install new python-ironicclient code. +- Restart Nova services. +- Install new Ironic code, run database migrations, restart Ironic services. +- Edit nova.conf and set force_config_drive to your liking, restaring + nova-compute if necessary. + +Note that during the period between Nova's upgrade and Ironic's upgrades, +instances can still be provisioned to nodes, however, any attempt by users +to specify a config drive for an instance will cause error until Ironic's +upgrade has completed. diff --git a/doc/source/deploy/user-guide.rst b/doc/source/deploy/user-guide.rst index 59d290a4e..89d0fd272 100644 --- a/doc/source/deploy/user-guide.rst +++ b/doc/source/deploy/user-guide.rst @@ -47,8 +47,8 @@ Conceptual Architecture ======================= The following diagram shows the relationships and how all services come into -play during the provisioning of a physical server. (Note that Swift can be -used with Ironic, but is missing from this diagram.) +play during the provisioning of a physical server. (Note that Ceilometer and +Swift can be used with Ironic, but are missing from this diagram.) .. figure:: ../images/conceptual_architecture.png diff --git a/doc/source/drivers/amt.rst b/doc/source/drivers/amt.rst index 33e9701ac..ef6701a83 100644 --- a/doc/source/drivers/amt.rst +++ b/doc/source/drivers/amt.rst @@ -76,3 +76,14 @@ A detailed reference is available here, and a short guide follows below: ``amt_address``, and ``amt_username`` * Boot an instance + +.. note:: + It is recommended that nodes using the pxe_amt driver be deployed with the + `local boot`_ option. This is because the AMT firmware currently has no + support for setting a persistent boot device. Nodes deployed without the + `local boot`_ option could fail to boot if they are restarted outside of + Ironic's control (I.E. rebooted by a local user) because the node will + not attempt to PXE / network boot the kernel, using `local boot`_ solves this + known issue. + +.. _`local boot`: http://docs.openstack.org/developer/ironic/deploy/install-guide.html#local-boot-with-partition-images diff --git a/doc/source/drivers/ilo.rst b/doc/source/drivers/ilo.rst index b7737a57a..6df4ac22f 100644 --- a/doc/source/drivers/ilo.rst +++ b/doc/source/drivers/ilo.rst @@ -40,9 +40,9 @@ Prerequisites managing HP Proliant hardware. Install ``proliantutils`` [2]_ module on the Ironic conductor node. Minimum - version required is 2.0.1.:: + version required is 2.1.0.:: - $ pip install "proliantutils>=2.0.1" + $ pip install "proliantutils>=2.1.0" * ``ipmitool`` command must be present on the service node(s) where ``ironic-conductor`` is running. On most distros, this is provided as part @@ -80,9 +80,10 @@ This driver should work on HP Proliant Gen8 Servers and above with iLO 4. It has been tested with the following servers: * ProLiant DL380e Gen8 -* ProLiant DL380e Gen8 * ProLiant DL580 Gen8 UEFI * ProLiant DL180 Gen9 UEFI +* ProLiant DL380 Gen9 UEFI +* ProLiant DL580 Gen9 UEFI For more up-to-date information on server platform support info, refer iLO driver wiki [6]_. @@ -95,6 +96,7 @@ Features by the nova flavor's extra spec. * Always boot from network using Virtual Media. * UEFI Boot Support +* UEFI Secure Boot Support * Passing authentication token via secure, encrypted management network (Virtual Media). Provisioning is done using iSCSI over data network (like PXE driver), so this driver has the benefit of security @@ -247,7 +249,11 @@ node:: Boot modes ~~~~~~~~~~ -Refer boot_mode_support_ for more information. +Refer to `Boot mode support`_ section for more information. + +UEFI Secure Boot +~~~~~~~~~~~~~~~~ +Refer to `UEFI Secure Boot support`_ section for more information. agent_ilo driver ^^^^^^^^^^^^^^^^ @@ -271,7 +277,8 @@ This driver should work on HP Proliant Gen8 Servers and above with iLO 4. It has been tested with the following servers: * ProLiant DL380e Gen8 -* ProLiant DL380e Gen8 +* ProLiant DL380 Gen9 UEFI +* ProLiant DL580 Gen9 UEFI This driver supports only Gen 8 Class 0 systems (BIOS only). For more up-to-date information, check the iLO driver wiki [6]_. @@ -284,6 +291,8 @@ Features * IPA runs on the baremetal node and pulls the image directly from Swift. * IPA deployed instances always boots from local disk. * Segregates management info from data channel. +* UEFI Boot Support +* UEFI Secure Boot Support Requirements ~~~~~~~~~~~~ @@ -421,6 +430,14 @@ node:: ironic node-create -d agent_ilo -i ilo_address=<ilo-ip-address> -i ilo_username=<ilo-username> -i ilo_password=<ilo-password> -i ilo_deploy_iso=<glance-uuid-of-deploy-iso> +Boot modes +~~~~~~~~~~ +Refer to `Boot mode support`_ section for more information. + +UEFI Secure Boot +~~~~~~~~~~~~~~~~ +Refer to `UEFI Secure Boot support`_ section for more information. + pxe_ilo driver ^^^^^^^^^^^^^^ @@ -510,13 +527,11 @@ node:: Boot modes ~~~~~~~~~~ -Refer boot_mode_support_ for more information. +Refer to `Boot mode support`_ section for more information. Functionalities across drivers ============================== -.. _boot_mode_support: - Boot mode support ^^^^^^^^^^^^^^^^^ The following drivers support automatic detection and setting of boot @@ -524,6 +539,7 @@ mode (Legacy BIOS or UEFI). * ``pxe_ilo`` * ``iscsi_ilo`` +* ``agent_ilo`` The boot modes can be configured in Ironic in the following way: @@ -570,6 +586,53 @@ diskimage-builder command to build the image. For example:: disk-image-create ubuntu baremetal iso +UEFI Secure Boot support +^^^^^^^^^^^^^^^^^^^^^^^^ +The following drivers support UEFI secure boot deploy: + +* ``iscsi_ilo`` +* ``agent_ilo`` + +The UEFI secure boot mode can be configured in Ironic by adding +``secure_boot`` parameter in the ``capabilities`` parameter within +``properties`` field of an Ironic node. + +``secure_boot`` is a boolean parameter and takes value as ``true`` or +``false``. + +To enable ``secure_boot`` on a node add it to ``capabilities`` as below:: + + ironic node-update <node-uuid> add properties/capabilities='secure_boot:true' + +Nodes having ``secure_boot`` set to ``true`` may be requested by adding an +``extra_spec`` to the Nova flavor:: + + nova flavor-key ironic-test-3 set capabilities:secure_boot="true" + nova boot --flavor ironic-test-3 --image test-image instance-1 + +If ``capabilities`` is used in ``extra_spec`` as above, Nova scheduler +(``ComputeCapabilitiesFilter``) will match only Ironic nodes which have +the ``secure_boot`` set appropriately in ``properties/capabilities``. It will +filter out rest of the nodes. + +The above facility for matching in Nova can be used in heterogeneous +environments where there is a mix of machines supporting and not supporting +UEFI secure boot, and operator wants to provide a choice to the user +regarding secure boot. If the flavor doesn't contain ``secure_boot`` then +Nova scheduler will not consider secure boot mode as a placement criteria, +hence user may get a secure boot capable machine that matches with user +specified flavors but deployment would not use its secure boot capability. +Secure boot deploy would happen only when it is explicitly specified through +flavor. + +Ensure the public key of the signed image is loaded into baremetal to deploy +signed images. +For HP Proliant Gen9 servers, one can enroll public key using iLO System +Utilities UI. Please refer to section ``Accessing Secure Boot options`` in +HP UEFI System Utilities User Guide. [7]_ +One can also refer to white paper on Secure Boot for Linux on HP Proliant +servers for additional details. [8]_ + References ========== @@ -579,4 +642,6 @@ References .. [4] http://docs.openstack.org/developer/glance/configuring.html#configuring-the-swift-storage-backend .. [5] Ironic Python Agent - https://github.com/openstack/ironic-python-agent .. [6] https://wiki.openstack.org/wiki/Ironic/Drivers/iLODrivers +.. [7] HP UEFI System Utilities User Guide - http://www.hp.com/ctg/Manual/c04398276.pdf +.. [8] Secure Boot for Linux on HP Proliant servers http://h20195.www2.hp.com/V2/getpdf.aspx/4AA5-4496ENW.pdf diff --git a/doc/source/index.rst b/doc/source/index.rst index a3339207d..7ea533fdb 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -57,6 +57,7 @@ Overview deploy/user-guide deploy/install-guide + deploy/upgrade-guide deploy/drivers deploy/cleaning diff --git a/driver-requirements.txt b/driver-requirements.txt index db32cebf7..842c51799 100644 --- a/driver-requirements.txt +++ b/driver-requirements.txt @@ -5,7 +5,7 @@ # These are available on pypi ironic-discoverd>=1.0.0 -proliantutils>=2.0.1 +proliantutils>=2.1.0 pyghmi pysnmp python-scciclient diff --git a/etc/ironic/ironic.conf.sample b/etc/ironic/ironic.conf.sample index a8a1501a6..ccf368f0d 100644 --- a/etc/ironic/ironic.conf.sample +++ b/etc/ironic/ironic.conf.sample @@ -360,6 +360,11 @@ # set to 0, will not run during cleaning. (integer value) #agent_erase_devices_priority=<None> +# Whether Ironic will manage TFTP files for the deploy +# ramdisks. If set to False, you will need to configure your +# own TFTP server that allows booting the deploy ramdisks. +# (boolean value) +#manage_tftp=true # # Options defined in ironic.drivers.modules.agent_base_vendor 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/glance_service/base_image_service.py b/ironic/common/glance_service/base_image_service.py index 1b646d587..9a97cbbf0 100644 --- a/ironic/common/glance_service/base_image_service.py +++ b/ironic/common/glance_service/base_image_service.py @@ -22,6 +22,7 @@ import sys import time from glanceclient import client +from glanceclient import exc as glance_exc from oslo_config import cfg import sendfile import six.moves.urllib.parse as urlparse @@ -36,23 +37,23 @@ CONF = cfg.CONF def _translate_image_exception(image_id, exc_value): - if isinstance(exc_value, (exception.Forbidden, - exception.Unauthorized)): + if isinstance(exc_value, (glance_exc.Forbidden, + glance_exc.Unauthorized)): return exception.ImageNotAuthorized(image_id=image_id) - if isinstance(exc_value, exception.NotFound): + if isinstance(exc_value, glance_exc.NotFound): return exception.ImageNotFound(image_id=image_id) - if isinstance(exc_value, exception.BadRequest): + if isinstance(exc_value, glance_exc.BadRequest): return exception.Invalid(exc_value) return exc_value def _translate_plain_exception(exc_value): - if isinstance(exc_value, (exception.Forbidden, - exception.Unauthorized)): + if isinstance(exc_value, (glance_exc.Forbidden, + glance_exc.Unauthorized)): return exception.NotAuthorized(exc_value) - if isinstance(exc_value, exception.NotFound): + if isinstance(exc_value, glance_exc.NotFound): return exception.NotFound(exc_value) - if isinstance(exc_value, exception.BadRequest): + if isinstance(exc_value, glance_exc.BadRequest): return exception.Invalid(exc_value) return exc_value @@ -109,13 +110,13 @@ class BaseImageService(object): :raises: GlanceConnectionFailed """ - retry_excs = (exception.ServiceUnavailable, - exception.InvalidEndpoint, - exception.CommunicationError) - image_excs = (exception.Forbidden, - exception.Unauthorized, - exception.NotFound, - exception.BadRequest) + retry_excs = (glance_exc.ServiceUnavailable, + glance_exc.InvalidEndpoint, + glance_exc.CommunicationError) + image_excs = (glance_exc.Forbidden, + glance_exc.Unauthorized, + glance_exc.NotFound, + glance_exc.BadRequest) num_attempts = 1 + CONF.glance.glance_num_retries for attempt in range(1, num_attempts + 1): diff --git a/ironic/common/grub_conf.template b/ironic/common/grub_conf.template index 746a43d97..2a979d2d6 100644 --- a/ironic/common/grub_conf.template +++ b/ironic/common/grub_conf.template @@ -1,4 +1,8 @@ -menuentry "install" { -linux {{ linux }} {{ kernel_params }} -- -initrd {{ initrd }} +set default=0 +set timeout=5 +set hidden_timeout_quiet=false + +menuentry "boot_partition" { +linuxefi {{ linux }} {{ kernel_params }} -- +initrdefi {{ initrd }} } diff --git a/ironic/common/pxe_utils.py b/ironic/common/pxe_utils.py index 8174eccc4..09528a218 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 @@ -79,12 +80,20 @@ def _link_mac_pxe_configs(task): :param task: A TaskManager instance. """ - pxe_config_file_path = get_pxe_config_file_path(task.node.uuid) - for mac in driver_utils.get_node_mac_addresses(task): - mac_path = _get_pxe_mac_path(mac) + + def create_link(mac_path): utils.unlink_without_raise(mac_path) utils.create_link_without_raise(pxe_config_file_path, mac_path) + pxe_config_file_path = get_pxe_config_file_path(task.node.uuid) + for mac in driver_utils.get_node_mac_addresses(task): + create_link(_get_pxe_mac_path(mac)) + # TODO(lucasagomes): Backward compatibility with :hexraw, + # to be removed in M. + # see: https://bugs.launchpad.net/ironic/+bug/1441710 + if CONF.pxe.ipxe_enabled: + create_link(_get_pxe_mac_path(mac, delimiter='')) + def _link_ip_address_pxe_configs(task): """Link each IP address with the PXE configuration file. @@ -109,17 +118,20 @@ def _link_ip_address_pxe_configs(task): ip_address_path) -def _get_pxe_mac_path(mac): +def _get_pxe_mac_path(mac, delimiter=None): """Convert a MAC address into a PXE config file name. :param mac: A MAC address string in the format xx:xx:xx:xx:xx:xx. + :param delimiter: The MAC address delimiter. Defaults to dash ('-'). :returns: the path to the config file. """ - if CONF.pxe.ipxe_enabled: - mac_file_name = mac.replace(':', '').lower() - else: - mac_file_name = "01-" + mac.replace(":", "-").lower() + if delimiter is None: + delimiter = '-' + + mac_file_name = mac.replace(':', delimiter).lower() + if not CONF.pxe.ipxe_enabled: + mac_file_name = '01-' + mac_file_name return os.path.join(get_root_dir(), PXE_CFG_DIR_NAME, mac_file_name) @@ -191,7 +203,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 +217,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: @@ -220,6 +232,12 @@ def clean_up_pxe_config(task): else: for mac in driver_utils.get_node_mac_addresses(task): utils.unlink_without_raise(_get_pxe_mac_path(mac)) + # TODO(lucasagomes): Backward compatibility with :hexraw, + # to be removed in M. + # see: https://bugs.launchpad.net/ironic/+bug/1441710 + if CONF.pxe.ipxe_enabled: + utils.unlink_without_raise(_get_pxe_mac_path(mac, + delimiter='')) utils.rmtree_without_raise(os.path.join(get_root_dir(), task.node.uuid)) @@ -252,7 +270,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/agent.py b/ironic/drivers/modules/agent.py index c257d2c77..6a590c8c4 100644 --- a/ironic/drivers/modules/agent.py +++ b/ironic/drivers/modules/agent.py @@ -57,7 +57,14 @@ agent_opts = [ 'Python Agent ramdisk. If unset, will use the priority ' 'set in the ramdisk (defaults to 10 for the ' 'GenericHardwareManager). If set to 0, will not run ' - 'during cleaning.') + 'during cleaning.'), + cfg.BoolOpt('manage_tftp', + default=True, + help='Whether Ironic will manage TFTP files for the deploy ' + 'ramdisks. If set to False, you will need to configure ' + 'your own TFTP server that allows booting the deploy ' + 'ramdisks.' + ), ] CONF = cfg.CONF @@ -196,12 +203,13 @@ def build_instance_info_for_deploy(task): def _prepare_pxe_boot(task): """Prepare the files required for PXE booting the agent.""" - pxe_info = _get_tftp_image_info(task.node) - pxe_options = _build_pxe_config_options(task.node, pxe_info) - pxe_utils.create_pxe_config(task, - pxe_options, - CONF.agent.agent_pxe_config_template) - _cache_tftp_images(task.context, task.node, pxe_info) + if CONF.agent.manage_tftp: + pxe_info = _get_tftp_image_info(task.node) + pxe_options = _build_pxe_config_options(task.node, pxe_info) + pxe_utils.create_pxe_config(task, + pxe_options, + CONF.agent.agent_pxe_config_template) + _cache_tftp_images(task.context, task.node, pxe_info) def _do_pxe_boot(task, ports=None): @@ -220,13 +228,13 @@ def _do_pxe_boot(task, ports=None): def _clean_up_pxe(task): """Clean up left over PXE and DHCP files.""" - pxe_info = _get_tftp_image_info(task.node) - for label in pxe_info: - path = pxe_info[label][1] - utils.unlink_without_raise(path) - AgentTFTPImageCache().clean_up() - - pxe_utils.clean_up_pxe_config(task) + if CONF.agent.manage_tftp: + pxe_info = _get_tftp_image_info(task.node) + for label in pxe_info: + path = pxe_info[label][1] + utils.unlink_without_raise(path) + AgentTFTPImageCache().clean_up() + pxe_utils.clean_up_pxe_config(task) class AgentDeploy(base.DeployInterface): @@ -251,10 +259,11 @@ class AgentDeploy(base.DeployInterface): """ node = task.node params = {} - params['driver_info.deploy_kernel'] = node.driver_info.get( - 'deploy_kernel') - params['driver_info.deploy_ramdisk'] = node.driver_info.get( - 'deploy_ramdisk') + if CONF.agent.manage_tftp: + params['driver_info.deploy_kernel'] = node.driver_info.get( + 'deploy_kernel') + params['driver_info.deploy_ramdisk'] = node.driver_info.get( + 'deploy_ramdisk') image_source = node.instance_info.get('image_source') params['instance_info.image_source'] = image_source error_msg = _('Node %s failed to validate deploy image info. Some ' diff --git a/ironic/drivers/modules/boot.ipxe b/ironic/drivers/modules/boot.ipxe index 25a0ea8dc..3567dc029 100644 --- a/ironic/drivers/modules/boot.ipxe +++ b/ironic/drivers/modules/boot.ipxe @@ -1,7 +1,7 @@ #!ipxe # load the MAC-specific file or fail if it's not found -chain --autofree pxelinux.cfg/${mac:hexraw} || goto error_no_config +chain --autofree pxelinux.cfg/${mac:hexhyp} || goto error_no_config :error_no_config echo PXE boot failed. No configuration found for MAC ${mac} diff --git a/ironic/drivers/modules/deploy_utils.py b/ironic/drivers/modules/deploy_utils.py index fb8d01064..e6c2c48ef 100644 --- a/ironic/drivers/modules/deploy_utils.py +++ b/ironic/drivers/modules/deploy_utils.py @@ -970,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) @@ -1041,3 +1041,34 @@ 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 be used for deploy. + It returns 'uefi' if 'secure_boot' is set to 'true' in + 'instance_info/capabilities' of node. + Otherwise it returns value of 'boot_mode' in 'properties/capabilities' + of node if set. If that is not set, it returns boot mode in + 'instance_info/deploy_boot_mode' for the node. + It would return None if boot mode is present neither in 'capabilities' of + node 'properties' nor in node's 'instance_info' (which could also be None). + + :param node: an ironic node object. + :returns: 'bios', 'uefi' or None + """ + + if is_secure_boot_requested(node): + LOG.debug('Deploy boot mode is uefi for %s.', node.uuid) + return 'uefi' + + 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.lower() if boot_mode else boot_mode diff --git a/ironic/drivers/modules/ilo/common.py b/ironic/drivers/modules/ilo/common.py index f2281c671..1d1363d0d 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,12 +343,12 @@ 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", {'uuid': node.uuid, 'boot_mode': boot_mode}) - set_boot_mode(node, boot_mode.lower()) + set_boot_mode(node, boot_mode) return LOG.debug("Check pending boot mode for node %s.", node.uuid) @@ -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 28bed4d9d..86dc0c729 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 will be 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, diff --git a/ironic/drivers/modules/ipmitool.py b/ironic/drivers/modules/ipmitool.py index 2826dd1e7..ddebd68ef 100644 --- a/ironic/drivers/modules/ipmitool.py +++ b/ironic/drivers/modules/ipmitool.py @@ -111,6 +111,13 @@ ipmitool_command_options = { 'dual_bridge': ['ipmitool', '-m', '0', '-b', '0', '-t', '0', '-B', '0', '-T', '0', '-h']} +# Note(TheJulia): This string is hardcoded in ipmitool's lanplus driver +# and is substituted in return for the error code received from the IPMI +# controller. As of 1.8.15, no internationalization support appears to +# be in ipmitool which means the string should always be returned in this +# form regardless of locale. +IPMITOOL_RETRYABLE_FAILURES = ['insufficient resources for session'] + def _check_option_support(options): """Checks if the specific ipmitool options are supported on host. @@ -335,32 +342,68 @@ def _exec_ipmitool(driver_info, command): args.append(driver_info[name]) # specify retry timing more precisely, if supported + num_tries = max( + (CONF.ipmi.retry_timeout // CONF.ipmi.min_command_interval), 1) + if _is_option_supported('timing'): - num_tries = max( - (CONF.ipmi.retry_timeout // CONF.ipmi.min_command_interval), 1) args.append('-R') args.append(str(num_tries)) args.append('-N') args.append(str(CONF.ipmi.min_command_interval)) - # 'ipmitool' command will prompt password if there is no '-f' option, - # we set it to '\0' to write a password file to support empty password - with _make_password_file(driver_info['password'] or '\0') as pw_file: - args.append('-f') - args.append(pw_file) - args.extend(command.split(" ")) + end_time = (time.time() + CONF.ipmi.retry_timeout) + + while True: + num_tries = num_tries - 1 # NOTE(deva): ensure that no communications are sent to a BMC more # often than once every min_command_interval seconds. time_till_next_poll = CONF.ipmi.min_command_interval - ( time.time() - LAST_CMD_TIME.get(driver_info['address'], 0)) if time_till_next_poll > 0: time.sleep(time_till_next_poll) - try: - out, err = utils.execute(*args) - finally: - LAST_CMD_TIME[driver_info['address']] = time.time() - return out, err + # Resetting the list that will be utilized so the password arguments + # from any previous execution are preserved. + cmd_args = args[:] + # 'ipmitool' command will prompt password if there is no '-f' + # option, we set it to '\0' to write a password file to support + # empty password + with _make_password_file( + driver_info['password'] or '\0' + ) as pw_file: + cmd_args.append('-f') + cmd_args.append(pw_file) + cmd_args.extend(command.split(" ")) + try: + out, err = utils.execute(*cmd_args) + return out, err + except processutils.ProcessExecutionError as e: + with excutils.save_and_reraise_exception() as ctxt: + err_list = [x for x in IPMITOOL_RETRYABLE_FAILURES + if x in e.message] + if ((time.time() > end_time) or + (num_tries == 0) or + not err_list): + LOG.error(_LE('IPMI Error while attempting ' + '"%(cmd)s" for node %(node)s. ' + 'Error: %(error)s'), + { + 'node': driver_info['uuid'], + 'cmd': e.cmd, + 'error': e + }) + else: + ctxt.reraise = False + LOG.warning(_LW('IPMI Error encountered, retrying ' + '"%(cmd)s" for node %(node)s. ' + 'Error: %(error)s'), + { + 'node': driver_info['uuid'], + 'cmd': e.cmd, + 'error': e + }) + finally: + LAST_CMD_TIME[driver_info['address']] = time.time() def _sleep_time(iter): diff --git a/ironic/drivers/modules/iscsi_deploy.py b/ironic/drivers/modules/iscsi_deploy.py index 1f3234b74..ac7315d33 100644 --- a/ironic/drivers/modules/iscsi_deploy.py +++ b/ironic/drivers/modules/iscsi_deploy.py @@ -420,9 +420,9 @@ 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 boot_mode return "bios" @@ -447,13 +447,20 @@ def build_deploy_ramdisk_options(node): node.instance_info = i_info node.save() + # XXX(jroll) DIB relies on boot_option=local to decide whether or not to + # lay down a bootloader. Hack this for now; fix it for real in Liberty. + # See also bug #1441556. + boot_option = get_boot_option(node) + if node.driver_internal_info.get('is_whole_disk_image'): + boot_option = 'netboot' + deploy_options = { 'deployment_id': node['uuid'], 'deployment_key': deploy_key, 'iscsi_target_iqn': "iqn-%s" % node.uuid, 'ironic_api_url': ironic_api, 'disk': CONF.pxe.disk_devices, - 'boot_option': get_boot_option(node), + 'boot_option': boot_option, 'boot_mode': _get_boot_mode(node), # NOTE: The below entry is a temporary workaround for bug/1433812 'coreos.configdrive': 0, diff --git a/ironic/drivers/modules/pxe.py b/ironic/drivers/modules/pxe.py index 9a03f53c5..9ab3fc32c 100644 --- a/ironic/drivers/modules/pxe.py +++ b/ironic/drivers/modules/pxe.py @@ -242,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 @@ -353,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: @@ -447,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 @@ -485,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): @@ -626,7 +626,7 @@ class VendorPassthru(agent_base_vendor.BaseAgentVendor): 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) @@ -681,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/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/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/ilo/test_deploy.py b/ironic/tests/drivers/ilo/test_deploy.py index 8cc70cab4..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): @@ -1179,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'} @@ -1189,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'} @@ -1205,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_agent.py b/ironic/tests/drivers/test_agent.py index b9ea638e0..bb9675f3f 100644 --- a/ironic/tests/drivers/test_agent.py +++ b/ironic/tests/drivers/test_agent.py @@ -164,6 +164,14 @@ class TestAgentDeploy(db_base.DbTestCase): self.assertIn('driver_info.deploy_ramdisk', str(e)) self.assertIn('driver_info.deploy_kernel', str(e)) + def test_validate_driver_info_manage_tftp_false(self): + self.config(manage_tftp=False, group='agent') + self.node.driver_info = {} + self.node.save() + with task_manager.acquire( + self.context, self.node['uuid'], shared=False) as task: + self.driver.validate(task) + def test_validate_instance_info_missing_params(self): self.node.instance_info = {} self.node.save() @@ -199,6 +207,37 @@ class TestAgentDeploy(db_base.DbTestCase): self.assertRaises(exception.InvalidParameterValue, task.driver.deploy.validate, task) + @mock.patch.object(agent, '_cache_tftp_images') + @mock.patch.object(pxe_utils, 'create_pxe_config') + @mock.patch.object(agent, '_build_pxe_config_options') + @mock.patch.object(agent, '_get_tftp_image_info') + def test__prepare_pxe_boot(self, pxe_info_mock, options_mock, + create_mock, cache_mock): + with task_manager.acquire( + self.context, self.node['uuid'], shared=False) as task: + agent._prepare_pxe_boot(task) + pxe_info_mock.assert_called_once_with(task.node) + options_mock.assert_called_once_with(task.node, mock.ANY) + create_mock.assert_called_once_with( + task, mock.ANY, CONF.agent.agent_pxe_config_template) + cache_mock.assert_called_once_with(task.context, task.node, + mock.ANY) + + @mock.patch.object(agent, '_cache_tftp_images') + @mock.patch.object(pxe_utils, 'create_pxe_config') + @mock.patch.object(agent, '_build_pxe_config_options') + @mock.patch.object(agent, '_get_tftp_image_info') + def test__prepare_pxe_boot_manage_tftp_false( + self, pxe_info_mock, options_mock, create_mock, cache_mock): + self.config(manage_tftp=False, group='agent') + with task_manager.acquire( + self.context, self.node['uuid'], shared=False) as task: + agent._prepare_pxe_boot(task) + self.assertFalse(pxe_info_mock.called) + self.assertFalse(options_mock.called) + self.assertFalse(create_mock.called) + self.assertFalse(cache_mock.called) + @mock.patch.object(dhcp_factory.DHCPFactory, 'update_dhcp') @mock.patch('ironic.conductor.utils.node_set_boot_device') @mock.patch('ironic.conductor.utils.node_power_action') @@ -221,6 +260,36 @@ class TestAgentDeploy(db_base.DbTestCase): power_mock.assert_called_once_with(task, states.POWER_OFF) self.assertEqual(driver_return, states.DELETED) + @mock.patch.object(pxe_utils, 'clean_up_pxe_config') + @mock.patch.object(agent, 'AgentTFTPImageCache') + @mock.patch('ironic.common.utils.unlink_without_raise') + @mock.patch.object(agent, '_get_tftp_image_info') + def test__clean_up_pxe(self, info_mock, unlink_mock, cache_mock, + clean_mock): + info_mock.return_value = {'label': ['fake1', 'fake2']} + with task_manager.acquire( + self.context, self.node['uuid'], shared=False) as task: + agent._clean_up_pxe(task) + info_mock.assert_called_once_with(task.node) + unlink_mock.assert_called_once_with('fake2') + clean_mock.assert_called_once_with(task) + + @mock.patch.object(pxe_utils, 'clean_up_pxe_config') + @mock.patch.object(agent.AgentTFTPImageCache, 'clean_up') + @mock.patch('ironic.common.utils.unlink_without_raise') + @mock.patch.object(agent, '_get_tftp_image_info') + def test__clean_up_pxe_manage_tftp_false( + self, info_mock, unlink_mock, cache_mock, clean_mock): + self.config(manage_tftp=False, group='agent') + info_mock.return_value = {'label': ['fake1', 'fake2']} + with task_manager.acquire( + self.context, self.node['uuid'], shared=False) as task: + agent._clean_up_pxe(task) + self.assertFalse(info_mock.called) + self.assertFalse(unlink_mock.called) + self.assertFalse(cache_mock.called) + self.assertFalse(clean_mock.called) + @mock.patch('ironic.dhcp.neutron.NeutronDHCPApi.delete_cleaning_ports') @mock.patch('ironic.dhcp.neutron.NeutronDHCPApi.create_cleaning_ports') @mock.patch('ironic.drivers.modules.agent._do_pxe_boot') diff --git a/ironic/tests/drivers/test_deploy_utils.py b/ironic/tests/drivers/test_deploy_utils.py index 033bd89d5..fdb6653a3 100644 --- a/ironic/tests/drivers/test_deploy_utils.py +++ b/ironic/tests/drivers/test_deploy_utils.py @@ -1020,13 +1020,18 @@ class WorkOnDiskTestCase(tests_base.TestCase): self.swap_part = '/dev/fake-part1' self.root_part = '/dev/fake-part2' - self.mock_ibd = mock.patch.object(utils, 'is_block_device').start() - self.mock_mp = mock.patch.object(utils, 'make_partitions').start() - self.addCleanup(self.mock_ibd.stop) - self.addCleanup(self.mock_mp.stop) - self.mock_remlbl = mock.patch.object(utils, - 'destroy_disk_metadata').start() - self.addCleanup(self.mock_remlbl.stop) + self.mock_ibd_obj = mock.patch.object( + utils, 'is_block_device', autospec=True) + self.mock_ibd = self.mock_ibd_obj.start() + self.addCleanup(self.mock_ibd_obj.stop) + self.mock_mp_obj = mock.patch.object( + utils, 'make_partitions', autospec=True) + self.mock_mp = self.mock_mp_obj.start() + self.addCleanup(self.mock_mp_obj.stop) + self.mock_remlbl_obj = mock.patch.object( + utils, 'destroy_disk_metadata', autospec=True) + self.mock_remlbl = self.mock_remlbl_obj.start() + self.addCleanup(self.mock_remlbl_obj.stop) self.mock_mp.return_value = {'swap': self.swap_part, 'root': self.root_part} @@ -1044,7 +1049,7 @@ class WorkOnDiskTestCase(tests_base.TestCase): boot_mode="bios") def test_no_swap_partition(self): - self.mock_ibd.side_effect = [True, False] + self.mock_ibd.side_effect = iter([True, False]) calls = [mock.call(self.root_part), mock.call(self.swap_part)] self.assertRaises(exception.InstanceDeployFailure, @@ -1068,7 +1073,7 @@ class WorkOnDiskTestCase(tests_base.TestCase): self.mock_mp.return_value = {'ephemeral': ephemeral_part, 'swap': swap_part, 'root': root_part} - self.mock_ibd.side_effect = [True, True, False] + self.mock_ibd.side_effect = iter([True, True, False]) calls = [mock.call(root_part), mock.call(swap_part), mock.call(ephemeral_part)] @@ -1096,7 +1101,7 @@ class WorkOnDiskTestCase(tests_base.TestCase): self.mock_mp.return_value = {'swap': swap_part, 'configdrive': configdrive_part, 'root': root_part} - self.mock_ibd.side_effect = [True, True, False] + self.mock_ibd.side_effect = iter([True, True, False]) calls = [mock.call(root_part), mock.call(swap_part), mock.call(configdrive_part)] @@ -1465,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_ipmitool.py b/ironic/tests/drivers/test_ipmitool.py index a27060d0f..2e0097fba 100644 --- a/ironic/tests/drivers/test_ipmitool.py +++ b/ironic/tests/drivers/test_ipmitool.py @@ -840,6 +840,86 @@ class IPMIToolPrivateMethodTestCase(db_base.DbTestCase): mock_support.assert_called_once_with('timing') mock_pwf.assert_called_once_with(self.info['password']) mock_exec.assert_called_once_with(*args) + self.assertEqual(1, mock_exec.call_count) + + @mock.patch.object(ipmi, '_is_option_supported', autospec=True) + @mock.patch.object(utils, 'execute', autospec=True) + def test__exec_ipmitool_exception_retry(self, + mock_exec, mock_support, mock_sleep): + + ipmi.LAST_CMD_TIME = {} + mock_support.return_value = False + mock_exec.side_effect = iter([ + processutils.ProcessExecutionError( + stderr="insufficient resources for session" + ), + (None, None) + ]) + + # Directly set the configuration values such that + # the logic will cause _exec_ipmitool to retry twice. + self.config(min_command_interval=1, group='ipmi') + self.config(retry_timeout=2, group='ipmi') + + ipmi._exec_ipmitool(self.info, 'A B C') + + mock_support.assert_called_once_with('timing') + self.assertEqual(2, mock_exec.call_count) + + @mock.patch.object(ipmi, '_is_option_supported', autospec=True) + @mock.patch.object(utils, 'execute', autospec=True) + def test__exec_ipmitool_exception_retries_exceeded(self, + mock_exec, mock_support, mock_sleep): + + ipmi.LAST_CMD_TIME = {} + mock_support.return_value = False + + mock_exec.side_effect = processutils.ProcessExecutionError( + stderr="insufficient resources for session" + ) + + # Directly set the configuration values such that + # the logic will cause _exec_ipmitool to timeout. + self.config(min_command_interval=1, group='ipmi') + self.config(retry_timeout=1, group='ipmi') + + self.assertRaises(processutils.ProcessExecutionError, + ipmi._exec_ipmitool, + self.info, 'A B C') + mock_support.assert_called_once_with('timing') + self.assertEqual(1, mock_exec.call_count) + + @mock.patch.object(ipmi, '_is_option_supported', autospec=True) + @mock.patch.object(utils, 'execute', autospec=True) + def test__exec_ipmitool_exception_non_retryable_failure(self, + mock_exec, mock_support, mock_sleep): + + ipmi.LAST_CMD_TIME = {} + mock_support.return_value = False + + # Return a retryable error, then an error that cannot + # be retried thus resulting in a single retry + # attempt by _exec_ipmitool. + mock_exec.side_effect = iter([ + processutils.ProcessExecutionError( + stderr="insufficient resources for session" + ), + processutils.ProcessExecutionError( + stderr="Unknown" + ), + ]) + + # Directly set the configuration values such that + # the logic will cause _exec_ipmitool to retry up + # to 3 times. + self.config(min_command_interval=1, group='ipmi') + self.config(retry_timeout=3, group='ipmi') + + self.assertRaises(processutils.ProcessExecutionError, + ipmi._exec_ipmitool, + self.info, 'A B C') + mock_support.assert_called_once_with('timing') + self.assertEqual(2, mock_exec.call_count) @mock.patch.object(ipmi, '_exec_ipmitool', autospec=True) def test__power_status_on(self, mock_exec, mock_sleep): diff --git a/ironic/tests/drivers/test_iscsi_deploy.py b/ironic/tests/drivers/test_iscsi_deploy.py index a0b1f40ba..4d3803542 100644 --- a/ironic/tests/drivers/test_iscsi_deploy.py +++ b/ironic/tests/drivers/test_iscsi_deploy.py @@ -487,6 +487,25 @@ class IscsiDeployMethodsTestCase(db_base.DbTestCase): self._test_build_deploy_ramdisk_options(mock_alnum, fake_api_url, expected_boot_option=expected) + @mock.patch.object(keystone, 'get_service_url', autospec=True) + @mock.patch.object(utils, 'random_alnum', autospec=True) + def test_build_deploy_ramdisk_options_whole_disk_image(self, mock_alnum, + mock_get_url): + """Tests a hack to boot_option for whole disk images. + + This hack is in place to fix bug #1441556. + """ + self.node.instance_info = {'capabilities': '{"boot_option": "local"}'} + dii = self.node.driver_internal_info + dii['is_whole_disk_image'] = True + self.node.driver_internal_info = dii + self.node.save() + expected = 'netboot' + fake_api_url = 'http://127.0.0.1:6385' + self.config(api_url=fake_api_url, group='conductor') + self._test_build_deploy_ramdisk_options(mock_alnum, fake_api_url, + expected_boot_option=expected) + def test_get_boot_option(self): self.node.instance_info = {'capabilities': '{"boot_option": "local"}'} result = iscsi_deploy.get_boot_option(self.node) diff --git a/ironic/tests/drivers/test_seamicro.py b/ironic/tests/drivers/test_seamicro.py index ad4586828..e477cddd4 100644 --- a/ironic/tests/drivers/test_seamicro.py +++ b/ironic/tests/drivers/test_seamicro.py @@ -129,6 +129,7 @@ class SeaMicroValidateParametersTestCase(db_base.DbTestCase): node) +@mock.patch('eventlet.greenthread.sleep', lambda n: None) class SeaMicroPrivateMethodsTestCase(db_base.DbTestCase): def setUp(self): @@ -144,8 +145,6 @@ class SeaMicroPrivateMethodsTestCase(db_base.DbTestCase): self.config(action_timeout=0, group='seamicro') self.config(max_retry=2, group='seamicro') - self.patcher = mock.patch('eventlet.greenthread.sleep') - self.mock_sleep = self.patcher.start() self.info = seamicro._parse_driver_info(self.node) @mock.patch.object(seamicro_client, "Client") 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/stubs.py b/ironic/tests/stubs.py index 7d43d2676..d20c1fd8a 100644 --- a/ironic/tests/stubs.py +++ b/ironic/tests/stubs.py @@ -12,7 +12,7 @@ # License for the specific language governing permissions and limitations # under the License. -from ironic.common import exception +from glanceclient import exc as glance_exc NOW_GLANCE_FORMAT = "2010-10-11T10:30:22" @@ -40,7 +40,7 @@ class StubGlanceClient(object): index += 1 break else: - raise exception.BadRequest('Marker not found') + raise glance_exc.BadRequest('Marker not found') return self._images[index:index + limit] @@ -48,7 +48,7 @@ class StubGlanceClient(object): for image in self._images: if image.id == str(image_id): return image - raise exception.ImageNotFound(image_id) + raise glance_exc.NotFound(image_id) def data(self, image_id): self.get(image_id) @@ -76,7 +76,7 @@ class StubGlanceClient(object): for k, v in metadata.items(): setattr(self._images[i], k, v) return self._images[i] - raise exception.NotFound(image_id) + raise glance_exc.NotFound(image_id) def delete(self, image_id): for i, image in enumerate(self._images): @@ -86,10 +86,10 @@ class StubGlanceClient(object): # HTTPForbidden. image_data = self._images[i] if image_data.deleted: - raise exception.Forbidden() + raise glance_exc.Forbidden() image_data.deleted = True return - raise exception.NotFound(image_id) + raise glance_exc.NotFound(image_id) class FakeImage(object): diff --git a/ironic/tests/test_glance_service.py b/ironic/tests/test_glance_service.py index 8482ed751..6c3276da6 100644 --- a/ironic/tests/test_glance_service.py +++ b/ironic/tests/test_glance_service.py @@ -20,8 +20,11 @@ import os import tempfile import time +from glanceclient import exc as glance_exc import mock +from oslo_config import cfg from oslo_context import context +from oslo_serialization import jsonutils import testtools @@ -33,8 +36,6 @@ from ironic.tests import base from ironic.tests import matchers from ironic.tests import stubs -from oslo_config import cfg -from oslo_serialization import jsonutils CONF = cfg.CONF @@ -468,7 +469,7 @@ class TestGlanceImageService(base.TestCase): def get(self, image_id): if tries[0] == 0: tries[0] = 1 - raise exception.ServiceUnavailable('') + raise glance_exc.ServiceUnavailable('') else: return {} @@ -536,7 +537,7 @@ class TestGlanceImageService(base.TestCase): class MyGlanceStubClient(stubs.StubGlanceClient): """A client that raises a Forbidden exception.""" def get(self, image_id): - raise exception.Forbidden(image_id) + raise glance_exc.Forbidden(image_id) stub_client = MyGlanceStubClient() stub_context = context.RequestContext(auth_token=True) @@ -552,7 +553,7 @@ class TestGlanceImageService(base.TestCase): class MyGlanceStubClient(stubs.StubGlanceClient): """A client that raises a HTTPForbidden exception.""" def get(self, image_id): - raise exception.HTTPForbidden(image_id) + raise glance_exc.HTTPForbidden(image_id) stub_client = MyGlanceStubClient() stub_context = context.RequestContext(auth_token=True) @@ -568,7 +569,7 @@ class TestGlanceImageService(base.TestCase): class MyGlanceStubClient(stubs.StubGlanceClient): """A client that raises a NotFound exception.""" def get(self, image_id): - raise exception.NotFound(image_id) + raise glance_exc.NotFound(image_id) stub_client = MyGlanceStubClient() stub_context = context.RequestContext(auth_token=True) @@ -584,7 +585,7 @@ class TestGlanceImageService(base.TestCase): class MyGlanceStubClient(stubs.StubGlanceClient): """A client that raises a HTTPNotFound exception.""" def get(self, image_id): - raise exception.HTTPNotFound(image_id) + raise glance_exc.HTTPNotFound(image_id) stub_client = MyGlanceStubClient() stub_context = context.RequestContext(auth_token=True) @@ -635,7 +636,7 @@ def _create_failing_glance_client(info): def get(self, image_id): info['num_calls'] += 1 if info['num_calls'] == 1: - raise exception.ServiceUnavailable('') + raise glance_exc.ServiceUnavailable('') return {} return MyGlanceStubClient() diff --git a/ironic/tests/test_images.py b/ironic/tests/test_images.py index fb1da9dbc..b610d4b0a 100644 --- a/ironic/tests/test_images.py +++ b/ironic/tests/test_images.py @@ -424,12 +424,15 @@ class FsImageTestCase(base.TestCase): self.assertEqual(expected_cfg, cfg) def test__generate_grub_cfg(self): - kernel_params = ['key1=value1', 'key2'] options = {'linux': '/vmlinuz', 'initrd': '/initrd'} - expected_cfg = ("menuentry \"install\" {\n" - "linux /vmlinuz key1=value1 key2 --\n" - "initrd /initrd\n" + expected_cfg = ("set default=0\n" + "set timeout=5\n" + "set hidden_timeout_quiet=false\n" + "\n" + "menuentry \"boot_partition\" {\n" + "linuxefi /vmlinuz key1=value1 key2 --\n" + "initrdefi /initrd\n" "}") cfg = images._generate_cfg(kernel_params, diff --git a/ironic/tests/test_pxe_utils.py b/ironic/tests/test_pxe_utils.py index f16cd3e1b..1792d840a 100644 --- a/ironic/tests/test_pxe_utils.py +++ b/ironic/tests/test_pxe_utils.py @@ -144,7 +144,40 @@ class TestPXEUtils(db_base.DbTestCase): ] unlink_calls = [ mock.call('/tftpboot/pxelinux.cfg/01-00-11-22-33-44-55-66'), - mock.call('/tftpboot/pxelinux.cfg/01-00-11-22-33-44-55-67') + mock.call('/tftpboot/pxelinux.cfg/01-00-11-22-33-44-55-67'), + ] + with task_manager.acquire(self.context, self.node.uuid) as task: + pxe_utils._link_mac_pxe_configs(task) + + unlink_mock.assert_has_calls(unlink_calls) + create_link_mock.assert_has_calls(create_link_calls) + + @mock.patch('ironic.common.utils.create_link_without_raise', autospec=True) + @mock.patch('ironic.common.utils.unlink_without_raise', autospec=True) + @mock.patch('ironic.drivers.utils.get_node_mac_addresses', autospec=True) + def test__write_mac_ipxe_configs(self, get_macs_mock, unlink_mock, + create_link_mock): + self.config(ipxe_enabled=True, group='pxe') + macs = [ + '00:11:22:33:44:55:66', + '00:11:22:33:44:55:67' + ] + get_macs_mock.return_value = macs + create_link_calls = [ + mock.call(u'/httpboot/1be26c0b-03f2-4d2e-ae87-c02d7f33c123/config', + '/httpboot/pxelinux.cfg/00-11-22-33-44-55-66'), + mock.call(u'/httpboot/1be26c0b-03f2-4d2e-ae87-c02d7f33c123/config', + '/httpboot/pxelinux.cfg/00112233445566'), + mock.call(u'/httpboot/1be26c0b-03f2-4d2e-ae87-c02d7f33c123/config', + '/httpboot/pxelinux.cfg/00-11-22-33-44-55-67'), + mock.call(u'/httpboot/1be26c0b-03f2-4d2e-ae87-c02d7f33c123/config', + '/httpboot/pxelinux.cfg/00112233445567'), + ] + unlink_calls = [ + mock.call('/httpboot/pxelinux.cfg/00-11-22-33-44-55-66'), + mock.call('/httpboot/pxelinux.cfg/00112233445566'), + mock.call('/httpboot/pxelinux.cfg/00-11-22-33-44-55-67'), + mock.call('/httpboot/pxelinux.cfg/00112233445567'), ] with task_manager.acquire(self.context, self.node.uuid) as task: pxe_utils._link_mac_pxe_configs(task) @@ -218,7 +251,7 @@ class TestPXEUtils(db_base.DbTestCase): self.config(ipxe_enabled=True, group='pxe') self.config(http_root='/httpboot', group='pxe') mac = '00:11:22:33:AA:BB:CC' - self.assertEqual('/httpboot/pxelinux.cfg/00112233aabbcc', + self.assertEqual('/httpboot/pxelinux.cfg/00-11-22-33-aa-bb-cc', pxe_utils._get_pxe_mac_path(mac)) def test__get_pxe_ip_address_path(self): |