Trove user page doesn't show allowed hosts AND databases

When creating a user with a --host parameter the database field
is not shown in the UI. Added code to support the host parameter
when modifying access to the database and when requesting user
access list.

Change-Id: I16293e9e220ce51e588f60a79ed28752cb89a6cc
Closes-Bug: #1615672
This commit is contained in:
Ali Asgar Adil
2016-08-22 10:52:38 -04:00
committed by Ali Adil
parent 265795c352
commit 2597c95de7
7 changed files with 86 additions and 69 deletions

View File

@@ -288,8 +288,8 @@ def user_create(request, instance_id, username, password,
return troveclient(request).users.create(instance_id, [user]) return troveclient(request).users.create(instance_id, [user])
def user_delete(request, instance_id, user): def user_delete(request, instance_id, user, host=None):
return troveclient(request).users.delete(instance_id, user) return troveclient(request).users.delete(instance_id, user, hostname=host)
def user_update_attributes(request, instance_id, name, host=None, def user_update_attributes(request, instance_id, name, host=None,
@@ -320,6 +320,11 @@ def user_revoke_access(request, instance_id, username, database, host=None):
instance_id, username, database, hostname=host) instance_id, username, database, hostname=host)
def user_show_access(request, instance_id, username, host=None):
return troveclient(request).users.list_access(
instance_id, username, hostname=host)
def datastore_list(request): def datastore_list(request):
return troveclient(request).datastores.list() return troveclient(request).datastores.list()

View File

@@ -199,7 +199,7 @@ class EditUserForm(forms.SelfHandlingForm):
user_name = forms.CharField( user_name = forms.CharField(
label=_("Name"), label=_("Name"),
widget=forms.TextInput(attrs={'readonly': 'readonly'})) widget=forms.TextInput(attrs={'readonly': 'readonly'}))
host = forms.CharField( user_host = forms.CharField(
label=_("Host"), required=False, label=_("Host"), required=False,
widget=forms.TextInput(attrs={'readonly': 'readonly'})) widget=forms.TextInput(attrs={'readonly': 'readonly'}))
new_name = forms.CharField(label=_("New Name"), required=False) new_name = forms.CharField(label=_("New Name"), required=False)
@@ -220,7 +220,7 @@ class EditUserForm(forms.SelfHandlingForm):
request, request,
instance, instance,
data['user_name'], data['user_name'],
host=data['host'], host=data['user_host'],
new_name=data['new_name'], new_name=data['new_name'],
new_password=data['new_password'], new_password=data['new_password'],
new_host=data['new_host']) new_host=data['new_host'])

View File

@@ -17,7 +17,7 @@ import six.moves.urllib.parse as urlparse
from django.conf import settings from django.conf import settings
from django.core import urlresolvers from django.core import urlresolvers
from django.template import defaultfilters as d_filters from django.template import defaultfilters as d_filters
from django.utils import http
from django.utils.translation import pgettext_lazy from django.utils.translation import pgettext_lazy
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ungettext_lazy from django.utils.translation import ungettext_lazy
@@ -197,7 +197,7 @@ class GrantAccess(tables.BatchAction):
self.table.kwargs['instance_id'], self.table.kwargs['instance_id'],
self.table.kwargs['user_name'], self.table.kwargs['user_name'],
[obj_id], [obj_id],
host=parse_host_param(request)) host=self.table.kwargs['user_host'])
class RevokeAccess(tables.BatchAction): class RevokeAccess(tables.BatchAction):
@@ -231,7 +231,7 @@ class RevokeAccess(tables.BatchAction):
self.table.kwargs['instance_id'], self.table.kwargs['instance_id'],
self.table.kwargs['user_name'], self.table.kwargs['user_name'],
obj_id, obj_id,
host=parse_host_param(request)) host=self.table.kwargs['user_host'])
def parse_host_param(request): def parse_host_param(request):
@@ -273,13 +273,9 @@ class ManageAccess(tables.LinkAction):
def get_link_url(self, datum): def get_link_url(self, datum):
user = datum user = datum
url = urlresolvers.reverse(self.url, args=[user.instance.id, return urlresolvers.reverse(self.url, args=[user.instance.id,
user.name]) user.name,
if user.host: user.host])
params = http.urlencode({"host": user.host})
url = "?".join([url, params])
return url
class CreateUser(tables.LinkAction): class CreateUser(tables.LinkAction):
@@ -313,13 +309,9 @@ class EditUser(tables.LinkAction):
def get_link_url(self, datum): def get_link_url(self, datum):
user = datum user = datum
url = urlresolvers.reverse(self.url, args=[user.instance.id, return urlresolvers.reverse(self.url, args=[user.instance.id,
user.name]) user.name,
if user.host: user.host])
params = http.urlencode({"host": user.host})
url = "?".join([url, params])
return url
def has_user_add_perm(request): def has_user_add_perm(request):
@@ -347,8 +339,9 @@ class DeleteUser(tables.DeleteAction):
) )
def delete(self, request, obj_id): def delete(self, request, obj_id):
datum = self.table.get_object_by_id(obj_id) user = self.table.get_object_by_id(obj_id)
api.trove.user_delete(request, datum.instance.id, datum.name) api.trove.user_delete(request, user.instance.id, user.name,
host=user.host)
class CreateDatabase(tables.LinkAction): class CreateDatabase(tables.LinkAction):

