Public environment template

This feature will allow having private and public environment templates, as well as,
to obtain all public templates from all tenants. In addition, a clone functionality
is added to copy a template from a tenant to another.

Change-Id: I702d9d707cb14195278b1cc2084fe9609660a3fe
Targets-blueprint: abstract-env-template
This commit is contained in:
Henar Muñoz Frutos 2015-08-21 11:21:16 +02:00 committed by Kirill Zaitsev
parent 7e07bafb7f
commit 02add081a2
11 changed files with 562 additions and 82 deletions

View File

@ -65,6 +65,13 @@ List Environments Templates
| | | environment templates |
+----------+----------------------------------+----------------------------------+
*Parameters:*
* `is_public` - boolean, indicates whether public environment templates are listed or not.
*True* public environments templates from all tenants are listed.
*False* private environments templates from current tenant are listed
*empty* all tenant templates plus public templates from all tenants are listed
*Response*
This call returns a list of environment templates. Only the basic properties are
@ -81,6 +88,7 @@ returned.
"created": "2014-05-14T13:02:46",
"tenant_id": "726ed856965f43cc8e565bc991fa76c3",
"version": 0,
"is_public": false,
"id": "2fa5ab704749444bbeafe7991b412c33"
},
{
@ -88,8 +96,9 @@ returned.
"networking": {},
"name": "test2",
"created": "2014-05-14T13:02:51",
"tenant_id": "726ed856965f43cc8e565bc991fa76c3",
"tenant_id": "123452452345346345634563456345346",
"version": 0,
"is_public": true,
"id": "744e44812da84e858946f5d817de4f72"
}
]
@ -414,3 +423,58 @@ Create an environment from an environment template
+----------------+-----------------------------------------------------------+
| 409 | The environment already exists |
+----------------+-----------------------------------------------------------+
**POST /templates/{env-temp-id}/clone**
*Request*
+----------+--------------------------------+-------------------------------------------------+
| Method | URI | Description |
+==========+================================+=================================================+
| POST | /templates/{env-temp-id}/clone | It clones a public template from one tenant |
| | | to another |
+----------+--------------------------------+-------------------------------------------------+
*Parameters:*
* `env-temp-id` - environment template ID, required
*Example Payload*
::
{
'name': 'cloned_env_template_name'
}
*Content-Type*
application/json
*Response*
::
{
"updated": "2015-01-26T09:12:51",
"name": "cloned_env_template_name",
"created": "2015-01-26T09:12:51",
"tenant_id": "00000000000000000000000000000001",
"version": 0,
"is_public": False,
"id": "aa9033ca7ce245fca10e38e1c8c4bbf7",
}
+----------------+-----------------------------------------------------------+
| Code | Description |
+================+===========================================================+
| 200 | OK. Environment Template cloned successfully |
+----------------+-----------------------------------------------------------+
| 401 | User is not authorized to access this session |
+----------------+-----------------------------------------------------------+
| 403 | User has no access to these resources |
+----------------+-----------------------------------------------------------+
| 404 | The environment template does not exist |
+----------------+-----------------------------------------------------------+
| 409 | Conflict. The environment template name already exists |
+----------------+-----------------------------------------------------------+

View File

