add SWIFT (openstack object storage) storage backend

This commit is contained in:
Robin Appelman 2012-04-18 20:54:07 +02:00
parent aceda02887
commit 9a707e10bf
12 changed files with 4864 additions and 1 deletions

3
3rdparty/php-cloudfiles/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
*.swp
*~
tests/output.log

11
3rdparty/php-cloudfiles/AUTHORS vendored Normal file
View file

@ -0,0 +1,11 @@
Current maintainer:
Conrad Weidenkeller <conrad.weidenkeller@rackspace.com>
Previous maintainer:
Eric "EJ" Johnson <ej@racklabs.com>
Chmouel Boudjnah <chmouel.boudjnah@rackspace.co.uk>
Contributors:
Paul Kehrer
Ben Arwin
Jordan Callicoat

27
3rdparty/php-cloudfiles/COPYING vendored Normal file
View file

@ -0,0 +1,27 @@
Unless otherwise noted, all files are released under the MIT license,
exceptions contain licensing information in them.
Copyright (C) 2008 Rackspace US, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Except as contained in this notice, the name of Rackspace US, Inc. shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Rackspace US, Inc.

93
3rdparty/php-cloudfiles/Changelog vendored Normal file
View file

@ -0,0 +1,93 @@
1.7.10 Conrad Weidenkeller <conrad.weidenkeller@rackspace.com>
* Added Streaming URI Functionality
1.7.9 Conrad Weidenkeller <conrad.weidenkeller@rackspace.com>
* Added Manifest file support for Large Objects
1.7.8 Conrad Weidenkeller <conrad.weidenkeller@rackspace.com>
* Added CDN SSL URI Stuff
1.7.7 Conrad Weidenkeller <conrad.weidenkeller@rackspace.com>
* Added CDN Purge Functionality
1.7.6 - Chmouel Boudjnah <chmouel.boudjnah@rackspace.co.uk>
* Add Cloud UK Support (conrad.weidenkeller).
1.7.5 - Conrad Weidenkeller <conrad.weidenkeller@rackspace.com>
* Added the ability to list only currently enabled CDN containers
* Added curl timeout to CF_Http
* Fixed some logic errors in some if statements.
1.7.4 - Conrad Weidenkeller <conrad.weidenkeller@rackspace.com>
* Added Manual SSL support for MacOSX users
1.7.3 - Conrad Weidenkeller <conrad.weidenkeller@rackspace.com>
* Fixed a Small Bug where some users were seeing response bodies for PUTs
1.7.1 - Conrad Weidenkeller <conrad.weidenkeller@rackspace.com>
* Added Support for Auth Token Caching.
1.7.0 - Chmouel Boudjnah <chmouel.boudjnah@rackspace.co.uk>
* Adjust api auth to rackspacecloud not mosso (mshuler).
1.6.2 - Chmouel Boudjnah <chmouel.boudjnah@rackspace.co.uk>
* Add a close method to close all the current connection.
* Fix when container_name is named 0.
1.6.1 - Chmouel Boudjnah <chmouel.boudjnah@rackspace.co.uk>
* Fix setting etag on objects.
* Fix throwing proper exception when an invalid etag has been set.
* Fix throwing proper exception when no content type has been set.
1.6.0 - Chmouel Boudjnah <chmouel.boudjnah@rackspace.co.uk>
* Add CDN ACL restriction by referrer feature.
* Add CDN ACL restriction by User Agent feature.
* Add documentation for log_retention method.
* Return True if log_retention as succeeded.
* Invalid the PHP stats cache before getting filesize.
1.5.1 - Chmouel Boudjnah <chmouel.boudjnah@rackspace.co.uk> - 20091020
* If the environement variable RACKSPACE_SERVICENET is defined then force to
connect via rakcspace servicenet.
1.5.0 - Chmouel Boudjnah <chmouel.boudjnah@rackspace.co.uk> - 20091015
* Add the option servicenet to connection to use Rackspace service net
instead of public network.
1.4.0 - Chmouel Boudjnah <chmouel.boudjnah@rackspace.co.uk> - 20090808
* Add the ability to store the container log.
1.3.2 - Chmouel Boudjnah <chmouel.boudjnah@rackspace.co.uk> - 20090606
* Change the Unit Tests to phpunit.
* Automatically set the updated CA bundle when on the windows OS.
* More simplification of the mimetype detection and support for PHP 5.3.
* Fix documentation information about the ttl for cached object.
* Use the hash library to compute MD5 for streams instead of storing the
stream in memory.
* Fix CF_Connection::get_containers to display the container name properly.
1.3.1 - <ej@racklabs.com> - 20090325
* Simplify use of FileInfo, remove packaged MIME/Magic file
* Throw Exception if no Content-Type is set
* Fix bug with tracking bytes transferred
* Support/tested on Windows XP (PHP v5.2.9)
1.3.0 - <ej@racklabs.com> - 20090311
* Support for list operations in JSON/XML
* Added support for FileInfo automatic Content-Type/MIME detection
* Workaround for cURL's old CA bundle with CF_Connection->ssl_use_cabundle()
* Supports limit/marker on Account and Container lists
* Support "pathname" traversal on Container lists
* Helper function on Container to create directory marker Objects
* Support for chunked transfer on PUT requests
1.2.3 - <ej@racklabs.com> - 20081210
* Improved in-line comments and generated HTML docs
* Callbacks for read/write progress on CF_Connection class
* Fixed minor bugs
* Started this Changelog