View File

@@ -82,7 +82,8 @@ class UserTab(tabs.TableTab):
try: try:
user.access = api.trove.user_list_access(self.request, user.access = api.trove.user_list_access(self.request,
instance.id, instance.id,
user.name) user.name,
host=user.host)
except exceptions.NOT_FOUND: except exceptions.NOT_FOUND:
pass pass
except Exception: except Exception:

View File

@@ -624,9 +624,10 @@ class DatabaseTests(test.TestCase):
self.assertEqual(table.data[0].enabled, True) self.assertEqual(table.data[0].enabled, True)
self.assertEqual(table.data[0].password, "password") self.assertEqual(table.data[0].password, "password")
@test.create_stubs( @test.create_stubs({
{api.trove: ('instance_get', 'flavor_get', 'users_list', api.trove: ('instance_get', 'flavor_get', 'user_delete', 'users_list',
'user_list_access', 'user_delete')}) 'user_list_access')
})
def test_user_delete(self): def test_user_delete(self):
database = self.databases.first() database = self.databases.first()
user = self.database_users.first() user = self.database_users.first()
@@ -644,15 +645,16 @@ class DatabaseTests(test.TestCase):
# tabs.py: UserTab.get_user_data # tabs.py: UserTab.get_user_data
api.trove.users_list(IsA(http.HttpRequest), api.trove.users_list(IsA(http.HttpRequest),
database_id).AndReturn([user]) IsA(str)).AndReturn([user])
api.trove.user_list_access(IsA(http.HttpRequest), api.trove.user_list_access(IsA(http.HttpRequest),
database_id, IsA(str),
user_id).AndReturn([user_db]) IsA(str),
host=IsA(str)).AndReturn([user_db])
# tables.py: DeleteUser.delete # tables.py: DeleteUser.delete
api.trove.user_delete(IsA(http.HttpRequest), api.trove.user_delete(IsA(http.HttpRequest),
database_id, IsA(six.text_type),
user_id).AndReturn(None) IsA(six.text_type)).AndReturn(None)
self.mox.ReplayAll() self.mox.ReplayAll()
@@ -726,18 +728,19 @@ class DatabaseTests(test.TestCase):
user = self.users.first() user = self.users.first()
api.trove.user_update_attributes( api.trove.user_update_attributes(
IsA(http.HttpRequest), database.id, user.name, host=u'', IsA(http.HttpRequest), IsA(six.text_type), IsA(six.text_type),
new_name=u'new_name', new_password=u'new_password', host=IsA(six.text_type), new_name=IsA(six.text_type),
new_host=u'127.0.0.1') new_password=IsA(six.text_type), new_host=IsA(six.text_type))
self.mox.ReplayAll() self.mox.ReplayAll()
url = reverse('horizon:project:databases:edit_user', url = reverse('horizon:project:databases:edit_user',
args=[database.id, user.name]) args=[database.id, user.name, '%'])
post = { post = {
'method': 'EditUserForm', 'method': 'EditUserForm',
'instance_id': database.id, 'instance_id': database.id,
'user_name': user.name, 'user_name': user.name,
'user_host': '%',
'new_name': 'new_name', 'new_name': 'new_name',
'new_password': 'new_password', 'new_password': 'new_password',
'new_host': '127.0.0.1'} 'new_host': '127.0.0.1'}
@@ -752,20 +755,20 @@ class DatabaseTests(test.TestCase):
user = self.users.first() user = self.users.first()
api.trove.user_update_attributes( api.trove.user_update_attributes(
IsA(http.HttpRequest), database.id, user.name, host=u'', IsA(http.HttpRequest), IsA(six.text_type), IsA(six.text_type),
new_name=u'new_name', new_password=u'new_password', host=IsA(six.text_type), new_name=IsA(six.text_type),
new_host=u'127.0.0.1') \ new_password=IsA(six.text_type), new_host=IsA(six.text_type))
.AndRaise(self.exceptions.trove)
self.mox.ReplayAll() self.mox.ReplayAll()
url = reverse('horizon:project:databases:edit_user', url = reverse('horizon:project:databases:edit_user',
args=[database.id, user.name]) args=[database.id, user.name, '%'])
post = { post = {
'method': 'EditUserForm', 'method': 'EditUserForm',
'instance_id': database.id, 'instance_id': database.id,
'user_name': user.name, 'user_name': user.name,
'new_name': 'new_name', 'new_name': 'new_name',
'user_host': '%',
'new_password': 'new_password', 'new_password': 'new_password',
'new_host': '127.0.0.1'} 'new_host': '127.0.0.1'}
@@ -777,60 +780,66 @@ class DatabaseTests(test.TestCase):
user = self.users.first() user = self.users.first()
url = reverse('horizon:project:databases:edit_user', url = reverse('horizon:project:databases:edit_user',
args=[database.id, user.name]) args=[database.id, user.name, '%'])
post = { post = {
'method': 'EditUserForm', 'method': 'EditUserForm',
'instance_id': database.id, 'instance_id': database.id,
'user_name': user.name} 'user_name': user.name,
'user_host': '%'}
res = self.client.post(url, post) res = self.client.post(url, post)
msg = forms.EditUserForm.validation_error_message msg = forms.EditUserForm.validation_error_message
self.assertFormError(res, "form", None, [msg]) self.assertFormError(res, "form", None, [msg])
@test.create_stubs({api.trove: ('database_list', 'user_list_access')}) @test.create_stubs({api.trove: ('database_list', 'user_show_access')})
def test_access_detail_get(self): def test_access_detail_get(self):
api.trove.database_list(IsA(http.HttpRequest), u'id') \ api.trove.database_list(IsA(http.HttpRequest), IsA(six.text_type)) \
.AndReturn(self.databases.list()) .AndReturn(self.databases.list())
api.trove.user_list_access(IsA(http.HttpRequest), u'id', u'name') \ api.trove.user_show_access(IsA(http.HttpRequest), IsA(six.text_type),
IsA(six.text_type),
host=IsA(six.text_type)) \
.AndReturn(self.databases.list()) .AndReturn(self.databases.list())
self.mox.ReplayAll() self.mox.ReplayAll()
url = reverse('horizon:project:databases:access_detail', url = reverse('horizon:project:databases:access_detail',
args=['id', 'name']) args=['id', 'name', 'host'])
res = self.client.get(url) res = self.client.get(url)
self.assertTemplateUsed( self.assertTemplateUsed(
res, 'project/databases/access_detail.html') res, 'project/databases/access_detail.html')
@test.create_stubs({api.trove: ('database_list', 'user_list_access')}) @test.create_stubs({api.trove: ('database_list', 'user_show_access')})
def test_access_detail_get_exception(self): def test_access_detail_get_exception(self):
api.trove.database_list(IsA(http.HttpRequest), u'id') \ api.trove.database_list(IsA(http.HttpRequest), IsA(six.text_type)) \
.AndReturn(self.databases.list()) .AndReturn(self.databases.list())
api.trove.user_list_access(IsA(http.HttpRequest), u'id', u'name') \ api.trove.user_show_access(IsA(http.HttpRequest), IsA(six.text_type),
IsA(six.text_type),
host=IsA(six.text_type)) \
.AndRaise(self.exceptions.trove) .AndRaise(self.exceptions.trove)
self.mox.ReplayAll() self.mox.ReplayAll()
url = reverse('horizon:project:databases:access_detail', url = reverse('horizon:project:databases:access_detail',
args=['id', 'name']) args=['id', 'name', 'host'])
res = self.client.get(url) res = self.client.get(url)
self.assertRedirectsNoFollow(res, DETAILS_URL) self.assertRedirectsNoFollow(res, DETAILS_URL)
@test.create_stubs({api.trove: ('user_grant_access',)}) @test.create_stubs({api.trove: ('user_grant_access',)})
def test_detail_grant_access(self): def test_detail_grant_access(self):
api.trove.user_grant_access( api.trove.user_grant_access(
IsA(http.HttpRequest), u'id', u'name', [u'db1'], None) IsA(http.HttpRequest), IsA(six.text_type), IsA(six.text_type),
[IsA(six.text_type)], host=IsA(six.text_type))
self.mox.ReplayAll() self.mox.ReplayAll()
url = reverse('horizon:project:databases:access_detail', url = reverse('horizon:project:databases:access_detail',
args=['id', 'name']) args=['id', 'name', 'host'])
form_data = {"action": "access__grant_access__%s" % 'db1'} form_data = {"action": "access__grant_access__%s" % 'db1'}
req = self.factory.post(url, form_data) req = self.factory.post(url, form_data)
kwargs = {'instance_id': 'id', 'user_name': 'name'} kwargs = {'instance_id': 'id', 'user_name': 'name', 'user_host': '%'}
db_access_list = [] db_access_list = []
db_access = views.DBAccess('db1', False) db_access = views.DBAccess('db1', False)
@@ -845,17 +854,18 @@ class DatabaseTests(test.TestCase):
@test.create_stubs({api.trove: ('user_grant_access',)}) @test.create_stubs({api.trove: ('user_grant_access',)})
def test_detail_grant_access_exception(self): def test_detail_grant_access_exception(self):
api.trove.user_grant_access( api.trove.user_grant_access(
IsA(http.HttpRequest), u'id', u'name', [u'db1'], None) \ IsA(http.HttpRequest), IsA(six.text_type), IsA(six.text_type),
[IsA(six.text_type)], host=IsA(six.text_type)) \
.AndRaise(self.exceptions.trove) .AndRaise(self.exceptions.trove)
self.mox.ReplayAll() self.mox.ReplayAll()
url = reverse('horizon:project:databases:access_detail', url = reverse('horizon:project:databases:access_detail',
args=['id', 'name']) args=['id', 'name', 'host'])
form_data = {"action": "access__grant_access__%s" % 'db1'} form_data = {"action": "access__grant_access__%s" % 'db1'}
req = self.factory.post(url, form_data) req = self.factory.post(url, form_data)
kwargs = {'instance_id': 'id', 'user_name': 'name'} kwargs = {'instance_id': 'id', 'user_name': 'name', 'user_host': '%'}
db_access_list = [] db_access_list = []
db_access = views.DBAccess('db1', False) db_access = views.DBAccess('db1', False)
@@ -871,15 +881,17 @@ class DatabaseTests(test.TestCase):
def test_detail_revoke_access(self): def test_detail_revoke_access(self):
api.trove.user_revoke_access( api.trove.user_revoke_access(
IsA(http.HttpRequest), u'id', u'name', u'db1', None) IsA(http.HttpRequest), IsA(six.text_type), IsA(six.text_type),
[IsA(six.text_type)], host=IsA(six.text_type))
self.mox.ReplayAll() self.mox.ReplayAll()
url = reverse('horizon:project:databases:access_detail', url = reverse('horizon:project:databases:access_detail',
args=['id', 'name']) args=['id', 'name', 'host'])
form_data = {"action": "access__revoke_access__%s" % 'db1'} form_data = {"action": "access__revoke_access__%s" % 'db1'}
req = self.factory.post(url, form_data) req = self.factory.post(url, form_data)
kwargs = {'instance_id': 'id', 'user_name': 'name'} kwargs = {'instance_id': 'id', 'user_name': 'name', 'user_host': '%'}
db_access_list = [] db_access_list = []
db_access = views.DBAccess('db1', True) db_access = views.DBAccess('db1', True)
@@ -895,16 +907,18 @@ class DatabaseTests(test.TestCase):
def test_detail_revoke_access_exception(self): def test_detail_revoke_access_exception(self):
api.trove.user_revoke_access( api.trove.user_revoke_access(
IsA(http.HttpRequest), u'id', u'name', u'db1', None) \ IsA(http.HttpRequest), IsA(six.text_type), IsA(six.text_type),
[IsA(six.text_type)], host=IsA(six.text_type)) \
.AndRaise(self.exceptions.trove) .AndRaise(self.exceptions.trove)
self.mox.ReplayAll() self.mox.ReplayAll()
url = reverse('horizon:project:databases:access_detail', url = reverse('horizon:project:databases:access_detail',
args=['id', 'name']) args=['id', 'name', 'host'])
form_data = {"action": "access__revoke_access__%s" % 'db1'} form_data = {"action": "access__revoke_access__%s" % 'db1'}
req = self.factory.post(url, form_data) req = self.factory.post(url, form_data)
kwargs = {'instance_id': 'id', 'user_name': 'name'} kwargs = {'instance_id': 'id', 'user_name': 'name', 'user_host': '%'}
db_access_list = [] db_access_list = []
db_access = views.DBAccess('db1', True) db_access = views.DBAccess('db1', True)

