Create user under project_id passed in request

Currently when user is created, its taking the project_id
parameter from the user who is creating the request.
However, given root users are expected to be ablet to create
users for all projects this patch modifies the behaviour
and ensure that the user creation is always under the
project_id parameter that is passed in.

Functional test for create call is added. However,
function test coverage is not complete. It needs to
be addressed as a separate commit, tacked in
issue: 1674287

Closes Bug: 1666695
Partial-Bug: 1674287
Parent: Ie5fac9ef4c305ff7e67fe32855ca8100a8adfa82

Change-Id: I19fb901ad41edeeb0a92f41264867a768a207fce
This commit is contained in:
Sulochan Acharya 2017-03-17 11:24:19 +00:00
parent 9ddf2c4cd5
commit 5f0e8d7622
6 changed files with 84 additions and 35 deletions

View File

@ -5,7 +5,6 @@ from oslo_utils import uuidutils
from craton.api import v1
from craton.api.v1 import base
from craton import db as dbapi
from craton import util
LOG = log.getLogger(__name__)
@ -41,12 +40,14 @@ class Users(base.Resource):
@base.http_codes
def post(self, context, request_data):
"""Create a new user. Requires project admin privileges."""
json = util.copy_project_id_into_json(context, request_data)
project_id = json["project_id"]
# NOTE(sulo): Instead of using context project_id from
# header, here we always ensure, user create gets project_id
# from request param.
project_id = request_data["project_id"]
dbapi.projects_get_by_id(context, project_id)
api_key = uuidutils.generate_uuid()
request_data["api_key"] = api_key
user_obj = dbapi.users_create(context, json)
user_obj = dbapi.users_create(context, request_data)
location = v1.api.url_for(
UserById, id=user_obj.id, _external=True

View File

@ -399,6 +399,7 @@ DefinitionUser = {
DefinitionUserCreate = {
"required": [
"username",
"project_id",
],
"type": "object",
"additionalProperties": False,

View File

@ -9,6 +9,8 @@ import testtools
import threading
from oslo_log import log as logging
from oslo_utils import uuidutils
LOG = logging.getLogger(__name__)
@ -266,6 +268,22 @@ class TestCase(testtools.TestCase):
self.assertJSON(resp)
return resp
def create_project(self, name, headers=None, variables=None):
url = self.url + '/v1/projects'
payload = {'name': name}
if variables:
payload['variables'] = variables
response = self.post(url, headers=headers, data=payload)
self.assertEqual(201, response.status_code)
self.assertIn('Location', response.headers)
project = response.json()
self.assertTrue(uuidutils.is_uuid_like(project['id']))
self.assertEqual(
response.headers['Location'],
"{}/{}".format(url, project['id'])
)
return project
def create_cloud(self, name, variables=None):
url = self.url + '/v1/clouds'

View File

@ -1,7 +1,5 @@
import copy
from oslo_utils import uuidutils
from craton.tests import functional
from craton.tests.functional.test_variable_calls import \
APIV1ResourceWithVariablesTestCase
@ -20,29 +18,13 @@ class ProjectTests(functional.TestCase):
def tearDown(self):
super(ProjectTests, self).tearDown()
def create_project(self, name, variables=None):
url = self.url + '/v1/projects'
payload = {'name': name}
if variables:
payload['variables'] = variables
response = self.post(url, headers=self.root_headers, data=payload)
self.assertEqual(201, response.status_code)
self.assertIn('Location', response.headers)
project = response.json()
self.assertTrue(uuidutils.is_uuid_like(project['id']))
self.assertEqual(
response.headers['Location'],
"{}/{}".format(url, project['id'])
)
return project
class TestPaginationOfProjects(ProjectTests):
def setUp(self):
super(TestPaginationOfProjects, self).setUp()
self.projects = [
self.create_project('project-{}'.format(i))
self.create_project('project-{}'.format(i),
headers=self.root_headers)
for i in range(0, 61)
]
@ -56,7 +38,7 @@ class TestPaginationOfProjects(ProjectTests):
self.assertEqual(30, len(projects))
def test_lists_projects_with_the_same_name(self):
self.create_project('project-0')
self.create_project('project-0', headers=self.root_headers)
response = self.get(self.url + '/v1/projects',
name='project-0',
@ -73,19 +55,22 @@ class APIV1ProjectTest(ProjectTests, APIV1ResourceWithVariablesTestCase):
def test_project_create_with_variables(self):
variables = {'a': 'b'}
project_name = 'test'
project = self.create_project(project_name, variables=variables)
project = self.create_project(project_name,
headers=self.root_headers,
variables=variables)
self.assertEqual(project_name, project['name'])
self.assertEqual(variables, project['variables'])
def test_create_project_supports_vars_ops(self):
project = self.create_project('test', {'a': 'b'})
project = self.create_project('test', headers=self.root_headers,
variables={'a': 'b'})
self.assert_vars_get_expected(project['id'], {'a': 'b'})
self.assert_vars_can_be_set(project['id'])
self.assert_vars_can_be_deleted(project['id'])
def test_project_create_with_duplicate_name_works(self):
project_name = 'test'
self.create_project(project_name)
self.create_project(project_name, headers=self.root_headers)
url = self.url + '/v1/projects'
payload = {'name': project_name}
project = self.post(url, headers=self.root_headers, data=payload)
@ -94,9 +79,9 @@ class APIV1ProjectTest(ProjectTests, APIV1ResourceWithVariablesTestCase):
def test_project_get_all_with_name_filter(self):
proj1 = 'test1'
proj2 = 'test2'
self.create_project(proj2)
self.create_project(proj2, headers=self.root_headers)
for i in range(3):
self.create_project(proj1)
self.create_project(proj1, headers=self.root_headers)
url = self.url + '/v1/projects?name={}'.format(proj1)
resp = self.get(url, headers=self.root_headers)
projects = resp.json()['projects']
@ -107,14 +92,15 @@ class APIV1ProjectTest(ProjectTests, APIV1ResourceWithVariablesTestCase):
def test_get_project_details(self):
project_name = 'test'
project_vars = {"who": "that"}
project = self.create_project(project_name, variables=project_vars)
project = self.create_project(project_name, headers=self.root_headers,
variables=project_vars)
url = self.url + '/v1/projects/{}'.format(project['id'])
project_with_detail = self.get(url, headers=self.root_headers)
self.assertEqual(project_name, project_with_detail.json()['name'])
self.assertEqual(project_vars, project_with_detail.json()['variables'])
def test_project_delete(self):
project1 = self.create_project('test1')
project1 = self.create_project('test1', headers=self.root_headers)
url = self.url + '/v1/projects'
projects = self.get(url, headers=self.root_headers)
# NOTE(thomasem): Have to include the default project created by
@ -129,7 +115,7 @@ class APIV1ProjectTest(ProjectTests, APIV1ResourceWithVariablesTestCase):
def test_project_variables_update(self):
project_name = 'test'
project = self.create_project(project_name)
project = self.create_project(project_name, headers=self.root_headers)
variables = {"bumbleywump": "cucumberpatch"}
put_url = self.url + '/v1/projects/{}/variables'.format(project['id'])
@ -149,6 +135,7 @@ class APIV1ProjectTest(ProjectTests, APIV1ResourceWithVariablesTestCase):
expected_vars = {'foo': 'bar'}
variables.update(expected_vars)
project = self.create_project(project_name, variables=variables)
project = self.create_project(project_name, headers=self.root_headers,
variables=variables)
self.assert_vars_get_expected(project['id'], variables)
self.assert_vars_can_be_deleted(project['id'])

View File

@ -0,0 +1,41 @@
import copy
from craton.tests import functional
class UserTests(functional.TestCase):
def setUp(self):
super(UserTests, self).setUp()
self.root_headers = copy.deepcopy(self.session.headers)
self.root_headers[functional.HEADER_USERNAME] = \
functional.FAKE_DATA_GEN_BOOTSTRAP_USERNAME
self.root_headers[functional.HEADER_TOKEN] = \
functional.FAKE_DATA_GEN_BOOTSTRAP_TOKEN
def tearDown(self):
super(UserTests, self).tearDown()
def test_create_user(self):
project = self.create_project('test', headers=self.root_headers)
url = self.url + '/v1/users'
payload = {'username': 'testuser', 'project_id': project['id']}
user = self.post(url, data=payload)
self.assertEqual(201, user.status_code)
self.assertEqual(payload['username'], user.json()['username'])
self.assertEqual(payload['project_id'], user.json()['project_id'])
def test_create_user_with_admin_priv(self):
project = self.create_project('test', headers=self.root_headers)
url = self.url + '/v1/users'
payload = {'username': 'testuser', 'project_id': project['id'],
'is_admin': True}
user = self.post(url, headers=self.root_headers, data=payload)
self.assertEqual(201, user.status_code)
self.assertEqual(payload['username'], user.json()['username'])
self.assertEqual(payload['is_admin'], user.json()['is_admin'])
def test_create_user_with_no_project_id_fails(self):
url = self.url + '/v1/users'
payload = {'username': 'testuser'}
user = self.post(url, headers=self.root_headers, data=payload)
self.assertEqual(400, user.status_code)

View File

@ -1241,7 +1241,8 @@ class APIV1UsersTest(APIV1Test):
def test_create_users(self, mock_project, mock_user):
mock_project.return_value = {'id': project_id1, 'name': 'project1'}
mock_user.return_value = fake_resources.USER1
data = {'username': 'user1', 'is_admin': False}
data = {'username': 'user1', 'is_admin': False,
'project_id': project_id1}
resp = self.post('v1/users', data=data)
self.assertEqual(resp.status_code, 201)
self.assertEqual(resp.json['id'], 1)