Fix application template update

Updating an application/service in a environment template
does not work and return 404 error.  This patchs solves that
bug.

Change-Id: I03f51c45512c4282ef99ddc1ed9ba55460827a94
Closes-Bug: #1587833
This commit is contained in:
visitor 2016-06-01 13:18:17 +02:00
parent 9c7187fb02
commit 6e35fb4b57
9 changed files with 242 additions and 7 deletions

View File

@ -414,6 +414,86 @@ Get applications information from an environment template
| 404 | The environment template does not exist |
+----------------+-----------------------------------------------------------+
Update applications information from an environment template
------------------------------------------------------------
*Request*
+----------+-----------------------------------------------+-----------------------------------+
| Method | URI | Description |
+==========+===============================================+===================================+
| PUT | /templates/{env-temp-id}/services/{service-id}| It updates the service description|
+----------+-----------------------------------------------+-----------------------------------+
*Parameters:*
* `env-temp-id` - The environment template ID, required
* `service-id` - The service ID to be updated
* payload - the service description
*Content-Type*
application/json
*Example*
::
{
"instance": {
"assignFloatingIp": "true",
"keyname": "mykeyname",
"image": "cloud-fedora-v3",
"flavor": "m1.medium",
"?": {
"type": "io.murano.resources.LinuxMuranoInstance",
"id": "ef984a74-29a4-45c0-b1dc-2ab9f075732e"
}
},
"name": "orion",
"port": "8080",
"?": {
"type": "io.murano.apps.apache.Tomcat",
"id": "54cea43d-5970-4c73-b9ac-fea656f3c722"
}
}
*Response*
::
{
"instance":
{
"assignFloatingIp": "true",
"keyname": "mykeyname",
"image": "cloud-fedora-v3",
"flavor": "m1.medium",
"?":
{
"type": "io.murano.resources.LinuxMuranoInstance",
"id": "ef984a74-29a4-45c0-b1dc-2ab9f075732e"
}
},
"name": "orion",
"?":
{
"type": "io.murano.apps.apache.Tomcat",
"id": "54cea43d-5970-4c73-b9ac-fea656f3c722"
},
"port": "8080"
}
+----------------+-----------------------------------------------------------+
| Code | Description |
+================+===========================================================+
| 200 | OK. Environment Template updated successfully |
+----------------+-----------------------------------------------------------+
| 401 | User is not authorized to access this session |
+----------------+-----------------------------------------------------------+
| 404 | The environment template does not exist |
+----------------+-----------------------------------------------------------+
Create an environment from an environment template
--------------------------------------------------

View File