73
3rdparty/php-cloudfiles/README vendored Normal file
View file

@ -0,0 +1,73 @@
;; PHP Cloud Files API
;; ========================================================================
;; This package contains the PHP API for the Cloud Files storage system.
;;
;; Please see http://www.rackspacecloud.com/ for more information regarding the
;; Cloud Files storage system.
;;
;; Install
;; ------------------------------------------------------------------------
;; Extract this archive and make sure the source code files are in your
;; PHP "include path". To use the API in your source code, just make
;; sure to include/require the "cloudfiles.php" script.
;;
;; Requirements
;; ------------------------------------------------------------------------
;; [mandatory] PHP version 5.x (developed against 5.2.0)
;; [mandatory] PHP's cURL module
;; [mandatory] PHP enabled with mbstring (multi-byte string) support
;; [suggested] PEAR FileInfo module (for Content-Type detection)
;;
;; Examples
;; ------------------------------------------------------------------------
;; For sample code, please see the tests and API docs.
;;
;; Docs
;; ------------------------------------------------------------------------
;; The included documentation was generated directly from the source
;; code files using the PHPDocumentor tool.
;;
;; This README file is actually the PHPDocumentor INI configuration file.
;; The following packages were installed via PEAR to generate the HTML
;; API documentation.
;;
;; * PEAR 1.4.11 (stable)
;; * PhpDocumentor 1.4.2 (stable)
;; * XML_Beautifier 1.2.0 (stable)
;; * XML_Parser 1.3.1 (stable)
;; * XML_Util 1.2.0 (stable)
;;
;; To re-generate the API docs, make sure the above software is
;; available and run:
;; rm -rf docs && phpdoc -c phpdoc.ini
;;
;; Tests
;; ------------------------------------------------------------------------
;; The tests are based on phpunit and are run with PHPUnit 3.3.17
;; please follow the instructions on :
;;
;; http://www.phpunit.de/manual/current/en/installation.html
;;
;; to install PHPUnit. When installed just run the command phpunit on
;; the top of the directory and it will launch the tests.
;;
;; The tests/Comprehensive.php is not enabled by default since
;; generating big files. If you want to run it you need to go in the
;; tests directory and run with phpunit Comprehensive.php
;;
;; ========================================================================
;; The lines below here are the configuration settings for re-generating
;; the PHP API documentation.
;;
[Parse Data]
title = php-cloudfiles
hidden = false
parseprivate = off
javadocdesc = off
defaultpackagename = php-cloudfiles
defaultcategoryname = php-cloudfiles
target = docs
directory = .
ignore = share/,examples/,tests/,.git/,.gitignore,*.ini,*.swp
output=HTML:Smarty:PHP
readmeinstallchangelog = README,COPYING,AUTHORS,Changelog

