You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@libcloud.apache.org by qu...@apache.org on 2017/10/16 06:28:32 UTC
[3/5] libcloud git commit: [LIBCLOUD-955] Add DigitalOcean Spaces
support.
[LIBCLOUD-955] Add DigitalOcean Spaces support.
Signed-off-by: Quentin Pradet <qu...@apache.org>
Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/79052a08
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/79052a08
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/79052a08
Branch: refs/heads/trunk
Commit: 79052a080f87a436f27701db7429fa7dcb11d433
Parents: 820ff6f
Author: Andrew Starr-Bochicchio <a....@gmail.com>
Authored: Fri Oct 6 15:59:48 2017 -0400
Committer: Quentin Pradet <qu...@apache.org>
Committed: Mon Oct 16 10:24:58 2017 +0400
----------------------------------------------------------------------
libcloud/storage/drivers/digitalocean_spaces.py | 101 +++++++++++++++
libcloud/storage/providers.py | 3 +
libcloud/storage/types.py | 1 +
.../test/storage/test_digitalocean_spaces.py | 122 +++++++++++++++++++
4 files changed, 227 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/libcloud/blob/79052a08/libcloud/storage/drivers/digitalocean_spaces.py
----------------------------------------------------------------------
diff --git a/libcloud/storage/drivers/digitalocean_spaces.py b/libcloud/storage/drivers/digitalocean_spaces.py
new file mode 100644
index 0000000..1808b4d
--- /dev/null
+++ b/libcloud/storage/drivers/digitalocean_spaces.py
@@ -0,0 +1,101 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from libcloud.common.types import LibcloudError
+from libcloud.common.aws import SignedAWSConnection, DEFAULT_SIGNATURE_VERSION
+from libcloud.storage.drivers.s3 import BaseS3Connection, S3Connection
+from libcloud.storage.drivers.s3 import S3StorageDriver, API_VERSION
+
+__all__ = [
+ 'DigitalOceanSpacesStorageDriver'
+]
+
+DO_SPACES_HOSTS_BY_REGION = {'nyc3': 'nyc3.digitaloceanspaces.com'}
+
+DO_SPACES_DEFAULT_REGION = 'nyc3'
+
+
+class DOSpacesConnectionAWS4(SignedAWSConnection, BaseS3Connection):
+ service_name = 's3'
+ version = API_VERSION
+
+ def __init__(self, user_id, key, secure=True, host=None, port=None,
+ url=None, timeout=None, proxy_url=None, token=None,
+ retry_delay=None, backoff=None, **kwargs):
+
+ super(DOSpacesConnectionAWS4, self).__init__(user_id, key,
+ secure, host,
+ port, url,
+ timeout,
+ proxy_url, token,
+ retry_delay,
+ backoff,
+ 4) # force aws4
+
+
+class DOSpacesConnectionAWS2(S3Connection):
+
+ def __init__(self, user_id, key, secure=True, host=None, port=None,
+ url=None, timeout=None, proxy_url=None, token=None,
+ retry_delay=None, backoff=None, **kwargs):
+
+ super(DOSpacesConnectionAWS2, self).__init__(user_id, key,
+ secure, host,
+ port, url,
+ timeout,
+ proxy_url, token,
+ retry_delay,
+ backoff)
+
+
+class DigitalOceanSpacesStorageDriver(S3StorageDriver):
+ name = 'DigitalOcean Spaces'
+ website = 'https://www.digitalocean.com/products/object-storage/'
+ supports_chunked_encoding = False
+ supports_s3_multipart_upload = True
+
+ def __init__(self, key, secret=None, secure=True, host=None, port=None,
+ api_version=None, region=DO_SPACES_DEFAULT_REGION, **kwargs):
+
+ if region not in DO_SPACES_HOSTS_BY_REGION:
+ raise LibcloudError('Unknown region (%s)' % (region), driver=self)
+
+ host = DO_SPACES_HOSTS_BY_REGION[region]
+ self.name = 'DigitalOcean Spaces (%s)' % (region)
+
+ self.region_name = region
+ self.signature_version = str(kwargs.pop('signature_version',
+ DEFAULT_SIGNATURE_VERSION))
+
+ if self.signature_version not in ['2', '4']:
+ raise ValueError('Invalid signature_version: %s' %
+ (self.signature_version))
+
+ if self.signature_version == '2':
+ self.connectionCls = DOSpacesConnectionAWS2
+ elif self.signature_version == '4':
+ self.connectionCls = DOSpacesConnectionAWS4
+ self.connectionCls.host = host
+
+ super(DigitalOceanSpacesStorageDriver,
+ self).__init__(key, secret,
+ secure, host, port,
+ api_version, region,
+ **kwargs)
+
+ def _ex_connection_class_kwargs(self):
+ kwargs = {}
+ kwargs['signature_version'] = self.signature_version
+ return kwargs
http://git-wip-us.apache.org/repos/asf/libcloud/blob/79052a08/libcloud/storage/providers.py
----------------------------------------------------------------------
diff --git a/libcloud/storage/providers.py b/libcloud/storage/providers.py
index 56b049e..183189e 100644
--- a/libcloud/storage/providers.py
+++ b/libcloud/storage/providers.py
@@ -81,6 +81,9 @@ DRIVERS = {
('libcloud.storage.drivers.backblaze_b2', 'BackblazeB2StorageDriver'),
Provider.ALIYUN_OSS:
('libcloud.storage.drivers.oss', 'OSSStorageDriver'),
+ Provider.DIGITALOCEAN_SPACES:
+ ('libcloud.storage.drivers.digitalocean_spaces',
+ 'DigitalOceanSpacesStorageDriver'),
}
http://git-wip-us.apache.org/repos/asf/libcloud/blob/79052a08/libcloud/storage/types.py
----------------------------------------------------------------------
diff --git a/libcloud/storage/types.py b/libcloud/storage/types.py
index c093a0b..c9e7451 100644
--- a/libcloud/storage/types.py
+++ b/libcloud/storage/types.py
@@ -62,6 +62,7 @@ class Provider(object):
AZURE_BLOBS = 'azure_blobs'
BACKBLAZE_B2 = 'backblaze_b2'
CLOUDFILES = 'cloudfiles'
+ DIGITALOCEAN_SPACES = 'digitalocean_spaces'
GOOGLE_STORAGE = 'google_storage'
KTUCLOUD = 'ktucloud'
LOCAL = 'local'
http://git-wip-us.apache.org/repos/asf/libcloud/blob/79052a08/libcloud/test/storage/test_digitalocean_spaces.py
----------------------------------------------------------------------
diff --git a/libcloud/test/storage/test_digitalocean_spaces.py b/libcloud/test/storage/test_digitalocean_spaces.py
new file mode 100644
index 0000000..47f4779
--- /dev/null
+++ b/libcloud/test/storage/test_digitalocean_spaces.py
@@ -0,0 +1,122 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+import unittest
+
+from libcloud.storage.base import Container, Object
+from libcloud.storage.drivers.digitalocean_spaces import (
+ DigitalOceanSpacesStorageDriver,
+ DOSpacesConnectionAWS4,
+ DOSpacesConnectionAWS2)
+
+from libcloud.test import LibcloudTestCase
+from libcloud.test.secrets import STORAGE_S3_PARAMS
+
+
+class DigitalOceanSpacesTests(LibcloudTestCase):
+ driver_type = DigitalOceanSpacesStorageDriver
+ driver_args = STORAGE_S3_PARAMS
+ default_host = 'nyc3.digitaloceanspaces.com'
+
+ @classmethod
+ def create_driver(self):
+ return self.driver_type(*self.driver_args,
+ signature_version='2',
+ host=self.default_host)
+
+ def setUp(self):
+ self.driver = self.create_driver()
+ self.container = Container('test-container', {}, self.driver)
+ self.object = Object('test-object', 1, 'hash', {},
+ 'meta_data', self.container, self.driver)
+
+ def test_connection_class_type(self):
+ res = self.driver.connectionCls is DOSpacesConnectionAWS2
+ self.assertTrue(res, 'driver.connectionCls does not match!')
+
+ def test_connection_class_host(self):
+ host = self.driver.connectionCls.host
+ self.assertEqual(host, self.default_host)
+
+ def test_container_enable_cdn_not_implemented(self):
+ with self.assertRaises(NotImplementedError):
+ self.container.enable_cdn()
+
+ def test_container_get_cdn_url_not_implemented(self):
+ with self.assertRaises(NotImplementedError):
+ self.container.get_cdn_url()
+
+ def test_object_enable_cdn_not_implemented(self):
+ with self.assertRaises(NotImplementedError):
+ self.object.enable_cdn()
+
+ def test_object_get_cdn_url_not_implemented(self):
+ with self.assertRaises(NotImplementedError):
+ self.object.get_cdn_url()
+
+
+class DigitalOceanSpacesTests_v4(DigitalOceanSpacesTests):
+ driver_type = DigitalOceanSpacesStorageDriver
+ driver_args = STORAGE_S3_PARAMS
+ default_host = 'nyc3.digitaloceanspaces.com'
+
+ @classmethod
+ def create_driver(self):
+ return self.driver_type(*self.driver_args,
+ signature_version='4')
+
+ def test_connection_class_type(self):
+ res = self.driver.connectionCls is DOSpacesConnectionAWS4
+ self.assertTrue(res, 'driver.connectionCls does not match!')
+
+ def test_connection_class_host(self):
+ host = self.driver.connectionCls.host
+ self.assertEqual(host, self.default_host)
+
+
+class DigitalOceanSpacesDoubleInstanceTests(LibcloudTestCase):
+ driver_type = DigitalOceanSpacesStorageDriver
+ driver_args = STORAGE_S3_PARAMS
+ default_host = 'nyc3.digitaloceanspaces.com'
+
+ def setUp(self):
+ self.driver_v2 = self.driver_type(*self.driver_args,
+ signature_version='2')
+ self.driver_v4 = self.driver_type(*self.driver_args,
+ signature_version='4')
+
+ def test_connection_class_type(self):
+ res = self.driver_v2.connectionCls is DOSpacesConnectionAWS2
+ self.assertTrue(res, 'driver.connectionCls does not match!')
+
+ res = self.driver_v4.connectionCls is DOSpacesConnectionAWS4
+ self.assertTrue(res, 'driver.connectionCls does not match!')
+
+ # Verify again that connection class hasn't been overriden when
+ # instantiating a second driver class
+ res = self.driver_v2.connectionCls is DOSpacesConnectionAWS2
+ self.assertTrue(res, 'driver.connectionCls does not match!')
+
+ def test_connection_class_host(self):
+ host = self.driver_v2.connectionCls.host
+ self.assertEqual(host, self.default_host)
+
+ host = self.driver_v4.connectionCls.host
+ self.assertEqual(host, self.default_host)
+
+
+if __name__ == '__main__':
+ sys.exit(unittest.main())