Add REST APIs for Keystone Group

This patch adds REST APIs (read, create, edit, delete)
for Keystone Group.

Change-Id: I9ca3b509bcd6ab3f255094fa367f9b236caf13da
Partially-Implements: blueprint ng-groups
Co-Authored-By: Shu Muto <shu-mutou@rf.jp.nec.com>
This commit is contained in:
Cindy Lu 2016-09-14 10:52:36 -07:00 committed by Shu Muto
parent 872ea43d65
commit 924fb68645
4 changed files with 260 additions and 1 deletions

View File

@ -589,3 +589,69 @@ class Groups(generic.View):
request, domain=request.GET.get('domain_id', domain_context))] request, domain=request.GET.get('domain_id', domain_context))]
return {'items': items} return {'items': items}
@rest_utils.ajax(data_required=True)
def post(self, request):
"""Create a group.
This action creates a group using parameters supplied in the POST
application/json object. The "name" (string) parameter is required,
"description" (string) is optional.
This method returns the new group object on success.
"""
domain_context = request.session.get('domain_context')
new_group = api.keystone.group_create(
request,
request.GET.get('domain_id', domain_context),
request.DATA['name'],
request.DATA.get("description", None))
return rest_utils.CreatedResponse(
'/api/keystone/groups/%s' % new_group.id,
new_group.to_dict()
)
@rest_utils.ajax(data_required=True)
def delete(self, request):
"""Delete multiple groups by id.
The DELETE data should be an application/json array of group ids to
delete.
This method returns HTTP 204 (no content) on success.
"""
for group_id in request.DATA:
api.keystone.group_delete(request, group_id)
@urls.register
class Group(generic.View):
"""API over a single group."""
url_regex = r'keystone/groups/(?P<id>[0-9a-f]+)$'
@rest_utils.ajax()
def get(self, request, id):
"""Get a specific group by id."""
return api.keystone.group_get(request, id).to_dict()
@rest_utils.ajax()
def delete(self, request, id):
"""Delete a single group by id.
This method returns HTTP 204 (no content) on success.
"""
api.keystone.group_delete(request, id)
@rest_utils.ajax(data_required=True)
def patch(self, request, id):
"""Update a single group.
The PATCH data should be an application/json object with the
"name" and "description" attribute to update.
This method returns HTTP 204 (no content) on success.
"""
api.keystone.group_update(request, id,
request.DATA['name'],
request.DATA.get("description", None))

View File

