Merge "Enable using multiple API versions for Identity Service."
This commit is contained in:
commit
ff573dae88
@ -33,6 +33,38 @@ __all__ = ('APIResourceWrapper', 'APIDictWrapper',
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class APIVersionManager(object):
|
||||
""" Object to store and manage API versioning data and utility methods. """
|
||||
|
||||
SETTINGS_KEY = "OPENSTACK_API_VERSIONS"
|
||||
|
||||
def __init__(self, service_type, preferred_version=None):
|
||||
self.service_type = service_type
|
||||
self.preferred = preferred_version
|
||||
self._active = None
|
||||
self.supported = {}
|
||||
|
||||
@property
|
||||
def active(self):
|
||||
if self._active is None:
|
||||
self.get_active_version()
|
||||
return self._active
|
||||
|
||||
def load_supported_version(self, version, data):
|
||||
self.supported[version] = data
|
||||
|
||||
def get_active_version(self):
|
||||
if self._active is not None:
|
||||
return self.supported[self._active]
|
||||
key = getattr(settings, self.SETTINGS_KEY, {}).get(self.service_type)
|
||||
if key is None:
|
||||
# TODO: support API version discovery here; we'll leave the setting
|
||||
# in as a way of overriding the latest available version.
|
||||
key = self.preferred
|
||||
self._active = key
|
||||
return self.supported[self._active]
|
||||
|
||||
|
||||
class APIResourceWrapper(object):
|
||||
""" Simple wrapper for api objects
|
||||
|
||||
|
@ -21,18 +21,17 @@
|
||||
|
||||
import logging
|
||||
import urlparse
|
||||
from pkg_resources import get_distribution
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import logout
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from keystoneclient import service_catalog
|
||||
from keystoneclient.v2_0 import client as keystone_client
|
||||
from keystoneclient.v2_0 import tokens
|
||||
from keystoneclient.exceptions import ClientException
|
||||
|
||||
from openstack_auth.backend import KEYSTONE_CLIENT_ATTR
|
||||
|
||||
from horizon import exceptions
|
||||
from horizon import messages
|
||||
|
||||
from openstack_dashboard.api import base
|
||||
|
||||
@ -41,6 +40,39 @@ LOG = logging.getLogger(__name__)
|
||||
DEFAULT_ROLE = None
|
||||
|
||||
|
||||
# Set up our data structure for managing Identity API versions, and
|
||||
# add a couple utility methods to it.
|
||||
class IdentityAPIVersionManager(base.APIVersionManager):
|
||||
def upgrade_v2_user(self, user):
|
||||
if getattr(user, "project_id", None) is None:
|
||||
user.project_id = getattr(user, "tenantId", None)
|
||||
return user
|
||||
|
||||
def get_project_manager(self, *args, **kwargs):
|
||||
if VERSIONS.active < 3:
|
||||
manager = keystoneclient(*args, **kwargs).tenants
|
||||
else:
|
||||
manager = keystoneclient(*args, **kwargs).projects
|
||||
return manager
|
||||
|
||||
|
||||
VERSIONS = IdentityAPIVersionManager("identity", preferred_version=3)
|
||||
|
||||
|
||||
# Import from oldest to newest so that "preferred" takes correct precedence.
|
||||
try:
|
||||
from keystoneclient.v2_0 import client as keystone_client_v2
|
||||
VERSIONS.load_supported_version(2.0, {"client": keystone_client_v2})
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
try:
|
||||
from keystoneclient.v3 import client as keystone_client_v3
|
||||
VERSIONS.load_supported_version(3, {"client": keystone_client_v3})
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
class Service(base.APIDictWrapper):
|
||||
""" Wrapper for a dict based on the service data from keystone. """
|
||||
_attrs = ['id', 'type', 'name']
|
||||
@ -55,8 +87,7 @@ class Service(base.APIDictWrapper):
|
||||
def __unicode__(self):
|
||||
if(self.type == "identity"):
|
||||
return _("%(type)s (%(backend)s backend)") \
|
||||
% {"type": self.type,
|
||||
"backend": keystone_backend_name()}
|
||||
% {"type": self.type, "backend": keystone_backend_name()}
|
||||
else:
|
||||
return self.type
|
||||
|
||||
@ -66,11 +97,20 @@ class Service(base.APIDictWrapper):
|
||||
|
||||
def _get_endpoint_url(request, endpoint_type, catalog=None):
|
||||
if getattr(request.user, "service_catalog", None):
|
||||
return base.url_for(request,
|
||||
service_type='identity',
|
||||
endpoint_type=endpoint_type)
|
||||
return request.session.get('region_endpoint',
|
||||
getattr(settings, 'OPENSTACK_KEYSTONE_URL'))
|
||||
url = base.url_for(request,
|
||||
service_type='identity',
|
||||
endpoint_type=endpoint_type)
|
||||
else:
|
||||
auth_url = getattr(settings, 'OPENSTACK_KEYSTONE_URL')
|
||||
url = request.session.get('region_endpoint', auth_url)
|
||||
|
||||
# TODO: When the Service Catalog no longer contains API versions
|
||||
# in the endpoints this can be removed.
|
||||
bits = urlparse.urlparse(url)
|
||||
root = "://".join((bits.scheme, bits.netloc))
|
||||
url = "%s/v%s" % (root, VERSIONS.active)
|
||||
|
||||
return url
|
||||
|
||||
|
||||
def keystoneclient(request, admin=False):
|
||||
@ -105,6 +145,8 @@ def keystoneclient(request, admin=False):
|
||||
'OPENSTACK_ENDPOINT_TYPE',
|
||||
'internalURL')
|
||||
|
||||
api_version = VERSIONS.get_active_version()
|
||||
|
||||
# Take care of client connection caching/fetching a new client.
|
||||
# Admin vs. non-admin clients are cached separately for token matching.
|
||||
cache_attr = "_keystoneclient_admin" if admin else KEYSTONE_CLIENT_ATTR
|
||||
@ -116,102 +158,168 @@ def keystoneclient(request, admin=False):
|
||||
endpoint = _get_endpoint_url(request, endpoint_type)
|
||||
insecure = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False)
|
||||
LOG.debug("Creating a new keystoneclient connection to %s." % endpoint)
|
||||
|
||||
conn = keystone_client.Client(
|
||||
token=user.token.id, endpoint=endpoint,
|
||||
original_ip=request.environ.get('REMOTE_ADDR', ''),
|
||||
insecure=insecure)
|
||||
remote_addr = request.environ.get('REMOTE_ADDR', '')
|
||||
conn = api_version['client'].Client(token=user.token.id,
|
||||
endpoint=endpoint,
|
||||
original_ip=remote_addr,
|
||||
insecure=insecure,
|
||||
debug=settings.DEBUG)
|
||||
setattr(request, cache_attr, conn)
|
||||
return conn
|
||||
|
||||
|
||||
def tenant_create(request, tenant_name, description, enabled):
|
||||
return keystoneclient(request, admin=True).tenants.create(tenant_name,
|
||||
description,
|
||||
enabled)
|
||||
|
||||
|
||||
def tenant_get(request, tenant_id, admin=False):
|
||||
return keystoneclient(request, admin=admin).tenants.get(tenant_id)
|
||||
|
||||
|
||||
def tenant_delete(request, tenant_id):
|
||||
keystoneclient(request, admin=True).tenants.delete(tenant_id)
|
||||
|
||||
|
||||
def tenant_list(request, admin=False):
|
||||
return keystoneclient(request, admin=admin).tenants.list()
|
||||
|
||||
|
||||
def tenant_update(request, tenant_id, tenant_name, description, enabled):
|
||||
return keystoneclient(request, admin=True).tenants.update(tenant_id,
|
||||
tenant_name,
|
||||
description,
|
||||
enabled)
|
||||
|
||||
|
||||
def token_create_scoped(request, tenant, token):
|
||||
'''
|
||||
Creates a scoped token using the tenant id and unscoped token; retrieves
|
||||
the service catalog for the given tenant.
|
||||
'''
|
||||
if hasattr(request, '_keystone'):
|
||||
del request._keystone
|
||||
c = keystoneclient(request)
|
||||
raw_token = c.tokens.authenticate(tenant_id=tenant,
|
||||
token=token,
|
||||
return_raw=True)
|
||||
c.service_catalog = service_catalog.ServiceCatalog(raw_token)
|
||||
if request.user.is_superuser:
|
||||
c.management_url = c.service_catalog.url_for(service_type='identity',
|
||||
endpoint_type='adminURL')
|
||||
def tenant_create(request, name, description=None, enabled=None, domain=None):
|
||||
manager = VERSIONS.get_project_manager(request, admin=True)
|
||||
if VERSIONS.active < 3:
|
||||
return manager.create(name, description, enabled)
|
||||
else:
|
||||
endpoint_type = getattr(settings,
|
||||
'OPENSTACK_ENDPOINT_TYPE',
|
||||
'internalURL')
|
||||
c.management_url = c.service_catalog.url_for(
|
||||
service_type='identity', endpoint_type=endpoint_type)
|
||||
scoped_token = tokens.Token(tokens.TokenManager, raw_token)
|
||||
return scoped_token
|
||||
return manager.create(name, domain,
|
||||
description=description,
|
||||
enabled=enabled)
|
||||
|
||||
|
||||
def user_list(request, tenant_id=None):
|
||||
return keystoneclient(request, admin=True).users.list(tenant_id=tenant_id)
|
||||
# TODO(gabriel): Is there ever a valid case for admin to be false here?
|
||||
# A quick search through the codebase reveals that it's always called with
|
||||
# admin=true so I suspect we could eliminate it entirely as with the other
|
||||
# tenant commands.
|
||||
def tenant_get(request, project, admin=True):
|
||||
manager = VERSIONS.get_project_manager(request, admin=admin)
|
||||
return manager.get(project)
|
||||
|
||||
|
||||
def user_create(request, user_id, email, password, tenant_id, enabled):
|
||||
return keystoneclient(request, admin=True).users.create(user_id,
|
||||
password,
|
||||
email,
|
||||
tenant_id,
|
||||
enabled)
|
||||
def tenant_delete(request, project):
|
||||
manager = VERSIONS.get_project_manager(request, admin=True)
|
||||
return manager.delete(project)
|
||||
|
||||
|
||||
def tenant_list(request, domain=None, user=None):
|
||||
manager = VERSIONS.get_project_manager(request, admin=True)
|
||||
if VERSIONS.active < 3:
|
||||
return manager.list()
|
||||
else:
|
||||
return manager.list(domain=domain, user=user)
|
||||
|
||||
|
||||
def tenant_update(request, project, name=None, description=None,
|
||||
enabled=None, domain=None):
|
||||
manager = VERSIONS.get_project_manager(request, admin=True)
|
||||
if VERSIONS.active < 3:
|
||||
return manager.update(project, name, description, enabled)
|
||||
else:
|
||||
return manager.update(project, name=name, description=description,
|
||||
enabled=enabled, domain=domain)
|
||||
|
||||
|
||||
def user_list(request, project=None, domain=None, group=None):
|
||||
if VERSIONS.active < 3:
|
||||
kwargs = {"tenant_id": project}
|
||||
else:
|
||||
kwargs = {
|
||||
"project": project,
|
||||
"domain": domain,
|
||||
"group": group
|
||||
}
|
||||
users = keystoneclient(request, admin=True).users.list(**kwargs)
|
||||
return [VERSIONS.upgrade_v2_user(user) for user in users]
|
||||
|
||||
|
||||
def user_create(request, name=None, email=None, password=None, project=None,
|
||||
enabled=None, domain=None):
|
||||
manager = keystoneclient(request, admin=True).users
|
||||
if VERSIONS.active < 3:
|
||||
user = manager.create(name, password, email, project, enabled)
|
||||
return VERSIONS.upgrade_v2_user(user)
|
||||
else:
|
||||
return manager.create(name, password=password, email=email,
|
||||
project=project, enabled=enabled, domain=domain)
|
||||
|
||||
|
||||
def user_delete(request, user_id):
|
||||
keystoneclient(request, admin=True).users.delete(user_id)
|
||||
return keystoneclient(request, admin=True).users.delete(user_id)
|
||||
|
||||
|
||||
def user_get(request, user_id, admin=True):
|
||||
return keystoneclient(request, admin=admin).users.get(user_id)
|
||||
user = keystoneclient(request, admin=admin).users.get(user_id)
|
||||
return VERSIONS.upgrade_v2_user(user)
|
||||
|
||||
|
||||
def user_update(request, user, **data):
|
||||
return keystoneclient(request, admin=True).users.update(user, **data)
|
||||
manager = keystoneclient(request, admin=True).users
|
||||
error = None
|
||||
|
||||
if not keystone_can_edit_user():
|
||||
raise ClientException(405, _("Identity service does not allow "
|
||||
"editing user data."))
|
||||
|
||||
# The v2 API updates user model, password and default project separately
|
||||
if VERSIONS.active < 3:
|
||||
password = data.pop('password')
|
||||
project = data.pop('project')
|
||||
|
||||
# Update user details
|
||||
try:
|
||||
user = manager.update(user, **data)
|
||||
except:
|
||||
error = exceptions.handle(request, ignore=True)
|
||||
|
||||
# Update default tenant
|
||||
try:
|
||||
user_update_tenant(request, user, project)
|
||||
user.tenantId = project
|
||||
except:
|
||||
error = exceptions.handle(request, ignore=True)
|
||||
|
||||
# Check for existing roles
|
||||
# Show a warning if no role exists for the project
|
||||
user_roles = roles_for_user(request, user, project)
|
||||
if not user_roles:
|
||||
messages.warning(request,
|
||||
_('User %s has no role defined for '
|
||||
'that project.')
|
||||
% data.get('name', None))
|
||||
|
||||
# If present, update password
|
||||
# FIXME(gabriel): password change should be its own form + view
|
||||
if password:
|
||||
try:
|
||||
user_update_password(request, user, password)
|
||||
if user == request.user.id:
|
||||
logout(request)
|
||||
except:
|
||||
error = exceptions.handle(request, ignore=True)
|
||||
|
||||
if error is not None:
|
||||
raise error
|
||||
|
||||
# v3 API is so much simpler...
|
||||
else:
|
||||
user = manager.update(user, **data)
|
||||
|
||||
return VERSIONS.upgrade_v2_user(user)
|
||||
|
||||
|
||||
def user_update_enabled(request, user_id, enabled):
|
||||
return keystoneclient(request, admin=True).users.update_enabled(user_id,
|
||||
enabled)
|
||||
def user_update_enabled(request, user, enabled):
|
||||
manager = keystoneclient(request, admin=True).users
|
||||
if VERSIONS.active < 3:
|
||||
return manager.update_enabled(user, enabled)
|
||||
else:
|
||||
return manager.update(user, enabled=enabled)
|
||||
|
||||
|
||||
def user_update_password(request, user_id, password, admin=True):
|
||||
return keystoneclient(request, admin=admin).users.update_password(user_id,
|
||||
password)
|
||||
def user_update_password(request, user, password, admin=True):
|
||||
manager = keystoneclient(request, admin=admin).users
|
||||
if VERSIONS.active < 3:
|
||||
return manager.update_password(user, password)
|
||||
else:
|
||||
return manager.update(user, password=password)
|
||||
|
||||
|
||||
def user_update_tenant(request, user_id, tenant_id, admin=True):
|
||||
return keystoneclient(request, admin=admin).users.update_tenant(user_id,
|
||||
tenant_id)
|
||||
def user_update_tenant(request, user, project, admin=True):
|
||||
manager = keystoneclient(request, admin=admin).users
|
||||
if VERSIONS.active < 3:
|
||||
return manager.update_tenant(user, project)
|
||||
else:
|
||||
return manager.update(user, project=project)
|
||||
|
||||
|
||||
def role_list(request):
|
||||
@ -220,29 +328,42 @@ def role_list(request):
|
||||
|
||||
|
||||
def roles_for_user(request, user, project):
|
||||
return keystoneclient(request, admin=True).roles.roles_for_user(user,
|
||||
project)
|
||||
manager = keystoneclient(request, admin=True).roles
|
||||
if VERSIONS.active < 3:
|
||||
return manager.roles_for_user(user, project)
|
||||
else:
|
||||
return manager.list(user=user, project=project)
|
||||
|
||||
|
||||
def add_tenant_user_role(request, tenant_id, user_id, role_id):
|
||||
def add_tenant_user_role(request, project=None, user=None, role=None,
|
||||
group=None, domain=None):
|
||||
""" Adds a role for a user on a tenant. """
|
||||
return keystoneclient(request, admin=True).roles.add_user_role(user_id,
|
||||
role_id,
|
||||
tenant_id)
|
||||
manager = keystoneclient(request, admin=True).roles
|
||||
if VERSIONS.active < 3:
|
||||
return manager.add_user_role(user, role, project)
|
||||
else:
|
||||
return manager.grant(role, user=user, project=project,
|
||||
group=group, domain=domain)
|
||||
|
||||
|
||||
def remove_tenant_user_role(request, tenant_id, user_id, role_id):
|
||||
def remove_tenant_user_role(request, project=None, user=None, role=None,
|
||||
group=None, domain=None):
|
||||
""" Removes a given single role for a user from a tenant. """
|
||||
client = keystoneclient(request, admin=True)
|
||||
client.roles.remove_user_role(user_id, role_id, tenant_id)
|
||||
manager = keystoneclient(request, admin=True).roles
|
||||
if VERSIONS.active < 3:
|
||||
return manager.remove_user_role(user, role, project)
|
||||
else:
|
||||
return manager.revoke(role, user=user, project=project,
|
||||
group=group, domain=domain)
|
||||
|
||||
|
||||
def remove_tenant_user(request, tenant_id, user_id):
|
||||
def remove_tenant_user(request, project=None, user=None, domain=None):
|
||||
""" Removes all roles from a user on a tenant, removing them from it. """
|
||||
client = keystoneclient(request, admin=True)
|
||||
roles = client.roles.roles_for_user(user_id, tenant_id)
|
||||
roles = client.roles.roles_for_user(user, project)
|
||||
for role in roles:
|
||||
client.roles.remove_user_role(user_id, role.id, tenant_id)
|
||||
remove_tenant_user_role(request, user=user, role=role.id,
|
||||
project=project, domain=domain)
|
||||
|
||||
|
||||
def get_default_role(request):
|
||||
|
@ -33,7 +33,7 @@ class InstanceViewTest(test.BaseAdminViewTests):
|
||||
servers = self.servers.list()
|
||||
flavors = self.flavors.list()
|
||||
tenants = self.tenants.list()
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest), admin=True).\
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest)).\
|
||||
AndReturn(tenants)
|
||||
search_opts = {'marker': None, 'paginate': True}
|
||||
api.nova.server_list(IsA(http.HttpRequest),
|
||||
@ -62,7 +62,7 @@ class InstanceViewTest(test.BaseAdminViewTests):
|
||||
.AndReturn([servers, False])
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)). \
|
||||
AndRaise(self.exceptions.nova)
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest), admin=True).\
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest)).\
|
||||
AndReturn(tenants)
|
||||
for server in servers:
|
||||
api.nova.flavor_get(IsA(http.HttpRequest), server.flavor["id"]). \
|
||||
@ -93,7 +93,7 @@ class InstanceViewTest(test.BaseAdminViewTests):
|
||||
.AndReturn([servers, False])
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)). \
|
||||
AndReturn(flavors)
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest), admin=True).\
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest)).\
|
||||
AndReturn(tenants)
|
||||
for server in servers:
|
||||
api.nova.flavor_get(IsA(http.HttpRequest), server.flavor["id"]). \
|
||||
@ -153,7 +153,7 @@ class InstanceViewTest(test.BaseAdminViewTests):
|
||||
@test.create_stubs({api.nova: ('flavor_list', 'server_list',),
|
||||
api.keystone: ('tenant_list',)})
|
||||
def test_index_options_before_migrate(self):
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest), admin=True).\
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest)).\
|
||||
AndReturn(self.tenants.list())
|
||||
search_opts = {'marker': None, 'paginate': True}
|
||||
api.nova.server_list(IsA(http.HttpRequest),
|
||||
@ -173,8 +173,8 @@ class InstanceViewTest(test.BaseAdminViewTests):
|
||||
def test_index_options_after_migrate(self):
|
||||
server = self.servers.first()
|
||||
server.status = "VERIFY_RESIZE"
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest), admin=True).\
|
||||
AndReturn(self.tenants.list())
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.tenants.list())
|
||||
search_opts = {'marker': None, 'paginate': True}
|
||||
api.nova.server_list(IsA(http.HttpRequest),
|
||||
all_tenants=True, search_opts=search_opts) \
|
||||
|
@ -73,7 +73,7 @@ class AdminIndexView(tables.DataTableView):
|
||||
|
||||
# Gather our tenants to correlate against IDs
|
||||
try:
|
||||
tenants = api.keystone.tenant_list(self.request, admin=True)
|
||||
tenants = api.keystone.tenant_list(self.request)
|
||||
except:
|
||||
tenants = []
|
||||
msg = _('Unable to retrieve instance tenant information.')
|
||||
|
@ -48,7 +48,7 @@ class CreateNetwork(forms.SelfHandlingForm):
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(CreateNetwork, self).__init__(request, *args, **kwargs)
|
||||
tenant_choices = [('', _("Select a project"))]
|
||||
for tenant in api.keystone.tenant_list(request, admin=True):
|
||||
for tenant in api.keystone.tenant_list(request):
|
||||
if tenant.enabled:
|
||||
tenant_choices.append((tenant.id, tenant.name))
|
||||
self.fields['tenant_id'].choices = tenant_choices
|
||||
|
@ -35,7 +35,7 @@ class NetworkTests(test.BaseAdminViewTests):
|
||||
tenants = self.tenants.list()
|
||||
api.quantum.network_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.networks.list())
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest), admin=True)\
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest))\
|
||||
.AndReturn(tenants)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
@ -151,7 +151,7 @@ class NetworkTests(test.BaseAdminViewTests):
|
||||
@test.create_stubs({api.keystone: ('tenant_list',)})
|
||||
def test_network_create_get(self):
|
||||
tenants = self.tenants.list()
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest), admin=True)\
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest))\
|
||||
.AndReturn(tenants)
|
||||
self.mox.ReplayAll()
|
||||
|
||||
@ -166,7 +166,7 @@ class NetworkTests(test.BaseAdminViewTests):
|
||||
tenants = self.tenants.list()
|
||||
tenant_id = self.tenants.first().id
|
||||
network = self.networks.first()
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest), admin=True)\
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest))\
|
||||
.AndReturn(tenants)
|
||||
params = {'name': network.name,
|
||||
'tenant_id': tenant_id,
|
||||
@ -194,7 +194,7 @@ class NetworkTests(test.BaseAdminViewTests):
|
||||
tenants = self.tenants.list()
|
||||
tenant_id = self.tenants.first().id
|
||||
network = self.networks.first()
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest), admin=True)\
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest))\
|
||||
.AndReturn(tenants)
|
||||
params = {'name': network.name,
|
||||
'tenant_id': tenant_id,
|
||||
@ -301,7 +301,7 @@ class NetworkTests(test.BaseAdminViewTests):
|
||||
def test_delete_network(self):
|
||||
tenants = self.tenants.list()
|
||||
network = self.networks.first()
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest), admin=True)\
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest))\
|
||||
.AndReturn(tenants)
|
||||
api.quantum.network_list(IsA(http.HttpRequest))\
|
||||
.AndReturn([network])
|
||||
@ -320,7 +320,7 @@ class NetworkTests(test.BaseAdminViewTests):
|
||||
def test_delete_network_exception(self):
|
||||
tenants = self.tenants.list()
|
||||
network = self.networks.first()
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest), admin=True)\
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest))\
|
||||
.AndReturn(tenants)
|
||||
api.quantum.network_list(IsA(http.HttpRequest))\
|
||||
.AndReturn([network])
|
||||
|
@ -42,7 +42,7 @@ class IndexView(tables.DataTableView):
|
||||
def _get_tenant_list(self):
|
||||
if not hasattr(self, "_tenants"):
|
||||
try:
|
||||
tenants = api.keystone.tenant_list(self.request, admin=True)
|
||||
tenants = api.keystone.tenant_list(self.request)
|
||||
except:
|
||||
tenants = []
|
||||
msg = _('Unable to retrieve instance tenant information.')
|
||||
|
@ -45,7 +45,7 @@ class UsageViewTests(test.BaseAdminViewTests):
|
||||
now = timezone.now()
|
||||
usage_obj = api.nova.NovaUsage(self.usages.first())
|
||||
quota_data = self.quota_usages.first()
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest), admin=True) \
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.tenants.list())
|
||||
api.nova.usage_list(IsA(http.HttpRequest),
|
||||
datetime.datetime(now.year, now.month, 1, 0, 0, 0),
|
||||
@ -77,7 +77,7 @@ class UsageViewTests(test.BaseAdminViewTests):
|
||||
now = timezone.now()
|
||||
usage_obj = api.nova.NovaUsage(self.usages.first())
|
||||
quota_data = self.quota_usages.first()
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest), admin=True) \
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.tenants.list())
|
||||
api.nova.usage_list(IsA(http.HttpRequest),
|
||||
datetime.datetime(now.year, now.month, 1, 0, 0, 0),
|
||||
|
@ -41,7 +41,7 @@ class GlobalOverview(usage.UsageView):
|
||||
data = super(GlobalOverview, self).get_data()
|
||||
# Pre-fill tenant names
|
||||
try:
|
||||
tenants = api.keystone.tenant_list(self.request, admin=True)
|
||||
tenants = api.keystone.tenant_list(self.request)
|
||||
except:
|
||||
tenants = []
|
||||
exceptions.handle(self.request,
|
||||
|
@ -25,9 +25,9 @@ from openstack_dashboard.dashboards.admin.users.forms import CreateUserForm
|
||||
|
||||
class CreateUser(CreateUserForm):
|
||||
role_id = forms.ChoiceField(widget=forms.HiddenInput())
|
||||
tenant_id = forms.CharField(widget=forms.HiddenInput())
|
||||
project = forms.CharField(widget=forms.HiddenInput())
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(CreateUser, self).__init__(request, *args, **kwargs)
|
||||
tenant_id = self.request.path.split("/")[-1]
|
||||
self.fields['tenant_id'].initial = tenant_id
|
||||
project = self.request.path.split("/")[-1]
|
||||
self.fields['project'].initial = project
|
||||
|
@ -34,7 +34,7 @@ INDEX_URL = reverse('horizon:admin:projects:index')
|
||||
class TenantsViewTests(test.BaseAdminViewTests):
|
||||
def test_index(self):
|
||||
self.mox.StubOutWithMock(api.keystone, 'tenant_list')
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest), admin=True) \
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.tenants.list())
|
||||
self.mox.ReplayAll()
|
||||
|
||||
@ -45,7 +45,7 @@ class TenantsViewTests(test.BaseAdminViewTests):
|
||||
|
||||
class CreateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||
def _get_project_info(self, project):
|
||||
project_info = {"tenant_name": project.name,
|
||||
project_info = {"name": project.name,
|
||||
"description": project.description,
|
||||
"enabled": project.enabled}
|
||||
return project_info
|
||||
@ -146,9 +146,9 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||
ulist = workflow_data["role_" + role.id]
|
||||
for user_id in ulist:
|
||||
api.keystone.add_tenant_user_role(IsA(http.HttpRequest),
|
||||
tenant_id=self.tenant.id,
|
||||
user_id=user_id,
|
||||
role_id=role.id)
|
||||
project=self.tenant.id,
|
||||
user=user_id,
|
||||
role=role.id)
|
||||
|
||||
nova_updated_quota = dict([(key, quota_data[key]) for key in
|
||||
quotas.NOVA_QUOTA_FIELDS])
|
||||
@ -276,9 +276,9 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||
ulist = workflow_data["role_" + role.id]
|
||||
for user_id in ulist:
|
||||
api.keystone.add_tenant_user_role(IsA(http.HttpRequest),
|
||||
tenant_id=self.tenant.id,
|
||||
user_id=user_id,
|
||||
role_id=role.id)
|
||||
project=self.tenant.id,
|
||||
user=user_id,
|
||||
role=role.id)
|
||||
|
||||
nova_updated_quota = dict([(key, quota_data[key]) for key in
|
||||
quotas.NOVA_QUOTA_FIELDS])
|
||||
@ -338,9 +338,9 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||
ulist = workflow_data["role_" + role.id]
|
||||
for user_id in ulist:
|
||||
api.keystone.add_tenant_user_role(IsA(http.HttpRequest),
|
||||
tenant_id=self.tenant.id,
|
||||
user_id=user_id,
|
||||
role_id=role.id) \
|
||||
project=self.tenant.id,
|
||||
user=user_id,
|
||||
role=role.id) \
|
||||
.AndRaise(self.exceptions.keystone)
|
||||
break
|
||||
break
|
||||
@ -506,8 +506,7 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||
quota.metadata_items = 444
|
||||
quota.volumes = 444
|
||||
|
||||
updated_project = {"tenant_name": project._info["name"],
|
||||
"tenant_id": project.id,
|
||||
updated_project = {"name": project._info["name"],
|
||||
"description": project._info["description"],
|
||||
"enabled": project.enabled}
|
||||
updated_quota = self._get_quota_info(quota)
|
||||
@ -516,12 +515,14 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||
api.keystone.role_list(IsA(http.HttpRequest)).AndReturn(roles)
|
||||
|
||||
# handle
|
||||
api.keystone.tenant_update(IsA(http.HttpRequest), **updated_project) \
|
||||
api.keystone.tenant_update(IsA(http.HttpRequest),
|
||||
project.id,
|
||||
**updated_project) \
|
||||
.AndReturn(project)
|
||||
|
||||
api.keystone.role_list(IsA(http.HttpRequest)).AndReturn(roles)
|
||||
api.keystone.user_list(IsA(http.HttpRequest),
|
||||
tenant_id=self.tenant.id).AndReturn(users)
|
||||
project=self.tenant.id).AndReturn(users)
|
||||
|
||||
# admin user - try to remove all roles on current project, warning
|
||||
api.keystone.roles_for_user(IsA(http.HttpRequest), '1',
|
||||
@ -534,14 +535,14 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||
.AndReturn((roles[0],))
|
||||
# remove role 1
|
||||
api.keystone.remove_tenant_user_role(IsA(http.HttpRequest),
|
||||
tenant_id=self.tenant.id,
|
||||
user_id='2',
|
||||
role_id='1')
|
||||
project=self.tenant.id,
|
||||
user='2',
|
||||
role='1')
|
||||
# add role 2
|
||||
api.keystone.add_tenant_user_role(IsA(http.HttpRequest),
|
||||
tenant_id=self.tenant.id,
|
||||
user_id='2',
|
||||
role_id='2')
|
||||
project=self.tenant.id,
|
||||
user='2',
|
||||
role='2')
|
||||
|
||||
# member user 3 - has role 2
|
||||
api.keystone.roles_for_user(IsA(http.HttpRequest), '3',
|
||||
@ -549,14 +550,14 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||
.AndReturn((roles[1],))
|
||||
# remove role 2
|
||||
api.keystone.remove_tenant_user_role(IsA(http.HttpRequest),
|
||||
tenant_id=self.tenant.id,
|
||||
user_id='3',
|
||||
role_id='2')
|
||||
project=self.tenant.id,
|
||||
user='3',
|
||||
role='2')
|
||||
# add role 1
|
||||
api.keystone.add_tenant_user_role(IsA(http.HttpRequest),
|
||||
tenant_id=self.tenant.id,
|
||||
user_id='3',
|
||||
role_id='1')
|
||||
project=self.tenant.id,
|
||||
user='3',
|
||||
role='1')
|
||||
|
||||
nova_updated_quota = dict([(key, updated_quota[key]) for key in
|
||||
quotas.NOVA_QUOTA_FIELDS])
|
||||
@ -647,8 +648,7 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||
quota.metadata_items = 444
|
||||
quota.volumes = 444
|
||||
|
||||
updated_project = {"tenant_name": project._info["name"],
|
||||
"tenant_id": project.id,
|
||||
updated_project = {"name": project._info["name"],
|
||||
"description": project._info["description"],
|
||||
"enabled": project.enabled}
|
||||
updated_quota = self._get_quota_info(quota)
|
||||
@ -657,7 +657,9 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||
api.keystone.role_list(IsA(http.HttpRequest)).AndReturn(roles)
|
||||
|
||||
# handle
|
||||
api.keystone.tenant_update(IsA(http.HttpRequest), **updated_project) \
|
||||
api.keystone.tenant_update(IsA(http.HttpRequest),
|
||||
project.id,
|
||||
**updated_project) \
|
||||
.AndRaise(self.exceptions.keystone)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
@ -722,8 +724,7 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||
quota[0].limit = 444
|
||||
quota[1].limit = -1
|
||||
|
||||
updated_project = {"tenant_name": project._info["name"],
|
||||
"tenant_id": project.id,
|
||||
updated_project = {"name": project._info["name"],
|
||||
"description": project._info["description"],
|
||||
"enabled": project.enabled}
|
||||
updated_quota = self._get_quota_info(quota)
|
||||
@ -733,12 +734,14 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||
|
||||
# handle
|
||||
# handle
|
||||
api.keystone.tenant_update(IsA(http.HttpRequest), **updated_project) \
|
||||
api.keystone.tenant_update(IsA(http.HttpRequest),
|
||||
project.id,
|
||||
**updated_project) \
|
||||
.AndReturn(project)
|
||||
|
||||
api.keystone.role_list(IsA(http.HttpRequest)).AndReturn(roles)
|
||||
api.keystone.user_list(IsA(http.HttpRequest),
|
||||
tenant_id=self.tenant.id).AndReturn(users)
|
||||
project=self.tenant.id).AndReturn(users)
|
||||
|
||||
# admin user - try to remove all roles on current project, warning
|
||||
api.keystone.roles_for_user(IsA(http.HttpRequest), '1',
|
||||
@ -756,9 +759,9 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||
.AndReturn((roles[0],))
|
||||
# add role 2
|
||||
api.keystone.add_tenant_user_role(IsA(http.HttpRequest),
|
||||
tenant_id=self.tenant.id,
|
||||
user_id='3',
|
||||
role_id='2')
|
||||
project=self.tenant.id,
|
||||
user='3',
|
||||
role='2')
|
||||
|
||||
nova_updated_quota = dict([(key, updated_quota[key]) for key in
|
||||
quotas.NOVA_QUOTA_FIELDS])
|
||||
@ -827,8 +830,7 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||
quota.metadata_items = 444
|
||||
quota.volumes = 444
|
||||
|
||||
updated_project = {"tenant_name": project._info["name"],
|
||||
"tenant_id": project.id,
|
||||
updated_project = {"name": project._info["name"],
|
||||
"description": project._info["description"],
|
||||
"enabled": project.enabled}
|
||||
updated_quota = self._get_quota_info(quota)
|
||||
@ -837,41 +839,40 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||
api.keystone.role_list(IsA(http.HttpRequest)).AndReturn(roles)
|
||||
|
||||
# handle
|
||||
api.keystone.tenant_update(IsA(http.HttpRequest), **updated_project) \
|
||||
api.keystone.tenant_update(IsA(http.HttpRequest),
|
||||
project.id,
|
||||
**updated_project) \
|
||||
.AndReturn(project)
|
||||
|
||||
api.keystone.role_list(IsA(http.HttpRequest)).AndReturn(roles)
|
||||
api.keystone.user_list(IsA(http.HttpRequest),
|
||||
tenant_id=self.tenant.id).AndReturn(users)
|
||||
project=self.tenant.id).AndReturn(users)
|
||||
|
||||
# admin user - try to remove all roles on current project, warning
|
||||
api.keystone.roles_for_user(IsA(http.HttpRequest), '1',
|
||||
self.tenant.id) \
|
||||
.AndReturn(roles)
|
||||
self.tenant.id).AndReturn(roles)
|
||||
|
||||
# member user 1 - has role 1, will remove it
|
||||
api.keystone.roles_for_user(IsA(http.HttpRequest), '2',
|
||||
self.tenant.id) \
|
||||
.AndReturn((roles[1],))
|
||||
self.tenant.id).AndReturn((roles[1],))
|
||||
|
||||
# member user 3 - has role 2
|
||||
api.keystone.roles_for_user(IsA(http.HttpRequest), '3',
|
||||
self.tenant.id) \
|
||||
.AndReturn((roles[0],))
|
||||
self.tenant.id).AndReturn((roles[0],))
|
||||
# add role 2
|
||||
api.keystone.add_tenant_user_role(IsA(http.HttpRequest),
|
||||
tenant_id=self.tenant.id,
|
||||
user_id='3',
|
||||
role_id='2')\
|
||||
.AndRaise(self.exceptions.nova)
|
||||
project=self.tenant.id,
|
||||
user='3',
|
||||
role='2')\
|
||||
.AndRaise(self.exceptions.keystone)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
# submit form data
|
||||
project_data = {"name": project._info["name"],
|
||||
"id": project.id,
|
||||
"description": project._info["description"],
|
||||
"enabled": project.enabled}
|
||||
"id": project.id,
|
||||
"description": project._info["description"],
|
||||
"enabled": project.enabled}
|
||||
workflow_data.update(project_data)
|
||||
workflow_data.update(updated_quota)
|
||||
url = reverse('horizon:admin:projects:update',
|
||||
|
@ -71,7 +71,7 @@ class IndexView(tables.DataTableView):
|
||||
def get_data(self):
|
||||
tenants = []
|
||||
try:
|
||||
tenants = api.keystone.tenant_list(self.request, admin=True)
|
||||
tenants = api.keystone.tenant_list(self.request)
|
||||
except:
|
||||
exceptions.handle(self.request,
|
||||
_("Unable to retrieve project list."))
|
||||
@ -183,7 +183,7 @@ class CreateUserView(CreateView):
|
||||
def get_initial(self):
|
||||
default_role = api.keystone.get_default_role(self.request)
|
||||
return {'role_id': getattr(default_role, "id", None),
|
||||
'tenant_id': self.kwargs['tenant_id']}
|
||||
'project': self.kwargs['tenant_id']}
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(CreateUserView, self).get_context_data(**kwargs)
|
||||
|
@ -218,7 +218,7 @@ class CreateProject(workflows.Workflow):
|
||||
try:
|
||||
desc = data['description']
|
||||
self.object = api.keystone.tenant_create(request,
|
||||
tenant_name=data['name'],
|
||||
name=data['name'],
|
||||
description=desc,
|
||||
enabled=data['enabled'])
|
||||
except:
|
||||
@ -242,9 +242,9 @@ class CreateProject(workflows.Workflow):
|
||||
users_added = 0
|
||||
for user in role_list:
|
||||
api.keystone.add_tenant_user_role(request,
|
||||
tenant_id=project_id,
|
||||
user_id=user,
|
||||
role_id=role.id)
|
||||
project=project_id,
|
||||
user=user,
|
||||
role=role.id)
|
||||
users_added += 1
|
||||
users_to_add -= users_added
|
||||
except:
|
||||
@ -300,12 +300,16 @@ class UpdateProject(workflows.Workflow):
|
||||
return message % self.context.get('name', 'unknown project')
|
||||
|
||||
def handle(self, request, data):
|
||||
# FIXME(gabriel): This should be refactored to use Python's built-in
|
||||
# sets and do this all in a single "roles to add" and "roles to remove"
|
||||
# pass instead of the multi-pass thing happening now.
|
||||
|
||||
project_id = data['project_id']
|
||||
# update project info
|
||||
try:
|
||||
api.keystone.tenant_update(request,
|
||||
tenant_id=project_id,
|
||||
tenant_name=data['name'],
|
||||
project_id,
|
||||
name=data['name'],
|
||||
description=data['description'],
|
||||
enabled=data['enabled'])
|
||||
except:
|
||||
@ -315,63 +319,80 @@ class UpdateProject(workflows.Workflow):
|
||||
# update project members
|
||||
users_to_modify = 0
|
||||
try:
|
||||
# Get our role options
|
||||
available_roles = api.keystone.role_list(request)
|
||||
|
||||
# Get the users currently associated with this project so we
|
||||
# can diff against it.
|
||||
project_members = api.keystone.user_list(request,
|
||||
tenant_id=project_id)
|
||||
project=project_id)
|
||||
users_to_modify = len(project_members)
|
||||
|
||||
for user in project_members:
|
||||
current_roles = [role for role in
|
||||
api.keystone.roles_for_user(self.request,
|
||||
user.id,
|
||||
project_id)]
|
||||
effective_roles = []
|
||||
# Check if there have been any changes in the roles of
|
||||
# Existing project members.
|
||||
current_roles = api.keystone.roles_for_user(self.request,
|
||||
user.id,
|
||||
project_id)
|
||||
current_role_ids = [role.id for role in current_roles]
|
||||
for role in available_roles:
|
||||
role_list = data["role_" + role.id]
|
||||
if user.id in role_list:
|
||||
effective_roles.append(role)
|
||||
if role not in current_roles:
|
||||
# Check if the user is in the list of users with this role.
|
||||
if user.id in data["role_" + role.id]:
|
||||
# Add it if necessary
|
||||
if role.id not in current_role_ids:
|
||||
# user role has changed
|
||||
api.keystone.add_tenant_user_role(
|
||||
request,
|
||||
tenant_id=project_id,
|
||||
user_id=user.id,
|
||||
role_id=role.id)
|
||||
project=project_id,
|
||||
user=user.id,
|
||||
role=role.id)
|
||||
else:
|
||||
# user role is unchanged
|
||||
current_roles.pop(current_roles.index(role))
|
||||
if user.id == request.user.id and \
|
||||
project_id == request.user.tenant_id and \
|
||||
any(x.name == 'admin' for x in current_roles):
|
||||
# Cannot remove "admin" role on current(admin) project
|
||||
msg = _('You cannot remove the "admin" role from the '
|
||||
'project you are currently logged into. Please '
|
||||
'switch to another project with admin permissions '
|
||||
'or remove the role manually via the CLI')
|
||||
messages.warning(request, msg)
|
||||
# User role is unchanged, so remove it from the
|
||||
# remaining roles list to avoid removing it later.
|
||||
index = current_role_ids.index(role.id)
|
||||
current_role_ids.pop(index)
|
||||
|
||||
# Prevent admins from doing stupid things to themselves.
|
||||
is_current_user = user.id == request.user.id
|
||||
is_current_project = project_id == request.user.tenant_id
|
||||
admin_roles = [role for role in current_roles
|
||||
if role.name.lower() == 'admin']
|
||||
if len(admin_roles):
|
||||
removing_admin = any([role.id in current_role_ids
|
||||
for role in admin_roles])
|
||||
else:
|
||||
# delete user's removed roles
|
||||
for to_delete in current_roles:
|
||||
removing_admin = False
|
||||
if is_current_user and is_current_project and removing_admin:
|
||||
# Cannot remove "admin" role on current(admin) project
|
||||
msg = _('You cannot revoke your administrative privileges '
|
||||
'from the project you are currently logged into. '
|
||||
'Please switch to another project with '
|
||||
'administrative privileges or remove the '
|
||||
'administrative role manually via the CLI.')
|
||||
messages.warning(request, msg)
|
||||
|
||||
# Otherwise go through and revoke any removed roles.
|
||||
else:
|
||||
for id_to_delete in current_role_ids:
|
||||
api.keystone.remove_tenant_user_role(
|
||||
request,
|
||||
tenant_id=project_id,
|
||||
user_id=user.id,
|
||||
role_id=to_delete.id)
|
||||
project=project_id,
|
||||
user=user.id,
|
||||
role=id_to_delete)
|
||||
users_to_modify -= 1
|
||||
|
||||
# add new roles to project
|
||||
# Grant new roles on the project.
|
||||
for role in available_roles:
|
||||
# count how many users may be added for exception handling
|
||||
role_list = data["role_" + role.id]
|
||||
users_to_modify += len(role_list)
|
||||
# Count how many users may be added for exception handling.
|
||||
users_to_modify += len(data["role_" + role.id])
|
||||
for role in available_roles:
|
||||
role_list = data["role_" + role.id]
|
||||
users_added = 0
|
||||
for user_id in role_list:
|
||||
for user_id in data["role_" + role.id]:
|
||||
if not filter(lambda x: user_id == x.id, project_members):
|
||||
api.keystone.add_tenant_user_role(request,
|
||||
tenant_id=project_id,
|
||||
user_id=user_id,
|
||||
role_id=role.id)
|
||||
project=project_id,
|
||||
user=user_id,
|
||||
role=role.id)
|
||||
users_added += 1
|
||||
users_to_modify -= users_added
|
||||
except:
|
||||
|
@ -34,8 +34,7 @@ class RouterTests(test.BaseAdminViewTests, r_test.RouterTests):
|
||||
api.quantum.router_list(
|
||||
IsA(http.HttpRequest),
|
||||
search_opts=None).AndReturn(self.routers.list())
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest), admin=True)\
|
||||
.AndReturn(tenants)
|
||||
api.keystone.tenant_list(IsA(http.HttpRequest)).AndReturn(tenants)
|
||||
self._mock_external_network_list()
|
||||
|
||||
self.mox.ReplayAll()
|
||||
@ -49,7 +48,6 @@ class RouterTests(test.BaseAdminViewTests, r_test.RouterTests):
|
||||
@test.create_stubs({api.quantum: ('router_list',),
|
||||
api.keystone: ('tenant_list',)})
|
||||
def test_index_router_list_exception(self):
|
||||
tenants = self.tenants.list()
|
||||
api.quantum.router_list(
|
||||
IsA(http.HttpRequest),
|
||||
search_opts=None).AndRaise(self.exceptions.quantum)
|
||||
|
@ -21,7 +21,6 @@
|
||||
import logging
|
||||
|
||||
from django.forms import ValidationError
|
||||
from django.utils.encoding import force_unicode
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.views.decorators.debug import sensitive_variables
|
||||
|
||||
@ -31,7 +30,6 @@ from horizon import messages
|
||||
from horizon.utils import validators
|
||||
|
||||
from openstack_dashboard import api
|
||||
from django.contrib.auth import logout
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
@ -40,13 +38,13 @@ LOG = logging.getLogger(__name__)
|
||||
class BaseUserForm(forms.SelfHandlingForm):
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(BaseUserForm, self).__init__(request, *args, **kwargs)
|
||||
# Populate tenant choices
|
||||
tenant_choices = [('', _("Select a project"))]
|
||||
# Populate project choices
|
||||
project_choices = [('', _("Select a project"))]
|
||||
|
||||
for tenant in api.keystone.tenant_list(request, admin=True):
|
||||
if tenant.enabled:
|
||||
tenant_choices.append((tenant.id, tenant.name))
|
||||
self.fields['tenant_id'].choices = tenant_choices
|
||||
for project in api.keystone.tenant_list(request):
|
||||
if project.enabled:
|
||||
project_choices.append((project.id, project.name))
|
||||
self.fields['project'].choices = project_choices
|
||||
|
||||
def clean(self):
|
||||
'''Check to make sure password fields match.'''
|
||||
@ -64,16 +62,16 @@ class CreateUserForm(BaseUserForm):
|
||||
name = forms.CharField(label=_("User Name"))
|
||||
email = forms.EmailField(label=_("Email"))
|
||||
password = forms.RegexField(
|
||||
label=_("Password"),
|
||||
widget=forms.PasswordInput(render_value=False),
|
||||
regex=validators.password_validator(),
|
||||
error_messages={'invalid': validators.password_validator_msg()})
|
||||
label=_("Password"),
|
||||
widget=forms.PasswordInput(render_value=False),
|
||||
regex=validators.password_validator(),
|
||||
error_messages={'invalid': validators.password_validator_msg()})
|
||||
confirm_password = forms.CharField(
|
||||
label=_("Confirm Password"),
|
||||
required=False,
|
||||
widget=forms.PasswordInput(render_value=False))
|
||||
tenant_id = forms.DynamicChoiceField(label=_("Primary Project"),
|
||||
add_item_link=ADD_PROJECT_URL)
|
||||
label=_("Confirm Password"),
|
||||
required=False,
|
||||
widget=forms.PasswordInput(render_value=False))
|
||||
project = forms.DynamicChoiceField(label=_("Primary Project"),
|
||||
add_item_link=ADD_PROJECT_URL)
|
||||
role_id = forms.ChoiceField(label=_("Role"))
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
@ -92,7 +90,7 @@ class CreateUserForm(BaseUserForm):
|
||||
data['name'],
|
||||
data['email'],
|
||||
data['password'],
|
||||
data['tenant_id'],
|
||||
data['project'],
|
||||
True)
|
||||
messages.success(request,
|
||||
_('User "%s" was successfully created.')
|
||||
@ -100,9 +98,9 @@ class CreateUserForm(BaseUserForm):
|
||||
if data['role_id']:
|
||||
try:
|
||||
api.keystone.add_tenant_user_role(request,
|
||||
data['tenant_id'],
|
||||
new_user.id,
|
||||
data['role_id'])
|
||||
data['project'],
|
||||
new_user.id,
|
||||
data['role_id'])
|
||||
except:
|
||||
exceptions.handle(request,
|
||||
_('Unable to add user'
|
||||
@ -116,17 +114,17 @@ class UpdateUserForm(BaseUserForm):
|
||||
id = forms.CharField(label=_("ID"), widget=forms.HiddenInput)
|
||||
name = forms.CharField(label=_("User Name"))
|
||||
email = forms.EmailField(label=_("Email"))
|
||||
password = forms.RegexField(label=_("Password"),
|
||||
widget=forms.PasswordInput(render_value=False),
|
||||
regex=validators.password_validator(),
|
||||
required=False,
|
||||
error_messages={'invalid':
|
||||
validators.password_validator_msg()})
|
||||
password = forms.RegexField(
|
||||
label=_("Password"),
|
||||
widget=forms.PasswordInput(render_value=False),
|
||||
regex=validators.password_validator(),
|
||||
required=False,
|
||||
error_messages={'invalid': validators.password_validator_msg()})
|
||||
confirm_password = forms.CharField(
|
||||
label=_("Confirm Password"),
|
||||
widget=forms.PasswordInput(render_value=False),
|
||||
required=False)
|
||||
tenant_id = forms.ChoiceField(label=_("Primary Project"))
|
||||
label=_("Confirm Password"),
|
||||
widget=forms.PasswordInput(render_value=False),
|
||||
required=False)
|
||||
project = forms.ChoiceField(label=_("Primary Project"))
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(UpdateUserForm, self).__init__(request, *args, **kwargs)
|
||||
@ -139,62 +137,16 @@ class UpdateUserForm(BaseUserForm):
|
||||
# password and confirm_password strings.
|
||||
@sensitive_variables('data', 'password')
|
||||
def handle(self, request, data):
|
||||
failed, succeeded = [], []
|
||||
user_is_editable = api.keystone.keystone_can_edit_user()
|
||||
user = data.pop('id')
|
||||
tenant = data.pop('tenant_id')
|
||||
|
||||
if user_is_editable:
|
||||
password = data.pop('password')
|
||||
data.pop('confirm_password', None)
|
||||
# Throw away the password confirmation, we're done with it.
|
||||
data.pop('confirm_password', None)
|
||||
|
||||
if user_is_editable:
|
||||
# Update user details
|
||||
msg_bits = (_('name'), _('email'))
|
||||
try:
|
||||
api.keystone.user_update(request, user, **data)
|
||||
succeeded.extend(msg_bits)
|
||||
except:
|
||||
failed.extend(msg_bits)
|
||||
exceptions.handle(request, ignore=True)
|
||||
|
||||
# Update default tenant
|
||||
msg_bits = (_('primary project'),)
|
||||
try:
|
||||
api.keystone.user_update_tenant(request, user, tenant)
|
||||
succeeded.extend(msg_bits)
|
||||
api.keystone.user_update(request, user, **data)
|
||||
messages.success(request,
|
||||
_('User has been updated successfully.'))
|
||||
except:
|
||||
failed.append(msg_bits)
|
||||
exceptions.handle(request, ignore=True)
|
||||
|
||||
# Check for existing roles
|
||||
# Show a warning if no role exists for the tenant
|
||||
user_roles = api.keystone.roles_for_user(request, user, tenant)
|
||||
if not user_roles:
|
||||
messages.warning(request,
|
||||
_('The user %s has no role defined for' +
|
||||
' that project.')
|
||||
% data.get('name', None))
|
||||
|
||||
if user_is_editable:
|
||||
# If present, update password
|
||||
# FIXME(gabriel): password change should be its own form and view
|
||||
if password:
|
||||
msg_bits = (_('password'),)
|
||||
try:
|
||||
api.keystone.user_update_password(request, user, password)
|
||||
succeeded.extend(msg_bits)
|
||||
if user == request.user.id:
|
||||
logout(request)
|
||||
except:
|
||||
failed.extend(msg_bits)
|
||||
exceptions.handle(request, ignore=True)
|
||||
|
||||
if succeeded:
|
||||
messages.success(request, _('User has been updated successfully.'))
|
||||
if failed:
|
||||
failed = map(force_unicode, failed)
|
||||
messages.error(request,
|
||||
_('Unable to update %(attributes)s for the user.')
|
||||
% {"attributes": ", ".join(failed)})
|
||||
messages.error(request, _('Unable to update the user.'))
|
||||
return True
|
||||
|
@ -55,8 +55,7 @@ class UsersViewTests(test.BaseAdminViewTests):
|
||||
user = self.users.get(id="1")
|
||||
role = self.roles.first()
|
||||
|
||||
api.keystone.tenant_list(IgnoreArg(), admin=True) \
|
||||
.AndReturn(self.tenants.list())
|
||||
api.keystone.tenant_list(IgnoreArg()).AndReturn(self.tenants.list())
|
||||
api.keystone.user_create(IgnoreArg(),
|
||||
user.name,
|
||||
user.email,
|
||||
@ -74,7 +73,7 @@ class UsersViewTests(test.BaseAdminViewTests):
|
||||
'name': user.name,
|
||||
'email': user.email,
|
||||
'password': user.password,
|
||||
'tenant_id': self.tenant.id,
|
||||
'project': self.tenant.id,
|
||||
'role_id': self.roles.first().id,
|
||||
'confirm_password': user.password}
|
||||
res = self.client.post(USER_CREATE_URL, formData)
|
||||
@ -88,8 +87,7 @@ class UsersViewTests(test.BaseAdminViewTests):
|
||||
def test_create_with_password_mismatch(self):
|
||||
user = self.users.get(id="1")
|
||||
|
||||
api.keystone.tenant_list(IgnoreArg(), admin=True) \
|
||||
.AndReturn(self.tenants.list())
|
||||
api.keystone.tenant_list(IgnoreArg()).AndReturn(self.tenants.list())
|
||||
api.keystone.role_list(IgnoreArg()).AndReturn(self.roles.list())
|
||||
api.keystone.get_default_role(IgnoreArg()) \
|
||||
.AndReturn(self.roles.first())
|
||||
@ -100,7 +98,7 @@ class UsersViewTests(test.BaseAdminViewTests):
|
||||
'name': user.name,
|
||||
'email': user.email,
|
||||
'password': user.password,
|
||||
'tenant_id': self.tenant.id,
|
||||
'project': self.tenant.id,
|
||||
'role_id': self.roles.first().id,
|
||||
'confirm_password': "doesntmatch"}
|
||||
|
||||
@ -114,8 +112,7 @@ class UsersViewTests(test.BaseAdminViewTests):
|
||||
def test_create_validation_for_password_too_short(self):
|
||||
user = self.users.get(id="1")
|
||||
|
||||
api.keystone.tenant_list(IgnoreArg(), admin=True) \
|
||||
.AndReturn(self.tenants.list())
|
||||
api.keystone.tenant_list(IgnoreArg()).AndReturn(self.tenants.list())
|
||||
api.keystone.role_list(IgnoreArg()).AndReturn(self.roles.list())
|
||||
api.keystone.get_default_role(IgnoreArg()) \
|
||||
.AndReturn(self.roles.first())
|
||||
@ -127,7 +124,7 @@ class UsersViewTests(test.BaseAdminViewTests):
|
||||
'name': user.name,
|
||||
'email': user.email,
|
||||
'password': 'four',
|
||||
'tenant_id': self.tenant.id,
|
||||
'project': self.tenant.id,
|
||||
'role_id': self.roles.first().id,
|
||||
'confirm_password': 'four'}
|
||||
|
||||
@ -143,8 +140,7 @@ class UsersViewTests(test.BaseAdminViewTests):
|
||||
def test_create_validation_for_password_too_long(self):
|
||||
user = self.users.get(id="1")
|
||||
|
||||
api.keystone.tenant_list(IgnoreArg(), admin=True) \
|
||||
.AndReturn(self.tenants.list())
|
||||
api.keystone.tenant_list(IgnoreArg()).AndReturn(self.tenants.list())
|
||||
api.keystone.role_list(IgnoreArg()).AndReturn(self.roles.list())
|
||||
api.keystone.get_default_role(IgnoreArg()) \
|
||||
.AndReturn(self.roles.first())
|
||||
@ -156,7 +152,7 @@ class UsersViewTests(test.BaseAdminViewTests):
|
||||
'name': user.name,
|
||||
'email': user.email,
|
||||
'password': 'MoreThanEighteenChars',
|
||||
'tenant_id': self.tenant.id,
|
||||
'project': self.tenant.id,
|
||||
'role_id': self.roles.first().id,
|
||||
'confirm_password': 'MoreThanEighteenChars'}
|
||||
|
||||
@ -174,24 +170,17 @@ class UsersViewTests(test.BaseAdminViewTests):
|
||||
'roles_for_user', )})
|
||||
def test_update(self):
|
||||
user = self.users.get(id="1")
|
||||
test_password = 'normalpwd'
|
||||
|
||||
api.keystone.user_get(IsA(http.HttpRequest), '1',
|
||||
admin=True).AndReturn(user)
|
||||
api.keystone.tenant_list(IgnoreArg(),
|
||||
admin=True).AndReturn(self.tenants.list())
|
||||
admin=True).AndReturn(user)
|
||||
api.keystone.tenant_list(IgnoreArg()).AndReturn(self.tenants.list())
|
||||
api.keystone.user_update(IsA(http.HttpRequest),
|
||||
user.id,
|
||||
email=u'test@example.com',
|
||||
name=u'test_user').AndReturn(None)
|
||||
api.keystone.user_update_tenant(IsA(http.HttpRequest),
|
||||
user.id,
|
||||
self.tenant.id).AndReturn(None)
|
||||
api.keystone.roles_for_user(IsA(http.HttpRequest),
|
||||
user.id,
|
||||
self.tenant.id).AndReturn(None)
|
||||
api.keystone.user_update_password(IsA(http.HttpRequest),
|
||||
user.id,
|
||||
IgnoreArg()).AndReturn(None)
|
||||
name=u'test_user',
|
||||
password=test_password,
|
||||
project=self.tenant.id).AndReturn(None)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
@ -199,14 +188,13 @@ class UsersViewTests(test.BaseAdminViewTests):
|
||||
'id': user.id,
|
||||
'name': user.name,
|
||||
'email': user.email,
|
||||
'password': 'normalpwd',
|
||||
'tenant_id': self.tenant.id,
|
||||
'confirm_password': 'normalpwd'}
|
||||
'password': test_password,
|
||||
'project': self.tenant.id,
|
||||
'confirm_password': test_password}
|
||||
|
||||
res = self.client.post(USER_UPDATE_URL, formData)
|
||||
|
||||
self.assertNoFormErrors(res)
|
||||
self.assertMessageCount(warning=1)
|
||||
|
||||
@test.create_stubs({api.keystone: ('user_get',
|
||||
'tenant_list',
|
||||
@ -219,28 +207,21 @@ class UsersViewTests(test.BaseAdminViewTests):
|
||||
api.keystone.user_get(IsA(http.HttpRequest),
|
||||
'1',
|
||||
admin=True).AndReturn(user)
|
||||
api.keystone.tenant_list(IgnoreArg(), admin=True) \
|
||||
.AndReturn(self.tenants.list())
|
||||
api.keystone.tenant_list(IgnoreArg()).AndReturn(self.tenants.list())
|
||||
api.keystone.keystone_can_edit_user().AndReturn(False)
|
||||
api.keystone.keystone_can_edit_user().AndReturn(False)
|
||||
api.keystone.user_update_tenant(IsA(http.HttpRequest),
|
||||
user.id,
|
||||
self.tenant.id).AndReturn(None)
|
||||
api.keystone.roles_for_user(IsA(http.HttpRequest),
|
||||
user.id,
|
||||
self.tenant.id).AndReturn(None)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
formData = {'method': 'UpdateUserForm',
|
||||
'id': user.id,
|
||||
'name': user.name,
|
||||
'tenant_id': self.tenant.id, }
|
||||
'project': self.tenant.id, }
|
||||
|
||||
res = self.client.post(USER_UPDATE_URL, formData)
|
||||
|
||||
self.assertNoFormErrors(res)
|
||||
self.assertMessageCount(warning=1)
|
||||
self.assertMessageCount(error=1)
|
||||
|
||||
@test.create_stubs({api.keystone: ('user_get', 'tenant_list')})
|
||||
def test_update_validation_for_password_too_short(self):
|
||||
@ -248,8 +229,7 @@ class UsersViewTests(test.BaseAdminViewTests):
|
||||
|
||||
api.keystone.user_get(IsA(http.HttpRequest), '1',
|
||||
admin=True).AndReturn(user)
|
||||
api.keystone.tenant_list(IgnoreArg(),
|
||||
admin=True).AndReturn(self.tenants.list())
|
||||
api.keystone.tenant_list(IgnoreArg()).AndReturn(self.tenants.list())
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
@ -258,7 +238,7 @@ class UsersViewTests(test.BaseAdminViewTests):
|
||||
'name': user.name,
|
||||
'email': user.email,
|
||||
'password': 't',
|
||||
'tenant_id': self.tenant.id,
|
||||
'project': self.tenant.id,
|
||||
'confirm_password': 't'}
|
||||
|
||||
res = self.client.post(USER_UPDATE_URL, formData)
|
||||
@ -273,8 +253,7 @@ class UsersViewTests(test.BaseAdminViewTests):
|
||||
|
||||
api.keystone.user_get(IsA(http.HttpRequest), '1',
|
||||
admin=True).AndReturn(user)
|
||||
api.keystone.tenant_list(IgnoreArg(),
|
||||
admin=True).AndReturn(self.tenants.list())
|
||||
api.keystone.tenant_list(IgnoreArg()).AndReturn(self.tenants.list())
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
@ -283,7 +262,7 @@ class UsersViewTests(test.BaseAdminViewTests):
|
||||
'name': user.name,
|
||||
'email': user.email,
|
||||
'password': 'ThisIsASuperLongPassword',
|
||||
'tenant_id': self.tenant.id,
|
||||
'project': self.tenant.id,
|
||||
'confirm_password': 'ThisIsASuperLongPassword'}
|
||||
|
||||
res = self.client.post(USER_UPDATE_URL, formData)
|
||||
@ -374,8 +353,7 @@ class SeleniumTests(test.SeleniumAdminTestCase):
|
||||
'role_list',
|
||||
'user_list')})
|
||||
def test_modal_create_user_with_passwords_not_matching(self):
|
||||
api.keystone.tenant_list(IgnoreArg(), admin=True) \
|
||||
.AndReturn(self.tenants.list())
|
||||
api.keystone.tenant_list(IgnoreArg()).AndReturn(self.tenants.list())
|
||||
api.keystone.role_list(IgnoreArg()).AndReturn(self.roles.list())
|
||||
api.keystone.user_list(IgnoreArg()).AndReturn(self.users.list())
|
||||
api.keystone.get_default_role(IgnoreArg()) \
|
||||
@ -406,8 +384,7 @@ class SeleniumTests(test.SeleniumAdminTestCase):
|
||||
def test_update_user_with_passwords_not_matching(self):
|
||||
api.keystone.user_get(IsA(http.HttpRequest), '1',
|
||||
admin=True).AndReturn(self.user)
|
||||
api.keystone.tenant_list(IgnoreArg(), admin=True) \
|
||||
.AndReturn(self.tenants.list())
|
||||
api.keystone.tenant_list(IgnoreArg()).AndReturn(self.tenants.list())
|
||||
self.mox.ReplayAll()
|
||||
|
||||
self.selenium.get("%s%s" % (self.live_server_url, USER_UPDATE_URL))
|
||||
|
@ -80,7 +80,7 @@ class UpdateView(forms.ModalFormView):
|
||||
user = self.get_object()
|
||||
return {'id': user.id,
|
||||
'name': user.name,
|
||||
'tenant_id': getattr(user, 'tenantId', None),
|
||||
'project': user.project_id,
|
||||
'email': user.email}
|
||||
|
||||
|
||||
|
@ -36,8 +36,8 @@ class VolumeTests(test.BaseAdminViewTests):
|
||||
AndReturn([self.servers.list(), False])
|
||||
cinder.volume_type_list(IsA(http.HttpRequest)).\
|
||||
AndReturn(self.volume_types.list())
|
||||
keystone.tenant_list(IsA(http.HttpRequest),
|
||||
admin=True).AndReturn(self.tenants.list())
|
||||
keystone.tenant_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.tenants.list())
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
@ -80,8 +80,8 @@ class VolumeTests(test.BaseAdminViewTests):
|
||||
AndReturn(self.volume_types.list())
|
||||
cinder.volume_type_delete(IsA(http.HttpRequest),
|
||||
str(volume_type.id))
|
||||
keystone.tenant_list(IsA(http.HttpRequest),
|
||||
admin=True).AndReturn(self.tenants.list())
|
||||
keystone.tenant_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.tenants.list())
|
||||
self.mox.ReplayAll()
|
||||
|
||||
res = self.client.post(reverse('horizon:admin:volumes:index'),
|
||||
|
@ -45,7 +45,7 @@ class IndexView(tables.MultiTableView, VolumeTableMixIn):
|
||||
|
||||
# Gather our tenants to correlate against IDs
|
||||
try:
|
||||
tenants = keystone.tenant_list(self.request, admin=True)
|
||||
tenants = keystone.tenant_list(self.request)
|
||||
except:
|
||||
tenants = []
|
||||
msg = _('Unable to retrieve volume tenant information.')
|
||||
|
@ -26,6 +26,15 @@ TEMPLATE_DEBUG = DEBUG
|
||||
#CSRF_COOKIE_SECURE = True
|
||||
#SESSION_COOKIE_SECURE = True
|
||||
|
||||
# Overrides for OpenStack API versions. Use this setting to force the
|
||||
# OpenStack dashboard to use a specfic API version for a given service API.
|
||||
# NOTE: The version should be formatted as it appears in the URL for the
|
||||
# service API. For example, The identity service APIs have inconsistent
|
||||
# use of the decimal point, so valid options would be "2.0" or "3".
|
||||
# OPENSTACK_API_VERSIONS = {
|
||||
# "identity": 3
|
||||
# }
|
||||
|
||||
# Default OpenStack Dashboard configuration.
|
||||
HORIZON_CONFIG = {
|
||||
'dashboards': ('project', 'admin', 'settings',),
|
||||
|
@ -66,9 +66,11 @@ class RoleAPITests(test.APITestCase):
|
||||
keystoneclient.roles.roles_for_user(self.user.id,
|
||||
tenant.id).AndReturn(self.roles)
|
||||
for role in self.roles:
|
||||
keystoneclient.roles.remove_user_role(self.user.id,
|
||||
role.id,
|
||||
tenant.id)
|
||||
keystoneclient.roles.revoke(role.id,
|
||||
domain=None,
|
||||
group=None,
|
||||
project=tenant.id,
|
||||
user=self.user.id)
|
||||
self.mox.ReplayAll()
|
||||
api.keystone.remove_tenant_user(self.request, tenant.id, self.user.id)
|
||||
|
||||
|
@ -108,6 +108,7 @@ def data(TEST):
|
||||
'email': 'test@example.com',
|
||||
'password': 'password',
|
||||
'token': 'test_token',
|
||||
'project_id': '1',
|
||||
'enabled': True}
|
||||
user = users.User(users.UserManager(None), user_dict)
|
||||
user_dict = {'id': "2",
|
||||
@ -115,6 +116,7 @@ def data(TEST):
|
||||
'email': 'two@example.com',
|
||||
'password': 'password',
|
||||
'token': 'test_token',
|
||||
'project_id': '1',
|
||||
'enabled': True}
|
||||
user2 = users.User(users.UserManager(None), user_dict)
|
||||
user_dict = {'id': "3",
|
||||
@ -122,6 +124,7 @@ def data(TEST):
|
||||
'email': 'three@example.com',
|
||||
'password': 'password',
|
||||
'token': 'test_token',
|
||||
'project_id': '1',
|
||||
'enabled': True}
|
||||
user3 = users.User(users.UserManager(None), user_dict)
|
||||
TEST.users.add(user, user2, user3)
|
||||
|
Loading…
Reference in New Issue
Block a user