Skip to content

Commit 36746a3

Browse files
authored
Merge pull request #116 from stackhpc/upstream/yoga-2024-10-07
Synchronise yoga with upstream
2 parents 651fed4 + 084b4d3 commit 36746a3

File tree

13 files changed

+182
-77
lines changed

13 files changed

+182
-77
lines changed

.zuul.yaml

Lines changed: 26 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -197,24 +197,11 @@
197197
parent: devstack-tempest
198198
description: |
199199
Run tempest compute API tests using LVM image backend. This only runs
200-
against nova/virt/libvirt/* changes.
201-
# Copy irrelevant-files from nova-dsvm-multinode-base and then exclude
202-
# anything that is not in nova/virt/libvirt/* or nova/privsep/*.
203-
irrelevant-files:
204-
- ^(?!.zuul.yaml)(?!nova/virt/libvirt/)(?!nova/privsep/).*$
205-
- ^api-.*$
206-
- ^(test-|)requirements.txt$
207-
- ^.*\.rst$
208-
- ^.git.*$
209-
- ^doc/.*$
210-
- ^nova/hacking/.*$
211-
- ^nova/locale/.*$
212-
- ^nova/tests/.*$
213-
- ^nova/test.py$
214-
- ^releasenotes/.*$
215-
- ^setup.cfg$
216-
- ^tools/.*$
217-
- ^tox.ini$
200+
against nova/virt/libvirt/*, nova/privsep/* and .zuul.yaml changes.
201+
files:
202+
- ^nova/virt/libvirt/.*$
203+
- ^nova/privsep/.*$
204+
- .zuul.yaml
218205
vars:
219206
# We use the "all" environment for tempest_test_regex and
220207
# tempest_exclude_regex.
@@ -253,22 +240,11 @@
253240
# NOTE(chateaulav): due to constraints with no IDE support for aarch64,
254241
# tests have been limited to eliminate any items that are incompatible.
255242
# This is to be re-evaluated as greater support is added and defined.
256-
irrelevant-files:
257-
- ^(?!.zuul.yaml)(?!nova/virt/libvirt/)(?!nova/objects/)(?!nova/scheduler/).*$
258-
- ^api-.*$
259-
- ^(test-|)requirements.txt$
260-
- ^.*\.rst$
261-
- ^.git.*$
262-
- ^doc/.*$
263-
- ^nova/hacking/.*$
264-
- ^nova/locale/.*$
265-
- ^nova/policies/.*$
266-
- ^nova/tests/.*$
267-
- ^nova/test.py$
268-
- ^releasenotes/.*$
269-
- ^setup.cfg$
270-
- ^tools/.*$
271-
- ^tox.ini$
243+
files:
244+
- ^nova/virt/libvirt/.*$
245+
- ^nova/objects/.*$
246+
- ^nova/scheduler/.*$
247+
- .zuul.yaml
272248
vars:
273249
tox_envlist: all
274250
tempest_test_regex: ^tempest\.(api\.compute\.servers|scenario\.test_network_basic_ops)
@@ -580,6 +556,16 @@
580556
GLANCE_STANDALONE: True
581557
GLANCE_USE_IMPORT_WORKFLOW: True
582558
DEVSTACK_PARALLEL: True
559+
MYSQL_REDUCE_MEMORY: True
560+
# NOTE(danms): This job is pretty heavy as it is, so we disable some
561+
# services that are not relevant to the nova-glance-ceph scenario
562+
# that this job is intended to validate.
563+
devstack_services:
564+
c-bak: false
565+
s-account: false
566+
s-container: false
567+
s-object: false
568+
s-proxy: false
583569
devstack_local_conf:
584570
post-config:
585571
$NOVA_CONF:
@@ -632,11 +618,12 @@
632618
- nova-ceph-multistore:
633619
irrelevant-files: *nova-base-irrelevant-files
634620
- neutron-linuxbridge-tempest:
635-
irrelevant-files:
621+
files:
636622
# NOTE(mriedem): This job has its own irrelevant-files section
637623
# so that we only run it on changes to networking and libvirt/vif
638624
# code; we don't need to run this on all changes.
639-
- ^(?!nova/network/.*)(?!nova/virt/libvirt/vif.py).*$
625+
- ^nova/network/.*$
626+
- nova/virt/libvirt/vif.py
640627
- nova-live-migration
641628
- nova-live-migration-ceph
642629
- nova-lvm
@@ -680,11 +667,6 @@
680667
- barbican-tempest-plugin-simple-crypto:
681668
irrelevant-files: *nova-base-irrelevant-files
682669
voting: false
683-
- tempest-integrated-compute-centos-8-stream:
684-
irrelevant-files: *nova-base-irrelevant-files
685-
- tempest-centos8-stream-fips:
686-
irrelevant-files: *nova-base-irrelevant-files
687-
voting: false
688670
gate:
689671
jobs:
690672
- nova-live-migration
@@ -697,11 +679,12 @@
697679
- nova-ceph-multistore:
698680
irrelevant-files: *nova-base-irrelevant-files
699681
- neutron-linuxbridge-tempest:
700-
irrelevant-files:
682+
files:
701683
# NOTE(mriedem): This job has its own irrelevant-files section
702684
# so that we only run it on changes to networking and libvirt/vif
703685
# code; we don't need to run this on all changes.
704-
- ^(?!nova/network/.*)(?!nova/virt/libvirt/vif.py).*$
686+
- ^nova/network/.*$
687+
- nova/virt/libvirt/vif.py
705688
- tempest-integrated-compute:
706689
irrelevant-files: *policies-irrelevant-files
707690
- nova-grenade-multinode:
@@ -710,8 +693,6 @@
710693
irrelevant-files: *nova-base-irrelevant-files
711694
- openstacksdk-functional-devstack:
712695
irrelevant-files: *nova-base-irrelevant-files
713-
- tempest-integrated-compute-centos-8-stream:
714-
irrelevant-files: *nova-base-irrelevant-files
715696
experimental:
716697
jobs:
717698
- ironic-tempest-bfv:

nova/compute/manager.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6646,9 +6646,9 @@ def _shelve_offload_instance(self, context, instance, clean_shutdown,
66466646

66476647
instance.power_state = current_power_state
66486648
# NOTE(mriedem): The vm_state has to be set before updating the
6649-
# resource tracker, see vm_states.ALLOW_RESOURCE_REMOVAL. The host/node
6650-
# values cannot be nulled out until after updating the resource tracker
6651-
# though.
6649+
# resource tracker, see vm_states.allow_resource_removal(). The
6650+
# host/node values cannot be nulled out until after updating the
6651+
# resource tracker though.
66526652
instance.vm_state = vm_states.SHELVED_OFFLOADED
66536653
instance.task_state = None
66546654
instance.save(expected_task_state=[task_states.SHELVING,

nova/compute/resource_tracker.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1495,7 +1495,8 @@ def _update_usage_from_instance(self, context, instance, nodename,
14951495
# NOTE(sfinucan): Both brand new instances as well as instances that
14961496
# are being unshelved will have is_new_instance == True
14971497
is_removed_instance = not is_new_instance and (is_removed or
1498-
instance['vm_state'] in vm_states.ALLOW_RESOURCE_REMOVAL)
1498+
vm_states.allow_resource_removal(
1499+
vm_state=instance['vm_state'], task_state=instance.task_state))
14991500

15001501
if is_new_instance:
15011502
self.tracked_instances.add(uuid)
@@ -1554,7 +1555,9 @@ def _update_usage_from_instances(self, context, instances, nodename):
15541555

15551556
instance_by_uuid = {}
15561557
for instance in instances:
1557-
if instance.vm_state not in vm_states.ALLOW_RESOURCE_REMOVAL:
1558+
if not vm_states.allow_resource_removal(
1559+
vm_state=instance['vm_state'],
1560+
task_state=instance.task_state):
15581561
self._update_usage_from_instance(context, instance, nodename)
15591562
instance_by_uuid[instance.uuid] = instance
15601563
return instance_by_uuid

nova/compute/stats.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@ def update_stats_for_instance(self, instance, is_removed=False):
105105
(vm_state, task_state, os_type, project_id) = \
106106
self._extract_state_from_instance(instance)
107107

108-
if is_removed or vm_state in vm_states.ALLOW_RESOURCE_REMOVAL:
108+
if is_removed or vm_states.allow_resource_removal(
109+
vm_state=vm_state, task_state=task_state):
109110
self._decrement("num_instances")
110111
self.states.pop(uuid)
111112
else:

nova/compute/vm_states.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
See http://wiki.openstack.org/VMState
2828
"""
2929

30+
from nova.compute import task_states
3031
from nova.objects import fields
3132

3233

@@ -74,5 +75,11 @@
7475
# states we allow to trigger crash dump
7576
ALLOW_TRIGGER_CRASH_DUMP = [ACTIVE, PAUSED, RESCUED, RESIZED, ERROR]
7677

77-
# states we allow resources to be freed in
78-
ALLOW_RESOURCE_REMOVAL = [DELETED, SHELVED_OFFLOADED]
78+
79+
def allow_resource_removal(vm_state, task_state=None):
80+
"""(vm_state, task_state) combinations we allow resources to be freed in"""
81+
82+
return (
83+
vm_state == DELETED or
84+
vm_state == SHELVED_OFFLOADED and task_state != task_states.SPAWNING
85+
)

nova/conf/workarounds.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,16 @@
416416
help="""
417417
When this is enabled, it will skip version-checking of hypervisors
418418
during live migration.
419+
"""),
420+
cfg.BoolOpt(
421+
'disable_deep_image_inspection',
422+
default=False,
423+
help="""
424+
This disables the additional deep image inspection that the compute node does
425+
when downloading from glance. This includes backing-file, data-file, and
426+
known-features detection *before* passing the image to qemu-img. Generally,
427+
this inspection should be enabled for maximum safety, but this workaround
428+
option allows disabling it if there is a compatibility concern.
419429
"""),
420430
cfg.BoolOpt(
421431
'skip_reserve_in_use_ironic_nodes',
@@ -431,16 +441,6 @@
431441
Howerver, if you don't use automatic cleaning, it can cause an
432442
extra delay before and Ironic node is available for building a
433443
new Nova instance.
434-
"""),
435-
cfg.BoolOpt(
436-
'disable_deep_image_inspection',
437-
default=False,
438-
help="""
439-
This disables the additional deep image inspection that the compute node does
440-
when downloading from glance. This includes backing-file, data-file, and
441-
known-features detection *before* passing the image to qemu-img. Generally,
442-
this inspection should be enabled for maximum safety, but this workaround
443-
option allows disabling it if there is a compatibility concern.
444444
"""),
445445
]
446446

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
2+
# not use this file except in compliance with the License. You may obtain
3+
# a copy of the License at
4+
#
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
#
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10+
# License for the specific language governing permissions and limitations
11+
# under the License.
12+
from unittest import mock
13+
14+
from nova import context
15+
from nova.objects import compute_node
16+
from nova import test
17+
from nova.tests import fixtures as nova_fixtures
18+
from nova.tests.functional import fixtures as func_fixtures
19+
from nova.tests.functional import integrated_helpers
20+
21+
22+
class UnshelveUpdateAvailableResourcesPeriodicRace(
23+
test.TestCase, integrated_helpers.InstanceHelperMixin):
24+
def setUp(self):
25+
super(UnshelveUpdateAvailableResourcesPeriodicRace, self).setUp()
26+
27+
placement = func_fixtures.PlacementFixture()
28+
self.useFixture(placement)
29+
self.placement = placement.api
30+
self.neutron = nova_fixtures.NeutronFixture(self)
31+
self.useFixture(self.neutron)
32+
self.useFixture(nova_fixtures.GlanceFixture(self))
33+
# Start nova services.
34+
self.api = self.useFixture(nova_fixtures.OSAPIFixture(
35+
api_version='v2.1')).admin_api
36+
self.api.microversion = 'latest'
37+
self.notifier = self.useFixture(
38+
nova_fixtures.NotificationFixture(self))
39+
40+
self.start_service('conductor')
41+
self.start_service('scheduler')
42+
43+
def test_unshelve_spawning_update_available_resources(self):
44+
compute = self._start_compute('compute1')
45+
46+
server = self._create_server(
47+
networks=[{'port': self.neutron.port_1['id']}])
48+
49+
node = compute_node.ComputeNode.get_by_nodename(
50+
context.get_admin_context(), 'compute1')
51+
self.assertEqual(1, node.vcpus_used)
52+
53+
# with default config shelve means immediate offload as well
54+
req = {
55+
'shelve': {}
56+
}
57+
self.api.post_server_action(server['id'], req)
58+
self._wait_for_server_parameter(
59+
server, {'status': 'SHELVED_OFFLOADED',
60+
'OS-EXT-SRV-ATTR:host': None})
61+
62+
node = compute_node.ComputeNode.get_by_nodename(
63+
context.get_admin_context(), 'compute1')
64+
self.assertEqual(0, node.vcpus_used)
65+
66+
def fake_spawn(*args, **kwargs):
67+
self._run_periodics()
68+
69+
with mock.patch.object(
70+
compute.driver, 'spawn', side_effect=fake_spawn):
71+
req = {'unshelve': None}
72+
self.api.post_server_action(server['id'], req)
73+
self.notifier.wait_for_versioned_notifications(
74+
'instance.unshelve.start')
75+
self._wait_for_server_parameter(
76+
server,
77+
{
78+
'status': 'ACTIVE',
79+
'OS-EXT-STS:task_state': None,
80+
'OS-EXT-SRV-ATTR:host': 'compute1',
81+
})
82+
83+
node = compute_node.ComputeNode.get_by_nodename(
84+
context.get_admin_context(), 'compute1')
85+
# After the fix, the instance should have resources claimed
86+
self.assertEqual(1, node.vcpus_used)

nova/tests/unit/compute/test_stats.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,22 @@ def test_update_stats_for_instance_offloaded(self):
208208
self.assertEqual(0, self.stats.num_os_type("Linux"))
209209
self.assertEqual(0, self.stats["num_vm_" + vm_states.BUILDING])
210210

211+
def test_update_stats_for_instance_being_unshelved(self):
212+
instance = self._create_instance()
213+
self.stats.update_stats_for_instance(instance)
214+
self.assertEqual(1, self.stats.num_instances_for_project("1234"))
215+
216+
instance["vm_state"] = vm_states.SHELVED_OFFLOADED
217+
instance["task_state"] = task_states.SPAWNING
218+
self.stats.update_stats_for_instance(instance)
219+
220+
self.assertEqual(1, self.stats.num_instances)
221+
self.assertEqual(1, self.stats.num_instances_for_project(1234))
222+
self.assertEqual(1, self.stats["num_os_type_Linux"])
223+
self.assertEqual(1, self.stats["num_vm_%s" %
224+
vm_states.SHELVED_OFFLOADED])
225+
self.assertEqual(1, self.stats["num_task_%s" % task_states.SPAWNING])
226+
211227
def test_io_workload(self):
212228
vms = [vm_states.ACTIVE, vm_states.BUILDING, vm_states.PAUSED]
213229
tasks = [task_states.RESIZE_MIGRATING, task_states.REBUILDING,

nova/tests/unit/image/test_format_inspector.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -426,12 +426,14 @@ def test_qcow2_safety_checks(self):
426426
inspector = format_inspector.QcowInspector.from_file(fn)
427427
self.assertFalse(inspector.safety_check())
428428

429+
# Note(lajoskatona): This image create fails on bionic due to
430+
# old qemu-img utilities, let's skip this only test from yoga
429431
# A data-file makes it unsafe
430-
fn = self._create_img('qcow2', 5 * units.Mi,
431-
options={'data_file': data_fn,
432-
'data_file_raw': 'on'})
433-
inspector = format_inspector.QcowInspector.from_file(fn)
434-
self.assertFalse(inspector.safety_check())
432+
# fn = self._create_img('qcow2', 5 * units.Mi,
433+
# options={'data_file': data_fn,
434+
# 'data_file_raw': 'on'})
435+
# inspector = format_inspector.QcowInspector.from_file(fn)
436+
# self.assertFalse(inspector.safety_check())
435437

436438
# Trying to load a non-QCOW file is an error
437439
self.assertRaises(format_inspector.ImageFormatError,

nova/tests/unit/virt/libvirt/test_driver.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8848,7 +8848,7 @@ def test_unquiesce(self, mock_has_min_version):
88488848

88498849
def test_create_snapshot_metadata(self):
88508850
base = objects.ImageMeta.from_dict(
8851-
{'disk_format': 'raw'})
8851+
{'disk_format': 'qcow2'})
88528852
instance_data = {'kernel_id': 'kernel',
88538853
'project_id': 'prj_id',
88548854
'ramdisk_id': 'ram_id',
@@ -8880,10 +8880,12 @@ def test_create_snapshot_metadata(self):
88808880
{'disk_format': 'ami',
88818881
'container_format': 'test_container'})
88828882
expected['properties']['os_type'] = instance['os_type']
8883-
expected['disk_format'] = base.disk_format
8883+
# The disk_format of the snapshot should be the *actual* format of the
8884+
# thing we upload, regardless of what type of image we booted from.
8885+
expected['disk_format'] = img_fmt
88848886
expected['container_format'] = base.container_format
88858887
ret = drvr._create_snapshot_metadata(base, instance, img_fmt, snp_name)
8886-
self.assertEqual(ret, expected)
8888+
self.assertEqual(expected, ret)
88878889

88888890
def test_get_volume_driver(self):
88898891
conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False)
@@ -28225,7 +28227,8 @@ def test_ami(self):
2822528227
utils.get_system_metadata_from_image(
2822628228
{'disk_format': 'ami'})
2822728229

28228-
self._test_snapshot(disk_format='ami')
28230+
# If we're uploading a qcow2, we must set the disk_format as such
28231+
self._test_snapshot(disk_format='qcow2')
2822928232

2823028233
@mock.patch('nova.virt.libvirt.utils.get_disk_type_from_path',
2823128234
new=mock.Mock(return_value=None))

0 commit comments

Comments
 (0)