diff options
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. @@ -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 |