View File

@@ -21,7 +21,8 @@ from trove_dashboard.content.databases import views
BASEINSTANCES = r'^(?P<instance_id>[^/]+)/%s' BASEINSTANCES = r'^(?P<instance_id>[^/]+)/%s'
INSTANCES = BASEINSTANCES + '$' INSTANCES = BASEINSTANCES + '$'
USERS = r'^(?P<instance_id>[^/]+)/(?P<user_name>[^/]+)/%s$' USERS = r'^(?P<instance_id>[^/]+)/(?P<user_name>[^/]+)/' \
r'(?P<user_host>[^/]+)/%s$'
urlpatterns = patterns( urlpatterns = patterns(

View File

@@ -146,16 +146,18 @@ class EditUserView(horizon_forms.ModalFormView):
context = super(EditUserView, self).get_context_data(**kwargs) context = super(EditUserView, self).get_context_data(**kwargs)
context['instance_id'] = self.kwargs['instance_id'] context['instance_id'] = self.kwargs['instance_id']
context['user_name'] = self.kwargs['user_name'] context['user_name'] = self.kwargs['user_name']
args = (self.kwargs['instance_id'], self.kwargs['user_name']) context['user_host'] = self.kwargs['user_host']
args = (self.kwargs['instance_id'], self.kwargs['user_name'],
self.kwargs['user_host'])
context['submit_url'] = reverse(self.submit_url, args=args) context['submit_url'] = reverse(self.submit_url, args=args)
return context return context
def get_initial(self): def get_initial(self):
instance_id = self.kwargs['instance_id'] instance_id = self.kwargs['instance_id']
user_name = self.kwargs['user_name'] user_name = self.kwargs['user_name']
host = tables.parse_host_param(self.request) user_host = self.kwargs['user_host']
return {'instance_id': instance_id, 'user_name': user_name, return {'instance_id': instance_id, 'user_name': user_name,
'host': host} 'user_host': user_host}
class AccessDetailView(horizon_tables.DataTableView): class AccessDetailView(horizon_tables.DataTableView):
@@ -167,6 +169,7 @@ class AccessDetailView(horizon_tables.DataTableView):
def get_data(self): def get_data(self):
instance_id = self.kwargs['instance_id'] instance_id = self.kwargs['instance_id']
user_name = self.kwargs['user_name'] user_name = self.kwargs['user_name']
user_host = self.kwargs['user_host']
try: try:
databases = api.trove.database_list(self.request, instance_id) databases = api.trove.database_list(self.request, instance_id)
except Exception: except Exception:
@@ -177,8 +180,8 @@ class AccessDetailView(horizon_tables.DataTableView):
_('Unable to retrieve databases.'), _('Unable to retrieve databases.'),
redirect=redirect) redirect=redirect)
try: try:
granted = api.trove.user_list_access( granted = api.trove.user_show_access(
self.request, instance_id, user_name) self.request, instance_id, user_name, host=user_host)
except Exception: except Exception:
granted = [] granted = []
redirect = reverse('horizon:project:databases:detail', redirect = reverse('horizon:project:databases:detail',