Upversioning platform horizon to master
- Removing murano-ui from iso as it's getting removed soon anyways and was causing problems with horizon - Removing patches for oslo-concurrency as it needed to be upversioned and the changes are no longer needed anyways - Removed patches for django-openstack-auth as it is now in horizon proper and our changes have been dropped - Upversioning horizon spec file Change-Id: I66d1dcf980ef40addbb082de59e56e2d522a9773 Story: 2004765 Task: 28883 Depends-On: https://review.openstack.org/#/c/642797 Signed-off-by: Tyler Smith <tyler.smith@windriver.com>
This commit is contained in:
parent
648757f152
commit
bf34c42fa9
@ -25,10 +25,6 @@ openstack-murano-doc
|
||||
python2-muranoclient
|
||||
python-muranoclient-doc
|
||||
|
||||
# openstack-murano-ui
|
||||
openstack-murano-ui
|
||||
openstack-murano-ui-doc
|
||||
|
||||
# openstack-ironic
|
||||
openstack-ironic-common
|
||||
openstack-ironic-api
|
||||
@ -162,9 +158,6 @@ rabbitmq-server-config
|
||||
# python-openstackclient
|
||||
python2-openstackclient
|
||||
|
||||
# python-django-openstack-auth
|
||||
python2-django-openstack-auth
|
||||
|
||||
# python-wsme
|
||||
python2-wsme
|
||||
|
||||
|
@ -15,7 +15,6 @@ openstack-neutron-wheels
|
||||
openstack-nova-wheels
|
||||
python-cinderclient-wheels
|
||||
python-django-horizon-wheels
|
||||
python-django-openstack-auth-wheels
|
||||
python-glanceclient-wheels
|
||||
python-gnocchiclient-wheels
|
||||
python-ironicclient-wheels
|
||||
|
@ -1,6 +1,5 @@
|
||||
openstack/openstack-murano
|
||||
openstack/python-muranoclient
|
||||
openstack/openstack-murano-ui
|
||||
openstack/openstack-ironic
|
||||
openstack/python-ironicclient
|
||||
openstack/python-magnumclient
|
||||
@ -37,7 +36,6 @@ openstack/python-neutronclient
|
||||
openstack/python-nova
|
||||
openstack/python-novaclient
|
||||
openstack/python-openstackdocstheme
|
||||
openstack/python-oslo-concurrency
|
||||
openstack/python-oslo-service
|
||||
openstack/python-oslo-messaging
|
||||
openstack/python-pankoclient
|
||||
@ -45,7 +43,6 @@ openstack/rabbitmq-server
|
||||
openstack/rabbitmq-server-config
|
||||
openstack/python-openstackclient
|
||||
openstack/python-openstacksdk
|
||||
openstack/python-django-openstack-auth
|
||||
openstack/python-wsme
|
||||
openstack/distributedcloud
|
||||
openstack/distributedcloud-client
|
||||
|
@ -1 +0,0 @@
|
||||
TIS_PATCH_VER=5
|
@ -1,25 +0,0 @@
|
||||
From bb0de73901801c5919041fa73699d6cc5e14495a Mon Sep 17 00:00:00 2001
|
||||
From: Scott Little <scott.little@windriver.com>
|
||||
Date: Wed, 8 Nov 2017 13:52:34 -0500
|
||||
Subject: [PATCH] Update package versioning for TIS format
|
||||
|
||||
---
|
||||
SPECS/python-django-openstack-auth.spec | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/SPECS/python-django-openstack-auth.spec b/SPECS/python-django-openstack-auth.spec
|
||||
index 7ac6008..fd06bbc 100644
|
||||
--- a/SPECS/python-django-openstack-auth.spec
|
||||
+++ b/SPECS/python-django-openstack-auth.spec
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
Name: python-django-openstack-auth
|
||||
Version: 3.6.1
|
||||
-Release: 1%{?dist}
|
||||
+Release: 1.el7%{?_tis_dist}.%{tis_patch_ver}
|
||||
Summary: Django authentication backend for OpenStack Keystone
|
||||
|
||||
License: BSD
|
||||
--
|
||||
1.8.3.1
|
||||
|
@ -1,36 +0,0 @@
|
||||
From 70ecee3d9c45b338a03e32cf59485ada4804f24d Mon Sep 17 00:00:00 2001
|
||||
From: Kam Nasim <kam.nasim@windriver.com>
|
||||
Date: Wed, 8 Nov 2017 14:14:54 -0500
|
||||
Subject: [PATCH] remove rpm build-time TOX tests
|
||||
|
||||
---
|
||||
SPECS/python-django-openstack-auth.spec | 6 +-----
|
||||
1 file changed, 1 insertion(+), 5 deletions(-)
|
||||
|
||||
diff --git a/SPECS/python-django-openstack-auth.spec b/SPECS/python-django-openstack-auth.spec
|
||||
index fd06bbc..2ab88bc 100644
|
||||
--- a/SPECS/python-django-openstack-auth.spec
|
||||
+++ b/SPECS/python-django-openstack-auth.spec
|
||||
@@ -129,7 +129,7 @@ find . -name "django.po" -exec rm -f '{}' \;
|
||||
%endif
|
||||
|
||||
# generate html docs
|
||||
-PYTHONPATH=.:$PYTHONPATH sphinx-build doc/source html
|
||||
+#PYTHONPATH=.:$PYTHONPATH sphinx-build doc/source html
|
||||
|
||||
%install
|
||||
%{__python2} setup.py install --skip-build --root %{buildroot}
|
||||
@@ -150,10 +150,6 @@ rm -rf %{buildroot}/%{python3_sitelib}/openstack_auth/tests
|
||||
%endif
|
||||
|
||||
|
||||
-%check
|
||||
-export PYTHONPATH=$PYTHONPATH
|
||||
-%{__python} openstack_auth/tests/run_tests.py
|
||||
-
|
||||
%files -n python2-django-openstack-auth -f django.lang
|
||||
%license LICENSE
|
||||
%dir %{python_sitelib}/openstack_auth
|
||||
--
|
||||
1.8.3.1
|
||||
|
@ -1,47 +0,0 @@
|
||||
From 4e7ae98c2ffb058711338161a283ce04e47d6bc9 Mon Sep 17 00:00:00 2001
|
||||
From: Kam Nasim <kam.nasim@windriver.com>
|
||||
Date: Wed, 8 Nov 2017 16:54:56 -0500
|
||||
Subject: [PATCH] meta to roll in pike rebase patches
|
||||
|
||||
---
|
||||
SPECS/python-django-openstack-auth.spec | 10 +++++++++-
|
||||
1 file changed, 9 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/SPECS/python-django-openstack-auth.spec b/SPECS/python-django-openstack-auth.spec
|
||||
index 3c65c20..6bd7088 100644
|
||||
--- a/SPECS/python-django-openstack-auth.spec
|
||||
+++ b/SPECS/python-django-openstack-auth.spec
|
||||
@@ -14,6 +14,9 @@ License: BSD
|
||||
URL: http://pypi.python.org/pypi/django_openstack_auth/
|
||||
Source0: https://tarballs.openstack.org/django_openstack_auth/django_openstack_auth-%{upstream_version}.tar.gz
|
||||
|
||||
+# WRS Patches
|
||||
+Patch0001: 0001-Pike-rebase-for-openstack-auth.patch
|
||||
+
|
||||
BuildArch: noarch
|
||||
|
||||
BuildRequires: git
|
||||
@@ -45,6 +48,11 @@ BuildRequires: python-mox3
|
||||
BuildRequires: python-mock
|
||||
BuildRequires: python-testscenarios
|
||||
|
||||
+#WRS: Need these for build_sphinx
|
||||
+BuildRequires: tsconfig
|
||||
+BuildRequires: python2-pycodestyle
|
||||
+BuildRequires: python2-oslo-concurrency
|
||||
+
|
||||
Requires: python-django
|
||||
BuildRequires: python-django
|
||||
|
||||
@@ -107,7 +115,7 @@ Keystone V2 API.
|
||||
|
||||
|
||||
%prep
|
||||
-%autosetup -n %{pypi_name}-%{upstream_version} -S git
|
||||
+%autosetup -n %{pypi_name}-%{upstream_version} -S git -p1
|
||||
|
||||
|
||||
# Remove the requirements file so that pbr hooks don't add it
|
||||
--
|
||||
1.8.3.1
|
||||
|
@ -1,24 +0,0 @@
|
||||
From 5dc546e81e87d78f97af2fd734d41119faa866fe Mon Sep 17 00:00:00 2001
|
||||
From: Kam Nasim <kam.nasim@windriver.com>
|
||||
Date: Mon, 12 Feb 2018 11:04:17 -0500
|
||||
Subject: [PATCH] meta patch for disable-token-validation-per-auth-request
|
||||
|
||||
---
|
||||
SPECS/python-django-openstack-auth.spec | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/SPECS/python-django-openstack-auth.spec b/SPECS/python-django-openstack-auth.spec
|
||||
index 4960ab2..3a462de 100644
|
||||
--- a/SPECS/python-django-openstack-auth.spec
|
||||
+++ b/SPECS/python-django-openstack-auth.spec
|
||||
@@ -16,6 +16,7 @@ Source0: https://tarballs.openstack.org/django_openstack_auth/django_open
|
||||
|
||||
# WRS Patches
|
||||
Patch0001: 0001-Pike-rebase-for-openstack-auth.patch
|
||||
+Patch0002: 0002-disable-token-validation-per-auth-request.patch
|
||||
|
||||
BuildArch: noarch
|
||||
|
||||
--
|
||||
1.8.3.1
|
||||
|
@ -1,25 +0,0 @@
|
||||
From ac0df9c1b8cddc4bb5a06d7e1226144d3f85e83d Mon Sep 17 00:00:00 2001
|
||||
From: Kam Nasim <kam.nasim@windriver.com>
|
||||
Date: Wed, 14 Feb 2018 10:39:33 -0500
|
||||
Subject: [PATCH] meta patch for
|
||||
cache-authorized-tenants-in-cookie-to-improve-performance
|
||||
|
||||
---
|
||||
SPECS/python-django-openstack-auth.spec | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/SPECS/python-django-openstack-auth.spec b/SPECS/python-django-openstack-auth.spec
|
||||
index 3a462de..21e4bde 100644
|
||||
--- a/SPECS/python-django-openstack-auth.spec
|
||||
+++ b/SPECS/python-django-openstack-auth.spec
|
||||
@@ -17,6 +17,7 @@ Source0: https://tarballs.openstack.org/django_openstack_auth/django_open
|
||||
# WRS Patches
|
||||
Patch0001: 0001-Pike-rebase-for-openstack-auth.patch
|
||||
Patch0002: 0002-disable-token-validation-per-auth-request.patch
|
||||
+Patch0003: 0003-cache-authorized-tenants-in-cookie-to-improve-performance.patch
|
||||
|
||||
BuildArch: noarch
|
||||
|
||||
--
|
||||
1.8.3.1
|
||||
|
@ -1,24 +0,0 @@
|
||||
From 186e684a33b3db1c5a5fc010cdb63b459351fcb7 Mon Sep 17 00:00:00 2001
|
||||
From: Kam Nasim <kam.nasim@windriver.com>
|
||||
Date: Wed, 30 May 2018 11:28:49 -0400
|
||||
Subject: [PATCH] meta patch for distributed keystone
|
||||
|
||||
---
|
||||
SPECS/python-django-openstack-auth.spec | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/SPECS/python-django-openstack-auth.spec b/SPECS/python-django-openstack-auth.spec
|
||||
index 21e4bde..f925d87 100644
|
||||
--- a/SPECS/python-django-openstack-auth.spec
|
||||
+++ b/SPECS/python-django-openstack-auth.spec
|
||||
@@ -18,6 +18,7 @@ Source0: https://tarballs.openstack.org/django_openstack_auth/django_open
|
||||
Patch0001: 0001-Pike-rebase-for-openstack-auth.patch
|
||||
Patch0002: 0002-disable-token-validation-per-auth-request.patch
|
||||
Patch0003: 0003-cache-authorized-tenants-in-cookie-to-improve-performance.patch
|
||||
+Patch0004: 0004-Distributed-Keystone.patch
|
||||
|
||||
BuildArch: noarch
|
||||
|
||||
--
|
||||
1.8.3.1
|
||||
|
@ -1,24 +0,0 @@
|
||||
From c047aecf35d067390d0e80e0149725c3031a19c3 Mon Sep 17 00:00:00 2001
|
||||
From: Tyler Smith <tyler.smith@windriver.com>
|
||||
Date: Fri, 29 Jun 2018 20:07:09 -0500
|
||||
Subject: [PATCH 1/1] [PATCH] meta patch for distributed keystone fix
|
||||
|
||||
---
|
||||
SPECS/python-django-openstack-auth.spec | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/SPECS/python-django-openstack-auth.spec b/SPECS/python-django-openstack-auth.spec
|
||||
index 90b4692..89acf21 100644
|
||||
--- a/SPECS/python-django-openstack-auth.spec
|
||||
+++ b/SPECS/python-django-openstack-auth.spec
|
||||
@@ -19,6 +19,7 @@ Patch0001: 0001-Pike-rebase-for-openstack-auth.patch
|
||||
Patch0002: 0002-disable-token-validation-per-auth-request.patch
|
||||
Patch0003: 0003-cache-authorized-tenants-in-cookie-to-improve-performance.patch
|
||||
Patch0004: 0004-Distributed-Keystone.patch
|
||||
+Patch0005: fix_for_dc_region_switching.patch
|
||||
|
||||
BuildArch: noarch
|
||||
|
||||
--
|
||||
2.7.4
|
||||
|
@ -1,58 +0,0 @@
|
||||
From 1a5349cf73177d155a3309737635bc1ae22ae051 Mon Sep 17 00:00:00 2001
|
||||
From: Don Penney <don.penney@windriver.com>
|
||||
Date: Mon, 17 Dec 2018 09:16:20 -0600
|
||||
Subject: [PATCH] Build python wheel
|
||||
|
||||
---
|
||||
SPECS/python-django-openstack-auth.spec | 14 ++++++++++++++
|
||||
1 file changed, 14 insertions(+)
|
||||
|
||||
diff --git a/SPECS/python-django-openstack-auth.spec b/SPECS/python-django-openstack-auth.spec
|
||||
index 89acf21..5e9e8e0 100644
|
||||
--- a/SPECS/python-django-openstack-auth.spec
|
||||
+++ b/SPECS/python-django-openstack-auth.spec
|
||||
@@ -39,6 +39,8 @@ Summary: Django authentication backend for OpenStack Keystone
|
||||
%{?python_provide:%python_provide python2-django-openstack-auth}
|
||||
BuildRequires: python2-devel
|
||||
BuildRequires: python-setuptools
|
||||
+BuildRequires: python2-pip
|
||||
+BuildRequires: python2-wheel
|
||||
BuildRequires: python-sphinx
|
||||
BuildRequires: python-keystoneclient
|
||||
BuildRequires: python-iso8601
|
||||
@@ -135,6 +137,7 @@ find . -name "django.po" -exec rm -f '{}' \;
|
||||
|
||||
|
||||
%{__python} setup.py build
|
||||
+%py2_build_wheel
|
||||
|
||||
%if 0%{?with_python3}
|
||||
%{__python3} setup.py build
|
||||
@@ -145,6 +148,8 @@ find . -name "django.po" -exec rm -f '{}' \;
|
||||
|
||||
%install
|
||||
%{__python2} setup.py install --skip-build --root %{buildroot}
|
||||
+mkdir -p $RPM_BUILD_ROOT/wheels
|
||||
+install -m 644 dist/*.whl $RPM_BUILD_ROOT/wheels/
|
||||
|
||||
cp -r openstack_auth/locale %{buildroot}/%{python_sitelib}/openstack_auth
|
||||
|
||||
@@ -189,6 +194,15 @@ rm -rf %{buildroot}/%{python3_sitelib}/openstack_auth/tests
|
||||
%{python3_sitelib}/%{pypi_name}-*.egg-info
|
||||
%endif
|
||||
|
||||
+%package wheels
|
||||
+Summary: %{name} wheels
|
||||
+
|
||||
+%description wheels
|
||||
+Contains python wheels for %{name}
|
||||
+
|
||||
+%files wheels
|
||||
+/wheels/*
|
||||
+
|
||||
%changelog
|
||||
* Tue Jun 12 2018 RDO <dev@lists.rdoproject.org> 3.6.1-1
|
||||
- Update to 3.6.1
|
||||
--
|
||||
1.8.3.1
|
||||
|
@ -1,8 +0,0 @@
|
||||
0001-Update-package-versioning-for-TIS-format.patch
|
||||
0002-remove-rpm-build-time-TOX-tests.patch
|
||||
0003-meta-roll-in-TIS-patches.patch
|
||||
0004-meta-disable-token-validation-per-auth-req.patch
|
||||
0005-meta-cache-authorized-tenants-in-cookie-to-improve-performance.patch
|
||||
0006-meta-Distributed-Keystone.patch
|
||||
0007-meta-patch-for-distributed-keystone-fix.patch
|
||||
0008-Build-python-wheel.patch
|
@ -1,495 +0,0 @@
|
||||
From b2e9d78e5385ad7c67b4ce2ef33b64206e5ccf6d Mon Sep 17 00:00:00 2001
|
||||
From: Kam Nasim <kam.nasim@windriver.com>
|
||||
Date: Wed, 25 Jan 2017 11:58:56 -0500
|
||||
Subject: [PATCH] Pike rebase for openstack auth
|
||||
|
||||
Squashes in the following Titanium patches (some patches have been
|
||||
upstreamed and not mentioned here):
|
||||
|
||||
- User lockout feature (Author: Aly Nathoo)
|
||||
- Add client ip to login / lockout activies and logging for user lockout
|
||||
(Author: David Balme)
|
||||
- Optimize keystone authentication requests during user lockout
|
||||
(Author: Kam Nasim)
|
||||
- Stop user lockout increment when Keystone is unavailable
|
||||
(Author: David Balme)
|
||||
- Change default region for openstack auth to local Horizon's region
|
||||
(Author: Tyler Smith)
|
||||
- Refactor user lockout for multiple browser sessions, and fix horizon
|
||||
session timeout issue (Author: Giao Le)
|
||||
- Validate token before initiating session to prevent invalid token
|
||||
issues (Author: Giao Le)
|
||||
---
|
||||
openstack_auth/backend.py | 4 +
|
||||
openstack_auth/forms.py | 35 ++++--
|
||||
openstack_auth/plugin/base.py | 7 +-
|
||||
openstack_auth/user.py | 15 +++
|
||||
openstack_auth/utils.py | 242 +++++++++++++++++++++++++++++++++++++++++-
|
||||
openstack_auth/views.py | 12 ++-
|
||||
6 files changed, 302 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/openstack_auth/backend.py b/openstack_auth/backend.py
|
||||
index dae603a..cd15ca8 100644
|
||||
--- a/openstack_auth/backend.py
|
||||
+++ b/openstack_auth/backend.py
|
||||
@@ -170,6 +170,10 @@ class KeystoneBackend(object):
|
||||
region_name = id_endpoint['region']
|
||||
break
|
||||
|
||||
+ local_region = getattr(settings, 'REGION_NAME', None)
|
||||
+ if local_region:
|
||||
+ region_name = local_region
|
||||
+
|
||||
interface = getattr(settings, 'OPENSTACK_ENDPOINT_TYPE', 'public')
|
||||
|
||||
endpoint, url_fixed = utils.fix_auth_url_version_prefix(
|
||||
diff --git a/openstack_auth/forms.py b/openstack_auth/forms.py
|
||||
index c7d0c51..90e281b 100644
|
||||
--- a/openstack_auth/forms.py
|
||||
+++ b/openstack_auth/forms.py
|
||||
@@ -24,7 +24,6 @@ from django.views.decorators.debug import sensitive_variables
|
||||
from openstack_auth import exceptions
|
||||
from openstack_auth import utils
|
||||
|
||||
-
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -118,6 +117,7 @@ class Login(django_auth_forms.AuthenticationForm):
|
||||
|
||||
@sensitive_variables()
|
||||
def clean(self):
|
||||
+ global failedUserLogins
|
||||
default_domain = getattr(settings,
|
||||
'OPENSTACK_KEYSTONE_DEFAULT_DOMAIN',
|
||||
'Default')
|
||||
@@ -131,6 +131,14 @@ class Login(django_auth_forms.AuthenticationForm):
|
||||
return self.cleaned_data
|
||||
|
||||
try:
|
||||
+ # assess the lockout status for this user.
|
||||
+ # If this user is already locked out then
|
||||
+ # do not attempt to authenticate as that is
|
||||
+ # a redundant hit on Keystone and web proxy.
|
||||
+ lockedout = utils.check_user_lockout(username)
|
||||
+ if lockedout:
|
||||
+ raise forms.ValidationError("user currently locked out.")
|
||||
+
|
||||
self.user_cache = authenticate(request=self.request,
|
||||
username=username,
|
||||
password=password,
|
||||
@@ -142,14 +150,27 @@ class Login(django_auth_forms.AuthenticationForm):
|
||||
'remote_ip': utils.get_client_ip(self.request)
|
||||
}
|
||||
LOG.info(msg)
|
||||
+
|
||||
+ # since this user logged in successfully, clear its
|
||||
+ # lockout status
|
||||
+ utils.clear_user_lockout(username)
|
||||
+
|
||||
+ # handle user login
|
||||
+ utils.handle_user_login(username, password)
|
||||
+
|
||||
except exceptions.KeystoneAuthException as exc:
|
||||
- msg = 'Login failed for user "%(username)s", remote address '\
|
||||
- '%(remote_ip)s.' % {
|
||||
- 'username': username,
|
||||
- 'remote_ip': utils.get_client_ip(self.request)
|
||||
- }
|
||||
- LOG.warning(msg)
|
||||
+ if getattr(exc,"invalidCredentials", False):
|
||||
+ msg = 'Login failed for user "%(username)s", remote address '\
|
||||
+ '%(remote_ip)s.' % {
|
||||
+ 'username': username,
|
||||
+ 'remote_ip': utils.get_client_ip(self.request)
|
||||
+ }
|
||||
+ LOG.warning(msg)
|
||||
+ utils.add_user_lockout(username)
|
||||
+ LOG.warning("Invalid password entered for User %s "
|
||||
+ "in web service." % username)
|
||||
raise forms.ValidationError(exc)
|
||||
+
|
||||
if hasattr(self, 'check_for_test_cookie'): # Dropped in django 1.7
|
||||
self.check_for_test_cookie()
|
||||
return self.cleaned_data
|
||||
diff --git a/openstack_auth/plugin/base.py b/openstack_auth/plugin/base.py
|
||||
index f1aff52..bbdaddc 100644
|
||||
--- a/openstack_auth/plugin/base.py
|
||||
+++ b/openstack_auth/plugin/base.py
|
||||
@@ -95,7 +95,7 @@ class BasePlugin(object):
|
||||
|
||||
except (keystone_exceptions.ClientException,
|
||||
keystone_exceptions.AuthorizationFailure):
|
||||
- msg = _('Unable to retrieve authorized projects.')
|
||||
+ msg = 'Unable to retrieve authorized projects.'
|
||||
raise exceptions.KeystoneAuthException(msg)
|
||||
|
||||
def list_domains(self, session, auth_plugin, auth_ref=None):
|
||||
@@ -132,7 +132,10 @@ class BasePlugin(object):
|
||||
keystone_exceptions.Forbidden,
|
||||
keystone_exceptions.NotFound) as exc:
|
||||
LOG.debug(str(exc))
|
||||
- raise exceptions.KeystoneAuthException(_('Invalid credentials.'))
|
||||
+ authException = exceptions.KeystoneAuthException(
|
||||
+ _('Invalid credentials.'))
|
||||
+ authException.invalidCredentials = True
|
||||
+ raise authException
|
||||
except (keystone_exceptions.ClientException,
|
||||
keystone_exceptions.AuthorizationFailure) as exc:
|
||||
msg = _("An error occurred authenticating. "
|
||||
diff --git a/openstack_auth/user.py b/openstack_auth/user.py
|
||||
index 063648b..c6f616c 100644
|
||||
--- a/openstack_auth/user.py
|
||||
+++ b/openstack_auth/user.py
|
||||
@@ -253,6 +253,9 @@ class User(models.AbstractBaseUser, models.AnonymousUser):
|
||||
# Required by AbstractBaseUser
|
||||
self.password = None
|
||||
|
||||
+ # WRS: additional check to validate token prior to using
|
||||
+ self.validate_token = False
|
||||
+
|
||||
def __unicode__(self):
|
||||
return self.username
|
||||
|
||||
@@ -305,6 +308,18 @@ class User(models.AbstractBaseUser, models.AnonymousUser):
|
||||
A default margin can be set by the TOKEN_TIMEOUT_MARGIN in the
|
||||
django settings.
|
||||
"""
|
||||
+ # WRS: validate token
|
||||
+ if not self.validate_token:
|
||||
+ try:
|
||||
+ utils.validate_token(
|
||||
+ auth_url=self.endpoint,
|
||||
+ auth_token=self.unscoped_token,
|
||||
+ token=self.token)
|
||||
+ except (keystone_exceptions.ClientException,
|
||||
+ keystone_exceptions.AuthorizationFailure):
|
||||
+ self.token.expires = None
|
||||
+ self.validate_token = True
|
||||
+
|
||||
return (self.token is not None and
|
||||
utils.is_token_valid(self.token, margin))
|
||||
|
||||
diff --git a/openstack_auth/utils.py b/openstack_auth/utils.py
|
||||
index cac0d7a..1b35592 100644
|
||||
--- a/openstack_auth/utils.py
|
||||
+++ b/openstack_auth/utils.py
|
||||
@@ -12,7 +12,13 @@
|
||||
# limitations under the License.
|
||||
|
||||
import datetime
|
||||
+import errno
|
||||
+import fcntl
|
||||
+import keyring
|
||||
import logging
|
||||
+import os
|
||||
+import time
|
||||
+import time
|
||||
import re
|
||||
|
||||
from django.conf import settings
|
||||
@@ -25,6 +31,8 @@ from keystoneauth1 import session
|
||||
from keystoneauth1 import token_endpoint
|
||||
from keystoneclient.v2_0 import client as client_v2
|
||||
from keystoneclient.v3 import client as client_v3
|
||||
+from oslo_concurrency import lockutils
|
||||
+from oslo_serialization import jsonutils
|
||||
from six.moves.urllib import parse as urlparse
|
||||
|
||||
|
||||
@@ -357,6 +365,14 @@ def get_token_auth_plugin(auth_url, token, project_id=None, domain_name=None):
|
||||
reauthenticate=False)
|
||||
|
||||
|
||||
+def validate_token(auth_url, auth_token, token):
|
||||
+ auth_url, _ = fix_auth_url_version_prefix(auth_url)
|
||||
+ auth = token_endpoint.Token(auth_url, auth_token)
|
||||
+ sess = get_session()
|
||||
+ client = get_keystone_client().Client(session=sess, auth=auth)
|
||||
+ _ = client.tokens.validate(token)
|
||||
+
|
||||
+
|
||||
def get_project_list(*args, **kwargs):
|
||||
is_federated = kwargs.get('is_federated', False)
|
||||
sess = kwargs.get('session') or get_session()
|
||||
@@ -489,9 +505,10 @@ def get_admin_permissions():
|
||||
return {get_role_permission(role) for role in get_admin_roles()}
|
||||
|
||||
|
||||
+
|
||||
def get_client_ip(request):
|
||||
"""Return client ip address using SECURE_PROXY_ADDR_HEADER variable.
|
||||
-
|
||||
+ If not present then consider using HTTP_X_FORWARDED_FOR from.
|
||||
If not present or not defined on settings then REMOTE_ADDR is used.
|
||||
|
||||
:param request: Django http request object.
|
||||
@@ -508,7 +525,12 @@ def get_client_ip(request):
|
||||
_SECURE_PROXY_ADDR_HEADER,
|
||||
request.META.get('REMOTE_ADDR')
|
||||
)
|
||||
- return request.META.get('REMOTE_ADDR')
|
||||
+ else:
|
||||
+ x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
|
||||
+ if x_forwarded_for:
|
||||
+ return (x_forwarded_for.split(',')[0])
|
||||
+ else:
|
||||
+ return request.META.get('REMOTE_ADDR')
|
||||
|
||||
|
||||
def store_initial_k2k_session(auth_url, request, scoped_auth_ref,
|
||||
@@ -560,3 +582,219 @@ def store_initial_k2k_session(auth_url, request, scoped_auth_ref,
|
||||
request.session['k2k_base_unscoped_token'] =\
|
||||
unscoped_auth_ref.auth_token
|
||||
request.session['k2k_auth_url'] = auth_url
|
||||
+
|
||||
+
|
||||
+def __log_cache_error__(op, fn, ex):
|
||||
+ msg = ("unable to %(op)s cache file %(fn)s due to %(ex)s") %\
|
||||
+ {'op': op, 'fn': fn, 'ex': ex}
|
||||
+ LOG.warning(msg)
|
||||
+
|
||||
+
|
||||
+def __lock_cache__(cache_file):
|
||||
+ try:
|
||||
+ f = open(cache_file, "r+")
|
||||
+ except Exception as ex:
|
||||
+ __log_cache_error__("open", cache_file, ex)
|
||||
+ raise
|
||||
+
|
||||
+ try:
|
||||
+ fcntl.flock(f.fileno(), fcntl.LOCK_EX)
|
||||
+ except Exception as ex:
|
||||
+ __log_cache_error__("lock", f.name, ex)
|
||||
+ raise
|
||||
+
|
||||
+ return f
|
||||
+
|
||||
+
|
||||
+def __write_cache__(f, filedata):
|
||||
+ try:
|
||||
+ f.seek(0, 0)
|
||||
+ f.truncate()
|
||||
+ f.write(jsonutils.dumps(filedata))
|
||||
+ except Exception as ex:
|
||||
+ __log_cache_error__("write", f.name, ex)
|
||||
+
|
||||
+
|
||||
+def __read_cache__(f, default=[]):
|
||||
+ try:
|
||||
+ f.seek(0, 0)
|
||||
+ return jsonutils.loads(f.read())
|
||||
+ except Exception as ex:
|
||||
+ __log_cache_error__("read", f.name, ex)
|
||||
+
|
||||
+ return default
|
||||
+
|
||||
+
|
||||
+def __create_cache__(fname, default=[]):
|
||||
+ try:
|
||||
+ with open(__file__, "r") as l:
|
||||
+ fcntl.flock(l.fileno(), fcntl.LOCK_EX)
|
||||
+ if not os.path.exists(fname):
|
||||
+ with open(fname, "w") as f:
|
||||
+ __write_cache__(f, default)
|
||||
+
|
||||
+ except Exception as ex:
|
||||
+ __log_cache_error__("create", fname, ex)
|
||||
+
|
||||
+
|
||||
+# Track failed logins
|
||||
+# Keep an array of failedUserLogins
|
||||
+# failedUserLogins : username NumFailedLogins LockoutTime
|
||||
+# if a login fails due to invalid password (username is ok),
|
||||
+# add username to array and increment NumFailedLogins
|
||||
+# if a login succeeds
|
||||
+# look up username in failedUserLogins, if found
|
||||
+# if NumFailedLogins > 3, check LockoutTime
|
||||
+# if CurrentTime - LockoutTime < 5min then
|
||||
+# fail login
|
||||
+# else
|
||||
+# remove username from failedUserLogins
|
||||
+# else
|
||||
+# remove username from failedUserLogins, let user log in
|
||||
+
|
||||
+FAILED_LOGINS_CACHE_FILE = "/tmp/.hacache"
|
||||
+FAILED_LOGINS_NAME_INDEX = 0
|
||||
+FAILED_LOGINS_COUNT_INDEX = 1
|
||||
+FAILED_LOGINS_TIME_INDEX = 2
|
||||
+
|
||||
+lockout_tuple = (settings.LOCKOUT_PERIOD_SEC, settings.LOCKOUT_RETRIES_NUM)
|
||||
+
|
||||
+if not os.path.exists(FAILED_LOGINS_CACHE_FILE):
|
||||
+ __create_cache__(FAILED_LOGINS_CACHE_FILE)
|
||||
+
|
||||
+
|
||||
+def check_user_lockout(username):
|
||||
+ try:
|
||||
+ with __lock_cache__(FAILED_LOGINS_CACHE_FILE) as f:
|
||||
+ failedUserLogins = __read_cache__(f)
|
||||
+ (lockout_period_sec, lockout_retries_num) = lockout_tuple
|
||||
+ for i, user in enumerate(failedUserLogins):
|
||||
+ if user[FAILED_LOGINS_NAME_INDEX] != username:
|
||||
+ continue
|
||||
+ if user[FAILED_LOGINS_COUNT_INDEX] >= lockout_retries_num:
|
||||
+ delta = time.time() - user[FAILED_LOGINS_TIME_INDEX]
|
||||
+ if delta < lockout_period_sec:
|
||||
+ msg = ("Cannot login/authenticate -"
|
||||
+ " user \"%(username)s\" locked out." % \
|
||||
+ {'username': username})
|
||||
+ LOG.info(msg)
|
||||
+ return True
|
||||
+ break
|
||||
+ except:
|
||||
+ pass
|
||||
+
|
||||
+ return False
|
||||
+
|
||||
+
|
||||
+def add_user_lockout(username):
|
||||
+ try:
|
||||
+ with __lock_cache__(FAILED_LOGINS_CACHE_FILE) as f:
|
||||
+ failedUserLogins = __read_cache__(f)
|
||||
+ (lockout_period_sec, lockout_retries_num) = lockout_tuple
|
||||
+ for user in failedUserLogins:
|
||||
+ if user[FAILED_LOGINS_NAME_INDEX] == username:
|
||||
+ user[FAILED_LOGINS_COUNT_INDEX] += 1
|
||||
+ if user[FAILED_LOGINS_COUNT_INDEX] >= lockout_retries_num:
|
||||
+ # user is now locked out, record the new time
|
||||
+ user[FAILED_LOGINS_TIME_INDEX] = time.time()
|
||||
+ LOG.warning("User %s is locked out of web service"
|
||||
+ "- attempted login." % (username))
|
||||
+ break
|
||||
+ else:
|
||||
+ failedUserLogins.append([username,1,0])
|
||||
+ __write_cache__(f, failedUserLogins)
|
||||
+ except:
|
||||
+ pass
|
||||
+
|
||||
+
|
||||
+def clear_user_lockout(username):
|
||||
+ try:
|
||||
+ with __lock_cache__(FAILED_LOGINS_CACHE_FILE) as f:
|
||||
+ failedUserLogins = __read_cache__(f)
|
||||
+ for i, user in enumerate(failedUserLogins):
|
||||
+ if user[FAILED_LOGINS_NAME_INDEX] == username:
|
||||
+ # clear the entry for this user
|
||||
+ failedUserLogins[i] = None
|
||||
+ failedUserLogins = [elem for elem in failedUserLogins if elem]
|
||||
+ __write_cache__(f, failedUserLogins)
|
||||
+ break
|
||||
+ except:
|
||||
+ pass
|
||||
+
|
||||
+
|
||||
+# Manage user password using keyring service
|
||||
+# 1. add user password to keyring service once
|
||||
+# user logs in the first time
|
||||
+# 2. delete user password from keyring service once
|
||||
+# user logs out all sessions
|
||||
+
|
||||
+USER_LOGINS_CACHE_FILE = '/tmp/.hacache1'
|
||||
+USER_LOGINS_NAME_INDEX = 0
|
||||
+USER_LOGINS_COUNT_INDEX = 1
|
||||
+USER_LOGINS_KEYRING = 'hakeyring'
|
||||
+
|
||||
+if not os.path.exists(USER_LOGINS_CACHE_FILE):
|
||||
+ __create_cache__(USER_LOGINS_CACHE_FILE)
|
||||
+
|
||||
+
|
||||
+def get_user_password(username):
|
||||
+ # use CGCS for admin
|
||||
+ service = 'CGCS' if username == 'admin' else USER_LOGINS_KEYRING
|
||||
+ return keyring.get_password(service, username)
|
||||
+
|
||||
+
|
||||
+def handle_user_login(username, password):
|
||||
+ if username == 'admin':
|
||||
+ return
|
||||
+
|
||||
+ try:
|
||||
+ with __lock_cache__(USER_LOGINS_CACHE_FILE) as f:
|
||||
+ logined = False
|
||||
+ userLogins = __read_cache__(f)
|
||||
+ for i, user in enumerate(userLogins):
|
||||
+ if user[USER_LOGINS_NAME_INDEX] == username:
|
||||
+ user[USER_LOGINS_COUNT_INDEX] += 1
|
||||
+ logined = True
|
||||
+ break
|
||||
+ try:
|
||||
+ old = keyring.get_password(USER_LOGINS_KEYRING, username)
|
||||
+ if old and old != password:
|
||||
+ keyring.delete_password(USER_LOGINS_KEYRING, username)
|
||||
+ old = None
|
||||
+ if not old:
|
||||
+ keyring.set_password(USER_LOGINS_KEYRING, username,
|
||||
+ password)
|
||||
+ except (keyring.errors.PasswordSetError, RuntimeError):
|
||||
+ LOG.warning("Failed to update keyring passord"
|
||||
+ " for user %s" % username)
|
||||
+
|
||||
+ if not logined:
|
||||
+ userLogins.append([username, 1])
|
||||
+ __write_cache__(f, userLogins)
|
||||
+ except:
|
||||
+ LOG.warning("Failed to handle login for user %s" % username)
|
||||
+
|
||||
+
|
||||
+def handle_user_logout(username):
|
||||
+ if username == 'admin':
|
||||
+ return
|
||||
+
|
||||
+ try:
|
||||
+ with __lock_cache__(USER_LOGINS_CACHE_FILE) as f:
|
||||
+ userLogins = __read_cache__(f)
|
||||
+ for i, user in enumerate(userLogins):
|
||||
+ if user[USER_LOGINS_NAME_INDEX] != username:
|
||||
+ continue
|
||||
+ user[USER_LOGINS_COUNT_INDEX] -= 1
|
||||
+ if user[USER_LOGINS_COUNT_INDEX] == 0:
|
||||
+ userLogins[i] = None
|
||||
+ userLogins = [e for e in userLogins if e]
|
||||
+ try:
|
||||
+ keyring.delete_password(USER_LOGINS_KEYRING, username)
|
||||
+ except keyring.errors.PasswordDeleteError:
|
||||
+ LOG.warning("Failed to delete keyring passowrd"
|
||||
+ " for user %s" % username)
|
||||
+ __write_cache__(f, userLogins)
|
||||
+ break
|
||||
+ except:
|
||||
+ LOG.warning("Failed to handle logout for user %s" % username)
|
||||
diff --git a/openstack_auth/views.py b/openstack_auth/views.py
|
||||
index 7ae3063..bf4aa99 100644
|
||||
--- a/openstack_auth/views.py
|
||||
+++ b/openstack_auth/views.py
|
||||
@@ -130,6 +130,10 @@ def login(request, template_name=None, extra_context=None, **kwargs):
|
||||
' in %s minutes') %
|
||||
expiration_time).replace(':', ' Hours and ')
|
||||
messages.warning(request, msg)
|
||||
+
|
||||
+ # WRS: add login user name to handle HORIZON session timeout
|
||||
+ utils.set_response_cookie(res, 'login_user',
|
||||
+ request.user.username)
|
||||
return res
|
||||
|
||||
|
||||
@@ -167,10 +171,14 @@ def logout(request, login_url=None, **kwargs):
|
||||
see django.contrib.auth.views.logout_then_login extra parameters.
|
||||
|
||||
"""
|
||||
- msg = 'Logging out user "%(username)s".' % \
|
||||
- {'username': request.user.username}
|
||||
+ msg = 'Logging out user "%(username)s", remote address %(remote_ip)s.' % \
|
||||
+ {'username': request.user.username,
|
||||
+ 'remote_ip': utils.get_client_ip(request)}
|
||||
LOG.info(msg)
|
||||
|
||||
+ # handle user logout
|
||||
+ utils.handle_user_logout(request.user.username)
|
||||
+
|
||||
""" Securely logs a user out. """
|
||||
return django_auth_views.logout_then_login(request, login_url=login_url,
|
||||
**kwargs)
|
||||
--
|
||||
1.8.3.1
|
||||
|
@ -1,28 +0,0 @@
|
||||
From 3b6605b547bb27b272345b03797abc94a23469ab Mon Sep 17 00:00:00 2001
|
||||
From: rpm-build <rpm-build>
|
||||
Date: Mon, 12 Feb 2018 10:59:39 -0500
|
||||
Subject: [PATCH] disable token validation per auth request
|
||||
|
||||
To prevent invalid tokens from being used, each request would previous
|
||||
attempt a token validation request. This causes 2x AUTH requests to
|
||||
Keystone which is affecting Host Swact/Lock and VM migration times
|
||||
---
|
||||
openstack_auth/user.py | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/openstack_auth/user.py b/openstack_auth/user.py
|
||||
index c6f616c..f486bfa 100644
|
||||
--- a/openstack_auth/user.py
|
||||
+++ b/openstack_auth/user.py
|
||||
@@ -254,7 +254,7 @@ class User(models.AbstractBaseUser, models.AnonymousUser):
|
||||
self.password = None
|
||||
|
||||
# WRS: additional check to validate token prior to using
|
||||
- self.validate_token = False
|
||||
+ self.validate_token = True
|
||||
|
||||
def __unicode__(self):
|
||||
return self.username
|
||||
--
|
||||
1.8.3.1
|
||||
|
@ -1,69 +0,0 @@
|
||||
From b6724faf6f485f08584a7965bcd881d1f3b78f7c Mon Sep 17 00:00:00 2001
|
||||
From: rpm-build <rpm-build>
|
||||
Date: Wed, 14 Feb 2018 16:55:29 -0500
|
||||
Subject: [PATCH] cache authorized tenants list in cookie to improve
|
||||
performance
|
||||
|
||||
---
|
||||
openstack_auth/utils.py | 9 +++++++++
|
||||
openstack_auth/views.py | 17 +++++++++++++++++
|
||||
2 files changed, 26 insertions(+)
|
||||
|
||||
diff --git a/openstack_auth/utils.py b/openstack_auth/utils.py
|
||||
index 1b35592..9a55790 100644
|
||||
--- a/openstack_auth/utils.py
|
||||
+++ b/openstack_auth/utils.py
|
||||
@@ -438,6 +438,15 @@ def set_response_cookie(response, cookie_name, cookie_value):
|
||||
response.set_cookie(cookie_name, cookie_value, expires=expire_date)
|
||||
|
||||
|
||||
+def delete_response_cookie(response, cookie_name):
|
||||
+ """ Common function for deleting a cookie from the response.
|
||||
+
|
||||
+ Deletes the cookie of the given cookie_name. Fails silently
|
||||
+ if cookie name doesn't exist
|
||||
+ """
|
||||
+ response.delete_cookie(cookie_name)
|
||||
+
|
||||
+
|
||||
def get_endpoint_region(endpoint):
|
||||
"""Common function for getting the region from endpoint.
|
||||
|
||||
diff --git a/openstack_auth/views.py b/openstack_auth/views.py
|
||||
index bf4aa99..a9d84df 100644
|
||||
--- a/openstack_auth/views.py
|
||||
+++ b/openstack_auth/views.py
|
||||
@@ -134,6 +134,15 @@ def login(request, template_name=None, extra_context=None, **kwargs):
|
||||
# WRS: add login user name to handle HORIZON session timeout
|
||||
utils.set_response_cookie(res, 'login_user',
|
||||
request.user.username)
|
||||
+
|
||||
+ # WRS: Store project list to handle frequent requests to
|
||||
+ # Keystone. Since the cookie is not removed on logout, we will
|
||||
+ # do it here.
|
||||
+ tenants = request.user.authorized_tenants
|
||||
+ tenants = map(lambda x: x.to_dict(), tenants)
|
||||
+ utils.delete_response_cookie(res, 'authorized_tenants')
|
||||
+ utils.set_response_cookie(res, 'authorized_tenants', tenants)
|
||||
+
|
||||
return res
|
||||
|
||||
|
||||
@@ -237,6 +246,14 @@ def switch(request, tenant_id, redirect_field_name=auth.REDIRECT_FIELD_NAME):
|
||||
response = shortcuts.redirect(redirect_to)
|
||||
utils.set_response_cookie(response, 'recent_project',
|
||||
request.user.project_id)
|
||||
+
|
||||
+ # WRS: Refresh the project list stored in the cookie, along with
|
||||
+ # the project switch event
|
||||
+ tenants = request.user.authorized_tenants
|
||||
+ tenants = map(lambda x: x.to_dict(), tenants)
|
||||
+ utils.delete_response_cookie(response, 'authorized_tenants')
|
||||
+ utils.set_response_cookie(response, 'authorized_tenants', tenants)
|
||||
+
|
||||
return response
|
||||
|
||||
|
||||
--
|
||||
1.8.3.1
|
||||
|
@ -1,275 +0,0 @@
|
||||
From 3e528e26f17593bb2c1a148768367f194adfa343 Mon Sep 17 00:00:00 2001
|
||||
From: Kam Nasim <kam.nasim@windriver.com>
|
||||
Date: Wed, 30 May 2018 11:01:33 -0400
|
||||
Subject: [PATCH] Distributed Keystone for Distributed Cloud -
|
||||
Horizon
|
||||
|
||||
In Distributed Cloud, Keystone is now running on each Subcloud.
|
||||
Switching to Subcloud region now requires Openstack Auth to retrieve an
|
||||
Unscoped token from the switched Region and reinitialize the django
|
||||
session and cookie data with token data retrieved from the Subcloud.
|
||||
|
||||
Since Subcloud's Keystone doesn't contain the Identity endpoint for the
|
||||
Central Region, there was no way to go back in Horizon from a subcloud
|
||||
region to the SystemController region. We achieve this by caching the
|
||||
SystemController endpoint in the Django Session at the time of login
|
||||
---
|
||||
openstack_auth/user.py | 8 ++++-
|
||||
openstack_auth/utils.py | 47 ++++++++++++++++++++++++-----
|
||||
openstack_auth/views.py | 78 ++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
3 files changed, 123 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/openstack_auth/user.py b/openstack_auth/user.py
|
||||
index f486bfa..39e3e34 100644
|
||||
--- a/openstack_auth/user.py
|
||||
+++ b/openstack_auth/user.py
|
||||
@@ -29,6 +29,7 @@ from openstack_auth import utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
_TOKEN_HASH_ENABLED = getattr(settings, 'OPENSTACK_TOKEN_HASH_ENABLED', True)
|
||||
+_DC_MODE = getattr(settings, 'DC_MODE', False)
|
||||
|
||||
|
||||
def set_session_from_user(request, user):
|
||||
@@ -387,12 +388,17 @@ class User(models.AbstractBaseUser, models.AnonymousUser):
|
||||
if self.service_catalog:
|
||||
for service in self.service_catalog:
|
||||
service_type = service.get('type')
|
||||
- if service_type is None or service_type == 'identity':
|
||||
+ if service_type is None:
|
||||
continue
|
||||
for endpoint in service.get('endpoints', []):
|
||||
region = utils.get_endpoint_region(endpoint)
|
||||
if region not in regions:
|
||||
regions.append(region)
|
||||
+ # If we are in Distributed Cloud mode, then ensure that
|
||||
+ # SystemController region is present in the Region Selection
|
||||
+ if _DC_MODE and utils.DC_SYSTEMCONTROLLER_REGION not in regions:
|
||||
+ regions.append(utils.DC_SYSTEMCONTROLLER_REGION)
|
||||
+
|
||||
return regions
|
||||
|
||||
def save(*args, **kwargs):
|
||||
diff --git a/openstack_auth/utils.py b/openstack_auth/utils.py
|
||||
index 9a55790..a2107a0 100644
|
||||
--- a/openstack_auth/utils.py
|
||||
+++ b/openstack_auth/utils.py
|
||||
@@ -18,7 +18,6 @@ import keyring
|
||||
import logging
|
||||
import os
|
||||
import time
|
||||
-import time
|
||||
import re
|
||||
|
||||
from django.conf import settings
|
||||
@@ -40,6 +39,10 @@ LOG = logging.getLogger(__name__)
|
||||
|
||||
_TOKEN_TIMEOUT_MARGIN = getattr(settings, 'TOKEN_TIMEOUT_MARGIN', 0)
|
||||
|
||||
+# Distributed Cloud Region Definitions
|
||||
+DC_SYSTEMCONTROLLER_REGION = "SystemController"
|
||||
+DC_LOCAL_REGION = "RegionOne"
|
||||
+
|
||||
"""
|
||||
We need the request object to get the user, so we'll slightly modify the
|
||||
existing django.contrib.auth.get_user method. To do so we update the
|
||||
@@ -346,7 +349,8 @@ def clean_up_auth_url(auth_url):
|
||||
scheme, netloc, re.sub(r'/auth.*', '', path), '', ''))
|
||||
|
||||
|
||||
-def get_token_auth_plugin(auth_url, token, project_id=None, domain_name=None):
|
||||
+def get_token_auth_plugin(auth_url, token, project_id=None, project_name=None,
|
||||
+ domain_name=None):
|
||||
if get_keystone_version() >= 3:
|
||||
if domain_name:
|
||||
return v3_auth.Token(auth_url=auth_url,
|
||||
@@ -354,9 +358,13 @@ def get_token_auth_plugin(auth_url, token, project_id=None, domain_name=None):
|
||||
domain_name=domain_name,
|
||||
reauthenticate=False)
|
||||
else:
|
||||
+ # If project ID is defined then use that
|
||||
+ # otherwise we expect the project_name
|
||||
+ # to be set
|
||||
return v3_auth.Token(auth_url=auth_url,
|
||||
token=token,
|
||||
project_id=project_id,
|
||||
+ project_name=project_name,
|
||||
reauthenticate=False)
|
||||
else:
|
||||
return v2_auth.Token(auth_url=auth_url,
|
||||
@@ -440,7 +448,7 @@ def set_response_cookie(response, cookie_name, cookie_value):
|
||||
|
||||
def delete_response_cookie(response, cookie_name):
|
||||
""" Common function for deleting a cookie from the response.
|
||||
-
|
||||
+
|
||||
Deletes the cookie of the given cookie_name. Fails silently
|
||||
if cookie name doesn't exist
|
||||
"""
|
||||
@@ -459,6 +467,30 @@ def get_endpoint_region(endpoint):
|
||||
return endpoint.get('region_id') or endpoint.get('region')
|
||||
|
||||
|
||||
+def get_internal_identity_endpoints(service_catalog, region_filter=""):
|
||||
+ """Retrieve Internal Identity endpoints organized by region
|
||||
+ """
|
||||
+ endpoint_dict = {}
|
||||
+ for service in service_catalog:
|
||||
+ service_type = service.get('type')
|
||||
+ if service_type is None or service_type != 'identity':
|
||||
+ continue
|
||||
+ for endpoint in service.get('endpoints', []):
|
||||
+ # only retrieve internal endpoints
|
||||
+ if endpoint['interface'] != 'internal':
|
||||
+ continue
|
||||
+ region = get_endpoint_region(endpoint)
|
||||
+ # If Region Filter is set then only retrieve
|
||||
+ # that specific region
|
||||
+ if region_filter and region != region_filter:
|
||||
+ continue
|
||||
+ if region not in endpoint_dict:
|
||||
+ endpoint_dict[region] = endpoint['url']
|
||||
+ if region_filter:
|
||||
+ break
|
||||
+ return endpoint_dict
|
||||
+
|
||||
+
|
||||
def using_cookie_backed_sessions():
|
||||
engine = getattr(settings, 'SESSION_ENGINE', '')
|
||||
return "signed_cookies" in engine
|
||||
@@ -514,7 +546,6 @@ def get_admin_permissions():
|
||||
return {get_role_permission(role) for role in get_admin_roles()}
|
||||
|
||||
|
||||
-
|
||||
def get_client_ip(request):
|
||||
"""Return client ip address using SECURE_PROXY_ADDR_HEADER variable.
|
||||
If not present then consider using HTTP_X_FORWARDED_FOR from.
|
||||
@@ -535,10 +566,10 @@ def get_client_ip(request):
|
||||
request.META.get('REMOTE_ADDR')
|
||||
)
|
||||
else:
|
||||
- x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
|
||||
- if x_forwarded_for:
|
||||
- return (x_forwarded_for.split(',')[0])
|
||||
- else:
|
||||
+ x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
|
||||
+ if x_forwarded_for:
|
||||
+ return (x_forwarded_for.split(',')[0])
|
||||
+ else:
|
||||
return request.META.get('REMOTE_ADDR')
|
||||
|
||||
|
||||
diff --git a/openstack_auth/views.py b/openstack_auth/views.py
|
||||
index a9d84df..ad339c4 100644
|
||||
--- a/openstack_auth/views.py
|
||||
+++ b/openstack_auth/views.py
|
||||
@@ -48,6 +48,8 @@ except AttributeError:
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
+_DC_MODE = getattr(settings, 'DC_MODE', False)
|
||||
+
|
||||
|
||||
@sensitive_post_parameters()
|
||||
@csrf_protect
|
||||
@@ -130,7 +132,14 @@ def login(request, template_name=None, extra_context=None, **kwargs):
|
||||
' in %s minutes') %
|
||||
expiration_time).replace(':', ' Hours and ')
|
||||
messages.warning(request, msg)
|
||||
-
|
||||
+
|
||||
+ # If we are in Distributed Cloud mode, and System Controller
|
||||
+ # region, then also store the Region Endpoint, as this will
|
||||
+ # be used by Subcloud Region Selector (switch_region()) to go
|
||||
+ # back to the Central Region
|
||||
+ if _DC_MODE:
|
||||
+ request.session['SystemController_endpoint'] = login_region
|
||||
+
|
||||
# WRS: add login user name to handle HORIZON session timeout
|
||||
utils.set_response_cookie(res, 'login_user',
|
||||
request.user.username)
|
||||
@@ -270,6 +279,60 @@ def switch_region(request, region_name,
|
||||
LOG.debug('Switching services region to %s for user "%s".'
|
||||
% (region_name, request.user.username))
|
||||
|
||||
+ # If this is a Distributed Cloud deployment then the Region may
|
||||
+ # correspond to a Subcloud, and we need to invalidate the existing
|
||||
+ # token as it will no longer be valid in this Subcloud
|
||||
+ if _DC_MODE:
|
||||
+ region_auth_url = None
|
||||
+ request.session['region_name'] = region_name
|
||||
+ request.session['login_region'] = region_name
|
||||
+ endpoint_dict = utils.get_internal_identity_endpoints(
|
||||
+ request.user.service_catalog, region_filter=region_name)
|
||||
+
|
||||
+ try:
|
||||
+ region_auth_url = endpoint_dict[region_name]
|
||||
+ except KeyError as e:
|
||||
+ # If we were on a subcloud, then the SystemController Identity
|
||||
+ # endpoint will not be available, therefore retrieve it from
|
||||
+ # the session (cached at login)
|
||||
+ if region_name == utils.DC_SYSTEMCONTROLLER_REGION:
|
||||
+ region_auth_url = request.session.get(
|
||||
+ 'SystemController_endpoint', None)
|
||||
+
|
||||
+ if not region_auth_url:
|
||||
+ msg = _('Cannot switch to subcloud %s, no Identity available '
|
||||
+ 'for subcloud with the provided credentials(%s)' %
|
||||
+ (region_name, request.user.username))
|
||||
+ raise exceptions.KeystoneAuthException(msg)
|
||||
+
|
||||
+ passwordPlugin = plugin.PasswordPlugin()
|
||||
+ unscoped_auth = passwordPlugin.get_plugin(
|
||||
+ auth_url=region_auth_url,
|
||||
+ username=request.user.username,
|
||||
+ password=utils.get_user_password(request.user.username),
|
||||
+ user_domain_name=request.user.user_domain_name)
|
||||
+ if not unscoped_auth:
|
||||
+ msg = _('Cannot switch to subcloud %s authentication backend %s '
|
||||
+ 'with the provided credentials(%s)' %
|
||||
+ (region_name, region_auth_url, request.user.username))
|
||||
+ raise exceptions.KeystoneAuthException(msg)
|
||||
+ unscoped_auth_ref = passwordPlugin.get_access_info(unscoped_auth)
|
||||
+ try:
|
||||
+ request.user = auth.authenticate(
|
||||
+ request=request, auth_url=unscoped_auth.auth_url,
|
||||
+ token=unscoped_auth_ref.auth_token)
|
||||
+ except exceptions.KeystoneAuthException as exc:
|
||||
+ msg = 'Switching to Subcloud failed: %s' % six.text_type(exc)
|
||||
+ res = django_http.HttpResponseRedirect(settings.LOGIN_URL)
|
||||
+ res.set_cookie('logout_reason', msg, max_age=10)
|
||||
+ return res
|
||||
+ auth_user.set_session_from_user(request, request.user)
|
||||
+ request.session['_auth_user_id'] = request.user.id
|
||||
+ message = (
|
||||
+ _('Switch to Subcloud "%(region_name)s"'
|
||||
+ 'successful.') % {'region_name': region_name})
|
||||
+ messages.success(request, message)
|
||||
+
|
||||
redirect_to = request.GET.get(redirect_field_name, '')
|
||||
if not is_safe_url(url=redirect_to, host=request.get_host()):
|
||||
redirect_to = settings.LOGIN_REDIRECT_URL
|
||||
@@ -277,6 +340,19 @@ def switch_region(request, region_name,
|
||||
response = shortcuts.redirect(redirect_to)
|
||||
utils.set_response_cookie(response, 'services_region',
|
||||
request.session['services_region'])
|
||||
+
|
||||
+ # If we were in Distributed Cloud mode then we need to refresh the
|
||||
+ # Project list as well since Identity Service provider has changed
|
||||
+ if _DC_MODE:
|
||||
+ # Refresh the project list stored in the cookie, along with
|
||||
+ # the project switch event
|
||||
+ utils.set_response_cookie(response, 'recent_project',
|
||||
+ request.user.project_id)
|
||||
+ tenants = request.user.authorized_tenants
|
||||
+ tenants = map(lambda x: x.to_dict(), tenants)
|
||||
+ utils.delete_response_cookie(response, 'authorized_tenants')
|
||||
+ utils.set_response_cookie(response, 'authorized_tenants', tenants)
|
||||
+
|
||||
return response
|
||||
|
||||
|
||||
--
|
||||
1.8.3.1
|
||||
|
@ -1,100 +0,0 @@
|
||||
From d7f75aa87d7b476509b21f9c29162763a73a65af Mon Sep 17 00:00:00 2001
|
||||
From: rpm-build <rpm-build>
|
||||
Date: Fri, 29 Jun 2018 19:51:32 -0500
|
||||
Subject: [PATCH 1/1] Horizon Distributed Cloud subcloud switching
|
||||
is broken
|
||||
|
||||
-Fixed switching from RegionOne to SystemController
|
||||
-Fixed tenant list not being displayed on login
|
||||
---
|
||||
openstack_auth/backend.py | 2 +-
|
||||
openstack_auth/forms.py | 15 ++++++++++++++-
|
||||
openstack_auth/views.py | 21 ++++++++++++---------
|
||||
3 files changed, 27 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/openstack_auth/backend.py b/openstack_auth/backend.py
|
||||
index cd15ca8..4fa7129 100644
|
||||
--- a/openstack_auth/backend.py
|
||||
+++ b/openstack_auth/backend.py
|
||||
@@ -162,7 +162,7 @@ class KeystoneBackend(object):
|
||||
# We want to try to use the same region we just logged into
|
||||
# which may or may not be the default depending upon the order
|
||||
# keystone uses
|
||||
- region_name = None
|
||||
+ region_name = kwargs.get('force_region', None)
|
||||
id_endpoints = scoped_auth_ref.service_catalog.\
|
||||
get_endpoints(service_type='identity')
|
||||
for id_endpoint in [cat for cat in id_endpoints['identity']]:
|
||||
diff --git a/openstack_auth/forms.py b/openstack_auth/forms.py
|
||||
index 4834ab2..49b8d8b 100644
|
||||
--- a/openstack_auth/forms.py
|
||||
+++ b/openstack_auth/forms.py
|
||||
@@ -139,11 +139,24 @@ class Login(django_auth_forms.AuthenticationForm):
|
||||
if lockedout:
|
||||
raise forms.ValidationError("user currently locked out.")
|
||||
|
||||
+ # when logging in in DC mode we will force the region to
|
||||
+ # be system controller since authenticate can't map our
|
||||
+ # hostname to an endpoint/regionname. Changing the hostname
|
||||
+ # in settings to ip will work but will break region switching
|
||||
+ # from RegionOne to SystemController since SystemController
|
||||
+ # region maps back to RegionOne (same keystone)
|
||||
+ force_region = None
|
||||
+ if getattr(settings, 'DC_MODE', False) and \
|
||||
+ region == getattr(settings, 'OPENSTACK_KEYSTONE_URL', None):
|
||||
+ force_region = utils.DC_SYSTEMCONTROLLER_REGION
|
||||
+
|
||||
self.user_cache = authenticate(request=self.request,
|
||||
username=username,
|
||||
password=password,
|
||||
user_domain_name=domain,
|
||||
- auth_url=region)
|
||||
+ auth_url=region,
|
||||
+ force_region=force_region)
|
||||
+
|
||||
msg = 'Login successful for user "%(username)s", remote address '\
|
||||
'%(remote_ip)s.' % {
|
||||
'username': username,
|
||||
diff --git a/openstack_auth/views.py b/openstack_auth/views.py
|
||||
index a680abf..0b1351d 100644
|
||||
--- a/openstack_auth/views.py
|
||||
+++ b/openstack_auth/views.py
|
||||
@@ -289,15 +289,17 @@ def switch_region(request, region_name,
|
||||
endpoint_dict = utils.get_internal_identity_endpoints(
|
||||
request.user.service_catalog, region_filter=region_name)
|
||||
|
||||
- try:
|
||||
+ # If we were on a subcloud, then the SystemController Identity
|
||||
+ # endpoint will not be functional, therefore retrieve the
|
||||
+ # RegionOne endpoint from the session (cached at login)
|
||||
+ force_region = None
|
||||
+ if region_name == utils.DC_SYSTEMCONTROLLER_REGION:
|
||||
+ force_region = utils.DC_SYSTEMCONTROLLER_REGION
|
||||
+ region_auth_url = request.session.get(
|
||||
+ 'SystemController_endpoint', None)
|
||||
+ else:
|
||||
region_auth_url = endpoint_dict[region_name]
|
||||
- except KeyError as e:
|
||||
- # If we were on a subcloud, then the SystemController Identity
|
||||
- # endpoint will not be available, therefore retrieve it from
|
||||
- # the session (cached at login)
|
||||
- if region_name == utils.DC_SYSTEMCONTROLLER_REGION:
|
||||
- region_auth_url = request.session.get(
|
||||
- 'SystemController_endpoint', None)
|
||||
+
|
||||
|
||||
if not region_auth_url:
|
||||
msg = _('Cannot switch to subcloud %s, no Identity available '
|
||||
@@ -320,7 +322,8 @@ def switch_region(request, region_name,
|
||||
try:
|
||||
request.user = auth.authenticate(
|
||||
request=request, auth_url=unscoped_auth.auth_url,
|
||||
- token=unscoped_auth_ref.auth_token)
|
||||
+ token=unscoped_auth_ref.auth_token,
|
||||
+ force_region=force_region)
|
||||
except exceptions.KeystoneAuthException as exc:
|
||||
msg = 'Switching to Subcloud failed: %s' % six.text_type(exc)
|
||||
res = django_http.HttpResponseRedirect(settings.LOGIN_URL)
|
||||
--
|
||||
1.8.3.1
|
||||
|
@ -1 +0,0 @@
|
||||
mirror:Source/python-django-openstack-auth-3.6.1-1.el7.src.rpm
|
@ -1,5 +1,5 @@
|
||||
TAR_NAME=horizon
|
||||
SRC_DIR="$CGCS_BASE/git/horizon"
|
||||
COPY_LIST="$FILES_BASE/*"
|
||||
TIS_BASE_SRCREV=79a529593f84e4ea0762dc4a72ca167a1c5d0c3d
|
||||
TIS_PATCH_VER=GITREVCOUNT
|
||||
TIS_BASE_SRCREV=a8df389822aaeaa29aded7e8c6614b51748ab914
|
||||
TIS_PATCH_VER=1
|
||||
|
@ -1,70 +0,0 @@
|
||||
diff --git a/openstack_dashboard/api/nova.py b/openstack_dashboard/api/nova.py
|
||||
index 39a7684..e6798e9 100755
|
||||
--- a/openstack_dashboard/api/nova.py
|
||||
+++ b/openstack_dashboard/api/nova.py
|
||||
@@ -38,10 +38,6 @@ from novaclient.v2 import instance_action as nova_instance_action
|
||||
from novaclient.v2 import list_extensions as nova_list_extensions
|
||||
from novaclient.v2 import servers as nova_servers
|
||||
|
||||
-# Todo (ediardo): move all wrs* and func wrappers into stx-gui
|
||||
-from novaclient.v2 import wrs_pci
|
||||
-from novaclient.v2 import wrs_providernets
|
||||
-
|
||||
from horizon import exceptions
|
||||
from horizon import exceptions as horizon_exceptions
|
||||
from horizon.utils import functions as utils
|
||||
@@ -1123,54 +1119,6 @@ def requires_keypair():
|
||||
return features.get('requires_keypair', False)
|
||||
|
||||
|
||||
-# WRS: Nova extension for provider network.
|
||||
-@profiler.trace
|
||||
-def provider_network_get(request, providernet_id):
|
||||
- return wrs_providernets.ProviderNetsManager(novaclient(request)).get(
|
||||
- providernet_id)
|
||||
-
|
||||
-
|
||||
-# WRS: Nova extension for device usage
|
||||
-@profiler.trace
|
||||
-class DeviceUsage(base.APIResourceWrapper):
|
||||
- """Wrapper for Inventory Device Usage"""
|
||||
- _attrs = ['device_name', 'device_id', 'vendor_id', 'class_id',
|
||||
- 'pci_vfs_configured', 'pci_vfs_used',
|
||||
- 'pci_pfs_configured', 'pci_pfs_used']
|
||||
-
|
||||
-
|
||||
-@profiler.trace
|
||||
-def get_device_usage_list(request):
|
||||
- usages = wrs_pci.PciDevicesManager(novaclient(request)).list()
|
||||
- return [DeviceUsage(n) for n in usages]
|
||||
-
|
||||
-
|
||||
-@profiler.trace
|
||||
-def get_device_usage(request, device_id):
|
||||
- if device_id is None:
|
||||
- raise nova_exceptions.ResourceNotFound
|
||||
-
|
||||
- usage = wrs_pci.PciDevicesManager(novaclient(request)).list(
|
||||
- device=device_id)
|
||||
- return DeviceUsage(usage[0])
|
||||
-
|
||||
-
|
||||
-# WRS: Nova extension for detail device usage
|
||||
-@profiler.trace
|
||||
-class DetailUsage(base.APIResourceWrapper):
|
||||
- """Wrapper for Inventory Device Usage"""
|
||||
- _attrs = ['host',
|
||||
- 'pci_vfs_configured', 'pci_vfs_used',
|
||||
- 'pci_pfs_configured', 'pci_pfs_used']
|
||||
-
|
||||
-
|
||||
-@profiler.trace
|
||||
-def get_detail_usage(request, device_id):
|
||||
- usages = wrs_pci.PciDevicesManager(novaclient(request)).get(
|
||||
- device_id)
|
||||
- return [DetailUsage(n) for n in usages]
|
||||
-
|
||||
-
|
||||
def can_set_quotas():
|
||||
features = getattr(settings, 'OPENSTACK_HYPERVISOR_FEATURES', {})
|
||||
return features.get('enable_quotas', True)
|
@ -4,7 +4,7 @@ Name: python-django-horizon
|
||||
# Liberty semver reset
|
||||
# https://review.openstack.org/#/q/I6a35fa0dda798fad93b804d00a46af80f08d475c,n,z
|
||||
Epoch: 1
|
||||
Version: 12.0.0
|
||||
Version: 14.0.0
|
||||
Release: 2%{?_tis_dist}.%{tis_patch_ver}
|
||||
Summary: Django application for talking to Openstack
|
||||
|
||||
@ -30,8 +30,6 @@ Source12: horizon-region-exclusions.csv
|
||||
Source13: guni_config.py
|
||||
Source14: horizon-assets-compress
|
||||
|
||||
Patch1: 0001-Remove-WRS-imports-from-novaclient.patch
|
||||
|
||||
#
|
||||
# BuildArch needs to be located below patches in the spec file. Don't ask!
|
||||
#
|
||||
@ -46,7 +44,7 @@ BuildRequires: cgts-client
|
||||
Requires: cgts-client
|
||||
|
||||
Requires: pytz
|
||||
Requires: python-six >= 1.9.0
|
||||
Requires: python-six >= 1.10.0
|
||||
Requires: python-pbr
|
||||
|
||||
BuildRequires: python2-devel
|
||||
@ -55,24 +53,31 @@ BuildRequires: python2-pip
|
||||
BuildRequires: python2-wheel
|
||||
BuildRequires: python-pbr >= 2.0.0
|
||||
BuildRequires: git
|
||||
BuildRequires: python-six >= 1.9.0
|
||||
BuildRequires: python-six >= 1.10.0
|
||||
BuildRequires: gettext
|
||||
|
||||
# for checks:
|
||||
%if 0%{?rhel} == 0
|
||||
BuildRequires: python-django-nose >= 1.2
|
||||
BuildRequires: python-coverage
|
||||
BuildRequires: python-django-nose
|
||||
BuildRequires: python-mox3
|
||||
BuildRequires: python-nose-exclude
|
||||
BuildRequires: python-nose
|
||||
BuildRequires: python-selenium
|
||||
%endif
|
||||
BuildRequires: python-osprofiler
|
||||
BuildRequires: python-netaddr
|
||||
BuildRequires: python-anyjson
|
||||
BuildRequires: python-iso8601
|
||||
BuildRequires: python-pep8
|
||||
|
||||
# additional provides to be consistent with other django packages
|
||||
Provides: django-horizon = %{epoch}:%{version}-%{release}
|
||||
Obsoletes: python-django-openstack-auth < 4.0.0-1
|
||||
Obsoletes: python2-django-openstack-auth < 4.0.0-1
|
||||
# (TODO) remove following provides once the requirements have been fixed
|
||||
# in all dashboard plugins
|
||||
Provides: python-django-openstack-auth = %{epoch}:%{version}-%{release}
|
||||
Provides: python2-django-openstack-auth = %{epoch}:%{version}-%{release}
|
||||
|
||||
%description
|
||||
Horizon is a Django application for providing Openstack UI components.
|
||||
@ -89,66 +94,68 @@ Group: Applications/System
|
||||
Requires: httpd
|
||||
Requires: mod_wsgi
|
||||
Requires: %{name} = %{epoch}:%{version}-%{release}
|
||||
Requires: python-django-openstack-auth >= 3.5.0
|
||||
Requires: python-django-compressor >= 2.0
|
||||
Requires: python2-django-compressor >= 2.0
|
||||
Requires: python-django-appconf
|
||||
Requires: python-django-babel
|
||||
Requires: python-lesscpy
|
||||
|
||||
Requires: python-iso8601
|
||||
Requires: python-glanceclient
|
||||
Requires: python-keystoneclient >= 1:3.8.0
|
||||
Requires: python-novaclient
|
||||
Requires: python-neutronclient
|
||||
Requires: python-cinderclient
|
||||
Requires: python-swiftclient >= 3.2.0
|
||||
Requires: python-heatclient >= 1.6.1
|
||||
Requires: python-netaddr
|
||||
Requires: python-osprofiler >= 1.4.0
|
||||
Requires: openstack-dashboard-theme >= %{epoch}:%{version}-%{release}
|
||||
|
||||
Requires: python2-iso8601
|
||||
Requires: python2-glanceclient >= 1:2.8.0
|
||||
Requires: python2-keystoneclient >= 1:3.15.0
|
||||
Requires: python2-keystoneauth1 >= 3.4.0
|
||||
Requires: python2-novaclient >= 1:9.1.0
|
||||
Requires: python2-neutronclient >= 6.7.0
|
||||
Requires: python2-cinderclient >= 3.3.0
|
||||
Requires: python2-swiftclient >= 3.2.0
|
||||
Requires: python2-netaddr
|
||||
Requires: python2-osprofiler >= 2.3.0
|
||||
Requires: python-pymongo >= 3.0.2
|
||||
Requires: python-django-pyscss >= 2.0.2
|
||||
Requires: python2-django-pyscss >= 2.0.2
|
||||
Requires: python-semantic_version
|
||||
Requires: python-XStatic
|
||||
Requires: python2-XStatic
|
||||
Requires: python-XStatic-jQuery
|
||||
Requires: python-XStatic-Angular >= 1:1.3.7
|
||||
Requires: python-XStatic-Angular-Bootstrap
|
||||
Requires: python-XStatic-Angular-Schema-Form
|
||||
Requires: python-XStatic-D3 >= 3.5.17.0
|
||||
Requires: python-XStatic-Font-Awesome >= 4.7.0
|
||||
Requires: python2-XStatic-Angular >= 1:1.5.8.0
|
||||
Requires: python2-XStatic-Angular-Bootstrap
|
||||
Requires: python2-XStatic-Angular-Schema-Form
|
||||
Requires: python2-XStatic-D3
|
||||
Requires: python2-XStatic-Font-Awesome
|
||||
Requires: python-XStatic-Hogan
|
||||
Requires: python-XStatic-JQuery-Migrate
|
||||
Requires: python-XStatic-JQuery-TableSorter
|
||||
Requires: python-XStatic-JQuery-quicksearch
|
||||
Requires: python-XStatic-JSEncrypt >= 2.3.1.1
|
||||
Requires: python-XStatic-Jasmine >= 2.4.1.1
|
||||
Requires: python2-XStatic-JSEncrypt
|
||||
Requires: python2-XStatic-Jasmine
|
||||
Requires: python-XStatic-Rickshaw
|
||||
Requires: python-XStatic-Spin
|
||||
Requires: python-XStatic-jquery-ui
|
||||
Requires: python-XStatic-Bootstrap-Datepicker
|
||||
Requires: python-XStatic-Bootstrap-SCSS >= 3.3.7.1
|
||||
Requires: python-XStatic-termjs >= 0.0.7.0
|
||||
Requires: python-XStatic-smart-table
|
||||
Requires: python2-XStatic-Bootstrap-SCSS >= 3.3.7.1
|
||||
Requires: python2-XStatic-termjs
|
||||
Requires: python2-XStatic-smart-table
|
||||
Requires: python-XStatic-Angular-lrdragndrop
|
||||
Requires: python-XStatic-Angular-Gettext
|
||||
Requires: python-XStatic-Angular-FileUpload
|
||||
Requires: python2-XStatic-Angular-Gettext
|
||||
Requires: python2-XStatic-Angular-FileUpload
|
||||
Requires: python-XStatic-Magic-Search
|
||||
Requires: python-XStatic-bootswatch
|
||||
Requires: python-XStatic-roboto-fontface >= 0.5.0.0
|
||||
Requires: python-XStatic-mdi
|
||||
Requires: python-XStatic-objectpath
|
||||
Requires: python-XStatic-tv4
|
||||
Requires: python2-XStatic-bootswatch
|
||||
Requires: python2-XStatic-roboto-fontface >= 0.5.0.0
|
||||
Requires: python2-XStatic-mdi
|
||||
Requires: python2-XStatic-objectpath
|
||||
Requires: python2-XStatic-tv4
|
||||
Requires: python2-django-debreach
|
||||
|
||||
Requires: python-scss >= 1.3.4
|
||||
Requires: python2-scss >= 1.3.4
|
||||
Requires: fontawesome-fonts-web >= 4.1.0
|
||||
|
||||
Requires: python-oslo-concurrency >= 3.8.0
|
||||
Requires: python-oslo-config >= 2:4.0.0
|
||||
Requires: python-oslo-i18n >= 2.1.0
|
||||
Requires: python-oslo-serialization >= 1.10.0
|
||||
Requires: python-oslo-utils >= 3.20.0
|
||||
Requires: python-oslo-policy >= 1.23.0
|
||||
Requires: python-babel
|
||||
Requires: python-futurist
|
||||
Requires: python2-oslo-concurrency >= 3.26.0
|
||||
Requires: python2-oslo-config >= 2:5.2.0
|
||||
Requires: python2-oslo-i18n >= 3.15.3
|
||||
Requires: python2-oslo-serialization >= 2.18.0
|
||||
Requires: python2-oslo-utils >= 3.33.0
|
||||
Requires: python2-oslo-policy >= 1.30.0
|
||||
Requires: python2-babel
|
||||
Requires: python2-futurist
|
||||
Requires: python-pint
|
||||
|
||||
Requires: openssl
|
||||
@ -156,51 +163,50 @@ Requires: logrotate
|
||||
|
||||
Requires: PyYAML >= 3.10
|
||||
|
||||
BuildRequires: python-django-openstack-auth >= 3.5.0
|
||||
BuildRequires: python-django-compressor >= 2.0
|
||||
BuildRequires: python2-django-compressor >= 2.0
|
||||
BuildRequires: python-django-appconf
|
||||
BuildRequires: python-lesscpy
|
||||
BuildRequires: python-semantic_version
|
||||
BuildRequires: python-django-pyscss >= 2.0.2
|
||||
BuildRequires: python-XStatic
|
||||
BuildRequires: python2-django-pyscss >= 2.0.2
|
||||
BuildRequires: python2-XStatic
|
||||
BuildRequires: python-XStatic-jQuery
|
||||
BuildRequires: python-XStatic-Angular >= 1:1.3.7
|
||||
BuildRequires: python-XStatic-Angular-Bootstrap
|
||||
BuildRequires: python-XStatic-Angular-Schema-Form
|
||||
BuildRequires: python-XStatic-D3
|
||||
BuildRequires: python-XStatic-Font-Awesome
|
||||
BuildRequires: python2-XStatic-Angular >= 1:1.5.8.0
|
||||
BuildRequires: python2-XStatic-Angular-Bootstrap
|
||||
BuildRequires: python2-XStatic-Angular-Schema-Form
|
||||
BuildRequires: python2-XStatic-D3
|
||||
BuildRequires: python2-XStatic-Font-Awesome
|
||||
BuildRequires: python-XStatic-Hogan
|
||||
BuildRequires: python-XStatic-JQuery-Migrate
|
||||
BuildRequires: python-XStatic-JQuery-TableSorter
|
||||
BuildRequires: python-XStatic-JQuery-quicksearch
|
||||
BuildRequires: python-XStatic-JSEncrypt >= 2.3.1.1
|
||||
BuildRequires: python-XStatic-Jasmine
|
||||
BuildRequires: python2-XStatic-JSEncrypt
|
||||
BuildRequires: python2-XStatic-Jasmine
|
||||
BuildRequires: python-XStatic-Rickshaw
|
||||
BuildRequires: python-XStatic-Spin
|
||||
BuildRequires: python-XStatic-jquery-ui
|
||||
BuildRequires: python-XStatic-Bootstrap-Datepicker
|
||||
BuildRequires: python-XStatic-Bootstrap-SCSS >= 3.3.7.1
|
||||
BuildRequires: python-XStatic-termjs
|
||||
BuildRequires: python-XStatic-smart-table
|
||||
BuildRequires: python2-XStatic-Bootstrap-SCSS
|
||||
BuildRequires: python2-XStatic-termjs
|
||||
BuildRequires: python2-XStatic-smart-table
|
||||
BuildRequires: python-XStatic-Angular-lrdragndrop
|
||||
BuildRequires: python-XStatic-Angular-FileUpload
|
||||
BuildRequires: python2-XStatic-Angular-FileUpload
|
||||
BuildRequires: python-XStatic-Magic-Search
|
||||
BuildRequires: python-XStatic-Angular-Gettext
|
||||
BuildRequires: python-XStatic-bootswatch
|
||||
BuildRequires: python-XStatic-roboto-fontface
|
||||
BuildRequires: python-XStatic-mdi
|
||||
BuildRequires: python-XStatic-objectpath
|
||||
BuildRequires: python-XStatic-tv4
|
||||
BuildRequires: python2-XStatic-Angular-Gettext
|
||||
BuildRequires: python2-XStatic-bootswatch
|
||||
BuildRequires: python2-XStatic-roboto-fontface
|
||||
BuildRequires: python2-XStatic-mdi
|
||||
BuildRequires: python2-XStatic-objectpath
|
||||
BuildRequires: python2-XStatic-tv4
|
||||
# bootstrap-scss requires at least python-scss >= 1.2.1
|
||||
BuildRequires: python-scss >= 1.3.4
|
||||
BuildRequires: python2-scss >= 1.3.4
|
||||
BuildRequires: fontawesome-fonts-web >= 4.1.0
|
||||
BuildRequires: python-oslo-concurrency
|
||||
BuildRequires: python-oslo-config
|
||||
BuildRequires: python-oslo-i18n
|
||||
BuildRequires: python-oslo-serialization
|
||||
BuildRequires: python-oslo-utils
|
||||
BuildRequires: python-oslo-policy
|
||||
BuildRequires: python-babel
|
||||
BuildRequires: python2-oslo-concurrency
|
||||
BuildRequires: python2-oslo-config
|
||||
BuildRequires: python2-oslo-i18n
|
||||
BuildRequires: python2-oslo-serialization
|
||||
BuildRequires: python2-oslo-utils
|
||||
BuildRequires: python2-oslo-policy
|
||||
BuildRequires: python2-babel
|
||||
BuildRequires: python-pint
|
||||
|
||||
BuildRequires: pytz
|
||||
@ -226,14 +232,13 @@ Requires: %{name} = %{epoch}:%{version}-%{release}
|
||||
BuildRequires: python-sphinx >= 1.1.3
|
||||
|
||||
# Doc building basically means we have to mirror Requires:
|
||||
BuildRequires: python-openstackdocstheme
|
||||
BuildRequires: python-glanceclient
|
||||
BuildRequires: python-keystoneclient
|
||||
BuildRequires: python-novaclient >= 1:6.0.0
|
||||
BuildRequires: python-neutronclient
|
||||
BuildRequires: python-cinderclient
|
||||
BuildRequires: python-swiftclient
|
||||
BuildRequires: python-heatclient
|
||||
BuildRequires: python2-openstackdocstheme
|
||||
BuildRequires: python2-glanceclient
|
||||
BuildRequires: python2-keystoneclient
|
||||
BuildRequires: python2-novaclient >= 1:9.1.0
|
||||
BuildRequires: python2-neutronclient
|
||||
BuildRequires: python2-cinderclient
|
||||
BuildRequires: python2-swiftclient
|
||||
|
||||
%description doc
|
||||
Documentation for the Django Horizon application for talking with Openstack
|
||||
@ -249,7 +254,6 @@ Customization module for OpenStack Dashboard to provide a branded logo.
|
||||
|
||||
%prep
|
||||
%autosetup -n horizon-%{upstream_version} -S git
|
||||
# autosetup automatically applies the patches
|
||||
|
||||
# STX remove troublesome files introduced by tox
|
||||
rm -f openstack_dashboard/test/.secret_key_store
|
||||
@ -368,6 +372,9 @@ mv %{buildroot}%{_datadir}/openstack-dashboard/openstack_dashboard/local/local_s
|
||||
#ln -s ../../../../../%{_sysconfdir}/openstack-dashboard/local_settings %{buildroot}%{_datadir}/openstack-dashboard/openstack_dashboard/local/local_settings.py
|
||||
|
||||
mv %{buildroot}%{_datadir}/openstack-dashboard/openstack_dashboard/conf/*.json %{buildroot}%{_sysconfdir}/openstack-dashboard
|
||||
mv %{buildroot}%{_datadir}/openstack-dashboard/openstack_dashboard/conf/cinder_policy.d %{buildroot}%{_sysconfdir}/openstack-dashboard
|
||||
mv %{buildroot}%{_datadir}/openstack-dashboard/openstack_dashboard/conf/nova_policy.d %{buildroot}%{_sysconfdir}/openstack-dashboard
|
||||
|
||||
|
||||
%find_lang django --all-name
|
||||
|
||||
@ -387,15 +394,14 @@ mkdir -p %{buildroot}%{_sharedstatedir}/openstack-dashboard
|
||||
# create /var/log/horizon and own it
|
||||
mkdir -p %{buildroot}%{_var}/log/horizon
|
||||
|
||||
# place logrotate config
|
||||
# place logrotate config:
|
||||
mkdir -p %{buildroot}%{_sysconfdir}/logrotate.d
|
||||
cp -a %{SOURCE5} %{buildroot}%{_sysconfdir}/logrotate.d/openstack-dashboard
|
||||
|
||||
%check
|
||||
# don't run tests on rhel
|
||||
%if 0%{?rhel} == 0
|
||||
# since rawhide has django-1.7 now, tests fail
|
||||
#./run_tests.sh -N -P
|
||||
%{__python2} manage.py test horizon --settings=horizon.test.settings
|
||||
%endif
|
||||
|
||||
%post -n openstack-dashboard
|
||||
@ -430,6 +436,7 @@ systemctl daemon-reload >/dev/null 2>&1 || :
|
||||
%{python_sitelib}/horizon/workflows
|
||||
%{python_sitelib}/horizon/karma.conf.js
|
||||
%{python_sitelib}/horizon/middleware
|
||||
%{python_sitelib}/openstack_auth
|
||||
%{python_sitelib}/*.egg-info
|
||||
|
||||
%files -n openstack-dashboard -f dashboard.lang
|
||||
@ -445,7 +452,6 @@ systemctl daemon-reload >/dev/null 2>&1 || :
|
||||
%{_datadir}/openstack-dashboard/openstack_dashboard/dashboards/identity
|
||||
%{_datadir}/openstack-dashboard/openstack_dashboard/dashboards/project
|
||||
%{_datadir}/openstack-dashboard/openstack_dashboard/dashboards/settings
|
||||
# STX
|
||||
%{_datadir}/openstack-dashboard/openstack_dashboard/dashboards/__init__.py*
|
||||
%{_datadir}/openstack-dashboard/openstack_dashboard/django_pyscss_fix
|
||||
%{_datadir}/openstack-dashboard/openstack_dashboard/enabled
|
||||
@ -469,6 +475,7 @@ systemctl daemon-reload >/dev/null 2>&1 || :
|
||||
%{_datadir}/openstack-dashboard/openstack_dashboard/.eslintrc
|
||||
|
||||
%dir %attr(0750, root, apache) %{_sysconfdir}/openstack-dashboard
|
||||
%dir %attr(0750, root, apache) %{_sysconfdir}/openstack-dashboard/cinder_policy.d/
|
||||
%dir %attr(0750, apache, apache) %{_sharedstatedir}/openstack-dashboard
|
||||
%dir %attr(0750, apache, apache) %{_var}/log/horizon
|
||||
%config(noreplace) %{_sysconfdir}/httpd/conf.d/openstack-dashboard.conf
|
||||
@ -478,8 +485,9 @@ systemctl daemon-reload >/dev/null 2>&1 || :
|
||||
%config(noreplace) %attr(0640, root, apache) %{_sysconfdir}/openstack-dashboard/nova_policy.json
|
||||
%config(noreplace) %attr(0640, root, apache) %{_sysconfdir}/openstack-dashboard/glance_policy.json
|
||||
%config(noreplace) %attr(0640, root, apache) %{_sysconfdir}/openstack-dashboard/neutron_policy.json
|
||||
%config(noreplace) %attr(0640, root, apache) %{_sysconfdir}/openstack-dashboard/heat_policy.json
|
||||
%config(noreplace) %{_sysconfdir}/logrotate.d/openstack-dashboard
|
||||
%config(noreplace) %attr(0640, root, apache) %{_sysconfdir}/openstack-dashboard/cinder_policy.d/consistencygroup.yaml
|
||||
%config(noreplace) %attr(0640, root, apache) %{_sysconfdir}/openstack-dashboard/nova_policy.d/api-extensions.yaml
|
||||
%config(noreplace) %attr(0644, root, root) %{_sysconfdir}/logrotate.d/openstack-dashboard
|
||||
%attr(755,root,root) %dir %{_unitdir}/httpd.service.d
|
||||
%config(noreplace) %{_unitdir}/httpd.service.d/openstack-dashboard.conf
|
||||
|
||||
@ -515,19 +523,19 @@ Contains python wheels for %{name}
|
||||
/wheels/*
|
||||
|
||||
%changelog
|
||||
* Mon Oct 04 2017 Radomir Dopieralski <rdopiera@redhat.com> 1:12.0.0-2
|
||||
- Require at least 3.3.7.1 version of XStatic-bootstrap-SCSS package
|
||||
* Mon Dec 03 2018 RDO <dev@lists.rdoproject.org> 1:14.0.2-1
|
||||
- Update to 14.0.2
|
||||
|
||||
* Wed Aug 30 2017 rdo-trunk <javier.pena@redhat.com> 1:12.0.0-1
|
||||
- Update to 12.0.0
|
||||
* Mon Oct 22 2018 RDO <dev@lists.rdoproject.org> 1:14.0.1-1
|
||||
- Update to 14.0.1
|
||||
|
||||
* Mon Aug 28 2017 rdo-trunk <javier.pena@redhat.com> 1:12.0.0-0.3.0rc3
|
||||
- Update to 12.0.0.0rc3
|
||||
* Thu Aug 30 2018 RDO <dev@lists.rdoproject.org> 1:14.0.0-1
|
||||
- Update to 14.0.0
|
||||
|
||||
* Fri Aug 25 2017 Alfredo Moralejo <amoralej@redhat.com> 1:12.0.0-0.2.0rc2
|
||||
- Update to 12.0.0.0rc2
|
||||
* Wed Aug 22 2018 RDO <dev@lists.rdoproject.org> 1:14.0.0-0.2.0rc1
|
||||
- Update to 14.0.0.0rc2
|
||||
|
||||
* Mon Aug 21 2017 Alfredo Moralejo <amoralej@redhat.com> 1:12.0.0-0.1.0rc1
|
||||
- Update to 12.0.0.0rc1
|
||||
* Mon Aug 20 2018 RDO <dev@lists.rdoproject.org> 1:14.0.0-0.1.0rc1
|
||||
- Update to 14.0.0.0rc1
|
||||
|
||||
|
||||
|
@ -1 +0,0 @@
|
||||
TIS_PATCH_VER=2
|
@ -1,2 +0,0 @@
|
||||
update-package-versioning-for-TIS-format.patch
|
||||
spec-add-fair-lock.patch
|
@ -1,15 +0,0 @@
|
||||
diff --git a/SPECS/python-oslo-concurrency.spec b/SPECS/python-oslo-concurrency.spec
|
||||
index a4a3883..cc9e799 100644
|
||||
--- a/SPECS/python-oslo-concurrency.spec
|
||||
+++ b/SPECS/python-oslo-concurrency.spec
|
||||
@@ -16,6 +16,10 @@ Summary: OpenStack Oslo concurrency library
|
||||
License: ASL 2.0
|
||||
URL: https://launchpad.net/oslo
|
||||
Source0: https://tarballs.openstack.org/%{pypi_name}/%{pypi_name}-%{upstream_version}.tar.gz
|
||||
+
|
||||
+# WRS
|
||||
+Patch0001: add-fair-lock.patch
|
||||
+
|
||||
BuildArch: noarch
|
||||
|
||||
%description
|
@ -1,13 +0,0 @@
|
||||
diff --git a/SPECS/python-oslo-concurrency.spec b/SPECS/python-oslo-concurrency.spec
|
||||
index dee2b71..a4a3883 100644
|
||||
--- a/SPECS/python-oslo-concurrency.spec
|
||||
+++ b/SPECS/python-oslo-concurrency.spec
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
Name: python-oslo-concurrency
|
||||
Version: 3.21.1
|
||||
-Release: 1%{?dist}
|
||||
+Release: 1.el7%{?_tis_dist}.%{tis_patch_ver}
|
||||
Summary: OpenStack Oslo concurrency library
|
||||
|
||||
License: ASL 2.0
|
@ -1,106 +0,0 @@
|
||||
diff --git a/oslo_concurrency/lockutils.py b/oslo_concurrency/lockutils.py
|
||||
index ea67571..4519463 100644
|
||||
--- a/oslo_concurrency/lockutils.py
|
||||
+++ b/oslo_concurrency/lockutils.py
|
||||
@@ -87,6 +87,43 @@ ReaderWriterLock = fasteners.ReaderWriterLock
|
||||
"""
|
||||
|
||||
|
||||
+class FairLocks(object):
|
||||
+ """A garbage collected container of fair locks.
|
||||
+
|
||||
+ This collection internally uses a weak value dictionary so that when a
|
||||
+ lock is no longer in use (by any threads) it will automatically be
|
||||
+ removed from this container by the garbage collector.
|
||||
+ """
|
||||
+
|
||||
+ def __init__(self):
|
||||
+ self._locks = weakref.WeakValueDictionary()
|
||||
+ self._lock = threading.Lock()
|
||||
+
|
||||
+ def get(self, name):
|
||||
+ """Gets (or creates) a lock with a given name.
|
||||
+
|
||||
+ :param name: The lock name to get/create (used to associate
|
||||
+ previously created names with the same lock).
|
||||
+
|
||||
+ Returns an newly constructed lock (or an existing one if it was
|
||||
+ already created for the given name).
|
||||
+ """
|
||||
+ with self._lock:
|
||||
+ try:
|
||||
+ return self._locks[name]
|
||||
+ except KeyError:
|
||||
+ rwlock = ReaderWriterLock()
|
||||
+ self._locks[name] = rwlock
|
||||
+ return rwlock
|
||||
+
|
||||
+
|
||||
+fair_locks = FairLocks()
|
||||
+
|
||||
+
|
||||
+def internal_fair_lock(name):
|
||||
+ return fair_locks.get(name)
|
||||
+
|
||||
+
|
||||
class Semaphores(object):
|
||||
"""A garbage collected container of semaphores.
|
||||
|
||||
@@ -170,7 +207,7 @@ def internal_lock(name, semaphores=None):
|
||||
|
||||
@contextlib.contextmanager
|
||||
def lock(name, lock_file_prefix=None, external=False, lock_path=None,
|
||||
- do_log=True, semaphores=None, delay=0.01):
|
||||
+ do_log=True, semaphores=None, delay=0.01, fair=False):
|
||||
"""Context based lock
|
||||
|
||||
This function yields a `threading.Semaphore` instance (if we don't use
|
||||
@@ -200,16 +237,22 @@ def lock(name, lock_file_prefix=None, external=False, lock_path=None,
|
||||
|
||||
:param delay: Delay between acquisition attempts (in seconds).
|
||||
|
||||
+ :param fair: Whether or not we want a "fair" lock where contending lockers
|
||||
+ will get the lock in the order in which they tried to acquire it.
|
||||
+
|
||||
.. versionchanged:: 0.2
|
||||
Added *do_log* optional parameter.
|
||||
|
||||
.. versionchanged:: 0.3
|
||||
Added *delay* and *semaphores* optional parameters.
|
||||
"""
|
||||
- int_lock = internal_lock(name, semaphores=semaphores)
|
||||
+ if fair:
|
||||
+ int_lock = internal_fair_lock(name).write_lock()
|
||||
+ else:
|
||||
+ int_lock = internal_lock(name, semaphores=semaphores)
|
||||
with int_lock:
|
||||
if do_log:
|
||||
- LOG.debug('Acquired semaphore "%(lock)s"', {'lock': name})
|
||||
+ LOG.debug('Acquired lock "%(lock)s"', {'lock': name})
|
||||
try:
|
||||
if external and not CONF.oslo_concurrency.disable_process_locking:
|
||||
ext_lock = external_lock(name, lock_file_prefix, lock_path)
|
||||
@@ -222,11 +265,11 @@ def lock(name, lock_file_prefix=None, external=False, lock_path=None,
|
||||
yield int_lock
|
||||
finally:
|
||||
if do_log:
|
||||
- LOG.debug('Releasing semaphore "%(lock)s"', {'lock': name})
|
||||
+ LOG.debug('Releasing lock "%(lock)s"', {'lock': name})
|
||||
|
||||
|
||||
def synchronized(name, lock_file_prefix=None, external=False, lock_path=None,
|
||||
- semaphores=None, delay=0.01):
|
||||
+ semaphores=None, delay=0.01, fair=False):
|
||||
"""Synchronization decorator.
|
||||
|
||||
Decorating a method like so::
|
||||
@@ -261,7 +304,8 @@ def synchronized(name, lock_file_prefix=None, external=False, lock_path=None,
|
||||
t2 = None
|
||||
try:
|
||||
with lock(name, lock_file_prefix, external, lock_path,
|
||||
- do_log=False, semaphores=semaphores, delay=delay):
|
||||
+ do_log=False, semaphores=semaphores, delay=delay,
|
||||
+ fair=fair):
|
||||
t2 = timeutils.now()
|
||||
LOG.debug('Lock "%(name)s" acquired by "%(function)s" :: '
|
||||
'waited %(wait_secs)0.3fs',
|
@ -1 +0,0 @@
|
||||
mirror:Source/python-oslo-concurrency-3.21.1-1.el7.src.rpm
|
Loading…
x
Reference in New Issue
Block a user