@ -58,7 +58,12 @@
grantRole: grantRole, grantRole: grantRole,
serviceCatalog: serviceCatalog, serviceCatalog: serviceCatalog,
getServices: getServices, getServices: getServices,
getGroups: getGroups getGroups: getGroups,
createGroup: createGroup,
getGroup: getGroup,
editGroup: editGroup,
deleteGroup: deleteGroup,
deleteGroups: deleteGroups
}; };
return service; return service;
@ -103,6 +108,7 @@
}); });
} }
// Group
function getGroups() { function getGroups() {
return apiService.get('/api/keystone/groups/') return apiService.get('/api/keystone/groups/')
.error(function () { .error(function () {
@ -110,6 +116,42 @@
}); });
} }
function createGroup(newGroup) {
return apiService.post('/api/keystone/groups/', newGroup)
.error(function () {
toastService.add('error', gettext('Unable to create the group.'));
});
}
function getGroup(groupId) {
return apiService.get('/api/keystone/groups/' + groupId)
.error(function () {
toastService.add('error', gettext('Unable to retrieve the group.'));
});
}
function editGroup(updatedGroup) {
var url = '/api/keystone/groups/' + updatedGroup.id;
return apiService.patch(url, updatedGroup)
.error(function () {
toastService.add('error', gettext('Unable to edit the group.'));
});
}
function deleteGroup(groupId) {
return apiService.delete('/api/keystone/groups/' + groupId)
.error(function () {
toastService.add('error', gettext('Unable to delete the group.'));
});
}
function deleteGroups(groupIds) {
return apiService.delete('/api/keystone/groups/', groupIds)
.error(function () {
toastService.add('error', gettext('Unable to delete the groups.'));
});
}
/** /**
* @name getCurrentUserSession * @name getCurrentUserSession
* @param {Object} config - The configuration for which we want a session * @param {Object} config - The configuration for which we want a session

View File

@ -390,6 +390,66 @@
"method": "get", "method": "get",
"path": "/api/keystone/groups/", "path": "/api/keystone/groups/",
"error": "Unable to fetch the groups." "error": "Unable to fetch the groups."
},
{
"func": "createGroup",
"method": "post",
"path": "/api/keystone/groups/",
"data": "new group",
"error": "Unable to create the group.",
"testInput": [
"new group"
]
},
{
"func": "getGroup",
"method": "get",
"path": "/api/keystone/groups/14",
"error": "Unable to retrieve the group.",
"testInput": [
14
]
},
{
"func": "editGroup",
"method": "patch",
"path": "/api/keystone/groups/42",
"data": {
"id": 42
},
"error": "Unable to edit the group.",
"testInput": [
{
"id": 42
}
]
},
{
"func": "deleteGroup",
"method": "delete",
"path": "/api/keystone/groups/14",
"error": "Unable to delete the group.",
"testInput": [
14
]
},
{
"func": "deleteGroups",
"method": "delete",
"path": "/api/keystone/groups/",
"data": [
1,
2,
3
],
"error": "Unable to delete the groups.",
"testInput": [
[
1,
2,
3
]
]
} }
]; ];

View File

@ -692,6 +692,97 @@ class KeystoneRestTestCase(test.TestCase):
{"items": [{"name": "uno!"}, {"name": "dos!"}]}) {"items": [{"name": "uno!"}, {"name": "dos!"}]})
kc.group_list.assert_called_once_with(request, domain='the_domain') kc.group_list.assert_called_once_with(request, domain='the_domain')
@mock.patch.object(keystone.api, 'keystone')
def test_group_create(self, kc):
request = self.mock_rest_request(**{
'session.get': mock.Mock(return_value='the_domain'),
'GET': {},
'body': '{"name": "bug!", "description": "bugaboo!!"}',
})
kc.group_create.return_value.id = 'group789'
kc.group_create.return_value.to_dict.return_value = {
'id': 'group789', 'name': 'bug!', 'description': 'bugaboo!!'
}
response = keystone.Groups().post(request)
self.assertStatusCode(response, 201)
self.assertEqual(response['location'],
'/api/keystone/groups/group789')
self.assertEqual(response.json,
{"id": "group789",
"name": "bug!",
"description": "bugaboo!!"})
kc.group_create.assert_called_once_with(request, 'the_domain',
'bug!', 'bugaboo!!')
@mock.patch.object(keystone.api, 'keystone')
def test_group_create_without_description(self, kc):
request = self.mock_rest_request(**{
'session.get': mock.Mock(return_value='the_domain'),
'GET': {},
'body': '{"name": "bug!"}',
})
kc.group_create.return_value.id = 'group789'
kc.group_create.return_value.to_dict.return_value = {
'id': 'group789', 'name': 'bug!'
}
response = keystone.Groups().post(request)
self.assertStatusCode(response, 201)
self.assertEqual(response['location'],
'/api/keystone/groups/group789')
self.assertEqual(response.json,
{"id": "group789",
"name": "bug!"})
kc.group_create.assert_called_once_with(request, 'the_domain',
'bug!', None)
@mock.patch.object(keystone.api, 'keystone')
def test_group_get(self, kc):
request = self.mock_rest_request()
kc.group_get.return_value.to_dict.return_value = {
'name': 'bug!', 'description': 'bugaboo!!'}
response = keystone.Group().get(request, 'the_id')
self.assertStatusCode(response, 200)
self.assertEqual(response.json, {"name": "bug!",
"description": "bugaboo!!"})
kc.group_get.assert_called_once_with(request, 'the_id')
@mock.patch.object(keystone.api, 'keystone')
def test_group_delete(self, kc):
request = self.mock_rest_request()
response = keystone.Group().delete(request, 'the_id')
self.assertStatusCode(response, 204)
self.assertEqual(response.content, b'')
kc.group_delete.assert_called_once_with(request, 'the_id')
@mock.patch.object(keystone.api, 'keystone')
def test_group_patch(self, kc):
request = self.mock_rest_request(
body='{"name": "spam_i_am", "description": "Sir Spam"}')
response = keystone.Group().patch(request, 'the_id')
self.assertStatusCode(response, 204)
self.assertEqual(response.content, b'')
kc.group_update.assert_called_once_with(request,
'the_id',
'spam_i_am',
'Sir Spam')
@mock.patch.object(keystone.api, 'keystone')
def test_group_delete_many(self, kc):
request = self.mock_rest_request(body='''
["id1", "id2", "id3"]
''')
response = keystone.Groups().delete(request)
self.assertStatusCode(response, 204)
self.assertEqual(response.content, b'')
kc.group_delete.assert_has_calls([
mock.call(request, 'id1'),
mock.call(request, 'id2'),
mock.call(request, 'id3'),
])
# #
# Services # Services
# #