From d2df08ecd82da45b2cb0076978f9c3342aa1540e Mon Sep 17 00:00:00 2001 From: Monty Taylor Date: Fri, 10 Feb 2017 10:44:29 -0600 Subject: [PATCH] Add all_projects parameter to list and search servers It is possible to tell nova to return the servers for all of the projects rather than just for the currently scoped project. Expose that. Change-Id: I4308758ac1c37ee7c1e63e0f2f58699966eb8364 --- ...servers-all-projects-349e6dc665ba2e8d.yaml | 6 +++++ shade/openstackcloud.py | 20 ++++++++++++----- shade/tests/functional/test_compute.py | 22 +++++++++++++++++++ shade/tests/unit/test_shade.py | 14 ++++++++++++ 4 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 releasenotes/notes/list-servers-all-projects-349e6dc665ba2e8d.yaml diff --git a/releasenotes/notes/list-servers-all-projects-349e6dc665ba2e8d.yaml b/releasenotes/notes/list-servers-all-projects-349e6dc665ba2e8d.yaml new file mode 100644 index 000000000..c993d2d81 --- /dev/null +++ b/releasenotes/notes/list-servers-all-projects-349e6dc665ba2e8d.yaml @@ -0,0 +1,6 @@ +--- +features: + - Add 'all_projects' parameter to list_servers and + search_servers which will tell Nova to return servers for all projects + rather than just for the current project. This is only available to + cloud admins. diff --git a/shade/openstackcloud.py b/shade/openstackcloud.py index 168a912f3..19714c476 100644 --- a/shade/openstackcloud.py +++ b/shade/openstackcloud.py @@ -1574,8 +1574,11 @@ class OpenStackCloud(_normalize.Normalizer): ) return _utils._filter_list(groups, name_or_id, filters) - def search_servers(self, name_or_id=None, filters=None, detailed=False): - servers = self.list_servers(detailed=detailed) + def search_servers( + self, name_or_id=None, filters=None, detailed=False, + all_projects=False): + servers = self.list_servers( + detailed=detailed, all_projects=all_projects) return _utils._filter_list(servers, name_or_id, filters) def search_server_groups(self, name_or_id=None, filters=None): @@ -1829,7 +1832,7 @@ class OpenStackCloud(_normalize.Normalizer): _tasks.NovaSecurityGroupList(search_opts=filters)) return self._normalize_secgroups(groups) - def list_servers(self, detailed=False): + def list_servers(self, detailed=False, all_projects=False): """List all available servers. :returns: A list of server ``munch.Munch``. @@ -1847,19 +1850,24 @@ class OpenStackCloud(_normalize.Normalizer): if self._servers_lock.acquire(first_run): try: if not (first_run and self._servers is not None): - self._servers = self._list_servers(detailed=detailed) + self._servers = self._list_servers( + detailed=detailed, + all_projects=all_projects) self._servers_time = time.time() finally: self._servers_lock.release() return self._servers - def _list_servers(self, detailed=False): + def _list_servers(self, detailed=False, all_projects=False): with _utils.shade_exceptions( "Error fetching server list on {cloud}:{region}:".format( cloud=self.name, region=self.region_name)): + kwargs = {} + if all_projects: + kwargs['search_opts'] = {'all_tenants': True} servers = self._normalize_servers( - self.manager.submit_task(_tasks.ServerList())) + self.manager.submit_task(_tasks.ServerList(**kwargs))) if detailed: return [ diff --git a/shade/tests/functional/test_compute.py b/shade/tests/functional/test_compute.py index a06c23376..399b37eb4 100644 --- a/shade/tests/functional/test_compute.py +++ b/shade/tests/functional/test_compute.py @@ -68,6 +68,28 @@ class TestCompute(base.BaseFunctionalTestCase): self.demo_cloud.delete_server(self.server_name, wait=True)) self.assertIsNone(self.demo_cloud.get_server(self.server_name)) + def test_list_all_servers(self): + self.addCleanup(self._cleanup_servers_and_volumes, self.server_name) + server = self.demo_cloud.create_server( + name=self.server_name, + image=self.image, + flavor=self.flavor, + wait=True) + # We're going to get servers from other tests, but that's ok, as long + # as we get the server we created with the demo user. + found_server = False + for s in self.operator_cloud.list_servers(all_projects=True): + if s.name == server.name: + found_server = True + self.assertTrue(found_server) + + def test_list_all_servers_bad_permissions(self): + # Normal users are not allowed to pass all_projects=True + self.assertRaises( + exc.OpenStackCloudException, + self.demo_cloud.list_servers, + all_projects=True) + def test_create_server_image_flavor_dict(self): self.addCleanup(self._cleanup_servers_and_volumes, self.server_name) server = self.demo_cloud.create_server( diff --git a/shade/tests/unit/test_shade.py b/shade/tests/unit/test_shade.py index 69992731c..568a52907 100644 --- a/shade/tests/unit/test_shade.py +++ b/shade/tests/unit/test_shade.py @@ -585,6 +585,20 @@ class TestShade(base.TestCase): self.assertEqual('server1', r[0]['name']) self.assertEqual('server2', r[1]['name']) + @mock.patch.object(shade.OpenStackCloud, 'nova_client') + def test_list_servers_all_projects(self, mock_nova_client): + '''This test verifies that when list_servers is called with + `all_projects=True` that it passes `all_tenants=1` to novaclient.''' + mock_nova_client.servers.list.return_value = [ + fakes.FakeServer('server1', '', 'ACTIVE'), + fakes.FakeServer('server2', '', 'ACTIVE'), + ] + + self.cloud.list_servers(all_projects=True) + + mock_nova_client.servers.list.assert_called_with( + search_opts={'all_tenants': True}) + def test_iterate_timeout_bad_wait(self): with testtools.ExpectedException( exc.OpenStackCloudException,