summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api-ref/source/samples/node-inventory-response.json1
-rw-r--r--devstack/lib/ironic2
-rw-r--r--doc/source/admin/drivers/idrac.rst1
-rw-r--r--doc/source/admin/drivers/ilo.rst5
-rw-r--r--doc/source/admin/drivers/irmc.rst5
-rw-r--r--doc/source/admin/troubleshooting.rst17
-rw-r--r--doc/source/conf.py2
-rw-r--r--doc/source/install/enrollment.rst10
-rw-r--r--doc/source/install/standalone/enrollment.rst4
-rw-r--r--doc/source/install/troubleshooting.rst3
-rw-r--r--ironic/conductor/manager.py17
-rw-r--r--ironic/conductor/utils.py6
-rw-r--r--ironic/conf/conductor.py8
-rw-r--r--ironic/conf/opts.py1
-rw-r--r--ironic/db/sqlalchemy/__init__.py19
-rw-r--r--ironic/db/sqlalchemy/api.py40
-rw-r--r--ironic/drivers/base.py4
-rw-r--r--ironic/drivers/modules/drac/inspect.py14
-rw-r--r--ironic/drivers/modules/drac/raid.py2
-rw-r--r--ironic/drivers/modules/irmc/inspect.py2
-rw-r--r--ironic/drivers/modules/redfish/inspect.py4
-rw-r--r--ironic/hacking/checks.py2
-rw-r--r--ironic/objects/node.py4
-rw-r--r--ironic/tests/base.py15
-rw-r--r--ironic/tests/unit/conductor/test_cleaning.py30
-rw-r--r--ironic/tests/unit/conductor/test_manager.py32
-rw-r--r--ironic/tests/unit/conductor/test_utils.py11
-rw-r--r--ironic/tests/unit/db/utils.py2
-rw-r--r--ironic/tests/unit/drivers/modules/drac/test_inspect.py22
-rw-r--r--ironic/tests/unit/drivers/modules/ilo/test_inspect.py47
-rw-r--r--ironic/tests/unit/drivers/modules/irmc/test_inspect.py6
-rw-r--r--ironic/tests/unit/drivers/modules/redfish/test_inspect.py18
-rw-r--r--ironic/tests/unit/objects/test_node.py7
-rw-r--r--releasenotes/notes/Cleanfail-power-off-13b5fdcc2727866a.yaml8
-rw-r--r--releasenotes/notes/fix-db-sqlite-OperationalError-7934dbda2a21c69e.yaml6
-rw-r--r--releasenotes/notes/no-cpus-c79717303470bf3c.yaml6
-rw-r--r--tox.ini2
-rw-r--r--zuul.d/ironic-jobs.yaml1
-rw-r--r--zuul.d/project.yaml9
39 files changed, 209 insertions, 186 deletions
diff --git a/api-ref/source/samples/node-inventory-response.json b/api-ref/source/samples/node-inventory-response.json
index 7916f6717..9355bcf1b 100644
--- a/api-ref/source/samples/node-inventory-response.json
+++ b/api-ref/source/samples/node-inventory-response.json
@@ -24,7 +24,6 @@
"52:54:00:90:35:d6"
],
"local_gb":10,
- "cpus":1,
"cpu_arch":"x86_64",
"memory_mb":2048
}
diff --git a/devstack/lib/ironic b/devstack/lib/ironic
index 17ba547f1..51b2e2ba8 100644
--- a/devstack/lib/ironic
+++ b/devstack/lib/ironic
@@ -3248,7 +3248,7 @@ function ironic_configure_tempest {
else
iniset $TEMPEST_CONFIG baremetal whole_disk_image_url "http://$IRONIC_HTTP_SERVER:$IRONIC_HTTP_PORT/${IRONIC_WHOLEDISK_IMAGE_NAME}.img"
fi
- iniset $TEMPEST_CONFIG baremetal whole_disk_image_checksum $(md5sum $FILES/${IRONIC_WHOLEDISK_IMAGE_NAME}.img)
+ iniset $TEMPEST_CONFIG baremetal whole_disk_image_checksum $(sha256sum $FILES/${IRONIC_WHOLEDISK_IMAGE_NAME}.img)
if [[ "$IRONIC_RAMDISK_IMAGE" != "" ]]; then
iniset $TEMPEST_CONFIG baremetal ramdisk_iso_image_ref "$IRONIC_RAMDISK_IMAGE"
diff --git a/doc/source/admin/drivers/idrac.rst b/doc/source/admin/drivers/idrac.rst
index a8d157ec8..41e17761e 100644
--- a/doc/source/admin/drivers/idrac.rst
+++ b/doc/source/admin/drivers/idrac.rst
@@ -250,7 +250,6 @@ without affecting the operation of the system being inspected.
The inspection discovers the following properties:
* ``cpu_arch``: cpu architecture
-* ``cpus``: number of cpus
* ``local_gb``: disk size in gigabytes
* ``memory_mb``: memory size in megabytes
diff --git a/doc/source/admin/drivers/ilo.rst b/doc/source/admin/drivers/ilo.rst
index b6825fc40..34401db0f 100644
--- a/doc/source/admin/drivers/ilo.rst
+++ b/doc/source/admin/drivers/ilo.rst
@@ -908,13 +908,10 @@ The hardware type ``ilo`` supports hardware inspection.
* ``snmp_auth_priv_protocol`` : The Privacy protocol. The valid
values are "AES" and "DES". The iLO default value is "DES".
-The inspection process will discover the following essential properties
-(properties required for scheduling deployment):
+The inspection process will discover the following properties:
* ``memory_mb``: memory size
-* ``cpus``: number of cpus
-
* ``cpu_arch``: cpu architecture
* ``local_gb``: disk size
diff --git a/doc/source/admin/drivers/irmc.rst b/doc/source/admin/drivers/irmc.rst
index 9ddfa3b3d..6bc6a1248 100644
--- a/doc/source/admin/drivers/irmc.rst
+++ b/doc/source/admin/drivers/irmc.rst
@@ -465,13 +465,10 @@ configuration:
Supported properties
~~~~~~~~~~~~~~~~~~~~
-The inspection process will discover the following essential properties
-(properties required for scheduling deployment):
+The inspection process will discover the following properties:
* ``memory_mb``: memory size
-* ``cpus``: number of cpus
-
* ``cpu_arch``: cpu architecture
* ``local_gb``: disk size
diff --git a/doc/source/admin/troubleshooting.rst b/doc/source/admin/troubleshooting.rst
index 72e969b6e..eef51cbf3 100644
--- a/doc/source/admin/troubleshooting.rst
+++ b/doc/source/admin/troubleshooting.rst
@@ -104,23 +104,6 @@ A few things should be checked in this case:
``True``; make sure the target nodes are in ``available`` and
``maintenance`` is ``False``;
-#. If you do not use scheduling based on resource classes, then the node's
- properties must have been set either manually or via inspection.
- For each node with ``available`` state check that the ``properties``
- JSON field has valid values for the keys ``cpus``, ``cpu_arch``,
- ``memory_mb`` and ``local_gb``. Example of valid properties::
-
- $ baremetal node show <IRONIC NODE> --fields properties
- +------------+------------------------------------------------------------------------------------+
- | Property | Value |
- +------------+------------------------------------------------------------------------------------+
- | properties | {u'memory_mb': u'8192', u'cpu_arch': u'x86_64', u'local_gb': u'41', u'cpus': u'4'} |
- +------------+------------------------------------------------------------------------------------+
-
- .. warning::
- If you're using exact match filters in the Nova Scheduler, make sure
- the flavor and the node properties match exactly.
-
#. The Nova flavor that you are using does not match any properties of the
available Ironic nodes. Use
::
diff --git a/doc/source/conf.py b/doc/source/conf.py
index a5b2edcfa..37d00f70d 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -59,7 +59,7 @@ apidoc_excluded_paths = [
apidoc_separate_modules = True
openstackdocs_repo_name = 'openstack/ironic'
-openstackdocs_use_storyboard = True
+openstackdocs_use_storyboard = False
openstackdocs_pdf_link = True
openstackdocs_projects = [
'bifrost',
diff --git a/doc/source/install/enrollment.rst b/doc/source/install/enrollment.rst
index 40c63b4bb..97e2d33d4 100644
--- a/doc/source/install/enrollment.rst
+++ b/doc/source/install/enrollment.rst
@@ -285,12 +285,13 @@ Adding scheduling information
This is not required for standalone deployments, only for those using
the Compute service for provisioning bare metal instances.
-#. Update the node's properties to match the actual hardware of the node:
+#. Update the node's properties to match the actual hardware of the node.
+ These are optional. When provided, ``memory_mb`` can be used for checking
+ if the instance image fits into the node's memory:
.. code-block:: console
$ baremetal node set $NODE_UUID \
- --property cpus=$CPU_COUNT \
--property memory_mb=$RAM_MB \
--property local_gb=$DISK_GB
@@ -303,14 +304,13 @@ Adding scheduling information
--driver-info ipmi_username=$USER \
--driver-info ipmi_password=$PASS \
--driver-info ipmi_address=$ADDRESS \
- --property cpus=$CPU_COUNT \
--property memory_mb=$RAM_MB \
--property local_gb=$DISK_GB
These values can also be discovered during `Hardware Inspection`_.
- .. warning::
- The value provided for the ``local_gb`` property must match the size of
+ .. note::
+ The value provided for the ``local_gb`` property should match the size of
the root device you're going to deploy on. By default
**ironic-python-agent** picks the smallest disk which is not smaller
than 4 GiB.
diff --git a/doc/source/install/standalone/enrollment.rst b/doc/source/install/standalone/enrollment.rst
index 305091070..4fd9ebb48 100644
--- a/doc/source/install/standalone/enrollment.rst
+++ b/doc/source/install/standalone/enrollment.rst
@@ -87,9 +87,7 @@ Enrolling nodes
#. As in case of Compute service, you can also provide ``capabilities`` to node
properties, but they will be used only by Bare Metal service (for example,
- boot mode). Although you don't need to add properties like ``memory_mb``,
- ``cpus`` etc. as Bare Metal service will require UUID of a node you're
- going to deploy.
+ boot mode).
#. Then create a port to inform Bare Metal service of the network interface
cards which are part of the node by creating a port with each NIC's MAC
diff --git a/doc/source/install/troubleshooting.rst b/doc/source/install/troubleshooting.rst
index 75f19c729..a40c19efd 100644
--- a/doc/source/install/troubleshooting.rst
+++ b/doc/source/install/troubleshooting.rst
@@ -33,8 +33,7 @@ service and Bare Metal service::
| Property | Value |
+------------------------+----------------------------------------------------------------------+
| instance_uuid | None |
- | properties | {u'memory_mb': u'1024', u'cpu_arch': u'x86_64', u'local_gb': u'10', |
- | | u'cpus': u'1'} |
+ | properties | {u'memory_mb': u'1024', u'cpu_arch': u'x86_64', u'local_gb': u'10'} |
| maintenance | False |
| driver_info | { [SNIP] } |
| extra | {} |
diff --git a/ironic/conductor/manager.py b/ironic/conductor/manager.py
index bbd2355bd..ef850753d 100644
--- a/ironic/conductor/manager.py
+++ b/ironic/conductor/manager.py
@@ -2284,10 +2284,13 @@ class ConductorManager(base_manager.BaseConductorManager):
LOG.debug("RPC create_port called for port %s.", port_uuid)
with task_manager.acquire(context, port_obj.node_id,
- purpose='port create') as task:
+ purpose='port create',
+ shared=True) as task:
+ # NOTE(TheJulia): We're creating a port, we don't need
+ # an exclusive parent lock to do so.
utils.validate_port_physnet(task, port_obj)
port_obj.create()
- return port_obj
+ return port_obj
@METRICS.timer('ConductorManager.update_port')
@messaging.expected_exceptions(exception.NodeLocked,
@@ -2373,7 +2376,7 @@ class ConductorManager(base_manager.BaseConductorManager):
port_obj.save()
- return port_obj
+ return port_obj
@METRICS.timer('ConductorManager.update_portgroup')
@messaging.expected_exceptions(exception.NodeLocked,
@@ -2452,7 +2455,7 @@ class ConductorManager(base_manager.BaseConductorManager):
portgroup_obj.save()
- return portgroup_obj
+ return portgroup_obj
@METRICS.timer('ConductorManager.update_volume_connector')
@messaging.expected_exceptions(
@@ -2496,7 +2499,7 @@ class ConductorManager(base_manager.BaseConductorManager):
connector.save()
LOG.info("Successfully updated volume connector %(connector)s.",
{'connector': connector.uuid})
- return connector
+ return connector
@METRICS.timer('ConductorManager.update_volume_target')
@messaging.expected_exceptions(
@@ -2537,7 +2540,7 @@ class ConductorManager(base_manager.BaseConductorManager):
target.save()
LOG.info("Successfully updated volume target %(target)s.",
{'target': target.uuid})
- return target
+ return target
@METRICS.timer('ConductorManager.get_driver_properties')
@messaging.expected_exceptions(exception.DriverNotFound)
@@ -3564,7 +3567,7 @@ class ConductorManager(base_manager.BaseConductorManager):
{'node': task.node.uuid})
utils.add_secret_token(task.node)
task.node.save()
- return task.node
+ return objects.Node.get(context, node_id)
@METRICS.timer('ConductorManager.manage_node_history')
@periodics.periodic(
diff --git a/ironic/conductor/utils.py b/ironic/conductor/utils.py
index 2272c0df7..39886bfd8 100644
--- a/ironic/conductor/utils.py
+++ b/ironic/conductor/utils.py
@@ -499,6 +499,11 @@ def cleaning_error_handler(task, logmsg, errmsg=None, traceback=False,
# NOTE(dtantsur): avoid overwriting existing maintenance_reason
if not node.maintenance_reason and set_maintenance:
node.maintenance_reason = errmsg
+
+ if CONF.conductor.poweroff_in_cleanfail:
+ # NOTE(NobodyCam): Power off node in clean fail
+ node_power_action(task, states.POWER_OFF)
+
node.save()
if set_fail_state and node.provision_state != states.CLEANFAIL:
@@ -803,7 +808,6 @@ def power_state_error_handler(e, node, power_state):
{'node': node.uuid, 'power_state': power_state})
-@task_manager.require_exclusive_lock
def validate_port_physnet(task, port_obj):
"""Validate the consistency of physical networks of ports in a portgroup.
diff --git a/ironic/conf/conductor.py b/ironic/conf/conductor.py
index 653e30f56..2452fafe7 100644
--- a/ironic/conf/conductor.py
+++ b/ironic/conf/conductor.py
@@ -349,6 +349,14 @@ opts = [
'is a global setting applying to all requests this '
'conductor receives, regardless of access rights. '
'The concurrent clean limit cannot be disabled.')),
+
+ cfg.BoolOpt('poweroff_in_cleanfail',
+ default=False,
+ help=_('If True power off nodes in the ``clean failed`` '
+ 'state. Default False. Option may be unsafe '
+ 'when using Cleaning to perform '
+ 'hardware-transformative actions such as '
+ 'firmware upgrade.')),
]
diff --git a/ironic/conf/opts.py b/ironic/conf/opts.py
index a7ebcfb30..0d8aeafd2 100644
--- a/ironic/conf/opts.py
+++ b/ironic/conf/opts.py
@@ -78,7 +78,6 @@ def update_opt_defaults():
# This comes in two flavors
'oslo.messaging=INFO',
'oslo_messaging=INFO',
- 'sqlalchemy=WARNING',
'stevedore=INFO',
'eventlet.wsgi.server=INFO',
'iso8601=WARNING',
diff --git a/ironic/db/sqlalchemy/__init__.py b/ironic/db/sqlalchemy/__init__.py
index 173b91fcc..c656ed227 100644
--- a/ironic/db/sqlalchemy/__init__.py
+++ b/ironic/db/sqlalchemy/__init__.py
@@ -10,9 +10,28 @@
# License for the specific language governing permissions and limitations
# under the License.
+from oslo_config import cfg
from oslo_db.sqlalchemy import enginefacade
+from sqlalchemy.engine import Engine
+from sqlalchemy import event
+
+CONF = cfg.CONF
# FIXME(stephenfin): we need to remove reliance on autocommit semantics ASAP
# since it's not compatible with SQLAlchemy 2.0
# NOTE(dtantsur): we want sqlite as close to a real database as possible.
enginefacade.configure(sqlite_fk=True, __autocommit=True)
+
+
+# NOTE(TheJulia): Setup a listener to trigger the sqlite write-ahead
+# log to be utilized to permit concurrent access, which is needed
+# as we can get read requests while we are writing via the API
+# surface *when* we're using sqlite as the database backend.
+@event.listens_for(Engine, "connect")
+def _setup_journal_mode(dbapi_connection, connection_record):
+ # NOTE(TheJulia): The string may not be loaded in some unit
+ # tests so handle whatever the output is as a string so we
+ # can lower/compare it and send the appropriate command to
+ # the database.
+ if 'sqlite' in str(CONF.database.connection).lower():
+ dbapi_connection.execute("PRAGMA journal_mode=WAL")
diff --git a/ironic/db/sqlalchemy/api.py b/ironic/db/sqlalchemy/api.py
index 93a211fc3..3ba31e233 100644
--- a/ironic/db/sqlalchemy/api.py
+++ b/ironic/db/sqlalchemy/api.py
@@ -324,7 +324,9 @@ def _paginate_query(model, limit=None, marker=None, sort_key=None,
# object is garbage collected as ORM Query objects allow
# for DB interactions to occur after the fact, so it remains
# connected to the DB..
- return query.all()
+ # Save the query.all() results, but don't return yet, so we
+ # begin to exit and unwind the session.
+ ref = query.all()
else:
# In this case, we have a sqlalchemy.sql.selectable.Select
# (most likely) which utilizes the unified select interface.
@@ -338,7 +340,10 @@ def _paginate_query(model, limit=None, marker=None, sort_key=None,
# Everything is a tuple in a resultset from the unified interface
# but for objects, our model expects just object access,
# so we extract and return them.
- return [r[0] for r in res]
+ ref = [r[0] for r in res]
+ # Return the results to the caller, outside of the session context
+ # if an ORM object, because we want the session to close.
+ return ref
def _filter_active_conductors(query, interval=None):
@@ -1341,6 +1346,12 @@ class Connection(api.Connection):
def get_active_hardware_type_dict(self, use_groups=False):
with _session_for_read() as session:
+ # TODO(TheJulia): We should likely take a look at this
+ # joined query, as we may not be getting what we expect.
+ # Metal3 logs upwards of 200 rows returned with multiple datetime
+ # columns.
+ # Given dualing datetime fields, we really can't just expect
+ # requesting a unique set to "just work".
query = (session.query(models.ConductorHardwareInterfaces,
models.Conductor)
.join(models.Conductor))
@@ -1375,16 +1386,19 @@ class Connection(api.Connection):
with _session_for_read() as session:
query = (session.query(models.ConductorHardwareInterfaces)
.filter_by(conductor_id=conductor_id))
- return query.all()
+ ref = query.all()
+ return ref
def list_hardware_type_interfaces(self, hardware_types):
with _session_for_read() as session:
- query = (session.query(models.ConductorHardwareInterfaces)
+ query = (session.query(models.ConductorHardwareInterfaces,
+ models.Conductor)
+ .join(models.Conductor)
.filter(models.ConductorHardwareInterfaces.hardware_type
.in_(hardware_types)))
query = _filter_active_conductors(query)
- return query.all()
+ return [row[0] for row in query]
@oslo_db_api.retry_on_deadlock
def register_conductor_hardware_interfaces(self, conductor_id, interfaces):
@@ -1395,6 +1409,8 @@ class Connection(api.Connection):
conductor_hw_iface['conductor_id'] = conductor_id
for k, v in iface.items():
conductor_hw_iface[k] = v
+ # TODO(TheJulia): Uhh... We should try to do this as one
+ # bulk operation and not insert each row.
session.add(conductor_hw_iface)
session.flush()
except db_exc.DBDuplicateEntry as e:
@@ -2078,9 +2094,10 @@ class Connection(api.Connection):
query = session.query(models.Allocation).filter_by(
id=allocation_id)
try:
- return query.one()
+ ref = query.one()
except NoResultFound:
raise exception.AllocationNotFound(allocation=allocation_id)
+ return ref
def get_allocation_by_uuid(self, allocation_uuid):
"""Return an allocation representation.
@@ -2093,9 +2110,10 @@ class Connection(api.Connection):
query = session.query(models.Allocation).filter_by(
uuid=allocation_uuid)
try:
- return query.one()
+ ref = query.one()
except NoResultFound:
raise exception.AllocationNotFound(allocation=allocation_uuid)
+ return ref
def get_allocation_by_name(self, name):
"""Return an allocation representation.
@@ -2107,9 +2125,10 @@ class Connection(api.Connection):
with _session_for_read() as session:
query = session.query(models.Allocation).filter_by(name=name)
try:
- return query.one()
+ ref = query.one()
except NoResultFound:
raise exception.AllocationNotFound(allocation=name)
+ return ref
def get_allocation_list(self, filters=None, limit=None, marker=None,
sort_key=None, sort_dir=None):
@@ -2453,7 +2472,7 @@ class Connection(api.Connection):
session.flush()
except db_exc.DBDuplicateEntry:
raise exception.NodeHistoryAlreadyExists(uuid=values['uuid'])
- return history
+ return history
@oslo_db_api.retry_on_deadlock
def destroy_node_history_by_uuid(self, history_uuid):
@@ -2467,9 +2486,10 @@ class Connection(api.Connection):
def get_node_history_by_id(self, history_id):
query = model_query(models.NodeHistory).filter_by(id=history_id)
try:
- return query.one()
+ res = query.one()
except NoResultFound:
raise exception.NodeHistoryNotFound(history=history_id)
+ return res
def get_node_history_by_uuid(self, history_uuid):
query = model_query(models.NodeHistory).filter_by(uuid=history_uuid)
diff --git a/ironic/drivers/base.py b/ironic/drivers/base.py
index bdd017b91..953ac056e 100644
--- a/ironic/drivers/base.py
+++ b/ironic/drivers/base.py
@@ -1224,7 +1224,7 @@ class InspectInterface(BaseInterface):
"""Interface for inspection-related actions."""
interface_type = 'inspect'
- ESSENTIAL_PROPERTIES = {'memory_mb', 'local_gb', 'cpus', 'cpu_arch'}
+ ESSENTIAL_PROPERTIES = {'memory_mb', 'local_gb', 'cpu_arch'}
"""The properties required by scheduler/deploy."""
@abc.abstractmethod
@@ -1662,7 +1662,7 @@ class NetworkInterface(BaseInterface):
"""
def need_power_on(self, task):
- """Check if ironic node must be powered on before applying network changes
+ """Check if node must be powered on before applying network changes
:param task: A TaskManager instance.
:returns: Boolean.
diff --git a/ironic/drivers/modules/drac/inspect.py b/ironic/drivers/modules/drac/inspect.py
index 8ba0be088..c9c58fbe9 100644
--- a/ironic/drivers/modules/drac/inspect.py
+++ b/ironic/drivers/modules/drac/inspect.py
@@ -176,8 +176,6 @@ class DracWSManInspect(base.InspectInterface):
[memory.size_mb for memory in client.list_memory()])
cpus = client.list_cpus()
if cpus:
- properties['cpus'] = sum(
- [self._calculate_cpus(cpu) for cpu in cpus])
properties['cpu_arch'] = 'x86_64' if cpus[0].arch64 else 'x86'
bios_settings = client.list_bios_settings()
@@ -264,18 +262,6 @@ class DracWSManInspect(base.InspectInterface):
if disk.size_mb >= min_size_required_mb:
return disk
- def _calculate_cpus(self, cpu):
- """Find actual CPU count.
-
- :param cpu: Pass cpu.
-
- :returns: returns total cpu count.
- """
- if cpu.ht_enabled:
- return cpu.cores * 2
- else:
- return cpu.cores
-
def _calculate_gpus(self, video_controllers):
"""Find actual GPU count.
diff --git a/ironic/drivers/modules/drac/raid.py b/ironic/drivers/modules/drac/raid.py
index 8bad02bba..404222f5d 100644
--- a/ironic/drivers/modules/drac/raid.py
+++ b/ironic/drivers/modules/drac/raid.py
@@ -1022,7 +1022,7 @@ def _commit_to_controllers(node, controllers, substep="completed"):
# all realtime controllers
all_realtime = all(
(cntlr['is_reboot_required'] == optional)
- and not(cntlr.get('is_ehba_mode'))
+ and not (cntlr.get('is_ehba_mode'))
for cntlr in controllers)
# check any controller with ehba mode
diff --git a/ironic/drivers/modules/irmc/inspect.py b/ironic/drivers/modules/irmc/inspect.py
index f7c2ad7ba..64708ff9b 100644
--- a/ironic/drivers/modules/irmc/inspect.py
+++ b/ironic/drivers/modules/irmc/inspect.py
@@ -236,7 +236,7 @@ def _inspect_hardware(node, existing_traits=None, **kwargs):
"with the server, please check if you have set them "
"correctly.")
error = (_("Inspection failed for node %(node_id)s "
- "with the following error: %(error)s. (advice)s") %
+ "with the following error: %(error)s. %(advice)s") %
{'node_id': node.uuid, 'error': e, 'advice': advice})
raise exception.HardwareInspectionFailure(error=error)
diff --git a/ironic/drivers/modules/redfish/inspect.py b/ironic/drivers/modules/redfish/inspect.py
index 4c5f7c344..c514df4fe 100644
--- a/ironic/drivers/modules/redfish/inspect.py
+++ b/ironic/drivers/modules/redfish/inspect.py
@@ -108,9 +108,7 @@ class RedfishInspect(base.InspectInterface):
system.memory_summary.size_gib * units.Ki)
if system.processors and system.processors.summary:
- cpus, arch = system.processors.summary
- if cpus:
- inspected_properties['cpus'] = cpus
+ arch = system.processors.summary[1]
if arch:
try:
diff --git a/ironic/hacking/checks.py b/ironic/hacking/checks.py
index 6c5b49776..57a3cbfe8 100644
--- a/ironic/hacking/checks.py
+++ b/ironic/hacking/checks.py
@@ -51,4 +51,4 @@ def check_explicit_underscore_import(logical_line, filename):
UNDERSCORE_IMPORT_FILES.append(filename)
elif (translated_log.match(logical_line)
or string_translation.match(logical_line)):
- yield(0, "N323: Found use of _() without explicit import of _!")
+ yield (0, "N323: Found use of _() without explicit import of _!")
diff --git a/ironic/objects/node.py b/ironic/objects/node.py
index 93df5b3c1..b680ac60a 100644
--- a/ironic/objects/node.py
+++ b/ironic/objects/node.py
@@ -29,7 +29,7 @@ from ironic.objects import base
from ironic.objects import fields as object_fields
from ironic.objects import notification
-REQUIRED_INT_PROPERTIES = ['local_gb', 'cpus', 'memory_mb']
+REQUIRED_INT_PROPERTIES = ['local_gb', 'memory_mb']
CONF = cfg.CONF
LOG = log.getLogger(__name__)
@@ -191,7 +191,7 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat):
return d
def _validate_property_values(self, properties):
- """Check if the input of local_gb, cpus and memory_mb are valid.
+ """Check if the input of local_gb and memory_mb are valid.
:param properties: a dict contains the node's information.
"""
diff --git a/ironic/tests/base.py b/ironic/tests/base.py
index 348f15c20..69e449d3b 100644
--- a/ironic/tests/base.py
+++ b/ironic/tests/base.py
@@ -102,6 +102,11 @@ class WarningsFixture(fixtures.Fixture):
category=UserWarning,
)
+ # NOTE(gibi): The UUIDFields emits a warning if the value is not a
+ # valid UUID. Let's escalate that to an exception in the test to
+ # prevent adding violations.
+ warnings.filterwarnings('error', message='.* is an invalid UUID.')
+
# Enable deprecation warnings to capture upcoming SQLAlchemy changes
warnings.filterwarnings(
@@ -125,16 +130,6 @@ class WarningsFixture(fixtures.Fixture):
category=sqla_exc.SAWarning,
)
- # ...but filter everything out until we get around to fixing them
- # TODO(stephenfin): Fix all of these
-
- warnings.filterwarnings(
- 'ignore',
- module='ironic',
- message='SELECT statement has a cartesian product ',
- category=sqla_exc.SAWarning,
- )
-
# FIXME(stephenfin): We can remove this once oslo.db is fixed
# https://review.opendev.org/c/openstack/oslo.db/+/856453
warnings.filterwarnings(
diff --git a/ironic/tests/unit/conductor/test_cleaning.py b/ironic/tests/unit/conductor/test_cleaning.py
index 34e805deb..cdfbf14ee 100644
--- a/ironic/tests/unit/conductor/test_cleaning.py
+++ b/ironic/tests/unit/conductor/test_cleaning.py
@@ -436,6 +436,36 @@ class DoNodeCleanTestCase(db_base.DbTestCase):
self.assertFalse(node.maintenance)
self.assertIsNone(node.fault)
+ @mock.patch('ironic.drivers.modules.fake.FakePower.set_power_state',
+ autospec=True)
+ @mock.patch.object(n_flat.FlatNetwork, 'validate', autospec=True)
+ @mock.patch.object(conductor_steps, 'set_node_cleaning_steps',
+ autospec=True)
+ def test_do_node_clean_steps_fail_poweroff(self, mock_steps, mock_validate,
+ mock_power, clean_steps=None,
+ invalid_exc=True):
+ if invalid_exc:
+ mock_steps.side_effect = exception.InvalidParameterValue('invalid')
+ else:
+ mock_steps.side_effect = exception.NodeCleaningFailure('failure')
+ tgt_prov_state = states.MANAGEABLE if clean_steps else states.AVAILABLE
+ self.config(poweroff_in_cleanfail=True, group='conductor')
+ node = obj_utils.create_test_node(
+ self.context, driver='fake-hardware',
+ uuid=uuidutils.generate_uuid(),
+ provision_state=states.CLEANING,
+ power_state=states.POWER_ON,
+ target_provision_state=tgt_prov_state)
+ with task_manager.acquire(
+ self.context, node.uuid, shared=False) as task:
+ cleaning.do_node_clean(task, clean_steps=clean_steps)
+ mock_validate.assert_called_once_with(mock.ANY, task)
+ node.refresh()
+ self.assertEqual(states.CLEANFAIL, node.provision_state)
+ self.assertEqual(tgt_prov_state, node.target_provision_state)
+ mock_steps.assert_called_once_with(mock.ANY, disable_ramdisk=False)
+ self.assertTrue(mock_power.called)
+
def test__do_node_clean_automated_steps_fail(self):
for invalid in (True, False):
self.__do_node_clean_steps_fail(invalid_exc=invalid)
diff --git a/ironic/tests/unit/conductor/test_manager.py b/ironic/tests/unit/conductor/test_manager.py
index 7278486a5..f0fb075b7 100644
--- a/ironic/tests/unit/conductor/test_manager.py
+++ b/ironic/tests/unit/conductor/test_manager.py
@@ -3568,6 +3568,23 @@ class MiscTestCase(mgr_utils.ServiceSetUpMixin, mgr_utils.CommonMixIn,
filters=mock.sentinel.filters))
self.assertEqual([], result)
+ def test_get_node_with_token(self):
+ node = obj_utils.create_test_node(
+ self.context, driver='fake-hardware',
+ network_interface='noop')
+ self.assertNotIn('agent_secret_token', node.driver_internal_info)
+ res = self.service.get_node_with_token(self.context, node.id)
+ self.assertIn('agent_secret_token', res.driver_internal_info)
+
+ def test_node_with_token_already_set(self):
+ node = obj_utils.create_test_node(
+ self.context, driver='fake-hardware',
+ network_interface='noop',
+ driver_internal_info={'agent_secret_token': 'secret'})
+ res = self.service.get_node_with_token(self.context, node.id)
+ self.assertEqual('******',
+ res.driver_internal_info['agent_secret_token'])
+
@mgr_utils.mock_record_keepalive
class ConsoleTestCase(mgr_utils.ServiceSetUpMixin, db_base.DbTestCase):
@@ -3953,18 +3970,6 @@ class CreatePortTestCase(mgr_utils.ServiceSetUpMixin, db_base.DbTestCase):
self.assertEqual({'foo': 'bar'}, res.extra)
mock_validate.assert_called_once_with(mock.ANY, port)
- def test_create_port_node_locked(self):
- node = obj_utils.create_test_node(self.context, driver='fake-hardware',
- reservation='fake-reserv')
- port = obj_utils.get_test_port(self.context, node_id=node.id)
- exc = self.assertRaises(messaging.rpc.ExpectedException,
- self.service.create_port,
- self.context, port)
- # Compare true exception hidden by @messaging.expected_exceptions
- self.assertEqual(exception.NodeLocked, exc.exc_info[0])
- self.assertRaises(exception.PortNotFound, port.get_by_uuid,
- self.context, port.uuid)
-
@mock.patch.object(conductor_utils, 'validate_port_physnet', autospec=True)
def test_create_port_mac_exists(self, mock_validate):
node = obj_utils.create_test_node(self.context, driver='fake-hardware')
@@ -5089,7 +5094,8 @@ class ManagerDoSyncPowerStateTestCase(db_base.DbTestCase):
self.power = self.driver.power
self.node = obj_utils.create_test_node(
self.context, driver='fake-hardware', maintenance=False,
- provision_state=states.AVAILABLE, instance_uuid=uuidutils.uuid)
+ provision_state=states.AVAILABLE,
+ instance_uuid=uuidutils.generate_uuid())
self.task = mock.Mock(spec_set=['context', 'driver', 'node',
'upgrade_lock', 'shared'])
self.task.context = self.context
diff --git a/ironic/tests/unit/conductor/test_utils.py b/ironic/tests/unit/conductor/test_utils.py
index 52fc72436..27c4bfa86 100644
--- a/ironic/tests/unit/conductor/test_utils.py
+++ b/ironic/tests/unit/conductor/test_utils.py
@@ -243,11 +243,12 @@ class NodePowerActionTestCase(db_base.DbTestCase):
self.config(host='my-host')
# Required for exception handling
mock_notif.__name__ = 'NodeSetPowerStateNotification'
- node = obj_utils.create_test_node(self.context,
- uuid=uuidutils.generate_uuid(),
- driver='fake-hardware',
- instance_uuid=uuidutils.uuid,
- power_state=states.POWER_OFF)
+ node = obj_utils.create_test_node(
+ self.context,
+ uuid=uuidutils.generate_uuid(),
+ driver='fake-hardware',
+ instance_uuid=uuidutils.generate_uuid(),
+ power_state=states.POWER_OFF)
task = task_manager.TaskManager(self.context, node.uuid)
get_power_mock.return_value = states.POWER_OFF
diff --git a/ironic/tests/unit/db/utils.py b/ironic/tests/unit/db/utils.py
index 10055d829..fc5bee226 100644
--- a/ironic/tests/unit/db/utils.py
+++ b/ironic/tests/unit/db/utils.py
@@ -165,7 +165,6 @@ def get_test_snmp_info(**kw):
def get_test_node(**kw):
properties = {
"cpu_arch": "x86_64",
- "cpus": "8",
"local_gb": "10",
"memory_mb": "4096",
}
@@ -509,7 +508,6 @@ def create_test_node_tag(**kw):
def get_test_xclarity_properties():
return {
"cpu_arch": "x86_64",
- "cpus": "8",
"local_gb": "10",
"memory_mb": "4096",
}
diff --git a/ironic/tests/unit/drivers/modules/drac/test_inspect.py b/ironic/tests/unit/drivers/modules/drac/test_inspect.py
index d12adba34..0c04ad887 100644
--- a/ironic/tests/unit/drivers/modules/drac/test_inspect.py
+++ b/ironic/tests/unit/drivers/modules/drac/test_inspect.py
@@ -185,7 +185,6 @@ class DracInspectionTestCase(test_utils.BaseDracTest):
expected_node_properties = {
'memory_mb': 32768,
'local_gb': 1116,
- 'cpus': 18,
'cpu_arch': 'x86_64',
'capabilities': 'boot_mode:uefi,pci_gpu_devices:1'}
mock_client = mock.Mock()
@@ -235,7 +234,6 @@ class DracInspectionTestCase(test_utils.BaseDracTest):
expected_node_properties = {
'memory_mb': 32768,
'local_gb': 279,
- 'cpus': 18,
'cpu_arch': 'x86_64',
'capabilities': 'boot_mode:uefi,pci_gpu_devices:1'}
mock_client = mock.Mock()
@@ -305,7 +303,6 @@ class DracInspectionTestCase(test_utils.BaseDracTest):
expected_node_properties = {
'memory_mb': 32768,
'local_gb': 279,
- 'cpus': 18,
'cpu_arch': 'x86_64',
'capabilities': 'boot_mode:uefi,pci_gpu_devices:0'}
mock_client = mock.Mock()
@@ -355,7 +352,6 @@ class DracInspectionTestCase(test_utils.BaseDracTest):
expected_node_properties = {
'memory_mb': 32768,
'local_gb': 279,
- 'cpus': 18,
'cpu_arch': 'x86_64',
'capabilities': 'boot_mode:uefi,pci_gpu_devices:2'}
mock_client = mock.Mock()
@@ -387,7 +383,6 @@ class DracInspectionTestCase(test_utils.BaseDracTest):
expected_node_properties = {
'memory_mb': 32768,
'local_gb': 279,
- 'cpus': 18,
'cpu_arch': 'x86_64',
'capabilities': 'boot_mode:uefi,pci_gpu_devices:0'}
mock_client = mock.Mock()
@@ -417,7 +412,6 @@ class DracInspectionTestCase(test_utils.BaseDracTest):
expected_node_properties = {
'memory_mb': 32768,
'local_gb': 1116,
- 'cpus': 18,
'cpu_arch': 'x86_64',
'capabilities': 'boot_mode:uefi,pci_gpu_devices:1'}
mock_client = mock.Mock()
@@ -449,22 +443,6 @@ class DracInspectionTestCase(test_utils.BaseDracTest):
self.assertEqual(285888, root_disk.size_mb)
- def test__calculate_cpus(self):
- with task_manager.acquire(self.context, self.node.uuid,
- shared=True) as task:
- cpu = task.driver.inspect._calculate_cpus(
- self.cpus[0])
-
- self.assertEqual(12, cpu)
-
- def test__calculate_cpus_without_ht_enabled(self):
- with task_manager.acquire(self.context, self.node.uuid,
- shared=True) as task:
- cpu = task.driver.inspect._calculate_cpus(
- self.cpus[1])
-
- self.assertEqual(6, cpu)
-
@mock.patch.object(drac_common, 'get_drac_client', spec_set=True,
autospec=True)
def test__get_pxe_dev_nics_with_UEFI_boot_mode(self, mock_get_drac_client):
diff --git a/ironic/tests/unit/drivers/modules/ilo/test_inspect.py b/ironic/tests/unit/drivers/modules/ilo/test_inspect.py
index 1a85d5b28..af262c0d0 100644
--- a/ironic/tests/unit/drivers/modules/ilo/test_inspect.py
+++ b/ironic/tests/unit/drivers/modules/ilo/test_inspect.py
@@ -65,7 +65,7 @@ class IloInspectTestCase(test_common.BaseIloTest):
get_capabilities_mock):
ilo_object_mock = get_ilo_object_mock.return_value
properties = {'memory_mb': '512', 'local_gb': '10',
- 'cpus': '1', 'cpu_arch': 'x86_64'}
+ 'cpu_arch': 'x86_64'}
macs = {'Port 1': 'aa:aa:aa:aa:aa:aa', 'Port 2': 'bb:bb:bb:bb:bb:bb'}
capabilities = {}
result = {'properties': properties, 'macs': macs}
@@ -103,8 +103,7 @@ class IloInspectTestCase(test_common.BaseIloTest):
get_capabilities_mock,
log_mock):
ilo_object_mock = get_ilo_object_mock.return_value
- properties = {'memory_mb': '512', 'local_gb': 0,
- 'cpus': '1', 'cpu_arch': 'x86_64'}
+ properties = {'memory_mb': '512', 'local_gb': 0, 'cpu_arch': 'x86_64'}
macs = {'Port 1': 'aa:aa:aa:aa:aa:aa', 'Port 2': 'bb:bb:bb:bb:bb:bb'}
capabilities = {}
result = {'properties': properties, 'macs': macs}
@@ -118,7 +117,7 @@ class IloInspectTestCase(test_common.BaseIloTest):
task.node.properties = properties
task.node.save()
expected_properties = {'memory_mb': '512', 'local_gb': 10,
- 'cpus': '1', 'cpu_arch': 'x86_64'}
+ 'cpu_arch': 'x86_64'}
task.driver.inspect.inspect_hardware(task)
self.assertEqual(expected_properties, task.node.properties)
power_mock.assert_called_once_with(mock.ANY, task)
@@ -149,8 +148,7 @@ class IloInspectTestCase(test_common.BaseIloTest):
get_capabilities_mock,
log_mock):
ilo_object_mock = get_ilo_object_mock.return_value
- properties = {'memory_mb': '512', 'local_gb': 10,
- 'cpus': '1', 'cpu_arch': 'x86_64'}
+ properties = {'memory_mb': '512', 'local_gb': 10, 'cpu_arch': 'x86_64'}
macs = {'Port 1': 'aa:aa:aa:aa:aa:aa', 'Port 2': 'bb:bb:bb:bb:bb:bb'}
capabilities = {'server_model': 'Gen8'}
result = {'properties': properties, 'macs': macs}
@@ -160,7 +158,7 @@ class IloInspectTestCase(test_common.BaseIloTest):
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
expected_properties = {'memory_mb': '512', 'local_gb': 10,
- 'cpus': '1', 'cpu_arch': 'x86_64',
+ 'cpu_arch': 'x86_64',
'capabilities': 'server_model:Gen8'}
task.driver.inspect.inspect_hardware(task)
self.assertEqual(expected_properties, task.node.properties)
@@ -195,8 +193,7 @@ class IloInspectTestCase(test_common.BaseIloTest):
get_security_params_mock,
log_mock):
ilo_object_mock = get_ilo_object_mock.return_value
- properties = {'memory_mb': '512', 'local_gb': 10,
- 'cpus': '1', 'cpu_arch': 'x86_64'}
+ properties = {'memory_mb': '512', 'local_gb': 10, 'cpu_arch': 'x86_64'}
macs = {'NIC.LOM.1.1': 'aa:aa:aa:aa:aa:aa'}
capabilities = {'server_model': 'Gen10'}
security_params = (
@@ -209,7 +206,7 @@ class IloInspectTestCase(test_common.BaseIloTest):
with task_manager.acquire(self.context, self.node.uuid,
shared=False) as task:
expected_properties = {
- 'memory_mb': '512', 'local_gb': 10, 'cpus': '1',
+ 'memory_mb': '512', 'local_gb': 10,
'cpu_arch': 'x86_64', 'capabilities': 'server_model:Gen10',
'security_parameters': {'Password Complexity': 'ok'}}
task.driver.inspect.inspect_hardware(task)
@@ -243,7 +240,7 @@ class IloInspectTestCase(test_common.BaseIloTest):
get_capabilities_mock):
ilo_object_mock = get_ilo_object_mock.return_value
properties = {'memory_mb': '512', 'local_gb': '10',
- 'cpus': '1', 'cpu_arch': 'x86_64'}
+ 'cpu_arch': 'x86_64'}
macs = {'Port 1': 'aa:aa:aa:aa:aa:aa', 'Port 2': 'bb:bb:bb:bb:bb:bb'}
capabilities = {}
result = {'properties': properties, 'macs': macs}
@@ -280,7 +277,7 @@ class IloInspectTestCase(test_common.BaseIloTest):
get_capabilities_mock):
ilo_object_mock = get_ilo_object_mock.return_value
properties = {'memory_mb': '512', 'local_gb': '10',
- 'cpus': '1', 'cpu_arch': 'x86_64'}
+ 'cpu_arch': 'x86_64'}
macs = {'Port 1': 'aa:aa:aa:aa:aa:aa', 'Port 2': 'bb:bb:bb:bb:bb:bb'}
capability_str = 'sriov_enabled:true'
capabilities = {'sriov_enabled': 'true'}
@@ -292,7 +289,7 @@ class IloInspectTestCase(test_common.BaseIloTest):
shared=False) as task:
task.driver.inspect.inspect_hardware(task)
expected_properties = {'memory_mb': '512', 'local_gb': '10',
- 'cpus': '1', 'cpu_arch': 'x86_64',
+ 'cpu_arch': 'x86_64',
'capabilities': capability_str}
self.assertEqual(expected_properties, task.node.properties)
power_mock.assert_called_once_with(mock.ANY, task)
@@ -320,8 +317,7 @@ class IloInspectTestCase(test_common.BaseIloTest):
get_capabilities_mock):
ilo_object_mock = get_ilo_object_mock.return_value
properties = {'memory_mb': '512', 'local_gb': '10',
- 'cpus': '1', 'cpu_arch': 'x86_64',
- 'somekey': 'somevalue'}
+ 'cpu_arch': 'x86_64', 'somekey': 'somevalue'}
macs = {'Port 1': 'aa:aa:aa:aa:aa:aa', 'Port 2': 'bb:bb:bb:bb:bb:bb'}
result = {'properties': properties, 'macs': macs}
capabilities = {'sriov_enabled': 'true'}
@@ -339,7 +335,7 @@ class IloInspectTestCase(test_common.BaseIloTest):
set2 = set(end_capabilities.split(','))
self.assertEqual(set1, set2)
expected_properties = {'memory_mb': '512', 'local_gb': '10',
- 'cpus': '1', 'cpu_arch': 'x86_64',
+ 'cpu_arch': 'x86_64',
'capabilities': end_capabilities}
power_mock.assert_called_once_with(mock.ANY, task)
self.assertEqual(task.node.properties, expected_properties)
@@ -356,7 +352,7 @@ class TestInspectPrivateMethods(test_common.BaseIloTest):
def test__get_essential_properties_ok(self):
ilo_mock = mock.MagicMock(spec=['get_essential_properties'])
properties = {'memory_mb': '512', 'local_gb': '10',
- 'cpus': '1', 'cpu_arch': 'x86_64'}
+ 'cpu_arch': 'x86_64'}
macs = {'Port 1': 'aa:aa:aa:aa:aa:aa', 'Port 2': 'bb:bb:bb:bb:bb:bb'}
result = {'properties': properties, 'macs': macs}
ilo_mock.get_essential_properties.return_value = result
@@ -368,8 +364,7 @@ class TestInspectPrivateMethods(test_common.BaseIloTest):
ilo_mock = mock.MagicMock(
spec=['get_additional_capabilities', 'get_essential_properties'])
# Missing key: cpu_arch
- properties = {'memory_mb': '512', 'local_gb': '10',
- 'cpus': '1'}
+ properties = {'memory_mb': '512', 'local_gb': '10'}
macs = {'Port 1': 'aa:aa:aa:aa:aa:aa', 'Port 2': 'bb:bb:bb:bb:bb:bb'}
result = {'properties': properties, 'macs': macs}
ilo_mock.get_essential_properties.return_value = result
@@ -386,8 +381,7 @@ class TestInspectPrivateMethods(test_common.BaseIloTest):
ilo_mock = mock.MagicMock(
spec=['get_additional_capabilities', 'get_essential_properties'])
# Not a dict
- properties = ['memory_mb', '512', 'local_gb', '10',
- 'cpus', '1']
+ properties = ['memory_mb', '512', 'local_gb', '10']
macs = ['aa:aa:aa:aa:aa:aa', 'bb:bb:bb:bb:bb:bb']
capabilities = ''
result = {'properties': properties, 'macs': macs}
@@ -400,7 +394,7 @@ class TestInspectPrivateMethods(test_common.BaseIloTest):
def test__get_essential_properties_fail_mac_invalid_format(self):
ilo_mock = mock.MagicMock(spec=['get_essential_properties'])
properties = {'memory_mb': '512', 'local_gb': '10',
- 'cpus': '1', 'cpu_arch': 'x86_64'}
+ 'cpu_arch': 'x86_64'}
# Not a dict
macs = 'aa:aa:aa:aa:aa:aa'
result = {'properties': properties, 'macs': macs}
@@ -413,7 +407,7 @@ class TestInspectPrivateMethods(test_common.BaseIloTest):
ilo_mock = mock.MagicMock(
spec=['get_additional_capabilities', 'get_essential_properties'])
properties = {'memory_mb': '512', 'local_gb': '10',
- 'cpus': '1', 'cpu_arch': 'x86_64'}
+ 'cpu_arch': 'x86_64'}
# Not a dictionary
macs = None
result = {'properties': properties, 'macs': macs}
@@ -427,7 +421,7 @@ class TestInspectPrivateMethods(test_common.BaseIloTest):
def test__get_essential_properties_hardware_port_not_dict(self):
ilo_mock = mock.MagicMock(spec=['get_essential_properties'])
properties = {'memory_mb': '512', 'local_gb': '10',
- 'cpus': '1', 'cpu_arch': 'x86_64'}
+ 'cpu_arch': 'x86_64'}
# Not a dict
macs = 'aa:bb:cc:dd:ee:ff'
result = {'properties': properties, 'macs': macs}
@@ -447,7 +441,7 @@ class TestInspectPrivateMethods(test_common.BaseIloTest):
def test__validate_ok(self):
properties = {'memory_mb': '512', 'local_gb': '10',
- 'cpus': '2', 'cpu_arch': 'x86_arch'}
+ 'cpu_arch': 'x86_arch'}
macs = {'Port 1': 'aa:aa:aa:aa:aa:aa'}
data = {'properties': properties, 'macs': macs}
valid_keys = ilo_inspect.IloInspect.ESSENTIAL_PROPERTIES
@@ -455,8 +449,7 @@ class TestInspectPrivateMethods(test_common.BaseIloTest):
self.assertEqual(sorted(set(properties)), sorted(valid_keys))
def test__validate_essential_keys_fail_missing_key(self):
- properties = {'memory_mb': '512', 'local_gb': '10',
- 'cpus': '1'}
+ properties = {'memory_mb': '512', 'local_gb': '10'}
macs = {'Port 1': 'aa:aa:aa:aa:aa:aa'}
data = {'properties': properties, 'macs': macs}
self.assertRaises(exception.HardwareInspectionFailure,
diff --git a/ironic/tests/unit/drivers/modules/irmc/test_inspect.py b/ironic/tests/unit/drivers/modules/irmc/test_inspect.py
index 2cec2429f..e8762391f 100644
--- a/ironic/tests/unit/drivers/modules/irmc/test_inspect.py
+++ b/ironic/tests/unit/drivers/modules/irmc/test_inspect.py
@@ -83,7 +83,6 @@ class IRMCInspectInternalMethodsTestCase(test_common.BaseIRMCTest):
inspected_props = {
'memory_mb': '1024',
'local_gb': 10,
- 'cpus': 2,
'cpu_arch': 'x86_64'}
inspected_capabilities = {
'irmc_firmware_version': 'iRMC S4-7.82F',
@@ -142,7 +141,6 @@ class IRMCInspectInternalMethodsTestCase(test_common.BaseIRMCTest):
inspected_props = {
'memory_mb': '1024',
'local_gb': 10,
- 'cpus': 2,
'cpu_arch': 'x86_64'}
inspected_capabilities = {
'irmc_firmware_version': 'iRMC S6-2.00S',
@@ -260,7 +258,6 @@ class IRMCInspectTestCase(test_common.BaseIRMCTest):
inspected_props = {
'memory_mb': '1024',
'local_gb': 10,
- 'cpus': 2,
'cpu_arch': 'x86_64'}
inspected_macs = ['aa:aa:aa:aa:aa:aa', 'bb:bb:bb:bb:bb:bb']
new_traits = ['CUSTOM_CPU_FPGA']
@@ -318,7 +315,6 @@ class IRMCInspectTestCase(test_common.BaseIRMCTest):
inspected_props = {
'memory_mb': '1024',
'local_gb': 10,
- 'cpus': 2,
'cpu_arch': 'x86_64'}
inspected_macs = ['aa:aa:aa:aa:aa:aa', 'bb:bb:bb:bb:bb:bb']
new_traits = ['CUSTOM_CPU_FPGA']
@@ -398,7 +394,6 @@ class IRMCInspectTestCase(test_common.BaseIRMCTest):
inspected_props = {
'memory_mb': '1024',
'local_gb': 10,
- 'cpus': 2,
'cpu_arch': 'x86_64'}
inspected_macs = ['aa:aa:aa:aa:aa:aa', 'bb:bb:bb:bb:bb:bb']
existing_traits = ['CUSTOM_CPU_FPGA']
@@ -459,7 +454,6 @@ class IRMCInspectTestCase(test_common.BaseIRMCTest):
inspected_props = {
'memory_mb': '1024',
'local_gb': 10,
- 'cpus': 2,
'cpu_arch': 'x86_64'}
inspected_macs = ['aa:aa:aa:aa:aa:aa', 'bb:bb:bb:bb:bb:bb']
diff --git a/ironic/tests/unit/drivers/modules/redfish/test_inspect.py b/ironic/tests/unit/drivers/modules/redfish/test_inspect.py
index dc1ffff4d..995dbb6d9 100644
--- a/ironic/tests/unit/drivers/modules/redfish/test_inspect.py
+++ b/ironic/tests/unit/drivers/modules/redfish/test_inspect.py
@@ -93,8 +93,7 @@ class RedfishInspectTestCase(db_base.DbTestCase):
mock_get_system):
expected_properties = {
'capabilities': 'boot_mode:uefi',
- 'cpu_arch': 'mips', 'cpus': '8',
- 'local_gb': '3', 'memory_mb': '2048'
+ 'cpu_arch': 'mips', 'local_gb': '3', 'memory_mb': '2048'
}
self.init_system_mock(mock_get_system.return_value)
@@ -140,8 +139,7 @@ class RedfishInspectTestCase(db_base.DbTestCase):
shared=True) as task:
expected_properties = {
'capabilities': 'boot_mode:uefi',
- 'cpu_arch': 'x86_64', 'cpus': '8',
- 'local_gb': '3', 'memory_mb': '2048'
+ 'cpu_arch': 'x86_64', 'local_gb': '3', 'memory_mb': '2048'
}
task.driver.inspect.inspect_hardware(task)
self.assertEqual(expected_properties, task.node.properties)
@@ -156,8 +154,7 @@ class RedfishInspectTestCase(db_base.DbTestCase):
shared=True) as task:
expected_properties = {
'capabilities': 'boot_mode:uefi',
- 'cpu_arch': 'mips', 'cpus': '8',
- 'local_gb': '0', 'memory_mb': '2048'
+ 'cpu_arch': 'mips', 'local_gb': '0', 'memory_mb': '2048'
}
task.driver.inspect.inspect_hardware(task)
self.assertEqual(expected_properties, task.node.properties)
@@ -182,8 +179,7 @@ class RedfishInspectTestCase(db_base.DbTestCase):
shared=True) as task:
expected_properties = {
'capabilities': 'boot_mode:uefi',
- 'cpu_arch': 'mips', 'cpus': '8',
- 'local_gb': '3', 'memory_mb': '4096'
+ 'cpu_arch': 'mips', 'local_gb': '3', 'memory_mb': '4096'
}
task.driver.inspect.inspect_hardware(task)
self.assertEqual(expected_properties, task.node.properties)
@@ -212,8 +208,7 @@ class RedfishInspectTestCase(db_base.DbTestCase):
}
expected_properties = {
'capabilities': 'boot_mode:bios',
- 'cpu_arch': 'mips', 'cpus': '8',
- 'local_gb': '3', 'memory_mb': '2048'
+ 'cpu_arch': 'mips', 'local_gb': '3', 'memory_mb': '2048'
}
task.driver.inspect.inspect_hardware(task)
self.assertEqual(expected_properties, task.node.properties)
@@ -226,8 +221,7 @@ class RedfishInspectTestCase(db_base.DbTestCase):
with task_manager.acquire(self.context, self.node.uuid,
shared=True) as task:
expected_properties = {
- 'cpu_arch': 'mips', 'cpus': '8',
- 'local_gb': '3', 'memory_mb': '2048'
+ 'cpu_arch': 'mips', 'local_gb': '3', 'memory_mb': '2048'
}
task.driver.inspect.inspect_hardware(task)
self.assertEqual(expected_properties, task.node.properties)
diff --git a/ironic/tests/unit/objects/test_node.py b/ironic/tests/unit/objects/test_node.py
index 146120644..5ba823a89 100644
--- a/ironic/tests/unit/objects/test_node.py
+++ b/ironic/tests/unit/objects/test_node.py
@@ -534,10 +534,10 @@ class TestNodeObject(db_base.DbTestCase, obj_utils.SchemasTestMixIn):
autospec=True) as mock_get_node:
mock_get_node.return_value = self.fake_node
node = objects.Node.get(self.context, uuid)
- node.properties = {"local_gb": "5G", "memory_mb": "5",
- 'cpus': '-1', 'cpu_arch': 'x86_64'}
+ node.properties = {"local_gb": "5G", "memory_mb": "-5",
+ 'cpu_arch': 'x86_64'}
self.assertRaisesRegex(exception.InvalidParameterValue,
- ".*local_gb=5G, cpus=-1$", node.save)
+ ".*local_gb=5G, memory_mb=-5$", node.save)
mock_get_node.assert_called_once_with(uuid)
def test__validate_property_values_success(self):
@@ -549,7 +549,6 @@ class TestNodeObject(db_base.DbTestCase, obj_utils.SchemasTestMixIn):
values = self.fake_node
expect = {
'cpu_arch': 'x86_64',
- "cpus": '8',
"local_gb": '10',
"memory_mb": '4096',
}
diff --git a/releasenotes/notes/Cleanfail-power-off-13b5fdcc2727866a.yaml b/releasenotes/notes/Cleanfail-power-off-13b5fdcc2727866a.yaml
new file mode 100644
index 000000000..2856bac06
--- /dev/null
+++ b/releasenotes/notes/Cleanfail-power-off-13b5fdcc2727866a.yaml
@@ -0,0 +1,8 @@
+---
+features:
+ - |
+ Add new conductor conf option: [conductor]poweroff_in_cleanfail
+ (default: False). when True nodes entering clean failed state
+ will be powered off. This option may be unsafe when using
+ Cleaning to perform hardware-transformative actions such as
+ firmware upgrade.
diff --git a/releasenotes/notes/fix-db-sqlite-OperationalError-7934dbda2a21c69e.yaml b/releasenotes/notes/fix-db-sqlite-OperationalError-7934dbda2a21c69e.yaml
new file mode 100644
index 000000000..85a604ae4
--- /dev/null
+++ b/releasenotes/notes/fix-db-sqlite-OperationalError-7934dbda2a21c69e.yaml
@@ -0,0 +1,6 @@
+---
+fixes:
+ - |
+ Fixes issues in Ironic's use of SQLAlchemy with SQLite Databases,
+ which is common with users like Metal3, which prevented Ironic from
+ supporting SQLAlchemy 2.0 properly, as autocommit was re-enabled.
diff --git a/releasenotes/notes/no-cpus-c79717303470bf3c.yaml b/releasenotes/notes/no-cpus-c79717303470bf3c.yaml
new file mode 100644
index 000000000..4f264e79b
--- /dev/null
+++ b/releasenotes/notes/no-cpus-c79717303470bf3c.yaml
@@ -0,0 +1,6 @@
+---
+upgrade:
+ - |
+ Fully removes the ``cpus`` property from the documentation and inspect
+ interface implementations. It was never used internally by Ironic,
+ and is no longer used by Nova.
diff --git a/tox.ini b/tox.ini
index 1fa446d66..bd564415b 100644
--- a/tox.ini
+++ b/tox.ini
@@ -37,7 +37,7 @@ commands = {toxinidir}/tools/states_to_dot.py -f {toxinidir}/doc/source/images/s
[testenv:pep8]
usedevelop = False
deps=
- hacking>=4.1.0,<5.0.0 # Apache-2.0
+ hacking~=6.0.0 # Apache-2.0
doc8>=0.6.0 # Apache-2.0
pycodestyle>=2.0.0,<3.0.0 # MIT
flake8-import-order>=0.17.1 # LGPLv3
diff --git a/zuul.d/ironic-jobs.yaml b/zuul.d/ironic-jobs.yaml
index ca1757417..d2e91875f 100644
--- a/zuul.d/ironic-jobs.yaml
+++ b/zuul.d/ironic-jobs.yaml
@@ -896,6 +896,7 @@
SWIFT_TEMPURL_KEY: secretkey
EBTABLES_RACE_FIX: True
LIBVIRT_STORAGE_POOL_PATH: /opt/libvirt/images
+ INSTANCE_WAIT: 120
old:
IRONIC_VM_LOG_DIR: '{{ devstack_bases.old }}/ironic-bm-logs'
grenade_localrc:
diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml
index 8fbfbb929..cf3a696db 100644
--- a/zuul.d/project.yaml
+++ b/zuul.d/project.yaml
@@ -13,7 +13,10 @@
- ironic-cross-sushy:
voting: false
- ironic-tempest-functional-python3
- - ironic-tempest-functional-rbac-scope-enforced
+ # NOTE(rpittau) moving to non-voting until we fix the tests
+ # see also https://review.opendev.org/c/openstack/ironic-tempest-plugin/+/882312
+ - ironic-tempest-functional-rbac-scope-enforced:
+ voting: false
- ironic-grenade
- ironic-standalone
- ironic-standalone-redfish
@@ -63,7 +66,9 @@
jobs:
- ironic-tox-unit-with-driver-libs
- ironic-tempest-functional-python3
- - ironic-tempest-functional-rbac-scope-enforced
+ # NOTE(rpittau) disabled until we fix the tests
+ # see also https://review.opendev.org/c/openstack/ironic-tempest-plugin/+/882312
+ #- ironic-tempest-functional-rbac-scope-enforced
- ironic-grenade
- ironic-standalone
- ironic-standalone-redfish