2599
3rdparty/php-cloudfiles/cloudfiles.php vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,41 @@
<?php
/**
* Custom Exceptions for the CloudFiles API
*
* Requres PHP 5.x (for Exceptions and OO syntax)
*
* See COPYING for license information.
*
* @author Eric "EJ" Johnson <ej@racklabs.com>
* @copyright Copyright (c) 2008, Rackspace US, Inc.
* @package php-cloudfiles-exceptions
*/
/**
* Custom Exceptions for the CloudFiles API
* @package php-cloudfiles-exceptions
*/
class SyntaxException extends Exception { }
class AuthenticationException extends Exception { }
class InvalidResponseException extends Exception { }
class NonEmptyContainerException extends Exception { }
class NoSuchObjectException extends Exception { }
class NoSuchContainerException extends Exception { }
class NoSuchAccountException extends Exception { }
class MisMatchedChecksumException extends Exception { }
class IOException extends Exception { }
class CDNNotEnabledException extends Exception { }
class BadContentTypeException extends Exception { }
class InvalidUTF8Exception extends Exception { }
class ConnectionNotOpenException extends Exception { }
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* c-hanging-comment-ender-p: nil
* End:
*/
?>

File diff suppressed because it is too large Load diff

View file

@ -9,3 +9,4 @@
OC::$CLASSPATH['OC_Filestorage_FTP']='apps/files_external/lib/ftp.php';
OC::$CLASSPATH['OC_Filestorage_DAV']='apps/files_external/lib/webdav.php';
OC::$CLASSPATH['OC_Filestorage_Google']='apps/files_external/lib/google.php';
OC::$CLASSPATH['OC_Filestorage_SWIFT']='apps/files_external/lib/swift.php';

View file

