Fix stack inconsistency after app deletion
To expose IP addresses of Instance in MuranoPL we place new entry to outputs section in Heat template that reference corresponding OS::Nova::Server resource. During clean-up stage, if some application was deleted from environment, we remove corresponding OS::Nova::Server resource, but reference in outputs section stays. Stack with reference to resource that is not present in template is invalid - environment deployment fails. This change add code that removes references to OS::Nova::Server when corresponding Instance is deleted. Attention: this change fix issue that can break murano-ci gate Closes-bug: #1339630 Co-Authored-By: Stan Lagun <slagun@mirantis.com> Change-Id: I74d32034969dd7f554d74fac87f407388e52dd7e
This commit is contained in:
parent
f051ff9d77
commit
4da6c43dd2
|
@ -85,6 +85,15 @@ class Client(object):
|
|||
return requests.post(endpoint, data=json.dumps(json_data),
|
||||
headers=headers).json()
|
||||
|
||||
def delete_service(self, environment_id, session_id, service_id):
|
||||
headers = self.headers.copy()
|
||||
headers.update({'x-configuration-session': session_id})
|
||||
|
||||
endpoint = '{0}environments/{1}/services/{2}'.format(
|
||||
self.endpoint, environment_id, service_id)
|
||||
|
||||
requests.delete(endpoint, headers=headers)
|
||||
|
||||
def wait_for_environment_deploy(self, environment_id):
|
||||
environment = self.get_environment(environment_id)
|
||||
|
||||
|
@ -365,3 +374,63 @@ class MuranoBase(testtools.TestCase, testtools.testcase.WithAttributes,
|
|||
self.assertIsNotNone(env)
|
||||
|
||||
self.deployment_success_check(env, 8080)
|
||||
|
||||
def _get_telnet_app(self):
|
||||
return {
|
||||
"instance": {
|
||||
"?": {
|
||||
"type": "io.murano.resources.LinuxMuranoInstance",
|
||||
"id": str(uuid.uuid4())
|
||||
},
|
||||
"flavor": "m1.medium",
|
||||
"image": self.linux,
|
||||
"name": "instance{0}".format(uuid.uuid4().hex[:5]),
|
||||
},
|
||||
"name": "app{0}".format(uuid.uuid4().hex[:5]),
|
||||
"?": {
|
||||
"type": "io.murano.apps.linux.Telnet",
|
||||
"id": str(uuid.uuid4())
|
||||
}
|
||||
}
|
||||
|
||||
def _quick_deploy(self, name, *apps):
|
||||
environment = self.client.create_environment(name)
|
||||
session = self.client.create_session(environment['id'])
|
||||
environment_id, session_id = environment['id'], session['id']
|
||||
|
||||
for app in apps:
|
||||
self.client.create_service(environment_id, session_id, app)
|
||||
self.client.deploy_session(environment_id, session_id)
|
||||
return self.client.wait_for_environment_deploy(environment_id)
|
||||
|
||||
def _get_stack(self, name):
|
||||
by_name = {'name': name}
|
||||
stack_iter = self.heat_client.stacks.list(limit=1, filters=by_name)
|
||||
return next(stack_iter, None)
|
||||
|
||||
def test_instance_refs_are_removed_after_application_is_removed(self):
|
||||
name = 'e' + str(uuid.uuid4().hex)
|
||||
|
||||
# create environment with telnet application
|
||||
application1 = self._get_telnet_app()
|
||||
application2 = self._get_telnet_app()
|
||||
application_id = application1['?']['id']
|
||||
instance_name = application1['instance']['name']
|
||||
apps = [application1, application2]
|
||||
environment_id = self._quick_deploy(name, *apps)['id']
|
||||
# add environment to the list for tear-down clean-up
|
||||
self.environments.append(environment_id)
|
||||
|
||||
# delete telnet application
|
||||
session_id = self.client.create_session(environment_id)['id']
|
||||
self.client.delete_service(environment_id, session_id, application_id)
|
||||
self.client.deploy_session(environment_id, session_id)
|
||||
self.client.wait_for_environment_deploy(environment_id)
|
||||
|
||||
template = self.heat_client.stacks.template(name)
|
||||
ip_addresses = '{0}-assigned-ip'.format(instance_name)
|
||||
floating_ip = '{0}-FloatingIPaddress'.format(instance_name)
|
||||
|
||||
self.assertNotIn(ip_addresses, template['outputs'])
|
||||
self.assertNotIn(floating_ip, template['outputs'])
|
||||
self.assertNotIn(instance_name, template['resources'])
|
||||
|
|
|
@ -215,12 +215,26 @@ Methods:
|
|||
- $.setAttr(fipAssigned, true)
|
||||
|
||||
destroy:
|
||||
# Fixme(smelikyan): We need to remove all associated resources on destroy
|
||||
Body:
|
||||
- $template: $.environment.stack.current()
|
||||
# Remove OS::Nova::Server resource
|
||||
- $patchBlock:
|
||||
op: remove
|
||||
path: format('/resources/{0}', $.name)
|
||||
- $template: patch($template, $patchBlock)
|
||||
# Remove Ip Addresses Outputs assigned to this Instance
|
||||
- $assignedIpBlock:
|
||||
op: remove
|
||||
path: format('/outputs/{0}-assigned-ip', $.name)
|
||||
- $template: patch($template, $assignedIpBlock)
|
||||
# Remove Floatting IP Addresses Outputs
|
||||
- If: $.getAttr(fipAssigned, false)
|
||||
Then:
|
||||
- $assignedFloatingIpBlock:
|
||||
op: remove
|
||||
path: format('/outputs/{0}-FloatingIPaddress', $.name)
|
||||
- $template: patch($template, $assignedFloatingIpBlock)
|
||||
- $.environment.stack.setTemplate($template)
|
||||
- $.environment.stack.push()
|
||||
- $.environment.instanceNotifier.untrackCloudInstance($this)
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
Namespaces:
|
||||
=: io.murano.system
|
||||
|
||||
Name: Agent
|
||||
|
||||
Properties:
|
||||
host:
|
||||
Contract: $
|
|
@ -0,0 +1,22 @@
|
|||
Namespaces:
|
||||
=: io.murano
|
||||
res: io.murano.resources
|
||||
sys: io.murano.system
|
||||
|
||||
Name: Environment
|
||||
|
||||
Properties:
|
||||
stack:
|
||||
Contract: $.class(sys:HeatStack)
|
||||
|
||||
instance:
|
||||
Contract: $.class(res:Instance)
|
||||
|
||||
instanceNotifier:
|
||||
Contract: $.class(sys:InstanceNotifier)
|
||||
Usage: Runtime
|
||||
|
||||
Methods:
|
||||
initialize:
|
||||
Body:
|
||||
$.instanceNotifier: new(sys:InstanceNotifier)
|
|
@ -0,0 +1,18 @@
|
|||
Namespaces:
|
||||
=: io.murano.system
|
||||
|
||||
Name: HeatStack
|
||||
|
||||
Methods:
|
||||
push:
|
||||
|
||||
current:
|
||||
Body:
|
||||
- Return: $.getAttr(stack)
|
||||
|
||||
setTemplate:
|
||||
Arguments:
|
||||
- template:
|
||||
Contract: {}
|
||||
Body:
|
||||
- $.setAttr(stack, $template)
|
|
@ -0,0 +1,10 @@
|
|||
Namespaces:
|
||||
=: io.murano.system
|
||||
|
||||
Name: InstanceNotifier
|
||||
|
||||
Methods:
|
||||
untrackCloudInstance:
|
||||
Arguments:
|
||||
- instance:
|
||||
Contract: $
|
|
@ -0,0 +1,5 @@
|
|||
Namespaces:
|
||||
=: io.murano.system
|
||||
|
||||
Name: Resources
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
# Copyright (c) 2014 Mirantis, Inc.
|
||||
#
|
||||
# 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 murano.tests.dsl.foundation import object_model as om
|
||||
from murano.tests.dsl.foundation import test_case
|
||||
|
||||
|
||||
TEMPLATE = {
|
||||
"outputs": {
|
||||
"instance64464-assigned-ip": {
|
||||
"value": {"get_attr": ["instance64464", "addresses"]}
|
||||
},
|
||||
"instance64464-FloatingIPaddress": {
|
||||
"value": {"get_attr": ["instance64464", "addresses"]}
|
||||
}
|
||||
},
|
||||
"resources": {
|
||||
"instance64464": {
|
||||
"type": "OS::Nova::Server",
|
||||
"properties": {
|
||||
"key_name": None,
|
||||
"flavor": "m1.medium",
|
||||
"image": "cloud-fedora-v3",
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class TestDestroy(test_case.DslTestCase):
|
||||
def test_destroy_removes_ip_address_from_outputs(self):
|
||||
heat_stack_obj = om.Object('io.murano.system.HeatStack')
|
||||
instance_obj = om.Object(
|
||||
'io.murano.resources.Instance',
|
||||
name='instance64464',
|
||||
flavor='m1.medium',
|
||||
image='cloud-fedora-v3'
|
||||
)
|
||||
|
||||
runner = self.new_runner({
|
||||
'Objects': om.Object(
|
||||
'io.murano.Environment',
|
||||
stack=heat_stack_obj,
|
||||
instance=instance_obj
|
||||
),
|
||||
'Attributes': [
|
||||
om.Attribute(heat_stack_obj, 'stack', TEMPLATE),
|
||||
om.Attribute(instance_obj, 'fipAssigned', True)
|
||||
]
|
||||
})
|
||||
|
||||
empty_env = runner.serialized_model
|
||||
empty_env['Objects']['instance'] = None
|
||||
model = self.new_runner(empty_env).serialized_model
|
||||
template = self.find_attribute(
|
||||
model, heat_stack_obj.id, heat_stack_obj.type_name, 'stack'
|
||||
)
|
||||
|
||||
instance_name = 'instance64464'
|
||||
ip_addresses = '{0}-assigned-ip'.format(instance_name)
|
||||
floating_ip = '{0}-FloatingIPaddress'.format(instance_name)
|
||||
|
||||
self.assertNotIn(ip_addresses, template['outputs'])
|
||||
self.assertNotIn(floating_ip, template['outputs'])
|
||||
self.assertNotIn(instance_name, template['resources'])
|
Loading…
Reference in New Issue