Fix cancel update for nova server with defined port
This particular patch fixes a behaviour of cancel update for
nova server with defined port, so there are no ports manageable
by nova. We have these issues while restoring ports after rollback:
1) We doesn't detach any ports from current server, because we
doesn't save them to resoruce data. (we store this data after
succesfull create of the server)
2) Detaching an interface from current server will fail, if the server
will be in building state, so we need to wait until server will be
in active or in error state.
Refresh ports list to solve problem (1).
Wait until nova moves to active/error state to solve (2).
A functional test to prove the fix was added. Note, that this test is
skipped for convergence engine tests until cancel update will work
properly in convergence mode (see bug 1533176).
Partial-Bug: #1570908
Change-Id: If6fd916068a425eea6dc795192f286cb5ffcb794
diff --git a/common/test.py b/common/test.py
index a7aec6c..b9bb036 100644
--- a/common/test.py
+++ b/common/test.py
@@ -411,6 +411,25 @@
self._wait_for_stack_status(**kwargs)
+ def cancel_update_stack(self, stack_identifier,
+ expected_status='ROLLBACK_COMPLETE'):
+
+ stack_name = stack_identifier.split('/')[0]
+
+ self.updated_time[stack_identifier] = self.client.stacks.get(
+ stack_identifier, resolve_outputs=False).updated_time
+
+ self.client.actions.cancel_update(stack_name)
+
+ kwargs = {'stack_identifier': stack_identifier,
+ 'status': expected_status}
+ if expected_status in ['ROLLBACK_COMPLETE']:
+ # To trigger rollback you would intentionally fail the stack
+ # Hence check for rollback failures
+ kwargs['failure_pattern'] = '^ROLLBACK_FAILED$'
+
+ self._wait_for_stack_status(**kwargs)
+
def preview_update_stack(self, stack_identifier, template,
environment=None, files=None, parameters=None,
tags=None, disable_rollback=True,
diff --git a/functional/test_cancel_update.py b/functional/test_cancel_update.py
new file mode 100644
index 0000000..c40aeb0
--- /dev/null
+++ b/functional/test_cancel_update.py
@@ -0,0 +1,63 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from heat_integrationtests.functional import functional_base
+
+
+class CancelUpdateTest(functional_base.FunctionalTestsBase):
+
+ template = '''
+heat_template_version: '2013-05-23'
+parameters:
+ InstanceType:
+ type: string
+ ImageId:
+ type: string
+ network:
+ type: string
+resources:
+ port:
+ type: OS::Neutron::Port
+ properties:
+ network: {get_param: network}
+ Server:
+ type: OS::Nova::Server
+ properties:
+ flavor_update_policy: REPLACE
+ image: {get_param: ImageId}
+ flavor: {get_param: InstanceType}
+ networks:
+ - port: {get_resource: port}
+'''
+
+ def setUp(self):
+ super(CancelUpdateTest, self).setUp()
+ if not self.conf.image_ref:
+ raise self.skipException("No image configured to test.")
+ if not self.conf.instance_type:
+ raise self.skipException("No flavor configured to test.")
+ if not self.conf.minimal_instance_type:
+ raise self.skipException("No minimal flavor configured to test.")
+
+ def test_cancel_update_server_with_port(self):
+ parameters = {'InstanceType': self.conf.minimal_instance_type,
+ 'ImageId': self.conf.image_ref,
+ 'network': self.conf.fixed_network_name}
+
+ stack_identifier = self.stack_create(template=self.template,
+ parameters=parameters)
+ parameters['InstanceType'] = 'm1.large'
+ self.update_stack(stack_identifier, self.template,
+ parameters=parameters,
+ expected_status='UPDATE_IN_PROGRESS')
+
+ self.cancel_update_stack(stack_identifier)