@ -139,6 +139,10 @@ class API(wsgi.Router):
controller=applications_resource,
action='post',
conditions={'method': ['POST']}, path='')
mapper.connect('/templates/{env_template_id}/services/{path:.*?}',
controller=applications_resource,
action='put',
conditions={'method': ['PUT']}, path='')
mapper.connect('/templates/{env_template_id}/services/{path:.*?}',
controller=applications_resource,
action='delete',

View File

@ -21,6 +21,7 @@ from webob import exc
from murano.api.v1 import request_statistics
from murano.common.helpers import token_sanitizer
from murano.common.i18n import _
from murano.common import policy
from murano.common import wsgi
from murano.db.services import core_services
from murano import utils
@ -144,16 +145,16 @@ class Controller(object):
:param body: the information about the service
:return: the service description updated.
"""
policy.check('update_service_env_template', request.context)
LOG.debug('Applications:Put <EnvTempId: {templ_id}, Path: {path}, '
'Body: {body}>'.format(templ_id=env_template_id,
body=body,
path=path))
put_data = core_services.CoreServices.put_data
session_id = request.context.session
put_data = core_services.CoreServices.put_application_data
try:
result = put_data(env_template_id, session_id, body, path)
result = put_data(env_template_id, body, path)
except (KeyError, ValueError):
msg = _('The template does not exist {templ_id}').format(
templ_id=env_template_id)

View File

@ -91,7 +91,10 @@ class TraverseHelper(object):
parent_path = '/'.join(path.split('/')[:-1])
node = TraverseHelper.get(parent_path, source)
key = path[1:].split('/')[-1]
node[key] = value
if is_number(key):
node[int(key)] = value
else:
node[key] = value
@staticmethod
def insert(path, value, source):
@ -139,6 +142,70 @@ class TraverseHelper(object):
raise ValueError(_('Source object or path is malformed'))
def is_number(var):
try:
int(var)
return True
except Exception:
return False
def is_different(obj1, obj2):
"""Stripped-down version of deep.diff comparator
Compares arbitrary nested objects, handles circular links, but doesn't
point to the first difference as deep.diff does.
"""
class Difference(Exception):
pass
def is_in(o, st):
for _o in st:
if o is _o:
return True
return False
def rec(o1, o2, stack1=(), stack2=()):
if is_in(o1, stack1) and is_in(o2, stack2):
# circular reference detected - break the loop
return
elif is_in(o1, stack1):
raise Difference()
else:
stack1 += (o1,)
stack2 += (o2,)
if o1 is o2:
return
elif (isinstance(o1, six.string_types) and
isinstance(o2, six.string_types)) and o1 == o2:
return
elif type(o1) != type(o2):
raise Difference()
elif isinstance(o1, dict):
# check for keys inequality
rec(o1.keys(), o2.keys(), stack1, stack2)
for key in o1.keys():
rec(o1[key], o2[key], stack1, stack2)
elif isinstance(o1, (list, tuple, set)):
if len(o1) != len(o2):
raise Difference()
else:
for _o1, _o2 in zip(o1, o2):
rec(_o1, _o2, stack1, stack2)
elif hasattr(o1, '__dict__'):
return rec(o1.__dict__, o2.__dict__, stack1, stack2)
elif o1 != o2:
raise Difference()
try:
rec(obj1, obj2)
except Difference:
return True
else:
return False
def build_entity_map(value):
def build_entity_map_recursive(value, id_map):
if isinstance(value, dict):

View File

@ -229,3 +229,36 @@ class CoreServices(object):
utils.TraverseHelper.remove(path, tmp_description)
save_description(tmp_description, env_template_id)
return tmp_description
@staticmethod
def put_application_data(env_template_id, data, path):
"""It stores the application data inside the template description.
:param env_template_id: The env_template_id to obtain the data
:param data: the template description
:param path: Id of service for which we checking status.
:return: The template description
"""
get_description = env_temp.EnvTemplateServices.get_description
save_description = env_temp.EnvTemplateServices.save_description
temp_description = get_description(env_template_id)
if temp_description is None:
msg = _('Environment Template <EnvId {0}> is not found').format(
env_template_id)
LOG.error(msg)
raise exc.HTTPNotFound(explanation=msg)
count = 0
id = path[1:].split('/')[-1]
for service in temp_description["services"]:
if service["?"]["id"]:
if service["?"]["id"] == id:
break
count+1
utils.TraverseHelper.update("services/{0}".format(count),
data, temp_description)
temp_description['updated'] = str(timeutils.utcnow())
save_description(temp_description, env_template_id)
return data

View File

@ -668,13 +668,35 @@ class TestEnvTemplateApi(tb.ControllerTest, tb.MuranoApiTestCase):
self.assertEqual(self.uuids[4], body_returned['session_id'])
self.assertEqual(self.uuids[3], body_returned['environment_id'])
def test_update_service_in_template(self):
"""Test the service is updated in the environment template"""
self.fixture = self.useFixture(config_fixture.Config())
self.fixture.conf(args=[])
self._set_policy_rules(
{'create_env_template': '@',
'update_service_env_template': '@'}
)
updated_env = "UPDATED_ENV"
env_template = self._create_env_template_services()
self.expect_policy_check('update_service_env_template')
env_template["name"] = updated_env
req = self._put('/templates/{0}/services/{1}'.
format(self.uuids[0], "service_id"),
jsonutils.dump_as_bytes(env_template))
result = req.get_response(self.api)
self.assertIsNotNone(result)
self.assertEqual(200, result.status_code)
body_returned = jsonutils.loads(result.body)
self.assertEqual(updated_env, body_returned['name'])
def test_mallformed_env_body(self):
"""Check that an illegal temp name results in an HTTPClientError."""
self._set_policy_rules(
{'create_env_template': '@',
'create_environment': '@'}
)
self. _create_env_template_no_service()
self._create_env_template_no_service()
self.expect_policy_check('create_environment',
{'env_template_id': self.uuids[0]})
@ -770,11 +792,12 @@ class TestEnvTemplateApi(tb.ControllerTest, tb.MuranoApiTestCase):
"port": "8080",
"?": {
"type": "io.murano.apps.apache.Tomcat",
"id": "54cea43d-5970-4c73-b9ac-fea656f3c722"
"id": "service_id"
}
}
]
}
req = self._post('/templates', jsonutils.dump_as_bytes(body))
req.get_response(self.api)
result = req.get_response(self.api)
return result.json

View File

@ -331,6 +331,14 @@ class ApplicationCatalogClient(rest_client.RestClient):
self.expected_success(200, resp.status)
return json.loads(body)
def update_service_from_env_template(self, env_template_id, service_id,
post_body):
uri = 'v1/templates/{0}/services/{1}'.format(env_template_id,
service_id)
resp, body = self.put(uri, json.dumps(post_body))
self.expected_success(200, resp.status)
return self._parse_resp(body)
def delete_service_from_env_template(self, env_template_name, service_id):
uri = 'v1/templates/{0}/services/{1}'.format(env_template_name,
service_id)

View File

@ -98,6 +98,22 @@ class TestEnvironmentTemplates(base.BaseApplicationCatalogTest):
get_services_list_in_env_template(self.env_template['id'])
self.assertNotIn(service, services)
@testtools.testcase.attr('smoke')
def test_update_service_in_env_templates(self):
env_template_services = self.application_catalog_client.\
get_services_list_in_env_template(self.env_template['id'])
self.assertIsInstance(env_template_services, list)
post_body = self._get_demo_app()
service = self.application_catalog_client.\
create_service_in_env_template(self.env_template['id'], post_body)
self.assertEqual(post_body['name'], service['name'])
post_body["name"] = "updated_name"
service = self.application_catalog_client.\
update_service_from_env_template(self.env_template['id'],
service["?"]["id"],
post_body)
self.assertEqual("updated_name", service['name'])
@testtools.testcase.attr('smoke')
def test_create_public_env_template(self):
name = utils.generate_name('create_public_env_template')

View File

@ -0,0 +1,3 @@
---
features:
- Add application template update endpoint