@ -121,6 +121,10 @@ class API(wsgi.Router):
controller=templates_resource,
action='create_environment',
conditions={'method': ['POST']})
mapper.connect('/templates/{env_template_id}/clone',
controller=templates_resource,
action='clone',
conditions={'method': ['POST']})
applications_resource = template_applications.create_resource()
mapper.connect('/templates/{env_template_id}/services',

View File

@ -17,10 +17,11 @@ from oslo_log import log as logging
from webob import exc
from murano.api.v1 import request_statistics
from murano.common.i18n import _
from murano.common.i18n import _, _LE
from murano.common import policy
from murano.common import utils
from murano.common import wsgi
from murano.db.models import EnvironmentTemplate
from murano.db.services import core_services
from murano.db.services import environment_templates as env_temps
from murano.db.services import environments as envs
@ -40,12 +41,27 @@ class Controller(object):
"""
LOG.debug('EnvTemplates:List')
policy.check('list_env_templates', request.context)
tenant_id = request.context.tenant
filters = {}
if request.GET.get('is_public'):
is_public = request.GET.get('is_public', 'false').lower() == 'true'
if not is_public:
filters['is_public'] = False
filters = {'tenant_id': tenant_id}
elif is_public:
filters['is_public'] = True
list_templates = env_temps.EnvTemplateServices.\
get_env_templates_by(filters)
else:
filters = (EnvironmentTemplate.is_public is True,
EnvironmentTemplate.tenant_id == tenant_id)
list_templates = env_temps.EnvTemplateServices.\
get_env_templates_or_by(filters)
filters = {'tenant_id': request.context.tenant}
list_templates = env_temps.EnvTemplateServices.\
get_env_templates_by(filters)
list_templates = [temp.to_dict() for temp in list_templates]
return {"templates": list_templates}
@request_statistics.stats_count(API_NAME, 'Create')
@ -59,24 +75,11 @@ class Controller(object):
"""
LOG.debug('EnvTemplates:Create <Body {body}>'.format(body=body))
policy.check('create_env_template', request.context)
self._validate_body_name(body)
try:
LOG.debug('ENV TEMP NAME: {templ_name}>'.format(
templ_name=body['name']))
if not str(body['name']).strip():
msg = _('Environment Template must contain at least one '
'non-white space symbol')
LOG.error(msg)
raise exc.HTTPBadRequest(msg)
except Exception:
msg = _('Env template body is incorrect')
LOG.exception(msg)
raise exc.HTTPClientError(msg)
if len(body['name']) > 255:
msg = _('Environment Template name should be 255 characters '
'maximum')
LOG.exception(msg)
raise exc.HTTPBadRequest(explanation=msg)
try:
LOG.debug('ENV TEMP NAME: {templ_name}>'.
format(templ_name=body['name']))
template = env_temps.EnvTemplateServices.create(
body.copy(), request.context.tenant)
return template.to_dict()
@ -172,23 +175,15 @@ class Controller(object):
:param body: the environment name
:return: session_id and environment_id
"""
LOG.debug('Templates:Create environment <Id: {templ_id}>'.
format(templ_id=env_template_id))
target = {"env_template_id": env_template_id}
policy.check('create_environment', request.context, target)
self._validate_request(request, env_template_id)
LOG.debug('Templates:Create environment <Id: {templ_id}>'.
format(templ_id=env_template_id))
template = env_temps.EnvTemplateServices.\
get_env_template(env_template_id)
if ('name' not in body or not str(body['name']).strip()):
msg = _('Environment Template must contain at least one '
'non-white space symbol')
LOG.error(msg)
raise exc.HTTPBadRequest(explanation=msg)
LOG.debug('ENVIRONMENT NAME: {env_name}>'.format(
env_name=body['name']))
self._validate_body_name(body)
try:
environment = envs.EnvironmentServices.create(
body.copy(), request.context)
@ -214,19 +209,75 @@ class Controller(object):
)
return {"session_id": session.id, "environment_id": environment.id}
@request_statistics.stats_count(API_NAME, 'Clone')
def clone(self, request, env_template_id, body):
"""It clones the env template from another env template
from other tenant.
:param request: the operation request.
:param env_template_id: the env template ID.
:param body: the request body.
:return: the description of the created template.
"""
LOG.debug('EnvTemplates:Clone <Env Template {0} for body {1}>'.
format(body, env_template_id))
policy.check('clone_env_template', request.context)
old_env_template = self._validate_exists(env_template_id)
if not old_env_template.get('is_public'):
msg = _LE('User has no access to these resources.')
LOG.error(msg)
raise exc.HTTPForbidden(explanation=msg)
self._validate_body_name(body)
LOG.debug('ENV TEMP NAME: {0}'.format(body['name']))
try:
is_public = body.get('is_public', False)
template = env_temps.EnvTemplateServices.clone(
env_template_id, request.context.tenant, body['name'],
is_public)
except db_exc.DBDuplicateEntry:
msg = _('Environment with specified name already exists')
LOG.error(msg)
raise exc.HTTPConflict(explanation=msg)
return template.to_dict()
def _validate_request(self, request, env_template_id):
self._validate_exists(env_template_id)
get_env_template = env_temps.EnvTemplateServices.get_env_template
env_template = get_env_template(env_template_id)
if env_template.is_public or request.context.is_admin:
return
if env_template.tenant_id != request.context.tenant:
msg = _LE('User has no access to these resources.')
LOG.error(msg)
raise exc.HTTPForbidden(explanation=msg)
def _validate_exists(self, env_template_id):
env_template_exists = env_temps.EnvTemplateServices.env_template_exist
if not env_template_exists(env_template_id):
msg = _('EnvTemplate <TempId {temp_id}> is not found').format(
temp_id=env_template_id)
LOG.exception(msg)
LOG.error(msg)
raise exc.HTTPNotFound(explanation=msg)
get_env_template = env_temps.EnvTemplateServices.get_env_template
env_template = get_env_template(env_template_id)
if env_template.tenant_id != request.context.tenant:
msg = _('User is not authorized to access this tenant resources')
LOG.error(msg)
raise exc.HTTPForbidden(explanation=msg)
return get_env_template(env_template_id)
def _validate_body_name(self, body):
if not('name' in body and body['name'].strip()):
msg = _('Please, specify a name of the environment template.')
LOG.exception(msg)
raise exc.HTTPBadRequest(explanation=msg)
name = unicode(body['name'])
if len(name) > 255:
msg = _('Environment template name should be 255 characters '
'maximum')
LOG.exception(msg)
raise exc.HTTPBadRequest(explanation=msg)
def create_resource():

View File

@ -0,0 +1,44 @@
# 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.
"""
Add the is_public column to the environment-template for public
environment template functionality.
Revision ID: 011
Revises: table template
"""
# revision identifiers, used by Alembic.
revision = '011'
down_revision = '010'
from alembic import op
import sqlalchemy as sa
MYSQL_ENGINE = 'InnoDB'
MYSQL_CHARSET = 'utf8'
def upgrade():
op.add_column('environment-template',
sa.Column('is_public', sa.Boolean(),
default=False, nullable=True))
# end Alembic commands #
def downgrade():
op.drop_column('environment-template', 'is_public')
# end Alembic commands #

View File

@ -97,6 +97,7 @@ class EnvironmentTemplate(Base, TimestampMixin):
tenant_id = sa.Column(sa.String(36), nullable=False)
version = sa.Column(sa.BigInteger, nullable=False, default=0)
description = sa.Column(st.JsonBlob(), nullable=False, default={})
is_public = sa.Column(sa.Boolean, default=False)
def to_dict(self):
dictionary = super(EnvironmentTemplate, self).to_dict()

View File

@ -19,6 +19,7 @@ from murano.db import session as db_session
from oslo_db import exception as db_exc
from oslo_log import log as logging
from sqlalchemy.sql import or_
LOG = logging.getLogger(__name__)
@ -38,6 +39,19 @@ class EnvTemplateServices(object):
return templates
@staticmethod
def get_env_templates_or_by(filters):
"""Returns list of environment-templates.
:param filters: property filters
:return: Returns list of environment-templates
"""
unit = db_session.get_session()
templates = unit.query(models.EnvironmentTemplate). \
filter(or_(*filters)).all()
return templates
@staticmethod
def create(env_template_params, tenant_id):
"""Creates environment-template with specified params, in particular - name.
@ -166,3 +180,32 @@ class EnvTemplateServices(object):
"""
session = db_session.get_session()
return session.query(models.EnvironmentTemplate).get(env_template_id)
@staticmethod
def clone(env_template_id, tenant_id, env_template_name, is_public):
"""Clones environment-template with specified params, in particular - name.
:param env_template_params: Dict, e.g. {'name': 'temp-name'}
:param tenant_id: Tenant Id
:return: Created Template
"""
template = EnvTemplateServices.get_env_template(env_template_id)
env_template_params = template.to_dict()
env_template_params['id'] = uuidutils.generate_uuid()
env_template_params['tenant_id'] = tenant_id
env_template_params['name'] = env_template_name
env_template_params['is_public'] = is_public
env_temp_desc = EnvTemplateServices.get_description(env_template_id)
if "services" in env_temp_desc:
env_template_params['services'] = env_temp_desc['services']
env_template = models.EnvironmentTemplate()
env_template.update(env_template_params)
unit = db_session.get_session()
with unit.begin():
unit.add(env_template)
env_template.update({'description': env_template_params})
env_template.save(unit)
return env_template

View File

@ -245,15 +245,40 @@ class MuranoClient(rest_client.RestClient):
"""Check the environment templates deployed by the user."""
resp, body = self.get('v1/templates')
return resp, json.loads(body)['templates']
def get_public_env_templates_list(self):
"""Check the public environment templates deployed by the user."""
resp, body = self.get('v1/templates?is_public=true')
return resp, json.loads(body)
def get_private_env_templates_list(self):
"""Check the public environment templates deployed by the user."""
resp, body = self.get('v1/templates?is_public=false')
return resp, json.loads(body)
def create_env_template(self, env_template_name):
"""Check the creation of an environment template."""
body = {'name': env_template_name}
body = {'name': env_template_name, "is_public": False}
resp, body = self.post('v1/templates', json.dumps(body))
return resp, json.loads(body)
def create_clone_env_template(self, env_template_id,
cloned_env_template_name):
"""Clone an environment template."""
body = {'name': cloned_env_template_name}
resp, body = self.post('v1/templates/{0}/clone'.
format(env_template_id), json.dumps(body))
return resp, json.loads(body)
def create_public_env_template(self, env_template_name):
"""Check the creation of an environment template."""
body = {'name': env_template_name, "is_public": True}
resp, body = self.post('v1/templates', json.dumps(body))
return resp, json.loads(body)
def create_env_template_with_apps(self, env_template_name):
"""Check the creation of an environment template."""
body = {'name': env_template_name}
@ -427,10 +452,34 @@ class TestCase(TestAuth):
return environment
def create_env_template(self, name):
env_template = self.client.create_env_template(name)[1]
resp, env_template = self.client.create_env_template(name)
self.env_templates.append(env_template)
return resp, env_template
return env_template
def create_public_env_template(self, name):
resp, env_template = self.client.create_public_env_template(name)
self.env_templates.append(env_template)
return resp, env_template
def create_env_template_with_apps(self, name):
resp, env_template = self.client.create_env_template_with_apps(name)
self.env_templates.append(env_template)
return resp, env_template
def clone_env_template(self, env_template_id, cloned_env_template_name):
create_clone_env_temp = self.client.create_clone_env_template
resp, env_template = create_clone_env_temp(env_template_id,
cloned_env_template_name)
self.env_templates.append(env_template)
return resp, env_template
def create_env_from_template(self, env_template_id, env_name):
resp, env_id = self.client.create_env_from_template(env_template_id,
env_name)
resp, env = self.client.get_environment(env_id['environment_id'])
self.environments.append(env)
return resp, env
def create_demo_service(self, environment_id, session_id, client=None):
if not client:

View File

@ -23,11 +23,11 @@ class TestEnvTemplate(base.TestCase):
@tag('all', 'coverage')
@attr(type='smoke')
def test_list_env_templates(self):
def test_list_empty_env_templates(self):
"""Check getting the list of environment templates."""
resp, body = self.client.get_env_templates_list()
self.assertIn('templates', body)
self.assertEqual(0, len(body))
self.assertEqual(resp.status, 200)
@tag('all', 'coverage')
@ -36,23 +36,24 @@ class TestEnvTemplate(base.TestCase):
"""It checks the creation and deletion of an enviroment template."""
env_templates_list_start = self.client.get_env_templates_list()[1]
resp, env_template = self.client.create_env_template('test_env_temp')
resp, env_template = self.create_env_template('test_env_temp')
self.env_templates.append(env_template)
self.assertEqual(resp.status, 200)
self.assertFalse(env_template['is_public'])
self.assertEqual('test_env_temp', env_template['name'])
env_templates_list = self.client.get_env_templates_list()[1]
self.assertEqual(len(env_templates_list_start['templates']) + 1,
len(env_templates_list['templates']))
self.assertEqual(len(env_templates_list_start) + 1,
len(env_templates_list))
self.client.delete_env_template(env_template['id'])
env_templates_list = self.client.get_env_templates_list()[1]
self.assertEqual(len(env_templates_list_start['templates']),
len(env_templates_list['templates']))
self.assertEqual(len(env_templates_list_start),
len(env_templates_list))
self.env_templates.pop(self.env_templates.index(env_template))
@ -60,78 +61,151 @@ class TestEnvTemplate(base.TestCase):
@attr(type='smoke')
def test_get_env_template(self):
"""Check getting information about an environment template."""
resp, env_template = self.client.create_env_template('test_env_temp')
resp, env_template = self.create_env_template('test_env_temp')
resp, env_obtained_template =\
self.client.get_env_template(env_template['id'])
self.assertEqual(resp.status, 200)
self.assertEqual(env_obtained_template['name'], 'test_env_temp')
self.client.delete_env_template(env_template['id'])
@tag('all', 'coverage')
@attr(type='smoke')
def test_create_env_template_with_apps(self):
"""Check the creation of an environment template with applications."""
resp, env_template = \
self.client.create_env_template_with_apps('test_env_temp')
self.create_env_template_with_apps('test_env_temp')
self.assertEqual(resp.status, 200)
resp, apps_template = \
self.client.get_apps_in_env_template(env_template['id'])
self.assertEqual(resp.status, 200)
self.assertEqual(len(apps_template), 1)
self.client.delete_env_template(env_template['id'])
@tag('all', 'coverage')
@attr(type='smoke')
def test_create_app_in_env_template(self):
"""Check the creationg of applications in an environment template."""
resp, env_template = self.client.create_env_template('test_env_temp')
resp, apps = self.client.get_apps_in_env_template(env_template['id'])
resp, env_temp = self.create_env_template('test_env_temp')
self.assertEqual(resp.status, 200)
resp, apps = self.client.get_apps_in_env_template(env_temp['id'])
self.assertEqual(resp.status, 200)
self.assertEqual(len(apps), 0)
resp, apps = self.client.create_app_in_env_template(env_template['id'])
resp, apps = self.client.create_app_in_env_template(env_temp['id'])
self.assertEqual(resp.status, 200)
resp, apps = self.client.get_apps_in_env_template(env_template['id'])
resp, apps = self.client.get_apps_in_env_template(env_temp['id'])
self.assertEqual(resp.status, 200)
self.assertEqual(len(apps), 1)
self.client.delete_env_template(env_template['id'])
@tag('all', 'coverage')
@attr(type='smoke')
def test_delete_app_in_env_template(self):
"""Check the deletion of applications in an environmente template."""
resp, env_template = self.client.create_env_template('test_env_temp')
resp, apps = self.client.create_app_in_env_template(env_template['id'])
resp, env_temp = self.create_env_template_with_apps('test_env_temp')
self.assertEqual(resp.status, 200)
resp, apps = self.client.get_apps_in_env_template(env_template['id'])
resp, apps = self.client.get_apps_in_env_template(env_temp['id'])
self.assertEqual(resp.status, 200)
self.assertEqual(len(apps), 1)
resp = self.client.delete_app_in_env_template(env_template['id'])
resp = self.client.delete_app_in_env_template(env_temp['id'])
self.assertEqual(resp.status, 200)
resp, apps = self.client.get_apps_in_env_template(env_template['id'])
resp, apps = self.client.get_apps_in_env_template(env_temp['id'])
self.assertEqual(resp.status, 200)
self.assertEqual(len(apps), 0)
self.client.delete_env_template(env_template['id'])
@tag('all', 'coverage')
@attr(type='smoke')
def test_create_public_env_template(self):
"""Check the creation of a public environment template."""
resp, env_temp = self.create_public_env_template('test_env_temp')
self.assertEqual(resp.status, 200)
resp, env = self.client.get_env_template(env_temp['id'])
self.assertEqual(resp.status, 200)
self.assertTrue(env['is_public'], 200)
@tag('all', 'coverage')
@attr(type='smoke')
def test_clone_env_template(self):
"""Check the creation of a public environment template."""
resp, env_template = self.\
create_public_env_template('test_env_temp')
self.assertEqual(resp.status, 200)
resp, cloned_templ = self.clone_env_template(env_template['id'],
'cloned_template')
self.assertEqual(resp.status, 200)
self.assertTrue(cloned_templ['name'], 'cloned_template')
@tag('all', 'coverage')
@attr(type='smoke')
def test_clone_env_template_private(self):
"""Check the creation of a public environment template."""
resp, env_template = self.\
create_env_template('test_env_temp')
self.assertEqual(resp.status, 200)
self.assertRaises(exceptions.Forbidden,
self.clone_env_template,
env_template['id'], 'cloned_template')
@tag('all', 'coverage')
@attr(type='smoke')
def test_get_public_env_templates(self):
"""Check the deletion of applications in an environmente template."""
resp, public_env_template = \
self.create_public_env_template('public_test_env_temp')
self.assertEqual(resp.status, 200)
self.assertEqual(public_env_template['is_public'], True)
resp, private_env_template = \
self.create_env_template('private_test_env_temp')
self.assertEqual(resp.status, 200)
self.assertEqual(private_env_template['is_public'], False)
resp, public_envs = self.client.get_public_env_templates_list()
self.assertEqual(resp.status, 200)
self.assertEqual(len(public_envs), 1)
@tag('all', 'coverage')
@attr(type='smoke')
def test_get_private_env_templates(self):
"""Check the deletion of applications in an environmente template."""
resp, public_env_template = \
self.create_public_env_template('public_test_env_temp')
self.assertEqual(resp.status, 200)
self.assertEqual(public_env_template['is_public'], True)
resp, private_env_template = \
self.create_env_template('private_test_env_temp')
self.assertEqual(resp.status, 200)
self.assertEqual(private_env_template['is_public'], False)
resp, private_envs = self.client.get_private_env_templates_list()
self.assertEqual(resp.status, 200)
self.assertEqual(len(private_envs), 1)
@tag('all', 'coverage')
@attr(type='smoke')
def test_get_env_templates(self):
"""Check the deletion of applications in an environmente template."""
resp, public_env_template = \
self.create_public_env_template('public_test_env_temp')
self.assertEqual(resp.status, 200)
self.assertEqual(public_env_template['is_public'], True)
resp, private_env_template = \
self.create_env_template('private_test_env_temp')
self.assertEqual(resp.status, 200)
self.assertEqual(private_env_template['is_public'], False)
resp, envs_templates = self.client.get_env_templates_list()
self.assertEqual(resp.status, 200)
self.assertEqual(len(envs_templates), 2)
@tag('all', 'coverage')
@attr(type='smoke')
def test_create_env_from_template(self):
"""Check the creation of an environment from a template."""
resp, env_template = \
self.client.create_env_template_with_apps('test_env_temp')
self.create_env_template_with_apps('test_env_temp')
self.assertEqual(resp.status, 200)
resp, env = self.client.create_env_from_template(env_template['id'],
"env")
resp, env = self.create_env_from_template(env_template['id'],
"env")
self.assertEqual(resp.status, 200)
self.client.delete_env_template(env_template['id'])
self.client.delete_environment(env['environment_id'])
self.assertIsNotNone(env)
@tag('all', 'coverage')
@attr(type='negative')
@ -153,7 +227,7 @@ class TestEnvTemplate(base.TestCase):
@attr(type='negative')
def test_double_delete_env_template(self):
"""Check the deletion of an wrong environment template request."""
_, env_template = self.client.create_env_template('test_env_temp')
_, env_template = self.create_env_template('test_env_temp')
self.client.delete_env_template(env_template['id'])
@ -165,7 +239,7 @@ class TestEnvTemplate(base.TestCase):
@attr(type='negative')
def test_get_deleted_env_template(self):
"""Check the deletion of an wrong environment template request."""
_, env_template = self.client.create_env_template('test_env_temp')
_, env_template = self.create_env_template('test_env_temp')
self.client.delete_env_template(env_template['id'])
@ -182,22 +256,19 @@ class TestEnvTemplatesTenantIsolation(base.NegativeTestCase):
"""It tests getting information from an environment
template from another user.
"""
env_template = self.create_env_template('test_env_temp')
_, env_template = self.create_env_template('test_env_temp')
self.assertRaises(exceptions.Forbidden,
self.alt_client.get_env_template, env_template['id'])
self.client.delete_env_template(env_template['id'])
@tag('all', 'coverage')
@attr(type='negative')
def test_delete_env_template_from_another_tenant(self):
"""It tests deleting information from an environment
template from another user.
"""
env_template = self.create_env_template('test_env_temp')
_, env_template = self.create_env_template('test_env_temp')
self.assertRaises(exceptions.Forbidden,
self.alt_client.delete_env_template,
env_template['id'])
self.client.delete_env_template(env_template['id'])

View File

@ -59,6 +59,7 @@ class TestEnvTemplateApi(tb.ControllerTest, tb.MuranoApiTestCase):
expected = {'tenant_id': self.tenant,
'id': 'env_template_id',
'is_public': False,
'name': 'mytemp',
'version': 0,
'created': timeutils.isotime(fake_now)[:-1],
@ -86,6 +87,138 @@ class TestEnvTemplateApi(tb.ControllerTest, tb.MuranoApiTestCase):
result = req.get_response(self.api)
self.assertEqual(expected, json.loads(result.body))
def test_list_public_env_templates(self):
"""Create an template, test templates.public()."""
self._set_policy_rules(
{'create_env_template': '@',
'list_env_templates': '@'}
)
self.expect_policy_check('create_env_template')
body = {'name': 'mytemp2', 'is_public': True}
req = self._post('/templates', json.dumps(body))
result = req.get_response(self.api)
self.assertTrue(json.loads(result.body)['is_public'])
self.expect_policy_check('list_env_templates')
req = self._get('/templates', {'is_public': True})
result = req.get_response(self.api)
self.assertEqual(1, len(json.loads(result.body)))
self.assertTrue(json.loads(result.body)['templates'][0]['is_public'])
def test_clone_env_templates(self):
"""Create an template, test templates.public()."""
self._set_policy_rules(
{'create_env_template': '@',
'clone_env_template': '@'}
)
self.expect_policy_check('create_env_template')
body = {'name': 'mytemp2', 'is_public': True}
req = self._post('/templates', json.dumps(body))
result = req.get_response(self.api)
env_template_id = json.loads(result.body)['id']
self.assertTrue(json.loads(result.body)['is_public'])
self.expect_policy_check('clone_env_template')
body = {'name': 'clone', 'is_public': False}
req = self._post('/templates/%s/clone' % env_template_id,
json.dumps(body))
result = req.get_response(self.api)
self.assertFalse(json.loads(result.body)['is_public'])
self.assertEqual('clone', json.loads(result.body)['name'])
def test_clone_env_templates_private(self):
"""Create an template, test templates.public()."""
self._set_policy_rules(
{'create_env_template': '@',
'clone_env_template': '@'}
)
self.expect_policy_check('create_env_template')
body = {'name': 'mytemp2', 'is_public': False}
req = self._post('/templates', json.dumps(body))
result = req.get_response(self.api)
env_template_id = json.loads(result.body)['id']
self.assertFalse(json.loads(result.body)['is_public'])
self.expect_policy_check('clone_env_template')
body = {'name': 'clone', 'is_public': False}
req = self._post('/templates/%s/clone' % env_template_id,
json.dumps(body))
result = req.get_response(self.api)
self.assertEqual(result.status_code, 403)
def test_list_public_env_templates_default(self):
"""Create an template, test list public with no
public templates.
"""
self._set_policy_rules(
{'create_env_template': '@',
'list_env_templates': '@'}
)
self.expect_policy_check('create_env_template')
body = {'name': 'mytemp'}
req = self._post('/templates', json.dumps(body))
result = req.get_response(self.api)
self.assertFalse(json.loads(result.body)['is_public'])
self.expect_policy_check('list_env_templates')
req = self._get('/templates', {'is_public': True})
result = req.get_response(self.api)
self.assertFalse(0, len(json.loads(result.body)))
def test_list_private_env_templates(self):
"""Create an template, test list public with no
public templates.
"""
self._set_policy_rules(
{'create_env_template': '@',
'list_env_templates': '@'}
)
self.expect_policy_check('create_env_template')
body = {'name': 'mytemp', 'is_public': False}
req = self._post('/templates', json.dumps(body))
result = req.get_response(self.api)
self.assertFalse(json.loads(result.body)['is_public'])
self.expect_policy_check('list_env_templates')
req = self._get('/templates', {'is_public': False})
result = req.get_response(self.api)
self.assertEqual(1, len(json.loads(result.body)['templates']))
def test_list_env_templates(self):
"""Create an template, test list public with no
public templates.
"""
self._set_policy_rules(
{'create_env_template': '@',
'list_env_templates': '@'}
)
self.expect_policy_check('create_env_template')
body = {'name': 'mytemp', 'is_public': False}
req = self._post('/templates', json.dumps(body))
result = req.get_response(self.api)
self.assertFalse(json.loads(result.body)['is_public'])
self.expect_policy_check('create_env_template')
body = {'name': 'mytemp1', 'is_public': True}
req = self._post('/templates', json.dumps(body))
result = req.get_response(self.api)
self.assertTrue(json.loads(result.body)['is_public'])
self.expect_policy_check('list_env_templates')
req = self._get('/templates')
result = req.get_response(self.api)
self.assertEqual(2, len(json.loads(result.body)['templates']))
def test_illegal_template_name_create(self):
"""Check that an illegal temp name results in an HTTPClientError."""
self._set_policy_rules(
@ -114,7 +247,7 @@ class TestEnvTemplateApi(tb.ControllerTest, tb.MuranoApiTestCase):
result = req.get_response(self.api)
self.assertEqual(400, result.status_code)
result_msg = result.text.replace('\n', '')
self.assertIn('Environment Template name should be 255 characters '
self.assertIn('Environment template name should be 255 characters '
'maximum',
result_msg)
@ -158,6 +291,7 @@ class TestEnvTemplateApi(tb.ControllerTest, tb.MuranoApiTestCase):
expected = dict(
id='12345',
is_public=False,
name='my-temp',
version=0,
created=fake_now,
@ -242,6 +376,7 @@ class TestEnvTemplateApi(tb.ControllerTest, tb.MuranoApiTestCase):
timeutils.utcnow.override_time = fake_now
expected = {'tenant_id': self.tenant,
'id': self.uuids[0],
'is_public': False,
'name': 'env_template_name',
'version': 0,
'created': timeutils.isotime(fake_now)[:-1],

View File

@ -27,7 +27,7 @@ class TestTemplateServices(base.MuranoWithDBTestCase,
def setUp(self):
super(TestTemplateServices, self).setUp()
self.template_services = env_temp.EnvTemplateServices
self.uuids = ['template_id']
self.uuids = ['template_id', 'template_id2']
self.mock_uuid = self._stub_uuid(self.uuids)
self.addCleanup(mock.patch.stopall)
@ -42,6 +42,18 @@ class TestTemplateServices(base.MuranoWithDBTestCase,
self.assertEqual(fixture.environment_template_desc,
template_des.description)
def test_clone_template(self):
"""Check the clonation of a template."""
body = {
"name": "my_template"
}
template = self.template_services.create(body, 'tenant_id')
cloned_template = self.template_services.clone(template['id'],
'id2',
"my_template2", False)
self.assertEqual(cloned_template.description['name'], 'my_template2')
self.assertEqual(cloned_template.description['tenant_id'], 'id2')
def test_get_empty_template(self):
"""Check obtaining information about a template without services."""
fixture = self.useFixture(et.EmptyEnvironmentTemplateFixture())

View File

@ -0,0 +1,6 @@
---
features:
- Added public field to environment templates. GET method
for api now displays public templates from other projects(tenants).
- Added public filter to environment templates api.
- Added clone action to environment templates.