Support to list software configs

APIImpact
List software configs
GET /v1/{tenant_id}/software_configs
Request params(optional)
limit,marker
Json response example
{'software_configs':[
    {'creation_time': '2015-06-25T07:15:56',
     'group': 'Heat::Ungrouped',
     'id': 'de879d1c-c9a5-4635-ba29-08a5690fec27',
     'name': 'foo'}]
}
Change-Id: Iad691672874b64b393b85d2eb9a55b22facbd263
Closes-Bug: #1464248
This commit is contained in:
lvdongbing 2015-06-19 10:54:49 +08:00 committed by Qiming Teng
parent 3fd6b53079
commit 7975d8b46a
15 changed files with 164 additions and 16 deletions

View File

@ -59,6 +59,8 @@
"stacks:list_snapshots": "rule:deny_stack_user",
"stacks:restore_snapshot": "rule:deny_stack_user",
"software_configs:global_index": "rule:deny_everybody",
"software_configs:index": "rule:deny_stack_user",
"software_configs:create": "rule:deny_stack_user",
"software_configs:show": "rule:deny_stack_user",
"software_configs:delete": "rule:deny_stack_user",

View File

@ -334,6 +334,12 @@ class API(wsgi.Router):
connect(controller=software_config_resource,
path_prefix='/{tenant_id}/software_configs',
routes=[
{
'name': 'software_config_index',
'url': '',
'action': 'index',
'method': 'GET'
},
{
'name': 'software_config_create',
'url': '',

View File

@ -11,11 +11,14 @@
# License for the specific language governing permissions and limitations
# under the License.
import six
from webob import exc
from heat.api.openstack.v1 import util
from heat.common import param_utils
from heat.common import serializers
from heat.common import wsgi
from heat.rpc import api as rpc_api
from heat.rpc import client as rpc_client
@ -34,6 +37,44 @@ class SoftwareConfigController(object):
def default(self, req, **args):
raise exc.HTTPNotFound()
def _extract_bool_param(self, name, value):
try:
return param_utils.extract_bool(name, value)
except ValueError as e:
raise exc.HTTPBadRequest(six.text_type(e))
def _index(self, req, tenant_safe=True):
whitelist = {
'limit': 'single',
'marker': 'single'
}
params = util.get_allowed_params(req.params, whitelist)
scs = self.rpc_client.list_software_configs(req.context,
tenant_safe=tenant_safe,
**params)
return {'software_configs': scs}
@util.policy_enforce
def global_index(self, req):
return self._index(req, tenant_safe=False)
@util.policy_enforce
def index(self, req):
"""
Lists summary information for all software configs
"""
global_tenant = False
name = rpc_api.PARAM_GLOBAL_TENANT
if name in req.params:
global_tenant = self._extract_bool_param(
name,
req.params.get(name))
if global_tenant:
return self.global_index(req, req.context.tenant_id)
return self._index(req)
@util.policy_enforce
def show(self, req, config_id):
"""

View File

@ -306,6 +306,14 @@ def software_config_get(context, config_id):
return IMPL.software_config_get(context, config_id)
def software_config_get_all(context, limit=None, marker=None,
tenant_safe=True):
return IMPL.software_config_get_all(context,
limit=limit,
marker=marker,
tenant_safe=tenant_safe)
def software_config_delete(context, config_id):
return IMPL.software_config_delete(context, config_id)

View File

@ -870,6 +870,15 @@ def software_config_get(context, config_id):
return result
def software_config_get_all(context, limit=None, marker=None,
tenant_safe=True):
query = model_query(context, models.SoftwareConfig)
if tenant_safe:
query = query.filter_by(tenant=context.tenant_id)
return _paginate_query(context, query, models.SoftwareConfig,
limit=limit, marker=marker).all()
def software_config_delete(context, config_id):
config = software_config_get(context, config_id)
session = orm_session.Session.object_session(config)

View File

@ -403,19 +403,20 @@ def format_validate_parameter(param):
return res
def format_software_config(sc):
def format_software_config(sc, detail=True):
if sc is None:
return
result = {
rpc_api.SOFTWARE_CONFIG_ID: sc.id,
rpc_api.SOFTWARE_CONFIG_NAME: sc.name,
rpc_api.SOFTWARE_CONFIG_GROUP: sc.group,
rpc_api.SOFTWARE_CONFIG_CONFIG: sc.config['config'],
rpc_api.SOFTWARE_CONFIG_INPUTS: sc.config['inputs'],
rpc_api.SOFTWARE_CONFIG_OUTPUTS: sc.config['outputs'],
rpc_api.SOFTWARE_CONFIG_OPTIONS: sc.config['options'],
rpc_api.SOFTWARE_CONFIG_CREATION_TIME: sc.created_at.isoformat(),
rpc_api.SOFTWARE_CONFIG_CREATION_TIME: sc.created_at.isoformat()
}
if detail:
result[rpc_api.SOFTWARE_CONFIG_CONFIG] = sc.config['config']
result[rpc_api.SOFTWARE_CONFIG_INPUTS] = sc.config['inputs']
result[rpc_api.SOFTWARE_CONFIG_OUTPUTS] = sc.config['outputs']
result[rpc_api.SOFTWARE_CONFIG_OPTIONS] = sc.config['options']
return result

View File

@ -266,7 +266,7 @@ class EngineService(service.Service):
by the RPC caller.
"""
RPC_API_VERSION = '1.9'
RPC_API_VERSION = '1.10'
def __init__(self, host, topic, manager=None):
super(EngineService, self).__init__()
@ -1477,6 +1477,15 @@ class EngineService(service.Service):
def show_software_config(self, cnxt, config_id):
return self.software_config.show_software_config(cnxt, config_id)
@context.request_context
def list_software_configs(self, cnxt, limit=None, marker=None,
tenant_safe=True):
return self.software_config.list_software_configs(
cnxt,
limit=limit,
marker=marker,
tenant_safe=tenant_safe)
@context.request_context
def create_software_config(self, cnxt, group, name, config,
inputs, outputs, options):

View File

@ -36,6 +36,16 @@ class SoftwareConfigService(service.Service):
sc = software_config_object.SoftwareConfig.get_by_id(cnxt, config_id)
return api.format_software_config(sc)
def list_software_configs(self, cnxt, limit=None, marker=None,
tenant_safe=True):
scs = software_config_object.SoftwareConfig.get_all(
cnxt,
limit=limit,
marker=marker,
tenant_safe=tenant_safe)
result = [api.format_software_config(sc, detail=False) for sc in scs]
return result
def create_software_config(self, cnxt, group, name, config,
inputs, outputs, options):

View File

@ -56,6 +56,11 @@ class SoftwareConfig(base.VersionedObject,
return cls._from_db_object(
context, cls(), db_api.software_config_get(context, config_id))
@classmethod
def get_all(cls, context, **kwargs):
scs = db_api.software_config_get_all(context, **kwargs)
return [cls._from_db_object(context, cls(), sc) for sc in scs]
@classmethod
def delete(cls, context, config_id):
db_api.software_config_delete(context, config_id)

View File

@ -30,6 +30,7 @@ class EngineClient(object):
1.1 - Add support_status argument to list_resource_types()
1.4 - Add support for service list
1.9 - Add template_type option to generate_template()
1.10 - Add support for software config list
'''
BASE_RPC_API_VERSION = '1.0'
@ -511,6 +512,15 @@ class EngineClient(object):
return self.call(cnxt, self.make_msg('show_software_config',
config_id=config_id))
def list_software_configs(self, cnxt, limit=None, marker=None,
tenant_safe=True):
return self.call(cnxt,
self.make_msg('list_software_configs',
limit=limit,
marker=marker,
tenant_safe=tenant_safe),
version='1.10')
def create_software_config(self, cnxt, group, name, config,
inputs=None, outputs=None, options=None):
inputs = inputs or []

View File

@ -1030,6 +1030,17 @@ class SqlAlchemyTest(common.HeatTestCase):
self.ctx,
config_id)
def test_software_config_get_all(self):
self.assertEqual([], db_api.software_config_get_all(self.ctx))
tenant_id = self.ctx.tenant_id
software_config = db_api.software_config_create(
self.ctx, {'name': 'config_mysql',
'tenant': tenant_id})
self.assertIsNotNone(software_config)
software_configs = db_api.software_config_get_all(self.ctx)
self.assertEqual(1, len(software_configs))
self.assertEqual(software_config, software_configs[0])
def test_software_config_delete(self):
tenant_id = self.ctx.tenant_id
config = db_api.software_config_create(
@ -1109,16 +1120,16 @@ class SqlAlchemyTest(common.HeatTestCase):
values = self._deployment_values()
deployment = db_api.software_deployment_create(self.ctx, values)
self.assertIsNotNone(deployment)
all = db_api.software_deployment_get_all(self.ctx)
self.assertEqual(1, len(all))
self.assertEqual(deployment, all[0])
all = db_api.software_deployment_get_all(
deployments = db_api.software_deployment_get_all(self.ctx)
self.assertEqual(1, len(deployments))
self.assertEqual(deployment, deployments[0])
deployments = db_api.software_deployment_get_all(
self.ctx, server_id=values['server_id'])
self.assertEqual(1, len(all))
self.assertEqual(deployment, all[0])
all = db_api.software_deployment_get_all(
self.assertEqual(1, len(deployments))
self.assertEqual(deployment, deployments[0])
deployments = db_api.software_deployment_get_all(
self.ctx, server_id=str(uuid.uuid4()))
self.assertEqual([], all)
self.assertEqual([], deployments)
def test_software_deployment_update(self):
deployment_id = str(uuid.uuid4())

View File

@ -39,7 +39,7 @@ class ServiceEngineTest(common.HeatTestCase):
def test_make_sure_rpc_version(self):
self.assertEqual(
'1.9',
'1.10',
service.EngineService.RPC_API_VERSION,
('RPC version is changed, please update this test to new version '
'and make sure additional test cases are added for RPC APIs '

View File

@ -48,6 +48,16 @@ class SoftwareConfigServiceTest(common.HeatTestCase):
return self.engine.create_software_config(
self.ctx, group, name, config, inputs, outputs, options)
def test_list_software_configs(self):
config = self._create_software_config()
config_id = config['id']
self.assertIsNotNone(config)
configs = self.engine.list_software_configs(self.ctx)
self.assertIsNotNone(configs)
config_ids = [x['id'] for x in configs]
self.assertIn(config_id, config_ids)
def test_show_software_config(self):
config_id = str(uuid.uuid4())

View File

@ -3737,6 +3737,15 @@ class RoutesTest(common.HeatTestCase):
})
def test_software_configs(self):
self.assertRoute(
self.m,
'/aaaa/software_configs',
'GET',
'index',
'SoftwareConfigController',
{
'tenant_id': 'aaaa'
})
self.assertRoute(
self.m,
'/aaaa/software_configs',
@ -4146,6 +4155,18 @@ class SoftwareConfigControllerTest(ControllerTest, common.HeatTestCase):
self.assertRaises(
webob.exc.HTTPNotFound, self.controller.default, None)
@mock.patch.object(policy.Enforcer, 'enforce')
def test_index(self, mock_enforce):
self._mock_enforce_setup(mock_enforce, 'index')
req = self._get('/software_configs')
with mock.patch.object(
self.controller.rpc_client,
'list_software_configs',
return_value=[]):
resp = self.controller.index(req, tenant_id=self.tenant)
self.assertEqual(
{'software_configs': []}, resp)
@mock.patch.object(policy.Enforcer, 'enforce')
def test_show(self, mock_enforce):
self._mock_enforce_setup(mock_enforce, 'show')

View File

@ -268,6 +268,11 @@ class EngineRpcAPITestCase(common.HeatTestCase):
self._test_engine_api('set_watch_state', 'call',
watch_name='watch1', state="xyz")
def test_list_software_configs(self):
self._test_engine_api('list_software_configs', 'call',
limit=mock.ANY, marker=mock.ANY,
tenant_safe=mock.ANY)
def test_show_software_config(self):
self._test_engine_api('show_software_config', 'call',
config_id='cda89008-6ea6-4057-b83d-ccde8f0b48c9')