diff options
-rw-r--r-- | .zuul.yaml | 43 | ||||
-rw-r--r-- | nova/api/openstack/placement/handlers/root.py | 12 | ||||
-rw-r--r-- | nova/compute/resource_tracker.py | 21 | ||||
-rw-r--r-- | nova/exception.py | 2 | ||||
-rw-r--r-- | nova/tests/functional/api/openstack/placement/gabbits/microversion.yaml | 2 | ||||
-rwxr-xr-x | nova/tests/live_migration/hooks/ceph.sh | 1 | ||||
-rwxr-xr-x | nova/tests/live_migration/hooks/run_tests.sh | 5 | ||||
-rw-r--r-- | nova/tests/unit/compute/test_resource_tracker.py | 52 | ||||
-rw-r--r-- | nova/virt/libvirt/host.py | 2 | ||||
-rw-r--r-- | nova/virt/libvirt/volume/mount.py | 2 | ||||
-rw-r--r-- | placement-api-ref/source/get-root.json | 9 | ||||
-rw-r--r-- | placement-api-ref/source/parameters.yaml | 13 | ||||
-rw-r--r-- | placement-api-ref/source/root.inc | 2 | ||||
-rw-r--r-- | test-requirements.txt | 2 | ||||
-rwxr-xr-x | tools/check-cherry-picks.sh | 2 |
15 files changed, 107 insertions, 63 deletions
diff --git a/.zuul.yaml b/.zuul.yaml index dd7e90ff44..4d34143075 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -162,7 +162,6 @@ - ^tests-py3.txt$ - ^tools/.*$ - ^tox.ini$ - - nova-grenade-live-migration - nova-live-migration - tempest-slow: irrelevant-files: @@ -181,21 +180,6 @@ - ^tox.ini$ - nova-tox-functional - nova-tox-functional-py35 - - neutron-grenade-multinode: - irrelevant-files: - - ^(placement-)?api-.*$ - - ^(test-|)requirements.txt$ - - ^.*\.rst$ - - ^.git.*$ - - ^doc/.*$ - - ^nova/hacking/.*$ - - ^nova/locale/.*$ - - ^nova/tests/.*$ - - ^releasenotes/.*$ - - ^setup.cfg$ - - ^tests-py3.txt$ - - ^tools/.*$ - - ^tox.ini$ - neutron-tempest-linuxbridge: irrelevant-files: - ^(?!nova/network/.*)(?!nova/virt/libvirt/vif.py).*$ @@ -243,7 +227,10 @@ - ^tests-py3.txt$ - ^tools/.*$ - ^tox.ini$ - - neutron-grenade: + gate: + jobs: + - nova-live-migration + - tempest-slow: irrelevant-files: - ^(placement-)?api-.*$ - ^(test-|)requirements.txt$ @@ -258,10 +245,9 @@ - ^tests-py3.txt$ - ^tools/.*$ - ^tox.ini$ - gate: - jobs: - - nova-live-migration - - tempest-slow: + - nova-tox-functional + - nova-tox-functional-py35 + - tempest-full: irrelevant-files: - ^(placement-)?api-.*$ - ^(test-|)requirements.txt$ @@ -276,9 +262,13 @@ - ^tests-py3.txt$ - ^tools/.*$ - ^tox.ini$ - - nova-tox-functional - - nova-tox-functional-py35 - - tempest-full: + post: + jobs: + - openstack-tox-cover + experimental: + jobs: + - nova-grenade-live-migration + - neutron-grenade-multinode: irrelevant-files: - ^(placement-)?api-.*$ - ^(test-|)requirements.txt$ @@ -308,11 +298,6 @@ - ^tests-py3.txt$ - ^tools/.*$ - ^tox.ini$ - post: - jobs: - - openstack-tox-cover - experimental: - jobs: - tempest-nova-v2-api: irrelevant-files: - ^(placement-)?api-.*$ diff --git a/nova/api/openstack/placement/handlers/root.py b/nova/api/openstack/placement/handlers/root.py index 9b5b1bb948..5c35039ce9 100644 --- a/nova/api/openstack/placement/handlers/root.py +++ b/nova/api/openstack/placement/handlers/root.py @@ -30,6 +30,18 @@ def home(req): 'id': 'v%s' % min_version, 'max_version': max_version, 'min_version': min_version, + # for now there is only ever one version, so it must be CURRENT + 'status': 'CURRENT', + 'links': [{ + # Point back to this same URL as the root of this version. + # NOTE(cdent): We explicitly want this to be a relative-URL + # representation of "this same URL", otherwise placement needs + # to keep track of proxy addresses and the like, which we have + # avoided thus far, in order to construct full URLs. Placement + # is much easier to scale if we never track that stuff. + 'rel': 'self', + 'href': '', + }], } version_json = jsonutils.dumps({'versions': [version_data]}) req.response.body = encodeutils.to_utf8(version_json) diff --git a/nova/compute/resource_tracker.py b/nova/compute/resource_tracker.py index 024d915875..adf26260c3 100644 --- a/nova/compute/resource_tracker.py +++ b/nova/compute/resource_tracker.py @@ -583,7 +583,6 @@ class ResourceTracker(object): cn = self.compute_nodes[nodename] self._copy_resources(cn, resources) self._setup_pci_tracker(context, cn, resources) - self._update(context, cn) return # now try to get the compute node record from the @@ -593,7 +592,6 @@ class ResourceTracker(object): self.compute_nodes[nodename] = cn self._copy_resources(cn, resources) self._setup_pci_tracker(context, cn, resources) - self._update(context, cn) return if self._check_for_nodes_rebalance(context, resources, nodename): @@ -616,7 +614,6 @@ class ResourceTracker(object): {'host': self.host, 'node': nodename, 'uuid': cn.uuid}) self._setup_pci_tracker(context, cn, resources) - self._update(context, cn) def _setup_pci_tracker(self, context, compute_node, resources): if not self.pci_tracker: @@ -895,10 +892,22 @@ class ResourceTracker(object): def _update(self, context, compute_node): """Update partial stats locally and populate them to Scheduler.""" - if not self._resource_change(compute_node): - return + if self._resource_change(compute_node): + # If the compute_node's resource changed, update to DB. + # NOTE(jianghuaw): Once we completely move to use get_inventory() + # for all resource provider's inv data. We can remove this check. + # At the moment we still need this check and save compute_node. + compute_node.save() + + # NOTE(jianghuaw): Some resources(e.g. ironic custom resources) are + # not saved in the object of compute_node; instead the inventory data + # for these resource is reported by driver's get_inventory(). So even + # there is no resource change for compute_node as above, we need + # proceed to get inventory and use scheduler_client interfaces to + # update inventory to placement. It's scheduler_client's responsibility + # to ensure the update request to placement only happens when inventory + # is changed. nodename = compute_node.hypervisor_hostname - compute_node.save() # Persist the stats to the Scheduler try: inv_data = self.driver.get_inventory(nodename) diff --git a/nova/exception.py b/nova/exception.py index 85fe8f8b0f..4eb436b827 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -462,7 +462,7 @@ class ComputeResourcesUnavailable(ServiceUnavailable): class HypervisorUnavailable(NovaException): - msg_fmt = _("Connection to the hypervisor is broken on host: %(host)s") + msg_fmt = _("Connection to the hypervisor is broken on host") class ComputeServiceUnavailable(ServiceUnavailable): diff --git a/nova/tests/functional/api/openstack/placement/gabbits/microversion.yaml b/nova/tests/functional/api/openstack/placement/gabbits/microversion.yaml index 778ab4fce0..abcec8f61a 100644 --- a/nova/tests/functional/api/openstack/placement/gabbits/microversion.yaml +++ b/nova/tests/functional/api/openstack/placement/gabbits/microversion.yaml @@ -22,6 +22,8 @@ tests: $.versions[0].max_version: /^\d+\.\d+$/ $.versions[0].min_version: /^\d+\.\d+$/ $.versions[0].id: v1.0 + $.versions[0].status: CURRENT + $.versions[0].links[?rel = 'self'].href: '' - name: unavailable microversion raises 406 GET: / diff --git a/nova/tests/live_migration/hooks/ceph.sh b/nova/tests/live_migration/hooks/ceph.sh index 4fbe3f2ad3..fd16fc2a7e 100755 --- a/nova/tests/live_migration/hooks/ceph.sh +++ b/nova/tests/live_migration/hooks/ceph.sh @@ -8,6 +8,7 @@ function prepare_ceph { configure_ceph #install ceph-common package on compute nodes $ANSIBLE subnodes --become -f 5 -i "$WORKSPACE/inventory" -m raw -a "executable=/bin/bash + export CEPH_RELEASE=nautilus source $BASE/new/devstack/functions source $BASE/new/devstack/functions-common git clone https://git.openstack.org/openstack/devstack-plugin-ceph /tmp/devstack-plugin-ceph diff --git a/nova/tests/live_migration/hooks/run_tests.sh b/nova/tests/live_migration/hooks/run_tests.sh index 21768642ed..7f27c334ac 100755 --- a/nova/tests/live_migration/hooks/run_tests.sh +++ b/nova/tests/live_migration/hooks/run_tests.sh @@ -54,6 +54,11 @@ if [[ "$GRENADE_OLD_BRANCH" == "stable/ocata" ]]; then echo '3. Grenade testing with Ceph is disabled until bug 1691769 is fixed or Queens.' else echo '3. test with Ceph for root + ephemeral disks' + # NOTE(lyarwood): Pin the CEPH_RELEASE to nautilus here as was the case + # prior to https://review.opendev.org/c/openstack/devstack-plugin-ceph/+/777232 + # landing in the branchless plugin, we also have to pin in ceph.sh when + # configuring ceph on a remote node via ansible. + export CEPH_RELEASE=nautilus GetOSVersion prepare_ceph GLANCE_API_CONF=${GLANCE_API_CONF:-/etc/glance/glance-api.conf} diff --git a/nova/tests/unit/compute/test_resource_tracker.py b/nova/tests/unit/compute/test_resource_tracker.py index 73a189dc21..9e9534b9cd 100644 --- a/nova/tests/unit/compute/test_resource_tracker.py +++ b/nova/tests/unit/compute/test_resource_tracker.py @@ -568,6 +568,7 @@ class TestUpdateAvailableResources(BaseTestCase): actual_resources = update_mock.call_args[0][1] self.assertTrue(obj_base.obj_equal_prims(expected_resources, actual_resources)) + update_mock.assert_called_once() @mock.patch('nova.objects.InstancePCIRequests.get_by_instance', return_value=objects.InstancePCIRequests(requests=[])) @@ -608,6 +609,7 @@ class TestUpdateAvailableResources(BaseTestCase): actual_resources = update_mock.call_args[0][1] self.assertTrue(obj_base.obj_equal_prims(expected_resources, actual_resources)) + update_mock.assert_called_once() @mock.patch('nova.objects.InstancePCIRequests.get_by_instance', return_value=objects.InstancePCIRequests(requests=[])) @@ -655,6 +657,7 @@ class TestUpdateAvailableResources(BaseTestCase): actual_resources = update_mock.call_args[0][1] self.assertTrue(obj_base.obj_equal_prims(expected_resources, actual_resources)) + update_mock.assert_called_once() @mock.patch('nova.objects.InstancePCIRequests.get_by_instance', return_value=objects.InstancePCIRequests(requests=[])) @@ -718,6 +721,7 @@ class TestUpdateAvailableResources(BaseTestCase): actual_resources = update_mock.call_args[0][1] self.assertTrue(obj_base.obj_equal_prims(expected_resources, actual_resources)) + update_mock.assert_called_once() @mock.patch('nova.objects.InstancePCIRequests.get_by_instance', return_value=objects.InstancePCIRequests(requests=[])) @@ -780,6 +784,7 @@ class TestUpdateAvailableResources(BaseTestCase): actual_resources = update_mock.call_args[0][1] self.assertTrue(obj_base.obj_equal_prims(expected_resources, actual_resources)) + update_mock.assert_called_once() @mock.patch('nova.objects.InstancePCIRequests.get_by_instance', return_value=objects.InstancePCIRequests(requests=[])) @@ -839,6 +844,7 @@ class TestUpdateAvailableResources(BaseTestCase): actual_resources = update_mock.call_args[0][1] self.assertTrue(obj_base.obj_equal_prims(expected_resources, actual_resources)) + update_mock.assert_called_once() @mock.patch('nova.objects.InstancePCIRequests.get_by_instance', return_value=objects.InstancePCIRequests(requests=[])) @@ -894,6 +900,7 @@ class TestUpdateAvailableResources(BaseTestCase): actual_resources = update_mock.call_args[0][1] self.assertTrue(obj_base.obj_equal_prims(expected_resources, actual_resources)) + update_mock.assert_called_once() @mock.patch('nova.objects.InstancePCIRequests.get_by_instance', return_value=objects.InstancePCIRequests(requests=[])) @@ -962,6 +969,7 @@ class TestUpdateAvailableResources(BaseTestCase): actual_resources = update_mock.call_args[0][1] self.assertTrue(obj_base.obj_equal_prims(expected_resources, actual_resources)) + update_mock.assert_called_once() class TestInitComputeNode(BaseTestCase): @@ -987,7 +995,7 @@ class TestInitComputeNode(BaseTestCase): self.assertFalse(get_mock.called) self.assertFalse(create_mock.called) self.assertTrue(pci_mock.called) - self.assertTrue(update_mock.called) + self.assertFalse(update_mock.called) @mock.patch('nova.objects.PciDeviceList.get_by_compute_node', return_value=objects.PciDeviceList()) @@ -1011,7 +1019,7 @@ class TestInitComputeNode(BaseTestCase): get_mock.assert_called_once_with(mock.sentinel.ctx, _HOSTNAME, _NODENAME) self.assertFalse(create_mock.called) - self.assertTrue(update_mock.called) + self.assertFalse(update_mock.called) @mock.patch('nova.objects.ComputeNodeList.get_by_hypervisor') @mock.patch('nova.objects.PciDeviceList.get_by_compute_node', @@ -1165,7 +1173,7 @@ class TestInitComputeNode(BaseTestCase): create_mock.assert_called_once_with() self.assertTrue(obj_base.obj_equal_prims(expected_compute, cn)) setup_pci.assert_called_once_with(mock.sentinel.ctx, cn, resources) - self.assertTrue(update_mock.called) + self.assertFalse(update_mock.called) @mock.patch('nova.compute.resource_tracker.ResourceTracker.' '_setup_pci_tracker') @@ -1195,11 +1203,8 @@ class TestInitComputeNode(BaseTestCase): _cn.uuid = uuids.cn_uuid return original_copy_resources(_cn, _resources) - with test.nested( - mock.patch.object(self.rt, '_copy_resources', - fake_copy_resources), - mock.patch.object(self.rt, '_update') - ) as (mock_copy_resources, mock_update): + with mock.patch.object(self.rt, '_copy_resources', + fake_copy_resources): self.rt._init_compute_node(ctxt, resources) self.assertIn(_NODENAME, self.rt.compute_nodes) mock_get.assert_has_calls([mock.call( @@ -1207,8 +1212,6 @@ class TestInitComputeNode(BaseTestCase): self.assertEqual(2, mock_create.call_count) mock_setup_pci.assert_called_once_with( ctxt, test.MatchType(objects.ComputeNode), resources) - mock_update.assert_called_once_with( - ctxt, self.rt.compute_nodes[_NODENAME]) @mock.patch('nova.objects.ComputeNodeList.get_by_hypervisor') @mock.patch('nova.objects.ComputeNode.create') @@ -1236,25 +1239,26 @@ class TestUpdateComputeNode(BaseTestCase): self._setup_rt() # This is the same set of resources as the fixture, deliberately. We - # are checking below to see that update_compute_node() is not - # needlessly called when the resources don't actually change. + # are checking below to see that compute_node.save is not needlessly + # called when the resources don't actually change. orig_compute = _COMPUTE_NODE_FIXTURES[0].obj_clone() self.rt.compute_nodes[_NODENAME] = orig_compute self.rt.old_resources[_NODENAME] = orig_compute new_compute = orig_compute.obj_clone() - # Here, we check that if we call _update() with the same resources that - # are already stored in the resource tracker, that the scheduler client - # won't be called again to update those (unchanged) resources for the - # compute node - ucn_mock = self.sched_client_mock.update_compute_node self.rt._update(mock.sentinel.ctx, new_compute) - self.assertFalse(ucn_mock.called) self.assertFalse(save_mock.called) + # Even the compute node is not updated, get_inventory still got called. + # And update_compute_node() is also called when get_inventory() is not + # implemented. + self.driver_mock.get_inventory.assert_called_once_with(_NODENAME) + ucn_mock = self.sched_client_mock.update_compute_node + ucn_mock.assert_called_once_with(new_compute) @mock.patch('nova.objects.ComputeNode.save') def test_existing_compute_node_updated_diff_updated_at(self, save_mock): + # if only updated_at is changed, it won't call compute_node.save() self._setup_rt() ts1 = timeutils.utcnow() ts2 = ts1 + datetime.timedelta(seconds=10) @@ -1269,13 +1273,14 @@ class TestUpdateComputeNode(BaseTestCase): new_compute = orig_compute.obj_clone() new_compute.updated_at = ts2 - ucn_mock = self.sched_client_mock.update_compute_node self.rt._update(mock.sentinel.ctx, new_compute) self.assertFalse(save_mock.called) - self.assertFalse(ucn_mock.called) + @mock.patch('nova.compute.resource_tracker.' + '_normalize_inventory_from_cn_obj') @mock.patch('nova.objects.ComputeNode.save') - def test_existing_compute_node_updated_new_resources(self, save_mock): + def test_existing_compute_node_updated_new_resources(self, save_mock, + norm_mock): self._setup_rt() orig_compute = _COMPUTE_NODE_FIXTURES[0].obj_clone() @@ -1291,9 +1296,12 @@ class TestUpdateComputeNode(BaseTestCase): new_compute.vcpus_used = 2 new_compute.local_gb_used = 4 - ucn_mock = self.sched_client_mock.update_compute_node self.rt._update(mock.sentinel.ctx, new_compute) save_mock.assert_called_once_with() + # The get_inventory() is not implemented, it shouldn't call + # _normalize_inventory_from_cn_obj but call update_compute_node(). + self.assertFalse(norm_mock.called) + ucn_mock = self.sched_client_mock.update_compute_node ucn_mock.assert_called_once_with(new_compute) @mock.patch('nova.compute.resource_tracker.' diff --git a/nova/virt/libvirt/host.py b/nova/virt/libvirt/host.py index 10a7dabfa4..3a885d33cd 100644 --- a/nova/virt/libvirt/host.py +++ b/nova/virt/libvirt/host.py @@ -457,7 +457,7 @@ class Host(object): rpc.get_notifier('compute').error(nova_context.get_admin_context(), 'compute.libvirt.error', payload) - raise exception.HypervisorUnavailable(host=CONF.host) + raise exception.HypervisorUnavailable() return conn diff --git a/nova/virt/libvirt/volume/mount.py b/nova/virt/libvirt/volume/mount.py index 476e914932..86ace4d5c6 100644 --- a/nova/virt/libvirt/volume/mount.py +++ b/nova/virt/libvirt/volume/mount.py @@ -84,7 +84,7 @@ class _HostMountStateManager(object): with self.cond: state = self.state if state is None: - raise exception.HypervisorUnavailable(host=CONF.host) + raise exception.HypervisorUnavailable() self.use_count += 1 try: diff --git a/placement-api-ref/source/get-root.json b/placement-api-ref/source/get-root.json index bdb92c3dec..2e4c862445 100644 --- a/placement-api-ref/source/get-root.json +++ b/placement-api-ref/source/get-root.json @@ -3,7 +3,14 @@ { "min_version" : "1.0", "id" : "v1.0", - "max_version" : "1.2" + "max_version" : "1.10", + "status": "CURRENT", + "links": [ + { + "href": "", + "rel": "self" + } + ] } ] } diff --git a/placement-api-ref/source/parameters.yaml b/placement-api-ref/source/parameters.yaml index 08fdf96ca3..1b7581cf4c 100644 --- a/placement-api-ref/source/parameters.yaml +++ b/placement-api-ref/source/parameters.yaml @@ -261,6 +261,12 @@ version_id: required: true description: > A common name for the version being described. Informative only. +version_links: + type: array + in: body + required: true + description: > + A list of links related to and describing this version. version_max: type: string in: body @@ -273,6 +279,13 @@ version_min: required: true description: > The minimum microversion that is supported. +version_status: + type: string + in: body + required: true + description: > + The status of the version being described. With placement this is + "CURRENT". versions: type: array in: body diff --git a/placement-api-ref/source/root.inc b/placement-api-ref/source/root.inc index edf9e63479..ab121a6aa5 100644 --- a/placement-api-ref/source/root.inc +++ b/placement-api-ref/source/root.inc @@ -24,6 +24,8 @@ Response - id: version_id - min_version: version_min - max_version: version_max + - status: version_status + - links: version_links Response Example ---------------- diff --git a/test-requirements.txt b/test-requirements.txt index b2444f6da0..27822d3fef 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -22,7 +22,7 @@ osprofiler>=1.4.0 # Apache-2.0 testresources>=0.2.4 # Apache-2.0/BSD testscenarios>=0.4 # Apache-2.0/BSD testtools>=1.4.0 # MIT -bandit>=1.1.0 # Apache-2.0 +bandit>=1.1.0,<=1.6.2 # Apache-2.0 openstackdocstheme>=1.16.0 # Apache-2.0 gabbi>=1.35.0 # Apache-2.0 diff --git a/tools/check-cherry-picks.sh b/tools/check-cherry-picks.sh index 32627e59b6..5a449c520b 100755 --- a/tools/check-cherry-picks.sh +++ b/tools/check-cherry-picks.sh @@ -32,7 +32,7 @@ if [ $checked -eq 0 ]; then echo "Checked $checked cherry-pick hashes: OK" exit 0 else - if ! git show --format='%B' --quiet | grep -qi 'stable.*only'; then + if ! git show --format='%B' --quiet $commit_hash | grep -qi 'stable.*only'; then echo 'Stable branch requires either cherry-pick -x headers or [stable-only] tag!' exit 1 fi |