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", "runtime:delete": "rule:context_is_admin",
"function:get_all:all_projects": "rule:context_is_admin", "function:get_all:all_projects": "rule:context_is_admin",
"function_worker:get_all": "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 from wsme import types as wtypes
import wsmeext.pecan as wsme_pecan 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 resources
from qinling.api.controllers.v1 import types from qinling.api.controllers.v1 import types
from qinling import context
from qinling.db import api as db_api from qinling.db import api as db_api
from qinling import rpc from qinling import rpc
from qinling.utils import executions from qinling.utils import executions
@ -62,13 +64,33 @@ class ExecutionsController(rest.RestController):
return resources.Execution.from_dict(db_model.to_dict()) return resources.Execution.from_dict(db_model.to_dict())
@rest_utils.wrap_wsme_controller_exception @rest_utils.wrap_wsme_controller_exception
@wsme_pecan.wsexpose(resources.Executions, wtypes.text) @wsme_pecan.wsexpose(resources.Executions, wtypes.text, bool, wtypes.text)
def get_all(self, function_id=None): def get_all(self, function_id=None, all_projects=False, project_id=None):
filters = rest_utils.get_filters(function_id=function_id) """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) 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()) 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) return resources.Executions(executions=executions)

View File

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

View File

@ -20,6 +20,7 @@ import futurist
from oslo_serialization import jsonutils from oslo_serialization import jsonutils
from tempest.lib.common.utils import data_utils from tempest.lib.common.utils import data_utils
from tempest.lib import decorators from tempest.lib import decorators
from tempest.lib import exceptions
from qinling_tempest_plugin.tests import base from qinling_tempest_plugin.tests import base
@ -122,6 +123,42 @@ class ExecutionsTest(base.BaseQinlingTest):
self.assertEqual(204, resp.status) 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') @decorators.idempotent_id('8096cc52-64d2-4660-a657-9ac0bdd743ae')
def test_execution_async(self): def test_execution_async(self):
self.await_runtime_available(self.runtime_id) self.await_runtime_available(self.runtime_id)