Add container action api
Add container action api to get container action information. Change-Id: Ic3fa5e879baa6a5a01a1ae83740a2149a6f8003b
This commit is contained in:
parent
79e01261ce
commit
07dd607dac
@ -9,7 +9,7 @@ stops, pauses, unpauses, restarts, renames, commits, kills, attaches to containe
|
||||
gets archive from container, puts archive to container, and adds security group
|
||||
for specified container, executes command in a running container, gets logs
|
||||
of a container, displays the running processes in a container, resizes
|
||||
the tty session used by the exec.
|
||||
the tty session used by the exec, list actions and action detail for a container.
|
||||
|
||||
Create new container
|
||||
====================
|
||||
@ -1227,3 +1227,101 @@ Response Example
|
||||
|
||||
.. literalinclude:: samples/container-network-list-resp.json
|
||||
:language: javascript
|
||||
|
||||
List Actions For Container
|
||||
==========================
|
||||
|
||||
.. rest_method:: GET /v1/containers/{container_ident}/container_actions
|
||||
|
||||
List actions for a container
|
||||
|
||||
Response Codes
|
||||
--------------
|
||||
|
||||
.. rest_status_code:: success status.yaml
|
||||
|
||||
- 200
|
||||
|
||||
.. rest_status_code:: error status.yaml
|
||||
|
||||
- 401
|
||||
- 403
|
||||
- 404
|
||||
|
||||
Request
|
||||
-------
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- container_ident: container_ident
|
||||
|
||||
Response
|
||||
--------
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- action: action
|
||||
- container_uuid: uuid
|
||||
- message: message
|
||||
- request_id: request_id_body
|
||||
- start_time: start_time
|
||||
- project_id: project_id_container_action
|
||||
- user_id: user_id
|
||||
|
||||
**Example List Actions For Container: JSON response**
|
||||
|
||||
.. literalinclude:: samples/container-actions-list-resp.json
|
||||
:language: javascript
|
||||
|
||||
|
||||
Show Container Action Details
|
||||
=============================
|
||||
|
||||
.. rest_method:: GET /v1/containers/{container_ident}/container_actions/{request_ident}
|
||||
|
||||
Show details for a container action.
|
||||
|
||||
Response Codes
|
||||
--------------
|
||||
|
||||
.. rest_status_code:: success status.yaml
|
||||
|
||||
- 200
|
||||
|
||||
.. rest_status_code:: error status.yaml
|
||||
|
||||
- 401
|
||||
- 403
|
||||
- 404
|
||||
|
||||
Request
|
||||
-------
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- container_ident: container_ident
|
||||
- request_ident: request_ident
|
||||
|
||||
Responce
|
||||
--------
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- action: action
|
||||
- container_uuid: uuid
|
||||
- message: message
|
||||
- project_id: project_id_container_action
|
||||
- request_id: request_id_body
|
||||
- start_time: start_time
|
||||
- user_id: user_id
|
||||
- events: container_action_events
|
||||
- events.event: event
|
||||
- events.start_time: event_start_time
|
||||
- events.finish_time: event_finish_time
|
||||
- events.result: event_result
|
||||
- events.traceback: event_traceback
|
||||
|
||||
**Example Show Container Action Details: JSON response**
|
||||
|
||||
.. literalinclude:: samples/container-action-get-resp.json
|
||||
:language: javascript
|
||||
|
@ -17,6 +17,12 @@ host_ident:
|
||||
in: path
|
||||
required: true
|
||||
type: string
|
||||
request_ident:
|
||||
description: |
|
||||
The ID of the request.
|
||||
in: path
|
||||
required: true
|
||||
type: string
|
||||
destination_path:
|
||||
description: |
|
||||
The destination path in a container when putting archive to a container.
|
||||
@ -164,6 +170,12 @@ width:
|
||||
in: query
|
||||
required: true
|
||||
type: string
|
||||
action:
|
||||
description: |
|
||||
The name of the action.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
addresses:
|
||||
type: string
|
||||
description: |
|
||||
@ -187,6 +199,24 @@ command:
|
||||
Send command to the container.
|
||||
in: body
|
||||
type: string
|
||||
container_action:
|
||||
description: |
|
||||
The container action object.
|
||||
in: body
|
||||
required: true
|
||||
type: object
|
||||
container_action_events:
|
||||
description: |
|
||||
The events occurred in this action.
|
||||
in: body
|
||||
required: true
|
||||
type: array
|
||||
container_actions:
|
||||
description: |
|
||||
List of the actions for the given container.
|
||||
in: body
|
||||
required: true
|
||||
type: array
|
||||
container_list:
|
||||
type: array
|
||||
in: body
|
||||
@ -240,6 +270,54 @@ environment:
|
||||
The environment variables.
|
||||
in: body
|
||||
type: array
|
||||
event:
|
||||
description: |
|
||||
The name of the event.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
event_finish_time:
|
||||
description: |
|
||||
The date and time when the event was finished. The date and time
|
||||
stamp format is `ISO 8601 <https://en.wikipedia.org/wiki/ISO_8601>`_
|
||||
|
||||
::
|
||||
|
||||
CCYY-MM-DDThh:mm:ss±hh:mm
|
||||
|
||||
For example, ``2015-08-27T09:49:58-05:00``. The ``±hh:mm``
|
||||
value, if included, is the time zone as an offset from UTC. In
|
||||
the previous example, the offset value is ``-05:00``.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
event_result:
|
||||
description: |
|
||||
The result of the event.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
event_start_time:
|
||||
description: |
|
||||
The date and time when the event was started. The date and time
|
||||
stamp format is `ISO 8601 <https://en.wikipedia.org/wiki/ISO_8601>`_
|
||||
|
||||
::
|
||||
|
||||
CCYY-MM-DDThh:mm:ss±hh:mm
|
||||
|
||||
For example, ``2015-08-27T09:49:58-05:00``. The ``±hh:mm``
|
||||
value, if included, is the time zone as an offset from UTC. In
|
||||
the previous example, the offset value is ``-05:00``.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
event_traceback:
|
||||
description: |
|
||||
The traceback stack if error occurred in this event.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
exec_exit_code:
|
||||
description: |
|
||||
The exit code of the command executed in a container.
|
||||
@ -346,6 +424,12 @@ memory:
|
||||
The container memory size in MiB.
|
||||
in: body
|
||||
type: integer
|
||||
message:
|
||||
description: |
|
||||
The error message message about this action when error occurred.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
name:
|
||||
description: |
|
||||
The name of the container.
|
||||
@ -394,6 +478,12 @@ ports:
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
project_id_container_action:
|
||||
description: |
|
||||
The UUID of the project that this container belongs to.
|
||||
in: body
|
||||
required: ture
|
||||
type: string
|
||||
ps_output:
|
||||
description: |
|
||||
The output of zun top.
|
||||
@ -406,6 +496,12 @@ report_count:
|
||||
in: body
|
||||
required: true
|
||||
type: integer
|
||||
request_id_body:
|
||||
description: |
|
||||
The request id generated when execute the API of this action.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
restart_policy:
|
||||
description: |
|
||||
Restart policy to apply when a container exits. Allowed values are
|
||||
@ -436,6 +532,21 @@ services:
|
||||
in: body
|
||||
required: true
|
||||
type: array
|
||||
start_time:
|
||||
description: |
|
||||
The date and time when the action was started. The date and time
|
||||
stamp format is `ISO 8601 <https://en.wikipedia.org/wiki/ISO_8601>`_
|
||||
|
||||
::
|
||||
|
||||
CCYY-MM-DDThh:mm:ss±hh:mm
|
||||
|
||||
For example, ``2015-08-27T09:49:58-05:00``. The ``±hh:mm``
|
||||
value, if included, is the time zone as an offset from UTC. In
|
||||
the previous example, the offset value is ``-05:00``.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
stat:
|
||||
description: |
|
||||
The stat information when doing get_archive.
|
||||
@ -506,6 +617,12 @@ updated_at:
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
user_id:
|
||||
description: |
|
||||
The user ID of the user who owns the container.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
uuid:
|
||||
description: |
|
||||
UUID of the resource.
|
||||
|
18
api-ref/source/samples/container-action-get-resp.json
Normal file
18
api-ref/source/samples/container-action-get-resp.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"action": "create",
|
||||
"events": [
|
||||
{
|
||||
"event": "container__do_container_start",
|
||||
"finish_time": "2018-03-04 17:03:07+00:00",
|
||||
"result": "Success",
|
||||
"start_time": "2018-03-04 17:02:57+00:00",
|
||||
"traceback": null
|
||||
}
|
||||
],
|
||||
"container_uuid": "b48316c5-71e8-45e4-9884-6c78055b9b13",
|
||||
"message": null,
|
||||
"project_id": "853719b303ef4858a195535eb520e58d",
|
||||
"request_id": "req-3293a3f1-b44c-4609-b8d2-d81b105636b8",
|
||||
"start_time": "2018-03-04 17:02:54+00:00",
|
||||
"user_id": "22e81669093742b7a74b1d715a9a5813"
|
||||
}
|
21
api-ref/source/samples/container-actions-list-resp.json
Normal file
21
api-ref/source/samples/container-actions-list-resp.json
Normal file
@ -0,0 +1,21 @@
|
||||
[
|
||||
{
|
||||
"action": "create",
|
||||
"container_uuid": "b48316c5-71e8-45e4-9884-6c78055b9b13",
|
||||
"message": null,
|
||||
"project_id": "853719b303ef4858a195535eb520e58d",
|
||||
"request_id": "req-25517360-b757-47d3-be45-0e8d2a01b36a",
|
||||
"start_time": "2018-03-04 19:48:49+00:00",
|
||||
"user_id": "22e81669093742b7a74b1d715a9a5813"
|
||||
},
|
||||
{
|
||||
"action": "stop",
|
||||
"container_uuid": "b48316c5-71e8-45e4-9884-6c78055b9b13",
|
||||
"message": null,
|
||||
"project_id": "853719b303ef4858a195535eb520e58d",
|
||||
"request_id": "req-3293a3f1-b44c-4609-b8d2-d81b105636b8",
|
||||
"start_time": "2018-03-04 17:02:54+00:00",
|
||||
"user_id": "22e81669093742b7a74b1d715a9a5813"
|
||||
}
|
||||
]
|
||||
|
@ -74,6 +74,82 @@ class ContainerCollection(collection.Collection):
|
||||
return collection
|
||||
|
||||
|
||||
class ContainersActionsController(base.Controller):
|
||||
"""Controller for Container Actions."""
|
||||
|
||||
def __init__(self):
|
||||
super(ContainersActionsController, self).__init__()
|
||||
self._action_keys = ['action', 'container_uuid', 'request_id',
|
||||
'user_id', 'project_id', 'start_time',
|
||||
'message']
|
||||
self._event_keys = ['event', 'start_time', 'finish_time', 'result',
|
||||
'traceback']
|
||||
|
||||
def _format_action(self, action_raw):
|
||||
action = {}
|
||||
action_dict = action_raw.as_dict()
|
||||
for key in self._action_keys:
|
||||
action[key] = action_dict.get(key)
|
||||
return action
|
||||
|
||||
def _format_event(self, event_raw, show_traceback=False):
|
||||
event = {}
|
||||
event_dict = event_raw.as_dict()
|
||||
for key in self._event_keys:
|
||||
# By default, non-admins are not allowed to see traceback details.
|
||||
if key == 'traceback' and not show_traceback:
|
||||
event['traceback'] = None
|
||||
continue
|
||||
event[key] = event_dict.get(key)
|
||||
return event
|
||||
|
||||
@pecan.expose('json')
|
||||
@exception.wrap_pecan_controller_exception
|
||||
def get_all(self, container_ident, **kwargs):
|
||||
"""Retrieve a list of container actions."""
|
||||
context = pecan.request.context
|
||||
policy.enforce(context, "container:actions",
|
||||
action="container:actions")
|
||||
container = utils.get_container(container_ident)
|
||||
actions_raw = objects.ContainerAction.get_by_container_uuid(
|
||||
context, container.uuid)
|
||||
actions = [self._format_action(action) for action in actions_raw]
|
||||
|
||||
return actions
|
||||
|
||||
@pecan.expose('json')
|
||||
@exception.wrap_pecan_controller_exception
|
||||
def get_one(self, container_ident, request_ident, **kwargs):
|
||||
"""Retrieve information about the action."""
|
||||
|
||||
context = pecan.request.context
|
||||
policy.enforce(context, "container:actions",
|
||||
action="container:actions")
|
||||
container = utils.get_container(container_ident)
|
||||
action = objects.ContainerAction.get_by_request_id(
|
||||
context, container.uuid, request_ident)
|
||||
|
||||
if action is None:
|
||||
raise exception.ResourceNotFound(name="Action", id=request_ident)
|
||||
|
||||
action_id = action.id
|
||||
if CONF.database.backend == 'etcd':
|
||||
# etcd using action.uuid get the unique action instead of action.id
|
||||
action_id = action.uuid
|
||||
|
||||
action = self._format_action(action)
|
||||
show_traceback = False
|
||||
if policy.enforce(context, "container:action:events",
|
||||
do_raise=False, action="container:action:events"):
|
||||
show_traceback = True
|
||||
|
||||
events_raw = objects.ContainerActionEvent.get_by_action(context,
|
||||
action_id)
|
||||
action['events'] = [self._format_event(evt, show_traceback)
|
||||
for evt in events_raw]
|
||||
return action
|
||||
|
||||
|
||||
class ContainersController(base.Controller):
|
||||
"""Controller for Containers."""
|
||||
|
||||
@ -102,6 +178,8 @@ class ContainersController(base.Controller):
|
||||
'remove_security_group': ['POST']
|
||||
}
|
||||
|
||||
container_actions = ContainersActionsController()
|
||||
|
||||
@pecan.expose('json')
|
||||
@exception.wrap_pecan_controller_exception
|
||||
def get_all(self, **kwargs):
|
||||
|
@ -15,6 +15,7 @@ import itertools
|
||||
from zun.common.policies import base
|
||||
from zun.common.policies import capsule
|
||||
from zun.common.policies import container
|
||||
from zun.common.policies import container_action
|
||||
from zun.common.policies import host
|
||||
from zun.common.policies import image
|
||||
from zun.common.policies import network
|
||||
@ -29,5 +30,6 @@ def list_rules():
|
||||
zun_service.list_rules(),
|
||||
host.list_rules(),
|
||||
capsule.list_rules(),
|
||||
network.list_rules()
|
||||
network.list_rules(),
|
||||
container_action.list_rules()
|
||||
)
|
||||
|
53
zun/common/policies/container_action.py
Normal file
53
zun/common/policies/container_action.py
Normal file
@ -0,0 +1,53 @@
|
||||
# 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.
|
||||
|
||||
from oslo_policy import policy
|
||||
|
||||
from zun.common.policies import base
|
||||
|
||||
ACTION = 'container:actions'
|
||||
EVENT = 'container:action:events'
|
||||
|
||||
rules = [
|
||||
policy.DocumentedRuleDefault(
|
||||
name=ACTION,
|
||||
check_str=base.RULE_ADMIN_OR_OWNER,
|
||||
description='List actions and show action details for a container',
|
||||
operations=[
|
||||
{
|
||||
'path': '/v1/containers/{container_ident}/container_actions/',
|
||||
'method': 'GET'
|
||||
},
|
||||
{
|
||||
'path': '/v1/containers/{container_ident}/container_actions/'
|
||||
'{request_id}',
|
||||
'method': 'GET'
|
||||
}
|
||||
]
|
||||
),
|
||||
policy.DocumentedRuleDefault(
|
||||
name=EVENT,
|
||||
check_str=base.RULE_ADMIN_API,
|
||||
description="Add events details in action details for a container.",
|
||||
operations=[
|
||||
{
|
||||
'path': '/v1/containers/{container_ident}/container_actions/'
|
||||
'{request_id}',
|
||||
'method': 'GET'
|
||||
}
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
def list_rules():
|
||||
return rules
|
@ -1891,3 +1891,180 @@ class TestContainerEnforcement(api_base.FunctionalTest):
|
||||
self._owner_check('container:%s' % action, self.post_json,
|
||||
'/containers/%s/%s/' % (container.uuid, action),
|
||||
{}, expect_errors=True)
|
||||
|
||||
|
||||
class TestContainerActionController(api_base.FunctionalTest):
|
||||
|
||||
def _format_action(self, action, expect_traceback=True):
|
||||
'''Remove keys that aren't serialized.'''
|
||||
to_delete = ('id', 'finish_time', 'created_at', 'updated_at',
|
||||
'deleted_at', 'deleted')
|
||||
for key in to_delete:
|
||||
if key in action:
|
||||
del (action[key])
|
||||
for event in action.get('events', []):
|
||||
self._format_event(event, expect_traceback)
|
||||
return action
|
||||
|
||||
def _format_event(self, event, expect_traceback=True):
|
||||
'''Remove keys that aren't serialized.'''
|
||||
to_delete = ['id', 'created_at', 'updated_at', 'deleted_at', 'deleted',
|
||||
'action_id']
|
||||
if not expect_traceback:
|
||||
event['traceback'] = None
|
||||
for key in to_delete:
|
||||
if key in event:
|
||||
del (event[key])
|
||||
return event
|
||||
|
||||
@mock.patch('zun.objects.Container.get_by_uuid')
|
||||
@mock.patch('zun.objects.ContainerAction.get_by_container_uuid')
|
||||
def test_list_actions(self, mock_get_by_container_uuid,
|
||||
mock_container_get_by_uuid):
|
||||
test_container = utils.get_test_container()
|
||||
test_action = utils.get_test_action_value(
|
||||
container_uuid=test_container['uuid'])
|
||||
|
||||
container_object = objects.Container(self.context, **test_container)
|
||||
action_object = objects.ContainerAction(self.context, **test_action)
|
||||
|
||||
mock_container_get_by_uuid.return_value = container_object
|
||||
mock_get_by_container_uuid.return_value = [action_object]
|
||||
response = self.get('/v1/containers/%s/container_actions' %
|
||||
test_container['uuid'])
|
||||
|
||||
mock_get_by_container_uuid.assert_called_once_with(
|
||||
mock.ANY,
|
||||
test_container['uuid'])
|
||||
|
||||
self.assertEqual(200, response.status_int)
|
||||
self.assertEqual(self._format_action(test_action),
|
||||
self._format_action(response.json[0]))
|
||||
|
||||
@mock.patch('zun.objects.Container.get_by_uuid')
|
||||
@mock.patch('zun.common.policy.enforce')
|
||||
@mock.patch('zun.objects.ContainerActionEvent.get_by_action')
|
||||
@mock.patch('zun.objects.ContainerAction.get_by_request_id')
|
||||
def test_get_action_with_events_allowed(self, mock_get_by_request_id,
|
||||
mock_get_by_action, mock_policy,
|
||||
mock_container_get_by_uuid):
|
||||
mock_policy.return_value = True
|
||||
test_container = utils.get_test_container()
|
||||
test_action = utils.get_test_action_value(
|
||||
container_uuid=test_container['uuid'])
|
||||
test_event = utils.get_test_action_event_value(
|
||||
action_id=test_action['id'])
|
||||
test_action['events'] = [test_event]
|
||||
|
||||
container_object = objects.Container(self.context, **test_container)
|
||||
action_object = objects.ContainerAction(self.context, **test_action)
|
||||
event_object = objects.ContainerActionEvent(self.context, **test_event)
|
||||
|
||||
mock_container_get_by_uuid.return_value = container_object
|
||||
mock_get_by_request_id.return_value = action_object
|
||||
mock_get_by_action.return_value = [event_object]
|
||||
|
||||
response = self.get('/v1/containers/%s/container_actions/%s' % (
|
||||
test_container['uuid'], test_action['request_id']))
|
||||
|
||||
mock_get_by_request_id.assert_called_once_with(
|
||||
mock.ANY, test_container['uuid'], test_action['request_id'])
|
||||
mock_get_by_action.assert_called_once_with(mock.ANY, test_action['id'])
|
||||
|
||||
self.assertEqual(200, response.status_int)
|
||||
self.assertEqual(self._format_action(test_action),
|
||||
self._format_action(response.json))
|
||||
|
||||
@mock.patch('zun.objects.Container.get_by_uuid')
|
||||
@mock.patch('zun.common.policy.enforce')
|
||||
@mock.patch('zun.objects.ContainerActionEvent.get_by_action')
|
||||
@mock.patch('zun.objects.ContainerAction.get_by_request_id')
|
||||
def test_get_action_with_events_not_allowed(self, mock_get_by_request_id,
|
||||
mock_get_by_action,
|
||||
mock_policy,
|
||||
mock_container_get_by_uuid):
|
||||
mock_policy.return_value = False
|
||||
test_container = utils.get_test_container()
|
||||
container_obj = objects.Container(self.context, **test_container)
|
||||
test_action = utils.get_test_action_value(
|
||||
container_uuid=test_container['uuid'])
|
||||
test_event = utils.get_test_action_event_value(
|
||||
action_id=test_action['id'])
|
||||
test_action['events'] = [test_event]
|
||||
action_object = objects.ContainerAction(self.context, **test_action)
|
||||
event_object = objects.ContainerActionEvent(self.context, **test_event)
|
||||
|
||||
mock_container_get_by_uuid.return_value = container_obj
|
||||
mock_get_by_request_id.return_value = action_object
|
||||
mock_get_by_action.return_value = [event_object]
|
||||
|
||||
response = self.get('/v1/containers/%s/container_actions/%s' % (
|
||||
test_container['uuid'], test_action['request_id']))
|
||||
|
||||
mock_get_by_request_id.assert_called_once_with(
|
||||
mock.ANY, test_container['uuid'], test_action['request_id'])
|
||||
mock_get_by_action.assert_called_once_with(mock.ANY, test_action['id'])
|
||||
|
||||
self.assertEqual(200, response.status_int)
|
||||
self.assertEqual(self._format_action(test_action,
|
||||
expect_traceback=False),
|
||||
self._format_action(response.json))
|
||||
|
||||
@mock.patch('zun.objects.Container.get_by_uuid')
|
||||
@mock.patch('zun.objects.ContainerAction.get_by_request_id')
|
||||
def test_action_not_found(self, mock_get_by_request_id,
|
||||
mock_container_get_by_uuid):
|
||||
|
||||
test_container = utils.get_test_container()
|
||||
container_obj = objects.Container(self.context, **test_container)
|
||||
|
||||
mock_container_get_by_uuid.return_value = container_obj
|
||||
mock_get_by_request_id.return_value = None
|
||||
|
||||
fake_request_id = 'request'
|
||||
|
||||
self.assertRaises(AppError, self.get,
|
||||
('/v1/containers/%s/container_actions/%s' %
|
||||
(test_container['uuid'], fake_request_id)))
|
||||
mock_get_by_request_id.assert_called_once_with(
|
||||
mock.ANY, test_container['uuid'], fake_request_id)
|
||||
|
||||
@mock.patch('zun.objects.Container.get_by_uuid')
|
||||
def test_container_not_found(self, mock_container_get_by_uuid):
|
||||
test_container = utils.get_test_container()
|
||||
|
||||
self.assertRaises(AppError, self.get,
|
||||
('/v1/containers/%s/container_actions'
|
||||
% test_container['uuid']))
|
||||
mock_container_get_by_uuid.assert_called_once_with(
|
||||
mock.ANY, test_container['uuid'])
|
||||
|
||||
|
||||
class TestContainerActionEnforcement(api_base.FunctionalTest):
|
||||
|
||||
def _common_policy_check(self, rule, func, *arg, **kwarg):
|
||||
rules = dict({rule: 'project_id:non_fake'},
|
||||
**kwarg.pop('bypass_rules', {}))
|
||||
self.policy.set_rules(rules)
|
||||
response = func(*arg, **kwarg)
|
||||
self.assertEqual(403, response.status_int)
|
||||
self.assertEqual('application/json', response.content_type)
|
||||
self.assertEqual(
|
||||
"Policy doesn't allow %s to be performed." % rule,
|
||||
response.json['errors'][0]['detail'])
|
||||
|
||||
def test_list_actions_disallow_by_project(self):
|
||||
container = obj_utils.create_test_container(self.context)
|
||||
|
||||
self._common_policy_check(
|
||||
'container:actions', self.get,
|
||||
'/v1/containers/%s/container_actions/' % container.uuid,
|
||||
expect_errors=True)
|
||||
|
||||
def test_get_action_disallow_by_project(self):
|
||||
container = obj_utils.create_test_container(self.context)
|
||||
|
||||
self._common_policy_check(
|
||||
'container:actions', self.get,
|
||||
'/v1/containers/%s/container_actions/fake_request' %
|
||||
container.uuid, expect_errors=True)
|
||||
|
@ -439,7 +439,7 @@ class FakeObject(object):
|
||||
return getattr(self, key)
|
||||
|
||||
|
||||
def get_test_action(**kwargs):
|
||||
def get_test_action_value(**kwargs):
|
||||
action_values = {
|
||||
'created_at': kwargs.get('created_at'),
|
||||
'updated_at': kwargs.get('updated_at'),
|
||||
@ -455,13 +455,19 @@ def get_test_action(**kwargs):
|
||||
'message': kwargs.get('message', 'fake-message'),
|
||||
}
|
||||
|
||||
return action_values
|
||||
|
||||
|
||||
def get_test_action(**kwargs):
|
||||
|
||||
action_values = get_test_action_value(**kwargs)
|
||||
fake_action = FakeObject()
|
||||
for k, v in action_values.items():
|
||||
setattr(fake_action, k, v)
|
||||
return fake_action
|
||||
|
||||
|
||||
def get_test_action_event(**kwargs):
|
||||
def get_test_action_event_value(**kwargs):
|
||||
|
||||
event_values = {
|
||||
'created_at': kwargs.get('created_at'),
|
||||
@ -475,6 +481,12 @@ def get_test_action_event(**kwargs):
|
||||
'traceback': kwargs.get('traceback', 'fake-tb'),
|
||||
}
|
||||
|
||||
return event_values
|
||||
|
||||
|
||||
def get_test_action_event(**kwargs):
|
||||
|
||||
event_values = get_test_action_event_value(**kwargs)
|
||||
fake_event = FakeObject()
|
||||
for k, v in event_values.items():
|
||||
setattr(fake_event, k, v)
|
||||
|
Loading…
x
Reference in New Issue
Block a user