@@ -28,23 +28,30 @@ class CrossAZAttachTestCase(test.TestCase,
28
28
def setUp (self ):
29
29
super (CrossAZAttachTestCase , self ).setUp ()
30
30
# Use the standard fixtures.
31
+ self .useFixture (nova_fixtures .CastAsCallFixture (self ))
31
32
self .useFixture (nova_fixtures .RealPolicyFixture ())
32
33
self .useFixture (nova_fixtures .CinderFixture (self , az = self .az ))
33
34
self .useFixture (nova_fixtures .GlanceFixture (self ))
34
35
self .useFixture (nova_fixtures .NeutronFixture (self ))
35
36
self .useFixture (func_fixtures .PlacementFixture ())
37
+ self .useFixture (nova_fixtures .HostNameWeigherFixture ())
38
+ self .notifier = self .useFixture (
39
+ nova_fixtures .NotificationFixture (self ))
36
40
# Start nova controller services.
37
41
self .api = self .useFixture (nova_fixtures .OSAPIFixture (
38
42
api_version = 'v2.1' )).admin_api
39
43
self .start_service ('conductor' )
40
44
self .start_service ('scheduler' )
41
- # Start one compute service and add it to the AZ. This allows us to
45
+ # Start two compute services and add them to the AZ. This allows us to
42
46
# get past the AvailabilityZoneFilter and build a server.
43
47
self .start_service ('compute' , host = 'host1' )
48
+ self .start_service ('compute' , host = 'host2' )
44
49
agg_id = self .api .post_aggregate ({'aggregate' : {
45
50
'name' : self .az , 'availability_zone' : self .az }})['id' ]
46
51
self .api .api_post ('/os-aggregates/%s/action' % agg_id ,
47
52
{'add_host' : {'host' : 'host1' }})
53
+ self .api .api_post ('/os-aggregates/%s/action' % agg_id ,
54
+ {'add_host' : {'host' : 'host2' }})
48
55
49
56
def test_cross_az_attach_false_boot_from_volume_no_az_specified (self ):
50
57
"""Tests the scenario where [cinder]/cross_az_attach=False and the
@@ -138,3 +145,41 @@ def test_cross_az_attach_false_no_volumes(self):
138
145
self .flags (cross_az_attach = False , group = 'cinder' )
139
146
server = self ._create_server (az = self .az )
140
147
self .assertEqual (self .az , server ['OS-EXT-AZ:availability_zone' ])
148
+
149
+ def test_cross_az_attach_false_migrate_continues_to_pin_an_az (self ):
150
+ self .flags (cross_az_attach = False , group = 'cinder' )
151
+ server = self ._build_server ()
152
+ server ['block_device_mapping_v2' ] = [{
153
+ 'source_type' : 'volume' ,
154
+ 'destination_type' : 'volume' ,
155
+ 'boot_index' : 0 ,
156
+ 'uuid' : nova_fixtures .CinderFixture .IMAGE_BACKED_VOL
157
+ }]
158
+ server = self .api .post_server ({'server' : server })
159
+ server = self ._wait_for_state_change (server , 'ACTIVE' )
160
+ # The instance is now pinned to a specific AZ.
161
+ self .assertEqual (self .az , server ['OS-EXT-AZ:availability_zone' ])
162
+ # Start a third compute service and add it to a different 'london' AZ.
163
+ self .start_service ('compute' , host = 'host3' )
164
+ agg_id = self .api .post_aggregate ({'aggregate' : {
165
+ 'name' : 'london' , 'availability_zone' : 'london' }})['id' ]
166
+ self .api .api_post ('/os-aggregates/%s/action' % agg_id ,
167
+ {'add_host' : {'host' : 'host3' }})
168
+
169
+ # we want 2.56 because of the host param in migrate action.
170
+ self .api .microversion = '2.56'
171
+
172
+ # We can migrate the instance to another host in the same AZ
173
+ server = self ._migrate_server (server , host = 'host2' )
174
+ # let's move it back to host1
175
+ server = self ._revert_resize (server )
176
+
177
+ # Now let's try to migrate to host3 which is a different AZ.
178
+ # It fails miserably.
179
+ ex = self .assertRaises (api_client .OpenStackApiException ,
180
+ self .api .post_server_action ,
181
+ server ['id' ], {'migrate' : {'host' : 'host3' }})
182
+ self .assertEqual (500 , ex .response .status_code )
183
+ # And yeah, that's due to the fact that the only tested host in not in
184
+ # the pinned AZ.
185
+ self .assertIn ('NoValidHost' , str (ex ))
0 commit comments