summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.openstack.org>2018-02-05 16:47:52 +0000
committerGerrit Code Review <review@openstack.org>2018-02-05 16:47:52 +0000
commit68877e995973e0a78d8ea501b4c19e64b720e7e8 (patch)
tree68291ea50d8e2163b16fd932b95b25b86bf91e97
parent5eb380d4c77986ad20c330fc9281514edeeb4f1a (diff)
parent9213ec2d32fa173ec9943c28fb6c3ba5c196015d (diff)
downloadpython-novaclient-68877e995973e0a78d8ea501b4c19e64b720e7e8.tar.gz
Merge "Implement hypervisor hostname exact pattern match"
-rw-r--r--novaclient/tests/unit/v2/fakes.py38
-rw-r--r--novaclient/tests/unit/v2/test_shell.py171
-rw-r--r--novaclient/v2/shell.py107
-rw-r--r--releasenotes/notes/strict_hostname_match-f37243f0520a09a2.yaml9
4 files changed, 289 insertions, 36 deletions
diff --git a/novaclient/tests/unit/v2/fakes.py b/novaclient/tests/unit/v2/fakes.py
index 4647d805..bd69bf9d 100644
--- a/novaclient/tests/unit/v2/fakes.py
+++ b/novaclient/tests/unit/v2/fakes.py
@@ -633,6 +633,12 @@ class FakeSessionClient(base_client.SessionClient):
def post_servers_uuid4_metadata(self, **kw):
return (204, {}, {'metadata': {'key1': 'val1'}})
+ def post_servers_uuid5_metadata(self, **kw):
+ return (204, {}, {'metadata': {'key1': 'val1'}})
+
+ def post_servers_uuid6_metadata(self, **kw):
+ return (204, {}, {'metadata': {'key1': 'val1'}})
+
def delete_servers_uuid1_metadata_key1(self, **kw):
return (200, {}, {'data': 'Fake diagnostics'})
@@ -645,6 +651,12 @@ class FakeSessionClient(base_client.SessionClient):
def delete_servers_uuid4_metadata_key1(self, **kw):
return (200, {}, {'data': 'Fake diagnostics'})
+ def delete_servers_uuid5_metadata_key1(self, **kw):
+ return (200, {}, {'data': 'Fake diagnostics'})
+
+ def delete_servers_uuid6_metadata_key1(self, **kw):
+ return (200, {}, {'data': 'Fake diagnostics'})
+
def get_servers_1234_os_security_groups(self, **kw):
return (200, {}, {
"security_groups": [{
@@ -1773,6 +1785,26 @@ class FakeSessionClient(base_client.SessionClient):
{'name': 'inst4', 'uuid': 'uuid4'}]}]
})
+ def get_os_hypervisors_hyper1_servers(self, **kw):
+ return (200, {}, {
+ 'hypervisors': [
+ {'id': 1234,
+ 'hypervisor_hostname': 'hyper1',
+ 'servers': [
+ {'name': 'inst1', 'uuid': 'uuid1'},
+ {'name': 'inst2', 'uuid': 'uuid2'}]}]
+ })
+
+ def get_os_hypervisors_hyper2_servers(self, **kw):
+ return (200, {}, {
+ 'hypervisors': [
+ {'id': 5678,
+ 'hypervisor_hostname': 'hyper2',
+ 'servers': [
+ {'name': 'inst3', 'uuid': 'uuid3'},
+ {'name': 'inst4', 'uuid': 'uuid4'}]}]
+ })
+
def get_os_hypervisors_hyper_no_servers_servers(self, **kw):
return (200, {}, {'hypervisors':
[{'id': 1234, 'hypervisor_hostname': 'hyper1'}]})
@@ -1986,6 +2018,12 @@ class FakeSessionClient(base_client.SessionClient):
def post_servers_uuid4_action(self, **kw):
return 202, {}, {}
+ def post_servers_uuid5_action(self, **kw):
+ return 202, {}, {}
+
+ def post_servers_uuid6_action(self, **kw):
+ return 202, {}, {}
+
def get_os_cells_child_cell(self, **kw):
cell = {'cell': {
'username': 'cell1_user',
diff --git a/novaclient/tests/unit/v2/test_shell.py b/novaclient/tests/unit/v2/test_shell.py
index 7a8169cb..2dc0f395 100644
--- a/novaclient/tests/unit/v2/test_shell.py
+++ b/novaclient/tests/unit/v2/test_shell.py
@@ -1921,16 +1921,40 @@ class ShellTest(utils.TestCase):
{'metadata': {'key1': 'val1', 'key2': 'val2'}},
pos=4)
+ def test_set_host_meta_strict(self):
+ self.run_command('host-meta hyper1 --strict set key1=val1 key2=val2')
+ self.assert_called('GET', '/os-hypervisors/hyper1/servers', pos=0)
+ self.assert_called('POST', '/servers/uuid1/metadata',
+ {'metadata': {'key1': 'val1', 'key2': 'val2'}},
+ pos=1)
+ self.assert_called('POST', '/servers/uuid2/metadata',
+ {'metadata': {'key1': 'val1', 'key2': 'val2'}},
+ pos=2)
+
+ def test_set_host_meta_no_match(self):
+ cmd = 'host-meta hyper --strict set key1=val1 key2=val2'
+ self.assertRaises(exceptions.NotFound, self.run_command, cmd)
+
def test_set_host_meta_with_no_servers(self):
self.run_command('host-meta hyper_no_servers set key1=val1 key2=val2')
self.assert_called('GET', '/os-hypervisors/hyper_no_servers/servers')
+ def test_set_host_meta_with_no_servers_strict(self):
+ cmd = 'host-meta hyper_no_servers --strict set key1=val1 key2=val2'
+ self.assertRaises(exceptions.NotFound, self.run_command, cmd)
+
def test_delete_host_meta(self):
self.run_command('host-meta hyper delete key1')
self.assert_called('GET', '/os-hypervisors/hyper/servers', pos=0)
self.assert_called('DELETE', '/servers/uuid1/metadata/key1', pos=1)
self.assert_called('DELETE', '/servers/uuid2/metadata/key1', pos=2)
+ def test_delete_host_meta_strict(self):
+ self.run_command('host-meta hyper1 --strict delete key1')
+ self.assert_called('GET', '/os-hypervisors/hyper1/servers', pos=0)
+ self.assert_called('DELETE', '/servers/uuid1/metadata/key1', pos=1)
+ self.assert_called('DELETE', '/servers/uuid2/metadata/key1', pos=2)
+
def test_usage_list(self):
cmd = 'usage-list --start 2000-01-20 --end 2005-02-01'
stdout, _stderr = self.run_command(cmd)
@@ -2306,6 +2330,19 @@ class ShellTest(utils.TestCase):
self.assert_called('POST', '/servers/uuid3/action', body, pos=3)
self.assert_called('POST', '/servers/uuid4/action', body, pos=4)
+ def test_host_evacuate_live_with_no_target_host_strict(self):
+ self.run_command('host-evacuate-live hyper1 --strict')
+ self.assert_called('GET', '/os-hypervisors/hyper1/servers', pos=0)
+ body = {'os-migrateLive': {'host': None,
+ 'block_migration': False,
+ 'disk_over_commit': False}}
+ self.assert_called('POST', '/servers/uuid1/action', body, pos=1)
+ self.assert_called('POST', '/servers/uuid2/action', body, pos=2)
+
+ def test_host_evacuate_live_no_match(self):
+ cmd = 'host-evacuate-live hyper --strict'
+ self.assertRaises(exceptions.NotFound, self.run_command, cmd)
+
def test_host_evacuate_live_2_25(self):
self.run_command('host-evacuate-live hyper', api_version='2.25')
self.assert_called('GET', '/os-hypervisors/hyper/servers', pos=0)
@@ -2315,6 +2352,14 @@ class ShellTest(utils.TestCase):
self.assert_called('POST', '/servers/uuid3/action', body, pos=3)
self.assert_called('POST', '/servers/uuid4/action', body, pos=4)
+ def test_host_evacuate_live_2_25_strict(self):
+ self.run_command('host-evacuate-live hyper1 --strict',
+ api_version='2.25')
+ self.assert_called('GET', '/os-hypervisors/hyper1/servers', pos=0)
+ body = {'os-migrateLive': {'host': None, 'block_migration': 'auto'}}
+ self.assert_called('POST', '/servers/uuid1/action', body, pos=1)
+ self.assert_called('POST', '/servers/uuid2/action', body, pos=2)
+
def test_host_evacuate_live_with_target_host(self):
self.run_command('host-evacuate-live hyper '
'--target-host hostname')
@@ -2327,6 +2372,16 @@ class ShellTest(utils.TestCase):
self.assert_called('POST', '/servers/uuid3/action', body, pos=3)
self.assert_called('POST', '/servers/uuid4/action', body, pos=4)
+ def test_host_evacuate_live_with_target_host_strict(self):
+ self.run_command('host-evacuate-live hyper1 '
+ '--target-host hostname --strict')
+ self.assert_called('GET', '/os-hypervisors/hyper1/servers', pos=0)
+ body = {'os-migrateLive': {'host': 'hostname',
+ 'block_migration': False,
+ 'disk_over_commit': False}}
+ self.assert_called('POST', '/servers/uuid1/action', body, pos=1)
+ self.assert_called('POST', '/servers/uuid2/action', body, pos=2)
+
def test_host_evacuate_live_2_30(self):
self.run_command('host-evacuate-live --force hyper '
'--target-host hostname',
@@ -2340,6 +2395,17 @@ class ShellTest(utils.TestCase):
self.assert_called('POST', '/servers/uuid3/action', body, pos=3)
self.assert_called('POST', '/servers/uuid4/action', body, pos=4)
+ def test_host_evacuate_live_2_30_strict(self):
+ self.run_command('host-evacuate-live --force hyper1 '
+ '--target-host hostname --strict',
+ api_version='2.30')
+ self.assert_called('GET', '/os-hypervisors/hyper1/servers', pos=0)
+ body = {'os-migrateLive': {'host': 'hostname',
+ 'block_migration': 'auto',
+ 'force': True}}
+ self.assert_called('POST', '/servers/uuid1/action', body, pos=1)
+ self.assert_called('POST', '/servers/uuid2/action', body, pos=2)
+
def test_host_evacuate_live_with_block_migration(self):
self.run_command('host-evacuate-live --block-migrate hyper')
self.assert_called('GET', '/os-hypervisors/hyper/servers', pos=0)
@@ -2351,6 +2417,15 @@ class ShellTest(utils.TestCase):
self.assert_called('POST', '/servers/uuid3/action', body, pos=3)
self.assert_called('POST', '/servers/uuid4/action', body, pos=4)
+ def test_host_evacuate_live_with_block_migration_strict(self):
+ self.run_command('host-evacuate-live --block-migrate hyper2 --strict')
+ self.assert_called('GET', '/os-hypervisors/hyper2/servers', pos=0)
+ body = {'os-migrateLive': {'host': None,
+ 'block_migration': True,
+ 'disk_over_commit': False}}
+ self.assert_called('POST', '/servers/uuid3/action', body, pos=1)
+ self.assert_called('POST', '/servers/uuid4/action', body, pos=2)
+
def test_host_evacuate_live_with_block_migration_2_25(self):
self.run_command('host-evacuate-live --block-migrate hyper',
api_version='2.25')
@@ -2361,6 +2436,14 @@ class ShellTest(utils.TestCase):
self.assert_called('POST', '/servers/uuid3/action', body, pos=3)
self.assert_called('POST', '/servers/uuid4/action', body, pos=4)
+ def test_host_evacuate_live_with_block_migration_2_25_strict(self):
+ self.run_command('host-evacuate-live --block-migrate hyper2 --strict',
+ api_version='2.25')
+ self.assert_called('GET', '/os-hypervisors/hyper2/servers', pos=0)
+ body = {'os-migrateLive': {'host': None, 'block_migration': True}}
+ self.assert_called('POST', '/servers/uuid3/action', body, pos=1)
+ self.assert_called('POST', '/servers/uuid4/action', body, pos=2)
+
def test_host_evacuate_live_with_disk_over_commit(self):
self.run_command('host-evacuate-live --disk-over-commit hyper')
self.assert_called('GET', '/os-hypervisors/hyper/servers', pos=0)
@@ -2372,11 +2455,26 @@ class ShellTest(utils.TestCase):
self.assert_called('POST', '/servers/uuid3/action', body, pos=3)
self.assert_called('POST', '/servers/uuid4/action', body, pos=4)
+ def test_host_evacuate_live_with_disk_over_commit_strict(self):
+ self.run_command('host-evacuate-live --disk-over-commit hyper2 '
+ '--strict')
+ self.assert_called('GET', '/os-hypervisors/hyper2/servers', pos=0)
+ body = {'os-migrateLive': {'host': None,
+ 'block_migration': False,
+ 'disk_over_commit': True}}
+ self.assert_called('POST', '/servers/uuid3/action', body, pos=1)
+ self.assert_called('POST', '/servers/uuid4/action', body, pos=2)
+
def test_host_evacuate_live_with_disk_over_commit_2_25(self):
self.assertRaises(SystemExit, self.run_command,
'host-evacuate-live --disk-over-commit hyper',
api_version='2.25')
+ def test_host_evacuate_live_with_disk_over_commit_2_25_strict(self):
+ self.assertRaises(SystemExit, self.run_command,
+ 'host-evacuate-live --disk-over-commit hyper2 '
+ '--strict', api_version='2.25')
+
def test_host_evacuate_list_with_max_servers(self):
self.run_command('host-evacuate-live --max-servers 1 hyper')
self.assert_called('GET', '/os-hypervisors/hyper/servers', pos=0)
@@ -2385,6 +2483,14 @@ class ShellTest(utils.TestCase):
'disk_over_commit': False}}
self.assert_called('POST', '/servers/uuid1/action', body, pos=1)
+ def test_host_evacuate_list_with_max_servers_strict(self):
+ self.run_command('host-evacuate-live --max-servers 1 hyper1 --strict')
+ self.assert_called('GET', '/os-hypervisors/hyper1/servers', pos=0)
+ body = {'os-migrateLive': {'host': None,
+ 'block_migration': False,
+ 'disk_over_commit': False}}
+ self.assert_called('POST', '/servers/uuid1/action', body, pos=1)
+
def test_reset_state(self):
self.run_command('reset-state sample-server')
self.assert_called('POST', '/servers/1234/action',
@@ -2512,6 +2618,15 @@ class ShellTest(utils.TestCase):
self.assert_called('POST', '/servers/uuid4/action',
{'evacuate': {'host': 'target_hyper'}}, pos=4)
+ def test_host_evacuate_v2_14_strict(self):
+ self.run_command('host-evacuate hyper1 --target target_hyper --strict',
+ api_version='2.14')
+ self.assert_called('GET', '/os-hypervisors/hyper1/servers', pos=0)
+ self.assert_called('POST', '/servers/uuid1/action',
+ {'evacuate': {'host': 'target_hyper'}}, pos=1)
+ self.assert_called('POST', '/servers/uuid2/action',
+ {'evacuate': {'host': 'target_hyper'}}, pos=2)
+
def test_host_evacuate(self):
self.run_command('host-evacuate hyper --target target_hyper')
self.assert_called('GET', '/os-hypervisors/hyper/servers', pos=0)
@@ -2528,6 +2643,20 @@ class ShellTest(utils.TestCase):
{'evacuate': {'host': 'target_hyper',
'onSharedStorage': False}}, pos=4)
+ def test_host_evacuate_strict(self):
+ self.run_command('host-evacuate hyper1 --target target_hyper --strict')
+ self.assert_called('GET', '/os-hypervisors/hyper1/servers', pos=0)
+ self.assert_called('POST', '/servers/uuid1/action',
+ {'evacuate': {'host': 'target_hyper',
+ 'onSharedStorage': False}}, pos=1)
+ self.assert_called('POST', '/servers/uuid2/action',
+ {'evacuate': {'host': 'target_hyper',
+ 'onSharedStorage': False}}, pos=2)
+
+ def test_host_evacuate_no_match(self):
+ cmd = 'host-evacuate hyper --target target_hyper --strict'
+ self.assertRaises(exceptions.NotFound, self.run_command, cmd)
+
def test_host_evacuate_v2_29(self):
self.run_command('host-evacuate hyper --target target_hyper --force',
api_version='2.29')
@@ -2545,6 +2674,17 @@ class ShellTest(utils.TestCase):
{'evacuate': {'host': 'target_hyper', 'force': True}
}, pos=4)
+ def test_host_evacuate_v2_29_strict(self):
+ self.run_command('host-evacuate hyper1 --target target_hyper'
+ ' --force --strict', api_version='2.29')
+ self.assert_called('GET', '/os-hypervisors/hyper1/servers', pos=0)
+ self.assert_called('POST', '/servers/uuid1/action',
+ {'evacuate': {'host': 'target_hyper', 'force': True}
+ }, pos=1)
+ self.assert_called('POST', '/servers/uuid2/action',
+ {'evacuate': {'host': 'target_hyper', 'force': True}
+ }, pos=2)
+
def test_host_evacuate_with_shared_storage(self):
self.run_command(
'host-evacuate --on-shared-storage hyper --target target_hyper')
@@ -2562,6 +2702,17 @@ class ShellTest(utils.TestCase):
{'evacuate': {'host': 'target_hyper',
'onSharedStorage': True}}, pos=4)
+ def test_host_evacuate_with_shared_storage_strict(self):
+ self.run_command('host-evacuate --on-shared-storage hyper1'
+ ' --target target_hyper --strict')
+ self.assert_called('GET', '/os-hypervisors/hyper1/servers', pos=0)
+ self.assert_called('POST', '/servers/uuid1/action',
+ {'evacuate': {'host': 'target_hyper',
+ 'onSharedStorage': True}}, pos=1)
+ self.assert_called('POST', '/servers/uuid2/action',
+ {'evacuate': {'host': 'target_hyper',
+ 'onSharedStorage': True}}, pos=2)
+
def test_host_evacuate_with_no_target_host(self):
self.run_command('host-evacuate --on-shared-storage hyper')
self.assert_called('GET', '/os-hypervisors/hyper/servers', pos=0)
@@ -2574,6 +2725,14 @@ class ShellTest(utils.TestCase):
self.assert_called('POST', '/servers/uuid4/action',
{'evacuate': {'onSharedStorage': True}}, pos=4)
+ def test_host_evacuate_with_no_target_host_strict(self):
+ self.run_command('host-evacuate --on-shared-storage hyper1 --strict')
+ self.assert_called('GET', '/os-hypervisors/hyper1/servers', pos=0)
+ self.assert_called('POST', '/servers/uuid1/action',
+ {'evacuate': {'onSharedStorage': True}}, pos=1)
+ self.assert_called('POST', '/servers/uuid2/action',
+ {'evacuate': {'onSharedStorage': True}}, pos=2)
+
def test_host_servers_migrate(self):
self.run_command('host-servers-migrate hyper')
self.assert_called('GET', '/os-hypervisors/hyper/servers', pos=0)
@@ -2586,6 +2745,18 @@ class ShellTest(utils.TestCase):
self.assert_called('POST',
'/servers/uuid4/action', {'migrate': None}, pos=4)
+ def test_host_servers_migrate_strict(self):
+ self.run_command('host-servers-migrate hyper1 --strict')
+ self.assert_called('GET', '/os-hypervisors/hyper1/servers', pos=0)
+ self.assert_called('POST',
+ '/servers/uuid1/action', {'migrate': None}, pos=1)
+ self.assert_called('POST',
+ '/servers/uuid2/action', {'migrate': None}, pos=2)
+
+ def test_host_servers_migrate_no_match(self):
+ cmd = 'host-servers-migrate hyper --strict'
+ self.assertRaises(exceptions.NotFound, self.run_command, cmd)
+
def test_hypervisor_list(self):
self.run_command('hypervisor-list')
self.assert_called('GET', '/os-hypervisors')
diff --git a/novaclient/v2/shell.py b/novaclient/v2/shell.py
index 2343c696..1f062946 100644
--- a/novaclient/v2/shell.py
+++ b/novaclient/v2/shell.py
@@ -4675,6 +4675,23 @@ def _server_evacuate(cs, server, args):
"error_message": error_message})
+def _hyper_servers(cs, host, strict):
+ hypervisors = cs.hypervisors.search(host, servers=True)
+ for hyper in hypervisors:
+ if strict and hyper.hypervisor_hostname != host:
+ continue
+ if hasattr(hyper, 'servers'):
+ for server in hyper.servers:
+ yield server
+ if strict:
+ break
+ else:
+ if strict:
+ msg = (_("No hypervisor matching '%s' could be found.") %
+ host)
+ raise exceptions.NotFound(404, msg)
+
+
@utils.arg('host', metavar='<host>',
help='The hypervisor hostname (or pattern) to search for. '
'WARNING: Use a fully qualified domain name if you only '
@@ -4700,18 +4717,22 @@ def _server_evacuate(cs, server, args):
default=False,
help=_('Force to not verify the scheduler if a host is provided.'),
start_version='2.29')
+@utils.arg(
+ '--strict',
+ dest='strict',
+ action='store_true',
+ default=False,
+ help=_('Evacuate host with exact hypervisor hostname match'))
def do_host_evacuate(cs, args):
"""Evacuate all instances from failed host."""
-
- hypervisors = cs.hypervisors.search(args.host, servers=True)
response = []
- for hyper in hypervisors:
- if hasattr(hyper, 'servers'):
- for server in hyper.servers:
- response.append(_server_evacuate(cs, server, args))
-
- utils.print_list(response,
- ["Server UUID", "Evacuate Accepted", "Error Message"])
+ for server in _hyper_servers(cs, args.host, args.strict):
+ response.append(_server_evacuate(cs, server, args))
+ utils.print_list(response, [
+ "Server UUID",
+ "Evacuate Accepted",
+ "Error Message",
+ ])
def _server_live_migrate(cs, server, args):
@@ -4781,22 +4802,29 @@ def _server_live_migrate(cs, server, args):
default=False,
help=_('Force to not verify the scheduler if a host is provided.'),
start_version='2.30')
+@utils.arg(
+ '--strict',
+ dest='strict',
+ action='store_true',
+ default=False,
+ help=_('live Evacuate host with exact hypervisor hostname match'))
def do_host_evacuate_live(cs, args):
"""Live migrate all instances of the specified host
to other available hosts.
"""
- hypervisors = cs.hypervisors.search(args.host, servers=True)
response = []
migrating = 0
- for hyper in hypervisors:
- for server in getattr(hyper, 'servers', []):
- response.append(_server_live_migrate(cs, server, args))
- migrating += 1
- if args.max_servers is not None and migrating >= args.max_servers:
- break
-
- utils.print_list(response, ["Server UUID", "Live Migration Accepted",
- "Error Message"])
+ for server in _hyper_servers(cs, args.host, args.strict):
+ response.append(_server_live_migrate(cs, server, args))
+ migrating = migrating + 1
+ if (args.max_servers is not None and
+ migrating >= args.max_servers):
+ break
+ utils.print_list(response, [
+ "Server UUID",
+ "Live Migration Accepted",
+ "Error Message",
+ ])
class HostServersMigrateResponse(base.Resource):
@@ -4821,20 +4849,24 @@ def _server_migrate(cs, server):
help='The hypervisor hostname (or pattern) to search for. '
'WARNING: Use a fully qualified domain name if you only '
'want to cold migrate from a specific host.')
+@utils.arg(
+ '--strict',
+ dest='strict',
+ action='store_true',
+ default=False,
+ help=_('Migrate host with exact hypervisor hostname match'))
def do_host_servers_migrate(cs, args):
"""Cold migrate all instances off the specified host to other available
hosts.
"""
-
- hypervisors = cs.hypervisors.search(args.host, servers=True)
response = []
- for hyper in hypervisors:
- if hasattr(hyper, 'servers'):
- for server in hyper.servers:
- response.append(_server_migrate(cs, server))
-
- utils.print_list(response,
- ["Server UUID", "Migration Accepted", "Error Message"])
+ for server in _hyper_servers(cs, args.host, args.strict):
+ response.append(_server_migrate(cs, server))
+ utils.print_list(response, [
+ "Server UUID",
+ "Migration Accepted",
+ "Error Message",
+ ])
@utils.arg(
@@ -4964,17 +4996,20 @@ def do_list_extensions(cs, _args):
action='append',
default=[],
help=_('Metadata to set or delete (only key is necessary on delete)'))
+@utils.arg(
+ '--strict',
+ dest='strict',
+ action='store_true',
+ default=False,
+ help=_('Set host-meta to the hypervisor with exact hostname match'))
def do_host_meta(cs, args):
"""Set or Delete metadata on all instances of a host."""
- hypervisors = cs.hypervisors.search(args.host, servers=True)
- for hyper in hypervisors:
+ for server in _hyper_servers(cs, args.host, args.strict):
metadata = _extract_metadata(args)
- if hasattr(hyper, 'servers'):
- for server in hyper.servers:
- if args.action == 'set':
- cs.servers.set_meta(server['uuid'], metadata)
- elif args.action == 'delete':
- cs.servers.delete_meta(server['uuid'], metadata.keys())
+ if args.action == 'set':
+ cs.servers.set_meta(server['uuid'], metadata)
+ elif args.action == 'delete':
+ cs.servers.delete_meta(server['uuid'], metadata.keys())
def _print_migrations(cs, migrations):
diff --git a/releasenotes/notes/strict_hostname_match-f37243f0520a09a2.yaml b/releasenotes/notes/strict_hostname_match-f37243f0520a09a2.yaml
new file mode 100644
index 00000000..04d77d4a
--- /dev/null
+++ b/releasenotes/notes/strict_hostname_match-f37243f0520a09a2.yaml
@@ -0,0 +1,9 @@
+---
+features:
+ - |
+ Provides "--strict" option for "nova host-servers-migrate", "nova host-evacuate",
+ "nova host-evacuate-live" and "nova host-meta" commands. When "--strict" option is
+ used, the action will be applied to a single compute with the exact hypervisor
+ hostname string match rather than to the computes with hostname substring match.
+ When the specified hostname does not exist in the system, "NotFound" error code
+ will be returned.