From 6631436455d3b9ec798780779709e915e243d6a7 Mon Sep 17 00:00:00 2001 From: Itamar Turner-Trauring Date: Tue, 5 Mar 2013 11:38:40 -0500 Subject: [PATCH] Configuration support for Google Cloud Storage backend. --- .../storage/backends/cloud/cloud_backend.py | 2 +- .../googlestorage/googlestorage_container.py | 35 ++++------ src/allmydata/test/test_client.py | 68 +++++++++++++++++++ 3 files changed, 82 insertions(+), 23 deletions(-) diff --git a/src/allmydata/storage/backends/cloud/cloud_backend.py b/src/allmydata/storage/backends/cloud/cloud_backend.py index 3d92525f..14dee749 100644 --- a/src/allmydata/storage/backends/cloud/cloud_backend.py +++ b/src/allmydata/storage/backends/cloud/cloud_backend.py @@ -20,7 +20,7 @@ from allmydata.storage.backends.cloud.cloud_common import get_share_key, delete_ from allmydata.mutable.layout import MUTABLE_MAGIC -CLOUD_INTERFACES = ("cloud.s3", "cloud.openstack") +CLOUD_INTERFACES = ("cloud.s3", "cloud.openstack", "cloud.googlestorage") def get_cloud_share(container, storage_index, shnum, total_size): diff --git a/src/allmydata/storage/backends/cloud/googlestorage/googlestorage_container.py b/src/allmydata/storage/backends/cloud/googlestorage/googlestorage_container.py index 75264e23..af3a82a9 100644 --- a/src/allmydata/storage/backends/cloud/googlestorage/googlestorage_container.py +++ b/src/allmydata/storage/backends/cloud/googlestorage/googlestorage_container.py @@ -26,12 +26,6 @@ from allmydata.storage.backends.cloud.cloud_common import IContainer, \ ContainerItem, ContainerListing, CommonContainerMixin -def configure_googlestorage_container(*args): - """ - Configure the Google Cloud Storage container. - """ - - class AuthenticationClient(object): """ Retrieve access tokens for the Google Storage API, using OAuth 2.0. @@ -227,19 +221,16 @@ class GoogleStorageContainer(CommonContainerMixin): return d -if __name__ == '__main__': - from twisted.internet import reactor - from twisted.web.client import getPage - import sys - auth = AuthenticationClient(sys.argv[1], file(sys.argv[2]).read()) - def println(result): - print result - reactor.stop() - def gotAuth(value): - return getPage("https://storage.googleapis.com/", - headers={"Authorization": value, - "x-goog-api-version": "2", - "x-goog-project-id": sys.argv[3]}).addCallback(println) - auth.get_authorization_header().addCallback(gotAuth) - reactor.run() - +def configure_googlestorage_container(storedir, config): + """ + Configure the Google Cloud Storage container. + """ + account_email = config.get_config("storage", "googlestorage.account_email") + private_key = config.get_private_config("googlestorage_private_key") + bucket_name = config.get_config("storage", "googlestorage.bucket_name") + # Only necessary if we do bucket creation/deletion, otherwise can be + # removed: + project_id = config.get_config("storage", "googlestorage.project_id") + + authclient = AuthenticationClient(account_email, private_key) + return GoogleStorageContainer(authclient, project_id, bucket_name) diff --git a/src/allmydata/test/test_client.py b/src/allmydata/test/test_client.py index 0888a0b6..bb7a086a 100644 --- a/src/allmydata/test/test_client.py +++ b/src/allmydata/test/test_client.py @@ -430,6 +430,74 @@ class Basic(testutil.ReallyEqualMixin, unittest.TestCase): "openstack.container = test\n") self.failUnlessRaises(MissingConfigEntry, client.Client, basedir) + def test_googlestorage_config_required(self): + """ + account_email, bucket_name and project_id are all required by + googlestorage configuration. + """ + configs = ["googlestorage.account_email = u@example.com", + "googlestorage.bucket_name = bucket", + "googlestorage.project_id = 456"] + for i in range(len(configs)): + basedir = self.mktemp() + os.mkdir(basedir) + bad_config = configs[:] + del bad_config[i] + self._write_secret(basedir, "googlestorage_private_key") + fileutil.write(os.path.join(basedir, "tahoe.cfg"), + BASECONFIG + + "[storage]\n" + + "enabled = true\n" + + "backend = cloud.googlestorage\n" + + "\n".join(bad_config) + "\n") + self.failUnlessRaises(MissingConfigEntry, client.Client, basedir) + + def test_googlestorage_config_required_private_key(self): + """ + googlestorage_private_key secret is required by googlestorage + configuration. + """ + basedir = self.mktemp() + os.mkdir(basedir) + fileutil.write(os.path.join(basedir, "tahoe.cfg"), + BASECONFIG + + "[storage]\n" + + "enabled = true\n" + + "backend = cloud.googlestorage\n" + + "googlestorage.account_email = u@example.com\n" + + "googlestorage.bucket_name = bucket\n" + + "googlestorage.project_id = 456\n") + self.failUnlessRaises(MissingConfigEntry, client.Client, basedir) + + @mock.patch('allmydata.storage.backends.cloud.googlestorage.googlestorage_container.AuthenticationClient') + @mock.patch('allmydata.storage.backends.cloud.googlestorage.googlestorage_container.GoogleStorageContainer') + def test_googlestorage_config(self, mock_OpenStackContainer, mock_AuthenticationClient): + """ + Given good configuration, we correctly configure a good GoogleStorageContainer. + """ + basedir = self.mktemp() + os.mkdir(basedir) + self._write_secret(basedir, "googlestorage_private_key", "sekrit") + fileutil.write(os.path.join(basedir, "tahoe.cfg"), + BASECONFIG + + "[storage]\n" + + "enabled = true\n" + + "backend = cloud.googlestorage\n" + + "googlestorage.account_email = u@example.com\n" + + "googlestorage.bucket_name = bucket\n" + + "googlestorage.project_id = 456\n") + c = client.Client(basedir) + server = c.getServiceNamed("storage") + self.failUnless(isinstance(server.backend, CloudBackend), server.backend) + # Protect against typos with isinstance(), because mock is dangerous. + self.assertFalse(isinstance(mock_AuthenticationClient.assert_called_once_with, + mock.Mock)) + mock_AuthenticationClient.assert_called_once_with("u@example.com", "sekrit") + self.assertFalse(isinstance(mock_OpenStackContainer.assert_called_once_with, + mock.Mock)) + mock_OpenStackContainer.assert_called_once_with(mock_AuthenticationClient.return_value, + "456", "bucket") + def test_expire_mutable_false_unsupported(self): basedir = "client.Basic.test_expire_mutable_false_unsupported" os.mkdir(basedir) -- 2.45.2