summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThiago da Silva <thiago@redhat.com>2014-04-22 14:15:02 -0400
committerPrashanth Pai <ppai@redhat.com>2016-01-06 07:53:12 -0800
commit2a8f9f0f530327039c32e444b6a27130b12666bd (patch)
treee24e38b5b3c0245a0acafc63fc50bacbf7de718a
parent4c6ca1db931377b75583f61a7bca262cfc27b0fa (diff)
Update repo
This is a squashed commit imported from this repo: https://github.com/openstack/swiftonfile/tree/icehouse Contains the follwing commits from above mentioned repo: eb50236 Merge "Backport: Fix metadata overall limits bug" into icehouse 79ea52a Backport: Fix metadata overall limits bug bc43f0b Fix inconsistent data being returned on GET ad0bb79 Import HTTPBadRequest from swift's module 74d02e6 Exclude .trashcan dir from container listing b2dbc15 Catch ESTALE in addition to ENOENT 8d60b48 Properly handle read_metadata() exceptions 6762fc6 Fix object server leaking file descriptors 2842e82 Fix API incompatibility in update_metadata() 2beeef6 Merge "Remove swiftkerbauth code" into icehouse 93dbcb5 Update object-expirer.conf with explanations c9d2f09 Merge "Check if /etc/swift exists in ring builder" into icehouse d66c14c Remove swiftkerbauth code 3142ed2 Add object expiration functests 97153d1 Merge "Cleanup functest and undo old patch" into icehouse bc234d0 Remove old travis config file and fix typo 260c8ef Check if /etc/swift exists in ring builder 637dac9 Cleanup functest and undo old patch 051e068 Merge pull request #35 from prashanthpai/backport-1 be104a3 Merge pull request #36 from prashanthpai/backport-2 ff76f42 fix issue with GET on large object (icehouse-backport) 04d0a99 Fix unlink call after successful rename 4c6ca1d updating README file with project name change 10b2680 Merge pull request #18 from thiagol11/icehouse 5bcab8f Updating version on __init__ file 5c2cba2 Merge pull request #15 from thiagol11/update_spec 52b00a8 updating spec file to add dependency on swift icehouse ae7c93b Merge pull request #6 from prashanthpai/rebase 191e55b Revert: allow non-root user to run functests cb7e968 Modify unit tests and func tests d23fd1b Sync with OpenStack Swift v1.13.1 b6d1671 Merge pull request #12 from pushpesh/functionalnosetestremove 962622b Merge pull request #8 from thiagol11/update_readme 4560857 Merge pull request #9 from prashanthpai/spec-expirer be0ae7e Minor update 65000f1 Removing functionalnosetests 8ab1069 Fix object-expirer.conf-gluster RPM build error afee30f added new support filesystem section 527b01f updated README.md to Swift-On-File 9a240c7 Merge pull request #3 from thiagol11/add_jenkins_to_travis 34b5a8b removing blank lines 3568b64 fixing missing fi d8f5b0f adding support to run jenkins triggered by travis 6f4a88c Removing functionalnosetests 8041944 Update README.md c015148 Merge pull request #2 from thiagol11/master 3ddd952 fixing travis file to run correct unit test c582669 adding travis status badge to README 8093096 adding py26 unit testing to travis 37835fd trigger travis build cb6332a adding travis ci testing All tests have been run sucessfully against this. tox -e p2p8,py27,functest Change-Id: I096b611da852d3eb3913844034b443b8272c2ac4 Signed-off-by: Prashanth Pai <ppai@redhat.com> Reviewed-on: http://review.gluster.org/13188
-rwxr-xr-x.functests35
-rw-r--r--.gitignore22
-rw-r--r--.gitreview2
-rwxr-xr-x.unittests (renamed from unittests.sh)19
-rw-r--r--README.md12
-rwxr-xr-xbin/gluster-swift-gen-builders5
-rw-r--r--doc/markdown/auth_guide.md16
-rw-r--r--doc/markdown/swiftkerbauth/AD_client.md206
-rw-r--r--doc/markdown/swiftkerbauth/AD_server.md119
-rw-r--r--doc/markdown/swiftkerbauth/architecture.md105
-rw-r--r--doc/markdown/swiftkerbauth/ipa_client.md80
-rw-r--r--doc/markdown/swiftkerbauth/ipa_server.md146
-rw-r--r--doc/markdown/swiftkerbauth/swiftkerbauth_guide.md517
-rw-r--r--etc/object-expirer.conf-gluster33
-rwxr-xr-xfunctests.sh15
-rw-r--r--gluster/swift/__init__.py8
-rw-r--r--gluster/swift/common/DiskDir.py61
-rw-r--r--gluster/swift/common/Glusterfs.py13
-rw-r--r--gluster/swift/common/constraints.py41
-rw-r--r--gluster/swift/common/fs_utils.py8
-rw-r--r--gluster/swift/common/middleware/gswauth/swauth/middleware.py33
-rw-r--r--gluster/swift/common/middleware/gswauth/test_swauth/__init__.py6
-rw-r--r--gluster/swift/common/middleware/gswauth/test_swauth/unit/test_authtypes.py63
-rw-r--r--gluster/swift/common/middleware/gswauth/test_swauth/unit/test_middleware.py4519
-rw-r--r--gluster/swift/common/middleware/swiftkerbauth/__init__.py38
-rw-r--r--gluster/swift/common/middleware/swiftkerbauth/apachekerbauth/etc/httpd/conf.d/swift-auth.conf12
-rwxr-xr-xgluster/swift/common/middleware/swiftkerbauth/apachekerbauth/var/www/cgi-bin/swift-auth70
-rw-r--r--gluster/swift/common/middleware/swiftkerbauth/kerbauth.py463
-rw-r--r--gluster/swift/common/middleware/swiftkerbauth/kerbauth_utils.py137
-rw-r--r--gluster/swift/common/utils.py32
-rw-r--r--gluster/swift/obj/diskfile.py94
-rw-r--r--glusterfs-openstack-swift.spec26
-rw-r--r--requirements.txt (renamed from tools/requirements.txt)0
-rw-r--r--setup.py2
-rw-r--r--test-requirements.txt (renamed from tools/test-requires)0
-rw-r--r--test/functional/gluster_swift_tests.py91
-rw-r--r--test/functional/swift_test_client.py47
-rw-r--r--test/functional/swift_testing.py45
-rwxr-xr-xtest/functional/test_account.py584
-rwxr-xr-xtest/functional/test_container.py833
-rwxr-xr-xtest/functional/test_object.py524
-rw-r--r--test/functional/tests.py470
-rw-r--r--test/functional_auth/common_conf/account-server.conf (renamed from test/functional_auth/tempauth/conf/account-server.conf)4
-rw-r--r--test/functional_auth/common_conf/container-server.conf (renamed from test/functional_auth/gswauth/conf/container-server.conf)4
-rw-r--r--test/functional_auth/common_conf/fs.conf (renamed from test/functional_auth/gswauth/conf/fs.conf)0
-rw-r--r--test/functional_auth/common_conf/object-expirer.conf27
-rw-r--r--test/functional_auth/common_conf/object-server.conf (renamed from test/functional_auth/gswauth/conf/object-server.conf)5
-rw-r--r--test/functional_auth/common_conf/swift.conf (renamed from test/functional_auth/gswauth/conf/swift.conf)0
-rw-r--r--test/functional_auth/common_conf/test.conf (renamed from test/functional_auth/swiftkerbauth/conf/test.conf)23
-rw-r--r--test/functional_auth/gswauth/conf/account-server.conf32
-rw-r--r--test/functional_auth/gswauth/conf/object-expirer.conf17
-rw-r--r--test/functional_auth/gswauth/conf/proxy-server.conf26
-rw-r--r--test/functional_auth/keystone/conf/account-server.conf32
-rw-r--r--test/functional_auth/keystone/conf/container-server.conf35
-rw-r--r--test/functional_auth/keystone/conf/fs.conf19
-rw-r--r--test/functional_auth/keystone/conf/object-server.conf48
-rw-r--r--test/functional_auth/keystone/conf/proxy-server.conf27
-rw-r--r--test/functional_auth/keystone/conf/swift.conf85
-rw-r--r--test/functional_auth/swiftkerbauth/__init__.py0
-rw-r--r--test/functional_auth/swiftkerbauth/conf/account-server.conf36
-rw-r--r--test/functional_auth/swiftkerbauth/conf/container-server.conf36
-rw-r--r--test/functional_auth/swiftkerbauth/conf/fs.conf13
-rw-r--r--test/functional_auth/swiftkerbauth/conf/object-server.conf51
-rw-r--r--test/functional_auth/swiftkerbauth/conf/proxy-server.conf17
-rw-r--r--test/functional_auth/swiftkerbauth/conf/swift.conf84
-rw-r--r--test/functional_auth/swiftkerbauth/test_swkrbath_active.py93
-rw-r--r--test/functional_auth/tempauth/conf/container-server.conf35
-rw-r--r--test/functional_auth/tempauth/conf/fs.conf19
-rw-r--r--test/functional_auth/tempauth/conf/object-expirer.conf17
-rw-r--r--test/functional_auth/tempauth/conf/object-server.conf48
-rw-r--r--test/functional_auth/tempauth/conf/proxy-server.conf21
-rw-r--r--test/functional_auth/tempauth/conf/swift.conf85
-rw-r--r--test/object_expirer_functional/__init__.py (renamed from gluster/swift/common/middleware/gswauth/test_swauth/unit/__init__.py)0
-rw-r--r--test/object_expirer_functional/test_object_expirer.py332
-rw-r--r--test/unit/__init__.py39
-rw-r--r--test/unit/common/middleware/swiftkerbauth/__init__.py0
-rw-r--r--test/unit/common/middleware/swiftkerbauth/test_kerbauth.py478
-rw-r--r--test/unit/common/middleware/swiftkerbauth/test_kerbauth_utils.py77
-rw-r--r--test/unit/common/test_constraints.py73
-rw-r--r--test/unit/common/test_diskdir.py14
-rw-r--r--test/unit/common/test_utils.py24
-rw-r--r--test/unit/obj/test_diskfile.py55
-rw-r--r--test/unit/obj/test_expirer.py14
-rwxr-xr-xtest/unit/proxy/controllers/test_obj.py98
-rw-r--r--test/unit/proxy/test_server.py794
-rwxr-xr-xtools/gswauth_functional_tests.sh13
-rwxr-xr-xtools/keystone_functional_tests.sh6
-rwxr-xr-xtools/object_expirer_functional.sh (renamed from tools/swkrbath_functional_tests.sh)53
-rwxr-xr-xtools/tempauth_functional_tests.sh (renamed from tools/functional_tests.sh)9
-rw-r--r--tox.ini42
90 files changed, 3780 insertions, 8832 deletions
diff --git a/.functests b/.functests
new file mode 100755
index 0000000..6b13b69
--- /dev/null
+++ b/.functests
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+# Copyright (c) 2013 Red Hat, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This program expects to be run by tox in a virtual python environment
+# so that it does not pollute the host development system
+
+EXIT_STATUS=0
+
+# Run functional tests with tempauth as auth middleware
+bash tools/tempauth_functional_tests.sh || EXIT_STATUS=$?
+
+# Run functional tests with gswauth as auth middleware
+bash tools/gswauth_functional_tests.sh || EXIT_STATUS=$?
+
+# Run object expirer functional tests if gsexpiring volume is found.
+if mount | grep "gsexpiring on /mnt/gluster-object/gsexpiring type fuse.glusterfs"; then
+ echo "Running object expirer functional tests"
+ bash tools/object_expirer_functional.sh || EXIT_STATUS=$?
+fi
+
+exit $EXIT_STATUS
diff --git a/.gitignore b/.gitignore
index cd4a111..938554e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,9 +1,13 @@
-/.tox
-gluster_swift.egg-info
-/test/unit/.coverage
-/test/unit/nosetests.xml
-/test/unit/coverage.xml
-/test/unit/cover
-/build
-/swift
-*.pyc
+*.py[co]
+*.sw?
+*~
+dist
+build
+cover
+functional_tests_result
+.coverage
+*.egg
+*.egg-info
+.tox
+pycscope.*
+cscope.*
diff --git a/.gitreview b/.gitreview
index 6b69219..466f899 100644
--- a/.gitreview
+++ b/.gitreview
@@ -1,2 +1,2 @@
[gerrit]
-defaultbranch=master
+defaultbranch=icehouse
diff --git a/unittests.sh b/.unittests
index 940ada7..fcd066a 100755
--- a/unittests.sh
+++ b/.unittests
@@ -15,10 +15,19 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+TOP_DIR=$(python -c "import os; print os.path.dirname(os.path.realpath('$0'))")
-cd $(dirname $0)/test/unit
-nosetests -v --exe --with-coverage --cover-package gluster --cover-erase --cover-html --cover-branches $@
-
-saved_status=$?
+python -c 'from distutils.version import LooseVersion as Ver; import nose, sys; sys.exit(0 if Ver(nose.__version__) >= Ver("1.2.0") else 1)'
+if [ $? != 0 ]; then
+ cover_branches=""
+else
+ # Having the HTML reports is REALLY useful for achieving 100% branch
+ # coverage.
+ cover_branches="--cover-branches --cover-html --cover-html-dir=$TOP_DIR/cover"
+fi
+cd $TOP_DIR/test/unit
+nosetests -v --exe --with-coverage --cover-package gluster. --cover-erase $cover_branches $@
+rvalue=$?
rm -f .coverage
-exit $saved_status
+cd -
+exit $rvalue
diff --git a/README.md b/README.md
index fd63499..42ab315 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,3 @@
-# Gluster-Swift has moved to Swift-On-File
-The Gluster-Swift project is being moved to a new project named [Swift-On-File][].
-This new name better represents its nature as a Swift backend that supports
-multiple Posix Filesystems, not just GlusterFS. The last released version of
-Gluster-Swift was the [Icehouse release][].
-
-[Swift-On-File][https://github.com/swiftonfile/swiftonfile]
-[Icehouse release][https://github.com/swiftonfile/swiftonfile/releases/tag/v1.13.1-2]
-
+# Gluster-Swift
+Gluster-Swift enables files and directories created on GlusterFS
+to be accessed as objects via the Swift API.
diff --git a/bin/gluster-swift-gen-builders b/bin/gluster-swift-gen-builders
index 2e5fe1f..4cf757d 100755
--- a/bin/gluster-swift-gen-builders
+++ b/bin/gluster-swift-gen-builders
@@ -68,7 +68,10 @@ if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
fi
-cd /etc/swift
+if ! cd "/etc/swift"; then
+ echo "The path /etc/swift not accessible. Please check if it exists."
+ exit 1
+fi
for builder_file in $builder_files
do
diff --git a/doc/markdown/auth_guide.md b/doc/markdown/auth_guide.md
index 274dd32..86c3650 100644
--- a/doc/markdown/auth_guide.md
+++ b/doc/markdown/auth_guide.md
@@ -12,13 +12,6 @@
* [User roles](#gswauth_user_roles)
* [GSwauth Tools](#gswauth_tools)
* [Authenticating a user](#gswauth_authenticate)
-* [Swiftkerbauth](#swiftkerbauth)
- * [Architecture](swiftkerbauth/architecture.md)
- * [RHEL IPA Server Guide](swiftkerbauth/ipa_server.md)
- * [RHEL IPA Client Guide](swiftkerbauth/ipa_client.md)
- * [Windows AD Server Guide](swiftkerbauth/AD_server.md)
- * [Windows AD Client Guide](swiftkerbauth/AD_client.md)
- * [Swiftkerbauth Guide](swiftkerbauth/swiftkerbauth_guide.md)
## <a name="keystone" />Keystone ##
The Standard Openstack authentication service
@@ -468,12 +461,3 @@ bash-4.2$ swift --os-auth-token=AUTH_tk7e68ef4698f14c7f95af07ab7b298610 --os-sto
README.md
~~~
**Note:** Reseller admins must always use the second method to acquire a token, in order to be given access to other accounts different than his own. The first method of using the username and password will give them access only to their own accounts.
-
-## <a name="swiftkerbauth" />Swiftkerbauth ##
-Kerberos authentication filter
-
-Carsten Clasohm implemented a new authentication filter for swift
-that uses Kerberos tickets for single sign on authentication, and
-grants administrator permissions based on the users group membership
-in a directory service like Red Hat Enterprise Linux Identity Management
-or Microsoft Active Directory.
diff --git a/doc/markdown/swiftkerbauth/AD_client.md b/doc/markdown/swiftkerbauth/AD_client.md
deleted file mode 100644
index 0947a1e..0000000
--- a/doc/markdown/swiftkerbauth/AD_client.md
+++ /dev/null
@@ -1,206 +0,0 @@
-#AD client setup guide
-
-###Contents
-* [Setup Overview] (#setup)
-* [Configure Network] (#network)
-* [Installing AD Client] (#AD-client)
-
-<a name="setup" />
-###Setup Overview
-
-This guide talks about adding fedora linux client to windows domain.
-The test setup included a client machine with Fedora 19 installed
-on it with all the latest packages updated. The crux is to add this linux
-machine to Windows Domain. This linux box is expected to act as RHS node and on which swiftkerbauth,
-apachekerbauth code would run.
-
-Set hostname (FQDN) to fcclient.winad.com
-
- # hostnamectl set-hostname "fcclient.winad.com"
-
- # hostname "fcclient.winad.com"
-
-
-<a name="network" />
-### Configure client
-
-* Deploy Fedora linux 19.
-
-* Update the system with latest packages.
-
-* Configure SELinux security parameters.
-
-* Install & configure samba
-
-* Configure DNS
-
-* Synchronize the time services
-
-* Join Domain
-
-* Install / Configure Kerberos Client
-
-
-The document assumes the installing Fedora Linux and configuring SELinux
-parameters to 'permissive' is known already.
-
-###Install & Configure Samba:
- # yum -y install samba samba-client samba-common samba-winbind
- samba-winbind-clients
-
- # service start smb
-
- # ps -aef | grep smb
- # chkconfig smb on
-
-###Synchronize time services
-The kerberos authentication and most of the DNS functionality could fail with
-clock skew if times are not synchronized.
-
- # cat /etc/ntp.conf
- server ns1.bos.redhat.com
- server 10.5.26.10
-
- # service ntpd stop
-
- # ntpdate 10.16.255.2
-
- # service ntpd start
-
- #chkconfig ntpd on
-
-Check if Windows server in the whole environment is also time synchronized with
-same source.
-
- # C:\Users\Administrator>w32tm /query /status | find "Source"
-
- Source: ns1.xxx.xxx.com
-
-###Configure DNS on client
-Improperly resolved hostname is the leading cause in authentication failures.
-Best practice is to configure fedora client to use Windows DNS.
-'nameserver' below is the IP address of the windows server.
- # cat /etc/resolve.conf
- domain server.winad.com
- search server.winad.com
- nameserver 10.nn.nnn.3
-
-###Set the hostname of the client properly (FQDN)
- # cat /etc/sysconfig/network
- HOSTNAME=fcclient.winad.com
-
-
-###Install & Configure kerberos client
-
- # yum -y install krb5-workstation
-
-Edit the /etc/krb5.conf as follows:
-
- # cat /etc/krb5.conf
- [logging]
- default = FILE:/var/log/krb5libs.log
- kdc = FILE:/var/log/krb5kdc.log
- admin_server = FILE:/var/log/kadmind.log
-
- [libdefaults]
- default_realm = WINAD.COM
- dns_lookup_realm = false
- dns_lookup_kdc = false
- ticket_lifetime = 24h
- renew_lifetime = 7d
- forwardable = true
-
- [realms]
- WINAD.COM = {
- kdc = server.winad.com
- admin_server = server.winad.com
- }
- [domain_realm]
- .demo = server.winad.com
- demo = server.winad.com
-
-###Join Domain
-Fire command 'system-config-authentication' on client. This should display a
-graphical wizard. Below inputs would help configure this wizard.
-
- - User account data base = winbind
- - winbind domain = winad
- - security model = ads
- - winbind ads realm = winad.com
- - winbind controller = server.winad.com
- - template shell = /bin/bash
- - let the other options be as is to default.
- - Perform Join domain and appy settings and quit. Please note this join should
- not see any errors. This makes the client fedora box to join the windows
- domain.
-
-###Configure the kerberos client
-This would bring the users/groups from Windows Active directory to this
-fedora client.
-
-Edit /etc/samba/smb.conf file to have below parameters in the global section.
-
- # cat /etc/samba/smb.conf
- [global]
- workgroup = winad
- realm = winad.com
- server string = Samba Server Version %v
- security = ADS
- allow trusted domains = No
- password server = server.winad.com
- log file = /var/log/samba/log.%m
- max log size = 50
- idmap uid = 10000­19999
- idmap gid = 10000­19999
- template shell = /bin/bash
- winbind separator = +
- winbind use default domain = Yes
- idmap config REFARCH­AD:range = 10000000­19999999
- idmap config REFARCH­AD:backend = rid
- cups options = raw
-
-
- # service smb stop
-
- # service winbind stop
-
- # tar -cvf /var/tmp/samba-cache-backup.tar /var/lib/samba
-
- # ls -la /var/tmp/samba-cache-backup.tar
-
- # rm ­-f /var/lib/samba/*
-
-
-Verify that no kerberos ticket available and cached.
-
- # kdestroy
-
- # klist
-
-Rejoin the domain.
-
- # net join -S server -U Administrstor
-
-Test that client rejoined the domain.
-
- # net ads info
-
-Restart smb and winbind service.
-
- # wbinfo --domain-users
-
-Perform kinit for the domain users prepared on active directory. This is obtain
-the kerberos ticket for user 'auth_admin'
-
- # kinit auth_admin
-
- # id -Gn auth_admin
-
-###Notes
-Obtaining the HTTP service principal & keytab file and installing it with
-swiftkerbauth is added to swiftkerbauth_guide
-
-###References
-Reference Document for adding Linux box to windows domain :
-Integrating Red Hat Enterprise Linux 6
-with Active Directory
diff --git a/doc/markdown/swiftkerbauth/AD_server.md b/doc/markdown/swiftkerbauth/AD_server.md
deleted file mode 100644
index 66d90f2..0000000
--- a/doc/markdown/swiftkerbauth/AD_server.md
+++ /dev/null
@@ -1,119 +0,0 @@
-#Windows Active Directory & Domain Controller Server Guide
-
-###Contents
-* [Setup Overview] (#Setup)
-* [Installing Active Directory Services] (#AD-server)
-* [Configuring DNS] (#DNS)
-* [Adding Users and Groups] (#users-groups)
-
-
-<a name="Setup" />
-###Setup Overview
-
-The setup includes a server machine installed with Windows 2008 R2 Server, with
-Domain Controller, Active Directory services & DNS server installed alongwith.
-The steps to install windows operating system and above servers can be found
-on MicroSoft Documentation. This windows Active Directory server would act as an
-authentication server in the whole setup. This would provide the access control
-and permissions for users on certain data objects.
-
-
-Windows 2008 R2 deployment:
-
-http://technet.microsoft.com/en-us/library/dd283085.aspx
-
-
-Configuring Active Directory, Domain Services, DNS server:
-
-http://technet.microsoft.com/en-us/library/cc770946.aspx
-
-
-<a name="AD-server" />
-###Installing AD Server
-
-Administrators need to follow simple instructions in Server Manager on Windows
-2008, and should add Active Directory Domain Services & DNS server. It is
-recommended to use static IP for DNS server. Preferred Hostname(FQDN) for
-Windows server could be of format hostname 'server.winad.com' where
-'winad.com' is a domain name.
-
-Following tips would help prepare a test setup neatly.
-
- - Select Active Directory Domain services wizard in Server Manager
- - Move on to install it with all the pre-requisits, e.g. .NET framework etc.
- - Configure Active directory after installtion via exapanding the 'Roles'
- section in the server manager.
- - Create a new Domain in the New Forest.
- - Type the FQDN, winad.com
- - Set Forest functional level Windows 2008 R2.
- - Selct additional options for this domain controller as DNS server.
- - Leave the log locations to default provided by wizard.
- - Set the Administrator Password carefully.
- - Thats it. You are done configuring active directory.
-
-
-<a name="dns" />
-###Configuring DNS
-
-This section explains configuring the DNS server installed on Windows 2008 R2
-server. You must know know about
-
- - Forward lookup zone
-
- - Reverse lookup zone
-
- - Zone type
-
-A forward lookup zone is simply a way to resolve hostnames to IP address.
-A reverse lookup zone is to lookup DNS hostname of the host IP.
-
-Following tips would help configure the Zones on DNS server.
-
- - Create a Forward lookup zone.
- - Create it a primary zone.
- - Add the Clients using their ip addresses and FQDN to this forward lookup
- zones.
- - This would add type 'A' record for that host on DNS server.
- - Similarly create a Reverser lookup zone.
- - Add clients 'PTR' record to this zone via browsing through the forward
- zones clients.
-
-The above setup can be tested on client once it joins the domain using 'dig'
-command as mentioned below.
-
-
-On client:
-
- # dig fcclient.winad.com
- This should yield you a Answer section mentioning its IP address.
-
- Reverse lookup can be tested using
-
- # 'dig -t ptr 101.56.168.192.in-addr.arpa.'
- The answer section should state the FQDN of the client.
-
- Repeat the above steps on client for Windows AD server as well.
-
-
-<a name="users-groups" />
-###Adding users and groups
-
-The following convention is to be followed in creating group names:
-
- <reseller-prefix>\_<volume-name>
-
- <reseller-prefix>\_<account-name>
-
-As of now, account=volume=group
-
-For example:
-
- AUTH\_test
-
-Adding groups and users to the Windows domain is easy task.
-
- - Start -> Administrative Tools -> Active Directory Users & Computers
- - Expand the domain name which was prepared earlier. e.g winad.com
- - Add groups with appropreate access rights.
- - Add users to the group with appropreate permissions.
- - Make sure you set password for users prepared on AD server.
diff --git a/doc/markdown/swiftkerbauth/architecture.md b/doc/markdown/swiftkerbauth/architecture.md
deleted file mode 100644
index fc6d764..0000000
--- a/doc/markdown/swiftkerbauth/architecture.md
+++ /dev/null
@@ -1,105 +0,0 @@
-# Architecture
-
-The Swift API is HTTP-based. As described in the Swift documentation
-[1], clients first make a request to an authentication URL, providing
-a username and password. The reply contains a token which is used in
-all subsequent requests.
-
-Swift has a chain of filters through which all client requests go. The
-filters to use are configured with the pipeline parameter in
-/etc/swift/proxy-server.conf:
-
- [pipeline:main]
- pipeline = healthcheck cache tempauth proxy-server
-
-For the single sign authentication, we added a new filter called
-"kerbauth" and put it into the filter pipeline in place of tempauth.
-
-The filter checks the URL for each client request. If it matches the
-authentication URL, the client is redirected to a URL on a different
-server (on the same machine). The URL is handled by a CGI script, which
-is set up to authenticate the client with Kerberos negotiation, retrieve
-the user's system groups [2], store them in a memcache ring shared with
-the Swift server, and return the authentication token to the client.
-
-When the client provides the token as part of a resource request, the
-kerbauth filter checks it against its memcache, grants administrator
-rights based on the group membership retrieved from memcache, and
-either grants or denies the resource access.
-
-[1] http://docs.openstack.org/api/openstack-object-storage/1.0/content/authentication-object-dev-guide.html
-
-[2] The user data and system groups are usually provided by Red Hat
- Enterprise Linux identity Management or Microsoft Active
- Directory. The script relies on the system configuration to be set
- accordingly (/etc/nsswitch.conf).
-
-*****
-
-## kerbauth.py
-
-The script kerbauth.py began as a copy of the tempauth.py script from
-from tempauth middleware. It contains the following modifications, among
-others:
-
-In the __init__ method, we read the ext_authentication_url parameter
-from /etc/swift/proxy-server.conf. This is the URL that clients are
-redirected to when they access either the Swift authentication URL, or
-when they request a resource without a valid authentication token.
-
-The configuration in proxy-server.conf looks like this:
-
- [filter:kerbauth]
- use = egg:swiftkerbauth#kerbauth
- ext_authentication_url = http://client.rhelbox.com/cgi-bin/swift-auth
-
-The authorize method was changed so that global administrator rights
-are granted if the user is a member of the auth_reseller_admin
-group. Administrator rights for a specific account like vol1 are
-granted if the user is a member of the auth_vol1 group. [3]
-
-The denied_response method was changed to return a HTTP redirect to
-the external authentication URL if no valid token was provided by the
-client.
-
-Most of the handle_get_token method was moved to the external
-authentication script. This method now returns a HTTP redirect.
-
-In the __call__ and get_groups method, we removed support for the
-HTTP_AUTHORIZATION header, which is only needed when Amazon S3 is
-used.
-
-Like tempauth.py, kerbauth.py uses a Swift wrapper to access
-memcache. This wrapper converts the key to an MD5 hash and uses the
-hash value to determine on which of a pre-defined list of servers to
-store the data.
-
-[3] "auth" is the default reseller prefix, and would be different if
- the reseller_prefix parameter in proxy-server.conf was set.
-
-## swift-auth CGI script
-
-swift-auth resides on an Apache server and assumes that Apache is
-configured to authenticate the user before this script is
-executed. The script retrieves the username from the REMOTE_USER
-environment variable, and checks if there already is a token for this
-user in the memcache ring. If not, it generates a new one, retrieves
-the user's system groups with "id -Gn USERNAME", stores this
-information in the memcache ring, and returns the token to the client.
-
-To allow the CGI script to connect to memcache, the SELinux booleans
-httpd_can_network_connect and httpd_can_network_memcache had to be
-set.
-
-The tempauth filter uses the uuid module to generate token
-strings. This module creates and runs temporary files, which leads to
-AVC denial messages in /var/log/audit/audit.log when used from an
-Apache CGI script. While the module still works, the audit log would
-grow quickly. Instead of writing an SELinux policy module to allow or
-to silently ignore these accesses, the swift-auth script uses the
-"random" module for generating token strings.
-
-Red Hat Enterprise Linux 6 comes with Python 2.6 which only provides
-method to list the locally defined user groups. To include groups from
-Red Hat Enterprise Linux Identity Management and in the future from
-Active Directory, the "id" command is run in a subprocess.
diff --git a/doc/markdown/swiftkerbauth/ipa_client.md b/doc/markdown/swiftkerbauth/ipa_client.md
deleted file mode 100644
index f6afc42..0000000
--- a/doc/markdown/swiftkerbauth/ipa_client.md
+++ /dev/null
@@ -1,80 +0,0 @@
-#IPA Client Guide
-
-##Contents
-* [Setup Overview] (#setup)
-* [Configure Network] (#network)
-* [Installing IPA Client] (#ipa-client)
-
-<a name="setup" />
-##Setup Overview
-We have used a F18 box as IPA client machine and used FreeIPA client.
-This document borrows instructions from the following more detailed guide.
-[RHEL 6 Identity Management Guide][]
-
-
-<a name="network" />
-## Configure network
-
-Set hostname (FQDN) to client.rhelbox.com
-> hostnamectl set-hostname "client.rhelbox.com"
->
-> hostname "client.rhelbox.com"
-
-Add following to /etc/sysconfig/network:
-
- HOSTNAME=client.rhelbox.com
-
-Add the following to /etc/hostname
-
- client.rhelbox.com
-
-Add the following to /etc/hosts
-
- 192.168.56.110 server.rhelbox.com server
- 192.168.56.101 client.rhelbox.com client
-
-Logout and login again and verify hostname :
-> hostname --fqdn
-
-Edit */etc/resolv.conf* to add this at beginning of file
-
- nameserver 192.168.56.110
-
-Warning: NetworkManager changes resolv.conf on restart
-
-Turn off firewall
-> service iptables stop
->
-> chkconfig iptables off
-
-<a name="ipa-client" />
-## Installing IPA Client
-
-Install IPA client packages:
-
-For RHEL:
-> yum install ipa-client ipa-admintools
-
-For Fedora:
-> yum install freeipa-client freeipa-admintools
-
-Install IPA client and add to domain:
->ipa-client-install --enable-dns-updates
-
- Discovery was successful!
- Hostname: client.rhelbox.com
- Realm: RHELBOX.COM
- DNS Domain: rhelbox.com
- IPA Server: server.rhelbox.com
- BaseDN: dc=rhelbox,dc=com
-
- Continue to configure the system with these values? [no]: yes
- User authorized to enroll computers: admin
-
-Check if client is configured correctly:
-> kinit admin
->
-> getent passwd admin
-
-
-[RHEL 6 Identity Management Guide]: https://access.redhat.com/site/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Identity_Management_Guide/
diff --git a/doc/markdown/swiftkerbauth/ipa_server.md b/doc/markdown/swiftkerbauth/ipa_server.md
deleted file mode 100644
index 55e654e..0000000
--- a/doc/markdown/swiftkerbauth/ipa_server.md
+++ /dev/null
@@ -1,146 +0,0 @@
-#IPA Server Guide
-
-##Contents
-* [Setup Overview] (#setup)
-* [Configure Network] (#network)
-* [Installing IPA Server] (#ipa-server)
-* [Configuring DNS] (#dns)
-* [Adding Users and Groups] (#users-groups)
-
-
-<a name="setup" />
-##Setup Overview
-We have used a RHEL 6.4 box as IPA and DNS server. This document borrows
-instructions from the following more detailed guide.
-[RHEL 6 Identity Management Guide][]
-
-
-<a name="network" />
-## Configure network
-
-Change hostname (FQDN) to server.rhelbox.com
-> hostname "server.rhelbox.com"
-
-Add following to */etc/sysconfig/network* file
-
- HOSTNAME=server.rhelbox.com
-
-Add the following to */etc/hosts* file
-
- 192.168.56.110 server.rhelbox.com server
- 192.168.56.101 client.rhelbox.com client
-
-Logout and login again and verify new hostname
-> hostname --fqdn
-
-Turn off firewall
-> service iptables stop
->
-> chkconfig iptables off
-
-
-<a name="ipa-server" />
-## Installing IPA Server
-
-Install IPA server packages and DNS dependencies
-> yum install ipa-server bind bind-dyndb-ldap
-
-Run the following interactive setup to install IPA server with DNS
-> ipa-server-install --setup-dns
-
- The IPA Master Server will be configured with:
- Hostname: server.rhelbox.com
- IP address: 192.168.56.110
- Domain name: rhelbox.com
- Realm name: RHELBOX.COM
-
- BIND DNS server will be configured to serve IPA domain with:
- Forwarders: No forwarders
- Reverse zone: 56.168.192.in-addr.arpa.
-
-The installation may take some time.
-
-Check if IPA is installed correctly :
-> kinit admin
->
-> ipa user-find admin
-
-
-<a name="dns" />
-## Configuring DNS
-
-Edit */etc/resolv.conf* to add this at beginning of file :
-
- nameserver 192.168.56.110
-
-Warning: NetworkManager changes resolv.conf on restart
-
-Add a DNS A record and PTR record for the client under rhelbox.com zone
-> ipa dnsrecord-add rhelbox.com client --a-rec=192.168.56.101 --a-create-reverse
-
-Check if DNS resolution is working by running :
-
-> dig server.rhelbox.com
-
- ;; ANSWER SECTION:
- server.rhelbox.com. 1200 IN A 192.168.56.110
-
-> dig client.rhelbox.com
-
- ;; ANSWER SECTION:
- client.rhelbox.com. 86400 IN A 192.168.56.101
-
-Check if reverse resolution works :
-
-> dig -t ptr 101.56.168.192.in-addr.arpa.
-
- ;; ANSWER SECTION:
- 101.56.168.192.in-addr.arpa. 86400 IN PTR client.rhelbox.com.
-
-
-> dig -t ptr 110.56.168.192.in-addr.arpa.
-
- ;; ANSWER SECTION:
- 110.56.168.192.in-addr.arpa. 86400 IN PTR server.rhelbox.com.
-
-
-<a name="users-groups" />
-## Adding users and groups
-
-The following convention is to be followed in creating group names:
-
- <reseller-prefix>\_<volume-name>
-
- <reseller-prefix>\_<account-name>
-
-As of now, account=volume=group
-
-For example:
-
- AUTH\_test
-
-Create *auth_reseller_admin* user group
-> ipa group-add auth_reseller_admin --desc="Full access to all Swift accounts"
-
-Create *auth_rhs_test* user group
-> ipa group-add auth_rhs_test --desc="Full access to rhs_test account"
-
-Create user *auth_admin* user as member of *auth_reseller_admin* user group
-> ipa user-add auth_admin --first=Auth --last=Admin --password
->
-> ipa group-add-member auth_reseller_admin --users=auth_admin
-
-Create user *rhs_test_admin* as member of *auth_rhs_test* user group
-> ipa user-add rhs_test_admin --first=RHS --last=Admin --password
->
-> ipa group-add-member auth_rhs_test --users=rhs_test_admin
-
-Create user *jsmith* with no relevant group membership
-> ipa user-add rhs_test_admin --first=RHS --last=Admin --password
-
-You can verify users have been added by running
->ipa user-find admin
-
-NOTE: Every user has to change password on first login.
-
-[RHEL 6 Identity Management Guide]: https://access.redhat.com/site/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Identity_Management_Guide/
diff --git a/doc/markdown/swiftkerbauth/swiftkerbauth_guide.md b/doc/markdown/swiftkerbauth/swiftkerbauth_guide.md
deleted file mode 100644
index 5da1827..0000000
--- a/doc/markdown/swiftkerbauth/swiftkerbauth_guide.md
+++ /dev/null
@@ -1,517 +0,0 @@
-#swiftkerbauth
-
-* [Installing Kerberos module for Apache] (#httpd-kerb-install)
-* [Creating HTTP Service Principal] (#http-principal)
-* [Installing and configuring swiftkerbauth] (#install-swiftkerbauth)
-* [Using swiftkerbauth] (#use-swiftkerbauth)
-* [Configurable Parameters] (#config-swiftkerbauth)
-* [Functional tests] (#swfunctest)
-
-<a name="httpd-kerb-install" />
-## Installing Kerberos module for Apache on IPA client
-
-Install httpd server with kerberos module:
-> yum install httpd mod_auth_kerb
->
-> service httpd restart
-
-Check if auth_kerb_module is loaded :
-> httpd -M | grep kerb
-
-Change httpd log level to debug by adding/changing the following in
-*/etc/httpd/conf/httpd.conf* file
-
- LogLevel debug
-
-httpd logs are at */var/log/httpd/error_log* for troubleshooting
-
-If SELinux is enabled, allow Apache to connect to memcache and
-activate the changes by running
->setsebool -P httpd_can_network_connect 1
->
->setsebool -P httpd_can_network_memcache 1
-
-*****
-
-<a name="http-principal" />
-## Creating HTTP Service Principal on IPA server
-
-Add a HTTP Kerberos service principal :
-> ipa service-add HTTP/client.rhelbox.com@RHELBOX.COM
-
-Retrieve the HTTP service principal to a keytab file:
-> ipa-getkeytab -s server.rhelbox.com -p HTTP/client.rhelbox.com@RHELBOX.COM -k /tmp/http.keytab
-
-Copy keytab file to client:
-> scp /tmp/http.keytab root@192.168.56.101:/etc/httpd/conf/http.keytab
-
-## Creating HTTP Service Principal on Windows AD server
-
-Add a HTTP Kerberos service principal:
-> c:\>ktpass.exe -princ HTTP/fcclient.winad.com@WINAD.COM -mapuser
-> auth_admin@WINAD.COM -pass Redhat*123 -out c:\HTTP.keytab -crypto DES-CBC-CRC
-> -kvno 0
-
-Use winscp to copy HTTP.ketab file to /etc/httpd/conf/http.keytab
-
-*****
-
-<a name="install-swiftkerbauth" />
-##Installing and configuring swiftkerbauth on IPA client
-
-Prerequisites for installing swiftkerbauth
-* swift (havana)
-* gluster-swift (optional)
-
-You can install swiftkerbauth using one of these three ways:
-
-Installing swiftkerbauth from source:
-> python setup.py install
-
-Installing swiftkerbauth using pip:
-> pip install swiftkerbauth
-
-Installing swiftkerbauth from RPMs:
-> ./makerpm.sh
->
-> rpm -ivh dist/swiftkerbauth-1.0.0-1.noarch.rpm
-
-Edit */etc/httpd/conf.d/swift-auth.conf* and change KrbServiceName, KrbAuthRealms and Krb5KeyTab parameters accordingly.
-More detail on configuring kerberos for apache can be found at:
-[auth_kerb_module Configuration][]
-
-Make /etc/httpd/conf/http.keytab readable by any user :
-> chmod 644 /etc/httpd/conf/http.keytab
-
-And preferably change owner of keytab file to apache :
-> chown apache:apache /etc/httpd/conf/http.keytab
-
-Reload httpd
-> service httpd reload
-
-Make authentication script executable:
-> chmod +x /var/www/cgi-bin/swift-auth
-
-*****
-
-<a name="#use-swiftkerbauth" />
-##Using swiftkerbauth
-
-### Adding kerbauth filter in swift pipeline
-
-Edit */etc/swift/proxy-server.conf* and add a new filter section as follows:
-
- [filter:kerbauth]
- use = egg:swiftkerbauth#kerbauth
- ext_authentication_url = http://client.rhelbox.com/cgi-bin/swift-auth
- auth_mode=passive
-
-Add kerbauth to pipeline
-
- [pipeline:main]
- pipeline = catch_errors healthcheck proxy-logging cache proxy-logging kerbauth proxy-server
-
-If the Swift server is not one of your Gluster nodes, edit
-*/etc/swift/fs.conf* and change the following lines in the DEFAULT
-section:
-
- mount_ip = RHS_NODE_HOSTNAME
- remote_cluster = yes
-
-Restart swift to activate kerbauth filer
-> swift-init main restart
-
-
-###Examples
-
-####Authenticate user and get Kerberos ticket
-
-> kinit auth_admin
-
-NOTE: curl ignores user specified in -u option. All further curl commands
-will use the currently authenticated auth_admin user.
-
-####Get an authentication token:
-> curl -v -u : --negotiate --location-trusted http://client.rhelbox.com:8080/auth/v1.0
-
- * About to connect() to client.rhelbox.com port 8080 (#0)
- * Trying 192.168.56.101...
- * connected
- * Connected to client.rhelbox.com (192.168.56.101) port 8080 (#0)
- > GET /auth/v1.0 HTTP/1.1
- > User-Agent: curl/7.27.0
- > Host: client.rhelbox.com:8080
- > Accept: */*
- >
- < HTTP/1.1 303 See Other
- < Content-Type: text/html; charset=UTF-8
- < Location: http://client.rhelbox.com/cgi-bin/swift-auth
- < Content-Length: 0
- < X-Trans-Id: txecd415aae89b4320b6145-0052417ea5
- < Date: Tue, 24 Sep 2013 11:59:33 GMT
- <
- * Connection #0 to host client.rhelbox.com left intact
- * Issue another request to this URL: 'http://client.rhelbox.com/cgi-bin/swift-auth'
- * About to connect() to client.rhelbox.com port 80 (#1)
- * Trying 192.168.56.101...
- * connected
- * Connected to client.rhelbox.com (192.168.56.101) port 80 (#1)
- > GET /cgi-bin/swift-auth HTTP/1.1
- > User-Agent: curl/7.27.0
- > Host: client.rhelbox.com
- > Accept: */*
- >
- < HTTP/1.1 401 Unauthorized
- < Date: Tue, 24 Sep 2013 11:59:33 GMT
- < Server: Apache/2.4.6 (Fedora) mod_auth_kerb/5.4
- < WWW-Authenticate: Negotiate
- < WWW-Authenticate: Basic realm="Swift Authentication"
- < Content-Length: 381
- < Content-Type: text/html; charset=iso-8859-1
- <
- * Ignoring the response-body
- * Connection #1 to host client.rhelbox.com left intact
- * Issue another request to this URL: 'http://client.rhelbox.com/cgi-bin/swift-auth'
- * Re-using existing connection! (#1) with host (nil)
- * Connected to (nil) (192.168.56.101) port 80 (#1)
- * Server auth using GSS-Negotiate with user ''
- > GET /cgi-bin/swift-auth HTTP/1.1
- > Authorization: Negotiate YIICYgYJKoZIhvcSAQICAQBuggJRMIICTaADAgEFoQMCAQ6iBwMFACAAAACjggFgYYIBXDCCAVigAwIBBaENGwtSSEVMQk9YLkNPTaIlMCOgAwIBA6EcMBobBEhUVFAbEmNsaWVudC5yaGVsYm94LmNvbaOCARkwggEVoAMCARKhAwIBAaKCAQcEggEDx9SH2R90RO4eAkhsNKow/DYfjv1rWhgxNRqj/My3yslASSgefls48VdDNHVVWqr1Kd6mB/9BIoumpA+of+KSAg2QfPtcWiVFj5n5Fa8fyCHyQPvV8c92KzUdrBPc8OVn0aldFp0I4P1MsYZbnddDRSH3kjVA5oSucHF59DhZWiGJV/F6sVimBSeoTBHQD38Cs5RhyDHNyUad9v3gZERVGCJXC76i7+yyaoIDA+N9s0hasHajhTnjs3XQBYfZFwp8lWl3Ub+sOtPO1Ng7mFlSAYXCM6ljlKTEaxRwaYoXUC1EoIqEOG/8pC9SJThS2M1G7MW1c5xm4lksNss72OH4gtPns6SB0zCB0KADAgESooHIBIHFrLtai5U8ajEWo1J9B26PnIUqLd+uA0KPd2Y2FjrH6rx4xT8qG2p8i36SVGubvwBVmfQ7lSJcXt6wUvb43qyPs/fMiSY7QxHxt7/btMgxQl6JWMagvXMhCNXnhEHNNaTdBcG5KFERDGeo0txaAD1bzZ4mnxCQmoqusGzZ6wdDw6+5wq1tK/hQTQUgk2NwxfXAg2J5K02/3fKjFR2h7zewI1pEyhhpeONRkkRETcyojkK2EbVzZ8kc3RsuwzFYsJ+9u5Qj3E4=
- > User-Agent: curl/7.27.0
- > Host: client.rhelbox.com
- > Accept: */*
- >
- < HTTP/1.1 200 OK
- < Date: Tue, 24 Sep 2013 11:59:33 GMT
- < Server: Apache/2.4.6 (Fedora) mod_auth_kerb/5.4
- < WWW-Authenticate: Negotiate YIGZBgkqhkiG9xIBAgICAG+BiTCBhqADAgEFoQMCAQ+iejB4oAMCARKicQRveeZTV/QRJSIOoOWPbZkEmtdug9V5ZcMGXWqAJvCAnrvw9gHbklMyLl8f8jU2e0wU3ehtchLEL4dVeAYgKsnUgw4wGhHu59AZBwSbHRKSpv3I6gWEZqC4NAEuZJFW9ipdUHOiclBQniVXXCsRF/5Y
- < X-Auth-Token: AUTH_tk083b8abc92f4a514f34224a181ed568a
- < X-Debug-Remote-User: auth_admin
- < X-Debug-Groups: auth_admin,auth_reseller_admin
- < X-Debug-Token-Life: 86400s
- < X-Debug-Token-Expires: Wed Sep 25 17:29:33 2013
- < Content-Length: 0
- < Content-Type: text/html; charset=UTF-8
- <
- * Connection #1 to host (nil) left intact
- * Closing connection #0
- * Closing connection #1
-
-The header *X-Auth-Token* in response contains the token *AUTH_tk083b8abc92f4a514f34224a181ed568a*.
-
-####PUT a container
->curl -v -X PUT -H 'X-Auth-Token: AUTH_tk083b8abc92f4a514f34224a181ed568a' http://client.rhelbox.com:8080/v1/AUTH_myvolume/c1
-
- * About to connect() to client.rhelbox.com port 8080 (#0)
- * Trying 192.168.56.101...
- * connected
- * Connected to client.rhelbox.com (192.168.56.101) port 8080 (#0)
- > PUT /v1/AUTH_myvolume/c1 HTTP/1.1
- > User-Agent: curl/7.27.0
- > Host: client.rhelbox.com:8080
- > Accept: */*
- > X-Auth-Token: AUTH_tk083b8abc92f4a514f34224a181ed568a
- >
- < HTTP/1.1 201 Created
- < Content-Length: 0
- < Content-Type: text/html; charset=UTF-8
- < X-Trans-Id: txc420b0ebf9714445900e8-0052418863
- < Date: Tue, 24 Sep 2013 12:41:07 GMT
- <
- * Connection #0 to host client.rhelbox.com left intact
- * Closing connection #0
-
-####GET a container listing
-> curl -v -X GET -H 'X-Auth-Token: AUTH_tk083b8abc92f4a514f34224a181ed568a' http://client.rhelbox.com:8080/v1/AUTH_myvolume
-
- * About to connect() to client.rhelbox.com port 8080 (#0)
- * Trying 192.168.56.101...
- * connected
- * Connected to client.rhelbox.com (192.168.56.101) port 8080 (#0)
- > GET /v1/AUTH_myvolume HTTP/1.1
- > User-Agent: curl/7.27.0
- > Host: client.rhelbox.com:8080
- > Accept: */*
- > X-Auth-Token: AUTH_tk083b8abc92f4a514f34224a181ed568a
- >
- < HTTP/1.1 200 OK
- < Content-Length: 3
- < X-Account-Container-Count: 0
- < Accept-Ranges: bytes
- < X-Account-Object-Count: 0
- < X-Bytes-Used: 0
- < X-Timestamp: 1379997117.09468
- < X-Object-Count: 0
- < X-Account-Bytes-Used: 0
- < X-Type: Account
- < Content-Type: text/plain; charset=utf-8
- < X-Container-Count: 0
- < X-Trans-Id: tx89826736a1ab4d6aae6e3-00524188dc
- < Date: Tue, 24 Sep 2013 12:43:08 GMT
- <
- c1
- * Connection #0 to host client.rhelbox.com left intact
- * Closing connection #0
-
-####PUT an object in container
-> curl -v -X PUT -H 'X-Auth-Token: AUTH_tk083b8abc92f4a514f34224a181ed568a' http://client.rhelbox.com:8080/v1/AUTH_myvolume/c1/object1 -d'Hello world'
-
- * About to connect() to client.rhelbox.com port 8080 (#0)
- * Trying 192.168.56.101...
- * connected
- * Connected to client.rhelbox.com (192.168.56.101) port 8080 (#0)
- > PUT /v1/AUTH_myvolume/c1/object1 HTTP/1.1
- > User-Agent: curl/7.27.0
- > Host: client.rhelbox.com:8080
- > Accept: */*
- > X-Auth-Token: AUTH_tk083b8abc92f4a514f34224a181ed568a
- > Content-Length: 11
- > Content-Type: application/x-www-form-urlencoded
- >
- * upload completely sent off: 11 out of 11 bytes
- < HTTP/1.1 201 Created
- < Last-Modified: Wed, 25 Sep 2013 06:08:00 GMT
- < Content-Length: 0
- < Etag: 3e25960a79dbc69b674cd4ec67a72c62
- < Content-Type: text/html; charset=UTF-8
- < X-Trans-Id: tx01f1b5a430cf4af3897be-0052427dc0
- < Date: Wed, 25 Sep 2013 06:08:01 GMT
- <
- * Connection #0 to host client.rhelbox.com left intact
- * Closing connection #0
-
-####Give permission to jsmith to list and download objects from c1 container
-> curl -v -X POST -H 'X-Auth-Token: AUTH_tk083b8abc92f4a514f34224a181ed568a' -H 'X-Container-Read: jsmith' http://client.rhelbox.com:8080/v1/AUTH_myvolume/c1
-
- * About to connect() to client.rhelbox.com port 8080 (#0)
- * Trying 192.168.56.101...
- * connected
- * Connected to client.rhelbox.com (192.168.56.101) port 8080 (#0)
- > POST /v1/AUTH_myvolume/c1 HTTP/1.1
- > User-Agent: curl/7.27.0
- > Host: client.rhelbox.com:8080
- > Accept: */*
- > X-Auth-Token: AUTH_tk083b8abc92f4a514f34224a181ed568a
- > X-Container-Read: jsmith
- >
- < HTTP/1.1 204 No Content
- < Content-Length: 0
- < Content-Type: text/html; charset=UTF-8
- < X-Trans-Id: txcedea3e2557d463eb591d-0052427f60
- < Date: Wed, 25 Sep 2013 06:14:56 GMT
- <
- * Connection #0 to host client.rhelbox.com left intact
- * Closing connection #0
-
-####Access container as jsmith
-
-> kinit jsmith
-
-Get token for jsmith
-> curl -v -u : --negotiate --location-trusted http://client.rhelbox.com:8080/auth/v1.0
-
- * About to connect() to client.rhelbox.com port 8080 (#0)
- * Trying 192.168.56.101...
- * connected
- * Connected to client.rhelbox.com (192.168.56.101) port 8080 (#0)
- > GET /auth/v1.0 HTTP/1.1
- > User-Agent: curl/7.27.0
- > Host: client.rhelbox.com:8080
- > Accept: */*
- >
- < HTTP/1.1 303 See Other
- < Content-Type: text/html; charset=UTF-8
- < Location: http://client.rhelbox.com/cgi-bin/swift-auth
- < Content-Length: 0
- < X-Trans-Id: txf51e1bf7f8c5496f8cc93-005242800b
- < Date: Wed, 25 Sep 2013 06:17:47 GMT
- <
- * Connection #0 to host client.rhelbox.com left intact
- * Issue another request to this URL: 'http://client.rhelbox.com/cgi-bin/swift-auth'
- * About to connect() to client.rhelbox.com port 80 (#1)
- * Trying 192.168.56.101...
- * connected
- * Connected to client.rhelbox.com (192.168.56.101) port 80 (#1)
- > GET /cgi-bin/swift-auth HTTP/1.1
- > User-Agent: curl/7.27.0
- > Host: client.rhelbox.com
- > Accept: */*
- >
- < HTTP/1.1 401 Unauthorized
- < Date: Wed, 25 Sep 2013 06:17:47 GMT
- < Server: Apache/2.4.6 (Fedora) mod_auth_kerb/5.4
- < WWW-Authenticate: Negotiate
- < WWW-Authenticate: Basic realm="Swift Authentication"
- < Content-Length: 381
- < Content-Type: text/html; charset=iso-8859-1
- <
- * Ignoring the response-body
- * Connection #1 to host client.rhelbox.com left intact
- * Issue another request to this URL: 'http://client.rhelbox.com/cgi-bin/swift-auth'
- * Re-using existing connection! (#1) with host (nil)
- * Connected to (nil) (192.168.56.101) port 80 (#1)
- * Server auth using GSS-Negotiate with user ''
- > GET /cgi-bin/swift-auth HTTP/1.1
- > Authorization: Negotiate YIICWAYJKoZIhvcSAQICAQBuggJHMIICQ6ADAgEFoQMCAQ6iBwMFACAAAACjggFbYYIBVzCCAVOgAwIBBaENGwtSSEVMQk9YLkNPTaIlMCOgAwIBA6EcMBobBEhUVFAbEmNsaWVudC5yaGVsYm94LmNvbaOCARQwggEQoAMCARKhAwIBAaKCAQIEgf/+3OaXYCSEjcsjU3t3lOLcYG84GBP9Kj9YTHc7yVMlcam4ivCwMqCkzxgvNo2E3a5KSWyFwngeX4b/QFbCKPXA4sfBibZRkeMk5gr2f0MLI3gWEAIYq7bJLre04bnkD2F0MzijPJrOLIx1KmFe08UGWCEmnG2uj07lvIR1RwV/7dMM4J1B+KKvDVKA0LxahwPIpx8oOON2yMGcstrBAHBBk5pmpt1Gg9Lh7xdNPsjP0IfI5Q0zkGCRBKpvpXymP1lQpQXlHbqkdBYOmG4+p/R+vIosO4ui1G6GWE9t71h3AqW61CcCj3/oOjZsG56k8HMSNk/+3mfUTP86nzLRGkekgc4wgcugAwIBEqKBwwSBwPsG9nGloEnOsA1abP4R1/yUDcikjjwKiacvZ+cu7bWEzu3L376k08U8C2YIClyUJy3Grt68LxhnfZ65VCZ5J5IOLiXOJnHBIoJ1L4GMYp4EgZzHvI7R3U3DApMzNWZwc1MsSF5UGhmLwxSevDLetJHjgKzKNteRyVN/8CFgjSBEjGSN1Qgy1RZHuQR9d3JHPczONZ4+ZgStfy+I1m2IUIgW3+4JGFVafHiBQVwSWRNfdXFgI3wBz7slntd7r3qMWA==
- > User-Agent: curl/7.27.0
- > Host: client.rhelbox.com
- > Accept: */*
- >
- < HTTP/1.1 200 OK
- < Date: Wed, 25 Sep 2013 06:17:47 GMT
- < Server: Apache/2.4.6 (Fedora) mod_auth_kerb/5.4
- < WWW-Authenticate: Negotiate YIGYBgkqhkiG9xIBAgICAG+BiDCBhaADAgEFoQMCAQ+ieTB3oAMCARKicARuH2YpjFrtgIhGr5nO7gh/21EvGH9tayRo5A3pw5pxD1B1036ePLG/x98OdMrSflse5s8ttz8FmvRphCFJa8kfYtnWULgoFLF2F2a1zBdSo2oCA0R05YFwArNhkg6ou5o7wWZkERHK33CKlhudSj8=
- < X-Auth-Token: AUTH_tkb5a20eb8207a819e76619431c8410447
- < X-Debug-Remote-User: jsmith
- < X-Debug-Groups: jsmith
- < X-Debug-Token-Life: 86400s
- < X-Debug-Token-Expires: Thu Sep 26 11:47:47 2013
- < Content-Length: 0
- < Content-Type: text/html; charset=UTF-8
- <
- * Connection #1 to host (nil) left intact
- * Closing connection #0
- * Closing connection #1
-
-List the container using authentication token for jsmith:
-> curl -v -X GET -H 'X-Auth-Token: AUTH_tkb5a20eb8207a819e76619431c8410447' http://client.rhelbox.com:8080/v1/AUTH_myvolume/c1
-
- * About to connect() to client.rhelbox.com port 8080 (#0)
- * Trying 192.168.56.101...
- * connected
- * Connected to client.rhelbox.com (192.168.56.101) port 8080 (#0)
- > GET /v1/AUTH_myvolume/c1 HTTP/1.1
- > User-Agent: curl/7.27.0
- > Host: client.rhelbox.com:8080
- > Accept: */*
- > X-Auth-Token: AUTH_tkb5a20eb8207a819e76619431c8410447
- >
- < HTTP/1.1 200 OK
- < Content-Length: 8
- < X-Container-Object-Count: 0
- < Accept-Ranges: bytes
- < X-Timestamp: 1
- < X-Container-Bytes-Used: 0
- < Content-Type: text/plain; charset=utf-8
- < X-Trans-Id: tx575215929c654d9f9f284-00524280a4
- < Date: Wed, 25 Sep 2013 06:20:20 GMT
- <
- object1
- * Connection #0 to host client.rhelbox.com left intact
- * Closing connection #0
-
-Downloading the object as jsmith:
-> curl -v -X GET -H 'X-Auth-Token: AUTH_tkb5a20eb8207a819e76619431c8410447' http://client.rhelbox.com:8080/v1/AUTH_myvolume/c1/object1
-
- * About to connect() to client.rhelbox.com port 8080 (#0)
- * Trying 192.168.56.101...
- * connected
- * Connected to client.rhelbox.com (192.168.56.101) port 8080 (#0)
- > GET /v1/AUTH_myvolume/c1/object1 HTTP/1.1
- > User-Agent: curl/7.27.0
- > Host: client.rhelbox.com:8080
- > Accept: */*
- > X-Auth-Token: AUTH_tkb5a20eb8207a819e76619431c8410447
- >
- < HTTP/1.1 200 OK
- < Content-Length: 11
- < Accept-Ranges: bytes
- < Last-Modified: Wed, 25 Sep 2013 06:08:00 GMT
- < Etag: 3e25960a79dbc69b674cd4ec67a72c62
- < X-Timestamp: 1380089280.98829
- < Content-Type: application/x-www-form-urlencoded
- < X-Trans-Id: tx19b5cc3847854f40a6ca8-00524281aa
- < Date: Wed, 25 Sep 2013 06:24:42 GMT
- <
- * Connection #0 to host client.rhelbox.com left intact
- Hello world* Closing connection #0
-
-For curl to follow the redirect, you need to specify additional
-options. With these, and with a current Kerberos ticket, you should
-get the Kerberos user's cached authentication token, or a new one if
-the previous token has expired.
-
-> curl -v -u : --negotiate --location-trusted -X GET http://client.rhelbox.com:8080/v1/AUTH_myvolume/c1/object1
-
-The --negotiate option is for curl to perform Kerberos authentication and
---location-trusted is for curl to follow the redirect.
-
-[auth_kerb_module Configuration]: http://modauthkerb.sourceforge.net/configure.html
-
-
-#### Get an authentication token when auth_mode=passive:
-> curl -v -H 'X-Auth-User: test:auth_admin' -H 'X-Auth-Key: Redhat*123' http://127.0.0.1:8080/auth/v1.0
-
-**NOTE**: X-Storage-Url response header can be returned only in passive mode.
-
-<a name="config-swiftkerbauth" />
-##Configurable Parameters
-
-The kerbauth filter section in **/etc/swift/proxy-server.conf** looks something
-like this:
-
- [filter:kerbauth]
- use = egg:swiftkerbauth#kerbauth
- ext_authentication_url = http://client.rhelbox.com/cgi-bin/swift-auth
- auth_method = active
- token_life = 86400
- debug_headers = yes
- realm_name = RHELBOX.COM
-
-Of all the options listed above, specifying **ext\_authentication\_url** is
-mandatory. The rest of the options are optional and have default values.
-
-#### ext\_authentication\_url
-A URL specifying location of the swift-auth CGI script. Avoid using IP address.
-Default value: None
-
-#### token_life
-After how many seconds the cached information about an authentication token is
-discarded.
-Default value: 86400
-
-#### debug_headers
-When turned on, the response headers sent to the user will contain additional
-debug information apart from the auth token.
-Default value: yes
-
-#### auth_method
-Set this to **"active"** when you want to allow access **only to clients
-residing inside the domain**. In this mode, authentication is performed by
-mod\_auth\_kerb using the Kerberos ticket bundled with the client request.
-No username and password have to be specified to get a token.
-Set this to **"passive"** when you want to allow access to clients residing
-outside the domain. In this mode, authentication is performed by gleaning
-username and password from request headers (X-Auth-User and X-Auth-Key) and
-running kinit command against it.
-Default value: passive
-
-#### realm_name
-This is applicable only when the auth_method=passive. This option specifies
-realm name if storage server belongs to more than one realm and realm name is not
-part of the username specified in X-Auth-User header.
-
-<a name="swfunctest" />
-##Functional tests for SwiftkerbAuth
-
-Functional tests to be run on the storage node after SwiftKerbAuth is setup using
-either IPA server or Windows AD. The gluster-swift/doc/markdown/swiftkerbauth
-directory contains the SwiftkerbAuth setup documents. There are two modes of
-working with SwiftKerbAuth. 'PASSIVE' mode indicates the client is outside the
-domain configured using SwiftKerbAuth. Client provides the 'Username' and
-'Password' while invoking a command. SwiftKerbAuth auth filter code then
-would get the ticket granting ticket from AD server or IPA server.
-In 'ACTIVE' mode of SwiftKerbAuth, User is already logged into storage node using
-its kerberos credentials. That user is authenticated across AD/IPA server.
-
-In PASSIVE mode all the generic functional tests are run. ACTIVE mode has a
-different way of acquiring Ticket Granting Ticket. And hence the different
-framework of functional tests there.
-
-The accounts, users, passwords must be prepared on AD/IPA server as per
-mentioned in test/functional_auth/swiftkerbauth/conf/test.conf
-
-Command to invoke SwiftKerbAuth functional tests is
-> $tox -e swfunctest
-
-This would run both ACTIVE and PASSIVE mode functional test cases.
diff --git a/etc/object-expirer.conf-gluster b/etc/object-expirer.conf-gluster
index 4449ee2..55c4fbf 100644
--- a/etc/object-expirer.conf-gluster
+++ b/etc/object-expirer.conf-gluster
@@ -1,18 +1,41 @@
-#TODO: Add documentation to explain various options
-#For now, refer: https://github.com/openstack/swift/blob/master/etc/object-expirer.conf-sample
-
[DEFAULT]
+user = root
[object-expirer]
user = root
log_facility = LOG_LOCAL2
-log_level = DEBUG
+log_level = INFO
+
# The following parameters are used by object-expirer and needs to be same
# across all conf files!
auto_create_account_prefix = gs
expiring_objects_account_name = expiring
-interval = 30
+# The swift-object-expirer daemon will run every 'interval' number of seconds
+# interval = 300
+
+# Emit a log line report of the progress so far every 'report_interval'
+# number of seconds.
+# report_interval = 300
+
+# concurrency is the level of concurrency to use to do the work, this value
+# must be set to at least 1
+# concurrency = 1
+
+# processes is how many parts to divide the work into, one part per process
+# that will be doing the work
+# processes set 0 means that a single process will be doing all the work
+# processes can also be specified on the command line and will override the
+# config value
+# processes = 0
+
+# process is which of the parts a particular process will work on
+# process can also be specified on the command line and will overide the config
+# value
+# process is "zero based", if you want to use 3 processes, you should run
+# processes with process set to 0, 1, and 2
+# process = 0
+
[pipeline:main]
pipeline = catch_errors cache proxy-server
diff --git a/functests.sh b/functests.sh
deleted file mode 100755
index 9797f58..0000000
--- a/functests.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/bash
-
-SRC_DIR=$(dirname $0)
-
-cd ${SRC_DIR}/test/functional
-nosetests --exe $@
-func1=$?
-cd -
-
-cd ${SRC_DIR}/test/functionalnosetests
-nosetests --exe $@
-func2=$?
-cd -
-
-exit $((func1 + func2))
diff --git a/gluster/swift/__init__.py b/gluster/swift/__init__.py
index 17f2fcf..555581a 100644
--- a/gluster/swift/__init__.py
+++ b/gluster/swift/__init__.py
@@ -42,9 +42,9 @@ class PkgInfo(object):
return '%s-dev' % (self.canonical_version,)
-###
-### Change the Package version here
-###
-_pkginfo = PkgInfo('1.13.0', '0', 'gluster_swift', False)
+#
+# Change the Package version here
+#
+_pkginfo = PkgInfo('1.13.1', '2', 'gluster_swift', False)
__version__ = _pkginfo.pretty_version
__canonical_version__ = _pkginfo.canonical_version
diff --git a/gluster/swift/common/DiskDir.py b/gluster/swift/common/DiskDir.py
index 0a91009..6112709 100644
--- a/gluster/swift/common/DiskDir.py
+++ b/gluster/swift/common/DiskDir.py
@@ -26,7 +26,10 @@ from gluster.swift.common.utils import validate_account, validate_container, \
X_CONTENT_LENGTH, X_TIMESTAMP, X_PUT_TIMESTAMP, X_ETAG, X_OBJECTS_COUNT, \
X_BYTES_USED, X_CONTAINER_COUNT, DIR_TYPE, rmobjdir, dir_is_object
from gluster.swift.common import Glusterfs
-from gluster.swift.common.exceptions import FileOrDirNotFoundError
+from gluster.swift.common.exceptions import FileOrDirNotFoundError, \
+ GlusterFileSystemIOError
+from swift.common.constraints import MAX_META_COUNT, MAX_META_OVERALL_SIZE
+from swift.common.swob import HTTPBadRequest
DATADIR = 'containers'
@@ -176,7 +179,12 @@ class DiskCommon(object):
def _dir_exists_read_metadata(self):
self._dir_exists = do_exists(self.datadir)
if self._dir_exists:
- self.metadata = _read_metadata(self.datadir)
+ try:
+ self.metadata = _read_metadata(self.datadir)
+ except GlusterFileSystemIOError as err:
+ if err.errno in (errno.ENOENT, errno.ESTALE):
+ return False
+ raise
return self._dir_exists
def is_deleted(self):
@@ -195,12 +203,41 @@ class DiskCommon(object):
except FileOrDirNotFoundError:
return True
- def update_metadata(self, metadata):
+ def validate_metadata(self, metadata):
+ """
+ Validates that metadata falls within acceptable limits.
+
+ :param metadata: to be validated
+ :raises: HTTPBadRequest if MAX_META_COUNT or MAX_META_OVERALL_SIZE
+ is exceeded
+ """
+ meta_count = 0
+ meta_size = 0
+ for key, (value, timestamp) in metadata.iteritems():
+ key = key.lower()
+ if value != '' and (key.startswith('x-account-meta') or
+ key.startswith('x-container-meta')):
+ prefix = 'x-account-meta-'
+ if key.startswith('x-container-meta-'):
+ prefix = 'x-container-meta-'
+ key = key[len(prefix):]
+ meta_count = meta_count + 1
+ meta_size = meta_size + len(key) + len(value)
+ if meta_count > MAX_META_COUNT:
+ raise HTTPBadRequest('Too many metadata items; max %d'
+ % MAX_META_COUNT)
+ if meta_size > MAX_META_OVERALL_SIZE:
+ raise HTTPBadRequest('Total metadata too large; max %d'
+ % MAX_META_OVERALL_SIZE)
+
+ def update_metadata(self, metadata, validate_metadata=False):
assert self.metadata, "Valid container/account metadata should have " \
"been created by now"
if metadata:
new_metadata = self.metadata.copy()
new_metadata.update(metadata)
+ if validate_metadata:
+ self.validate_metadata(new_metadata)
if new_metadata != self.metadata:
write_metadata(self.datadir, new_metadata)
self.metadata = new_metadata
@@ -362,7 +399,15 @@ class DiskDir(DiskCommon):
count = 0
for obj in objects:
obj_path = os.path.join(self.datadir, obj)
- metadata = read_metadata(obj_path)
+ try:
+ metadata = read_metadata(obj_path)
+ except GlusterFileSystemIOError as err:
+ if err.errno in (errno.ENOENT, errno.ESTALE):
+ # obj might have been deleted by another process
+ # since the objects list was originally built
+ continue
+ else:
+ raise err
if not metadata or not validate_object(metadata):
if delimiter == '/' and obj_path[-1] == delimiter:
clean_obj_path = obj_path[:-1]
@@ -373,7 +418,7 @@ class DiskDir(DiskCommon):
except OSError as e:
# FIXME - total hack to get upstream swift ported unit
# test cases working for now.
- if e.errno != errno.ENOENT:
+ if e.errno not in (errno.ENOENT, errno.ESTALE):
raise
if not Glusterfs._implicit_dir_objects and metadata \
and metadata[X_CONTENT_TYPE] == DIR_TYPE \
@@ -450,7 +495,7 @@ class DiskDir(DiskCommon):
# If we create it, ensure we own it.
do_chown(self.datadir, self.uid, self.gid)
metadata = get_container_metadata(self.datadir)
- metadata[X_TIMESTAMP] = timestamp
+ metadata[X_TIMESTAMP] = (timestamp, 0)
write_metadata(self.datadir, metadata)
self.metadata = metadata
self._dir_exists = True
@@ -562,7 +607,7 @@ class DiskAccount(DiskCommon):
:param metadata: Metadata to write.
"""
metadata = get_account_metadata(self.datadir)
- metadata[X_TIMESTAMP] = timestamp
+ metadata[X_TIMESTAMP] = (timestamp, 0)
write_metadata(self.datadir, metadata)
self.metadata = metadata
@@ -672,7 +717,7 @@ class DiskAccount(DiskCommon):
except OSError as e:
# FIXME - total hack to get upstream swift ported unit
# test cases working for now.
- if e.errno != errno.ENOENT:
+ if e.errno not in (errno.ENOENT, errno.ESTALE):
raise
if metadata:
list_item.append(metadata[X_OBJECTS_COUNT][0])
diff --git a/gluster/swift/common/Glusterfs.py b/gluster/swift/common/Glusterfs.py
index 5d2cab1..0098bff 100644
--- a/gluster/swift/common/Glusterfs.py
+++ b/gluster/swift/common/Glusterfs.py
@@ -37,7 +37,6 @@ _allow_mount_per_server = False
_implicit_dir_objects = False
_container_update_object_count = False
_account_update_container_count = False
-_ignore_unsupported_headers = False
if _fs_conf.read(os.path.join(SWIFT_DIR, 'fs.conf')):
try:
@@ -98,18 +97,6 @@ if _fs_conf.read(os.path.join(SWIFT_DIR, 'fs.conf')):
except (NoSectionError, NoOptionError):
pass
- # -- Hidden configuration option --
- # Ignore unsupported headers and allow them in a request without
- # returning a 400-BadRequest. This setting can be set to
- # allow unsupported headers such as X-Delete-At and
- # X-Delete-After even though they will not be used.
- try:
- _ignore_unsupported_headers = \
- _fs_conf.get('DEFAULT',
- 'ignore_unsupported_headers',
- "no") in TRUE_VALUES
- except (NoSectionError, NoOptionError):
- pass
NAME = 'glusterfs'
diff --git a/gluster/swift/common/constraints.py b/gluster/swift/common/constraints.py
index 80616f2..7979b43 100644
--- a/gluster/swift/common/constraints.py
+++ b/gluster/swift/common/constraints.py
@@ -14,16 +14,12 @@
# limitations under the License.
import os
-try:
- from webob.exc import HTTPBadRequest
-except ImportError:
- from swift.common.swob import HTTPBadRequest
+from swift.common.swob import HTTPBadRequest
import swift.common.constraints
import swift.common.ring as _ring
from gluster.swift.common import Glusterfs, ring
MAX_OBJECT_NAME_COMPONENT_LENGTH = 255
-UNSUPPORTED_HEADERS = []
def set_object_name_component_length(len=None):
@@ -56,40 +52,8 @@ def validate_obj_name_component(obj):
return ''
-def validate_headers(req):
- """
- Validate client header requests
- :param req: Http request
- """
- if not Glusterfs._ignore_unsupported_headers:
- for unsupported_header in UNSUPPORTED_HEADERS:
- if unsupported_header in req.headers:
- return '%s headers are not supported' \
- % ','.join(UNSUPPORTED_HEADERS)
- return ''
-
# Save the original check object creation
__check_object_creation = swift.common.constraints.check_object_creation
-__check_metadata = swift.common.constraints.check_metadata
-
-
-def gluster_check_metadata(req, target_type, POST=True):
- """
- :param req: HTTP request object
- :param target_type: Value from POST passed to __check_metadata
- :param POST: Only call __check_metadata on POST since Swift only
- calls check_metadata on POSTs.
- """
- ret = None
- if POST:
- ret = __check_metadata(req, target_type)
- if ret is None:
- bdy = validate_headers(req)
- if bdy:
- ret = HTTPBadRequest(body=bdy,
- request=req,
- content_type='text/plain')
- return ret
# Define our new one which invokes the original
@@ -119,14 +83,11 @@ def gluster_check_object_creation(req, object_name):
ret = HTTPBadRequest(body=bdy,
request=req,
content_type='text/plain')
- if ret is None:
- ret = gluster_check_metadata(req, 'object', POST=False)
return ret
# Replace the original checks with ours
swift.common.constraints.check_object_creation = gluster_check_object_creation
-swift.common.constraints.check_metadata = gluster_check_metadata
# Replace the original check mount with ours
swift.common.constraints.check_mount = Glusterfs.mount
diff --git a/gluster/swift/common/fs_utils.py b/gluster/swift/common/fs_utils.py
index 9f698df..e0fa7ce 100644
--- a/gluster/swift/common/fs_utils.py
+++ b/gluster/swift/common/fs_utils.py
@@ -162,7 +162,7 @@ def dir_empty(path):
files = do_listdir(path)
return not files
except GlusterFileSystemOSError as err:
- if err.errno == errno.ENOENT:
+ if err.errno in (errno.ENOENT, errno.ESTALE):
raise FileOrDirNotFoundError()
if err.errno == errno.ENOTDIR:
raise NotDirectoryError()
@@ -210,7 +210,7 @@ def do_stat(path):
serr = err
sleep(random.uniform(0.001, 0.005))
continue
- if err.errno == errno.ENOENT:
+ if err.errno in (errno.ENOENT, errno.ESTALE):
stats = None
else:
raise GlusterFileSystemOSError(
@@ -268,10 +268,10 @@ def do_unlink(path, log=True):
try:
os.unlink(path)
except OSError as err:
- if err.errno != errno.ENOENT:
+ if err.errno not in (errno.ENOENT, errno.ESTALE):
raise GlusterFileSystemOSError(
err.errno, '%s, os.unlink("%s")' % (err.strerror, path))
- elif log:
+ else:
logging.warn("fs_utils: os.unlink failed on non-existent path: %s",
path)
diff --git a/gluster/swift/common/middleware/gswauth/swauth/middleware.py b/gluster/swift/common/middleware/gswauth/swauth/middleware.py
index 314eedb..cdcc638 100644
--- a/gluster/swift/common/middleware/gswauth/swauth/middleware.py
+++ b/gluster/swift/common/middleware/gswauth/swauth/middleware.py
@@ -241,7 +241,7 @@ class Swauth(object):
version, rest = split_path(env.get('PATH_INFO', ''),
1, 2, True)
except ValueError:
- version, rest = None, None
+ rest = None
if rest and rest.startswith(self.reseller_prefix):
# Handle anonymous access to accounts I'm the definitive
# auth for.
@@ -693,7 +693,7 @@ class Swauth(object):
return HTTPBadRequest(request=req)
try:
new_services = json.loads(req.body)
- except ValueError, err:
+ except ValueError as err:
return HTTPBadRequest(body=str(err))
# Get the current services information
path = quote('/v1/%s/%s/.services' % (self.auth_account, account))
@@ -1405,7 +1405,7 @@ class Swauth(object):
memcache_key,
(self.itoken_expires,
'%s,.reseller_admin,%s' % (self.metadata_volume,
- self.auth_account)),
+ self.auth_account)),
timeout=self.token_life)
return self.itoken
@@ -1589,19 +1589,20 @@ class Swauth(object):
if getattr(req, 'client_disconnect', False) or \
getattr(response, 'client_disconnect', False):
status_int = 499
- self.logger.info(
- ' '.join(quote(str(x)) for x in (client or '-',
- req.remote_addr or '-', strftime('%d/%b/%Y/%H/%M/%S', gmtime()),
- req.method, the_request, req.environ['SERVER_PROTOCOL'],
- status_int, req.referer or '-', req.user_agent or '-',
- req.headers.get(
- 'x-auth-token',
- req.headers.get('x-auth-admin-user', '-')),
- getattr(req, 'bytes_transferred', 0) or '-',
- getattr(response, 'bytes_transferred', 0) or '-',
- req.headers.get('etag', '-'),
- req.headers.get('x-trans-id', '-'), logged_headers or '-',
- trans_time)))
+ self.logger.info(' '.join(quote(str(x)) for x in
+ (client or '-',
+ req.remote_addr or '-', strftime('%d/%b/%Y/%H/%M/%S',
+ gmtime()),
+ req.method, the_request,
+ req.environ['SERVER_PROTOCOL'], status_int,
+ req.referer or '-', req.user_agent or '-',
+ req.headers.get('x-auth-token', req.headers.get(
+ 'x-auth-admin-user', '-')),
+ getattr(req, 'bytes_transferred', 0) or '-',
+ getattr(response, 'bytes_transferred', 0) or '-',
+ req.headers.get('etag', '-'),
+ req.headers.get('x-trans-id', '-'), logged_headers
+ or '-', trans_time)))
def filter_factory(global_conf, **local_conf):
diff --git a/gluster/swift/common/middleware/gswauth/test_swauth/__init__.py b/gluster/swift/common/middleware/gswauth/test_swauth/__init__.py
deleted file mode 100644
index f53bc5a..0000000
--- a/gluster/swift/common/middleware/gswauth/test_swauth/__init__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-# See http://code.google.com/p/python-nose/issues/detail?id=373
-# The code below enables nosetests to work with i18n _() blocks
-
-import __builtin__
-
-setattr(__builtin__, '_', lambda x: x)
diff --git a/gluster/swift/common/middleware/gswauth/test_swauth/unit/test_authtypes.py b/gluster/swift/common/middleware/gswauth/test_swauth/unit/test_authtypes.py
deleted file mode 100644
index d9b7b55..0000000
--- a/gluster/swift/common/middleware/gswauth/test_swauth/unit/test_authtypes.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-# implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# Pablo Llopis 2011
-
-import unittest
-from swauth import authtypes
-
-
-class TestPlaintext(unittest.TestCase):
-
- def setUp(self):
- self.auth_encoder = authtypes.Plaintext()
-
- def test_plaintext_encode(self):
- enc_key = self.auth_encoder.encode('keystring')
- self.assertEquals('plaintext:keystring', enc_key)
-
- def test_plaintext_valid_match(self):
- creds = 'plaintext:keystring'
- match = self.auth_encoder.match('keystring', creds)
- self.assertEquals(match, True)
-
- def test_plaintext_invalid_match(self):
- creds = 'plaintext:other-keystring'
- match = self.auth_encoder.match('keystring', creds)
- self.assertEquals(match, False)
-
-
-class TestSha1(unittest.TestCase):
-
- def setUp(self):
- self.auth_encoder = authtypes.Sha1()
- self.auth_encoder.salt = 'salt'
-
- def test_sha1_encode(self):
- enc_key = self.auth_encoder.encode('keystring')
- self.assertEquals('sha1:salt$d50dc700c296e23ce5b41f7431a0e01f69010f06',
- enc_key)
-
- def test_sha1_valid_match(self):
- creds = 'sha1:salt$d50dc700c296e23ce5b41f7431a0e01f69010f06'
- match = self.auth_encoder.match('keystring', creds)
- self.assertEquals(match, True)
-
- def test_sha1_invalid_match(self):
- creds = 'sha1:salt$deadbabedeadbabedeadbabec0ffeebadc0ffeee'
- match = self.auth_encoder.match('keystring', creds)
- self.assertEquals(match, False)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/gluster/swift/common/middleware/gswauth/test_swauth/unit/test_middleware.py b/gluster/swift/common/middleware/gswauth/test_swauth/unit/test_middleware.py
deleted file mode 100644
index 62259ff..0000000
--- a/gluster/swift/common/middleware/gswauth/test_swauth/unit/test_middleware.py
+++ /dev/null
@@ -1,4519 +0,0 @@
-# Copyright (c) 2010-2011 OpenStack, LLC.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-# implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-try:
- import simplejson as json
-except ImportError:
- import json
-import unittest
-from contextlib import contextmanager
-from time import time
-
-from swift.common.swob import Request, Response
-
-from swauth import middleware as auth
-from swauth.authtypes import MAX_TOKEN_LENGTH
-
-
-DEFAULT_TOKEN_LIFE = 86400
-MAX_TOKEN_LIFE = 100000
-
-
-class FakeMemcache(object):
-
- def __init__(self):
- self.store = {}
-
- def get(self, key):
- return self.store.get(key)
-
- def set(self, key, value, timeout=0, time=0):
- self.store[key] = value
- return True
-
- def incr(self, key, timeout=0, time=0):
- self.store[key] = self.store.setdefault(key, 0) + 1
- return self.store[key]
-
- @contextmanager
- def soft_lock(self, key, timeout=0, retries=5, time=0):
- yield True
-
- def delete(self, key):
- try:
- del self.store[key]
- except Exception:
- pass
- return True
-
-
-class FakeApp(object):
-
- def __init__(
- self, status_headers_body_iter=None, acl=None, sync_key=None):
- self.calls = 0
- self.status_headers_body_iter = status_headers_body_iter
- if not self.status_headers_body_iter:
- self.status_headers_body_iter = iter(
- [('404 Not Found', {}, '')])
- self.acl = acl
- self.sync_key = sync_key
-
- def __call__(self, env, start_response):
- self.calls += 1
- self.request = Request.blank('', environ=env)
- if self.acl:
- self.request.acl = self.acl
- if self.sync_key:
- self.request.environ[
- 'swift_sync_key'] = self.sync_key
- if 'swift.authorize' in env:
- resp = env['swift.authorize'](self.request)
- if resp:
- return resp(env, start_response)
- status, headers, body = self.status_headers_body_iter.next(
- )
- return Response(status=status, headers=headers,
- body=body)(env, start_response)
-
-
-class FakeConn(object):
-
- def __init__(self, status_headers_body_iter=None):
- self.calls = 0
- self.status_headers_body_iter = status_headers_body_iter
- if not self.status_headers_body_iter:
- self.status_headers_body_iter = iter(
- [('404 Not Found', {}, '')])
-
- def request(self, method, path, headers):
- self.calls += 1
- self.request_path = path
- self.status, self.headers, self.body = \
- self.status_headers_body_iter.next()
- self.status, self.reason = self.status.split(' ', 1)
- self.status = int(self.status)
-
- def getresponse(self):
- return self
-
- def read(self):
- body = self.body
- self.body = ''
- return body
-
-
-class TestAuth(unittest.TestCase):
-
- def setUp(self):
- self.test_auth = \
- auth.filter_factory({
- 'super_admin_key': 'supertest',
- 'token_life': str(DEFAULT_TOKEN_LIFE),
- 'max_token_life': str(MAX_TOKEN_LIFE)})(FakeApp())
-
- def test_super_admin_key_not_required(self):
- auth.filter_factory({})(FakeApp())
-
- def test_reseller_prefix_init(self):
- app = FakeApp()
- ath = auth.filter_factory(
- {'super_admin_key': 'supertest'})(app)
- self.assertEquals(ath.reseller_prefix, 'AUTH_')
- ath = auth.filter_factory(
- {'super_admin_key': 'supertest',
- 'reseller_prefix': 'TEST'})(app)
- self.assertEquals(ath.reseller_prefix, 'TEST_')
- ath = auth.filter_factory(
- {'super_admin_key': 'supertest',
- 'reseller_prefix': 'TEST_'})(app)
- self.assertEquals(ath.reseller_prefix, 'TEST_')
-
- def test_auth_prefix_init(self):
- app = FakeApp()
- ath = auth.filter_factory(
- {'super_admin_key': 'supertest'})(app)
- self.assertEquals(ath.auth_prefix, '/auth/')
- ath = auth.filter_factory(
- {'super_admin_key': 'supertest',
- 'auth_prefix': ''})(app)
- self.assertEquals(ath.auth_prefix, '/auth/')
- ath = auth.filter_factory(
- {'super_admin_key': 'supertest',
- 'auth_prefix': '/test/'})(app)
- self.assertEquals(ath.auth_prefix, '/test/')
- ath = auth.filter_factory(
- {'super_admin_key': 'supertest',
- 'auth_prefix': '/test'})(app)
- self.assertEquals(ath.auth_prefix, '/test/')
- ath = auth.filter_factory(
- {'super_admin_key': 'supertest',
- 'auth_prefix': 'test/'})(app)
- self.assertEquals(ath.auth_prefix, '/test/')
- ath = auth.filter_factory(
- {'super_admin_key': 'supertest',
- 'auth_prefix': 'test'})(app)
- self.assertEquals(ath.auth_prefix, '/test/')
-
- def test_no_auth_type_init(self):
- app = FakeApp()
- ath = auth.filter_factory({})(app)
- self.assertEquals(ath.auth_type, 'Plaintext')
-
- def test_valid_auth_type_init(self):
- app = FakeApp()
- ath = auth.filter_factory(
- {'auth_type': 'sha1'})(app)
- self.assertEquals(ath.auth_type, 'Sha1')
- ath = auth.filter_factory(
- {'auth_type': 'plaintext'})(app)
- self.assertEquals(ath.auth_type, 'Plaintext')
-
- def test_invalid_auth_type_init(self):
- app = FakeApp()
- exc = None
- try:
- auth.filter_factory(
- {'auth_type': 'NONEXISTANT'})(app)
- except Exception as err:
- exc = err
- self.assertEquals(str(exc),
- 'Invalid auth_type in config file: %s' %
- 'Nonexistant')
-
- def test_default_swift_cluster_init(self):
- app = FakeApp()
- self.assertRaises(Exception, auth.filter_factory({
- 'super_admin_key': 'supertest',
- 'default_swift_cluster': 'local#badscheme://host/path'}), app)
- ath = auth.filter_factory(
- {'super_admin_key': 'supertest'})(app)
- self.assertEquals(ath.default_swift_cluster,
- 'local#http://127.0.0.1:8080/v1')
- ath = auth.filter_factory({
- 'super_admin_key': 'supertest',
- 'default_swift_cluster': 'local#http://host/path'})(app)
- self.assertEquals(ath.default_swift_cluster,
- 'local#http://host/path')
- ath = auth.filter_factory({
- 'super_admin_key': 'supertest',
- 'default_swift_cluster': 'local#https://host/path/'})(app)
- self.assertEquals(ath.dsc_url, 'https://host/path')
- self.assertEquals(ath.dsc_url2, 'https://host/path')
- ath = auth.filter_factory({
- 'super_admin_key': 'supertest',
- 'default_swift_cluster':
- 'local#https://host/path/#http://host2/path2/'})(app)
- self.assertEquals(ath.dsc_url, 'https://host/path')
- self.assertEquals(
- ath.dsc_url2,
- 'http://host2/path2')
-
- def test_top_level_denied(self):
- resp = Request.blank(
- '/').get_response(self.test_auth)
- self.assertEquals(resp.status_int, 401)
-
- def test_anon(self):
- resp = Request.blank(
- '/v1/AUTH_account').get_response(self.test_auth)
- self.assertEquals(resp.status_int, 401)
- self.assertEquals(resp.environ['swift.authorize'],
- self.test_auth.authorize)
-
- def test_auth_deny_non_reseller_prefix(self):
- resp = Request.blank(
- '/v1/BLAH_account',
- headers={'X-Auth-Token': 'BLAH_t'}).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 401)
- self.assertEquals(resp.environ['swift.authorize'],
- self.test_auth.denied_response)
-
- def test_auth_deny_non_reseller_prefix_no_override(
- self):
- fake_authorize = lambda x: Response(
- status='500 Fake')
- resp = Request.blank(
- '/v1/BLAH_account',
- headers={'X-Auth-Token': 'BLAH_t'},
- environ={'swift.authorize': fake_authorize}).get_response(
- self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(resp.environ['swift.authorize'], fake_authorize)
-
- def test_auth_no_reseller_prefix_deny(self):
- # Ensures that when we have no reseller prefix, we don't deny a request
- # outright but set up a denial swift.authorize and pass the request on
- # down the chain.
- local_app = FakeApp()
- local_auth = auth.filter_factory(
- {'super_admin_key': 'supertest',
- 'reseller_prefix': ''})(local_app)
- resp = Request.blank(
- '/v1/account',
- headers={'X-Auth-Token': 't'}).get_response(local_auth)
- self.assertEquals(resp.status_int, 401)
- # one for checking auth, two for request passed
- # along
- self.assertEquals(local_app.calls, 2)
- self.assertEquals(resp.environ['swift.authorize'],
- local_auth.denied_response)
-
- def test_auth_no_reseller_prefix_allow(self):
- # Ensures that when we have no reseller prefix, we can still allow
- # access if our auth server accepts requests
- local_app = FakeApp(iter([
- ('200 Ok', {},
- json.dumps(
- {'account': 'act', 'user': 'act:usr',
- 'account_id': 'AUTH_cfa',
- 'groups': [{'name': 'act:usr'}, {'name': 'act'},
- {'name': '.admin'}],
- 'expires': time() + 60})),
- ('204 No Content', {}, '')]))
- local_auth = auth.filter_factory(
- {'super_admin_key': 'supertest',
- 'reseller_prefix': ''})(local_app)
- resp = Request.blank(
- '/v1/act',
- headers={'X-Auth-Token': 't'}).get_response(local_auth)
- self.assertEquals(resp.status_int, 204)
- self.assertEquals(local_app.calls, 2)
- self.assertEquals(resp.environ['swift.authorize'],
- local_auth.authorize)
-
- def test_auth_no_reseller_prefix_no_token(self):
- # Check that normally we set up a call back to our
- # authorize.
- local_auth = \
- auth.filter_factory(
- {'super_admin_key': 'supertest',
- 'reseller_prefix': ''})(FakeApp(iter([])))
- resp = Request.blank(
- '/v1/account').get_response(
- local_auth)
- self.assertEquals(resp.status_int, 401)
- self.assertEquals(
- resp.environ['swift.authorize'], local_auth.authorize)
- # Now make sure we don't override an existing swift.authorize when we
- # have no reseller prefix.
- local_auth = \
- auth.filter_factory(
- {'super_admin_key': 'supertest',
- 'reseller_prefix': ''})(FakeApp())
- local_authorize = lambda req: Response('test')
- resp = Request.blank(
- '/v1/account', environ={'swift.authorize':
- local_authorize}).get_response(local_auth)
- self.assertEquals(resp.status_int, 200)
- self.assertEquals(
- resp.environ['swift.authorize'],
- local_authorize)
-
- def test_auth_fail(self):
- resp = Request.blank(
- '/v1/AUTH_cfa',
- headers={'X-Auth-Token': 'AUTH_t'}).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 401)
-
- def test_auth_success(self):
- self.test_auth.app = FakeApp(iter([
- ('200 Ok', {},
- json.dumps(
- {'account': 'act', 'user': 'act:usr',
- 'account_id': 'AUTH_cfa',
- 'groups': [{'name': 'act:usr'}, {'name': 'act'},
- {'name': '.admin'}],
- 'expires': time() + 60})),
- ('204 No Content', {}, '')]))
- resp = Request.blank(
- '/v1/AUTH_cfa',
- headers={'X-Auth-Token': 'AUTH_t'}).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 204)
- self.assertEquals(self.test_auth.app.calls, 2)
-
- def test_auth_memcache(self):
- # First run our test without memcache, showing we need to return the
- # token contents twice.
- self.test_auth.app = FakeApp(iter([
- ('200 Ok', {},
- json.dumps(
- {'account': 'act', 'user': 'act:usr',
- 'account_id': 'AUTH_cfa',
- 'groups': [{'name': 'act:usr'}, {'name': 'act'},
- {'name': '.admin'}],
- 'expires': time() + 60})),
- ('204 No Content', {}, ''),
- ('200 Ok', {},
- json.dumps(
- {'account': 'act', 'user': 'act:usr',
- 'account_id': 'AUTH_cfa',
- 'groups': [{'name': 'act:usr'}, {'name': 'act'},
- {'name': '.admin'}],
- 'expires': time() + 60})),
- ('204 No Content', {}, '')]))
- resp = Request.blank(
- '/v1/AUTH_cfa',
- headers={'X-Auth-Token': 'AUTH_t'}).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 204)
- resp = Request.blank(
- '/v1/AUTH_cfa',
- headers={'X-Auth-Token': 'AUTH_t'}).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 204)
- self.assertEquals(self.test_auth.app.calls, 4)
- # Now run our test with memcache, showing we no longer need to return
- # the token contents twice.
- self.test_auth.app = FakeApp(iter([
- ('200 Ok', {},
- json.dumps(
- {'account': 'act', 'user': 'act:usr',
- 'account_id': 'AUTH_cfa',
- 'groups': [{'name': 'act:usr'}, {'name': 'act'},
- {'name': '.admin'}],
- 'expires': time() + 60})),
- ('204 No Content', {}, ''),
- # Don't need a second token object returned if memcache is
- # used
- ('204 No Content', {}, '')]))
- fake_memcache = FakeMemcache()
- resp = Request.blank(
- '/v1/AUTH_cfa',
- headers={'X-Auth-Token': 'AUTH_t'},
- environ={'swift.cache': fake_memcache}).get_response(
- self.test_auth)
- self.assertEquals(resp.status_int, 204)
- resp = Request.blank(
- '/v1/AUTH_cfa',
- headers={'X-Auth-Token': 'AUTH_t'},
- environ={'swift.cache': fake_memcache}).get_response(
- self.test_auth)
- self.assertEquals(resp.status_int, 204)
- self.assertEquals(self.test_auth.app.calls, 3)
-
- def test_auth_just_expired(self):
- self.test_auth.app = FakeApp(iter([
- # Request for token (which will have expired)
- ('200 Ok', {},
- json.dumps(
- {'account': 'act', 'user': 'act:usr',
- 'account_id': 'AUTH_cfa',
- 'groups': [{'name': 'act:usr'}, {'name': 'act'},
- {'name': '.admin'}],
- 'expires': time() - 1})),
- # Request to delete token
- ('204 No Content', {}, '')]))
- resp = Request.blank(
- '/v1/AUTH_cfa',
- headers={'X-Auth-Token': 'AUTH_t'}).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 401)
- self.assertEquals(self.test_auth.app.calls, 2)
-
- def test_middleware_storage_token(self):
- self.test_auth.app = FakeApp(iter([
- ('200 Ok', {},
- json.dumps(
- {'account': 'act', 'user': 'act:usr',
- 'account_id': 'AUTH_cfa',
- 'groups': [{'name': 'act:usr'}, {'name': 'act'},
- {'name': '.admin'}],
- 'expires': time() + 60})),
- ('204 No Content', {}, '')]))
- resp = Request.blank(
- '/v1/AUTH_cfa',
- headers={'X-Storage-Token': 'AUTH_t'}).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 204)
- self.assertEquals(self.test_auth.app.calls, 2)
-
- def test_authorize_bad_path(self):
- req = Request.blank('/badpath')
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp.status_int, 401)
- req = Request.blank('/badpath')
- req.remote_user = 'act:usr,act,AUTH_cfa'
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp.status_int, 403)
-
- def test_authorize_account_access(self):
- req = Request.blank('/v1/AUTH_cfa')
- req.remote_user = 'act:usr,act,AUTH_cfa'
- self.assertEquals(
- self.test_auth.authorize(req),
- None)
- req = Request.blank('/v1/AUTH_cfa')
- req.remote_user = 'act:usr,act'
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp.status_int, 403)
-
- def test_authorize_acl_group_access(self):
- req = Request.blank('/v1/AUTH_cfa')
- req.remote_user = 'act:usr,act'
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp.status_int, 403)
- req = Request.blank('/v1/AUTH_cfa')
- req.remote_user = 'act:usr,act'
- req.acl = 'act'
- self.assertEquals(
- self.test_auth.authorize(req),
- None)
- req = Request.blank('/v1/AUTH_cfa')
- req.remote_user = 'act:usr,act'
- req.acl = 'act:usr'
- self.assertEquals(
- self.test_auth.authorize(req),
- None)
- req = Request.blank('/v1/AUTH_cfa')
- req.remote_user = 'act:usr,act'
- req.acl = 'act2'
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp.status_int, 403)
- req = Request.blank('/v1/AUTH_cfa')
- req.remote_user = 'act:usr,act'
- req.acl = 'act:usr2'
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp.status_int, 403)
-
- def test_deny_cross_reseller(self):
- # Tests that cross-reseller is denied, even if ACLs/group
- # names match
- req = Request.blank('/v1/OTHER_cfa')
- req.remote_user = 'act:usr,act,AUTH_cfa'
- req.acl = 'act'
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp.status_int, 403)
-
- def test_authorize_acl_referrer_access(self):
- req = Request.blank('/v1/AUTH_cfa/c')
- req.remote_user = 'act:usr,act'
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp.status_int, 403)
- req = Request.blank('/v1/AUTH_cfa/c')
- req.remote_user = 'act:usr,act'
- req.acl = '.r:*,.rlistings'
- self.assertEquals(
- self.test_auth.authorize(req),
- None)
- req = Request.blank('/v1/AUTH_cfa/c')
- req.remote_user = 'act:usr,act'
- req.acl = '.r:*' # No listings allowed
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp.status_int, 403)
- req = Request.blank('/v1/AUTH_cfa/c')
- req.remote_user = 'act:usr,act'
- req.acl = '.r:.example.com,.rlistings'
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp.status_int, 403)
- req = Request.blank('/v1/AUTH_cfa/c')
- req.remote_user = 'act:usr,act'
- req.referer = 'http://www.example.com/index.html'
- req.acl = '.r:.example.com,.rlistings'
- self.assertEquals(
- self.test_auth.authorize(req),
- None)
- req = Request.blank('/v1/AUTH_cfa/c')
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp.status_int, 401)
- req = Request.blank('/v1/AUTH_cfa/c')
- req.acl = '.r:*,.rlistings'
- self.assertEquals(
- self.test_auth.authorize(req),
- None)
- req = Request.blank('/v1/AUTH_cfa/c')
- req.acl = '.r:*' # No listings allowed
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp.status_int, 401)
- req = Request.blank('/v1/AUTH_cfa/c')
- req.acl = '.r:.example.com,.rlistings'
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp.status_int, 401)
- req = Request.blank('/v1/AUTH_cfa/c')
- req.referer = 'http://www.example.com/index.html'
- req.acl = '.r:.example.com,.rlistings'
- self.assertEquals(
- self.test_auth.authorize(req),
- None)
-
- def test_detect_reseller_request(self):
- req = self._make_request('/v1/AUTH_admin',
- headers={'X-Auth-Token': 'AUTH_t'})
- cache_key = 'AUTH_/auth/AUTH_t'
- cache_entry = (time() + 3600, '.reseller_admin')
- req.environ['swift.cache'].set(
- cache_key, cache_entry)
- self.assertTrue(req.environ.get('reseller_request'))
-
- def test_account_put_permissions(self):
- req = Request.blank(
- '/v1/AUTH_new',
- environ={'REQUEST_METHOD': 'PUT'})
- req.remote_user = 'act:usr,act'
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp.status_int, 403)
-
- req = Request.blank(
- '/v1/AUTH_new',
- environ={'REQUEST_METHOD': 'PUT'})
- req.remote_user = 'act:usr,act,AUTH_other'
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp.status_int, 403)
-
- # Even PUTs to your own account as account admin
- # should fail
- req = Request.blank(
- '/v1/AUTH_old',
- environ={'REQUEST_METHOD': 'PUT'})
- req.remote_user = 'act:usr,act,AUTH_old'
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp.status_int, 403)
-
- req = Request.blank(
- '/v1/AUTH_new',
- environ={'REQUEST_METHOD': 'PUT'})
- req.remote_user = 'act:usr,act,.reseller_admin'
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp, None)
-
- # .super_admin is not something the middleware should ever see or care
- # about
- req = Request.blank(
- '/v1/AUTH_new',
- environ={'REQUEST_METHOD': 'PUT'})
- req.remote_user = 'act:usr,act,.super_admin'
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp.status_int, 403)
-
- def test_account_delete_permissions(self):
- req = Request.blank('/v1/AUTH_new',
- environ={'REQUEST_METHOD': 'DELETE'})
- req.remote_user = 'act:usr,act'
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp.status_int, 403)
-
- req = Request.blank('/v1/AUTH_new',
- environ={'REQUEST_METHOD': 'DELETE'})
- req.remote_user = 'act:usr,act,AUTH_other'
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp.status_int, 403)
-
- # Even DELETEs to your own account as account admin should
- # fail
- req = Request.blank('/v1/AUTH_old',
- environ={'REQUEST_METHOD': 'DELETE'})
- req.remote_user = 'act:usr,act,AUTH_old'
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp.status_int, 403)
-
- req = Request.blank('/v1/AUTH_new',
- environ={'REQUEST_METHOD': 'DELETE'})
- req.remote_user = 'act:usr,act,.reseller_admin'
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp, None)
-
- # .super_admin is not something the middleware should ever see or care
- # about
- req = Request.blank('/v1/AUTH_new',
- environ={'REQUEST_METHOD': 'DELETE'})
- req.remote_user = 'act:usr,act,.super_admin'
- resp = self.test_auth.authorize(req)
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp.status_int, 403)
-
- def test_get_token_fail(self):
- resp = Request.blank(
- '/auth/v1.0').get_response(
- self.test_auth)
- self.assertEquals(resp.status_int, 401)
- resp = Request.blank(
- '/auth/v1.0',
- headers={'X-Auth-User': 'act:usr',
- 'X-Auth-Key': 'key'}).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 401)
-
- def test_get_token_fail_invalid_key(self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object
- ('200 Ok', {},
- json.dumps({"auth": "plaintext:key",
- "groups": [{'name': "act:usr"}, {'name': "act"},
- {'name': ".admin"}]}))]))
- resp = Request.blank(
- '/auth/v1.0',
- headers={'X-Auth-User': 'act:usr',
- 'X-Auth-Key': 'invalid'}).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 401)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- def test_get_token_fail_invalid_x_auth_user_format(
- self):
- resp = Request.blank(
- '/auth/v1/act/auth',
- headers={'X-Auth-User': 'usr',
- 'X-Auth-Key': 'key'}).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 401)
-
- def test_get_token_fail_non_matching_account_in_request(
- self):
- resp = Request.blank(
- '/auth/v1/act/auth',
- headers={'X-Auth-User': 'act2:usr',
- 'X-Auth-Key': 'key'}).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 401)
-
- def test_get_token_fail_bad_path(self):
- resp = Request.blank(
- '/auth/v1/act/auth/invalid',
- headers={'X-Auth-User': 'act:usr',
- 'X-Auth-Key': 'key'}).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 400)
-
- def test_get_token_fail_missing_key(self):
- resp = Request.blank(
- '/auth/v1/act/auth',
- headers={'X-Auth-User': 'act:usr'}).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 401)
-
- def test_get_token_fail_get_user_details(self):
- self.test_auth.app = FakeApp(iter([
- ('503 Service Unavailable', {}, '')]))
- resp = Request.blank(
- '/auth/v1.0',
- headers={'X-Auth-User': 'act:usr',
- 'X-Auth-Key': 'key'}).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- def test_get_token_fail_get_account(self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object
- ('200 Ok', {},
- json.dumps({"auth": "plaintext:key",
- "groups": [{'name': "act:usr"}, {'name': "act"},
- {'name': ".admin"}]})),
- # GET of account
- ('503 Service Unavailable', {}, '')]))
- resp = Request.blank(
- '/auth/v1.0',
- headers={'X-Auth-User': 'act:usr',
- 'X-Auth-Key': 'key'}).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 2)
-
- def test_get_token_fail_put_new_token(self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object
- ('200 Ok', {},
- json.dumps({"auth": "plaintext:key",
- "groups": [{'name': "act:usr"}, {'name': "act"},
- {'name': ".admin"}]})),
- # GET of account
- ('204 Ok',
- {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, ''),
- # PUT of new token
- ('503 Service Unavailable', {}, '')]))
- resp = Request.blank(
- '/auth/v1.0',
- headers={'X-Auth-User': 'act:usr',
- 'X-Auth-Key': 'key'}).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 3)
-
- def test_get_token_fail_post_to_user(self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object
- ('200 Ok', {},
- json.dumps({"auth": "plaintext:key",
- "groups": [{'name': "act:usr"}, {'name': "act"},
- {'name': ".admin"}]})),
- # GET of account
- ('204 Ok',
- {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, ''),
- # PUT of new token
- ('201 Created', {}, ''),
- # POST of token to user object
- ('503 Service Unavailable', {}, '')]))
- resp = Request.blank(
- '/auth/v1.0',
- headers={'X-Auth-User': 'act:usr',
- 'X-Auth-Key': 'key'}).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 4)
-
- def test_get_token_fail_get_services(self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object
- ('200 Ok', {},
- json.dumps({"auth": "plaintext:key",
- "groups": [{'name': "act:usr"}, {'name': "act"},
- {'name': ".admin"}]})),
- # GET of account
- ('204 Ok',
- {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, ''),
- # PUT of new token
- ('201 Created', {}, ''),
- # POST of token to user object
- ('204 No Content', {}, ''),
- # GET of services object
- ('503 Service Unavailable', {}, '')]))
- resp = Request.blank(
- '/auth/v1.0',
- headers={'X-Auth-User': 'act:usr',
- 'X-Auth-Key': 'key'}).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 5)
-
- def test_get_token_fail_get_existing_token(self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object
- ('200 Ok', {'X-Object-Meta-Auth-Token': 'AUTH_tktest'},
- json.dumps({"auth": "plaintext:key",
- "groups": [{'name': "act:usr"}, {'name': "act"},
- {'name': ".admin"}]})),
- # GET of token
- ('503 Service Unavailable', {}, '')]))
- resp = Request.blank(
- '/auth/v1.0',
- headers={'X-Auth-User': 'act:usr',
- 'X-Auth-Key': 'key'}).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 2)
-
- def test_get_token_success_v1_0(self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object
- ('200 Ok', {},
- json.dumps({"auth": "plaintext:key",
- "groups": [{'name': "act:usr"}, {'name': "act"},
- {'name': ".admin"}]})),
- # GET of account
- ('204 Ok',
- {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, ''),
- # PUT of new token
- ('201 Created', {}, ''),
- # POST of token to user object
- ('204 No Content', {}, ''),
- # GET of services object
- ('200 Ok', {}, json.dumps({"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}}))]))
- resp = Request.blank(
- '/auth/v1.0',
- headers={'X-Auth-User': 'act:usr',
- 'X-Auth-Key': 'key'}).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 200)
- self.assert_(resp.headers.get(
- 'x-auth-token',
- '').startswith('AUTH_tk'), resp.headers.get('x-auth-token'))
- self.assertEquals(resp.headers.get('x-auth-token'),
- resp.headers.get('x-storage-token'))
- self.assertEquals(resp.headers.get('x-storage-url'),
- 'http://127.0.0.1:8080/v1/AUTH_cfa')
- self.assertEquals(
- json.loads(resp.body),
- {"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}})
- self.assertEquals(self.test_auth.app.calls, 5)
-
- def test_get_token_success_v1_0_with_user_token_life(
- self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object
- ('200 Ok', {},
- json.dumps({"auth": "plaintext:key",
- "groups": [{'name': "act:usr"}, {'name': "act"},
- {'name': ".admin"}]})),
- # GET of account
- ('204 Ok',
- {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, ''),
- # PUT of new token
- ('201 Created', {}, ''),
- # POST of token to user object
- ('204 No Content', {}, ''),
- # GET of services object
- ('200 Ok', {}, json.dumps({"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}}))]))
- resp = Request.blank(
- '/auth/v1.0',
- headers={'X-Auth-User': 'act:usr',
- 'X-Auth-Key': 'key',
- 'X-Auth-Token-Lifetime': 10}).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 200)
- left = int(resp.headers['x-auth-token-expires'])
- self.assertTrue(left > 0, '%d > 0' % left)
- self.assertTrue(left <= 10, '%d <= 10' % left)
- self.assert_(resp.headers.get(
- 'x-auth-token',
- '').startswith('AUTH_tk'), resp.headers.get('x-auth-token'))
- self.assertEquals(resp.headers.get('x-auth-token'),
- resp.headers.get('x-storage-token'))
- self.assertEquals(resp.headers.get('x-storage-url'),
- 'http://127.0.0.1:8080/v1/AUTH_cfa')
- self.assertEquals(
- json.loads(resp.body),
- {"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}})
- self.assertEquals(self.test_auth.app.calls, 5)
-
- def test_get_token_success_v1_0_with_user_token_life_past_max(
- self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object
- ('200 Ok', {},
- json.dumps({"auth": "plaintext:key",
- "groups": [{'name': "act:usr"}, {'name': "act"},
- {'name': ".admin"}]})),
- # GET of account
- ('204 Ok',
- {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, ''),
- # PUT of new token
- ('201 Created', {}, ''),
- # POST of token to user object
- ('204 No Content', {}, ''),
- # GET of services object
- ('200 Ok', {}, json.dumps({"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}}))]))
- req = Request.blank(
- '/auth/v1.0',
- headers={'X-Auth-User': 'act:usr',
- 'X-Auth-Key': 'key',
- 'X-Auth-Token-Lifetime': MAX_TOKEN_LIFE * 10})
- resp = req.get_response(self.test_auth)
- self.assertEquals(resp.status_int, 200)
- left = int(resp.headers['x-auth-token-expires'])
- self.assertTrue(left > DEFAULT_TOKEN_LIFE,
- '%d > %d' % (left, DEFAULT_TOKEN_LIFE))
- self.assertTrue(left <= MAX_TOKEN_LIFE,
- '%d <= %d' % (left, MAX_TOKEN_LIFE))
- self.assert_(resp.headers.get(
- 'x-auth-token',
- '').startswith('AUTH_tk'), resp.headers.get('x-auth-token'))
- self.assertEquals(resp.headers.get('x-auth-token'),
- resp.headers.get('x-storage-token'))
- self.assertEquals(resp.headers.get('x-storage-url'),
- 'http://127.0.0.1:8080/v1/AUTH_cfa')
- self.assertEquals(
- json.loads(resp.body),
- {"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}})
- self.assertEquals(self.test_auth.app.calls, 5)
-
- def test_get_token_success_v1_act_auth(self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object
- ('200 Ok', {},
- json.dumps({"auth": "plaintext:key",
- "groups": [{'name': "act:usr"}, {'name': "act"},
- {'name': ".admin"}]})),
- # GET of account
- ('204 Ok',
- {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, ''),
- # PUT of new token
- ('201 Created', {}, ''),
- # POST of token to user object
- ('204 No Content', {}, ''),
- # GET of services object
- ('200 Ok', {}, json.dumps({"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}}))]))
- resp = Request.blank(
- '/auth/v1/act/auth',
- headers={'X-Storage-User': 'usr',
- 'X-Storage-Pass': 'key'}).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 200)
- self.assert_(resp.headers.get(
- 'x-auth-token',
- '').startswith('AUTH_tk'), resp.headers.get('x-auth-token'))
- self.assertEquals(resp.headers.get('x-auth-token'),
- resp.headers.get('x-storage-token'))
- self.assertEquals(resp.headers.get('x-storage-url'),
- 'http://127.0.0.1:8080/v1/AUTH_cfa')
- self.assertEquals(
- json.loads(resp.body),
- {"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}})
- self.assertEquals(self.test_auth.app.calls, 5)
-
- def test_get_token_success_storage_instead_of_auth(
- self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object
- ('200 Ok', {},
- json.dumps({"auth": "plaintext:key",
- "groups": [{'name': "act:usr"}, {'name': "act"},
- {'name': ".admin"}]})),
- # GET of account
- ('204 Ok',
- {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, ''),
- # PUT of new token
- ('201 Created', {}, ''),
- # POST of token to user object
- ('204 No Content', {}, ''),
- # GET of services object
- ('200 Ok', {}, json.dumps({"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}}))]))
- resp = Request.blank(
- '/auth/v1.0',
- headers={'X-Storage-User': 'act:usr',
- 'X-Storage-Pass': 'key'}).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 200)
- self.assert_(
- resp.headers.get(
- 'x-auth-token',
- '').startswith('AUTH_tk'), resp.headers.get('x-auth-token'))
- self.assertEquals(resp.headers.get('x-auth-token'),
- resp.headers.get('x-storage-token'))
- self.assertEquals(resp.headers.get('x-storage-url'),
- 'http://127.0.0.1:8080/v1/AUTH_cfa')
- self.assertEquals(
- json.loads(resp.body),
- {"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}})
- self.assertEquals(self.test_auth.app.calls, 5)
-
- def test_get_token_success_v1_act_auth_auth_instead_of_storage(
- self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object
- ('200 Ok', {},
- json.dumps({"auth": "plaintext:key",
- "groups": [{'name': "act:usr"}, {'name': "act"},
- {'name': ".admin"}]})),
- # GET of account
- ('204 Ok',
- {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, ''),
- # PUT of new token
- ('201 Created', {}, ''),
- # POST of token to user object
- ('204 No Content', {}, ''),
- # GET of services object
- ('200 Ok', {}, json.dumps({"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}}))]))
- resp = Request.blank(
- '/auth/v1/act/auth',
- headers={'X-Auth-User': 'act:usr',
- 'X-Auth-Key': 'key'}).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 200)
- self.assert_(resp.headers.get(
- 'x-auth-token',
- '').startswith('AUTH_tk'), resp.headers.get('x-auth-token'))
- self.assertEquals(resp.headers.get('x-auth-token'),
- resp.headers.get('x-storage-token'))
- self.assertEquals(resp.headers.get('x-storage-url'),
- 'http://127.0.0.1:8080/v1/AUTH_cfa')
- self.assertEquals(
- json.loads(resp.body),
- {"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}})
- self.assertEquals(self.test_auth.app.calls, 5)
-
- def test_get_token_success_existing_token(self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object
- ('200 Ok', {'X-Object-Meta-Auth-Token': 'AUTH_tktest'},
- json.dumps({"auth": "plaintext:key",
- "groups": [{'name': "act:usr"}, {'name': "act"},
- {'name': ".admin"}]})),
- # GET of token
- ('200 Ok', {}, json.dumps(
- {"account": "act", "user": "usr",
- "account_id": "AUTH_cfa",
- "groups": [{'name': "act:usr"},
- {'name': "key"}, {'name': ".admin"}],
- "expires": 9999999999.9999999})),
- # GET of services object
- ('200 Ok', {}, json.dumps({"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}}))]))
- resp = Request.blank(
- '/auth/v1.0',
- headers={'X-Auth-User': 'act:usr',
- 'X-Auth-Key': 'key'}).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 200)
- self.assertEquals(
- resp.headers.get('x-auth-token'),
- 'AUTH_tktest')
- self.assertEquals(resp.headers.get('x-auth-token'),
- resp.headers.get('x-storage-token'))
- self.assertEquals(resp.headers.get('x-storage-url'),
- 'http://127.0.0.1:8080/v1/AUTH_cfa')
- self.assertEquals(
- json.loads(resp.body),
- {"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}})
- self.assertEquals(self.test_auth.app.calls, 3)
-
- def test_get_token_success_existing_token_but_request_new_one(
- self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object
- ('200 Ok', {'X-Object-Meta-Auth-Token': 'AUTH_tktest'},
- json.dumps({"auth": "plaintext:key",
- "groups": [{'name': "act:usr"}, {'name': "act"},
- {'name': ".admin"}]})),
- # DELETE of expired token
- ('204 No Content', {}, ''),
- # GET of account
- ('204 Ok',
- {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, ''),
- # PUT of new token
- ('201 Created', {}, ''),
- # POST of token to user object
- ('204 No Content', {}, ''),
- # GET of services object
- ('200 Ok', {}, json.dumps({"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}}))]))
- resp = Request.blank(
- '/auth/v1.0',
- headers={'X-Auth-User': 'act:usr',
- 'X-Auth-Key': 'key',
- 'X-Auth-New-Token': 'true'}).get_response(
- self.test_auth)
- self.assertEquals(resp.status_int, 200)
- self.assertNotEquals(
- resp.headers.get('x-auth-token'), 'AUTH_tktest')
- self.assertEquals(resp.headers.get('x-auth-token'),
- resp.headers.get('x-storage-token'))
- self.assertEquals(resp.headers.get('x-storage-url'),
- 'http://127.0.0.1:8080/v1/AUTH_cfa')
- self.assertEquals(
- json.loads(resp.body),
- {"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}})
- self.assertEquals(self.test_auth.app.calls, 6)
-
- def test_get_token_success_existing_token_expired(self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object
- ('200 Ok', {'X-Object-Meta-Auth-Token': 'AUTH_tktest'},
- json.dumps({"auth": "plaintext:key",
- "groups": [{'name': "act:usr"}, {'name': "act"},
- {'name': ".admin"}]})),
- # GET of token
- ('200 Ok', {}, json.dumps(
- {"account": "act", "user": "usr",
- "account_id": "AUTH_cfa",
- "groups": [{'name': "act:usr"},
- {'name': "key"}, {'name': ".admin"}],
- "expires": 0.0})),
- # DELETE of expired token
- ('204 No Content', {}, ''),
- # GET of account
- ('204 Ok',
- {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, ''),
- # PUT of new token
- ('201 Created', {}, ''),
- # POST of token to user object
- ('204 No Content', {}, ''),
- # GET of services object
- ('200 Ok', {}, json.dumps({"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}}))]))
- resp = Request.blank(
- '/auth/v1.0',
- headers={'X-Auth-User': 'act:usr',
- 'X-Auth-Key': 'key'}).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 200)
- self.assertNotEquals(
- resp.headers.get('x-auth-token'),
- 'AUTH_tktest')
- self.assertEquals(resp.headers.get('x-auth-token'),
- resp.headers.get('x-storage-token'))
- self.assertEquals(resp.headers.get('x-storage-url'),
- 'http://127.0.0.1:8080/v1/AUTH_cfa')
- self.assertEquals(
- json.loads(resp.body),
- {"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}})
- self.assertEquals(self.test_auth.app.calls, 7)
-
- def test_get_token_success_existing_token_expired_fail_deleting_old(
- self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object
- ('200 Ok', {'X-Object-Meta-Auth-Token': 'AUTH_tktest'},
- json.dumps({"auth": "plaintext:key",
- "groups": [{'name': "act:usr"}, {'name': "act"},
- {'name': ".admin"}]})),
- # GET of token
- ('200 Ok', {}, json.dumps({"account": "act", "user": "usr",
- "account_id": "AUTH_cfa",
- "groups": [{'name': "act:usr"},
- {'name': "key"}, {'name': ".admin"}],
- "expires": 0.0})),
- # DELETE of expired token
- ('503 Service Unavailable', {}, ''),
- # GET of account
- ('204 Ok',
- {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, ''),
- # PUT of new token
- ('201 Created', {}, ''),
- # POST of token to user object
- ('204 No Content', {}, ''),
- # GET of services object
- ('200 Ok', {}, json.dumps({"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}}))]))
- resp = Request.blank(
- '/auth/v1.0',
- headers={'X-Auth-User': 'act:usr',
- 'X-Auth-Key': 'key'}).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 200)
- self.assertNotEquals(
- resp.headers.get('x-auth-token'),
- 'AUTH_tktest')
- self.assertEquals(resp.headers.get('x-auth-token'),
- resp.headers.get('x-storage-token'))
- self.assertEquals(resp.headers.get('x-storage-url'),
- 'http://127.0.0.1:8080/v1/AUTH_cfa')
- self.assertEquals(
- json.loads(resp.body),
- {"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}})
- self.assertEquals(self.test_auth.app.calls, 7)
-
- def test_prep_success(self):
- list_to_iter = [
- # PUT of .auth account
- ('201 Created', {}, ''),
- # PUT of .account_id container
- ('201 Created', {}, '')]
- # PUT of .token* containers
- for x in xrange(16):
- list_to_iter.append(('201 Created', {}, ''))
- self.test_auth.app = FakeApp(iter(list_to_iter))
- resp = Request.blank('/auth/v2/.prep',
- environ={
- 'REQUEST_METHOD': 'POST'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 204)
- self.assertEquals(self.test_auth.app.calls, 18)
-
- def test_prep_bad_method(self):
- resp = Request.blank('/auth/v2/.prep',
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 400)
- resp = Request.blank('/auth/v2/.prep',
- environ={
- 'REQUEST_METHOD': 'HEAD'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 400)
- resp = Request.blank('/auth/v2/.prep',
- environ={
- 'REQUEST_METHOD': 'PUT'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 400)
-
- def test_prep_bad_creds(self):
- resp = Request.blank('/auth/v2/.prep',
- environ={
- 'REQUEST_METHOD': 'POST'},
- headers={
- 'X-Auth-Admin-User':
- 'super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 403)
- resp = Request.blank('/auth/v2/.prep',
- environ={
- 'REQUEST_METHOD': 'POST'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'upertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 403)
- resp = Request.blank('/auth/v2/.prep',
- environ={
- 'REQUEST_METHOD': 'POST'},
- headers={
- 'X-Auth-Admin-User': '.super_admin'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 403)
- resp = Request.blank('/auth/v2/.prep',
- environ={
- 'REQUEST_METHOD': 'POST'},
- headers={
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 403)
- resp = Request.blank(
- '/auth/v2/.prep',
- environ={'REQUEST_METHOD': 'POST'}).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 403)
-
- def test_prep_fail_account_create(self):
- self.test_auth.app = FakeApp(iter([
- # PUT of .auth account
- ('503 Service Unavailable', {}, '')]))
- resp = Request.blank('/auth/v2/.prep',
- environ={
- 'REQUEST_METHOD': 'POST'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- def test_prep_fail_token_container_create(self):
- self.test_auth.app = FakeApp(iter([
- # PUT of .auth account
- ('201 Created', {}, ''),
- # PUT of .token container
- ('503 Service Unavailable', {}, '')]))
- resp = Request.blank('/auth/v2/.prep',
- environ={
- 'REQUEST_METHOD': 'POST'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 2)
-
- def test_prep_fail_account_id_container_create(self):
- self.test_auth.app = FakeApp(iter([
- # PUT of .auth account
- ('201 Created', {}, ''),
- # PUT of .token container
- ('201 Created', {}, ''),
- # PUT of .account_id container
- ('503 Service Unavailable', {}, '')]))
- resp = Request.blank('/auth/v2/.prep',
- environ={
- 'REQUEST_METHOD': 'POST'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 3)
-
- def test_get_reseller_success(self):
- self.test_auth.app = FakeApp(iter([
- # GET of .auth account (list containers)
- ('200 Ok', {}, json.dumps([
- {"name": ".token", "count": 0, "bytes": 0},
- {"name": ".account_id",
- "count": 0, "bytes": 0},
- {"name": "act", "count": 0, "bytes": 0}])),
- # GET of .auth account (list containers
- # continuation)
- ('200 Ok', {}, '[]')]))
- resp = Request.blank('/auth/v2',
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 200)
- self.assertEquals(json.loads(resp.body),
- {"accounts": [{"name": "act"}]})
- self.assertEquals(self.test_auth.app.calls, 2)
-
- self.test_auth.app = FakeApp(iter([
- # GET of user object
- ('200 Ok', {}, json.dumps({"groups": [{"name": "act:adm"},
- {"name": "test"}, {"name": ".admin"},
- {"name": ".reseller_admin"}], "auth": "plaintext:key"})),
- # GET of .auth account (list containers)
- ('200 Ok', {}, json.dumps([
- {"name": ".token", "count": 0, "bytes": 0},
- {"name": ".account_id",
- "count": 0, "bytes": 0},
- {"name": "act", "count": 0, "bytes": 0}])),
- # GET of .auth account (list containers
- # continuation)
- ('200 Ok', {}, '[]')]))
- resp = Request.blank('/auth/v2',
- headers={
- 'X-Auth-Admin-User':
- 'act:adm',
- 'X-Auth-Admin-Key': 'key'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 200)
- self.assertEquals(json.loads(resp.body),
- {"accounts": [{"name": "act"}]})
- self.assertEquals(self.test_auth.app.calls, 3)
-
- def test_get_reseller_fail_bad_creds(self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object
- ('404 Not Found', {}, '')]))
- resp = Request.blank('/auth/v2',
- headers={
- 'X-Auth-Admin-User':
- 'super:admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 403)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- self.test_auth.app = FakeApp(iter([
- # GET of user object (account admin, but not reseller
- # admin)
- ('200 Ok', {}, json.dumps({"groups": [{"name": "act:adm"},
- {"name": "test"}, {"name": ".admin"}],
- "auth": "plaintext:key"}))]))
- resp = Request.blank('/auth/v2',
- headers={
- 'X-Auth-Admin-User':
- 'act:adm',
- 'X-Auth-Admin-Key': 'key'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 403)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- self.test_auth.app = FakeApp(iter([
- # GET of user object (regular user)
- ('200 Ok', {}, json.dumps({"groups": [{"name": "act:usr"},
- {"name": "test"}], "auth": "plaintext:key"}))]))
- resp = Request.blank('/auth/v2',
- headers={
- 'X-Auth-Admin-User':
- 'act:usr',
- 'X-Auth-Admin-Key': 'key'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 403)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- def test_get_reseller_fail_listing(self):
- self.test_auth.app = FakeApp(iter([
- # GET of .auth account (list containers)
- ('503 Service Unavailable', {}, '')]))
- resp = Request.blank('/auth/v2',
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- self.test_auth.app = FakeApp(iter([
- # GET of .auth account (list containers)
- ('200 Ok', {}, json.dumps([
- {"name": ".token", "count": 0, "bytes": 0},
- {"name": ".account_id",
- "count": 0, "bytes": 0},
- {"name": "act", "count": 0, "bytes": 0}])),
- # GET of .auth account (list containers
- # continuation)
- ('503 Service Unavailable', {}, '')]))
- resp = Request.blank('/auth/v2',
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 2)
-
- def test_get_account_success(self):
- self.test_auth.app = FakeApp(iter([
- # GET of .services object
- ('200 Ok', {},
- json.dumps(
- {"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}})),
- # GET of account container (list objects)
- ('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'},
- json.dumps([
- {"name": ".services", "hash": "etag", "bytes": 112,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:27.618110"},
- {"name": "tester", "hash": "etag", "bytes": 104,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:27.736680"},
- {"name": "tester3", "hash": "etag", "bytes": 86,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:28.135530"}])),
- # GET of account container (list objects
- # continuation)
- ('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, '[]')]))
- resp = Request.blank('/auth/v2/act',
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 200)
- self.assertEquals(
- json.loads(resp.body),
- {'account_id': 'AUTH_cfa',
- 'services': {'storage':
- {'default': 'local',
- 'local': 'http://127.0.0.1:8080/v1/AUTH_cfa'}},
- 'users': [{'name': 'tester'}, {'name': 'tester3'}]})
- self.assertEquals(self.test_auth.app.calls, 3)
-
- self.test_auth.app = FakeApp(iter([
- # GET of user object
- ('200 Ok', {}, json.dumps({"groups": [{"name": "act:adm"},
- {"name": "test"}, {"name": ".admin"}],
- "auth": "plaintext:key"})),
- # GET of .services object
- ('200 Ok', {},
- json.dumps({"storage":
- {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}})),
- # GET of account container (list objects)
- ('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'},
- json.dumps([
- {"name": ".services", "hash": "etag", "bytes": 112,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:27.618110"},
- {"name": "tester", "hash": "etag", "bytes": 104,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:27.736680"},
- {"name": "tester3", "hash": "etag", "bytes": 86,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:28.135530"}])),
- # GET of account container (list objects
- # continuation)
- ('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, '[]')]))
- resp = Request.blank('/auth/v2/act',
- headers={
- 'X-Auth-Admin-User':
- 'act:adm',
- 'X-Auth-Admin-Key': 'key'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 200)
- self.assertEquals(
- json.loads(resp.body),
- {'account_id': 'AUTH_cfa',
- 'services': {'storage':
- {'default': 'local',
- 'local': 'http://127.0.0.1:8080/v1/AUTH_cfa'}},
- 'users': [{'name': 'tester'}, {'name': 'tester3'}]})
- self.assertEquals(self.test_auth.app.calls, 4)
-
- def test_get_account_fail_bad_account_name(self):
- resp = Request.blank('/auth/v2/.token',
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 400)
- resp = Request.blank('/auth/v2/.anything',
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 400)
-
- def test_get_account_fail_creds(self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object
- ('404 Not Found', {}, '')]))
- resp = Request.blank('/auth/v2/act',
- headers={
- 'X-Auth-Admin-User':
- 'super:admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 403)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- self.test_auth.app = FakeApp(iter([
- # GET of user object (account admin, but wrong
- # account)
- ('200 Ok', {}, json.dumps({"groups": [{"name": "act2:adm"},
- {"name": "test"}, {"name": ".admin"}],
- "auth": "plaintext:key"}))]))
- resp = Request.blank('/auth/v2/act',
- headers={
- 'X-Auth-Admin-User':
- 'act2:adm',
- 'X-Auth-Admin-Key': 'key'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 403)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- self.test_auth.app = FakeApp(iter([
- # GET of user object (regular user)
- ('200 Ok', {}, json.dumps({"groups": [{"name": "act:usr"},
- {"name": "test"}], "auth": "plaintext:key"}))]))
- resp = Request.blank('/auth/v2/act',
- headers={
- 'X-Auth-Admin-User':
- 'act:usr',
- 'X-Auth-Admin-Key': 'key'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 403)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- def test_get_account_fail_get_services(self):
- self.test_auth.app = FakeApp(iter([
- # GET of .services object
- ('503 Service Unavailable', {}, '')]))
- resp = Request.blank('/auth/v2/act',
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- self.test_auth.app = FakeApp(iter([
- # GET of .services object
- ('404 Not Found', {}, '')]))
- resp = Request.blank('/auth/v2/act',
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 404)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- def test_get_account_fail_listing(self):
- self.test_auth.app = FakeApp(iter([
- # GET of .services object
- ('200 Ok', {}, json.dumps(
- {"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}})),
- # GET of account container (list objects)
- ('503 Service Unavailable', {}, '')]))
- resp = Request.blank('/auth/v2/act',
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 2)
-
- self.test_auth.app = FakeApp(iter([
- # GET of .services object
- ('200 Ok', {}, json.dumps(
- {"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}})),
- # GET of account container (list objects)
- ('404 Not Found', {}, '')]))
- resp = Request.blank('/auth/v2/act',
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 404)
- self.assertEquals(self.test_auth.app.calls, 2)
-
- self.test_auth.app = FakeApp(iter([
- # GET of .services object
- ('200 Ok', {}, json.dumps(
- {"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}})),
- # GET of account container (list objects)
- ('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'},
- json.dumps([
- {"name": ".services", "hash": "etag", "bytes": 112,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:27.618110"},
- {"name": "tester", "hash": "etag", "bytes": 104,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:27.736680"},
- {"name": "tester3", "hash": "etag", "bytes": 86,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:28.135530"}])),
- # GET of account container (list objects
- # continuation)
- ('503 Service Unavailable', {}, '')]))
- resp = Request.blank('/auth/v2/act',
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 3)
-
- def test_set_services_new_service(self):
- self.test_auth.app = FakeApp(iter([
- # GET of .services object
- ('200 Ok', {},
- json.dumps({"storage":
- {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}})),
- # PUT of new .services object
- ('204 No Content', {}, '')]))
- resp = Request.blank('/auth/v2/act/.services',
- environ={
- 'REQUEST_METHOD': 'POST'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'},
- body=json.dumps(
- {'new_service':
- {'new_endpoint': 'new_value'}})
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 200)
- self.assertEquals(
- json.loads(resp.body),
- {'storage': {'default': 'local',
- 'local': 'http://127.0.0.1:8080/v1/AUTH_cfa'},
- 'new_service': {'new_endpoint': 'new_value'}})
- self.assertEquals(self.test_auth.app.calls, 2)
-
- def test_set_services_new_endpoint(self):
- self.test_auth.app = FakeApp(iter([
- # GET of .services object
- ('200 Ok', {}, json.dumps(
- {"storage":
- {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}})),
- # PUT of new .services object
- ('204 No Content', {}, '')]))
- resp = Request.blank('/auth/v2/act/.services',
- environ={
- 'REQUEST_METHOD': 'POST'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'},
- body=json.dumps(
- {'storage': {'new_endpoint': 'new_value'}})
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 200)
- self.assertEquals(
- json.loads(resp.body),
- {'storage': {'default': 'local',
- 'local':
- 'http://127.0.0.1:8080/v1/AUTH_cfa',
- 'new_endpoint': 'new_value'}})
- self.assertEquals(self.test_auth.app.calls, 2)
-
- def test_set_services_update_endpoint(self):
- self.test_auth.app = FakeApp(iter([
- # GET of .services object
- ('200 Ok', {}, json.dumps(
- {"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}})),
- # PUT of new .services object
- ('204 No Content', {}, '')]))
- resp = Request.blank('/auth/v2/act/.services',
- environ={
- 'REQUEST_METHOD': 'POST'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'},
- body=json.dumps(
- {'storage': {'local': 'new_value'}})
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 200)
- self.assertEquals(json.loads(resp.body),
- {'storage': {'default': 'local',
- 'local': 'new_value'}})
- self.assertEquals(self.test_auth.app.calls, 2)
-
- def test_set_services_fail_bad_creds(self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object
- ('404 Not Found', {}, '')]))
- resp = Request.blank('/auth/v2/act/.services',
- environ={
- 'REQUEST_METHOD': 'POST'},
- headers={
- 'X-Auth-Admin-User':
- 'super:admin',
- 'X-Auth-Admin-Key': 'supertest'},
- body=json.dumps(
- {'storage': {'local': 'new_value'}})
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 403)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- self.test_auth.app = FakeApp(iter([
- # GET of user object (account admin, but not reseller
- # admin)
- ('200 Ok', {}, json.dumps({"groups": [{"name": "act:adm"},
- {"name": "test"}, {"name": ".admin"}],
- "auth": "plaintext:key"}))]))
- resp = Request.blank('/auth/v2/act/.services',
- environ={
- 'REQUEST_METHOD': 'POST'},
- headers={
- 'X-Auth-Admin-User':
- 'act:adm',
- 'X-Auth-Admin-Key': 'key'},
- body=json.dumps(
- {'storage': {'local': 'new_value'}})
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 403)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- self.test_auth.app = FakeApp(iter([
- # GET of user object (regular user)
- ('200 Ok', {}, json.dumps({"groups": [{"name": "act:usr"},
- {"name": "test"}], "auth": "plaintext:key"}))]))
- resp = Request.blank('/auth/v2/act/.services',
- environ={
- 'REQUEST_METHOD': 'POST'},
- headers={
- 'X-Auth-Admin-User':
- 'act:usr',
- 'X-Auth-Admin-Key': 'key'},
- body=json.dumps(
- {'storage': {'local': 'new_value'}})
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 403)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- def test_set_services_fail_bad_account_name(self):
- resp = Request.blank('/auth/v2/.act/.services',
- environ={
- 'REQUEST_METHOD': 'POST'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'},
- body=json.dumps(
- {'storage': {'local': 'new_value'}})
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 400)
-
- def test_set_services_fail_bad_json(self):
- resp = Request.blank('/auth/v2/act/.services',
- environ={
- 'REQUEST_METHOD': 'POST'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'},
- body='garbage'
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 400)
- resp = Request.blank('/auth/v2/act/.services',
- environ={
- 'REQUEST_METHOD': 'POST'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'},
- body=''
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 400)
-
- def test_set_services_fail_get_services(self):
- self.test_auth.app = FakeApp(iter([
- # GET of .services object
- ('503 Unavailable', {}, '')]))
- resp = Request.blank('/auth/v2/act/.services',
- environ={
- 'REQUEST_METHOD': 'POST'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'},
- body=json.dumps({
- 'new_service': {'new_endpoint': 'new_value'}})
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- self.test_auth.app = FakeApp(iter([
- # GET of .services object
- ('404 Not Found', {}, '')]))
- resp = Request.blank('/auth/v2/act/.services',
- environ={
- 'REQUEST_METHOD': 'POST'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'},
- body=json.dumps({
- 'new_service': {'new_endpoint': 'new_value'}})
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 404)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- def test_set_services_fail_put_services(self):
- self.test_auth.app = FakeApp(iter([
- # GET of .services object
- ('200 Ok', {}, json.dumps(
- {"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}})),
- # PUT of new .services object
- ('503 Unavailable', {}, '')]))
- resp = Request.blank('/auth/v2/act/.services',
- environ={
- 'REQUEST_METHOD': 'POST'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'},
- body=json.dumps(
- {'new_service':
- {'new_endpoint': 'new_value'}})
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 2)
-
- def test_put_account_success(self):
- conn = FakeConn(iter([
- # PUT of storage account itself
- ('201 Created', {}, '')]))
- self.test_auth.get_conn = lambda: conn
- self.test_auth.app = FakeApp(iter([
- # Initial HEAD of account container to check for
- # pre-existence
- ('404 Not Found', {}, ''),
- # PUT of account container
- ('204 No Content', {}, ''),
- # PUT of .account_id mapping object
- ('204 No Content', {}, ''),
- # PUT of .services object
- ('204 No Content', {}, ''),
- # POST to account container updating
- # X-Container-Meta-Account-Id
- ('204 No Content', {}, '')]))
- resp = Request.blank(
- '/auth/v2/act',
- environ={
- 'REQUEST_METHOD': 'PUT', 'swift.cache': FakeMemcache()},
- headers={'X-Auth-Admin-User': '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 201)
- self.assertEquals(self.test_auth.app.calls, 5)
- self.assertEquals(conn.calls, 1)
-
- def test_put_account_success_preexist_but_not_completed(
- self):
- conn = FakeConn(iter([
- # PUT of storage account itself
- ('201 Created', {}, '')]))
- self.test_auth.get_conn = lambda: conn
- self.test_auth.app = FakeApp(iter([
- # Initial HEAD of account container to check for pre-existence
- # We're going to show it as existing this time, but with no
- # X-Container-Meta-Account-Id, indicating a failed
- # previous attempt
- ('200 Ok', {}, ''),
- # PUT of .account_id mapping object
- ('204 No Content', {}, ''),
- # PUT of .services object
- ('204 No Content', {}, ''),
- # POST to account container updating
- # X-Container-Meta-Account-Id
- ('204 No Content', {}, '')]))
- resp = Request.blank(
- '/auth/v2/act',
- environ={
- 'REQUEST_METHOD': 'PUT',
- 'swift.cache': FakeMemcache()},
- headers={'X-Auth-Admin-User': '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 201)
- self.assertEquals(self.test_auth.app.calls, 4)
- self.assertEquals(conn.calls, 1)
-
- def test_put_account_success_preexist_and_completed(
- self):
- self.test_auth.app = FakeApp(iter([
- # Initial HEAD of account container to check for pre-existence
- # We're going to show it as existing this time, and with an
- # X-Container-Meta-Account-Id, indicating it already
- # exists
- ('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, '')]))
- resp = Request.blank(
- '/auth/v2/act',
- environ={
- 'REQUEST_METHOD': 'PUT', 'swift.cache': FakeMemcache()},
- headers={'X-Auth-Admin-User': '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 202)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- def test_put_account_success_with_given_suffix(self):
- conn = FakeConn(iter([
- # PUT of storage account itself
- ('201 Created', {}, '')]))
- self.test_auth.get_conn = lambda: conn
- self.test_auth.app = FakeApp(iter([
- # Initial HEAD of account container to check for
- # pre-existence
- ('404 Not Found', {}, ''),
- # PUT of account container
- ('204 No Content', {}, ''),
- # PUT of .account_id mapping object
- ('204 No Content', {}, ''),
- # PUT of .services object
- ('204 No Content', {}, ''),
- # POST to account container updating
- # X-Container-Meta-Account-Id
- ('204 No Content', {}, '')]))
- resp = Request.blank(
- '/auth/v2/act',
- environ={
- 'REQUEST_METHOD': 'PUT', 'swift.cache': FakeMemcache()},
- headers={'X-Auth-Admin-User': '.super_admin',
- 'X-Auth-Admin-Key': 'supertest',
- 'X-Account-Suffix': 'test-suffix'}).get_response(
- self.test_auth)
- self.assertEquals(resp.status_int, 201)
- self.assertEquals(
- conn.request_path,
- '/v1/AUTH_test-suffix')
- self.assertEquals(self.test_auth.app.calls, 5)
- self.assertEquals(conn.calls, 1)
-
- def test_put_account_fail_bad_creds(self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object
- ('404 Not Found', {}, '')]))
- resp = Request.blank(
- '/auth/v2/act',
- environ={'REQUEST_METHOD': 'PUT',
- 'swift.cache': FakeMemcache()},
- headers={'X-Auth-Admin-User': 'super:admin',
- 'X-Auth-Admin-Key': 'supertest'},).get_response(
- self.test_auth)
- self.assertEquals(resp.status_int, 403)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- self.test_auth.app = FakeApp(iter([
- # GET of user object (account admin, but not reseller
- # admin)
- ('200 Ok', {}, json.dumps({"groups": [{"name": "act:adm"},
- {"name": "test"}, {"name": ".admin"}],
- "auth": "plaintext:key"}))]))
- resp = Request.blank(
- '/auth/v2/act',
- environ={'REQUEST_METHOD': 'PUT',
- 'swift.cache': FakeMemcache()},
- headers={'X-Auth-Admin-User': 'act:adm',
- 'X-Auth-Admin-Key': 'key'},).get_response(
- self.test_auth)
- self.assertEquals(resp.status_int, 403)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- self.test_auth.app = FakeApp(iter([
- # GET of user object (regular user)
- ('200 Ok', {}, json.dumps({"groups": [{"name": "act:usr"},
- {"name": "test"}], "auth": "plaintext:key"}))]))
- resp = Request.blank(
- '/auth/v2/act',
- environ={'REQUEST_METHOD': 'PUT', 'swift.cache': FakeMemcache()},
- headers={'X-Auth-Admin-User': 'act:usr',
- 'X-Auth-Admin-Key': 'key'},).get_response(
- self.test_auth)
- self.assertEquals(resp.status_int, 403)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- def test_put_account_fail_invalid_account_name(self):
- resp = Request.blank(
- '/auth/v2/.act',
- environ={'REQUEST_METHOD': 'PUT', 'swift.cache': FakeMemcache()},
- headers={'X-Auth-Admin-User': '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'},).get_response(
- self.test_auth)
- self.assertEquals(resp.status_int, 400)
-
- def test_put_account_fail_on_initial_account_head(self):
- self.test_auth.app = FakeApp(iter([
- # Initial HEAD of account container to check for
- # pre-existence
- ('503 Service Unavailable', {}, '')]))
- resp = Request.blank(
- '/auth/v2/act',
- environ={'REQUEST_METHOD': 'PUT',
- 'swift.cache': FakeMemcache()},
- headers={'X-Auth-Admin-User': '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}).get_response(
- self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- def test_put_account_fail_on_account_marker_put(self):
- self.test_auth.app = FakeApp(iter([
- # Initial HEAD of account container to check for
- # pre-existence
- ('404 Not Found', {}, ''),
- # PUT of account container
- ('503 Service Unavailable', {}, '')]))
- resp = Request.blank(
- '/auth/v2/act',
- environ={'REQUEST_METHOD': 'PUT',
- 'swift.cache': FakeMemcache()},
- headers={'X-Auth-Admin-User': '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}).get_response(
- self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 2)
-
- def test_put_account_fail_on_storage_account_put(self):
- conn = FakeConn(iter([
- # PUT of storage account itself
- ('503 Service Unavailable', {}, '')]))
- self.test_auth.get_conn = lambda: conn
- self.test_auth.app = FakeApp(iter([
- # Initial HEAD of account container to check for
- # pre-existence
- ('404 Not Found', {}, ''),
- # PUT of account container
- ('204 No Content', {}, '')]))
- resp = Request.blank(
- '/auth/v2/act',
- environ={'REQUEST_METHOD': 'PUT',
- 'swift.cache': FakeMemcache()},
- headers={'X-Auth-Admin-User': '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}).get_response(
- self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(conn.calls, 1)
- self.assertEquals(self.test_auth.app.calls, 2)
-
- def test_put_account_fail_on_account_id_mapping(self):
- conn = FakeConn(iter([
- # PUT of storage account itself
- ('201 Created', {}, '')]))
- self.test_auth.get_conn = lambda: conn
- self.test_auth.app = FakeApp(iter([
- # Initial HEAD of account container to check for
- # pre-existence
- ('404 Not Found', {}, ''),
- # PUT of account container
- ('204 No Content', {}, ''),
- # PUT of .account_id mapping object
- ('503 Service Unavailable', {}, '')]))
- resp = Request.blank(
- '/auth/v2/act',
- environ={'REQUEST_METHOD': 'PUT',
- 'swift.cache': FakeMemcache()},
- headers={'X-Auth-Admin-User': '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}).get_response(
- self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(conn.calls, 1)
- self.assertEquals(self.test_auth.app.calls, 3)
-
- def test_put_account_fail_on_services_object(self):
- conn = FakeConn(iter([
- # PUT of storage account itself
- ('201 Created', {}, '')]))
- self.test_auth.get_conn = lambda: conn
- self.test_auth.app = FakeApp(iter([
- # Initial HEAD of account container to check for
- # pre-existence
- ('404 Not Found', {}, ''),
- # PUT of account container
- ('204 No Content', {}, ''),
- # PUT of .account_id mapping object
- ('204 No Content', {}, ''),
- # PUT of .services object
- ('503 Service Unavailable', {}, '')]))
- resp = Request.blank(
- '/auth/v2/act',
- environ={'REQUEST_METHOD': 'PUT',
- 'swift.cache': FakeMemcache()},
- headers={'X-Auth-Admin-User': '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}).get_response(
- self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(conn.calls, 1)
- self.assertEquals(self.test_auth.app.calls, 4)
-
- def test_put_account_fail_on_post_mapping(self):
- conn = FakeConn(iter([
- # PUT of storage account itself
- ('201 Created', {}, '')]))
- self.test_auth.get_conn = lambda: conn
- self.test_auth.app = FakeApp(iter([
- # Initial HEAD of account container to check for
- # pre-existence
- ('404 Not Found', {}, ''),
- # PUT of account container
- ('204 No Content', {}, ''),
- # PUT of .account_id mapping object
- ('204 No Content', {}, ''),
- # PUT of .services object
- ('204 No Content', {}, ''),
- # POST to account container updating
- # X-Container-Meta-Account-Id
- ('503 Service Unavailable', {}, '')]))
- resp = Request.blank(
- '/auth/v2/act',
- environ={'REQUEST_METHOD': 'PUT', 'swift.cache': FakeMemcache()},
- headers={'X-Auth-Admin-User': '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}).get_response(
- self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(conn.calls, 1)
- self.assertEquals(self.test_auth.app.calls, 5)
-
- def test_delete_account_success(self):
- conn = FakeConn(iter([
- # DELETE of storage account itself
- ('204 No Content', {}, '')]))
- self.test_auth.get_conn = lambda x: conn
- self.test_auth.app = FakeApp(iter([
- # Account's container listing, checking for
- # users
- ('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'},
- json.dumps([
- {"name": ".services", "hash": "etag", "bytes": 112,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:27.618110"}])),
- # Account's container listing, checking for users
- # (continuation)
- ('200 Ok',
- {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, '[]'),
- # GET the .services object
- ('200 Ok', {}, json.dumps(
- {"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}})),
- # DELETE the .services object
- ('204 No Content', {}, ''),
- # DELETE the .account_id mapping object
- ('204 No Content', {}, ''),
- # DELETE the account container
- ('204 No Content', {}, '')]))
- resp = Request.blank('/auth/v2/act',
- environ={
- 'REQUEST_METHOD': 'DELETE',
- 'swift.cache': FakeMemcache()},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 204)
- self.assertEquals(self.test_auth.app.calls, 6)
- self.assertEquals(conn.calls, 1)
-
- def test_delete_account_success_missing_services(self):
- self.test_auth.app = FakeApp(iter([
- # Account's container listing, checking for
- # users
- ('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'},
- json.dumps([
- {"name": ".services", "hash": "etag", "bytes": 112,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:27.618110"}])),
- # Account's container listing, checking for users
- # (continuation)
- ('200 Ok',
- {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, '[]'),
- # GET the .services object
- ('404 Not Found', {}, ''),
- # DELETE the .account_id mapping object
- ('204 No Content', {}, ''),
- # DELETE the account container
- ('204 No Content', {}, '')]))
- resp = Request.blank('/auth/v2/act',
- environ={
- 'REQUEST_METHOD': 'DELETE',
- 'swift.cache': FakeMemcache()},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 204)
- self.assertEquals(self.test_auth.app.calls, 5)
-
- def test_delete_account_success_missing_storage_account(
- self):
- conn = FakeConn(iter([
- # DELETE of storage account itself
- ('404 Not Found', {}, '')]))
- self.test_auth.get_conn = lambda x: conn
- self.test_auth.app = FakeApp(iter([
- # Account's container listing, checking for
- # users
- ('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'},
- json.dumps([
- {"name": ".services", "hash": "etag", "bytes": 112,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:27.618110"}])),
- # Account's container listing, checking for users
- # (continuation)
- ('200 Ok',
- {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, '[]'),
- # GET the .services object
- ('200 Ok', {}, json.dumps(
- {"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}})),
- # DELETE the .services object
- ('204 No Content', {}, ''),
- # DELETE the .account_id mapping object
- ('204 No Content', {}, ''),
- # DELETE the account container
- ('204 No Content', {}, '')]))
- resp = Request.blank('/auth/v2/act',
- environ={
- 'REQUEST_METHOD': 'DELETE',
- 'swift.cache': FakeMemcache()},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 204)
- self.assertEquals(self.test_auth.app.calls, 6)
- self.assertEquals(conn.calls, 1)
-
- def test_delete_account_success_missing_account_id_mapping(
- self):
- conn = FakeConn(iter([
- # DELETE of storage account itself
- ('204 No Content', {}, '')]))
- self.test_auth.get_conn = lambda x: conn
- self.test_auth.app = FakeApp(iter([
- # Account's container listing, checking for
- # users
- ('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'},
- json.dumps([
- {"name": ".services", "hash": "etag", "bytes": 112,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:27.618110"}])),
- # Account's container listing, checking for users
- # (continuation)
- ('200 Ok',
- {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, '[]'),
- # GET the .services object
- ('200 Ok', {}, json.dumps(
- {"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}})),
- # DELETE the .services object
- ('204 No Content', {}, ''),
- # DELETE the .account_id mapping object
- ('404 Not Found', {}, ''),
- # DELETE the account container
- ('204 No Content', {}, '')]))
- resp = Request.blank('/auth/v2/act',
- environ={
- 'REQUEST_METHOD': 'DELETE',
- 'swift.cache': FakeMemcache()},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 204)
- self.assertEquals(self.test_auth.app.calls, 6)
- self.assertEquals(conn.calls, 1)
-
- def test_delete_account_success_missing_account_container_at_end(
- self):
- conn = FakeConn(iter([
- # DELETE of storage account itself
- ('204 No Content', {}, '')]))
- self.test_auth.get_conn = lambda x: conn
- self.test_auth.app = FakeApp(iter([
- # Account's container listing, checking for
- # users
- ('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'},
- json.dumps([
- {"name": ".services", "hash": "etag", "bytes": 112,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:27.618110"}])),
- # Account's container listing, checking for users
- # (continuation)
- ('200 Ok',
- {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, '[]'),
- # GET the .services object
- ('200 Ok', {}, json.dumps(
- {"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}})),
- # DELETE the .services object
- ('204 No Content', {}, ''),
- # DELETE the .account_id mapping object
- ('204 No Content', {}, ''),
- # DELETE the account container
- ('404 Not Found', {}, '')]))
- resp = Request.blank('/auth/v2/act',
- environ={
- 'REQUEST_METHOD': 'DELETE',
- 'swift.cache': FakeMemcache()},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 204)
- self.assertEquals(self.test_auth.app.calls, 6)
- self.assertEquals(conn.calls, 1)
-
- def test_delete_account_fail_bad_creds(self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object
- ('404 Not Found', {}, '')]))
- resp = Request.blank('/auth/v2/act',
- environ={
- 'REQUEST_METHOD': 'DELETE',
- 'swift.cache': FakeMemcache()},
- headers={
- 'X-Auth-Admin-User':
- 'super:admin',
- 'X-Auth-Admin-Key': 'supertest'},
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 403)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- self.test_auth.app = FakeApp(iter([
- # GET of user object (account admin, but not reseller
- # admin)
- ('200 Ok', {}, json.dumps({"groups": [{"name": "act:adm"},
- {"name": "test"}, {"name": ".admin"}],
- "auth": "plaintext:key"}))]))
- resp = Request.blank('/auth/v2/act',
- environ={
- 'REQUEST_METHOD': 'DELETE',
- 'swift.cache': FakeMemcache()},
- headers={
- 'X-Auth-Admin-User':
- 'act:adm',
- 'X-Auth-Admin-Key': 'key'},
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 403)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- self.test_auth.app = FakeApp(iter([
- # GET of user object (regular user)
- ('200 Ok', {}, json.dumps({"groups": [{"name": "act:usr"},
- {"name": "test"}], "auth": "plaintext:key"}))]))
- resp = Request.blank('/auth/v2/act',
- environ={
- 'REQUEST_METHOD': 'DELETE',
- 'swift.cache': FakeMemcache()},
- headers={
- 'X-Auth-Admin-User':
- 'act:usr',
- 'X-Auth-Admin-Key': 'key'},
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 403)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- def test_delete_account_fail_invalid_account_name(self):
- resp = Request.blank('/auth/v2/.act',
- environ={
- 'REQUEST_METHOD': 'DELETE'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 400)
-
- def test_delete_account_fail_not_found(self):
- self.test_auth.app = FakeApp(iter([
- # Account's container listing, checking for
- # users
- ('404 Not Found', {}, '')]))
- resp = Request.blank('/auth/v2/act',
- environ={
- 'REQUEST_METHOD': 'DELETE',
- 'swift.cache': FakeMemcache()},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 404)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- def test_delete_account_fail_not_found_concurrency(
- self):
- self.test_auth.app = FakeApp(iter([
- # Account's container listing, checking for
- # users
- ('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'},
- json.dumps([
- {"name": ".services", "hash": "etag", "bytes": 112,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:27.618110"}])),
- # Account's container listing, checking for users
- # (continuation)
- ('404 Not Found', {}, '')]))
- resp = Request.blank('/auth/v2/act',
- environ={
- 'REQUEST_METHOD': 'DELETE',
- 'swift.cache': FakeMemcache()},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 404)
- self.assertEquals(self.test_auth.app.calls, 2)
-
- def test_delete_account_fail_list_account(self):
- self.test_auth.app = FakeApp(iter([
- # Account's container listing, checking for
- # users
- ('503 Service Unavailable', {}, '')]))
- resp = Request.blank('/auth/v2/act',
- environ={
- 'REQUEST_METHOD': 'DELETE',
- 'swift.cache': FakeMemcache()},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- def test_delete_account_fail_list_account_concurrency(
- self):
- self.test_auth.app = FakeApp(iter([
- # Account's container listing, checking for
- # users
- ('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'},
- json.dumps([
- {"name": ".services", "hash": "etag", "bytes": 112,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:27.618110"}])),
- # Account's container listing, checking for users
- # (continuation)
- ('503 Service Unavailable', {}, '')]))
- resp = Request.blank('/auth/v2/act',
- environ={
- 'REQUEST_METHOD': 'DELETE',
- 'swift.cache': FakeMemcache()},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 2)
-
- def test_delete_account_fail_has_users(self):
- self.test_auth.app = FakeApp(iter([
- # Account's container listing, checking for
- # users
- ('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'},
- json.dumps([
- {"name": ".services", "hash": "etag", "bytes": 112,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:27.618110"},
- {"name": "tester", "hash": "etag", "bytes": 104,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:27.736680"}]))]))
- resp = Request.blank('/auth/v2/act',
- environ={
- 'REQUEST_METHOD': 'DELETE',
- 'swift.cache': FakeMemcache()},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 409)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- def test_delete_account_fail_has_users2(self):
- self.test_auth.app = FakeApp(iter([
- # Account's container listing, checking for
- # users
- ('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'},
- json.dumps([
- {"name": ".services", "hash": "etag", "bytes": 112,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:27.618110"}])),
- # Account's container listing, checking for users
- # (continuation)
- ('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'},
- json.dumps([
- {"name": "tester", "hash": "etag", "bytes": 104,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:27.736680"}]))]))
- resp = Request.blank('/auth/v2/act',
- environ={
- 'REQUEST_METHOD': 'DELETE',
- 'swift.cache': FakeMemcache()},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 409)
- self.assertEquals(self.test_auth.app.calls, 2)
-
- def test_delete_account_fail_get_services(self):
- self.test_auth.app = FakeApp(iter([
- # Account's container listing, checking for
- # users
- ('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'},
- json.dumps([
- {"name": ".services", "hash": "etag", "bytes": 112,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:27.618110"}])),
- # Account's container listing, checking for users
- # (continuation)
- ('200 Ok',
- {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, '[]'),
- # GET the .services object
- ('503 Service Unavailable', {}, '')]))
- resp = Request.blank('/auth/v2/act',
- environ={
- 'REQUEST_METHOD': 'DELETE',
- 'swift.cache': FakeMemcache()},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 3)
-
- def test_delete_account_fail_delete_storage_account(
- self):
- conn = FakeConn(iter([
- # DELETE of storage account itself
- ('409 Conflict', {}, '')]))
- self.test_auth.get_conn = lambda x: conn
- self.test_auth.app = FakeApp(iter([
- # Account's container listing, checking for
- # users
- ('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'},
- json.dumps([
- {"name": ".services", "hash": "etag", "bytes": 112,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:27.618110"}])),
- # Account's container listing, checking for users
- # (continuation)
- ('200 Ok',
- {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, '[]'),
- # GET the .services object
- ('200 Ok', {}, json.dumps(
- {"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}}))]))
- resp = Request.blank('/auth/v2/act',
- environ={
- 'REQUEST_METHOD': 'DELETE',
- 'swift.cache': FakeMemcache()},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 409)
- self.assertEquals(self.test_auth.app.calls, 3)
- self.assertEquals(conn.calls, 1)
-
- def test_delete_account_fail_delete_storage_account2(
- self):
- conn = FakeConn(iter([
- # DELETE of storage account itself
- ('204 No Content', {}, ''),
- # DELETE of storage account itself
- ('409 Conflict', {}, '')]))
- self.test_auth.get_conn = lambda x: conn
- self.test_auth.app = FakeApp(iter([
- # Account's container listing, checking for
- # users
- ('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'},
- json.dumps([
- {"name": ".services", "hash": "etag", "bytes": 112,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:27.618110"}])),
- # Account's container listing, checking for users
- # (continuation)
- ('200 Ok',
- {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, '[]'),
- # GET the .services object
- ('200 Ok', {}, json.dumps(
- {"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa",
- "other": "http://127.0.0.1:8080/v1/AUTH_cfa2"}}))]))
- resp = Request.blank('/auth/v2/act',
- environ={
- 'REQUEST_METHOD': 'DELETE',
- 'swift.cache': FakeMemcache()},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 3)
- self.assertEquals(conn.calls, 2)
-
- def test_delete_account_fail_delete_storage_account3(
- self):
- conn = FakeConn(iter([
- # DELETE of storage account itself
- ('503 Service Unavailable', {}, '')]))
- self.test_auth.get_conn = lambda x: conn
- self.test_auth.app = FakeApp(iter([
- # Account's container listing, checking for
- # users
- ('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'},
- json.dumps([
- {"name": ".services", "hash": "etag", "bytes": 112,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:27.618110"}])),
- # Account's container listing, checking for users
- # (continuation)
- ('200 Ok',
- {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, '[]'),
- # GET the .services object
- ('200 Ok', {}, json.dumps(
- {"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}}))]))
- resp = Request.blank('/auth/v2/act',
- environ={
- 'REQUEST_METHOD': 'DELETE',
- 'swift.cache': FakeMemcache()},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 3)
- self.assertEquals(conn.calls, 1)
-
- def test_delete_account_fail_delete_storage_account4(
- self):
- conn = FakeConn(iter([
- # DELETE of storage account itself
- ('204 No Content', {}, ''),
- # DELETE of storage account itself
- ('503 Service Unavailable', {}, '')]))
- self.test_auth.get_conn = lambda x: conn
- self.test_auth.app = FakeApp(iter([
- # Account's container listing, checking for
- # users
- ('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'},
- json.dumps([
- {"name": ".services", "hash": "etag", "bytes": 112,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:27.618110"}])),
- # Account's container listing, checking for users
- # (continuation)
- ('200 Ok',
- {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, '[]'),
- # GET the .services object
- ('200 Ok', {}, json.dumps(
- {"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa",
- "other": "http://127.0.0.1:8080/v1/AUTH_cfa2"}}))]))
- resp = Request.blank('/auth/v2/act',
- environ={
- 'REQUEST_METHOD': 'DELETE',
- 'swift.cache': FakeMemcache()},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 3)
- self.assertEquals(conn.calls, 2)
-
- def test_delete_account_fail_delete_services(self):
- conn = FakeConn(iter([
- # DELETE of storage account itself
- ('204 No Content', {}, '')]))
- self.test_auth.get_conn = lambda x: conn
- self.test_auth.app = FakeApp(iter([
- # Account's container listing, checking for
- # users
- ('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'},
- json.dumps([
- {"name": ".services", "hash": "etag", "bytes": 112,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:27.618110"}])),
- # Account's container listing, checking for users
- # (continuation)
- ('200 Ok',
- {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, '[]'),
- # GET the .services object
- ('200 Ok', {}, json.dumps(
- {"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}})),
- # DELETE the .services object
- ('503 Service Unavailable', {}, '')]))
- resp = Request.blank('/auth/v2/act',
- environ={
- 'REQUEST_METHOD': 'DELETE',
- 'swift.cache': FakeMemcache()},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 4)
- self.assertEquals(conn.calls, 1)
-
- def test_delete_account_fail_delete_account_id_mapping(
- self):
- conn = FakeConn(iter([
- # DELETE of storage account itself
- ('204 No Content', {}, '')]))
- self.test_auth.get_conn = lambda x: conn
- self.test_auth.app = FakeApp(iter([
- # Account's container listing, checking for
- # users
- ('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'},
- json.dumps([
- {"name": ".services", "hash": "etag", "bytes": 112,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:27.618110"}])),
- # Account's container listing, checking for users
- # (continuation)
- ('200 Ok',
- {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, '[]'),
- # GET the .services object
- ('200 Ok', {}, json.dumps(
- {"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}})),
- # DELETE the .services object
- ('204 No Content', {}, ''),
- # DELETE the .account_id mapping object
- ('503 Service Unavailable', {}, '')]))
- resp = Request.blank('/auth/v2/act',
- environ={
- 'REQUEST_METHOD': 'DELETE',
- 'swift.cache': FakeMemcache()},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 5)
- self.assertEquals(conn.calls, 1)
-
- def test_delete_account_fail_delete_account_container(
- self):
- conn = FakeConn(iter([
- # DELETE of storage account itself
- ('204 No Content', {}, '')]))
- self.test_auth.get_conn = lambda x: conn
- self.test_auth.app = FakeApp(iter([
- # Account's container listing, checking for
- # users
- ('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'},
- json.dumps([
- {"name": ".services", "hash": "etag", "bytes": 112,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:27.618110"}])),
- # Account's container listing, checking for users
- # (continuation)
- ('200 Ok',
- {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, '[]'),
- # GET the .services object
- ('200 Ok', {}, json.dumps(
- {"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}})),
- # DELETE the .services object
- ('204 No Content', {}, ''),
- # DELETE the .account_id mapping object
- ('204 No Content', {}, ''),
- # DELETE the account container
- ('503 Service Unavailable', {}, '')]))
- resp = Request.blank('/auth/v2/act',
- environ={
- 'REQUEST_METHOD': 'DELETE',
- 'swift.cache': FakeMemcache()},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 6)
- self.assertEquals(conn.calls, 1)
-
- def test_get_user_success(self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object
- ('200 Ok', {}, json.dumps(
- {"groups": [{"name": "act:usr"}, {"name": "act"},
- {"name": ".admin"}],
- "auth": "plaintext:key"}))]))
- resp = Request.blank('/auth/v2/act/usr',
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 200)
- self.assertEquals(resp.body, json.dumps(
- {"groups": [{"name": "act:usr"}, {"name": "act"},
- {"name": ".admin"}],
- "auth": "plaintext:key"}))
- self.assertEquals(self.test_auth.app.calls, 1)
-
- def test_get_user_fail_no_super_admin_key(self):
- local_auth = auth.filter_factory({})(FakeApp(iter([
- # GET of user object (but we should never get
- # here)
- ('200 Ok', {}, json.dumps(
- {"groups": [{"name": "act:usr"}, {"name": "act"},
- {"name": ".admin"}],
- "auth": "plaintext:key"}))])))
- resp = Request.blank('/auth/v2/act/usr',
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(local_auth)
- self.assertEquals(resp.status_int, 404)
- self.assertEquals(local_auth.app.calls, 0)
-
- def test_get_user_groups_success(self):
- self.test_auth.app = FakeApp(iter([
- # GET of account container (list objects)
- ('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'},
- json.dumps([
- {"name": ".services", "hash": "etag", "bytes": 112,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:27.618110"},
- {"name": "tester", "hash": "etag", "bytes": 104,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:27.736680"},
- {"name": "tester3", "hash": "etag", "bytes": 86,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:28.135530"}])),
- # GET of user object
- ('200 Ok', {}, json.dumps(
- {"groups": [{"name": "act:tester"}, {"name": "act"},
- {"name": ".admin"}],
- "auth": "plaintext:key"})),
- # GET of user object
- ('200 Ok', {}, json.dumps(
- {"groups": [{"name": "act:tester3"}, {"name": "act"}],
- "auth": "plaintext:key3"})),
- # GET of account container (list objects
- # continuation)
- ('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, '[]')]))
- resp = Request.blank('/auth/v2/act/.groups',
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 200)
- self.assertEquals(resp.body, json.dumps(
- {"groups": [{"name": ".admin"}, {"name": "act"},
- {"name": "act:tester"}, {"name": "act:tester3"}]}))
- self.assertEquals(self.test_auth.app.calls, 4)
-
- def test_get_user_groups_success2(self):
- self.test_auth.app = FakeApp(iter([
- # GET of account container (list objects)
- ('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'},
- json.dumps([
- {"name": ".services", "hash": "etag", "bytes": 112,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:27.618110"},
- {"name": "tester", "hash": "etag", "bytes": 104,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:27.736680"}])),
- # GET of user object
- ('200 Ok', {}, json.dumps(
- {"groups": [{"name": "act:tester"}, {"name": "act"},
- {"name": ".admin"}],
- "auth": "plaintext:key"})),
- # GET of account container (list objects
- # continuation)
- ('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'},
- json.dumps([
- {"name": "tester3", "hash": "etag", "bytes": 86,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:28.135530"}])),
- # GET of user object
- ('200 Ok', {}, json.dumps(
- {"groups": [{"name": "act:tester3"}, {"name": "act"}],
- "auth": "plaintext:key3"})),
- # GET of account container (list objects
- # continuation)
- ('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, '[]')]))
- resp = Request.blank('/auth/v2/act/.groups',
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 200)
- self.assertEquals(resp.body, json.dumps(
- {"groups": [{"name": ".admin"}, {"name": "act"},
- {"name": "act:tester"}, {"name": "act:tester3"}]}))
- self.assertEquals(self.test_auth.app.calls, 5)
-
- def test_get_user_fail_invalid_account(self):
- resp = Request.blank('/auth/v2/.invalid/usr',
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 400)
-
- def test_get_user_fail_invalid_user(self):
- resp = Request.blank('/auth/v2/act/.invalid',
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 400)
-
- def test_get_user_fail_bad_creds(self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object
- ('404 Not Found', {}, '')]))
- resp = Request.blank('/auth/v2/act/usr',
- headers={
- 'X-Auth-Admin-User':
- 'super:admin',
- 'X-Auth-Admin-Key': 'supertest'},
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 403)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- self.test_auth.app = FakeApp(iter([
- # GET of user object (regular user)
- ('200 Ok', {}, json.dumps({"groups": [{"name": "act:usr"},
- {"name": "test"}], "auth": "plaintext:key"}))]))
- resp = Request.blank('/auth/v2/act/usr',
- headers={
- 'X-Auth-Admin-User':
- 'act:usr',
- 'X-Auth-Admin-Key': 'key'},
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 403)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- def test_get_user_account_admin_success(self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object (account admin, but not reseller
- # admin)
- ('200 Ok', {}, json.dumps({"groups": [{"name": "act:adm"},
- {"name": "test"}, {"name": ".admin"}],
- "auth": "plaintext:key"})),
- # GET of requested user object
- ('200 Ok', {}, json.dumps(
- {"groups": [{"name": "act:usr"}, {"name": "act"}],
- "auth": "plaintext:key"}))]))
- resp = Request.blank('/auth/v2/act/usr',
- headers={
- 'X-Auth-Admin-User':
- 'act:adm',
- 'X-Auth-Admin-Key': 'key'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 200)
- self.assertEquals(resp.body, json.dumps(
- {"groups": [{"name": "act:usr"}, {"name": "act"}],
- "auth": "plaintext:key"}))
- self.assertEquals(self.test_auth.app.calls, 2)
-
- def test_get_user_account_admin_fail_getting_account_admin(
- self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object (account admin check)
- ('200 Ok', {}, json.dumps({"groups": [{"name": "act:adm"},
- {"name": "test"}, {"name": ".admin"}],
- "auth": "plaintext:key"})),
- # GET of requested user object [who is an .admin
- # as well]
- ('200 Ok', {}, json.dumps(
- {"groups": [{"name": "act:usr"}, {"name": "act"},
- {"name": ".admin"}],
- "auth": "plaintext:key"})),
- # GET of user object (reseller admin check [and fail
- # here])
- ('200 Ok', {}, json.dumps({"groups": [{"name": "act:adm"},
- {"name": "test"}, {"name": ".admin"}],
- "auth": "plaintext:key"}))]))
- resp = Request.blank('/auth/v2/act/usr',
- headers={
- 'X-Auth-Admin-User':
- 'act:adm',
- 'X-Auth-Admin-Key': 'key'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 403)
- self.assertEquals(self.test_auth.app.calls, 3)
-
- def test_get_user_account_admin_fail_getting_reseller_admin(
- self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object (account admin check)
- ('200 Ok', {}, json.dumps({"groups": [{"name": "act:adm"},
- {"name": "test"}, {"name": ".admin"}],
- "auth": "plaintext:key"})),
- # GET of requested user object [who is a
- # .reseller_admin]
- ('200 Ok', {}, json.dumps(
- {"groups": [{"name": "act:usr"}, {"name": "act"},
- {"name": ".reseller_admin"}],
- "auth": "plaintext:key"}))]))
- resp = Request.blank('/auth/v2/act/usr',
- headers={
- 'X-Auth-Admin-User':
- 'act:adm',
- 'X-Auth-Admin-Key': 'key'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 403)
- self.assertEquals(self.test_auth.app.calls, 2)
-
- def test_get_user_reseller_admin_fail_getting_reseller_admin(
- self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object (account admin check)
- ('200 Ok', {}, json.dumps({"groups": [{"name": "act:adm"},
- {"name": "test"}, {"name": ".reseller_admin"}],
- "auth": "plaintext:key"})),
- # GET of requested user object [who also is a
- # .reseller_admin]
- ('200 Ok', {}, json.dumps(
- {"groups": [{"name": "act:usr"}, {"name": "act"},
- {"name": ".reseller_admin"}],
- "auth": "plaintext:key"}))]))
- resp = Request.blank('/auth/v2/act/usr',
- headers={
- 'X-Auth-Admin-User':
- 'act:adm',
- 'X-Auth-Admin-Key': 'key'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 403)
- self.assertEquals(self.test_auth.app.calls, 2)
-
- def test_get_user_super_admin_succeed_getting_reseller_admin(
- self):
- self.test_auth.app = FakeApp(iter([
- # GET of requested user object
- ('200 Ok', {}, json.dumps(
- {"groups": [{"name": "act:usr"}, {"name": "act"},
- {"name": ".reseller_admin"}],
- "auth": "plaintext:key"}))]))
- resp = Request.blank('/auth/v2/act/usr',
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 200)
- self.assertEquals(resp.body, json.dumps(
- {"groups": [{"name": "act:usr"}, {"name": "act"},
- {"name": ".reseller_admin"}],
- "auth": "plaintext:key"}))
- self.assertEquals(self.test_auth.app.calls, 1)
-
- def test_get_user_groups_not_found(self):
- self.test_auth.app = FakeApp(iter([
- # GET of account container (list objects)
- ('404 Not Found', {}, '')]))
- resp = Request.blank('/auth/v2/act/.groups',
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 404)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- def test_get_user_groups_fail_listing(self):
- self.test_auth.app = FakeApp(iter([
- # GET of account container (list objects)
- ('503 Service Unavailable', {}, '')]))
- resp = Request.blank('/auth/v2/act/.groups',
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- def test_get_user_groups_fail_get_user(self):
- self.test_auth.app = FakeApp(iter([
- # GET of account container (list objects)
- ('200 Ok', {'X-Container-Meta-Account-Id': 'AUTH_cfa'},
- json.dumps([
- {"name": ".services", "hash": "etag", "bytes": 112,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:27.618110"},
- {"name": "tester", "hash": "etag", "bytes": 104,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:27.736680"},
- {"name": "tester3", "hash": "etag", "bytes": 86,
- "content_type":
- "application/octet-stream",
- "last_modified": "2010-12-03T17:16:28.135530"}])),
- # GET of user object
- ('503 Service Unavailable', {}, '')]))
- resp = Request.blank('/auth/v2/act/.groups',
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 2)
-
- def test_get_user_not_found(self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object
- ('404 Not Found', {}, '')]))
- resp = Request.blank('/auth/v2/act/usr',
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 404)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- def test_get_user_fail(self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object
- ('503 Service Unavailable', {}, '')]))
- resp = Request.blank('/auth/v2/act/usr',
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key':
- 'supertest',
- 'X-Auth-User-Key': 'key'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- def test_put_user_fail_invalid_account(self):
- resp = Request.blank('/auth/v2/.invalid/usr',
- environ={
- 'REQUEST_METHOD': 'PUT'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key':
- 'supertest',
- 'X-Auth-User-Key': 'key'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 400)
-
- def test_put_user_fail_invalid_user(self):
- resp = Request.blank('/auth/v2/act/.usr',
- environ={
- 'REQUEST_METHOD': 'PUT'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key':
- 'supertest',
- 'X-Auth-User-Key': 'key'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 400)
-
- def test_put_user_fail_no_user_key(self):
- resp = Request.blank('/auth/v2/act/usr',
- environ={
- 'REQUEST_METHOD': 'PUT'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 400)
-
- def test_put_user_reseller_admin_fail_bad_creds(self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object (reseller admin)
- # This shouldn't actually get called, checked
- # below
- ('200 Ok', {}, json.dumps({"groups": [{"name": "act:rdm"},
- {"name": "test"}, {"name": ".admin"},
- {"name": ".reseller_admin"}], "auth": "plaintext:key"}))]))
- resp = Request.blank('/auth/v2/act/usr',
- environ={
- 'REQUEST_METHOD': 'PUT'},
- headers={
- 'X-Auth-Admin-User':
- 'act:rdm',
- 'X-Auth-Admin-Key':
- 'key',
- 'X-Auth-User-Key':
- 'key',
- 'X-Auth-User-Reseller-Admin': 'true'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 403)
- self.assertEquals(self.test_auth.app.calls, 0)
-
- self.test_auth.app = FakeApp(iter([
- # GET of user object (account admin, but not reseller admin)
- # This shouldn't actually get called, checked
- # below
- ('200 Ok', {}, json.dumps({"groups": [{"name": "act:adm"},
- {"name": "test"}, {"name": ".admin"}],
- "auth": "plaintext:key"}))]))
- resp = Request.blank('/auth/v2/act/usr',
- environ={
- 'REQUEST_METHOD': 'PUT'},
- headers={
- 'X-Auth-Admin-User':
- 'act:adm',
- 'X-Auth-Admin-Key':
- 'key',
- 'X-Auth-User-Key':
- 'key',
- 'X-Auth-User-Reseller-Admin': 'true'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 403)
- self.assertEquals(self.test_auth.app.calls, 0)
-
- self.test_auth.app = FakeApp(iter([
- # GET of user object (regular user)
- # This shouldn't actually get called, checked
- # below
- ('200 Ok', {}, json.dumps({"groups": [{"name": "act:usr"},
- {"name": "test"}], "auth": "plaintext:key"}))]))
- resp = Request.blank('/auth/v2/act/usr',
- environ={
- 'REQUEST_METHOD': 'PUT'},
- headers={
- 'X-Auth-Admin-User':
- 'act:adm',
- 'X-Auth-Admin-Key':
- 'key',
- 'X-Auth-User-Key':
- 'key',
- 'X-Auth-User-Reseller-Admin': 'true'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 403)
- self.assertEquals(self.test_auth.app.calls, 0)
-
- def test_put_user_account_admin_fail_bad_creds(self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object (account admin, but wrong
- # account)
- ('200 Ok', {}, json.dumps({"groups": [{"name": "act2:adm"},
- {"name": "test"}, {"name": ".admin"}],
- "auth": "plaintext:key"}))]))
- resp = Request.blank('/auth/v2/act/usr',
- environ={
- 'REQUEST_METHOD': 'PUT'},
- headers={
- 'X-Auth-Admin-User':
- 'act2:adm',
- 'X-Auth-Admin-Key':
- 'key',
- 'X-Auth-User-Key':
- 'key',
- 'X-Auth-User-Admin': 'true'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 403)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- self.test_auth.app = FakeApp(iter([
- # GET of user object (regular user)
- ('200 Ok', {}, json.dumps({"groups": [{"name": "act:usr"},
- {"name": "test"}], "auth": "plaintext:key"}))]))
- resp = Request.blank('/auth/v2/act/usr',
- environ={
- 'REQUEST_METHOD': 'PUT'},
- headers={
- 'X-Auth-Admin-User':
- 'act:usr',
- 'X-Auth-Admin-Key':
- 'key',
- 'X-Auth-User-Key':
- 'key',
- 'X-Auth-User-Admin': 'true'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 403)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- def test_put_user_regular_fail_bad_creds(self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object (account admin, but wrong
- # account)
- ('200 Ok', {}, json.dumps({"groups": [{"name": "act2:adm"},
- {"name": "test"}, {"name": ".admin"}],
- "auth": "plaintext:key"}))]))
- resp = Request.blank('/auth/v2/act/usr',
- environ={
- 'REQUEST_METHOD': 'PUT'},
- headers={
- 'X-Auth-Admin-User':
- 'act2:adm',
- 'X-Auth-Admin-Key':
- 'key',
- 'X-Auth-User-Key': 'key'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 403)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- self.test_auth.app = FakeApp(iter([
- # GET of user object (regular user)
- ('200 Ok', {}, json.dumps({"groups": [{"name": "act:usr"},
- {"name": "test"}], "auth": "plaintext:key"}))]))
- resp = Request.blank('/auth/v2/act/usr',
- environ={
- 'REQUEST_METHOD': 'PUT'},
- headers={
- 'X-Auth-Admin-User':
- 'act:usr',
- 'X-Auth-Admin-Key':
- 'key',
- 'X-Auth-User-Key': 'key'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 403)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- def test_put_user_regular_success(self):
- self.test_auth.app = FakeApp(iter([
- ('200 Ok',
- {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, ''),
- # PUT of user object
- ('201 Created', {}, '')]))
- resp = Request.blank('/auth/v2/act/usr',
- environ={
- 'REQUEST_METHOD': 'PUT'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key':
- 'supertest',
- 'X-Auth-User-Key': 'key'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 201)
- self.assertEquals(self.test_auth.app.calls, 2)
- self.assertEquals(
- json.loads(self.test_auth.app.request.body),
- {"groups": [{"name": "act:usr"}, {"name": "act"}],
- "auth": "plaintext:key"})
-
- def test_put_user_special_chars_success(self):
- self.test_auth.app = FakeApp(iter([
- ('200 Ok',
- {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, ''),
- # PUT of user object
- ('201 Created', {}, '')]))
- resp = Request.blank('/auth/v2/act/u_s-r',
- environ={
- 'REQUEST_METHOD': 'PUT'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key':
- 'supertest',
- 'X-Auth-User-Key': 'key'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 201)
- self.assertEquals(self.test_auth.app.calls, 2)
- self.assertEquals(
- json.loads(self.test_auth.app.request.body),
- {"groups": [{"name": "act:u_s-r"}, {"name": "act"}],
- "auth": "plaintext:key"})
-
- def test_put_user_account_admin_success(self):
- self.test_auth.app = FakeApp(iter([
- ('200 Ok',
- {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, ''),
- # PUT of user object
- ('201 Created', {}, '')]))
- resp = Request.blank('/auth/v2/act/usr',
- environ={
- 'REQUEST_METHOD': 'PUT'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key':
- 'supertest',
- 'X-Auth-User-Key': 'key',
- 'X-Auth-User-Admin': 'true'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 201)
- self.assertEquals(self.test_auth.app.calls, 2)
- self.assertEquals(
- json.loads(self.test_auth.app.request.body),
- {"groups": [{"name": "act:usr"}, {"name": "act"},
- {"name": ".admin"}],
- "auth": "plaintext:key"})
-
- def test_put_user_reseller_admin_success(self):
- self.test_auth.app = FakeApp(iter([
- ('200 Ok',
- {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, ''),
- # PUT of user object
- ('201 Created', {}, '')]))
- resp = Request.blank('/auth/v2/act/usr',
- environ={
- 'REQUEST_METHOD': 'PUT'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key':
- 'supertest',
- 'X-Auth-User-Key': 'key',
- 'X-Auth-User-Reseller-Admin': 'true'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 201)
- self.assertEquals(self.test_auth.app.calls, 2)
- self.assertEquals(
- json.loads(self.test_auth.app.request.body),
- {"groups": [{"name": "act:usr"}, {"name": "act"},
- {"name": ".admin"}, {"name": ".reseller_admin"}],
- "auth": "plaintext:key"})
-
- def test_put_user_fail_not_found(self):
- self.test_auth.app = FakeApp(iter([
- ('200 Ok',
- {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, ''),
- # PUT of user object
- ('404 Not Found', {}, '')]))
- resp = Request.blank('/auth/v2/act/usr',
- environ={
- 'REQUEST_METHOD': 'PUT'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key':
- 'supertest',
- 'X-Auth-User-Key': 'key'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 404)
- self.assertEquals(self.test_auth.app.calls, 2)
-
- def test_put_user_fail(self):
- self.test_auth.app = FakeApp(iter([
- # PUT of user object
- ('503 Service Unavailable', {}, '')]))
- resp = Request.blank('/auth/v2/act/usr',
- environ={
- 'REQUEST_METHOD': 'PUT'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key':
- 'supertest',
- 'X-Auth-User-Key': 'key'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- def test_delete_user_bad_creds(self):
- self.test_auth.app = FakeApp(iter([
- # GET of user object (account admin, but wrong
- # account)
- ('200 Ok', {}, json.dumps({"groups": [{"name": "act2:adm"},
- {"name": "test"}, {"name": ".admin"}],
- "auth": "plaintext:key"}))]))
- resp = Request.blank('/auth/v2/act/usr',
- environ={
- 'REQUEST_METHOD': 'DELETE'},
- headers={
- 'X-Auth-Admin-User':
- 'act2:adm',
- 'X-Auth-Admin-Key': 'key'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 403)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- self.test_auth.app = FakeApp(iter([
- # GET of user object (regular user)
- ('200 Ok', {}, json.dumps({"groups": [{"name": "act:usr"},
- {"name": "test"}], "auth": "plaintext:key"}))]))
- resp = Request.blank('/auth/v2/act/usr',
- environ={
- 'REQUEST_METHOD': 'DELETE'},
- headers={
- 'X-Auth-Admin-User':
- 'act:usr',
- 'X-Auth-Admin-Key': 'key'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 403)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- def test_delete_user_invalid_account(self):
- resp = Request.blank('/auth/v2/.invalid/usr',
- environ={
- 'REQUEST_METHOD': 'DELETE'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 400)
-
- def test_delete_user_invalid_user(self):
- resp = Request.blank('/auth/v2/act/.invalid',
- environ={
- 'REQUEST_METHOD': 'DELETE'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 400)
-
- def test_delete_user_not_found(self):
- self.test_auth.app = FakeApp(iter([
- # HEAD of user object
- ('404 Not Found', {}, '')]))
- resp = Request.blank('/auth/v2/act/usr',
- environ={
- 'REQUEST_METHOD': 'DELETE'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 404)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- def test_delete_user_fail_head_user(self):
- self.test_auth.app = FakeApp(iter([
- # HEAD of user object
- ('503 Service Unavailable', {}, '')]))
- resp = Request.blank('/auth/v2/act/usr',
- environ={
- 'REQUEST_METHOD': 'DELETE'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- def test_delete_user_fail_delete_token(self):
- self.test_auth.app = FakeApp(iter([
- # HEAD of user object
- ('200 Ok',
- {'X-Object-Meta-Auth-Token': 'AUTH_tk'}, ''),
- # DELETE of token
- ('503 Service Unavailable', {}, '')]))
- resp = Request.blank('/auth/v2/act/usr',
- environ={
- 'REQUEST_METHOD': 'DELETE'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 2)
-
- def test_delete_user_fail_delete_user(self):
- self.test_auth.app = FakeApp(iter([
- # HEAD of user object
- ('200 Ok',
- {'X-Object-Meta-Auth-Token': 'AUTH_tk'}, ''),
- # DELETE of token
- ('204 No Content', {}, ''),
- # DELETE of user object
- ('503 Service Unavailable', {}, '')]))
- resp = Request.blank('/auth/v2/act/usr',
- environ={
- 'REQUEST_METHOD': 'DELETE'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(self.test_auth.app.calls, 3)
-
- def test_delete_user_success(self):
- self.test_auth.app = FakeApp(iter([
- # HEAD of user object
- ('200 Ok',
- {'X-Object-Meta-Auth-Token': 'AUTH_tk'}, ''),
- # DELETE of token
- ('204 No Content', {}, ''),
- # DELETE of user object
- ('204 No Content', {}, '')]))
- resp = Request.blank('/auth/v2/act/usr',
- environ={
- 'REQUEST_METHOD': 'DELETE'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 204)
- self.assertEquals(self.test_auth.app.calls, 3)
-
- def test_delete_user_success_missing_user_at_end(self):
- self.test_auth.app = FakeApp(iter([
- # HEAD of user object
- ('200 Ok',
- {'X-Object-Meta-Auth-Token': 'AUTH_tk'}, ''),
- # DELETE of token
- ('204 No Content', {}, ''),
- # DELETE of user object
- ('404 Not Found', {}, '')]))
- resp = Request.blank('/auth/v2/act/usr',
- environ={
- 'REQUEST_METHOD': 'DELETE'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 204)
- self.assertEquals(self.test_auth.app.calls, 3)
-
- def test_delete_user_success_missing_token(self):
- self.test_auth.app = FakeApp(iter([
- # HEAD of user object
- ('200 Ok',
- {'X-Object-Meta-Auth-Token': 'AUTH_tk'}, ''),
- # DELETE of token
- ('404 Not Found', {}, ''),
- # DELETE of user object
- ('204 No Content', {}, '')]))
- resp = Request.blank('/auth/v2/act/usr',
- environ={
- 'REQUEST_METHOD': 'DELETE'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 204)
- self.assertEquals(self.test_auth.app.calls, 3)
-
- def test_delete_user_success_no_token(self):
- self.test_auth.app = FakeApp(iter([
- # HEAD of user object
- ('200 Ok', {}, ''),
- # DELETE of user object
- ('204 No Content', {}, '')]))
- resp = Request.blank('/auth/v2/act/usr',
- environ={
- 'REQUEST_METHOD': 'DELETE'},
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 204)
- self.assertEquals(self.test_auth.app.calls, 2)
-
- def test_validate_token_bad_prefix(self):
- resp = Request.blank('/auth/v2/.token/BAD_token'
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 400)
-
- def test_validate_token_tmi(self):
- resp = Request.blank(
- '/auth/v2/.token/AUTH_token/tmi').get_response(self.test_auth)
- self.assertEquals(resp.status_int, 400)
-
- def test_validate_token_bad_memcache(self):
- fake_memcache = FakeMemcache()
- fake_memcache.set('AUTH_/auth/AUTH_token', 'bogus')
- resp = Request.blank(
- '/auth/v2/.token/AUTH_token',
- environ={'swift.cache': fake_memcache}).get_response(
- self.test_auth)
- self.assertEquals(resp.status_int, 500)
-
- def test_validate_token_from_memcache(self):
- fake_memcache = FakeMemcache()
- fake_memcache.set(
- 'AUTH_/auth/AUTH_token',
- (time() + 1,
- 'act:usr,act'))
- resp = Request.blank(
- '/auth/v2/.token/AUTH_token',
- environ={'swift.cache': fake_memcache}).get_response(
- self.test_auth)
- self.assertEquals(resp.status_int, 204)
- self.assertEquals(
- resp.headers.get('x-auth-groups'),
- 'act:usr,act')
- self.assert_(float(resp.headers['x-auth-ttl']) < 1,
- resp.headers['x-auth-ttl'])
-
- def test_validate_token_from_memcache_expired(self):
- fake_memcache = FakeMemcache()
- fake_memcache.set(
- 'AUTH_/auth/AUTH_token',
- (time() - 1,
- 'act:usr,act'))
- resp = Request.blank(
- '/auth/v2/.token/AUTH_token',
- environ={'swift.cache': fake_memcache}).get_response(
- self.test_auth)
- self.assertEquals(resp.status_int, 404)
- self.assert_('x-auth-groups' not in resp.headers)
- self.assert_('x-auth-ttl' not in resp.headers)
-
- def test_validate_token_from_object(self):
- self.test_auth.app = FakeApp(iter([
- # GET of token object
- ('200 Ok', {}, json.dumps({'groups': [{'name': 'act:usr'},
- {'name': 'act'}], 'expires': time() + 1}))]))
- resp = Request.blank('/auth/v2/.token/AUTH_token'
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 204)
- self.assertEquals(self.test_auth.app.calls, 1)
- self.assertEquals(
- resp.headers.get('x-auth-groups'),
- 'act:usr,act')
- self.assert_(float(resp.headers['x-auth-ttl']) < 1,
- resp.headers['x-auth-ttl'])
-
- def test_validate_token_from_object_expired(self):
- self.test_auth.app = FakeApp(iter([
- # GET of token object
- ('200 Ok', {}, json.dumps({'groups': 'act:usr,act',
- 'expires': time() - 1})),
- # DELETE of expired token object
- ('204 No Content', {}, '')]))
- resp = Request.blank('/auth/v2/.token/AUTH_token'
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 404)
- self.assertEquals(self.test_auth.app.calls, 2)
-
- def test_validate_token_from_object_with_admin(self):
- self.test_auth.app = FakeApp(iter([
- # GET of token object
- ('200 Ok', {}, json.dumps({'account_id': 'AUTH_cfa', 'groups':
- [{'name': 'act:usr'},
- {'name': 'act'},
- {'name': '.admin'}],
- 'expires': time() + 1}))]))
- resp = Request.blank('/auth/v2/.token/AUTH_token'
- ).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 204)
- self.assertEquals(self.test_auth.app.calls, 1)
- self.assertEquals(resp.headers.get('x-auth-groups'),
- 'act:usr,act,AUTH_cfa')
- self.assert_(float(resp.headers['x-auth-ttl']) < 1,
- resp.headers['x-auth-ttl'])
-
- def test_get_conn_default(self):
- conn = self.test_auth.get_conn()
- self.assertEquals(
- conn.__class__,
- auth.HTTPConnection)
- self.assertEquals(conn.host, '127.0.0.1')
- self.assertEquals(conn.port, 8080)
-
- def test_get_conn_default_https(self):
- local_auth = auth.filter_factory(
- {'super_admin_key': 'supertest',
- 'default_swift_cluster': 'local#https://1.2.3.4/v1'})(FakeApp())
- conn = local_auth.get_conn()
- self.assertEquals(
- conn.__class__,
- auth.HTTPSConnection)
- self.assertEquals(conn.host, '1.2.3.4')
- self.assertEquals(conn.port, 443)
-
- def test_get_conn_overridden(self):
- local_auth = auth.filter_factory(
- {'super_admin_key': 'supertest',
- 'default_swift_cluster': 'local#https://1.2.3.4/v1'})(FakeApp())
- conn = \
- local_auth.get_conn(
- urlparsed=auth.urlparse('http://5.6.7.8/v1'))
- self.assertEquals(
- conn.__class__,
- auth.HTTPConnection)
- self.assertEquals(conn.host, '5.6.7.8')
- self.assertEquals(conn.port, 80)
-
- def test_get_conn_overridden_https(self):
- local_auth = auth.filter_factory(
- {'super_admin_key': 'supertest',
- 'default_swift_cluster': 'local#http://1.2.3.4/v1'})(FakeApp())
- conn = \
- local_auth.get_conn(
- urlparsed=auth.urlparse(
- 'https://5.6.7.8/v1'))
- self.assertEquals(
- conn.__class__,
- auth.HTTPSConnection)
- self.assertEquals(conn.host, '5.6.7.8')
- self.assertEquals(conn.port, 443)
-
- def test_get_itoken_fail_no_memcache(self):
- exc = None
- try:
- self.test_auth.get_itoken({})
- except Exception as err:
- exc = err
- self.assertEquals(str(exc),
- 'No memcache set up; required for Swauth middleware')
-
- def test_get_itoken_success(self):
- fmc = FakeMemcache()
- itk = self.test_auth.get_itoken(
- {'swift.cache': fmc})
- self.assert_(itk.startswith('AUTH_itk'), itk)
- expires, groups = fmc.get('AUTH_/auth/%s' % itk)
- self.assert_(expires > time(), expires)
- self.assertEquals(
- groups,
- '.auth,.reseller_admin,AUTH_.auth')
-
- def test_get_admin_detail_fail_no_colon(self):
- self.test_auth.app = FakeApp(iter([]))
- self.assertEquals(
- self.test_auth.get_admin_detail(
- Request.blank('/')),
- None)
- self.assertEquals(
- self.test_auth.get_admin_detail(
- Request.blank('/',
- headers={'X-Auth-Admin-User': 'usr'})), None)
- self.assertRaises(
- StopIteration, self.test_auth.get_admin_detail,
- Request.blank('/', headers={'X-Auth-Admin-User': 'act:usr'}))
-
- def test_get_admin_detail_fail_user_not_found(self):
- self.test_auth.app = FakeApp(
- iter([('404 Not Found', {}, '')]))
- self.assertEquals(
- self.test_auth.get_admin_detail(
- Request.blank('/',
- headers={'X-Auth-Admin-User': 'act:usr'})), None)
- self.assertEquals(self.test_auth.app.calls, 1)
-
- def test_get_admin_detail_fail_get_user_error(self):
- self.test_auth.app = FakeApp(iter([
- ('503 Service Unavailable', {}, '')]))
- exc = None
- try:
- self.test_auth.get_admin_detail(
- Request.blank('/',
- headers={'X-Auth-Admin-User': 'act:usr'}))
- except Exception as err:
- exc = err
- self.assertEquals(str(exc), 'Could not get admin user object: '
- '/v1/AUTH_.auth/act/usr 503 Service Unavailable')
- self.assertEquals(self.test_auth.app.calls, 1)
-
- def test_get_admin_detail_success(self):
- self.test_auth.app = FakeApp(iter([
- ('200 Ok', {},
- json.dumps({"auth": "plaintext:key",
- "groups": [{'name': "act:usr"}, {'name': "act"},
- {'name': ".admin"}]}))]))
- detail = self.test_auth.get_admin_detail(
- Request.blank('/',
- headers={'X-Auth-Admin-User': 'act:usr'}))
- self.assertEquals(self.test_auth.app.calls, 1)
- self.assertEquals(
- detail, {'account': 'act',
- 'auth': 'plaintext:key',
- 'groups': [{'name': 'act:usr'}, {'name': 'act'},
- {'name': '.admin'}]})
-
- def test_credentials_match_success(self):
- self.assert_(self.test_auth.credentials_match(
- {'auth': 'plaintext:key'}, 'key'))
-
- def test_credentials_match_fail_no_details(self):
- self.assert_(
- not self.test_auth.credentials_match(None, 'notkey'))
-
- def test_credentials_match_fail_plaintext(self):
- self.assert_(not self.test_auth.credentials_match(
- {'auth': 'plaintext:key'}, 'notkey'))
-
- def test_is_super_admin_success(self):
- self.assert_(
- self.test_auth.is_super_admin(
- Request.blank(
- '/',
- headers={'X-Auth-Admin-User': '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'})))
-
- def test_is_super_admin_fail_bad_key(self):
- self.assert_(
- not self.test_auth.is_super_admin(
- Request.blank('/',
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'bad'})))
- self.assert_(
- not self.test_auth.is_super_admin(
- Request.blank('/',
- headers={'X-Auth-Admin-User': '.super_admin'})))
- self.assert_(
- not self.test_auth.is_super_admin(Request.blank('/')))
-
- def test_is_super_admin_fail_bad_user(self):
- self.assert_(
- not self.test_auth.is_super_admin(
- Request.blank('/',
- headers={
- 'X-Auth-Admin-User':
- 'bad',
- 'X-Auth-Admin-Key': 'supertest'})))
- self.assert_(
- not self.test_auth.is_super_admin(
- Request.blank('/',
- headers={'X-Auth-Admin-Key': 'supertest'})))
- self.assert_(
- not self.test_auth.is_super_admin(Request.blank('/')))
-
- def test_is_reseller_admin_success_is_super_admin(self):
- self.assert_(
- self.test_auth.is_reseller_admin(
- Request.blank('/',
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'})))
-
- def test_is_reseller_admin_success_called_get_admin_detail(
- self):
- self.test_auth.app = FakeApp(iter([
- ('200 Ok', {},
- json.dumps({'auth': 'plaintext:key',
- 'groups': [{'name': 'act:rdm'}, {'name': 'act'},
- {'name': '.admin'},
- {'name': '.reseller_admin'}]}))]))
- self.assert_(
- self.test_auth.is_reseller_admin(
- Request.blank('/',
- headers={
- 'X-Auth-Admin-User':
- 'act:rdm',
- 'X-Auth-Admin-Key': 'key'})))
-
- def test_is_reseller_admin_fail_only_account_admin(
- self):
- self.test_auth.app = FakeApp(iter([
- ('200 Ok', {},
- json.dumps({'auth': 'plaintext:key',
- 'groups': [{'name': 'act:adm'}, {'name': 'act'},
- {'name': '.admin'}]}))]))
- self.assert_(
- not self.test_auth.is_reseller_admin(
- Request.blank('/',
- headers={
- 'X-Auth-Admin-User':
- 'act:adm',
- 'X-Auth-Admin-Key': 'key'})))
-
- def test_is_reseller_admin_fail_regular_user(self):
- self.test_auth.app = FakeApp(iter([
- ('200 Ok', {},
- json.dumps({'auth': 'plaintext:key',
- 'groups': [{'name': 'act:usr'}, {'name': 'act'}]}))]))
- self.assert_(
- not self.test_auth.is_reseller_admin(
- Request.blank('/',
- headers={
- 'X-Auth-Admin-User':
- 'act:usr',
- 'X-Auth-Admin-Key': 'key'})))
-
- def test_is_reseller_admin_fail_bad_key(self):
- self.test_auth.app = FakeApp(iter([
- ('200 Ok', {},
- json.dumps({'auth': 'plaintext:key',
- 'groups': [{'name': 'act:rdm'}, {'name': 'act'},
- {'name': '.admin'},
- {'name': '.reseller_admin'}]}))]))
- self.assert_(
- not self.test_auth.is_reseller_admin(
- Request.blank('/',
- headers={
- 'X-Auth-Admin-User':
- 'act:rdm',
- 'X-Auth-Admin-Key': 'bad'})))
-
- def test_is_account_admin_success_is_super_admin(self):
- self.assert_(
- self.test_auth.is_account_admin(
- Request.blank('/',
- headers={
- 'X-Auth-Admin-User':
- '.super_admin',
- 'X-Auth-Admin-Key': 'supertest'}), 'act'))
-
- def test_is_account_admin_success_is_reseller_admin(
- self):
- self.test_auth.app = FakeApp(iter([
- ('200 Ok', {},
- json.dumps({'auth': 'plaintext:key',
- 'groups': [{'name': 'act:rdm'}, {'name': 'act'},
- {'name': '.admin'},
- {'name': '.reseller_admin'}]}))]))
- self.assert_(
- self.test_auth.is_account_admin(
- Request.blank('/',
- headers={
- 'X-Auth-Admin-User':
- 'act:rdm',
- 'X-Auth-Admin-Key': 'key'}), 'act'))
-
- def test_is_account_admin_success(self):
- self.test_auth.app = FakeApp(iter([
- ('200 Ok', {},
- json.dumps({'auth': 'plaintext:key',
- 'groups': [{'name': 'act:adm'}, {'name': 'act'},
- {'name': '.admin'}]}))]))
- self.assert_(
- self.test_auth.is_account_admin(
- Request.blank('/',
- headers={
- 'X-Auth-Admin-User':
- 'act:adm',
- 'X-Auth-Admin-Key': 'key'}), 'act'))
-
- def test_is_account_admin_fail_account_admin_different_account(
- self):
- self.test_auth.app = FakeApp(iter([
- ('200 Ok', {},
- json.dumps({'auth': 'plaintext:key',
- 'groups': [{'name': 'act2:adm'}, {'name': 'act2'},
- {'name': '.admin'}]}))]))
- self.assert_(
- not self.test_auth.is_account_admin(
- Request.blank('/',
- headers={
- 'X-Auth-Admin-User':
- 'act2:adm',
- 'X-Auth-Admin-Key': 'key'}), 'act'))
-
- def test_is_account_admin_fail_regular_user(self):
- self.test_auth.app = FakeApp(iter([
- ('200 Ok', {},
- json.dumps({'auth': 'plaintext:key',
- 'groups': [{'name': 'act:usr'}, {'name': 'act'}]}))]))
- self.assert_(
- not self.test_auth.is_account_admin(
- Request.blank('/',
- headers={
- 'X-Auth-Admin-User':
- 'act:usr',
- 'X-Auth-Admin-Key': 'key'}), 'act'))
-
- def test_is_account_admin_fail_bad_key(self):
- self.test_auth.app = FakeApp(iter([
- ('200 Ok', {},
- json.dumps({'auth': 'plaintext:key',
- 'groups': [{'name': 'act:rdm'}, {'name': 'act'},
- {'name': '.admin'},
- {'name': '.reseller_admin'}]}))]))
- self.assert_(
- not self.test_auth.is_account_admin(
- Request.blank('/',
- headers={
- 'X-Auth-Admin-User':
- 'act:rdm',
- 'X-Auth-Admin-Key': 'bad'}), 'act'))
-
- def test_reseller_admin_but_account_is_internal_use_only(
- self):
- req = Request.blank('/v1/AUTH_.auth',
- environ={'REQUEST_METHOD': 'GET'})
- req.remote_user = 'act:usr,act,.reseller_admin'
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp.status_int, 403)
-
- def test_reseller_admin_but_account_is_exactly_reseller_prefix(
- self):
- req = Request.blank(
- '/v1/AUTH_',
- environ={'REQUEST_METHOD': 'GET'})
- req.remote_user = 'act:usr,act,.reseller_admin'
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp.status_int, 403)
-
- def _get_token_success_v1_0_encoded(
- self, saved_user, saved_key, sent_user,
- sent_key):
- self.test_auth.app = FakeApp(iter([
- # GET of user object
- ('200 Ok', {},
- json.dumps({"auth": "plaintext:%s" % saved_key,
- "groups": [{'name': saved_user}, {'name': "act"},
- {'name': ".admin"}]})),
- # GET of account
- ('204 Ok',
- {'X-Container-Meta-Account-Id': 'AUTH_cfa'}, ''),
- # PUT of new token
- ('201 Created', {}, ''),
- # POST of token to user object
- ('204 No Content', {}, ''),
- # GET of services object
- ('200 Ok', {}, json.dumps({"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}}))]))
- resp = Request.blank(
- '/auth/v1.0',
- headers={'X-Auth-User': sent_user,
- 'X-Auth-Key': sent_key}).get_response(self.test_auth)
- self.assertEquals(resp.status_int, 200)
- self.assert_(
- resp.headers.get('x-auth-token',
- '').startswith('AUTH_tk'),
- resp.headers.get('x-auth-token'))
- self.assertEquals(resp.headers.get('x-auth-token'),
- resp.headers.get('x-storage-token'))
- self.assertEquals(resp.headers.get('x-storage-url'),
- 'http://127.0.0.1:8080/v1/AUTH_cfa')
- self.assertEquals(
- json.loads(resp.body),
- {"storage": {"default": "local",
- "local": "http://127.0.0.1:8080/v1/AUTH_cfa"}})
- self.assertEquals(self.test_auth.app.calls, 5)
-
- def test_get_token_success_v1_0_encoded1(self):
- self._get_token_success_v1_0_encoded(
- 'act:usr', 'key', 'act%3ausr', 'key')
-
- def test_get_token_success_v1_0_encoded2(self):
- self._get_token_success_v1_0_encoded(
- 'act:u s r', 'key', 'act%3au%20s%20r', 'key')
-
- def test_get_token_success_v1_0_encoded3(self):
- self._get_token_success_v1_0_encoded(
- 'act:u s r', 'k:e:y', 'act%3au%20s%20r', 'k%3Ae%3ay')
-
- def test_allowed_sync_hosts(self):
- a = auth.filter_factory(
- {'super_admin_key': 'supertest'})(FakeApp())
- self.assertEquals(
- a.allowed_sync_hosts,
- ['127.0.0.1'])
- a = auth.filter_factory({
- 'super_admin_key': 'supertest',
- 'allowed_sync_hosts':
- '1.1.1.1,2.1.1.1, 3.1.1.1 , 4.1.1.1,, , 5.1.1.1'})(FakeApp())
- self.assertEquals(
- a.allowed_sync_hosts,
- ['1.1.1.1', '2.1.1.1', '3.1.1.1', '4.1.1.1', '5.1.1.1'])
-
- def test_reseller_admin_is_owner(self):
- orig_authorize = self.test_auth.authorize
- owner_values = []
-
- def mitm_authorize(req):
- rv = orig_authorize(req)
- owner_values.append(
- req.environ.get('swift_owner', False))
- return rv
-
- self.test_auth.authorize = mitm_authorize
-
- self.test_auth.app = FakeApp(iter([
- ('200 Ok', {},
- json.dumps(
- {'account': 'other', 'user': 'other:usr',
- 'account_id': 'AUTH_other',
- 'groups': [{'name': 'other:usr'}, {'name': 'other'},
- {'name': '.reseller_admin'}],
- 'expires': time() + 60})),
- ('204 No Content', {}, '')]))
- req = Request.blank(
- '/v1/AUTH_cfa',
- headers={'X-Auth-Token': 'AUTH_t'})
- resp = req.get_response(self.test_auth)
- self.assertEquals(resp.status_int, 204)
- self.assertEquals(owner_values, [True])
-
- def test_admin_is_owner(self):
- orig_authorize = self.test_auth.authorize
- owner_values = []
-
- def mitm_authorize(req):
- rv = orig_authorize(req)
- owner_values.append(
- req.environ.get('swift_owner', False))
- return rv
-
- self.test_auth.authorize = mitm_authorize
-
- self.test_auth.app = FakeApp(iter([
- ('200 Ok', {},
- json.dumps(
- {'account': 'act', 'user': 'act:usr',
- 'account_id': 'AUTH_cfa',
- 'groups': [{'name': 'act:usr'}, {'name': 'act'},
- {'name': '.admin'}],
- 'expires': time() + 60})),
- ('204 No Content', {}, '')]))
- req = Request.blank(
- '/v1/AUTH_cfa',
- headers={'X-Auth-Token': 'AUTH_t'})
- resp = req.get_response(self.test_auth)
- self.assertEquals(resp.status_int, 204)
- self.assertEquals(owner_values, [True])
-
- def test_regular_is_not_owner(self):
- orig_authorize = self.test_auth.authorize
- owner_values = []
-
- def mitm_authorize(req):
- rv = orig_authorize(req)
- owner_values.append(
- req.environ.get('swift_owner', False))
- return rv
-
- self.test_auth.authorize = mitm_authorize
-
- self.test_auth.app = FakeApp(iter([
- ('200 Ok', {},
- json.dumps(
- {'account': 'act', 'user': 'act:usr',
- 'account_id': 'AUTH_cfa',
- 'groups':
- [{'name': 'act:usr'}, {
- 'name': 'act'}],
- 'expires': time() + 60})),
- ('204 No Content', {}, '')]), acl='act:usr')
- req = Request.blank('/v1/AUTH_cfa/c',
- headers={'X-Auth-Token': 'AUTH_t'})
- resp = req.get_response(self.test_auth)
- self.assertEquals(resp.status_int, 204)
- self.assertEquals(owner_values, [False])
-
- def test_sync_request_success(self):
- self.test_auth.app = FakeApp(
- iter([('204 No Content', {}, '')]),
- sync_key='secret')
- req = Request.blank('/v1/AUTH_cfa/c/o',
- environ={
- 'REQUEST_METHOD': 'DELETE'},
- headers={
- 'x-container-sync-key':
- 'secret',
- 'x-timestamp': '123.456'})
- req.remote_addr = '127.0.0.1'
- resp = req.get_response(self.test_auth)
- self.assertEquals(resp.status_int, 204)
-
- def test_sync_request_fail_key(self):
- self.test_auth.app = FakeApp(
- iter([('204 No Content', {}, '')]),
- sync_key='secret')
- req = Request.blank('/v1/AUTH_cfa/c/o',
- environ={
- 'REQUEST_METHOD': 'DELETE'},
- headers={
- 'x-container-sync-key':
- 'wrongsecret',
- 'x-timestamp': '123.456'})
- req.remote_addr = '127.0.0.1'
- resp = req.get_response(self.test_auth)
- self.assertEquals(resp.status_int, 401)
-
- self.test_auth.app = FakeApp(
- iter([('204 No Content', {}, '')]),
- sync_key='othersecret')
- req = Request.blank('/v1/AUTH_cfa/c/o',
- environ={
- 'REQUEST_METHOD': 'DELETE'},
- headers={
- 'x-container-sync-key':
- 'secret',
- 'x-timestamp': '123.456'})
- req.remote_addr = '127.0.0.1'
- resp = req.get_response(self.test_auth)
- self.assertEquals(resp.status_int, 401)
-
- self.test_auth.app = FakeApp(
- iter([('204 No Content', {}, '')]),
- sync_key=None)
- req = Request.blank('/v1/AUTH_cfa/c/o',
- environ={
- 'REQUEST_METHOD': 'DELETE'},
- headers={
- 'x-container-sync-key':
- 'secret',
- 'x-timestamp': '123.456'})
- req.remote_addr = '127.0.0.1'
- resp = req.get_response(self.test_auth)
- self.assertEquals(resp.status_int, 401)
-
- def test_sync_request_fail_no_timestamp(self):
- self.test_auth.app = FakeApp(
- iter([('204 No Content', {}, '')]),
- sync_key='secret')
- req = Request.blank('/v1/AUTH_cfa/c/o',
- environ={
- 'REQUEST_METHOD': 'DELETE'},
- headers={'x-container-sync-key': 'secret'})
- req.remote_addr = '127.0.0.1'
- resp = req.get_response(self.test_auth)
- self.assertEquals(resp.status_int, 401)
-
- def test_sync_request_fail_sync_host(self):
- self.test_auth.app = FakeApp(
- iter([('204 No Content', {}, '')]),
- sync_key='secret')
- req = Request.blank('/v1/AUTH_cfa/c/o',
- environ={
- 'REQUEST_METHOD': 'DELETE'},
- headers={
- 'x-container-sync-key':
- 'secret',
- 'x-timestamp': '123.456'})
- req.remote_addr = '127.0.0.2'
- resp = req.get_response(self.test_auth)
- self.assertEquals(resp.status_int, 401)
-
- def test_sync_request_success_lb_sync_host(self):
- self.test_auth.app = FakeApp(
- iter([('204 No Content', {}, '')]),
- sync_key='secret')
- req = Request.blank('/v1/AUTH_cfa/c/o',
- environ={
- 'REQUEST_METHOD': 'DELETE'},
- headers={
- 'x-container-sync-key':
- 'secret',
- 'x-timestamp':
- '123.456',
- 'x-forwarded-for': '127.0.0.1'})
- req.remote_addr = '127.0.0.2'
- resp = req.get_response(self.test_auth)
- self.assertEquals(resp.status_int, 204)
-
- self.test_auth.app = FakeApp(
- iter([('204 No Content', {}, '')]),
- sync_key='secret')
- req = Request.blank('/v1/AUTH_cfa/c/o',
- environ={
- 'REQUEST_METHOD': 'DELETE'},
- headers={
- 'x-container-sync-key':
- 'secret',
- 'x-timestamp':
- '123.456',
- 'x-cluster-client-ip': '127.0.0.1'})
- req.remote_addr = '127.0.0.2'
- resp = req.get_response(self.test_auth)
- self.assertEquals(resp.status_int, 204)
-
- def _make_request(self, path, **kwargs):
- req = Request.blank(path, **kwargs)
- req.environ['swift.cache'] = FakeMemcache()
- return req
-
- def test_override_asked_for_but_not_allowed(self):
- self.test_auth = \
- auth.filter_factory(
- {'allow_overrides': 'false'})(FakeApp())
- req = self._make_request('/v1/AUTH_account',
- environ={'swift.authorize_override': True})
- resp = req.get_response(self.test_auth)
- self.assertEquals(resp.status_int, 401)
- self.assertEquals(resp.environ['swift.authorize'],
- self.test_auth.authorize)
-
- def test_override_asked_for_and_allowed(self):
- self.test_auth = \
- auth.filter_factory(
- {'allow_overrides': 'true'})(FakeApp())
- req = self._make_request('/v1/AUTH_account',
- environ={'swift.authorize_override': True})
- resp = req.get_response(self.test_auth)
- self.assertEquals(resp.status_int, 404)
- self.assertTrue(
- 'swift.authorize' not in resp.environ)
-
- def test_override_default_allowed(self):
- req = self._make_request('/v1/AUTH_account',
- environ={'swift.authorize_override': True})
- resp = req.get_response(self.test_auth)
- self.assertEquals(resp.status_int, 404)
- self.assertTrue(
- 'swift.authorize' not in resp.environ)
-
- def test_token_too_long(self):
- req = self._make_request('/v1/AUTH_account', headers={
- 'x-auth-token': 'a' * MAX_TOKEN_LENGTH})
- resp = req.get_response(self.test_auth)
- self.assertEquals(resp.status_int, 401)
- self.assertNotEquals(
- resp.body,
- 'Token exceeds maximum length.')
- req = self._make_request('/v1/AUTH_account', headers={
- 'x-auth-token': 'a' * (MAX_TOKEN_LENGTH + 1)})
- resp = req.get_response(self.test_auth)
- self.assertEquals(resp.status_int, 400)
- self.assertEquals(
- resp.body,
- 'Token exceeds maximum length.')
-
- def test_crazy_authorization(self):
- req = self._make_request('/v1/AUTH_account', headers={
- 'authorization': 'somebody elses header value'})
- resp = req.get_response(self.test_auth)
- self.assertEquals(resp.status_int, 401)
- self.assertEquals(resp.environ['swift.authorize'],
- self.test_auth.denied_response)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/gluster/swift/common/middleware/swiftkerbauth/__init__.py b/gluster/swift/common/middleware/swiftkerbauth/__init__.py
deleted file mode 100644
index c752df7..0000000
--- a/gluster/swift/common/middleware/swiftkerbauth/__init__.py
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2013 Red Hat, Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-# implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from swift.common.utils import readconf, config_true_value
-
-config_file = {}
-try:
- config_file = readconf("/etc/swift/proxy-server.conf",
- section_name="filter:cache")
-except SystemExit:
- pass
-
-MEMCACHE_SERVERS = config_file.get('memcache_servers', None)
-
-config_file = {}
-
-try:
- config_file = readconf("/etc/swift/proxy-server.conf",
- section_name="filter:kerbauth")
-except SystemExit:
- pass
-
-TOKEN_LIFE = int(config_file.get('token_life', 86400))
-RESELLER_PREFIX = config_file.get('reseller_prefix', "AUTH_")
-DEBUG_HEADERS = config_true_value(config_file.get('debug_headers', 'yes'))
diff --git a/gluster/swift/common/middleware/swiftkerbauth/apachekerbauth/etc/httpd/conf.d/swift-auth.conf b/gluster/swift/common/middleware/swiftkerbauth/apachekerbauth/etc/httpd/conf.d/swift-auth.conf
deleted file mode 100644
index 68472d8..0000000
--- a/gluster/swift/common/middleware/swiftkerbauth/apachekerbauth/etc/httpd/conf.d/swift-auth.conf
+++ /dev/null
@@ -1,12 +0,0 @@
-<Location /cgi-bin/swift-auth>
- AuthType Kerberos
- AuthName "Swift Authentication"
- KrbMethodNegotiate On
- KrbMethodK5Passwd On
- KrbSaveCredentials On
- KrbServiceName HTTP/client.example.com
- KrbAuthRealms EXAMPLE.COM
- Krb5KeyTab /etc/httpd/conf/http.keytab
- KrbVerifyKDC Off
- Require valid-user
-</Location>
diff --git a/gluster/swift/common/middleware/swiftkerbauth/apachekerbauth/var/www/cgi-bin/swift-auth b/gluster/swift/common/middleware/swiftkerbauth/apachekerbauth/var/www/cgi-bin/swift-auth
deleted file mode 100755
index 11fe0e2..0000000
--- a/gluster/swift/common/middleware/swiftkerbauth/apachekerbauth/var/www/cgi-bin/swift-auth
+++ /dev/null
@@ -1,70 +0,0 @@
-#!/usr/bin/python
-
-# Copyright (c) 2013 Red Hat, Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Requires the following command to be run:
-# setsebool -P httpd_can_network_connect 1
-# setsebool -P httpd_can_network_memcache 1
-
-import os
-import cgi
-from swift.common.memcached import MemcacheRing
-from time import time, ctime
-from swiftkerbauth import MEMCACHE_SERVERS, TOKEN_LIFE, DEBUG_HEADERS
-from swiftkerbauth.kerbauth_utils import get_remote_user, get_auth_data, \
- generate_token, set_auth_data, get_groups_from_username
-
-
-def main():
- try:
- username = get_remote_user(os.environ)
- except RuntimeError:
- print "Status: 401 Unauthorized\n"
- print "Malformed REMOTE_USER"
- return
-
- if not MEMCACHE_SERVERS:
- print "Status: 500 Internal Server Error\n"
- print "Memcache not configured in /etc/swift/proxy-server.conf"
- return
-
- mc_servers = [s.strip() for s in MEMCACHE_SERVERS.split(',') if s.strip()]
- mc = MemcacheRing(mc_servers)
-
- token, expires, groups = get_auth_data(mc, username)
-
- if not token:
- token = generate_token()
- expires = time() + TOKEN_LIFE
- groups = get_groups_from_username(username)
- set_auth_data(mc, username, token, expires, groups)
-
- print "X-Auth-Token: %s" % token
- print "X-Storage-Token: %s" % token
-
- # For debugging.
- if DEBUG_HEADERS:
- print "X-Debug-Remote-User: %s" % username
- print "X-Debug-Groups: %s" % groups
- print "X-Debug-Token-Life: %ss" % TOKEN_LIFE
- print "X-Debug-Token-Expires: %s" % ctime(expires)
-
- print ""
-
-try:
- print("Content-Type: text/html")
- main()
-except:
- cgi.print_exception()
diff --git a/gluster/swift/common/middleware/swiftkerbauth/kerbauth.py b/gluster/swift/common/middleware/swiftkerbauth/kerbauth.py
deleted file mode 100644
index 1a63a40..0000000
--- a/gluster/swift/common/middleware/swiftkerbauth/kerbauth.py
+++ /dev/null
@@ -1,463 +0,0 @@
-# Copyright (c) 2013 Red Hat, Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import errno
-from time import time, ctime
-from traceback import format_exc
-from eventlet import Timeout
-from urllib import unquote
-
-from swift.common.swob import Request, Response
-from swift.common.swob import HTTPBadRequest, HTTPForbidden, HTTPNotFound, \
- HTTPSeeOther, HTTPUnauthorized, HTTPServerError
-
-from swift.common.middleware.acl import clean_acl, parse_acl, referrer_allowed
-from swift.common.utils import cache_from_env, get_logger, \
- split_path, config_true_value
-from gluster.swift.common.middleware.swiftkerbauth.kerbauth_utils import \
- get_auth_data, generate_token, \
- set_auth_data, run_kinit, get_groups_from_username
-
-
-class KerbAuth(object):
- """
- Test authentication and authorization system.
-
- Add to your pipeline in proxy-server.conf, such as::
-
- [pipeline:main]
- pipeline = catch_errors cache kerbauth proxy-server
-
- Set account auto creation to true in proxy-server.conf::
-
- [app:proxy-server]
- account_autocreate = true
-
- And add a kerbauth filter section, such as::
-
- [filter:kerbauth]
- use = egg:swiftkerbauth#kerbauth
-
- See the proxy-server.conf-sample for more information.
-
- :param app: The next WSGI app in the pipeline
- :param conf: The dict of configuration values
- """
-
- def __init__(self, app, conf):
- self.app = app
- self.conf = conf
- self.logger = get_logger(conf, log_route='kerbauth')
- self.log_headers = config_true_value(conf.get('log_headers', 'f'))
- self.reseller_prefix = conf.get('reseller_prefix', 'AUTH').strip()
- if self.reseller_prefix and self.reseller_prefix[-1] != '_':
- self.reseller_prefix += '_'
- self.logger.set_statsd_prefix('kerbauth.%s' % (
- self.reseller_prefix if self.reseller_prefix else 'NONE',))
- self.auth_prefix = conf.get('auth_prefix', '/auth/')
- if not self.auth_prefix or not self.auth_prefix.strip('/'):
- self.logger.warning('Rewriting invalid auth prefix "%s" to '
- '"/auth/" (Non-empty auth prefix path '
- 'is required)' % self.auth_prefix)
- self.auth_prefix = '/auth/'
- if self.auth_prefix[0] != '/':
- self.auth_prefix = '/' + self.auth_prefix
- if self.auth_prefix[-1] != '/':
- self.auth_prefix += '/'
- self.token_life = int(conf.get('token_life', 86400))
- self.auth_method = conf.get('auth_method', 'passive')
- self.debug_headers = config_true_value(
- conf.get('debug_headers', 'yes'))
- self.realm_name = conf.get('realm_name', None)
- self.allow_overrides = config_true_value(
- conf.get('allow_overrides', 't'))
- self.storage_url_scheme = conf.get('storage_url_scheme', 'default')
- self.ext_authentication_url = conf.get('ext_authentication_url')
- if not self.ext_authentication_url:
- raise RuntimeError("Missing filter parameter ext_authentication_"
- "url in /etc/swift/proxy-server.conf")
-
- def __call__(self, env, start_response):
- """
- Accepts a standard WSGI application call, authenticating the request
- and installing callback hooks for authorization and ACL header
- validation. For an authenticated request, REMOTE_USER will be set to a
- comma separated list of the user's groups.
-
- If the request matches the self.auth_prefix, the request will be
- routed through the internal auth request handler (self.handle).
- This is to handle granting tokens, etc.
- """
- if self.allow_overrides and env.get('swift.authorize_override', False):
- return self.app(env, start_response)
- if env.get('PATH_INFO', '').startswith(self.auth_prefix):
- return self.handle(env, start_response)
- token = env.get('HTTP_X_AUTH_TOKEN', env.get('HTTP_X_STORAGE_TOKEN'))
- if token and token.startswith(self.reseller_prefix):
- groups = self.get_groups(env, token)
- if groups:
- user = groups and groups.split(',', 1)[0] or ''
- trans_id = env.get('swift.trans_id')
- self.logger.debug('User: %s uses token %s (trans_id %s)' %
- (user, token, trans_id))
- env['REMOTE_USER'] = groups
- env['swift.authorize'] = self.authorize
- env['swift.clean_acl'] = clean_acl
- if '.reseller_admin' in groups:
- env['reseller_request'] = True
- else:
- # Invalid token (may be expired)
- if self.auth_method == "active":
- return HTTPSeeOther(
- location=self.ext_authentication_url)(env,
- start_response)
- elif self.auth_method == "passive":
- self.logger.increment('unauthorized')
- return HTTPUnauthorized()(env, start_response)
- else:
- # With a non-empty reseller_prefix, I would like to be called
- # back for anonymous access to accounts I know I'm the
- # definitive auth for.
- try:
- version, rest = split_path(env.get('PATH_INFO', ''),
- 1, 2, True)
- except ValueError:
- version, rest = None, None
- self.logger.increment('errors')
- # Not my token, not my account, I can't authorize this request,
- # deny all is a good idea if not already set...
- if 'swift.authorize' not in env:
- env['swift.authorize'] = self.denied_response
-
- return self.app(env, start_response)
-
- def get_groups(self, env, token):
- """
- Get groups for the given token.
-
- :param env: The current WSGI environment dictionary.
- :param token: Token to validate and return a group string for.
-
- :returns: None if the token is invalid or a string containing a comma
- separated list of groups the authenticated user is a member
- of. The first group in the list is also considered a unique
- identifier for that user.
- """
- groups = None
- memcache_client = cache_from_env(env)
- if not memcache_client:
- raise Exception('Memcache required')
- memcache_token_key = '%s/token/%s' % (self.reseller_prefix, token)
- cached_auth_data = memcache_client.get(memcache_token_key)
- if cached_auth_data:
- expires, groups = cached_auth_data
- if expires < time():
- groups = None
-
- return groups
-
- def authorize(self, req):
- """
- Returns None if the request is authorized to continue or a standard
- WSGI response callable if not.
-
- Assumes that user groups are all lower case, which is true when Red Hat
- Enterprise Linux Identity Management is used.
- """
- try:
- version, account, container, obj = req.split_path(1, 4, True)
- except ValueError:
- self.logger.increment('errors')
- return HTTPNotFound(request=req)
-
- if not account or not account.startswith(self.reseller_prefix):
- self.logger.debug("Account name: %s doesn't start with "
- "reseller_prefix: %s."
- % (account, self.reseller_prefix))
- return self.denied_response(req)
-
- user_groups = (req.remote_user or '').split(',')
- account_user = user_groups[1] if len(user_groups) > 1 else None
- # If the user is in the reseller_admin group for our prefix, he gets
- # full access to all accounts we manage. For the default reseller
- # prefix, the group name is auth_reseller_admin.
- admin_group = ("%sreseller_admin" % self.reseller_prefix).lower()
- if admin_group in user_groups and \
- account != self.reseller_prefix and \
- account[len(self.reseller_prefix)] != '.':
- req.environ['swift_owner'] = True
- return None
-
- # The "account" is part of the request URL, and already contains the
- # reseller prefix, like in "/v1/AUTH_vol1/pictures/pic1.png".
- if account.lower() in user_groups and \
- (req.method not in ('DELETE', 'PUT') or container):
- # If the user is admin for the account and is not trying to do an
- # account DELETE or PUT...
- req.environ['swift_owner'] = True
- self.logger.debug("User %s has admin authorizing."
- % account_user)
- return None
-
- if (req.environ.get('swift_sync_key')
- and (req.environ['swift_sync_key'] ==
- req.headers.get('x-container-sync-key', None))
- and 'x-timestamp' in req.headers):
- self.logger.debug("Allow request with container sync-key: %s."
- % req.environ['swift_sync_key'])
- return None
-
- if req.method == 'OPTIONS':
- #allow OPTIONS requests to proceed as normal
- self.logger.debug("Allow OPTIONS request.")
- return None
-
- referrers, groups = parse_acl(getattr(req, 'acl', None))
-
- if referrer_allowed(req.referer, referrers):
- if obj or '.rlistings' in groups:
- self.logger.debug("Allow authorizing %s via referer ACL."
- % req.referer)
- return None
-
- for user_group in user_groups:
- if user_group in groups:
- self.logger.debug("User %s allowed in ACL: %s authorizing."
- % (account_user, user_group))
- return None
-
- return self.denied_response(req)
-
- def denied_response(self, req):
- """
- Returns a standard WSGI response callable with the status of 403 or 401
- depending on whether the REMOTE_USER is set or not.
- """
- if req.remote_user:
- self.logger.increment('forbidden')
- return HTTPForbidden(request=req)
- else:
- if self.auth_method == "active":
- return HTTPSeeOther(location=self.ext_authentication_url)
- elif self.auth_method == "passive":
- self.logger.increment('unauthorized')
- return HTTPUnauthorized(request=req)
-
- def handle(self, env, start_response):
- """
- WSGI entry point for auth requests (ones that match the
- self.auth_prefix).
- Wraps env in swob.Request object and passes it down.
-
- :param env: WSGI environment dictionary
- :param start_response: WSGI callable
- """
- try:
- req = Request(env)
- if self.auth_prefix:
- req.path_info_pop()
- req.bytes_transferred = '-'
- req.client_disconnect = False
- if 'x-storage-token' in req.headers and \
- 'x-auth-token' not in req.headers:
- req.headers['x-auth-token'] = req.headers['x-storage-token']
- return self.handle_request(req)(env, start_response)
- except (Exception, Timeout):
- print "EXCEPTION IN handle: %s: %s" % (format_exc(), env)
- self.logger.increment('errors')
- start_response('500 Server Error',
- [('Content-Type', 'text/plain')])
- return ['Internal server error.\n']
-
- def handle_request(self, req):
- """
- Entry point for auth requests (ones that match the self.auth_prefix).
- Should return a WSGI-style callable (such as webob.Response).
-
- :param req: swob.Request object
- """
- req.start_time = time()
- handler = None
- try:
- version, account, user, _junk = req.split_path(1, 4, True)
- except ValueError:
- self.logger.increment('errors')
- return HTTPNotFound(request=req)
- if version in ('v1', 'v1.0', 'auth'):
- if req.method == 'GET':
- handler = self.handle_get_token
- if not handler:
- self.logger.increment('errors')
- req.response = HTTPBadRequest(request=req)
- else:
- req.response = handler(req)
- return req.response
-
- def handle_get_token(self, req):
- """
- Handles the various `request for token and service end point(s)` calls.
- There are various formats to support the various auth servers in the
- past.
-
- "Active Mode" usage:
- All formats require GSS (Kerberos) authentication.
-
- GET <auth-prefix>/v1/<act>/auth
- GET <auth-prefix>/auth
- GET <auth-prefix>/v1.0
-
- On successful authentication, the response will have X-Auth-Token
- and X-Storage-Token set to the token to use with Swift.
-
- "Passive Mode" usage::
-
- GET <auth-prefix>/v1/<act>/auth
- X-Auth-User: <act>:<usr> or X-Storage-User: <usr>
- X-Auth-Key: <key> or X-Storage-Pass: <key>
- GET <auth-prefix>/auth
- X-Auth-User: <act>:<usr> or X-Storage-User: <act>:<usr>
- X-Auth-Key: <key> or X-Storage-Pass: <key>
- GET <auth-prefix>/v1.0
- X-Auth-User: <act>:<usr> or X-Storage-User: <act>:<usr>
- X-Auth-Key: <key> or X-Storage-Pass: <key>
-
- Values should be url encoded, "act%3Ausr" instead of "act:usr" for
- example; however, for backwards compatibility the colon may be
- included unencoded.
-
- On successful authentication, the response will have X-Auth-Token
- and X-Storage-Token set to the token to use with Swift and
- X-Storage-URL set to the URL to the default Swift cluster to use.
-
- :param req: The swob.Request to process.
- :returns: swob.Response, 2xx on success with data set as explained
- above.
- """
- # Validate the request info
- try:
- pathsegs = split_path(req.path_info, 1, 3, True)
- except ValueError:
- self.logger.increment('errors')
- return HTTPNotFound(request=req)
- if not ((pathsegs[0] == 'v1' and pathsegs[2] == 'auth')
- or pathsegs[0] in ('auth', 'v1.0')):
- return HTTPBadRequest(request=req)
-
- # Client is inside the domain
- if self.auth_method == "active":
- return HTTPSeeOther(location=self.ext_authentication_url)
-
- # Client is outside the domain
- elif self.auth_method == "passive":
- account, user, key = None, None, None
- # Extract user, account and key from request
- if pathsegs[0] == 'v1' and pathsegs[2] == 'auth':
- account = pathsegs[1]
- user = req.headers.get('x-storage-user')
- if not user:
- user = unquote(req.headers.get('x-auth-user', ''))
- if user:
- if ':' not in user:
- return HTTPUnauthorized(request=req)
- else:
- account2, user = user.split(':', 1)
- if account != account2:
- return HTTPUnauthorized(request=req)
- key = req.headers.get('x-storage-pass')
- if not key:
- key = unquote(req.headers.get('x-auth-key', ''))
- elif pathsegs[0] in ('auth', 'v1.0'):
- user = unquote(req.headers.get('x-auth-user', ''))
- if not user:
- user = req.headers.get('x-storage-user')
- if user:
- if ':' not in user:
- return HTTPUnauthorized(request=req)
- else:
- account, user = user.split(':', 1)
- key = unquote(req.headers.get('x-auth-key', ''))
- if not key:
- key = req.headers.get('x-storage-pass')
-
- if not (account or user or key):
- # If all are not given, client may be part of the domain
- return HTTPSeeOther(location=self.ext_authentication_url)
- elif None in (key, user, account):
- # If only one or two of them is given, but not all
- return HTTPUnauthorized(request=req)
-
- # Run kinit on the user
- if self.realm_name and "@" not in user:
- user = user + "@" + self.realm_name
- try:
- ret = run_kinit(user, key)
- except OSError as e:
- if e.errno == errno.ENOENT:
- return HTTPServerError("kinit command not found\n")
- if ret != 0:
- self.logger.warning("Failed: kinit %s", user)
- if ret == -1:
- self.logger.warning("Failed: kinit: Password has probably "
- "expired.")
- return HTTPServerError("Kinit is taking too long.\n")
- return HTTPUnauthorized(request=req)
- self.logger.debug("kinit succeeded")
-
- if "@" in user:
- user = user.split("@")[0]
-
- # Check if user really belongs to the account
- groups_list = get_groups_from_username(user).strip().split(",")
- user_group = ("%s%s" % (self.reseller_prefix, account)).lower()
- reseller_admin_group = \
- ("%sreseller_admin" % self.reseller_prefix).lower()
- if user_group not in groups_list:
- # Check if user is reseller_admin. If not, return Unauthorized.
- # On AD/IdM server, auth_reseller_admin is a separate group
- if reseller_admin_group not in groups_list:
- return HTTPUnauthorized(request=req)
-
- mc = cache_from_env(req.environ)
- if not mc:
- raise Exception('Memcache required')
- token, expires, groups = get_auth_data(mc, user)
- if not token:
- token = generate_token()
- expires = time() + self.token_life
- groups = get_groups_from_username(user)
- set_auth_data(mc, user, token, expires, groups)
-
- headers = {'X-Auth-Token': token,
- 'X-Storage-Token': token}
-
- if self.debug_headers:
- headers.update({'X-Debug-Remote-User': user,
- 'X-Debug-Groups:': groups,
- 'X-Debug-Token-Life': self.token_life,
- 'X-Debug-Token-Expires': ctime(expires)})
-
- resp = Response(request=req, headers=headers)
- resp.headers['X-Storage-Url'] = \
- '%s/v1/%s%s' % (resp.host_url, self.reseller_prefix, account)
- return resp
-
-
-def filter_factory(global_conf, **local_conf):
- """Returns a WSGI filter app for use with paste.deploy."""
- conf = global_conf.copy()
- conf.update(local_conf)
-
- def auth_filter(app):
- return KerbAuth(app, conf)
- return auth_filter
diff --git a/gluster/swift/common/middleware/swiftkerbauth/kerbauth_utils.py b/gluster/swift/common/middleware/swiftkerbauth/kerbauth_utils.py
deleted file mode 100644
index 599ef99..0000000
--- a/gluster/swift/common/middleware/swiftkerbauth/kerbauth_utils.py
+++ /dev/null
@@ -1,137 +0,0 @@
-# Copyright (c) 2013 Red Hat, Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-# implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import re
-import random
-import grp
-import signal
-from subprocess import Popen, PIPE
-from time import time
-from gluster.swift.common.middleware.swiftkerbauth \
- import TOKEN_LIFE, RESELLER_PREFIX
-
-
-def get_remote_user(env):
- """Retrieve REMOTE_USER set by Apache from environment."""
- remote_user = env.get('REMOTE_USER', "")
- matches = re.match('([^@]+)@.*', remote_user)
- if not matches:
- raise RuntimeError("Malformed REMOTE_USER \"%s\"" % remote_user)
- return matches.group(1)
-
-
-def get_auth_data(mc, username):
- """
- Returns the token, expiry time and groups for the user if it already exists
- on memcache. Returns None otherwise.
-
- :param mc: MemcacheRing object
- :param username: swift user
- """
- token, expires, groups = None, None, None
- memcache_user_key = '%s/user/%s' % (RESELLER_PREFIX, username)
- candidate_token = mc.get(memcache_user_key)
- if candidate_token:
- memcache_token_key = '%s/token/%s' % (RESELLER_PREFIX, candidate_token)
- cached_auth_data = mc.get(memcache_token_key)
- if cached_auth_data:
- expires, groups = cached_auth_data
- if expires > time():
- token = candidate_token
- else:
- expires, groups = None, None
- return (token, expires, groups)
-
-
-def set_auth_data(mc, username, token, expires, groups):
- """
- Stores the following key value pairs on Memcache:
- (token, expires+groups)
- (user, token)
- """
- auth_data = (expires, groups)
- memcache_token_key = "%s/token/%s" % (RESELLER_PREFIX, token)
- mc.set(memcache_token_key, auth_data, time=TOKEN_LIFE)
-
- # Record the token with the user info for future use.
- memcache_user_key = '%s/user/%s' % (RESELLER_PREFIX, username)
- mc.set(memcache_user_key, token, time=TOKEN_LIFE)
-
-
-def generate_token():
- """Generates a random token."""
- # We don't use uuid.uuid4() here because importing the uuid module
- # causes (harmless) SELinux denials in the audit log on RHEL 6. If this
- # is a security concern, a custom SELinux policy module could be
- # written to not log those denials.
- r = random.SystemRandom()
- token = '%stk%s' % \
- (RESELLER_PREFIX,
- ''.join(r.choice('abcdef0123456789') for x in range(32)))
- return token
-
-
-def get_groups_from_username(username):
- """Return a set of groups to which the user belongs to."""
- # Retrieve the numerical group IDs. We cannot list the group names
- # because group names from Active Directory may contain spaces, and
- # we wouldn't be able to split the list of group names into its
- # elements.
- p = Popen(['id', '-G', username], stdout=PIPE)
- if p.wait() != 0:
- raise RuntimeError("Failure running id -G for %s" % username)
- (p_stdout, p_stderr) = p.communicate()
-
- # Convert the group numbers into group names.
- groups = []
- for gid in p_stdout.strip().split(" "):
- groups.append(grp.getgrgid(int(gid))[0])
-
- # The first element of the list is considered a unique identifier
- # for the user. We add the username to accomplish this.
- if username in groups:
- groups.remove(username)
- groups = [username] + groups
- groups = ','.join(groups)
- return groups
-
-
-def run_kinit(username, password):
- """Runs kinit command as a child process and returns the status code."""
- kinit = Popen(['kinit', username],
- stdin=PIPE, stdout=PIPE, stderr=PIPE)
- kinit.stdin.write('%s\n' % password)
-
- # The following code handles a corner case where the Kerberos password
- # has expired and a prompt is displayed to enter new password. Ideally,
- # we would want to read from stdout but these are blocked reads. This is
- # a hack to kill the process if it's taking too long!
-
- class Alarm(Exception):
- pass
-
- def signal_handler(signum, frame):
- raise Alarm
- # Set the signal handler and a 1-second alarm
- signal.signal(signal.SIGALRM, signal_handler)
- signal.alarm(1)
- try:
- kinit.wait() # Wait for the child to exit
- signal.alarm(0) # Reset the alarm
- return kinit.returncode # Exit status of child on graceful exit
- except Alarm:
- # Taking too long, kill and return error
- kinit.kill()
- return -1
diff --git a/gluster/swift/common/utils.py b/gluster/swift/common/utils.py
index 145add3..95c8739 100644
--- a/gluster/swift/common/utils.py
+++ b/gluster/swift/common/utils.py
@@ -47,6 +47,7 @@ DIR_NON_OBJECT = 'dir'
DIR_OBJECT = 'marker_dir'
TEMP_DIR = 'tmp'
ASYNCDIR = 'async_pending' # Keep in sync with swift.obj.server.ASYNCDIR
+TRASHCAN = '.trashcan'
FILE = 'file'
FILE_TYPE = 'application/octet-stream'
OBJECT = 'Object'
@@ -212,7 +213,7 @@ def validate_account(metadata):
return False
-def validate_object(metadata):
+def validate_object(metadata, stat=None):
if not metadata:
return False
@@ -224,6 +225,12 @@ def validate_object(metadata):
X_OBJECT_TYPE not in metadata.keys():
return False
+ if stat and (int(metadata[X_CONTENT_LENGTH]) != stat.st_size):
+ # File length has changed.
+ # TODO: Handle case where file content has changed but the length
+ # remains the same.
+ return False
+
if metadata[X_TYPE] == OBJECT:
return True
@@ -242,8 +249,16 @@ def _update_list(path, cont_path, src_list, reg_file=True, object_count=0,
if not reg_file and not Glusterfs._implicit_dir_objects:
# Now check if this is a dir object or a gratuiously crated
# directory
- metadata = \
- read_metadata(os.path.join(cont_path, obj_path, obj_name))
+ try:
+ metadata = \
+ read_metadata(os.path.join(cont_path, obj_path, obj_name))
+ except GlusterFileSystemIOError as err:
+ if err.errno in (errno.ENOENT, errno.ESTALE):
+ # object might have been deleted by another process
+ # since the src_list was originally built
+ continue
+ else:
+ raise err
if not dir_is_object(metadata):
continue
@@ -304,6 +319,7 @@ def get_account_details(acc_path):
for name in do_listdir(acc_path):
if name.lower() == TEMP_DIR \
or name.lower() == ASYNCDIR \
+ or name.lower() == TRASHCAN \
or not do_isdir(os.path.join(acc_path, name)):
continue
container_count += 1
@@ -476,7 +492,7 @@ def rmobjdir(dir_path):
try:
do_rmdir(dir_path)
except OSError as err:
- if err.errno == errno.ENOENT:
+ if err.errno in (errno.ENOENT, errno.ESTALE):
# No such directory exists
return False
if err.errno != errno.ENOTEMPTY:
@@ -494,8 +510,8 @@ def rmobjdir(dir_path):
try:
metadata = read_metadata(fullpath)
- except OSError as err:
- if err.errno == errno.ENOENT:
+ except GlusterFileSystemIOError as err:
+ if err.errno in (errno.ENOENT, errno.ESTALE):
# Ignore removal from another entity.
continue
raise
@@ -513,7 +529,7 @@ def rmobjdir(dir_path):
if err.errno == errno.ENOTEMPTY:
# Directory is not empty, it might have objects in it
return False
- if err.errno == errno.ENOENT:
+ if err.errno in (errno.ENOENT, errno.ESTALE):
# No such directory exists, already removed, ignore
continue
raise
@@ -524,7 +540,7 @@ def rmobjdir(dir_path):
if err.errno == errno.ENOTEMPTY:
# Directory is not empty, race with object creation
return False
- if err.errno == errno.ENOENT:
+ if err.errno in (errno.ENOENT, errno.ESTALE):
# No such directory exists, already removed, ignore
return True
raise
diff --git a/gluster/swift/obj/diskfile.py b/gluster/swift/obj/diskfile.py
index 47cde89..eb180a2 100644
--- a/gluster/swift/obj/diskfile.py
+++ b/gluster/swift/obj/diskfile.py
@@ -447,9 +447,9 @@ class DiskFileWriter(object):
df._threadpool.force_run_in_thread(self._finalize_put, metadata)
- # Avoid the unlink() system call as part of the mkstemp context
- # cleanup
- self.tmppath = None
+ # Avoid the unlink() system call as part of the DiskFile.create()
+ # context cleanup
+ self._tmppath = None
class DiskFileReader(object):
@@ -509,7 +509,7 @@ class DiskFileReader(object):
bytes_read += len(chunk)
diff = bytes_read - dropped_cache
if diff > (1024 * 1024):
- self._drop_cache(self._fd, dropped_cache, diff)
+ self._drop_cache(dropped_cache, diff)
dropped_cache = bytes_read
yield chunk
if self._iter_hook:
@@ -604,6 +604,7 @@ class DiskFile(object):
self._logger = mgr.logger
self._metadata = None
self._fd = None
+ self._stat = None
# Don't store a value for data_file until we know it exists.
self._data_file = None
@@ -644,37 +645,49 @@ class DiskFile(object):
"""
# Writes are always performed to a temporary file
try:
- fd = do_open(self._data_file, os.O_RDONLY | O_CLOEXEC)
+ self._fd = do_open(self._data_file, os.O_RDONLY | O_CLOEXEC)
except GlusterFileSystemOSError as err:
if err.errno in (errno.ENOENT, errno.ENOTDIR):
# If the file does exist, or some part of the path does not
# exist, raise the expected DiskFileNotExist
raise DiskFileNotExist
raise
- else:
- stats = do_fstat(fd)
- if not stats:
- return
- self._is_dir = stat.S_ISDIR(stats.st_mode)
- obj_size = stats.st_size
-
- self._metadata = read_metadata(fd)
- if not validate_object(self._metadata):
- create_object_metadata(fd)
- self._metadata = read_metadata(fd)
- assert self._metadata is not None
- self._filter_metadata()
-
- if self._is_dir:
- do_close(fd)
- obj_size = 0
- self._fd = -1
- else:
- if self._is_object_expired(self._metadata):
- raise DiskFileExpired(metadata=self._metadata)
- self._fd = fd
-
- self._obj_size = obj_size
+ try:
+ self._stat = do_fstat(self._fd)
+ self._is_dir = stat.S_ISDIR(self._stat.st_mode)
+ obj_size = self._stat.st_size
+
+ self._metadata = read_metadata(self._fd)
+ if not validate_object(self._metadata, self._stat):
+ create_object_metadata(self._fd)
+ self._metadata = read_metadata(self._fd)
+ assert self._metadata is not None
+ self._filter_metadata()
+
+ if self._is_dir:
+ do_close(self._fd)
+ obj_size = 0
+ self._fd = -1
+ else:
+ if self._is_object_expired(self._metadata):
+ raise DiskFileExpired(metadata=self._metadata)
+ self._obj_size = obj_size
+ except (OSError, IOError, DiskFileExpired) as err:
+ # Something went wrong. Context manager will not call
+ # __exit__. So we close the fd manually here.
+ self._close_fd()
+ if hasattr(err, 'errno') and \
+ err.errno in (errno.ENOENT, errno.ESTALE):
+ # Handle races: ENOENT/ESTALE can be raised by read_metadata()
+ # call in GlusterFS if file gets deleted by another
+ # client after do_open() succeeds
+ logging.warn("open(%s) succeeded but one of the subsequent "
+ "syscalls failed with ENOENT/ESTALE. Raising "
+ "DiskFileNotExist." % (self._data_file))
+ raise DiskFileNotExist
+ else:
+ # Re-raise the original exception after fd has been closed
+ raise err
return self
def _is_object_expired(self, metadata):
@@ -712,6 +725,12 @@ class DiskFile(object):
raise DiskFileNotOpen()
return self
+ def _close_fd(self):
+ if self._fd is not None:
+ fd, self._fd = self._fd, None
+ if fd > -1:
+ do_close(fd)
+
def __exit__(self, t, v, tb):
"""
Context exit.
@@ -723,10 +742,7 @@ class DiskFile(object):
responsibility of the implementation to properly handle that.
"""
self._metadata = None
- if self._fd is not None:
- fd, self._fd = self._fd, None
- if fd > -1:
- do_close(fd)
+ self._close_fd()
def get_metadata(self):
"""
@@ -833,10 +849,6 @@ class DiskFile(object):
" on subpath: %s" % (full_path, cur_path))
child = stack.pop() if stack else None
return True, newmd
- # Exists, but as a file
- #raise DiskFileError('DiskFile.put(): directory creation failed'
- # ' since the target, %s, already exists as'
- # ' a file' % df._data_file)
@contextmanager
def create(self, size=None):
@@ -893,7 +905,7 @@ class DiskFile(object):
if attempts >= MAX_OPEN_ATTEMPTS:
# We failed after N attempts to create the temporary
# file.
- raise DiskFileError('DiskFile.mkstemp(): failed to'
+ raise DiskFileError('DiskFile.create(): failed to'
' successfully create a temporary file'
' without running into a name conflict'
' after %d of %d attempts for: %s' % (
@@ -906,7 +918,7 @@ class DiskFile(object):
# FIXME: Possible FUSE issue or race condition, let's
# sleep on it and retry the operation.
_random_sleep()
- logging.warn("DiskFile.mkstemp(): %s ... retrying in"
+ logging.warn("DiskFile.create(): %s ... retrying in"
" 0.1 secs", gerr)
attempts += 1
elif not self._obj_path:
@@ -915,7 +927,7 @@ class DiskFile(object):
# could be a FUSE issue or some race condition, so let's
# sleep a bit and retry.
_random_sleep()
- logging.warn("DiskFile.mkstemp(): %s ... retrying in"
+ logging.warn("DiskFile.create(): %s ... retrying in"
" 0.1 secs", gerr)
attempts += 1
elif attempts > 1:
@@ -923,7 +935,7 @@ class DiskFile(object):
# also be a FUSE issue or some race condition, nap and
# retry.
_random_sleep()
- logging.warn("DiskFile.mkstemp(): %s ... retrying in"
+ logging.warn("DiskFile.create(): %s ... retrying in"
" 0.1 secs" % gerr)
attempts += 1
else:
diff --git a/glusterfs-openstack-swift.spec b/glusterfs-openstack-swift.spec
index bca64c3..79defc4 100644
--- a/glusterfs-openstack-swift.spec
+++ b/glusterfs-openstack-swift.spec
@@ -24,11 +24,11 @@ Requires : memcached
Requires : openssl
Requires : python
Requires : python-prettytable
-Requires : openstack-swift = 1.10.0
-Requires : openstack-swift-account = 1.10.0
-Requires : openstack-swift-container = 1.10.0
-Requires : openstack-swift-object = 1.10.0
-Requires : openstack-swift-proxy = 1.10.0
+Requires : openstack-swift = 1.13.1
+Requires : openstack-swift-account = 1.13.1
+Requires : openstack-swift-container = 1.13.1
+Requires : openstack-swift-object = 1.13.1
+Requires : openstack-swift-proxy = 1.13.1
Requires : glusterfs-api >= 3.4.1
Obsoletes: glusterfs-swift-plugin
Obsoletes: glusterfs-swift
@@ -39,11 +39,11 @@ Obsoletes: glusterfs-swift-proxy
Obsoletes: glusterfs-swift-account
%description
-Gluster-For-Swift (G4S, pronounced "gee-force") integrates GlusterFS as an
-alternative back end for OpenStack Object Storage (Swift) leveraging the
-existing front end OpenStack Swift code. Gluster volumes are used to store
-objects in files, containers are maintained as top-level directories of volumes,
-where accounts are mapped one-to-one to gluster volumes.
+SwiftOnFile integrates GlusterFS as an alternative back end for OpenStack
+Object Storage (Swift) leveraging the existing front end OpenStack Swift code.
+Gluster volumes are used to store objects in files, containers are maintained
+as top-level directories of volumes, where accounts are mapped one-to-one to
+gluster volumes.
%prep
%setup -q -n gluster_swift-%{_version}
@@ -94,10 +94,14 @@ done
%config(noreplace) %{_confdir}/swift.conf-gluster
%config(noreplace) %{_confdir}/proxy-server.conf-gluster
%config(noreplace) %{_confdir}/fs.conf-gluster
+%config(noreplace) %{_confdir}/object-expirer.conf-gluster
%changelog
+* Fri May 23 2014 Thiago da Silva <thiago@redhat.com> - 1.13.1-1
+- Update to Icehouse release
+
* Mon Oct 28 2013 Luis Pabon <lpabon@redhat.com> - 1.10.1-0
-- IceHouse Release
+- Havana Release
* Wed Aug 21 2013 Luis Pabon <lpabon@redhat.com> - 1.8.0-7
- Update RPM spec file to support SRPMS
diff --git a/tools/requirements.txt b/requirements.txt
index bbac51a..bbac51a 100644
--- a/tools/requirements.txt
+++ b/requirements.txt
diff --git a/setup.py b/setup.py
index 0b52115..5673bdc 100644
--- a/setup.py
+++ b/setup.py
@@ -64,8 +64,6 @@ setup(
'paste.filter_factory': [
'gswauth=gluster.swift.common.middleware.gswauth.swauth.'
'middleware:filter_factory',
- 'kerbauth=gluster.swift.common.middleware.'
- 'swiftkerbauth.kerbauth:filter_factory',
],
},
)
diff --git a/tools/test-requires b/test-requirements.txt
index 63d499e..63d499e 100644
--- a/tools/test-requires
+++ b/test-requirements.txt
diff --git a/test/functional/gluster_swift_tests.py b/test/functional/gluster_swift_tests.py
index 2768f9d..b4514c9 100644
--- a/test/functional/gluster_swift_tests.py
+++ b/test/functional/gluster_swift_tests.py
@@ -58,44 +58,13 @@ class TestFile(Base):
data_read = file.read()
self.assertEquals(data,data_read)
- def testInvalidHeadersPUT(self):
- #TODO: Although we now support x-delete-at and x-delete-after,
- #retained this test case as we may add some other header to
- #unsupported list in future
- raise SkipTest()
- file = self.env.container.file(Utils.create_name())
- self.assertRaises(ResponseError,
- file.write_random,
- self.env.file_size,
- hdrs={'X-Delete-At': '9876545321'})
- self.assert_status(400)
- self.assertRaises(ResponseError,
- file.write_random,
- self.env.file_size,
- hdrs={'X-Delete-After': '60'})
- self.assert_status(400)
-
- def testInvalidHeadersPOST(self):
- #TODO: Although we now support x-delete-at and x-delete-after,
- #retained this test case as we may add some other header to
- #unsupported list in future
- raise SkipTest()
- file = self.env.container.file(Utils.create_name())
- file.write_random(self.env.file_size)
- headers = file.make_headers(cfg={})
- headers.update({ 'X-Delete-At' : '987654321'})
- # Need to call conn.make_request instead of file.sync_metadata
- # because sync_metadata calls make_headers. make_headers()
- # overwrites any headers in file.metadata as 'user' metadata
- # by appending 'X-Object-Meta-' to any of the headers
- # in file.metadata.
- file.conn.make_request('POST', file.path, hdrs=headers, cfg={})
- self.assertEqual(400, file.conn.response.status)
-
- headers = file.make_headers(cfg={})
- headers.update({ 'X-Delete-After' : '60'})
- file.conn.make_request('POST', file.path, hdrs=headers, cfg={})
- self.assertEqual(400, file.conn.response.status)
+ def test_PUT_large_object(self):
+ file_item = self.env.container.file(Utils.create_name())
+ data = File.random_data(1024 * 1024 * 2)
+ self.assertTrue(file_item.write(data))
+ self.assert_status(201)
+ self.assertTrue(data == file_item.read())
+ self.assert_status(200)
class TestFileUTF8(Base2, TestFile):
@@ -375,3 +344,49 @@ class TestMultiProtocolAccess(Base):
md5_returned = hashlib.md5(data_read_from_mountP).hexdigest()
self.assertEquals(md5_returned,file_info['etag'])
fhOnMountPoint.close()
+
+ def testObjectMetadataWhenFileModified(self):
+ data = "I'm whatever Gotham needs me to be "
+ data_hash = hashlib.md5(data).hexdigest()
+ # Create an object through object interface
+ object_name = Utils.create_name()
+ object_item = self.env.container.file(object_name)
+ object_item.write(data)
+ # Make sure GET works
+ self.assertEqual(data, object_item.read())
+ self.assert_status(200)
+ # Check Etag is right
+ self.assertEqual(data_hash, object_item.info()['etag'])
+ self.assert_status(200)
+
+ # Extend/append more data to file from filesystem interface
+ file_path = os.path.join(self.env.root_dir,
+ self.env.container.name,
+ object_name)
+ more_data = "- Batman"
+ with open(file_path, 'a') as f:
+ f.write(more_data)
+ total_data = data + more_data
+ total_data_hash = hashlib.md5(total_data).hexdigest()
+ # Make sure GET works
+ self.assertEqual(total_data, object_item.read())
+ self.assert_status(200)
+ # Check Etag and content-length is right
+ metadata = object_item.info()
+ self.assert_status(200)
+ self.assertEqual(total_data_hash, metadata['etag'])
+ self.assertEqual(len(total_data), int(metadata['content_length']))
+
+ # Re-write the file to be shorter
+ new_data = "I am Batman"
+ new_data_hash = hashlib.md5(new_data).hexdigest()
+ with open(file_path, 'w') as f:
+ f.write(new_data)
+ # Make sure GET works
+ self.assertEqual(new_data, object_item.read())
+ self.assert_status(200)
+ # Check Etag and content-length is right
+ metadata = object_item.info()
+ self.assert_status(200)
+ self.assertEqual(new_data_hash, metadata['etag'])
+ self.assertEqual(len(new_data), int(metadata['content_length']))
diff --git a/test/functional/swift_test_client.py b/test/functional/swift_test_client.py
index a7c7c96..27e025b 100644
--- a/test/functional/swift_test_client.py
+++ b/test/functional/swift_test_client.py
@@ -144,6 +144,7 @@ class Connection(object):
auth_scheme = 'https://' if self.auth_ssl else 'http://'
auth_netloc = "%s:%d" % (self.auth_host, self.auth_port)
auth_url = auth_scheme + auth_netloc + auth_path
+
(storage_url, storage_token) = get_auth(
auth_url, auth_user, self.password, snet=False,
tenant_name=self.account, auth_version=self.auth_version,
@@ -166,17 +167,29 @@ class Connection(object):
self.storage_host = x[2].split(':')[0]
if ':' in x[2]:
self.storage_port = int(x[2].split(':')[1])
- # Make sure storage_url and the storage_token are
- # strings and not unicode, since
+ # Make sure storage_url is a string and not unicode, since
# keystoneclient (called by swiftclient) returns them in
# unicode and this would cause troubles when doing
# no_safe_quote query.
self.storage_url = str('/%s/%s' % (x[3], x[4]))
- self.storage_token = str(storage_token)
+
+ self.storage_token = storage_token
self.http_connect()
return self.storage_url, self.storage_token
+ def cluster_info(self):
+ """
+ Retrieve the data in /info, or {} on 404
+ """
+ status = self.make_request('GET', '/info',
+ cfg={'absolute_path': True})
+ if status == 404:
+ return {}
+ if not 200 <= status <= 299:
+ raise ResponseError(self.response, 'GET', '/info')
+ return json.loads(self.response.read())
+
def http_connect(self):
self.connection = self.conn_class(self.storage_host,
port=self.storage_port)
@@ -207,8 +220,8 @@ class Connection(object):
def make_request(self, method, path=[], data='', hdrs={}, parms={},
cfg={}):
- if not cfg.get('verbatim_path'):
- # Set verbatim_path=True to make a request to exactly the given
+ if not cfg.get('absolute_path'):
+ # Set absolute_path=True to make a request to exactly the given
# path, not storage path + given path. Useful for
# non-account/container/object requests.
path = self.make_path(path, cfg=cfg)
@@ -305,7 +318,7 @@ class Connection(object):
return self.response.status
-class Base:
+class Base(object):
def __str__(self):
return self.name
@@ -339,6 +352,16 @@ class Account(Base):
self.conn = conn
self.name = str(name)
+ def update_metadata(self, metadata={}, cfg={}):
+ headers = dict(("X-Account-Meta-%s" % k, v)
+ for k, v in metadata.items())
+
+ self.conn.make_request('POST', self.path, hdrs=headers, cfg=cfg)
+ if not 200 <= self.conn.response.status <= 299:
+ raise ResponseError(self.conn.response, 'POST',
+ self.conn.make_path(self.path))
+ return True
+
def container(self, container_name):
return Container(self.conn, self.name, container_name)
@@ -532,6 +555,11 @@ class File(Base):
else:
headers['Content-Type'] = 'application/octet-stream'
+ if cfg.get('x_delete_at'):
+ headers['X-Delete-At'] = cfg.get('x_delete_at')
+ if cfg.get('x_delete_after'):
+ headers['X-Delete-After'] = cfg.get('x_delete_after')
+
for key in self.metadata:
headers['X-Object-Meta-' + key] = self.metadata[key]
@@ -588,7 +616,11 @@ class File(Base):
['last_modified', 'last-modified'],
['etag', 'etag']]
- header_fields = self.header_fields(fields)
+ optional_fields = [['x_delete_at', 'x-delete-at'],
+ ['x_delete_after', 'x-delete-after']]
+
+ header_fields = self.header_fields(fields,
+ optional_fields=optional_fields)
header_fields['etag'] = header_fields['etag'].strip('"')
return header_fields
@@ -705,7 +737,6 @@ class File(Base):
cfg.get('set_content_length')
else:
headers['Content-Length'] = 0
-
self.conn.make_request('POST', self.path, hdrs=headers, cfg=cfg)
if self.conn.response.status not in (201, 202):
diff --git a/test/functional/swift_testing.py b/test/functional/swift_testing.py
index f05cb48..2a1e1fa 100644
--- a/test/functional/swift_testing.py
+++ b/test/functional/swift_testing.py
@@ -19,10 +19,13 @@ import socket
import sys
from time import sleep
from urlparse import urlparse
+import functools
+from nose import SkipTest
from test import get_config
from swiftclient import get_auth, http_connection
+from test.functional.swift_test_client import Connection
conf = get_config('func_test')
web_front_end = conf.get('web_front_end', 'integral')
@@ -184,3 +187,45 @@ def check_response(conn):
resp.read()
raise InternalServerError()
return resp
+
+cluster_info = {}
+
+
+def get_cluster_info():
+ conn = Connection(conf)
+ conn.authenticate()
+ global cluster_info
+ cluster_info = conn.cluster_info()
+
+
+def reset_acl():
+ def post(url, token, parsed, conn):
+ conn.request('POST', parsed.path, '', {
+ 'X-Auth-Token': token,
+ 'X-Account-Access-Control': '{}'
+ })
+ return check_response(conn)
+ resp = retry(post, use_account=1)
+ resp.read()
+
+
+def requires_acls(f):
+ @functools.wraps(f)
+ def wrapper(*args, **kwargs):
+ if skip:
+ raise SkipTest
+ if not cluster_info:
+ get_cluster_info()
+ # Determine whether this cluster has account ACLs; if not, skip test
+ if not cluster_info.get('tempauth', {}).get('account_acls'):
+ raise SkipTest
+ if 'keystoneauth' in cluster_info:
+ # remove when keystoneauth supports account acls
+ raise SkipTest
+ reset_acl()
+ try:
+ rv = f(*args, **kwargs)
+ finally:
+ reset_acl()
+ return rv
+ return wrapper
diff --git a/test/functional/test_account.py b/test/functional/test_account.py
index d456090..1cc61bc 100755
--- a/test/functional/test_account.py
+++ b/test/functional/test_account.py
@@ -17,19 +17,57 @@
import unittest
import json
+from uuid import uuid4
from nose import SkipTest
+from string import letters
from swift.common.constraints import MAX_META_COUNT, MAX_META_NAME_LENGTH, \
MAX_META_OVERALL_SIZE, MAX_META_VALUE_LENGTH
from swift.common.middleware.acl import format_acl
-from test.functional.swift_test_client import Connection
-from test import get_config
-from swift_testing import check_response, retry, skip, web_front_end
+from swift_testing import (check_response, retry, skip, skip2, skip3,
+ web_front_end, requires_acls)
import swift_testing
+from test.functional.tests import load_constraint
class TestAccount(unittest.TestCase):
+ def setUp(self):
+ self.max_meta_count = load_constraint('max_meta_count')
+ self.max_meta_name_length = load_constraint('max_meta_name_length')
+ self.max_meta_overall_size = load_constraint('max_meta_overall_size')
+ self.max_meta_value_length = load_constraint('max_meta_value_length')
+
+ def head(url, token, parsed, conn):
+ conn.request('HEAD', parsed.path, '', {'X-Auth-Token': token})
+ return check_response(conn)
+ resp = retry(head)
+ self.existing_metadata = set([
+ k for k, v in resp.getheaders() if
+ k.lower().startswith('x-account-meta')])
+
+ def tearDown(self):
+ def head(url, token, parsed, conn):
+ conn.request('HEAD', parsed.path, '', {'X-Auth-Token': token})
+ return check_response(conn)
+ resp = retry(head)
+ resp.read()
+ new_metadata = set(
+ [k for k, v in resp.getheaders() if
+ k.lower().startswith('x-account-meta')])
+
+ def clear_meta(url, token, parsed, conn, remove_metadata_keys):
+ headers = {'X-Auth-Token': token}
+ headers.update((k, '') for k in remove_metadata_keys)
+ conn.request('POST', parsed.path, '', headers)
+ return check_response(conn)
+ extra_metadata = list(self.existing_metadata ^ new_metadata)
+ for i in range(0, len(extra_metadata), 90):
+ batch = extra_metadata[i:i + 90]
+ resp = retry(clear_meta, batch)
+ resp.read()
+ self.assertEqual(resp.status // 100, 2)
+
def test_metadata(self):
if skip:
raise SkipTest
@@ -49,49 +87,338 @@ class TestAccount(unittest.TestCase):
resp = retry(post, '')
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
resp = retry(head)
resp.read()
self.assert_(resp.status in (200, 204), resp.status)
- self.assertEquals(resp.getheader('x-account-meta-test'), None)
+ self.assertEqual(resp.getheader('x-account-meta-test'), None)
resp = retry(get)
resp.read()
self.assert_(resp.status in (200, 204), resp.status)
- self.assertEquals(resp.getheader('x-account-meta-test'), None)
+ self.assertEqual(resp.getheader('x-account-meta-test'), None)
resp = retry(post, 'Value')
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
resp = retry(head)
resp.read()
self.assert_(resp.status in (200, 204), resp.status)
- self.assertEquals(resp.getheader('x-account-meta-test'), 'Value')
+ self.assertEqual(resp.getheader('x-account-meta-test'), 'Value')
resp = retry(get)
resp.read()
self.assert_(resp.status in (200, 204), resp.status)
- self.assertEquals(resp.getheader('x-account-meta-test'), 'Value')
+ self.assertEqual(resp.getheader('x-account-meta-test'), 'Value')
- def test_tempauth_account_acls(self):
- if skip:
+ def test_invalid_acls(self):
+ def post(url, token, parsed, conn, headers):
+ new_headers = dict({'X-Auth-Token': token}, **headers)
+ conn.request('POST', parsed.path, '', new_headers)
+ return check_response(conn)
+
+ # needs to be an acceptable header size
+ num_keys = 8
+ max_key_size = load_constraint('max_header_size') / num_keys
+ acl = {'admin': [c * max_key_size for c in letters[:num_keys]]}
+ headers = {'x-account-access-control': format_acl(
+ version=2, acl_dict=acl)}
+ resp = retry(post, headers=headers, use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 400)
+
+ # and again a touch smaller
+ acl = {'admin': [c * max_key_size for c in letters[:num_keys - 1]]}
+ headers = {'x-account-access-control': format_acl(
+ version=2, acl_dict=acl)}
+ resp = retry(post, headers=headers, use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+
+ @requires_acls
+ def test_invalid_acl_keys(self):
+ def post(url, token, parsed, conn, headers):
+ new_headers = dict({'X-Auth-Token': token}, **headers)
+ conn.request('POST', parsed.path, '', new_headers)
+ return check_response(conn)
+
+ # needs to be json
+ resp = retry(post, headers={'X-Account-Access-Control': 'invalid'},
+ use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 400)
+
+ acl_user = swift_testing.swift_test_user[1]
+ acl = {'admin': [acl_user], 'invalid_key': 'invalid_value'}
+ headers = {'x-account-access-control': format_acl(
+ version=2, acl_dict=acl)}
+
+ resp = retry(post, headers, use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 400)
+ self.assertEqual(resp.getheader('X-Account-Access-Control'), None)
+
+ @requires_acls
+ def test_invalid_acl_values(self):
+ def post(url, token, parsed, conn, headers):
+ new_headers = dict({'X-Auth-Token': token}, **headers)
+ conn.request('POST', parsed.path, '', new_headers)
+ return check_response(conn)
+
+ acl = {'admin': 'invalid_value'}
+ headers = {'x-account-access-control': format_acl(
+ version=2, acl_dict=acl)}
+
+ resp = retry(post, headers=headers, use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 400)
+ self.assertEqual(resp.getheader('X-Account-Access-Control'), None)
+
+ @requires_acls
+ def test_read_only_acl(self):
+ if skip3:
raise SkipTest
- # Determine whether this cluster has account ACLs; if not, skip test
- conn = Connection(get_config('func_test'))
- conn.authenticate()
- status = conn.make_request(
- 'GET', '/info', cfg={'verbatim_path': True})
- if status // 100 != 2:
- # Can't tell if account ACLs are enabled; skip tests proactively.
+ def get(url, token, parsed, conn):
+ conn.request('GET', parsed.path, '', {'X-Auth-Token': token})
+ return check_response(conn)
+
+ def post(url, token, parsed, conn, headers):
+ new_headers = dict({'X-Auth-Token': token}, **headers)
+ conn.request('POST', parsed.path, '', new_headers)
+ return check_response(conn)
+
+ # cannot read account
+ resp = retry(get, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 403)
+
+ # grant read access
+ acl_user = swift_testing.swift_test_user[2]
+ acl = {'read-only': [acl_user]}
+ headers = {'x-account-access-control': format_acl(
+ version=2, acl_dict=acl)}
+ resp = retry(post, headers=headers, use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+
+ # read-only can read account headers
+ resp = retry(get, use_account=3)
+ resp.read()
+ self.assert_(resp.status in (200, 204))
+ # but not acls
+ self.assertEqual(resp.getheader('X-Account-Access-Control'), None)
+
+ # read-only can not write metadata
+ headers = {'x-account-meta-test': 'value'}
+ resp = retry(post, headers=headers, use_account=3)
+ resp.read()
+ self.assertEqual(resp.status, 403)
+
+ # but they can read it
+ headers = {'x-account-meta-test': 'value'}
+ resp = retry(post, headers=headers, use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+ resp = retry(get, use_account=3)
+ resp.read()
+ self.assert_(resp.status in (200, 204))
+ self.assertEqual(resp.getheader('X-Account-Meta-Test'), 'value')
+
+ @requires_acls
+ def test_read_write_acl(self):
+ if skip3:
+ raise SkipTest
+
+ def get(url, token, parsed, conn):
+ conn.request('GET', parsed.path, '', {'X-Auth-Token': token})
+ return check_response(conn)
+
+ def post(url, token, parsed, conn, headers):
+ new_headers = dict({'X-Auth-Token': token}, **headers)
+ conn.request('POST', parsed.path, '', new_headers)
+ return check_response(conn)
+
+ # cannot read account
+ resp = retry(get, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 403)
+
+ # grant read-write access
+ acl_user = swift_testing.swift_test_user[2]
+ acl = {'read-write': [acl_user]}
+ headers = {'x-account-access-control': format_acl(
+ version=2, acl_dict=acl)}
+ resp = retry(post, headers=headers, use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+
+ # read-write can read account headers
+ resp = retry(get, use_account=3)
+ resp.read()
+ self.assert_(resp.status in (200, 204))
+ # but not acls
+ self.assertEqual(resp.getheader('X-Account-Access-Control'), None)
+
+ # read-write can not write account metadata
+ headers = {'x-account-meta-test': 'value'}
+ resp = retry(post, headers=headers, use_account=3)
+ resp.read()
+ self.assertEqual(resp.status, 403)
+
+ @requires_acls
+ def test_admin_acl(self):
+ if skip3:
+ raise SkipTest
+
+ def get(url, token, parsed, conn):
+ conn.request('GET', parsed.path, '', {'X-Auth-Token': token})
+ return check_response(conn)
+
+ def post(url, token, parsed, conn, headers):
+ new_headers = dict({'X-Auth-Token': token}, **headers)
+ conn.request('POST', parsed.path, '', new_headers)
+ return check_response(conn)
+
+ # cannot read account
+ resp = retry(get, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 403)
+
+ # grant admin access
+ acl_user = swift_testing.swift_test_user[2]
+ acl = {'admin': [acl_user]}
+ acl_json_str = format_acl(version=2, acl_dict=acl)
+ headers = {'x-account-access-control': acl_json_str}
+ resp = retry(post, headers=headers, use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+
+ # admin can read account headers
+ resp = retry(get, use_account=3)
+ resp.read()
+ self.assert_(resp.status in (200, 204))
+ # including acls
+ self.assertEqual(resp.getheader('X-Account-Access-Control'),
+ acl_json_str)
+
+ # admin can write account metadata
+ value = str(uuid4())
+ headers = {'x-account-meta-test': value}
+ resp = retry(post, headers=headers, use_account=3)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+ resp = retry(get, use_account=3)
+ resp.read()
+ self.assert_(resp.status in (200, 204))
+ self.assertEqual(resp.getheader('X-Account-Meta-Test'), value)
+
+ # admin can even revoke their own access
+ headers = {'x-account-access-control': '{}'}
+ resp = retry(post, headers=headers, use_account=3)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+
+ # and again, cannot read account
+ resp = retry(get, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 403)
+
+ @requires_acls
+ def test_protected_tempurl(self):
+ if skip3:
+ raise SkipTest
+
+ def get(url, token, parsed, conn):
+ conn.request('GET', parsed.path, '', {'X-Auth-Token': token})
+ return check_response(conn)
+
+ def post(url, token, parsed, conn, headers):
+ new_headers = dict({'X-Auth-Token': token}, **headers)
+ conn.request('POST', parsed.path, '', new_headers)
+ return check_response(conn)
+
+ # add a account metadata, and temp-url-key to account
+ value = str(uuid4())
+ headers = {
+ 'x-account-meta-temp-url-key': 'secret',
+ 'x-account-meta-test': value,
+ }
+ resp = retry(post, headers=headers, use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+
+ # grant read-only access to tester3
+ acl_user = swift_testing.swift_test_user[2]
+ acl = {'read-only': [acl_user]}
+ acl_json_str = format_acl(version=2, acl_dict=acl)
+ headers = {'x-account-access-control': acl_json_str}
+ resp = retry(post, headers=headers, use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+
+ # read-only tester3 can read account metadata
+ resp = retry(get, use_account=3)
+ resp.read()
+ self.assert_(resp.status in (200, 204),
+ 'Expected status in (200, 204), got %s' % resp.status)
+ self.assertEqual(resp.getheader('X-Account-Meta-Test'), value)
+ # but not temp-url-key
+ self.assertEqual(resp.getheader('X-Account-Meta-Temp-Url-Key'), None)
+
+ # grant read-write access to tester3
+ acl_user = swift_testing.swift_test_user[2]
+ acl = {'read-write': [acl_user]}
+ acl_json_str = format_acl(version=2, acl_dict=acl)
+ headers = {'x-account-access-control': acl_json_str}
+ resp = retry(post, headers=headers, use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+
+ # read-write tester3 can read account metadata
+ resp = retry(get, use_account=3)
+ resp.read()
+ self.assert_(resp.status in (200, 204),
+ 'Expected status in (200, 204), got %s' % resp.status)
+ self.assertEqual(resp.getheader('X-Account-Meta-Test'), value)
+ # but not temp-url-key
+ self.assertEqual(resp.getheader('X-Account-Meta-Temp-Url-Key'), None)
+
+ # grant admin access to tester3
+ acl_user = swift_testing.swift_test_user[2]
+ acl = {'admin': [acl_user]}
+ acl_json_str = format_acl(version=2, acl_dict=acl)
+ headers = {'x-account-access-control': acl_json_str}
+ resp = retry(post, headers=headers, use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+
+ # admin tester3 can read account metadata
+ resp = retry(get, use_account=3)
+ resp.read()
+ self.assert_(resp.status in (200, 204),
+ 'Expected status in (200, 204), got %s' % resp.status)
+ self.assertEqual(resp.getheader('X-Account-Meta-Test'), value)
+ # including temp-url-key
+ self.assertEqual(resp.getheader('X-Account-Meta-Temp-Url-Key'),
+ 'secret')
+
+ # admin tester3 can even change temp-url-key
+ secret = str(uuid4())
+ headers = {
+ 'x-account-meta-temp-url-key': secret,
+ }
+ resp = retry(post, headers=headers, use_account=3)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+ resp = retry(get, use_account=3)
+ resp.read()
+ self.assert_(resp.status in (200, 204),
+ 'Expected status in (200, 204), got %s' % resp.status)
+ self.assertEqual(resp.getheader('X-Account-Meta-Temp-Url-Key'),
+ secret)
+
+ @requires_acls
+ def test_account_acls(self):
+ if skip2:
raise SkipTest
- else:
- cluster_info = json.loads(conn.response.read())
- if not cluster_info.get('tempauth', {}).get('account_acls'):
- raise SkipTest
- if 'keystoneauth' in cluster_info:
- # Unfortunate hack -- tempauth (with account ACLs) is expected
- # to play nice with Keystone (without account ACLs), but Zuul
- # functest framework doesn't give us an easy way to get a
- # tempauth user.
- raise SkipTest
def post(url, token, parsed, conn, headers):
new_headers = dict({'X-Auth-Token': token}, **headers)
@@ -212,6 +539,137 @@ class TestAccount(unittest.TestCase):
use_account=1)
resp.read()
+ @requires_acls
+ def test_swift_account_acls(self):
+ if skip:
+ raise SkipTest
+
+ def post(url, token, parsed, conn, headers):
+ new_headers = dict({'X-Auth-Token': token}, **headers)
+ conn.request('POST', parsed.path, '', new_headers)
+ return check_response(conn)
+
+ def head(url, token, parsed, conn):
+ conn.request('HEAD', parsed.path, '', {'X-Auth-Token': token})
+ return check_response(conn)
+
+ def get(url, token, parsed, conn):
+ conn.request('GET', parsed.path, '', {'X-Auth-Token': token})
+ return check_response(conn)
+
+ try:
+ # User1 can POST to their own account
+ resp = retry(post, headers={'X-Account-Access-Control': '{}'})
+ resp.read()
+ self.assertEqual(resp.status, 204)
+ self.assertEqual(resp.getheader('X-Account-Access-Control'), None)
+
+ # User1 can GET their own empty account
+ resp = retry(get)
+ resp.read()
+ self.assertEqual(resp.status // 100, 2)
+ self.assertEqual(resp.getheader('X-Account-Access-Control'), None)
+
+ # User1 can POST non-empty data
+ acl_json = '{"admin":["bob"]}'
+ resp = retry(post, headers={'X-Account-Access-Control': acl_json})
+ resp.read()
+ self.assertEqual(resp.status, 204)
+
+ # User1 can GET the non-empty data
+ resp = retry(get)
+ resp.read()
+ self.assertEqual(resp.status // 100, 2)
+ self.assertEqual(resp.getheader('X-Account-Access-Control'),
+ acl_json)
+
+ # POST non-JSON ACL should fail
+ resp = retry(post, headers={'X-Account-Access-Control': 'yuck'})
+ resp.read()
+ # resp.status will be 400 if tempauth or some other ACL-aware
+ # auth middleware rejects it, or 200 (but silently swallowed by
+ # core Swift) if ACL-unaware auth middleware approves it.
+
+ # A subsequent GET should show the old, valid data, not the garbage
+ resp = retry(get)
+ resp.read()
+ self.assertEqual(resp.status // 100, 2)
+ self.assertEqual(resp.getheader('X-Account-Access-Control'),
+ acl_json)
+
+ finally:
+ # Make sure to clean up even if tests fail -- User2 should not
+ # have access to User1's account in other functional tests!
+ resp = retry(post, headers={'X-Account-Access-Control': '{}'})
+ resp.read()
+
+ def test_swift_prohibits_garbage_account_acls(self):
+ if skip:
+ raise SkipTest
+
+ def post(url, token, parsed, conn, headers):
+ new_headers = dict({'X-Auth-Token': token}, **headers)
+ conn.request('POST', parsed.path, '', new_headers)
+ return check_response(conn)
+
+ def get(url, token, parsed, conn):
+ conn.request('GET', parsed.path, '', {'X-Auth-Token': token})
+ return check_response(conn)
+
+ try:
+ # User1 can POST to their own account
+ resp = retry(post, headers={'X-Account-Access-Control': '{}'})
+ resp.read()
+ self.assertEqual(resp.status, 204)
+ self.assertEqual(resp.getheader('X-Account-Access-Control'), None)
+
+ # User1 can GET their own empty account
+ resp = retry(get)
+ resp.read()
+ self.assertEqual(resp.status // 100, 2)
+ self.assertEqual(resp.getheader('X-Account-Access-Control'), None)
+
+ # User1 can POST non-empty data
+ acl_json = '{"admin":["bob"]}'
+ resp = retry(post, headers={'X-Account-Access-Control': acl_json})
+ resp.read()
+ self.assertEqual(resp.status, 204)
+ # If this request is handled by ACL-aware auth middleware, then the
+ # ACL will be persisted. If it is handled by ACL-unaware auth
+ # middleware, then the header will be thrown out. But the request
+ # should return successfully in any case.
+
+ # User1 can GET the non-empty data
+ resp = retry(get)
+ resp.read()
+ self.assertEqual(resp.status // 100, 2)
+ # ACL will be set if some ACL-aware auth middleware (e.g. tempauth)
+ # propagates it to sysmeta; if no ACL-aware auth middleware does,
+ # then X-Account-Access-Control will still be empty.
+
+ # POST non-JSON ACL should fail
+ resp = retry(post, headers={'X-Account-Access-Control': 'yuck'})
+ resp.read()
+ # resp.status will be 400 if tempauth or some other ACL-aware
+ # auth middleware rejects it, or 200 (but silently swallowed by
+ # core Swift) if ACL-unaware auth middleware approves it.
+
+ # A subsequent GET should either show the old, valid data (if
+ # ACL-aware auth middleware is propagating it) or show nothing
+ # (if no auth middleware in the pipeline is ACL-aware), but should
+ # never return the garbage ACL.
+ resp = retry(get)
+ resp.read()
+ self.assertEqual(resp.status // 100, 2)
+ self.assertNotEqual(resp.getheader('X-Account-Access-Control'),
+ 'yuck')
+
+ finally:
+ # Make sure to clean up even if tests fail -- User2 should not
+ # have access to User1's account in other functional tests!
+ resp = retry(post, headers={'X-Account-Access-Control': '{}'})
+ resp.read()
+
def test_unicode_metadata(self):
if skip:
raise SkipTest
@@ -233,24 +691,24 @@ class TestAccount(unittest.TestCase):
resp = retry(head)
resp.read()
self.assert_(resp.status in (200, 204), resp.status)
- self.assertEquals(resp.getheader(uni_key.encode('utf-8')), '1')
+ self.assertEqual(resp.getheader(uni_key.encode('utf-8')), '1')
resp = retry(post, 'X-Account-Meta-uni', uni_value)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
resp = retry(head)
resp.read()
self.assert_(resp.status in (200, 204), resp.status)
- self.assertEquals(resp.getheader('X-Account-Meta-uni'),
- uni_value.encode('utf-8'))
+ self.assertEqual(resp.getheader('X-Account-Meta-uni'),
+ uni_value.encode('utf-8'))
if (web_front_end == 'integral'):
resp = retry(post, uni_key, uni_value)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
resp = retry(head)
resp.read()
self.assert_(resp.status in (200, 204), resp.status)
- self.assertEquals(resp.getheader(uni_key.encode('utf-8')),
- uni_value.encode('utf-8'))
+ self.assertEqual(resp.getheader(uni_key.encode('utf-8')),
+ uni_value.encode('utf-8'))
def test_multi_metadata(self):
if skip:
@@ -267,19 +725,19 @@ class TestAccount(unittest.TestCase):
resp = retry(post, 'X-Account-Meta-One', '1')
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
resp = retry(head)
resp.read()
self.assert_(resp.status in (200, 204), resp.status)
- self.assertEquals(resp.getheader('x-account-meta-one'), '1')
+ self.assertEqual(resp.getheader('x-account-meta-one'), '1')
resp = retry(post, 'X-Account-Meta-Two', '2')
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
resp = retry(head)
resp.read()
self.assert_(resp.status in (200, 204), resp.status)
- self.assertEquals(resp.getheader('x-account-meta-one'), '1')
- self.assertEquals(resp.getheader('x-account-meta-two'), '2')
+ self.assertEqual(resp.getheader('x-account-meta-one'), '1')
+ self.assertEqual(resp.getheader('x-account-meta-two'), '2')
def test_bad_metadata(self):
if skip:
@@ -294,35 +752,65 @@ class TestAccount(unittest.TestCase):
resp = retry(post,
{'X-Account-Meta-' + ('k' * MAX_META_NAME_LENGTH): 'v'})
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
resp = retry(
post,
{'X-Account-Meta-' + ('k' * (MAX_META_NAME_LENGTH + 1)): 'v'})
resp.read()
- self.assertEquals(resp.status, 400)
+ self.assertEqual(resp.status, 400)
resp = retry(post,
{'X-Account-Meta-Too-Long': 'k' * MAX_META_VALUE_LENGTH})
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
resp = retry(
post,
{'X-Account-Meta-Too-Long': 'k' * (MAX_META_VALUE_LENGTH + 1)})
resp.read()
- self.assertEquals(resp.status, 400)
+ self.assertEqual(resp.status, 400)
+
+ def test_bad_metadata2(self):
+ if skip:
+ raise SkipTest
+
+ def post(url, token, parsed, conn, extra_headers):
+ headers = {'X-Auth-Token': token}
+ headers.update(extra_headers)
+ conn.request('POST', parsed.path, '', headers)
+ return check_response(conn)
+
+ # TODO: Find the test that adds these and remove them.
+ headers = {'x-remove-account-meta-temp-url-key': 'remove',
+ 'x-remove-account-meta-temp-url-key-2': 'remove'}
+ resp = retry(post, headers)
headers = {}
for x in xrange(MAX_META_COUNT):
headers['X-Account-Meta-%d' % x] = 'v'
resp = retry(post, headers)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
headers = {}
for x in xrange(MAX_META_COUNT + 1):
headers['X-Account-Meta-%d' % x] = 'v'
resp = retry(post, headers)
resp.read()
- self.assertEquals(resp.status, 400)
+ self.assertEqual(resp.status, 400)
+
+ def test_bad_metadata3(self):
+ if skip:
+ raise SkipTest
+
+ def post(url, token, parsed, conn, extra_headers):
+ headers = {'X-Auth-Token': token}
+ headers.update(extra_headers)
+ conn.request('POST', parsed.path, '', headers)
+ return check_response(conn)
+
+ # TODO: Find the test that adds these and remove them.
+ headers = {'x-remove-account-meta-temp-url-key': 'remove',
+ 'x-remove-account-meta-temp-url-key-2': 'remove'}
+ resp = retry(post, headers)
headers = {}
header_value = 'k' * MAX_META_VALUE_LENGTH
@@ -337,12 +825,12 @@ class TestAccount(unittest.TestCase):
'v' * (MAX_META_OVERALL_SIZE - size - 1)
resp = retry(post, headers)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
headers['X-Account-Meta-k'] = \
'v' * (MAX_META_OVERALL_SIZE - size)
resp = retry(post, headers)
resp.read()
- self.assertEquals(resp.status, 400)
+ self.assertEqual(resp.status, 400)
if __name__ == '__main__':
diff --git a/test/functional/test_container.py b/test/functional/test_container.py
index 15f7fc1..91702e9 100755
--- a/test/functional/test_container.py
+++ b/test/functional/test_container.py
@@ -24,7 +24,7 @@ from swift.common.constraints import MAX_META_COUNT, MAX_META_NAME_LENGTH, \
MAX_META_OVERALL_SIZE, MAX_META_VALUE_LENGTH
from swift_testing import check_response, retry, skip, skip2, skip3, \
- swift_test_perm, web_front_end
+ swift_test_perm, web_front_end, requires_acls, swift_test_user
class TestContainer(unittest.TestCase):
@@ -41,7 +41,7 @@ class TestContainer(unittest.TestCase):
resp = retry(put)
resp.read()
- self.assertEquals(resp.status, 201)
+ self.assertEqual(resp.status, 201)
def tearDown(self):
if skip:
@@ -68,7 +68,7 @@ class TestContainer(unittest.TestCase):
for obj in objs:
resp = retry(delete, obj)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
def delete(url, token, parsed, conn):
conn.request('DELETE', parsed.path + '/' + self.name, '',
@@ -77,7 +77,7 @@ class TestContainer(unittest.TestCase):
resp = retry(delete)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
def test_multi_metadata(self):
if skip:
@@ -95,19 +95,19 @@ class TestContainer(unittest.TestCase):
resp = retry(post, 'X-Container-Meta-One', '1')
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
resp = retry(head)
resp.read()
self.assert_(resp.status in (200, 204), resp.status)
- self.assertEquals(resp.getheader('x-container-meta-one'), '1')
+ self.assertEqual(resp.getheader('x-container-meta-one'), '1')
resp = retry(post, 'X-Container-Meta-Two', '2')
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
resp = retry(head)
resp.read()
self.assert_(resp.status in (200, 204), resp.status)
- self.assertEquals(resp.getheader('x-container-meta-one'), '1')
- self.assertEquals(resp.getheader('x-container-meta-two'), '2')
+ self.assertEqual(resp.getheader('x-container-meta-one'), '1')
+ self.assertEqual(resp.getheader('x-container-meta-two'), '2')
def test_unicode_metadata(self):
if skip:
@@ -128,28 +128,28 @@ class TestContainer(unittest.TestCase):
if (web_front_end == 'integral'):
resp = retry(post, uni_key, '1')
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
resp = retry(head)
resp.read()
self.assert_(resp.status in (200, 204), resp.status)
- self.assertEquals(resp.getheader(uni_key.encode('utf-8')), '1')
+ self.assertEqual(resp.getheader(uni_key.encode('utf-8')), '1')
resp = retry(post, 'X-Container-Meta-uni', uni_value)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
resp = retry(head)
resp.read()
self.assert_(resp.status in (200, 204), resp.status)
- self.assertEquals(resp.getheader('X-Container-Meta-uni'),
- uni_value.encode('utf-8'))
+ self.assertEqual(resp.getheader('X-Container-Meta-uni'),
+ uni_value.encode('utf-8'))
if (web_front_end == 'integral'):
resp = retry(post, uni_key, uni_value)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
resp = retry(head)
resp.read()
self.assert_(resp.status in (200, 204), resp.status)
- self.assertEquals(resp.getheader(uni_key.encode('utf-8')),
- uni_value.encode('utf-8'))
+ self.assertEqual(resp.getheader(uni_key.encode('utf-8')),
+ uni_value.encode('utf-8'))
def test_PUT_metadata(self):
if skip:
@@ -179,34 +179,34 @@ class TestContainer(unittest.TestCase):
name = uuid4().hex
resp = retry(put, name, 'Value')
resp.read()
- self.assertEquals(resp.status, 201)
+ self.assertEqual(resp.status, 201)
resp = retry(head, name)
resp.read()
self.assert_(resp.status in (200, 204), resp.status)
- self.assertEquals(resp.getheader('x-container-meta-test'), 'Value')
+ self.assertEqual(resp.getheader('x-container-meta-test'), 'Value')
resp = retry(get, name)
resp.read()
self.assert_(resp.status in (200, 204), resp.status)
- self.assertEquals(resp.getheader('x-container-meta-test'), 'Value')
+ self.assertEqual(resp.getheader('x-container-meta-test'), 'Value')
resp = retry(delete, name)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
name = uuid4().hex
resp = retry(put, name, '')
resp.read()
- self.assertEquals(resp.status, 201)
+ self.assertEqual(resp.status, 201)
resp = retry(head, name)
resp.read()
self.assert_(resp.status in (200, 204), resp.status)
- self.assertEquals(resp.getheader('x-container-meta-test'), None)
+ self.assertEqual(resp.getheader('x-container-meta-test'), None)
resp = retry(get, name)
resp.read()
self.assert_(resp.status in (200, 204), resp.status)
- self.assertEquals(resp.getheader('x-container-meta-test'), None)
+ self.assertEqual(resp.getheader('x-container-meta-test'), None)
resp = retry(delete, name)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
def test_POST_metadata(self):
if skip:
@@ -231,22 +231,22 @@ class TestContainer(unittest.TestCase):
resp = retry(head)
resp.read()
self.assert_(resp.status in (200, 204), resp.status)
- self.assertEquals(resp.getheader('x-container-meta-test'), None)
+ self.assertEqual(resp.getheader('x-container-meta-test'), None)
resp = retry(get)
resp.read()
self.assert_(resp.status in (200, 204), resp.status)
- self.assertEquals(resp.getheader('x-container-meta-test'), None)
+ self.assertEqual(resp.getheader('x-container-meta-test'), None)
resp = retry(post, 'Value')
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
resp = retry(head)
resp.read()
self.assert_(resp.status in (200, 204), resp.status)
- self.assertEquals(resp.getheader('x-container-meta-test'), 'Value')
+ self.assertEqual(resp.getheader('x-container-meta-test'), 'Value')
resp = retry(get)
resp.read()
self.assert_(resp.status in (200, 204), resp.status)
- self.assertEquals(resp.getheader('x-container-meta-test'), 'Value')
+ self.assertEqual(resp.getheader('x-container-meta-test'), 'Value')
def test_PUT_bad_metadata(self):
if skip:
@@ -268,38 +268,38 @@ class TestContainer(unittest.TestCase):
put, name,
{'X-Container-Meta-' + ('k' * MAX_META_NAME_LENGTH): 'v'})
resp.read()
- self.assertEquals(resp.status, 201)
+ self.assertEqual(resp.status, 201)
resp = retry(delete, name)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
name = uuid4().hex
resp = retry(
put, name,
{'X-Container-Meta-' + ('k' * (MAX_META_NAME_LENGTH + 1)): 'v'})
resp.read()
- self.assertEquals(resp.status, 400)
+ self.assertEqual(resp.status, 400)
resp = retry(delete, name)
resp.read()
- self.assertEquals(resp.status, 404)
+ self.assertEqual(resp.status, 404)
name = uuid4().hex
resp = retry(
put, name,
{'X-Container-Meta-Too-Long': 'k' * MAX_META_VALUE_LENGTH})
resp.read()
- self.assertEquals(resp.status, 201)
+ self.assertEqual(resp.status, 201)
resp = retry(delete, name)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
name = uuid4().hex
resp = retry(
put, name,
{'X-Container-Meta-Too-Long': 'k' * (MAX_META_VALUE_LENGTH + 1)})
resp.read()
- self.assertEquals(resp.status, 400)
+ self.assertEqual(resp.status, 400)
resp = retry(delete, name)
resp.read()
- self.assertEquals(resp.status, 404)
+ self.assertEqual(resp.status, 404)
name = uuid4().hex
headers = {}
@@ -307,20 +307,20 @@ class TestContainer(unittest.TestCase):
headers['X-Container-Meta-%d' % x] = 'v'
resp = retry(put, name, headers)
resp.read()
- self.assertEquals(resp.status, 201)
+ self.assertEqual(resp.status, 201)
resp = retry(delete, name)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
name = uuid4().hex
headers = {}
for x in xrange(MAX_META_COUNT + 1):
headers['X-Container-Meta-%d' % x] = 'v'
resp = retry(put, name, headers)
resp.read()
- self.assertEquals(resp.status, 400)
+ self.assertEqual(resp.status, 400)
resp = retry(delete, name)
resp.read()
- self.assertEquals(resp.status, 404)
+ self.assertEqual(resp.status, 404)
name = uuid4().hex
headers = {}
@@ -336,19 +336,19 @@ class TestContainer(unittest.TestCase):
'v' * (MAX_META_OVERALL_SIZE - size - 1)
resp = retry(put, name, headers)
resp.read()
- self.assertEquals(resp.status, 201)
+ self.assertEqual(resp.status, 201)
resp = retry(delete, name)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
name = uuid4().hex
headers['X-Container-Meta-k'] = \
'v' * (MAX_META_OVERALL_SIZE - size)
resp = retry(put, name, headers)
resp.read()
- self.assertEquals(resp.status, 400)
+ self.assertEqual(resp.status, 400)
resp = retry(delete, name)
resp.read()
- self.assertEquals(resp.status, 404)
+ self.assertEqual(resp.status, 404)
def test_POST_bad_metadata(self):
if skip:
@@ -364,36 +364,56 @@ class TestContainer(unittest.TestCase):
post,
{'X-Container-Meta-' + ('k' * MAX_META_NAME_LENGTH): 'v'})
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
resp = retry(
post,
{'X-Container-Meta-' + ('k' * (MAX_META_NAME_LENGTH + 1)): 'v'})
resp.read()
- self.assertEquals(resp.status, 400)
+ self.assertEqual(resp.status, 400)
resp = retry(
post,
{'X-Container-Meta-Too-Long': 'k' * MAX_META_VALUE_LENGTH})
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
resp = retry(
post,
{'X-Container-Meta-Too-Long': 'k' * (MAX_META_VALUE_LENGTH + 1)})
resp.read()
- self.assertEquals(resp.status, 400)
+ self.assertEqual(resp.status, 400)
+
+ def test_POST_bad_metadata2(self):
+ if skip:
+ raise SkipTest
+
+ def post(url, token, parsed, conn, extra_headers):
+ headers = {'X-Auth-Token': token}
+ headers.update(extra_headers)
+ conn.request('POST', parsed.path + '/' + self.name, '', headers)
+ return check_response(conn)
headers = {}
for x in xrange(MAX_META_COUNT):
headers['X-Container-Meta-%d' % x] = 'v'
resp = retry(post, headers)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
headers = {}
for x in xrange(MAX_META_COUNT + 1):
headers['X-Container-Meta-%d' % x] = 'v'
resp = retry(post, headers)
resp.read()
- self.assertEquals(resp.status, 400)
+ self.assertEqual(resp.status, 400)
+
+ def test_POST_bad_metadata3(self):
+ if skip:
+ raise SkipTest
+
+ def post(url, token, parsed, conn, extra_headers):
+ headers = {'X-Auth-Token': token}
+ headers.update(extra_headers)
+ conn.request('POST', parsed.path + '/' + self.name, '', headers)
+ return check_response(conn)
headers = {}
header_value = 'k' * MAX_META_VALUE_LENGTH
@@ -408,12 +428,12 @@ class TestContainer(unittest.TestCase):
'v' * (MAX_META_OVERALL_SIZE - size - 1)
resp = retry(post, headers)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
headers['X-Container-Meta-k'] = \
'v' * (MAX_META_OVERALL_SIZE - size)
resp = retry(post, headers)
resp.read()
- self.assertEquals(resp.status, 400)
+ self.assertEqual(resp.status, 400)
def test_public_container(self):
if skip:
@@ -437,10 +457,10 @@ class TestContainer(unittest.TestCase):
resp = retry(post)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
resp = retry(get)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
def post(url, token, parsed, conn):
conn.request('POST', parsed.path + '/' + self.name, '',
@@ -449,7 +469,7 @@ class TestContainer(unittest.TestCase):
resp = retry(post)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
try:
resp = retry(get)
raise Exception('Should not have been able to GET')
@@ -479,7 +499,7 @@ class TestContainer(unittest.TestCase):
resp = retry(get2, use_account=2)
resp.read()
- self.assertEquals(resp.status, 403)
+ self.assertEqual(resp.status, 403)
# Make the container accessible by the second account
def post(url, token, parsed, conn):
@@ -491,11 +511,11 @@ class TestContainer(unittest.TestCase):
resp = retry(post)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
# Ensure we can now use the container with the second account
resp = retry(get2, use_account=2)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
# Make the container private again
def post(url, token, parsed, conn):
@@ -506,11 +526,11 @@ class TestContainer(unittest.TestCase):
resp = retry(post)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
# Ensure we can't access the container with the second account again
resp = retry(get2, use_account=2)
resp.read()
- self.assertEquals(resp.status, 403)
+ self.assertEqual(resp.status, 403)
def test_cross_account_public_container(self):
if skip or skip2:
@@ -535,7 +555,7 @@ class TestContainer(unittest.TestCase):
resp = retry(get2, use_account=2)
resp.read()
- self.assertEquals(resp.status, 403)
+ self.assertEqual(resp.status, 403)
# Make the container completely public
def post(url, token, parsed, conn):
@@ -546,11 +566,11 @@ class TestContainer(unittest.TestCase):
resp = retry(post)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
# Ensure we can now read the container with the second account
resp = retry(get2, use_account=2)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
# But we shouldn't be able to write with the second account
def put2(url, token, parsed, conn):
@@ -560,7 +580,7 @@ class TestContainer(unittest.TestCase):
resp = retry(put2, use_account=2)
resp.read()
- self.assertEquals(resp.status, 403)
+ self.assertEqual(resp.status, 403)
# Now make the container also writeable by the second account
def post(url, token, parsed, conn):
@@ -571,15 +591,15 @@ class TestContainer(unittest.TestCase):
resp = retry(post)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
# Ensure we can still read the container with the second account
resp = retry(get2, use_account=2)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
# And that we can now write with the second account
resp = retry(put2, use_account=2)
resp.read()
- self.assertEquals(resp.status, 201)
+ self.assertEqual(resp.status, 201)
def test_nonadmin_user(self):
if skip or skip3:
@@ -604,7 +624,7 @@ class TestContainer(unittest.TestCase):
resp = retry(get3, use_account=3)
resp.read()
- self.assertEquals(resp.status, 403)
+ self.assertEqual(resp.status, 403)
# Make the container accessible by the third account
def post(url, token, parsed, conn):
@@ -615,11 +635,11 @@ class TestContainer(unittest.TestCase):
resp = retry(post)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
# Ensure we can now read the container with the third account
resp = retry(get3, use_account=3)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
# But we shouldn't be able to write with the third account
def put3(url, token, parsed, conn):
@@ -629,7 +649,7 @@ class TestContainer(unittest.TestCase):
resp = retry(put3, use_account=3)
resp.read()
- self.assertEquals(resp.status, 403)
+ self.assertEqual(resp.status, 403)
# Now make the container also writeable by the third account
def post(url, token, parsed, conn):
@@ -640,15 +660,666 @@ class TestContainer(unittest.TestCase):
resp = retry(post)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
# Ensure we can still read the container with the third account
resp = retry(get3, use_account=3)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
# And that we can now write with the third account
resp = retry(put3, use_account=3)
resp.read()
+ self.assertEqual(resp.status, 201)
+
+ @requires_acls
+ def test_read_only_acl_listings(self):
+ if skip3:
+ raise SkipTest
+
+ def get(url, token, parsed, conn):
+ conn.request('GET', parsed.path, '', {'X-Auth-Token': token})
+ return check_response(conn)
+
+ def post_account(url, token, parsed, conn, headers):
+ new_headers = dict({'X-Auth-Token': token}, **headers)
+ conn.request('POST', parsed.path, '', new_headers)
+ return check_response(conn)
+
+ def put(url, token, parsed, conn, name):
+ conn.request('PUT', parsed.path + '/%s' % name, '',
+ {'X-Auth-Token': token})
+ return check_response(conn)
+
+ # cannot list containers
+ resp = retry(get, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 403)
+
+ # grant read-only access
+ acl_user = swift_test_user[2]
+ acl = {'read-only': [acl_user]}
+ headers = {'x-account-access-control': json.dumps(acl)}
+ resp = retry(post_account, headers=headers, use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+
+ # read-only can list containers
+ resp = retry(get, use_account=3)
+ listing = resp.read()
+ self.assertEquals(resp.status, 200)
+ self.assert_(self.name in listing)
+
+ # read-only can not create containers
+ new_container_name = str(uuid4())
+ resp = retry(put, new_container_name, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 403)
+
+ # but it can see newly created ones
+ resp = retry(put, new_container_name, use_account=1)
+ resp.read()
self.assertEquals(resp.status, 201)
+ resp = retry(get, use_account=3)
+ listing = resp.read()
+ self.assertEquals(resp.status, 200)
+ self.assert_(new_container_name in listing)
+
+ @requires_acls
+ def test_read_only_acl_metadata(self):
+ if skip3:
+ raise SkipTest
+
+ def get(url, token, parsed, conn, name):
+ conn.request('GET', parsed.path + '/%s' % name, '',
+ {'X-Auth-Token': token})
+ return check_response(conn)
+
+ def post_account(url, token, parsed, conn, headers):
+ new_headers = dict({'X-Auth-Token': token}, **headers)
+ conn.request('POST', parsed.path, '', new_headers)
+ return check_response(conn)
+
+ def post(url, token, parsed, conn, name, headers):
+ new_headers = dict({'X-Auth-Token': token}, **headers)
+ conn.request('POST', parsed.path + '/%s' % name, '', new_headers)
+ return check_response(conn)
+
+ # add some metadata
+ value = str(uuid4())
+ headers = {'x-container-meta-test': value}
+ resp = retry(post, self.name, headers=headers, use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+ resp = retry(get, self.name, use_account=1)
+ resp.read()
+ self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.getheader('X-Container-Meta-Test'), value)
+
+ # cannot see metadata
+ resp = retry(get, self.name, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 403)
+
+ # grant read-only access
+ acl_user = swift_test_user[2]
+ acl = {'read-only': [acl_user]}
+ headers = {'x-account-access-control': json.dumps(acl)}
+ resp = retry(post_account, headers=headers, use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+
+ # read-only can NOT write container metadata
+ new_value = str(uuid4())
+ headers = {'x-container-meta-test': new_value}
+ resp = retry(post, self.name, headers=headers, use_account=3)
+ resp.read()
+ self.assertEqual(resp.status, 403)
+
+ # read-only can read container metadata
+ resp = retry(get, self.name, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.getheader('X-Container-Meta-Test'), value)
+
+ @requires_acls
+ def test_read_write_acl_listings(self):
+ if skip3:
+ raise SkipTest
+
+ def get(url, token, parsed, conn):
+ conn.request('GET', parsed.path, '', {'X-Auth-Token': token})
+ return check_response(conn)
+
+ def post(url, token, parsed, conn, headers):
+ new_headers = dict({'X-Auth-Token': token}, **headers)
+ conn.request('POST', parsed.path, '', new_headers)
+ return check_response(conn)
+
+ def put(url, token, parsed, conn, name):
+ conn.request('PUT', parsed.path + '/%s' % name, '',
+ {'X-Auth-Token': token})
+ return check_response(conn)
+
+ def delete(url, token, parsed, conn, name):
+ conn.request('DELETE', parsed.path + '/%s' % name, '',
+ {'X-Auth-Token': token})
+ return check_response(conn)
+
+ # cannot list containers
+ resp = retry(get, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 403)
+
+ # grant read-write access
+ acl_user = swift_test_user[2]
+ acl = {'read-write': [acl_user]}
+ headers = {'x-account-access-control': json.dumps(acl)}
+ resp = retry(post, headers=headers, use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+
+ # can list containers
+ resp = retry(get, use_account=3)
+ listing = resp.read()
+ self.assertEquals(resp.status, 200)
+ self.assert_(self.name in listing)
+
+ # can create new containers
+ new_container_name = str(uuid4())
+ resp = retry(put, new_container_name, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 201)
+ resp = retry(get, use_account=3)
+ listing = resp.read()
+ self.assertEquals(resp.status, 200)
+ self.assert_(new_container_name in listing)
+
+ # can also delete them
+ resp = retry(delete, new_container_name, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 204)
+ resp = retry(get, use_account=3)
+ listing = resp.read()
+ self.assertEquals(resp.status, 200)
+ self.assert_(new_container_name not in listing)
+
+ # even if they didn't create them
+ empty_container_name = str(uuid4())
+ resp = retry(put, empty_container_name, use_account=1)
+ resp.read()
+ self.assertEquals(resp.status, 201)
+ resp = retry(delete, empty_container_name, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 204)
+
+ @requires_acls
+ def test_read_write_acl_metadata(self):
+ if skip3:
+ raise SkipTest
+
+ def get(url, token, parsed, conn, name):
+ conn.request('GET', parsed.path + '/%s' % name, '',
+ {'X-Auth-Token': token})
+ return check_response(conn)
+
+ def post_account(url, token, parsed, conn, headers):
+ new_headers = dict({'X-Auth-Token': token}, **headers)
+ conn.request('POST', parsed.path, '', new_headers)
+ return check_response(conn)
+
+ def post(url, token, parsed, conn, name, headers):
+ new_headers = dict({'X-Auth-Token': token}, **headers)
+ conn.request('POST', parsed.path + '/%s' % name, '', new_headers)
+ return check_response(conn)
+
+ # add some metadata
+ value = str(uuid4())
+ headers = {'x-container-meta-test': value}
+ resp = retry(post, self.name, headers=headers, use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+ resp = retry(get, self.name, use_account=1)
+ resp.read()
+ self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.getheader('X-Container-Meta-Test'), value)
+
+ # cannot see metadata
+ resp = retry(get, self.name, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 403)
+
+ # grant read-write access
+ acl_user = swift_test_user[2]
+ acl = {'read-write': [acl_user]}
+ headers = {'x-account-access-control': json.dumps(acl)}
+ resp = retry(post_account, headers=headers, use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+
+ # read-write can read container metadata
+ resp = retry(get, self.name, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.getheader('X-Container-Meta-Test'), value)
+
+ # read-write can also write container metadata
+ new_value = str(uuid4())
+ headers = {'x-container-meta-test': new_value}
+ resp = retry(post, self.name, headers=headers, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 204)
+ resp = retry(get, self.name, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.getheader('X-Container-Meta-Test'), new_value)
+
+ # and remove it
+ headers = {'x-remove-container-meta-test': 'true'}
+ resp = retry(post, self.name, headers=headers, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 204)
+ resp = retry(get, self.name, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.getheader('X-Container-Meta-Test'), None)
+
+ @requires_acls
+ def test_admin_acl_listing(self):
+ if skip3:
+ raise SkipTest
+
+ def get(url, token, parsed, conn):
+ conn.request('GET', parsed.path, '', {'X-Auth-Token': token})
+ return check_response(conn)
+
+ def post(url, token, parsed, conn, headers):
+ new_headers = dict({'X-Auth-Token': token}, **headers)
+ conn.request('POST', parsed.path, '', new_headers)
+ return check_response(conn)
+
+ def put(url, token, parsed, conn, name):
+ conn.request('PUT', parsed.path + '/%s' % name, '',
+ {'X-Auth-Token': token})
+ return check_response(conn)
+
+ def delete(url, token, parsed, conn, name):
+ conn.request('DELETE', parsed.path + '/%s' % name, '',
+ {'X-Auth-Token': token})
+ return check_response(conn)
+
+ # cannot list containers
+ resp = retry(get, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 403)
+
+ # grant admin access
+ acl_user = swift_test_user[2]
+ acl = {'admin': [acl_user]}
+ headers = {'x-account-access-control': json.dumps(acl)}
+ resp = retry(post, headers=headers, use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+
+ # can list containers
+ resp = retry(get, use_account=3)
+ listing = resp.read()
+ self.assertEquals(resp.status, 200)
+ self.assert_(self.name in listing)
+
+ # can create new containers
+ new_container_name = str(uuid4())
+ resp = retry(put, new_container_name, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 201)
+ resp = retry(get, use_account=3)
+ listing = resp.read()
+ self.assertEquals(resp.status, 200)
+ self.assert_(new_container_name in listing)
+
+ # can also delete them
+ resp = retry(delete, new_container_name, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 204)
+ resp = retry(get, use_account=3)
+ listing = resp.read()
+ self.assertEquals(resp.status, 200)
+ self.assert_(new_container_name not in listing)
+
+ # even if they didn't create them
+ empty_container_name = str(uuid4())
+ resp = retry(put, empty_container_name, use_account=1)
+ resp.read()
+ self.assertEquals(resp.status, 201)
+ resp = retry(delete, empty_container_name, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 204)
+
+ @requires_acls
+ def test_admin_acl_metadata(self):
+ if skip3:
+ raise SkipTest
+
+ def get(url, token, parsed, conn, name):
+ conn.request('GET', parsed.path + '/%s' % name, '',
+ {'X-Auth-Token': token})
+ return check_response(conn)
+
+ def post_account(url, token, parsed, conn, headers):
+ new_headers = dict({'X-Auth-Token': token}, **headers)
+ conn.request('POST', parsed.path, '', new_headers)
+ return check_response(conn)
+
+ def post(url, token, parsed, conn, name, headers):
+ new_headers = dict({'X-Auth-Token': token}, **headers)
+ conn.request('POST', parsed.path + '/%s' % name, '', new_headers)
+ return check_response(conn)
+
+ # add some metadata
+ value = str(uuid4())
+ headers = {'x-container-meta-test': value}
+ resp = retry(post, self.name, headers=headers, use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+ resp = retry(get, self.name, use_account=1)
+ resp.read()
+ self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.getheader('X-Container-Meta-Test'), value)
+
+ # cannot see metadata
+ resp = retry(get, self.name, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 403)
+
+ # grant access
+ acl_user = swift_test_user[2]
+ acl = {'admin': [acl_user]}
+ headers = {'x-account-access-control': json.dumps(acl)}
+ resp = retry(post_account, headers=headers, use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+
+ # can read container metadata
+ resp = retry(get, self.name, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.getheader('X-Container-Meta-Test'), value)
+
+ # can also write container metadata
+ new_value = str(uuid4())
+ headers = {'x-container-meta-test': new_value}
+ resp = retry(post, self.name, headers=headers, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 204)
+ resp = retry(get, self.name, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.getheader('X-Container-Meta-Test'), new_value)
+
+ # and remove it
+ headers = {'x-remove-container-meta-test': 'true'}
+ resp = retry(post, self.name, headers=headers, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 204)
+ resp = retry(get, self.name, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.getheader('X-Container-Meta-Test'), None)
+
+ @requires_acls
+ def test_protected_container_sync(self):
+ if skip3:
+ raise SkipTest
+
+ def get(url, token, parsed, conn, name):
+ conn.request('GET', parsed.path + '/%s' % name, '',
+ {'X-Auth-Token': token})
+ return check_response(conn)
+
+ def post_account(url, token, parsed, conn, headers):
+ new_headers = dict({'X-Auth-Token': token}, **headers)
+ conn.request('POST', parsed.path, '', new_headers)
+ return check_response(conn)
+
+ def post(url, token, parsed, conn, name, headers):
+ new_headers = dict({'X-Auth-Token': token}, **headers)
+ conn.request('POST', parsed.path + '/%s' % name, '', new_headers)
+ return check_response(conn)
+
+ # add some metadata
+ value = str(uuid4())
+ headers = {
+ 'x-container-sync-key': 'secret',
+ 'x-container-meta-test': value,
+ }
+ resp = retry(post, self.name, headers=headers, use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+ resp = retry(get, self.name, use_account=1)
+ resp.read()
+ self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.getheader('X-Container-Sync-Key'), 'secret')
+ self.assertEqual(resp.getheader('X-Container-Meta-Test'), value)
+
+ # grant read-only access
+ acl_user = swift_test_user[2]
+ acl = {'read-only': [acl_user]}
+ headers = {'x-account-access-control': json.dumps(acl)}
+ resp = retry(post_account, headers=headers, use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+
+ # can read container metadata
+ resp = retry(get, self.name, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.getheader('X-Container-Meta-Test'), value)
+ # but not sync-key
+ self.assertEqual(resp.getheader('X-Container-Sync-Key'), None)
+
+ # and can not write
+ headers = {'x-container-sync-key': str(uuid4())}
+ resp = retry(post, self.name, headers=headers, use_account=3)
+ resp.read()
+ self.assertEqual(resp.status, 403)
+
+ # grant read-write access
+ acl_user = swift_test_user[2]
+ acl = {'read-write': [acl_user]}
+ headers = {'x-account-access-control': json.dumps(acl)}
+ resp = retry(post_account, headers=headers, use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+
+ # can read container metadata
+ resp = retry(get, self.name, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.getheader('X-Container-Meta-Test'), value)
+ # but not sync-key
+ self.assertEqual(resp.getheader('X-Container-Sync-Key'), None)
+
+ # sanity check sync-key w/ account1
+ resp = retry(get, self.name, use_account=1)
+ resp.read()
+ self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.getheader('X-Container-Sync-Key'), 'secret')
+
+ # and can write
+ new_value = str(uuid4())
+ headers = {
+ 'x-container-sync-key': str(uuid4()),
+ 'x-container-meta-test': new_value,
+ }
+ resp = retry(post, self.name, headers=headers, use_account=3)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+ resp = retry(get, self.name, use_account=1) # validate w/ account1
+ resp.read()
+ self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.getheader('X-Container-Meta-Test'), new_value)
+ # but can not write sync-key
+ self.assertEqual(resp.getheader('X-Container-Sync-Key'), 'secret')
+
+ # grant admin access
+ acl_user = swift_test_user[2]
+ acl = {'admin': [acl_user]}
+ headers = {'x-account-access-control': json.dumps(acl)}
+ resp = retry(post_account, headers=headers, use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+
+ # admin can read container metadata
+ resp = retry(get, self.name, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.getheader('X-Container-Meta-Test'), new_value)
+ # and ALSO sync-key
+ self.assertEqual(resp.getheader('X-Container-Sync-Key'), 'secret')
+
+ # admin tester3 can even change sync-key
+ new_secret = str(uuid4())
+ headers = {'x-container-sync-key': new_secret}
+ resp = retry(post, self.name, headers=headers, use_account=3)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+ resp = retry(get, self.name, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.getheader('X-Container-Sync-Key'), new_secret)
+
+ @requires_acls
+ def test_protected_container_acl(self):
+ if skip3:
+ raise SkipTest
+
+ def get(url, token, parsed, conn, name):
+ conn.request('GET', parsed.path + '/%s' % name, '',
+ {'X-Auth-Token': token})
+ return check_response(conn)
+
+ def post_account(url, token, parsed, conn, headers):
+ new_headers = dict({'X-Auth-Token': token}, **headers)
+ conn.request('POST', parsed.path, '', new_headers)
+ return check_response(conn)
+
+ def post(url, token, parsed, conn, name, headers):
+ new_headers = dict({'X-Auth-Token': token}, **headers)
+ conn.request('POST', parsed.path + '/%s' % name, '', new_headers)
+ return check_response(conn)
+
+ # add some container acls
+ value = str(uuid4())
+ headers = {
+ 'x-container-read': 'jdoe',
+ 'x-container-write': 'jdoe',
+ 'x-container-meta-test': value,
+ }
+ resp = retry(post, self.name, headers=headers, use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+ resp = retry(get, self.name, use_account=1)
+ resp.read()
+ self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.getheader('X-Container-Read'), 'jdoe')
+ self.assertEqual(resp.getheader('X-Container-Write'), 'jdoe')
+ self.assertEqual(resp.getheader('X-Container-Meta-Test'), value)
+
+ # grant read-only access
+ acl_user = swift_test_user[2]
+ acl = {'read-only': [acl_user]}
+ headers = {'x-account-access-control': json.dumps(acl)}
+ resp = retry(post_account, headers=headers, use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+
+ # can read container metadata
+ resp = retry(get, self.name, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.getheader('X-Container-Meta-Test'), value)
+ # but not container acl
+ self.assertEqual(resp.getheader('X-Container-Read'), None)
+ self.assertEqual(resp.getheader('X-Container-Write'), None)
+
+ # and can not write
+ headers = {
+ 'x-container-read': 'frank',
+ 'x-container-write': 'frank',
+ }
+ resp = retry(post, self.name, headers=headers, use_account=3)
+ resp.read()
+ self.assertEqual(resp.status, 403)
+
+ # grant read-write access
+ acl_user = swift_test_user[2]
+ acl = {'read-write': [acl_user]}
+ headers = {'x-account-access-control': json.dumps(acl)}
+ resp = retry(post_account, headers=headers, use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+
+ # can read container metadata
+ resp = retry(get, self.name, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.getheader('X-Container-Meta-Test'), value)
+ # but not container acl
+ self.assertEqual(resp.getheader('X-Container-Read'), None)
+ self.assertEqual(resp.getheader('X-Container-Write'), None)
+
+ # sanity check container acls with account1
+ resp = retry(get, self.name, use_account=1)
+ resp.read()
+ self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.getheader('X-Container-Read'), 'jdoe')
+ self.assertEqual(resp.getheader('X-Container-Write'), 'jdoe')
+
+ # and can write
+ new_value = str(uuid4())
+ headers = {
+ 'x-container-read': 'frank',
+ 'x-container-write': 'frank',
+ 'x-container-meta-test': new_value,
+ }
+ resp = retry(post, self.name, headers=headers, use_account=3)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+ resp = retry(get, self.name, use_account=1) # validate w/ account1
+ resp.read()
+ self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.getheader('X-Container-Meta-Test'), new_value)
+ # but can not write container acls
+ self.assertEqual(resp.getheader('X-Container-Read'), 'jdoe')
+ self.assertEqual(resp.getheader('X-Container-Write'), 'jdoe')
+
+ # grant admin access
+ acl_user = swift_test_user[2]
+ acl = {'admin': [acl_user]}
+ headers = {'x-account-access-control': json.dumps(acl)}
+ resp = retry(post_account, headers=headers, use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+
+ # admin can read container metadata
+ resp = retry(get, self.name, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.getheader('X-Container-Meta-Test'), new_value)
+ # and ALSO container acls
+ self.assertEqual(resp.getheader('X-Container-Read'), 'jdoe')
+ self.assertEqual(resp.getheader('X-Container-Write'), 'jdoe')
+
+ # admin tester3 can even change container acls
+ new_value = str(uuid4())
+ headers = {
+ 'x-container-read': '.r:*',
+ }
+ resp = retry(post, self.name, headers=headers, use_account=3)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+ resp = retry(get, self.name, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.getheader('X-Container-Read'), '.r:*')
def test_long_name_content_type(self):
if skip:
@@ -662,9 +1333,9 @@ class TestContainer(unittest.TestCase):
resp = retry(put)
resp.read()
- self.assertEquals(resp.status, 400)
- self.assertEquals(resp.getheader('Content-Type'),
- 'text/html; charset=UTF-8')
+ self.assertEqual(resp.status, 400)
+ self.assertEqual(resp.getheader('Content-Type'),
+ 'text/html; charset=UTF-8')
def test_null_name(self):
if skip:
@@ -677,10 +1348,10 @@ class TestContainer(unittest.TestCase):
resp = retry(put)
if (web_front_end == 'apache2'):
- self.assertEquals(resp.status, 404)
+ self.assertEqual(resp.status, 404)
else:
- self.assertEquals(resp.read(), 'Invalid UTF8 or contains NULL')
- self.assertEquals(resp.status, 412)
+ self.assertEqual(resp.read(), 'Invalid UTF8 or contains NULL')
+ self.assertEqual(resp.status, 412)
if __name__ == '__main__':
diff --git a/test/functional/test_object.py b/test/functional/test_object.py
index dad8635..675de30 100755
--- a/test/functional/test_object.py
+++ b/test/functional/test_object.py
@@ -19,8 +19,10 @@ import unittest
from nose import SkipTest
from uuid import uuid4
+from swift.common.utils import json
+
from swift_testing import check_response, retry, skip, skip3, \
- swift_test_perm, web_front_end
+ swift_test_perm, web_front_end, requires_acls, swift_test_user
class TestObject(unittest.TestCase):
@@ -36,7 +38,7 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(put)
resp.read()
- self.assertEquals(resp.status, 201)
+ self.assertEqual(resp.status, 201)
self.obj = uuid4().hex
def put(url, token, parsed, conn):
@@ -46,7 +48,7 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(put)
resp.read()
- self.assertEquals(resp.status, 201)
+ self.assertEqual(resp.status, 201)
def tearDown(self):
if skip:
@@ -66,13 +68,13 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(list)
object_listing = resp.read()
- self.assertEquals(resp.status, 200)
+ self.assertEqual(resp.status, 200)
# iterate over object listing and delete all objects
for obj in object_listing.splitlines():
resp = retry(delete, obj)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
# delete the container
def delete(url, token, parsed, conn):
@@ -81,7 +83,33 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(delete)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
+
+ def test_if_none_match(self):
+ def put(url, token, parsed, conn):
+ conn.request('PUT', '%s/%s/%s' % (
+ parsed.path, self.container, 'if_none_match_test'), '',
+ {'X-Auth-Token': token,
+ 'Content-Length': '0',
+ 'If-None-Match': '*'})
+ return check_response(conn)
+ resp = retry(put)
+ resp.read()
+ self.assertEquals(resp.status, 201)
+ resp = retry(put)
+ resp.read()
+ self.assertEquals(resp.status, 412)
+
+ def put(url, token, parsed, conn):
+ conn.request('PUT', '%s/%s/%s' % (
+ parsed.path, self.container, 'if_none_match_test'), '',
+ {'X-Auth-Token': token,
+ 'Content-Length': '0',
+ 'If-None-Match': 'somethingelse'})
+ return check_response(conn)
+ resp = retry(put)
+ resp.read()
+ self.assertEquals(resp.status, 400)
def test_copy_object(self):
if skip:
@@ -98,8 +126,8 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(get_source)
source_contents = resp.read()
- self.assertEquals(resp.status, 200)
- self.assertEquals(source_contents, 'test')
+ self.assertEqual(resp.status, 200)
+ self.assertEqual(source_contents, 'test')
# copy source to dest with X-Copy-From
def put(url, token, parsed, conn):
@@ -110,7 +138,7 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(put)
resp.read()
- self.assertEquals(resp.status, 201)
+ self.assertEqual(resp.status, 201)
# contents of dest should be the same as source
def get_dest(url, token, parsed, conn):
@@ -120,8 +148,8 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(get_dest)
dest_contents = resp.read()
- self.assertEquals(resp.status, 200)
- self.assertEquals(dest_contents, source_contents)
+ self.assertEqual(resp.status, 200)
+ self.assertEqual(dest_contents, source_contents)
# delete the copy
def delete(url, token, parsed, conn):
@@ -130,11 +158,11 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(delete)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
# verify dest does not exist
resp = retry(get_dest)
resp.read()
- self.assertEquals(resp.status, 404)
+ self.assertEqual(resp.status, 404)
# copy source to dest with COPY
def copy(url, token, parsed, conn):
@@ -144,18 +172,18 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(copy)
resp.read()
- self.assertEquals(resp.status, 201)
+ self.assertEqual(resp.status, 201)
# contents of dest should be the same as source
resp = retry(get_dest)
dest_contents = resp.read()
- self.assertEquals(resp.status, 200)
- self.assertEquals(dest_contents, source_contents)
+ self.assertEqual(resp.status, 200)
+ self.assertEqual(dest_contents, source_contents)
# delete the copy
resp = retry(delete)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
def test_public_object(self):
if skip:
@@ -178,10 +206,10 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(post)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
resp = retry(get)
resp.read()
- self.assertEquals(resp.status, 200)
+ self.assertEqual(resp.status, 200)
def post(url, token, parsed, conn):
conn.request('POST', parsed.path + '/' + self.container, '',
@@ -189,7 +217,7 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(post)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
try:
resp = retry(get)
raise Exception('Should not have been able to GET')
@@ -208,7 +236,7 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(get, use_account=3)
resp.read()
- self.assertEquals(resp.status, 403)
+ self.assertEqual(resp.status, 403)
# create a shared container writable by account3
shared_container = uuid4().hex
@@ -222,7 +250,7 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(put)
resp.read()
- self.assertEquals(resp.status, 201)
+ self.assertEqual(resp.status, 201)
# verify third account can not copy from private container
def copy(url, token, parsed, conn):
@@ -234,7 +262,7 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(copy, use_account=3)
resp.read()
- self.assertEquals(resp.status, 403)
+ self.assertEqual(resp.status, 403)
# verify third account can write "obj1" to shared container
def put(url, token, parsed, conn):
@@ -244,7 +272,7 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(put, use_account=3)
resp.read()
- self.assertEquals(resp.status, 201)
+ self.assertEqual(resp.status, 201)
# verify third account can copy "obj1" to shared container
def copy2(url, token, parsed, conn):
@@ -255,7 +283,7 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(copy2, use_account=3)
resp.read()
- self.assertEquals(resp.status, 201)
+ self.assertEqual(resp.status, 201)
# verify third account STILL can not copy from private container
def copy3(url, token, parsed, conn):
@@ -267,7 +295,7 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(copy3, use_account=3)
resp.read()
- self.assertEquals(resp.status, 403)
+ self.assertEqual(resp.status, 403)
# clean up "obj1"
def delete(url, token, parsed, conn):
@@ -277,7 +305,7 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(delete)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
# clean up shared_container
def delete(url, token, parsed, conn):
@@ -287,8 +315,251 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(delete)
resp.read()
+ self.assertEqual(resp.status, 204)
+
+ @requires_acls
+ def test_read_only(self):
+ if skip3:
+ raise SkipTest
+
+ def get_listing(url, token, parsed, conn):
+ conn.request('GET', '%s/%s' % (parsed.path, self.container), '',
+ {'X-Auth-Token': token})
+ return check_response(conn)
+
+ def post_account(url, token, parsed, conn, headers):
+ new_headers = dict({'X-Auth-Token': token}, **headers)
+ conn.request('POST', parsed.path, '', new_headers)
+ return check_response(conn)
+
+ def get(url, token, parsed, conn, name):
+ conn.request('GET', '%s/%s/%s' % (
+ parsed.path, self.container, name), '',
+ {'X-Auth-Token': token})
+ return check_response(conn)
+
+ def put(url, token, parsed, conn, name):
+ conn.request('PUT', '%s/%s/%s' % (
+ parsed.path, self.container, name), 'test',
+ {'X-Auth-Token': token})
+ return check_response(conn)
+
+ def delete(url, token, parsed, conn, name):
+ conn.request('PUT', '%s/%s/%s' % (
+ parsed.path, self.container, name), '',
+ {'X-Auth-Token': token})
+ return check_response(conn)
+
+ # cannot list objects
+ resp = retry(get_listing, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 403)
+
+ # cannot get object
+ resp = retry(get, self.obj, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 403)
+
+ # grant read-only access
+ acl_user = swift_test_user[2]
+ acl = {'read-only': [acl_user]}
+ headers = {'x-account-access-control': json.dumps(acl)}
+ resp = retry(post_account, headers=headers, use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+
+ # can list objects
+ resp = retry(get_listing, use_account=3)
+ listing = resp.read()
+ self.assertEquals(resp.status, 200)
+ self.assert_(self.obj in listing)
+
+ # can get object
+ resp = retry(get, self.obj, use_account=3)
+ body = resp.read()
+ self.assertEquals(resp.status, 200)
+ self.assertEquals(body, 'test')
+
+ # can not put an object
+ obj_name = str(uuid4())
+ resp = retry(put, obj_name, use_account=3)
+ body = resp.read()
+ self.assertEquals(resp.status, 403)
+
+ # can not delete an object
+ resp = retry(delete, self.obj, use_account=3)
+ body = resp.read()
+ self.assertEquals(resp.status, 403)
+
+ # sanity with account1
+ resp = retry(get_listing, use_account=3)
+ listing = resp.read()
+ self.assertEquals(resp.status, 200)
+ self.assert_(obj_name not in listing)
+ self.assert_(self.obj in listing)
+
+ @requires_acls
+ def test_read_write(self):
+ if skip3:
+ raise SkipTest
+
+ def get_listing(url, token, parsed, conn):
+ conn.request('GET', '%s/%s' % (parsed.path, self.container), '',
+ {'X-Auth-Token': token})
+ return check_response(conn)
+
+ def post_account(url, token, parsed, conn, headers):
+ new_headers = dict({'X-Auth-Token': token}, **headers)
+ conn.request('POST', parsed.path, '', new_headers)
+ return check_response(conn)
+
+ def get(url, token, parsed, conn, name):
+ conn.request('GET', '%s/%s/%s' % (
+ parsed.path, self.container, name), '',
+ {'X-Auth-Token': token})
+ return check_response(conn)
+
+ def put(url, token, parsed, conn, name):
+ conn.request('PUT', '%s/%s/%s' % (
+ parsed.path, self.container, name), 'test',
+ {'X-Auth-Token': token})
+ return check_response(conn)
+
+ def delete(url, token, parsed, conn, name):
+ conn.request('DELETE', '%s/%s/%s' % (
+ parsed.path, self.container, name), '',
+ {'X-Auth-Token': token})
+ return check_response(conn)
+
+ # cannot list objects
+ resp = retry(get_listing, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 403)
+
+ # cannot get object
+ resp = retry(get, self.obj, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 403)
+
+ # grant read-write access
+ acl_user = swift_test_user[2]
+ acl = {'read-write': [acl_user]}
+ headers = {'x-account-access-control': json.dumps(acl)}
+ resp = retry(post_account, headers=headers, use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+
+ # can list objects
+ resp = retry(get_listing, use_account=3)
+ listing = resp.read()
+ self.assertEquals(resp.status, 200)
+ self.assert_(self.obj in listing)
+
+ # can get object
+ resp = retry(get, self.obj, use_account=3)
+ body = resp.read()
+ self.assertEquals(resp.status, 200)
+ self.assertEquals(body, 'test')
+
+ # can put an object
+ obj_name = str(uuid4())
+ resp = retry(put, obj_name, use_account=3)
+ body = resp.read()
+ self.assertEquals(resp.status, 201)
+
+ # can delete an object
+ resp = retry(delete, self.obj, use_account=3)
+ body = resp.read()
self.assertEquals(resp.status, 204)
+ # sanity with account1
+ resp = retry(get_listing, use_account=3)
+ listing = resp.read()
+ self.assertEquals(resp.status, 200)
+ self.assert_(obj_name in listing)
+ self.assert_(self.obj not in listing)
+
+ @requires_acls
+ def test_admin(self):
+ if skip3:
+ raise SkipTest
+
+ def get_listing(url, token, parsed, conn):
+ conn.request('GET', '%s/%s' % (parsed.path, self.container), '',
+ {'X-Auth-Token': token})
+ return check_response(conn)
+
+ def post_account(url, token, parsed, conn, headers):
+ new_headers = dict({'X-Auth-Token': token}, **headers)
+ conn.request('POST', parsed.path, '', new_headers)
+ return check_response(conn)
+
+ def get(url, token, parsed, conn, name):
+ conn.request('GET', '%s/%s/%s' % (
+ parsed.path, self.container, name), '',
+ {'X-Auth-Token': token})
+ return check_response(conn)
+
+ def put(url, token, parsed, conn, name):
+ conn.request('PUT', '%s/%s/%s' % (
+ parsed.path, self.container, name), 'test',
+ {'X-Auth-Token': token})
+ return check_response(conn)
+
+ def delete(url, token, parsed, conn, name):
+ conn.request('DELETE', '%s/%s/%s' % (
+ parsed.path, self.container, name), '',
+ {'X-Auth-Token': token})
+ return check_response(conn)
+
+ # cannot list objects
+ resp = retry(get_listing, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 403)
+
+ # cannot get object
+ resp = retry(get, self.obj, use_account=3)
+ resp.read()
+ self.assertEquals(resp.status, 403)
+
+ # grant admin access
+ acl_user = swift_test_user[2]
+ acl = {'admin': [acl_user]}
+ headers = {'x-account-access-control': json.dumps(acl)}
+ resp = retry(post_account, headers=headers, use_account=1)
+ resp.read()
+ self.assertEqual(resp.status, 204)
+
+ # can list objects
+ resp = retry(get_listing, use_account=3)
+ listing = resp.read()
+ self.assertEquals(resp.status, 200)
+ self.assert_(self.obj in listing)
+
+ # can get object
+ resp = retry(get, self.obj, use_account=3)
+ body = resp.read()
+ self.assertEquals(resp.status, 200)
+ self.assertEquals(body, 'test')
+
+ # can put an object
+ obj_name = str(uuid4())
+ resp = retry(put, obj_name, use_account=3)
+ body = resp.read()
+ self.assertEquals(resp.status, 201)
+
+ # can delete an object
+ resp = retry(delete, self.obj, use_account=3)
+ body = resp.read()
+ self.assertEquals(resp.status, 204)
+
+ # sanity with account1
+ resp = retry(get_listing, use_account=3)
+ listing = resp.read()
+ self.assertEquals(resp.status, 200)
+ self.assert_(obj_name in listing)
+ self.assert_(self.obj not in listing)
+
def test_manifest(self):
if skip:
raise SkipTest
@@ -306,7 +577,7 @@ class TestObject(unittest.TestCase):
for objnum in xrange(len(segments1)):
resp = retry(put, objnum)
resp.read()
- self.assertEquals(resp.status, 201)
+ self.assertEqual(resp.status, 201)
# Upload the manifest
def put(url, token, parsed, conn):
@@ -318,7 +589,7 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(put)
resp.read()
- self.assertEquals(resp.status, 201)
+ self.assertEqual(resp.status, 201)
# Get the manifest (should get all the segments as the body)
def get(url, token, parsed, conn):
@@ -326,9 +597,9 @@ class TestObject(unittest.TestCase):
parsed.path, self.container), '', {'X-Auth-Token': token})
return check_response(conn)
resp = retry(get)
- self.assertEquals(resp.read(), ''.join(segments1))
- self.assertEquals(resp.status, 200)
- self.assertEquals(resp.getheader('content-type'), 'text/jibberish')
+ self.assertEqual(resp.read(), ''.join(segments1))
+ self.assertEqual(resp.status, 200)
+ self.assertEqual(resp.getheader('content-type'), 'text/jibberish')
# Get with a range at the start of the second segment
def get(url, token, parsed, conn):
@@ -337,8 +608,8 @@ class TestObject(unittest.TestCase):
'X-Auth-Token': token, 'Range': 'bytes=3-'})
return check_response(conn)
resp = retry(get)
- self.assertEquals(resp.read(), ''.join(segments1[1:]))
- self.assertEquals(resp.status, 206)
+ self.assertEqual(resp.read(), ''.join(segments1[1:]))
+ self.assertEqual(resp.status, 206)
# Get with a range in the middle of the second segment
def get(url, token, parsed, conn):
@@ -347,8 +618,8 @@ class TestObject(unittest.TestCase):
'X-Auth-Token': token, 'Range': 'bytes=5-'})
return check_response(conn)
resp = retry(get)
- self.assertEquals(resp.read(), ''.join(segments1)[5:])
- self.assertEquals(resp.status, 206)
+ self.assertEqual(resp.read(), ''.join(segments1)[5:])
+ self.assertEqual(resp.status, 206)
# Get with a full start and stop range
def get(url, token, parsed, conn):
@@ -357,8 +628,8 @@ class TestObject(unittest.TestCase):
'X-Auth-Token': token, 'Range': 'bytes=5-10'})
return check_response(conn)
resp = retry(get)
- self.assertEquals(resp.read(), ''.join(segments1)[5:11])
- self.assertEquals(resp.status, 206)
+ self.assertEqual(resp.read(), ''.join(segments1)[5:11])
+ self.assertEqual(resp.status, 206)
# Upload the second set of segments
def put(url, token, parsed, conn, objnum):
@@ -369,7 +640,7 @@ class TestObject(unittest.TestCase):
for objnum in xrange(len(segments2)):
resp = retry(put, objnum)
resp.read()
- self.assertEquals(resp.status, 201)
+ self.assertEqual(resp.status, 201)
# Get the manifest (should still be the first segments of course)
def get(url, token, parsed, conn):
@@ -377,8 +648,8 @@ class TestObject(unittest.TestCase):
parsed.path, self.container), '', {'X-Auth-Token': token})
return check_response(conn)
resp = retry(get)
- self.assertEquals(resp.read(), ''.join(segments1))
- self.assertEquals(resp.status, 200)
+ self.assertEqual(resp.read(), ''.join(segments1))
+ self.assertEqual(resp.status, 200)
# Update the manifest
def put(url, token, parsed, conn):
@@ -390,7 +661,7 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(put)
resp.read()
- self.assertEquals(resp.status, 201)
+ self.assertEqual(resp.status, 201)
# Get the manifest (should be the second set of segments now)
def get(url, token, parsed, conn):
@@ -398,8 +669,8 @@ class TestObject(unittest.TestCase):
parsed.path, self.container), '', {'X-Auth-Token': token})
return check_response(conn)
resp = retry(get)
- self.assertEquals(resp.read(), ''.join(segments2))
- self.assertEquals(resp.status, 200)
+ self.assertEqual(resp.read(), ''.join(segments2))
+ self.assertEqual(resp.status, 200)
if not skip3:
@@ -410,7 +681,7 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(get, use_account=3)
resp.read()
- self.assertEquals(resp.status, 403)
+ self.assertEqual(resp.status, 403)
# Grant access to the third account
def post(url, token, parsed, conn):
@@ -420,7 +691,7 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(post)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
# The third account should be able to get the manifest now
def get(url, token, parsed, conn):
@@ -428,8 +699,8 @@ class TestObject(unittest.TestCase):
parsed.path, self.container), '', {'X-Auth-Token': token})
return check_response(conn)
resp = retry(get, use_account=3)
- self.assertEquals(resp.read(), ''.join(segments2))
- self.assertEquals(resp.status, 200)
+ self.assertEqual(resp.read(), ''.join(segments2))
+ self.assertEqual(resp.status, 200)
# Create another container for the third set of segments
acontainer = uuid4().hex
@@ -440,7 +711,7 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(put)
resp.read()
- self.assertEquals(resp.status, 201)
+ self.assertEqual(resp.status, 201)
# Upload the third set of segments in the other container
def put(url, token, parsed, conn, objnum):
@@ -451,7 +722,7 @@ class TestObject(unittest.TestCase):
for objnum in xrange(len(segments3)):
resp = retry(put, objnum)
resp.read()
- self.assertEquals(resp.status, 201)
+ self.assertEqual(resp.status, 201)
# Update the manifest
def put(url, token, parsed, conn):
@@ -463,7 +734,7 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(put)
resp.read()
- self.assertEquals(resp.status, 201)
+ self.assertEqual(resp.status, 201)
# Get the manifest to ensure it's the third set of segments
def get(url, token, parsed, conn):
@@ -471,8 +742,8 @@ class TestObject(unittest.TestCase):
parsed.path, self.container), '', {'X-Auth-Token': token})
return check_response(conn)
resp = retry(get)
- self.assertEquals(resp.read(), ''.join(segments3))
- self.assertEquals(resp.status, 200)
+ self.assertEqual(resp.read(), ''.join(segments3))
+ self.assertEqual(resp.status, 200)
if not skip3:
@@ -486,7 +757,7 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(get, use_account=3)
resp.read()
- self.assertEquals(resp.status, 403)
+ self.assertEqual(resp.status, 403)
# Grant access to the third account
def post(url, token, parsed, conn):
@@ -496,7 +767,7 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(post)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
# The third account should be able to get the manifest now
def get(url, token, parsed, conn):
@@ -504,8 +775,8 @@ class TestObject(unittest.TestCase):
parsed.path, self.container), '', {'X-Auth-Token': token})
return check_response(conn)
resp = retry(get, use_account=3)
- self.assertEquals(resp.read(), ''.join(segments3))
- self.assertEquals(resp.status, 200)
+ self.assertEqual(resp.read(), ''.join(segments3))
+ self.assertEqual(resp.status, 200)
# Delete the manifest
def delete(url, token, parsed, conn, objnum):
@@ -515,7 +786,7 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(delete, objnum)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
# Delete the third set of segments
def delete(url, token, parsed, conn, objnum):
@@ -526,7 +797,7 @@ class TestObject(unittest.TestCase):
for objnum in xrange(len(segments3)):
resp = retry(delete, objnum)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
# Delete the second set of segments
def delete(url, token, parsed, conn, objnum):
@@ -537,7 +808,7 @@ class TestObject(unittest.TestCase):
for objnum in xrange(len(segments2)):
resp = retry(delete, objnum)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
# Delete the first set of segments
def delete(url, token, parsed, conn, objnum):
@@ -548,7 +819,7 @@ class TestObject(unittest.TestCase):
for objnum in xrange(len(segments1)):
resp = retry(delete, objnum)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
# Delete the extra container
def delete(url, token, parsed, conn):
@@ -557,7 +828,7 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(delete)
resp.read()
- self.assertEquals(resp.status, 204)
+ self.assertEqual(resp.status, 204)
def test_delete_content_type(self):
if skip:
@@ -569,7 +840,7 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(put)
resp.read()
- self.assertEquals(resp.status, 201)
+ self.assertEqual(resp.status, 201)
def delete(url, token, parsed, conn):
conn.request('DELETE', '%s/%s/hi' % (parsed.path, self.container),
@@ -577,9 +848,9 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(delete)
resp.read()
- self.assertEquals(resp.status, 204)
- self.assertEquals(resp.getheader('Content-Type'),
- 'text/html; charset=UTF-8')
+ self.assertEqual(resp.status, 204)
+ self.assertEqual(resp.getheader('Content-Type'),
+ 'text/html; charset=UTF-8')
def test_delete_if_delete_at_bad(self):
if skip:
@@ -592,7 +863,7 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(put)
resp.read()
- self.assertEquals(resp.status, 201)
+ self.assertEqual(resp.status, 201)
def delete(url, token, parsed, conn):
conn.request('DELETE', '%s/%s/hi' % (parsed.path, self.container),
@@ -601,7 +872,7 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(delete)
resp.read()
- self.assertEquals(resp.status, 400)
+ self.assertEqual(resp.status, 400)
def test_null_name(self):
if skip:
@@ -614,10 +885,121 @@ class TestObject(unittest.TestCase):
return check_response(conn)
resp = retry(put)
if (web_front_end == 'apache2'):
- self.assertEquals(resp.status, 404)
+ self.assertEqual(resp.status, 404)
else:
- self.assertEquals(resp.read(), 'Invalid UTF8 or contains NULL')
- self.assertEquals(resp.status, 412)
+ self.assertEqual(resp.read(), 'Invalid UTF8 or contains NULL')
+ self.assertEqual(resp.status, 412)
+
+ def test_cors(self):
+ if skip:
+ raise SkipTest
+
+ def is_strict_mode(url, token, parsed, conn):
+ conn.request('GET', '/info')
+ resp = conn.getresponse()
+ if resp.status // 100 == 2:
+ info = json.loads(resp.read())
+ return info.get('swift', {}).get('strict_cors_mode', False)
+ return False
+
+ def put_cors_cont(url, token, parsed, conn, orig):
+ conn.request(
+ 'PUT', '%s/%s' % (parsed.path, self.container),
+ '', {'X-Auth-Token': token,
+ 'X-Container-Meta-Access-Control-Allow-Origin': orig})
+ return check_response(conn)
+
+ def put_obj(url, token, parsed, conn, obj):
+ conn.request(
+ 'PUT', '%s/%s/%s' % (parsed.path, self.container, obj),
+ 'test', {'X-Auth-Token': token})
+ return check_response(conn)
+
+ def check_cors(url, token, parsed, conn,
+ method, obj, headers):
+ if method != 'OPTIONS':
+ headers['X-Auth-Token'] = token
+ conn.request(
+ method, '%s/%s/%s' % (parsed.path, self.container, obj),
+ '', headers)
+ return conn.getresponse()
+
+ strict_cors = retry(is_strict_mode)
+
+ resp = retry(put_cors_cont, '*')
+ resp.read()
+ self.assertEquals(resp.status // 100, 2)
+
+ resp = retry(put_obj, 'cat')
+ resp.read()
+ self.assertEquals(resp.status // 100, 2)
+
+ resp = retry(check_cors,
+ 'OPTIONS', 'cat', {'Origin': 'http://m.com'})
+ self.assertEquals(resp.status, 401)
+
+ resp = retry(check_cors,
+ 'OPTIONS', 'cat',
+ {'Origin': 'http://m.com',
+ 'Access-Control-Request-Method': 'GET'})
+
+ self.assertEquals(resp.status, 200)
+ resp.read()
+ headers = dict((k.lower(), v) for k, v in resp.getheaders())
+ self.assertEquals(headers.get('access-control-allow-origin'),
+ '*')
+
+ resp = retry(check_cors,
+ 'GET', 'cat', {'Origin': 'http://m.com'})
+ self.assertEquals(resp.status, 200)
+ headers = dict((k.lower(), v) for k, v in resp.getheaders())
+ self.assertEquals(headers.get('access-control-allow-origin'),
+ '*')
+
+ resp = retry(check_cors,
+ 'GET', 'cat', {'Origin': 'http://m.com',
+ 'X-Web-Mode': 'True'})
+ self.assertEquals(resp.status, 200)
+ headers = dict((k.lower(), v) for k, v in resp.getheaders())
+ self.assertEquals(headers.get('access-control-allow-origin'),
+ '*')
+
+ ####################
+
+ resp = retry(put_cors_cont, 'http://secret.com')
+ resp.read()
+ self.assertEquals(resp.status // 100, 2)
+
+ resp = retry(check_cors,
+ 'OPTIONS', 'cat',
+ {'Origin': 'http://m.com',
+ 'Access-Control-Request-Method': 'GET'})
+ resp.read()
+ self.assertEquals(resp.status, 401)
+
+ if strict_cors:
+ resp = retry(check_cors,
+ 'GET', 'cat', {'Origin': 'http://m.com'})
+ resp.read()
+ self.assertEquals(resp.status, 200)
+ headers = dict((k.lower(), v) for k, v in resp.getheaders())
+ self.assertTrue('access-control-allow-origin' not in headers)
+
+ resp = retry(check_cors,
+ 'GET', 'cat', {'Origin': 'http://secret.com'})
+ resp.read()
+ self.assertEquals(resp.status, 200)
+ headers = dict((k.lower(), v) for k, v in resp.getheaders())
+ self.assertEquals(headers.get('access-control-allow-origin'),
+ 'http://secret.com')
+ else:
+ resp = retry(check_cors,
+ 'GET', 'cat', {'Origin': 'http://m.com'})
+ resp.read()
+ self.assertEquals(resp.status, 200)
+ headers = dict((k.lower(), v) for k, v in resp.getheaders())
+ self.assertEquals(headers.get('access-control-allow-origin'),
+ 'http://m.com')
if __name__ == '__main__':
diff --git a/test/functional/tests.py b/test/functional/tests.py
index 0d9a9ef..ad87d7e 100644
--- a/test/functional/tests.py
+++ b/test/functional/tests.py
@@ -19,14 +19,16 @@
from datetime import datetime
import os
import hashlib
+import hmac
import json
import locale
import random
import StringIO
import time
import threading
-import uuid
import unittest
+import urllib
+import uuid
from nose import SkipTest
from ConfigParser import ConfigParser
@@ -36,7 +38,7 @@ from test.functional.swift_test_client import Account, Connection, File, \
from swift.common.constraints import MAX_FILE_SIZE, MAX_META_NAME_LENGTH, \
MAX_META_VALUE_LENGTH, MAX_META_COUNT, MAX_META_OVERALL_SIZE, \
MAX_OBJECT_NAME_LENGTH, CONTAINER_LISTING_LIMIT, ACCOUNT_LISTING_LIMIT, \
- MAX_ACCOUNT_NAME_LENGTH, MAX_CONTAINER_NAME_LENGTH
+ MAX_ACCOUNT_NAME_LENGTH, MAX_CONTAINER_NAME_LENGTH, MAX_HEADER_SIZE
from gluster.swift.common.constraints import \
set_object_name_component_length, get_object_name_component_length
@@ -50,7 +52,8 @@ default_constraints = dict((
('container_listing_limit', CONTAINER_LISTING_LIMIT),
('account_listing_limit', ACCOUNT_LISTING_LIMIT),
('max_account_name_length', MAX_ACCOUNT_NAME_LENGTH),
- ('max_container_name_length', MAX_CONTAINER_NAME_LENGTH)))
+ ('max_container_name_length', MAX_CONTAINER_NAME_LENGTH),
+ ('max_header_size', MAX_HEADER_SIZE)))
constraints_conf = ConfigParser()
conf_exists = constraints_conf.read('/etc/swift/swift.conf')
# Constraints are set first from the test config, then from
@@ -285,7 +288,7 @@ class TestAccount(Base):
if try_count < 5:
time.sleep(1)
- self.assertEquals(info['container_count'], len(self.env.containers))
+ self.assertEqual(info['container_count'], len(self.env.containers))
self.assert_status(204)
def testContainerSerializedInfo(self):
@@ -309,11 +312,11 @@ class TestAccount(Base):
headers = dict(self.env.conn.response.getheaders())
if format_type == 'json':
- self.assertEquals(headers['content-type'],
- 'application/json; charset=utf-8')
+ self.assertEqual(headers['content-type'],
+ 'application/json; charset=utf-8')
elif format_type == 'xml':
- self.assertEquals(headers['content-type'],
- 'application/xml; charset=utf-8')
+ self.assertEqual(headers['content-type'],
+ 'application/xml; charset=utf-8')
def testListingLimit(self):
limit = load_constraint('account_listing_limit')
@@ -337,7 +340,7 @@ class TestAccount(Base):
if isinstance(b[0], dict):
b = [x['name'] for x in b]
- self.assertEquals(a, b)
+ self.assertEqual(a, b)
def testInvalidAuthToken(self):
hdrs = {'X-Auth-Token': 'bogus_auth_token'}
@@ -347,12 +350,12 @@ class TestAccount(Base):
def testLastContainerMarker(self):
for format_type in [None, 'json', 'xml']:
containers = self.env.account.containers({'format': format_type})
- self.assertEquals(len(containers), len(self.env.containers))
+ self.assertEqual(len(containers), len(self.env.containers))
self.assert_status(200)
containers = self.env.account.containers(
parms={'format': format_type, 'marker': containers[-1]})
- self.assertEquals(len(containers), 0)
+ self.assertEqual(len(containers), 0)
if format_type is None:
self.assert_status(204)
else:
@@ -380,8 +383,8 @@ class TestAccount(Base):
parms={'format': format_type})
if isinstance(containers[0], dict):
containers = [x['name'] for x in containers]
- self.assertEquals(sorted(containers, cmp=locale.strcoll),
- containers)
+ self.assertEqual(sorted(containers, cmp=locale.strcoll),
+ containers)
class TestAccountUTF8(Base2, TestAccount):
@@ -518,13 +521,13 @@ class TestContainer(Base):
for format_type in [None, 'json', 'xml']:
for prefix in prefixs:
files = cont.files(parms={'prefix': prefix})
- self.assertEquals(files, sorted(prefix_files[prefix]))
+ self.assertEqual(files, sorted(prefix_files[prefix]))
for format_type in [None, 'json', 'xml']:
for prefix in prefixs:
files = cont.files(parms={'limit': limit_count,
'prefix': prefix})
- self.assertEquals(len(files), limit_count)
+ self.assertEqual(len(files), limit_count)
for file_item in files:
self.assert_(file_item.startswith(prefix))
@@ -548,7 +551,7 @@ class TestContainer(Base):
container = self.env.account.container(valid_utf8)
self.assert_(container.create(cfg={'no_path_quote': True}))
self.assert_(container.name in self.env.account.containers())
- self.assertEquals(container.files(), [])
+ self.assertEqual(container.files(), [])
self.assert_(container.delete())
container = self.env.account.container(invalid_utf8)
@@ -614,12 +617,12 @@ class TestContainer(Base):
def testLastFileMarker(self):
for format_type in [None, 'json', 'xml']:
files = self.env.container.files({'format': format_type})
- self.assertEquals(len(files), len(self.env.files))
+ self.assertEqual(len(files), len(self.env.files))
self.assert_status(200)
files = self.env.container.files(
parms={'format': format_type, 'marker': files[-1]})
- self.assertEquals(len(files), 0)
+ self.assertEqual(len(files), 0)
if format_type is None:
self.assert_status(204)
@@ -665,14 +668,14 @@ class TestContainer(Base):
files = self.env.container.files(parms={'format': format_type})
if isinstance(files[0], dict):
files = [x['name'] for x in files]
- self.assertEquals(sorted(files, cmp=locale.strcoll), files)
+ self.assertEqual(sorted(files, cmp=locale.strcoll), files)
def testContainerInfo(self):
info = self.env.container.info()
self.assert_status(204)
- self.assertEquals(info['object_count'], self.env.file_count)
- self.assertEquals(info['bytes_used'],
- self.env.file_count * self.env.file_size)
+ self.assertEqual(info['object_count'], self.env.file_count)
+ self.assertEqual(info['bytes_used'],
+ self.env.file_count * self.env.file_size)
def testContainerInfoOnContainerThatDoesNotExist(self):
container = self.env.account.container(Utils.create_name())
@@ -683,7 +686,7 @@ class TestContainer(Base):
for format_type in [None, 'json', 'xml']:
files = self.env.container.files(parms={'format': format_type,
'limit': 2})
- self.assertEquals(len(files), 2)
+ self.assertEqual(len(files), 2)
def testTooLongName(self):
cont = self.env.account.container('x' * 257)
@@ -838,7 +841,7 @@ class TestContainerPaths(Base):
if isinstance(files[0], dict):
files = [str(x['name']) for x in files]
- self.assertEquals(files, self.env.stored_files)
+ self.assertEqual(files, self.env.stored_files)
for format_type in ('json', 'xml'):
for file_item in self.env.container.files(parms={'format':
@@ -846,13 +849,13 @@ class TestContainerPaths(Base):
self.assert_(int(file_item['bytes']) >= 0)
self.assert_('last_modified' in file_item)
if file_item['name'].endswith('/'):
- self.assertEquals(file_item['content_type'],
- 'application/directory')
+ self.assertEqual(file_item['content_type'],
+ 'application/directory')
def testStructure(self):
def assert_listing(path, file_list):
files = self.env.container.files(parms={'path': path})
- self.assertEquals(sorted(file_list, cmp=locale.strcoll), files)
+ self.assertEqual(sorted(file_list, cmp=locale.strcoll), files)
if not normalized_urls:
assert_listing('/', ['/dir1/', '/dir2/', '/file1', '/file A'])
assert_listing('/dir1',
@@ -1176,7 +1179,7 @@ class TestFile(Base):
for i in container.files(parms={'format': 'json'}):
file_types_read[i['name'].split('.')[1]] = i['content_type']
- self.assertEquals(file_types, file_types_read)
+ self.assertEqual(file_types, file_types_read)
def testRangedGets(self):
file_length = 10000
@@ -1201,7 +1204,7 @@ class TestFile(Base):
self.assertRaises(ResponseError, file_item.read, hdrs=hdrs)
self.assert_status(416)
else:
- self.assertEquals(file_item.read(hdrs=hdrs), data[-i:])
+ self.assertEqual(file_item.read(hdrs=hdrs), data[-i:])
range_string = 'bytes=%d-' % (i)
hdrs = {'Range': range_string}
@@ -1350,9 +1353,9 @@ class TestFile(Base):
info = file_item.info()
self.assert_status(200)
- self.assertEquals(info['content_length'], self.env.file_size)
- self.assertEquals(info['etag'], md5)
- self.assertEquals(info['content_type'], content_type)
+ self.assertEqual(info['content_length'], self.env.file_size)
+ self.assertEqual(info['etag'], md5)
+ self.assertEqual(info['content_type'], content_type)
self.assert_('last_modified' in info)
def testDeleteOfFileThatDoesNotExist(self):
@@ -1395,7 +1398,7 @@ class TestFile(Base):
file_item = self.env.container.file(file_item.name)
self.assert_(file_item.initialize())
self.assert_status(200)
- self.assertEquals(file_item.metadata, metadata)
+ self.assertEqual(file_item.metadata, metadata)
def testGetContentType(self):
file_name = Utils.create_name()
@@ -1408,7 +1411,7 @@ class TestFile(Base):
file_item = self.env.container.file(file_name)
file_item.read()
- self.assertEquals(content_type, file_item.content_type)
+ self.assertEqual(content_type, file_item.content_type)
def testGetOnFileThatDoesNotExist(self):
# in container that exists
@@ -1449,7 +1452,7 @@ class TestFile(Base):
file_item = self.env.container.file(file_item.name)
self.assert_(file_item.initialize())
self.assert_status(200)
- self.assertEquals(file_item.metadata, metadata)
+ self.assertEqual(file_item.metadata, metadata)
def testSerialization(self):
container = self.env.account.container(Utils.create_name())
@@ -1478,9 +1481,9 @@ class TestFile(Base):
if f['name'] != file_item['name']:
continue
- self.assertEquals(file_item['content_type'],
- f['content_type'])
- self.assertEquals(int(file_item['bytes']), f['bytes'])
+ self.assertEqual(file_item['content_type'],
+ f['content_type'])
+ self.assertEqual(int(file_item['bytes']), f['bytes'])
d = datetime.strptime(
file_item['last_modified'].split('.')[0],
@@ -1488,7 +1491,7 @@ class TestFile(Base):
lm = time.mktime(d.timetuple())
if 'last_modified' in f:
- self.assertEquals(f['last_modified'], lm)
+ self.assertEqual(f['last_modified'], lm)
else:
f['last_modified'] = lm
@@ -1500,11 +1503,11 @@ class TestFile(Base):
headers = dict(self.env.conn.response.getheaders())
if format_type == 'json':
- self.assertEquals(headers['content-type'],
- 'application/json; charset=utf-8')
+ self.assertEqual(headers['content-type'],
+ 'application/json; charset=utf-8')
elif format_type == 'xml':
- self.assertEquals(headers['content-type'],
- 'application/xml; charset=utf-8')
+ self.assertEqual(headers['content-type'],
+ 'application/xml; charset=utf-8')
lm_diff = max([f['last_modified'] for f in files]) -\
min([f['last_modified'] for f in files])
@@ -1547,7 +1550,7 @@ class TestFile(Base):
self.assert_('etag' in headers.keys())
header_etag = headers['etag'].strip('"')
- self.assertEquals(etag, header_etag)
+ self.assertEqual(etag, header_etag)
def testChunkedPut(self):
if (web_front_end == 'apache2'):
@@ -1565,7 +1568,7 @@ class TestFile(Base):
self.assert_(data == file_item.read())
info = file_item.info()
- self.assertEquals(etag, info['etag'])
+ self.assertEqual(etag, info['etag'])
class TestFileUTF8(Base2, TestFile):
@@ -1677,12 +1680,30 @@ class TestDlo(Base):
file_contents,
"aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffffffffff")
+ def test_copy_manifest(self):
+ # Copying the manifest should result in another manifest
+ try:
+ man1_item = self.env.container.file('man1')
+ man1_item.copy(self.env.container.name, "copied-man1",
+ parms={'multipart-manifest': 'get'})
+
+ copied = self.env.container.file("copied-man1")
+ copied_contents = copied.read(parms={'multipart-manifest': 'get'})
+ self.assertEqual(copied_contents, "man1-contents")
+
+ copied_contents = copied.read()
+ self.assertEqual(
+ copied_contents,
+ "aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeee")
+ finally:
+ # try not to leave this around for other tests to stumble over
+ self.env.container.file("copied-man1").delete()
class TestDloUTF8(Base2, TestDlo):
set_up = False
-class TestFileComparisonEnv:
+class TestFileComparisonEnv(object):
@classmethod
def setUp(cls):
cls.conn = Connection(config)
@@ -1806,19 +1827,8 @@ class TestSloEnv(object):
cls.conn.authenticate()
if cls.slo_enabled is None:
- status = cls.conn.make_request('GET', '/info',
- cfg={'verbatim_path': True})
- if not (200 <= status <= 299):
- # Can't tell if SLO is enabled or not since we're running
- # against an old cluster, so let's skip the tests instead of
- # possibly having spurious failures.
- cls.slo_enabled = False
- else:
- # Don't bother looking for ValueError here. If something is
- # responding to a GET /info request with invalid JSON, then
- # the cluster is broken and a test failure will let us know.
- cluster_info = json.loads(cls.conn.response.read())
- cls.slo_enabled = 'slo' in cluster_info
+ cluster_info = cls.conn.cluster_info()
+ cls.slo_enabled = 'slo' in cluster_info
if not cls.slo_enabled:
return
@@ -2034,5 +2044,347 @@ class TestSloUTF8(Base2, TestSlo):
set_up = False
+class TestObjectVersioningEnv(object):
+ versioning_enabled = None # tri-state: None initially, then True/False
+
+ @classmethod
+ def setUp(cls):
+ cls.conn = Connection(config)
+ cls.conn.authenticate()
+
+ cls.account = Account(cls.conn, config.get('account',
+ config['username']))
+
+ # avoid getting a prefix that stops halfway through an encoded
+ # character
+ prefix = Utils.create_name().decode("utf-8")[:10].encode("utf-8")
+
+ cls.versions_container = cls.account.container(prefix + "-versions")
+ if not cls.versions_container.create():
+ raise ResponseError(cls.conn.response)
+
+ cls.container = cls.account.container(prefix + "-objs")
+ if not cls.container.create(
+ hdrs={'X-Versions-Location': cls.versions_container.name}):
+ raise ResponseError(cls.conn.response)
+
+ container_info = cls.container.info()
+ # if versioning is off, then X-Versions-Location won't persist
+ cls.versioning_enabled = 'versions' in container_info
+
+
+class TestObjectVersioning(Base):
+ env = TestObjectVersioningEnv
+ set_up = False
+
+ def setUp(self):
+ super(TestObjectVersioning, self).setUp()
+ if self.env.versioning_enabled is False:
+ raise SkipTest("Object versioning not enabled")
+ elif self.env.versioning_enabled is not True:
+ # just some sanity checking
+ raise Exception(
+ "Expected versioning_enabled to be True/False, got %r" %
+ (self.env.versioning_enabled,))
+
+ def test_overwriting(self):
+ container = self.env.container
+ versions_container = self.env.versions_container
+ obj_name = Utils.create_name()
+
+ versioned_obj = container.file(obj_name)
+ versioned_obj.write("aaaaa")
+
+ self.assertEqual(0, versions_container.info()['object_count'])
+
+ versioned_obj.write("bbbbb")
+
+ # the old version got saved off
+ self.assertEqual(1, versions_container.info()['object_count'])
+ versioned_obj_name = versions_container.files()[0]
+ self.assertEqual(
+ "aaaaa", versions_container.file(versioned_obj_name).read())
+
+ # if we overwrite it again, there are two versions
+ versioned_obj.write("ccccc")
+ self.assertEqual(2, versions_container.info()['object_count'])
+
+ # as we delete things, the old contents return
+ self.assertEqual("ccccc", versioned_obj.read())
+ versioned_obj.delete()
+ self.assertEqual("bbbbb", versioned_obj.read())
+ versioned_obj.delete()
+ self.assertEqual("aaaaa", versioned_obj.read())
+ versioned_obj.delete()
+ self.assertRaises(ResponseError, versioned_obj.read)
+
+
+class TestObjectVersioningUTF8(Base2, TestObjectVersioning):
+ set_up = False
+
+
+class TestTempurlEnv(object):
+ tempurl_enabled = None # tri-state: None initially, then True/False
+
+ @classmethod
+ def setUp(cls):
+ cls.conn = Connection(config)
+ cls.conn.authenticate()
+
+ if cls.tempurl_enabled is None:
+ cluster_info = cls.conn.cluster_info()
+ cls.tempurl_enabled = 'tempurl' in cluster_info
+ if not cls.tempurl_enabled:
+ return
+ cls.tempurl_methods = cluster_info['tempurl']['methods']
+
+ cls.tempurl_key = Utils.create_name()
+ cls.tempurl_key2 = Utils.create_name()
+
+ cls.account = Account(
+ cls.conn, config.get('account', config['username']))
+ cls.account.delete_containers()
+ cls.account.update_metadata({
+ 'temp-url-key': cls.tempurl_key,
+ 'temp-url-key-2': cls.tempurl_key2
+ })
+
+ cls.container = cls.account.container(Utils.create_name())
+ if not cls.container.create():
+ raise ResponseError(cls.conn.response)
+
+ cls.obj = cls.container.file(Utils.create_name())
+ cls.obj.write("obj contents")
+ cls.other_obj = cls.container.file(Utils.create_name())
+ cls.other_obj.write("other obj contents")
+
+
+class TestTempurl(Base):
+ env = TestTempurlEnv
+ set_up = False
+
+ def setUp(self):
+ super(TestTempurl, self).setUp()
+ if self.env.tempurl_enabled is False:
+ raise SkipTest("TempURL not enabled")
+ elif self.env.tempurl_enabled is not True:
+ # just some sanity checking
+ raise Exception(
+ "Expected tempurl_enabled to be True/False, got %r" %
+ (self.env.tempurl_enabled,))
+
+ expires = int(time.time()) + 86400
+ sig = self.tempurl_sig(
+ 'GET', expires, self.env.conn.make_path(self.env.obj.path),
+ self.env.tempurl_key)
+ self.obj_tempurl_parms = {'temp_url_sig': sig,
+ 'temp_url_expires': str(expires)}
+
+ def tempurl_sig(self, method, expires, path, key):
+ return hmac.new(
+ key,
+ '%s\n%s\n%s' % (method, expires, urllib.unquote(path)),
+ hashlib.sha1).hexdigest()
+
+ def test_GET(self):
+ contents = self.env.obj.read(
+ parms=self.obj_tempurl_parms,
+ cfg={'no_auth_token': True})
+ self.assertEqual(contents, "obj contents")
+
+ # GET tempurls also allow HEAD requests
+ self.assert_(self.env.obj.info(parms=self.obj_tempurl_parms,
+ cfg={'no_auth_token': True}))
+
+ def test_GET_with_key_2(self):
+ expires = int(time.time()) + 86400
+ sig = self.tempurl_sig(
+ 'GET', expires, self.env.conn.make_path(self.env.obj.path),
+ self.env.tempurl_key2)
+ parms = {'temp_url_sig': sig,
+ 'temp_url_expires': str(expires)}
+
+ contents = self.env.obj.read(parms=parms, cfg={'no_auth_token': True})
+ self.assertEqual(contents, "obj contents")
+
+ def test_PUT(self):
+ new_obj = self.env.container.file(Utils.create_name())
+
+ expires = int(time.time()) + 86400
+ sig = self.tempurl_sig(
+ 'PUT', expires, self.env.conn.make_path(new_obj.path),
+ self.env.tempurl_key)
+ put_parms = {'temp_url_sig': sig,
+ 'temp_url_expires': str(expires)}
+
+ new_obj.write('new obj contents',
+ parms=put_parms, cfg={'no_auth_token': True})
+ self.assertEqual(new_obj.read(), "new obj contents")
+
+ # PUT tempurls also allow HEAD requests
+ self.assert_(new_obj.info(parms=put_parms,
+ cfg={'no_auth_token': True}))
+
+ def test_HEAD(self):
+ expires = int(time.time()) + 86400
+ sig = self.tempurl_sig(
+ 'HEAD', expires, self.env.conn.make_path(self.env.obj.path),
+ self.env.tempurl_key)
+ head_parms = {'temp_url_sig': sig,
+ 'temp_url_expires': str(expires)}
+
+ self.assert_(self.env.obj.info(parms=head_parms,
+ cfg={'no_auth_token': True}))
+ # HEAD tempurls don't allow PUT or GET requests, despite the fact that
+ # PUT and GET tempurls both allow HEAD requests
+ self.assertRaises(ResponseError, self.env.other_obj.read,
+ cfg={'no_auth_token': True},
+ parms=self.obj_tempurl_parms)
+ self.assert_status([401])
+
+ self.assertRaises(ResponseError, self.env.other_obj.write,
+ 'new contents',
+ cfg={'no_auth_token': True},
+ parms=self.obj_tempurl_parms)
+ self.assert_status([401])
+
+ def test_different_object(self):
+ contents = self.env.obj.read(
+ parms=self.obj_tempurl_parms,
+ cfg={'no_auth_token': True})
+ self.assertEqual(contents, "obj contents")
+
+ self.assertRaises(ResponseError, self.env.other_obj.read,
+ cfg={'no_auth_token': True},
+ parms=self.obj_tempurl_parms)
+ self.assert_status([401])
+
+ def test_changing_sig(self):
+ contents = self.env.obj.read(
+ parms=self.obj_tempurl_parms,
+ cfg={'no_auth_token': True})
+ self.assertEqual(contents, "obj contents")
+
+ parms = self.obj_tempurl_parms.copy()
+ if parms['temp_url_sig'][0] == 'a':
+ parms['temp_url_sig'] = 'b' + parms['temp_url_sig'][1:]
+ else:
+ parms['temp_url_sig'] = 'a' + parms['temp_url_sig'][1:]
+
+ self.assertRaises(ResponseError, self.env.obj.read,
+ cfg={'no_auth_token': True},
+ parms=parms)
+ self.assert_status([401])
+
+ def test_changing_expires(self):
+ contents = self.env.obj.read(
+ parms=self.obj_tempurl_parms,
+ cfg={'no_auth_token': True})
+ self.assertEqual(contents, "obj contents")
+
+ parms = self.obj_tempurl_parms.copy()
+ if parms['temp_url_expires'][-1] == '0':
+ parms['temp_url_expires'] = parms['temp_url_expires'][:-1] + '1'
+ else:
+ parms['temp_url_expires'] = parms['temp_url_expires'][:-1] + '0'
+
+ self.assertRaises(ResponseError, self.env.obj.read,
+ cfg={'no_auth_token': True},
+ parms=parms)
+ self.assert_status([401])
+
+
+class TestTempurlUTF8(Base2, TestTempurl):
+ set_up = False
+
+
+class TestSloTempurlEnv(object):
+ enabled = None # tri-state: None initially, then True/False
+
+ @classmethod
+ def setUp(cls):
+ cls.conn = Connection(config)
+ cls.conn.authenticate()
+
+ if cls.enabled is None:
+ cluster_info = cls.conn.cluster_info()
+ cls.enabled = 'tempurl' in cluster_info and 'slo' in cluster_info
+
+ cls.tempurl_key = Utils.create_name()
+
+ cls.account = Account(
+ cls.conn, config.get('account', config['username']))
+ cls.account.delete_containers()
+ cls.account.update_metadata({'temp-url-key': cls.tempurl_key})
+
+ cls.manifest_container = cls.account.container(Utils.create_name())
+ cls.segments_container = cls.account.container(Utils.create_name())
+ if not cls.manifest_container.create():
+ raise ResponseError(cls.conn.response)
+ if not cls.segments_container.create():
+ raise ResponseError(cls.conn.response)
+
+ seg1 = cls.segments_container.file(Utils.create_name())
+ seg1.write('1' * 1024 * 1024)
+
+ seg2 = cls.segments_container.file(Utils.create_name())
+ seg2.write('2' * 1024 * 1024)
+
+ cls.manifest_data = [{'size_bytes': 1024 * 1024,
+ 'etag': seg1.md5,
+ 'path': '/%s/%s' % (cls.segments_container.name,
+ seg1.name)},
+ {'size_bytes': 1024 * 1024,
+ 'etag': seg2.md5,
+ 'path': '/%s/%s' % (cls.segments_container.name,
+ seg2.name)}]
+
+ cls.manifest = cls.manifest_container.file(Utils.create_name())
+ cls.manifest.write(
+ json.dumps(cls.manifest_data),
+ parms={'multipart-manifest': 'put'})
+
+
+class TestSloTempurl(Base):
+ env = TestSloTempurlEnv
+ set_up = False
+
+ def setUp(self):
+ super(TestSloTempurl, self).setUp()
+ if self.env.enabled is False:
+ raise SkipTest("TempURL and SLO not both enabled")
+ elif self.env.enabled is not True:
+ # just some sanity checking
+ raise Exception(
+ "Expected enabled to be True/False, got %r" %
+ (self.env.enabled,))
+
+ def tempurl_sig(self, method, expires, path, key):
+ return hmac.new(
+ key,
+ '%s\n%s\n%s' % (method, expires, urllib.unquote(path)),
+ hashlib.sha1).hexdigest()
+
+ def test_GET(self):
+ expires = int(time.time()) + 86400
+ sig = self.tempurl_sig(
+ 'GET', expires, self.env.conn.make_path(self.env.manifest.path),
+ self.env.tempurl_key)
+ parms = {'temp_url_sig': sig, 'temp_url_expires': str(expires)}
+
+ contents = self.env.manifest.read(
+ parms=parms,
+ cfg={'no_auth_token': True})
+ self.assertEqual(len(contents), 2 * 1024 * 1024)
+
+ # GET tempurls also allow HEAD requests
+ self.assert_(self.env.manifest.info(
+ parms=parms, cfg={'no_auth_token': True}))
+
+
+class TestSloTempurlUTF8(Base2, TestSloTempurl):
+ set_up = False
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/test/functional_auth/tempauth/conf/account-server.conf b/test/functional_auth/common_conf/account-server.conf
index 4996367..549a094 100644
--- a/test/functional_auth/tempauth/conf/account-server.conf
+++ b/test/functional_auth/common_conf/account-server.conf
@@ -30,3 +30,7 @@ log_level = WARN
# normal request logging for the account server to unclutter the log
# files. Warnings and errors will still be logged.
log_requests = off
+
+# The following parameter is used by object-expirer and needs to be same
+# across all conf files!
+auto_create_account_prefix = gs
diff --git a/test/functional_auth/gswauth/conf/container-server.conf b/test/functional_auth/common_conf/container-server.conf
index 122d97e..487ccb8 100644
--- a/test/functional_auth/gswauth/conf/container-server.conf
+++ b/test/functional_auth/common_conf/container-server.conf
@@ -33,3 +33,7 @@ log_requests = off
#enable object versioning for functional test
allow_versions = on
+
+# The following parameter is used by object-expirer and needs to be same
+# across all conf files!
+auto_create_account_prefix = gs
diff --git a/test/functional_auth/gswauth/conf/fs.conf b/test/functional_auth/common_conf/fs.conf
index b06a854..b06a854 100644
--- a/test/functional_auth/gswauth/conf/fs.conf
+++ b/test/functional_auth/common_conf/fs.conf
diff --git a/test/functional_auth/common_conf/object-expirer.conf b/test/functional_auth/common_conf/object-expirer.conf
new file mode 100644
index 0000000..4449ee2
--- /dev/null
+++ b/test/functional_auth/common_conf/object-expirer.conf
@@ -0,0 +1,27 @@
+#TODO: Add documentation to explain various options
+#For now, refer: https://github.com/openstack/swift/blob/master/etc/object-expirer.conf-sample
+
+[DEFAULT]
+
+[object-expirer]
+user = root
+log_facility = LOG_LOCAL2
+log_level = DEBUG
+# The following parameters are used by object-expirer and needs to be same
+# across all conf files!
+auto_create_account_prefix = gs
+expiring_objects_account_name = expiring
+
+interval = 30
+
+[pipeline:main]
+pipeline = catch_errors cache proxy-server
+
+[app:proxy-server]
+use = egg:gluster_swift#proxy
+
+[filter:cache]
+use = egg:swift#memcache
+
+[filter:catch_errors]
+use = egg:swift#catch_errors
diff --git a/test/functional_auth/gswauth/conf/object-server.conf b/test/functional_auth/common_conf/object-server.conf
index 3cb9ead..2599c87 100644
--- a/test/functional_auth/gswauth/conf/object-server.conf
+++ b/test/functional_auth/common_conf/object-server.conf
@@ -46,3 +46,8 @@ disk_chunk_size = 65536
# Adjust this value match whatever is set for the disk_chunk_size initially.
# This will provide a reasonable starting point for tuning this value.
network_chunk_size = 65556
+
+# The following parameter is used by object-expirer and needs to be same
+# across all conf files!
+auto_create_account_prefix = gs
+expiring_objects_account_name = expiring
diff --git a/test/functional_auth/gswauth/conf/swift.conf b/test/functional_auth/common_conf/swift.conf
index f64ba5a..f64ba5a 100644
--- a/test/functional_auth/gswauth/conf/swift.conf
+++ b/test/functional_auth/common_conf/swift.conf
diff --git a/test/functional_auth/swiftkerbauth/conf/test.conf b/test/functional_auth/common_conf/test.conf
index 643f2d1..15c9aea 100644
--- a/test/functional_auth/swiftkerbauth/conf/test.conf
+++ b/test/functional_auth/common_conf/test.conf
@@ -1,16 +1,25 @@
[func_test]
-# Swiftkerbauth configuration
+# sample config
auth_host = 127.0.0.1
auth_port = 8080
+auth_ssl = no
auth_prefix = /auth/
-auth_scheme = http://
-auth_mode = passive
-auth_version = 1
-domain_name = RHELBOX.COM
+## sample config for Swift with Keystone
+#auth_version = 2
+#auth_host = localhost
+#auth_port = 5000
+#auth_ssl = no
+#auth_prefix = /v2.0/
+
+# GSWauth internal admin user configuration information
+admin_key = gswauthkey
+admin_user = .super_admin
+
+# Gluster setup information
+devices = /mnt/gluster-object
+gsmetadata_volume = gsmetadata
-#All the accounts, users & passwords to be prepared on kerberos server.
# Primary functional test account (needs admin access to the account)
-# Note: Account name to be prepared on kerberos server 'AUTH_accoun'
account = test
username = tester
password = testing
diff --git a/test/functional_auth/gswauth/conf/account-server.conf b/test/functional_auth/gswauth/conf/account-server.conf
deleted file mode 100644
index 4996367..0000000
--- a/test/functional_auth/gswauth/conf/account-server.conf
+++ /dev/null
@@ -1,32 +0,0 @@
-[DEFAULT]
-devices = /mnt/gluster-object
-#
-# Once you are confident that your startup processes will always have your
-# gluster volumes properly mounted *before* the account-server workers start,
-# you can *consider* setting this value to "false" to reduce the per-request
-# overhead it can incur.
-#
-# *** Keep false for Functional Tests ***
-mount_check = false
-bind_port = 6012
-#
-# Override swift's default behaviour for fallocate.
-disable_fallocate = true
-#
-# One or two workers should be sufficient for almost any installation of
-# Gluster.
-workers = 1
-
-[pipeline:main]
-pipeline = account-server
-
-[app:account-server]
-use = egg:gluster_swift#account
-user = root
-log_facility = LOG_LOCAL2
-log_level = WARN
-#
-# After ensuring things are running in a stable manner, you can turn off
-# normal request logging for the account server to unclutter the log
-# files. Warnings and errors will still be logged.
-log_requests = off
diff --git a/test/functional_auth/gswauth/conf/object-expirer.conf b/test/functional_auth/gswauth/conf/object-expirer.conf
deleted file mode 100644
index b75963c..0000000
--- a/test/functional_auth/gswauth/conf/object-expirer.conf
+++ /dev/null
@@ -1,17 +0,0 @@
-[DEFAULT]
-
-[object-expirer]
-# auto_create_account_prefix = .
-
-[pipeline:main]
-pipeline = catch_errors cache proxy-server
-
-[app:proxy-server]
-use = egg:swift#proxy
-
-[filter:cache]
-use = egg:swift#memcache
-memcache_servers = 127.0.0.1:11211
-
-[filter:catch_errors]
-use = egg:swift#catch_errors
diff --git a/test/functional_auth/gswauth/conf/proxy-server.conf b/test/functional_auth/gswauth/conf/proxy-server.conf
index 165cb0c..0a3c1f6 100644
--- a/test/functional_auth/gswauth/conf/proxy-server.conf
+++ b/test/functional_auth/gswauth/conf/proxy-server.conf
@@ -5,7 +5,7 @@ user = root
workers = 1
[pipeline:main]
-pipeline = catch_errors healthcheck proxy-logging cache gswauth proxy-logging proxy-server
+pipeline = catch_errors healthcheck proxy-logging cache tempurl gswauth proxy-logging proxy-server
[app:proxy-server]
use = egg:gluster_swift#proxy
@@ -48,6 +48,10 @@ object_chunk_size = 65536
# amount of memory available on the system can accommodate increased values
# for object_chunk_size.
put_queue_depth = 10
+# The following parameter is used by object-expirer and needs to be same
+# across all conf files!
+auto_create_account_prefix = gs
+expiring_objects_account_name = expiring
[filter:catch_errors]
use = egg:swift#catch_errors
@@ -58,21 +62,17 @@ use = egg:swift#proxy_logging
[filter:healthcheck]
use = egg:swift#healthcheck
-[filter:tempauth]
-use = egg:swift#tempauth
-user_admin_admin = admin .admin .reseller_admin
-user_test_tester = testing .admin
-user_test2_tester2 = testing2 .admin
-user_test_tester3 = testing3
+[filter:cache]
+use = egg:swift#memcache
+# Update this line to contain a comma separated list of memcache servers
+# shared by all nodes running the proxy-server service.
+memcache_servers = localhost:11211
+
+[filter:tempurl]
+use = egg:swift#tempurl
[filter:gswauth]
use = egg:gluster_swift#gswauth
set log_name = gswauth
super_admin_key = gswauthkey
metadata_volume = gsmetadata
-
-[filter:cache]
-use = egg:swift#memcache
-# Update this line to contain a comma separated list of memcache servers
-# shared by all nodes running the proxy-server service.
-memcache_servers = localhost:11211
diff --git a/test/functional_auth/keystone/conf/account-server.conf b/test/functional_auth/keystone/conf/account-server.conf
deleted file mode 100644
index 4996367..0000000
--- a/test/functional_auth/keystone/conf/account-server.conf
+++ /dev/null
@@ -1,32 +0,0 @@
-[DEFAULT]
-devices = /mnt/gluster-object
-#
-# Once you are confident that your startup processes will always have your
-# gluster volumes properly mounted *before* the account-server workers start,
-# you can *consider* setting this value to "false" to reduce the per-request
-# overhead it can incur.
-#
-# *** Keep false for Functional Tests ***
-mount_check = false
-bind_port = 6012
-#
-# Override swift's default behaviour for fallocate.
-disable_fallocate = true
-#
-# One or two workers should be sufficient for almost any installation of
-# Gluster.
-workers = 1
-
-[pipeline:main]
-pipeline = account-server
-
-[app:account-server]
-use = egg:gluster_swift#account
-user = root
-log_facility = LOG_LOCAL2
-log_level = WARN
-#
-# After ensuring things are running in a stable manner, you can turn off
-# normal request logging for the account server to unclutter the log
-# files. Warnings and errors will still be logged.
-log_requests = off
diff --git a/test/functional_auth/keystone/conf/container-server.conf b/test/functional_auth/keystone/conf/container-server.conf
deleted file mode 100644
index 122d97e..0000000
--- a/test/functional_auth/keystone/conf/container-server.conf
+++ /dev/null
@@ -1,35 +0,0 @@
-[DEFAULT]
-devices = /mnt/gluster-object
-#
-# Once you are confident that your startup processes will always have your
-# gluster volumes properly mounted *before* the container-server workers
-# start, you can *consider* setting this value to "false" to reduce the
-# per-request overhead it can incur.
-#
-# *** Keep false for Functional Tests ***
-mount_check = false
-bind_port = 6011
-#
-# Override swift's default behaviour for fallocate.
-disable_fallocate = true
-#
-# One or two workers should be sufficient for almost any installation of
-# Gluster.
-workers = 1
-
-[pipeline:main]
-pipeline = container-server
-
-[app:container-server]
-use = egg:gluster_swift#container
-user = root
-log_facility = LOG_LOCAL2
-log_level = WARN
-#
-# After ensuring things are running in a stable manner, you can turn off
-# normal request logging for the container server to unclutter the log
-# files. Warnings and errors will still be logged.
-log_requests = off
-
-#enable object versioning for functional test
-allow_versions = on
diff --git a/test/functional_auth/keystone/conf/fs.conf b/test/functional_auth/keystone/conf/fs.conf
deleted file mode 100644
index b06a854..0000000
--- a/test/functional_auth/keystone/conf/fs.conf
+++ /dev/null
@@ -1,19 +0,0 @@
-[DEFAULT]
-#
-# IP address of a node in the GlusterFS server cluster hosting the
-# volumes to be served via Swift API.
-mount_ip = localhost
-
-# Performance optimization parameter. When turned off, the filesystem will
-# see a reduced number of stat calls, resulting in substantially faster
-# response time for GET and HEAD container requests on containers with large
-# numbers of objects, at the expense of an accurate count of combined bytes
-# used by all objects in the container. For most installations "off" works
-# fine.
-#
-# *** Keep on for Functional Tests ***
-accurate_size_in_listing = on
-
-# *** Keep on for Functional Tests ***
-container_update_object_count = on
-account_update_container_count = on
diff --git a/test/functional_auth/keystone/conf/object-server.conf b/test/functional_auth/keystone/conf/object-server.conf
deleted file mode 100644
index 3cb9ead..0000000
--- a/test/functional_auth/keystone/conf/object-server.conf
+++ /dev/null
@@ -1,48 +0,0 @@
-[DEFAULT]
-devices = /mnt/gluster-object
-#
-# Once you are confident that your startup processes will always have your
-# gluster volumes properly mounted *before* the object-server workers start,
-# you can *consider* setting this value to "false" to reduce the per-request
-# overhead it can incur.
-#
-# *** Keep false for Functional Tests ***
-mount_check = false
-bind_port = 6010
-#
-# Maximum number of clients one worker can process simultaneously (it will
-# actually accept N + 1). Setting this to one (1) will only handle one request
-# at a time, without accepting another request concurrently. By increasing the
-# number of workers to a much higher value, one can prevent slow file system
-# operations for one request from starving other requests.
-max_clients = 1024
-#
-# If not doing the above, setting this value initially to match the number of
-# CPUs is a good starting point for determining the right value.
-workers = 1
-# Override swift's default behaviour for fallocate.
-disable_fallocate = true
-
-[pipeline:main]
-pipeline = object-server
-
-[app:object-server]
-use = egg:gluster_swift#object
-user = root
-log_facility = LOG_LOCAL2
-log_level = WARN
-#
-# For performance, after ensuring things are running in a stable manner, you
-# can turn off normal request logging for the object server to reduce the
-# per-request overhead and unclutter the log files. Warnings and errors will
-# still be logged.
-log_requests = off
-#
-# Adjust this value to match the stripe width of the underlying storage array
-# (not the stripe element size). This will provide a reasonable starting point
-# for tuning this value.
-disk_chunk_size = 65536
-#
-# Adjust this value match whatever is set for the disk_chunk_size initially.
-# This will provide a reasonable starting point for tuning this value.
-network_chunk_size = 65556
diff --git a/test/functional_auth/keystone/conf/proxy-server.conf b/test/functional_auth/keystone/conf/proxy-server.conf
index 084e6a5..72a84da 100644
--- a/test/functional_auth/keystone/conf/proxy-server.conf
+++ b/test/functional_auth/keystone/conf/proxy-server.conf
@@ -6,7 +6,7 @@ workers = 1
[pipeline:main]
#pipeline = catch_errors healthcheck proxy-logging cache tempauth proxy-logging proxy-server
-pipeline = catch_errors healthcheck proxy-logging cache authtoken keystoneauth proxy-logging proxy-server
+pipeline = catch_errors healthcheck proxy-logging cache tempurl authtoken keystoneauth proxy-logging proxy-server
[app:proxy-server]
use = egg:gluster_swift#proxy
@@ -49,6 +49,10 @@ object_chunk_size = 65536
# amount of memory available on the system can accommodate increased values
# for object_chunk_size.
put_queue_depth = 10
+# The following parameter is used by object-expirer and needs to be same
+# across all conf files!
+auto_create_account_prefix = gs
+expiring_objects_account_name = expiring
[filter:catch_errors]
use = egg:swift#catch_errors
@@ -59,13 +63,14 @@ use = egg:swift#proxy_logging
[filter:healthcheck]
use = egg:swift#healthcheck
-[filter:tempauth]
-use = egg:swift#tempauth
-user_admin_admin = admin .admin .reseller_admin
-user_d4dde08c621a4f0fb4cde0ac6a62aa0c_tester = testing .admin
-user_test_tester = testing .admin
-user_test2_tester2 = testing2 .admin
-user_test_tester3 = testing3
+[filter:cache]
+use = egg:swift#memcache
+# Update this line to contain a comma separated list of memcache servers
+# shared by all nodes running the proxy-server service.
+memcache_servers = localhost:11211
+
+[filter:tempurl]
+use = egg:swift#tempurl
[filter:authtoken]
paste.filter_factory = keystoneclient.middleware.auth_token:filter_factory
@@ -87,8 +92,4 @@ operator_roles = admin
is_admin = true
cache = swift.cache
-[filter:cache]
-use = egg:swift#memcache
-# Update this line to contain a comma separated list of memcache servers
-# shared by all nodes running the proxy-server service.
-memcache_servers = localhost:11211
+
diff --git a/test/functional_auth/keystone/conf/swift.conf b/test/functional_auth/keystone/conf/swift.conf
deleted file mode 100644
index ce9a4d0..0000000
--- a/test/functional_auth/keystone/conf/swift.conf
+++ /dev/null
@@ -1,85 +0,0 @@
-[DEFAULT]
-
-
-[swift-hash]
-# random unique string that can never change (DO NOT LOSE)
-swift_hash_path_suffix = gluster
-
-
-# The swift-constraints section sets the basic constraints on data
-# saved in the swift cluster.
-
-[swift-constraints]
-
-# max_file_size is the largest "normal" object that can be saved in
-# the cluster. This is also the limit on the size of each segment of
-# a "large" object when using the large object manifest support.
-# This value is set in bytes. Setting it to lower than 1MiB will cause
-# some tests to fail.
-# Default is 1 TiB = 2**30*1024
-max_file_size = 1099511627776
-
-
-# max_meta_name_length is the max number of bytes in the utf8 encoding
-# of the name portion of a metadata header.
-
-#max_meta_name_length = 128
-
-
-# max_meta_value_length is the max number of bytes in the utf8 encoding
-# of a metadata value
-
-#max_meta_value_length = 256
-
-
-# max_meta_count is the max number of metadata keys that can be stored
-# on a single account, container, or object
-
-#max_meta_count = 90
-
-
-# max_meta_overall_size is the max number of bytes in the utf8 encoding
-# of the metadata (keys + values)
-
-#max_meta_overall_size = 4096
-
-
-# max_object_name_length is the max number of bytes in the utf8 encoding of an
-# object name: Gluster FS can handle much longer file names, but the length
-# between the slashes of the URL is handled below. Remember that most web
-# clients can't handle anything greater than 2048, and those that do are
-# rather clumsy.
-
-max_object_name_length = 2048
-
-# max_object_name_component_length (GlusterFS) is the max number of bytes in
-# the utf8 encoding of an object name component (the part between the
-# slashes); this is a limit imposed by the underlying file system (for XFS it
-# is 255 bytes).
-
-max_object_name_component_length = 255
-
-# container_listing_limit is the default (and max) number of items
-# returned for a container listing request
-
-#container_listing_limit = 10000
-
-
-# account_listing_limit is the default (and max) number of items returned
-# for an account listing request
-
-#account_listing_limit = 10000
-
-
-# max_account_name_length is the max number of bytes in the utf8 encoding of
-# an account name: Gluster FS Filename limit (XFS limit?), must be the same
-# size as max_object_name_component_length above.
-
-max_account_name_length = 255
-
-
-# max_container_name_length is the max number of bytes in the utf8 encoding
-# of a container name: Gluster FS Filename limit (XFS limit?), must be the same
-# size as max_object_name_component_length above.
-
-max_container_name_length = 255
diff --git a/test/functional_auth/swiftkerbauth/__init__.py b/test/functional_auth/swiftkerbauth/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/test/functional_auth/swiftkerbauth/__init__.py
+++ /dev/null
diff --git a/test/functional_auth/swiftkerbauth/conf/account-server.conf b/test/functional_auth/swiftkerbauth/conf/account-server.conf
deleted file mode 100644
index 9ad458a..0000000
--- a/test/functional_auth/swiftkerbauth/conf/account-server.conf
+++ /dev/null
@@ -1,36 +0,0 @@
-[DEFAULT]
-#
-# Default gluster mount point to be used for object store,can be changed by
-# setting the following value in {account,container,object}-server.conf files.
-# It is recommended to keep this value same for all the three services but can
-# be kept different if environment demands.
-devices = /mnt/gluster-object
-#
-# Once you are confident that your startup processes will always have your
-# gluster volumes properly mounted *before* the account-server workers start,
-# you can *consider* setting this value to "false" to reduce the per-request
-# overhead it can incur.
-mount_check = true
-bind_port = 6012
-#
-# Override swift's default behaviour for fallocate.
-disable_fallocate = true
-#
-# One or two workers should be sufficient for almost any installation of
-# Gluster.
-workers = 1
-
-[pipeline:main]
-pipeline = account-server
-
-[app:account-server]
-use = egg:gluster_swift#account
-user = root
-log_facility = LOG_LOCAL2
-log_level = WARN
-#
-# After ensuring things are running in a stable manner, you can turn off
-# normal request logging for the account server to unclutter the log
-# files. Warnings and errors will still be logged.
-log_requests = off
-
diff --git a/test/functional_auth/swiftkerbauth/conf/container-server.conf b/test/functional_auth/swiftkerbauth/conf/container-server.conf
deleted file mode 100644
index a406b4d..0000000
--- a/test/functional_auth/swiftkerbauth/conf/container-server.conf
+++ /dev/null
@@ -1,36 +0,0 @@
-[DEFAULT]
-#
-# Default gluster mount point to be used for object store,can be changed by
-# setting the following value in {account,container,object}-server.conf files.
-# It is recommended to keep this value same for all the three services but can
-# be kept different if environment demands.
-devices = /mnt/gluster-object
-#
-# Once you are confident that your startup processes will always have your
-# gluster volumes properly mounted *before* the container-server workers
-# start, you can *consider* setting this value to "false" to reduce the
-# per-request overhead it can incur.
-mount_check = true
-bind_port = 6011
-#
-# Override swift's default behaviour for fallocate.
-disable_fallocate = true
-#
-# One or two workers should be sufficient for almost any installation of
-# Gluster.
-workers = 1
-
-[pipeline:main]
-pipeline = container-server
-
-[app:container-server]
-use = egg:gluster_swift#container
-user = root
-log_facility = LOG_LOCAL2
-log_level = WARN
-#
-# After ensuring things are running in a stable manner, you can turn off
-# normal request logging for the container server to unclutter the log
-# files. Warnings and errors will still be logged.
-log_requests = off
-
diff --git a/test/functional_auth/swiftkerbauth/conf/fs.conf b/test/functional_auth/swiftkerbauth/conf/fs.conf
deleted file mode 100644
index 6d2a791..0000000
--- a/test/functional_auth/swiftkerbauth/conf/fs.conf
+++ /dev/null
@@ -1,13 +0,0 @@
-[DEFAULT]
-#
-# IP address of a node in the GlusterFS server cluster hosting the
-# volumes to be served via Swift API.
-mount_ip = localhost
-
-# Performance optimization parameter. When turned off, the filesystem will
-# see a reduced number of stat calls, resulting in substantially faster
-# response time for GET and HEAD container requests on containers with large
-# numbers of objects, at the expense of an accurate count of combined bytes
-# used by all objects in the container. For most installations "off" works
-# fine.
-accurate_size_in_listing = off \ No newline at end of file
diff --git a/test/functional_auth/swiftkerbauth/conf/object-server.conf b/test/functional_auth/swiftkerbauth/conf/object-server.conf
deleted file mode 100644
index d10d282..0000000
--- a/test/functional_auth/swiftkerbauth/conf/object-server.conf
+++ /dev/null
@@ -1,51 +0,0 @@
-[DEFAULT]
-#
-# Default gluster mount point to be used for object store,can be changed by
-# setting the following value in {account,container,object}-server.conf files.
-# It is recommended to keep this value same for all the three services but can
-# be kept different if environment demands.
-devices = /mnt/gluster-object
-#
-# Once you are confident that your startup processes will always have your
-# gluster volumes properly mounted *before* the object-server workers start,
-# you can *consider* setting this value to "false" to reduce the per-request
-# overhead it can incur.
-mount_check = true
-bind_port = 6010
-#
-# Maximum number of clients one worker can process simultaneously (it will
-# actually accept N + 1). Setting this to one (1) will only handle one request
-# at a time, without accepting another request concurrently. By increasing the
-# number of workers to a much higher value, one can prevent slow file system
-# operations for one request from starving other requests.
-max_clients = 1024
-#
-# If not doing the above, setting this value initially to match the number of
-# CPUs is a good starting point for determining the right value.
-workers = 1
-# Override swift's default behaviour for fallocate.
-disable_fallocate = true
-
-[pipeline:main]
-pipeline = object-server
-
-[app:object-server]
-use = egg:gluster_swift#object
-user = root
-log_facility = LOG_LOCAL2
-log_level = WARN
-#
-# For performance, after ensuring things are running in a stable manner, you
-# can turn off normal request logging for the object server to reduce the
-# per-request overhead and unclutter the log files. Warnings and errors will
-# still be logged.
-log_requests = off
-#
-# Adjust this value to match the stripe width of the underlying storage array
-# (not the stripe element size). This will provide a reasonable starting point
-# for tuning this value.
-disk_chunk_size = 65536
-#
-# Adjust this value match whatever is set for the disk_chunk_size initially.
-# This will provide a reasonable starting point for tuning this value.
-network_chunk_size = 65536
diff --git a/test/functional_auth/swiftkerbauth/conf/proxy-server.conf b/test/functional_auth/swiftkerbauth/conf/proxy-server.conf
index e6f8aa1..248f87c 100644
--- a/test/functional_auth/swiftkerbauth/conf/proxy-server.conf
+++ b/test/functional_auth/swiftkerbauth/conf/proxy-server.conf
@@ -5,7 +5,7 @@ user = root
workers = 1
[pipeline:main]
-pipeline = catch_errors healthcheck proxy-logging cache proxy-logging kerbauth proxy-server
+pipeline = catch_errors healthcheck proxy-logging cache tempurl proxy-logging kerbauth proxy-server
[app:proxy-server]
use = egg:gluster_swift#proxy
@@ -48,6 +48,10 @@ object_chunk_size = 65536
# amount of memory available on the system can accommodate increased values
# for object_chunk_size.
put_queue_depth = 10
+# The following parameter is used by object-expirer and needs to be same
+# across all conf files!
+auto_create_account_prefix = gs
+expiring_objects_account_name = expiring
[filter:catch_errors]
use = egg:swift#catch_errors
@@ -59,12 +63,15 @@ access_log_level = WARN
[filter:healthcheck]
use = egg:swift#healthcheck
-[filter:kerbauth]
-use = egg:gluster_swift#kerbauth
-ext_authentication_url = http://client.rhelbox.com/cgi-bin/swift-auth
-
[filter:cache]
use = egg:swift#memcache
# Update this line to contain a comma separated list of memcache servers
# shared by all nodes running the proxy-server service.
memcache_servers = localhost:11211
+
+[filter:tempurl]
+use = egg:swift#tempurl
+
+[filter:kerbauth]
+use = egg:gluster_swift#kerbauth
+ext_authentication_url = http://client.rhelbox.com/cgi-bin/swift-auth
diff --git a/test/functional_auth/swiftkerbauth/conf/swift.conf b/test/functional_auth/swiftkerbauth/conf/swift.conf
deleted file mode 100644
index 0d25209..0000000
--- a/test/functional_auth/swiftkerbauth/conf/swift.conf
+++ /dev/null
@@ -1,84 +0,0 @@
-[DEFAULT]
-
-
-[swift-hash]
-# random unique string that can never change (DO NOT LOSE)
-swift_hash_path_suffix = gluster
-
-
-# The swift-constraints section sets the basic constraints on data
-# saved in the swift cluster.
-
-[swift-constraints]
-# max_file_size is the largest "normal" object that can be saved in
-# the cluster. This is also the limit on the size of each segment of
-# a "large" object when using the large object manifest support.
-# This value is set in bytes. Setting it to lower than 1MiB will cause
-# some tests to fail.
-# Default is 1 TiB = 2**30*1024
-
-max_file_size = 1099511627776
-
-# max_meta_name_length is the max number of bytes in the utf8 encoding
-# of the name portion of a metadata header.
-
-#max_meta_name_length = 128
-
-
-# max_meta_value_length is the max number of bytes in the utf8 encoding
-# of a metadata value
-
-#max_meta_value_length = 256
-
-
-# max_meta_count is the max number of metadata keys that can be stored
-# on a single account, container, or object
-
-#max_meta_count = 90
-
-
-# max_meta_overall_size is the max number of bytes in the utf8 encoding
-# of the metadata (keys + values)
-
-#max_meta_overall_size = 4096
-
-
-# max_object_name_length is the max number of bytes in the utf8 encoding of an
-# object name: Gluster FS can handle much longer file names, but the length
-# between the slashes of the URL is handled below. Remember that most web
-# clients can't handle anything greater than 2048, and those that do are
-# rather clumsy.
-
-max_object_name_length = 2048
-
-# max_object_name_component_length (GlusterFS) is the max number of bytes in
-# the utf8 encoding of an object name component (the part between the
-# slashes); this is a limit imposed by the underlying file system (for XFS it
-# is 255 bytes).
-
-max_object_name_component_length = 255
-
-# container_listing_limit is the default (and max) number of items
-# returned for a container listing request
-
-#container_listing_limit = 10000
-
-
-# account_listing_limit is the default (and max) number of items returned
-# for an account listing request
-
-#account_listing_limit = 10000
-
-
-# max_account_name_length is the max number of bytes in the utf8 encoding of
-# an account name: Gluster FS Filename limit (XFS limit?), must be the same
-# size as max_object_name_component_length above.
-
-max_account_name_length = 255
-
-
-# max_container_name_length is the max number of bytes in the utf8 encoding
-# of a container name: Gluster FS Filename limit (XFS limit?), must be the same
-# size as max_object_name_component_length above.
-
-max_container_name_length = 255
diff --git a/test/functional_auth/swiftkerbauth/test_swkrbath_active.py b/test/functional_auth/swiftkerbauth/test_swkrbath_active.py
deleted file mode 100644
index 86c79ef..0000000
--- a/test/functional_auth/swiftkerbauth/test_swkrbath_active.py
+++ /dev/null
@@ -1,93 +0,0 @@
-#!/usr/bin/python
-
-# Copyright (c) 2010-2014 OpenStack Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-# implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import re
-import unittest
-from nose import SkipTest
-import commands
-import os
-from test import get_config
-from swift.common.bufferedhttp import http_connect_raw as http_connect
-
-config = get_config('func_test')
-
-class Utils:
- @classmethod
- def SwiftKerbAuthPrep(self,
- user=config['username'],domain=config['domain_name'],\
- passwd=config['password']):
- username = '%s@%s' % (user, domain)
- return commands.getstatusoutput('kinit %s <<< %s' % (username, passwd))
-
- @classmethod
- def SwiftKerbAuthCleanAll(self):
- return commands.getstatusoutput('kdestroy')
-
-
-class TestSwKrbAthActive(unittest.TestCase):
- def setUp(self):
- #Perform kinit in active mode.
- (status, output) = Utils.SwiftKerbAuthPrep()
- self.assertEqual(status, 0, \
- 'swkrbauth prep failed with valid credentials'+output)
- self.auth_host = config['auth_host']
- self.auth_port = int(config['auth_port'])
- self.auth_prefix = config.get('auth_prefix', '/auth/')
- self.auth_version = str(config.get('auth_version', '1'))
- self.account_name = config['account']
- self.username = config['username']
- self.password = config['password']
- self.auth_scheme = config['auth_scheme']
-
- #Prepare auth_url. e.g. http://client.rhelbox.com:8080/auth/v1.0
- if self.auth_version == "1":
- self.auth_path = '%sv1.0' % (self.auth_prefix)
- else:
- self.auth_path = self.auth_prefix
- self.auth_netloc = "%s:%d" % (self.auth_host, self.auth_port)
- auth_url = self.auth_scheme + self.auth_netloc + self.auth_path
-
- #Obtain the X-Auth-Token from kerberos server to use it in furhter
- #testing
- self.auth_token = None
- (status, output) = commands.getstatusoutput('curl -v -u : --negotiate\
- --location-trusted %s' % (auth_url))
- self.assertEqual(status, 0, 'Token negotiation failed:' +output)
- match = re.search('X-Auth-Token: AUTH.*', output)
- if match:
- self.auth_token = match.group(0).split(':')[1].strip()
- else:
- self.fail('No X-Auth-Token found, failed')
-
- def tearDown(self):
- Utils.SwiftKerbAuthCleanAll()
-
-
- def _get_auth_token(self):
- return {'X-Auth-Token' : self.auth_token}
-
- def testGetAccounts(self):
- #TODO: The test case is to perform GET on the account mentioned via
- #configuration file. This is a sample test case. The whole test
- #suite can be enhanced further to have further complicated test cases.
- path = '/v1/AUTH_%s' % (config['account'])
-
- headers = self._get_auth_token()
- conn = http_connect(config['auth_host'], config['auth_port'], 'GET',
- path, headers)
- resp = conn.getresponse()
- self.assertTrue(resp.status == 204)
diff --git a/test/functional_auth/tempauth/conf/container-server.conf b/test/functional_auth/tempauth/conf/container-server.conf
deleted file mode 100644
index 122d97e..0000000
--- a/test/functional_auth/tempauth/conf/container-server.conf
+++ /dev/null
@@ -1,35 +0,0 @@
-[DEFAULT]
-devices = /mnt/gluster-object
-#
-# Once you are confident that your startup processes will always have your
-# gluster volumes properly mounted *before* the container-server workers
-# start, you can *consider* setting this value to "false" to reduce the
-# per-request overhead it can incur.
-#
-# *** Keep false for Functional Tests ***
-mount_check = false
-bind_port = 6011
-#
-# Override swift's default behaviour for fallocate.
-disable_fallocate = true
-#
-# One or two workers should be sufficient for almost any installation of
-# Gluster.
-workers = 1
-
-[pipeline:main]
-pipeline = container-server
-
-[app:container-server]
-use = egg:gluster_swift#container
-user = root
-log_facility = LOG_LOCAL2
-log_level = WARN
-#
-# After ensuring things are running in a stable manner, you can turn off
-# normal request logging for the container server to unclutter the log
-# files. Warnings and errors will still be logged.
-log_requests = off
-
-#enable object versioning for functional test
-allow_versions = on
diff --git a/test/functional_auth/tempauth/conf/fs.conf b/test/functional_auth/tempauth/conf/fs.conf
deleted file mode 100644
index b06a854..0000000
--- a/test/functional_auth/tempauth/conf/fs.conf
+++ /dev/null
@@ -1,19 +0,0 @@
-[DEFAULT]
-#
-# IP address of a node in the GlusterFS server cluster hosting the
-# volumes to be served via Swift API.
-mount_ip = localhost
-
-# Performance optimization parameter. When turned off, the filesystem will
-# see a reduced number of stat calls, resulting in substantially faster
-# response time for GET and HEAD container requests on containers with large
-# numbers of objects, at the expense of an accurate count of combined bytes
-# used by all objects in the container. For most installations "off" works
-# fine.
-#
-# *** Keep on for Functional Tests ***
-accurate_size_in_listing = on
-
-# *** Keep on for Functional Tests ***
-container_update_object_count = on
-account_update_container_count = on
diff --git a/test/functional_auth/tempauth/conf/object-expirer.conf b/test/functional_auth/tempauth/conf/object-expirer.conf
deleted file mode 100644
index b75963c..0000000
--- a/test/functional_auth/tempauth/conf/object-expirer.conf
+++ /dev/null
@@ -1,17 +0,0 @@
-[DEFAULT]
-
-[object-expirer]
-# auto_create_account_prefix = .
-
-[pipeline:main]
-pipeline = catch_errors cache proxy-server
-
-[app:proxy-server]
-use = egg:swift#proxy
-
-[filter:cache]
-use = egg:swift#memcache
-memcache_servers = 127.0.0.1:11211
-
-[filter:catch_errors]
-use = egg:swift#catch_errors
diff --git a/test/functional_auth/tempauth/conf/object-server.conf b/test/functional_auth/tempauth/conf/object-server.conf
deleted file mode 100644
index 3cb9ead..0000000
--- a/test/functional_auth/tempauth/conf/object-server.conf
+++ /dev/null
@@ -1,48 +0,0 @@
-[DEFAULT]
-devices = /mnt/gluster-object
-#
-# Once you are confident that your startup processes will always have your
-# gluster volumes properly mounted *before* the object-server workers start,
-# you can *consider* setting this value to "false" to reduce the per-request
-# overhead it can incur.
-#
-# *** Keep false for Functional Tests ***
-mount_check = false
-bind_port = 6010
-#
-# Maximum number of clients one worker can process simultaneously (it will
-# actually accept N + 1). Setting this to one (1) will only handle one request
-# at a time, without accepting another request concurrently. By increasing the
-# number of workers to a much higher value, one can prevent slow file system
-# operations for one request from starving other requests.
-max_clients = 1024
-#
-# If not doing the above, setting this value initially to match the number of
-# CPUs is a good starting point for determining the right value.
-workers = 1
-# Override swift's default behaviour for fallocate.
-disable_fallocate = true
-
-[pipeline:main]
-pipeline = object-server
-
-[app:object-server]
-use = egg:gluster_swift#object
-user = root
-log_facility = LOG_LOCAL2
-log_level = WARN
-#
-# For performance, after ensuring things are running in a stable manner, you
-# can turn off normal request logging for the object server to reduce the
-# per-request overhead and unclutter the log files. Warnings and errors will
-# still be logged.
-log_requests = off
-#
-# Adjust this value to match the stripe width of the underlying storage array
-# (not the stripe element size). This will provide a reasonable starting point
-# for tuning this value.
-disk_chunk_size = 65536
-#
-# Adjust this value match whatever is set for the disk_chunk_size initially.
-# This will provide a reasonable starting point for tuning this value.
-network_chunk_size = 65556
diff --git a/test/functional_auth/tempauth/conf/proxy-server.conf b/test/functional_auth/tempauth/conf/proxy-server.conf
index 830fadf..554ce61 100644
--- a/test/functional_auth/tempauth/conf/proxy-server.conf
+++ b/test/functional_auth/tempauth/conf/proxy-server.conf
@@ -5,7 +5,7 @@ user = root
workers = 1
[pipeline:main]
-pipeline = catch_errors healthcheck proxy-logging cache tempauth proxy-logging proxy-server
+pipeline = catch_errors healthcheck proxy-logging cache tempurl tempauth proxy-logging proxy-server
[app:proxy-server]
use = egg:gluster_swift#proxy
@@ -48,6 +48,10 @@ object_chunk_size = 65536
# amount of memory available on the system can accommodate increased values
# for object_chunk_size.
put_queue_depth = 10
+# The following parameter is used by object-expirer and needs to be same
+# across all conf files!
+auto_create_account_prefix = gs
+expiring_objects_account_name = expiring
[filter:catch_errors]
use = egg:swift#catch_errors
@@ -58,15 +62,18 @@ use = egg:swift#proxy_logging
[filter:healthcheck]
use = egg:swift#healthcheck
+[filter:cache]
+use = egg:swift#memcache
+# Update this line to contain a comma separated list of memcache servers
+# shared by all nodes running the proxy-server service.
+memcache_servers = localhost:11211
+
+[filter:tempurl]
+use = egg:swift#tempurl
+
[filter:tempauth]
use = egg:swift#tempauth
user_admin_admin = admin .admin .reseller_admin
user_test_tester = testing .admin
user_test2_tester2 = testing2 .admin
user_test_tester3 = testing3
-
-[filter:cache]
-use = egg:swift#memcache
-# Update this line to contain a comma separated list of memcache servers
-# shared by all nodes running the proxy-server service.
-memcache_servers = localhost:11211
diff --git a/test/functional_auth/tempauth/conf/swift.conf b/test/functional_auth/tempauth/conf/swift.conf
deleted file mode 100644
index ce9a4d0..0000000
--- a/test/functional_auth/tempauth/conf/swift.conf
+++ /dev/null
@@ -1,85 +0,0 @@
-[DEFAULT]
-
-
-[swift-hash]
-# random unique string that can never change (DO NOT LOSE)
-swift_hash_path_suffix = gluster
-
-
-# The swift-constraints section sets the basic constraints on data
-# saved in the swift cluster.
-
-[swift-constraints]
-
-# max_file_size is the largest "normal" object that can be saved in
-# the cluster. This is also the limit on the size of each segment of
-# a "large" object when using the large object manifest support.
-# This value is set in bytes. Setting it to lower than 1MiB will cause
-# some tests to fail.
-# Default is 1 TiB = 2**30*1024
-max_file_size = 1099511627776
-
-
-# max_meta_name_length is the max number of bytes in the utf8 encoding
-# of the name portion of a metadata header.
-
-#max_meta_name_length = 128
-
-
-# max_meta_value_length is the max number of bytes in the utf8 encoding
-# of a metadata value
-
-#max_meta_value_length = 256
-
-
-# max_meta_count is the max number of metadata keys that can be stored
-# on a single account, container, or object
-
-#max_meta_count = 90
-
-
-# max_meta_overall_size is the max number of bytes in the utf8 encoding
-# of the metadata (keys + values)
-
-#max_meta_overall_size = 4096
-
-
-# max_object_name_length is the max number of bytes in the utf8 encoding of an
-# object name: Gluster FS can handle much longer file names, but the length
-# between the slashes of the URL is handled below. Remember that most web
-# clients can't handle anything greater than 2048, and those that do are
-# rather clumsy.
-
-max_object_name_length = 2048
-
-# max_object_name_component_length (GlusterFS) is the max number of bytes in
-# the utf8 encoding of an object name component (the part between the
-# slashes); this is a limit imposed by the underlying file system (for XFS it
-# is 255 bytes).
-
-max_object_name_component_length = 255
-
-# container_listing_limit is the default (and max) number of items
-# returned for a container listing request
-
-#container_listing_limit = 10000
-
-
-# account_listing_limit is the default (and max) number of items returned
-# for an account listing request
-
-#account_listing_limit = 10000
-
-
-# max_account_name_length is the max number of bytes in the utf8 encoding of
-# an account name: Gluster FS Filename limit (XFS limit?), must be the same
-# size as max_object_name_component_length above.
-
-max_account_name_length = 255
-
-
-# max_container_name_length is the max number of bytes in the utf8 encoding
-# of a container name: Gluster FS Filename limit (XFS limit?), must be the same
-# size as max_object_name_component_length above.
-
-max_container_name_length = 255
diff --git a/gluster/swift/common/middleware/gswauth/test_swauth/unit/__init__.py b/test/object_expirer_functional/__init__.py
index e69de29..e69de29 100644
--- a/gluster/swift/common/middleware/gswauth/test_swauth/unit/__init__.py
+++ b/test/object_expirer_functional/__init__.py
diff --git a/test/object_expirer_functional/test_object_expirer.py b/test/object_expirer_functional/test_object_expirer.py
new file mode 100644
index 0000000..aaec75e
--- /dev/null
+++ b/test/object_expirer_functional/test_object_expirer.py
@@ -0,0 +1,332 @@
+# Copyright (c) 2014 Red Hat, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import time
+
+from swift.common.manager import Manager
+from swift.common.internal_client import InternalClient
+
+from test.functional.tests import Base, config, Utils
+from test.functional.swift_test_client import Account, Connection, \
+ ResponseError
+
+
+class TestObjectExpirerEnv:
+ @classmethod
+ def setUp(cls):
+ cls.conn = Connection(config)
+ cls.conn.authenticate()
+ cls.account = Account(cls.conn,
+ config.get('account',
+ config['username']))
+ cls.account.delete_containers()
+ cls.container = cls.account.container(Utils.create_name())
+ if not cls.container.create():
+ raise ResponseError(cls.conn.response)
+ cls.file_size = 8
+ cls.root_dir = os.path.join('/mnt/gluster-object',
+ cls.account.conn.storage_url.split('/')[2].split('_')[1])
+ cls.client = InternalClient('/etc/swift/object-expirer.conf',
+ 'Test Object Expirer', 1)
+ cls.expirer = Manager(['object-expirer'])
+
+
+class TestObjectExpirer(Base):
+ env = TestObjectExpirerEnv
+ set_up = False
+
+ def test_object_expiry_X_Delete_At_PUT(self):
+ obj = self.env.container.file(Utils.create_name())
+ x_delete_at = str(int(time.time()) + 2)
+ obj.write_random(self.env.file_size,
+ hdrs={'X-Delete-At': x_delete_at})
+
+ # Object is not expired. Should still be accessible.
+ obj.read()
+ self.assert_status(200)
+
+ # Ensure X-Delete-At is saved as object metadata.
+ self.assertEqual(x_delete_at, str(obj.info()['x_delete_at']))
+
+ # Wait for object to be expired.
+ time.sleep(3)
+
+ # Object has expired. Should no longer be accessible.
+ self.assertRaises(ResponseError, obj.read)
+ self.assert_status(404)
+
+ # Object should still be present on filesystem.
+ self.assertTrue(os.path.isfile(os.path.join(self.env.root_dir,
+ self.env.container.name,
+ obj.name)))
+
+ # But, GET on container should list the expired object.
+ result = self.env.container.files()
+ self.assertTrue(obj.name in self.env.container.files())
+
+ # Check existence of corresponding tracker object in gsexpiring
+ # account.
+ enteredLoop = False
+ for c in self.env.client.iter_containers("gsexpiring"):
+ for o in self.env.client.iter_objects("gsexpiring", c['name']):
+ enteredLoop = True
+ l = o['name'].split('/')
+ self.assertTrue(l[0].endswith('AUTH_' + self.env.account.name))
+ self.assertEqual(l[1], self.env.container.name)
+ self.assertEqual(l[2], obj.name)
+ if not enteredLoop:
+ self.fail("Tracker object not found.")
+
+ # Run expirer daemon once.
+ self.env.expirer.once()
+
+ # Ensure object is physically deleted from filesystem.
+ self.assertFalse(os.path.exists(os.path.join(self.env.root_dir,
+ self.env.container.name,
+ obj.name)))
+
+ # Ensure tracker object is consumed.
+ try:
+ self.env.client.iter_containers("gsexpiring").next()
+ except StopIteration:
+ pass
+ else:
+ self.fail("Tracker object persists!")
+
+ # GET on container should no longer list the object.
+ self.assertFalse(obj.name in self.env.container.files())
+
+ def test_object_expiry_X_Delete_After_PUT(self):
+ obj = self.env.container.file(Utils.create_name())
+ obj.write_random(self.env.file_size,
+ hdrs={'X-Delete-After': 2})
+
+ # Object is not expired. Should still be accessible.
+ obj.read()
+ self.assert_status(200)
+
+ # Ensure X-Delete-At is saved as object metadata.
+ self.assertTrue(str(obj.info()['x_delete_at']))
+
+ # Wait for object to be expired.
+ time.sleep(3)
+
+ # Object has expired. Should no longer be accessible.
+ self.assertRaises(ResponseError, obj.read)
+ self.assert_status(404)
+
+ # Object should still be present on filesystem.
+ self.assertTrue(os.path.isfile(os.path.join(self.env.root_dir,
+ self.env.container.name,
+ obj.name)))
+
+ # But, GET on container should list the expired object.
+ result = self.env.container.files()
+ self.assertTrue(obj.name in self.env.container.files())
+
+ # Check existence of corresponding tracker object in gsexpiring
+ # account.
+ enteredLoop = False
+ for c in self.env.client.iter_containers("gsexpiring"):
+ for o in self.env.client.iter_objects("gsexpiring", c['name']):
+ enteredLoop = True
+ l = o['name'].split('/')
+ self.assertTrue(l[0].endswith('AUTH_' + self.env.account.name))
+ self.assertEqual(l[1], self.env.container.name)
+ self.assertEqual(l[2], obj.name)
+ if not enteredLoop:
+ self.fail("Tracker object not found.")
+
+ # Run expirer daemon once.
+ self.env.expirer.once()
+
+ # Ensure object is physically deleted from filesystem.
+ self.assertFalse(os.path.exists(os.path.join(self.env.root_dir,
+ self.env.container.name,
+ obj.name)))
+
+ # Ensure tracker object is consumed.
+ try:
+ self.env.client.iter_containers("gsexpiring").next()
+ except StopIteration:
+ pass
+ else:
+ self.fail("Tracker object persists!")
+
+ # GET on container should no longer list the object.
+ self.assertFalse(obj.name in self.env.container.files())
+
+
+ def test_object_expiry_X_Delete_At_POST(self):
+
+ # Create normal object
+ obj = self.env.container.file(Utils.create_name())
+ obj.write_random(self.env.file_size)
+ obj.read()
+ self.assert_status(200)
+
+ # Send POST on that object and set it to be expired.
+ x_delete_at = str(int(time.time()) + 2)
+ obj.sync_metadata(metadata={'X-Delete-At': x_delete_at},
+ cfg={'x_delete_at': x_delete_at})
+
+ # Ensure X-Delete-At is saved as object metadata.
+ self.assertEqual(x_delete_at, str(obj.info()['x_delete_at']))
+
+ # Object is not expired. Should still be accessible.
+ obj.read()
+ self.assert_status(200)
+
+ # Wait for object to be expired.
+ time.sleep(3)
+
+ # Object has expired. Should no longer be accessible.
+ self.assertRaises(ResponseError, obj.read)
+ self.assert_status(404)
+
+ # Object should still be present on filesystem.
+ self.assertTrue(os.path.isfile(os.path.join(self.env.root_dir,
+ self.env.container.name,
+ obj.name)))
+
+ # But, GET on container should list the expired object.
+ result = self.env.container.files()
+ self.assertTrue(obj.name in self.env.container.files())
+
+ # Check existence of corresponding tracker object in gsexpiring
+ # account.
+
+ enteredLoop = False
+ for c in self.env.client.iter_containers("gsexpiring"):
+ for o in self.env.client.iter_objects("gsexpiring", c['name']):
+ enteredLoop = True
+ l = o['name'].split('/')
+ self.assertTrue(l[0].endswith('AUTH_' + self.env.account.name))
+ self.assertEqual(l[1], self.env.container.name)
+ self.assertEqual(l[2], obj.name)
+ if not enteredLoop:
+ self.fail("Tracker object not found.")
+
+ # Run expirer daemon once.
+ self.env.expirer.once()
+ time.sleep(3)
+
+ # Ensure object is physically deleted from filesystem.
+ self.assertFalse(os.path.exists(os.path.join(self.env.root_dir,
+ self.env.container.name,
+ obj.name)))
+
+ # Ensure tracker object is consumed.
+ try:
+ self.env.client.iter_containers("gsexpiring").next()
+ except StopIteration:
+ pass
+ else:
+ self.fail("Tracker object persists!")
+
+ # GET on container should no longer list the object.
+ self.assertFalse(obj.name in self.env.container.files())
+
+
+ def test_object_expiry_X_Delete_After_POST(self):
+
+ # Create normal object
+ obj = self.env.container.file(Utils.create_name())
+ obj.write_random(self.env.file_size)
+ obj.read()
+ self.assert_status(200)
+
+ # Send POST on that object and set it to be expired.
+ obj.sync_metadata(metadata={'X-Delete-After': 2},
+ cfg={'x_delete_after': 2})
+
+ # Ensure X-Delete-At is saved as object metadata.
+ self.assertTrue(str(obj.info()['x_delete_at']))
+
+ # Object is not expired. Should still be accessible.
+ obj.read()
+ self.assert_status(200)
+
+ # Wait for object to be expired.
+ time.sleep(3)
+
+ # Object has expired. Should no longer be accessible.
+ self.assertRaises(ResponseError, obj.read)
+ self.assert_status(404)
+
+ # Object should still be present on filesystem.
+ self.assertTrue(os.path.isfile(os.path.join(self.env.root_dir,
+ self.env.container.name,
+ obj.name)))
+
+ # But, GET on container should list the expired object.
+ result = self.env.container.files()
+ self.assertTrue(obj.name in self.env.container.files())
+
+ # Check existence of corresponding tracker object in gsexpiring
+ # account.
+
+ enteredLoop = False
+ for c in self.env.client.iter_containers("gsexpiring"):
+ for o in self.env.client.iter_objects("gsexpiring", c['name']):
+ enteredLoop = True
+ l = o['name'].split('/')
+ self.assertTrue(l[0].endswith('AUTH_' + self.env.account.name))
+ self.assertEqual(l[1], self.env.container.name)
+ self.assertEqual(l[2], obj.name)
+ if not enteredLoop:
+ self.fail("Tracker object not found.")
+
+ # Run expirer daemon once.
+ self.env.expirer.once()
+ time.sleep(3)
+
+ # Ensure object is physically deleted from filesystem.
+ self.assertFalse(os.path.exists(os.path.join(self.env.root_dir,
+ self.env.container.name,
+ obj.name)))
+
+ # Ensure tracker object is consumed.
+ try:
+ self.env.client.iter_containers("gsexpiring").next()
+ except StopIteration:
+ pass
+ else:
+ self.fail("Tracker object persists!")
+
+ # GET on container should no longer list the object.
+ self.assertFalse(obj.name in self.env.container.files())
+
+
+ def test_object_expiry_err(self):
+ obj = self.env.container.file(Utils.create_name())
+
+ # X-Delete-At is invalid or is in the past
+ for i in (-2, 'abc', str(int(time.time()) - 2), 5.8):
+ self.assertRaises(ResponseError,
+ obj.write_random,
+ self.env.file_size,
+ hdrs={'X-Delete-At': i})
+ self.assert_status(400)
+
+ # X-Delete-After is invalid.
+ for i in (-2, 'abc', 3.7):
+ self.assertRaises(ResponseError,
+ obj.write_random,
+ self.env.file_size,
+ hdrs={'X-Delete-After': i})
+ self.assert_status(400)
+
diff --git a/test/unit/__init__.py b/test/unit/__init__.py
index 847479a..a1bfef8 100644
--- a/test/unit/__init__.py
+++ b/test/unit/__init__.py
@@ -33,6 +33,7 @@ from hashlib import md5
from eventlet import sleep, Timeout
import logging.handlers
from httplib import HTTPException
+from numbers import Number
class FakeRing(object):
@@ -248,6 +249,7 @@ class FakeLogger(logging.Logger):
if 'facility' in kwargs:
self.facility = kwargs['facility']
self.statsd_client = None
+ self.thread_locals = None
def _clear(self):
self.log_dict = defaultdict(list)
@@ -465,8 +467,11 @@ def fake_http_connect(*code_iter, **kwargs):
self.body = body
self.headers = headers or {}
self.timestamp = timestamp
- if kwargs.get('slow') and isinstance(kwargs['slow'], list):
- kwargs['slow'][0] -= 1
+ if 'slow' in kwargs and isinstance(kwargs['slow'], list):
+ try:
+ self._next_sleep = kwargs['slow'].pop(0)
+ except IndexError:
+ self._next_sleep = None
def getresponse(self):
if kwargs.get('raise_exc'):
@@ -482,6 +487,8 @@ def fake_http_connect(*code_iter, **kwargs):
return FakeConn(507)
if self.expect_status == -4:
return FakeConn(201)
+ if self.expect_status == 412:
+ return FakeConn(412)
return FakeConn(100)
def getheaders(self):
@@ -510,31 +517,39 @@ def fake_http_connect(*code_iter, **kwargs):
headers['x-container-timestamp'] = '1'
except StopIteration:
pass
- if self.am_slow():
+ am_slow, value = self.get_slow()
+ if am_slow:
headers['content-length'] = '4'
headers.update(self.headers)
return headers.items()
- def am_slow(self):
- if kwargs.get('slow') and isinstance(kwargs['slow'], list):
- return kwargs['slow'][0] >= 0
- return bool(kwargs.get('slow'))
+ def get_slow(self):
+ if 'slow' in kwargs and isinstance(kwargs['slow'], list):
+ if self._next_sleep is not None:
+ return True, self._next_sleep
+ else:
+ return False, 0.01
+ if kwargs.get('slow') and isinstance(kwargs['slow'], Number):
+ return True, kwargs['slow']
+ return bool(kwargs.get('slow')), 0.1
def read(self, amt=None):
- if self.am_slow():
+ am_slow, value = self.get_slow()
+ if am_slow:
if self.sent < 4:
self.sent += 1
- sleep(0.1)
+ sleep(value)
return ' '
rv = self.body[:amt]
self.body = self.body[amt:]
return rv
def send(self, amt=None):
- if self.am_slow():
+ am_slow, value = self.get_slow()
+ if am_slow:
if self.received < 4:
self.received += 1
- sleep(0.1)
+ sleep(value)
def getheader(self, name, default=None):
return dict(self.getheaders()).get(name.lower(), default)
@@ -584,4 +599,6 @@ def fake_http_connect(*code_iter, **kwargs):
return FakeConn(status, etag, body=body, timestamp=timestamp,
expect_status=expect_status, headers=headers)
+ connect.code_iter = code_iter
+
return connect
diff --git a/test/unit/common/middleware/swiftkerbauth/__init__.py b/test/unit/common/middleware/swiftkerbauth/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/test/unit/common/middleware/swiftkerbauth/__init__.py
+++ /dev/null
diff --git a/test/unit/common/middleware/swiftkerbauth/test_kerbauth.py b/test/unit/common/middleware/swiftkerbauth/test_kerbauth.py
deleted file mode 100644
index 537b8d3..0000000
--- a/test/unit/common/middleware/swiftkerbauth/test_kerbauth.py
+++ /dev/null
@@ -1,478 +0,0 @@
-# Copyright (c) 2013 Red Hat, Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-# implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import os
-import errno
-import unittest
-from time import time
-from mock import patch, Mock
-from test.unit import FakeMemcache
-from swift.common.swob import Request, Response
-from gluster.swift.common.middleware.swiftkerbauth import kerbauth as auth
-
-EXT_AUTHENTICATION_URL = "127.0.0.1"
-REDIRECT_STATUS = 303 # HTTPSeeOther
-
-
-def my_filter_factory(global_conf, **local_conf):
- if 'ext_authentication_url' not in global_conf:
- global_conf['ext_authentication_url'] = EXT_AUTHENTICATION_URL
- conf = global_conf.copy()
- conf.update(local_conf)
-
- def auth_filter(app):
- return auth.KerbAuth(app, conf)
- return auth_filter
-
-# Monkey patching filter_factory to always pass ext_authentication_url
-# as a parameter. Absence of ext_authentication_url raises a RuntimeError
-
-
-def patch_filter_factory():
- auth.filter_factory = my_filter_factory
-
-
-def unpatch_filter_factory():
- reload(auth)
-
-
-class FakeApp(object):
-
- def __init__(self, status_headers_body_iter=None, acl=None, sync_key=None):
- self.calls = 0
- self.status_headers_body_iter = status_headers_body_iter
- if not self.status_headers_body_iter:
- self.status_headers_body_iter = iter([('404 Not Found', {}, '')])
- self.acl = acl
- self.sync_key = sync_key
-
- def __call__(self, env, start_response):
- self.calls += 1
- self.request = Request.blank('', environ=env)
- if self.acl:
- self.request.acl = self.acl
- if self.sync_key:
- self.request.environ['swift_sync_key'] = self.sync_key
- if 'swift.authorize' in env:
- resp = env['swift.authorize'](self.request)
- if resp:
- return resp(env, start_response)
- status, headers, body = self.status_headers_body_iter.next()
- return Response(status=status, headers=headers,
- body=body)(env, start_response)
-
-
-class TestKerbAuth(unittest.TestCase):
-
- # Patch auth.filter_factory()
- patch_filter_factory()
-
- def setUp(self):
- self.test_auth = \
- auth.filter_factory({'auth_method': 'active'})(FakeApp())
- self.test_auth_passive = \
- auth.filter_factory({'auth_method': 'passive'})(FakeApp())
-
- def _make_request(self, path, **kwargs):
- req = Request.blank(path, **kwargs)
- req.environ['swift.cache'] = FakeMemcache()
- return req
-
- def test_no_ext_authentication_url(self):
- app = FakeApp()
- try:
- # Use original auth.filter_factory and NOT monkey patched version
- unpatch_filter_factory()
- auth.filter_factory({})(app)
- except RuntimeError as e:
- # Restore monkey patched version
- patch_filter_factory()
- self.assertTrue(e.args[0].startswith("Missing filter parameter "
- "ext_authentication_url"))
-
- def test_reseller_prefix_init(self):
- app = FakeApp()
- ath = auth.filter_factory({})(app)
- self.assertEquals(ath.reseller_prefix, 'AUTH_')
- ath = auth.filter_factory({'reseller_prefix': 'TEST'})(app)
- self.assertEquals(ath.reseller_prefix, 'TEST_')
- ath = auth.filter_factory({'reseller_prefix': 'TEST_'})(app)
- self.assertEquals(ath.reseller_prefix, 'TEST_')
-
- def test_auth_prefix_init(self):
- app = FakeApp()
- ath = auth.filter_factory({})(app)
- self.assertEquals(ath.auth_prefix, '/auth/')
- ath = auth.filter_factory({'auth_prefix': ''})(app)
- self.assertEquals(ath.auth_prefix, '/auth/')
- ath = auth.filter_factory({'auth_prefix': '/'})(app)
- self.assertEquals(ath.auth_prefix, '/auth/')
- ath = auth.filter_factory({'auth_prefix': '/test/'})(app)
- self.assertEquals(ath.auth_prefix, '/test/')
- ath = auth.filter_factory({'auth_prefix': '/test'})(app)
- self.assertEquals(ath.auth_prefix, '/test/')
- ath = auth.filter_factory({'auth_prefix': 'test/'})(app)
- self.assertEquals(ath.auth_prefix, '/test/')
- ath = auth.filter_factory({'auth_prefix': 'test'})(app)
- self.assertEquals(ath.auth_prefix, '/test/')
-
- def test_top_level_redirect(self):
- req = self._make_request('/')
- resp = req.get_response(self.test_auth)
- self.assertEquals(resp.status_int, REDIRECT_STATUS)
- self.assertEquals(req.environ['swift.authorize'],
- self.test_auth.denied_response)
-
- def test_passive_top_level_deny(self):
- req = self._make_request('/')
- resp = req.get_response(self.test_auth_passive)
- self.assertEquals(resp.status_int, 401)
- self.assertEquals(req.environ['swift.authorize'],
- self.test_auth_passive.denied_response)
-
- def test_passive_deny_invalid_token(self):
- req = self._make_request('/v1/AUTH_account',
- headers={'X-Auth-Token': 'AUTH_t'})
- resp = req.get_response(self.test_auth_passive)
- self.assertEquals(resp.status_int, 401)
-
- def test_override_asked_for_and_allowed(self):
- self.test_auth = \
- auth.filter_factory({'allow_overrides': 'true'})(FakeApp())
- req = self._make_request('/v1/AUTH_account',
- environ={'swift.authorize_override': True})
- resp = req.get_response(self.test_auth)
- self.assertEquals(resp.status_int, 404)
- self.assertTrue('swift.authorize' not in req.environ)
-
- def test_override_default_allowed(self):
- req = self._make_request('/v1/AUTH_account',
- environ={'swift.authorize_override': True})
- resp = req.get_response(self.test_auth)
- self.assertEquals(resp.status_int, 404)
- self.assertTrue('swift.authorize' not in req.environ)
-
- def test_options_call(self):
- req = self._make_request('/v1/AUTH_cfa/c/o',
- environ={'REQUEST_METHOD': 'OPTIONS'})
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp, None)
-
- def test_auth_deny_non_reseller_prefix_no_override(self):
- fake_authorize = lambda x: Response(status='500 Fake')
- req = self._make_request('/v1/BLAH_account',
- headers={'X-Auth-Token': 'BLAH_t'},
- environ={'swift.authorize': fake_authorize}
- )
- resp = req.get_response(self.test_auth)
- self.assertEquals(resp.status_int, 500)
- self.assertEquals(req.environ['swift.authorize'], fake_authorize)
-
- def test_authorize_acl_group_access(self):
- req = self._make_request('/v1/AUTH_cfa')
- req.remote_user = 'act:usr,act'
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp.status_int, 403)
- req = self._make_request('/v1/AUTH_cfa')
- req.remote_user = 'act:usr,act'
- req.acl = 'act'
- self.assertEquals(self.test_auth.authorize(req), None)
- req = self._make_request('/v1/AUTH_cfa')
- req.remote_user = 'act:usr,act'
- req.acl = 'act:usr'
- self.assertEquals(self.test_auth.authorize(req), None)
- req = self._make_request('/v1/AUTH_cfa')
- req.remote_user = 'act:usr,act'
-
- def test_deny_cross_reseller(self):
- # Tests that cross-reseller is denied, even if ACLs/group names match
- req = self._make_request('/v1/OTHER_cfa')
- req.remote_user = 'act:usr,act,AUTH_cfa'
- req.acl = 'act'
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp.status_int, 403)
-
- def test_authorize_acl_referer_after_user_groups(self):
- req = self._make_request('/v1/AUTH_cfa/c')
- req.remote_user = 'act:usr'
- req.acl = '.r:*,act:usr'
- self.assertEquals(self.test_auth.authorize(req), None)
-
- def test_detect_reseller_request(self):
- req = self._make_request('/v1/AUTH_admin',
- headers={'X-Auth-Token': 'AUTH_t'})
- cache_key = 'AUTH_/token/AUTH_t'
- cache_entry = (time() + 3600, '.reseller_admin')
- req.environ['swift.cache'].set(cache_key, cache_entry)
- req.get_response(self.test_auth)
- self.assertTrue(req.environ.get('reseller_request', False))
-
- def test_regular_is_not_owner(self):
- orig_authorize = self.test_auth.authorize
- owner_values = []
-
- def mitm_authorize(req):
- rv = orig_authorize(req)
- owner_values.append(req.environ.get('swift_owner', False))
- return rv
-
- self.test_auth.authorize = mitm_authorize
-
- req = self._make_request(
- '/v1/AUTH_cfa/c',
- headers={'X-Auth-Token': 'AUTH_t'})
- req.remote_user = 'act:usr'
- self.test_auth.authorize(req)
- self.assertEquals(owner_values, [False])
-
- def test_no_memcache(self):
- env = {'swift.cache': None}
- try:
- self.test_auth.get_groups(env, None)
- except Exception as e:
- self.assertTrue(e.args[0].startswith("Memcache required"))
-
- def test_handle_request(self):
- req = self._make_request('/auth/v1.0')
- resp = self.test_auth.handle_request(req)
- self.assertEquals(resp.status_int, REDIRECT_STATUS)
-
- def test_handle_request_bad_request(self):
- req = self._make_request('////')
- resp = self.test_auth.handle_request(req)
- self.assertEquals(resp.status_int, 404)
-
- def test_handle_request_no_handler(self):
- req = self._make_request('/blah/blah/blah/blah')
- resp = self.test_auth.handle_request(req)
- self.assertEquals(resp.status_int, 400)
-
- def test_handle_get_token_bad_request(self):
- req = self._make_request('/blah/blah')
- resp = self.test_auth.handle_get_token(req)
- self.assertEquals(resp.status_int, 400)
- req = self._make_request('/////')
- resp = self.test_auth.handle_get_token(req)
- self.assertEquals(resp.status_int, 404)
-
- def test_passive_handle_get_token_no_user_or_key(self):
- #No user and key
- req = self._make_request('/auth/v1.0')
- resp = self.test_auth_passive.handle_get_token(req)
- self.assertEquals(resp.status_int, REDIRECT_STATUS)
- #User given but no key
- req = self._make_request('/auth/v1.0',
- headers={'X-Auth-User': 'test:user'})
- resp = self.test_auth_passive.handle_get_token(req)
- self.assertEquals(resp.status_int, 401)
-
- def test_passive_handle_get_token_account_in_req_path(self):
- req = self._make_request('/v1/test/auth',
- headers={'X-Auth-User': 'test:user',
- 'X-Auth-Key': 'password'})
- _mock_run_kinit = Mock(return_value=0)
- _mock_get_groups = Mock(return_value="user,auth_test")
- with patch('gluster.swift.common.middleware.swiftkerbauth.kerbauth.run_kinit', _mock_run_kinit):
- with patch('gluster.swift.common.middleware.swiftkerbauth.kerbauth.get_groups_from_username',
- _mock_get_groups):
- resp = self.test_auth_passive.handle_get_token(req)
- _mock_run_kinit.assert_called_once_with('user', 'password')
- self.assertEquals(_mock_get_groups.call_count, 2)
- self.assertEquals(resp.status_int, 200)
- self.assertTrue(resp.headers['X-Auth-Token'] is not None)
- self.assertTrue(resp.headers['X-Storage-Token'] is not None)
- self.assertTrue(resp.headers['X-Storage-Url'] is not None)
-
- def test_passive_handle_get_token_user_invalid_or_no__account(self):
- #X-Auth-User not in acc:user format
- req = self._make_request('/auth/v1.0',
- headers={'X-Auth-User': 'user'})
- resp = self.test_auth_passive.handle_get_token(req)
- self.assertEquals(resp.status_int, 401)
- req = self._make_request('/v1/test/auth',
- headers={'X-Auth-User': 'user'})
- resp = self.test_auth_passive.handle_get_token(req)
- self.assertEquals(resp.status_int, 401)
- # Account name mismatch
- req = self._make_request('/v1/test/auth',
- headers={'X-Auth-User': 'wrongacc:user'})
- resp = self.test_auth_passive.handle_get_token(req)
- self.assertEquals(resp.status_int, 401)
-
- def test_passive_handle_get_token_no_kinit(self):
- req = self._make_request('/auth/v1.0',
- headers={'X-Auth-User': 'test:user',
- 'X-Auth-Key': 'password'})
- _mock_run_kinit = Mock(side_effect=OSError(errno.ENOENT,
- os.strerror(errno.ENOENT)))
- with patch('gluster.swift.common.middleware.swiftkerbauth.kerbauth.run_kinit', _mock_run_kinit):
- resp = self.test_auth_passive.handle_get_token(req)
- self.assertEquals(resp.status_int, 500)
- self.assertTrue("kinit command not found" in resp.body)
- _mock_run_kinit.assert_called_once_with('user', 'password')
-
- def test_passive_handle_get_token_kinit_fail(self):
- req = self._make_request('/auth/v1.0',
- headers={'X-Auth-User': 'test:user',
- 'X-Auth-Key': 'password'})
- _mock_run_kinit = Mock(return_value=1)
- with patch('gluster.swift.common.middleware.swiftkerbauth.kerbauth.run_kinit', _mock_run_kinit):
- resp = self.test_auth_passive.handle_get_token(req)
- self.assertEquals(resp.status_int, 401)
- _mock_run_kinit.assert_called_once_with('user', 'password')
-
- def test_passive_handle_get_token_kinit_success_token_not_present(self):
- req = self._make_request('/auth/v1.0',
- headers={'X-Auth-User': 'test:user',
- 'X-Auth-Key': 'password'})
- _mock_run_kinit = Mock(return_value=0)
- _mock_get_groups = Mock(return_value="user,auth_test")
- with patch('gluster.swift.common.middleware.swiftkerbauth.kerbauth.run_kinit', _mock_run_kinit):
- with patch('gluster.swift.common.middleware.swiftkerbauth.kerbauth.get_groups_from_username',
- _mock_get_groups):
- resp = self.test_auth_passive.handle_get_token(req)
- _mock_run_kinit.assert_called_once_with('user', 'password')
- self.assertEquals(_mock_get_groups.call_count, 2)
- self.assertEquals(resp.status_int, 200)
- self.assertTrue(resp.headers['X-Auth-Token'] is not None)
- self.assertTrue(resp.headers['X-Storage-Token'] is not None)
- self.assertTrue(resp.headers['X-Storage-Url'] is not None)
-
- def test_passive_handle_get_token_kinit_realm_and_memcache(self):
- req = self._make_request('/auth/v1.0',
- headers={'X-Auth-User': 'test:user',
- 'X-Auth-Key': 'password'})
- req.environ['swift.cache'] = None
- _auth_passive = \
- auth.filter_factory({'auth_method': 'passive',
- 'realm_name': 'EXAMPLE.COM'})(FakeApp())
- _mock_run_kinit = Mock(return_value=0)
- _mock_get_groups = Mock(return_value="user,auth_test")
- with patch('gluster.swift.common.middleware.swiftkerbauth.kerbauth.run_kinit', _mock_run_kinit):
- with patch('gluster.swift.common.middleware.swiftkerbauth.kerbauth.get_groups_from_username',
- _mock_get_groups):
- try:
- _auth_passive.handle_get_token(req)
- except Exception as e:
- self.assertTrue(e.args[0].startswith("Memcache "
- "required"))
- else:
- self.fail("Expected Exception - Memcache required")
- _mock_run_kinit.assert_called_once_with('user@EXAMPLE.COM', 'password')
- _mock_get_groups.assert_called_once_with('user')
-
- def test_passive_handle_get_token_user_in_any__account(self):
- req = self._make_request('/auth/v1.0',
- headers={'X-Auth-User': 'test:user',
- 'X-Auth-Key': 'password'})
- _mock_run_kinit = Mock(return_value=0)
- _mock_get_groups = Mock(return_value="user,auth_blah")
- with patch('gluster.swift.common.middleware.swiftkerbauth.kerbauth.run_kinit', _mock_run_kinit):
- with patch('gluster.swift.common.middleware.swiftkerbauth.kerbauth.get_groups_from_username',
- _mock_get_groups):
- resp = self.test_auth_passive.handle_get_token(req)
- self.assertEquals(resp.status_int, 401)
- _mock_run_kinit.assert_called_once_with('user', 'password')
- _mock_get_groups.assert_called_once_with('user')
-
- def test_handle(self):
- req = self._make_request('/auth/v1.0')
- resp = req.get_response(self.test_auth)
- self.assertEquals(resp.status_int, REDIRECT_STATUS)
-
- def test_authorize_invalid_req(self):
- req = self._make_request('/')
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp.status_int, 404)
-
- def test_authorize_set_swift_owner(self):
- req = self._make_request('/v1/AUTH_test/c1/o1')
- req.remote_user = 'test,auth_reseller_admin'
- resp = self.test_auth.authorize(req)
- self.assertEquals(req.environ['swift_owner'], True)
- self.assertTrue(resp is None)
- req = self._make_request('/v1/AUTH_test/c1/o1')
- req.remote_user = 'test,auth_test'
- resp = self.test_auth.authorize(req)
- self.assertEquals(req.environ['swift_owner'], True)
- self.assertTrue(resp is None)
-
- def test_authorize_swift_sync_key(self):
- req = self._make_request(
- '/v1/AUTH_cfa/c/o',
- environ={'swift_sync_key': 'secret'},
- headers={'x-container-sync-key': 'secret',
- 'x-timestamp': '123.456'})
- resp = self.test_auth.authorize(req)
- self.assertTrue(resp is None)
-
- def test_authorize_acl_referrer_access(self):
- req = self._make_request('/v1/AUTH_cfa/c')
- req.remote_user = 'act:usr,act'
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp.status_int, 403)
- req = self._make_request('/v1/AUTH_cfa/c')
- req.remote_user = 'act:usr,act'
- req.acl = '.r:*,.rlistings'
- self.assertEquals(self.test_auth.authorize(req), None)
- req = self._make_request('/v1/AUTH_cfa/c')
- req.remote_user = 'act:usr,act'
- req.acl = '.r:*' # No listings allowed
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp.status_int, 403)
- req = self._make_request('/v1/AUTH_cfa/c')
- req.remote_user = 'act:usr,act'
- req.acl = '.r:.example.com,.rlistings'
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp.status_int, 403)
- req = self._make_request('/v1/AUTH_cfa/c')
- req.remote_user = 'act:usr,act'
- req.referer = 'http://www.example.com/index.html'
- req.acl = '.r:.example.com,.rlistings'
- self.assertEquals(self.test_auth.authorize(req), None)
- req = self._make_request('/v1/AUTH_cfa/c')
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp.status_int, REDIRECT_STATUS)
- req = self._make_request('/v1/AUTH_cfa/c')
- req.acl = '.r:*,.rlistings'
- self.assertEquals(self.test_auth.authorize(req), None)
- req = self._make_request('/v1/AUTH_cfa/c')
- req.acl = '.r:*' # No listings allowed
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp.status_int, REDIRECT_STATUS)
- req = self._make_request('/v1/AUTH_cfa/c')
- req.acl = '.r:.example.com,.rlistings'
- resp = self.test_auth.authorize(req)
- self.assertEquals(resp.status_int, REDIRECT_STATUS)
- req = self._make_request('/v1/AUTH_cfa/c')
- req.referer = 'http://www.example.com/index.html'
- req.acl = '.r:.example.com,.rlistings'
- self.assertEquals(self.test_auth.authorize(req), None)
-
- def test_handle_x_storage_token(self):
- req = self._make_request(
- '/auth/v1.0',
- headers={'x-storage-token': 'blahblah', })
- resp = req.get_response(self.test_auth)
- self.assertEquals(resp.status_int, REDIRECT_STATUS)
-
- def test_invalid_token(self):
- req = self._make_request('/k1/test')
- req.environ['HTTP_X_AUTH_TOKEN'] = 'AUTH_blahblahblah'
- resp = req.get_response(self.test_auth)
- self.assertEquals(resp.status_int, REDIRECT_STATUS)
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/test/unit/common/middleware/swiftkerbauth/test_kerbauth_utils.py b/test/unit/common/middleware/swiftkerbauth/test_kerbauth_utils.py
deleted file mode 100644
index 2a4e90b..0000000
--- a/test/unit/common/middleware/swiftkerbauth/test_kerbauth_utils.py
+++ /dev/null
@@ -1,77 +0,0 @@
-# Copyright (c) 2013 Red Hat, Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-# implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import unittest
-import re
-from time import time
-from test.unit import FakeMemcache
-from gluster.swift.common.middleware.swiftkerbauth import kerbauth_utils as ku
-
-
-class TestKerbUtils(unittest.TestCase):
-
- def test_get_remote_user(self):
- env = {'REMOTE_USER': "auth_admin@EXAMPLE.COM"}
- result = ku.get_remote_user(env)
- self.assertEqual(result, "auth_admin")
-
- def test_get_remote_user_err(self):
- env = {'REMOTE_USER': "auth_admin"}
- try:
- ku.get_remote_user(env)
- except RuntimeError as err:
- self.assertTrue(err.args[0].startswith("Malformed REMOTE_USER"))
- else:
- self.fail("Expected RuntimeError")
-
- def test_get_auth_data(self):
- mc = FakeMemcache()
- expiry = time() + 100
- ku.set_auth_data(mc, "root", "AUTH_tk", expiry, "root,admin")
- (token, expires, groups) = ku.get_auth_data(mc, "root")
- self.assertEqual(("AUTH_tk", expiry, "root,admin"),
- (token, expires, groups))
-
- def test_get_auth_data_err(self):
- mc = FakeMemcache()
- (token, expires, groups) = ku.get_auth_data(mc, "root")
- self.assertEqual((token, expires, groups), (None, None, None))
-
- expiry = time() - 1
- ku.set_auth_data(mc, "root", "AUTH_tk", expiry, "root,admin")
- (token, expires, groups) = ku.get_auth_data(mc, "root")
- self.assertEqual((token, expires, groups), (None, None, None))
-
- def test_set_auth_data(self):
- mc = FakeMemcache()
- expiry = time() + 100
- ku.set_auth_data(mc, "root", "AUTH_tk", expiry, "root,admin")
-
- def test_generate_token(self):
- token = ku.generate_token()
- matches = re.match('AUTH_tk[a-f0-9]{32}', token)
- self.assertTrue(matches is not None)
-
- def test_get_groups_from_username(self):
- groups = ku.get_groups_from_username("root")
- self.assertTrue("root" in groups)
-
- def test_get_groups_from_username_err(self):
- try:
- ku.get_groups_from_username("Zroot")
- except RuntimeError as err:
- self.assertTrue(err.args[0].startswith("Failure running id -G"))
- else:
- self.fail("Expected RuntimeError")
diff --git a/test/unit/common/test_constraints.py b/test/unit/common/test_constraints.py
index 6c78d75..e8ddd69 100644
--- a/test/unit/common/test_constraints.py
+++ b/test/unit/common/test_constraints.py
@@ -57,10 +57,10 @@ class TestConstraints(unittest.TestCase):
cnt.set_object_name_component_length()
self.assertEqual(len, cnt.get_object_name_component_length())
- with patch('swift.common.constraints.constraints_conf_int',
- mock_constraints_conf_int):
- cnt.set_object_name_component_length()
- self.assertEqual(cnt.get_object_name_component_length(), 1000)
+ with patch('swift.common.constraints.constraints_conf_int',
+ mock_constraints_conf_int):
+ cnt.set_object_name_component_length()
+ self.assertEqual(cnt.get_object_name_component_length(), 1000)
def test_validate_obj_name_component(self):
max_obj_len = cnt.get_object_name_component_length()
@@ -75,65 +75,6 @@ class TestConstraints(unittest.TestCase):
self.assertTrue(cnt.validate_obj_name_component('..'))
self.assertTrue(cnt.validate_obj_name_component(''))
- def test_validate_headers(self):
- req = Mock()
- req.headers = []
- self.assertEqual(cnt.validate_headers(req), '')
- req.headers = ['x-some-header']
- self.assertEqual(cnt.validate_headers(req), '')
- #TODO: Although we now support x-delete-at and x-delete-after,
- #retained this test case as we may add some other header to
- #unsupported list in future
- raise SkipTest
- req.headers = ['x-delete-at', 'x-some-header']
- self.assertNotEqual(cnt.validate_headers(req), '')
- req.headers = ['x-delete-after', 'x-some-header']
- self.assertNotEqual(cnt.validate_headers(req), '')
- req.headers = ['x-delete-at', 'x-delete-after', 'x-some-header']
- self.assertNotEqual(cnt.validate_headers(req), '')
-
- def test_validate_headers_ignoring_config_set(self):
- with patch('gluster.swift.common.constraints.'
- 'Glusterfs._ignore_unsupported_headers', True):
- req = Mock()
- req.headers = []
- self.assertEqual(cnt.validate_headers(req), '')
- req.headers = ['x-some-header']
- self.assertEqual(cnt.validate_headers(req), '')
- #TODO: Although we now support x-delete-at and x-delete-after,
- #retained this test case as we may add some other header to
- #unsupported list in future
- raise SkipTest
- req.headers = ['x-delete-at', 'x-some-header']
- self.assertEqual(cnt.validate_headers(req), '')
- req.headers = ['x-delete-after', 'x-some-header']
- self.assertEqual(cnt.validate_headers(req), '')
- req.headers = ['x-delete-at', 'x-delete-after', 'x-some-header']
- self.assertEqual(cnt.validate_headers(req), '')
-
- def test_gluster_check_metadata(self):
- mock_check_metadata = Mock()
- with patch('gluster.swift.common.constraints.__check_metadata',
- mock_check_metadata):
- req = Mock()
- req.headers = []
- cnt.gluster_check_metadata(req, 'object')
- self.assertTrue(1, mock_check_metadata.call_count)
- cnt.gluster_check_metadata(req, 'object', POST=False)
- self.assertTrue(1, mock_check_metadata.call_count)
- req.headers = ['x-some-header']
- self.assertEqual(cnt.gluster_check_metadata(req, 'object', POST=False), None)
- #TODO: Although we now support x-delete-at and x-delete-after,
- #retained this test case as we may add some other header to
- #unsupported list in future
- raise SkipTest
- req.headers = ['x-delete-at', 'x-some-header']
- self.assertNotEqual(cnt.gluster_check_metadata(req, 'object', POST=False), None)
- req.headers = ['x-delete-after', 'x-some-header']
- self.assertNotEqual(cnt.gluster_check_metadata(req, 'object', POST=False), None)
- req.headers = ['x-delete-at', 'x-delete-after', 'x-some-header']
- self.assertNotEqual(cnt.gluster_check_metadata(req, 'object', POST=False), None)
-
def test_gluster_check_object_creation(self):
with patch('gluster.swift.common.constraints.__check_object_creation',
mock_check_object_creation):
@@ -147,9 +88,3 @@ class TestConstraints(unittest.TestCase):
req = Mock()
req.headers = []
self.assertTrue(cnt.gluster_check_object_creation(req, 'dir/.'))
- #TODO: Although we now support x-delete-at and x-delete-after,
- #retained this test case as we may add some other header to
- #unsupported list in future
- raise SkipTest
- req.headers = ['x-delete-at']
- self.assertTrue(cnt.gluster_check_object_creation(req, 'dir/z'))
diff --git a/test/unit/common/test_diskdir.py b/test/unit/common/test_diskdir.py
index f32c3ad..ebc554a 100644
--- a/test/unit/common/test_diskdir.py
+++ b/test/unit/common/test_diskdir.py
@@ -408,7 +408,7 @@ class TestContainerBroker(unittest.TestCase):
self.assertEqual(os.path.basename(broker.db_file), 'db_file.db')
broker.initialize(self.initial_ts)
self.assertTrue(os.path.isdir(self.container))
- self.assertEquals(self.initial_ts, broker.metadata[utils.X_TIMESTAMP])
+ self.assertEquals(self.initial_ts, broker.metadata[utils.X_TIMESTAMP][0])
self.assertFalse(broker.is_deleted())
def test_creation_existing(self):
@@ -419,7 +419,7 @@ class TestContainerBroker(unittest.TestCase):
self.assertEqual(os.path.basename(broker.db_file), 'db_file.db')
broker.initialize(self.initial_ts)
self.assertTrue(os.path.isdir(self.container))
- self.assertEquals(self.initial_ts, broker.metadata[utils.X_TIMESTAMP])
+ self.assertEquals(self.initial_ts, broker.metadata[utils.X_TIMESTAMP][0])
self.assertFalse(broker.is_deleted())
def test_creation_existing_bad_metadata(self):
@@ -432,7 +432,7 @@ class TestContainerBroker(unittest.TestCase):
self.assertEqual(os.path.basename(broker.db_file), 'db_file.db')
broker.initialize(self.initial_ts)
self.assertTrue(os.path.isdir(self.container))
- self.assertEquals(self.initial_ts, broker.metadata[utils.X_TIMESTAMP])
+ self.assertEquals(self.initial_ts, broker.metadata[utils.X_TIMESTAMP][0])
self.assertFalse(broker.is_deleted())
def test_empty(self):
@@ -954,7 +954,7 @@ class TestContainerBroker(unittest.TestCase):
self.assertEqual(os.path.basename(broker.db_file), 'db_file.db')
broker.initialize(self.initial_ts)
self.assertTrue(os.path.isdir(self.container))
- self.assertEquals(self.initial_ts, broker.metadata[utils.X_TIMESTAMP])
+ self.assertEquals(self.initial_ts, broker.metadata[utils.X_TIMESTAMP][0])
self.assertFalse(broker.is_deleted())
broker.delete_db(normalize_timestamp(time()))
self.assertTrue(broker.is_deleted())
@@ -1005,7 +1005,7 @@ class TestAccountBroker(unittest.TestCase):
self.assertEqual(os.path.basename(broker.db_file), 'db_file.db')
broker.initialize(self.initial_ts)
self.assertTrue(os.path.isdir(self.drive_fullpath))
- self.assertEquals(self.initial_ts, broker.metadata[utils.X_TIMESTAMP])
+ self.assertEquals(self.initial_ts, broker.metadata[utils.X_TIMESTAMP][0])
self.assertFalse(broker.is_deleted())
def test_creation_bad_metadata(self):
@@ -1016,7 +1016,7 @@ class TestAccountBroker(unittest.TestCase):
self.assertEqual(os.path.basename(broker.db_file), 'db_file.db')
broker.initialize(self.initial_ts)
self.assertTrue(os.path.isdir(self.drive_fullpath))
- self.assertEquals(self.initial_ts, broker.metadata[utils.X_TIMESTAMP])
+ self.assertEquals(self.initial_ts, broker.metadata[utils.X_TIMESTAMP][0])
self.assertFalse(broker.is_deleted())
def test_empty(self):
@@ -1219,7 +1219,7 @@ class TestAccountBroker(unittest.TestCase):
self.assertEqual(os.path.basename(broker.db_file), 'db_file.db')
broker.initialize(self.initial_ts)
self.assertTrue(os.path.isdir(self.drive_fullpath))
- self.assertEquals(self.initial_ts, broker.metadata[utils.X_TIMESTAMP])
+ self.assertEquals(self.initial_ts, broker.metadata[utils.X_TIMESTAMP][0])
self.assertFalse(broker.is_deleted())
broker.delete_db(normalize_timestamp(time()))
# Deleting the "db" should be a NOOP
diff --git a/test/unit/common/test_utils.py b/test/unit/common/test_utils.py
index dd03bd8..55bd0cf 100644
--- a/test/unit/common/test_utils.py
+++ b/test/unit/common/test_utils.py
@@ -25,9 +25,10 @@ import hashlib
import tarfile
import shutil
from collections import defaultdict
-from mock import patch
+from mock import patch, Mock
from gluster.swift.common import utils, Glusterfs
-from gluster.swift.common.exceptions import GlusterFileSystemOSError
+from gluster.swift.common.exceptions import GlusterFileSystemOSError,\
+ GlusterFileSystemIOError
from swift.common.exceptions import DiskFileNoSpace
#
@@ -712,6 +713,18 @@ class TestUtils(unittest.TestCase):
ret = utils.validate_object(md)
assert ret
+ def test_validate_object_with_stat(self):
+ md = {utils.X_TIMESTAMP: 'na',
+ utils.X_CONTENT_TYPE: 'na',
+ utils.X_ETAG: 'bad',
+ utils.X_CONTENT_LENGTH: '12345',
+ utils.X_TYPE: utils.OBJECT,
+ utils.X_OBJECT_TYPE: 'na'}
+ fake_stat = Mock(st_size=12346)
+ self.assertFalse(utils.validate_object(md, fake_stat))
+ fake_stat = Mock(st_size=12345)
+ self.assertTrue(utils.validate_object(md, fake_stat))
+
class TestUtilsDirObjects(unittest.TestCase):
@@ -794,7 +807,8 @@ class TestUtilsDirObjects(unittest.TestCase):
def _mock_rm(path):
print "_mock_rm-metadata_enoent(%s)" % path
shutil.rmtree(path)
- raise OSError(errno.ENOENT, os.strerror(errno.ENOENT))
+ raise GlusterFileSystemIOError(errno.ENOENT,
+ os.strerror(errno.ENOENT))
# Remove the files
for f in self.files:
@@ -805,8 +819,8 @@ class TestUtilsDirObjects(unittest.TestCase):
try:
try:
self.assertTrue(utils.rmobjdir(self.rootdir))
- except OSError:
- self.fail("Unexpected OSError")
+ except IOError:
+ self.fail("Unexpected IOError")
else:
pass
finally:
diff --git a/test/unit/obj/test_diskfile.py b/test/unit/obj/test_diskfile.py
index f8c26db..1fe0904 100644
--- a/test/unit/obj/test_diskfile.py
+++ b/test/unit/obj/test_diskfile.py
@@ -223,7 +223,7 @@ class TestDiskFile(unittest.TestCase):
ini_md = {
'X-Type': 'Object',
'X-Object-Type': 'file',
- 'Content-Length': 5,
+ 'Content-Length': 4,
'ETag': 'etag',
'X-Timestamp': 'ts',
'Content-Type': 'application/loctet-stream'}
@@ -283,9 +283,8 @@ class TestDiskFile(unittest.TestCase):
with gdf.open():
assert gdf._is_dir
assert gdf._data_file == the_dir
- assert gdf._metadata == exp_md
- def _create_and_get_diskfile(self, dev, par, acc, con, obj):
+ def _create_and_get_diskfile(self, dev, par, acc, con, obj, fsize=256):
# FIXME: assumes account === volume
the_path = os.path.join(self.td, dev, con)
the_file = os.path.join(the_path, obj)
@@ -293,7 +292,7 @@ class TestDiskFile(unittest.TestCase):
base_dir = os.path.dirname(the_file)
os.makedirs(base_dir)
with open(the_file, "wb") as fd:
- fd.write("y" * 256)
+ fd.write("y" * fsize)
gdf = self._get_diskfile(dev, par, acc, con, obj)
assert gdf._obj == base_obj
assert not gdf._is_dir
@@ -353,6 +352,26 @@ class TestDiskFile(unittest.TestCase):
assert len(chunks) == 1, repr(chunks)
assert called[0] == 1, called
+ def test_reader_larger_file(self):
+ closed = [False]
+ fd = [-1]
+
+ def mock_close(*args, **kwargs):
+ closed[0] = True
+ os.close(fd[0])
+
+ with mock.patch("gluster.swift.obj.diskfile.do_close", mock_close):
+ gdf = self._create_and_get_diskfile("vol0", "p57", "ufo47", "bar", "z", fsize=1024*1024*2)
+ with gdf.open():
+ assert gdf._fd is not None
+ assert gdf._data_file == os.path.join(self.td, "vol0", "bar", "z")
+ reader = gdf.reader()
+ assert reader._fd is not None
+ fd[0] = reader._fd
+ chunks = [ck for ck in reader]
+ assert reader._fd is None
+ assert closed[0]
+
def test_reader_dir_object(self):
called = [False]
@@ -926,3 +945,31 @@ class TestDiskFile(unittest.TestCase):
dw.write("123")
os.unlink(saved_tmppath)
assert not os.path.exists(saved_tmppath)
+
+ def test_unlink_not_called_after_rename(self):
+ the_obj_path = os.path.join("b", "a")
+ the_file = os.path.join(the_obj_path, "z")
+ gdf = self._get_diskfile("vol0", "p57", "ufo47", "bar", the_file)
+
+ body = '1234\n'
+ etag = md5(body).hexdigest()
+ metadata = {
+ 'X-Timestamp': '1234',
+ 'Content-Type': 'file',
+ 'ETag': etag,
+ 'Content-Length': '5',
+ }
+
+ _mock_do_unlink = Mock() # Shouldn't be called
+ with patch("gluster.swift.obj.diskfile.do_unlink", _mock_do_unlink):
+ with gdf.create() as dw:
+ assert dw._tmppath is not None
+ tmppath = dw._tmppath
+ dw.write(body)
+ dw.put(metadata)
+ # do_unlink is not called if dw._tmppath is set to None
+ assert dw._tmppath is None
+ self.assertFalse(_mock_do_unlink.called)
+
+ assert os.path.exists(gdf._data_file) # Real file exists
+ assert not os.path.exists(tmppath) # Temp file does not exist
diff --git a/test/unit/obj/test_expirer.py b/test/unit/obj/test_expirer.py
index 4329eef..236775e 100644
--- a/test/unit/obj/test_expirer.py
+++ b/test/unit/obj/test_expirer.py
@@ -46,7 +46,7 @@ class TestObjectExpirer(TestCase):
self.old_loadapp = internal_client.loadapp
self.old_sleep = internal_client.sleep
- internal_client.loadapp = lambda x: None
+ internal_client.loadapp = lambda *a, **kw: None
internal_client.sleep = not_sleep
def teardown(self):
@@ -618,7 +618,7 @@ class TestObjectExpirer(TestCase):
start_response('204 No Content', [('Content-Length', '0')])
return []
- internal_client.loadapp = lambda x: fake_app
+ internal_client.loadapp = lambda *a, **kw: fake_app
x = expirer.ObjectExpirer({})
ts = '1234'
@@ -635,7 +635,7 @@ class TestObjectExpirer(TestCase):
start_response('204 No Content', [('Content-Length', '0')])
return []
- internal_client.loadapp = lambda x: fake_app
+ internal_client.loadapp = lambda *a, **kw: fake_app
x = expirer.ObjectExpirer({})
ts = '1234'
@@ -649,7 +649,7 @@ class TestObjectExpirer(TestCase):
start_response('404 Not Found', [('Content-Length', '0')])
return []
- internal_client.loadapp = lambda x: fake_app
+ internal_client.loadapp = lambda *a, **kw: fake_app
x = expirer.ObjectExpirer({})
x.delete_actual_object('/path/to/object', '1234')
@@ -661,7 +661,7 @@ class TestObjectExpirer(TestCase):
[('Content-Length', '0')])
return []
- internal_client.loadapp = lambda x: fake_app
+ internal_client.loadapp = lambda *a, **kw: fake_app
x = expirer.ObjectExpirer({})
x.delete_actual_object('/path/to/object', '1234')
@@ -674,7 +674,7 @@ class TestObjectExpirer(TestCase):
[('Content-Length', '0')])
return []
- internal_client.loadapp = lambda x: fake_app
+ internal_client.loadapp = lambda *a, **kw: fake_app
x = expirer.ObjectExpirer({})
exc = None
@@ -692,7 +692,7 @@ class TestObjectExpirer(TestCase):
x = expirer.ObjectExpirer({})
x.swift.make_request = mock.MagicMock()
x.delete_actual_object(name, timestamp)
- x.swift.make_request.assert_called_once()
+ self.assertTrue(x.swift.make_request.called)
self.assertEqual(x.swift.make_request.call_args[0][1],
'/v1/' + urllib.quote(name))
diff --git a/test/unit/proxy/controllers/test_obj.py b/test/unit/proxy/controllers/test_obj.py
index aada616..4942691 100755
--- a/test/unit/proxy/controllers/test_obj.py
+++ b/test/unit/proxy/controllers/test_obj.py
@@ -22,7 +22,7 @@ import mock
import swift
from swift.proxy import server as proxy_server
from swift.common.swob import HTTPException
-from test.unit import FakeRing, FakeMemcache, fake_http_connect
+from test.unit import FakeRing, FakeMemcache, fake_http_connect, debug_logger
@contextmanager
@@ -90,26 +90,96 @@ class TestObjControllerWriteAffinity(unittest.TestCase):
class TestObjController(unittest.TestCase):
+ def setUp(self):
+ logger = debug_logger('proxy-server')
+ logger.thread_locals = ('txn1', '127.0.0.2')
+ self.app = proxy_server.Application(
+ None, FakeMemcache(), account_ring=FakeRing(),
+ container_ring=FakeRing(), object_ring=FakeRing(),
+ logger=logger)
+ self.controller = proxy_server.ObjectController(self.app,
+ 'a', 'c', 'o')
+ self.controller.container_info = mock.MagicMock(return_value={
+ 'partition': 1,
+ 'nodes': [
+ {'ip': '127.0.0.1', 'port': '1', 'device': 'sda'},
+ {'ip': '127.0.0.1', 'port': '2', 'device': 'sda'},
+ {'ip': '127.0.0.1', 'port': '3', 'device': 'sda'},
+ ],
+ 'write_acl': None,
+ 'read_acl': None,
+ 'sync_key': None,
+ 'versions': None})
+
+ def test_PUT_simple(self):
+ req = swift.common.swob.Request.blank('/v1/a/c/o')
+ req.headers['content-length'] = '0'
+ with set_http_connect(201, 201, 201):
+ resp = self.controller.PUT(req)
+ self.assertEquals(resp.status_int, 201)
+
+ def test_PUT_if_none_match(self):
+ req = swift.common.swob.Request.blank('/v1/a/c/o')
+ req.headers['if-none-match'] = '*'
+ req.headers['content-length'] = '0'
+ with set_http_connect(201, 201, 201):
+ resp = self.controller.PUT(req)
+ self.assertEquals(resp.status_int, 201)
+
+ def test_PUT_if_none_match_denied(self):
+ req = swift.common.swob.Request.blank('/v1/a/c/o')
+ req.headers['if-none-match'] = '*'
+ req.headers['content-length'] = '0'
+ with set_http_connect(201, (412, 412), 201):
+ resp = self.controller.PUT(req)
+ self.assertEquals(resp.status_int, 412)
+
+ def test_PUT_if_none_match_not_star(self):
+ req = swift.common.swob.Request.blank('/v1/a/c/o')
+ req.headers['if-none-match'] = 'somethingelse'
+ req.headers['content-length'] = '0'
+ with set_http_connect(201, 201, 201):
+ resp = self.controller.PUT(req)
+ self.assertEquals(resp.status_int, 400)
+
+ def test_GET_simple(self):
+ req = swift.common.swob.Request.blank('/v1/a/c/o')
+ with set_http_connect(200):
+ resp = self.controller.GET(req)
+ self.assertEquals(resp.status_int, 200)
+
+ def test_DELETE_simple(self):
+ req = swift.common.swob.Request.blank('/v1/a/c/o')
+ with set_http_connect(204, 204, 204):
+ resp = self.controller.DELETE(req)
+ self.assertEquals(resp.status_int, 204)
+
+ def test_POST_simple(self):
+ req = swift.common.swob.Request.blank('/v1/a/c/o')
+ with set_http_connect(200, 200, 200, 201, 201, 201):
+ resp = self.controller.POST(req)
+ self.assertEquals(resp.status_int, 202)
+
+ def test_COPY_simple(self):
+ req = swift.common.swob.Request.blank('/v1/a/c/o')
+ with set_http_connect(200, 200, 200, 201, 201, 201):
+ resp = self.controller.POST(req)
+ self.assertEquals(resp.status_int, 202)
+
+ def test_HEAD_simple(self):
+ req = swift.common.swob.Request.blank('/v1/a/c/o')
+ with set_http_connect(200, 200, 200, 201, 201, 201):
+ resp = self.controller.POST(req)
+ self.assertEquals(resp.status_int, 202)
def test_PUT_log_info(self):
# mock out enough to get to the area of the code we want to test
with mock.patch('swift.proxy.controllers.obj.check_object_creation',
mock.MagicMock(return_value=None)):
- app = mock.MagicMock()
- app.container_ring.get_nodes.return_value = (1, [2])
- app.object_ring.get_nodes.return_value = (1, [2])
- controller = proxy_server.ObjectController(app, 'a', 'c', 'o')
- controller.container_info = mock.MagicMock(return_value={
- 'partition': 1,
- 'nodes': [{}],
- 'write_acl': None,
- 'sync_key': None,
- 'versions': None})
- # and now test that we add the header to log_info
req = swift.common.swob.Request.blank('/v1/a/c/o')
req.headers['x-copy-from'] = 'somewhere'
try:
- controller.PUT(req)
+ self.controller.PUT(req)
except HTTPException:
pass
self.assertEquals(
@@ -119,7 +189,7 @@ class TestObjController(unittest.TestCase):
req.method = 'POST'
req.headers['x-copy-from'] = 'elsewhere'
try:
- controller.PUT(req)
+ self.controller.PUT(req)
except HTTPException:
pass
self.assertEquals(req.environ.get('swift.log_info'), None)
diff --git a/test/unit/proxy/test_server.py b/test/unit/proxy/test_server.py
index 0cb2278..1a59016 100644
--- a/test/unit/proxy/test_server.py
+++ b/test/unit/proxy/test_server.py
@@ -30,6 +30,7 @@ from urllib import quote
from hashlib import md5
from tempfile import mkdtemp
import weakref
+import re
import mock
from eventlet import sleep, spawn, wsgi, listen
@@ -60,7 +61,8 @@ from swift.proxy.controllers.base import get_container_memcache_key, \
get_account_memcache_key, cors_validation
import swift.proxy.controllers
from swift.common.request_helpers import get_sys_meta_prefix
-from swift.common.swob import Request, Response, HTTPUnauthorized
+from swift.common.swob import Request, Response, HTTPUnauthorized, \
+ HTTPException
# mocks
logging.getLogger().addHandler(logging.StreamHandler(sys.stdout))
@@ -245,6 +247,7 @@ def set_http_connect(*args, **kwargs):
swift.proxy.controllers.obj.http_connect = new_connect
swift.proxy.controllers.account.http_connect = new_connect
swift.proxy.controllers.container.http_connect = new_connect
+ return new_connect
# tests
@@ -692,10 +695,10 @@ class TestObjectController(unittest.TestCase):
def setUp(self):
self.app = proxy_server.Application(None, FakeMemcache(),
+ logger=debug_logger('proxy-ut'),
account_ring=FakeRing(),
container_ring=FakeRing(),
object_ring=FakeRing())
- monkey_patch_mimetools()
def tearDown(self):
self.app.account_ring.set_replicas(3)
@@ -802,6 +805,7 @@ class TestObjectController(unittest.TestCase):
self.app.update_request(req)
self.app.memcache.store = {}
res = controller.PUT(req)
+ self.assertEqual(test_errors, [])
self.assertTrue(res.status.startswith('201 '))
def test_PUT_respects_write_affinity(self):
@@ -1609,7 +1613,7 @@ class TestObjectController(unittest.TestCase):
dev['ip'] = '127.0.0.1'
dev['port'] = 1
- class SlowBody():
+ class SlowBody(object):
def __init__(self):
self.sent = 0
@@ -1658,7 +1662,7 @@ class TestObjectController(unittest.TestCase):
dev['ip'] = '127.0.0.1'
dev['port'] = 1
- class SlowBody():
+ class SlowBody(object):
def __init__(self):
self.sent = 0
@@ -1693,7 +1697,7 @@ class TestObjectController(unittest.TestCase):
dev['port'] = 1
req = Request.blank('/v1/a/c/o', environ={'REQUEST_METHOD': 'GET'})
self.app.update_request(req)
- set_http_connect(200, 200, 200, slow=True)
+ set_http_connect(200, 200, 200, slow=0.1)
req.sent_size = 0
resp = req.get_response(self.app)
got_exc = False
@@ -1703,7 +1707,7 @@ class TestObjectController(unittest.TestCase):
got_exc = True
self.assert_(not got_exc)
self.app.recoverable_node_timeout = 0.1
- set_http_connect(200, 200, 200, slow=True)
+ set_http_connect(200, 200, 200, slow=1.0)
resp = req.get_response(self.app)
got_exc = False
try:
@@ -1718,16 +1722,17 @@ class TestObjectController(unittest.TestCase):
self.app.update_request(req)
self.app.recoverable_node_timeout = 0.1
- set_http_connect(200, 200, 200, slow=[3])
+ set_http_connect(200, 200, 200, slow=[1.0, 1.0, 1.0])
resp = req.get_response(self.app)
got_exc = False
try:
- resp.body
+ self.assertEquals('', resp.body)
except ChunkReadTimeout:
got_exc = True
self.assert_(got_exc)
- set_http_connect(200, 200, 200, body='lalala', slow=[2])
+ set_http_connect(200, 200, 200, body='lalala',
+ slow=[1.0, 1.0])
resp = req.get_response(self.app)
got_exc = False
try:
@@ -1736,8 +1741,8 @@ class TestObjectController(unittest.TestCase):
got_exc = True
self.assert_(not got_exc)
- set_http_connect(200, 200, 200, body='lalala', slow=[2],
- etags=['a', 'a', 'a'])
+ set_http_connect(200, 200, 200, body='lalala',
+ slow=[1.0, 1.0], etags=['a', 'a', 'a'])
resp = req.get_response(self.app)
got_exc = False
try:
@@ -1746,8 +1751,8 @@ class TestObjectController(unittest.TestCase):
got_exc = True
self.assert_(not got_exc)
- set_http_connect(200, 200, 200, body='lalala', slow=[2],
- etags=['a', 'b', 'a'])
+ set_http_connect(200, 200, 200, body='lalala',
+ slow=[1.0, 1.0], etags=['a', 'b', 'a'])
resp = req.get_response(self.app)
got_exc = False
try:
@@ -1757,8 +1762,8 @@ class TestObjectController(unittest.TestCase):
self.assert_(not got_exc)
req = Request.blank('/v1/a/c/o', environ={'REQUEST_METHOD': 'GET'})
- set_http_connect(200, 200, 200, body='lalala', slow=[2],
- etags=['a', 'b', 'b'])
+ set_http_connect(200, 200, 200, body='lalala',
+ slow=[1.0, 1.0], etags=['a', 'b', 'b'])
resp = req.get_response(self.app)
got_exc = False
try:
@@ -1787,17 +1792,17 @@ class TestObjectController(unittest.TestCase):
'Content-Type': 'text/plain'},
body=' ')
self.app.update_request(req)
- set_http_connect(200, 200, 201, 201, 201, slow=True)
+ set_http_connect(200, 200, 201, 201, 201, slow=0.1)
resp = req.get_response(self.app)
self.assertEquals(resp.status_int, 201)
self.app.node_timeout = 0.1
- set_http_connect(201, 201, 201, slow=True)
req = Request.blank('/v1/a/c/o',
environ={'REQUEST_METHOD': 'PUT'},
headers={'Content-Length': '4',
'Content-Type': 'text/plain'},
body=' ')
self.app.update_request(req)
+ set_http_connect(201, 201, 201, slow=1.0)
resp = req.get_response(self.app)
self.assertEquals(resp.status_int, 503)
@@ -2227,307 +2232,322 @@ class TestObjectController(unittest.TestCase):
resp = controller.PUT(req)
self.assertEquals(resp.status_int, 400)
- def test_copy_from(self):
+ @contextmanager
+ def controller_context(self, req, *args, **kwargs):
+ _v, account, container, obj = utils.split_path(req.path, 4, 4, True)
+ controller = proxy_server.ObjectController(self.app, account,
+ container, obj)
+ self.app.update_request(req)
+ self.app.memcache.store = {}
with save_globals():
- controller = proxy_server.ObjectController(self.app, 'account',
- 'container', 'object')
- # initial source object PUT
- req = Request.blank('/v1/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
- headers={'Content-Length': '0'})
- self.app.update_request(req)
- set_http_connect(200, 200, 201, 201, 201)
- # acct cont obj obj obj
+ new_connect = set_http_connect(*args, **kwargs)
+ yield controller
+ unused_status_list = []
+ while True:
+ try:
+ unused_status_list.append(new_connect.code_iter.next())
+ except StopIteration:
+ break
+ if unused_status_list:
+ raise self.fail('UN-USED STATUS CODES: %r' %
+ unused_status_list)
+
+ def test_basic_put_with_x_copy_from(self):
+ req = Request.blank('/v1/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
+ headers={'Content-Length': '0',
+ 'X-Copy-From': 'c/o'})
+ status_list = (200, 200, 200, 200, 200, 201, 201, 201)
+ # acct cont objc objc objc obj obj obj
+ with self.controller_context(req, *status_list) as controller:
resp = controller.PUT(req)
- self.assertEquals(resp.status_int, 201)
+ self.assertEquals(resp.status_int, 201)
+ self.assertEquals(resp.headers['x-copied-from'], 'c/o')
- # basic copy
- req = Request.blank('/v1/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
- headers={'Content-Length': '0',
- 'X-Copy-From': 'c/o'})
- self.app.update_request(req)
- set_http_connect(200, 200, 200, 200, 200, 200, 200, 201, 201, 201)
- # acct cont acct cont objc objc objc obj obj obj
- self.app.memcache.store = {}
+ def test_basic_put_with_x_copy_from_across_container(self):
+ req = Request.blank('/v1/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
+ headers={'Content-Length': '0',
+ 'X-Copy-From': 'c2/o'})
+ status_list = (200, 200, 200, 200, 200, 200, 201, 201, 201)
+ # acct cont conc objc objc objc obj obj obj
+ with self.controller_context(req, *status_list) as controller:
resp = controller.PUT(req)
- self.assertEquals(resp.status_int, 201)
- self.assertEquals(resp.headers['x-copied-from'], 'c/o')
+ self.assertEquals(resp.status_int, 201)
+ self.assertEquals(resp.headers['x-copied-from'], 'c2/o')
- # non-zero content length
- req = Request.blank('/v1/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
- headers={'Content-Length': '5',
- 'X-Copy-From': 'c/o'})
- self.app.update_request(req)
- set_http_connect(200, 200, 200, 200, 200, 200, 200)
- # acct cont acct cont objc objc objc
- self.app.memcache.store = {}
+ def test_copy_non_zero_content_length(self):
+ req = Request.blank('/v1/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
+ headers={'Content-Length': '5',
+ 'X-Copy-From': 'c/o'})
+ status_list = (200, 200)
+ # acct cont
+ with self.controller_context(req, *status_list) as controller:
resp = controller.PUT(req)
- self.assertEquals(resp.status_int, 400)
+ self.assertEquals(resp.status_int, 400)
- # extra source path parsing
- req = Request.blank('/v1/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
- headers={'Content-Length': '0',
- 'X-Copy-From': 'c/o/o2'})
- req.account = 'a'
- set_http_connect(200, 200, 200, 200, 200, 200, 200, 201, 201, 201)
- # acct cont acct cont objc objc objc obj obj obj
- self.app.memcache.store = {}
+ def test_copy_with_slashes_in_x_copy_from(self):
+ # extra source path parsing
+ req = Request.blank('/v1/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
+ headers={'Content-Length': '0',
+ 'X-Copy-From': 'c/o/o2'})
+ status_list = (200, 200, 200, 200, 200, 201, 201, 201)
+ # acct cont objc objc objc obj obj obj
+ with self.controller_context(req, *status_list) as controller:
resp = controller.PUT(req)
- self.assertEquals(resp.status_int, 201)
- self.assertEquals(resp.headers['x-copied-from'], 'c/o/o2')
+ self.assertEquals(resp.status_int, 201)
+ self.assertEquals(resp.headers['x-copied-from'], 'c/o/o2')
- # space in soure path
- req = Request.blank('/v1/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
- headers={'Content-Length': '0',
- 'X-Copy-From': 'c/o%20o2'})
- req.account = 'a'
- set_http_connect(200, 200, 200, 200, 200, 200, 200, 201, 201, 201)
- # acct cont acct cont objc objc objc obj obj obj
- self.app.memcache.store = {}
+ def test_copy_with_spaces_in_x_copy_from(self):
+ # space in soure path
+ req = Request.blank('/v1/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
+ headers={'Content-Length': '0',
+ 'X-Copy-From': 'c/o%20o2'})
+ status_list = (200, 200, 200, 200, 200, 201, 201, 201)
+ # acct cont objc objc objc obj obj obj
+ with self.controller_context(req, *status_list) as controller:
resp = controller.PUT(req)
- self.assertEquals(resp.status_int, 201)
- self.assertEquals(resp.headers['x-copied-from'], 'c/o%20o2')
+ self.assertEquals(resp.status_int, 201)
+ self.assertEquals(resp.headers['x-copied-from'], 'c/o%20o2')
- # repeat tests with leading /
- req = Request.blank('/v1/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
- headers={'Content-Length': '0',
- 'X-Copy-From': '/c/o'})
- self.app.update_request(req)
- set_http_connect(200, 200, 200, 200, 200, 200, 200, 201, 201, 201)
- # acct cont acct cont objc objc objc obj obj obj
- self.app.memcache.store = {}
+ def test_copy_with_leading_slash_in_x_copy_from(self):
+ # repeat tests with leading /
+ req = Request.blank('/v1/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
+ headers={'Content-Length': '0',
+ 'X-Copy-From': '/c/o'})
+ status_list = (200, 200, 200, 200, 200, 201, 201, 201)
+ # acct cont objc objc objc obj obj obj
+ with self.controller_context(req, *status_list) as controller:
resp = controller.PUT(req)
- self.assertEquals(resp.status_int, 201)
- self.assertEquals(resp.headers['x-copied-from'], 'c/o')
+ self.assertEquals(resp.status_int, 201)
+ self.assertEquals(resp.headers['x-copied-from'], 'c/o')
- req = Request.blank('/v1/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
- headers={'Content-Length': '0',
- 'X-Copy-From': '/c/o/o2'})
- req.account = 'a'
- set_http_connect(200, 200, 200, 200, 200, 200, 200, 201, 201, 201)
- # acct cont acct cont objc objc objc obj obj obj
- self.app.memcache.store = {}
+ def test_copy_with_leading_slash_and_slashes_in_x_copy_from(self):
+ req = Request.blank('/v1/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
+ headers={'Content-Length': '0',
+ 'X-Copy-From': '/c/o/o2'})
+ status_list = (200, 200, 200, 200, 200, 201, 201, 201)
+ # acct cont objc objc objc obj obj obj
+ with self.controller_context(req, *status_list) as controller:
resp = controller.PUT(req)
- self.assertEquals(resp.status_int, 201)
- self.assertEquals(resp.headers['x-copied-from'], 'c/o/o2')
+ self.assertEquals(resp.status_int, 201)
+ self.assertEquals(resp.headers['x-copied-from'], 'c/o/o2')
- # negative tests
+ def test_copy_with_no_object_in_x_copy_from(self):
+ req = Request.blank('/v1/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
+ headers={'Content-Length': '0',
+ 'X-Copy-From': '/c'})
+ status_list = (200, 200)
+ # acct cont
+ with self.controller_context(req, *status_list) as controller:
+ try:
+ controller.PUT(req)
+ except HTTPException as resp:
+ self.assertEquals(resp.status_int // 100, 4) # client error
+ else:
+ raise self.fail('Invalid X-Copy-From did not raise '
+ 'client error')
- # invalid x-copy-from path
- req = Request.blank('/v1/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
- headers={'Content-Length': '0',
- 'X-Copy-From': '/c'})
- self.app.update_request(req)
- self.app.memcache.store = {}
+ def test_copy_server_error_reading_source(self):
+ req = Request.blank('/v1/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
+ headers={'Content-Length': '0',
+ 'X-Copy-From': '/c/o'})
+ status_list = (200, 200, 503, 503, 503)
+ # acct cont objc objc objc
+ with self.controller_context(req, *status_list) as controller:
resp = controller.PUT(req)
- self.assertEquals(resp.status_int // 100, 4) # client error
+ self.assertEquals(resp.status_int, 503)
- # server error
- req = Request.blank('/v1/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
- headers={'Content-Length': '0',
- 'X-Copy-From': '/c/o'})
- self.app.update_request(req)
- set_http_connect(200, 200, 503, 503, 503)
- # acct cont objc objc objc
- self.app.memcache.store = {}
+ def test_copy_not_found_reading_source(self):
+ req = Request.blank('/v1/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
+ headers={'Content-Length': '0',
+ 'X-Copy-From': '/c/o'})
+ # not found
+ status_list = (200, 200, 404, 404, 404)
+ # acct cont objc objc objc
+ with self.controller_context(req, *status_list) as controller:
resp = controller.PUT(req)
- self.assertEquals(resp.status_int, 503)
+ self.assertEquals(resp.status_int, 404)
- # not found
- req = Request.blank('/v1/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
- headers={'Content-Length': '0',
- 'X-Copy-From': '/c/o'})
- self.app.update_request(req)
- set_http_connect(200, 200, 404, 404, 404)
- # acct cont objc objc objc
- self.app.memcache.store = {}
+ def test_copy_with_some_missing_sources(self):
+ req = Request.blank('/v1/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
+ headers={'Content-Length': '0',
+ 'X-Copy-From': '/c/o'})
+ status_list = (200, 200, 404, 404, 200, 201, 201, 201)
+ # acct cont objc objc objc obj obj obj
+ with self.controller_context(req, *status_list) as controller:
resp = controller.PUT(req)
- self.assertEquals(resp.status_int, 404)
+ self.assertEquals(resp.status_int, 201)
- # some missing containers
- req = Request.blank('/v1/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
- headers={'Content-Length': '0',
- 'X-Copy-From': '/c/o'})
- self.app.update_request(req)
- set_http_connect(200, 200, 404, 404, 200, 201, 201, 201)
- # acct cont objc objc objc obj obj obj
- self.app.memcache.store = {}
+ def test_copy_with_object_metadata(self):
+ req = Request.blank('/v1/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
+ headers={'Content-Length': '0',
+ 'X-Copy-From': '/c/o',
+ 'X-Object-Meta-Ours': 'okay'})
+ # test object metadata
+ status_list = (200, 200, 200, 200, 200, 201, 201, 201)
+ # acct cont objc objc objc obj obj obj
+ with self.controller_context(req, *status_list) as controller:
resp = controller.PUT(req)
- self.assertEquals(resp.status_int, 201)
+ self.assertEquals(resp.status_int, 201)
+ self.assertEquals(resp.headers.get('x-object-meta-test'), 'testing')
+ self.assertEquals(resp.headers.get('x-object-meta-ours'), 'okay')
+ self.assertEquals(resp.headers.get('x-delete-at'), '9876543210')
- # test object meta data
- req = Request.blank('/v1/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
- headers={'Content-Length': '0',
- 'X-Copy-From': '/c/o',
- 'X-Object-Meta-Ours': 'okay'})
- self.app.update_request(req)
- set_http_connect(200, 200, 200, 200, 200, 201, 201, 201)
- # acct cont objc objc objc obj obj obj
- self.app.memcache.store = {}
- resp = controller.PUT(req)
- self.assertEquals(resp.status_int, 201)
- self.assertEquals(resp.headers.get('x-object-meta-test'),
- 'testing')
- self.assertEquals(resp.headers.get('x-object-meta-ours'), 'okay')
- self.assertEquals(resp.headers.get('x-delete-at'), '9876543210')
+ def test_copy_source_larger_than_max_file_size(self):
+ req = Request.blank('/v1/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
+ headers={'Content-Length': '0',
+ 'X-Copy-From': '/c/o'})
- # copy-from object is too large to fit in target object
- req = Request.blank('/v1/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
- headers={'Content-Length': '0',
- 'X-Copy-From': '/c/o'})
- self.app.update_request(req)
+ # copy-from object is too large to fit in target object
+ class LargeResponseBody(object):
- class LargeResponseBody(object):
+ def __len__(self):
+ return MAX_FILE_SIZE + 1
- def __len__(self):
- return MAX_FILE_SIZE + 1
+ def __getitem__(self, key):
+ return ''
- def __getitem__(self, key):
- return ''
+ copy_from_obj_body = LargeResponseBody()
+ status_list = (200, 200, 200, 200, 200)
+ # acct cont objc objc objc
+ kwargs = dict(body=copy_from_obj_body)
+ with self.controller_context(req, *status_list,
+ **kwargs) as controller:
+ self.app.update_request(req)
- copy_from_obj_body = LargeResponseBody()
- set_http_connect(200, 200, 200, 200, 200, 201, 201, 201,
- body=copy_from_obj_body)
self.app.memcache.store = {}
resp = controller.PUT(req)
self.assertEquals(resp.status_int, 413)
- def test_COPY(self):
- with save_globals():
- controller = proxy_server.ObjectController(self.app, 'a', 'c', 'o')
- req = Request.blank('/v1/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
- headers={'Content-Length': '0'})
- req.account = 'a'
- set_http_connect(200, 200, 201, 201, 201)
- # acct cont obj obj obj
- resp = controller.PUT(req)
- self.assertEquals(resp.status_int, 201)
-
- req = Request.blank('/v1/a/c/o',
- environ={'REQUEST_METHOD': 'COPY'},
- headers={'Destination': 'c/o'})
- req.account = 'a'
- set_http_connect(200, 200, 200, 200, 200, 201, 201, 201, 200, 200)
- # acct cont acct cont objc objc objc obj obj obj
- self.app.memcache.store = {}
+ def test_basic_COPY(self):
+ req = Request.blank('/v1/a/c/o',
+ environ={'REQUEST_METHOD': 'COPY'},
+ headers={'Destination': 'c/o2'})
+ status_list = (200, 200, 200, 200, 200, 201, 201, 201)
+ # acct cont objc objc objc obj obj obj
+ with self.controller_context(req, *status_list) as controller:
resp = controller.COPY(req)
- self.assertEquals(resp.status_int, 201)
- self.assertEquals(resp.headers['x-copied-from'], 'c/o')
+ self.assertEquals(resp.status_int, 201)
+ self.assertEquals(resp.headers['x-copied-from'], 'c/o')
- req = Request.blank('/v1/a/c/o/o2',
- environ={'REQUEST_METHOD': 'COPY'},
- headers={'Destination': 'c/o'})
- req.account = 'a'
- controller.object_name = 'o/o2'
- set_http_connect(200, 200, 200, 200, 200, 201, 201, 201, 200, 200)
- # acct cont acct cont objc objc objc obj obj obj
- self.app.memcache.store = {}
+ def test_COPY_across_containers(self):
+ req = Request.blank('/v1/a/c/o',
+ environ={'REQUEST_METHOD': 'COPY'},
+ headers={'Destination': 'c2/o'})
+ status_list = (200, 200, 200, 200, 200, 200, 201, 201, 201)
+ # acct cont c2 objc objc objc obj obj obj
+ with self.controller_context(req, *status_list) as controller:
resp = controller.COPY(req)
- self.assertEquals(resp.status_int, 201)
- self.assertEquals(resp.headers['x-copied-from'], 'c/o/o2')
-
- req = Request.blank('/v1/a/c/o',
- environ={'REQUEST_METHOD': 'COPY'},
- headers={'Destination': '/c/o'})
- req.account = 'a'
- controller.object_name = 'o'
- set_http_connect(200, 200, 200, 200, 200, 201, 201, 201, 200, 200)
- # acct cont acct cont objc objc objc obj obj obj
- self.app.memcache.store = {}
+ self.assertEquals(resp.status_int, 201)
+ self.assertEquals(resp.headers['x-copied-from'], 'c/o')
+
+ def test_COPY_source_with_slashes_in_name(self):
+ req = Request.blank('/v1/a/c/o/o2',
+ environ={'REQUEST_METHOD': 'COPY'},
+ headers={'Destination': 'c/o'})
+ status_list = (200, 200, 200, 200, 200, 201, 201, 201)
+ # acct cont objc objc objc obj obj obj
+ with self.controller_context(req, *status_list) as controller:
resp = controller.COPY(req)
- self.assertEquals(resp.status_int, 201)
- self.assertEquals(resp.headers['x-copied-from'], 'c/o')
+ self.assertEquals(resp.status_int, 201)
+ self.assertEquals(resp.headers['x-copied-from'], 'c/o/o2')
- req = Request.blank('/v1/a/c/o/o2',
- environ={'REQUEST_METHOD': 'COPY'},
- headers={'Destination': '/c/o'})
- req.account = 'a'
- controller.object_name = 'o/o2'
- set_http_connect(200, 200, 200, 200, 200, 201, 201, 201, 200, 200)
- # acct cont acct cont objc objc objc obj obj obj
- self.app.memcache.store = {}
+ def test_COPY_destination_leading_slash(self):
+ req = Request.blank('/v1/a/c/o',
+ environ={'REQUEST_METHOD': 'COPY'},
+ headers={'Destination': '/c/o'})
+ status_list = (200, 200, 200, 200, 200, 201, 201, 201)
+ # acct cont objc objc objc obj obj obj
+ with self.controller_context(req, *status_list) as controller:
resp = controller.COPY(req)
- self.assertEquals(resp.status_int, 201)
- self.assertEquals(resp.headers['x-copied-from'], 'c/o/o2')
+ self.assertEquals(resp.status_int, 201)
+ self.assertEquals(resp.headers['x-copied-from'], 'c/o')
+
+ def test_COPY_source_with_slashes_destination_leading_slash(self):
+ req = Request.blank('/v1/a/c/o/o2',
+ environ={'REQUEST_METHOD': 'COPY'},
+ headers={'Destination': '/c/o'})
+ status_list = (200, 200, 200, 200, 200, 201, 201, 201)
+ # acct cont objc objc objc obj obj obj
+ with self.controller_context(req, *status_list) as controller:
+ resp = controller.COPY(req)
+ self.assertEquals(resp.status_int, 201)
+ self.assertEquals(resp.headers['x-copied-from'], 'c/o/o2')
- req = Request.blank('/v1/a/c/o',
- environ={'REQUEST_METHOD': 'COPY'},
- headers={'Destination': 'c_o'})
- req.account = 'a'
- controller.object_name = 'o'
- set_http_connect(200, 200)
- # acct cont
- self.app.memcache.store = {}
+ def test_COPY_no_object_in_destination(self):
+ req = Request.blank('/v1/a/c/o',
+ environ={'REQUEST_METHOD': 'COPY'},
+ headers={'Destination': 'c_o'})
+ status_list = [] # no requests needed
+ with self.controller_context(req, *status_list) as controller:
resp = controller.COPY(req)
- self.assertEquals(resp.status_int, 412)
+ self.assertEquals(resp.status_int, 412)
- req = Request.blank('/v1/a/c/o',
- environ={'REQUEST_METHOD': 'COPY'},
- headers={'Destination': '/c/o'})
- req.account = 'a'
- controller.object_name = 'o'
- set_http_connect(200, 200, 503, 503, 503)
- # acct cont objc objc objc
- self.app.memcache.store = {}
+ def test_COPY_server_error_reading_source(self):
+ req = Request.blank('/v1/a/c/o',
+ environ={'REQUEST_METHOD': 'COPY'},
+ headers={'Destination': '/c/o'})
+ status_list = (200, 200, 503, 503, 503)
+ # acct cont objc objc objc
+ with self.controller_context(req, *status_list) as controller:
resp = controller.COPY(req)
- self.assertEquals(resp.status_int, 503)
+ self.assertEquals(resp.status_int, 503)
- req = Request.blank('/v1/a/c/o',
- environ={'REQUEST_METHOD': 'COPY'},
- headers={'Destination': '/c/o'})
- req.account = 'a'
- controller.object_name = 'o'
- set_http_connect(200, 200, 404, 404, 404)
- # acct cont objc objc objc
- self.app.memcache.store = {}
+ def test_COPY_not_found_reading_source(self):
+ req = Request.blank('/v1/a/c/o',
+ environ={'REQUEST_METHOD': 'COPY'},
+ headers={'Destination': '/c/o'})
+ status_list = (200, 200, 404, 404, 404)
+ # acct cont objc objc objc
+ with self.controller_context(req, *status_list) as controller:
resp = controller.COPY(req)
- self.assertEquals(resp.status_int, 404)
+ self.assertEquals(resp.status_int, 404)
- req = Request.blank('/v1/a/c/o',
- environ={'REQUEST_METHOD': 'COPY'},
- headers={'Destination': '/c/o'})
- req.account = 'a'
- controller.object_name = 'o'
- set_http_connect(200, 200, 404, 404, 200, 201, 201, 201)
- # acct cont objc objc objc obj obj obj
- self.app.memcache.store = {}
+ def test_COPY_with_some_missing_sources(self):
+ req = Request.blank('/v1/a/c/o',
+ environ={'REQUEST_METHOD': 'COPY'},
+ headers={'Destination': '/c/o'})
+ status_list = (200, 200, 404, 404, 200, 201, 201, 201)
+ # acct cont objc objc objc obj obj obj
+ with self.controller_context(req, *status_list) as controller:
resp = controller.COPY(req)
- self.assertEquals(resp.status_int, 201)
+ self.assertEquals(resp.status_int, 201)
- req = Request.blank('/v1/a/c/o',
- environ={'REQUEST_METHOD': 'COPY'},
- headers={'Destination': '/c/o',
- 'X-Object-Meta-Ours': 'okay'})
- req.account = 'a'
- controller.object_name = 'o'
- set_http_connect(200, 200, 200, 200, 200, 201, 201, 201)
- # acct cont objc objc objc obj obj obj
- self.app.memcache.store = {}
+ def test_COPY_with_metadata(self):
+ req = Request.blank('/v1/a/c/o',
+ environ={'REQUEST_METHOD': 'COPY'},
+ headers={'Destination': '/c/o',
+ 'X-Object-Meta-Ours': 'okay'})
+ status_list = (200, 200, 200, 200, 200, 201, 201, 201)
+ # acct cont objc objc objc obj obj obj
+ with self.controller_context(req, *status_list) as controller:
resp = controller.COPY(req)
- self.assertEquals(resp.status_int, 201)
- self.assertEquals(resp.headers.get('x-object-meta-test'),
- 'testing')
- self.assertEquals(resp.headers.get('x-object-meta-ours'), 'okay')
- self.assertEquals(resp.headers.get('x-delete-at'), '9876543210')
+ self.assertEquals(resp.status_int, 201)
+ self.assertEquals(resp.headers.get('x-object-meta-test'),
+ 'testing')
+ self.assertEquals(resp.headers.get('x-object-meta-ours'), 'okay')
+ self.assertEquals(resp.headers.get('x-delete-at'), '9876543210')
- req = Request.blank('/v1/a/c/o',
- environ={'REQUEST_METHOD': 'COPY'},
- headers={'Destination': '/c/o'})
- self.app.update_request(req)
+ def test_COPY_source_larger_than_max_file_size(self):
+ req = Request.blank('/v1/a/c/o',
+ environ={'REQUEST_METHOD': 'COPY'},
+ headers={'Destination': '/c/o'})
- class LargeResponseBody(object):
+ class LargeResponseBody(object):
- def __len__(self):
- return MAX_FILE_SIZE + 1
+ def __len__(self):
+ return MAX_FILE_SIZE + 1
- def __getitem__(self, key):
- return ''
+ def __getitem__(self, key):
+ return ''
- copy_from_obj_body = LargeResponseBody()
- set_http_connect(200, 200, 200, 200, 200, 201, 201, 201,
- body=copy_from_obj_body)
- self.app.memcache.store = {}
+ copy_from_obj_body = LargeResponseBody()
+ status_list = (200, 200, 200, 200, 200)
+ # acct cont objc objc objc
+ kwargs = dict(body=copy_from_obj_body)
+ with self.controller_context(req, *status_list,
+ **kwargs) as controller:
resp = controller.COPY(req)
- self.assertEquals(resp.status_int, 413)
+ self.assertEquals(resp.status_int, 413)
def test_COPY_newest(self):
with save_globals():
@@ -2574,7 +2594,7 @@ class TestObjectController(unittest.TestCase):
def test_chunked_put(self):
- class ChunkedFile():
+ class ChunkedFile(object):
def __init__(self, bytes):
self.bytes = bytes
@@ -3824,9 +3844,7 @@ class TestObjectController(unittest.TestCase):
req.content_length = 0
resp = controller.OPTIONS(req)
self.assertEquals(200, resp.status_int)
- self.assertEquals(
- 'https://bar.baz',
- resp.headers['access-control-allow-origin'])
+ self.assertEquals('*', resp.headers['access-control-allow-origin'])
for verb in 'OPTIONS COPY GET POST PUT DELETE HEAD'.split():
self.assertTrue(
verb in resp.headers['access-control-allow-methods'])
@@ -3842,10 +3860,11 @@ class TestObjectController(unittest.TestCase):
def stubContainerInfo(*args):
return {
'cors': {
- 'allow_origin': 'http://foo.bar'
+ 'allow_origin': 'http://not.foo.bar'
}
}
controller.container_info = stubContainerInfo
+ controller.app.strict_cors_mode = False
def objectGET(controller, req):
return Response(headers={
@@ -3876,6 +3895,50 @@ class TestObjectController(unittest.TestCase):
'x-trans-id', 'x-object-meta-color'])
self.assertEquals(expected_exposed, exposed)
+ controller.app.strict_cors_mode = True
+ req = Request.blank(
+ '/v1/a/c/o.jpg',
+ {'REQUEST_METHOD': 'GET'},
+ headers={'Origin': 'http://foo.bar'})
+
+ resp = cors_validation(objectGET)(controller, req)
+
+ self.assertEquals(200, resp.status_int)
+ self.assertTrue('access-control-allow-origin' not in resp.headers)
+
+ def test_CORS_valid_with_obj_headers(self):
+ with save_globals():
+ controller = proxy_server.ObjectController(self.app, 'a', 'c', 'o')
+
+ def stubContainerInfo(*args):
+ return {
+ 'cors': {
+ 'allow_origin': 'http://foo.bar'
+ }
+ }
+ controller.container_info = stubContainerInfo
+
+ def objectGET(controller, req):
+ return Response(headers={
+ 'X-Object-Meta-Color': 'red',
+ 'X-Super-Secret': 'hush',
+ 'Access-Control-Allow-Origin': 'http://obj.origin',
+ 'Access-Control-Expose-Headers': 'x-trans-id'
+ })
+
+ req = Request.blank(
+ '/v1/a/c/o.jpg',
+ {'REQUEST_METHOD': 'GET'},
+ headers={'Origin': 'http://foo.bar'})
+
+ resp = cors_validation(objectGET)(controller, req)
+
+ self.assertEquals(200, resp.status_int)
+ self.assertEquals('http://obj.origin',
+ resp.headers['access-control-allow-origin'])
+ self.assertEquals('x-trans-id',
+ resp.headers['access-control-expose-headers'])
+
def _gather_x_container_headers(self, controller_call, req, *connect_args,
**kwargs):
header_list = kwargs.pop('header_list', ['X-Container-Device',
@@ -4092,7 +4155,8 @@ class TestContainerController(unittest.TestCase):
self.app = proxy_server.Application(None, FakeMemcache(),
account_ring=FakeRing(),
container_ring=FakeRing(),
- object_ring=FakeRing())
+ object_ring=FakeRing(),
+ logger=FakeLogger())
def test_transfer_headers(self):
src_headers = {'x-remove-versions-location': 'x',
@@ -4843,9 +4907,7 @@ class TestContainerController(unittest.TestCase):
req.content_length = 0
resp = controller.OPTIONS(req)
self.assertEquals(200, resp.status_int)
- self.assertEquals(
- 'https://bar.baz',
- resp.headers['access-control-allow-origin'])
+ self.assertEquals('*', resp.headers['access-control-allow-origin'])
for verb in 'OPTIONS GET POST PUT DELETE HEAD'.split():
self.assertTrue(
verb in resp.headers['access-control-allow-methods'])
@@ -5016,11 +5078,60 @@ class TestContainerController(unittest.TestCase):
'X-Account-Device': 'sdc'}
])
+ def test_PUT_backed_x_timestamp_header(self):
+ timestamps = []
+
+ def capture_timestamps(*args, **kwargs):
+ headers = kwargs['headers']
+ timestamps.append(headers.get('X-Timestamp'))
+
+ req = Request.blank('/v1/a/c', method='PUT', headers={'': ''})
+ with save_globals():
+ new_connect = set_http_connect(200, # account existance check
+ 201, 201, 201,
+ give_connect=capture_timestamps)
+ resp = self.app.handle_request(req)
+
+ # sanity
+ self.assertRaises(StopIteration, new_connect.code_iter.next)
+ self.assertEqual(2, resp.status_int // 100)
+
+ timestamps.pop(0) # account existance check
+ self.assertEqual(3, len(timestamps))
+ for timestamp in timestamps:
+ self.assertEqual(timestamp, timestamps[0])
+ self.assert_(re.match('[0-9]{10}\.[0-9]{5}', timestamp))
+
+ def test_DELETE_backed_x_timestamp_header(self):
+ timestamps = []
+
+ def capture_timestamps(*args, **kwargs):
+ headers = kwargs['headers']
+ timestamps.append(headers.get('X-Timestamp'))
+
+ req = Request.blank('/v1/a/c', method='DELETE', headers={'': ''})
+ self.app.update_request(req)
+ with save_globals():
+ new_connect = set_http_connect(200, # account existance check
+ 201, 201, 201,
+ give_connect=capture_timestamps)
+ resp = self.app.handle_request(req)
+
+ # sanity
+ self.assertRaises(StopIteration, new_connect.code_iter.next)
+ self.assertEqual(2, resp.status_int // 100)
+
+ timestamps.pop(0) # account existance check
+ self.assertEqual(3, len(timestamps))
+ for timestamp in timestamps:
+ self.assertEqual(timestamp, timestamps[0])
+ self.assert_(re.match('[0-9]{10}\.[0-9]{5}', timestamp))
+
def test_node_read_timeout_retry_to_container(self):
with save_globals():
req = Request.blank('/v1/a/c', environ={'REQUEST_METHOD': 'GET'})
self.app.node_timeout = 0.1
- set_http_connect(200, 200, 200, body='abcdef', slow=[2])
+ set_http_connect(200, 200, 200, body='abcdef', slow=[1.0, 1.0])
resp = req.get_response(self.app)
got_exc = False
try:
@@ -5547,6 +5658,143 @@ class TestAccountControllerFakeGetResponse(unittest.TestCase):
resp = req.get_response(self.app)
self.assertEqual(400, resp.status_int)
+ def test_account_acl_header_access(self):
+ acl = {
+ 'admin': ['AUTH_alice'],
+ 'read-write': ['AUTH_bob'],
+ 'read-only': ['AUTH_carol'],
+ }
+ prefix = get_sys_meta_prefix('account')
+ privileged_headers = {(prefix + 'core-access-control'): format_acl(
+ version=2, acl_dict=acl)}
+
+ app = proxy_server.Application(
+ None, FakeMemcache(), account_ring=FakeRing(),
+ container_ring=FakeRing(), object_ring=FakeRing())
+
+ with save_globals():
+ # Mock account server will provide privileged information (ACLs)
+ set_http_connect(200, 200, 200, headers=privileged_headers)
+ req = Request.blank('/v1/a', environ={'REQUEST_METHOD': 'GET'})
+ resp = app.handle_request(req)
+
+ # Not a swift_owner -- ACLs should NOT be in response
+ header = 'X-Account-Access-Control'
+ self.assert_(header not in resp.headers, '%r was in %r' % (
+ header, resp.headers))
+
+ # Same setup -- mock acct server will provide ACLs
+ set_http_connect(200, 200, 200, headers=privileged_headers)
+ req = Request.blank('/v1/a', environ={'REQUEST_METHOD': 'GET',
+ 'swift_owner': True})
+ resp = app.handle_request(req)
+
+ # For a swift_owner, the ACLs *should* be in response
+ self.assert_(header in resp.headers, '%r not in %r' % (
+ header, resp.headers))
+
+ def test_account_acls_through_delegation(self):
+
+ # Define a way to grab the requests sent out from the AccountController
+ # to the Account Server, and a way to inject responses we'd like the
+ # Account Server to return.
+ resps_to_send = []
+
+ @contextmanager
+ def patch_account_controller_method(verb):
+ old_method = getattr(proxy_server.AccountController, verb)
+ new_method = lambda self, req, *_, **__: resps_to_send.pop(0)
+ try:
+ setattr(proxy_server.AccountController, verb, new_method)
+ yield
+ finally:
+ setattr(proxy_server.AccountController, verb, old_method)
+
+ def make_test_request(http_method, swift_owner=True):
+ env = {
+ 'REQUEST_METHOD': http_method,
+ 'swift_owner': swift_owner,
+ }
+ acl = {
+ 'admin': ['foo'],
+ 'read-write': ['bar'],
+ 'read-only': ['bas'],
+ }
+ headers = {} if http_method in ('GET', 'HEAD') else {
+ 'x-account-access-control': format_acl(version=2, acl_dict=acl)
+ }
+
+ return Request.blank('/v1/a', environ=env, headers=headers)
+
+ # Our AccountController will invoke methods to communicate with the
+ # Account Server, and they will return responses like these:
+ def make_canned_response(http_method):
+ acl = {
+ 'admin': ['foo'],
+ 'read-write': ['bar'],
+ 'read-only': ['bas'],
+ }
+ headers = {'x-account-sysmeta-core-access-control': format_acl(
+ version=2, acl_dict=acl)}
+ canned_resp = Response(headers=headers)
+ canned_resp.environ = {
+ 'PATH_INFO': '/acct',
+ 'REQUEST_METHOD': http_method,
+ }
+ resps_to_send.append(canned_resp)
+
+ app = proxy_server.Application(
+ None, FakeMemcache(), account_ring=FakeRing(),
+ container_ring=FakeRing(), object_ring=FakeRing())
+ app.allow_account_management = True
+
+ ext_header = 'x-account-access-control'
+ with patch_account_controller_method('GETorHEAD_base'):
+ # GET/HEAD requests should remap sysmeta headers from acct server
+ for verb in ('GET', 'HEAD'):
+ make_canned_response(verb)
+ req = make_test_request(verb)
+ resp = app.handle_request(req)
+ h = parse_acl(version=2, data=resp.headers.get(ext_header))
+ self.assertEqual(h['admin'], ['foo'])
+ self.assertEqual(h['read-write'], ['bar'])
+ self.assertEqual(h['read-only'], ['bas'])
+
+ # swift_owner = False: GET/HEAD shouldn't return sensitive info
+ make_canned_response(verb)
+ req = make_test_request(verb, swift_owner=False)
+ resp = app.handle_request(req)
+ h = resp.headers
+ self.assertEqual(None, h.get(ext_header))
+
+ # swift_owner unset: GET/HEAD shouldn't return sensitive info
+ make_canned_response(verb)
+ req = make_test_request(verb, swift_owner=False)
+ del req.environ['swift_owner']
+ resp = app.handle_request(req)
+ h = resp.headers
+ self.assertEqual(None, h.get(ext_header))
+
+ # Verify that PUT/POST requests remap sysmeta headers from acct server
+ with patch_account_controller_method('make_requests'):
+ make_canned_response('PUT')
+ req = make_test_request('PUT')
+ resp = app.handle_request(req)
+
+ h = parse_acl(version=2, data=resp.headers.get(ext_header))
+ self.assertEqual(h['admin'], ['foo'])
+ self.assertEqual(h['read-write'], ['bar'])
+ self.assertEqual(h['read-only'], ['bas'])
+
+ make_canned_response('POST')
+ req = make_test_request('POST')
+ resp = app.handle_request(req)
+
+ h = parse_acl(version=2, data=resp.headers.get(ext_header))
+ self.assertEqual(h['admin'], ['foo'])
+ self.assertEqual(h['read-write'], ['bar'])
+ self.assertEqual(h['read-only'], ['bas'])
+
class FakeObjectController(object):
diff --git a/tools/gswauth_functional_tests.sh b/tools/gswauth_functional_tests.sh
index dbe2248..287a20a 100755
--- a/tools/gswauth_functional_tests.sh
+++ b/tools/gswauth_functional_tests.sh
@@ -50,7 +50,7 @@ quit()
fail()
{
cleanup
- quit "$1"
+ quit "$1"
}
run_generic_tests()
@@ -66,9 +66,9 @@ run_generic_tests()
nosetests -v --exe \
--with-xunit \
- --xunit-file functional_tests/gluster-swift-gswauth-generic-functional-TC-report.xml \
+ --xunit-file functional_tests_result/gluster-swift-gswauth-generic-functional-TC-report.xml \
--with-html-output \
- --html-out-file functional_tests/gluster-swift-gswauth-generic-functional-result.html \
+ --html-out-file functional_tests_result/gluster-swift-gswauth-generic-functional-result.html \
test/functional || fail "Functional tests failed"
}
@@ -91,6 +91,7 @@ export SWIFT_TEST_CONFIG_FILE=/etc/swift/test.conf
# Install the configuration files
sudo mkdir /etc/swift > /dev/null 2>&1
+sudo cp -r test/functional_auth/common_conf/* /etc/swift || fail "Unable to copy configuration files to /etc/swift"
sudo cp -r test/functional_auth/gswauth/conf/* /etc/swift || fail "Unable to copy configuration files to /etc/swift"
sudo_env gluster-swift-gen-builders test test2 gsmetadata || fail "Unable to create ring files"
@@ -101,12 +102,12 @@ sudo_env swift-init main start || fail "Unable to start swift"
#swauth-prep
sudo_env gswauth-prep -K gswauthkey || fail "Unable to prep gswauth"
-mkdir functional_tests > /dev/null 2>&1
+mkdir functional_tests_result > /dev/null 2>&1
nosetests -v --exe \
--with-xunit \
- --xunit-file functional_tests/gluster-swift-gswauth-functional-TC-report.xml \
+ --xunit-file functional_tests_result/gluster-swift-gswauth-functional-TC-report.xml \
--with-html-output \
- --html-out-file functional_tests/gluster-swift-gswauth-functional-result.html \
+ --html-out-file functional_tests_result/gluster-swift-gswauth-functional-result.html \
test/functional_auth/gswauth || fail "Functional gswauth test failed"
run_generic_tests
diff --git a/tools/keystone_functional_tests.sh b/tools/keystone_functional_tests.sh
index 620bcc7..b5aa25a 100755
--- a/tools/keystone_functional_tests.sh
+++ b/tools/keystone_functional_tests.sh
@@ -87,15 +87,15 @@ sudo_env gluster-swift-gen-builders $accounts || fail "Unable to create ring fil
sudo service memcached start || fail "Unable to start memcached"
sudo_env swift-init main start || fail "Unable to start swift"
-mkdir functional_tests > /dev/null 2>&1
+mkdir functional_tests_result > /dev/null 2>&1
echo "== Keystone: Generic Functional Tests =="
nosetests -v --exe \
--with-xunit \
- --xunit-file functional_tests/gluster-swift-keystone-generic-functional-TC-report.xml \
+ --xunit-file functional_tests_result/gluster-swift-keystone-generic-functional-TC-report.xml \
--with-html-output \
- --html-out-file functional_tests/gluster-swift-keystone-generic-functional-result.html \
+ --html-out-file functional_tests_result/gluster-swift-keystone-generic-functional-result.html \
test/functional || fail "Functional tests failed"
cleanup
diff --git a/tools/swkrbath_functional_tests.sh b/tools/object_expirer_functional.sh
index 9995f1d..2578619 100755
--- a/tools/swkrbath_functional_tests.sh
+++ b/tools/object_expirer_functional.sh
@@ -1,6 +1,6 @@
#!/bin/bash
-# Copyright (c) 2014 Red Hat, Inc.
+# Copyright (c) 2013 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -28,69 +28,60 @@ cleanup()
sudo service memcached stop
sudo_env swift-init main stop
sudo rm -rf /etc/swift > /dev/null 2>&1
- for acct in /mnt/gluster-object/* ; do
- sudo rm -rf /mnt/gluster-object/${acct}/* > /dev/null 2>&1
- sudo setfattr -x user.swift.metadata /mnt/gluster-object/${acct} > /dev/null 2>&1
- done
+ sudo rm -rf /mnt/gluster-object/test{,2}/* > /dev/null 2>&1
+ sudo rm -rf /mnt/gluster-object/gsexpiring/* > /dev/null 2>&1
+ sudo setfattr -x user.swift.metadata /mnt/gluster-object/test{,2} > /dev/null 2>&1
}
quit()
{
- echo "$1"
- exit 1
+ echo "$1"
+ exit 1
}
fail()
{
- cleanup
- quit "$1"
+ cleanup
+ quit "$1"
}
### MAIN ###
# Only run if there is no configuration in the system
if [ -x /etc/swift ] ; then
- quit "/etc/swift exists, cannot run functional tests."
+ quit "/etc/swift exists, cannot run functional tests."
fi
# Check the directories exist
-DIRS="/mnt/gluster-object /mnt/gluster-object/test /mnt/gluster-object/test2 /mnt/gluster-object/gsmetadata"
+DIRS="/mnt/gluster-object /mnt/gluster-object/test /mnt/gluster-object/test2 /mnt/gluster-object/gsexpiring"
for d in $DIRS ; do
- if [ ! -x $d ] ; then
- quit "$d must exist on an XFS or GlusterFS volume"
- fi
+ if [ ! -x $d ] ; then
+ quit "$d must exist on an XFS or GlusterFS volume"
+ fi
done
export SWIFT_TEST_CONFIG_FILE=/etc/swift/test.conf
# Install the configuration files
sudo mkdir /etc/swift > /dev/null 2>&1
-sudo cp -r test/functional_auth/swiftkerbauth/conf/* /etc/swift || fail "Unable to copy configuration files to /etc/swift"
+sudo cp -r test/functional_auth/common_conf/* /etc/swift || fail "Unable to copy configuration files to /etc/swift"
+sudo cp -r test/functional_auth/tempauth/conf/* /etc/swift || fail "Unable to copy configuration files to /etc/swift"
+sudo_env gluster-swift-gen-builders gsexpiring test || fail "Unable to create ring files"
-# Create the ring files
-accounts=""
-for acct in /mnt/gluster-object/* ; do
- acct=`basename $acct`
- accounts="$acct $accounts"
-done
-sudo_env gluster-swift-gen-builders $accounts || fail "Unable to create ring files"
+# Remove old files
+sudo rm -rf /mnt/gluster-object/test* > /dev/null 2>&1
+sudo rm -rf /mnt/gluster-object/gsexpiring/* > /dev/null 2>&1
# Start the services
sudo service memcached start || fail "Unable to start memcached"
sudo_env swift-init main start || fail "Unable to start swift"
-mkdir functional_tests > /dev/null 2>&1
-
-echo "== SwiftKerbAuth: Functional Tests =="
-
+echo "Running functional tests with tempauth"
+mkdir functional_tests > /dev/null 2>&1
nosetests -v --exe \
- --with-xunit \
- --xunit-file functional_tests/gluster-swift-swiftkerbauth-generic-functional-TC-report.xml \
- --with-html-output \
- --html-out-file functional_tests/gluster-swift-swiftkerbauth-generic-functional-result.html \
- test/functional_auth/swiftkerbauth || fail "Functional tests failed"
+ test/object_expirer_functional || fail "Object expirer functional tests failed"
cleanup
exit 0
diff --git a/tools/functional_tests.sh b/tools/tempauth_functional_tests.sh
index 94d5d9b..f237f3e 100755
--- a/tools/functional_tests.sh
+++ b/tools/tempauth_functional_tests.sh
@@ -64,6 +64,7 @@ export SWIFT_TEST_CONFIG_FILE=/etc/swift/test.conf
# Install the configuration files
sudo mkdir /etc/swift > /dev/null 2>&1
+sudo cp -r test/functional_auth/common_conf/* /etc/swift || fail "Unable to copy configuration files to /etc/swift"
sudo cp -r test/functional_auth/tempauth/conf/* /etc/swift || fail "Unable to copy configuration files to /etc/swift"
sudo_env gluster-swift-gen-builders test test2 || fail "Unable to create ring files"
@@ -71,13 +72,15 @@ sudo_env gluster-swift-gen-builders test test2 || fail "Unable to create ring fi
sudo service memcached start || fail "Unable to start memcached"
sudo_env swift-init main start || fail "Unable to start swift"
+echo "Running functional tests with tempauth"
+
mkdir functional_tests > /dev/null 2>&1
nosetests -v --exe \
--with-xunit \
--xunit-file functional_tests/gluster-swift-generic-functional-TC-report.xml \
- --with-html-output \
- --html-out-file functional_tests/gluster-swift-generic-functional-result.html \
- test/functional || fail "Functional tests failed"
+ --with-html-output \
+ --html-out-file functional_tests/gluster-swift-generic-functional-result.html \
+ test/functional || fail "Functional tests failed"
cleanup
exit 0
diff --git a/tox.ini b/tox.ini
index a00a36a..1942c26 100644
--- a/tox.ini
+++ b/tox.ini
@@ -14,45 +14,47 @@ setenv = VIRTUAL_ENV={envdir}
NOSE_OPENSTACK_YELLOW=0.025
NOSE_OPENSTACK_SHOW_ELAPSED=1
NOSE_OPENSTACK_STDOUT=1
+ NOSE_WITH_COVERAGE=1
+ NOSE_COVER_BRANCHES=1
+ NOSE_COVER_PACKAGE=gluster
deps =
- https://launchpad.net/gluster-swift/icehouse/1.13.0/+download/swift-1.13.0.tar.gz
- --download-cache={homedir}/.pipcache
- -r{toxinidir}/tools/test-requires
- -r{toxinidir}/tools/requirements.txt
+ git+https://github.com/openstack/swift.git@icehouse-eol
+ -r{toxinidir}/requirements.txt
+ -r{toxinidir}/test-requirements.txt
+# Just having testtools package installed fixes some dependency issue
+# https://github.com/swiftstack/vagrant-swift-all-in-one/issues/19
+# pip needs a good dependency resolver :/
+ testtools
+ flake8
changedir = {toxinidir}/test/unit
-commands = nosetests -v --exe --with-xunit --with-coverage --cover-package gluster --cover-erase --cover-xml --cover-html --cover-branches --with-html-output {posargs}
+commands = nosetests -v {posargs}
+
+[testenv:cover]
+setenv = VIRTUAL_ENV={envdir}
+ NOSE_WITH_COVERAGE=1
+ NOSE_COVER_BRANCHES=1
+ NOSE_COVER_HTML=1
+ NOSE_COVER_HTML_DIR={toxinidir}/cover
[tox:jenkins]
downloadcache = ~/cache/pip
[testenv:functest]
changedir = {toxinidir}
-commands = bash tools/functional_tests.sh
- bash tools/gswauth_functional_tests.sh
+commands = bash ./.functests
[testenv:ksfunctest]
changedir = {toxinidir}
commands = bash tools/keystone_functional_tests.sh
-[testenv:swfunctest]
-changedir = {toxinidir}
-commands = bash tools/swkrbath_functional_tests.sh
-
[testenv:pep8]
-deps =
- --download-cache={homedir}/.pipcache
- -r{toxinidir}/tools/test-requires
changedir = {toxinidir}
commands =
- flake8
- flake8 gluster test
-
-[testenv:cover]
-setenv = NOSE_WITH_COVERAGE=1
+ flake8 gluster test setup.py
[testenv:venv]
-commands =
changedir = {toxinidir}
+commands = {posargs}
[testenv:run]
changedir = {toxinidir}