@ -0,0 +1,488 @@
<?php
/**
* Copyright (c) 2012 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
require_once('php-cloudfiles/cloudfiles.php');
class OC_FileStorage_SWIFT extends OC_Filestorage_Common{
private $host;
private $root;
private $user;
private $token;
private $secure;
/**
* @var CF_Authentication auth
*/
private $auth;
/**
* @var CF_Connection conn
*/
private $conn;
/**
* @var CF_Container rootContainer
*/
private $rootContainer;
private static $tempFiles=array();
const SUBCONTAINER_FILE='.subcontainers';
/**
* translate directory path to container name
* @param string path
* @return string
*/
private function getContainerName($path){
$path=trim($this->root.$path,'/');
return md5($path);
}
/**
* get container by path
* @param string path
* @return CF_Container
*/
private function getContainer($path){
if($path=='' or $path=='/'){
return $this->rootContainer;
}
try{
$container=$this->conn->get_container($this->getContainerName($path));
return $container;
}catch(NoSuchContainerException $e){
return null;
}
}
/**
* create container
* @param string path
* @return CF_Container
*/
private function createContainer($path){
if($path=='' or $path=='/'){
return $this->conn->create_container($this->getContainerName($path));
}
$parent=dirname($path);
if($parent=='' or $parent=='/'){
$parentContainer=$this->rootContainer;
}else{
if(!$this->containerExists($parent)){
$parentContainer=$this->createContainer($parent);
}else{
$parentContainer=$this->getContainer($parent);
}
}
$this->addSubContainer($parentContainer,basename($path));
return $this->conn->create_container($this->getContainerName($path));
}
/**
* get object by path
* @param string path
* @return CF_Object
*/
private function getObject($path){
$container=$this->getContainer(dirname($path));
if(is_null($container)){
return null;
}else{
try{
$obj=$container->get_object(basename($path));
return $obj;
}catch(NoSuchObjectException $e){
return null;
}
}
}
/**
* get the names of all objects in a container
* @param CF_Container
* @return array
*/
private function getObjects($container){
if(is_null($container)){
return array();
}else{
$files=$container->get_objects();
foreach($files as &$file){
$file=$file->name;
}
return $files;
}
}
/**
* create object
* @param string path
* @return CF_Object
*/
private function createObject($path){
$container=$this->getContainer(dirname($path));
if(!is_null($container)){
$container=$this->createContainer($path);
}
return $container->create_object(basename($path));
}
/**
* check if an object exists
* @param string
* @return bool
*/
private function objectExists($path){
return !is_null($this->getObject($path));
}
/**
* check if container for path exists
* @param string path
* @return bool
*/
private function containerExists($path){
return !is_null($this->getContainer($path));
}
/**
* get the list of emulated sub containers
* @param CF_Container container
* @return array
*/
private function getSubContainers($container){
$tmpFile=OC_Helper::tmpFile();
$obj=$this->getSubContainerFile($container);
try{
$obj->save_to_filename($tmpFile);
}catch(Exception $e){
return array();
}
$obj->save_to_filename($tmpFile);
$containers=file($tmpFile);
unlink($tmpFile);
foreach($containers as &$sub){
$sub=trim($sub);
}
return $containers;
}
/**
* add an emulated sub container
* @param CF_Container container
* @param string name
* @return bool
*/
private function addSubContainer($container,$name){
if(!$name){
return false;
}
$tmpFile=OC_Helper::tmpFile();
$obj=$this->getSubContainerFile($container);
try{
$obj->save_to_filename($tmpFile);
$containers=file($tmpFile);
foreach($containers as &$sub){
$sub=trim($sub);
}
if(array_search($name,$containers)!==false){
unlink($tmpFile);
return false;
}else{
$fh=fopen($tmpFile,'a');
fwrite($fh,$name."\n");
}
}catch(Exception $e){
$containers=array();
file_put_contents($tmpFile,$name."\n");
}
$obj->load_from_filename($tmpFile);
unlink($tmpFile);
return true;
}
/**
* remove an emulated sub container
* @param CF_Container container
* @param string name
* @return bool
*/
private function removeSubContainer($container,$name){
if(!$name){
return false;
}
$tmpFile=OC_Helper::tmpFile();
$obj=$this->getSubContainerFile($container);
try{
$obj->save_to_filename($tmpFile);
$containers=file($tmpFile);
}catch(Exception $e){
return false;
}
foreach($containers as &$sub){
$sub=trim($sub);
}
$i=array_search($name,$containers);
if($i===false){
unlink($tmpFile);
return false;
}else{
unset($containers[$i]);
file_put_contents($tmpFile,implode("\n",$containers)."\n");
}
$obj->load_from_filename($tmpFile);
unlink($tmpFile);
return true;
}
/**
* ensure a subcontainer file exists and return it's object
* @param CF_Container container
* @return CF_Object
*/
private function getSubContainerFile($container){
try{
return $container->get_object(self::SUBCONTAINER_FILE);
}catch(NoSuchObjectException $e){
return $container->create_object(self::SUBCONTAINER_FILE);
}
}
public function __construct($params){
$this->token=$params['token'];
$this->host=$params['host'];
$this->user=$params['user'];
$this->root=isset($params['root'])?$params['root']:'/';
$this->secure=isset($params['secure'])?(bool)$params['secure']:true;
if(substr($this->root,0,1)!='/'){
$this->root='/'.$this->root;
}
$this->auth = new CF_Authentication($this->user, $this->token, null, $this->host);
$this->auth->authenticate();
$this->conn = new CF_Connection($this->auth);
if(!$this->containerExists($this->root)){
$this->rootContainer=$this->createContainer('/');
}else{
$this->rootContainer=$this->getContainer('/');
}
}
public function mkdir($path){
if($this->containerExists($path)){
return false;
}else{
$this->createContainer($path);
return true;
}
}
public function rmdir($path){
if(!$this->containerExists($path)){
return false;
}else{
$this->emptyContainer($path);
if($path!='' and $path!='/'){
$parentContainer=$this->getContainer(dirname($path));
$this->removeSubContainer($parentContainer,basename($path));
}
$this->conn->delete_container($this->getContainerName($path));
return true;
}
}
private function emptyContainer($path){
$container=$this->getContainer($path);
if(is_null($container)){
return;
}
$subContainers=$this->getSubContainers($container);
foreach($subContainers as $sub){
if($sub){
$this->emptyContainer($path.'/'.$sub);
$this->conn->delete_container($this->getContainerName($path.'/'.$sub));
}
}
$objects=$this->getObjects($container);
foreach($objects as $object){
$container->delete_object($object);
}
}
public function opendir($path){
$container=$this->getContainer($path);
$files=$this->getObjects($container);
$i=array_search(self::SUBCONTAINER_FILE,$files);
if($i!==false){
unset($files[$i]);
}
$subContainers=$this->getSubContainers($container);
$files=array_merge($files,$subContainers);
$id=$this->getContainerName($path);
OC_FakeDirStream::$dirs[$id]=$files;
return opendir('fakedir://'.$id);
}
public function filetype($path){
if($this->containerExists($path)){
return 'dir';
}else{
return 'file';
}
}
public function is_readable($path){
return true;
}
public function is_writable($path){
return true;
}
public function file_exists($path){
if($this->is_dir($path)){
return true;
}else{
return $this->objectExists($path);
}
}
public function file_get_contents($path){
$obj=$this->getObject($path);
if(is_null($obj)){
return false;
}
return $obj->read();
}
public function file_put_contents($path,$content){
$obj=$this->getObject($path);
if(is_null($obj)){
$container=$this->getContainer(dirname($path));
if(is_null($container)){
return false;
}
$obj=$container->create_object(basename($path));
}
return $obj->write($content);
}
public function unlink($path){
if($this->objectExists($path)){
$container=$this->getContainer(dirname($path));
$container->delete_object(basename($path));
}else{
return false;
}
}
public function fopen($path,$mode){
$obj=$this->getObject($path);
if(is_null($obj)){
return false;
}
switch($mode){
case 'r':
case 'rb':
$fp = fopen('php://temp', 'r+');
$obj->stream($fp);
rewind($fp);
return $fp;
case 'w':
case 'wb':
case 'a':
case 'ab':
case 'r+':
case 'w+':
case 'wb+':
case 'a+':
case 'x':
case 'x+':
case 'c':
case 'c+':
$tmpFile=$this->getTmpFile($path);
OC_CloseStreamWrapper::$callBacks[$tmpFile]=array($this,'writeBack');
self::$tempFiles[$tmpFile]=$path;
return fopen('close://'.$tmpFile,$mode);
}
}
public function writeBack($tmpFile){
if(isset(self::$tempFiles[$tmpFile])){
$this->fromTmpFile($tmpFile,self::$tempFiles[$tmpFile]);
unlink($tmpFile);
}
}
public function free_space($path){
return 0;
}
public function touch($path,$mtime=null){
if(!is_null($mtime)){
return false;
}
$obj=$this->getObject($path);
if(is_null($obj)){
return false;
}
$fp = fopen('php://temp', 'r+');
$obj->stream($fp);
rewind($fp);
$obj->write($fp);
fclose($fp);
}
public function rename($path1,$path2){
$sourceContainer=$this->getContainer(dirname($path1));
$targetContainer=$this->getContainer(dirname($path2));
return $sourceContainer->move_object_to(basename($path1),$targetContainer,basename($path2));
}
public function copy($path1,$path2){
$sourceContainer=$this->getContainer(dirname($path1));
$targetContainer=$this->getContainer(dirname($path2));
return $sourceContainer->copy_object_to(basename($path1),$targetContainer,basename($path2));
}
public function stat($path){
$obj=$this->getObject($path);
if(is_null($obj)){
return false;
}
return array(
'mtime'=>strtotime($obj->last_modified),
'size'=>$obj->content_length,
'ctime'=>-1,
);
}
private function getTmpFile($path){
$obj=$this->getObject($path);
if(!is_null($obj)){
$tmpFile=OC_Helper::tmpFile();
$obj->save_to_filename($tmpFile);
return $tmpFile;
}else{
return false;
}
}
private function fromTmpFile($tmpFile,$path){
$obj=$this->getObject($path);
if(is_null($obj)){
$obj=$this->createObject($path);
}
$obj->load_from_filename($tmpFile);
}
}

View file

@ -21,5 +21,12 @@ return array(
'token'=>'test',
'token_secret'=>'test',
'root'=>'/google',
)
),
'swift'=>array(
'run'=>true,
'user'=>'test:tester',
'token'=>'testing',
'host'=>'localhost:8080/auth',
'root'=>'/',
),
);

View file

@ -0,0 +1,32 @@
<?php
/**
* Copyright (c) 2012 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
$config=include('apps/files_external/tests/config.php');
if(!is_array($config) or !isset($config['swift']) or !$config['swift']['run']){
abstract class Test_Filestorage_SWIFT extends Test_FileStorage{}
return;
}else{
class Test_Filestorage_SWIFT extends Test_FileStorage {
private $config;
private $id;
public function setUp(){
$id=uniqid();
$this->config=include('apps/files_external/tests/config.php');
$this->config['swift']['root'].='/'.$id;//make sure we have an new empty folder to work in
$this->instance=new OC_Filestorage_SWIFT($this->config['swift']);
}
public function tearDown(){
$this->instance->rmdir('');
}
}
}