Enable using multiple API versions for Identity Service.
Introduces a mechanism for switching between API versions, and implements it in a proof-of-concept fashion for the Keystone v3 API. Converts the existing Users and Projects API methods to use it. This changed some method signatures, and therefore altered a number of views and tests. However, all code related to the version cahnges is contained in the api.keystone module. This seems like a sane process going forwards. Future TODOs are marked in the code, including auto-detection of API versions and better endpoint URL construction. Partially implements blueprint api-capability-detection Change-Id: Ied04200fe6c257aac2241d36628965a3bb6658b9
This commit is contained in:
parent
a424a35da4
commit
68a55e3fe8
@ -33,6 +33,38 @@ __all__ = ('APIResourceWrapper', 'APIDictWrapper',
|
|||||||
LOG = logging.getLogger(__name__)
|
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):
|
class APIResourceWrapper(object):
|
||||||
""" Simple wrapper for api objects
|
""" Simple wrapper for api objects
|
||||||
|
|
||||||
|
@ -21,18 +21,17 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
import urlparse
|
import urlparse
|
||||||
from pkg_resources import get_distribution
|
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.contrib.auth import logout
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from keystoneclient import service_catalog
|
from keystoneclient.exceptions import ClientException
|
||||||
from keystoneclient.v2_0 import client as keystone_client
|
|
||||||
from keystoneclient.v2_0 import tokens
|
|
||||||
|
|
||||||
from openstack_auth.backend import KEYSTONE_CLIENT_ATTR
|
from openstack_auth.backend import KEYSTONE_CLIENT_ATTR
|
||||||
|
|
||||||
from horizon import exceptions
|
from horizon import exceptions
|
||||||
|
from horizon import messages
|
||||||
|
|
||||||
from openstack_dashboard.api import base
|
from openstack_dashboard.api import base
|
||||||
|
|
||||||
@ -41,6 +40,39 @@ LOG = logging.getLogger(__name__)
|
|||||||
DEFAULT_ROLE = None
|
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):
|
class Service(base.APIDictWrapper):
|
||||||
""" Wrapper for a dict based on the service data from keystone. """
|
""" Wrapper for a dict based on the service data from keystone. """
|
||||||
_attrs = ['id', 'type', 'name']
|
_attrs = ['id', 'type', 'name']
|
||||||
@ -55,8 +87,7 @@ class Service(base.APIDictWrapper):
|
|||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
if(self.type == "identity"):
|
if(self.type == "identity"):
|
||||||
return _("%(type)s (%(backend)s backend)") \
|
return _("%(type)s (%(backend)s backend)") \
|
||||||
% {"type": self.type,
|
% {"type": self.type, "backend": keystone_backend_name()}
|
||||||
"backend": keystone_backend_name()}
|
|
||||||
else:
|
else:
|
||||||
return self.type
|
return self.type
|
||||||
|
|
||||||
@ -66,11 +97,20 @@ class Service(base.APIDictWrapper):
|
|||||||
|
|
||||||
def _get_endpoint_url(request, endpoint_type, catalog=None):
|
def _get_endpoint_url(request, endpoint_type, catalog=None):
|
||||||
if getattr(request.user, "service_catalog", None):
|
if getattr(request.user, "service_catalog", None):
|
||||||
return base.url_for(request,
|
url = base.url_for(request,
|
||||||
service_type='identity',
|
service_type='identity',
|
||||||
endpoint_type=endpoint_type)
|
endpoint_type=endpoint_type)
|
||||||
return request.session.get('region_endpoint',
|
else:
|
||||||
getattr(settings, 'OPENSTACK_KEYSTONE_URL'))
|
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):
|
def keystoneclient(request, admin=False):
|
||||||
@ -105,6 +145,8 @@ def keystoneclient(request, admin=False):
|
|||||||
'OPENSTACK_ENDPOINT_TYPE',
|
'OPENSTACK_ENDPOINT_TYPE',
|
||||||
'internalURL')
|
'internalURL')
|
||||||
|
|
||||||
|
api_version = VERSIONS.get_active_version()
|
||||||
|
|
||||||
# Take care of client connection caching/fetching a new client.
|
# Take care of client connection caching/fetching a new client.
|
||||||
# Admin vs. non-admin clients are cached separately for token matching.
|
# Admin vs. non-admin clients are cached separately for token matching.
|
||||||
cache_attr = "_keystoneclient_admin" if admin else KEYSTONE_CLIENT_ATTR
|
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)
|
endpoint = _get_endpoint_url(request, endpoint_type)
|
||||||
insecure = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False)
|
insecure = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False)
|
||||||
LOG.debug("Creating a new keystoneclient connection to %s." % endpoint)
|
LOG.debug("Creating a new keystoneclient connection to %s." % endpoint)
|
||||||
|
remote_addr = request.environ.get('REMOTE_ADDR', '')
|
||||||
conn = keystone_client.Client(
|
conn = api_version['client'].Client(token=user.token.id,
|
||||||
token=user.token.id, endpoint=endpoint,
|
endpoint=endpoint,
|
||||||
original_ip=request.environ.get('REMOTE_ADDR', ''),
|
original_ip=remote_addr,
|
||||||
insecure=insecure)
|
insecure=insecure,
|
||||||
|
debug=settings.DEBUG)
|
||||||
setattr(request, cache_attr, conn)
|
setattr(request, cache_attr, conn)
|
||||||
return conn
|
return conn
|
||||||
|
|
||||||
|
|
||||||
def tenant_create(request, tenant_name, description, enabled):
|
def tenant_create(request, name, description=None, enabled=None, domain=None):
|
||||||
return keystoneclient(request, admin=True).tenants.create(tenant_name,
|
manager = VERSIONS.get_project_manager(request, admin=True)
|
||||||
description,
|
if VERSIONS.active < 3:
|
||||||
enabled)
|
return manager.create(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')
|
|
||||||
else:
|
else:
|
||||||
endpoint_type = getattr(settings,
|
return manager.create(name, domain,
|
||||||
'OPENSTACK_ENDPOINT_TYPE',
|
description=description,
|
||||||
'internalURL')
|
enabled=enabled)
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
def user_list(request, tenant_id=None):
|
# TODO(gabriel): Is there ever a valid case for admin to be false here?
|
||||||
return keystoneclient(request, admin=True).users.list(tenant_id=tenant_id)
|
# 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):
|
def tenant_delete(request, project):
|
||||||
return keystoneclient(request, admin=True).users.create(user_id,
|
manager = VERSIONS.get_project_manager(request, admin=True)
|
||||||
password,
|
return manager.delete(project)
|
||||||
email,
|
|
||||||
tenant_id,
|
|
||||||
enabled)
|
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):
|
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):
|
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):
|
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):
|
def user_update_enabled(request, user, enabled):
|
||||||
return keystoneclient(request, admin=True).users.update_enabled(user_id,
|
manager = keystoneclient(request, admin=True).users
|
||||||
enabled)
|
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):
|
def user_update_password(request, user, password, admin=True):
|
||||||
return keystoneclient(request, admin=admin).users.update_password(user_id,
|
manager = keystoneclient(request, admin=admin).users
|
||||||
password)
|
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):
|
def user_update_tenant(request, user, project, admin=True):
|
||||||
return keystoneclient(request, admin=admin).users.update_tenant(user_id,
|
manager = keystoneclient(request, admin=admin).users
|
||||||
tenant_id)
|
if VERSIONS.active < 3:
|
||||||
|
return manager.update_tenant(user, project)
|
||||||
|
else:
|
||||||
|
return manager.update(user, project=project)
|
||||||
|
|
||||||
|
|
||||||
def role_list(request):
|
def role_list(request):
|
||||||
@ -220,29 +328,42 @@ def role_list(request):
|
|||||||
|
|
||||||
|
|
||||||
def roles_for_user(request, user, project):
|
def roles_for_user(request, user, project):
|
||||||
return keystoneclient(request, admin=True).roles.roles_for_user(user,
|
manager = keystoneclient(request, admin=True).roles
|
||||||
project)
|
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. """
|
""" Adds a role for a user on a tenant. """
|
||||||
return keystoneclient(request, admin=True).roles.add_user_role(user_id,
|
manager = keystoneclient(request, admin=True).roles
|
||||||
role_id,
|
if VERSIONS.active < 3:
|
||||||
tenant_id)
|
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. """
|
""" Removes a given single role for a user from a tenant. """
|
||||||
client = keystoneclient(request, admin=True)
|
manager = keystoneclient(request, admin=True).roles
|
||||||
client.roles.remove_user_role(user_id, role_id, tenant_id)
|
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. """
|
""" Removes all roles from a user on a tenant, removing them from it. """
|
||||||
client = keystoneclient(request, admin=True)
|
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:
|
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):
|
def get_default_role(request):
|
||||||
|
@ -33,7 +33,7 @@ class InstanceViewTest(test.BaseAdminViewTests):
|
|||||||
servers = self.servers.list()
|
servers = self.servers.list()
|
||||||
flavors = self.flavors.list()
|
flavors = self.flavors.list()
|
||||||
tenants = self.tenants.list()
|
tenants = self.tenants.list()
|
||||||
api.keystone.tenant_list(IsA(http.HttpRequest), admin=True).\
|
api.keystone.tenant_list(IsA(http.HttpRequest)).\
|
||||||
AndReturn(tenants)
|
AndReturn(tenants)
|
||||||
search_opts = {'marker': None, 'paginate': True}
|
search_opts = {'marker': None, 'paginate': True}
|
||||||
api.nova.server_list(IsA(http.HttpRequest),
|
api.nova.server_list(IsA(http.HttpRequest),
|
||||||
@ -62,7 +62,7 @@ class InstanceViewTest(test.BaseAdminViewTests):
|
|||||||
.AndReturn([servers, False])
|
.AndReturn([servers, False])
|
||||||
api.nova.flavor_list(IsA(http.HttpRequest)). \
|
api.nova.flavor_list(IsA(http.HttpRequest)). \
|
||||||
AndRaise(self.exceptions.nova)
|
AndRaise(self.exceptions.nova)
|
||||||
api.keystone.tenant_list(IsA(http.HttpRequest), admin=True).\
|
api.keystone.tenant_list(IsA(http.HttpRequest)).\
|
||||||
AndReturn(tenants)
|
AndReturn(tenants)
|
||||||
for server in servers:
|
for server in servers:
|
||||||
api.nova.flavor_get(IsA(http.HttpRequest), server.flavor["id"]). \
|
api.nova.flavor_get(IsA(http.HttpRequest), server.flavor["id"]). \
|
||||||
@ -93,7 +93,7 @@ class InstanceViewTest(test.BaseAdminViewTests):
|
|||||||
.AndReturn([servers, False])
|
.AndReturn([servers, False])
|
||||||
api.nova.flavor_list(IsA(http.HttpRequest)). \
|
api.nova.flavor_list(IsA(http.HttpRequest)). \
|
||||||
AndReturn(flavors)
|
AndReturn(flavors)
|
||||||
api.keystone.tenant_list(IsA(http.HttpRequest), admin=True).\
|
api.keystone.tenant_list(IsA(http.HttpRequest)).\
|
||||||
AndReturn(tenants)
|
AndReturn(tenants)
|
||||||
for server in servers:
|
for server in servers:
|
||||||
api.nova.flavor_get(IsA(http.HttpRequest), server.flavor["id"]). \
|
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',),
|
@test.create_stubs({api.nova: ('flavor_list', 'server_list',),
|
||||||
api.keystone: ('tenant_list',)})
|
api.keystone: ('tenant_list',)})
|
||||||
def test_index_options_before_migrate(self):
|
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())
|
AndReturn(self.tenants.list())
|
||||||
search_opts = {'marker': None, 'paginate': True}
|
search_opts = {'marker': None, 'paginate': True}
|
||||||
api.nova.server_list(IsA(http.HttpRequest),
|
api.nova.server_list(IsA(http.HttpRequest),
|
||||||
@ -173,8 +173,8 @@ class InstanceViewTest(test.BaseAdminViewTests):
|
|||||||
def test_index_options_after_migrate(self):
|
def test_index_options_after_migrate(self):
|
||||||
server = self.servers.first()
|
server = self.servers.first()
|
||||||
server.status = "VERIFY_RESIZE"
|
server.status = "VERIFY_RESIZE"
|
||||||
api.keystone.tenant_list(IsA(http.HttpRequest), admin=True).\
|
api.keystone.tenant_list(IsA(http.HttpRequest)) \
|
||||||
AndReturn(self.tenants.list())
|
.AndReturn(self.tenants.list())
|
||||||
search_opts = {'marker': None, 'paginate': True}
|
search_opts = {'marker': None, 'paginate': True}
|
||||||
api.nova.server_list(IsA(http.HttpRequest),
|
api.nova.server_list(IsA(http.HttpRequest),
|
||||||
all_tenants=True, search_opts=search_opts) \
|
all_tenants=True, search_opts=search_opts) \
|
||||||
|
@ -73,7 +73,7 @@ class AdminIndexView(tables.DataTableView):
|
|||||||
|
|
||||||
# Gather our tenants to correlate against IDs
|
# Gather our tenants to correlate against IDs
|
||||||
try:
|
try:
|
||||||
tenants = api.keystone.tenant_list(self.request, admin=True)
|
tenants = api.keystone.tenant_list(self.request)
|
||||||
except:
|
except:
|
||||||
tenants = []
|
tenants = []
|
||||||
msg = _('Unable to retrieve instance tenant information.')
|
msg = _('Unable to retrieve instance tenant information.')
|
||||||
|
@ -48,7 +48,7 @@ class CreateNetwork(forms.SelfHandlingForm):
|
|||||||
def __init__(self, request, *args, **kwargs):
|
def __init__(self, request, *args, **kwargs):
|
||||||
super(CreateNetwork, self).__init__(request, *args, **kwargs)
|
super(CreateNetwork, self).__init__(request, *args, **kwargs)
|
||||||
tenant_choices = [('', _("Select a project"))]
|
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:
|
if tenant.enabled:
|
||||||
tenant_choices.append((tenant.id, tenant.name))
|
tenant_choices.append((tenant.id, tenant.name))
|
||||||
self.fields['tenant_id'].choices = tenant_choices
|
self.fields['tenant_id'].choices = tenant_choices
|
||||||
|
@ -35,7 +35,7 @@ class NetworkTests(test.BaseAdminViewTests):
|
|||||||
tenants = self.tenants.list()
|
tenants = self.tenants.list()
|
||||||
api.quantum.network_list(IsA(http.HttpRequest)) \
|
api.quantum.network_list(IsA(http.HttpRequest)) \
|
||||||
.AndReturn(self.networks.list())
|
.AndReturn(self.networks.list())
|
||||||
api.keystone.tenant_list(IsA(http.HttpRequest), admin=True)\
|
api.keystone.tenant_list(IsA(http.HttpRequest))\
|
||||||
.AndReturn(tenants)
|
.AndReturn(tenants)
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
@ -151,7 +151,7 @@ class NetworkTests(test.BaseAdminViewTests):
|
|||||||
@test.create_stubs({api.keystone: ('tenant_list',)})
|
@test.create_stubs({api.keystone: ('tenant_list',)})
|
||||||
def test_network_create_get(self):
|
def test_network_create_get(self):
|
||||||
tenants = self.tenants.list()
|
tenants = self.tenants.list()
|
||||||
api.keystone.tenant_list(IsA(http.HttpRequest), admin=True)\
|
api.keystone.tenant_list(IsA(http.HttpRequest))\
|
||||||
.AndReturn(tenants)
|
.AndReturn(tenants)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
@ -166,7 +166,7 @@ class NetworkTests(test.BaseAdminViewTests):
|
|||||||
tenants = self.tenants.list()
|
tenants = self.tenants.list()
|
||||||
tenant_id = self.tenants.first().id
|
tenant_id = self.tenants.first().id
|
||||||
network = self.networks.first()
|
network = self.networks.first()
|
||||||
api.keystone.tenant_list(IsA(http.HttpRequest), admin=True)\
|
api.keystone.tenant_list(IsA(http.HttpRequest))\
|
||||||
.AndReturn(tenants)
|
.AndReturn(tenants)
|
||||||
params = {'name': network.name,
|
params = {'name': network.name,
|
||||||
'tenant_id': tenant_id,
|
'tenant_id': tenant_id,
|
||||||
@ -194,7 +194,7 @@ class NetworkTests(test.BaseAdminViewTests):
|
|||||||
tenants = self.tenants.list()
|
tenants = self.tenants.list()
|
||||||
tenant_id = self.tenants.first().id
|
tenant_id = self.tenants.first().id
|
||||||
network = self.networks.first()
|
network = self.networks.first()
|
||||||
api.keystone.tenant_list(IsA(http.HttpRequest), admin=True)\
|
api.keystone.tenant_list(IsA(http.HttpRequest))\
|
||||||
.AndReturn(tenants)
|
.AndReturn(tenants)
|
||||||
params = {'name': network.name,
|
params = {'name': network.name,
|
||||||
'tenant_id': tenant_id,
|
'tenant_id': tenant_id,
|
||||||
@ -301,7 +301,7 @@ class NetworkTests(test.BaseAdminViewTests):
|
|||||||
def test_delete_network(self):
|
def test_delete_network(self):
|
||||||
tenants = self.tenants.list()
|
tenants = self.tenants.list()
|
||||||
network = self.networks.first()
|
network = self.networks.first()
|
||||||
api.keystone.tenant_list(IsA(http.HttpRequest), admin=True)\
|
api.keystone.tenant_list(IsA(http.HttpRequest))\
|
||||||
.AndReturn(tenants)
|
.AndReturn(tenants)
|
||||||
api.quantum.network_list(IsA(http.HttpRequest))\
|
api.quantum.network_list(IsA(http.HttpRequest))\
|
||||||
.AndReturn([network])
|
.AndReturn([network])
|
||||||
@ -320,7 +320,7 @@ class NetworkTests(test.BaseAdminViewTests):
|
|||||||
def test_delete_network_exception(self):
|
def test_delete_network_exception(self):
|
||||||
tenants = self.tenants.list()
|
tenants = self.tenants.list()
|
||||||
network = self.networks.first()
|
network = self.networks.first()
|
||||||
api.keystone.tenant_list(IsA(http.HttpRequest), admin=True)\
|
api.keystone.tenant_list(IsA(http.HttpRequest))\
|
||||||
.AndReturn(tenants)
|
.AndReturn(tenants)
|
||||||
api.quantum.network_list(IsA(http.HttpRequest))\
|
api.quantum.network_list(IsA(http.HttpRequest))\
|
||||||
.AndReturn([network])
|
.AndReturn([network])
|
||||||
|
@ -42,7 +42,7 @@ class IndexView(tables.DataTableView):
|
|||||||
def _get_tenant_list(self):
|
def _get_tenant_list(self):
|
||||||
if not hasattr(self, "_tenants"):
|
if not hasattr(self, "_tenants"):
|
||||||
try:
|
try:
|
||||||
tenants = api.keystone.tenant_list(self.request, admin=True)
|
tenants = api.keystone.tenant_list(self.request)
|
||||||
except:
|
except:
|
||||||
tenants = []
|
tenants = []
|
||||||
msg = _('Unable to retrieve instance tenant information.')
|
msg = _('Unable to retrieve instance tenant information.')
|
||||||
|
@ -45,7 +45,7 @@ class UsageViewTests(test.BaseAdminViewTests):
|
|||||||
now = timezone.now()
|
now = timezone.now()
|
||||||
usage_obj = api.nova.NovaUsage(self.usages.first())
|
usage_obj = api.nova.NovaUsage(self.usages.first())
|
||||||
quota_data = self.quota_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())
|
.AndReturn(self.tenants.list())
|
||||||
api.nova.usage_list(IsA(http.HttpRequest),
|
api.nova.usage_list(IsA(http.HttpRequest),
|
||||||
datetime.datetime(now.year, now.month, 1, 0, 0, 0),
|
datetime.datetime(now.year, now.month, 1, 0, 0, 0),
|
||||||
@ -77,7 +77,7 @@ class UsageViewTests(test.BaseAdminViewTests):
|
|||||||
now = timezone.now()
|
now = timezone.now()
|
||||||
usage_obj = api.nova.NovaUsage(self.usages.first())
|
usage_obj = api.nova.NovaUsage(self.usages.first())
|
||||||
quota_data = self.quota_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())
|
.AndReturn(self.tenants.list())
|
||||||
api.nova.usage_list(IsA(http.HttpRequest),
|
api.nova.usage_list(IsA(http.HttpRequest),
|
||||||
datetime.datetime(now.year, now.month, 1, 0, 0, 0),
|
datetime.datetime(now.year, now.month, 1, 0, 0, 0),
|
||||||
|
@ -41,7 +41,7 @@ class GlobalOverview(usage.UsageView):
|
|||||||
data = super(GlobalOverview, self).get_data()
|
data = super(GlobalOverview, self).get_data()
|
||||||
# Pre-fill tenant names
|
# Pre-fill tenant names
|
||||||
try:
|
try:
|
||||||
tenants = api.keystone.tenant_list(self.request, admin=True)
|
tenants = api.keystone.tenant_list(self.request)
|
||||||
except:
|
except:
|
||||||
tenants = []
|
tenants = []
|
||||||
exceptions.handle(self.request,
|
exceptions.handle(self.request,
|
||||||
|
@ -25,9 +25,9 @@ from openstack_dashboard.dashboards.admin.users.forms import CreateUserForm
|
|||||||
|
|
||||||
class CreateUser(CreateUserForm):
|
class CreateUser(CreateUserForm):
|
||||||
role_id = forms.ChoiceField(widget=forms.HiddenInput())
|
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):
|
def __init__(self, request, *args, **kwargs):
|
||||||
super(CreateUser, self).__init__(request, *args, **kwargs)
|
super(CreateUser, self).__init__(request, *args, **kwargs)
|
||||||
tenant_id = self.request.path.split("/")[-1]
|
project = self.request.path.split("/")[-1]
|
||||||
self.fields['tenant_id'].initial = tenant_id
|
self.fields['project'].initial = project
|
||||||
|
@ -34,7 +34,7 @@ INDEX_URL = reverse('horizon:admin:projects:index')
|
|||||||
class TenantsViewTests(test.BaseAdminViewTests):
|
class TenantsViewTests(test.BaseAdminViewTests):
|
||||||
def test_index(self):
|
def test_index(self):
|
||||||
self.mox.StubOutWithMock(api.keystone, 'tenant_list')
|
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())
|
.AndReturn(self.tenants.list())
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ class TenantsViewTests(test.BaseAdminViewTests):
|
|||||||
|
|
||||||
class CreateProjectWorkflowTests(test.BaseAdminViewTests):
|
class CreateProjectWorkflowTests(test.BaseAdminViewTests):
|
||||||
def _get_project_info(self, project):
|
def _get_project_info(self, project):
|
||||||
project_info = {"tenant_name": project.name,
|
project_info = {"name": project.name,
|
||||||
"description": project.description,
|
"description": project.description,
|
||||||
"enabled": project.enabled}
|
"enabled": project.enabled}
|
||||||
return project_info
|
return project_info
|
||||||
@ -146,9 +146,9 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
|
|||||||
ulist = workflow_data["role_" + role.id]
|
ulist = workflow_data["role_" + role.id]
|
||||||
for user_id in ulist:
|
for user_id in ulist:
|
||||||
api.keystone.add_tenant_user_role(IsA(http.HttpRequest),
|
api.keystone.add_tenant_user_role(IsA(http.HttpRequest),
|
||||||
tenant_id=self.tenant.id,
|
project=self.tenant.id,
|
||||||
user_id=user_id,
|
user=user_id,
|
||||||
role_id=role.id)
|
role=role.id)
|
||||||
|
|
||||||
nova_updated_quota = dict([(key, quota_data[key]) for key in
|
nova_updated_quota = dict([(key, quota_data[key]) for key in
|
||||||
quotas.NOVA_QUOTA_FIELDS])
|
quotas.NOVA_QUOTA_FIELDS])
|
||||||
@ -276,9 +276,9 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
|
|||||||
ulist = workflow_data["role_" + role.id]
|
ulist = workflow_data["role_" + role.id]
|
||||||
for user_id in ulist:
|
for user_id in ulist:
|
||||||
api.keystone.add_tenant_user_role(IsA(http.HttpRequest),
|
api.keystone.add_tenant_user_role(IsA(http.HttpRequest),
|
||||||
tenant_id=self.tenant.id,
|
project=self.tenant.id,
|
||||||
user_id=user_id,
|
user=user_id,
|
||||||
role_id=role.id)
|
role=role.id)
|
||||||
|
|
||||||
nova_updated_quota = dict([(key, quota_data[key]) for key in
|
nova_updated_quota = dict([(key, quota_data[key]) for key in
|
||||||
quotas.NOVA_QUOTA_FIELDS])
|
quotas.NOVA_QUOTA_FIELDS])
|
||||||
@ -338,9 +338,9 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
|
|||||||
ulist = workflow_data["role_" + role.id]
|
ulist = workflow_data["role_" + role.id]
|
||||||
for user_id in ulist:
|
for user_id in ulist:
|
||||||
api.keystone.add_tenant_user_role(IsA(http.HttpRequest),
|
api.keystone.add_tenant_user_role(IsA(http.HttpRequest),
|
||||||
tenant_id=self.tenant.id,
|
project=self.tenant.id,
|
||||||
user_id=user_id,
|
user=user_id,
|
||||||
role_id=role.id) \
|
role=role.id) \
|
||||||
.AndRaise(self.exceptions.keystone)
|
.AndRaise(self.exceptions.keystone)
|
||||||
break
|
break
|
||||||
break
|
break
|
||||||
@ -506,8 +506,7 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
|||||||
quota.metadata_items = 444
|
quota.metadata_items = 444
|
||||||
quota.volumes = 444
|
quota.volumes = 444
|
||||||
|
|
||||||
updated_project = {"tenant_name": project._info["name"],
|
updated_project = {"name": project._info["name"],
|
||||||
"tenant_id": project.id,
|
|
||||||
"description": project._info["description"],
|
"description": project._info["description"],
|
||||||
"enabled": project.enabled}
|
"enabled": project.enabled}
|
||||||
updated_quota = self._get_quota_info(quota)
|
updated_quota = self._get_quota_info(quota)
|
||||||
@ -516,12 +515,14 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
|||||||
api.keystone.role_list(IsA(http.HttpRequest)).AndReturn(roles)
|
api.keystone.role_list(IsA(http.HttpRequest)).AndReturn(roles)
|
||||||
|
|
||||||
# handle
|
# handle
|
||||||
api.keystone.tenant_update(IsA(http.HttpRequest), **updated_project) \
|
api.keystone.tenant_update(IsA(http.HttpRequest),
|
||||||
|
project.id,
|
||||||
|
**updated_project) \
|
||||||
.AndReturn(project)
|
.AndReturn(project)
|
||||||
|
|
||||||
api.keystone.role_list(IsA(http.HttpRequest)).AndReturn(roles)
|
api.keystone.role_list(IsA(http.HttpRequest)).AndReturn(roles)
|
||||||
api.keystone.user_list(IsA(http.HttpRequest),
|
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
|
# admin user - try to remove all roles on current project, warning
|
||||||
api.keystone.roles_for_user(IsA(http.HttpRequest), '1',
|
api.keystone.roles_for_user(IsA(http.HttpRequest), '1',
|
||||||
@ -534,14 +535,14 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
|||||||
.AndReturn((roles[0],))
|
.AndReturn((roles[0],))
|
||||||
# remove role 1
|
# remove role 1
|
||||||
api.keystone.remove_tenant_user_role(IsA(http.HttpRequest),
|
api.keystone.remove_tenant_user_role(IsA(http.HttpRequest),
|
||||||
tenant_id=self.tenant.id,
|
project=self.tenant.id,
|
||||||
user_id='2',
|
user='2',
|
||||||
role_id='1')
|
role='1')
|
||||||
# add role 2
|
# add role 2
|
||||||
api.keystone.add_tenant_user_role(IsA(http.HttpRequest),
|
api.keystone.add_tenant_user_role(IsA(http.HttpRequest),
|
||||||
tenant_id=self.tenant.id,
|
project=self.tenant.id,
|
||||||
user_id='2',
|
user='2',
|
||||||
role_id='2')
|
role='2')
|
||||||
|
|
||||||
# member user 3 - has role 2
|
# member user 3 - has role 2
|
||||||
api.keystone.roles_for_user(IsA(http.HttpRequest), '3',
|
api.keystone.roles_for_user(IsA(http.HttpRequest), '3',
|
||||||
@ -549,14 +550,14 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
|||||||
.AndReturn((roles[1],))
|
.AndReturn((roles[1],))
|
||||||
# remove role 2
|
# remove role 2
|
||||||
api.keystone.remove_tenant_user_role(IsA(http.HttpRequest),
|
api.keystone.remove_tenant_user_role(IsA(http.HttpRequest),
|
||||||
tenant_id=self.tenant.id,
|
project=self.tenant.id,
|
||||||
user_id='3',
|
user='3',
|
||||||
role_id='2')
|
role='2')
|
||||||
# add role 1
|
# add role 1
|
||||||
api.keystone.add_tenant_user_role(IsA(http.HttpRequest),
|
api.keystone.add_tenant_user_role(IsA(http.HttpRequest),
|
||||||
tenant_id=self.tenant.id,
|
project=self.tenant.id,
|
||||||
user_id='3',
|
user='3',
|
||||||
role_id='1')
|
role='1')
|
||||||
|
|
||||||
nova_updated_quota = dict([(key, updated_quota[key]) for key in
|
nova_updated_quota = dict([(key, updated_quota[key]) for key in
|
||||||
quotas.NOVA_QUOTA_FIELDS])
|
quotas.NOVA_QUOTA_FIELDS])
|
||||||
@ -647,8 +648,7 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
|||||||
quota.metadata_items = 444
|
quota.metadata_items = 444
|
||||||
quota.volumes = 444
|
quota.volumes = 444
|
||||||
|
|
||||||
updated_project = {"tenant_name": project._info["name"],
|
updated_project = {"name": project._info["name"],
|
||||||
"tenant_id": project.id,
|
|
||||||
"description": project._info["description"],
|
"description": project._info["description"],
|
||||||
"enabled": project.enabled}
|
"enabled": project.enabled}
|
||||||
updated_quota = self._get_quota_info(quota)
|
updated_quota = self._get_quota_info(quota)
|
||||||
@ -657,7 +657,9 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
|||||||
api.keystone.role_list(IsA(http.HttpRequest)).AndReturn(roles)
|
api.keystone.role_list(IsA(http.HttpRequest)).AndReturn(roles)
|
||||||
|
|
||||||
# handle
|
# 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)
|
.AndRaise(self.exceptions.keystone)
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
@ -722,8 +724,7 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
|||||||
quota[0].limit = 444
|
quota[0].limit = 444
|
||||||
quota[1].limit = -1
|
quota[1].limit = -1
|
||||||
|
|
||||||
updated_project = {"tenant_name": project._info["name"],
|
updated_project = {"name": project._info["name"],
|
||||||
"tenant_id": project.id,
|
|
||||||
"description": project._info["description"],
|
"description": project._info["description"],
|
||||||
"enabled": project.enabled}
|
"enabled": project.enabled}
|
||||||
updated_quota = self._get_quota_info(quota)
|
updated_quota = self._get_quota_info(quota)
|
||||||
@ -733,12 +734,14 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
|||||||
|
|
||||||
# handle
|
# handle
|
||||||
# handle
|
# handle
|
||||||
api.keystone.tenant_update(IsA(http.HttpRequest), **updated_project) \
|
api.keystone.tenant_update(IsA(http.HttpRequest),
|
||||||
|
project.id,
|
||||||
|
**updated_project) \
|
||||||
.AndReturn(project)
|
.AndReturn(project)
|
||||||
|
|
||||||
api.keystone.role_list(IsA(http.HttpRequest)).AndReturn(roles)
|
api.keystone.role_list(IsA(http.HttpRequest)).AndReturn(roles)
|
||||||
api.keystone.user_list(IsA(http.HttpRequest),
|
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
|
# admin user - try to remove all roles on current project, warning
|
||||||
api.keystone.roles_for_user(IsA(http.HttpRequest), '1',
|
api.keystone.roles_for_user(IsA(http.HttpRequest), '1',
|
||||||
@ -756,9 +759,9 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
|||||||
.AndReturn((roles[0],))
|
.AndReturn((roles[0],))
|
||||||
# add role 2
|
# add role 2
|
||||||
api.keystone.add_tenant_user_role(IsA(http.HttpRequest),
|
api.keystone.add_tenant_user_role(IsA(http.HttpRequest),
|
||||||
tenant_id=self.tenant.id,
|
project=self.tenant.id,
|
||||||
user_id='3',
|
user='3',
|
||||||
role_id='2')
|
role='2')
|
||||||
|
|
||||||
nova_updated_quota = dict([(key, updated_quota[key]) for key in
|
nova_updated_quota = dict([(key, updated_quota[key]) for key in
|
||||||
quotas.NOVA_QUOTA_FIELDS])
|
quotas.NOVA_QUOTA_FIELDS])
|
||||||
@ -827,8 +830,7 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
|||||||
quota.metadata_items = 444
|
quota.metadata_items = 444
|
||||||
quota.volumes = 444
|
quota.volumes = 444
|
||||||
|
|
||||||
updated_project = {"tenant_name": project._info["name"],
|
updated_project = {"name": project._info["name"],
|
||||||
"tenant_id": project.id,
|
|
||||||
"description": project._info["description"],
|
"description": project._info["description"],
|
||||||
"enabled": project.enabled}
|
"enabled": project.enabled}
|
||||||
updated_quota = self._get_quota_info(quota)
|
updated_quota = self._get_quota_info(quota)
|
||||||
@ -837,41 +839,40 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
|
|||||||
api.keystone.role_list(IsA(http.HttpRequest)).AndReturn(roles)
|
api.keystone.role_list(IsA(http.HttpRequest)).AndReturn(roles)
|
||||||
|
|
||||||
# handle
|
# handle
|
||||||
api.keystone.tenant_update(IsA(http.HttpRequest), **updated_project) \
|
api.keystone.tenant_update(IsA(http.HttpRequest),
|
||||||
|
project.id,
|
||||||
|
**updated_project) \
|
||||||
.AndReturn(project)
|
.AndReturn(project)
|
||||||
|
|
||||||
api.keystone.role_list(IsA(http.HttpRequest)).AndReturn(roles)
|
api.keystone.role_list(IsA(http.HttpRequest)).AndReturn(roles)
|
||||||
api.keystone.user_list(IsA(http.HttpRequest),
|
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
|
# admin user - try to remove all roles on current project, warning
|
||||||
api.keystone.roles_for_user(IsA(http.HttpRequest), '1',
|
api.keystone.roles_for_user(IsA(http.HttpRequest), '1',
|
||||||
self.tenant.id) \
|
self.tenant.id).AndReturn(roles)
|
||||||
.AndReturn(roles)
|
|
||||||
|
|
||||||
# member user 1 - has role 1, will remove it
|
# member user 1 - has role 1, will remove it
|
||||||
api.keystone.roles_for_user(IsA(http.HttpRequest), '2',
|
api.keystone.roles_for_user(IsA(http.HttpRequest), '2',
|
||||||
self.tenant.id) \
|
self.tenant.id).AndReturn((roles[1],))
|
||||||
.AndReturn((roles[1],))
|
|
||||||
|
|
||||||
# member user 3 - has role 2
|
# member user 3 - has role 2
|
||||||
api.keystone.roles_for_user(IsA(http.HttpRequest), '3',
|
api.keystone.roles_for_user(IsA(http.HttpRequest), '3',
|
||||||
self.tenant.id) \
|
self.tenant.id).AndReturn((roles[0],))
|
||||||
.AndReturn((roles[0],))
|
|
||||||
# add role 2
|
# add role 2
|
||||||
api.keystone.add_tenant_user_role(IsA(http.HttpRequest),
|
api.keystone.add_tenant_user_role(IsA(http.HttpRequest),
|
||||||
tenant_id=self.tenant.id,
|
project=self.tenant.id,
|
||||||
user_id='3',
|
user='3',
|
||||||
role_id='2')\
|
role='2')\
|
||||||
.AndRaise(self.exceptions.nova)
|
.AndRaise(self.exceptions.keystone)
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
# submit form data
|
# submit form data
|
||||||
project_data = {"name": project._info["name"],
|
project_data = {"name": project._info["name"],
|
||||||
"id": project.id,
|
"id": project.id,
|
||||||
"description": project._info["description"],
|
"description": project._info["description"],
|
||||||
"enabled": project.enabled}
|
"enabled": project.enabled}
|
||||||
workflow_data.update(project_data)
|
workflow_data.update(project_data)
|
||||||
workflow_data.update(updated_quota)
|
workflow_data.update(updated_quota)
|
||||||
url = reverse('horizon:admin:projects:update',
|
url = reverse('horizon:admin:projects:update',
|
||||||
|
@ -71,7 +71,7 @@ class IndexView(tables.DataTableView):
|
|||||||
def get_data(self):
|
def get_data(self):
|
||||||
tenants = []
|
tenants = []
|
||||||
try:
|
try:
|
||||||
tenants = api.keystone.tenant_list(self.request, admin=True)
|
tenants = api.keystone.tenant_list(self.request)
|
||||||
except:
|
except:
|
||||||
exceptions.handle(self.request,
|
exceptions.handle(self.request,
|
||||||
_("Unable to retrieve project list."))
|
_("Unable to retrieve project list."))
|
||||||
@ -183,7 +183,7 @@ class CreateUserView(CreateView):
|
|||||||
def get_initial(self):
|
def get_initial(self):
|
||||||
default_role = api.keystone.get_default_role(self.request)
|
default_role = api.keystone.get_default_role(self.request)
|
||||||
return {'role_id': getattr(default_role, "id", None),
|
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):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(CreateUserView, self).get_context_data(**kwargs)
|
context = super(CreateUserView, self).get_context_data(**kwargs)
|
||||||
|
@ -218,7 +218,7 @@ class CreateProject(workflows.Workflow):
|
|||||||
try:
|
try:
|
||||||
desc = data['description']
|
desc = data['description']
|
||||||
self.object = api.keystone.tenant_create(request,
|
self.object = api.keystone.tenant_create(request,
|
||||||
tenant_name=data['name'],
|
name=data['name'],
|
||||||
description=desc,
|
description=desc,
|
||||||
enabled=data['enabled'])
|
enabled=data['enabled'])
|
||||||
except:
|
except:
|
||||||
@ -242,9 +242,9 @@ class CreateProject(workflows.Workflow):
|
|||||||
users_added = 0
|
users_added = 0
|
||||||
for user in role_list:
|
for user in role_list:
|
||||||
api.keystone.add_tenant_user_role(request,
|
api.keystone.add_tenant_user_role(request,
|
||||||
tenant_id=project_id,
|
project=project_id,
|
||||||
user_id=user,
|
user=user,
|
||||||
role_id=role.id)
|
role=role.id)
|
||||||
users_added += 1
|
users_added += 1
|
||||||
users_to_add -= users_added
|
users_to_add -= users_added
|
||||||
except:
|
except:
|
||||||
@ -300,12 +300,16 @@ class UpdateProject(workflows.Workflow):
|
|||||||
return message % self.context.get('name', 'unknown project')
|
return message % self.context.get('name', 'unknown project')
|
||||||
|
|
||||||
def handle(self, request, data):
|
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']
|
project_id = data['project_id']
|
||||||
# update project info
|
# update project info
|
||||||
try:
|
try:
|
||||||
api.keystone.tenant_update(request,
|
api.keystone.tenant_update(request,
|
||||||
tenant_id=project_id,
|
project_id,
|
||||||
tenant_name=data['name'],
|
name=data['name'],
|
||||||
description=data['description'],
|
description=data['description'],
|
||||||
enabled=data['enabled'])
|
enabled=data['enabled'])
|
||||||
except:
|
except:
|
||||||
@ -315,63 +319,80 @@ class UpdateProject(workflows.Workflow):
|
|||||||
# update project members
|
# update project members
|
||||||
users_to_modify = 0
|
users_to_modify = 0
|
||||||
try:
|
try:
|
||||||
|
# Get our role options
|
||||||
available_roles = api.keystone.role_list(request)
|
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,
|
project_members = api.keystone.user_list(request,
|
||||||
tenant_id=project_id)
|
project=project_id)
|
||||||
users_to_modify = len(project_members)
|
users_to_modify = len(project_members)
|
||||||
|
|
||||||
for user in project_members:
|
for user in project_members:
|
||||||
current_roles = [role for role in
|
# Check if there have been any changes in the roles of
|
||||||
api.keystone.roles_for_user(self.request,
|
# Existing project members.
|
||||||
user.id,
|
current_roles = api.keystone.roles_for_user(self.request,
|
||||||
project_id)]
|
user.id,
|
||||||
effective_roles = []
|
project_id)
|
||||||
|
current_role_ids = [role.id for role in current_roles]
|
||||||
for role in available_roles:
|
for role in available_roles:
|
||||||
role_list = data["role_" + role.id]
|
# Check if the user is in the list of users with this role.
|
||||||
if user.id in role_list:
|
if user.id in data["role_" + role.id]:
|
||||||
effective_roles.append(role)
|
# Add it if necessary
|
||||||
if role not in current_roles:
|
if role.id not in current_role_ids:
|
||||||
# user role has changed
|
# user role has changed
|
||||||
api.keystone.add_tenant_user_role(
|
api.keystone.add_tenant_user_role(
|
||||||
request,
|
request,
|
||||||
tenant_id=project_id,
|
project=project_id,
|
||||||
user_id=user.id,
|
user=user.id,
|
||||||
role_id=role.id)
|
role=role.id)
|
||||||
else:
|
else:
|
||||||
# user role is unchanged
|
# User role is unchanged, so remove it from the
|
||||||
current_roles.pop(current_roles.index(role))
|
# remaining roles list to avoid removing it later.
|
||||||
if user.id == request.user.id and \
|
index = current_role_ids.index(role.id)
|
||||||
project_id == request.user.tenant_id and \
|
current_role_ids.pop(index)
|
||||||
any(x.name == 'admin' for x in current_roles):
|
|
||||||
# Cannot remove "admin" role on current(admin) project
|
# Prevent admins from doing stupid things to themselves.
|
||||||
msg = _('You cannot remove the "admin" role from the '
|
is_current_user = user.id == request.user.id
|
||||||
'project you are currently logged into. Please '
|
is_current_project = project_id == request.user.tenant_id
|
||||||
'switch to another project with admin permissions '
|
admin_roles = [role for role in current_roles
|
||||||
'or remove the role manually via the CLI')
|
if role.name.lower() == 'admin']
|
||||||
messages.warning(request, msg)
|
if len(admin_roles):
|
||||||
|
removing_admin = any([role.id in current_role_ids
|
||||||
|
for role in admin_roles])
|
||||||
else:
|
else:
|
||||||
# delete user's removed roles
|
removing_admin = False
|
||||||
for to_delete in current_roles:
|
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(
|
api.keystone.remove_tenant_user_role(
|
||||||
request,
|
request,
|
||||||
tenant_id=project_id,
|
project=project_id,
|
||||||
user_id=user.id,
|
user=user.id,
|
||||||
role_id=to_delete.id)
|
role=id_to_delete)
|
||||||
users_to_modify -= 1
|
users_to_modify -= 1
|
||||||
|
|
||||||
# add new roles to project
|
# Grant new roles on the project.
|
||||||
for role in available_roles:
|
for role in available_roles:
|
||||||
# count how many users may be added for exception handling
|
# Count how many users may be added for exception handling.
|
||||||
role_list = data["role_" + role.id]
|
users_to_modify += len(data["role_" + role.id])
|
||||||
users_to_modify += len(role_list)
|
|
||||||
for role in available_roles:
|
for role in available_roles:
|
||||||
role_list = data["role_" + role.id]
|
|
||||||
users_added = 0
|
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):
|
if not filter(lambda x: user_id == x.id, project_members):
|
||||||
api.keystone.add_tenant_user_role(request,
|
api.keystone.add_tenant_user_role(request,
|
||||||
tenant_id=project_id,
|
project=project_id,
|
||||||
user_id=user_id,
|
user=user_id,
|
||||||
role_id=role.id)
|
role=role.id)
|
||||||
users_added += 1
|
users_added += 1
|
||||||
users_to_modify -= users_added
|
users_to_modify -= users_added
|
||||||
except:
|
except:
|
||||||
|
@ -34,8 +34,7 @@ class RouterTests(test.BaseAdminViewTests, r_test.RouterTests):
|
|||||||
api.quantum.router_list(
|
api.quantum.router_list(
|
||||||
IsA(http.HttpRequest),
|
IsA(http.HttpRequest),
|
||||||
search_opts=None).AndReturn(self.routers.list())
|
search_opts=None).AndReturn(self.routers.list())
|
||||||
api.keystone.tenant_list(IsA(http.HttpRequest), admin=True)\
|
api.keystone.tenant_list(IsA(http.HttpRequest)).AndReturn(tenants)
|
||||||
.AndReturn(tenants)
|
|
||||||
self._mock_external_network_list()
|
self._mock_external_network_list()
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
@ -49,7 +48,6 @@ class RouterTests(test.BaseAdminViewTests, r_test.RouterTests):
|
|||||||
@test.create_stubs({api.quantum: ('router_list',),
|
@test.create_stubs({api.quantum: ('router_list',),
|
||||||
api.keystone: ('tenant_list',)})
|
api.keystone: ('tenant_list',)})
|
||||||
def test_index_router_list_exception(self):
|
def test_index_router_list_exception(self):
|
||||||
tenants = self.tenants.list()
|
|
||||||
api.quantum.router_list(
|
api.quantum.router_list(
|
||||||
IsA(http.HttpRequest),
|
IsA(http.HttpRequest),
|
||||||
search_opts=None).AndRaise(self.exceptions.quantum)
|
search_opts=None).AndRaise(self.exceptions.quantum)
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from django.forms import ValidationError
|
from django.forms import ValidationError
|
||||||
from django.utils.encoding import force_unicode
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.views.decorators.debug import sensitive_variables
|
from django.views.decorators.debug import sensitive_variables
|
||||||
|
|
||||||
@ -31,7 +30,6 @@ from horizon import messages
|
|||||||
from horizon.utils import validators
|
from horizon.utils import validators
|
||||||
|
|
||||||
from openstack_dashboard import api
|
from openstack_dashboard import api
|
||||||
from django.contrib.auth import logout
|
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
@ -40,13 +38,13 @@ LOG = logging.getLogger(__name__)
|
|||||||
class BaseUserForm(forms.SelfHandlingForm):
|
class BaseUserForm(forms.SelfHandlingForm):
|
||||||
def __init__(self, request, *args, **kwargs):
|
def __init__(self, request, *args, **kwargs):
|
||||||
super(BaseUserForm, self).__init__(request, *args, **kwargs)
|
super(BaseUserForm, self).__init__(request, *args, **kwargs)
|
||||||
# Populate tenant choices
|
# Populate project choices
|
||||||
tenant_choices = [('', _("Select a project"))]
|
project_choices = [('', _("Select a project"))]
|
||||||
|
|
||||||
for tenant in api.keystone.tenant_list(request, admin=True):
|
for project in api.keystone.tenant_list(request):
|
||||||
if tenant.enabled:
|
if project.enabled:
|
||||||
tenant_choices.append((tenant.id, tenant.name))
|
project_choices.append((project.id, project.name))
|
||||||
self.fields['tenant_id'].choices = tenant_choices
|
self.fields['project'].choices = project_choices
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
'''Check to make sure password fields match.'''
|
'''Check to make sure password fields match.'''
|
||||||
@ -64,16 +62,16 @@ class CreateUserForm(BaseUserForm):
|
|||||||
name = forms.CharField(label=_("User Name"))
|
name = forms.CharField(label=_("User Name"))
|
||||||
email = forms.EmailField(label=_("Email"))
|
email = forms.EmailField(label=_("Email"))
|
||||||
password = forms.RegexField(
|
password = forms.RegexField(
|
||||||
label=_("Password"),
|
label=_("Password"),
|
||||||
widget=forms.PasswordInput(render_value=False),
|
widget=forms.PasswordInput(render_value=False),
|
||||||
regex=validators.password_validator(),
|
regex=validators.password_validator(),
|
||||||
error_messages={'invalid': validators.password_validator_msg()})
|
error_messages={'invalid': validators.password_validator_msg()})
|
||||||
confirm_password = forms.CharField(
|
confirm_password = forms.CharField(
|
||||||
label=_("Confirm Password"),
|
label=_("Confirm Password"),
|
||||||
required=False,
|
required=False,
|
||||||
widget=forms.PasswordInput(render_value=False))
|
widget=forms.PasswordInput(render_value=False))
|
||||||
tenant_id = forms.DynamicChoiceField(label=_("Primary Project"),
|
project = forms.DynamicChoiceField(label=_("Primary Project"),
|
||||||
add_item_link=ADD_PROJECT_URL)
|
add_item_link=ADD_PROJECT_URL)
|
||||||
role_id = forms.ChoiceField(label=_("Role"))
|
role_id = forms.ChoiceField(label=_("Role"))
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@ -92,7 +90,7 @@ class CreateUserForm(BaseUserForm):
|
|||||||
data['name'],
|
data['name'],
|
||||||
data['email'],
|
data['email'],
|
||||||
data['password'],
|
data['password'],
|
||||||
data['tenant_id'],
|
data['project'],
|
||||||
True)
|
True)
|
||||||
messages.success(request,
|
messages.success(request,
|
||||||
_('User "%s" was successfully created.')
|
_('User "%s" was successfully created.')
|
||||||
@ -100,9 +98,9 @@ class CreateUserForm(BaseUserForm):
|
|||||||
if data['role_id']:
|
if data['role_id']:
|
||||||
try:
|
try:
|
||||||
api.keystone.add_tenant_user_role(request,
|
api.keystone.add_tenant_user_role(request,
|
||||||
data['tenant_id'],
|
data['project'],
|
||||||
new_user.id,
|
new_user.id,
|
||||||
data['role_id'])
|
data['role_id'])
|
||||||
except:
|
except:
|
||||||
exceptions.handle(request,
|
exceptions.handle(request,
|
||||||
_('Unable to add user'
|
_('Unable to add user'
|
||||||
@ -116,17 +114,17 @@ class UpdateUserForm(BaseUserForm):
|
|||||||
id = forms.CharField(label=_("ID"), widget=forms.HiddenInput)
|
id = forms.CharField(label=_("ID"), widget=forms.HiddenInput)
|
||||||
name = forms.CharField(label=_("User Name"))
|
name = forms.CharField(label=_("User Name"))
|
||||||
email = forms.EmailField(label=_("Email"))
|
email = forms.EmailField(label=_("Email"))
|
||||||
password = forms.RegexField(label=_("Password"),
|
password = forms.RegexField(
|
||||||
widget=forms.PasswordInput(render_value=False),
|
label=_("Password"),
|
||||||
regex=validators.password_validator(),
|
widget=forms.PasswordInput(render_value=False),
|
||||||
required=False,
|
regex=validators.password_validator(),
|
||||||
error_messages={'invalid':
|
required=False,
|
||||||
validators.password_validator_msg()})
|
error_messages={'invalid': validators.password_validator_msg()})
|
||||||
confirm_password = forms.CharField(
|
confirm_password = forms.CharField(
|
||||||
label=_("Confirm Password"),
|
label=_("Confirm Password"),
|
||||||
widget=forms.PasswordInput(render_value=False),
|
widget=forms.PasswordInput(render_value=False),
|
||||||
required=False)
|
required=False)
|
||||||
tenant_id = forms.ChoiceField(label=_("Primary Project"))
|
project = forms.ChoiceField(label=_("Primary Project"))
|
||||||
|
|
||||||
def __init__(self, request, *args, **kwargs):
|
def __init__(self, request, *args, **kwargs):
|
||||||
super(UpdateUserForm, self).__init__(request, *args, **kwargs)
|
super(UpdateUserForm, self).__init__(request, *args, **kwargs)
|
||||||
@ -139,62 +137,16 @@ class UpdateUserForm(BaseUserForm):
|
|||||||
# password and confirm_password strings.
|
# password and confirm_password strings.
|
||||||
@sensitive_variables('data', 'password')
|
@sensitive_variables('data', 'password')
|
||||||
def handle(self, request, data):
|
def handle(self, request, data):
|
||||||
failed, succeeded = [], []
|
|
||||||
user_is_editable = api.keystone.keystone_can_edit_user()
|
|
||||||
user = data.pop('id')
|
user = data.pop('id')
|
||||||
tenant = data.pop('tenant_id')
|
|
||||||
|
|
||||||
if user_is_editable:
|
# Throw away the password confirmation, we're done with it.
|
||||||
password = data.pop('password')
|
data.pop('confirm_password', None)
|
||||||
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:
|
try:
|
||||||
api.keystone.user_update_tenant(request, user, tenant)
|
api.keystone.user_update(request, user, **data)
|
||||||
succeeded.extend(msg_bits)
|
messages.success(request,
|
||||||
|
_('User has been updated successfully.'))
|
||||||
except:
|
except:
|
||||||
failed.append(msg_bits)
|
|
||||||
exceptions.handle(request, ignore=True)
|
exceptions.handle(request, ignore=True)
|
||||||
|
messages.error(request, _('Unable to update the user.'))
|
||||||
# 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)})
|
|
||||||
return True
|
return True
|
||||||
|
@ -55,8 +55,7 @@ class UsersViewTests(test.BaseAdminViewTests):
|
|||||||
user = self.users.get(id="1")
|
user = self.users.get(id="1")
|
||||||
role = self.roles.first()
|
role = self.roles.first()
|
||||||
|
|
||||||
api.keystone.tenant_list(IgnoreArg(), admin=True) \
|
api.keystone.tenant_list(IgnoreArg()).AndReturn(self.tenants.list())
|
||||||
.AndReturn(self.tenants.list())
|
|
||||||
api.keystone.user_create(IgnoreArg(),
|
api.keystone.user_create(IgnoreArg(),
|
||||||
user.name,
|
user.name,
|
||||||
user.email,
|
user.email,
|
||||||
@ -74,7 +73,7 @@ class UsersViewTests(test.BaseAdminViewTests):
|
|||||||
'name': user.name,
|
'name': user.name,
|
||||||
'email': user.email,
|
'email': user.email,
|
||||||
'password': user.password,
|
'password': user.password,
|
||||||
'tenant_id': self.tenant.id,
|
'project': self.tenant.id,
|
||||||
'role_id': self.roles.first().id,
|
'role_id': self.roles.first().id,
|
||||||
'confirm_password': user.password}
|
'confirm_password': user.password}
|
||||||
res = self.client.post(USER_CREATE_URL, formData)
|
res = self.client.post(USER_CREATE_URL, formData)
|
||||||
@ -88,8 +87,7 @@ class UsersViewTests(test.BaseAdminViewTests):
|
|||||||
def test_create_with_password_mismatch(self):
|
def test_create_with_password_mismatch(self):
|
||||||
user = self.users.get(id="1")
|
user = self.users.get(id="1")
|
||||||
|
|
||||||
api.keystone.tenant_list(IgnoreArg(), admin=True) \
|
api.keystone.tenant_list(IgnoreArg()).AndReturn(self.tenants.list())
|
||||||
.AndReturn(self.tenants.list())
|
|
||||||
api.keystone.role_list(IgnoreArg()).AndReturn(self.roles.list())
|
api.keystone.role_list(IgnoreArg()).AndReturn(self.roles.list())
|
||||||
api.keystone.get_default_role(IgnoreArg()) \
|
api.keystone.get_default_role(IgnoreArg()) \
|
||||||
.AndReturn(self.roles.first())
|
.AndReturn(self.roles.first())
|
||||||
@ -100,7 +98,7 @@ class UsersViewTests(test.BaseAdminViewTests):
|
|||||||
'name': user.name,
|
'name': user.name,
|
||||||
'email': user.email,
|
'email': user.email,
|
||||||
'password': user.password,
|
'password': user.password,
|
||||||
'tenant_id': self.tenant.id,
|
'project': self.tenant.id,
|
||||||
'role_id': self.roles.first().id,
|
'role_id': self.roles.first().id,
|
||||||
'confirm_password': "doesntmatch"}
|
'confirm_password': "doesntmatch"}
|
||||||
|
|
||||||
@ -114,8 +112,7 @@ class UsersViewTests(test.BaseAdminViewTests):
|
|||||||
def test_create_validation_for_password_too_short(self):
|
def test_create_validation_for_password_too_short(self):
|
||||||
user = self.users.get(id="1")
|
user = self.users.get(id="1")
|
||||||
|
|
||||||
api.keystone.tenant_list(IgnoreArg(), admin=True) \
|
api.keystone.tenant_list(IgnoreArg()).AndReturn(self.tenants.list())
|
||||||
.AndReturn(self.tenants.list())
|
|
||||||
api.keystone.role_list(IgnoreArg()).AndReturn(self.roles.list())
|
api.keystone.role_list(IgnoreArg()).AndReturn(self.roles.list())
|
||||||
api.keystone.get_default_role(IgnoreArg()) \
|
api.keystone.get_default_role(IgnoreArg()) \
|
||||||
.AndReturn(self.roles.first())
|
.AndReturn(self.roles.first())
|
||||||
@ -127,7 +124,7 @@ class UsersViewTests(test.BaseAdminViewTests):
|
|||||||
'name': user.name,
|
'name': user.name,
|
||||||
'email': user.email,
|
'email': user.email,
|
||||||
'password': 'four',
|
'password': 'four',
|
||||||
'tenant_id': self.tenant.id,
|
'project': self.tenant.id,
|
||||||
'role_id': self.roles.first().id,
|
'role_id': self.roles.first().id,
|
||||||
'confirm_password': 'four'}
|
'confirm_password': 'four'}
|
||||||
|
|
||||||
@ -143,8 +140,7 @@ class UsersViewTests(test.BaseAdminViewTests):
|
|||||||
def test_create_validation_for_password_too_long(self):
|
def test_create_validation_for_password_too_long(self):
|
||||||
user = self.users.get(id="1")
|
user = self.users.get(id="1")
|
||||||
|
|
||||||
api.keystone.tenant_list(IgnoreArg(), admin=True) \
|
api.keystone.tenant_list(IgnoreArg()).AndReturn(self.tenants.list())
|
||||||
.AndReturn(self.tenants.list())
|
|
||||||
api.keystone.role_list(IgnoreArg()).AndReturn(self.roles.list())
|
api.keystone.role_list(IgnoreArg()).AndReturn(self.roles.list())
|
||||||
api.keystone.get_default_role(IgnoreArg()) \
|
api.keystone.get_default_role(IgnoreArg()) \
|
||||||
.AndReturn(self.roles.first())
|
.AndReturn(self.roles.first())
|
||||||
@ -156,7 +152,7 @@ class UsersViewTests(test.BaseAdminViewTests):
|
|||||||
'name': user.name,
|
'name': user.name,
|
||||||
'email': user.email,
|
'email': user.email,
|
||||||
'password': 'MoreThanEighteenChars',
|
'password': 'MoreThanEighteenChars',
|
||||||
'tenant_id': self.tenant.id,
|
'project': self.tenant.id,
|
||||||
'role_id': self.roles.first().id,
|
'role_id': self.roles.first().id,
|
||||||
'confirm_password': 'MoreThanEighteenChars'}
|
'confirm_password': 'MoreThanEighteenChars'}
|
||||||
|
|
||||||
@ -174,24 +170,17 @@ class UsersViewTests(test.BaseAdminViewTests):
|
|||||||
'roles_for_user', )})
|
'roles_for_user', )})
|
||||||
def test_update(self):
|
def test_update(self):
|
||||||
user = self.users.get(id="1")
|
user = self.users.get(id="1")
|
||||||
|
test_password = 'normalpwd'
|
||||||
|
|
||||||
api.keystone.user_get(IsA(http.HttpRequest), '1',
|
api.keystone.user_get(IsA(http.HttpRequest), '1',
|
||||||
admin=True).AndReturn(user)
|
admin=True).AndReturn(user)
|
||||||
api.keystone.tenant_list(IgnoreArg(),
|
api.keystone.tenant_list(IgnoreArg()).AndReturn(self.tenants.list())
|
||||||
admin=True).AndReturn(self.tenants.list())
|
|
||||||
api.keystone.user_update(IsA(http.HttpRequest),
|
api.keystone.user_update(IsA(http.HttpRequest),
|
||||||
user.id,
|
user.id,
|
||||||
email=u'test@example.com',
|
email=u'test@example.com',
|
||||||
name=u'test_user').AndReturn(None)
|
name=u'test_user',
|
||||||
api.keystone.user_update_tenant(IsA(http.HttpRequest),
|
password=test_password,
|
||||||
user.id,
|
project=self.tenant.id).AndReturn(None)
|
||||||
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)
|
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
@ -199,14 +188,13 @@ class UsersViewTests(test.BaseAdminViewTests):
|
|||||||
'id': user.id,
|
'id': user.id,
|
||||||
'name': user.name,
|
'name': user.name,
|
||||||
'email': user.email,
|
'email': user.email,
|
||||||
'password': 'normalpwd',
|
'password': test_password,
|
||||||
'tenant_id': self.tenant.id,
|
'project': self.tenant.id,
|
||||||
'confirm_password': 'normalpwd'}
|
'confirm_password': test_password}
|
||||||
|
|
||||||
res = self.client.post(USER_UPDATE_URL, formData)
|
res = self.client.post(USER_UPDATE_URL, formData)
|
||||||
|
|
||||||
self.assertNoFormErrors(res)
|
self.assertNoFormErrors(res)
|
||||||
self.assertMessageCount(warning=1)
|
|
||||||
|
|
||||||
@test.create_stubs({api.keystone: ('user_get',
|
@test.create_stubs({api.keystone: ('user_get',
|
||||||
'tenant_list',
|
'tenant_list',
|
||||||
@ -219,28 +207,21 @@ class UsersViewTests(test.BaseAdminViewTests):
|
|||||||
api.keystone.user_get(IsA(http.HttpRequest),
|
api.keystone.user_get(IsA(http.HttpRequest),
|
||||||
'1',
|
'1',
|
||||||
admin=True).AndReturn(user)
|
admin=True).AndReturn(user)
|
||||||
api.keystone.tenant_list(IgnoreArg(), admin=True) \
|
api.keystone.tenant_list(IgnoreArg()).AndReturn(self.tenants.list())
|
||||||
.AndReturn(self.tenants.list())
|
|
||||||
api.keystone.keystone_can_edit_user().AndReturn(False)
|
api.keystone.keystone_can_edit_user().AndReturn(False)
|
||||||
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()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
formData = {'method': 'UpdateUserForm',
|
formData = {'method': 'UpdateUserForm',
|
||||||
'id': user.id,
|
'id': user.id,
|
||||||
'name': user.name,
|
'name': user.name,
|
||||||
'tenant_id': self.tenant.id, }
|
'project': self.tenant.id, }
|
||||||
|
|
||||||
res = self.client.post(USER_UPDATE_URL, formData)
|
res = self.client.post(USER_UPDATE_URL, formData)
|
||||||
|
|
||||||
self.assertNoFormErrors(res)
|
self.assertNoFormErrors(res)
|
||||||
self.assertMessageCount(warning=1)
|
self.assertMessageCount(error=1)
|
||||||
|
|
||||||
@test.create_stubs({api.keystone: ('user_get', 'tenant_list')})
|
@test.create_stubs({api.keystone: ('user_get', 'tenant_list')})
|
||||||
def test_update_validation_for_password_too_short(self):
|
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',
|
api.keystone.user_get(IsA(http.HttpRequest), '1',
|
||||||
admin=True).AndReturn(user)
|
admin=True).AndReturn(user)
|
||||||
api.keystone.tenant_list(IgnoreArg(),
|
api.keystone.tenant_list(IgnoreArg()).AndReturn(self.tenants.list())
|
||||||
admin=True).AndReturn(self.tenants.list())
|
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
@ -258,7 +238,7 @@ class UsersViewTests(test.BaseAdminViewTests):
|
|||||||
'name': user.name,
|
'name': user.name,
|
||||||
'email': user.email,
|
'email': user.email,
|
||||||
'password': 't',
|
'password': 't',
|
||||||
'tenant_id': self.tenant.id,
|
'project': self.tenant.id,
|
||||||
'confirm_password': 't'}
|
'confirm_password': 't'}
|
||||||
|
|
||||||
res = self.client.post(USER_UPDATE_URL, formData)
|
res = self.client.post(USER_UPDATE_URL, formData)
|
||||||
@ -273,8 +253,7 @@ class UsersViewTests(test.BaseAdminViewTests):
|
|||||||
|
|
||||||
api.keystone.user_get(IsA(http.HttpRequest), '1',
|
api.keystone.user_get(IsA(http.HttpRequest), '1',
|
||||||
admin=True).AndReturn(user)
|
admin=True).AndReturn(user)
|
||||||
api.keystone.tenant_list(IgnoreArg(),
|
api.keystone.tenant_list(IgnoreArg()).AndReturn(self.tenants.list())
|
||||||
admin=True).AndReturn(self.tenants.list())
|
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
@ -283,7 +262,7 @@ class UsersViewTests(test.BaseAdminViewTests):
|
|||||||
'name': user.name,
|
'name': user.name,
|
||||||
'email': user.email,
|
'email': user.email,
|
||||||
'password': 'ThisIsASuperLongPassword',
|
'password': 'ThisIsASuperLongPassword',
|
||||||
'tenant_id': self.tenant.id,
|
'project': self.tenant.id,
|
||||||
'confirm_password': 'ThisIsASuperLongPassword'}
|
'confirm_password': 'ThisIsASuperLongPassword'}
|
||||||
|
|
||||||
res = self.client.post(USER_UPDATE_URL, formData)
|
res = self.client.post(USER_UPDATE_URL, formData)
|
||||||
@ -374,8 +353,7 @@ class SeleniumTests(test.SeleniumAdminTestCase):
|
|||||||
'role_list',
|
'role_list',
|
||||||
'user_list')})
|
'user_list')})
|
||||||
def test_modal_create_user_with_passwords_not_matching(self):
|
def test_modal_create_user_with_passwords_not_matching(self):
|
||||||
api.keystone.tenant_list(IgnoreArg(), admin=True) \
|
api.keystone.tenant_list(IgnoreArg()).AndReturn(self.tenants.list())
|
||||||
.AndReturn(self.tenants.list())
|
|
||||||
api.keystone.role_list(IgnoreArg()).AndReturn(self.roles.list())
|
api.keystone.role_list(IgnoreArg()).AndReturn(self.roles.list())
|
||||||
api.keystone.user_list(IgnoreArg()).AndReturn(self.users.list())
|
api.keystone.user_list(IgnoreArg()).AndReturn(self.users.list())
|
||||||
api.keystone.get_default_role(IgnoreArg()) \
|
api.keystone.get_default_role(IgnoreArg()) \
|
||||||
@ -406,8 +384,7 @@ class SeleniumTests(test.SeleniumAdminTestCase):
|
|||||||
def test_update_user_with_passwords_not_matching(self):
|
def test_update_user_with_passwords_not_matching(self):
|
||||||
api.keystone.user_get(IsA(http.HttpRequest), '1',
|
api.keystone.user_get(IsA(http.HttpRequest), '1',
|
||||||
admin=True).AndReturn(self.user)
|
admin=True).AndReturn(self.user)
|
||||||
api.keystone.tenant_list(IgnoreArg(), admin=True) \
|
api.keystone.tenant_list(IgnoreArg()).AndReturn(self.tenants.list())
|
||||||
.AndReturn(self.tenants.list())
|
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
self.selenium.get("%s%s" % (self.live_server_url, USER_UPDATE_URL))
|
self.selenium.get("%s%s" % (self.live_server_url, USER_UPDATE_URL))
|
||||||
|
@ -80,7 +80,7 @@ class UpdateView(forms.ModalFormView):
|
|||||||
user = self.get_object()
|
user = self.get_object()
|
||||||
return {'id': user.id,
|
return {'id': user.id,
|
||||||
'name': user.name,
|
'name': user.name,
|
||||||
'tenant_id': getattr(user, 'tenantId', None),
|
'project': user.project_id,
|
||||||
'email': user.email}
|
'email': user.email}
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,8 +36,8 @@ class VolumeTests(test.BaseAdminViewTests):
|
|||||||
AndReturn([self.servers.list(), False])
|
AndReturn([self.servers.list(), False])
|
||||||
cinder.volume_type_list(IsA(http.HttpRequest)).\
|
cinder.volume_type_list(IsA(http.HttpRequest)).\
|
||||||
AndReturn(self.volume_types.list())
|
AndReturn(self.volume_types.list())
|
||||||
keystone.tenant_list(IsA(http.HttpRequest),
|
keystone.tenant_list(IsA(http.HttpRequest)) \
|
||||||
admin=True).AndReturn(self.tenants.list())
|
.AndReturn(self.tenants.list())
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
@ -80,8 +80,8 @@ class VolumeTests(test.BaseAdminViewTests):
|
|||||||
AndReturn(self.volume_types.list())
|
AndReturn(self.volume_types.list())
|
||||||
cinder.volume_type_delete(IsA(http.HttpRequest),
|
cinder.volume_type_delete(IsA(http.HttpRequest),
|
||||||
str(volume_type.id))
|
str(volume_type.id))
|
||||||
keystone.tenant_list(IsA(http.HttpRequest),
|
keystone.tenant_list(IsA(http.HttpRequest)) \
|
||||||
admin=True).AndReturn(self.tenants.list())
|
.AndReturn(self.tenants.list())
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
res = self.client.post(reverse('horizon:admin:volumes:index'),
|
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
|
# Gather our tenants to correlate against IDs
|
||||||
try:
|
try:
|
||||||
tenants = keystone.tenant_list(self.request, admin=True)
|
tenants = keystone.tenant_list(self.request)
|
||||||
except:
|
except:
|
||||||
tenants = []
|
tenants = []
|
||||||
msg = _('Unable to retrieve volume tenant information.')
|
msg = _('Unable to retrieve volume tenant information.')
|
||||||
|
@ -26,6 +26,15 @@ TEMPLATE_DEBUG = DEBUG
|
|||||||
#CSRF_COOKIE_SECURE = True
|
#CSRF_COOKIE_SECURE = True
|
||||||
#SESSION_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.
|
# Default OpenStack Dashboard configuration.
|
||||||
HORIZON_CONFIG = {
|
HORIZON_CONFIG = {
|
||||||
'dashboards': ('project', 'admin', 'settings',),
|
'dashboards': ('project', 'admin', 'settings',),
|
||||||
|
@ -66,9 +66,11 @@ class RoleAPITests(test.APITestCase):
|
|||||||
keystoneclient.roles.roles_for_user(self.user.id,
|
keystoneclient.roles.roles_for_user(self.user.id,
|
||||||
tenant.id).AndReturn(self.roles)
|
tenant.id).AndReturn(self.roles)
|
||||||
for role in self.roles:
|
for role in self.roles:
|
||||||
keystoneclient.roles.remove_user_role(self.user.id,
|
keystoneclient.roles.revoke(role.id,
|
||||||
role.id,
|
domain=None,
|
||||||
tenant.id)
|
group=None,
|
||||||
|
project=tenant.id,
|
||||||
|
user=self.user.id)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
api.keystone.remove_tenant_user(self.request, tenant.id, self.user.id)
|
api.keystone.remove_tenant_user(self.request, tenant.id, self.user.id)
|
||||||
|
|
||||||
|
@ -108,6 +108,7 @@ def data(TEST):
|
|||||||
'email': 'test@example.com',
|
'email': 'test@example.com',
|
||||||
'password': 'password',
|
'password': 'password',
|
||||||
'token': 'test_token',
|
'token': 'test_token',
|
||||||
|
'project_id': '1',
|
||||||
'enabled': True}
|
'enabled': True}
|
||||||
user = users.User(users.UserManager(None), user_dict)
|
user = users.User(users.UserManager(None), user_dict)
|
||||||
user_dict = {'id': "2",
|
user_dict = {'id': "2",
|
||||||
@ -115,6 +116,7 @@ def data(TEST):
|
|||||||
'email': 'two@example.com',
|
'email': 'two@example.com',
|
||||||
'password': 'password',
|
'password': 'password',
|
||||||
'token': 'test_token',
|
'token': 'test_token',
|
||||||
|
'project_id': '1',
|
||||||
'enabled': True}
|
'enabled': True}
|
||||||
user2 = users.User(users.UserManager(None), user_dict)
|
user2 = users.User(users.UserManager(None), user_dict)
|
||||||
user_dict = {'id': "3",
|
user_dict = {'id': "3",
|
||||||
@ -122,6 +124,7 @@ def data(TEST):
|
|||||||
'email': 'three@example.com',
|
'email': 'three@example.com',
|
||||||
'password': 'password',
|
'password': 'password',
|
||||||
'token': 'test_token',
|
'token': 'test_token',
|
||||||
|
'project_id': '1',
|
||||||
'enabled': True}
|
'enabled': True}
|
||||||
user3 = users.User(users.UserManager(None), user_dict)
|
user3 = users.User(users.UserManager(None), user_dict)
|
||||||
TEST.users.add(user, user2, user3)
|
TEST.users.add(user, user2, user3)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user