Remove Keystone v2 related code

Kyestone V2 support was removed in Train, so it's safe to do such cleanup.

* Functions which just return horizon settings are dropped and
  the settings are referred directly now.
* The service catalog in the sample test data is updated to match
  the format of the keystone API v3.
* Related to the above change of the sample service catalog,
  openstack_dashboard.test.unit.api.test_keystone.ServiceAPITests is
  updated to specify the region name explicitly because 'RegionTwo'
  endpoint is no longer the second entry of the endpoint list in the
  keystone API v3.

Co-Authored-By: Akihiro Motoki <amotoki@gmail.com>
Change-Id: Ib60f360c96341fa5c618595f4a9bfdfe7ec5ae83
This commit is contained in:
Ivan Kolodyazhny 2020-04-10 17:15:39 +03:00 committed by Akihiro Motoki
parent 50837618bd
commit ee6fa9a245
29 changed files with 377 additions and 570 deletions

View File

@ -100,7 +100,7 @@ class Login(django_auth_forms.AuthenticationForm):
# if websso is enabled and keystone version supported # if websso is enabled and keystone version supported
# prepend the websso_choices select input to the form # prepend the websso_choices select input to the form
if utils.is_websso_enabled(): if settings.WEBSSO_ENABLED:
initial = settings.WEBSSO_INITIAL_CHOICE initial = settings.WEBSSO_INITIAL_CHOICE
self.fields['auth_type'] = forms.ChoiceField( self.fields['auth_type'] = forms.ChoiceField(
label=_("Authenticate using"), label=_("Authenticate using"),

View File

@ -967,7 +967,6 @@ class OpenStackAuthTestsWebSSO(OpenStackAuthTestsMixin, test.TestCase):
(settings.OPENSTACK_KEYSTONE_URL, protocol, origin)) (settings.OPENSTACK_KEYSTONE_URL, protocol, origin))
url = reverse('login') url = reverse('login')
# POST to the page and redirect to keystone. # POST to the page and redirect to keystone.
response = self.client.get(url) response = self.client.get(url)
self.assertRedirects(response, redirect_url, status_code=302, self.assertRedirects(response, redirect_url, status_code=302,

View File

@ -11,6 +11,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from django.conf import settings
from django.conf.urls import url from django.conf.urls import url
from django.views import generic from django.views import generic
@ -37,7 +38,7 @@ if utils.allow_expired_passowrd_change():
name='password') name='password')
) )
if utils.is_websso_enabled(): if settings.WEBSSO_ENABLED:
urlpatterns += [ urlpatterns += [
url(r"^websso/$", views.websso, name='websso'), url(r"^websso/$", views.websso, name='websso'),
url(r"^error/$", url(r"^error/$",

View File

@ -187,8 +187,7 @@ class User(models.AbstractBaseUser, models.AnonymousUser):
.. attribute:: password_expires_at .. attribute:: password_expires_at
Password expiration date. This attribute could be None when using Password expiration date.
keystone version < 3.0 or if the feature is not enabled in keystone.
""" """

View File

@ -136,33 +136,6 @@ def allow_expired_passowrd_change():
return getattr(settings, 'ALLOW_USERS_CHANGE_EXPIRED_PASSWORD', True) return getattr(settings, 'ALLOW_USERS_CHANGE_EXPIRED_PASSWORD', True)
def is_websso_enabled():
"""Websso is supported in Keystone version 3."""
return settings.WEBSSO_ENABLED
def is_websso_default_redirect():
"""Checks if the websso default redirect is available.
As with websso, this is only supported in Keystone version 3.
"""
websso_default_redirect = settings.WEBSSO_DEFAULT_REDIRECT
keystonev3_plus = (get_keystone_version() >= 3)
return websso_default_redirect and keystonev3_plus
def get_websso_default_redirect_protocol():
return settings.WEBSSO_DEFAULT_REDIRECT_PROTOCOL
def get_websso_default_redirect_region():
return settings.WEBSSO_DEFAULT_REDIRECT_REGION
def get_websso_default_redirect_logout():
return settings.WEBSSO_DEFAULT_REDIRECT_LOGOUT
def build_absolute_uri(request, relative_url): def build_absolute_uri(request, relative_url):
"""Ensure absolute_uri are relative to WEBROOT.""" """Ensure absolute_uri are relative to WEBROOT."""
webroot = settings.WEBROOT webroot = settings.WEBROOT

View File

@ -56,10 +56,10 @@ def login(request):
# If the user enabled websso and the default redirect # If the user enabled websso and the default redirect
# redirect to the default websso url # redirect to the default websso url
if (request.method == 'GET' and utils.is_websso_enabled and if (request.method == 'GET' and settings.WEBSSO_ENABLED and
utils.is_websso_default_redirect()): settings.WEBSSO_DEFAULT_REDIRECT):
protocol = utils.get_websso_default_redirect_protocol() protocol = settings.WEBSSO_DEFAULT_REDIRECT_PROTOCOL
region = utils.get_websso_default_redirect_region() region = settings.WEBSSO_DEFAULT_REDIRECT_REGION
origin = utils.build_absolute_uri(request, '/auth/websso/') origin = utils.build_absolute_uri(request, '/auth/websso/')
url = ('%s/auth/OS-FEDERATION/websso/%s?origin=%s' % url = ('%s/auth/OS-FEDERATION/websso/%s?origin=%s' %
(region, protocol, origin)) (region, protocol, origin))
@ -70,7 +70,7 @@ def login(request):
if request.method == 'POST': if request.method == 'POST':
auth_type = request.POST.get('auth_type', 'credentials') auth_type = request.POST.get('auth_type', 'credentials')
request.session['auth_type'] = auth_type request.session['auth_type'] = auth_type
if utils.is_websso_enabled() and auth_type != 'credentials': if settings.WEBSSO_ENABLED and auth_type != 'credentials':
region_id = request.POST.get('region') region_id = request.POST.get('region')
auth_url = getattr(settings, 'WEBSSO_KEYSTONE_URL', None) auth_url = getattr(settings, 'WEBSSO_KEYSTONE_URL', None)
if auth_url is None: if auth_url is None:
@ -105,7 +105,7 @@ def login(request):
extra_context = { extra_context = {
'redirect_field_name': auth.REDIRECT_FIELD_NAME, 'redirect_field_name': auth.REDIRECT_FIELD_NAME,
'csrf_failure': request.GET.get('csrf_failure'), 'csrf_failure': request.GET.get('csrf_failure'),
'show_sso_opts': utils.is_websso_enabled() and len(choices) > 1, 'show_sso_opts': settings.WEBSSO_ENABLED and len(choices) > 1,
} }
if request.is_ajax(): if request.is_ajax():
@ -171,7 +171,7 @@ def websso(request):
request.user = auth.authenticate(request, auth_url=auth_url, request.user = auth.authenticate(request, auth_url=auth_url,
token=token) token=token)
except exceptions.KeystoneAuthException as exc: except exceptions.KeystoneAuthException as exc:
if utils.is_websso_default_redirect(): if settings.WEBSSO_DEFAULT_REDIRECT:
res = django_http.HttpResponseRedirect(settings.LOGIN_ERROR) res = django_http.HttpResponseRedirect(settings.LOGIN_ERROR)
else: else:
msg = 'Login failed: %s' % exc msg = 'Login failed: %s' % exc
@ -202,11 +202,11 @@ def logout(request, login_url=None, **kwargs):
LOG.info(msg) LOG.info(msg)
""" Securely logs a user out. """ """ Securely logs a user out. """
if (utils.is_websso_enabled and utils.is_websso_default_redirect() and if (settings.WEBSSO_ENABLED and settings.WEBSSO_DEFAULT_REDIRECT and
utils.get_websso_default_redirect_logout()): settings.WEBSSO_DEFAULT_REDIRECT_LOGOUT):
auth_user.unset_session_user_variables(request) auth_user.unset_session_user_variables(request)
return django_http.HttpResponseRedirect( return django_http.HttpResponseRedirect(
utils.get_websso_default_redirect_logout()) settings.WEBSSO_DEFAULT_REDIRECT_LOGOUT)
else: else:
return django_auth_views.logout_then_login(request, return django_auth_views.logout_then_login(request,
login_url=login_url, login_url=login_url,

View File

@ -293,17 +293,9 @@ def get_service_from_catalog(catalog, service_type):
return None return None
def get_version_from_service(service):
if service and service.get('endpoints'):
endpoint = service['endpoints'][0]
if 'interface' in endpoint:
return 3
else:
return 2.0
return 2.0
# Mapping of V2 Catalog Endpoint_type to V3 Catalog Interfaces # Mapping of V2 Catalog Endpoint_type to V3 Catalog Interfaces
# TODO(e0ne): remove this mapping once OPENSTACK_ENDPOINT_TYPE config option
# will be removed.
ENDPOINT_TYPE_TO_INTERFACE = { ENDPOINT_TYPE_TO_INTERFACE = {
'publicURL': 'public', 'publicURL': 'public',
'internalURL': 'internal', 'internalURL': 'internal',
@ -315,31 +307,25 @@ def get_url_for_service(service, region, endpoint_type):
if 'type' not in service: if 'type' not in service:
return None return None
identity_version = get_version_from_service(service)
service_endpoints = service.get('endpoints', []) service_endpoints = service.get('endpoints', [])
available_endpoints = [endpoint for endpoint in service_endpoints available_endpoints = [endpoint for endpoint in service_endpoints
if region == _get_endpoint_region(endpoint)] if region == _get_endpoint_region(endpoint)]
"""if we are dealing with the identity service and there is no endpoint # if we are dealing with the identity service and there is no endpoint
in the current region, it is okay to use the first endpoint for any # in the current region, it is okay to use the first endpoint for any
identity service endpoints and we can assume that it is global # identity service endpoints and we can assume that it is global
"""
if service['type'] == 'identity' and not available_endpoints: if service['type'] == 'identity' and not available_endpoints:
available_endpoints = [endpoint for endpoint in service_endpoints] available_endpoints = [endpoint for endpoint in service_endpoints]
for endpoint in available_endpoints: for endpoint in available_endpoints:
try: try:
if identity_version < 3: interface = \
return endpoint.get(endpoint_type) ENDPOINT_TYPE_TO_INTERFACE.get(endpoint_type, '')
else: if endpoint['interface'] == interface:
interface = \ return endpoint['url']
ENDPOINT_TYPE_TO_INTERFACE.get(endpoint_type, '') except KeyError:
if endpoint.get('interface') == interface:
return endpoint.get('url')
except (IndexError, KeyError):
# it could be that the current endpoint just doesn't match the # it could be that the current endpoint just doesn't match the
# type, continue trying the next one # type, continue trying the next one
pass pass
return None
def url_for(request, service_type, endpoint_type=None, region=None): def url_for(request, service_type, endpoint_type=None, region=None):

View File

@ -146,7 +146,7 @@ def keystoneclient(request, admin=False):
user = request.user user = request.user
token_id = user.token.id token_id = user.token.id
if is_multi_domain_enabled(): if settings.OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT:
is_domain_context_specified = bool( is_domain_context_specified = bool(
request.session.get("domain_context")) request.session.get("domain_context"))
@ -274,8 +274,7 @@ def get_default_domain(request, get_name=True):
""" """
domain_id = request.session.get("domain_context", None) domain_id = request.session.get("domain_context", None)
domain_name = request.session.get("domain_context_name", None) domain_name = request.session.get("domain_context_name", None)
# if running in Keystone V3 or later if domain_id is None:
if VERSIONS.active >= 3 and domain_id is None:
# if no domain context set, default to user's domain # if no domain context set, default to user's domain
domain_id = request.user.user_domain_id domain_id = request.user.user_domain_id
domain_name = request.user.user_domain_name domain_name = request.user.user_domain_name
@ -861,15 +860,6 @@ def get_version():
return VERSIONS.active return VERSIONS.active
def is_multi_domain_enabled():
return (VERSIONS.active >= 3 and
settings.OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT)
def is_federation_management_enabled():
return settings.OPENSTACK_KEYSTONE_FEDERATION_MANAGEMENT
def identity_provider_create(request, idp_id, description=None, def identity_provider_create(request, idp_id, description=None,
enabled=False, remote_ids=None): enabled=False, remote_ids=None):
manager = keystoneclient(request, admin=True).federation.identity_providers manager = keystoneclient(request, admin=True).federation.identity_providers

View File

@ -24,10 +24,6 @@ class ApplicationCredentialsPanel(horizon.Panel):
slug = 'application_credentials' slug = 'application_credentials'
policy_rules = (('identity', 'identity:list_application_credentials'),) policy_rules = (('identity', 'identity:list_application_credentials'),)
@staticmethod
def can_register():
return keystone.VERSIONS.active >= 3
def can_access(self, context): def can_access(self, context):
request = context['request'] request = context['request']
keystone_version = keystone.get_identity_api_version(request) keystone_version = keystone.get_identity_api_version(request)

View File

@ -16,8 +16,6 @@ from django.utils.translation import ugettext_lazy as _
import horizon import horizon
from openstack_dashboard.api import keystone
class Domains(horizon.Panel): class Domains(horizon.Panel):
name = _("Domains") name = _("Domains")
@ -25,10 +23,6 @@ class Domains(horizon.Panel):
policy_rules = (("identity", "identity:get_domain"), policy_rules = (("identity", "identity:get_domain"),
("identity", "identity:list_domains")) ("identity", "identity:list_domains"))
@staticmethod
def can_register():
return keystone.VERSIONS.active >= 3
def can_access(self, context): def can_access(self, context):
request = context['request'] request = context['request']
domain_token = request.session.get('domain_token') domain_token = request.session.get('domain_token')

View File

@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from django.conf import settings
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
import horizon import horizon
@ -24,12 +25,8 @@ class Groups(horizon.Panel):
slug = 'groups' slug = 'groups'
policy_rules = (("identity", "identity:list_groups"),) policy_rules = (("identity", "identity:list_groups"),)
@staticmethod
def can_register():
return keystone.VERSIONS.active >= 3
def can_access(self, context): def can_access(self, context):
if keystone.is_multi_domain_enabled() \ if (settings.OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT and
and not keystone.is_domain_admin(context['request']): not keystone.is_domain_admin(context['request'])):
return False return False
return super(Groups, self).can_access(context) return super(Groups, self).can_access(context)

View File

@ -243,15 +243,10 @@ class GroupsViewTests(test.BaseAdminViewTests):
self.mock_group_get.assert_called_once_with(test.IsHttpRequest(), self.mock_group_get.assert_called_once_with(test.IsHttpRequest(),
group.id) group.id)
if api.keystone.VERSIONS.active >= 3: self.mock_get_effective_domain_id.assert_called_once_with(
self.mock_get_effective_domain_id.assert_called_once_with( test.IsHttpRequest())
test.IsHttpRequest()) self.mock_user_list.assert_called_once_with(
self.mock_user_list.assert_called_once_with( test.IsHttpRequest(), group=group.id, domain=domain_id)
test.IsHttpRequest(), group=group.id, domain=domain_id)
else:
self.mock_get_effective_domain_id.assert_not_called()
self.mock_user_list.assert_called_once_with(
test.IsHttpRequest(), group=group.id)
@test.create_mocks({api.keystone: ('get_effective_domain_id', @test.create_mocks({api.keystone: ('get_effective_domain_id',
'user_list', 'user_list',
@ -271,15 +266,10 @@ class GroupsViewTests(test.BaseAdminViewTests):
self.assertRedirectsNoFollow(res, GROUP_MANAGE_URL) self.assertRedirectsNoFollow(res, GROUP_MANAGE_URL)
self.assertMessageCount(success=1) self.assertMessageCount(success=1)
if api.keystone.VERSIONS.active >= 3: self.mock_get_effective_domain_id.assert_called_once_with(
self.mock_get_effective_domain_id.assert_called_once_with( test.IsHttpRequest())
test.IsHttpRequest()) self.mock_user_list.assert_called_once_with(
self.mock_user_list.assert_called_once_with( test.IsHttpRequest(), group=group.id, domain=domain_id)
test.IsHttpRequest(), group=group.id, domain=domain_id)
else:
self.mock_get_effective_domain_id.assert_not_called()
self.mock_user_list.assert_called_once_with(
test.IsHttpRequest(), group=group.id)
self.mock_remove_group_user.assert_called_once_with( self.mock_remove_group_user.assert_called_once_with(
test.IsHttpRequest(), test.IsHttpRequest(),

View File

@ -12,12 +12,11 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from django.conf import settings
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
import horizon import horizon
from openstack_dashboard.api import keystone
class IdentityProviders(horizon.Panel): class IdentityProviders(horizon.Panel):
name = _("Identity Providers") name = _("Identity Providers")
@ -26,5 +25,4 @@ class IdentityProviders(horizon.Panel):
@staticmethod @staticmethod
def can_register(): def can_register():
return (keystone.VERSIONS.active >= 3 and return settings.OPENSTACK_KEYSTONE_FEDERATION_MANAGEMENT
keystone.is_federation_management_enabled())

View File

@ -12,12 +12,11 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from django.conf import settings
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
import horizon import horizon
from openstack_dashboard.api import keystone
class Mappings(horizon.Panel): class Mappings(horizon.Panel):
name = _("Mappings") name = _("Mappings")
@ -26,5 +25,4 @@ class Mappings(horizon.Panel):
@staticmethod @staticmethod
def can_register(): def can_register():
return (keystone.VERSIONS.active >= 3 and return settings.OPENSTACK_KEYSTONE_FEDERATION_MANAGEMENT
keystone.is_federation_management_enabled())

View File

@ -10,6 +10,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from django.conf import settings
from django.template import defaultfilters as filters from django.template import defaultfilters as filters
from django.urls import reverse from django.urls import reverse
from django.utils.http import urlencode from django.utils.http import urlencode
@ -62,7 +63,7 @@ class UpdateMembersLink(tables.LinkAction):
return "?".join([base_url, param]) return "?".join([base_url, param])
def allowed(self, request, project): def allowed(self, request, project):
if api.keystone.is_multi_domain_enabled(): if settings.OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT:
# domain admin or cloud admin = True # domain admin or cloud admin = True
# project admin or member = False # project admin or member = False
return api.keystone.is_domain_admin(request) return api.keystone.is_domain_admin(request)
@ -79,7 +80,7 @@ class UpdateGroupsLink(tables.LinkAction):
policy_rules = (("identity", "identity:list_groups"),) policy_rules = (("identity", "identity:list_groups"),)
def allowed(self, request, project): def allowed(self, request, project):
if api.keystone.is_multi_domain_enabled(): if settings.OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT:
# domain admin or cloud admin = True # domain admin or cloud admin = True
# project admin or member = False # project admin or member = False
return api.keystone.is_domain_admin(request) return api.keystone.is_domain_admin(request)
@ -114,7 +115,7 @@ class CreateProject(tables.LinkAction):
policy_rules = (('identity', 'identity:create_project'),) policy_rules = (('identity', 'identity:create_project'),)
def allowed(self, request, project): def allowed(self, request, project):
if api.keystone.is_multi_domain_enabled(): if settings.OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT:
# domain admin or cloud admin = True # domain admin or cloud admin = True
# project admin or member = False # project admin or member = False
return api.keystone.is_domain_admin(request) return api.keystone.is_domain_admin(request)
@ -132,7 +133,7 @@ class UpdateProject(policy.PolicyTargetMixin, tables.LinkAction):
policy_target_attrs = (("target.project.domain_id", "domain_id"),) policy_target_attrs = (("target.project.domain_id", "domain_id"),)
def allowed(self, request, project): def allowed(self, request, project):
if api.keystone.is_multi_domain_enabled(): if settings.OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT:
# domain admin or cloud admin = True # domain admin or cloud admin = True
# project admin or member = False # project admin or member = False
return api.keystone.is_domain_admin(request) return api.keystone.is_domain_admin(request)
@ -180,8 +181,8 @@ class DeleteTenantsAction(policy.PolicyTargetMixin, tables.DeleteAction):
policy_target_attrs = (("target.project.domain_id", "domain_id"),) policy_target_attrs = (("target.project.domain_id", "domain_id"),)
def allowed(self, request, project): def allowed(self, request, project):
if api.keystone.is_multi_domain_enabled() \ if (settings.OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT and
and not api.keystone.is_domain_admin(request): not api.keystone.is_domain_admin(request)):
return False return False
return api.keystone.keystone_can_edit_project() return api.keystone.keystone_can_edit_project()
@ -220,11 +221,8 @@ class TenantsTable(tables.DataTable):
widget=forms.Textarea(attrs={'rows': 4}), widget=forms.Textarea(attrs={'rows': 4}),
required=False)) required=False))
id = tables.Column('id', verbose_name=_('Project ID')) id = tables.Column('id', verbose_name=_('Project ID'))
domain_name = tables.Column(
if api.keystone.VERSIONS.active >= 3: 'domain_name', verbose_name=_('Domain Name'))
domain_name = tables.Column(
'domain_name', verbose_name=_('Domain Name'))
enabled = tables.Column('enabled', verbose_name=_('Enabled'), status=True, enabled = tables.Column('enabled', verbose_name=_('Enabled'), status=True,
filters=(filters.yesno, filters.capfirst), filters=(filters.yesno, filters.capfirst),
form_field=forms.BooleanField( form_field=forms.BooleanField(

View File

@ -41,28 +41,24 @@ class OverviewTab(tabs.Tab):
def _get_domain_name(self, project): def _get_domain_name(self, project):
domain_name = '' domain_name = ''
if api.keystone.VERSIONS.active >= 3: try:
try: if policy.check((("identity", "identity:get_domain"),),
if policy.check((("identity", "identity:get_domain"),), self.request):
self.request): domain = api.keystone.domain_get(
domain = api.keystone.domain_get( self.request, project.domain_id)
self.request, project.domain_id) domain_name = domain.name
domain_name = domain.name else:
else: domain = api.keystone.get_default_domain(self.request)
domain = api.keystone.get_default_domain(self.request) domain_name = domain.get('name')
domain_name = domain.get('name') except Exception:
except Exception: exceptions.handle(self.request,
exceptions.handle(self.request, _('Unable to retrieve project domain.'))
_('Unable to retrieve project domain.'))
return domain_name return domain_name
def _get_extras(self, project): def _get_extras(self, project):
if api.keystone.VERSIONS.active >= 3: extra_info = settings.PROJECT_TABLE_EXTRA_INFO
extra_info = settings.PROJECT_TABLE_EXTRA_INFO return dict((display_key, getattr(project, key, ''))
return dict((display_key, getattr(project, key, '')) for key, display_key in extra_info.items())
for key, display_key in extra_info.items())
else:
return {}
class UsersTab(tabs.TableTab): class UsersTab(tabs.TableTab):

View File

@ -541,15 +541,12 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
'role_list', 'role_list',
'role_assignments_list')}) 'role_assignments_list')})
def test_update_project_get(self): def test_update_project_get(self):
keystone_api_version = api.keystone.VERSIONS.active
project = self.tenants.first() project = self.tenants.first()
default_role = self.roles.first() default_role = self.roles.first()
domain_id = project.domain_id domain_id = project.domain_id
users = self._get_all_users(domain_id) users = self._get_all_users(domain_id)
groups = self._get_all_groups(domain_id) groups = self._get_all_groups(domain_id)
roles = self.roles.list() roles = self.roles.list()
proj_users = self._get_proj_users(project.id)
role_assignments = self._get_proj_role_assignment(project.id) role_assignments = self._get_proj_role_assignment(project.id)
self.mock_tenant_get.return_value = project self.mock_tenant_get.return_value = project
@ -564,13 +561,7 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
self.mock_role_list.return_value = roles self.mock_role_list.return_value = roles
self.mock_group_list.return_value = groups self.mock_group_list.return_value = groups
if keystone_api_version >= 3: self.mock_role_assignments_list.return_value = role_assignments
self.mock_role_assignments_list.return_value = role_assignments
else:
retvals_user_list.append(proj_users)
expected_user_list.append(
mock.call(test.IsHttpRequest(), project=self.tenant.id))
self.mock_roles_for_user.return_value = roles
url = reverse('horizon:identity:projects:update', url = reverse('horizon:identity:projects:update',
args=[self.tenant.id]) args=[self.tenant.id])
@ -609,16 +600,10 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
self.mock_group_list.assert_called_once_with( self.mock_group_list.assert_called_once_with(
test.IsHttpRequest(), domain=domain_id) test.IsHttpRequest(), domain=domain_id)
if keystone_api_version >= 3: self.assert_mock_multiple_calls_with_same_arguments(
self.assert_mock_multiple_calls_with_same_arguments( self.mock_role_assignments_list, 2,
self.mock_role_assignments_list, 2, mock.call(test.IsHttpRequest(), project=self.tenant.id))
mock.call(test.IsHttpRequest(), project=self.tenant.id)) self.mock_roles_for_user.assert_not_called()
self.mock_roles_for_user.assert_not_called()
else:
self.mock_roles_for_user.assert_has_calls(
[mock.call(test.IsHttpRequest(), user.id, self.tenant.id)
for user in proj_users])
self.mock_role_assignments_list.assert_not_called()
@test.create_mocks({api.keystone: ('tenant_get', @test.create_mocks({api.keystone: ('tenant_get',
'domain_get', 'domain_get',
@ -636,13 +621,10 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
'role_list', 'role_list',
'role_assignments_list')}) 'role_assignments_list')})
def test_update_project_save(self): def test_update_project_save(self):
keystone_api_version = api.keystone.VERSIONS.active
project = self.tenants.first() project = self.tenants.first()
default_role = self.roles.first() default_role = self.roles.first()
domain_id = project.domain_id domain_id = project.domain_id
users = self._get_all_users(domain_id) users = self._get_all_users(domain_id)
proj_users = self._get_proj_users(project.id)
groups = self._get_all_groups(domain_id) groups = self._get_all_groups(domain_id)
roles = self.roles.list() roles = self.roles.list()
role_assignments = self._get_proj_role_assignment(project.id) role_assignments = self._get_proj_role_assignment(project.id)
@ -670,16 +652,6 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
expected_roles_for_user = [] expected_roles_for_user = []
self.mock_roles_for_user.side_effect = retvals_roles_for_user self.mock_roles_for_user.side_effect = retvals_roles_for_user
if keystone_api_version < 3:
retvals_user_list.append(proj_users)
expected_user_list.append(
mock.call(test.IsHttpRequest(),
project=self.tenant.id))
for user in proj_users:
retvals_roles_for_user.append(roles)
expected_roles_for_user.append(
mock.call(test.IsHttpRequest(), user.id, self.tenant.id))
workflow_data[USER_ROLE_PREFIX + "1"] = ['3'] # admin role workflow_data[USER_ROLE_PREFIX + "1"] = ['3'] # admin role
workflow_data[USER_ROLE_PREFIX + "2"] = ['2'] # member role workflow_data[USER_ROLE_PREFIX + "2"] = ['2'] # member role
# Group assignment form data # Group assignment form data
@ -716,95 +688,67 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
expected_remove_group_role = [] expected_remove_group_role = []
self.mock_remove_group_role.side_effect = retvals_remove_group_role self.mock_remove_group_role.side_effect = retvals_remove_group_role
if keystone_api_version >= 3: # admin role with attempt to remove current admin, results in
# admin role with attempt to remove current admin, results in # warning message
# warning message workflow_data[USER_ROLE_PREFIX + "1"] = ['3']
workflow_data[USER_ROLE_PREFIX + "1"] = ['3']
# member role # member role
workflow_data[USER_ROLE_PREFIX + "2"] = ['1', '3'] workflow_data[USER_ROLE_PREFIX + "2"] = ['1', '3']
# admin role # admin role
workflow_data[GROUP_ROLE_PREFIX + "1"] = ['2', '3'] workflow_data[GROUP_ROLE_PREFIX + "1"] = ['2', '3']
# member role # member role
workflow_data[GROUP_ROLE_PREFIX + "2"] = ['1', '2', '3'] workflow_data[GROUP_ROLE_PREFIX + "2"] = ['1', '2', '3']
self.mock_role_assignments_list.return_value = role_assignments self.mock_role_assignments_list.return_value = role_assignments
# Give user 1 role 2 # Give user 1 role 2
retvals_add_tenant_user_role.append(None) retvals_add_tenant_user_role.append(None)
expected_add_tenant_user_role.append( expected_add_tenant_user_role.append(
mock.call(test.IsHttpRequest(), mock.call(test.IsHttpRequest(),
project=self.tenant.id, project=self.tenant.id,
user='1', user='1',
role='2',)) role='2',))
# remove role 2 from user 2 # remove role 2 from user 2
retvals_remove_tenant_user_role.append(None) retvals_remove_tenant_user_role.append(None)
expected_remove_tenant_user_role.append( expected_remove_tenant_user_role.append(
mock.call(test.IsHttpRequest(), mock.call(test.IsHttpRequest(),
project=self.tenant.id, project=self.tenant.id,
user='2', user='2',
role='2')) role='2'))
# Give user 3 role 1 # Give user 3 role 1
retvals_add_tenant_user_role.append(None) retvals_add_tenant_user_role.append(None)
expected_add_tenant_user_role.append( expected_add_tenant_user_role.append(
mock.call(test.IsHttpRequest(), mock.call(test.IsHttpRequest(),
project=self.tenant.id, project=self.tenant.id,
user='3', user='3',
role='1')) role='1'))
retvals_group_list.append(groups) retvals_group_list.append(groups)
expected_group_list.append( expected_group_list.append(
mock.call(test.IsHttpRequest(), mock.call(test.IsHttpRequest(),
domain=self.domain.id, domain=self.domain.id,
project=self.tenant.id)) project=self.tenant.id))
retvals_roles_for_group.append(roles) retvals_roles_for_group.append(roles)
expected_roles_for_group.append( expected_roles_for_group.append(
mock.call(test.IsHttpRequest(), mock.call(test.IsHttpRequest(),
group='1', group='1',
project=self.tenant.id)) project=self.tenant.id))
retvals_remove_group_role.append(None) retvals_remove_group_role.append(None)
expected_remove_group_role.append( expected_remove_group_role.append(
mock.call(test.IsHttpRequest(), mock.call(test.IsHttpRequest(),
project=self.tenant.id, project=self.tenant.id,
group='1', group='1',
role='1')) role='1'))
retvals_roles_for_group.append(roles) retvals_roles_for_group.append(roles)
expected_roles_for_group.append( expected_roles_for_group.append(
mock.call(test.IsHttpRequest(), mock.call(test.IsHttpRequest(),
group='2', group='2',
project=self.tenant.id)) project=self.tenant.id))
retvals_roles_for_group.append(roles) retvals_roles_for_group.append(roles)
expected_roles_for_group.append( expected_roles_for_group.append(
mock.call(test.IsHttpRequest(), mock.call(test.IsHttpRequest(),
group='3', group='3',
project=self.tenant.id)) project=self.tenant.id))
else:
retvals_user_list.append(proj_users)
expected_user_list.append(
mock.call(test.IsHttpRequest(),
project=self.tenant.id))
# admin user - try to remove all roles on current project, warning
retvals_roles_for_user.append(roles)
expected_roles_for_group.append(
mock.call(test.IsHttpRequest(), '1', self.tenant.id))
# member user 1 - has role 1, will remove it
retvals_roles_for_user.append((roles[1],))
expected_roles_for_group.append(
mock.call(test.IsHttpRequest(), '2', self.tenant.id))
# member user 3 - has role 2
retvals_roles_for_user.append((roles[0],))
expected_roles_for_group.append(
mock.call(test.IsHttpRequest(), '3', self.tenant.id))
# add role 2
retvals_add_tenant_user_role.append(self.exceptions.keystone)
expected_add_tenant_user_role.append(
mock.call(test.IsHttpRequest(),
project=self.tenant.id,
user='3',
role='2'))
# submit form data # submit form data
project_data = {"domain_id": project._info["domain_id"], project_data = {"domain_id": project._info["domain_id"],
@ -859,12 +803,9 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
_check_mock_calls(self.mock_remove_group_role, _check_mock_calls(self.mock_remove_group_role,
expected_remove_group_role) expected_remove_group_role)
if keystone_api_version >= 3: self.assert_mock_multiple_calls_with_same_arguments(
self.assert_mock_multiple_calls_with_same_arguments( self.mock_role_assignments_list, 3,
self.mock_role_assignments_list, 3, mock.call(test.IsHttpRequest(), project=self.tenant.id))
mock.call(test.IsHttpRequest(), project=self.tenant.id))
else:
self.mock_role_assignments_list.assert_not_called()
@test.create_mocks({api.keystone: ('tenant_get',)}) @test.create_mocks({api.keystone: ('tenant_get',)})
def test_update_project_get_error(self): def test_update_project_get_error(self):
@ -895,8 +836,6 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
'role_list', 'role_list',
'role_assignments_list')}) 'role_assignments_list')})
def test_update_project_tenant_update_error(self): def test_update_project_tenant_update_error(self):
keystone_api_version = api.keystone.VERSIONS.active
project = self.tenants.first() project = self.tenants.first()
default_role = self.roles.first() default_role = self.roles.first()
domain_id = project.domain_id domain_id = project.domain_id
@ -925,16 +864,7 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
expected_roles_for_user = [] expected_roles_for_user = []
self.mock_roles_for_user.side_effect = retvals_roles_for_user self.mock_roles_for_user.side_effect = retvals_roles_for_user
if keystone_api_version >= 3: self.mock_role_assignments_list.return_value = role_assignments
self.mock_role_assignments_list.return_value = role_assignments
else:
retvals_user_list.append(proj_users)
expected_roles_for_user.append(
mock.call(test.IsHttpRequest(), project=self.tenant.id))
for user in proj_users:
retvals_roles_for_user.append(roles)
expected_roles_for_user.append(
mock.call(test.IsHttpRequest(), user.id, self.tenant.id))
role_ids = [role.id for role in roles] role_ids = [role.id for role in roles]
for user in proj_users: for user in proj_users:
@ -992,12 +922,9 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
self.assertEqual(len(expected_roles_for_user), self.assertEqual(len(expected_roles_for_user),
self.mock_roles_for_user.call_count) self.mock_roles_for_user.call_count)
if keystone_api_version >= 3: self.assert_mock_multiple_calls_with_same_arguments(
self.assert_mock_multiple_calls_with_same_arguments( self.mock_role_assignments_list, 2,
self.mock_role_assignments_list, 2, mock.call(test.IsHttpRequest(), project=self.tenant.id))
mock.call(test.IsHttpRequest(), project=self.tenant.id))
else:
self.mock_role_assignments_list.assert_not_called()
self.mock_get_effective_domain_id.assert_called_once_with( self.mock_get_effective_domain_id.assert_called_once_with(
test.IsHttpRequest()) test.IsHttpRequest())

View File

@ -131,10 +131,9 @@ class IndexView(tables.DataTableView):
_("Insufficient privilege level to view project information.") _("Insufficient privilege level to view project information.")
messages.info(self.request, msg) messages.info(self.request, msg)
if api.keystone.VERSIONS.active >= 3: domain_lookup = api.keystone.domain_lookup(self.request)
domain_lookup = api.keystone.domain_lookup(self.request) for t in tenants:
for t in tenants: t.domain_name = domain_lookup.get(t.domain_id)
t.domain_name = domain_lookup.get(t.domain_id)
return tenants return tenants
@ -182,28 +181,27 @@ class UpdateProjectView(workflows.WorkflowView):
for field in PROJECT_INFO_FIELDS: for field in PROJECT_INFO_FIELDS:
initial[field] = getattr(project_info, field, None) initial[field] = getattr(project_info, field, None)
if keystone.VERSIONS.active >= 3: # get extra columns info
# get extra columns info ex_info = settings.PROJECT_TABLE_EXTRA_INFO
ex_info = settings.PROJECT_TABLE_EXTRA_INFO for ex_field in ex_info:
for ex_field in ex_info: initial[ex_field] = getattr(project_info, ex_field, None)
initial[ex_field] = getattr(project_info, ex_field, None)
# Retrieve the domain name where the project belong # Retrieve the domain name where the project belong
try: try:
if policy.check((("identity", "identity:get_domain"),), if policy.check((("identity", "identity:get_domain"),),
self.request): self.request):
domain = api.keystone.domain_get(self.request, domain = api.keystone.domain_get(self.request,
initial["domain_id"]) initial["domain_id"])
initial["domain_name"] = domain.name initial["domain_name"] = domain.name
else: else:
domain = api.keystone.get_default_domain(self.request) domain = api.keystone.get_default_domain(self.request)
initial["domain_name"] = domain.name initial["domain_name"] = domain.name
except Exception: except Exception:
exceptions.handle(self.request, exceptions.handle(self.request,
_('Unable to retrieve project domain.'), _('Unable to retrieve project domain.'),
redirect=reverse(INDEX_URL)) redirect=reverse(INDEX_URL))
except Exception: except Exception:
exceptions.handle(self.request, exceptions.handle(self.request,
_('Unable to retrieve project details.'), _('Unable to retrieve project details.'),

View File

@ -43,7 +43,6 @@ LOG = logging.getLogger(__name__)
INDEX_URL = "horizon:identity:projects:index" INDEX_URL = "horizon:identity:projects:index"
ADD_USER_URL = "horizon:identity:projects:create_user" ADD_USER_URL = "horizon:identity:projects:create_user"
PROJECT_GROUP_ENABLED = keystone.VERSIONS.active >= 3
PROJECT_USER_MEMBER_SLUG = "update_members" PROJECT_USER_MEMBER_SLUG = "update_members"
PROJECT_GROUP_MEMBER_SLUG = "update_group_members" PROJECT_GROUP_MEMBER_SLUG = "update_group_members"
COMMON_HORIZONTAL_TEMPLATE = "identity/projects/_common_horizontal_form.html" COMMON_HORIZONTAL_TEMPLATE = "identity/projects/_common_horizontal_form.html"
@ -232,12 +231,10 @@ class CreateProjectInfoAction(workflows.Action):
super(CreateProjectInfoAction, self).__init__(request, super(CreateProjectInfoAction, self).__init__(request,
*args, *args,
**kwargs) **kwargs)
# For keystone V3, display the two fields in read-only readonlyInput = forms.TextInput(attrs={'readonly': 'readonly'})
if keystone.VERSIONS.active >= 3: self.fields["domain_id"].widget = readonlyInput
readonlyInput = forms.TextInput(attrs={'readonly': 'readonly'}) self.fields["domain_name"].widget = readonlyInput
self.fields["domain_id"].widget = readonlyInput self.add_extra_fields()
self.fields["domain_name"].widget = readonlyInput
self.add_extra_fields()
def add_extra_fields(self): def add_extra_fields(self):
# add extra column defined by setting # add extra column defined by setting
@ -263,9 +260,8 @@ class CreateProjectInfo(workflows.Step):
def __init__(self, workflow): def __init__(self, workflow):
super(CreateProjectInfo, self).__init__(workflow) super(CreateProjectInfo, self).__init__(workflow)
if keystone.VERSIONS.active >= 3: EXTRA_INFO = settings.PROJECT_TABLE_EXTRA_INFO
EXTRA_INFO = settings.PROJECT_TABLE_EXTRA_INFO self.contributes += tuple(EXTRA_INFO.keys())
self.contributes += tuple(EXTRA_INFO.keys())
class UpdateProjectMembersAction(workflows.MembershipAction): class UpdateProjectMembersAction(workflows.MembershipAction):
@ -478,10 +474,9 @@ class CreateProject(workflows.Workflow):
def __init__(self, request=None, context_seed=None, entry_point=None, def __init__(self, request=None, context_seed=None, entry_point=None,
*args, **kwargs): *args, **kwargs):
if PROJECT_GROUP_ENABLED: self.default_steps = (CreateProjectInfo,
self.default_steps = (CreateProjectInfo, UpdateProjectMembers,
UpdateProjectMembers, UpdateProjectGroups)
UpdateProjectGroups)
super(CreateProject, self).__init__(request=request, super(CreateProject, self).__init__(request=request,
context_seed=context_seed, context_seed=context_seed,
entry_point=entry_point, entry_point=entry_point,
@ -499,11 +494,8 @@ class CreateProject(workflows.Workflow):
domain_id = data['domain_id'] domain_id = data['domain_id']
try: try:
# add extra information # add extra information
if keystone.VERSIONS.active >= 3: EXTRA_INFO = settings.PROJECT_TABLE_EXTRA_INFO
EXTRA_INFO = settings.PROJECT_TABLE_EXTRA_INFO kwargs = dict((key, data.get(key)) for key in EXTRA_INFO)
kwargs = dict((key, data.get(key)) for key in EXTRA_INFO)
else:
kwargs = {}
desc = data['description'] desc = data['description']
self.object = api.keystone.tenant_create(request, self.object = api.keystone.tenant_create(request,
@ -545,10 +537,7 @@ class CreateProject(workflows.Workflow):
users_added += 1 users_added += 1
users_to_add -= users_added users_to_add -= users_added
except Exception: except Exception:
if PROJECT_GROUP_ENABLED: group_msg = _(", add project groups")
group_msg = _(", add project groups")
else:
group_msg = ""
exceptions.handle(request, exceptions.handle(request,
_('Failed to add %(users_to_add)s project ' _('Failed to add %(users_to_add)s project '
'members%(group_msg)s and set project quotas.') 'members%(group_msg)s and set project quotas.')
@ -591,8 +580,7 @@ class CreateProject(workflows.Workflow):
return False return False
project_id = project.id project_id = project.id
self._update_project_members(request, data, project_id) self._update_project_members(request, data, project_id)
if PROJECT_GROUP_ENABLED: self._update_project_groups(request, data, project_id)
self._update_project_groups(request, data, project_id)
return True return True
@ -640,9 +628,8 @@ class UpdateProjectInfo(workflows.Step):
def __init__(self, workflow): def __init__(self, workflow):
super(UpdateProjectInfo, self).__init__(workflow) super(UpdateProjectInfo, self).__init__(workflow)
if keystone.VERSIONS.active >= 3: EXTRA_INFO = settings.PROJECT_TABLE_EXTRA_INFO
EXTRA_INFO = settings.PROJECT_TABLE_EXTRA_INFO self.contributes += tuple(EXTRA_INFO.keys())
self.contributes += tuple(EXTRA_INFO.keys())
class UpdateProject(workflows.Workflow): class UpdateProject(workflows.Workflow):
@ -657,10 +644,9 @@ class UpdateProject(workflows.Workflow):
def __init__(self, request=None, context_seed=None, entry_point=None, def __init__(self, request=None, context_seed=None, entry_point=None,
*args, **kwargs): *args, **kwargs):
if PROJECT_GROUP_ENABLED: self.default_steps = (UpdateProjectInfo,
self.default_steps = (UpdateProjectInfo, UpdateProjectMembers,
UpdateProjectMembers, UpdateProjectGroups)
UpdateProjectGroups)
super(UpdateProject, self).__init__(request=request, super(UpdateProject, self).__init__(request=request,
context_seed=context_seed, context_seed=context_seed,
@ -685,11 +671,8 @@ class UpdateProject(workflows.Workflow):
project_id = data['project_id'] project_id = data['project_id']
# add extra information # add extra information
if keystone.VERSIONS.active >= 3: EXTRA_INFO = settings.PROJECT_TABLE_EXTRA_INFO
EXTRA_INFO = settings.PROJECT_TABLE_EXTRA_INFO kwargs = dict((key, data.get(key)) for key in EXTRA_INFO)
kwargs = dict((key, data.get(key)) for key in EXTRA_INFO)
else:
kwargs = {}
return api.keystone.tenant_update( return api.keystone.tenant_update(
request, request,
@ -832,10 +815,7 @@ class UpdateProject(workflows.Workflow):
users_to_modify -= users_added users_to_modify -= users_added
return True return True
except Exception: except Exception:
if PROJECT_GROUP_ENABLED: group_msg = _(", update project groups")
group_msg = _(", update project groups")
else:
group_msg = ""
exceptions.handle(request, exceptions.handle(request,
_('Failed to modify %(users_to_modify)s' _('Failed to modify %(users_to_modify)s'
' project members%(group_msg)s and ' ' project members%(group_msg)s and '
@ -935,10 +915,9 @@ class UpdateProject(workflows.Workflow):
if not ret: if not ret:
return False return False
if PROJECT_GROUP_ENABLED: ret = self._update_project_groups(request, data,
ret = self._update_project_groups(request, data, project_id, domain_id)
project_id, domain_id) if not ret:
if not ret: return False
return False
return True return True

View File

@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from django.conf import settings
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
import horizon import horizon
@ -25,11 +26,7 @@ class Roles(horizon.Panel):
policy_rules = (("identity", "identity:list_roles"),) policy_rules = (("identity", "identity:list_roles"),)
def can_access(self, context): def can_access(self, context):
if keystone.is_multi_domain_enabled() \ if (settings.OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT and
and not keystone.is_domain_admin(context['request']): not keystone.is_domain_admin(context['request'])):
return False return False
return super(Roles, self).can_access(context) return super(Roles, self).can_access(context)
@staticmethod
def can_register():
return keystone.VERSIONS.active >= 3

View File

@ -35,7 +35,6 @@ from horizon.utils import validators
from openstack_dashboard import api from openstack_dashboard import api
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
PROJECT_REQUIRED = api.keystone.VERSIONS.active < 3
class PasswordMixin(forms.SelfHandlingForm): class PasswordMixin(forms.SelfHandlingForm):
@ -72,12 +71,8 @@ class BaseUserForm(forms.SelfHandlingForm):
default_project_id = kwargs['initial'].get('project', None) default_project_id = kwargs['initial'].get('project', None)
try: try:
if api.keystone.VERSIONS.active >= 3: projects, has_more = api.keystone.tenant_list(
projects, has_more = api.keystone.tenant_list( request, domain=domain_id)
request, domain=domain_id)
else:
projects, has_more = api.keystone.tenant_list(
request, user=user_id)
for project in sorted(projects, key=lambda p: p.name.lower()): for project in sorted(projects, key=lambda p: p.name.lower()):
if project.enabled: if project.enabled:
@ -96,14 +91,13 @@ class BaseUserForm(forms.SelfHandlingForm):
class AddExtraColumnMixIn(object): class AddExtraColumnMixIn(object):
def add_extra_fields(self, ordering=None): def add_extra_fields(self, ordering=None):
if api.keystone.VERSIONS.active >= 3: # add extra column defined by setting
# add extra column defined by setting EXTRA_INFO = settings.USER_TABLE_EXTRA_INFO
EXTRA_INFO = settings.USER_TABLE_EXTRA_INFO for key, value in EXTRA_INFO.items():
for key, value in EXTRA_INFO.items(): self.fields[key] = forms.CharField(label=value,
self.fields[key] = forms.CharField(label=value, required=False)
required=False) if ordering:
if ordering: ordering.append(key)
ordering.append(key)
ADD_PROJECT_URL = "horizon:identity:projects:create" ADD_PROJECT_URL = "horizon:identity:projects:create"
@ -126,10 +120,10 @@ class CreateUserForm(PasswordMixin, BaseUserForm, AddExtraColumnMixIn):
label=_("Email"), label=_("Email"),
required=False) required=False)
project = forms.ThemableDynamicChoiceField(label=_("Primary Project"), project = forms.ThemableDynamicChoiceField(label=_("Primary Project"),
required=PROJECT_REQUIRED, required=False,
add_item_link=ADD_PROJECT_URL) add_item_link=ADD_PROJECT_URL)
role_id = forms.ThemableChoiceField(label=_("Role"), role_id = forms.ThemableChoiceField(label=_("Role"),
required=PROJECT_REQUIRED) required=False)
enabled = forms.BooleanField(label=_("Enabled"), enabled = forms.BooleanField(label=_("Enabled"),
required=False, required=False,
initial=True) initial=True)
@ -155,13 +149,9 @@ class CreateUserForm(PasswordMixin, BaseUserForm, AddExtraColumnMixIn):
self.fields['role_id'].choices = role_choices self.fields['role_id'].choices = role_choices
# For keystone V3, display the two fields in read-only # For keystone V3, display the two fields in read-only
if api.keystone.VERSIONS.active >= 3: readonlyInput = forms.TextInput(attrs={'readonly': 'readonly'})
readonlyInput = forms.TextInput(attrs={'readonly': 'readonly'}) self.fields["domain_id"].widget = readonlyInput
self.fields["domain_id"].widget = readonlyInput self.fields["domain_name"].widget = readonlyInput
self.fields["domain_name"].widget = readonlyInput
# For keystone V2.0, hide description field
else:
self.fields["description"].widget = forms.HiddenInput()
# We have to protect the entire "data" dict because it contains the # We have to protect the entire "data" dict because it contains the
# password and confirm_password strings. # password and confirm_password strings.
@ -175,11 +165,8 @@ class CreateUserForm(PasswordMixin, BaseUserForm, AddExtraColumnMixIn):
data['email'] = data['email'] or None data['email'] = data['email'] or None
# add extra information # add extra information
if api.keystone.VERSIONS.active >= 3: EXTRA_INFO = settings.USER_TABLE_EXTRA_INFO
EXTRA_INFO = settings.USER_TABLE_EXTRA_INFO kwargs = dict((key, data.get(key)) for key in EXTRA_INFO)
kwargs = dict((key, data.get(key)) for key in EXTRA_INFO)
else:
kwargs = {}
if "lock_password" in data: if "lock_password" in data:
kwargs.update({'options': kwargs.update({'options':
@ -240,7 +227,7 @@ class UpdateUserForm(BaseUserForm, AddExtraColumnMixIn):
label=_("Email"), label=_("Email"),
required=False) required=False)
project = forms.ThemableChoiceField(label=_("Primary Project"), project = forms.ThemableChoiceField(label=_("Primary Project"),
required=PROJECT_REQUIRED) required=False)
lock_password = forms.BooleanField(label=_("Lock password"), lock_password = forms.BooleanField(label=_("Lock password"),
required=False, required=False,
@ -252,14 +239,9 @@ class UpdateUserForm(BaseUserForm, AddExtraColumnMixIn):
if api.keystone.keystone_can_edit_user() is False: if api.keystone.keystone_can_edit_user() is False:
for field in ('name', 'email'): for field in ('name', 'email'):
self.fields.pop(field) self.fields.pop(field)
# For keystone V3, display the two fields in read-only readonlyInput = forms.TextInput(attrs={'readonly': 'readonly'})
if api.keystone.VERSIONS.active >= 3: self.fields["domain_id"].widget = readonlyInput
readonlyInput = forms.TextInput(attrs={'readonly': 'readonly'}) self.fields["domain_name"].widget = readonlyInput
self.fields["domain_id"].widget = readonlyInput
self.fields["domain_name"].widget = readonlyInput
# For keystone V2.0, hide description field
else:
self.fields["description"].widget = forms.HiddenInput()
def handle(self, request, data): def handle(self, request, data):
user = data.pop('id') user = data.pop('id')
@ -267,7 +249,7 @@ class UpdateUserForm(BaseUserForm, AddExtraColumnMixIn):
data.pop('domain_id') data.pop('domain_id')
data.pop('domain_name') data.pop('domain_name')
if not PROJECT_REQUIRED and 'project' not in self.changed_data: if 'project' not in self.changed_data:
data.pop('project') data.pop('project')
if 'description' not in self.changed_data: if 'description' not in self.changed_data:

View File

@ -16,6 +16,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from django.conf import settings
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
import horizon import horizon
@ -30,7 +31,7 @@ class Users(horizon.Panel):
("identity", "identity:list_users")) ("identity", "identity:list_users"))
def can_access(self, context): def can_access(self, context):
if keystone.is_multi_domain_enabled() \ if (settings.OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT and
and not keystone.is_domain_admin(context['request']): not keystone.is_domain_admin(context['request'])):
return False return False
return super(Users, self).can_access(context) return super(Users, self).can_access(context)

View File

@ -159,13 +159,10 @@ class DeleteUsersAction(policy.PolicyTargetMixin, tables.DeleteAction):
class UserFilterAction(tables.FilterAction): class UserFilterAction(tables.FilterAction):
if api.keystone.VERSIONS.active < 3: filter_type = "server"
filter_type = "query" filter_choices = (("name", _("User Name ="), True),
else: ("id", _("User ID ="), True),
filter_type = "server" ("enabled", _("Enabled ="), True, _('e.g. Yes/No')))
filter_choices = (("name", _("User Name ="), True),
("id", _("User ID ="), True),
("enabled", _("Enabled ="), True, _('e.g. Yes/No')))
class UpdateRow(tables.Row): class UpdateRow(tables.Row):
@ -209,11 +206,9 @@ class UsersTable(tables.DataTable):
filters=(defaultfilters.yesno, filters=(defaultfilters.yesno,
defaultfilters.capfirst), defaultfilters.capfirst),
empty_value="False") empty_value="False")
domain_name = tables.Column('domain_name',
if api.keystone.VERSIONS.active >= 3: verbose_name=_('Domain Name'),
domain_name = tables.Column('domain_name', attrs={'data-type': 'uuid'})
verbose_name=_('Domain Name'),
attrs={'data-type': 'uuid'})
class Meta(object): class Meta(object):
name = "users" name = "users"

View File

@ -40,19 +40,18 @@ class OverviewTab(tabs.Tab):
def _get_domain_name(self, user): def _get_domain_name(self, user):
domain_name = '' domain_name = ''
if api.keystone.VERSIONS.active >= 3: try:
try: if policy.check((("identity", "identity:get_domain"),),
if policy.check((("identity", "identity:get_domain"),), self.request):
self.request): domain = api.keystone.domain_get(
domain = api.keystone.domain_get( self.request, user.domain_id)
self.request, user.domain_id) domain_name = domain.name
domain_name = domain.name else:
else: domain = api.keystone.get_default_domain(self.request)
domain = api.keystone.get_default_domain(self.request) domain_name = domain.get('name')
domain_name = domain.get('name') except Exception:
except Exception: exceptions.handle(self.request,
exceptions.handle(self.request, _('Unable to retrieve user domain.'))
_('Unable to retrieve user domain.'))
return domain_name return domain_name
def _get_project_name(self, user): def _get_project_name(self, user):
@ -67,12 +66,9 @@ class OverviewTab(tabs.Tab):
{'project_id': project_id, 'reason': e}) {'project_id': project_id, 'reason': e})
def _get_extras(self, user): def _get_extras(self, user):
if api.keystone.VERSIONS.active >= 3: extra_info = settings.USER_TABLE_EXTRA_INFO
extra_info = settings.USER_TABLE_EXTRA_INFO return dict((display_key, getattr(user, key, ''))
return dict((display_key, getattr(user, key, '')) for key, display_key in extra_info.items())
for key, display_key in extra_info.items())
else:
return {}
def get_context_data(self, request): def get_context_data(self, request):
user = self.tab_group.kwargs['user'] user = self.tab_group.kwargs['user']

View File

@ -143,12 +143,8 @@ class UsersViewTests(test.BaseAdminViewTests):
]) ])
self.assertEqual(2, self.mock_get_default_domain.call_count) self.assertEqual(2, self.mock_get_default_domain.call_count)
if api.keystone.VERSIONS.active >= 3: self.mock_tenant_list.assert_called_once_with(
self.mock_tenant_list.assert_called_once_with( test.IsHttpRequest(), domain=domain.id)
test.IsHttpRequest(), domain=domain.id)
else:
self.mock_tenant_list.assert_called_once_with(
test.IsHttpRequest(), user=None)
kwargs = {'phone_num': phone_number} kwargs = {'phone_num': phone_number}
self.mock_user_create.assert_called_once_with( self.mock_user_create.assert_called_once_with(
@ -217,12 +213,8 @@ class UsersViewTests(test.BaseAdminViewTests):
mock.call(test.IsHttpRequest()), mock.call(test.IsHttpRequest()),
mock.call(test.IsHttpRequest(), False), mock.call(test.IsHttpRequest(), False),
]) ])
if api.keystone.VERSIONS.active >= 3: self.mock_tenant_list.assert_called_once_with(
self.mock_tenant_list.assert_called_once_with( test.IsHttpRequest(), domain=domain.id)
test.IsHttpRequest(), domain=domain.id)
else:
self.mock_tenant_list.assert_called_once_with(
test.IsHttpRequest(), user=user.id)
self.mock_user_create.assert_called_once_with( self.mock_user_create.assert_called_once_with(
test.IsHttpRequest(), test.IsHttpRequest(),
name=user.name, name=user.name,
@ -276,14 +268,9 @@ class UsersViewTests(test.BaseAdminViewTests):
self.assert_mock_multiple_calls_with_same_arguments( self.assert_mock_multiple_calls_with_same_arguments(
self.mock_get_default_domain, 2, self.mock_get_default_domain, 2,
mock.call(test.IsHttpRequest())) mock.call(test.IsHttpRequest()))
if api.keystone.VERSIONS.active >= 3: self.assert_mock_multiple_calls_with_same_arguments(
self.assert_mock_multiple_calls_with_same_arguments( self.mock_tenant_list, 2,
self.mock_tenant_list, 2, mock.call(test.IsHttpRequest(), domain=domain_id))
mock.call(test.IsHttpRequest(), domain=domain_id))
else:
self.assert_mock_multiple_calls_with_same_arguments(
self.mock_tenant_list, 2,
mock.call(test.IsHttpRequest(), user=None))
self.assert_mock_multiple_calls_with_same_arguments( self.assert_mock_multiple_calls_with_same_arguments(
self.mock_role_list, 2, self.mock_role_list, 2,
mock.call(test.IsHttpRequest())) mock.call(test.IsHttpRequest()))
@ -329,14 +316,9 @@ class UsersViewTests(test.BaseAdminViewTests):
self.assert_mock_multiple_calls_with_same_arguments( self.assert_mock_multiple_calls_with_same_arguments(
self.mock_get_default_domain, 2, self.mock_get_default_domain, 2,
mock.call(test.IsHttpRequest())) mock.call(test.IsHttpRequest()))
if api.keystone.VERSIONS.active >= 3: self.assert_mock_multiple_calls_with_same_arguments(
self.assert_mock_multiple_calls_with_same_arguments( self.mock_tenant_list, 2,
self.mock_tenant_list, 2, mock.call(test.IsHttpRequest(), domain=domain_id))
mock.call(test.IsHttpRequest(), domain=domain_id))
else:
self.assert_mock_multiple_calls_with_same_arguments(
self.mock_tenant_list, 2,
mock.call(test.IsHttpRequest(), user=None))
self.assert_mock_multiple_calls_with_same_arguments( self.assert_mock_multiple_calls_with_same_arguments(
self.mock_role_list, 2, self.mock_role_list, 2,
mock.call(test.IsHttpRequest())) mock.call(test.IsHttpRequest()))
@ -382,14 +364,9 @@ class UsersViewTests(test.BaseAdminViewTests):
self.assert_mock_multiple_calls_with_same_arguments( self.assert_mock_multiple_calls_with_same_arguments(
self.mock_get_default_domain, 2, self.mock_get_default_domain, 2,
mock.call(test.IsHttpRequest())) mock.call(test.IsHttpRequest()))
if api.keystone.VERSIONS.active >= 3: self.assert_mock_multiple_calls_with_same_arguments(
self.assert_mock_multiple_calls_with_same_arguments( self.mock_tenant_list, 2,
self.mock_tenant_list, 2, mock.call(test.IsHttpRequest(), domain=domain_id))
mock.call(test.IsHttpRequest(), domain=domain_id))
else:
self.assert_mock_multiple_calls_with_same_arguments(
self.mock_tenant_list, 2,
mock.call(test.IsHttpRequest(), user=None))
self.assert_mock_multiple_calls_with_same_arguments( self.assert_mock_multiple_calls_with_same_arguments(
self.mock_role_list, 2, self.mock_role_list, 2,
mock.call(test.IsHttpRequest())) mock.call(test.IsHttpRequest()))
@ -493,12 +470,8 @@ class UsersViewTests(test.BaseAdminViewTests):
admin=True) admin=True)
self.mock_domain_get.assert_called_once_with(test.IsHttpRequest(), self.mock_domain_get.assert_called_once_with(test.IsHttpRequest(),
domain_id) domain_id)
if api.keystone.VERSIONS.active >= 3: self.mock_tenant_list.assert_called_once_with(
self.mock_tenant_list.assert_called_once_with( test.IsHttpRequest(), domain=domain.id)
test.IsHttpRequest(), domain=domain.id)
else:
self.mock_tenant_list.assert_called_once_with(
test.IsHttpRequest(), user=user.id)
kwargs = {'phone_num': phone_number} kwargs = {'phone_num': phone_number}
self.mock_user_update.assert_called_once_with(test.IsHttpRequest(), self.mock_user_update.assert_called_once_with(test.IsHttpRequest(),
user.id, user.id,
@ -538,12 +511,8 @@ class UsersViewTests(test.BaseAdminViewTests):
admin=True) admin=True)
self.mock_domain_get.assert_called_once_with(test.IsHttpRequest(), self.mock_domain_get.assert_called_once_with(test.IsHttpRequest(),
domain_id) domain_id)
if api.keystone.VERSIONS.active >= 3: self.mock_tenant_list.assert_called_once_with(
self.mock_tenant_list.assert_called_once_with( test.IsHttpRequest(), domain=domain.id)
test.IsHttpRequest(), domain=domain.id)
else:
self.mock_tenant_list.assert_called_once_with(
test.IsHttpRequest(), user=user.id)
self.mock_user_update.assert_called_once_with(test.IsHttpRequest(), self.mock_user_update.assert_called_once_with(test.IsHttpRequest(),
user.id, user.id,
email=user.email, email=user.email,
@ -581,12 +550,8 @@ class UsersViewTests(test.BaseAdminViewTests):
admin=True) admin=True)
self.mock_domain_get.assert_called_once_with(test.IsHttpRequest(), self.mock_domain_get.assert_called_once_with(test.IsHttpRequest(),
domain_id) domain_id)
if api.keystone.VERSIONS.active >= 3: self.mock_tenant_list.assert_called_once_with(
self.mock_tenant_list.assert_called_once_with( test.IsHttpRequest(), domain=domain.id)
test.IsHttpRequest(), domain=domain.id)
else:
self.mock_tenant_list.assert_called_once_with(
test.IsHttpRequest(), user=user.id)
self.mock_user_update.assert_called_once_with(test.IsHttpRequest(), self.mock_user_update.assert_called_once_with(test.IsHttpRequest(),
user.id, user.id,
email=user.email or "", email=user.email or "",
@ -657,12 +622,8 @@ class UsersViewTests(test.BaseAdminViewTests):
admin=True) admin=True)
self.mock_domain_get.assert_called_once_with(test.IsHttpRequest(), self.mock_domain_get.assert_called_once_with(test.IsHttpRequest(),
domain_id) domain_id)
if api.keystone.VERSIONS.active >= 3: self.mock_tenant_list.assert_called_once_with(
self.mock_tenant_list.assert_called_once_with( test.IsHttpRequest(), domain=domain.id)
test.IsHttpRequest(), domain=domain.id)
else:
self.mock_tenant_list.assert_called_once_with(
test.IsHttpRequest(), user=user.id)
self.assert_mock_multiple_calls_with_same_arguments( self.assert_mock_multiple_calls_with_same_arguments(
self.mock_keystone_can_edit_user, 2, self.mock_keystone_can_edit_user, 2,
mock.call()) mock.call())
@ -1339,12 +1300,8 @@ class UsersViewTests(test.BaseAdminViewTests):
admin=True) admin=True)
self.mock_domain_get.assert_called_once_with(test.IsHttpRequest(), self.mock_domain_get.assert_called_once_with(test.IsHttpRequest(),
domain_id) domain_id)
if api.keystone.VERSIONS.active >= 3: self.mock_tenant_list.assert_called_once_with(test.IsHttpRequest(),
self.mock_tenant_list.assert_called_once_with(test.IsHttpRequest(), domain=domain.id)
domain=domain.id)
else:
self.mock_tenant_list.assert_called_once_with(test.IsHttpRequest(),
user=user.id)
self.mock_user_update.assert_called_once_with(test.IsHttpRequest(), self.mock_user_update.assert_called_once_with(test.IsHttpRequest(),
user.id, user.id,
email=user.email, email=user.email,

View File

@ -95,10 +95,9 @@ class IndexView(tables.DataTableView):
msg = _("Insufficient privilege level to view user information.") msg = _("Insufficient privilege level to view user information.")
messages.info(self.request, msg) messages.info(self.request, msg)
if api.keystone.VERSIONS.active >= 3: domain_lookup = api.keystone.domain_lookup(self.request)
domain_lookup = api.keystone.domain_lookup(self.request) for u in users:
for u in users: u.domain_name = domain_lookup.get(u.domain_id)
u.domain_name = domain_lookup.get(u.domain_id)
return users return users
@ -134,20 +133,19 @@ class UpdateView(forms.ModalFormView):
domain_id = getattr(user, "domain_id", None) domain_id = getattr(user, "domain_id", None)
domain_name = '' domain_name = ''
# Retrieve the domain name where the project belongs # Retrieve the domain name where the project belongs
if api.keystone.VERSIONS.active >= 3: try:
try: if policy.check((("identity", "identity:get_domain"),),
if policy.check((("identity", "identity:get_domain"),), self.request):
self.request): domain = api.keystone.domain_get(self.request, domain_id)
domain = api.keystone.domain_get(self.request, domain_id) domain_name = domain.name
domain_name = domain.name
else: else:
domain = api.keystone.get_default_domain(self.request) domain = api.keystone.get_default_domain(self.request)
domain_name = domain.get('name') domain_name = domain.get('name')
except Exception: except Exception:
exceptions.handle(self.request, exceptions.handle(self.request,
_('Unable to retrieve project domain.')) _('Unable to retrieve project domain.'))
data = {'domain_id': domain_id, data = {'domain_id': domain_id,
'domain_name': domain_name, 'domain_name': domain_name,
@ -157,9 +155,8 @@ class UpdateView(forms.ModalFormView):
'email': getattr(user, 'email', None), 'email': getattr(user, 'email', None),
'description': getattr(user, 'description', None), 'description': getattr(user, 'description', None),
'lock_password': options.get("lock_password", False)} 'lock_password': options.get("lock_password", False)}
if api.keystone.VERSIONS.active >= 3: for key in settings.USER_TABLE_EXTRA_INFO:
for key in settings.USER_TABLE_EXTRA_INFO: data[key] = getattr(user, key, None)
data[key] = getattr(user, key, None)
return data return data

View File

@ -17,8 +17,6 @@ from __future__ import absolute_import
from django.conf import settings from django.conf import settings
from django import template from django import template
from openstack_dashboard.api import keystone
register = template.Library() register = template.Library()
@ -27,9 +25,10 @@ def is_multi_region_configured(request):
return len(request.user.available_services_regions) > 1 return len(request.user.available_services_regions) > 1
# TODO(e0ne): pass OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT to the template
# context and remove `is_multidomain` template tag
def is_multidomain_supported(): def is_multidomain_supported():
return (keystone.VERSIONS.active >= 3 and return settings.OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT
settings.OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT)
@register.simple_tag(takes_context=True) @register.simple_tag(takes_context=True)

View File

@ -36,86 +36,152 @@ from openstack_auth import user as auth_user
from openstack_dashboard.test.test_data import utils from openstack_dashboard.test.test_data import utils
# Dummy service catalog with all service. # Dummy service catalog with all service. All data should match
# scoped_auth_ref.service_catalog.catalog from keystoneauth1.
# All endpoint URLs should point to example.com. # All endpoint URLs should point to example.com.
# Try to keep them as accurate to real data as possible (ports, URIs, etc.) # Try to keep them as accurate to real data as possible (ports, URIs, etc.)
# TODO(e0ne): make RegionOne and RegionTwo links unique.
SERVICE_CATALOG = [ SERVICE_CATALOG = [
{"type": "compute", {"type": "compute",
"name": "nova", "name": "nova",
"endpoints_links": [], "endpoints_links": [],
"endpoints": [ "endpoints": [
{"region": "RegionOne", {"region": "RegionOne",
"adminURL": "http://admin.nova.example.com:8774/v2", "interface": "admin",
"internalURL": "http://int.nova.example.com:8774/v2", "url": "http://admin.nova.example.com:8774/v2"},
"publicURL": "http://public.nova.example.com:8774/v2"}, {"region": "RegionOne",
"interface": "internal",
"url": "http://int.nova.example.com:8774/v2"},
{"region": "RegionOne",
"interface": "public",
"url": "http://public.nova.example.com:8774/v2"},
{"region": "RegionTwo", {"region": "RegionTwo",
"adminURL": "http://admin.nova2.example.com:8774/v2", "interface": "admin",
"internalURL": "http://int.nova2.example.com:8774/v2", "url": "http://admin.nova2.example.com:8774/v2"},
"publicURL": "http://public.nova2.example.com:8774/v2"}]}, {"region": "RegionTwo",
"interface": "internal",
"url": "http://int.nova2.example.com:8774/v2"},
{"region": "RegionTwo",
"interface": "public",
"url": "http://public.nova2.example.com:8774/v2"}
]},
{"type": "volumev2", {"type": "volumev2",
"name": "cinderv2", "name": "cinderv2",
"endpoints_links": [], "endpoints_links": [],
"endpoints": [ "endpoints": [
{"region": "RegionOne", {"region": "RegionOne",
"adminURL": "http://admin.cinder.example.com:8776/v2", "interface": "admin",
"internalURL": "http://int.cinder.example.com:8776/v2", "url": "http://admin.cinder.example.com:8776/v2"},
"publicURL": "http://public.cinder.example.com:8776/v2"}, {"region": "RegionOne",
"interface": "internal",
"url": "http://int.cinder.example.com:8776/v2"},
{"region": "RegionOne",
"interface": "public",
"url": "http://public.cinder.example.com:8776/v2"},
{"region": "RegionTwo", {"region": "RegionTwo",
"adminURL": "http://admin.cinder.example.com:8776/v2", "interface": "admin",
"internalURL": "http://int.cinder.example.com:8776/v2", "url": "http://admin.cinder2.example.com:8776/v2"},
"publicURL": "http://public.cinder.example.com:8776/v2"}]}, {"region": "RegionTwo",
"interface": "internal",
"url": "http://int.cinder2.example.com:8776/v2"},
{"region": "RegionTwo",
"interface": "public",
"url": "http://public.cinder.example.com:8776/v2"}
]},
{"type": "volumev3", {"type": "volumev3",
"name": "cinderv3", "name": "cinderv3",
"endpoints_links": [], "endpoints_links": [],
"endpoints": [ "endpoints": [
{"region": "RegionOne", {"region": "RegionOne",
"adminURL": "http://admin.cinder.example.com:8776/v3", "interface": "admin",
"internalURL": "http://int.cinder.example.com:8776/v3", "url": "http://admin.cinder.example.com:8776/v3"},
"publicURL": "http://public.cinder.example.com:8776/v3"}, {"region": "RegionOne",
"interface": "internal",
"url": "http://int.cinder.example.com:8776/v3"},
{"region": "RegionOne",
"interface": "public",
"url": "http://public.cinder.example.com:8776/v3"},
{"region": "RegionTwo", {"region": "RegionTwo",
"adminURL": "http://admin.cinder.example.com:8776/v3", "interface": "admin",
"internalURL": "http://int.cinder.example.com:8776/v3", "url": "http://admin.cinder2.example.com:8776/v3"},
"publicURL": "http://public.cinder.example.com:8776/v3"}]}, {"region": "RegionTwo",
"interface": "internal",
"url": "http://int.cinder2.example.com:8776/v3"},
{"region": "RegionTwo",
"interface": "public",
"url": "http://public.cinder2.example.com:8776/v3"}
]},
{"type": "image", {"type": "image",
"name": "glance", "name": "glance",
"endpoints_links": [], "endpoints_links": [],
"endpoints": [ "endpoints": [
{"region": "RegionOne", {"region": "RegionOne",
"adminURL": "http://admin.glance.example.com:9292", "interface": "admin",
"internalURL": "http://int.glance.example.com:9292", "url": "http://admin.glance.example.com:9292",
"publicURL": "http://public.glance.example.com:9292"}]}, },
{"region": "RegionOne",
"interface": "internal",
"url": "http://int.glance.example.com:9292"},
{"region": "RegionOne",
"interface": "public",
"url": "http://public.glance.example.com:9292"}
]},
{"type": "identity", {"type": "identity",
"name": "keystone", "name": "keystone",
"endpoints_links": [], "endpoints_links": [],
"endpoints": [ "endpoints": [
{"region": "RegionOne", {"region": "RegionOne",
"adminURL": "http://admin.keystone.example.com/identity/v3", "interface": "admin",
"internalURL": "http://int.keystone.example.com/identity/v3", "url": "http://admin.keystone.example.com/identity/v3"},
"publicURL": "http://public.keystone.example.com/identity/v3"}]}, {"region": "RegionOne",
"interface": "internal",
"url": "http://int.keystone.example.com/identity/v3"},
{"region": "RegionOne",
"interface": "public",
"url": "http://public.keystone.example.com/identity/v3"}
]},
{"type": "object-store", {"type": "object-store",
"name": "swift", "name": "swift",
"endpoints_links": [], "endpoints_links": [],
"endpoints": [ "endpoints": [
{"region": "RegionOne", {"region": "RegionOne",
"adminURL": "http://admin.swift.example.com:8080/", "interface": "admin",
"internalURL": "http://int.swift.example.com:8080/", "url": "http://admin.swift.example.com:8080/"},
"publicURL": "http://public.swift.example.com:8080/"}]}, {"region": "RegionOne",
"interface": "internal",
"url": "http://int.swift.example.com:8080/"},
{"region": "RegionOne",
"interface": "public",
"url": "http://public.swift.example.com:8080/"}
]},
{"type": "network", {"type": "network",
"name": "neutron", "name": "neutron",
"endpoints_links": [], "endpoints_links": [],
"endpoints": [ "endpoints": [
{"region": "RegionOne", {"region": "RegionOne",
"adminURL": "http://admin.neutron.example.com:9696/", "interface": "admin",
"internalURL": "http://int.neutron.example.com:9696/", "url": "http://admin.neutron.example.com:9696/"},
"publicURL": "http://public.neutron.example.com:9696/"}]}, {"region": "RegionOne",
"interface": "internal",
"url": "http://int.neutron.example.com:9696/"},
{"region": "RegionOne",
"interface": "public",
"url": "http://public.neutron.example.com:9696/"}
]},
{"type": "ec2", {"type": "ec2",
"name": "EC2 Service", "name": "EC2 Service",
"endpoints_links": [], "endpoints_links": [],
"endpoints": [ "endpoints": [
{"region": "RegionOne", {"region": "RegionOne",
"adminURL": "http://admin.nova.example.com:8773/services/Admin", "interface": "admin",
"publicURL": "http://public.nova.example.com:8773/services/Cloud", "url": "http://admin.nova.example.com:8773/services/Admin"},
"internalURL": "http://int.nova.example.com:8773/services/Cloud"}]}, {"region": "RegionOne",
"interface": "public",
"url": "http://public.nova.example.com:8773/services/Cloud"},
{"region": "RegionOne",
"interface": "internal",
"url": "http://int.nova.example.com:8773/services/Cloud"}
]},
] ]

View File

@ -74,12 +74,11 @@ class ServiceAPITests(test.APIMockTestCase):
def test_service_wrapper(self): def test_service_wrapper(self):
catalog = self.service_catalog catalog = self.service_catalog
identity_data = api.base.get_service_from_catalog(catalog, "identity") identity_data = api.base.get_service_from_catalog(catalog, "identity")
# 'Service' class below requires 'id', so populate it here.
identity_data['id'] = 1 identity_data['id'] = 1
region = identity_data["endpoints"][0]["region"] service = api.keystone.Service(identity_data, "RegionOne")
service = api.keystone.Service(identity_data, region)
self.assertEqual(u"identity (native backend)", str(service)) self.assertEqual(u"identity (native backend)", str(service))
self.assertEqual(identity_data["endpoints"][0]["region"], self.assertEqual("RegionOne", service.region)
service.region)
self.assertEqual("http://int.keystone.example.com/identity/v3", self.assertEqual("http://int.keystone.example.com/identity/v3",
service.url) service.url)
self.assertEqual("http://public.keystone.example.com/identity/v3", self.assertEqual("http://public.keystone.example.com/identity/v3",
@ -89,12 +88,11 @@ class ServiceAPITests(test.APIMockTestCase):
def test_service_wrapper_service_in_region(self): def test_service_wrapper_service_in_region(self):
catalog = self.service_catalog catalog = self.service_catalog
compute_data = api.base.get_service_from_catalog(catalog, "compute") compute_data = api.base.get_service_from_catalog(catalog, "compute")
# 'Service' class below requires 'id', so populate it here.
compute_data['id'] = 1 compute_data['id'] = 1
region = compute_data["endpoints"][1]["region"] service = api.keystone.Service(compute_data, 'RegionTwo')
service = api.keystone.Service(compute_data, region)
self.assertEqual(u"compute", str(service)) self.assertEqual(u"compute", str(service))
self.assertEqual(compute_data["endpoints"][1]["region"], self.assertEqual("RegionTwo", service.region)
service.region)
self.assertEqual("http://int.nova2.example.com:8774/v2", self.assertEqual("http://int.nova2.example.com:8774/v2",
service.url) service.url)
self.assertEqual("http://public.nova2.example.com:8774/v2", self.assertEqual("http://public.nova2.example.com:8774/v2",