Execution operations by admin user

Partially implements: blueprint qinling-admin-operations
Change-Id: Ie2f7572b61b0a88a488f8dcceea35e8d7c689abe
This commit is contained in:
Lingxian Kong 2017-12-13 21:56:44 +13:00
parent 939ba95cc4
commit e120058fbe
4 changed files with 68 additions and 8 deletions

View File

@ -9,6 +9,7 @@
"runtime:delete": "rule:context_is_admin",
"function:get_all:all_projects": "rule:context_is_admin",
"function_worker:get_all": "rule:context_is_admin",
"execution:get_all:all_projects": "rule:context_is_admin",
}

View File

@ -18,8 +18,10 @@ from pecan import rest
from wsme import types as wtypes
import wsmeext.pecan as wsme_pecan
from qinling.api import access_control as acl
from qinling.api.controllers.v1 import resources
from qinling.api.controllers.v1 import types
from qinling import context
from qinling.db import api as db_api
from qinling import rpc
from qinling.utils import executions
@ -62,13 +64,33 @@ class ExecutionsController(rest.RestController):
return resources.Execution.from_dict(db_model.to_dict())
@rest_utils.wrap_wsme_controller_exception
@wsme_pecan.wsexpose(resources.Executions, wtypes.text)
def get_all(self, function_id=None):
filters = rest_utils.get_filters(function_id=function_id)
@wsme_pecan.wsexpose(resources.Executions, wtypes.text, bool, wtypes.text)
def get_all(self, function_id=None, all_projects=False, project_id=None):
"""Return a list of executions.
:param function_id: Optional. Filtering executions by function_id.
:param project_id: Optional. Admin user can query other projects
resources, the param is ignored for normal user.
:param all_projects: Optional. Get resources of all projects.
"""
ctx = context.get_ctx()
if project_id and not ctx.is_admin:
project_id = context.ctx().projectid
if project_id and ctx.is_admin:
all_projects = True
if all_projects:
acl.enforce('execution:get_all:all_projects', ctx)
filters = rest_utils.get_filters(
function_id=function_id,
project_id=project_id,
)
LOG.info("Get all %ss. filters=%s", self.type, filters)
db_execs = db_api.get_executions(insecure=all_projects, **filters)
executions = [resources.Execution.from_dict(db_model.to_dict())
for db_model in db_api.get_executions(**filters)]
for db_model in db_execs]
return resources.Executions(executions=executions)

View File

@ -22,6 +22,7 @@ from oslo_utils import strutils
import pecan
from pecan import rest
from webob.static import FileIter
from wsme import types as wtypes
import wsmeext.pecan as wsme_pecan
from qinling.api import access_control as acl
@ -193,7 +194,7 @@ class FunctionsController(rest.RestController):
return resources.Function.from_dict(func_db.to_dict()).to_dict()
@rest_utils.wrap_wsme_controller_exception
@wsme_pecan.wsexpose(resources.Functions, bool, types.uuid)
@wsme_pecan.wsexpose(resources.Functions, bool, wtypes.text)
def get_all(self, all_projects=False, project_id=None):
"""Return a list of functions.
@ -210,11 +211,10 @@ class FunctionsController(rest.RestController):
if all_projects:
acl.enforce('function:get_all:all_projects', ctx)
LOG.info("Get all functions.")
filters = rest_utils.get_filters(
project_id=project_id,
)
LOG.info("Get all %ss. filters=%s", self.type, filters)
db_functions = db_api.get_functions(insecure=all_projects, **filters)
functions = [resources.Function.from_dict(db_model.to_dict())

View File

@ -20,6 +20,7 @@ import futurist
from oslo_serialization import jsonutils
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions
from qinling_tempest_plugin.tests import base
@ -122,6 +123,42 @@ class ExecutionsTest(base.BaseQinlingTest):
self.assertEqual(204, resp.status)
@decorators.idempotent_id('2199d1e6-de7d-4345-8745-a8184d6022b1')
def test_get_all_admin(self):
"""Admin user can get executions of other projects"""
self.await_runtime_available(self.runtime_id)
self._create_function()
resp, body = self.client.create_execution(self.function_id,
input={'name': 'Qinling'})
self.assertEqual(201, resp.status)
execution_id = body['id']
self.addCleanup(self.client.delete_resource, 'executions',
execution_id, ignore_notfound=True)
resp, body = self.admin_client.get_resources(
'executions?all_projects=true'
)
self.assertEqual(200, resp.status)
self.assertIn(
execution_id,
[execution['id'] for execution in body['executions']]
)
@decorators.idempotent_id('009fba47-957e-4de5-82e8-a032386d3ac0')
def test_get_all_not_allowed(self):
# Get other projects functions by normal user
context = self.assertRaises(
exceptions.Forbidden,
self.client.get_resources,
'executions?all_projects=true'
)
self.assertIn(
'Operation not allowed',
context.resp_body.get('faultstring')
)
@decorators.idempotent_id('8096cc52-64d2-4660-a657-9ac0bdd743ae')
def test_execution_async(self):
self.await_runtime_available(self.runtime_id)