Skip to content

Commit 7446155

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Add functional test for AggregateMultiTenancyIsolation + migrate"
2 parents c43ec6b + a638685 commit 7446155

File tree

1 file changed

+120
-0
lines changed

1 file changed

+120
-0
lines changed

nova/tests/functional/test_aggregates.py

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,3 +551,123 @@ def spy_get_filtered_hosts(*args, **kwargs):
551551
server = user_api.post_server(server_req)
552552
self._wait_for_state_change(user_api, server, 'ACTIVE')
553553
self.assertEqual(2, len(self.filtered_hosts))
554+
555+
556+
class AggregateMultiTenancyIsolationColdMigrateTest(
557+
test.TestCase, integrated_helpers.InstanceHelperMixin):
558+
559+
@staticmethod
560+
def _create_aggregate(admin_api, name):
561+
return admin_api.api_post(
562+
'/os-aggregates', {'aggregate': {'name': name}}).body['aggregate']
563+
564+
@staticmethod
565+
def _add_host_to_aggregate(admin_api, aggregate, host):
566+
add_host_req_body = {
567+
"add_host": {
568+
"host": host
569+
}
570+
}
571+
admin_api.api_post(
572+
'/os-aggregates/%s/action' % aggregate['id'], add_host_req_body)
573+
574+
@staticmethod
575+
def _isolate_aggregate(admin_api, aggregate, tenant_id):
576+
set_meta_req_body = {
577+
"set_metadata": {
578+
"metadata": {
579+
"filter_tenant_id": tenant_id
580+
}
581+
}
582+
}
583+
admin_api.api_post(
584+
'/os-aggregates/%s/action' % aggregate['id'], set_meta_req_body)
585+
586+
def setUp(self):
587+
super(AggregateMultiTenancyIsolationColdMigrateTest, self).setUp()
588+
self.useFixture(policy_fixture.RealPolicyFixture())
589+
self.useFixture(nova_fixtures.NeutronFixture(self))
590+
self.useFixture(func_fixtures.PlacementFixture())
591+
# Intentionally keep these separate since we want to create the
592+
# server with the non-admin user in a different project.
593+
admin_api_fixture = self.useFixture(nova_fixtures.OSAPIFixture(
594+
api_version='v2.1', project_id=uuids.admin_project))
595+
self.admin_api = admin_api_fixture.admin_api
596+
self.admin_api.microversion = 'latest'
597+
user_api_fixture = self.useFixture(nova_fixtures.OSAPIFixture(
598+
api_version='v2.1', project_id=uuids.user_project))
599+
self.api = user_api_fixture.api
600+
self.api.microversion = 'latest'
601+
602+
# the image fake backend needed for image discovery
603+
nova.tests.unit.image.fake.stub_out_image_service(self)
604+
self.addCleanup(nova.tests.unit.image.fake.FakeImageService_reset)
605+
606+
self.start_service('conductor')
607+
# Enable the AggregateMultiTenancyIsolation filter before starting the
608+
# scheduler service.
609+
enabled_filters = CONF.filter_scheduler.enabled_filters
610+
if 'AggregateMultiTenancyIsolation' not in enabled_filters:
611+
enabled_filters.append('AggregateMultiTenancyIsolation')
612+
self.flags(
613+
enabled_filters=enabled_filters, group='filter_scheduler')
614+
# Add a custom weigher which will weigh host1, which will be in the
615+
# admin project aggregate, higher than the other hosts which are in
616+
# the non-admin project aggregate.
617+
self.flags(weight_classes=[__name__ + '.HostNameWeigher'],
618+
group='filter_scheduler')
619+
self.start_service('scheduler')
620+
621+
for host in ('host1', 'host2', 'host3'):
622+
self.start_service('compute', host=host)
623+
624+
# Create an admin-only aggregate for the admin project. This is needed
625+
# because if host1 is not in an aggregate with the filter_tenant_id
626+
# metadata key, the filter will accept that host even for the non-admin
627+
# project.
628+
admin_aggregate = self._create_aggregate(
629+
self.admin_api, 'admin-aggregate')
630+
self._add_host_to_aggregate(self.admin_api, admin_aggregate, 'host1')
631+
632+
# Restrict the admin project to the admin aggregate.
633+
self._isolate_aggregate(
634+
self.admin_api, admin_aggregate, uuids.admin_project)
635+
636+
# Create the tenant aggregate for the non-admin project.
637+
tenant_aggregate = self._create_aggregate(
638+
self.admin_api, 'tenant-aggregate')
639+
640+
# Add two compute hosts to the tenant aggregate. We exclude host1
641+
# since that is weighed higher in HostNameWeigher and we want to
642+
# ensure the scheduler properly filters out host1 before we even get
643+
# to weighing the selected hosts.
644+
for host in ('host2', 'host3'):
645+
self._add_host_to_aggregate(self.admin_api, tenant_aggregate, host)
646+
647+
# Restrict the non-admin project to the tenant aggregate.
648+
self._isolate_aggregate(
649+
self.admin_api, tenant_aggregate, uuids.user_project)
650+
651+
def test_cold_migrate_server(self):
652+
"""Creates a server using the non-admin project, then cold migrates
653+
the server and asserts the server goes to the other host in the
654+
isolated host aggregate via the AggregateMultiTenancyIsolation filter.
655+
"""
656+
img = nova.tests.unit.image.fake.AUTO_DISK_CONFIG_ENABLED_IMAGE_UUID
657+
server_req_body = self._build_minimal_create_server_request(
658+
self.api, 'test_cold_migrate_server', image_uuid=img,
659+
networks='none')
660+
server = self.api.post_server({'server': server_req_body})
661+
server = self._wait_for_state_change(self.admin_api, server, 'ACTIVE')
662+
# Ensure the server ended up in host2 or host3
663+
original_host = server['OS-EXT-SRV-ATTR:host']
664+
self.assertNotEqual('host1', original_host)
665+
# Now cold migrate the server and it should end up in the other host
666+
# in the same tenant-isolated aggregate.
667+
self.admin_api.api_post(
668+
'/servers/%s/action' % server['id'], {'migrate': None})
669+
server = self._wait_for_state_change(
670+
self.admin_api, server, 'VERIFY_RESIZE')
671+
# Ensure the server is on the other host in the same aggregate.
672+
expected_host = 'host3' if original_host == 'host2' else 'host2'
673+
self.assertEqual(expected_host, server['OS-EXT-SRV-ATTR:host'])

0 commit comments

Comments
 (0)