From 7156df1a6315b67577757d15fd00ba03a07d2ecc Mon Sep 17 00:00:00 2001 From: Steve Pulec Date: Wed, 3 Jun 2015 22:55:07 -0400 Subject: [PATCH] Add vault operations. --- moto/__init__.py | 1 + moto/backends.py | 2 + moto/glacier/__init__.py | 12 +++++ moto/glacier/models.py | 52 ++++++++++++++++++ moto/glacier/responses.py | 64 +++++++++++++++++++++++ moto/glacier/urls.py | 11 ++++ moto/glacier/utils.py | 14 +++++ tests/test_glacier/test_glacier_server.py | 21 ++++++++ tests/test_glacier/test_glacier_vaults.py | 31 +++++++++++ 9 files changed, 208 insertions(+) create mode 100644 moto/glacier/__init__.py create mode 100644 moto/glacier/models.py create mode 100644 moto/glacier/responses.py create mode 100644 moto/glacier/urls.py create mode 100644 moto/glacier/utils.py create mode 100644 tests/test_glacier/test_glacier_server.py create mode 100644 tests/test_glacier/test_glacier_vaults.py diff --git a/moto/__init__.py b/moto/__init__.py index 7e13cf6bf..851a84a0d 100644 --- a/moto/__init__.py +++ b/moto/__init__.py @@ -13,6 +13,7 @@ from .dynamodb2 import mock_dynamodb2 # flake8: noqa from .ec2 import mock_ec2 # flake8: noqa from .elb import mock_elb # flake8: noqa from .emr import mock_emr # flake8: noqa +from .glacier import mock_glacier # flake8: noqa from .iam import mock_iam # flake8: noqa from .kinesis import mock_kinesis # flake8: noqa from .rds import mock_rds # flake8: noqa diff --git a/moto/backends.py b/moto/backends.py index 460ac028f..aad7d403c 100644 --- a/moto/backends.py +++ b/moto/backends.py @@ -6,6 +6,7 @@ from moto.dynamodb2 import dynamodb_backend2 from moto.ec2 import ec2_backend from moto.elb import elb_backend from moto.emr import emr_backend +from moto.glacier import glacier_backend from moto.kinesis import kinesis_backend from moto.rds import rds_backend from moto.redshift import redshift_backend @@ -24,6 +25,7 @@ BACKENDS = { 'ec2': ec2_backend, 'elb': elb_backend, 'emr': emr_backend, + 'glacier': glacier_backend, 'kinesis': kinesis_backend, 'redshift': redshift_backend, 'rds': rds_backend, diff --git a/moto/glacier/__init__.py b/moto/glacier/__init__.py new file mode 100644 index 000000000..bc6fd1ff4 --- /dev/null +++ b/moto/glacier/__init__.py @@ -0,0 +1,12 @@ +from __future__ import unicode_literals +from .models import glacier_backends +from ..core.models import MockAWS + +glacier_backend = glacier_backends['us-east-1'] + + +def mock_glacier(func=None): + if func: + return MockAWS(glacier_backends)(func) + else: + return MockAWS(glacier_backends) diff --git a/moto/glacier/models.py b/moto/glacier/models.py new file mode 100644 index 000000000..b5b5e38d1 --- /dev/null +++ b/moto/glacier/models.py @@ -0,0 +1,52 @@ +from __future__ import unicode_literals + +import boto.glacier +from moto.core import BaseBackend + + +class Vault(object): + def __init__(self, vault_name, region): + self.vault_name = vault_name + self.region = region + + @property + def arn(self): + return "arn:aws:glacier:{}:012345678901:vaults/{}".format(self.region, self.vault_name) + + def to_dict(self): + return { + "CreationDate": "2013-03-20T17:03:43.221Z", + "LastInventoryDate": "2013-03-20T17:03:43.221Z", + "NumberOfArchives": None, + "SizeInBytes": None, + "VaultARN": self.arn, + "VaultName": self.vault_name, + } + + +class GlacierBackend(BaseBackend): + + def __init__(self, region_name): + self.vaults = {} + self.region_name = region_name + + def reset(self): + region_name = self.region_name + self.__dict__ = {} + self.__init__(region_name) + + def get_vault(self, vault_name): + return self.vaults[vault_name] + + def create_vault(self, vault_name): + self.vaults[vault_name] = Vault(vault_name, self.region_name) + + def list_vaules(self): + return self.vaults.values() + + def delete_vault(self, vault_name): + self.vaults.pop(vault_name) + +glacier_backends = {} +for region in boto.glacier.regions(): + glacier_backends[region.name] = GlacierBackend(region) diff --git a/moto/glacier/responses.py b/moto/glacier/responses.py new file mode 100644 index 000000000..a8194b317 --- /dev/null +++ b/moto/glacier/responses.py @@ -0,0 +1,64 @@ +from __future__ import unicode_literals + +import json +from six.moves.urllib.parse import urlparse, parse_qs + +from moto.core.responses import _TemplateEnvironmentMixin +from .models import glacier_backends +from .utils import region_from_glacier_url, vault_from_glacier_url + + +class GlacierResponse(_TemplateEnvironmentMixin): + + def __init__(self, backend): + self.backend = backend + + @classmethod + def all_vault_response(clazz, request, full_url, headers): + region_name = region_from_glacier_url(full_url) + response_instance = GlacierResponse(glacier_backends[region_name]) + return response_instance._all_vault_response(request, full_url, headers) + + def _all_vault_response(self, request, full_url, headers): + vaults = self.backend.list_vaules() + response = json.dumps({ + "Marker": None, + "VaultList": [ + vault.to_dict() for vault in vaults + ] + }) + + headers['content-type'] = 'application/json' + return 200, headers, response + + @classmethod + def vault_response(clazz, request, full_url, headers): + region_name = region_from_glacier_url(full_url) + response_instance = GlacierResponse(glacier_backends[region_name]) + return response_instance._vault_response(request, full_url, headers) + + def _vault_response(self, request, full_url, headers): + method = request.method + parsed_url = urlparse(full_url) + querystring = parse_qs(parsed_url.query, keep_blank_values=True) + vault_name = vault_from_glacier_url(full_url) + + if method == 'GET': + return self._vault_response_get(vault_name, querystring, headers) + elif method == 'PUT': + return self._vault_response_put(vault_name, querystring, headers) + elif method == 'DELETE': + return self._vault_response_delete(vault_name, querystring, headers) + + def _vault_response_get(self, vault_name, querystring, headers): + vault = self.backend.get_vault(vault_name) + headers['content-type'] = 'application/json' + return 200, headers, json.dumps(vault.to_dict()) + + def _vault_response_put(self, vault_name, querystring, headers): + self.backend.create_vault(vault_name) + return 201, headers, "" + + def _vault_response_delete(self, vault_name, querystring, headers): + self.backend.delete_vault(vault_name) + return 204, headers, "" diff --git a/moto/glacier/urls.py b/moto/glacier/urls.py new file mode 100644 index 000000000..d5d812896 --- /dev/null +++ b/moto/glacier/urls.py @@ -0,0 +1,11 @@ +from __future__ import unicode_literals +from .responses import GlacierResponse + +url_bases = [ + "https?://glacier.(.+).amazonaws.com", +] + +url_paths = { + '{0}/(?P.+)/vaults$': GlacierResponse.all_vault_response, + '{0}/(?P.+)/vaults/(?P.+)$': GlacierResponse.vault_response, +} diff --git a/moto/glacier/utils.py b/moto/glacier/utils.py new file mode 100644 index 000000000..5b53a089c --- /dev/null +++ b/moto/glacier/utils.py @@ -0,0 +1,14 @@ +from six.moves.urllib.parse import urlparse + + +def region_from_glacier_url(url): + domain = urlparse(url).netloc + + if '.' in domain: + return domain.split(".")[1] + else: + return 'us-east-1' + + +def vault_from_glacier_url(full_url): + return full_url.split("/")[-1] diff --git a/tests/test_glacier/test_glacier_server.py b/tests/test_glacier/test_glacier_server.py new file mode 100644 index 000000000..cbdd00b2e --- /dev/null +++ b/tests/test_glacier/test_glacier_server.py @@ -0,0 +1,21 @@ +from __future__ import unicode_literals + +import json +import sure # noqa + +import moto.server as server +from moto import mock_glacier + +''' +Test the different server responses +''' + + +@mock_glacier +def test_list_vaults(): + backend = server.create_backend_app("glacier") + test_client = backend.test_client() + + res = test_client.get('/1234bcd/vaults') + + json.loads(res.data).should.equal({u'Marker': None, u'VaultList': []}) diff --git a/tests/test_glacier/test_glacier_vaults.py b/tests/test_glacier/test_glacier_vaults.py new file mode 100644 index 000000000..40f20e58e --- /dev/null +++ b/tests/test_glacier/test_glacier_vaults.py @@ -0,0 +1,31 @@ +from __future__ import unicode_literals + +import boto.glacier +import sure # noqa + +from moto import mock_glacier + + +@mock_glacier +def test_create_vault(): + conn = boto.glacier.connect_to_region("us-west-2") + + conn.create_vault("my_vault") + + vaults = conn.list_vaults() + vaults.should.have.length_of(1) + vaults[0].name.should.equal("my_vault") + + +@mock_glacier +def test_delete_vault(): + conn = boto.glacier.connect_to_region("us-west-2") + + conn.create_vault("my_vault") + + vaults = conn.list_vaults() + vaults.should.have.length_of(1) + + conn.delete_vault("my_vault") + vaults = conn.list_vaults() + vaults.should.have.length_of(0)