Add environment edit API
'/environments/<env_id>/model/<path>' endpoint added. GET request responds with the subsection of <env_id>'s object model located in its <path>. PATCH request applies json-patch from request body to <end_id>'s model. It does not contain <path> in the URL. Change-Id: I672d43464ed7d5722cc574f1a10700b070664f34 Implements: bp environment-edit
This commit is contained in:
parent
f258b577fb
commit
b3a06349c5
|
@ -12,6 +12,7 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import jsonpatch
|
||||
from oslo_db import exception as db_exc
|
||||
from oslo_log import log as logging
|
||||
import six
|
||||
|
@ -192,6 +193,62 @@ class Controller(object):
|
|||
result[service_id] = None
|
||||
return {'lastStatuses': result}
|
||||
|
||||
@request_statistics.stats_count(API_NAME, 'GetModel')
|
||||
@verify_env
|
||||
def get_model(self, request, environment_id, path):
|
||||
LOG.debug('Environments:GetModel <Id: %(env_id)s>, Path: %(path)s',
|
||||
{'env_id': environment_id, 'path': path})
|
||||
target = {"environment_id": environment_id}
|
||||
policy.check('show_environment', request.context, target)
|
||||
|
||||
session_id = None
|
||||
if hasattr(request, 'context') and request.context.session:
|
||||
session_id = request.context.session
|
||||
|
||||
get_description = envs.EnvironmentServices.get_environment_description
|
||||
env_model = get_description(environment_id, session_id)
|
||||
try:
|
||||
result = utils.TraverseHelper.get(path, env_model)
|
||||
except (KeyError, ValueError):
|
||||
raise exc.HTTPNotFound
|
||||
|
||||
return result
|
||||
|
||||
@request_statistics.stats_count(API_NAME, 'UpdateModel')
|
||||
@verify_env
|
||||
def update_model(self, request, environment_id, body=None):
|
||||
if not body:
|
||||
msg = _('Request body is empty: please, provide '
|
||||
'environment object model patch')
|
||||
LOG.error(msg)
|
||||
raise exc.HTTPBadRequest(msg)
|
||||
LOG.debug('Environments:UpdateModel <Id: %(env_id)s, Body: %(body)s>',
|
||||
{'env_id': environment_id, 'body': body})
|
||||
target = {"environment_id": environment_id}
|
||||
policy.check('update_environment', request.context, target)
|
||||
|
||||
session_id = None
|
||||
if hasattr(request, 'context') and request.context.session:
|
||||
session_id = request.context.session
|
||||
|
||||
get_description = envs.EnvironmentServices.get_environment_description
|
||||
env_model = get_description(environment_id, session_id)
|
||||
|
||||
for change in body:
|
||||
change['path'] = '/' + '/'.join(change['path'])
|
||||
|
||||
patch = jsonpatch.JsonPatch(body)
|
||||
try:
|
||||
patch.apply(env_model, in_place=True)
|
||||
except jsonpatch.JsonPatchException as e:
|
||||
raise exc.HTTPNotFound(str(e))
|
||||
|
||||
save_description = envs.EnvironmentServices. \
|
||||
save_environment_description
|
||||
save_description(session_id, env_model)
|
||||
|
||||
return env_model
|
||||
|
||||
|
||||
def create_resource():
|
||||
return wsgi.Resource(Controller())
|
||||
|
|
|
@ -97,6 +97,14 @@ class API(wsgi.Router):
|
|||
controller=environments_resource,
|
||||
action='last',
|
||||
conditions={'method': ['GET']})
|
||||
mapper.connect('/environments/{environment_id}/model/{path:.*?}',
|
||||
controller=environments_resource,
|
||||
action='get_model',
|
||||
conditions={'method': ['GET']})
|
||||
mapper.connect('/environments/{environment_id}/model/',
|
||||
controller=environments_resource,
|
||||
action='update_model',
|
||||
conditions={'method': ['PATCH']})
|
||||
|
||||
templates_resource = templates.create_resource()
|
||||
mapper.connect('/templates',
|
||||
|
|
|
@ -12,16 +12,60 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
# TODO(all): write detailed schema.
|
||||
ENV_SCHEMA = {
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {"type": "string"},
|
||||
"name": {"type": "string"}
|
||||
"?": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {"type": "string"},
|
||||
"name": {"type": "string"},
|
||||
"type": {"type": "string"},
|
||||
"_actions": {"type": "object"}
|
||||
},
|
||||
"required": ["id", "type"]
|
||||
},
|
||||
"name": {"type": "string"},
|
||||
"region": {"type": ["string", "null"]},
|
||||
"regions": {"type": "object"},
|
||||
"defaultNetworks": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"environment": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"type": "string"},
|
||||
"?": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {"type": "string"},
|
||||
"id": {"type": "string"},
|
||||
"name": {"type": "string"}
|
||||
},
|
||||
},
|
||||
"autoUplink": {"type": "boolean"},
|
||||
"externalRouterId": {"type": "string"},
|
||||
"dnsNameServers": {"type": "array"},
|
||||
"autogenerateSubnet": {"type": "boolean"},
|
||||
"subnetCidr": {"type": "string"},
|
||||
"openstackId": {"type": "string"},
|
||||
"regionName": {"type": "string"}
|
||||
},
|
||||
"required": ["name", "?"]
|
||||
},
|
||||
"flat": {"type": ["boolean", "null"]}
|
||||
},
|
||||
"required": ["environment", "flat"]
|
||||
},
|
||||
"services": {
|
||||
"type": "array",
|
||||
"minItems": 0,
|
||||
"items": {"type": "object"}
|
||||
}
|
||||
},
|
||||
"required": ["id", "name"]
|
||||
"required": ["?", "name", "region", "defaultNetworks"]
|
||||
}
|
||||
|
||||
PKG_UPLOAD_SCHEMA = {
|
||||
|
|
|
@ -308,6 +308,7 @@ class Request(webob.Request):
|
|||
default_request_content_types = ('application/json',
|
||||
'application/xml',
|
||||
'application/murano-packages-json-patch',
|
||||
'application/env-model-json-patch',
|
||||
'multipart/form-data')
|
||||
default_accept_types = ('application/json',
|
||||
'application/xml',
|
||||
|
@ -737,7 +738,10 @@ class RequestDeserializer(object):
|
|||
self.body_deserializers = {
|
||||
'application/xml': XMLDeserializer(),
|
||||
'application/json': JSONDeserializer(),
|
||||
'application/murano-packages-json-patch': JSONPatchDeserializer(),
|
||||
'application/murano-packages-json-patch':
|
||||
MuranoPackageJSONPatchDeserializer(),
|
||||
'application/env-model-json-patch':
|
||||
EnvModelJSONPatchDeserializer(),
|
||||
'multipart/form-data': FormDataDeserializer()
|
||||
}
|
||||
self.body_deserializers.update(body_deserializers or {})
|
||||
|
@ -846,12 +850,9 @@ class JSONDeserializer(TextDeserializer):
|
|||
|
||||
|
||||
class JSONPatchDeserializer(TextDeserializer):
|
||||
allowed_operations = {"categories": ["add", "replace", "remove"],
|
||||
"tags": ["add", "replace", "remove"],
|
||||
"is_public": ["replace"],
|
||||
"enabled": ["replace"],
|
||||
"description": ["replace"],
|
||||
"name": ["replace"]}
|
||||
allowed_operations = {}
|
||||
schema = None
|
||||
allow_unknown_path = False
|
||||
|
||||
def _from_json_patch(self, datastring):
|
||||
try:
|
||||
|
@ -860,6 +861,10 @@ class JSONPatchDeserializer(TextDeserializer):
|
|||
msg = _("cannot understand JSON")
|
||||
raise exceptions.MalformedRequestBody(reason=msg)
|
||||
|
||||
if not isinstance(operations, list):
|
||||
msg = _('JSON-patch must be a list.')
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
changes = []
|
||||
for raw_change in operations:
|
||||
if not isinstance(raw_change, dict):
|
||||
|
@ -898,32 +903,53 @@ class JSONPatchDeserializer(TextDeserializer):
|
|||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
def _validate_change(self, change):
|
||||
change_path = change['path'][0]
|
||||
change_op = change['op']
|
||||
allowed_methods = self.allowed_operations.get(change_path)
|
||||
self._validate_allowed_methods(change, self.allow_unknown_path)
|
||||
|
||||
if not allowed_methods:
|
||||
msg = _("Attribute '{0}' is invalid").format(change_path)
|
||||
raise webob.exc.HTTPForbidden(explanation=six.text_type(msg))
|
||||
if self.schema:
|
||||
self._validate_schema(change)
|
||||
|
||||
def _validate_allowed_methods(self, change, allow_unknown_path=False):
|
||||
full_path = '/'.join(change['path'])
|
||||
change_op = change['op']
|
||||
allowed_methods = self.allowed_operations.get(full_path)
|
||||
|
||||
if allowed_methods is None:
|
||||
if allow_unknown_path:
|
||||
allowed_methods = ['add', 'replace', 'remove']
|
||||
else:
|
||||
msg = _("Attribute '{0}' is invalid").format(full_path)
|
||||
raise webob.exc.HTTPForbidden(explanation=six.text_type(msg))
|
||||
|
||||
if change_op not in allowed_methods:
|
||||
ops = ', '.join(allowed_methods) if allowed_methods\
|
||||
else 'no operations'
|
||||
msg = _("Method '{method}' is not allowed for a path with name "
|
||||
"'{name}'. Allowed operations are: "
|
||||
"'{ops}'").format(method=change_op,
|
||||
name=change_path,
|
||||
ops=', '.join(allowed_methods))
|
||||
"{ops}").format(method=change_op, name=full_path, ops=ops)
|
||||
|
||||
raise webob.exc.HTTPForbidden(explanation=six.text_type(msg))
|
||||
|
||||
property_to_update = {change_path: change['value']}
|
||||
|
||||
try:
|
||||
jsonschema.validate(property_to_update,
|
||||
validation_schemas.PKG_UPDATE_SCHEMA)
|
||||
except jsonschema.ValidationError as e:
|
||||
LOG.error(_LE("Schema validation error occurred: {error}")
|
||||
.format(error=e))
|
||||
raise webob.exc.HTTPBadRequest(explanation=e.message)
|
||||
def _validate_schema(self, change):
|
||||
property_to_update = change['value']
|
||||
can_validate = True
|
||||
schema = self.schema
|
||||
for p in change['path']:
|
||||
if schema['type'] == 'array':
|
||||
try:
|
||||
schema = schema['items']
|
||||
except KeyError:
|
||||
can_validate = False
|
||||
elif schema['type'] == 'object':
|
||||
try:
|
||||
schema = schema['properties'][p]
|
||||
except KeyError:
|
||||
can_validate = False
|
||||
if can_validate:
|
||||
try:
|
||||
jsonschema.validate(property_to_update, schema)
|
||||
except jsonschema.ValidationError as e:
|
||||
LOG.error(_LE("Schema validation error occurred: %s"), e)
|
||||
raise webob.exc.HTTPBadRequest(explanation=e.message)
|
||||
|
||||
def _decode_json_pointer(self, pointer):
|
||||
"""Parse a json pointer.
|
||||
|
@ -972,13 +998,42 @@ class JSONPatchDeserializer(TextDeserializer):
|
|||
path_list = self._decode_json_pointer(path)
|
||||
return op, path_list
|
||||
|
||||
def _validate_path(self, path):
|
||||
pass
|
||||
|
||||
def default(self, request):
|
||||
return {'body': self._from_json_patch(request.body)}
|
||||
|
||||
|
||||
class MuranoPackageJSONPatchDeserializer(JSONPatchDeserializer):
|
||||
allowed_operations = {"categories": ["add", "replace", "remove"],
|
||||
"tags": ["add", "replace", "remove"],
|
||||
"is_public": ["replace"],
|
||||
"enabled": ["replace"],
|
||||
"description": ["replace"],
|
||||
"name": ["replace"]}
|
||||
allow_unknown_path = False
|
||||
schema = validation_schemas.PKG_UPDATE_SCHEMA
|
||||
|
||||
def _validate_path(self, path):
|
||||
if len(path) > 1:
|
||||
msg = _('Nested paths are not allowed')
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
def default(self, request):
|
||||
return {'body': self._from_json_patch(request.body)}
|
||||
|
||||
class EnvModelJSONPatchDeserializer(JSONPatchDeserializer):
|
||||
allowed_operations = {"": [],
|
||||
"defaultNetworks": ["replace"],
|
||||
"defaultNetworks/environment": ["replace"],
|
||||
"defaultNetworks/environment/?/id": [],
|
||||
"defaultNetworks/flat": ["replace"],
|
||||
"name": ["replace"],
|
||||
"region": ["replace"],
|
||||
"?/type": ["replace"],
|
||||
"?/id": []
|
||||
}
|
||||
allow_unknown_path = True
|
||||
schema = validation_schemas.ENV_SCHEMA
|
||||
|
||||
|
||||
class XMLDeserializer(TextDeserializer):
|
||||
|
|
|
@ -584,3 +584,208 @@ class TestEnvironmentApi(tb.ControllerTest, tb.MuranoApiTestCase):
|
|||
|
||||
response_body = jsonutils.loads(request.get_response(self.api).body)
|
||||
self.assertEqual(ENVIRONMENT_ID, response_body['id'])
|
||||
|
||||
def _create_env_and_session(self):
|
||||
creds = {'tenant': 'test_tenant', 'user': 'test_user'}
|
||||
|
||||
self._set_policy_rules(
|
||||
{'show_environment': '@',
|
||||
'update_environment': '@'}
|
||||
)
|
||||
|
||||
env_id = '123'
|
||||
self._create_fake_environment(env_id=env_id)
|
||||
|
||||
# Create session
|
||||
request = self._post('/environments/{environment_id}/configure'
|
||||
.format(environment_id=env_id), b'',
|
||||
**creds)
|
||||
response_body = jsonutils.loads(request.get_response(self.api).body)
|
||||
session_id = response_body['id']
|
||||
return env_id, session_id
|
||||
|
||||
def test_get_and_update_environment_model(self):
|
||||
"""Test GET and PATCH requests of an environment object model"""
|
||||
env_id, session_id = self._create_env_and_session()
|
||||
|
||||
# Get entire env's model
|
||||
self.expect_policy_check('show_environment',
|
||||
{'environment_id': '123'})
|
||||
req = self._get('/environments/{0}/model/'.format(env_id))
|
||||
result = req.get_response(self.api)
|
||||
self.assertEqual(200, result.status_code)
|
||||
expected = {'?': {'id': '{0}'.format(env_id)}}
|
||||
self.assertEqual(expected, jsonutils.loads(result.body))
|
||||
|
||||
# Add some data to the '?' section of env's model
|
||||
self.expect_policy_check('update_environment',
|
||||
{'environment_id': '123'})
|
||||
data = [{
|
||||
"op": "add",
|
||||
"path": "/?/name",
|
||||
"value": 'my_env'
|
||||
}]
|
||||
|
||||
expected = {
|
||||
'id': '{0}'.format(env_id),
|
||||
'name': 'my_env'
|
||||
}
|
||||
|
||||
req = self._patch('/environments/{0}/model/'.format(env_id),
|
||||
jsonutils.dump_as_bytes(data),
|
||||
content_type='application/env-model-json-patch')
|
||||
req.headers['X-Configuration-Session'] = str(session_id)
|
||||
req.context.session = session_id
|
||||
result = req.get_response(self.api)
|
||||
self.assertEqual(200, result.status_code)
|
||||
observed = jsonutils.loads(result.body)['?']
|
||||
self.assertEqual(expected, observed)
|
||||
|
||||
# Check that changes are stored in session
|
||||
self.expect_policy_check('show_environment',
|
||||
{'environment_id': '123'})
|
||||
req = self._get('/environments/{0}/model/{1}'.format(
|
||||
env_id, '/?'))
|
||||
req.headers['X-Configuration-Session'] = str(session_id)
|
||||
req.context.session = session_id
|
||||
result = req.get_response(self.api)
|
||||
self.assertEqual(200, result.status_code)
|
||||
self.assertEqual(expected, jsonutils.loads(result.body))
|
||||
|
||||
# Check that actual model remains unchanged
|
||||
self.expect_policy_check('show_environment',
|
||||
{'environment_id': '123'})
|
||||
req = self._get('/environments/{0}/model/{1}'.format(
|
||||
env_id, '/?'))
|
||||
result = req.get_response(self.api)
|
||||
self.assertEqual(200, result.status_code)
|
||||
expected = {'id': '{0}'.format(env_id)}
|
||||
self.assertEqual(expected, jsonutils.loads(result.body))
|
||||
|
||||
def test_get_environment_model_non_existing_path(self):
|
||||
env_id, session_id = self._create_env_and_session()
|
||||
|
||||
# Try to get non-existing section of env's model
|
||||
self.expect_policy_check('show_environment',
|
||||
{'environment_id': '123'})
|
||||
path = 'foo/bar'
|
||||
req = self._get('/environments/{0}/model/{1}'.format(
|
||||
env_id, path))
|
||||
result = req.get_response(self.api)
|
||||
self.assertEqual(404, result.status_code)
|
||||
|
||||
def test_update_environment_model_empty_body(self):
|
||||
env_id, session_id = self._create_env_and_session()
|
||||
data = None
|
||||
req = self._patch('/environments/{0}/model/'.format(env_id),
|
||||
jsonutils.dump_as_bytes(data),
|
||||
content_type='application/env-model-json-patch')
|
||||
req.headers['X-Configuration-Session'] = str(session_id)
|
||||
req.context.session = session_id
|
||||
result = req.get_response(self.api)
|
||||
self.assertEqual(400, result.status_code)
|
||||
result_msg = result.text.replace('\n', '')
|
||||
msg = "JSON-patch must be a list."
|
||||
self.assertIn(msg, result_msg)
|
||||
|
||||
def test_update_environment_model_no_patch(self):
|
||||
env_id, session_id = self._create_env_and_session()
|
||||
data = ["foo"]
|
||||
req = self._patch('/environments/{0}/model/'.format(env_id),
|
||||
jsonutils.dump_as_bytes(data),
|
||||
content_type='application/env-model-json-patch')
|
||||
req.headers['X-Configuration-Session'] = str(session_id)
|
||||
req.context.session = session_id
|
||||
result = req.get_response(self.api)
|
||||
self.assertEqual(400, result.status_code)
|
||||
result_msg = result.text.replace('\n', '')
|
||||
msg = "Operations must be JSON objects."
|
||||
self.assertIn(msg, result_msg)
|
||||
|
||||
def test_update_environment_model_no_op(self):
|
||||
env_id, session_id = self._create_env_and_session()
|
||||
data = [{
|
||||
"path": "/?/name",
|
||||
"value": 'my_env'
|
||||
}]
|
||||
req = self._patch('/environments/{0}/model/'.format(env_id),
|
||||
jsonutils.dump_as_bytes(data),
|
||||
content_type='application/env-model-json-patch')
|
||||
req.headers['X-Configuration-Session'] = str(session_id)
|
||||
req.context.session = session_id
|
||||
result = req.get_response(self.api)
|
||||
self.assertEqual(400, result.status_code)
|
||||
result_msg = result.text.replace('\n', '')
|
||||
msg = "Unable to find 'op' in JSON Schema change"
|
||||
self.assertIn(msg, result_msg)
|
||||
|
||||
def test_update_environment_model_no_path(self):
|
||||
env_id, session_id = self._create_env_and_session()
|
||||
data = [{
|
||||
"op": "add",
|
||||
"value": 'my_env'
|
||||
}]
|
||||
req = self._patch('/environments/{0}/model/'.format(env_id),
|
||||
jsonutils.dump_as_bytes(data),
|
||||
content_type='application/env-model-json-patch')
|
||||
req.headers['X-Configuration-Session'] = str(session_id)
|
||||
req.context.session = session_id
|
||||
result = req.get_response(self.api)
|
||||
self.assertEqual(400, result.status_code)
|
||||
result_msg = result.text.replace('\n', '')
|
||||
msg = "Unable to find 'path' in JSON Schema change"
|
||||
self.assertIn(msg, result_msg)
|
||||
|
||||
def test_update_environment_model_no_value(self):
|
||||
env_id, session_id = self._create_env_and_session()
|
||||
data = [{
|
||||
"op": "add",
|
||||
"path": "/?/name"
|
||||
}]
|
||||
req = self._patch('/environments/{0}/model/'.format(env_id),
|
||||
jsonutils.dump_as_bytes(data),
|
||||
content_type='application/env-model-json-patch')
|
||||
req.headers['X-Configuration-Session'] = str(session_id)
|
||||
req.context.session = session_id
|
||||
result = req.get_response(self.api)
|
||||
self.assertEqual(400, result.status_code)
|
||||
result_msg = result.text.replace('\n', '')
|
||||
msg = 'Operation "add" requires a member named "value".'
|
||||
self.assertIn(msg, result_msg)
|
||||
|
||||
def test_update_environment_model_forbidden_operation(self):
|
||||
env_id, session_id = self._create_env_and_session()
|
||||
data = [{
|
||||
"op": "add",
|
||||
"path": "/?/id",
|
||||
"value": "foo"
|
||||
}]
|
||||
req = self._patch('/environments/{0}/model/'.format(env_id),
|
||||
jsonutils.dump_as_bytes(data),
|
||||
content_type='application/env-model-json-patch')
|
||||
req.headers['X-Configuration-Session'] = str(session_id)
|
||||
req.context.session = session_id
|
||||
result = req.get_response(self.api)
|
||||
self.assertEqual(403, result.status_code)
|
||||
result_msg = result.text.replace('\n', '')
|
||||
msg = ("Method 'add' is not allowed for a path with name '?/id'. "
|
||||
"Allowed operations are: no operations")
|
||||
self.assertIn(msg, result_msg)
|
||||
|
||||
def test_update_environment_model_invalid_schema(self):
|
||||
env_id, session_id = self._create_env_and_session()
|
||||
data = [{
|
||||
"op": "add",
|
||||
"path": "/?/name",
|
||||
"value": 111
|
||||
}]
|
||||
req = self._patch('/environments/{0}/model/'.format(env_id),
|
||||
jsonutils.dump_as_bytes(data),
|
||||
content_type='application/env-model-json-patch')
|
||||
req.headers['X-Configuration-Session'] = str(session_id)
|
||||
req.context.session = session_id
|
||||
result = req.get_response(self.api)
|
||||
self.assertEqual(400, result.status_code)
|
||||
result_msg = result.text.replace('\n', '')
|
||||
msg = "111 is not of type 'string'"
|
||||
self.assertIn(msg, result_msg)
|
||||
|
|
|
@ -155,6 +155,28 @@ class ApplicationCatalogClient(rest_client.RestClient):
|
|||
self.expected_success(200, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
def get_environment_model(self, environment_id, path='/', session_id=None):
|
||||
headers = self.get_headers()
|
||||
if session_id:
|
||||
headers.update(
|
||||
{'X-Configuration-Session': session_id}
|
||||
)
|
||||
uri = '/v1/environments/{id}/model/{path}'.format(
|
||||
id=environment_id, path=path)
|
||||
resp, body = self.get(uri, headers=headers)
|
||||
self.expected_success(200, resp.status)
|
||||
return json.loads(body)
|
||||
|
||||
def update_environment_model(self, environment_id, data, session_id):
|
||||
headers = self.get_headers(send_type='env-model-json-patch')
|
||||
headers.update(
|
||||
{'X-Configuration-Session': session_id}
|
||||
)
|
||||
uri = '/v1/environments/{id}/model/'.format(id=environment_id)
|
||||
resp, body = self.patch(uri, json.dumps(data), headers=headers)
|
||||
self.expected_success(200, resp.status)
|
||||
return json.loads(body)
|
||||
|
||||
# -----------------------Methods for session manage ---------------------------
|
||||
def create_session(self, environment_id):
|
||||
body = None
|
||||
|
|
|
@ -84,3 +84,42 @@ class TestEnvironments(base.BaseApplicationCatalogTest):
|
|||
environment = self.application_catalog_client.\
|
||||
update_environment(self.environment['id'])
|
||||
self.assertIsNot(self.environment['name'], environment['name'])
|
||||
|
||||
@testtools.testcase.attr('smoke')
|
||||
def test_get_environment_model(self):
|
||||
model = self.application_catalog_client.\
|
||||
get_environment_model(self.environment['id'])
|
||||
self.assertIsInstance(model, dict)
|
||||
self.assertIn('defaultNetworks', model)
|
||||
self.assertEqual(self.environment['name'], model['name'])
|
||||
self.assertEqual(model['?']['type'], "io.murano.Environment")
|
||||
|
||||
net_name = self.application_catalog_client.\
|
||||
get_environment_model(self.environment['id'],
|
||||
path='/defaultNetworks/environment/name')
|
||||
self.assertEqual("{0}-network".format(self.environment['name']),
|
||||
net_name)
|
||||
|
||||
@testtools.testcase.attr('smoke')
|
||||
def test_update_environment_model(self):
|
||||
session = self.application_catalog_client. \
|
||||
create_session(self.environment['id'])
|
||||
patch = [{
|
||||
"op": "replace",
|
||||
"path": "/defaultNetworks/flat",
|
||||
"value": True
|
||||
}]
|
||||
new_model = self.application_catalog_client. \
|
||||
update_environment_model(self.environment['id'], patch,
|
||||
session['id'])
|
||||
self.assertTrue(new_model['defaultNetworks']['flat'])
|
||||
|
||||
value_draft = self.application_catalog_client. \
|
||||
get_environment_model(self.environment['id'],
|
||||
'/defaultNetworks/flat',
|
||||
session['id'])
|
||||
self.assertTrue(value_draft)
|
||||
|
||||
model_current = self.application_catalog_client. \
|
||||
get_environment_model(self.environment['id'])
|
||||
self.assertIsNone(model_current['defaultNetworks']['flat'])
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
features:
|
||||
- /environments/ENV_ID/model/PATH endpoint added.
|
||||
GET request responds with the subsection of ENV_ID's object model
|
||||
located in its PATH.
|
||||
PATCH request applies json-patch from request body to ENV_ID's model. It
|
||||
does not contain PATH in the URL.
|
Loading…
Reference in New Issue