diff --git a/openstackclient/compute/v2/server.py b/openstackclient/compute/v2/server.py index 414abb626a..84061a53c9 100644 --- a/openstackclient/compute/v2/server.py +++ b/openstackclient/compute/v2/server.py @@ -1242,7 +1242,8 @@ class ListServer(command.Lister): default=None, help=_('The last server of the previous page. Display ' 'list of servers after marker. Display all servers if not ' - 'specified. (name or ID)') + 'specified. When used with ``--deleted``, the marker must ' + 'be an ID, otherwise a name or ID can be used.'), ) parser.add_argument( '--limit', @@ -1450,9 +1451,17 @@ class ListServer(command.Lister): mixed_case_fields = [] marker_id = None + if parsed_args.marker: - marker_id = utils.find_resource(compute_client.servers, - parsed_args.marker).id + # Check if both "--marker" and "--deleted" are used. + # In that scenario a lookup is not needed as the marker + # needs to be an ID, because find_resource does not + # handle deleted resources + if parsed_args.deleted: + marker_id = parsed_args.marker + else: + marker_id = utils.find_resource(compute_client.servers, + parsed_args.marker).id data = compute_client.servers.list(search_opts=search_opts, marker=marker_id, diff --git a/openstackclient/tests/functional/compute/v2/test_server.py b/openstackclient/tests/functional/compute/v2/test_server.py index 2bca70d0ec..6e080e9ba2 100644 --- a/openstackclient/tests/functional/compute/v2/test_server.py +++ b/openstackclient/tests/functional/compute/v2/test_server.py @@ -63,6 +63,49 @@ class ServerTests(common.ComputeTestCase): self.assertNotIn(name1, col_name) self.assertIn(name2, col_name) + def test_server_list_with_marker_and_deleted(self): + """Test server list with deleted and marker""" + cmd_output = self.server_create(cleanup=False) + name1 = cmd_output['name'] + cmd_output = self.server_create(cleanup=False) + name2 = cmd_output['name'] + id2 = cmd_output['id'] + self.wait_for_status(name1, "ACTIVE") + self.wait_for_status(name2, "ACTIVE") + + # Test list --marker with ID + cmd_output = json.loads(self.openstack( + 'server list -f json --marker ' + id2 + )) + col_name = [x["Name"] for x in cmd_output] + self.assertIn(name1, col_name) + + # Test list --marker with Name + cmd_output = json.loads(self.openstack( + 'server list -f json --marker ' + name2 + )) + col_name = [x["Name"] for x in cmd_output] + self.assertIn(name1, col_name) + + self.openstack('server delete --wait ' + name1) + self.openstack('server delete --wait ' + name2) + + # Test list --deleted --marker with ID + cmd_output = json.loads(self.openstack( + 'server list -f json --deleted --marker ' + id2 + )) + col_name = [x["Name"] for x in cmd_output] + self.assertIn(name1, col_name) + + # Test list --deleted --marker with Name + try: + cmd_output = json.loads(self.openstack( + 'server list -f json --deleted --marker ' + name2 + )) + except exceptions.CommandFailed as e: + self.assertIn('marker [%s] not found (HTTP 400)' % (name2), + e.stderr.decode('utf-8')) + def test_server_list_with_changes_before(self): """Test server list. diff --git a/releasenotes/notes/bug-2006761-9041d1b25e845cfb.yaml b/releasenotes/notes/bug-2006761-9041d1b25e845cfb.yaml new file mode 100644 index 0000000000..e647cf2114 --- /dev/null +++ b/releasenotes/notes/bug-2006761-9041d1b25e845cfb.yaml @@ -0,0 +1,8 @@ +--- +fixes: + - | + Fixes the "No server with a name or ID of 'id' exists" error when running + ``server list --deleted --marker``. The fix removes using a name for + the marker when both ``--deleted`` and ``--marker`` are used. In + this scenario an ID must be supplied for the marker. + [Story `2006761 `_]