diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index a4a4cc9..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,9 +0,0 @@
-.idea/
-build/
-vendor/
-
-.DS_Store
-composer.lock
-composer.phar
-phpunit.xml
-tests/settings.ini*
\ No newline at end of file
diff --git a/.gitreview b/.gitreview
deleted file mode 100644
index d63960b..0000000
--- a/.gitreview
+++ /dev/null
@@ -1,4 +0,0 @@
-[gerrit]
-host=review.openstack.org
-port=29418
-project=stackforge/openstack-sdk-php.git
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
deleted file mode 100644
index 8952345..0000000
--- a/CHANGELOG.rst
+++ /dev/null
@@ -1,4 +0,0 @@
-Release Notes
-=============
-
-This changelog contains the relevant feature additions and bug fixes.
diff --git a/LICENSE.txt b/LICENSE.txt
deleted file mode 100644
index 68c771a..0000000
--- a/LICENSE.txt
+++ /dev/null
@@ -1,176 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
diff --git a/README.rst b/README.rst
index 5a0d327..9006052 100644
--- a/README.rst
+++ b/README.rst
@@ -1,103 +1,7 @@
-OpenStack PHP-Client
-====================
+This project is no longer maintained.
-This package provides PHP OpenStack bindings.
+The contents of this repository are still available in the Git source code
+management system. To see the contents of this repository before it reached
+its end of life, please check out the previous commit with
+"git checkout HEAD^1".
-You can use this library to:
-
-- Authenticate your application to OpenStack.
-- Interact with Object Storage (aka Swift).
-
-Coming soon:
-
-- Intect with the Compute (Nova) manager.
-- Interact with other OpenStack services
-
-Requirements
-------------
-
-- PHP 5.3
-- An active OpenStack account with the desired services.
-
-Suggestions
-~~~~~~~~~~~
-
-- Enable the cURL extension for full protocol support.
-
-We also have support for using PHP's native HTTP stream wrapper, but it
-is not as reliable. We recommend cURL.
-
-Versioning
-----------
-
-We have a goal to be as consistent as possible with `Semantic
-Versioning `__. For released HP Cloud services this
-is what you can expect.
-
-Installation
-------------
-
-There are currently two methods of installation. We've been considering
-PEAR and Phar releases, but have currently limited to only Composer and
-builds because these cover our needs.
-
-Method #1:
-~~~~~~~~~~
-
-Use `Composer `__ to download and install the
-latest version of OpenStack.
-
-Method #2:
-~~~~~~~~~~
-
-Download a tagged release and include it in your project.
-
-Features
---------
-
-Identity Services
-~~~~~~~~~~~~~~~~~
-
-Authenticate, authorize service usage, and retrieve account information.
-
-Object Storage
-~~~~~~~~~~~~~~
-
-Store files or other data objects in containers on your OpenStack object
-storage instance. Create, modify and delete containers. Manage ACLs.
-Read, write, and delete objects. Expose objects in your object storage
-to other services.
-
-With full stream wrapper support, you can use built-in PHP functions
-like ``file_get_contents()``, ``fopen()``, and ``stat()`` for reading
-and writing files into object storage.
-
-Autoloading
-^^^^^^^^^^^
-
-OpenStack SDK for PHP is `PSR-4
-compliant `__,
-which means that it should work with any PSR-4 autoloader. However, it
-also comes with its own autoloader for apps that don't yet make use of a
-standard autoloader.
-
-Composer Support
-^^^^^^^^^^^^^^^^
-
-OpenStack PHP-Client is available as part of the Packagist archive,
-which means you can use Composer to automatically download, install, and
-manage revisions to OpenStack from within your project.
-
-We're big fans of `Composer `__.
-
-More information
-----------------
-
-`OpenStack `__ is a cloud computing platform that
-provides many services, inlcuding compute installs, object and block
-storage, and a host of hosted services.
-
-This library provides access to those services.
-
-The best source of documentation is the official API documentation,
-which is available at http://FIXME
diff --git a/composer.json b/composer.json
deleted file mode 100644
index 2ef9227..0000000
--- a/composer.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "name": "openstack/openstack-sdk-php",
- "description": "Access OpenStack services in PHP.",
- "type": "library",
- "keywords": ["openstack","keystone","cloud","swift","nova"],
- "license": "Apache-2.0",
- "require": {
- "php": ">=5.4.0",
- "guzzlehttp/guzzle": "~4.1"
- },
- "require-dev": {
- "phpunit/phpunit": "~4.1"
- },
- "support": {
- "irc": "irc://irc.freenode.org/openstack-sdks",
- "issues": "https://bugs.launchpad.net/openstack-sdk-php",
- "forum": "https://ask.openstack.org/",
- "wiki": "https://wiki.openstack.org/wiki/OpenStack-SDK-PHP",
- "source": "http://git.openstack.org/cgit/stackforge/openstack-sdk-php"
- },
- "autoload": {
- "psr-4": {
- "OpenStack\\": "src/OpenStack",
- "OpenStack\\Tests\\": "tests/Tests"
- }
- }
-}
diff --git a/doc/documentation.php b/doc/documentation.php
deleted file mode 100644
index 8b28486..0000000
--- a/doc/documentation.php
+++ /dev/null
@@ -1,227 +0,0 @@
- 'foo@example.com',
- * 'password' => 'secret',
- * 'tenantid' => '123456',
- * 'endpoint' => 'http://url.from.hpcloud.com/',
- * ));
- *
- *
- * // Get an object from the remote object storage and read it as a string
- * // right into $myObject.
- * $myObject = file_get_contents('swift://mycontainer/foo.txt', FALSE, $cxt);
- *
- * ?>
- *
- * With stream wrapper support, you can transparently read and write files to the
- * ObjectStorage service without using any fancy API at all. Use the
- * normal file methods like this:
- *
- *- fopen()/fclose()
- *- fread()/fwrite()
- *- file_get_contents(), stream_get_contents()
- *- stat()/fstat()
- *- is_readable()/is_writable()
- *- And so on
- * @see http://us3.php.net/manual/en/ref.filesystem.php
- *
- * Learn more about this at \OpenStack\ObjectStore\v1\Resource\StreamWrapper.
- *
- * Basic Example: Identity Service
- *
- * Stream wrappers are nice and all, but
- * some of us love fancy APIs. So here's an example using the full API
- * to log in and then dump a list of services that are available to you:
- *
- * token().
- * $token = $identity->authenticateAsUser($username, $password, $tenantId);
- *
- * // Get a listing of all of the services you currently have configured in
- * // OpenStack.
- * $catalog = $identity->serviceCatalog();
- *
- * var_dump($catalog);
- *
- * ?>
- *
- *- Our classes use PHP namespaces to organize components. If you've never used
- * them before, don't worry. They're easy to get the hang of.
- *- The Bootstrap class handles setting up OpenStack services. Read about it at \OpenStack\Bootstrap.
- *- The IdentityServices class handles authenticating to OpenStack, discovering services, and providing
- * access to your account. \OpenStack\Identity\v1\IdentityService explains the details, but here are
- * a few functions you'll want to know:
- * - \OpenStack\Identity\v1\IdentityService::__construct() tells the object where to connect.
- * - \OpenStack\Identity\v1\IdentityService::authenticateAsUser() lets you log
- * in with username and password.
- * - \OpenStack\Identity\v1\IdentityService::serviceCatalog() tells you about
- * the services you have activated on this account.
- *
- * Basic Example: Object Storage
- *
- * Assuming you have an object storage instance available in your service
- * catalog, we could continue on with something like this:
- *
- * serviceCatalog('object-storage');
- * // $objectStorageUrl = storageList[0]['endpoints'][0]['publicURL'];
- *
- * // Create a new ObjectStorage instance:
- * // $objectStore = new \OpenStack\ObjectStore\v1\ObjectStorage($token, $objectStorageUrl);
- *
- * // Or let ObjectStorage figure out which instance to use:
- * $objectStore = \OpenStack\ObjectStore\v1\ObjectStorage::newFromIdentity($identity);
- *
- * // List containers:
- * print_r($objectStore->containers());
- *
- * // Get a container named 'stuff':
- * $container = $objectStore->container('stuff');
- *
- * // List all of the objects in that container:
- * print_r($container->objects());
- *
- * // Get an object named 'example.txt'
- * $obj = $container->object('example.txt');
- *
- * // Print that object's contents:
- * print $obj->content();
- *
- * // Actually, since it implements __tostring, we could do this:
- * print $obj;
- * ?>
- *
- * This shows you a few methods for accessing objects and containers on your
- * \OpenStack\ObjectStore\v1\ObjectStorage account. There are many functions for
- * creating and modifying containers and objects, too.
- *
- *- \OpenStack\ObjectStore\v1\ObjectStorage is where you will start.
- *- Container services are in \OpenStack\ObjectStore\v1\ObjectStorage\Container
- *- There are two classes for objects:
- * - \OpenStack\ObjectStore\v1\ObjectStorage\Object is for creating new objects.
- * - \OpenStack\ObjectStore\v1\ObjectStorage\RemoteObject provides better network
- * performance when reading objects.
- *
- */
-
-/**
- * @package OpenStack
- * The OpenStack PHP-Client library.
- */
-/**
- * @namespace OpenStack.Services
- * OpenStack classes providing access to various services.
- *
- * OpenStack offers a number of services, including Compute (Nova),
- * and IdentityService.
- *
- * This package is reserved for classes that provide access to
- * services.
- */
-/**
- * @package OpenStack.Storage
- * OpenStack classes for remote storage.
- *
- * Services for now and the future:
- *
- *- ObjectStorage
- *- Others coming.
- *
- */
-/**
- * @package OpenStack.Storage.ObjectStorage
- * Classes specific to ObjectStorage.
- *
- * The main class is \OpenStack\ObjectStore\v1\ObjectStorage.
- */
-/**
- * @package OpenStack.Transport
- * HTTP/REST/JSON classes.
- *
- * HTTP/HTTPS is the transport protocol for OpenStack's RESTful services.
- *
- * This library provides both CURL and PHP Streams-based HTTP support,
- * and this package provides a simple REST client architecture, along
- * with the minimal JSON processing necessary.
- *
- *
- */
-?>
diff --git a/doc/introduction.md b/doc/introduction.md
deleted file mode 100644
index f7a8467..0000000
--- a/doc/introduction.md
+++ /dev/null
@@ -1,74 +0,0 @@
-# Using the OpenStack PHP-CLient API
-
-This tutorial explains how you can use the PHP API to connect to your OpenStack
-services and interact programmatically.
-
-## Object Storage (Swift)
-
-One of the services that OpenStack offers is called "Object Storage".
-This service provides a useful means of storing objects (usually files)
-on a service that you control, but that is available to other services
-in your cloud (and optionally is availably publically).
-
-This section of the tutorial describes how you can write PHP code to
-interact with the Object Storage service.
-
-## Authenticating to Object Storage
-
-There are two ways to authenticate to Object Storage:
-
-- Legacy Swift authentication
-- Control Services authentication
-
-For legacy swift authentication, you will need to use your Tenant ID, your username,
-and your password, along with the URL to the Object Storage endpoint.
-
-### Using Stream Wrappers
-
-There are two main methods for accessing OpenStack through this library.
-The first is through PHP *stream wrappers*. In PHP, stream wrappers
-provide a facility with which you can access various data streams (like
-a webpage, the data in a ZIP file, or an OpenStack object store) as if
-they were local files on your file system.
-
-Stream wrappers have a huge advantage for you: You can use the normal
-file system functions (`fread()`, `mkdir()`, `file_get_contents()`, etc)
-to access things not necessarily on your local filesystem. The PHP-Client
-library integrates with this facility of PHP.
-
-
-### Using the PHP-Client Classes
-
-While the stream wrappers are a fantastic way to accomplish many common
-tasks, sometimes you need a finer level of control, or you wish to use
-an Object-Oriented API. We provide you with the classes you need to work
-this way.
-
-(Deep dark secret: Actually, these are the classes that underly the
-stream wrappers.)
-
-In this section of the tutorial, we focus on using this API as a
-data-access layer.
-
-#### Main Classes
-
-- \OpenStack\Bootstrap: Provides services for bootstrapping the library.
- It's not necessary, but it can be helpful.
-- \OpenStack\ObjectStorage: The main interface to the OpenStack object
- storage.
-
-## Slightly Irreverant Glossary
-
-*Tenant ID:* You service provider will provide you with
-an account ID and a secret key, along with a URL, that can be used to
-access the cloud APIs.
-
-*Container:* A namespace extension useful for differentiating object
-space with pseudo-containment logical units. Or, a directory. (see
-_Object Storage_)
-
-*Object Storage:* A service provided by OpenStack that allows you to store
-entire files on the cloud. Files can be organized into _containers_, which are
-rough analogs to file system directories (or folders).
-
-
diff --git a/doc/oo-tutorial-code.php b/doc/oo-tutorial-code.php
deleted file mode 100644
index ea98e0c..0000000
--- a/doc/oo-tutorial-code.php
+++ /dev/null
@@ -1,36 +0,0 @@
-authenticateAsUser($username, $password, $tenantId);
-
-$catalog = $idService->serviceCatalog();
-
-$store = ObjectStorage::newFromServiceCatalog($catalog, $token);
-
-$store->createContainer('Example');
-$container = $store->container('Example');
-
-$name = 'hello.txt';
-$content = 'Hello World';
-$mime = 'text/plain';
-
-$localObject = new Object($name, $content, $mime);
-$container->save($localObject);
-
-$object = $container->object('hello.txt');
-printf("Name: %s \n", $object->name());
-printf("Size: %d \n", $object->contentLength());
-printf("Type: %s \n", $object->contentType());
-print $object->content() . PHP_EOL;
diff --git a/doc/oo-tutorial.md b/doc/oo-tutorial.md
deleted file mode 100644
index 7d0f572..0000000
--- a/doc/oo-tutorial.md
+++ /dev/null
@@ -1,480 +0,0 @@
-Tutorial: Using OpenStack PHP-Client
-=================
-
-PHP-Client provides PHP language bindings for the OpenStack APIs.
-
-In this tutorial, we will walk through the process of creating a simple
-tool that interacts with OpenStack's Object Storage. The emphasis in this
-article is on getting started and learning the concepts, not building a
-polished product.
-
-**This tutorial focuses on the object-oriented API.** The other way to
-work with this library is through the stream wrapper. That topic is
-covered in [another tutorial](@ref streams-tutorial).
-
-## Pre-flight Check
-
-PHP-Client has been developed to require PHP 5.3 or later. You are
-strongly encouraged to also install the CURL PHP extension. Many
-distributions of PHP come with this enabled. Sometimes, though, you may
-need to do something like `apt-get php5-curl` or similar. (Don't take
-our word for it -- check your system's documentation.)
-
-You can check for both of these conditions by checking the output of
-`php --info` (on the commandline) or ``.
-
-### Check the pilot, too!
-
-In our pre-flight check, we would be remiss if we didn't point out that
-there are some requirements for the pilot (that's you), too.
-
-The PHP-Client library is composed of two parts:
-
-1. The Object-Oriented part, which is the subject of this tutorial.
-2. The Stream Wrapper, which is the subject of another tutorial.
-
-The object-oriented library makes ample use of PHP namespaces. If you've
-never seen these before, they look like this:
-
-
-
-The namespace above is read like this: "The RemoteObject class is part
-of the ObjectStorage package in the Storage package in the base OpenStack
-package." Those familiar with Java, Python, and other languages will
-recognize this way of talking (though the backslash is an unfortunate
-symbol choice).
-
-For our library, we followed the recommendation of SPR-0, which means
-that the class above can be found in the file at:
-
- src/OpenStack/ObjectStore/v1/Resource/RemoteObject.php
-
-The pattern of matching namespace to file name should (we hope) make it
-easier for you to navigate our code.
-
-If this namespace stuff continues to confuse you, you may want to take a
-look at [the PHP documentation](http://us3.php.net/manual/en/language.namespaces.php),
-or you may just prefer to keep on reading and learn by example. We don't
-do anything really fancy with namespaces.
-
-**In this document, we sometimes replace the backslash (\\) with double
-colons (`::`) so that links are automatically generated.** So
-`\OpenStack\Bootstrap` may appear as OpenStack::Bootstrap. The reason for
-this is [explained elsewhere](@ref styleguide).
-
-## Step 1: Getting the Library
-
-You can get the OpenStack PHP-CLient library at the [OpenStack PHP-Client
-Repository](https://FIXME). The latest code is always
-available there.
-
-The project also uses [Composer](http://packagist.org/), and this is the
-best method for adding PHP-Client to your PHP project.
-
-For our example, we will assume that the library is accessible in the
-default include path, so the following line will include the
-`Bootstrap.php` file:
-
- include 'OpenStack/Bootstrap.php';
-
-## Step 2: Bootstrap the Library
-
-The first thing to do in your application is make sure the OpenStack
-library is bootstrapped. When we say "bootstrap", what we really mean is
-letting the library initialize itself.
-
-The only thing you will need to do is require Composer's PSR-compliant
-autoloader, like so:
-
- authenticateAsUser($username, $password, $tenantId);
- ?>
-
-Assuming the variables above have been set to include valid data, this
-script can connect to OpenStack and authenticate.
-
-When we construct a new OpenStack::Services::IdentityService object, we must pass it the
-endpoint URL for OpenStack Identity Service. Typically, that URL will
-look something like this:
-
-~~~
-https://region-a.geo-1.identity.hpcloudsvc.com:35357
-~~~
-
-The `authenticateAsUser()` method will authenticate to the
-Identity Services endpoint. For convenience, it returns the
-authorization token (`$token`), though we can also get the token from
-`$idService->token()`.
-
-Note that the `IdentityService` object may throw various exceptions
-(all subclasses of OpenStack\Common\Exception) during authentication. Failed
-authentication results in an \OpenStack\Common\Transport\AuthorizationException, while
-a network failure may result in an \OpenStack\Common\Transport\ServerException.
-
-Earlier, we talked about the service catalog. Once we've authenticated,
-we can get the service catalog from `$idService->serviceCatalog()`. It
-is an associative array, and you can get an idea of what it contains by
-dumping it with `var_dump()`, should you so desire.
-
-At this point, we have what we need from Identity Service. It's time to
-look at Object Storage.
-
-### IdentityService in a Nutshell
-
-Instances of `OpenStack\Identity\v2\IdentityService` are responsible for:
-
-- Authentication
-- Accessing the service catalog
-- Accessing account info
-- Associating tenant IDs with accounts (advanced)
-
-## Step 4: Connecting to Object Storage
-
-The Object Storage system is concerned with two classes of things:
-
-- An Object: A self-contained bundle of data (back in my day, we called
- them "files").
-- A Container: A storage container (bucket) for objects.
-
-Your object storage can have any number of containers, and each
-container can have any number of objects.
-
-In the object model for the OpenStack PHP-Client library, a top-level object
-called OpenStack::Storage::ObjectStorage provides access to the Object
-Storage service. In this step, we will be working with that object.
-
-### Getting an ObjectStorage Instance
-
-Earlier, we created an `IdentityService` instance called `$idService`.
-We will use that here to get the service catalog. Once we have the
-catalog, we can have a new `ObjectStorage` instance created for us,
-configured to talk to our account's Object Storage instance in
-OpenStack. Along with the service catalog, we also need our token that
-shows the Object Storage endpoint that we have already authenticated to
-Identity Services. Earlier, we captured that value in the `$token`
-variable.
-
-Now we can get a new `\OpenStack\ObjectStore\v1\ObjectStorage` instance:
-
- serviceCatalog();
-
- $store = ObjectStorage::newFromServiceCatalog($catalog, $token);
-
- // UPDATE: As of Beta 6, you can use newFromIdentity():
- // $store = ObjectStorage::newFromIdentity($idService);
- ?>
-
-First we get the service catalog (`$catalog`), and then we use the
-`ObjectStorage::newFromServiceCatalog()` static method to create the new
-Object Storage instance.
-
-The pattern of using a constructor-like static function is used
-throughout the OpenStack PHP-Client library. Inspired by Objective-C constructors
-and the Factory design pattern, it makes it possible for a single class
-to have multiple constructors.
-
-In particular, many top-level classes provide a
-`newFromServiceCatalog()` constructor function, since these classes know
-how to construct instances from a service catalog, thus freeing the
-developer up from knowing the details of a service catalog entry.
-
-Now we have an `ObjectStorage` instance that is already configured to
-talk to our OpenStack object storage service. Next, we can create a
-container.
-
-### ObjectStorage in a Nutshell
-
-Instances of OpenStack::Storage::ObjectStorage are responsbile for:
-
-- Providing high-level information about the Object Storage service
-- Creating, deleting, loading, and listing Containers
-- Modifying Container ACLs
-
-## Step 5: Adding a Container
-
-Before we can start putting objects (files) into our Object Storage
-service, we need a place to put them. An Object Storage service can hold
-numerous containers (and each container can have different access
-controls -- a topic we won't get into here).
-
-Containers are represented in the library by the
-OpenStack::Storage::ObjectStorage::Container class. And creating a
-container is done by a method on the `ObjectStorage` object that we
-created above:
-
- createContainer('Example');
- $container = $store->container('Example');
- ?>
-
-Recall that `$store` is the name of our `ObjectStorage` instance. In the
-first of the two lines above, we create a new container named `Example`.
-Then in the second line, we get that container.
-
-Why is this two steps? The answer is that the OpenStack PHP-Client library mimics
-the architecture of the underlying API. This is two operations (which
-means it requires two network requests to the remote host), and so we
-must perform two operations.
-
-The `createContainer()` call actually creates the new container on the
-cloud's Object Storage. The second call connects to the remote object
-storage, and gets the new container. The container that is returned will
-have some additional information, such as the amount of space it takes
-up on the remote storage, and the access control rules for that
-container. All of this information will be available on the `$container`
-instance.
-
-Our `$container` instance is an instance of
-OpenStack::Storage::ObjectStorage::Container. This object can be used not
-only to find out about a container, but also to get information about
-the objects in that container.
-
-Now that we have a `Container`, we can add an object.
-
-### The Container in a Nutshell
-
-(Yes, we realize the irony of that title.)
-
-A `\OpenStack\ObjectStore\v1\Resource\Container` instance is responsible for the following:
-
-- Accessing information about the container
-- Creating, saving, deleting, and listing objects in the container
-- Providing path-like traversal of objects
-- Copying objects across containers
-- Loading a lightweight representation of an object without fetching the
- entire object (more on this later).
-
-Among the features of a Container, it can act like an `Iterator` and is
-`Countable`. That means you can loop through a Container in a `foreach`
-loop and also use `count($container)` to find out the number of objects
-in a Container.
-
-## Step 6: Storing an Object
-
-Now we are ready to create an object, and then store it in our
-container.
-
-Before diving too deeply, it is important to point out a detail: When
-working with a remote data storage service, we are typically working
-with a local copy and a remote copy. If our code isn't constructed
-correctly, it is possible for these two to get out of sync.
-
-Earlier, we created a container directly on the remote side, and then
-fetched the container. As we create an object, we are going to do the
-opposite: We will create a local object, and then save it to the remote
-storage. Later, we will fetch the remote object.
-
- save($localObject);
- ?>
-
-In the code above, we create `$localObject` with a `$name`, some
-`$content`, and a `$mime` type. Strictly speaking, only `$name` is
-required.
-
-The OpenStack::Storage::ObjectStorage::Object class is used primarily to
-describe a locally created object. Once we have our new `Object`, we can
-save it remotely using the `save()` method on our `$container` object.
-This will push the object to the remote object storage service.
-
-While we can continue manipulating `$localObject`, we are working with
-the local version, not the latest version of what's on the server. This
-is fine if what we are doing is writing more data. However, when
-examining the content of the object, remember that we are working with
-the local copy, and its properties may differ from the remote copy's.
-
-### What if I call save() twice with the same Object?
-
-Objects, like files on a file system, are referenced by name. Any time
-you `save()` an object, it will be pushed to the remote object storage
-server, which will happily replace the old content with your newly
-submitted content.
-
-Next let's turn to loading objects from the remote object storage.
-
-### The Object in a Nutshell
-
-The `\OpenStack\ObjectStore\v1\Resource\Object` instances are used for:
-
-- Creating a local object to be stored remotely
-
-This class is also the base class for the `RemoteObject` class that we
-will look at later.
-
-The API is generally constructed so that a developer needn't worry about
-the differences between an `Object` and a `RemoteObject`. But in all but
-the edgiest of edge cases, you would only create an instance of
-`Object`, never of `RemoteObject`.
-
-## Step 7: Loading an Object
-
-Containers not only provide the methods for saving objects, but also for
-loading objects. Thus, we can fetch the object that we just created:
-
- object('hello.txt');
-
- printf("Name: %s \n", $object->name());
- printf("Size: %d \n", $object->contentLength());
- printf("Type: %s \n", $object->contentType());
- print $object->content() . PHP_EOL;
- ?>
-
-The `$object` variable now references an instance of a
-`\OpenStack\ObjectStore\v1\Resource\RemoteObject` that contains the entire
-object. `RemoteObject` represents an object that was loaded from the
-remote server. Along with providing the features of the `Object` class
-we saw earlier, it also provides numerous optimizations for working over
-the network.
-
-Now that we have the object, we print out several pieces of information
--- `name()`, `size()`, amd `type()`. Then, using `content()`, we fetch
-the content of the object.
-
-### Lazily Loading an Object
-
-The method we used above to fetch the object is perfect for our needs.
-It pulls the entire object down in a single request. But imagine this
-scenario: Our object storage has large media files, and we don't know
-at loading time whether or not we need to access the body content, or
-just the other data about the object.
-
-It would be a time-consuming task to download the entire body of a large
-media file if we don't actually use the body. On the other hand, from an
-API standpoint it is great to be able to pass around a single object,
-and not require the application to know whether or not the body has been
-retrieved.
-
-The `RemoteObject` solves this problem using a technique known as "lazy
-loading". That is, it can pull some of the data right away, but defer
-fetching the rest of the data until that data is actually needed.
-
-To fetch an object this way, we can just swap out one line in the
-example above:
-
- proxyObject('hello.txt');
-
- printf("Name: %s \n", $object->name());
- printf("Size: %d \n", $object->contentLength());
- printf("Type: %s \n", $object->contentType());
- print $object->content() . PHP_EOL;
- ?>
-
-Instead of using `object()`, we now use `proxyObject()`. This method
-immediately loads the core data about the remote object, but defers
-fetching the content until the content is requested.
-
-In the example above, then, one network request is issued by
-`proxyObject()`, but another is initiated when `$object->content()` is
-called.
-
-### The RemoteObject in a Nutshell
-
-Instances of a `\OpenStack\ObjectStore\v1\Resource\RemoteObject` offer the following features:
-
-- Access to an object stored on the remote object storage
-- A proxying mechanism for lazily loading objects
-- A stream-based API for using stream and file-based PHP functions
-- Automatic tempfile-based caching for large objects (using
- `php://temp`).
-
-`RemoteObject` instances can be updated and then passed to
-`Container::save()` to update the copy on the server, too.
-
-## Summary
-
-At this point we have created a very basic script that connects to
-OpenStack and works with object storage. Clearly, this only scratches the
-surface of what the OpenStack PHP-Client library does. But hopefully this is
-enough to get you started with the library.
-
-\see oo-tutorial-code.php
diff --git a/doc/streams-tutorial-example.php b/doc/streams-tutorial-example.php
deleted file mode 100644
index 5aeddb1..0000000
--- a/doc/streams-tutorial-example.php
+++ /dev/null
@@ -1,40 +0,0 @@
- $ini['account'],
- 'key' => $ini['secret'],
- 'tenantid' => $ini['tenantId'],
- 'endpoint' => $ini['url'],
-];
-Bootstrap::setConfiguration($settings);
-
-// Create a new file and write it to the object store.
-$newfile = fopen('swift://Example/my_file.txt', 'w');
-fwrite($newfile, "Good Morning!");
-fclose($newfile);
-
-// Check for an object:
-if (file_exists('swift://Example/my_file.txt')) {
- print "Found my_file.txt." . PHP_EOL;
-}
-
-// Get an entire object at once:
-$file = file_get_contents('swift://Example/my_file.txt');
-print 'File: ' . $file . PHP_EOL;
-
-$cxt = stream_context_create([
- 'swift' => [
- 'account' => $ini['account'],
- 'key' => $ini['secret'],
- 'tenantid' => $ini['tenantId'],
- 'endpoint' => $ini['url'],
- ],
-]);
-
-print file_get_contents('swift://Example/my_file.txt', FALSE, $cxt);
diff --git a/doc/streams-tutorial.md b/doc/streams-tutorial.md
deleted file mode 100644
index fe5ea5e..0000000
--- a/doc/streams-tutorial.md
+++ /dev/null
@@ -1,236 +0,0 @@
-Tutorial: Using Stream Wrappers {#streams-tutorial}
-===============================
-
-This is an introduction to the OpenStack PHP-Client library. While the library is
-large and feature-rich, this tutorial focuses on the Stream Wrapper
-feature. (There is also a [tutorial about the object-oriented
-library](@ref 00-tutorial).)
-
-## TL;DR
-
-With a few lines of setup code, you can fetch objects from OpenStack's
-object storage using built-in PHP functions like this:
-
-
-
-In fact, the vast majority of file and stream functions work with
-OpenStack's `swift://` URLs.
-
-The rest of this tutorial explains how they work.
-
-## The Setup
-
-The example above does not show the code necessary for initializing the
-OpenStack PHP-Client stream wrapper. In this section, we will look at the necessary
-setup code.
-
-### Loading Classes
-
-The OpenStack PHP-Client library is structured following PSR-4 recommendations.
-Practically speaking, what this means is that applications that use an
-PSR-4 autoloader may be able to automatically load the OpenStack PHP-Client.
-
-However, we'll assume that that is not the case. We'll assume that the
-library needs to be initialized manually.
-
-What we will do is first load the PHP-Client Bootstrap.php file, and then
-use the autoloader in that file to load the rest of the library:
-
- YOUR_USERNAME,
- 'password' => YOUR_PASSWORD,
- 'tenantid' => YOUR_TENANT_ID,
- 'endpoint' => IDENTITY_SERVICES_URL,
- );
- Bootstrap::setConfiguration($settings);
-
-Basically, what we do above is declare an associative array of
-configuration parameters and then tell OpenStack::Bootstrap to set these
-as the default configuration.
-
-Once the above is done, all of those PHP stream and file functions will
-just work. All you need to do is pass them `swift://` URLs, and they
-will do the rest.
-
-## The Format of Swift URLs
-
-Early in the tutorial we saw some swift URLs like this:
-`swift://Example/my_file.txt` . What is this URL referencing?
-
-The URL above has three important parts, in the form
-`swift://CONTAINER/OBJECT_NAME`.
-
-- *swift://*: This is the schema. This part of the URL tells PHP to pass
- the request to the OpenStack stream wrapper. (Swift, by the way, is the
- [OpenStack name for object storage](http://openstack.org/projects/storage/).
-- *Example*: This is the *container name*. In Object Storage parlance, a
- container is a place to store documents. One account can have lots of
- containers, and each container can have lots of objects.
-- *my_file.txt*: This is the object name. An object is basically the
- same as a file.
-
-Swift does not support directories, but it does allow slashes in object
-names. So `swift://Example/this/is/my/file.png' checks the container
-*Example* for the object named `this/is/my/file.png`.
-
-(For power users, there are some fancy operations you can do to treat
-Swift filename parts as if they were directories. Check out
-`\OpenStack\ObjectStore\v1\Resource\Container`.)
-
-## Using Stream Contexts for Authentication
-
-Sometimes it is better to pass authentication information directly to
-the stream or file function, instead of relying upon a global
-configuration. PHP provides for this with **stream contexts**.
-
-Stream contexts have one major downside: Not all PHP functions accept
-stream contexts. Here are some notable examples:
-
-- file_exists()
-- is_readable()
-- stat()
-
-(Basically, anything that calls the underlying `stat(3)`.)
-
-The advantage, though, is that each call can have its own authentication
-data. This is good for supporting multiple accounts, and can also be
-used to optimize long-term performance (e.g. by saving authentication
-tokens in a database and re-using them).
-
-Here's how a stream context is used:
-
- array(
- 'username' => YOUR_USERNAME,
- 'password' => YOUR_PASSWORD,
- 'tenantid' => YOUR_TENANT_ID,
- 'endpoint' => IDENTITY_SERVICES_URL,
- ),
- ));
-
- print file_get_contents('swift://Example/my_file.txt', FALSE, $cxt);
- ?>
-
-The main difference is the creation of `$cxt` using PHP's
-`stream_context_create()`. To fully understand this, you may want to
-take a look at the [PHP documentation](http://us3.php.net/manual/en/book.stream.php)
-for streams.
-
-## Stream Wrapper As A File System
-As it was noted earlier in this tutorial, swift does not support directories.
-Instead the names of a file can be path like with a separator. For example,
-`swiftfs://Example/path/to/my_file.txt` has a name of `path/to/my_file.txt`.
-
-To enable applications to use swift in a more directory like manner there is a
-second stream wrapper with a prefix `swiftfs://`. swiftfs stands for swift file
-system. It works in a similar manner to to the standard stream wrappers with a
-few key differences:
-
-- mkdir will return TRUE is no objects start with the directory you are trying
- to crate. Otherwise it will return FALSE.
-- rmdir will return FALSE if any objects start with the directory prefix you are
- trying to remove. rmdir does not allow you to remove directories with files
- in them.
-- Running stat on a directory that is a prefix for some objects (e.g.,
- `swiftfs://Example/path/to/`) will see this is a prefix for a file and treat
- it as if it were a directory.
-
-To use this stream wrapper instead of the standard swift one simple replace the
-usage of `swift://` with `swiftfs://`.
-
-## Summary
-
-This tutorial is focused on using stream wrappers to interact with your
-OpenStack Object Storage service. We focused on configuring the
-environment for transparently using PHP functions like `fopen()` and
-`file_get_contents()` to work with objects in OpenStack's object storage.
-
-This is just one way of interoperating with the OpenStack PHP-Client library. For
-more detail-oriented work, you may find the Object Oriented facilities
-better suited. You can read [the OO tutorial](@ref oo-tutorial) to learn
-more about that.
-
-Addidtionally, you may wish to learn more about the internals of the
-stream wrapper, the main class,
-`\OpenStack\ObjectStore\v1\Resource\StreamWrapper`, is well-documented.
diff --git a/doc/style.md b/doc/style.md
deleted file mode 100644
index a155ab2..0000000
--- a/doc/style.md
+++ /dev/null
@@ -1,120 +0,0 @@
-Coding and Documentation Style Guide {#styleguide}
-====================================
-
-This guide explain coding style, coding structure, and documentation
-style.
-
-## TL;DR
-
-- Read the [coding standards](https://github.com/mattfarina/Coding-Standards)
- to learn why we code the way we do.
-- Read about [PHPDoc](http://www.phpdoc.org/)
- if you're curious about our source code documentation.
-- Two spaces, no tabs.
-- WE LOVE GITHUB ISSUES AND PULL REQUESTS
-
-## Code Style
-
-The code in this package rigidly conforms to a given coding standard.
-The standard we use is published here and is based
-on the Drupal coding standards, the PEAR coding standards, and several
-other popular standards.
-
-Important highlights:
-
-- Indentation uses *two space characters* and no tabs.
-- Variables and class names use CamelCasing (details above).
-
-Please do your best to follow coding standards when submitting patches.
-
-### Object Orientation
-
-We have chosen to give the library a strongly object-oriented flavor.
-However, the stream wrapper integration provides a procudural interface
-to some of the services.
-
-### Design Patterns and Coding Practices
-
-Where applicable, we use established coding patterns and practices. Some
-are PHP specific (like stream wrappers), while most enjoy broader
-industry support.
-
-There are a few things a developer should be aware of:
-
-**Accessors and Mutators**: The naming convention for methods on an
-object are as follows:
-
-- A function that accesses an object's data is a *noun*. Thus, the color
- of a fictional `Pillow` object may be accessed using
- `Pillow::color()`.
-- A function that performs an action is verbal, and this includes
- mutator functions (so-called "setters"). Thus,
- `Pillow::changeColor()`, `Pillow::setColor()`, and `Pillow::fight()` may
- all be appropriate mutator names.
-- Unless a contract (interface or superclass) requires it, we do not ever
- define "getters".
-
-**Constructor Functions**: PHP does not support method overloading
-(that is, declaring multiple methods with the same name, but different
-signatures). While some languages (viz. Java, C++, C#) allow more than
-one constructor, PHP limits you to just one constructor.
-
-One strategy for working around this is to create constructors that take
-vague or generic parameters, and then perform various inspection tasks
-to figure out what the parameters are:
-
-~~~{.php}
-
-~~~
-
-The above quickly degenerates into code that is both slow
-(because of the inspection tasks) and difficult to read and use.
-
-Another option, following Objective-C and Vala, is to create constructor
-functions. These are static functions (in PHP, at least) that can build
-instances. Constructor functions have signatures like
-`Pillow::newFromJSON()` and `Pillow::newFromXML()`.
-
-*This library uses constructor functions.* Generally, a very basic
-constructor is provided for cases where it is needed, but more complex
-cases are handled with specialized constructor functions.
-
-**Namespaces**: The library has been divided up into namespaces
-according to the following principles:
-
-- Each broad service category should have a namespace. Currently, the
- service categories are *Services* and *Storage*.
- * Services handle computing tasks on behalf of the client.
- * Storage handles data storage and retrieval
-- Individual services and storage services may have their own namespace
- if the number of supporting classes requires this.
-- The *Transport* namespace deals with lower-level details that are
- shared across all services.
-
-Otherwise, we have attempted to keep the namespace relatively shallow.
-
-### Balancing Performance and Elegance
-
-Any network-based library must struggle with the inefficiencies of
-working over a network. This library is no exception. We've done our
-best to straddle the line between keeping load times down and making the
-code simple and elegant. Doubtless we have sometimes failed. Please feel
-free to suggest improvements on either side of the scales.
-
-## Documentation Style
-
-This project is documented with PHPDoc.
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
deleted file mode 100644
index 2cc04ad..0000000
--- a/phpunit.xml.dist
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
- tests/Tests/
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/OpenStack/Bootstrap.php b/src/OpenStack/Bootstrap.php
deleted file mode 100644
index 9b9d83d..0000000
--- a/src/OpenStack/Bootstrap.php
+++ /dev/null
@@ -1,298 +0,0 @@
- 'OpenStack\Common\Transport\Guzzle\GuzzleAdapter',
- * // Set the HTTP max wait time to 500 seconds.
- * 'transport.timeout' => 500,
- * );
- * Bootstrap::setConfiguration($config);
- *
- * // Check and get params.
- * if (Bootstrap::hasConf('transport.timeout') {
- * $to = Bootstrap::conf('transport.timeout');
- * }
- *
- * // Or get a param with a default value:
- * $val = Bootstrap::conf('someval', 'default value');
- *
- * // $val will be set to 'default value' because there
- * // is no 'someval' configuration param.
- *
- * ?>
- *
- * STREAM WRAPPERS
- *
- * Stream wrappers allow you to use the built-in file manipulation
- * functions in PHP to interact with other services. Specifically,
- * the OpenStack stream wrappers allow you to use built-in file commands
- * to access Object Storage (Swift) and other OpenStack services using
- * commands like file_get_contents() and fopen().
- *
- * It's awesome. Trust me.
- */
-class Bootstrap
-{
- const VERSION = '0.0.1';
-
- public static $config = [
- // The transport implementation. By default, we use the Guzzle Client
- 'transport' => 'OpenStack\Common\Transport\Guzzle\GuzzleAdapter',
- ];
-
- /**
- * @var \OpenStack\Identity\v2\IdentityService An identity services object
- * created from the global settings.
- */
- public static $identity = null;
-
- /**
- * @var \OpenStack\Common\Transport\ClientInterface A transport client for requests.
- */
- public static $transport = null;
-
- /**
- * Register stream wrappers for OpenStack.
- *
- * This registers the ObjectStorage stream wrappers, which allow you to access
- * ObjectStorage through standard file access mechanisms.
- *
- * // Enable stream wrapper.
- * Bootstrap::useStreamWrappers();
- *
- * // Create a context resource.
- * $cxt = stream_context_create(array(
- * 'tenantid' => '12de21',
- * 'username' => 'foobar',
- * 'password' => 'f78saf7hhlll',
- * 'endpoint' => 'https://identity.hpcloud.com' // <-- not real URL!
- * ));
- *
- * // Get the contents of a Swift object.
- * $content = file_get_contents('swift://public/notes.txt', 'r', false, $cxt);
- */
- public static function useStreamWrappers()
- {
- self::enableStreamWrapper(
- StreamWrapper::DEFAULT_SCHEME,
- 'OpenStack\ObjectStore\v1\Resource\StreamWrapper'
- );
- self::enableStreamWrapper(
- StreamWrapperFS::DEFAULT_SCHEME,
- 'OpenStack\ObjectStore\v1\Resource\StreamWrapperFS'
- );
- }
-
- /**
- * Register a stream wrapper according to its scheme and class
- *
- * @param $scheme Stream wrapper's scheme
- * @param $class The class that contains stream wrapper functionality
- */
- private static function enableStreamWrapper($scheme, $class)
- {
- if (in_array($scheme, stream_get_wrappers())) {
- stream_wrapper_unregister($scheme);
- }
-
- stream_wrapper_register($scheme, $class);
- }
-
- /**
- * Set configuration directives for OpenStack.
- *
- * This merges the provided associative array into the existing
- * configuration parameters (Bootstrap::$config).
- *
- * All of the OpenStack classes share the same configuration. This
- * ensures that a stable runtime environment is maintained.
- *
- * Common configuration directives:
- *
- * - 'transport': The namespaced classname for the transport that
- * should be used. Example: \OpenStack\Common\Transport\Guzzle\GuzzleAdapter
- * - 'transport.debug': The integer 1 for enabling debug, 0 for
- * disabling. Enabling will turn on verbose debugging output
- * for any transport that supports it.
- * - 'transport.timeout': An integer value indicating how long
- * the transport layer should wait for an HTTP request. A
- * transport MAY ignore this parameter, but the ones included
- * with the library honor it.
- * - 'transport.ssl_verify': Set this to false to turn off SSL certificate
- * verification. This is NOT recommended, but is sometimes necessary for
- * certain proxy configurations.
- * - 'transport.proxy': Set the proxy as a string.
- * - 'username' and 'password'
- * - 'tenantid'
- * - 'endpoint': The full URL to identity services. This is used by stream
- * wrappers.
- *
- * @param array $array An associative array of configuration directives.
- */
- public static function setConfiguration($array)
- {
- self::$config = $array + self::$config;
- }
-
- /**
- * Get a configuration option.
- *
- * Get a configuration option by name, with an optional default.
- *
- * @param string $name The name of the configuration option to get.
- * @param mixed $default The default value to return if the name is not found.
- *
- * @return mixed The value, if found; or the default, if set; or null.
- */
- public static function config($name = null, $default = null)
- {
- // If no name is specified, return the entire config array.
- if (empty($name)) {
- return self::$config;
- }
-
- // If the config value exists, return that.
- if (isset(self::$config[$name])) {
- return self::$config[$name];
- }
-
- // Otherwise, just return the default value.
- return $default;
- }
-
- /**
- * Check whether the given configuration option is set.
- *
- * if (Bootstrap::hasConfig('transport')) {
- * syslog(LOG_INFO, 'An alternate transport is supplied.');
- * }
- *
- * @param string $name The name of the item to check for.
- *
- * @return boolean true if the named option is set, false otherwise. Note that
- * the value may be falsey (false, 0, etc.), but if the value is null, this
- * will return false.
- */
- public static function hasConfig($name)
- {
- return isset(self::$config[$name]);
- }
-
- /**
- * Get a \OpenStack\Identity\v2\IdentityService object from the bootstrap config.
- *
- * A factory helper function that uses the bootstrap configuration to create
- * a ready to use \OpenStack\Identity\v2\IdentityService object.
- *
- * @param bool $force Whether to force the generation of a new object even if
- * one is already cached.
- *
- * @return \OpenStack\Identity\v2\IdentityService An authenticated ready to use
- * \OpenStack\Identity\v2\IdentityService object.
- * @throws \OpenStack\Common\Exception When the needed configuration to authenticate
- * is not available.
- */
- public static function identity($force = false)
- {
- $transport = self::transport();
-
- // If we already have an identity make sure the token is not expired.
- if ($force || is_null(self::$identity) || self::$identity->isExpired()) {
-
- // Make sure we have an endpoint to use
- if (!self::hasConfig('endpoint')) {
- throw new Exception('Unable to authenticate. No endpoint supplied.');
- }
-
- // User cannot be an empty string, so we need
- // to do more checking than self::hasConfig(), which returns true
- // if an item exists and is an empty string.
- $user = self::config('username', null);
-
- // Check if we have a username/password
- if (!empty($user) && self::hasConfig('password')) {
- $is = new IdentityService(self::config('endpoint'), $transport);
- $is->authenticateAsUser($user, self::config('password'), self::config('tenantid', null), self::config('tenantname', null));
- self::$identity = $is;
- } else {
- throw new Exception('Unable to authenticate. No user credentials supplied.');
- }
- }
-
- return self::$identity;
- }
-
- /**
- * Get a transport client.
- *
- * @param boolean $reset Whether to recreate the transport client if one already exists.
- *
- * @return \OpenStack\Common\Transport\ClientInterface A transport client.
- */
- public static function transport($reset = false)
- {
- if (is_null(self::$transport) || $reset == true) {
- $options = [
- 'ssl_verify' => self::config('ssl_verify', true),
- 'timeout' => self::config('timeout', 0), // 0 is no timeout.
- 'debug' => self::config('debug', 0),
- ];
- $proxy = self::config('proxy', false);
- if ($proxy) {
- $options['proxy'] = $proxy;
- }
-
- $class = self::config('transport');
- self::$transport = $class::create($options);
- }
-
- return self::$transport;
- }
-}
diff --git a/src/OpenStack/Common/Exception.php b/src/OpenStack/Common/Exception.php
deleted file mode 100644
index 731827a..0000000
--- a/src/OpenStack/Common/Exception.php
+++ /dev/null
@@ -1,27 +0,0 @@
-send($this->createRequest('GET', $uri, null, $options));
- }
-
- public function head($uri, array $options = [])
- {
- return $this->send($this->createRequest('HEAD', $uri, null, $options));
- }
-
- public function post($uri, $body = null, array $options = [])
- {
- return $this->send($this->createRequest('POST', $uri, $body, $options));
- }
-
- public function put($uri, $body = null, array $options = [])
- {
- return $this->send($this->createRequest('PUT', $uri, $body, $options));
- }
-
- public function delete($uri, array $options = [])
- {
- return $this->send($this->createRequest('DELETE', $uri, null, $options));
- }
-}
\ No newline at end of file
diff --git a/src/OpenStack/Common/Transport/ClientInterface.php b/src/OpenStack/Common/Transport/ClientInterface.php
deleted file mode 100644
index 2768061..0000000
--- a/src/OpenStack/Common/Transport/ClientInterface.php
+++ /dev/null
@@ -1,138 +0,0 @@
-getStatusCode());
-
- $this->request = $request;
- $this->response = $response;
- }
-
- /**
- * Factory method that creates an appropriate Exception object based on the
- * Response's status code. The message is constructed here also.
- *
- * @param \OpenStack\Common\Transport\RequestInterface $request The failed request
- * @param \OpenStack\Common\Transport\ResponseInterface $response The API's response
- * @return self
- */
- public static function create(RequestInterface $request, ResponseInterface $response)
- {
- $label = 'A HTTP error occurred';
-
- $status = $response->getStatusCode();
-
- $exceptions = [
- 401 => 'UnauthorizedException',
- 403 => 'ForbiddenException',
- 404 => 'ResourceNotFoundException',
- 405 => 'MethodNotAllowedException',
- 409 => 'ConflictException',
- 411 => 'LengthRequiredException',
- 422 => 'UnprocessableEntityException',
- 500 => 'ServerException'
- ];
-
- $message = sprintf(
- "%s\n[Status] %s (%s)\n[URL] %s\n[Message] %s\n", $label,
- (string) $request->getUrl(),
- $status, $response->getReasonPhrase(),
- (string) $response->getBody()
- );
-
- // Find custom exception class or use default
- $exceptionClass = isset($exceptions[$status])
- ? sprintf("%s\\%s", __NAMESPACE__, $exceptions[$status])
- : __CLASS__;
-
- return new $exceptionClass($message, $request, $response);
- }
-
- /**
- * Returns the server response.
- *
- * @return \OpenStack\Common\Transport\ResponseInterface
- */
- public function getResponse()
- {
- return $this->response;
- }
-
- /**
- * Returns the request that caused error.
- *
- * @return \OpenStack\Common\Transport\RequestInterface
- */
- public function getRequest()
- {
- return $this->request;
- }
-}
\ No newline at end of file
diff --git a/src/OpenStack/Common/Transport/Exception/ResourceNotFoundException.php b/src/OpenStack/Common/Transport/Exception/ResourceNotFoundException.php
deleted file mode 100644
index f4aacda..0000000
--- a/src/OpenStack/Common/Transport/Exception/ResourceNotFoundException.php
+++ /dev/null
@@ -1,30 +0,0 @@
- false,
- 'subscribers' => [new HttpError()],
- 'headers' => ['User-Agent' => self::getDefaultUserAgent()]
- ];
-
- // Inject client and pass in options for adapter
- return new self(new Client($options));
- }
-
- /**
- * Instantiate a new Adapter which wraps a Guzzle client.
- *
- * @param \GuzzleHttp\ClientInterface $guzzle The Client being wrapped
- */
- public function __construct(GuzzleClientInterface $guzzle)
- {
- $this->client = $guzzle;
- }
-
- public function createRequest($method, $uri = null, $body = null, array $options = [])
- {
- $headers = isset($options['headers']) ? $options['headers'] : [];
-
- $request = $this->client->createRequest($method, $uri, [
- 'headers' => $headers,
- 'body' => $body,
- ]);
-
- return new RequestAdapter($request);
- }
-
- /**
- * @inheritDoc
- * @param \OpenStack\Common\Transport\RequestInterface $adapter
- * @return \OpenStack\Common\Transport\ResponseInterface
- * @throws \OpenStack\Common\Transport\Exception\RequestException
- * @throws \GuzzleHttp\Exception\RequestException
- */
- public function send(RequestInterface $adapter)
- {
- try {
- $guzzleResponse = $this->client->send($adapter->getMessage());
- return new ResponseAdapter($guzzleResponse);
- } catch (GuzzleRequestException $e) {
- // In order to satisfy {@see GuzzleHttp\ClientInterface}, Guzzle
- // wraps all exceptions in its own RequestException class. This is
- // not useful for our end-users, so we need to make sure our own
- // versions are returned (Guzzle buffers them).
- $previous = $e->getPrevious();
- if ($previous instanceof Exception\RequestException) {
- throw $previous;
- }
- throw $e;
- }
- }
-
- /**
- * Guzzle handles options using the defaults/ prefix. So if a key is passed
- * in to be set, or got, that contains this prefix - assume that its a
- * Guzzle option, not an adapter one.
- *
- * @inheritDoc
- */
- public function setOption($key, $value)
- {
- $this->client->setDefaultOption($key, $value);
- }
-
- /**
- * Guzzle handles options using the defaults/ prefix. So if a key is passed
- * in to be set, or got, that contains this prefix - assume that its a
- * Guzzle option, not an adapter one.
- *
- * @inheritDoc
- */
- public function getOption($key)
- {
- if ($key == 'base_url') {
- return $this->getBaseUrl();
- } else {
- return $this->client->getDefaultOption($key);
- }
- }
-
- public function getBaseUrl()
- {
- return $this->client->getBaseUrl();
- }
-
- /**
- * Prepends the SDK's version number to the standard Guzzle string.
- *
- * @return string
- */
- public static function getDefaultUserAgent()
- {
- return sprintf("OpenStack/%f %s", Bootstrap::VERSION, Client::getDefaultUserAgent());
- }
-}
\ No newline at end of file
diff --git a/src/OpenStack/Common/Transport/Guzzle/HttpError.php b/src/OpenStack/Common/Transport/Guzzle/HttpError.php
deleted file mode 100644
index f279187..0000000
--- a/src/OpenStack/Common/Transport/Guzzle/HttpError.php
+++ /dev/null
@@ -1,57 +0,0 @@
- ['onComplete', RequestEvents::VERIFY_RESPONSE]];
- }
-
- /**
- * When a request completes, this method is executed. Because this class
- * checks for HTTP errors and handles them, this method checks the HTTP
- * status code and invokes {@see RequestException} if necessary.
- *
- * @param CompleteEvent $event
- * @throws \OpenStack\Common\Transport\Exception\RequestException
- */
- public function onComplete(CompleteEvent $event)
- {
- $status = (int) $event->getResponse()->getStatusCode();
-
- // Has an error occurred (4xx or 5xx status)?
- if ($status >= 400 && $status <= 505) {
- $request = new RequestAdapter($event->getRequest());
- $response = new ResponseAdapter($event->getResponse());
- throw RequestException::create($request, $response);
- }
- }
-}
\ No newline at end of file
diff --git a/src/OpenStack/Common/Transport/Guzzle/MessageAdapter.php b/src/OpenStack/Common/Transport/Guzzle/MessageAdapter.php
deleted file mode 100644
index 266792c..0000000
--- a/src/OpenStack/Common/Transport/Guzzle/MessageAdapter.php
+++ /dev/null
@@ -1,118 +0,0 @@
-setMessage($guzzleMessage);
- }
-
- /**
- * This sets the Guzzle object being wrapped.
- *
- * @param \GuzzleHttp\Message\MessageInterface $guzzleMessage The object being wrapped.
- */
- public function setMessage(GuzzleMessageInterface $guzzleMessage)
- {
- $this->message = $guzzleMessage;
- }
-
- /**
- * @return \GuzzleHttp\Message\MessageInterface
- */
- public function getMessage()
- {
- return $this->message;
- }
-
- public function getProtocolVersion()
- {
- return $this->message->getProtocolVersion();
- }
-
- public function getBody()
- {
- return $this->message->getBody();
- }
-
- public function setBody(/* StreamInterface */ $body = null)
- {
- $this->message->setBody($body);
- }
-
- public function getHeaders()
- {
- return $this->message->getHeaders();
- }
-
- public function hasHeader($header)
- {
- return $this->message->hasHeader($header);
- }
-
- public function getHeader($header, $asArray = false)
- {
- return $this->message->getHeader($header, $asArray);
- }
-
- public function setHeader($header, $value)
- {
- $this->message->setHeader($header, $value);
- }
-
- public function setHeaders(array $headers)
- {
- $this->message->setHeaders($headers);
- }
-
- public function addHeader($header, $value)
- {
- $this->message->addHeader($header, $value);
- }
-
- public function addHeaders(array $headers)
- {
- $this->message->addHeaders($headers);
- }
-
- public function removeHeader($header)
- {
- $this->message->removeHeader($header);
- }
-}
\ No newline at end of file
diff --git a/src/OpenStack/Common/Transport/Guzzle/RequestAdapter.php b/src/OpenStack/Common/Transport/Guzzle/RequestAdapter.php
deleted file mode 100644
index 098f381..0000000
--- a/src/OpenStack/Common/Transport/Guzzle/RequestAdapter.php
+++ /dev/null
@@ -1,55 +0,0 @@
-setMessage($guzzleRequest);
- }
-
- public function getMethod()
- {
- return $this->message->getMethod();
- }
-
- public function setMethod($method)
- {
- $this->message->setMethod($method);
- }
-
- public function getUrl()
- {
- return $this->message->getUrl();
- }
-
- public function setUrl($url)
- {
- $this->message->setUrl($url);
- }
-}
\ No newline at end of file
diff --git a/src/OpenStack/Common/Transport/Guzzle/ResponseAdapter.php b/src/OpenStack/Common/Transport/Guzzle/ResponseAdapter.php
deleted file mode 100644
index 39db781..0000000
--- a/src/OpenStack/Common/Transport/Guzzle/ResponseAdapter.php
+++ /dev/null
@@ -1,50 +0,0 @@
-setMessage($guzzleResponse);
- }
-
- public function getStatusCode()
- {
- return $this->message->getStatusCode();
- }
-
- public function getReasonPhrase()
- {
- return $this->message->getReasonPhrase();
- }
-
- public function json()
- {
- return $this->message->json();
- }
-}
\ No newline at end of file
diff --git a/src/OpenStack/Common/Transport/MessageInterface.php b/src/OpenStack/Common/Transport/MessageInterface.php
deleted file mode 100644
index c82a233..0000000
--- a/src/OpenStack/Common/Transport/MessageInterface.php
+++ /dev/null
@@ -1,160 +0,0 @@
-getHeaders() as $name => $values) {
- * echo $name . ": " . implode(", ", $values);
- * }
- *
- * @return array Returns an associative array of the message's headers.
- */
- public function getHeaders();
-
- /**
- * Checks if a header exists by the given case-insensitive name.
- *
- * @param string $header Case-insensitive header name.
- *
- * @return bool Returns true if any header names match the given header
- * name using a case-insensitive string comparison. Returns false if
- * no matching header name is found in the message.
- */
- public function hasHeader($header);
-
- /**
- * Retrieve a header by the given case-insensitive name.
- *
- * By default, this method returns all of the header values of the given
- * case-insensitive header name as a string concatenated together using
- * a comma. Because some header should not be concatenated together using a
- * comma, this method provides a Boolean argument that can be used to
- * retrieve the associated header values as an array of strings.
- *
- * @param string $header Case-insensitive header name.
- * @param bool $asArray Set to true to retrieve the header value as an
- * array of strings.
- *
- * @return array|string
- */
- public function getHeader($header, $asArray = false);
-
- /**
- * Sets a header, replacing any existing values of any headers with the
- * same case-insensitive name.
- *
- * The header values MUST be a string or an array of strings.
- *
- * @param string $header Header name
- * @param string|array $value Header value(s)
- *
- * @return self Returns the message.
- */
- public function setHeader($header, $value);
-
- /**
- * Sets headers, replacing any headers that have already been set on the
- * message.
- *
- * The array keys MUST be a string. The array values must be either a
- * string or an array of strings.
- *
- * @param array $headers Headers to set.
- *
- * @return self Returns the message.
- */
- public function setHeaders(array $headers);
-
- /**
- * Appends a header value to any existing values associated with the
- * given header name.
- *
- * @param string $header Header name to add
- * @param string $value Value of the header
- *
- * @return self
- */
- public function addHeader($header, $value);
-
- /**
- * Merges in an associative array of headers.
- *
- * Each array key MUST be a string representing the case-insensitive name
- * of a header. Each value MUST be either a string or an array of strings.
- * For each value, the value is appended to any existing header of the same
- * name, or, if a header does not already exist by the given name, then the
- * header is added.
- *
- * @param array $headers Associative array of headers to add to the message
- *
- * @return self
- */
- public function addHeaders(array $headers);
-
- /**
- * Remove a specific header by case-insensitive name.
- *
- * @param string $header HTTP header to remove
- *
- * @return self
- */
- public function removeHeader($header);
-}
\ No newline at end of file
diff --git a/src/OpenStack/Common/Transport/RequestInterface.php b/src/OpenStack/Common/Transport/RequestInterface.php
deleted file mode 100644
index 6033f29..0000000
--- a/src/OpenStack/Common/Transport/RequestInterface.php
+++ /dev/null
@@ -1,66 +0,0 @@
-populateFromArray($value);
- }
-
- /**
- * Internal method that allows for the hydration of this object with an
- * array. It iterates through each element and calls the necessary setter
- * method if it exists.
- *
- * @param array $array The input array
- */
- private function populateFromArray(array $array)
- {
- foreach ($array as $key => $val) {
- if ($key == 'pass') {
- $key = 'password';
- }
- $method = 'set' . $key;
- if ($val && method_exists($this, $method)) {
- $this->$method($val);
- }
- }
- }
-
- /**
- * @param string $scheme
- */
- public function setScheme($scheme)
- {
- $this->scheme = (string)$scheme;
- }
-
- /**
- * @return string
- */
- public function getScheme()
- {
- return $this->scheme;
- }
-
- /**
- * @param string $host
- */
- public function setHost($host)
- {
- $this->host = (string)$host;
- }
-
- /**
- * @return string
- */
- public function getHost()
- {
- return $this->host;
- }
-
- /**
- * @param int $port
- */
- public function setPort($port)
- {
- $this->port = (int)$port;
- }
-
- /**
- * @return int|null
- */
- public function getPort()
- {
- return $this->port;
- }
-
- /**
- * @param string $user
- */
- public function setUser($user)
- {
- $this->user = (string)$user;
- }
-
- /**
- * @return string
- */
- public function getUser()
- {
- return $this->user;
- }
-
- /**
- * @param string $password
- */
- public function setPassword($password)
- {
- $this->password = (string)$password;
- }
-
- /**
- * @return string
- */
- public function getPassword()
- {
- return $this->password;
- }
-
- /**
- * Sets the path to a string value, ensuring that a trailing slash is always
- * added.
- *
- * @param string $path
- */
- public function setPath($path)
- {
- $this->path = rtrim((string)$path, '/');
- }
-
- /**
- * Adds a string path to the existing path value.
- *
- * @param string $path
- */
- public function addPath($path)
- {
- $path = '/' . ltrim((string)$path, '/');
- $this->setPath($this->path . $path);
- }
-
- /**
- * @return string
- */
- public function getPath()
- {
- return $this->path;
- }
-
- /**
- * Sets the query value. If a string is provided, it is expanded according
- * to conventional key=pair representation, where `&' is a delimeter. An
- * array can also be provided.
- *
- * @param string|array $query
- *
- * @throws \InvalidArgumentException
- */
- public function setQuery($query)
- {
- if (is_string($query)) {
- $query = $this->expandQueryString($query);
- } elseif (!is_array($query)) {
- throw new \InvalidArgumentException("Query must be an array");
- }
-
- $this->query = $query;
- }
-
- /**
- * Internal method for expanding a string representation of a query into an
- * array. The return value should be a simple key/value pair. Query arrays
- * are also supported.
- *
- * @param string $value A string based query representation, in the form of
- * ?foo=val&bar=val&baz[]=val_1&baz[]=val_2
- *
- * @return array
- */
- private function expandQueryString($value)
- {
- $parts = explode('&', $value);
- $array = [];
- foreach ($parts as $partArray) {
- $inner = explode('=', $partArray);
- $key = str_replace('[]', '', $inner[0]);
- $val = $inner[1];
-
- if (isset($array[$key])) {
- $array[$key] = [$array[$key], $val];
- } else {
- $array[$key] = $val;
- }
- }
-
- return $array;
- }
-
- /**
- * @param array $query
- */
- public function addQuery(array $query)
- {
- $this->setQuery((array)$this->query + $query);
- }
-
- /**
- * @return array
- */
- public function getQuery()
- {
- return $this->query;
- }
-
- /**
- * @param string $fragment
- */
- public function setFragment($fragment)
- {
- $this->fragment = (string)$fragment;
- }
-
- /**
- * @return string
- */
- public function getFragment()
- {
- return $this->fragment;
- }
-
- /**
- * Shrinks the query array and returns as a string representation.
- *
- * @return string
- */
- private function shrinkQueryArray()
- {
- $url = '?';
- foreach ($this->query as $key => $val) {
- if (is_array($val)) {
- foreach ($val as $subVal) {
- $url .= $key . '[]=' . $subVal . '&';
- }
- } else {
- $url .= $key . '=' . $val . '&';
- }
- }
-
- return rtrim($url, '&');
- }
-
- /**
- * Cast this URL object into a string representation
- *
- * @return string
- */
- public function __toString()
- {
- $url = ($this->scheme) ? $this->scheme . '://' : '//';
-
- if ($this->user && $this->password) {
- $url .= sprintf("%s:%s@", $this->user, $this->password);
- }
-
- $url .= $this->host;
-
- if ($this->port) {
- $url .= ':' . (int)$this->port;
- }
-
- $url .= $this->path;
-
- if (!empty($this->query)) {
- $url .= $this->shrinkQueryArray();
- }
-
- if ($this->fragment) {
- $url .= '#' . $this->fragment;
- }
-
- return $url;
- }
-}
\ No newline at end of file
diff --git a/src/OpenStack/Identity/v2/IdentityService.php b/src/OpenStack/Identity/v2/IdentityService.php
deleted file mode 100644
index 5f19ca3..0000000
--- a/src/OpenStack/Identity/v2/IdentityService.php
+++ /dev/null
@@ -1,740 +0,0 @@
-authenticateAsUser('me@example.com', 'password', '1234567');
- *
- * // The token to use when connecting to other services:
- * $token = $ident->token();
- *
- * // The tenant ID.
- * $tenant = $ident->tenantId();
- *
- * // Details about what services this token can access.
- * $services = $ident->serviceCatalog();
- *
- * // List all available tenants.
- * $tenants = $ident->tenants();
- *
- * // Switch to a different tenant.
- * $ident->rescopeUsingTenantId($tenants[0]['id']);
- *
- * ?>
- *
- * PERFORMANCE CONSIDERATIONS
- *
- * The following methods require network requests:
- *
- * - authenticate()
- * - authenticateAsUser()
- * - tenants()
- * - rescopeUsingTenantId()
- * - rescopeUsingTenantName()
- *
- * Serializing
- *
- * IdentityService has been intentionally built to serialize well.
- * This allows implementors to cache IdentityService objects rather
- * than make repeated requests for identity information.
- *
- */
-class IdentityService
-{
- /**
- * The version of the API currently supported.
- */
- const API_VERSION = '2.0';
-
- /**
- * The full OpenStack accept type.
- */
- const ACCEPT_TYPE = 'application/json';
-
- // This is no longer supported.
- //const ACCEPT_TYPE = 'application/vnd.openstack.identity+json;version=2.0';
-
- /**
- * The URL to the CS endpoint.
- */
- protected $endpoint;
-
- /**
- * The details sent with the token.
- *
- * The exact details of this array will differ depending on what type of
- * authentication is used. For example, authenticating by username and
- * password will set tenant information. Authenticating by username and
- * password, however, will leave the tenant section empty.
- *
- * This is an associative array looking like this:
- *
- * 'auth_123abc321defef99',
- * // Only non-empty for username/password auth.
- * 'tenant' => array(
- * 'id' => '123456',
- * 'name' => 'matt.butcher@hp.com',
- * ),
- * 'expires' => '2012-01-24T12:46:01.682Z'
- * );
- */
- protected $tokenDetails;
-
- /**
- * The service catalog.
- */
- protected $catalog = [];
-
- protected $userDetails;
-
- /**
- * The HTTP Client
- */
- protected $client;
-
- /**
- * Build a new IdentityService object.
- *
- * Each object is bound to a particular identity services endpoint.
- *
- * For the URL, you are advised to use the version without a
- * version number at the end, e.g. http://cs.example.com/ rather
- * than http://cs.example.com/v2.0. The version number must be
- * controlled by the library.
- *
- * If a version is included in the URI, the library will attempt to use
- * that URI.
- *
- * authenticateAsUser($username, $password);
- * ?>
- *
- * @param string $url An URL pointing to the Identity Service endpoint.
- * Note that you do not need the version identifier in the URL, as version
- * information is sent in the HTTP headers rather than in the URL. The URL
- * should always be to an SSL/TLS encrypted endpoint.
- *
- * @param \OpenStack\Common\Transport\ClientInterface $client An optional HTTP client to use when making the requests.
- */
- public function __construct($url, ClientInterface $client = null)
- {
- $parts = parse_url($url);
-
- if (!empty($parts['path'])) {
- $this->endpoint = rtrim($url, '/');
- } else {
- $this->endpoint = rtrim($url, '/') . '/v' . self::API_VERSION;
- }
-
- // Guzzle is the default client to use.
- if (is_null($client)) {
- $this->client = GuzzleAdapter::create();
- } else {
- $this->client = $client;
- }
- }
-
- /**
- * Get the endpoint URL.
- *
- * This includes version number, so in that regard it is not an identical
- * URL to the one passed into the constructor.
- *
- * @return string The complete URL to the identity services endpoint.
- */
- public function url()
- {
- return $this->endpoint;
- }
-
- /**
- * Send an authentication request.
- *
- * EXPERT: This allows authentication requests at a low level. For simple
- * authentication requests using a username, see the
- * authenticateAsUser() method.
- *
- * Here is an example of username/password-based authentication done with
- * the authenticate() method:
- *
- * array(
- * 'username' => $username,
- * 'password' => $password,
- * ),
- * 'tenantId' => $tenantId,
- * );
- * $token = $cs->authenticate($ops);
- * ?>
- *
- * Note that the same authentication can be done by authenticateAsUser().
- *
- * @param array $ops An associative array of authentication operations and
- * their respective parameters.
- *
- * @return string The token. This is returned for simplicity. The full
- * response is used to populate this object's service catalog, etc. The
- * token is also retrievable with token().
- *
- * @throws \OpenStack\Common\Transport\Exception\AuthorizationException If authentication failed.
- * @throws \OpenStack\Common\Exception For abnormal network conditions. The message
- * will give an indication as to the underlying problem.
- */
- public function authenticate(array $ops)
- {
- $url = $this->url() . '/tokens';
- $envelope = [
- 'auth' => $ops,
- ];
-
- $body = json_encode($envelope);
-
- $headers = [
- 'Content-Type' => 'application/json',
- 'Accept' => self::ACCEPT_TYPE,
- 'Content-Length' => strlen($body),
- ];
-
- $response = $this->client->post($url, $body, ['headers' => $headers]);
-
- $this->handleResponse($response);
-
- return $this->token();
- }
-
- /**
- * Authenticate to Identity Services with username, password, and either
- * tenant ID or tenant Name.
- *
- * Given a OpenStack username and password, authenticate to Identity Services.
- * Identity Services will then issue a token that can be used to access other
- * OpenStack services.
- *
- * If a tenant ID is provided, this will also associate the user with the
- * given tenant ID. If a tenant Name is provided, this will associate the user
- * with the given tenant Name. Only the tenant ID or tenant Name needs to be
- * given, not both.
- *
- * If no tenant ID or tenant Name is given, it will likely be necessary to
- * rescopeUsingTenantId() the request (See also tenants()).
- *
- * Other authentication methods:
- * - authenticate()
- *
- * @param string $username A valid username.
- * @param string $password A password string.
- * @param string $tenantId The tenant ID. This can be obtained through the
- * OpenStack console.
- * @param string $tenantName The tenant Name. This can be obtained through the
- * OpenStack console.
- *
- * @throws \OpenStack\Common\Transport\Exception\AuthorizationException If authentication failed.
- * @throws \OpenStack\Common\Exception For abnormal network conditions. The message will give an
- * indication as to the underlying problem.
- */
- public function authenticateAsUser($username, $password, $tenantId = null, $tenantName = null)
- {
- $ops = [
- 'passwordCredentials' => [
- 'username' => $username,
- 'password' => $password,
- ]
- ];
-
- // If a tenant ID is provided, added it to the auth array.
- if (!empty($tenantId)) {
- $ops['tenantId'] = $tenantId;
- } elseif (!empty($tenantName)) {
- $ops['tenantName'] = $tenantName;
- }
-
- return $this->authenticate($ops);
- }
-
- /**
- * Get the token.
- *
- * This will not be populated until after one of the authentication
- * methods has been run.
- *
- * @return string The token ID to be used in subsequent calls.
- */
- public function token()
- {
- return $this->tokenDetails['id'];
- }
-
- /**
- * Get the tenant ID associated with this token.
- *
- * If this token has a tenant ID, the ID will be returned. Otherwise, this
- * will return null.
- *
- * This will not be populated until after an authentication method has been
- * run.
- *
- * @return string The tenant ID if available, or null.
- */
- public function tenantId()
- {
- if (!empty($this->tokenDetails['tenant']['id'])) {
- return $this->tokenDetails['tenant']['id'];
- }
- }
-
- /**
- * Get the tenant name associated with this token.
- *
- * If this token has a tenant name, the name will be returned. Otherwise, this
- * will return null.
- *
- * This will not be populated until after an authentication method has been
- * run.
- *
- * @return string The tenant name if available, or null.
- */
- public function tenantName()
- {
- if (!empty($this->tokenDetails['tenant']['name'])) {
- return $this->tokenDetails['tenant']['name'];
- }
- }
-
- /**
- * Get the token details.
- *
- * This returns an associative array with several pieces of information
- * about the token, including:
- *
- * - id: The token itself
- * - expires: When the token expires
- * - tenant_id: The tenant ID of the authenticated user.
- * - tenant_name: The username of the authenticated user.
- *
- * 'auth_123abc321defef99',
- * 'tenant' => array(
- * 'id' => '123456',
- * 'name' => 'matt.butcher@hp.com',
- * ),
- * 'expires' => '2012-01-24T12:46:01.682Z'
- * );
- *
- * This will not be populated until after authentication has been done.
- *
- * @return array An associative array of details.
- */
- public function tokenDetails()
- {
- return $this->tokenDetails;
- }
-
- /**
- * Check whether the current identity has an expired token.
- *
- * This does not perform a round-trip to the server. Instead, it compares the
- * machine's local timestamp with the server's expiration time stamp. A
- * mis-configured machine timestamp could give spurious results.
- *
- * @return boolean This will return false if there is a current token and it
- * has not yet expired (according to the date info). In all
- * other cases it returns true.
- */
- public function isExpired()
- {
- $details = $this->tokenDetails();
-
- if (empty($details['expires'])) {
- return true;
- }
-
- $currentDateTime = new \DateTime('now');
- $expireDateTime = new \DateTime($details['expires']);
-
- return $currentDateTime > $expireDateTime;
- }
-
- /**
- * Get the service catalog, optionaly filtering by type.
- *
- * This returns the service catalog (largely unprocessed) that
- * is returned during an authentication request. If a type is passed in,
- * only entries of that type are returned. If no type is passed in, the
- * entire service catalog is returned.
- *
- * The service catalog contains information about what services (if any) are
- * available for the present user. Object storage (Swift) Compute instances
- * (Nova) and other services will each be listed here if they are enabled
- * for your user in the current tenant. Only services that have been turned on
- * for the user on the tenant will be available. (That is, even if you *can*
- * create a compute instance, until you have actually created one, it will not
- * show up in this list.)
- *
- * One of the authentication methods MUST be run before obtaining the service
- * catalog.
- *
- * The return value is an indexed array of associative arrays, where each assoc
- * array describes an individual service.
- *
- * 'object-store',
- * 'endpoints' => array(
- * 'tenantId' => '123456',
- * 'adminURL' => 'https://example.hpcloud.net/1.0',
- * 'publicURL' => 'https://example.hpcloud.net/1.0/123456',
- * 'region' => 'region-a.geo-1',
- * 'id' => '1.0',
- * ),
- * ),
- * array(
- * 'name' => 'Identity',
- * 'type' => 'identity'
- * 'endpoints' => array(
- * 'publicURL' => 'https://example.hpcloud.net/1.0/123456',
- * 'region' => 'region-a.geo-1',
- * 'id' => '2.0',
- * 'list' => 'http://example.hpcloud.net/extension',
- * ),
- * )
- *
- * );
- * ?>
- *
- * This will not be populated until after authentication has been done.
- *
- * Types:
- *
- * While this is by no means an exhaustive list, here are a few types that
- * might appear in a service catalog (and upon which you can filter):
- *
- * - identity: Identity Services (i.e. Keystone)
- * - compute: Compute instance (Nova)
- * - object-store: Object Storage (Swift)
- *
- * Other services will be added.
- *
- * @todo Paging on the service catalog is not yet implemented.
- *
- * @return array An associative array representing the service catalog.
- */
- public function serviceCatalog($type = null)
- {
- // If no type is specified, return the entire
- // catalog.
- if (empty($type)) {
- return $this->serviceCatalog;
- }
-
- $list = [];
- foreach ($this->serviceCatalog as $entry) {
- if ($entry['type'] == $type) {
- $list[] = $entry;
- }
- }
-
- return $list;
- }
-
- /**
- * Get information about the currently authenticated user.
- *
- * This returns an associative array of information about the authenticated
- * user, including the user's username and roles.
- *
- * The returned data is structured like this:
- *
- * 'matthew.butcher@hp.com',
- * 'id' => '1234567890'
- * 'roles' => array(
- * array(
- * 'name' => 'domainuser',
- * 'serviceId' => '100',
- * 'id' => '000100400010011',
- * ),
- * // One array for each role...
- * ),
- * )
- * ?>
- *
- * This will not have data until after authentication has been done.
- *
- * @return array An associative array, as described above.
- */
- public function user()
- {
- return $this->userDetails;
- }
-
- /**
- * Get a list of all tenants associated with this account.
- *
- * If a valid token is passed into this object, the method can be invoked
- * before authentication. However, if no token is supplied, this attempts
- * to use the one returned by an authentication call.
- *
- * Returned data will follow this format:
- *
- * "395I91234514446",
- * "name" => "Banking Tenant Services",
- * "description" => "Banking Tenant Services for TimeWarner",
- * "enabled" => true,
- * "created" => "2011-11-29T16:59:52.635Z",
- * "updated" => "2011-11-29T16:59:52.635Z",
- * ),
- * );
- * ?>
- *
- * Note that this method invokes a new request against the remote server.
- *
- * @return array An indexed array of tenant info. Each entry will be an
- * associative array containing tenant details.
- *
- * @throws \OpenStack\Common\Transport\Exception\AuthorizationException If authentication failed.
- * @throws \OpenStack\Common\Exception For abnormal network conditions. The message will give an
- * indication as to the underlying problem.
- */
- public function tenants($token = null)
- {
- $url = $this->url() . '/tenants';
-
- if (empty($token)) {
- $token = $this->token();
- }
-
- $headers = [
- 'X-Auth-Token' => $token,
- 'Accept' => 'application/json'
- ];
-
- $response = $this->client->get($url, ['headers' => $headers]);
-
- return $response->json()['tenants'];
- }
-
- /**
- * Rescope the authentication token to a different tenant.
- *
- * Note that this will rebuild the service catalog and user information for
- * the current object, since this information is sensitive to tenant info.
- *
- * An authentication token can be in one of two states:
- *
- * - unscoped: It has no associated tenant ID.
- * - scoped: It has a tenant ID, and can thus access that tenant's services.
- *
- * This method allows you to do any of the following:
- *
- * - Begin with an unscoped token, and assign it a tenant ID.
- * - Change a token from one tenant ID to another (re-scoping).
- * - Remove the tenant ID from a scoped token (unscoping).
- *
- * @param string $tenantId The tenant ID that this present token should be
- * bound to. If this is the empty string (`''`), the
- * present token will be "unscoped" and its tenant
- * ID will be removed.
- *
- * @return string The authentication token.
- *
- * @throws \OpenStack\Common\Transport\Exception\AuthorizationException If authentication failed.
- * @throws \OpenStack\Common\Exception For abnormal network conditions. The message will give an
- * indication as to the underlying problem.
- */
- public function rescopeUsingTenantId($tenantId)
- {
- $url = $this->url() . '/tokens';
-
- $body = json_encode([
- 'auth' => [
- 'tenantId' => $tenantId,
- 'token' => [
- 'id' => $this->token(),
- ]
- ]
- ]);
-
- $headers = [
- 'Accept' => self::ACCEPT_TYPE,
- 'Content-Type' => 'application/json',
- 'Content-Length' => strlen($body)
- ];
-
- $response = $this->client->post($url, $body, ['headers' => $headers]);
-
- $this->handleResponse($response);
-
- return $this->token();
- }
-
- /**
- * Rescope the authentication token to a different tenant.
- *
- * Note that this will rebuild the service catalog and user information for
- * the current object, since this information is sensitive to tenant info.
- *
- * An authentication token can be in one of two states:
- *
- * - unscoped: It has no associated tenant ID.
- * - scoped: It has a tenant ID, and can thus access that tenant's services.
- *
- * This method allows you to do any of the following:
- *
- * - Begin with an unscoped token, and assign it a tenant ID.
- * - Change a token from one tenant ID to another (re-scoping).
- * - Remove the tenant ID from a scoped token (unscoping).
- *
- * @param string $tenantName The tenant name that this present token should be
- * bound to. If this is the empty string (`''`), the
- * present token will be "unscoped" and its tenant
- * name will be removed.
- *
- * @return string The authentication token.
- *
- * @throws \OpenStack\Common\Transport\Exception\AuthorizationException If authentication failed.
- * @throws \OpenStack\Common\Exception For abnormal network conditions. The message will
- * give an indication as to the underlying problem.
- */
- public function rescopeUsingTenantName($tenantName)
- {
- $url = $this->url() . '/tokens';
-
- $body = json_encode([
- 'auth' => [
- 'tenantName' => $tenantName,
- 'token' => [
- 'id' => $this->token()
- ]
- ]
- ]);
-
- $headers = [
- 'Accept' => self::ACCEPT_TYPE,
- 'Content-Type' => 'application/json',
- 'Content-Length' => strlen($body)
- ];
-
- $response = $this->client->post($url, $body, ['headers' => $headers]);
-
- $this->handleResponse($response);
-
- return $this->token();
- }
-
- /**
- * Given a response object, populate this object.
- *
- * This parses the JSON data and parcels out the data to the appropriate
- * fields.
- *
- * @param \OpenStack\Common\Transport\ResponseInterface $response A response object.
- *
- * @return \OpenStack\Identity\v2\IdentityService $this for the current object so
- * it can be used in chaining.
- */
- protected function handleResponse($response)
- {
- $json = $response->json();
-
- $this->tokenDetails = $json['access']['token'];
- $this->userDetails = $json['access']['user'];
- $this->serviceCatalog = $json['access']['serviceCatalog'];
-
- return $this;
- }
-}
diff --git a/src/OpenStack/ObjectStore/v1/Exception/ContainerNotEmptyException.php b/src/OpenStack/ObjectStore/v1/Exception/ContainerNotEmptyException.php
deleted file mode 100644
index ce254b8..0000000
--- a/src/OpenStack/ObjectStore/v1/Exception/ContainerNotEmptyException.php
+++ /dev/null
@@ -1,29 +0,0 @@
-serviceCatalog();
- $tok = $identity->token();
-
- return self::newFromServiceCatalog($cat, $tok, $region, $client);
- }
-
- /**
- * Given a service catalog and a token, create an ObjectStorage instance.
- *
- * The IdentityService object contains a service catalog listing all of the
- * services to which the present user has access.
- *
- * This builder can scan the catalog and generate a new ObjectStorage
- * instance pointed to the first object storage endpoint in the catalog
- * that matches the specified parameters.
- *
- * @param array $catalog The service catalog from IdentityService::serviceCatalog().
- * This can be either the entire catalog or a catalog
- * filtered to just ObjectStorage::SERVICE_TYPE.
- * @param string $authToken The auth token returned by IdentityService.
- * @param string $region The Object Storage region
- * @param \OpenStack\Common\Transport\ClientInterface $client The HTTP client
- *
- *
- * @return \OpenStack\ObjectStore\v1\ObjectStorage A new ObjectStorage instance.
- */
- public static function newFromServiceCatalog($catalog, $authToken, $region, \OpenStack\Common\Transport\ClientInterface $client = null)
- {
- $c = count($catalog);
- for ($i = 0; $i < $c; ++$i) {
- if ($catalog[$i]['type'] == self::SERVICE_TYPE) {
- foreach ($catalog[$i]['endpoints'] as $endpoint) {
- if (isset($endpoint['publicURL']) && $endpoint['region'] == $region) {
- return new ObjectStorage($authToken, $endpoint['publicURL'], $client);
- }
- }
- }
- }
-
- return false;
-
- }
-
- /**
- * Construct a new ObjectStorage object.
- *
- * Use this if newFromServiceCatalog() does not meet your needs.
- *
- * @param string $authToken A token that will be included in subsequent
- * requests to validate that this client has authenticated
- * correctly.
- * @param string $url The URL to the endpoint. This typically is returned
- * after authentication.
- * @param \OpenStack\Common\Transport\ClientInterface $client The HTTP client
- */
- public function __construct($authToken, $url, ClientInterface $client = null)
- {
- $this->token = $authToken;
- $this->url = $url;
-
- // Guzzle is the default client to use.
- if (is_null($client)) {
- $this->client = GuzzleAdapter::create();
- } else {
- $this->client = $client;
- }
- }
-
- /**
- * Get the authentication token.
- *
- * @return string The authentication token.
- */
- public function token()
- {
- return $this->token;
- }
-
- /**
- * Get the URL endpoint.
- *
- * @return string The URL that is the endpoint for this service.
- */
- public function url()
- {
- return $this->url;
- }
-
- /**
- * Fetch a list of containers for this user.
- *
- * By default, this fetches the entire list of containers for the
- * given user. If you have more than 10,000 containers (who
- * wouldn't?), you will need to use $marker for paging.
- *
- * If you want more controlled paging, you can use $limit to indicate
- * the number of containers returned per page, and $marker to indicate
- * the last container retrieved.
- *
- * Containers are ordered. That is, they will always come back in the
- * same order. For that reason, the pager takes $marker (the name of
- * the last container) as a paging parameter, rather than an offset
- * number.
- *
- * @todo For some reason, ACL information does not seem to be returned
- * in the JSON data. Need to determine how to get that. As a
- * stop-gap, when a container object returned from here has its ACL
- * requested, it makes an additional round-trip to the server to
- * fetch that data.
- *
- * @param int $limit The maximum number to return at a time. The default is
- * -- brace yourself -- 10,000 (as determined by OpenStack. Implementations
- * may vary).
- * @param string $marker The name of the last object seen. Used when paging.
- *
- * @return array An associative array of containers, where the key is the
- * container's name and the value is an \OpenStack\ObjectStore\v1\ObjectStorage\Container
- * object. Results are ordered in server order (the order that the remote
- * host puts them in).
- */
- public function containers($limit = 0, $marker = null)
- {
- $url = $this->url() . '?format=json';
-
- if ($limit > 0) {
- $url .= sprintf('&limit=%d', $limit);
- }
- if (!empty($marker)) {
- $url .= sprintf('&marker=%d', $marker);
- }
-
- $headers = ['X-Auth-Token' => $this->token];
- $response = $this->client->get($url, ['headers' => $headers]);
- $containers = $response->json();
-
- $containerList = [];
- foreach ($containers as $container) {
- $cname = $container['name'];
- $containerList[$cname] = Container::newFromJSON($container, $this->token(), $this->url(), $this->client);
- }
-
- return $containerList;
- }
-
- /**
- * Get a single specific container.
- *
- * This loads only the named container from the remote server.
- *
- * @param string $name The name of the container to load.
- *
- * @return \OpenStack\ObjectStore\v1\Resource\Container A container.
- *
- * @throws \OpenStack\Common\Transport\Exception\ResourceNotFoundException if the named container is not
- * found on the remote server.
- */
- public function container($name)
- {
- $url = $this->url() . '/' . rawurlencode($name);
-
- $headers = ['X-Auth-Token' => $this->token()];
- $response = $this->client->head($url, ['headers' => $headers]);
-
- $status = $response->getStatusCode();
-
- if ($status == 204) {
- return Container::newFromResponse($name, $response, $this->token(), $this->url());
- }
-
- // If we get here, it's not a 404 and it's not a 204.
- throw new Exception(sprintf("Unknown status: %d", $status));
- }
-
- /**
- * Check to see if this container name exists.
- *
- * This method directly checks the remote server. Calling container()
- * or containers() might be more efficient if you plan to work with
- * the resulting container.
- *
- * @param string $name The name of the container to test.
- *
- * @return boolean true if the container exists, false if it does not.
- *
- * @throws \OpenStack\Common\Exception If an unexpected network error occurs.
- */
- public function hasContainer($name)
- {
- try {
- $container = $this->container($name);
- } catch (ResourceNotFoundException $e) {
- return false;
- }
-
- return true;
- }
-
- /**
- * Create a container with the given name.
- *
- * This creates a new container on the ObjectStorage
- * server with the name provided in $name.
- *
- * A boolean is returned when the operation did not generate an error
- * condition.
- *
- * - true means that the container was created.
- * - false means that the container was not created because it already
- * exists.
- *
- * Any actual error will cause an exception to be thrown. These will
- * be the HTTP-level exceptions.
- *
- * ACLs
- *
- * Swift supports an ACL stream that allows for specifying (with
- * certain caveats) various levels of read and write access. However,
- * there are two standard settings that cover the vast majority of
- * cases.
- *
- * - Make the resource private: This grants read and write access to
- * ONLY the creating user tenant. This is the default; it can also be
- * specified with ACL::makeNonPublic().
- * - Make the resource public: This grants READ permission to any
- * requesting host, yet only allows the creator to WRITE to the
- * object. This level can be granted by ACL::makePublic().
- *
- * Note that ACLs operate at a container level. Thus, marking a
- * container public will allow access to ALL objects inside of the
- * container.
- *
- * To find out whether an existing container is public, you can
- * write something like this:
- *
- * container('my_container');
- *
- * //Check the permission on the ACL:
- * $boolean = $container->acl()->isPublic();
- * ?>
- *
- * For details on ACLs, see \OpenStack\ObjectStore\v1\Resource\ACL.
- *
- * @param string $name The name of the container.
- * @param object $acl \OpenStack\ObjectStore\v1\Resource\ACL An access control
- * list object. By default, a container is non-public
- * (private). To change this behavior, you can add a
- * custom ACL. To make the container publically
- * readable, you can use this: \OpenStack\ObjectStore\v1\Resource\ACL::makePublic().
- * @param array $metadata An associative array of metadata to attach to the
- * container.
- *
- * @return boolean true if the container was created, false if the container
- * was not created because it already exists.
- */
- public function createContainer($name, ACL $acl = null, $metadata = [])
- {
- $url = $this->url() . '/' . rawurlencode($name);
- $headers = ['X-Auth-Token' => $this->token()];
-
- if (!empty($metadata)) {
- $prefix = Container::CONTAINER_METADATA_HEADER_PREFIX;
- $headers += Container::generateMetadataHeaders($metadata, $prefix);
- }
-
- // Add ACLs to header.
- if (!empty($acl)) {
- $headers += $acl->headers();
- }
-
- $data = $this->client->put($url, null, ['headers' => $headers]);
-
- $status = $data->getStatusCode();
-
- if ($status == 201) {
- return true;
- } elseif ($status == 202) {
- return false;
- } else {
- // According to the OpenStack docs, there are no other return codes.
- throw new Exception('Server returned unexpected code: ' . $status);
- }
- }
-
- /**
- * Alias of createContainer().
- *
- * At present, there is no distinction in the Swift REST API between
- * creating an updating a container. In the future this may change, so
- * you are encouraged to use this alias in cases where you clearly intend
- * to update an existing container.
- */
- public function updateContainer($name, ACL $acl = null, $metadata = [])
- {
- return $this->createContainer($name, $acl, $metadata);
- }
-
- /**
- * Change the container's ACL.
- *
- * This will attempt to change the ACL on a container. If the
- * container does not already exist, it will be created first, and
- * then the ACL will be set. (This is a relic of the OpenStack Swift
- * implementation, which uses the same HTTP verb to create a container
- * and to set the ACL.)
- *
- * @param string $name The name of the container.
- * @param object $acl \OpenStack\ObjectStore\v1\Resource\ACL An ACL. To make the
- * container publically readable, use ACL::makePublic().
- *
- * @return boolean true if the cointainer was created, false otherwise.
- */
- public function changeContainerACL($name, ACL $acl)
- {
- // Oddly, the way to change an ACL is to issue the
- // same request as is used to create a container.
- return $this->createContainer($name, $acl);
- }
-
- /**
- * Delete an empty container.
- *
- * Given a container name, this attempts to delete the container in
- * the object storage.
- *
- * The container MUST be empty before it can be deleted. If it is not,
- * an \OpenStack\ObjectStore\v1\Exception\ContainerNotEmptyException will
- * be thrown.
- *
- * @param string $name The name of the container.
- *
- * @return boolean true if the container was deleted, false if the container
- * was not found (and hence, was not deleted).
- *
- * @throws \OpenStack\ObjectStore\v1\Exception\ContainerNotEmptyException if the container is not empty.
- *
- * @throws \OpenStack\Common\Exception if an unexpected response code is returned. While this should never happen on
- * OpenStack servers, forks of OpenStack may choose to extend object storage in a way
- * that results in a non-standard code.
- */
- public function deleteContainer($name)
- {
- $url = $this->url() . '/' . rawurlencode($name);
-
- try {
- $headers = ['X-Auth-Token' => $this->token()];
- $data = $this->client->delete($url, ['headers' => $headers]);
- } catch (ResourceNotFoundException $e) {
- return false;
- } catch (ConflictException $e) {
- // XXX: I'm not terribly sure about this. Why not just throw the
- // ConflictException?
- throw new ContainerNotEmptyException(
- "Non-empty container cannot be deleted",
- $e->getRequest(),
- $e->getResponse()
- );
- }
-
- $status = $data->getStatusCode();
-
- // 204 indicates that the container has been deleted.
- if ($status == 204) {
- return true;
- } else {
- // OpenStacks documentation doesn't suggest any other return codes.
- throw new Exception('Server returned unexpected code: ' . $status);
- }
- }
-
- /**
- * Retrieve account info.
- *
- * This returns information about:
- *
- * - The total bytes used by this Object Storage instance (`bytes`).
- * - The number of containers (`count`).
- *
- * @return array An associative array of account info. Typical keys are:
- * - bytes: Bytes consumed by existing content.
- * - containers: Number of containers.
- * - objects: Number of objects.
- *
- * @throws \OpenStack\Common\Transport\Exception\AuthorizationException if the user credentials
- * are invalid or have expired.
- */
- public function accountInfo()
- {
- $headers = ['X-Auth-Token' => $this->token()];
- $response = $this->client->head($this->url(), ['headers' => $headers]);
-
- return [
- 'bytes' => $response->getHeader('X-Account-Bytes-Used', 0),
- 'containers' => $response->getHeader('X-Account-Container-Count', 0),
- 'objects' => $response->getHeader('X-Account-Container-Count', 0)
- ];
- }
-}
diff --git a/src/OpenStack/ObjectStore/v1/Resource/ACL.php b/src/OpenStack/ObjectStore/v1/Resource/ACL.php
deleted file mode 100644
index 774307b..0000000
--- a/src/OpenStack/ObjectStore/v1/Resource/ACL.php
+++ /dev/null
@@ -1,567 +0,0 @@
-
- *
- * Public read access is granted like this:
- *
- *
- *
- * (Note that in both cases, what is returned is an instance of an ACL with
- * all of the necessary configuration done.)
- *
- * Sometimes you will need more sophisticated access control rules. The
- * following grants READ access to anyone coming from an `example.com`
- * domain, but grants WRITE access only to the account `admins:`
- *
- * addReferrer(ACL::READ, '*.example.com');
- *
- * // Allow only people in the account 'admins' access to
- * // write.
- * $acl->addAccount(ACL::WRITE, 'admins');
- *
- * // Allow example.com users to view the container
- * // listings:
- * $acl->allowListings();
- *
- * ?>
- *
- * Notes
- *
- * - The current implementation does not do any validation of rules.
- * This will likely change in the future.
- * - There is discussion in OpenStack about providing a different or
- * drastically improved ACL mechanism. This class would then be
- * replaced by a new mechanism.
- *
- * For a detailed description of the rules for ACL creation,
- * @see http://swift.openstack.org/misc.html#acls
- */
-class ACL
-{
- /**
- * Read flag.
- *
- * This is for an ACL of the READ type.
- */
- const READ = 1;
- /**
- * Write flag.
- *
- * This is for an ACL of the WRITE type.
- */
- const WRITE = 2;
- /**
- * Flag for READ and WRITE.
- *
- * This is equivalent to `ACL::READ | ACL::WRITE`
- */
- const READ_WRITE = 3; // self::READ | self::WRITE;
-
- /**
- * Header string for a read flag.
- */
- const HEADER_READ = 'X-Container-Read';
- /**
- * Header string for a write flag.
- */
- const HEADER_WRITE = 'X-Container-Write';
-
- protected $rules = [];
-
- /**
- * Allow READ access to the public.
- *
- * This grants the following:
- *
- * - READ to any host, with container listings.
- *
- * @return \OpenStack\ObjectStore\v1\Resource\ACL an ACL object with the
- * appopriate permissions set.
- */
- public static function makePublic()
- {
- $acl = new ACL();
- $acl->addReferrer(self::READ, '*');
- $acl->allowListings();
-
- return $acl;
- }
-
- /**
- * Disallow all public access.
- *
- * Non-public is the same as private. Private, however, is a reserved
- * word in PHP.
- *
- * This does not grant any permissions. OpenStack interprets an object
- * with no permissions as a private object.
- *
- * @return \OpenStack\ObjectStore\v1\Resource\ACL an ACL object with the
- * appopriate permissions set.
- */
- public static function makeNonPublic()
- {
- // Default ACL is private.
- return new ACL();
- }
-
- /**
- * Alias of ACL::makeNonPublic().
- */
- public static function makePrivate()
- {
- return self::makeNonPublic();
- }
-
- /**
- * Given a list of headers, get the ACL info.
- *
- * This is a utility for processing headers and discovering any ACLs embedded
- * inside the headers.
- *
- * @param array $headers An associative array of headers.
- *
- * @return \OpenStack\ObjectStore\v1\Resource\ACL A new ACL.
- */
- public static function newFromHeaders($headers)
- {
- $acl = new ACL();
-
- // READ rules.
- $rules = [];
- if (!empty($headers[self::HEADER_READ])) {
- $read = $headers[self::HEADER_READ];
- $rules = explode(',', $read);
- foreach ($rules as $rule) {
- $ruleArray = self::parseRule(self::READ, $rule);
- if (!empty($ruleArray)) {
- $acl->rules[] = $ruleArray;
- }
- }
- }
-
- // WRITE rules.
- $rules = [];
- if (!empty($headers[self::HEADER_WRITE])) {
- $write = $headers[self::HEADER_WRITE];
- $rules = explode(',', $write);
- foreach ($rules as $rule) {
- $ruleArray = self::parseRule(self::WRITE, $rule);
- if (!empty($ruleArray)) {
- $acl->rules[] = $ruleArray;
- }
- }
- }
-
- //throw new \Exception(print_r($acl->rules(), true));
- return $acl;
- }
-
- /**
- * Parse a rule.
- *
- * This attempts to parse an ACL rule. It is not particularly
- * fault-tolerant.
- *
- * @param int $perm The permission (ACL::READ, ACL::WRITE).
- * @param string $rule The string rule to parse.
- *
- * @return array The rule as an array.
- */
- public static function parseRule($perm, $rule)
- {
- // This regular expression generates the following:
- //
- // array(
- // 0 => ENTIRE RULE
- // 1 => WHOLE EXPRESSION, no whitespace
- // 2 => domain compontent
- // 3 => 'rlistings', set if .rincludes is the directive
- // 4 => account name
- // 5 => :username
- // 6 => username
- // );
- $exp = '/^\s*(.r:([a-zA-Z0-9\*\-\.]+)|\.(rlistings)|([a-zA-Z0-9]+)(\:([a-zA-Z0-9]+))?)\s*$/';
-
- $matches = [];
- preg_match($exp, $rule, $matches);
-
- $entry = ['mask' => $perm];
- if (!empty($matches[2])) {
- $entry['host'] = $matches[2];
- } elseif (!empty($matches[3])) {
- $entry['rlistings'] = true;
- } elseif (!empty($matches[4])) {
- $entry['account'] = $matches[4];
- if (!empty($matches[6])) {
- $entry['user'] = $matches[6];
- }
- }
-
- return $entry;
- }
-
- /**
- * Create a new ACL.
- *
- * This creates an empty ACL with no permissions granted. When no
- * permissions are granted, the file is effectively private
- * (nonPublic()).
- *
- * Use add* methods to add permissions.
- */
- public function __construct() {}
-
- /**
- * Grant ACL access to an account.
- *
- * Optionally, a user may be given to further limit access.
- *
- * This is used to restrict access to a particular account and, if so
- * specified, a specific user on that account.
- *
- * If just an account is given, any user on that account will be
- * automatically granted access.
- *
- * If an account and a user is given, only that user of the account is
- * granted access.
- *
- * If $user is an array, every user in the array will be granted
- * access under the provided account. That is, for each user in the
- * array, an entry of the form `account:user` will be generated in the
- * final ACL.
- *
- * At this time there does not seem to be a way to grant global write
- * access to an object.
- *
- * @param int $perm ACL::READ, ACL::WRITE or ACL::READ_WRITE (which is the
- * same as ACL::READ|ACL::WRITE).
- * @param string $account The name of the account.
- * @param mixed $user The name of the user, or optionally an indexed array of
- * user names.
- *
- * @return \OpenStack\ObjectStore\v1\Resource\ACL $this for current object so
- * the method can be used in chaining.
- */
- public function addAccount($perm, $account, $user = null)
- {
- $rule = ['account' => $account];
-
- if (!empty($user)) {
- $rule['user'] = $user;
- }
-
- $this->addRule($perm, $rule);
-
- return $this;
- }
-
- /**
- * Allow (or deny) a hostname or host pattern.
- *
- * In current Swift implementations, only READ rules can have host
- * patterns. WRITE permissions cannot be granted to hostnames.
- *
- * Formats:
- * - Allow any host: '*'
- * - Allow exact host: 'www.example.com'
- * - Allow hosts in domain: '.example.com'
- * - Disallow exact host: '-www.example.com'
- * - Disallow hosts in domain: '-.example.com'
- *
- * Note that a simple minus sign ('-') is illegal, though it seems it
- * should be "disallow all hosts."
- *
- * @param string $perm The permission being granted. One of ACL:READ,
- * ACL::WRITE, or ACL::READ_WRITE.
- * @param string $host A host specification string as described above.
- *
- * @return \OpenStack\ObjectStore\v1\Resource\ACL $this for current object so
- * the method can be used in chaining.
- */
- public function addReferrer($perm, $host = '*')
- {
- $this->addRule($perm, ['host' => $host]);
-
- return $this;
- }
-
- /**
- * Add a rule to the appropriate stack of rules.
- *
- * @param int $perm One of the predefined permission constants.
- * @param array $rule A rule array.
- *
- * @return \OpenStack\ObjectStore\v1\Resource\ACL $this for current object so
- * the method can be used in chaining.
- */
- protected function addRule($perm, $rule)
- {
- $rule['mask'] = $perm;
-
- $this->rules[] = $rule;
-
- return $this;
- }
-
- /**
- * Allow hosts with READ permissions to list a container's content.
- *
- * By default, granting READ permission on a container does not grant
- * permission to list the contents of a container. Setting the
- * ACL::allowListings() permission will allow matching hosts to also list
- * the contents of a container.
- *
- * In the current Swift implementation, there is no mechanism for
- * allowing some hosts to get listings, while denying others.
- *
- * @return \OpenStack\ObjectStore\v1\Resource\ACL $this for current object so
- * the method can be used in chaining.
- */
- public function allowListings()
- {
- $this->rules[] = [
- 'mask' => self::READ,
- 'rlistings' => true,
- ];
-
- return $this;
- }
-
- /**
- * Get the rules array for this ACL.
- *
- * @return array An array of associative arrays of rules.
- */
- public function rules()
- {
- return $this->rules;
- }
-
- /**
- * Generate HTTP headers for this ACL.
- *
- * If this is called on an empty object, an empty set of headers is
- * returned.
- *
- * @return array Array of headers
- */
- public function headers()
- {
- $headers = [];
- $readers = [];
- $writers = [];
-
- // Create the rule strings. We need two copies, one for READ and
- // one for WRITE.
- foreach ($this->rules as $rule) {
- // We generate read and write rules separately so that the
- // generation logic has a chance to respond to the differences
- // allowances for READ and WRITE ACLs.
- if (self::READ & $rule['mask']) {
- $ruleStr = $this->ruleToString(self::READ, $rule);
- if (!empty($ruleStr)) {
- $readers[] = $ruleStr;
- }
- }
- if (self::WRITE & $rule['mask']) {
- $ruleStr = $this->ruleToString(self::WRITE, $rule);
- if (!empty($ruleStr)) {
- $writers[] = $ruleStr;
- }
- }
- }
-
- // Create the HTTP headers.
- if (!empty($readers)) {
- $headers[self::HEADER_READ] = implode(',', $readers);
- }
- if (!empty($writers)) {
- $headers[self::HEADER_WRITE] = implode(',', $writers);
- }
-
- return $headers;
- }
-
- /**
- * Convert a rule to a string.
- *
- * @param int $perm The permission for which to generate the rule.
- * @param array $rule A rule array.
- */
- protected function ruleToString($perm, $rule)
- {
- // Some rules only apply to READ.
- if (self::READ & $perm) {
-
- // Host rule.
- if (!empty($rule['host'])) {
- return '.r:' . $rule['host'];
- }
-
- // Listing rule.
- if (!empty($rule['rlistings'])) {
- return '.rlistings';
- }
- }
-
- // READ and WRITE both allow account/user rules.
- if (!empty($rule['account'])) {
-
- // Just an account name.
- if (empty($rule['user'])) {
- return $rule['account'];
- }
-
- // Account + multiple users.
- elseif (is_array($rule['user'])) {
- $buffer = [];
- foreach ($rule['user'] as $user) {
- $buffer[] = $rule['account'] . ':' . $user;
- }
-
- return implode(',', $buffer);
-
- }
-
- // Account + one user.
- else {
- return $rule['account'] . ':' . $rule['user'];
- }
- }
- }
-
- /**
- * Check if the ACL marks this private.
- *
- * This returns true only if this ACL does not grant any permissions
- * at all.
- *
- * @return boolean true if this is private (non-public), false if any
- * permissions are granted via this ACL.
- */
- public function isNonPublic()
- {
- return empty($this->rules);
- }
-
- /**
- * Alias of isNonPublic().
- */
- public function isPrivate()
- {
- return $this->isNonPublic();
- }
-
- /**
- * Check whether this object allows public reading.
- *
- * This will return true the ACL allows (a) any host to access
- * the item, and (b) it allows container listings.
- *
- * This checks whether the object allows public reading,
- * not whether it is ONLY allowing public reads.
- *
- * @see ACL::makePublic().
- *
- * @return boolean Whether or not the object allows public reading.
- */
- public function isPublic()
- {
- $allowsAllHosts = false;
- $allowsRListings = false;
- foreach ($this->rules as $rule) {
- if (self::READ & $rule['mask']) {
- if (!empty($rule['rlistings'])) {
- $allowsRListings = true;
- } elseif (!empty($rule['host']) && trim($rule['host']) == '*') {
- $allowsAllHosts = true;
- }
- }
- }
-
- return $allowsAllHosts && $allowsRListings;
- }
-
- /**
- * Implements the magic `__toString()` PHP function.
- *
- * This allows you to `print $acl` and get back
- * a pretty string.
- *
- * @return string The ACL represented as a string.
- */
- public function __toString()
- {
- $headers = $this->headers();
-
- $buffer = [];
- foreach ($headers as $k => $v) {
- $buffer[] = $k . ': ' . $v;
- }
-
- return implode("\t", $buffer);
- }
-
-}
diff --git a/src/OpenStack/ObjectStore/v1/Resource/Container.php b/src/OpenStack/ObjectStore/v1/Resource/Container.php
deleted file mode 100644
index 59b2155..0000000
--- a/src/OpenStack/ObjectStore/v1/Resource/Container.php
+++ /dev/null
@@ -1,1084 +0,0 @@
-container('foo');
- *
- * // Create an object.
- * $obj = new Object('bar.txt');
- * $obj->setContent('Example content.', 'text/plain');
- *
- * // Save the new object in the container.
- * $container->save($obj);
- *
- * ?>
- *
- * Once you have a Container, you manipulate objects inside of the
- * container.
- *
- * @todo Add support for container metadata.
- */
-class Container implements \Countable, \IteratorAggregate
-{
- /**
- * The prefix for any piece of metadata passed in HTTP headers.
- */
- const METADATA_HEADER_PREFIX = 'X-Object-Meta-';
- const CONTAINER_METADATA_HEADER_PREFIX = 'X-Container-Meta-';
-
- //protected $properties = array();
- protected $name = null;
-
- // These were both changed from 0 to null to allow lazy loading.
- protected $count = null;
- protected $bytes = null;
-
- protected $token;
- protected $url;
- protected $baseUrl;
- protected $acl;
- protected $metadata;
-
- /**
- * The HTTP Client
- */
- protected $client;
-
- /**
- * Transform a metadata array into headers.
- *
- * This is used when storing an object in a container.
- *
- * @param array $metadata An associative array of metadata. Metadata is not
- * escaped in any way (there is no codified spec by which to escape), so
- * make sure that keys are alphanumeric (dashes allowed) and values are
- * ASCII-armored with no newlines.
- * @param string $prefix A prefix for the metadata headers.
- *
- * @return array An array of headers.
- *
- * @see http://docs.openstack.org/bexar/openstack-object-storage/developer/content/ch03s03.html#d5e635
- * @see http://docs.openstack.org/bexar/openstack-object-storage/developer/content/ch03s03.html#d5e700
- */
- public static function generateMetadataHeaders(array $metadata, $prefix = null)
- {
- if (empty($prefix)) {
- $prefix = Container::METADATA_HEADER_PREFIX;
- }
- $headers = [];
- foreach ($metadata as $key => $val) {
- $headers[$prefix . $key] = $val;
- }
-
- return $headers;
- }
- /**
- * Create an object URL.
- *
- * Given a base URL and an object name, create an object URL.
- *
- * This is useful because object names can contain certain characters
- * (namely slashes (`/`)) that are normally URLencoded when they appear
- * inside of path sequences.
- *
- * Swift does not distinguish between `%2F` and a slash character, so
- * this is not strictly necessary.
- *
- * @param string $base The base URL. This is not altered; it is just prepended
- * to the returned string.
- * @param string $oname The name of the object.
- *
- * @return string The URL to the object. Characters that need escaping will be
- * escaped, while slash characters are not. Thus, the URL will
- * look pathy.
- */
- public static function objectUrl($base, $oname)
- {
- if (strpos($oname, '/') === false) {
- return $base . '/' . rawurlencode($oname);
- }
-
- $oParts = explode('/', $oname);
- $buffer = [];
- foreach ($oParts as $part) {
- $buffer[] = rawurlencode($part);
- }
- $newname = implode('/', $buffer);
-
- return $base . '/' . $newname;
- }
-
- /**
- * Extract object attributes from HTTP headers.
- *
- * When OpenStack sends object attributes, it sometimes embeds them in
- * HTTP headers with a prefix. This function parses the headers and
- * returns the attributes as name/value pairs.
- *
- * Note that no decoding (other than the minimum amount necessary) is
- * done to the attribute names or values. The Open Stack Swift
- * documentation does not prescribe encoding standards for name or
- * value data, so it is left up to implementors to choose their own
- * strategy.
- *
- * @param array $headers An associative array of HTTP headers.
- * @param string $prefix The prefix on metadata headers.
- *
- * @return array An associative array of name/value attribute pairs.
- */
- public static function extractHeaderAttributes($headers, $prefix = null)
- {
- if (empty($prefix)) {
- $prefix = Container::METADATA_HEADER_PREFIX;
- }
- $attributes = [];
- $offset = strlen($prefix);
- foreach ($headers as $header => $value) {
-
- $index = strpos($header, $prefix);
- if ($index === 0) {
- $key = substr($header, $offset);
- $attributes[$key] = $value;
- }
- }
-
- return $attributes;
- }
-
- /**
- * Create a new Container from JSON data.
- *
- * This is used in lieue of a standard constructor when
- * fetching containers from ObjectStorage.
- *
- * @param array $jsonArray An associative array as returned by
- * json_decode($foo, true);
- * @param string $token The auth token.
- * @param string $url The base URL. The container name is automatically
- * appended to this at construction time.
- * @param \OpenStack\Common\Transport\ClientInterface $client A HTTP transport client.
- *
- * @return \OpenStack\ObjectStore\v1\Resource\Container A new container object.
- */
- public static function newFromJSON($jsonArray, $token, $url, ClientInterface $client = null)
- {
- $container = new Container($jsonArray['name'], null, null, $client);
-
- $container->baseUrl = $url;
-
- $container->url = $url . '/' . rawurlencode($jsonArray['name']);
- $container->token = $token;
-
- // Access to count and bytes is basically controlled. This is is to
- // prevent a local copy of the object from getting out of sync with
- // the remote copy.
- if (!empty($jsonArray['count'])) {
- $container->count = $jsonArray['count'];
- }
-
- if (!empty($jsonArray['bytes'])) {
- $container->bytes = $jsonArray['bytes'];
- }
-
- //syslog(LOG_WARNING, print_r($jsonArray, true));
- return $container;
- }
-
- /**
- * Given an OpenStack HTTP response, build a Container.
- *
- * This factory is intended for use by low-level libraries. In most
- * cases, the standard constructor is preferred for client-size
- * Container initialization.
- *
- * @param string $name The name of the container.
- * @param object $response \OpenStack\Common\Transport\Response The HTTP response object from the Transporter layer
- * @param string $token The auth token.
- * @param string $url The base URL. The container name is automatically
- * appended to this at construction time.
- * @param \OpenStack\Common\Transport\ClientInterface $client A HTTP transport client.
- *
- * @return \OpenStack\ObjectStore\v1\Resource\Container The Container object, initialized and ready for use.
- */
- public static function newFromResponse($name, $response, $token, $url, ClientInterface $client = null)
- {
- $container = new Container($name, null, null, $client);
- $container->bytes = $response->getHeader('X-Container-Bytes-Used', 0);
- $container->count = $response->getHeader('X-Container-Object-Count', 0);
- $container->baseUrl = $url;
- $container->url = $url . '/' . rawurlencode($name);
- $container->token = $token;
-
- $headers = self::reformatHeaders($response->getHeaders());
-
- $container->acl = ACL::newFromHeaders($headers);
-
- $prefix = Container::CONTAINER_METADATA_HEADER_PREFIX;
- $metadata = Container::extractHeaderAttributes($headers, $prefix);
- $container->setMetadata($metadata);
-
- return $container;
- }
-
- /**
- * Construct a new Container.
- *
- * Typically a container should be created by ObjectStorage::createContainer().
- * Get existing containers with ObjectStorage::container() or
- * ObjectStorage::containers(). Using the constructor directly has some
- * side effects of which you should be aware.
- *
- * Simply creating a container does not save the container remotely.
- *
- * Also, this does no checking of the underlying container. That is, simply
- * constructing a Container in no way guarantees that such a container exists
- * on the origin object store.
- *
- * The constructor involves a selective lazy loading. If a new container is created,
- * and one of its accessors is called before the accessed values are initialized, then
- * this will make a network round-trip to get the container from the remote server.
- *
- * Containers loaded from ObjectStorage::container() or Container::newFromRemote()
- * will have all of the necessary values set, and thus will not require an extra network
- * transaction to fetch properties.
- *
- * The practical result of this:
- *
- * - If you are creating a new container, it is best to do so with
- * ObjectStorage::createContainer().
- * - If you are manipulating an existing container, it is best to load the
- * container with ObjectStorage::container().
- * - If you are simply using the container to fetch resources from the
- * container, you may wish to use `new Container($name, $url, $token)`
- * and then load objects from that container. Note, however, that
- * manipulating the container directly will likely involve an extra HTTP
- * transaction to load the container data.
- * - When in doubt, use the ObjectStorage methods. That is always the safer
- * option.
- *
- * @param string $name The name.
- * @param string $url The full URL to the container.
- * @param string $token The auth token.
- * @param \OpenStack\Common\Transport\ClientInterface $client A HTTP transport client.
- */
- public function __construct($name , $url = null, $token = null, ClientInterface $client = null)
- {
- $this->name = $name;
- $this->url = $url;
- $this->token = $token;
-
- // Guzzle is the default client to use.
- if (is_null($client)) {
- $this->client = GuzzleAdapter::create();
- } else {
- $this->client = $client;
- }
- }
-
- /**
- * Get the name of this container.
- *
- * @return string The name of the container.
- */
- public function name()
- {
- return $this->name;
- }
-
- /**
- * Get the number of bytes in this container.
- *
- * @return int The number of bytes in this container.
- */
- public function bytes()
- {
- if (is_null($this->bytes)) {
- $this->loadExtraData();
- }
-
- return $this->bytes;
- }
-
- /**
- * Get the container metadata.
- *
- * Metadata (also called tags) are name/value pairs that can be
- * attached to a container.
- *
- * Names can be no longer than 128 characters, and values can be no
- * more than 256. UTF-8 or ASCII characters are allowed, though ASCII
- * seems to be preferred.
- *
- * If the container was loaded from a container listing, the metadata
- * will be fetched in a new HTTP request. This is because container
- * listings do not supply the metadata, while loading a container
- * directly does.
- *
- * @return array An array of metadata name/value pairs.
- */
- public function metadata()
- {
- // If created from JSON, metadata does not get fetched.
- if (!isset($this->metadata)) {
- $this->loadExtraData();
- }
-
- return $this->metadata;
- }
-
- /**
- * Set the tags on the container.
- *
- * Container metadata (sometimes called "tags") provides a way of
- * storing arbitrary name/value pairs on a container.
- *
- * Since saving a container is a function of the ObjectStorage
- * itself, if you change the metadta, you will need to call
- * ObjectStorage::updateContainer() to save the new container metadata
- * on the remote object storage.
- *
- * (Similarly, when it comes to objects, an object's metdata is saved
- * by the container.)
- *
- * Names can be no longer than 128 characters, and values can be no
- * more than 256. UTF-8 or ASCII characters are allowed, though ASCII
- * seems to be preferred.
- *
- * @return \OpenStack\ObjectStore\v1\Resource\Container $this so the method can
- * be used in chaining.
- */
- public function setMetadata($metadata)
- {
- $this->metadata = $metadata;
-
- return $this;
- }
-
- /**
- * Get the number of items in this container.
- *
- * Since Container implements Countable, the PHP builtin count() can be used
- * on a Container instance:
- *
- * count();
- * ?>
- *
- * @return int The number of items in this container.
- */
- public function count()
- {
- if (is_null($this->count)) {
- $this->loadExtraData();
- }
-
- return $this->count;
- }
-
- /**
- * Save an Object into Object Storage.
- *
- * This takes an \OpenStack\ObjectStore\v1\Resource\Object
- * and stores it in the given container in the present
- * container on the remote object store.
- *
- * @param object $obj \OpenStack\ObjectStore\v1\Resource\Object The object to
- * store.
- * @param resource $file An optional file argument that, if set, will be
- * treated as the contents of the object.
- *
- * @return boolean true if the object was saved.
- *
- * @throws \OpenStack\Common\Transport\Exception\LengthRequiredException if the Content-Length could not be
- * determined and chunked encoding was
- * not enabled. This should not occur for
- * this class, which always automatically
- * generates Content-Length headers.
- * However, subclasses could generate
- * this error.
- * @throws \OpenStack\Common\Transport\Exception\UnprocessableEntityException if the checksum passed here does not
- * match the checksum calculated remotely.
- * @throws \OpenStack\Common\Exception when an unexpected (usually
- * network-related) error condition arises.
- */
- public function save(Object $obj, $file = null)
- {
- if (empty($this->token)) {
- throw new Exception('Container does not have an auth token.');
- }
- if (empty($this->url)) {
- throw new Exception('Container does not have a URL to send data.');
- }
-
- //$url = $this->url . '/' . rawurlencode($obj->name());
- $url = self::objectUrl($this->url, $obj->name());
-
- // See if we have any metadata.
- $headers = [];
- $md = $obj->metadata();
- if (!empty($md)) {
- $headers = self::generateMetadataHeaders($md, Container::METADATA_HEADER_PREFIX);
- }
-
- // Set the content type.
- $headers['Content-Type'] = $obj->contentType();
-
-
- // Add content encoding, if necessary.
- $encoding = $obj->encoding();
- if (!empty($encoding)) {
- $headers['Content-Encoding'] = rawurlencode($encoding);
- }
-
- // Add content disposition, if necessary.
- $disposition = $obj->disposition();
- if (!empty($disposition)) {
- $headers['Content-Disposition'] = $disposition;
- }
-
- // Auth token.
- $headers['X-Auth-Token'] = $this->token;
-
- // Add any custom headers:
- $moreHeaders = $obj->additionalHeaders();
- if (!empty($moreHeaders)) {
- $headers += $moreHeaders;
- }
-
- if (empty($file)) {
- // Now build up the rest of the headers:
- $headers['Etag'] = $obj->eTag();
-
- // If chunked, we set transfer encoding; else
- // we set the content length.
- if ($obj->isChunked()) {
- // How do we handle this? Does the underlying
- // stream wrapper pay any attention to this?
- $headers['Transfer-Encoding'] = 'chunked';
- } else {
- $headers['Content-Length'] = $obj->contentLength();
- }
- $response = $this->client->put($url, $obj->content(), ['headers' => $headers]);
- } else {
- // Rewind the file.
- rewind($file);
-
- // XXX: What do we do about Content-Length header?
- //$headers['Transfer-Encoding'] = 'chunked';
- $stat = fstat($file);
- $headers['Content-Length'] = $stat['size'];
-
- // Generate an eTag:
- $hash = hash_init('md5');
- hash_update_stream($hash, $file);
- $etag = hash_final($hash);
- $headers['Etag'] = $etag;
-
- // Not sure if this is necessary:
- rewind($file);
-
- $response = $this->client->put($url, $file, ['headers' => $headers]);
- }
-
- if ($response->getStatusCode() != 201) {
- throw new Exception('An unknown error occurred while saving: ' . $response->status());
- }
-
- return true;
- }
-
- /**
- * Update an object's metadata.
- *
- * This updates the metadata on an object without modifying anything
- * else. This is a convenient way to set additional metadata without
- * having to re-upload a potentially large object.
- *
- * Swift's behavior during this operation is sometimes unpredictable,
- * particularly in cases where custom headers have been set.
- * Use with caution.
- *
- * @param object $obj \OpenStack\ObjectStore\v1\Resource\Object The object to update.
- *
- * @return boolean true if the metadata was updated.
- *
- * @throws \OpenStack\Common\Transport\Exception\ResourceNotFoundException if the object does not already
- * exist on the object storage.
- */
- public function updateMetadata(Object $obj)
- {
- $url = self::objectUrl($this->url, $obj->name());
- $headers = ['X-Auth-Token' => $this->token];
-
- // See if we have any metadata. We post this even if there
- // is no metadata.
- $metadata = $obj->metadata();
- if (!empty($metadata)) {
- $headers += self::generateMetadataHeaders($metadata, Container::METADATA_HEADER_PREFIX);
- }
-
- // In spite of the documentation's claim to the contrary,
- // content type IS reset during this operation.
- $headers['Content-Type'] = $obj->contentType();
-
- // The POST verb is for updating headers.
-
- $response = $this->client->post($url, $obj->content(), ['headers' => $headers]);
-
- if ($response->getStatusCode() != 202) {
- throw new Exception(sprintf(
- "An unknown error occurred while saving: %d", $response->status()
- ));
- }
-
- return true;
- }
-
- /**
- * Copy an object to another place in object storage.
- *
- * An object can be copied within a container. Essentially, this will
- * give you duplicates of the file, each with a new name.
- *
- * An object can be copied to another container if the name of the
- * other container is specified, and if that container already exists.
- *
- * Note that there is no MOVE operation. You must copy and then DELETE
- * in order to achieve that.
- *
- * @param object $obj \OpenStack\ObjectStore\v1\Resource\Object The object to
- * copy. This object MUST already be saved on the remote server. The body of
- * the object is not sent. Instead, the copy operation is performed on the
- * remote server. You can, and probably should, use a RemoteObject here.
- * @param string $newName The new name of this object. If you are copying a
- * cross containers, the name can be the same. If you are copying within
- * the same container, though, you will need to supply a new name.
- * @param string $container The name of the alternate container. If this is
- * set, the object will be saved into this container. If this is not sent,
- * the copy will be performed inside of the original container.
- */
- public function copy(Object $obj, $newName, $container = null)
- {
- $sourceUrl = self::objectUrl($this->url, $obj->name());
-
- if (empty($newName)) {
- throw new Exception("An object name is required to copy the object.");
- }
-
- // Figure out what container we store in.
- if (empty($container)) {
- $container = $this->name;
- }
- $container = rawurlencode($container);
- $destUrl = self::objectUrl('/' . $container, $newName);
-
- $headers = [
- 'X-Auth-Token' => $this->token,
- 'Destination' => $destUrl,
- 'Content-Type' => $obj->contentType(),
- ];
-
- $response = $this->client->send(
- $this->client->createRequest('COPY', $sourceUrl, null, ['headers' => $headers])
- );
-
- if ($response->getStatusCode() != 201) {
- throw new Exception("An unknown condition occurred during copy. " . $response->getStatusCode());
- }
-
- return true;
- }
-
- /**
- * Get the object with the given name.
- *
- * This fetches a single object with the given name. It downloads the
- * entire object at once. This is useful if the object is small (under
- * a few megabytes) and the content of the object will be used. For
- * example, this is the right operation for accessing a text file
- * whose contents will be processed.
- *
- * For larger files or files whose content may never be accessed, use
- * proxyObject(), which delays loading the content until one of its
- * content methods (e.g. RemoteObject::content()) is called.
- *
- * This does not yet support the following features of Swift:
- *
- * - Byte range queries.
- * - If-Modified-Since/If-Unmodified-Since
- * - If-Match/If-None-Match
- *
- * @param string $name The name of the object to load.
- *
- * @return \OpenStack\ObjectStore\v1\Resource\RemoteObject A remote object with the content already stored locally.
- */
- public function object($name)
- {
- $url = self::objectUrl($this->url, $name);
- $headers = ['X-Auth-Token' => $this->token];
-
- $response = $this->client->get($url, ['headers' => $headers]);
-
- if ($response->getStatusCode() != 200) {
- throw new Exception('An unknown error occurred while saving: ' . $response->status());
- }
-
- $remoteObject = RemoteObject::newFromHeaders($name, self::reformatHeaders($response->getHeaders()), $this->token, $url, $this->client);
- $remoteObject->setContent($response->getBody());
-
- return $remoteObject;
- }
-
- /**
- * Fetch an object, but delay fetching its contents.
- *
- * This retrieves all of the information about an object except for
- * its contents. Size, hash, metadata, and modification date
- * information are all retrieved and wrapped.
- *
- * The data comes back as a RemoteObject, which can be used to
- * transparently fetch the object's content, too.
- *
- * Why Use This?
- *
- * The regular object() call will fetch an entire object, including
- * its content. This may not be desireable for cases where the object
- * is large.
- *
- * This method can fetch the relevant metadata, but delay fetching
- * the content until it is actually needed.
- *
- * Since RemoteObject extends Object, all of the calls that can be
- * made to an Object can also be made to a RemoteObject. Be aware,
- * though, that calling RemoteObject::content() will initiate another
- * network operation.
- *
- * @param string $name The name of the object to fetch.
- *
- * @return \OpenStack\ObjectStore\v1\Resource\RemoteObject A remote object ready for use.
- */
- public function proxyObject($name)
- {
- $url = self::objectUrl($this->url, $name);
- $headers = ['X-Auth-Token' => $this->token];
-
- $response = $this->client->head($url, ['headers' => $headers]);
-
- if ($response->getStatusCode() != 200) {
- throw new Exception('An unknown error occurred while saving: ' . $response->status());
- }
-
- $headers = self::reformatHeaders($response->getHeaders());
-
- return RemoteObject::newFromHeaders($name, $headers, $this->token, $url, $this->client);
- }
-
- /**
- * Get a list of objects in this container.
- *
- * This will return a list of objects in the container. With no parameters, it
- * will attempt to return a listing of all objects in the container. However,
- * by setting contraints, you can retrieve only a specific subset of objects.
- *
- * Note that OpenStacks Swift will return no more than 10,000 objects
- * per request. When dealing with large datasets, you are encouraged
- * to use paging.
- *
- * Paging
- *
- * Paging is done with a combination of a limit and a marker. The
- * limit is an integer indicating the maximum number of items to
- * return. The marker is the string name of an object. Typically, this
- * is the last object in the previously returned set. The next batch
- * will begin with the next item after the marker (assuming the marker
- * is found.)
- *
- * @param int $limit An integer indicating the maximum number of items to
- * return. This cannot be greater than the Swift maximum (10k).
- * @param string $marker The name of the object to start with. The query will
- * begin with the next object AFTER this one.
- *
- * @return array List of RemoteObject or Subdir instances.
- */
- public function objects($limit = null, $marker = null)
- {
- return $this->objectQuery([], $limit, $marker);
- }
-
- /**
- * Retrieve a list of Objects with the given prefix.
- *
- * Object Storage containers support directory-like organization. To
- * get a list of items inside of a particular "subdirectory", provide
- * the directory name as a "prefix". This will return only objects
- * that begin with that prefix.
- *
- * (Directory-like behavior is also supported by using "directory
- * markers". See objectsByPath().)
- *
- * Prefixes
- *
- * Prefixes are basically substring patterns that are matched against
- * files on the remote object storage.
- *
- * When a prefix is used, object storage will begin to return not just
- * Object instsances, but also Subdir instances. A Subdir is simply a
- * container for a "path name".
- *
- * Delimiters
- *
- * Object Storage (OpenStack Swift) does not have a native concept of
- * files and directories when it comes to paths. Instead, it merely
- * represents them and simulates their behavior under specific
- * circumstances.
- *
- * The default behavior (when prefixes are used) is to treat the '/'
- * character as a delimiter. Thus, when it encounters a name like
- * this: `foo/bar/baz.txt` and the prefix is `foo/`, it will
- * parse return a Subdir called `foo/bar`.
- *
- * Similarly, if you store a file called `foo:bar:baz.txt` and then
- * set the delimiter to `:` and the prefix to `foo:`, it will return
- * the Subdir `foo:bar`. However, merely setting the delimiter back to
- * `/` will not allow you to query `foo/bar` and get the contents of
- * `foo:bar`.
- *
- * Setting $delimiter will tell the Object Storage server which
- * character to parse the filenames on. This means that if you use
- * delimiters other than '/', you need to be very consistent with your
- * usage or else you may get surprising results.
- *
- * @param string $prefix The leading prefix.
- * @param string $delimiter The character used to delimit names. By default,
- * this is '/'.
- * @param int $limit An integer indicating the maximum number of items to
- * return. This cannot be greater than the Swift maximum (10k).
- * @param string $marker The name of the object to start with. The query will
- * begin with the next object AFTER this one.
- *
- * @return array List of RemoteObject or Subdir instances.
- */
- public function objectsWithPrefix($prefix, $delimiter = '/', $limit = null, $marker = null)
- {
- $params = [
- 'prefix' => $prefix,
- 'delimiter' => $delimiter
- ];
-
- return $this->objectQuery($params, $limit, $marker);
- }
-
- /**
- * Specify a path (subdirectory) to traverse.
- *
- * OpenStack Swift provides two basic ways to handle directory-like
- * structures. The first is using a prefix (see objectsWithPrefix()).
- * The second is to create directory markers and use a path.
- *
- * A directory marker is just a file with a name that is
- * directory-like. You create it exactly as you create any other file.
- * Typically, it is 0 bytes long.
- *
- * save($dir);
- * ?>
- *
- * Using objectsByPath() with directory markers will return a list of
- * Object instances, some of which are regular files, and some of
- * which are just empty directory marker files. When creating
- * directory markers, you may wish to set metadata or content-type
- * information indicating that they are directory markers.
- *
- * At one point, the OpenStack documentation suggested that the path
- * method was legacy. More recent versions of the documentation no
- * longer indicate this.
- *
- * @param string $path The path prefix.
- * @param string $delimiter The character used to delimit names. By default,
- * this is '/'.
- * @param int $limit An integer indicating the maximum number of items to
- * return. This cannot be greater than the Swift maximum (10k).
- * @param string $marker The name of the object to start with. The query will
- * begin with the next object AFTER this one.
- */
- public function objectsByPath($path, $delimiter = '/', $limit = null, $marker = null)
- {
- $params = [
- 'path' => $path,
- 'delimiter' => $delimiter,
- ];
-
- return $this->objectQuery($params, $limit, $marker);
- }
-
- /**
- * Get the URL to this container.
- *
- * Any container that has been created will have a valid URL. If the
- * Container was set to be public (See
- * ObjectStorage::createContainer()) will be accessible by this URL.
- *
- * @return string The URL.
- */
- public function url()
- {
- return $this->url;
- }
-
- /**
- * Get the ACL.
- *
- * Currently, if the ACL wasn't added during object construction,
- * calling acl() will trigger a request to the remote server to fetch
- * the ACL. Since only some Swift calls return ACL data, this is an
- * unavoidable artifact.
- *
- * Calling this on a Container that has not been stored on the remote
- * ObjectStorage will produce an error. However, this should not be an
- * issue, since containers should always come from one of the
- * ObjectStorage methods.
- *
- * @todo Determine how to get the ACL from JSON data.
- *
- * @return \OpenStack\ObjectStore\v1\Resource\ACL An ACL, or null if the ACL could not be retrieved.
- */
- public function acl()
- {
- if (!isset($this->acl)) {
- $this->loadExtraData();
- }
-
- return $this->acl;
- }
-
- /**
- * Get missing fields.
- *
- * Not all containers come fully instantiated. This method is sometimes
- * called to "fill in" missing fields.
- *
- * @return \OpenStack\ObjectStore\v1\Resource\Container
- */
- protected function loadExtraData()
- {
- // If URL and token are empty, we are dealing with a local item that
- // has not been saved, and was not created with Container::createContainer().
- // We treat this as an error condition.
- if (empty($this->url) || empty($this->token)) {
- throw new Exception('Remote data cannot be fetched. A Token and endpoint URL are required.');
- }
-
- // Do a GET on $url to fetch headers.
- $headers = ['X-Auth-Token' => $this->token];
- $response = $this->client->get($this->url, ['headers' => $headers]);
-
- $headers = self::reformatHeaders($response->getHeaders());
- // Get ACL.
- $this->acl = ACL::newFromHeaders($headers);
-
- // Update size and count.
- $this->bytes = $response->getHeader('X-Container-Bytes-Used', 0);
- $this->count = $response->getHeader('X-Container-Object-Count', 0);
-
- // Get metadata.
- $prefix = Container::CONTAINER_METADATA_HEADER_PREFIX;
- $this->setMetadata(Container::extractHeaderAttributes($headers, $prefix));
-
- return $this;
- }
-
- /**
- * Perform the HTTP query for a list of objects and de-serialize the
- * results.
- */
- protected function objectQuery($params = [], $limit = null, $marker = null)
- {
- if (isset($limit)) {
- $params['limit'] = (int) $limit;
- if (!empty($marker)) {
- $params['marker'] = (string) $marker;
- }
- }
-
- // We always want JSON.
- $params['format'] = 'json';
-
- $query = http_build_query($params);
- $query = str_replace('%2F', '/', $query);
- $url = $this->url . '?' . $query;
-
- $headers = ['X-Auth-Token' => $this->token];
-
- $response = $this->client->get($url, ['headers' => $headers]);
-
- // The only codes that should be returned are 200 and the ones
- // already thrown by GET.
- if ($response->getStatusCode() != 200) {
- throw new Exception('An unknown exception occurred while processing the request.');
- }
-
- $json = $response->json();
-
- // Turn the array into a list of RemoteObject instances.
- $list = [];
- foreach ($json as $item) {
- if (!empty($item['subdir'])) {
- $list[] = new Subdir($item['subdir'], $params['delimiter']);
- } elseif (empty($item['name'])) {
- throw new Exception('Unexpected entity returned.');
- } else {
- //$url = $this->url . '/' . rawurlencode($item['name']);
- $url = self::objectUrl($this->url, $item['name']);
- $list[] = RemoteObject::newFromJSON($item, $this->token, $url, $this->client);
- }
- }
-
- return $list;
- }
-
- /**
- * Return the iterator of contents.
- *
- * A Container is Iterable. This means that you can use a container in
- * a `foreach` loop directly:
- *
- * name();
- * }
- * ?>
- *
- * The above is equivalent to doing the following:
- *
- * objects();
- * foreach ($objects as $object) {
- * print $object->name();
- * }
- * ?>
- *
- * Note that there is no way to pass any constraints into an iterator.
- * You cannot limit the number of items, set an marker, or add a
- * prefix.
- */
- public function getIterator()
- {
- return new \ArrayIterator($this->objects());
- }
-
- /**
- * Remove the named object from storage.
- *
- * @param string $name The name of the object to remove.
- *
- * @return boolean true if the file was deleted, false if no such file is
- * found.
- */
- public function delete($name)
- {
- $url = self::objectUrl($this->url, $name);
- $headers = [
- 'X-Auth-Token' => $this->token,
- ];
-
- try {
- $response = $this->client->delete($url, ['headers' => $headers]);
- } catch (ResourceNotFoundException $e) {
- return false;
- }
-
- if ($response->getStatusCode() != 204) {
- throw new Exception(sprintf(
- "An unknown exception occured while deleting %s", $name
- ));
- }
-
- return true;
- }
-
- /**
- * Reformat the headers array to remove a nested array.
- *
- * For example, headers coming in could be in the format:
- *
- * $headers = [
- * 'Content-Type' => [
- * [0] => 'Foo',
- * ],
- * ];
- *
- * This method would reformat the array into:
- *
- * $headers = [
- * 'Content-Type' => 'Foo',
- * ];
- *
- * Note, for cases where multiple values for a header are needed this method
- * should not be used.
- *
- * @param array $headers A headers array from the response.
- *
- * @return array A new shallower array.
- */
- public static function reformatHeaders(array $headers)
- {
- $newHeaders = [];
-
- foreach ($headers as $name => $header) {
- $newHeaders[$name] = $header[0];
- }
-
- return $newHeaders;
- }
-}
diff --git a/src/OpenStack/ObjectStore/v1/Resource/Object.php b/src/OpenStack/ObjectStore/v1/Resource/Object.php
deleted file mode 100644
index 1efc0c3..0000000
--- a/src/OpenStack/ObjectStore/v1/Resource/Object.php
+++ /dev/null
@@ -1,524 +0,0 @@
-name = $name;
-
- if (!is_null($content)) {
- $this->content = $content;
- }
- if (!empty($type)) {
- $this->contentType = $type;
- }
- }
-
- /**
- * Set the metadata.
- *
- * OpenStack allows you to specify metadata for a file. Metadata items
- * must follow these conventions:
- *
- * - names must contain only letters, numbers, and short dashes. Since
- * OpenStack normalizes the name to begin with uppercase, it is
- * suggested that you follow this convetion: Foo, not foo. Or you
- * can do your own normalizing (such as converting all to lowercase.
- * OpenStack limits the name length to 126 unicode chars.
- * - values must be encoded if they contain newlines or binary data.
- * While the exact encoding is up to you, Base-64 encoding is probably
- * your best bet. OpenStack limits the value to 256 unicode chars.
- *
- * (The docs are ambiguous -- they say chars, but they may mean
- * bytes.)
- *
- * This library does only minimal processing of metadata, and does no
- * error checking, escaping, etc. This is up to the implementor. The
- * OpenStack Swift implementation does not dictate what encoding is
- * used, though it suggests url encoding of both name and values.
- *
- * Currently, no length checking is performed in the library, nor is
- * any encoding of the data performed.
- *
- * IMPORTANT: Current versions of OpenStack Swift normalize metadata
- * names so that the name is always given an initial capital leter.
- * That is, `foo` becomes `Foo`.
- *
- * @param array $array An associative array of metadata names to values.
- *
- * @return \OpenStack\ObjectStore\v1\Resource\Object $this so the method can be
- * used in chaining.
- */
- public function setMetadata(array $array)
- {
- $this->metadata = $array;
-
- return $this;
- }
-
- /**
- * Get any associated metadata.
- *
- * This returns an associative array of all metadata for this object.
- *
- * @return array An associative array of metadata. This may be empty.
- */
- public function metadata()
- {
- return $this->metadata;
- }
-
- /**
- * Override (change) the name of an object.
- *
- * Note that this changes only the local copy of an object. It
- * does not rename the remote copy. In fact, changing the local name
- * and then saving it will result in a new object being created in the
- * object store.
- *
- * To copy an object:
- * @see \OpenStack\ObjectStore\v1\Resource\Container::copyObject().
- *
- * @param string $name A file or object name.
- *
- * @return \OpenStack\ObjectStore\v1\Resource\Object $this so the method can be
- * used in chaining.
- */
- public function setName($name)
- {
- $this->name = $name;
-
- return $this;
- }
-
- /**
- * Get the name.
- *
- * Returns the name of an object. If the name has been overwritten
- * using setName(), this will return the latest (overwritten) name.
- *
- * @return string The name of the object.
- */
- public function name()
- {
- return $this->name;
- }
-
- /**
- * Set the content type (MIME type) for the object.
- *
- * Object storage is, to a certain degree, content-type aware. For
- * that reason, a content type is mandatory.
- *
- * The default MIME type used is `application/octet-stream`, which is
- * the generic content type for a byte stream. Where possible, you
- * should set a more accurate content type.
- *
- * All HTTP type options are allowed. So, for example, you can add a
- * charset to a text type:
- *
- * setContentType('text/html; charset=iso-8859-13');
- * ?>
- *
- * Content type is not parsed or verified locally (though it is
- * remotely). It can be dangerous, too, to allow users to specify a
- * content type.
- *
- * @param string $type A valid content type.
- *
- * @return \OpenStack\ObjectStore\v1\Resource\Object $this so the method can be
- * used in chaining.
- */
- public function setContentType($type)
- {
- $this->contentType = $type;
-
- return $this;
- }
-
- /**
- * Get the content type.
- *
- * This returns the currently set content type.
- *
- * @return string The content type, including any additional options.
- */
- public function contentType()
- {
- return $this->contentType;
- }
-
- /**
- * Set the content for this object.
- *
- * Place the content into the object. Typically, this is string
- * content that will be stored remotely.
- *
- * PHP's string is backed by a robust system that can accomodate
- * moderately sized files. However, it is best to keep strings short
- * (<2MB, for example -- test for your own system's sweet spot).
- * Larger data may be better handled with file system entries or
- * database storage.
- *
- * Note that the OpenStack will not allow files larger than 5G, and
- * PHP will likely croak well before that marker. So use discretion.
- *
- * @param string $content The content of the object.
- * @param string $type The content type (MIME type). This can be set here for
- * convenience, or you can call setContentType() directly.
- *
- * @return \OpenStack\ObjectStore\v1\Resource\Object $this so the method can be
- * used in chaining.
- */
- public function setContent($content, $type = null)
- {
- $this->content = $content;
- if (!empty($type)) {
- $this->contentType = $type;
- }
-
- return $this;
- }
-
- /**
- * Retrieve the content.
- *
- * Retrieve the ENTIRE content of an object.
- *
- * Note that this may be binary data (depending on what the original
- * content is). PHP strings are generally binary safe, but use this
- * with caution if you do not know what kind of data is stored in an
- * object.
- *
- * OpenStack does not do anything to validate that the content type is
- * accurate. While contentType() is intended to provide useful
- * information, poorly managed data can be written with the wrong
- * content type.
- *
- * When extending this class, you should make sure that this function
- * returns the entire contents of an object.
- *
- * @return string The content of the file.
- */
- public function content()
- {
- return $this->content;
- }
-
- /**
- * Calculate the content length.
- *
- * This returns the number of bytes in a piece of content (not
- * the number of characters). Among other things, it is used to let
- * the remote object store know how big of an object to expect when
- * transmitting data.
- *
- * When extending this class, you should make sure to calculate the
- * content length appropriately.
- *
- * @return int The length of the content, in bytes.
- */
- public function contentLength()
- {
- // strlen() is binary safe (or at least it seems to be).
- return strlen($this->content);
- }
-
- /**
- * Generate an ETag for the ObjectStorage server.
- *
- * OpenStack uses ETag to pass validation data. This generates an ETag
- * using an MD5 hash of the content.
- *
- * When extending this class, generate an ETag by creating an MD5 of
- * the entire object's content (but not the metadata or name).
- *
- * @return string An MD5 value as a string of 32 hex digits (0-9a-f).
- */
- public function eTag()
- {
- return md5($this->content);
- }
-
- /**
- * Set the encoding for a file.
- *
- * You can use content encoding on compressed content to indicate to
- * the receiving agent that a file is encoded using a specific
- * compression type.
- *
- * Typical compression types are 'gzip', 'zip', and 'compress', though
- * many others exist.
- *
- * This allows you, for example, to save a zipped file, yet preserve
- * its underlying content type. For example, for a gzipped text/plain
- * file, you can set the content type to "text/plain" and the encoding
- * to "gzip". This allows many user agents to receive the compressed
- * data and automatically decompress them and display them correctly.
- *
- * @param string $encoding A valid encoding type.
- *
- * @return \OpenStack\ObjectStore\v1\Resource\Object $this so the method can be
- * used in chaining.
- */
- public function setEncoding($encoding)
- {
- $this->contentEncoding = $encoding;
-
- return $this;
- }
-
- /**
- * Get the encoding (if any) for this object.
- *
- * Encoding is used to indicate how a file was encoded or compressed.
- * See setEncoding() for more information.
- *
- * @return string The encoding type.
- */
- public function encoding()
- {
- return $this->contentEncoding;
- }
-
- /**
- * Set the content disposition.
- *
- * This makes it possible to have the file act like a download (in a
- * browser or similar agent), even if the MIME type normally triggers
- * a display.
- *
- * The typical value for this is:
- *
- * setDisposition('attachment; filename=foo.png');
- * ?>
- *
- * A disposition string should not include any newline characters or
- * binary data.
- *
- * @param string $disposition A valid disposition declaration. These are
- * defined in various HTTP specifications.
- *
- * @return \OpenStack\ObjectStore\v1\Resource\Object $this so the method can be
- * used in chaining.
- */
- public function setDisposition($disposition)
- {
- $this->contentDisposition = $disposition;
-
- return $this;
- }
-
- /**
- * Get the current disposition string, if any.
- *
- * See setDisposition() for discussion.
- *
- * @return string The disposition string, or null if none is set.
- */
- public function disposition()
- {
- return $this->contentDisposition;
- }
-
- /**
- * Set additional headers for storage.
- *
- * EXPERT: You will need to understand OpenStack internals to use this
- * effectively.
- *
- * Headers set here will be added to the HTTP request during save
- * operations. They are not merged into existing headers until
- * save-time.
- *
- * This provides a mechanism for adding extension headers. CORS
- * headers and possibly others are stored by Swift, but have no
- * semantic value to Swift or to popular user agents.
- *
- * There are a few things to note about this mechanism:
- *
- * - Existing headers cannot be overwritten. Only new headers can be
- * added.
- * - Headers are not merged. They are simply sent to the remote
- * server. A new object must be retrieved from the server before
- * these headers will be accessible.
- * - Swift only stores certain headers. If you supply an unrecognized
- * header to Swift, it may simply ignore it.
- * - The RemoteObject::headers() method provides access to all of the
- * headers returned from Swift.
- * - Headers are merged in as they are, with no cleaning, encoding, or
- * checking. You must ensure that the headers are in the proper
- * format.
- *
- * @param array $headers An associative array where each name is an HTTP
- * header name, and each value is the HTTP header value. No encoding or
- * escaping is done.
- *
- * @return \OpenStack\ObjectStore\v1\Resource\Object $this so the method can be
- * used in chaining.
- */
- public function setAdditionalHeaders($headers)
- {
- $this->additionalHeaders = $headers;
-
- return $this;
- }
-
- /**
- * Return additional headers.
- *
- * Headers here have likely not been stored remotely until
- * Container::save() is called on the object.
- */
- public function additionalHeaders()
- {
- return $this->additionalHeaders;
- }
-
- /**
- * Remove headers.
- *
- * This takes an array of header names, and removes
- * any matching headers. Typically, only headers set
- * by setAdditionalHeaders() are removed from an Object.
- * (RemoteObject works differently).
- *
- * Many headers are generated automatically, such as
- * Content-Type and Content-Length. Removing these
- * will simply result in their being regenerated.
- *
- * @param array $keys The header names to be removed.
- *
- * @return \OpenStack\ObjectStore\v1\Resource\Object $this for the current
- * object so it can be used in chaining methods.
- */
- public function removeHeaders($keys)
- {
- foreach ($keys as $k) {
- unset($this->additionalHeaders[$k]);
- }
-
- return $this;
- }
-
- /**
- * This object should be transmitted in chunks.
- *
- * Indicates whether or not this object should be transmitted as
- * chunked data (in HTTP).
- *
- * This should be used when (a) the file size is large, or (b) the
- * exact size of the file is unknown.
- *
- * If this returns true, it does not guarantee that the data
- * will be transmitted in chunks. But it recommends that the
- * underlying transport layer use chunked encoding.
- *
- * The contentLength() method is not called for chunked transfers. So
- * if this returns true, contentLength() is ignored.
- *
- * @return boolean true to recommend chunked transfer, false otherwise.
- */
- public function isChunked()
- {
- // Currently, this value is hard-coded. The default Object
- // implementation does not get chunked.
- return false;
- }
-}
diff --git a/src/OpenStack/ObjectStore/v1/Resource/RemoteObject.php b/src/OpenStack/ObjectStore/v1/Resource/RemoteObject.php
deleted file mode 100644
index 3670ab0..0000000
--- a/src/OpenStack/ObjectStore/v1/Resource/RemoteObject.php
+++ /dev/null
@@ -1,669 +0,0 @@
-setContentType($data['content_type']);
-
- $object->contentLength = (int) $data['bytes'];
- $object->etag = (string) $data['hash'];
- $object->lastModified = strtotime($data['last_modified']);
-
- $object->token = $token;
- $object->url = $url;
-
- // FIXME: What do we do about HTTP header data that doesn't come
- // back in JSON?
-
- if (is_null($client)) {
- $client = GuzzleAdapter::create();
- }
- $object->setClient($client);
-
- return $object;
- }
-
- /**
- * Create a new RemoteObject from HTTP headers.
- *
- * This is used to create objects from GET and HEAD requests, which
- * return all of the metadata inside of the headers.
- *
- * @param string $name The name of the object.
- * @param array $headers An associative array of HTTP headers in the exact
- * format documented by OpenStack's API docs.
- * @param string $token The current auth token (used for issuing subsequent
- * requests).
- * @param string $url The URL to the object in the object storage. Used for
- * issuing subsequent requests.
- *
- * @return \OpenStack\ObjectStore\v1\Resource\RemoteObject A new RemoteObject.
- */
- public static function newFromHeaders($name, $headers, $token, $url, ClientInterface $client = null)
- {
- $object = new RemoteObject($name);
-
- //$object->allHeaders = $headers;
- $object->setHeaders($headers);
-
- //throw new \Exception(print_r($headers, true));
-
- // Fix inconsistant header.
- if (isset($headers['ETag'])) {
- $headers['Etag'] = $headers['ETag'];
- }
-
- $object->setContentType($headers['Content-Type']);
- $object->contentLength = empty($headers['Content-Length']) ? 0 : (int) $headers['Content-Length'];
- $object->etag = (string) $headers['Etag']; // ETag is now Etag.
- $object->lastModified = strtotime($headers['Last-Modified']);
-
- // Set the metadata, too.
- $object->setMetadata(Container::extractHeaderAttributes($headers));
-
-
- // If content encoding and disposition exist, set them on the
- // object.
- if (!empty($headers['Content-Disposition'])) {
- $object->setDisposition($headers['Content-Disposition']);
-
- }
- if (!empty($headers['Content-Encoding'])) {
- $object->setEncoding($headers['Content-Encoding']);
- }
-
- $object->token = $token;
- $object->url = $url;
-
- if (is_null($client)) {
- $client = GuzzleAdapter::create();
- }
- $object->setClient($client);
-
- return $object;
- }
-
- /**
- * Set the HTTP Client to use.
- *
- * @param OpenStackTransportClientInterface $client The HTTP Client
- */
- public function setClient(ClientInterface $client)
- {
- $this->client = $client;
- }
-
- /**
- * Get the URL to this object.
- *
- * If this object has been stored remotely, it will have
- * a valid URL.
- *
- * @return string A URL to the object. The following considerations apply:
- * - If the container is public, this URL can be loaded without
- * authentication. You can, for example, pass the URL to a browser
- * user agent.
- * - If this object has never been saved remotely, then there will be
- * no URL, and this will return null.
- */
- public function url()
- {
- return $this->url;
- }
-
-
- public function contentLength()
- {
- if (!empty($this->content)) {
- return parent::contentLength();
- }
-
- return $this->contentLength;
- }
-
- public function eTag()
- {
- if (!empty($this->content)) {
- return parent::eTag();
- }
-
- return $this->etag;
- }
-
- /**
- * Get the modification time, as reported by the server.
- *
- * This returns an integer timestamp indicating when the server's
- * copy of this file was last modified.
- */
- public function lastModified()
- {
- return $this->lastModified;
- }
-
- public function metadata()
- {
- // How do we get this?
- return $this->metadata;
- }
-
- /**
- * Set the headers
- *
- * @return \OpenStack\ObjectStore\v1\Resource\RemoteObject $this for the current object so it can be used in chaining
- * methods.
- */
- public function setHeaders($headers)
- {
- $this->allHeaders = [];
-
- foreach ($headers as $name => $value) {
- if (strpos($name, Container::METADATA_HEADER_PREFIX) !== 0) {
- $this->allHeaders[$name] = $value;
- }
- }
-
- return $this;
- }
-
- /**
- * Get the HTTP headers sent by the server.
- *
- * EXPERT.
- *
- * This returns the array of minimally processed HTTP headers that
- * were sent from the server.
- *
- * @return array An associative array of header names and values.
- */
- public function headers()
- {
- return $this->allHeaders;
- }
-
- public function additionalHeaders($mergeAll = false)
- {
- // Any additional headers will be set. Note that $this->headers will contain
- // some headers that are NOT additional. But we do not know which headers are
- // additional and which are from Swift because Swift does not commit to using
- // a specific set of headers.
- if ($mergeAll) {
- $additionalHeaders = parent::additionalHeaders() + $this->allHeaders;
- $this->filterHeaders($additionalHeaders);
- } else {
- $additionalHeaders = parent::additionalHeaders();
- }
-
- return $additionalHeaders;
- }
-
- protected $reservedHeaders = [
- 'etag' => true, 'content-length' => true,
- 'x-auth-token' => true,
- 'transfer-encoding' => true,
- 'x-trans-id' => true,
- ];
-
- /**
- * Filter the headers.
- *
- * @return \OpenStack\ObjectStore\v1\Resource\RemoteObject $this for the current object so it can be used in chaining
- * methods.
- */
- public function filterHeaders(&$headers)
- {
- $unset = [];
- foreach ($headers as $name => $value) {
- $lower = strtolower($name);
- if (isset($this->reservedHeaders[$lower])) {
- $unset[] = $name;
- }
- }
- foreach ($unset as $u) {
- unset($headers[$u]);
- }
-
- return $this;
- }
-
- /**
- * Given an array of header names.
- *
- * This will remove the given headers from the existing headers.
- * Both additional headers and the original headers from the
- * server are affected here.
- *
- * Note that you cannot remove metadata through this mechanism,
- * as it is managed using the metadata() methods.
- *
- * Many headers are generated automatically, such as
- * Content-Type and Content-Length. Removing these
- * will simply result in their being regenerated.
- *
- * @param array $keys The header names to be removed.
- *
- * @return \OpenStack\ObjectStore\v1\Resource\RemoteObject $this for the current object so it can be used in chaining
- * methods.
- */
- public function removeHeaders($keys)
- {
- foreach ($keys as $key) {
- unset($this->allHeaders[$key]);
- unset($this->additionalHeaders[$key]);
- }
-
- return $this;
- }
-
- /**
- * Get the content of this object.
- *
- * Since this is a proxy object, calling content() will cause the
- * object to be fetched from the remote data storage. The result will
- * be delivered as one large string.
- *
- * The file size, content type, etag, and modification date of the
- * object are all updated during this command, too. This accounts for
- * the possibility that the content was modified externally between
- * the time this object was constructed and the time this method was
- * executed.
- *
- * Be wary of using this method with large files.
- *
- * @return string The contents of the file as a string.
- *
- * @throws \OpenStack\Common\Transport\Exception\ResourceNotFoundException when the requested content cannot be
- * located on the remote server.
- * @throws \OpenStack\Common\Exception when an unknown exception (usually an
- * abnormal network condition) occurs.
- */
- public function content()
- {
- // XXX: This allows local overwrites. Is this a good idea?
- if (!empty($this->content)) {
- return $this->content;
- }
-
- // Get the object, content included.
- $response = $this->fetchObject(true);
-
- $content = $response->getBody();
-
- // Checksum the content.
- // XXX: Right now the md5 is done even if checking is turned off.
- // Should fix that.
- $check = md5($content);
- if ($this->isVerifyingContent() && $check != $this->etag()) {
- throw new Exception\ContentVerificationException("Checksum $check does not match Etag " . $this->etag());
- }
-
- // If we are caching, set the content locally when we retrieve
- // remotely.
- if ($this->isCaching()) {
- $this->setContent($content);
- }
-
- return $content;
- }
-
- /**
- * Get the content of this object as a file stream.
- *
- * This is useful for large objects. Such objects should not be read
- * into memory all at once (as content() does), but should instead be
- * made available as an input stream.
- *
- * PHP offers low-level stream support in the form of PHP stream
- * wrappers, and this mechanism is used internally whenever available.
- *
- * If there is a local copy of the content, the stream will be read
- * out of the content as if it were a temp-file backed in-memory
- * resource. To ignore the local version, pass in true for the
- * $refresh parameter.
- *
- * If the content is coming from a remote copy, the stream will be
- * read directly from the underlying IO stream.
- *
- * Each time stream() is called, a new stream is created. In most
- * cases, this results in a new HTTP transaction (unless $refresh is
- * false and the content is already stored locally).
- *
- * The stream is read-only.
- *
- * @param boolean $refresh If this is set to true, any existing local
- * modifications will be ignored and the content will
- * be refreshed from the server. Any local changes to
- * the object will be discarded.
- *
- * @return resource A handle to the stream, which is already opened and
- * positioned at the beginning of the stream.
- */
- public function stream($refresh = false)
- {
- // If we're working on local content, return that content wrapped in
- // a fake IO stream.
- if (!$refresh && isset($this->content)) {
- return $this->localFileStream();
- }
-
- // Otherwise, we fetch a fresh version from the remote server and
- // return its stream handle.
- $response = $this->fetchObject(true);
-
- // Write to in-mem handle backed by a temp file.
- $out = fopen('php://temp', 'rb+');
- fwrite($out, $response->getBody());
- rewind($out);
-
- return $out;
- }
-
- /**
- * Transform a local copy of content into a file stream.
- *
- * This buffers the content into a stream resource and then returns
- * the stream resource. The resource is not used internally, and its
- * data is never written back to the remote object storage.
- */
- protected function localFileStream()
- {
- $tmp = fopen('php://temp', 'rw');
- fwrite($tmp, $this->content(), $this->contentLength());
- rewind($tmp);
-
- return $tmp;
- }
-
- /**
- * Enable or disable content caching.
- *
- * If a RemoteObject is set to cache then the first time content() is
- * called, its results will be cached locally. This is very useful for
- * small files whose content is accessed repeatedly, but can be a
- * cause of memory consumption for larger files.
- *
- * If caching settings are changed after content is retrieved, the
- * already retrieved content will not be affected, though any
- * subsequent requests will use the new caching settings. That is,
- * existing cached content will not be removed if caching is turned
- * off.
- *
- * @param boolean $enabled If this is true, caching will be enabled. If this
- * is false, caching will be disabled.
- *
- * @return \OpenStack\ObjectStore\v1\Resource\RemoteObject $this so the method can be used in chaining.
- */
- public function setCaching($enabled)
- {
- $this->caching = $enabled;
-
- return $this;
- }
-
- /**
- * Indicates whether this object caches content.
- *
- * Importantly, this indicates whether the object will cache
- * its contents, not whether anything is actually cached.
- *
- * @return boolean true if caching is enabled, false otherwise.
- */
- public function isCaching()
- {
- return $this->caching;
- }
-
- /**
- * Enable or disable content verification (checksum/md5).
- *
- * The default behavior of a RemoteObject is to verify that the MD5
- * provided by the server matches the locally generated MD5 of the
- * file contents.
- *
- * If content verification is enabled, then whenever the content is
- * fetched from the remote server, its checksum is calculated and
- * tested against the ETag value. This provides a layer of assurance
- * that the payload of the HTTP request was not altered during
- * transmission.
- *
- * This featured can be turned off, which is sometimes necessary on
- * systems that do not correctly produce MD5s. Turning this off might
- * also provide a small performance improvement on large files, but at
- * the expense of security.
- *
- * @param boolean $enabled If this is true, content verification is performed.
- * The content is hashed and checked against a
- * server-supplied MD5 hashcode. If this is false,
- * no checking is done.
- *
- * @return \OpenStack\ObjectStore\v1\Resource\RemoteObject $this so the method can be used in chaining.
- */
- public function setContentVerification($enabled)
- {
- $this->contentVerification = $enabled;
-
- return $this;
- }
-
- /**
- * Indicate whether this object verifies content (checksum).
- *
- * When content verification is on, RemoteObject attemts to perform a
- * checksum on the object, calculating the MD5 hash of the content
- * returned by the remote server, and comparing that to the server's
- * supplied ETag hash.
- *
- * @return boolean true if this is verifying, false otherwise.
- */
- public function isVerifyingContent()
- {
- return $this->contentVerification;
- }
-
- /**
- * Check whether there are unsaved changes.
- *
- * An object is marked "dirty" if it has been altered
- * locally in such a way that it no longer matches the
- * remote version.
- *
- * The practical definition of dirtiness, for us, is this: An object
- * is dirty if and only if (a) it has locally buffered content AND (b)
- * the checksum of the local content does not match the checksom of
- * the remote content.
- *
- * Not that minor differences, such as altered character encoding, may
- * change the checksum value, and thus (correctly) mark the object as
- * dirty.
- *
- * The RemoteObject implementation does not internally check dirty
- * markers. It is left to implementors to ensure that dirty content is
- * written to the remote server when desired.
- *
- * To replace dirty content with a clean copy, see refresh().
- *
- * @return boolean Whether or not there are unsaved changes.
- */
- public function isDirty()
- {
- // If there is no content, the object can't be dirty.
- if (!isset($this->content)) {
- return false;
- }
-
- // Content is dirty iff content is set, and it is
- // different from the original content. Note that
- // we are using the etag from the original headers.
- if ($this->etag != md5($this->content)) {
- return true;
- }
-
- return false;
- }
-
- /**
- * Rebuild the local object from the remote.
- *
- * This refetches the object from the object store and then
- * reconstructs the present object based on the refreshed data.
- *
- * WARNING: This will destroy any unsaved local changes. You can use
- * isDirty() to determine whether or not a local change has been made.
- *
- * @param boolean $fetchContent If this is true, the content will be
- * downloaded as well.
- *
- * @return \OpenStack\ObjectStore\v1\Resource\RemoteObject $this for the current object so it
- * can be used in chaining methods.
- */
- public function refresh($fetchContent = false)
- {
- // Kill old content.
- unset($this->content);
-
- $response = $this->fetchObject($fetchContent);
-
-
- if ($fetchContent) {
- $this->setContent($response->getBody());
- }
-
- return $this;
- }
-
- /**
- * Helper function for fetching an object.
- *
- * @param boolean $fetchContent If this is set to true, a GET request will be
- * issued, which will cause the remote host to
- * return the object in the response body. The
- * response body is not handled, though. If this
- * is set to false, a HEAD request is sent, and
- * no body is returned.
- *
- * @return \OpenStack\Common\Transport\Response containing the object metadata and (depending
- * on the $fetchContent flag) optionally the data.
- */
- protected function fetchObject($fetchContent = false)
- {
- $method = $fetchContent ? 'GET' : 'HEAD';
-
- $headers = ['X-Auth-Token' => $this->token];
-
- $response = $this->client->send(
- $this->client->createRequest($method, $this->url, null, ['headers' => $headers])
- );
-
- if ($response->getStatusCode() != 200) {
- throw new \OpenStack\Common\Exception('An unknown exception occurred during transmission.');
- }
-
- $this->extractFromHeaders($response);
-
- return $response;
- }
-
- /**
- * Extract information from HTTP headers.
- *
- * This is used internally to set object properties from headers.
- *
- * @return \OpenStack\ObjectStore\v1\Resource\RemoteObject $this for the current object so it
- * can be used in chaining methods.
- */
- protected function extractFromHeaders($response)
- {
- $this->setContentType($response->getHeader('Content-Type') ? $response->getHeader('Content-Type') : $this->contentType());
- $this->lastModified = strtotime($response->getHeader('Last-Modified') ? $response->getHeader('Last-Modified') : 0);
- $this->etag = $response->getHeader('Etag') ? $response->getHeader('Etag') : $this->etag;
- $this->contentLength = (int) ($response->getHeader('Content-Length') ? $response->getHeader('Content-Length') : 0);
-
- $this->setDisposition($response->getHeader('Content-Disposition', null));
- $this->setEncoding($response->getHeader('Content-Encoding', null));
-
- // Reset the metadata, too:
- $headers = [];
- foreach ($response->getHeaders() as $name => $header) {
- $headers[$name] = $header[0];
- }
- $this->setMetadata(Container::extractHeaderAttributes($headers));
-
- return $this;
- }
-}
\ No newline at end of file
diff --git a/src/OpenStack/ObjectStore/v1/Resource/StreamWrapper.php b/src/OpenStack/ObjectStore/v1/Resource/StreamWrapper.php
deleted file mode 100644
index ebefdc2..0000000
--- a/src/OpenStack/ObjectStore/v1/Resource/StreamWrapper.php
+++ /dev/null
@@ -1,1495 +0,0 @@
- array(
- * 'username' => USERNAME,
- * 'password' => PASSWORD,
- * 'tenantid' => TENANT_ID,
- * 'tenantname' => TENANT_NAME, // Optional instead of tenantid.
- * 'endpoint' => AUTH_ENDPOINT_URL,
- * )
- * )
- * );
- * // Open the file.
- * $handle = fopen('swift://mycontainer/myobject.txt', 'r+', false, $context);
- *
- * // You can get the entire file, or use fread() to loop through the file.
- * $contents = stream_get_contents($handle);
- *
- * fclose($handle);
- * ?>
- *
- * Remarks
- * - file_get_contents() works fine.
- * - You can write to a stream, too. Nothing is pushed to the server until
- * fflush() or fclose() is called.
- * - Mode strings (w, r, w+, r+, c, c+, a, a+, x, x+) all work, though certain
- * constraints are slightly relaxed to accomodate efficient local buffering.
- * - Files are buffered locally.
- *
- * USING FILE-LEVEL FUNCTIONS
- *
- * PHP provides a number of file-level functions that stream wrappers can
- * optionally support. Here are a few such functions:
- *
- * - file_exists()
- * - is_readable()
- * - stat()
- * - filesize()
- * - fileperms()
- *
- * The OpenStack stream wrapper provides support for these file-level functions.
- * But there are a few things you should know:
- *
- * - Each call to one of these functions generates at least one request. It may
- * be as many as three:
- * * An auth request
- * * A request for the container (to get container permissions)
- * * A request for the object
- * - IMPORTANT: Unlike the fopen()/fclose()... functions NONE of these functions
- * retrieves the body of the file. If you are working with large files, using
- * these functions may be orders of magnitude faster than using fopen(), etc.
- * (The crucial detail: These kick off a HEAD request, will fopen() does a
- * GET request).
- * - You must use Bootstrap::setConfiguration() to pass in all of the values you
- * would normally pass into a stream context:
- * * endpoint
- * * username
- * * password
- * - Most of the information from this family of calls can also be obtained using
- * fstat(). If you were going to open a stream anyway, you might as well use
- * fopen()/fstat().
- * - stat() and fstat() fake the permissions and ownership as follows:
- * * uid/gid are always sset to the current user. This basically assumes that if
- * the current user can access the object, the current user has ownership over
- * the file. As the OpenStack ACL system developers, this may change.
- * * Mode is faked. Swift uses ACLs, not UNIX mode strings. So we fake the string:
- * - 770: The ACL has the object marked as private.
- * - 775: The ACL has the object marked as public.
- * - ACLs are actually set on the container, so every file in a public container
- * will return 775.
- * - stat/fstat provide only one timestamp. Swift only tracks mtime, so mtime, atime,
- * and ctime are all set to the last modified time.
- *
- * DIRECTORIES
- *
- * OpenStack Swift does not really have directories. Rather, it allows
- * characters such as '/' to be used to designate namespaces on object
- * names. (For simplicity, this library uses only '/' as a separator).
- *
- * This allows for simulated directory listings. Requesting
- * `scandir('swift://foo/bar/')` is really a request to "find all of the items
- * in the 'foo' container whose names start with 'bar/'".
- *
- * Because of this...
- *
- * - Directory reading functions like scandir(), opendir(), readdir()
- * and so forth are supported.
- * - Functions to create or remove directories (mkdir() and rmdir()) are
- * meaningless, and thus not supported.
- *
- * Swift still has support for "directory markers" (special zero-byte files
- * that act like directories). However, since there are no standards for how
- * said markers ought to be created, they are not supported by the stream
- * wrapper.
- *
- * As usual, the underlying \OpenStack\ObjectStore\v1\Resource\Container class
- * supports the full range of Swift features.
- *
- * SUPPORTED CONTEXT PARAMETERS
- *
- * This section details paramters that can be passed either
- * through a stream context or through
- * \OpenStack\Bootstrap\setConfiguration().
- *
- * PHP functions that do not allow you to pass a context may still be supported
- * here IF you have set options using Bootstrap::setConfiguration().
- *
- * You are required to pass in authentication information. This
- * comes in one of three forms:
- *
- * -# User login: username, password, tenantid, endpoint
- * -# Existing (valid) token: token, swift_endpoint
- *
- * As of 1.0.0-beta6, you may use `tenantname` instead of `tenantid`.
- *
- * The third method (token) can be used when the application has already
- * authenticated. In this case, a token has been generated and assigned
- * to an user and tenant.
- *
- * The following parameters may be set either in the stream context
- * or through OpenStack\Bootstrap::setConfiguration():
- *
- * - token: An auth token. If this is supplied, authentication is skipped and
- * this token is used. NOTE: You MUST set swift_endpoint if using this
- * option.
- * - swift_endpoint: The URL to the swift instance. This is only necessary if
- * 'token' is set. Otherwise it is ignored.
- * - username: A username. MUST be accompanied by 'password' and 'tenantid' (or 'tenantname').
- * - password: A password. MUST be accompanied by 'username' and 'tenantid' (or 'tenantname').
- * - endpoint: The URL to the authentication endpoint. Necessary if you are not
- * using a 'token' and 'swift_endpoint'.
- * - content_type: This is effective only when writing files. It will
- * set the Content-Type of the file during upload.
- * - tenantid: The tenant ID for the services you will use. (A user may
- * have multiple tenancies associated.)
- * - tenantname: The tenant name for the services you will use. You may use
- * this in lieu of tenant ID.
- *
- * @see http://us3.php.net/manual/en/class.streamwrapper.php
- *
- * @todo The service catalog should be cached in the context like the token so that
- * it can be retrieved later.
- */
-class StreamWrapper
-{
- const DEFAULT_SCHEME = 'swift';
-
- /**
- * Cache of auth token -> service catalog.
- *
- * This will eventually be replaced by a better system, but for a system of
- * moderate complexity, many, many file operations may be run during the
- * course of a request. Caching the catalog can prevent numerous calls
- * to identity services.
- */
- protected static $serviceCatalogCache = [];
-
- /**
- * The stream context.
- *
- * This is set automatically when the stream wrapper is created by
- * PHP. Note that it is not set through a constructor.
- */
- public $context;
- protected $contextArray = [];
-
- protected $schemeName = self::DEFAULT_SCHEME;
- protected $authToken;
-
- // File flags. These should probably be replaced by O_ const's at some point.
- protected $isBinary = false;
- protected $isText = true;
- protected $isWriting = false;
- protected $isReading = false;
- protected $isTruncating = false;
- protected $isAppending = false;
- protected $noOverwrite = false;
- protected $createIfNotFound = true;
-
- /**
- * If this is true, no data is ever sent to the remote server.
- */
- protected $isNeverDirty = false;
-
- protected $triggerErrors = false;
-
- /**
- * Indicate whether the local differs from remote.
- *
- * When the file is modified in such a way that
- * it needs to be written remotely, the isDirty flag
- * is set to true.
- */
- protected $isDirty = false;
-
- /**
- * Object storage instance.
- */
- protected $store;
-
- /**
- * The Container.
- */
- protected $container;
-
- /**
- * The Object.
- */
- protected $obj;
-
- /**
- * The IO stream for the Object.
- */
- protected $objStream;
-
- /**
- * Directory listing.
- *
- * Used for directory methods.
- */
- protected $dirListing = [];
- protected $dirIndex = 0;
- protected $dirPrefix = '';
-
- /**
- * Close a directory.
- *
- * This closes a directory handle, freeing up the resources.
- *
- *
- *
- * NB: Some versions of PHP 5.3 don't clear all buffers when
- * closing, and the handle can occasionally remain accessible for
- * some period of time.
- */
- public function dir_closedir()
- {
- $this->dirIndex = 0;
- $this->dirListing = [];
-
- //syslog(LOG_WARNING, "CLOSEDIR called.");
- return true;
- }
-
- /**
- * Open a directory for reading.
- *
- *
- *
- * See opendir() and scandir().
- *
- * @param string $path The URL to open.
- * @param int $options Unused.
- *
- * @return boolean true if the directory is opened, false otherwise.
- */
- public function dir_opendir($path, $options)
- {
- $url = $this->parseUrl($path);
-
- if (empty($url['host'])) {
- trigger_error('Container name is required.' , E_USER_WARNING);
-
- return false;
- }
-
- try {
- $this->initializeObjectStorage();
- $container = $this->store->container($url['host']);
-
- if (empty($url['path'])) {
- $this->dirPrefix = '';
- } else {
- $this->dirPrefix = $url['path'];
- }
-
- $sep = '/';
-
- $this->dirListing = $container->objectsWithPrefix($this->dirPrefix, $sep);
- } catch (\OpenStack\Common\Exception $e) {
- trigger_error('Directory could not be opened: ' . $e->getMessage(), E_USER_WARNING);
-
- return false;
- }
-
- return true;
- }
-
- /**
- * Read an entry from the directory.
- *
- * This gets a single line from the directory.
- *
- *
- *
- * @return string The name of the resource or false when the directory has no
- * more entries.
- */
- public function dir_readdir()
- {
- // If we are at the end of the listing, return false.
- if (count($this->dirListing) <= $this->dirIndex) {
- return false;
- }
-
- $curr = $this->dirListing[$this->dirIndex];
- $this->dirIndex++;
-
- if ($curr instanceof \OpenStack\ObjectStore\v1\Resource\Subdir) {
- $fullpath = $curr->path();
- } else {
- $fullpath = $curr->name();
- }
-
- if (!empty($this->dirPrefix)) {
- $len = strlen($this->dirPrefix);
- $fullpath = substr($fullpath, $len);
- }
-
- return $fullpath;
- }
-
- /**
- * Rewind to the beginning of the listing.
- *
- * This repositions the read pointer at the first entry in the directory.
- *
- *
- */
- public function dir_rewinddir()
- {
- $this->dirIndex = 0;
- }
-
- /*
- public function mkdir($path, $mode, $options)
- {
- }
-
- public function rmdir($path, $options)
- {
- }
- */
-
- /**
- * Rename a swift object.
- *
- * This works by copying the object (metadata) and
- * then removing the original version.
- *
- * This DOES support cross-container renaming.
- *
- * @see Container::copy().
- *
- * 'foo@example.com',
- * // 'tenantid' => '1234', // You can use this instead of tenantname
- * 'username' => 'foobar',
- * 'password' => 'baz',
- * 'endpoint' => 'https://auth.example.com',
- * ));
- *
- * $from = 'swift://containerOne/file.txt';
- * $to = 'swift://containerTwo/file.txt';
- *
- * // Rename can also take a context as a third param.
- * rename($from, $to);
- *
- * ?>
- *
- * @param string $path_from A swift URL that exists on the remote.
- * @param string $path_to A swift URL to another path.
- *
- * @return boolean true on success, false otherwise.
- */
- public function rename($path_from, $path_to)
- {
- $this->initializeObjectStorage();
- $src = $this->parseUrl($path_from);
- $dest = $this->parseUrl($path_to);
-
- if ($src['scheme'] != $dest['scheme']) {
- trigger_error("I'm too stupid to copy across protocols.", E_USER_WARNING);
- }
-
- if ( empty($src['host']) || empty($src['path'])
- || empty($dest['host']) || empty($dest['path'])) {
- trigger_error('Container and path are required for both source and destination URLs.', E_USER_WARNING);
-
- return false;
- }
-
- try {
- $container = $this->store->container($src['host']);
-
- $object = $container->proxyObject($src['path']);
-
- $ret = $container->copy($object, $dest['path'], $dest['host']);
- if ($ret) {
- return $container->delete($src['path']);
- }
- } catch (\OpenStack\Common\Exception $e) {
- trigger_error('Rename was not completed: ' . $e->getMessage(), E_USER_WARNING);
-
- return false;
- }
- }
-
- /*
- public function copy($path_from, $path_to)
- {
- throw new \Exception("UNDOCUMENTED.");
- }
- */
-
- /**
- * Cast stream into a lower-level stream.
- *
- * This is used for stream_select() and perhaps others.Because it exposes
- * the lower-level buffer objects, this function can have unexpected
- * side effects.
- *
- * @return resource this returns the underlying stream.
- */
- public function stream_cast($cast_as)
- {
- return $this->objStream;
- }
-
- /**
- * Close a stream, writing if necessary.
- *
- *
- *
- * This will close the present stream. Importantly,
- * this will also write to the remote object storage if
- * any changes have been made locally.
- *
- * @see stream_open().
- */
- public function stream_close()
- {
- try {
- $this->writeRemote();
- } catch (\OpenStack\Common\Exception $e) {
- trigger_error('Error while closing: ' . $e->getMessage(), E_USER_NOTICE);
-
- return false;
- }
-
- // Force-clear the memory hogs.
- unset($this->obj);
-
- fclose($this->objStream);
- }
-
- /**
- * Check whether the stream has reached its end.
- *
- * This checks whether the stream has reached the
- * end of the object's contents.
- *
- * Called when `feof()` is called on a stream.
- *
- * @see stream_seek().
- *
- * @return boolean true if it has reached the end, false otherwise.
- */
- public function stream_eof()
- {
- return feof($this->objStream);
- }
-
- /**
- * Initiate saving data on the remote object storage.
- *
- * If the local copy of this object has been modified,
- * it is written remotely.
- *
- * Called when `fflush()` is called on a stream.
- */
- public function stream_flush()
- {
- try {
- $this->writeRemote();
- } catch (\OpenStack\Common\Exception $e) {
- syslog(LOG_WARNING, $e);
- trigger_error('Error while flushing: ' . $e->getMessage(), E_USER_NOTICE);
-
- return false;
- }
- }
-
- /**
- * Write data to the remote object storage.
- *
- * Internally, this is used by flush and close.
- */
- protected function writeRemote()
- {
- $contentType = $this->cxt('content_type');
- if (!empty($contentType)) {
- $this->obj->setContentType($contentType);
- }
-
- // Skip debug streams.
- if ($this->isNeverDirty) {
- return;
- }
-
- // Stream is dirty and needs a write.
- if ($this->isDirty) {
- $position = ftell($this->objStream);
-
- rewind($this->objStream);
- $this->container->save($this->obj, $this->objStream);
-
- fseek($this->objStream, SEEK_SET, $position);
-
- }
- $this->isDirty = false;
- }
-
- /*
- * Locking is currently unsupported.
- *
- * There is no remote support for locking a
- * file.
- public function stream_lock($operation)
- {
- }
- */
-
- /**
- * Open a stream resource.
- *
- * This opens a given stream resource and prepares it for reading or writing.
- *
- * 'foobar',
- * 'tenantid' => '987654321',
- * 'password' => 'eieio',
- * 'endpoint' => 'https://auth.example.com',
- * ));
- * ?>
- *
- * $file = fopen('swift://myContainer/myObject.csv', 'rb', false, $cxt);
- * while ($bytes = fread($file, 8192)) {
- * print $bytes;
- * }
- * fclose($file);
- * ?>
- *
- * If a file is opened in write mode, its contents will be retrieved from the
- * remote storage and cached locally for manipulation. If the file is opened
- * in a write-only mode, the contents will be created locally and then pushed
- * remotely as necessary.
- *
- * During this operation, the remote host may need to be contacted for
- * authentication as well as for file retrieval.
- *
- * @param string $path The URL to the resource. See the class description for
- * details, but typically this expects URLs in the form `swift://CONTAINER/OBJECT`.
- * @param string $mode Any of the documented mode strings. See fopen(). For
- * any file that is in a writing mode, the file will be saved remotely on
- * flush or close. Note that there is an extra mode: 'nope'. It acts like
- * 'c+' except that it is never written remotely. This is useful for
- * debugging the stream locally without sending that data to object storage.
- * (Note that data is still fetched -- just never written.)
- * @param int $options An OR'd list of options. Only STREAM_REPORT_ERRORS has
- * any meaning to this wrapper, as it is not working with local files.
- * @param string $opened_path This is not used, as this wrapper deals only
- * with remote objects.
- */
- public function stream_open($path, $mode, $options, &$opened_path)
- {
- //syslog(LOG_WARNING, "I received this URL: " . $path);
-
- // If STREAM_REPORT_ERRORS is set, we are responsible for
- // all error handling while opening the stream.
- if (STREAM_REPORT_ERRORS & $options) {
- $this->triggerErrors = true;
- }
-
- // Using the mode string, set the internal mode.
- $this->setMode($mode);
-
- // Parse the URL.
- $url = $this->parseUrl($path);
- //syslog(LOG_WARNING, print_r($url, true));
-
- // Container name is required.
- if (empty($url['host'])) {
- //if ($this->triggerErrors) {
- trigger_error('No container name was supplied in ' . $path, E_USER_WARNING);
- //}
- return false;
- }
-
- // A path to an object is required.
- if (empty($url['path'])) {
- //if ($this->triggerErrors) {
- trigger_error('No object name was supplied in ' . $path, E_USER_WARNING);
- //}
- return false;
- }
-
- // We set this because it is possible to bind another scheme name,
- // and we need to know that name if it's changed.
- //$this->schemeName = isset($url['scheme']) ? $url['scheme'] : self::DEFAULT_SCHEME;
- if (isset($url['scheme'])) {
- $this->schemeName == $url['scheme'];
- }
-
- // Now we find out the container name. We walk a fine line here, because we don't
- // create a new container, but we don't want to incur heavy network
- // traffic, either. So we have to assume that we have a valid container
- // until we issue our first request.
- $containerName = $url['host'];
-
- // Object name.
- $objectName = $url['path'];
-
- // XXX: We reserve the query string for passing additional params.
-
- try {
- $this->initializeObjectStorage();
- } catch (\OpenStack\Common\Exception $e) {
- trigger_error('Failed to init object storage: ' . $e->getMessage(), E_USER_WARNING);
-
- return false;
- }
-
- //syslog(LOG_WARNING, "Container: " . $containerName);
-
- // Now we need to get the container. Doing a server round-trip here gives
- // us the peace of mind that we have an actual container.
- // XXX: Should we make it possible to get a container blindly, without the
- // server roundtrip?
- try {
- $this->container = $this->store->container($containerName);
- } catch (ResourceNotFoundException $e) {
- trigger_error('Container not found.', E_USER_WARNING);
- return false;
- }
-
- try {
- // Now we fetch the file. Only under certain circumstances do we generate
- // an error if the file is not found.
- // FIXME: We should probably allow a context param that can be set to
- // mark the file as lazily fetched.
- $this->obj = $this->container->object($objectName);
- $stream = $this->obj->stream();
- $streamMeta = stream_get_meta_data($stream);
-
- // Support 'x' and 'x+' modes.
- if ($this->noOverwrite) {
- //if ($this->triggerErrors) {
- trigger_error('File exists and cannot be overwritten.', E_USER_WARNING);
- //}
- return false;
- }
-
- // If we need to write to it, we need a writable
- // stream. Also, if we need to block reading, this
- // will require creating an alternate stream.
- if ($this->isWriting && ($streamMeta['mode'] == 'r' || !$this->isReading)) {
- $newMode = $this->isReading ? 'rb+' : 'wb';
- $tmpStream = fopen('php://temp', $newMode);
- stream_copy_to_stream($stream, $tmpStream);
-
- // Skip rewinding if we can.
- if (!$this->isAppending) {
- rewind($tmpStream);
- }
-
- $this->objStream = $tmpStream;
- } else {
- $this->objStream = $this->obj->stream();
- }
-
- // Append mode requires seeking to the end.
- if ($this->isAppending) {
- fseek($this->objStream, -1, SEEK_END);
- }
- } catch (ResourceNotFoundException $nf) {
- // If a 404 is thrown, we need to determine whether
- // or not a new file should be created.
-
- // For many modes, we just go ahead and create.
- if ($this->createIfNotFound) {
- $this->obj = new Object($objectName);
- $this->objStream = fopen('php://temp', 'rb+');
-
- $this->isDirty = true;
- } else {
- //if ($this->triggerErrors) {
- trigger_error($nf->getMessage(), E_USER_WARNING);
- //}
- return false;
- }
-
- } catch (Exception $e) {
- // All other exceptions are fatal.
- //if ($this->triggerErrors) {
- trigger_error('Failed to fetch object: ' . $e->getMessage(), E_USER_WARNING);
- //}
- return false;
- }
-
- // At this point, we have a file that may be read-only. It also may be
- // reading off of a socket. It will be positioned at the beginning of
- // the stream.
- return true;
- }
-
- /**
- * Read N bytes from the stream.
- *
- * This will read up to the requested number of bytes. Or, upon
- * hitting the end of the file, it will return null.
- *
- * @see fread(), fgets(), and so on for examples.
- *
- * 'me@example.com',
- * 'username' => 'me@example.com',
- * 'password' => 'secret',
- * 'endpoint' => 'https://auth.example.com',
- * ));
- *
- * $content = file_get_contents('swift://public/myfile.txt', false, $cxt);
- * ?>
- *
- * @param int $count The number of bytes to read (usually 8192).
- *
- * @return string The data read.
- */
- public function stream_read($count)
- {
- return fread($this->objStream, $count);
- }
-
- /**
- * Perform a seek.
- *
- * This is called whenever `fseek()` or `rewind()` is called on a
- * Swift stream.
- *
- * IMPORTANT: Unlike the PHP core, this library
- * allows you to `fseek()` inside of a file opened
- * in append mode ('a' or 'a+').
- */
- public function stream_seek($offset, $whence)
- {
- $ret = fseek($this->objStream, $offset, $whence);
-
- // fseek returns 0 for success, -1 for failure.
- // We need to return true for success, false for failure.
- return $ret === 0;
- }
-
- /**
- * Set options on the underlying stream.
- *
- * The settings here do not trickle down to the network socket, which is
- * left open for only a brief period of time. Instead, they impact the middle
- * buffer stream, where the file is read and written to between flush/close
- * operations. Thus, tuning these will not have any impact on network
- * performance.
- *
- * See stream_set_blocking(), stream_set_timeout(), and stream_write_buffer().
- */
- public function stream_set_option($option, $arg1, $arg2)
- {
- switch ($option) {
- case STREAM_OPTION_BLOCKING:
- return stream_set_blocking($this->objStream, $arg1);
- case STREAM_OPTION_READ_TIMEOUT:
- // XXX: Should this have any effect on the lower-level
- // socket, too? Or just the buffered tmp storage?
- return stream_set_timeout($this->objStream, $arg1, $arg2);
- case STREAM_OPTION_WRITE_BUFFER:
- return stream_set_write_buffer($this->objStream, $arg2);
- }
-
- }
-
- /**
- * Perform stat()/lstat() operations.
- *
- *
- *
- * To use standard `stat()` on a Swift stream, you will
- * need to set account information (tenant ID, username, password,
- * etc.) through \OpenStack\Bootstrap::setConfiguration().
- *
- * @return array The stats array.
- */
- public function stream_stat()
- {
- $stat = fstat($this->objStream);
-
- // FIXME: Need to calculate the length of the $objStream.
- //$contentLength = $this->obj->contentLength();
- $contentLength = $stat['size'];
-
- return $this->generateStat($this->obj, $this->container, $contentLength);
- }
-
- /**
- * Get the current position in the stream.
- *
- * @see `ftell()` and `fseek()`.
- *
- * @return int The current position in the stream.
- */
- public function stream_tell()
- {
- return ftell($this->objStream);
- }
-
- /**
- * Write data to stream.
- *
- * This writes data to the local stream buffer. Data
- * is not pushed remotely until stream_close() or
- * stream_flush() is called.
- *
- * @param string $data Data to write to the stream.
- *
- * @return int The number of bytes written. 0 indicates and error.
- */
- public function stream_write($data)
- {
- $this->isDirty = true;
-
- return fwrite($this->objStream, $data);
- }
-
- /**
- * Unlink a file.
- *
- * This removes the remote copy of the file. Like a normal unlink operation,
- * it does not destroy the (local) file handle until the file is closed.
- * Therefore you can continue accessing the object locally.
- *
- * Note that OpenStack Swift does not draw a distinction between file objects
- * and "directory" objects (where the latter is a 0-byte object). This will
- * delete either one. If you are using directory markers, not that deleting
- * a marker will NOT delete the contents of the "directory".
- *
- * You will need to use \OpenStack\Bootstrap::setConfiguration() to set the
- * necessary stream configuration, since `unlink()` does not take a context.
- *
- * @param string $path The URL.
- *
- * @return boolean true if the file was deleted, false otherwise.
- */
- public function unlink($path)
- {
- $url = $this->parseUrl($path);
-
- // Host is required.
- if (empty($url['host'])) {
- trigger_error('Container name is required.', E_USER_WARNING);
-
- return false;
- }
-
- // I suppose we could allow deleting containers,
- // but that isn't really the purpose of the
- // stream wrapper.
- if (empty($url['path'])) {
- trigger_error('Path is required.', E_USER_WARNING);
-
- return false;
- }
-
- try {
- $this->initializeObjectStorage();
- // $container = $this->store->container($url['host']);
- $name = $url['host'];
- $token = $this->store->token();
- $endpoint_url = $this->store->url() . '/' . rawurlencode($name);
- $client = $this->cxt('transport_client', null);
- $container = new \OpenStack\ObjectStore\v1\Resource\Container($name, $endpoint_url, $token, $client);
-
- return $container->delete($url['path']);
- } catch (\OpenStack\Common\Exception $e) {
- trigger_error('Error during unlink: ' . $e->getMessage(), E_USER_WARNING);
-
- return false;
- }
-
- }
-
- /**
- * @see stream_stat().
- */
- public function url_stat($path, $flags)
- {
- $url = $this->parseUrl($path);
-
- if (empty($url['host']) || empty($url['path'])) {
- if ($flags & STREAM_URL_STAT_QUIET) {
- trigger_error('Container name (host) and path are required.', E_USER_WARNING);
- }
-
- return false;
- }
-
- try {
- $this->initializeObjectStorage();
-
- // Since we are throwing the $container away without really using its
- // internals, we create an unchecked container. It may not actually
- // exist on the server, which will cause a 404 error.
- //$container = $this->store->container($url['host']);
- $name = $url['host'];
- $token = $this->store->token();
- $endpoint_url = $this->store->url() . '/' . rawurlencode($name);
- $client = $this->cxt('transport_client', null);
- $container = new \OpenStack\ObjectStore\v1\Resource\Container($name, $endpoint_url, $token, $client);
- $obj = $container->proxyObject($url['path']);
- } catch (\OpenStack\Common\Exception $e) {
- // Apparently file_exists does not set STREAM_URL_STAT_QUIET.
- //if ($flags & STREAM_URL_STAT_QUIET) {
- //trigger_error('Could not stat remote file: ' . $e->getMessage(), E_USER_WARNING);
- //}
- return false;
- }
-
- if ($flags & STREAM_URL_STAT_QUIET) {
- try {
- return @$this->generateStat($obj, $container, $obj->contentLength());
- } catch (\OpenStack\Common\Exception $e) {
- return false;
- }
- }
-
- return $this->generateStat($obj, $container, $obj->contentLength());
- }
-
- /**
- * Get the Object.
- *
- * This provides low-level access to the
- * \OpenStack\ObjectStore\v1\ObjectStorage::Object instance in which the content
- * is stored.
- *
- * Accessing the object's payload (Object::content()) is strongly
- * discouraged, as it will modify the pointers in the stream that the
- * stream wrapper is using.
- *
- * HOWEVER, accessing the Object's metadata properties, content type,
- * and so on is okay. Changes to this data will be written on the next
- * flush, provided that the file stream data has also been changed.
- *
- * To access this:
- *
- * object();
- * ?>
- */
- public function object()
- {
- return $this->obj;
- }
-
- /**
- * EXPERT: Get the ObjectStorage for this wrapper.
- *
- * @return object \OpenStack\ObjectStorage An ObjectStorage object.
- * @see object()
- */
- public function objectStorage()
- {
- return $this->store;
- }
-
- /**
- * EXPERT: Get the auth token for this wrapper.
- *
- * @return string A token.
- * @see object()
- */
- public function token()
- {
- return $this->store->token();
- }
-
- /**
- * EXPERT: Get the service catalog (IdentityService) for this wrapper.
- *
- * This is only available when a file is opened via fopen().
- *
- * @return array A service catalog.
- * @see object()
- */
- public function serviceCatalog()
- {
- return self::$serviceCatalogCache[$this->token()];
- }
-
- /**
- * Generate a reasonably accurate STAT array.
- *
- * Notes on mode:
- * - All modes are of the (octal) form 100XXX, where
- * XXX is replaced by the permission string. Thus,
- * this always reports that the type is "file" (100).
- * - Currently, only two permission sets are generated:
- * - 770: Represents the ACL::makePrivate() perm.
- * - 775: Represents the ACL::makePublic() perm.
- *
- * Notes on mtime/atime/ctime:
- * - For whatever reason, Swift only stores one timestamp.
- * We use that for mtime, atime, and ctime.
- *
- * Notes on size:
- * - Size must be calculated externally, as it will sometimes
- * be the remote's Content-Length, and it will sometimes be
- * the cached stat['size'] for the underlying buffer.
- */
- protected function generateStat($object, $container, $size)
- {
- // This is not entirely accurate. Basically, if the
- // file is marked public, it gets 100775, and if
- // it is private, it gets 100770.
- //
- // Mode is always set to file (100XXX) because there
- // is no alternative that is more sensible. PHP docs
- // do not recommend an alternative.
- //
- // octdec(100770) == 33272
- // octdec(100775) == 33277
- $mode = $container->acl()->isPublic() ? 33277 : 33272;
-
- // We have to fake the UID value in order for is_readible()/is_writable()
- // to work. Note that on Windows systems, stat does not look for a UID.
- if (function_exists('posix_geteuid')) {
- $uid = posix_geteuid();
- $gid = posix_getegid();
- } else {
- $uid = 0;
- $gid = 0;
- }
-
- if ($object instanceof \OpenStack\ObjectStore\v1\Resource\RemoteObject) {
- $modTime = $object->lastModified();
- } else {
- $modTime = 0;
- }
- $values = [
- 'dev' => 0,
- 'ino' => 0,
- 'mode' => $mode,
- 'nlink' => 0,
- 'uid' => $uid,
- 'gid' => $gid,
- 'rdev' => 0,
- 'size' => $size,
- 'atime' => $modTime,
- 'mtime' => $modTime,
- 'ctime' => $modTime,
- 'blksize' => -1,
- 'blocks' => -1,
- ];
-
- $final = array_values($values) + $values;
-
- return $final;
-
- }
-
- ///////////////////////////////////////////////////////////////////
- // INTERNAL METHODS
- // All methods beneath this line are not part of the Stream API.
- ///////////////////////////////////////////////////////////////////
-
- /**
- * Set the fopen mode.
- *
- * @param string $mode The mode string, e.g. `r+` or `wb`.
- *
- * @return \OpenStack\ObjectStore\v1\Resource\StreamWrapper $this so the method
- * can be used in chaining.
- */
- protected function setMode($mode)
- {
- $mode = strtolower($mode);
-
- // These are largely ignored, as the remote
- // object storage does not distinguish between
- // text and binary files. Per the PHP recommendation
- // files are treated as binary.
- $this->isBinary = strpos($mode, 'b') !== false;
- $this->isText = strpos($mode, 't') !== false;
-
- // Rewrite mode to remove b or t:
- $mode = preg_replace('/[bt]?/', '', $mode);
-
- switch ($mode) {
- case 'r+':
- $this->isWriting = true;
- case 'r':
- $this->isReading = true;
- $this->createIfNotFound = false;
- break;
-
-
- case 'w+':
- $this->isReading = true;
- case 'w':
- $this->isTruncating = true;
- $this->isWriting = true;
- break;
-
-
- case 'a+':
- $this->isReading = true;
- case 'a':
- $this->isAppending = true;
- $this->isWriting = true;
- break;
-
-
- case 'x+':
- $this->isReading = true;
- case 'x':
- $this->isWriting = true;
- $this->noOverwrite = true;
- break;
-
- case 'c+':
- $this->isReading = true;
- case 'c':
- $this->isWriting = true;
- break;
-
- // nope mode: Mock read/write support,
- // but never write to the remote server.
- // (This is accomplished by never marking
- // the stream as dirty.)
- case 'nope':
- $this->isReading = true;
- $this->isWriting = true;
- $this->isNeverDirty = true;
- break;
-
- // Default case is read/write
- // like c+.
- default:
- $this->isReading = true;
- $this->isWriting = true;
- break;
-
- }
-
- return $this;
- }
-
- /**
- * Get an item out of the context.
- *
- * @todo Should there be an option to NOT query the Bootstrap::conf()?
- *
- * @param string $name The name to look up. First look it up in the context,
- * then look it up in the Bootstrap config.
- * @param mixed $default The default value to return if no config param was
- * found.
- *
- * @return mixed The discovered result, or $default if specified, or null if
- * no $default is specified.
- */
- protected function cxt($name, $default = null)
- {
- // Lazilly populate the context array.
- if (is_resource($this->context) && empty($this->contextArray)) {
- $cxt = stream_context_get_options($this->context);
-
- // If a custom scheme name has been set, use that.
- if (!empty($cxt[$this->schemeName])) {
- $this->contextArray = $cxt[$this->schemeName];
- }
- // We fall back to this just in case.
- elseif (!empty($cxt[self::DEFAULT_SCHEME])) {
- $this->contextArray = $cxt[self::DEFAULT_SCHEME];
- }
- }
-
- // Should this be array_key_exists()?
- if (isset($this->contextArray[$name])) {
- return $this->contextArray[$name];
- }
-
- // Check to see if the value can be gotten from
- // \OpenStack\Bootstrap.
- $val = \OpenStack\Bootstrap::config($name, null);
- if (isset($val)) {
- return $val;
- }
-
- return $default;
- }
-
- /**
- * Parse a URL.
- *
- * In order to provide full UTF-8 support, URLs must be
- * rawurlencoded before they are passed into the stream wrapper.
- *
- * This parses the URL and urldecodes the container name and
- * the object name.
- *
- * @param string $url A Swift URL.
- *
- * @return array An array as documented in parse_url().
- */
- protected function parseUrl($url)
- {
- $res = parse_url($url);
-
-
- // These have to be decode because they will later
- // be encoded.
- foreach ($res as $key => $val) {
- if ($key == 'host') {
- $res[$key] = urldecode($val);
- } elseif ($key == 'path') {
- if (strpos($val, '/') === 0) {
- $val = substr($val, 1);
- }
- $res[$key] = urldecode($val);
-
- }
- }
-
- return $res;
- }
-
- /**
- * Based on the context, initialize the ObjectStorage.
- *
- * The following parameters may be set either in the stream context
- * or through \OpenStack\Bootstrap::setConfiguration():
- *
- * - token: An auth token. If this is supplied, authentication is skipped and
- * this token is used. NOTE: You MUST set swift_endpoint if using this
- * option.
- * - swift_endpoint: The URL to the swift instance. This is only necessary if
- * 'token' is set. Otherwise it is ignored.
- * - username: A username. MUST be accompanied by 'password' and 'tenantname'.
- * - password: A password. MUST be accompanied by 'username' and 'tenantname'.
- * - endpoint: The URL to the authentication endpoint. Necessary if you are not
- * using a 'token' and 'swift_endpoint'.
- * - transport_client: A transport client for the HTTP requests.
- *
- * To find these params, the method first checks the supplied context. If the
- * key is not found there, it checks the Bootstrap::conf().
- */
- protected function initializeObjectStorage()
- {
- $token = $this->cxt('token');
-
- $tenantId = $this->cxt('tenantid');
- $tenantName = $this->cxt('tenantname');
- $authUrl = $this->cxt('endpoint');
- $endpoint = $this->cxt('swift_endpoint');
- $client = $this->cxt('transport_client', null);
-
- $serviceCatalog = null;
-
- if (!empty($token) && isset(self::$serviceCatalogCache[$token])) {
- $serviceCatalog = self::$serviceCatalogCache[$token];
- }
-
- // FIXME: If a token is invalidated, we should try to re-authenticate.
- // If context has the info we need, start from there.
- if (!empty($token) && !empty($endpoint)) {
- $this->store = new \OpenStack\ObjectStore\v1\ObjectStorage($token, $endpoint, $client);
- }
- // If we get here and tenant ID is not set, we can't get a container.
- elseif (empty($tenantId) && empty($tenantName)) {
- throw new \OpenStack\Common\Exception('Either Tenant ID (tenantid) or Tenant Name (tenantname) is required.');
- } elseif (empty($authUrl)) {
- throw new \OpenStack\Common\Exception('An Identity Service Endpoint (endpoint) is required.');
- }
- // Try to authenticate and get a new token.
- else {
- $ident = $this->authenticate();
-
- // Update token and service catalog. The old pair may be out of date.
- $token = $ident->token();
- $serviceCatalog = $ident->serviceCatalog();
- self::$serviceCatalogCache[$token] = $serviceCatalog;
-
- $region = $this->cxt('openstack.swift.region');
-
- $this->store = ObjectStorage::newFromServiceCatalog($serviceCatalog, $token, $region, $client);
- }
-
- return !empty($this->store);
- }
-
- protected function authenticate()
- {
- $username = $this->cxt('username');
- $password = $this->cxt('password');
-
- $tenantId = $this->cxt('tenantid');
- $tenantName = $this->cxt('tenantname');
- $authUrl = $this->cxt('endpoint');
-
- $client = $this->cxt('transport_client', null);
-
- $ident = new \OpenStack\Identity\v2\IdentityService($authUrl, $client);
-
- // Frustrated? Go burninate. http://www.homestarrunner.com/trogdor.html
-
- if (!empty($username) && !empty($password)) {
- $token = $ident->authenticateAsUser($username, $password, $tenantId, $tenantName);
- } else {
- throw new \OpenStack\Common\Exception('Username/password must be provided.');
- }
- // Cache the service catalog.
- self::$serviceCatalogCache[$token] = $ident->serviceCatalog();
-
- return $ident;
- }
-
-}
diff --git a/src/OpenStack/ObjectStore/v1/Resource/StreamWrapperFS.php b/src/OpenStack/ObjectStore/v1/Resource/StreamWrapperFS.php
deleted file mode 100644
index 436d487..0000000
--- a/src/OpenStack/ObjectStore/v1/Resource/StreamWrapperFS.php
+++ /dev/null
@@ -1,218 +0,0 @@
-cxt('swiftfs_fake_isdir_true', false) || !($this->testDirectoryExists($uri)));
-
- }
-
- /**
- * Fake Remove a directory.
- *
- * ObjectStorage has pathy objects not directories. If no objects with a path
- * prefix exist we can pass removing it. If objects with a path prefix exist
- * removing the directory will fail.
- */
- public function rmdir($path, $options)
- {
- return !($this->testDirectoryExists($path));
-
- }
-
- /**
- * @see stream_stat().
- */
- public function url_stat($path, $flags)
- {
- $stat = parent::url_stat($path, $flags);
-
- // If the file stat setup returned anything return it.
- if ($stat) {
- return $stat;
- }
- // When false is returned there is no file to stat. So, we attempt to handle
- // it like a directory.
- else {
- if ($this->cxt('swiftfs_fake_isdir_true', false) || $this->testDirectoryExists($path)) {
- // The directory prefix exists. Fake the directory file permissions.
- return $this->fakeStat(true);
- } else {
- // The directory does not exist as a prefix.
- return false;
- }
- }
- }
-
- ///////////////////////////////////////////////////////////////////
- // INTERNAL METHODS
- // All methods beneath this line are not part of the Stream API.
- ///////////////////////////////////////////////////////////////////
-
- /**
- * Test if a path prefix (directory like) esits.
- *
- * ObjectStorage has pathy objects not directories. If objects exist with a
- * path prefix we can consider that the directory exists. For example, if
- * we have an object at foo/bar/baz.txt and test the existance of the
- * directory foo/bar/ we sould see it.
- *
- * @param string $path The directory path to test.
- *
- * @return boolean true if the directory prefix exists and false otherwise.
- */
- protected function testDirectoryExists($path)
- {
- $url = $this->parseUrl($path);
-
- if (empty($url['host'])) {
- trigger_error('Container name is required.' , E_USER_WARNING);
-
- return false;
- }
-
- try {
- $this->initializeObjectStorage();
- $container = $this->store->container($url['host']);
-
- if (empty($url['path'])) {
- $this->dirPrefix = '';
- } else {
- $this->dirPrefix = $url['path'];
- }
-
- $sep = '/';
-
-
- $dirListing = $container->objectsWithPrefix($this->dirPrefix, $sep);
-
- return !empty($dirListing);
- } catch (\OpenStack\Common\Exception $e) {
- trigger_error('Path could not be opened: ' . $e->getMessage(), E_USER_WARNING);
-
- return false;
- }
- }
-
- /**
- * Fake stat data.
- *
- * Under certain conditions we have to return totally trumped-up
- * stats. This generates those.
- */
- protected function fakeStat($dir = false)
- {
- $request_time = time();
-
- // Set inode type to directory or file.
- $type = $dir ? 040000 : 0100000;
- // Fake world-readible
- $mode = $type + $this->cxt('swiftfs_fake_stat_mode', 0777);
-
- $values = [
- 'dev' => 0,
- 'ino' => 0,
- 'mode' => $mode,
- 'nlink' => 0,
- 'uid' => posix_getuid(),
- 'gid' => posix_getgid(),
- 'rdev' => 0,
- 'size' => 0,
- 'atime' => $request_time,
- 'mtime' => $request_time,
- 'ctime' => $request_time,
- 'blksize' => -1,
- 'blocks' => -1,
- ];
-
- $final = array_values($values) + $values;
-
- return $final;
- }
-
-}
diff --git a/src/OpenStack/ObjectStore/v1/Resource/Subdir.php b/src/OpenStack/ObjectStore/v1/Resource/Subdir.php
deleted file mode 100644
index 491b589..0000000
--- a/src/OpenStack/ObjectStore/v1/Resource/Subdir.php
+++ /dev/null
@@ -1,75 +0,0 @@
-path = $path;
- $this->delimiter = $delimiter;
- }
-
- /**
- * Get the path.
- *
- * The path is delimited using the string returned by delimiter().
- *
- * @return string The path
- */
- public function path()
- {
- return $this->path;
- }
- /**
- * Get the delimiter used by the server.
- *
- * @return string The value used as a delimiter.
- */
- public function delimiter()
- {
- return $this->delimiter;
- }
-}
diff --git a/tests/README.md b/tests/README.md
deleted file mode 100644
index fb011af..0000000
--- a/tests/README.md
+++ /dev/null
@@ -1,105 +0,0 @@
-# Running Tests for the PHP-Client bindings
-
-This file explains how to configured your environment for running the
-PHP-Client automated testing.
-
-The OpenStack bindings offer a few stand-alone tests for testing basic
-connectivity to OpenStack services, but most tests are of the
-automated variety.
-
-*IMPORTANT*: Make sure your settings.ini file is up-to-date! Options
-have changed!
-
-## Stand-alone Tests
-
-Stand-alone tests are designed to verify that certain preconditions of
-the libary are met.
-
-### AuthTest.php
-
-The AuthTest test is a simple commandline program that allows you to
-verify that your PHP client can successfully connect to OpenStack. To
-run this test, do the following:
-
-1. Begin from the root directory of this project, where you should see
- the directories `tests/` and `src/`, among others.
-2. Execute the following command on the commandline:
-
-```
-$ php tests/AuthTest.php
-```
-
-This will instruct you to use a more complete version of the command,
-including:
-
-* USERNAME: The username given to you.
-* PASSWORD: The password associated with the username.
-* URL: The Endpoint URL.
-* TENANT ID: Your users's tenant ID.
-
-All four pieces of information can be found by logging into the
-console. From there, you can execute a command like this:
-
-```
-$ php tests/AuthTest.php myusername apassword https://region-a.geo-1.identity.hpcloudsvc.com:35357/v2.0/ 1234567
-
-```
-
-If successfull, it should return details about your username, token, and
-the services in your service catalog.
-
-## Unit Tests
-
-Unit and behavioral tests are built using [PHPUnit](http://www.phpunit.de/). Before you can
-test this package, you will need to [install that tool](http://www.phpunit.de/manual/3.7/en/installation.html).
-
-Next, you need to create your own `settings.ini` file to contain your HP
-Cloud credentials, along with your preferred testing parameters.
-
-### Creating settings.ini
-
-The easiest way to do this is to copy the example settings file, and
-then make the necessary changes:
-
- $ cd tests/
- $ cp example.settings.ini settings.ini
- $ edit settings.ini
-
-### Running Tests
-
-The test suite uses PHPUnit and can generate a code coverage report if
-xdebug is installed. To run the test suite make sure PHPUnit is installed
-via composer by using `composer install` or `composer update`. Once PHPUnit is
-installed execute the following command from the root of the project.
-
- $ ./vendor/bin/phpunit
-
-This should generate output looking something like this:
-
- PHPUnit 4.0.13 by Sebastian Bergmann.
-
- Configuration read from /path/to/openstack-sdk-php/phpunit.xml.dist
-
- ............................................................... 63 / 146 ( 43%)
- ............................................................... 126 / 146 ( 86%)
- ....................
-
- Time: 4.94 minutes, Memory: 17.50Mb
-
- OK (146 tests, 413 assertions)
-
- Generating code coverage report in Clover XML format ... done
-
- Generating code coverage report in HTML format ... done
-
-If the tests fail, detailed information about the failure will be
-displayed.
-
-PHPUnit has a wide variety of commandline options. Other sorts of
-reports and analyses can be done using those.
-
-## Writing Tests
-
-Tests should be written according to the PHPUnit documentation. Tests
-should follow the same coding standards as all other parts of the
-library.
diff --git a/tests/Tests/BootstrapTest.php b/tests/Tests/BootstrapTest.php
deleted file mode 100644
index 673eb5e..0000000
--- a/tests/Tests/BootstrapTest.php
+++ /dev/null
@@ -1,30 +0,0 @@
-assertTrue(!empty(self::$settings));
- }
-}
diff --git a/tests/Tests/Common/Transport/AbstractClientTest.php b/tests/Tests/Common/Transport/AbstractClientTest.php
deleted file mode 100644
index 6555b23..0000000
--- a/tests/Tests/Common/Transport/AbstractClientTest.php
+++ /dev/null
@@ -1,94 +0,0 @@
- 'bar'];
- private $body = 'baz';
-
- public function setUp()
- {
- $this->request = $this->getMockBuilder('OpenStack\Common\Transport\RequestInterface')
- ->disableOriginalConstructor()
- ->getMock();
-
- $this->client = $this->getMockForAbstractClass('OpenStack\Common\Transport\AbstractClient');
-
- $this->client->expects($this->once())
- ->method('send')
- ->with($this->request);
- }
-
- public function testGet()
- {
- $this->client->expects($this->once())
- ->method('createRequest')
- ->with('GET', self::URI, null, $this->options)
- ->will($this->returnValue($this->request));
-
- $this->client->get(self::URI, $this->options);
- }
-
- public function testHead()
- {
- $this->client->expects($this->once())
- ->method('createRequest')
- ->with('HEAD', self::URI, null, $this->options)
- ->will($this->returnValue($this->request));
-
- $this->client->head(self::URI, $this->options);
- }
-
- public function testPost()
- {
- $this->client->expects($this->once())
- ->method('createRequest')
- ->with('POST', self::URI, $this->body, $this->options)
- ->will($this->returnValue($this->request));
-
- $this->client->post(self::URI, $this->body, $this->options);
- }
-
- public function testPut()
- {
- $this->client->expects($this->once())
- ->method('createRequest')
- ->with('PUT', self::URI, $this->body, $this->options)
- ->will($this->returnValue($this->request));
-
- $this->client->put(self::URI, $this->body, $this->options);
- }
-
- public function testDelete()
- {
- $this->client->expects($this->once())
- ->method('createRequest')
- ->with('DELETE', self::URI, null, $this->options)
- ->will($this->returnValue($this->request));
-
- $this->client->delete(self::URI, $this->options);
- }
-}
\ No newline at end of file
diff --git a/tests/Tests/Common/Transport/Guzzle/GuzzleAdapterTest.php b/tests/Tests/Common/Transport/Guzzle/GuzzleAdapterTest.php
deleted file mode 100644
index f98b071..0000000
--- a/tests/Tests/Common/Transport/Guzzle/GuzzleAdapterTest.php
+++ /dev/null
@@ -1,92 +0,0 @@
-mockClient = $this->getMockBuilder('GuzzleHttp\Client')
- ->disableOriginalConstructor()
- ->getMock();
-
- $this->adapter = new GuzzleAdapter($this->mockClient);
- }
-
- public function testFactoryReturnsInstance()
- {
- $this->assertInstanceOf(
- 'OpenStack\Common\Transport\Guzzle\GuzzleAdapter',
- $this->adapter
- );
- }
-
- public function testFactoryMethod()
- {
- $this->assertInstanceOf(
- 'OpenStack\Common\Transport\Guzzle\GuzzleAdapter',
- GuzzleAdapter::create()
- );
- }
-
- public function testCreateRequestCallsClientAndReturnsAdapter()
- {
- $this->mockClient
- ->expects($this->once())
- ->method('createRequest')
- ->with('GET')
- ->will($this->returnValue(
- $this->getMock('GuzzleHttp\Message\RequestInterface')
- ));
-
- $adapter = (new GuzzleAdapter($this->mockClient))->createRequest('GET');
- $this->assertInstanceOf('OpenStack\Common\Transport\Guzzle\RequestAdapter', $adapter);
- $this->assertInstanceOf('GuzzleHttp\Message\RequestInterface', $adapter->getMessage());
- }
-
- public function testSetOptionCallsClient()
- {
- $key = 'foo';
- $value = 'bar';
- $this->mockClient->expects($this->once())->method('setDefaultOption')->with($key, $value);
-
- (new GuzzleAdapter($this->mockClient))->setOption($key, $value);
- }
-
- public function testGetBaseUrlWithOption()
- {
- $this->mockClient->expects($this->once())->method('getBaseUrl');
- (new GuzzleAdapter($this->mockClient))->getOption('base_url');
- }
-
- public function testGetOption()
- {
- $this->mockClient->expects($this->once())->method('getDefaultOption')->with('foo');
- (new GuzzleAdapter($this->mockClient))->getOption('foo');
- }
-}
\ No newline at end of file
diff --git a/tests/Tests/Common/Transport/Guzzle/HttpErrorTest.php b/tests/Tests/Common/Transport/Guzzle/HttpErrorTest.php
deleted file mode 100644
index 01bb6b1..0000000
--- a/tests/Tests/Common/Transport/Guzzle/HttpErrorTest.php
+++ /dev/null
@@ -1,128 +0,0 @@
-assertInstanceOf('OpenStack\Common\Transport\Guzzle\HttpError', $sub);
- }
-
- private function getEvent()
- {
- return new CompleteEvent(new Transaction(new Client(), new Request('GET', '/')));
- }
-
- public function testSuccessfulResponsesThrowNothing()
- {
- $event = $this->getEvent();
- $event->intercept(new Response(200));
- (new HttpError())->onComplete($event);
- }
-
- /**
- * @expectedException \OpenStack\Common\Transport\Exception\ConflictException
- */
- public function testConflictExceptionRaisedFor409Error()
- {
- $event = $this->getEvent();
- $event->intercept(new Response(409));
- (new HttpError())->onComplete($event);
- }
-
- /**
- * @expectedException \OpenStack\Common\Transport\Exception\ForbiddenException
- */
- public function testConflictExceptionRaisedFor403Error()
- {
- $event = $this->getEvent();
- $event->intercept(new Response(403));
- (new HttpError())->onComplete($event);
- }
-
- /**
- * @expectedException \OpenStack\Common\Transport\Exception\LengthRequiredException
- */
- public function testConflictExceptionRaisedFor411Error()
- {
- $event = $this->getEvent();
- $event->intercept(new Response(411));
- (new HttpError())->onComplete($event);
- }
-
- /**
- * @expectedException \OpenStack\Common\Transport\Exception\MethodNotAllowedException
- */
- public function testConflictExceptionRaisedFor405Error()
- {
- $event = $this->getEvent();
- $event->intercept(new Response(405));
- (new HttpError())->onComplete($event);
- }
-
- /**
- * @expectedException \OpenStack\Common\Transport\Exception\ResourceNotFoundException
- */
- public function testConflictExceptionRaisedFor404Error()
- {
- $event = $this->getEvent();
- $event->intercept(new Response(404));
- (new HttpError())->onComplete($event);
- }
-
- /**
- * @expectedException \OpenStack\Common\Transport\Exception\ServerException
- */
- public function testConflictExceptionRaisedFor500Error()
- {
- $event = $this->getEvent();
- $event->intercept(new Response(500));
- (new HttpError())->onComplete($event);
- }
-
- /**
- * @expectedException \OpenStack\Common\Transport\Exception\UnauthorizedException
- */
- public function testConflictExceptionRaisedFor401Error()
- {
- $event = $this->getEvent();
- $event->intercept(new Response(401));
- (new HttpError())->onComplete($event);
- }
-
- /**
- * @expectedException \OpenStack\Common\Transport\Exception\UnprocessableEntityException
- */
- public function testConflictExceptionRaisedFor422Error()
- {
- $event = $this->getEvent();
- $event->intercept(new Response(422));
- (new HttpError())->onComplete($event);
- }
-}
\ No newline at end of file
diff --git a/tests/Tests/Common/Transport/Guzzle/MessageAdapterTest.php b/tests/Tests/Common/Transport/Guzzle/MessageAdapterTest.php
deleted file mode 100644
index 2392a8b..0000000
--- a/tests/Tests/Common/Transport/Guzzle/MessageAdapterTest.php
+++ /dev/null
@@ -1,139 +0,0 @@
-getMockBuilder($class)
- ->disableOriginalConstructor()
- ->getMock();
- }
-
- public function setUp()
- {
- $this->mock = $this->getStub(self::REQUEST_CLASS);
- $this->adapter = new MessageAdapter($this->mock);
- }
-
- public function testConstructorSetsMessage()
- {
- $this->assertInstanceOf(self::REQUEST_CLASS, $this->adapter->getMessage());
- }
-
- public function testSettingMessage()
- {
- $this->adapter->setMessage($this->getStub(self::RESPONSE_CLASS));
- $this->assertInstanceOf(self::RESPONSE_CLASS, $this->adapter->getMessage());
- }
-
- public function testGetProtocol()
- {
- $this->mock->expects($this->once())->method('getProtocolVersion');
- $this->adapter->setMessage($this->mock);
- $this->adapter->getProtocolVersion();
- }
-
- public function testSetBody()
- {
- $body = $this->getMock('GuzzleHttp\Stream\StreamInterface');
- $this->mock->expects($this->once())->method('setBody')->with($body);
- $this->adapter->setMessage($this->mock);
- $this->adapter->setBody($body);
- }
-
- public function testGetBody()
- {
- $this->mock->expects($this->once())->method('getBody');
- $this->adapter->setMessage($this->mock);
- $this->adapter->getBody();
- }
-
- public function testGetHeaders()
- {
- $this->mock->expects($this->once())->method('getHeaders');
- $this->adapter->setMessage($this->mock);
- $this->adapter->getHeaders();
- }
-
- public function testHasHeader()
- {
- $this->mock->expects($this->once())->method('hasHeader')->with('foo');
- $this->adapter->setMessage($this->mock);
- $this->adapter->hasHeader('foo');
- }
-
- public function testSetHeader()
- {
- $header = 'foo';
- $value = 'bar';
- $this->mock->expects($this->once())->method('setHeader')->with($header, $value);
- $this->adapter->setMessage($this->mock);
- $this->adapter->setHeader($header, $value);
- }
-
- public function testGetHeader()
- {
- $this->mock->expects($this->once())->method('getHeader')->with('foo');
- $this->adapter->setMessage($this->mock);
- $this->adapter->getHeader('foo');
- }
-
- public function testSetHeaders()
- {
- $headers = ['foo' => 'bar'];
- $this->mock->expects($this->once())->method('setHeaders')->with($headers);
- $this->adapter->setMessage($this->mock);
- $this->adapter->setHeaders($headers);
- }
-
- public function testAddHeader()
- {
- $header = 'foo';
- $value = 'bar';
- $this->mock->expects($this->once())->method('addHeader')->with($header, $value);
- $this->adapter->setMessage($this->mock);
- $this->adapter->addHeader($header, $value);
- }
-
- public function testAddHeaders()
- {
- $headers = ['foo' => 'bar'];
- $this->mock->expects($this->once())->method('addHeaders')->with($headers);
- $this->adapter->setMessage($this->mock);
- $this->adapter->addHeaders($headers);
- }
-
- public function testRemoveHeader()
- {
- $this->mock->expects($this->once())->method('removeHeader')->with('foo');
- $this->adapter->setMessage($this->mock);
- $this->adapter->removeHeader('foo');
- }
-}
\ No newline at end of file
diff --git a/tests/Tests/Common/Transport/Guzzle/RequestAdapterTest.php b/tests/Tests/Common/Transport/Guzzle/RequestAdapterTest.php
deleted file mode 100644
index c278919..0000000
--- a/tests/Tests/Common/Transport/Guzzle/RequestAdapterTest.php
+++ /dev/null
@@ -1,69 +0,0 @@
-getMockBuilder($class)
- ->disableOriginalConstructor()
- ->getMock();
- }
-
- public function setUp()
- {
- $this->mock = $this->getStub('GuzzleHttp\Message\Request');
- $this->adapter = new RequestAdapter($this->mock);
- }
-
- public function testGetMethod()
- {
- $this->mock->expects($this->once())->method('getMethod');
- $this->adapter->setMessage($this->mock);
- $this->adapter->getMethod();
- }
-
- public function testSetMethod()
- {
- $this->mock->expects($this->once())->method('setMethod')->with('foo');
- $this->adapter->setMessage($this->mock);
- $this->adapter->setMethod('foo');
- }
-
- public function testGetUrl()
- {
- $this->mock->expects($this->once())->method('getUrl');
- $this->adapter->setMessage($this->mock);
- $this->adapter->getUrl();
- }
-
- public function testSetUrl()
- {
- $this->mock->expects($this->once())->method('setUrl')->with('foo');
- $this->adapter->setMessage($this->mock);
- $this->adapter->setUrl('foo');
- }
-}
\ No newline at end of file
diff --git a/tests/Tests/Common/Transport/Guzzle/ResponseAdapterTest.php b/tests/Tests/Common/Transport/Guzzle/ResponseAdapterTest.php
deleted file mode 100644
index 653ddf2..0000000
--- a/tests/Tests/Common/Transport/Guzzle/ResponseAdapterTest.php
+++ /dev/null
@@ -1,55 +0,0 @@
-getMockBuilder($class)
- ->disableOriginalConstructor()
- ->getMock();
- }
-
- public function setUp()
- {
- $this->mock = $this->getStub('GuzzleHttp\Message\Response');
- $this->adapter = new ResponseAdapter($this->mock);
- }
-
- public function testGetStatusCode()
- {
- $this->mock->expects($this->once())->method('getStatusCode');
- $this->adapter->setMessage($this->mock);
- $this->adapter->getStatusCode();
- }
-
- public function testGetReasonPhrase()
- {
- $this->mock->expects($this->once())->method('getReasonPhrase');
- $this->adapter->setMessage($this->mock);
- $this->adapter->getReasonPhrase();
- }
-}
\ No newline at end of file
diff --git a/tests/Tests/Common/Transport/UrlTest.php b/tests/Tests/Common/Transport/UrlTest.php
deleted file mode 100644
index 3ee4515..0000000
--- a/tests/Tests/Common/Transport/UrlTest.php
+++ /dev/null
@@ -1,113 +0,0 @@
-url = new Url(self::URL_STRING);
- }
-
- public function testIsConstructedWithProperties()
- {
- $this->assertEquals('https', $this->url->getScheme());
- $this->assertEquals('openstack.org', $this->url->getHost());
- $this->assertEquals('80', $this->url->getPort());
- $this->assertEquals('/community/members', $this->url->getPath());
- $this->assertEquals('username', $this->url->getUser());
- $this->assertEquals('password', $this->url->getPassword());
- $this->assertEquals('anchor', $this->url->getFragment());
- }
-
- public function testSettingStringUrlResultsInArrayBasedQuery()
- {
- $url = new Url('//foo.com?bar=a&baz=b');
- $this->assertEquals(['bar' => 'a', 'baz' => 'b'], $url->getQuery());
- }
-
- /**
- * @expectedException \InvalidArgumentException
- */
- public function testExceptionIsThrownWhenPopulatingWithInvalidDataType()
- {
- $value = (object) ['path' => 'https', 'host' => 'openstack.org'];
- new Url($value);
- }
-
- public function testSettingQueryWithString()
- {
- $this->url->setQuery('foo=bar&baz=boo');
- $this->assertEquals(['foo' => 'bar', 'baz' => 'boo'], $this->url->getQuery());
- }
-
- public function testSettingQueryWithStringArray()
- {
- $this->url->setQuery('foo[]=bar&foo[]=baz');
- $this->assertEquals(['foo' => ['bar', 'baz']], $this->url->getQuery());
- }
-
- public function testSettingQueryWithArray()
- {
- $query = ['foo' => 'bar'];
- $this->url->setQuery($query);
- $this->assertEquals($query, $this->url->getQuery());
- }
-
- /**
- * @expectedException \InvalidArgumentException
- */
- public function testExceptionIsThrownWhenSettingQueryWithInvalidDataType()
- {
- $this->url->setQuery(false);
- }
-
- public function testAddPath()
- {
- $this->url->addPath('foo');
- $this->assertEquals('/community/members/foo', $this->url->getPath());
- }
-
- public function testAddQuery()
- {
- $this->url->setQuery(['foo' => 'bar']);
- $this->url->addQuery(['baz' => 'boo']);
- $this->assertEquals(['foo' => 'bar', 'baz' => 'boo'], $this->url->getQuery());
- }
-
- public function testCastingToString()
- {
- $this->assertEquals(self::URL_STRING, (string) $this->url);
- }
-
- public function testCastingToStringForQueryArrays()
- {
- $url = new Url('http://openstack.org');
- $url->setQuery(['foo' => ['val1', 'val2'], 'bar' => 'val3']);
-
- $this->assertEquals('http://openstack.org?foo[]=val1&foo[]=val2&bar=val3', (string) $url);
- }
-}
\ No newline at end of file
diff --git a/tests/Tests/Identity/v2/IdentityServicesTest.php b/tests/Tests/Identity/v2/IdentityServicesTest.php
deleted file mode 100644
index d6d9103..0000000
--- a/tests/Tests/Identity/v2/IdentityServicesTest.php
+++ /dev/null
@@ -1,439 +0,0 @@
-assertNotEmpty($endpoint);
-
- $service = new IdentityService($endpoint, $this->getTransportClient());
-
- $this->assertInstanceOf('\OpenStack\Identity\v2\IdentityService', $service);
-
- return $service;
- }
-
- /**
- * @depends testConstructor
- */
- public function testUrl()
- {
- $endpoint = self::conf('openstack.identity.url');
- $service = new IdentityService($endpoint, $this->getTransportClient());
-
- // If there is a trailing / we remove that from the endpoint. Our calls add
- // the / back where appropriate.
- $this->assertStringStartsWith(rtrim($endpoint, '/'), $service->url());
-
- return $service;
- }
-
- /**
- * @depends testUrl
- */
- public function testAuthenticate($service)
- {
- // Canary: Make sure all the required params are declared.
- $settings = [
- 'openstack.identity.username',
- 'openstack.identity.password',
- 'openstack.identity.tenantId',
- ];
- foreach ($settings as $setting) {
- $this->assertNotEmpty(self::conf($setting), "Required param: " . $setting);
- }
-
- // Test username/password auth.
- $auth = [
- 'passwordCredentials' => [
- 'username' => self::conf('openstack.identity.username'),
- 'password' => self::conf('openstack.identity.password'),
- ],
- 'tenantId' => self::conf('openstack.identity.tenantId'),
- ];
- $tok = $service->authenticate($auth);
- $this->assertNotEmpty($tok);
-
- // Again with no tenant ID.
- $auth = [
- 'passwordCredentials' => [
- 'username' => self::conf('openstack.identity.username'),
- 'password' => self::conf('openstack.identity.password'),
- ],
- //'tenantId' => self::conf('openstack.identity.tenantId'),
- ];
- $tok = $service->authenticate($auth);
- $this->assertNotEmpty($tok);
- }
-
- /**
- * @depends testAuthenticate
- */
- public function testAuthenticateAsUser()
- {
- $service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
-
- $user = self::conf('openstack.identity.username');
- $pass = self::conf('openstack.identity.password');
- $tenantId = self::conf('openstack.identity.tenantId');
-
- $tok = $service->authenticateAsUser($user, $pass, $tenantId);
- $this->assertNotEmpty($tok);
-
- return $service;
- }
-
- public function testAuthenticatingAsUserWithoutTenant()
- {
- $service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
-
- $username = self::conf('openstack.identity.username');
- $password = self::conf('openstack.identity.password');
-
- $this->assertNotEmpty($service->authenticateAsUser($username, $password));
- }
-
- /**
- * @depends testAuthenticateAsUser
- */
- public function testToken($service)
- {
- $this->assertNotEmpty($service->token());
- }
-
- /**
- * @depends testAuthenticateAsUser
- */
- public function testIsExpired($service)
- {
- $this->assertFalse($service->isExpired());
-
- $service2 = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
- $this->assertTrue($service2->isExpired());
- }
-
- /**
- * @depends testAuthenticateAsUser
- */
- public function testTenantName()
- {
- $user = self::conf('openstack.identity.username');
- $pass = self::conf('openstack.identity.password');
- $tenantName = self::conf('openstack.identity.tenantName');
-
- $service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
- $this->assertNull($service->tenantName());
-
- $service->authenticateAsUser($user, $pass);
- $this->assertEmpty($service->tenantName());
-
- $service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
- $ret = $service->authenticateAsUser($user, $pass, null, $tenantName);
- $this->assertNotEmpty($service->tenantName());
-
- $service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
- $this->assertNull($service->tenantName());
- }
-
- /**
- * @depends testAuthenticateAsUser
- */
- public function testTenantId()
- {
- $user = self::conf('openstack.identity.username');
- $pass = self::conf('openstack.identity.password');
- $tenantId = self::conf('openstack.identity.tenantId');
-
- $service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
- $this->assertNull($service->tenantId());
-
- $service->authenticateAsUser($user, $pass);
- $this->assertEmpty($service->tenantId());
-
- $service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
- $service->authenticateAsUser($user, $pass, $tenantId);
- $this->assertNotEmpty($service->tenantId());
- }
-
- /**
- * @depends testAuthenticateAsUser
- */
- public function testTokenDetails()
- {
- $now = time();
- $user = self::conf('openstack.identity.username');
- $pass = self::conf('openstack.identity.password');
- $tenantId = self::conf('openstack.identity.tenantId');
-
- $service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
- $service->authenticateAsUser($user, $pass);
-
- // Details for user auth.
- $details = $service->tokenDetails();
- $this->assertNotEmpty($details['id']);
- $this->assertFalse(isset($details['tenant']));
-
- $ts = strtotime($details['expires']);
- $this->assertGreaterThan($now, $ts);
-
- // Test details for username auth.
- $service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
- $service->authenticateAsUser($user, $pass, $tenantId);
-
- $details = $service->tokenDetails();
-
- $expectUser = self::conf('openstack.identity.username');
-
- $this->assertStringStartsWith($expectUser, $details['tenant']['name']);
- $this->assertNotEmpty($details['id']);
- $this->assertNotEmpty($details['tenant']['id']);
-
- $this->assertEquals($tenantId, $details['tenant']['id']);
-
- $ts = strtotime($details['expires']);
- $this->assertGreaterThan($now, $ts);
- }
-
- /**
- * @depends testAuthenticateAsUser
- */
- public function testServiceCatalog($service)
- {
- $catalog = $service->serviceCatalog();
-
- $this->assertGreaterThan(0, count($catalog));
-
- $idService = null;
- foreach ($catalog as $item) {
- if ($item['type'] == 'identity') {
- $idService = $item;
- }
- }
-
- $this->assertNotEmpty($idService['endpoints']);
- $this->assertNotEmpty($idService['endpoints'][0]['publicURL']);
-
- // Test filters.
- $justID = $service->serviceCatalog('identity');
- $this->assertEquals(1, count($justID));
-
- $idService = $justID[0];
- $this->assertNotEmpty($idService['endpoints']);
- $this->assertNotEmpty($idService['endpoints'][0]['publicURL']);
-
- // Make sure a missed filter returns an empty set.
- $expectEmpty = $service->serviceCatalog('no-such-servicename');
- $this->assertEmpty($expectEmpty);
- }
-
- /**
- * @depends testAuthenticateAsUser
- */
- public function testUser($service)
- {
- $user = $service->user();
-
- $this->assertEquals(self::conf('openstack.identity.username'), $user['name']);
- $this->assertNotEmpty($user['roles']);
- }
-
- /**
- * @depends testAuthenticateAsUser
- * @group serialize
- */
- public function testSerialization($service)
- {
- $ser = serialize($service);
-
- $this->assertNotEmpty($ser);
-
- $again = unserialize($ser);
-
- $this->assertInstanceOf('\OpenStack\Identity\v2\IdentityService', $again);
-
- $this->assertEquals($service->tenantId(), $again->tenantId());
- $this->assertEquals($service->serviceCatalog(), $again->serviceCatalog());
- $this->assertEquals($service->tokenDetails(), $again->tokenDetails());
- $this->assertEquals($service->user(), $again->user());
- $this->assertFalse($again->isExpired());
-
- $tenantId = $again->tenantId();
-
- $newTok = $again->rescopeUsingTenantId($tenantId);
-
- $this->assertNotEmpty($newTok);
- }
-
- /**
- * @group tenant
- */
- public function testTenants()
- {
- $service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
- $service2 = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
- $user = self::conf('openstack.identity.username');
- $pass = self::conf('openstack.identity.password');
- $tenantId = self::conf('openstack.identity.tenantId');
- $service->authenticateAsUser($user, $pass, $tenantId);
-
- $tenants = $service2->tenants($service->token());
-
- $this->assertGreaterThan(0, count($tenants));
- $this->assertNotEmpty($tenants[0]['name']);
- $this->assertNotEmpty($tenants[0]['id']);
-
- $tenants = $service->tenants();
- $this->assertGreaterThan(0, count($tenants));
- $this->assertNotEmpty($tenants[0]['name']);
- $this->assertNotEmpty($tenants[0]['id']);
-
- }
-
- /**
- * @group tenant
- * @depends testTenants
- */
- public function testRescopeUsingTenantId()
- {
- $service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
- $user = self::conf('openstack.identity.username');
- $pass = self::conf('openstack.identity.password');
- $tenantId = self::conf('openstack.identity.tenantId');
-
- // Authenticate without a tenant ID.
- $token = $service->authenticateAsUser($user, $pass);
-
- $this->assertNotEmpty($token);
-
- $details = $service->tokenDetails();
- $this->assertFalse(isset($details['tenant']));
-
- $service->rescopeUsingTenantId($tenantId);
-
- $details = $service->tokenDetails();
- $this->assertEquals($tenantId, $details['tenant']['id']);
-
- // Test unscoping
- $service->rescopeUsingTenantId('');
- $details = $service->tokenDetails();
- $this->assertFalse(isset($details['tenant']));
- }
-
- /**
- * @group tenant
- * @depends testTenants
- */
- public function testRescopeByTenantName()
- {
- $service = new IdentityService(self::conf('openstack.identity.url'), $this->getTransportClient());
- $user = self::conf('openstack.identity.username');
- $pass = self::conf('openstack.identity.password');
- $tenantName = self::conf('openstack.identity.tenantName');
-
- // Authenticate without a tenant ID.
- $token = $service->authenticateAsUser($user, $pass);
-
- $this->assertNotEmpty($token);
-
- $details = $service->tokenDetails();
- $this->assertFalse(isset($details['tenant']));
-
- $service->rescopeUsingTenantName($tenantName);
-
- $details = $service->tokenDetails();
- $this->assertEquals($tenantName, $details['tenant']['name']);
-
- // Test unscoping
- $service->rescopeUsingTenantName('');
- $details = $service->tokenDetails();
- $this->assertFalse(isset($details['tenant']));
- }
-
- /**
- * Test the bootstrap identity factory.
- * @depends testAuthenticateAsUser
- */
- public function testBootstrap()
- {
- // We need to save the config settings and reset the bootstrap to this.
- // It does not remove the old settings. The means the identity fall through
- // for different settings may not happen because of ordering. So, we cache
- // and reset back to the default for each test.
- $reset = Bootstrap::$config;
-
- // Test authenticating as a user.
- $settings = [
- 'username' => self::conf('openstack.identity.username'),
- 'password' => self::conf('openstack.identity.password'),
- 'endpoint' => self::conf('openstack.identity.url'),
- 'tenantid' => self::conf('openstack.identity.tenantId'),
- 'transport' => self::conf('transport'),
- 'transport.debug' => self::conf('transport.debug', false),
- 'transport.ssl_verify' => self::conf('transport.ssl', true),
- ];
- if (self::conf('transport.timeout')) {
- $setting['transport.timeout'] = self::conf('transport.timeout');
- }
- if (self::conf('transport.proxy')) {
- $setting['transport.proxy'] = self::conf('transport.proxy');
- }
- Bootstrap::setConfiguration($settings);
-
- $is = Bootstrap::identity(true);
- $this->assertInstanceOf('\OpenStack\Identity\v2\IdentityService', $is);
-
- // Test getting a second instance from the cache.
- $is2 = Bootstrap::identity();
- $this->assertEquals($is, $is2);
-
- // Test that forcing a refresh does so.
- $is2 = Bootstrap::identity(true);
- $this->assertNotEquals($is, $is2);
-
- Bootstrap::$config = $reset;
-
- // Test with tenant name
- $settings = [
- 'username' => self::conf('openstack.identity.username'),
- 'password' => self::conf('openstack.identity.password'),
- 'endpoint' => self::conf('openstack.identity.url'),
- 'tenantname' => self::conf('openstack.identity.tenantName'),
- 'transport' => self::conf('transport'),
- 'transport.debug' => self::conf('transport.debug', false),
- 'transport.ssl_verify' => self::conf('transport.ssl', true),
- ];
- if (self::conf('transport.timeout')) {
- $setting['transport.timeout'] = self::conf('transport.timeout');
- }
- if (self::conf('transport.proxy')) {
- $setting['transport.proxy'] = self::conf('transport.proxy');
- }
- Bootstrap::setConfiguration($settings);
-
- $is = Bootstrap::identity(true);
- $this->assertInstanceOf('\OpenStack\Identity\v2\IdentityService', $is);
- }
-}
diff --git a/tests/Tests/ObjectStore/v1/ObjectStorageTest.php b/tests/Tests/ObjectStore/v1/ObjectStorageTest.php
deleted file mode 100644
index 33cd359..0000000
--- a/tests/Tests/ObjectStore/v1/ObjectStorageTest.php
+++ /dev/null
@@ -1,287 +0,0 @@
-assertTrue(!empty(self::$settings));
- }
-
- /**
- * @group auth
- */
- public function testConstructor()
- {
- $ident = $this->identity();
-
- $services = $ident->serviceCatalog(\OpenStack\ObjectStore\v1\ObjectStorage::SERVICE_TYPE);
-
- if (empty($services)) {
- throw new \Exception('No object-store service found.');
- }
-
- //$serviceURL = $services[0]['endpoints'][0]['adminURL'];
- $serviceURL = $services[0]['endpoints'][0]['publicURL'];
-
- $ostore = new \OpenStack\ObjectStore\v1\ObjectStorage($ident->token(), $serviceURL, $this->getTransportClient());
-
- $this->assertInstanceOf('\OpenStack\ObjectStore\v1\ObjectStorage', $ostore);
- $this->assertTrue(strlen($ostore->token()) > 0);
-
- }
-
- public function testNewFromServiceCatalog()
- {
- $ident = $this->identity();
- $tok = $ident->token();
- $cat = $ident->serviceCatalog();
- $region = self::$settings['openstack.swift.region'];
- $client = $this->getTransportClient();
- $ostore = \OpenStack\ObjectStore\v1\ObjectStorage::newFromServiceCatalog($cat, $tok, $region, $client);
- $this->assertInstanceOf('\OpenStack\ObjectStore\v1\ObjectStorage', $ostore);
- $this->assertTrue(strlen($ostore->token()) > 0);
- }
-
- public function testFailedNewFromServiceCatalog()
- {
- $ident = $this->identity();
- $tok = $ident->token();
- $cat = $ident->serviceCatalog();
- $client = $this->getTransportClient();
- $ostore = \OpenStack\ObjectStore\v1\ObjectStorage::newFromServiceCatalog($cat, $tok, 'region-w.geo-99999.fake');
- $this->assertEmpty($ostore);
- }
-
- public function testNewFromIdentity()
- {
- $ident = $this->identity();
- $region = self::$settings['openstack.swift.region'];
- $client = $this->getTransportClient();
- $ostore = \OpenStack\ObjectStore\v1\ObjectStorage::newFromIdentity($ident, $region, $client);
- $this->assertInstanceOf('\OpenStack\ObjectStore\v1\ObjectStorage', $ostore);
- $this->assertTrue(strlen($ostore->token()) > 0);
- }
-
- /**
- * @group auth
- * @group acl
- */
- public function testCreateContainer()
- {
- $testCollection = self::$settings['openstack.swift.container'];
-
- $this->assertNotEmpty($testCollection, "Canary: container name must be in settings file.");
-
- $store = $this->objectStore();
-
- $this->destroyContainerFixture();
- /*
- if ($store->hasContainer($testCollection)) {
- $store->deleteContainer($testCollection);
- }
- */
-
- $md = ['Foo' => 1234];
-
- $ret = $store->createContainer($testCollection, null, $md);
- $this->assertTrue($ret, "Create container");
-
- }
-
- /**
- * @group auth
- * @depends testCreateContainer
- */
- public function testAccountInfo()
- {
- $store = $this->objectStore();
-
- $info = $store->accountInfo();
-
- $this->assertGreaterThan(0, $info['containers']);
- $this->assertGreaterThanOrEqual(0, $info['bytes']);
- $this->assertGreaterThanOrEqual(0, $info['objects']);
- }
-
- /**
- * @depends testCreateContainer
- */
- public function testContainers()
- {
- $store = $this->objectStore();
- $containers = $store->containers();
-
- $this->assertNotEmpty($containers);
-
- //$first = array_shift($containers);
-
- $testCollection = self::conf('openstack.swift.container');
- $testContainer = $containers[$testCollection];
- $this->assertEquals($testCollection, $testContainer->name());
- $this->assertEquals(0, $testContainer->bytes());
- $this->assertEquals(0, $testContainer->count());
-
- // Make sure we get back an ACL:
- $this->assertInstanceOf('\OpenStack\ObjectStore\v1\Resource\ACL', $testContainer->acl());
- }
-
- /**
- * @depends testCreateContainer
- */
- public function testContainer()
- {
- $testCollection = self::$settings['openstack.swift.container'];
- $store = $this->objectStore();
-
- $container = $store->container($testCollection);
-
- $this->assertEquals(0, $container->bytes());
- $this->assertEquals(0, $container->count());
- $this->assertEquals($testCollection, $container->name());
-
- $md = $container->metadata();
- $this->assertEquals(1, count($md));
- $this->assertEquals('1234', $md['Foo']);
- }
-
- /**
- * @depends testCreateContainer
- */
- public function testHasContainer()
- {
- $testCollection = self::$settings['openstack.swift.container'];
- $store = $this->objectStore();
-
- $this->assertTrue($store->hasContainer($testCollection));
- $this->assertFalse($store->hasContainer('nihil'));
- }
-
- /**
- * @depends testHasContainer
- */
- public function testDeleteContainer()
- {
- $testCollection = self::$settings['openstack.swift.container'];
-
- $store = $this->objectStore();
- //$ret = $store->createContainer($testCollection);
- //$this->assertTrue($store->hasContainer($testCollection));
-
- $ret = $store->deleteContainer($testCollection);
-
- $this->assertTrue($ret);
-
- // Now we try to delete a container that does not exist.
- $ret = $store->deleteContainer('nihil');
- $this->assertFalse($ret);
- }
-
- /**
- * @expectedException \OpenStack\ObjectStore\v1\Exception\ContainerNotEmptyException
- */
- public function testDeleteNonEmptyContainer()
- {
- $testCollection = self::$settings['openstack.swift.container'];
-
- $this->assertNotEmpty($testCollection);
-
- $store = $this->objectStore();
- $store->createContainer($testCollection);
-
- $container = $store->container($testCollection);
- $container->save(new Object('test', 'test', 'text/plain'));
-
- try {
- $ret = $store->deleteContainer($testCollection);
- } catch (\Exception $e) {
- $container->delete('test');
- $store->deleteContainer($testCollection);
- throw $e;
- }
-
- try {
- $container->delete('test');
- }
- // Skip 404s.
- catch (\Exception $e) {}
-
- $store->deleteContainer($testCollection);
- }
-
- /**
- * @depends testCreateContainer
- * @group acl
- */
- public function testCreateContainerPublic()
- {
- $testCollection = self::$settings['openstack.swift.container'] . 'PUBLIC';
- $store = $this->objectStore();
- if ($store->hasContainer($testCollection)) {
- $store->deleteContainer($testCollection);
- }
-
- $ret = $store->createContainer($testCollection, ACL::makePublic());
- $container = $store->container($testCollection);
-
- // Now test that we can get the container contents. Since there is
- // no content in the container, we use the format=xml to make sure
- // we get some data back.
- $url = $container->url() . '?format=xml';
-
- $data = file_get_contents($url);
- $this->assertNotEmpty($data, $url);
-
- $containers = $store->containers();
-
- $store->deleteContainer($testCollection);
- }
-
- /**
- * @depends testCreateContainerPublic
- */
- public function testChangeContainerACL()
- {
- $testCollection = self::$settings['openstack.swift.container'] . 'PUBLIC';
- $store = $this->objectStore();
- if ($store->hasContainer($testCollection)) {
- $store->deleteContainer($testCollection);
- }
- $ret = $store->createContainer($testCollection);
-
- $acl = ACL::makePublic();
- $ret = $store->changeContainerACL($testCollection, $acl);
-
- $this->assertFalse($ret);
-
- $container = $store->container($testCollection);
- $url = $container->url() . '?format=xml';
-
- $data = file_get_contents($url);
- $this->assertNotEmpty($data, $url);
-
- $store->deleteContainer($testCollection);
- }
-}
diff --git a/tests/Tests/ObjectStore/v1/Resource/ACLTest.php b/tests/Tests/ObjectStore/v1/Resource/ACLTest.php
deleted file mode 100644
index 4ea8fa9..0000000
--- a/tests/Tests/ObjectStore/v1/Resource/ACLTest.php
+++ /dev/null
@@ -1,215 +0,0 @@
-assertEmpty($acl->rules());
-
- }
-
- public function testAddAccount()
- {
- $acl = new ACL();
-
- $acl->addAccount(ACL::READ, 'test');
-
- $rules = $acl->rules();
-
- $this->assertEquals(1, count($rules));
-
- $rule = array_shift($rules);
-
- $this->assertEquals(ACL::READ, $rule['mask']);
- $this->assertEquals('test', $rule['account']);
-
- // Test with user
- $acl = new ACL();
- $acl->addAccount(ACL::WRITE, 'admin', 'earnie');
- $rules = $acl->rules();
- $rule = array_shift($rules);
-
- $this->assertEquals(ACL::WRITE, $rule['mask']);
- $this->assertEquals('admin', $rule['account']);
- $this->assertEquals('earnie', $rule['user']);
-
- // Test with multiple users:
- $acl = new ACL();
- $acl->addAccount(ACL::WRITE, 'admin', ['earnie', 'bert']);
- $rules = $acl->rules();
- $rule = array_shift($rules);
-
- $this->assertEquals(ACL::WRITE, $rule['mask']);
- $this->assertEquals('admin', $rule['account']);
- $this->assertEquals('earnie', $rule['user'][0]);
- $this->assertEquals('bert', $rule['user'][1]);
-
- }
-
- public function testAddReferrer()
- {
- $acl = new ACL();
- $acl->addReferrer(ACL::READ, '.example.com');
- $acl->addReferrer(ACL::READ_WRITE, '-bad.example.com');
-
- $rules = $acl->rules();
-
- $this->assertEquals(2, count($rules));
-
- $first = array_shift($rules);
- $this->assertEquals(ACL::READ, $first['mask']);
- $this->assertEquals('.example.com', $first['host']);
- }
-
- public function testAllowListings()
- {
- $acl = new ACL();
- $acl->allowListings();
- $rules = $acl->rules();
-
- $this->assertEquals(1, count($rules));
- $this->assertTrue($rules[0]['rlistings']);
- $this->assertEquals(ACL::READ, $rules[0]['mask']);
- }
-
- public function testHeaders()
- {
- $acl = new ACL();
- $acl->addAccount(ACL::READ_WRITE, 'test');
-
- $headers = $acl->headers();
-
- $this->assertEquals(2, count($headers));
- $read = $headers[ACL::HEADER_READ];
- $write = $headers[ACL::HEADER_WRITE];
-
- $this->assertEquals('test', $read);
- $this->assertEquals('test', $write);
-
- // Test hostname rules, which should only appear in READ.
- $acl = new ACL();
- $acl->addReferrer(ACL::READ_WRITE, '.example.com');
- $headers = $acl->headers();
-
- $this->assertEquals(1, count($headers), print_r($headers, true));
- $read = $headers[ACL::HEADER_READ];
-
- $this->assertEquals('.r:.example.com', $read);
- }
-
- public function testToString()
- {
- $acl = new ACL();
- $acl->addReferrer(ACL::READ_WRITE, '.example.com');
-
- $str = (string) $acl;
-
- $this->assertEquals('X-Container-Read: .r:.example.com', $str);
- }
-
- public function testMakePublic()
- {
- $acl = (string) ACL::makePublic();
-
- $this->assertEquals('X-Container-Read: .r:*,.rlistings', $acl);
- }
-
- public function testMakeNonPublic()
- {
- $acl = (string) ACL::makeNonPublic();
-
- $this->assertEmpty($acl);
- }
-
- public function testNewFromHeaders()
- {
- $headers = [
- ACL::HEADER_READ => '.r:.example.com,.rlistings,.r:-*.evil.net',
- ACL::HEADER_WRITE => 'testact2, testact3:earnie, .rlistings ',
- ];
-
- $acl = ACL::newFromHeaders($headers);
-
- $rules = $acl->rules();
-
- $this->assertEquals(6, count($rules));
-
- // Yay, now we get to test each one.
-
- $this->assertEquals(ACL::READ, $rules[0]['mask']);
- $this->assertEquals('.example.com', $rules[0]['host']);
- $this->assertTrue($rules[1]['rlistings']);
- $this->assertEquals('-*.evil.net', $rules[2]['host']);
-
- $this->assertEquals(ACL::WRITE, $rules[3]['mask']);
- $this->assertEquals('testact2', $rules[3]['account']);
- $this->assertEquals('testact3', $rules[4]['account']);
- $this->assertEquals('earnie', $rules[4]['user']);
- $this->assertTrue($rules[5]['rlistings']);
-
- // Final canary:
- $headers = $acl->headers();
- $read = $headers[ACL::HEADER_READ];
- $write = $headers[ACL::HEADER_WRITE];
-
- $this->assertEquals('.r:.example.com,.rlistings,.r:-*.evil.net', $read);
- // Note that the spurious .rlistings was removed.
- $this->assertEquals('testact2,testact3:earnie', $write);
-
- }
-
- public function testIsNonPublic()
- {
- $acl = new ACL();
-
- $this->assertTrue($acl->isNonPublic());
-
- $acl->addReferrer(ACL::READ, '*.evil.net');
- $this->assertFalse($acl->isNonPublic());
-
- $acl = ACL::makeNonPublic();
- $this->assertTrue($acl->isNonPublic());
- }
-
- public function testIsPublic()
- {
- $acl = new ACL();
-
- $this->assertFalse($acl->isPublic());
- $acl->allowListings();
- $acl->addReferrer(ACL::READ, '*');
-
- $this->assertTrue($acl->isPublic());
-
- $acl->addAccount(ACL::WRITE, 'foo', 'bar');
- $this->assertTrue($acl->isPublic());
-
- $acl = ACL::makePublic();
- $this->assertTrue($acl->isPublic());
- }
-
-}
diff --git a/tests/Tests/ObjectStore/v1/Resource/ContainerTest.php b/tests/Tests/ObjectStore/v1/Resource/ContainerTest.php
deleted file mode 100644
index 30724bc..0000000
--- a/tests/Tests/ObjectStore/v1/Resource/ContainerTest.php
+++ /dev/null
@@ -1,393 +0,0 @@
-assertEquals('foo', $container->name());
- }
-
- /**
- * @expectedException \OpenStack\Common\Exception
- */
- public function testExceptionIsThrownWhenContainerNotFound()
- {
- $container = new Container('foo');
- $container->bytes();
- }
-
- public function testCountable()
- {
- // Verify that the interface Countable is properly implemented.
-
- $mockJSON = ['count' => 5, 'bytes' => 128, 'name' => 'foo'];
- $container = Container::newFromJSON($mockJSON, 'fake', 'fake');
- $this->assertCount(5, $container);
- }
-
- public function testSave()
- {
- // Clean up anything left.
- $this->destroyContainerFixture();
-
- $container = $this->containerFixture();
-
- $object = new Object(self::FNAME, self::FCONTENT, self::FTYPE);
- $object->setMetadata(['foo' => '1234']);
-
- $this->assertEquals(self::FCONTENT, $object->content());
-
- try {
- $ret = $container->save($object);
- } catch (\Exception $e) {
- $this->destroyContainerFixture();
- throw $e;
- }
-
- $this->assertTrue($ret);
- }
-
- /**
- * @depends testSave
- */
- public function testProxyObject()
- {
- $container = $this->containerFixture();
- $object = $container->proxyObject(self::FNAME);
-
- $this->assertEquals(self::FNAME, $object->name());
- $this->assertEquals(self::FTYPE, $object->contentType());
-
- $etag = md5(self::FCONTENT);
- $this->assertEquals($etag, $object->eTag());
-
- $md = $object->metadata();
- $this->assertEquals(1, count($md));
-
- // Note that headers are normalized remotely to have initial
- // caps. Since we have no way of knowing what the original
- // metadata casing is, we leave it with initial caps.
- $this->assertEquals('1234', $md['Foo']);
-
- $content = $object->content();
- $this->assertEquals(self::FCONTENT, $content);
-
- // Make sure I can do this twice (regression).
- // Note that this SHOULD perform another request.
- $this->assertEquals(self::FCONTENT, $object->content());
-
- // Overwrite the copy:
- $object->setContent('HI');
- $this->assertEquals('HI', $object->content());
-
- // Make sure I can do this twice (regression check).
- $this->assertEquals('HI', $object->content());
- }
-
-
- /**
- * @depends testProxyObject
- */
- public function testRefresh()
- {
- $container = $this->containerFixture();
- $object = $container->proxyObject(self::FNAME);
-
- $content = (string) $object->content();
- $object->setContent('FOO');
- $this->assertEquals('FOO', $object->content());
-
- $object->refresh(true);
- $this->assertEquals($content, (string) $object->content());
-
- $object->refresh(false);
- $this->assertEquals($content, (string) $object->content());
-
- }
-
- /**
- * @depends testProxyObject
- */
- public function testObject()
- {
- $container = $this->containerFixture();
- $object = $container->object(self::FNAME);
-
- $this->assertEquals(self::FNAME, $object->name());
- $this->assertEquals(self::FTYPE, $object->contentType());
-
- $etag = md5(self::FCONTENT);
- $this->assertEquals($etag, $object->eTag());
-
- $md = $object->metadata();
- $this->assertEquals(1, count($md));
-
- // Note that headers are normalized remotely to have initial
- // caps. Since we have no way of knowing what the original
- // metadata casing is, we leave it with initial caps.
- $this->assertEquals('1234', $md['Foo']);
-
- $content = $object->content();
-
- $this->assertEquals(self::FCONTENT, $content);
-
- // Overwrite the copy:
- $object->setContent('HI');
- $this->assertEquals('HI', $object->content());
-
- // Make sure this throws a 404.
- try {
- $foo = $container->object('no/such');
- } catch (\OpenStack\Common\Exception $e) {
- $this->assertInstanceOf('OpenStack\Common\Transport\Exception\ResourceNotFoundException', $e);
- }
- }
-
- /**
- * @depends testSave
- */
- public function testObjects()
- {
- $container = $this->containerFixture();
- $obj1 = new Object('a/' . self::FNAME, self::FCONTENT, self::FTYPE);
- $obj2 = new Object('a/b/' . self::FNAME, self::FCONTENT, self::FTYPE);
-
- $container->save($obj1);
- $container->save($obj2);
-
- // Now we have a container with three items.
- $objects = $container->objects();
-
- $this->assertEquals(3, count($objects));
-
- $objects = $container->objects(1, 'a/' . self::FNAME);
-
- $this->assertEquals(1, count($objects));
- }
-
- /**
- * @depends testObjects
- */
- public function testGetIterator()
- {
- $container = $this->containerFixture();
-
- $it = $container->getIterator();
- $this->assertInstanceOf('Traversable', $it);
-
- $i = 0;
- foreach ($container as $item) {
- ++$i;
- }
- $this->assertEquals(3, $i);
- }
-
- /**
- * @depends testObjects
- */
- public function testObjectsWithPrefix()
- {
- $container = $this->containerFixture();
-
- $objects = $container->objectsWithPrefix('a/');
- $this->assertEquals(2, count($objects));
-
- foreach ($objects as $o) {
- if ($o instanceof Object) {
- $this->assertEquals('a/' . self::FNAME, $o->name());
- } else {
- $this->assertEquals('a/b/', $o->path());
- }
-
- }
-
- // Since we set the delimiter to ':' we will get back
- // all of the objects in a/. This is because none of
- // the objects contain ':' in their names.
- $objects = $container->objectsWithPrefix('a/', ':');
- $this->assertEquals(2, count($objects));
-
- foreach ($objects as $o) {
- $this->assertInstanceOf('\OpenStack\ObjectStore\v1\Resource\Object', $o);
- }
-
- // This should give us one file and one subdir.
- $objects = $container->objectsWithPrefix('', '/');
- $this->assertEquals(2, count($objects));
-
- foreach ($objects as $o) {
- if ($o instanceof Object) {
- $this->assertEquals(self::FNAME, $o->name());
- } else {
- $this->assertEquals('a/', $o->path());
- }
- }
- }
-
- /**
- * @depends testObjects
- */
- public function testObjectsWithPath()
- {
- $container = $this->containerFixture();
- $objects = $container->objectsByPath('a/b/');
-
- $this->assertEquals(1, count($objects));
-
- $o = array_shift($objects);
- $this->assertEquals('a/b/' . self::FNAME, $o->name());
- }
-
- /**
- * @depends testProxyObject
- */
- public function testUpdateMetadata()
- {
- $container = $this->containerFixture();
- $object = $container->proxyObject(self::FNAME);
-
- $md = $object->metadata();
-
- $this->assertEquals('1234', $md['Foo']);
-
- $md['Foo'] = 456;
- $md['Bar'] = 'bert';
- $object->setMetadata($md);
-
- $container->updateMetadata($object);
-
- $copy = $container->proxyObject(self::FNAME);
-
- $this->assertEquals('456', $md['Foo']);
- $this->assertEquals('bert', $md['Bar']);
-
- // Now we need to canary test:
- $this->assertEquals($object->contentType(), $copy->contentType());
- $this->assertEquals($object->contentLength(), $copy->contentLength());
-
-
- }
-
- /**
- * @depends testProxyObject
- */
- public function testCopy()
- {
- $container = $this->containerFixture();
- $object = $container->proxyObject(self::FNAME);
-
- $container->copy($object, 'FOO-1.txt');
-
- $copy = $container->proxyObject('FOO-1.txt');
-
- $this->assertEquals($object->contentType(), $copy->contentType());
- $this->assertEquals($object->etag(), $copy->etag());
-
- $container->delete('foo-1.txt');
-
- }
-
- /**
- * @depends testCopy
- */
- public function testCopyAcrossContainers()
- {
- // Create a new container.
- $store = $this->objectStore();
- $cname = self::$settings['openstack.swift.container'] . 'COPY';
- if ($store->hasContainer($cname)) {
- $this->eradicateContainer($cname);
- }
-
- $store->createContainer($cname);
- $newContainer = $store->container($cname);
-
- // Get teh old container and its object.
- $container = $this->containerFixture();
- $object = $container->proxyObject(self::FNAME);
-
- $ret = $container->copy($object, 'foo-1.txt', $cname);
-
- $this->assertTrue($ret);
-
- $copy = $newContainer->proxyObject('foo-1.txt');
-
- $this->assertEquals($object->etag(), $copy->etag());
-
- $this->eradicateContainer($cname);
-
- }
-
- /**
- * @depends testSave
- */
- public function testDelete()
- {
- $container = $this->containerFixture();
-
- $ret = $container->delete(self::FNAME);
-
- $fail = $container->delete('no_such_file.txt');
-
- $this->destroyContainerFixture();
- $this->assertTrue($ret);
- $this->assertFalse($fail);
- }
-
- /**
- * @group public
- */
- public function testAcl()
- {
- $store = $this->objectStore();
- $cname = self::$settings['openstack.swift.container'] . 'PUBLIC';
-
- if ($store->hasContainer($cname)) {
- $store->deleteContainer($cname);
- }
-
- $store->createContainer($cname, ACL::makePublic());
-
- $store->containers();
- $container = $store->container($cname);
-
- $acl = $container->acl();
-
- $this->assertInstanceOf('\OpenStack\ObjectStore\v1\Resource\ACL', $acl);
- $this->assertTrue($acl->isPublic());
-
- $store->deleteContainer($cname);
- }
-}
diff --git a/tests/Tests/ObjectStore/v1/Resource/ObjectTest.php b/tests/Tests/ObjectStore/v1/Resource/ObjectTest.php
deleted file mode 100644
index f3940a6..0000000
--- a/tests/Tests/ObjectStore/v1/Resource/ObjectTest.php
+++ /dev/null
@@ -1,150 +0,0 @@
-setContent(self::FCONTENT, self::FTYPE);
-
- return $o;
- }
-
- public function testConstructor()
- {
- $o = $this->basicObjectFixture();
-
- $this->assertEquals(self::FNAME, $o->name());
-
- $o = new Object('a', 'b', 'text/plain');
-
- $this->assertEquals('a', $o->name());
- $this->assertEquals('b', $o->content());
- $this->assertEquals('text/plain', $o->contentType());
- }
-
- public function testContentType()
- {
- // Don't use the fixture, we want to test content
- // type in its raw state.
- $o = new Object('foo.txt');
-
- $this->assertEquals('application/octet-stream', $o->contentType());
-
- $o->setContentType('text/plain; charset=UTF-8');
- $this->assertEquals('text/plain; charset=UTF-8', $o->contentType());
- }
-
- public function testContent()
- {
- $o = $this->basicObjectFixture();
-
- $this->assertEquals(self::FCONTENT, $o->content());
-
- // Test binary data.
- $bin = sha1(self::FCONTENT, true);
- $o->setContent($bin, 'application/octet-stream');
-
- $this->assertEquals($bin, $o->content());
- }
-
- public function testEtag()
- {
- $o = $this->basicObjectFixture();
- $md5 = md5(self::FCONTENT);
-
- $this->assertEquals($md5, $o->eTag());
- }
-
- public function testIsChunked()
- {
- $o = $this->basicObjectFixture();
- $this->assertFalse($o->isChunked());
- }
-
- public function testContentLength()
- {
- $o = $this->basicObjectFixture();
- $this->assertEquals(strlen(self::FCONTENT), $o->contentLength());
-
- // Test on binary data.
- $bin = sha1(self::FCONTENT, true);
-
- $o->setContent($bin);
- $this->assertFalse($o->contentLength() == 0);
- $this->assertEquals(strlen($bin), $o->contentLength());
- }
-
- public function testMetadata()
- {
- $md = [
- 'Immanuel' => 'Kant',
- 'David' => 'Hume',
- 'Gottfried' => 'Leibniz',
- 'Jean-Jaques' => 'Rousseau',
- ];
-
- $o = $this->basicObjectFixture();
- $o->setMetadata($md);
-
- $got = $o->metadata();
-
- $this->assertEquals(4, count($got));
- $this->assertArrayHasKey('Immanuel', $got);
- $this->assertEquals('Leibniz', $got['Gottfried']);
-
- }
-
- public function testAdditionalHeaders()
- {
- $o = $this->basicObjectFixture();
-
- $extra = [
- 'a' => 'b',
- 'aaa' => 'bbb',
- 'ccc' => 'bbb',
- ];
- $o->setAdditionalHeaders($extra);
-
- $got = $o->additionalHeaders();
- $this->assertEquals(3, count($got));
-
- $o->removeHeaders(['ccc']);
-
- $got = $o->additionalHeaders();
- $this->assertEquals(2, count($got));
- }
-}
diff --git a/tests/Tests/ObjectStore/v1/Resource/RemoteObjectTest.php b/tests/Tests/ObjectStore/v1/Resource/RemoteObjectTest.php
deleted file mode 100644
index 4b50f5d..0000000
--- a/tests/Tests/ObjectStore/v1/Resource/RemoteObjectTest.php
+++ /dev/null
@@ -1,330 +0,0 @@
-containerFixture();
-
- $object = new Object(self::FNAME, self::FCONTENT, self::FTYPE);
- $object->setMetadata([self::FMETA_NAME => self::FMETA_VALUE]);
- $object->setDisposition(self::FDISPOSITION);
- $object->setEncoding(self::FENCODING);
- $object->setAdditionalHeaders([
- 'Access-Control-Allow-Origin' => 'http://example.com',
- 'Access-control-allow-origin' => 'http://example.com',
- ]);
-
- // Need some headers that Swift actually stores and returns. This
- // one does not seem to be returned ever.
- //$object->setAdditionalHeaders(array(self::FCORS_NAME => self::FCORS_VALUE));
-
- $container->save($object);
- }
-
- public function testNewFromHeaders()
- {
- // This is tested via the container.
-
- $this->destroyContainerFixture();
- $container = $this->containerFixture();
- $this->createAnObject();
-
- $obj = $container->proxyObject(self::FNAME);
-
- $this->assertInstanceOf('\OpenStack\ObjectStore\v1\Resource\RemoteObject', $obj);
-
- return $obj;
- }
- /**
- * @depends testNewFromHeaders
- */
- public function testContentLength($obj)
- {
- $len = strlen(self::FCONTENT);
-
- $this->assertEquals($len, $obj->contentLength());
-
- return $obj;
- }
-
- /**
- * @depends testContentLength
- */
- public function testContentType($obj)
- {
- $this->assertEquals(self::FTYPE, $obj->contentType());
-
- return $obj;
- }
-
- /**
- * @depends testContentType
- */
- public function testEtag($obj)
- {
- $hash = md5(self::FCONTENT);
-
- $this->assertEquals($hash, $obj->eTag());
-
- return $obj;
- }
-
- /**
- * @depends testContentType
- */
- public function testLastModified($obj)
- {
- $date = $obj->lastModified();
-
- $this->assertTrue(is_int($date));
- $this->assertTrue($date > 0);
- }
-
- /**
- * @depends testNewFromHeaders
- */
- public function testMetadata($obj)
- {
- $md = $obj->metadata();
-
- $this->assertArrayHasKey(self::FMETA_NAME, $md);
- $this->assertEquals(self::FMETA_VALUE, $md[self::FMETA_NAME]);
- }
-
- /**
- * @depends testNewFromHeaders
- */
- public function testDisposition($obj)
- {
- $this->assertEquals(self::FDISPOSITION, $obj->disposition());
- }
-
- /**
- * @depends testNewFromHeaders
- */
- public function testEncoding($obj)
- {
- $this->assertEquals(self::FENCODING, $obj->encoding());
- }
-
- /**
- * @depends testNewFromHeaders
- */
- public function testHeaders($obj)
- {
- $headers = $obj->headers();
- $this->assertTrue(count($headers) > 1);
-
- //fwrite(STDOUT, print_r($headers, true));
-
- $this->assertNotEmpty($headers['Date']);
-
- $obj->removeHeaders(['Date']);
-
- $headers = $obj->headers();
- $this->assertFalse(isset($headers['Date']));
-
- // Swift doesn't return CORS headers even though it is supposed to.
- //$this->assertEquals(self::FCORS_VALUE, $headers[self::FCORS_NAME]);
- }
-
- /**
- * @depends testNewFromHeaders
- */
- public function testUrl($obj)
- {
- $url = $obj->url();
-
- $this->assertTrue(strpos($obj->url(), $obj->name())> 0);
- }
- /**
- * @depends testNewFromHeaders
- */
- public function testStream($obj)
- {
- $res = $obj->stream();
-
- $this->assertTrue(is_resource($res));
-
- $res_md = stream_get_meta_data($res);
-
- $content = fread($res, $obj->contentLength());
-
- fclose($res);
-
- $this->assertEquals(self::FCONTENT, $content);
-
- // Now repeat the tests, only with a local copy of the data.
- // This allows us to test the local tempfile buffering.
-
- $obj->setContent($content);
-
- $res2 = $obj->stream();
- $res_md = stream_get_meta_data($res2);
-
- $this->assertEquals('PHP', $res_md['wrapper_type']);
-
- $content = fread($res2, $obj->contentLength());
-
- fclose($res2);
-
- $this->assertEquals(self::FCONTENT, $content);
-
- // Finally, we redo the first part of the test to make sure that
- // refreshing gets us a new copy:
-
- $res3 = $obj->stream(true);
- $res_md = stream_get_meta_data($res3);
- $this->assertEquals('PHP', $res_md['wrapper_type']);
- fclose($res3);
-
- return $obj;
- }
-
- // To avoid test tainting from testStream(), we start over.
- public function testContent()
- {
- $container = $this->containerFixture();
- $obj = $container->object(self::FNAME);
-
- $content = $obj->content();
- $this->assertEquals(self::FCONTENT, $content);
-
- // Make sure proxyObject retrieves the same content.
- $obj = $container->proxyObject(self::FNAME);
- $content = $obj->content();
- $this->assertEquals(self::FCONTENT, $content);
-
- }
-
- /**
- * @depends testStream
- */
- public function testCaching()
- {
- $container = $this->containerFixture();
- $obj = $container->proxyObject(self::FNAME);
-
- $this->assertFalse($obj->isCaching());
-
- $content = $obj->content();
-
- $res1 = $obj->stream();
- $md = stream_get_meta_data($res1);
- $this->assertEquals('PHP', $md['wrapper_type']);
-
- fclose($res1);
-
- // Enable caching and retest.
- $obj->setCaching(true);
- $this->assertTrue($obj->isCaching());
-
- // This will cache the content.
- $content = $obj->content();
-
- $res2 = $obj->stream();
- $md = stream_get_meta_data($res2);
-
- // If this is using the PHP version, it built content from the
- // cached version.
- $this->assertEquals('PHP', $md['wrapper_type']);
-
- fclose($res2);
- }
-
- /**
- * @depends testNewFromHeaders
- */
- public function testContentVerification($obj)
- {
- $this->assertTrue($obj->isVerifyingContent());
- $obj->setContentVerification(false);
- $this->assertfalse($obj->isVerifyingContent());
- $obj->setContentVerification(true);
- }
-
- /**
- * @depends testCaching
- */
- public function testIsDirty()
- {
- $container = $this->containerFixture();
- $obj = $container->proxyObject(self::FNAME);
-
- // THere is no content. Assert false.
- $this->assertFalse($obj->isDirty());
-
- $obj->setCaching(true);
- $obj->content();
-
- // THere is content, but it is unchanged.
- $this->assertFalse($obj->isDirty());
-
- // Change content and retest.
- $obj->setContent('foo');
-
- $this->assertTrue($obj->isDirty());
- }
-
- /**
- * @depends testIsDirty
- */
- public function testRefresh()
- {
- $container = $this->containerFixture();
- $obj = $container->proxyObject(self::FNAME);
-
- $obj->setContent('foo');
- $this->assertTrue($obj->isDirty());
-
- $obj->refresh(false);
- $this->assertFalse($obj->isDirty());
- $this->assertEquals(self::FCONTENT, $obj->content());
-
- $obj->setContent('foo');
- $this->assertTrue($obj->isDirty());
-
- $obj->refresh(true);
- $this->assertFalse($obj->isDirty());
- $this->assertEquals(self::FCONTENT, $obj->content());
-
- $this->destroyContainerFixture();
-
- }
-
-}
diff --git a/tests/Tests/ObjectStore/v1/Resource/StreamWrapperFSTest.php b/tests/Tests/ObjectStore/v1/Resource/StreamWrapperFSTest.php
deleted file mode 100644
index 68189c1..0000000
--- a/tests/Tests/ObjectStore/v1/Resource/StreamWrapperFSTest.php
+++ /dev/null
@@ -1,353 +0,0 @@
-context)['swiftfs'];
- $this->assertNotEmpty($context['token']);
- $this->assertNotEmpty($context['swift_endpoint']);
- $this->assertEquals(self::FTYPE, $context['content_type']);
- }
-
- public function testRegister()
- {
- $this->assertNotEmpty(StreamWrapperFS::DEFAULT_SCHEME);
- $this->assertContains(StreamWrapperFS::DEFAULT_SCHEME, stream_get_wrappers());
- }
-
- public function testOpenFailureWithoutContext()
- {
- $url = $this->createNewUrl('non_existent_container/foo.txt');
- $this->assertFalse(@fopen($url, 'r'));
- }
-
- public function testResourceType()
- {
- $this->assertInternalType('resource', $this->resource);
- }
-
- public function testCreatingResourceInWriteMode()
- {
- $resource = $this->createNewResource($this->createNewUrl(), 'w+');
- $this->assertInternalType('resource', $resource);
- fclose($resource);
- }
-
- public function testCreatingResourceInCreateMode()
- {
- $resource = $this->createNewResource($this->createNewUrl(), 'c+');
- $this->assertInternalType('resource', $resource);
- fclose($resource);
- }
-
- public function testTell()
- {
- // Sould be at the beginning of the buffer.
- $this->assertEquals(0, ftell($this->resource));
- }
-
- public function testWrite()
- {
- $string = 'To be is to be the value of a bound variable. -- Quine';
- fwrite($this->resource, $string);
- $this->assertGreaterThan(0, ftell($this->resource));
- }
-
- public function testStat()
- {
- $this->assertEquals(0, fstat($this->resource)['size']);
-
- fwrite($this->resource, 'foo');
- fflush($this->resource);
- $this->assertGreaterThan(0, fstat($this->resource)['size']);
- }
-
- public function testSeek()
- {
- $text = 'Foo bar';
- fwrite($this->resource, $text);
-
- fseek($this->resource, 0, SEEK_END);
- $pointer = ftell($this->resource);
-
- $this->assertGreaterThan(0, $pointer);
- }
-
- public function testEof()
- {
- $this->assertFalse(feof($this->resource));
-
- fwrite($this->resource, 'foo');
- rewind($this->resource);
- stream_get_contents($this->resource);
-
- $this->assertTrue(feof($this->resource));
- }
-
- public function testFlush()
- {
- $content = str_repeat('foo', 50);
-
- fwrite($this->resource, $content);
- fflush($this->resource);
- rewind($this->resource);
-
- $this->assertEquals($content, stream_get_contents($this->resource));
- }
-
- public function testStreamGetMetadata()
- {
- $object = stream_get_meta_data($this->resource)['wrapper_data']->object();
- $this->assertInstanceOf('OpenStack\ObjectStore\v1\Resource\Object', $object);
- $this->assertEquals(self::FTYPE, $object->contentType());
- }
-
- public function testClose()
- {
- fclose($this->resource);
- $this->assertFalse(is_resource($this->resource));
- }
-
- public function testCast()
- {
- $read = [$this->resource];
- $write = [];
- $except = [];
- $this->assertGreaterThan(0, stream_select($read, $write, $except, 0));
- }
-
- public function testUrlStat()
- {
- $stat = stat($this->url);
-
- // Check that the array looks right.
- $this->assertCount(26, $stat);
- $this->assertEquals(0, $stat[3]);
- $this->assertEquals($stat[2], $stat['mode']);
- }
-
- public function testFileExists()
- {
- $this->assertTrue(file_exists($this->url));
- }
-
- public function testFileIsReadable()
- {
- $this->assertTrue(is_readable($this->url));
- }
-
- public function testFileIsWritable()
- {
- $this->assertTrue(is_writeable($this->url));
- }
-
- public function testFileModifyTime()
- {
- $this->assertGreaterThan(0, filemtime($this->url));
- }
-
- public function testFileSize()
- {
- $url = $this->createNewUrl('file_size_test');
-
- $resource = $this->createNewResource($url, 'w+');
- fwrite($resource, '!');
- fclose($resource);
-
- $this->assertEquals(1, filesize($url));
- unlink($url);
- }
-
- public function testPermissions()
- {
- $perm = fileperms($this->url);
-
- // Assert that this is a file. Objects are *always* marked as files.
- $this->assertEquals(0x8000, $perm & 0x8000);
-
- // Assert writeable by owner.
- $this->assertEquals(0x0080, $perm & 0x0080);
-
- // Assert not world writable.
- $this->assertEquals(0, $perm & 0x0002);
- }
-
- public function testFileGetContents()
- {
- $url = $this->createNewUrl('get_contents');
- $resource = $this->createNewResource($url, 'w+');
-
- fwrite($resource, '!');
- fclose($resource);
-
- $contents = file_get_contents($url, null, $this->context);
- $this->assertEquals('!', $contents);
- unlink($url);
- }
-
- public function testCopy()
- {
- $newUrl = '/tmp/new_file_from_swift.txt';
- copy($this->url, $newUrl, $this->context);
-
- $this->assertTrue(file_exists($newUrl));
- unlink($newUrl);
- }
-
- public function testUnlink()
- {
- unlink($this->url, $this->context);
- $this->assertFalse(file_exists($this->url));
- }
-
- public function testSetOption()
- {
- $this->assertTrue(stream_set_blocking($this->resource, 1));
-
- // Returns 0 on success.
- $this->assertEquals(0, stream_set_write_buffer($this->resource, 8192));
-
- // Cannot set a timeout on a tmp storage:
- $this->assertFalse(stream_set_timeout($this->resource, 10));
- }
-
- public function testRename()
- {
- $oldUrl = $this->createNewUrl('old');
- $newUrl = $this->createNewUrl('new');
-
- $original = $this->createNewResource($oldUrl, 'w+');
- fwrite($original, 'fooooo');
- fclose($original);
-
- rename($oldUrl, $newUrl, $this->context);
-
- $this->assertTrue(file_exists($newUrl));
- $this->assertFalse(file_exists($this->url));
-
- unlink($newUrl, $this->context);
- }
-
- public function testOpenDir()
- {
- $baseDirectory = opendir($this->createNewUrl(''), $this->context);
- $this->assertInternalType('resource', $baseDirectory);
- closedir($baseDirectory);
- }
-
- public function testReadDir()
- {
- $paths = ['test1.txt', 'foo/test2.txt', 'foo/test3.txt', 'bar/test4.txt'];
-
- foreach ($paths as $path) {
- $file = fopen($this->createNewUrl($path), 'c+', false, $this->context);
- fwrite($file, 'Test.');
- fclose($file);
- }
-
- $baseDirectory = opendir($this->createNewUrl(''), $this->context);
-
- $expectedPaths = ['bar/', 'foo/', 'test1.txt'];
- while (false !== ($currentEntry = readdir($baseDirectory))) {
- $nextPath = array_shift($expectedPaths);
- $this->assertEquals($nextPath, $currentEntry);
- }
-
- $this->assertFalse(readdir($baseDirectory));
-
- closedir($baseDirectory);
- }
-
- public function testRewindDir()
- {
- $baseDirectory = opendir($this->createNewUrl(''), $this->context);
- rewinddir($baseDirectory);
-
- $this->assertEquals('bar/', readdir($baseDirectory));
-
- closedir($baseDirectory);
- }
-
- public function testCloseDir()
- {
- $baseDirectory = opendir($this->createNewUrl(''), $this->context);
- closedir($baseDirectory);
- $this->assertFalse(is_resource($baseDirectory));
- }
-
- public function testOpenSubdir()
- {
- // Opening foo we should find test2.txt and test3.txt.
- $url = $this->createNewUrl('foo/');
- $dir = opendir($url, $this->context);
-
- $this->assertEquals('test2.txt', readdir($dir));
- $this->assertEquals('test3.txt', readdir($dir));
-
- $array = scandir($url, -1, $this->context);
- $this->assertEquals(2, count($array));
- $this->assertEquals('test3.txt', $array[0]);
- }
-
- public function testIsDir()
- {
- // Object names are pathy. If objects exist starting with this path we can
- // consider the directory to exist.
- $url = $this->createNewUrl('baz/');
- $this->assertFalse(is_dir($url));
-
- $url = $this->createNewUrl('foo/');
- $this->assertTrue(is_dir($url));
- }
-
- public function testMkdir()
- {
- // Object names are pathy. If no object names start with the a path we can
- // consider mkdir passed. If object names exist we should fail mkdir.
- $url = $this->createNewUrl('baz/');
- $this->assertTrue(mkdir($url, 0700, true, $this->context));
-
- // Test the case for an existing directory.
- $url = $this->createNewUrl('foo/');
- $this->assertFalse(mkdir($url, 0700, true, $this->context));
- }
-
- public function testRmdir()
- {
- // Object names are pathy. If no object names start with the a path we can
- // consider rmdir passed. If object names exist we should fail rmdir.
- $url = $this->createNewUrl('baz/');
- $this->assertTrue(rmdir($url, $this->context));
-
- // Test the case for an existing directory.
- $url = $this->createNewUrl('foo/');
- $this->assertFalse(rmdir($url, $this->context));
- }
-}
\ No newline at end of file
diff --git a/tests/Tests/ObjectStore/v1/Resource/StreamWrapperTest.php b/tests/Tests/ObjectStore/v1/Resource/StreamWrapperTest.php
deleted file mode 100644
index b361844..0000000
--- a/tests/Tests/ObjectStore/v1/Resource/StreamWrapperTest.php
+++ /dev/null
@@ -1,314 +0,0 @@
-context)['swift'];
- $this->assertNotEmpty($context['token']);
- $this->assertNotEmpty($context['swift_endpoint']);
- $this->assertEquals(self::FTYPE, $context['content_type']);
- }
-
- public function testOpenFailureWithoutContext()
- {
- $url = $this->createNewUrl('non_existent_container/foo.txt');
- $this->assertFalse(@fopen($url, 'r'));
- }
-
- public function testResourceType()
- {
- $this->assertInternalType('resource', $this->resource);
- }
-
- public function testCreatingResourceInWriteMode()
- {
- $resource = $this->createNewResource($this->createNewUrl(), 'w+');
- $this->assertInternalType('resource', $resource);
- fclose($resource);
- }
-
- public function testCreatingResourceInCreateMode()
- {
- $resource = $this->createNewResource($this->createNewUrl(), 'c+');
- $this->assertInternalType('resource', $resource);
- fclose($resource);
- }
-
- public function testTell()
- {
- // Sould be at the beginning of the buffer.
- $this->assertEquals(0, ftell($this->resource));
- }
-
- public function testWrite()
- {
- $string = 'To be is to be the value of a bound variable. -- Quine';
- fwrite($this->resource, $string);
- $this->assertGreaterThan(0, ftell($this->resource));
- }
-
- public function testStat()
- {
- $this->assertEquals(0, fstat($this->resource)['size']);
-
- fwrite($this->resource, 'foo');
- fflush($this->resource);
- $this->assertGreaterThan(0, fstat($this->resource)['size']);
- }
-
- public function testSeek()
- {
- $text = 'Foo bar';
- fwrite($this->resource, $text);
-
- fseek($this->resource, 0, SEEK_END);
- $pointer = ftell($this->resource);
-
- $this->assertGreaterThan(0, $pointer);
- }
-
- public function testEof()
- {
- $this->assertFalse(feof($this->resource));
-
- fwrite($this->resource, 'foo');
- rewind($this->resource);
- stream_get_contents($this->resource);
-
- $this->assertTrue(feof($this->resource));
- }
-
- public function testFlush()
- {
- $content = str_repeat('foo', 50);
-
- fwrite($this->resource, $content);
- fflush($this->resource);
- rewind($this->resource);
-
- $this->assertEquals($content, stream_get_contents($this->resource));
- }
-
- public function testStreamGetMetadata()
- {
- $object = stream_get_meta_data($this->resource)['wrapper_data']->object();
- $this->assertInstanceOf('OpenStack\ObjectStore\v1\Resource\Object', $object);
- $this->assertEquals(self::FTYPE, $object->contentType());
- }
-
- public function testClose()
- {
- fclose($this->resource);
- $this->assertFalse(is_resource($this->resource));
- }
-
- public function testCast()
- {
- $read = [$this->resource];
- $write = [];
- $except = [];
- $this->assertGreaterThan(0, stream_select($read, $write, $except, 0));
- }
-
- public function testUrlStat()
- {
- $stat = stat($this->url);
-
- // Check that the array looks right.
- $this->assertCount(26, $stat);
- $this->assertEquals(0, $stat[3]);
- $this->assertEquals($stat[2], $stat['mode']);
- }
-
- public function testFileExists()
- {
- $this->assertTrue(file_exists($this->url));
- }
-
- public function testFileIsReadable()
- {
- $this->assertTrue(is_readable($this->url));
- }
-
- public function testFileIsWritable()
- {
- $this->assertTrue(is_writeable($this->url));
- }
-
- public function testFileModifyTime()
- {
- $this->assertGreaterThan(0, filemtime($this->url));
- }
-
- public function testFileSize()
- {
- $url = $this->createNewUrl('file_size_test');
-
- $resource = $this->createNewResource($url, 'w+');
- fwrite($resource, '!');
- fclose($resource);
-
- $this->assertEquals(1, filesize($url));
- unlink($url);
- }
-
- public function testPermissions()
- {
- $perm = fileperms($this->url);
-
- // Assert that this is a file. Objects are *always* marked as files.
- $this->assertEquals(0x8000, $perm & 0x8000);
-
- // Assert writeable by owner.
- $this->assertEquals(0x0080, $perm & 0x0080);
-
- // Assert not world writable.
- $this->assertEquals(0, $perm & 0x0002);
- }
-
- public function testFileGetContents()
- {
- $url = $this->createNewUrl('get_contents');
- $resource = $this->createNewResource($url, 'w+');
-
- fwrite($resource, '!');
- fclose($resource);
-
- $contents = file_get_contents($url, null, $this->context);
- $this->assertEquals('!', $contents);
- unlink($url);
- }
-
- public function testCopy()
- {
- $newUrl = '/tmp/new_file_from_swift.txt';
- copy($this->url, $newUrl, $this->context);
-
- $this->assertTrue(file_exists($newUrl));
- unlink($newUrl);
- }
-
- public function testUnlink()
- {
- unlink($this->url, $this->context);
- $this->assertFalse(file_exists($this->url));
- }
-
- public function testSetOption()
- {
- $this->assertTrue(stream_set_blocking($this->resource, 1));
-
- // Returns 0 on success.
- $this->assertEquals(0, stream_set_write_buffer($this->resource, 8192));
-
- // Cannot set a timeout on a tmp storage:
- $this->assertFalse(stream_set_timeout($this->resource, 10));
- }
-
- public function testRename()
- {
- $oldUrl = $this->createNewUrl('old');
- $newUrl = $this->createNewUrl('new');
-
- $original = $this->createNewResource($oldUrl, 'w+');
- fwrite($original, 'fooooo');
- fclose($original);
-
- rename($oldUrl, $newUrl, $this->context);
-
- $this->assertTrue(file_exists($newUrl));
- $this->assertFalse(file_exists($this->url));
-
- unlink($newUrl, $this->context);
- }
-
- public function testOpenDir()
- {
- $baseDirectory = opendir($this->createNewUrl(''), $this->context);
- $this->assertInternalType('resource', $baseDirectory);
- closedir($baseDirectory);
- }
-
- public function testReadDir()
- {
- $paths = ['test1.txt', 'foo/test2.txt', 'foo/test3.txt', 'bar/test4.txt'];
-
- foreach ($paths as $path) {
- $file = fopen($this->createNewUrl($path), 'c+', false, $this->context);
- fwrite($file, 'Test.');
- fclose($file);
- }
-
- $baseDirectory = opendir($this->createNewUrl(''), $this->context);
-
- $expectedPaths = ['bar/', 'foo/', 'test1.txt'];
- while (false !== ($currentEntry = readdir($baseDirectory))) {
- $nextPath = array_shift($expectedPaths);
- $this->assertEquals($nextPath, $currentEntry);
- }
-
- $this->assertFalse(readdir($baseDirectory));
-
- closedir($baseDirectory);
- }
-
- public function testRewindDir()
- {
- $baseDirectory = opendir($this->createNewUrl(''), $this->context);
- rewinddir($baseDirectory);
-
- $this->assertEquals('bar/', readdir($baseDirectory));
-
- closedir($baseDirectory);
- }
-
- public function testCloseDir()
- {
- $baseDirectory = opendir($this->createNewUrl(''), $this->context);
- closedir($baseDirectory);
- $this->assertFalse(is_resource($baseDirectory));
- }
-
- public function testOpenSubdir()
- {
- // Opening foo we should find test2.txt and test3.txt.
- $url = $this->createNewUrl('foo/');
- $dir = opendir($url, $this->context);
-
- $this->assertEquals('test2.txt', readdir($dir));
- $this->assertEquals('test3.txt', readdir($dir));
-
- $array = scandir($url, -1, $this->context);
- $this->assertEquals(2, count($array));
- $this->assertEquals('test3.txt', $array[0]);
- }
-}
\ No newline at end of file
diff --git a/tests/Tests/ObjectStore/v1/Resource/StreamWrapperTestCase.php b/tests/Tests/ObjectStore/v1/Resource/StreamWrapperTestCase.php
deleted file mode 100644
index bd370bc..0000000
--- a/tests/Tests/ObjectStore/v1/Resource/StreamWrapperTestCase.php
+++ /dev/null
@@ -1,135 +0,0 @@
-createContainer($containerName);
-
- try {
- self::$container = $service->container($containerName);
- } catch (\Exception $e) {
- $service->deleteContainer($containerName);
- throw $e;
- }
-
- self::$settings += [
- 'username' => self::$settings['openstack.identity.username'],
- 'password' => self::$settings['openstack.identity.password'],
- 'endpoint' => self::$settings['openstack.identity.url'],
- 'tenantid' => self::$settings['openstack.identity.tenantId'],
- 'token' => $service->token(),
- 'swift_endpoint' => $service->url(),
- ];
- Bootstrap::setConfiguration(self::$settings);
- }
-
- public static function tearDownAfterClass()
- {
- if (!self::$container) {
- return;
- }
-
- foreach (self::$container as $object) {
- try {
- self::$container->delete($object->name());
- } catch (\Exception $e) {}
- }
-
- $service = self::createObjectStoreService();
- $service->deleteContainer(self::$container->name());
- }
-
- public function setUp()
- {
- Bootstrap::useStreamWrappers();
-
- $this->url = $this->createNewUrl();
- $this->context = $this->createStreamContext();
- $this->resource = $this->createNewResource($this->url);
- }
-
- public function tearDown()
- {
- if (is_resource($this->resource)) {
- fclose($this->resource);
- }
-
- $this->resource = null;
- stream_wrapper_unregister(static::SCHEME);
- }
-
- protected function createNewResource($url, $mode = self::DEFAULT_MODE)
- {
- return fopen($url, $mode, false, $this->context);
- }
-
- protected function createNewUrl($objectName = self::FILE_PATH)
- {
- return sprintf("%s://%s/%s",
- static::SCHEME,
- urlencode(self::$settings['openstack.swift.container']),
- join('/', array_map('urlencode', explode('/', $objectName)))
- );
- }
-
- private function createStreamContext(array $params = [], $scheme = null)
- {
- if (!$scheme) {
- $scheme = static::SCHEME;
- }
-
- if (!($objectStore = $this->objectStore())) {
- throw new \Exception('Object storage service could not be created');
- }
-
- $params += [
- 'token' => $objectStore->token(),
- 'swift_endpoint' => $objectStore->url(),
- 'content_type' => self::FTYPE,
- 'transport_client' => $this->getTransportClient(),
- ];
-
- return stream_context_create([
- $scheme => $params
- ]);
- }
-}
\ No newline at end of file
diff --git a/tests/Tests/TestCase.php b/tests/Tests/TestCase.php
deleted file mode 100644
index d48b02f..0000000
--- a/tests/Tests/TestCase.php
+++ /dev/null
@@ -1,240 +0,0 @@
-authenticateAsUser($username, $password, $tenantId);
-
- return $service;
- }
-
- protected static function createObjectStoreService()
- {
- return ObjectStorage::newFromIdentity(
- self::createIdentityService(),
- self::$settings['openstack.swift.region'],
- self::getTransportClient()
- );
- }
-
- /**
- * Get a handle to an IdentityService object.
- *
- * Authentication is performed, and the returned
- * service has its tenant ID set already.
- *
- * identity()->token();
- * ?>
- */
- protected function identity($reset = false)
- {
- if ($reset || empty(self::$ident)) {
- self::$ident = self::createIdentityService();
- }
-
- return self::$ident;
- }
-
- protected function objectStore($reset = false)
- {
- if ($reset || !$this->objectStoreService) {
- $this->objectStoreService = self::createObjectStoreService();
- }
-
- return $this->objectStoreService;
- }
-
- /**
- * Get a container from the server.
- */
- protected function containerFixture()
- {
- if (empty($this->containerFixture)) {
- $store = $this->objectStore();
- $cname = self::$settings['openstack.swift.container'];
-
- try {
- $store->createContainer($cname);
- $this->containerFixture = $store->container($cname);
- } catch (\Exception $e) {
- // Delete the container.
- $store->deleteContainer($cname);
- throw $e;
- }
- }
-
- return $this->containerFixture;
- }
-
- /**
- * Clear and destroy a container.
- *
- * Destroy all of the files in a container, then destroy the
- * container.
- *
- * If the container doesn't exist, this will silently return.
- *
- * @param string $cname The name of the container.
- */
- protected function eradicateContainer($cname)
- {
- $store = $this->objectStore();
- try {
- $container = $store->container($cname);
- } catch (ResourceNotFoundException $e) {
- // The container was never created.
- return;
- }
-
- foreach ($container as $object) {
- try {
- $container->delete($object->name());
- } catch (\Exception $e) {}
- }
-
- $store->deleteContainer($cname);
-
- }
-
- /**
- * Retrieve the HTTP Transport Client
- *
- * @return \OpenStack\Common\Transport\ClientInterface A transport client.
- */
- public static function getTransportClient()
- {
- if (is_null(self::$httpClient)) {
- $options = [];
-
- if (isset(self::$settings['transport.proxy'])) {
- $options['proxy'] = self::$settings['transport.proxy'];
- }
- if (isset(self::$settings['transport.debug'])) {
- $options['debug'] = self::$settings['transport.debug'];
- }
- if (isset(self::$settings['transport.ssl.verify'])) {
- $options['ssl_verify'] = self::$settings['transport.ssl.verify'];
- }
- if (isset(self::$settings['transport.timeout'])) {
- $options['timeout'] = self::$settings['transport.timeout'];
- }
-
- self::$httpClient = GuzzleAdapter::create([
- 'defaults' => $options
- ]);
- }
-
- return self::$httpClient;
- }
-
- /**
- * Destroy a container fixture.
- *
- * This should be called in any method that uses containerFixture().
- */
- protected function destroyContainerFixture()
- {
- $store = $this->objectStore();
- $cname = self::$settings['openstack.swift.container'];
-
- try {
- $container = $store->container($cname);
- }
- // The container was never created.
- catch (ResourceNotFoundException $e) {
- return;
- }
-
- foreach ($container as $object) {
- try {
- $container->delete($object->name());
- } catch (\Exception $e) {
- syslog(LOG_WARNING, $e);
- }
- }
-
- $store->deleteContainer($cname);
- }
-}
\ No newline at end of file
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
deleted file mode 100644
index 1e8ac20..0000000
--- a/tests/bootstrap.php
+++ /dev/null
@@ -1,19 +0,0 @@
-