From cb28eeefbbe75a289fe3ca165bfc73ca2baddd9e Mon Sep 17 00:00:00 2001 From: Steve Pulec Date: Mon, 20 Feb 2017 18:25:10 -0500 Subject: [PATCH] Add moto reset API. --- moto/backends.py | 4 ++++ moto/core/__init__.py | 2 +- moto/core/models.py | 50 ++++++++++++++++++++++++++++++++++++++++++ moto/core/responses.py | 8 +++++++ moto/server.py | 8 ++++++- moto/sns/urls.py | 2 +- 6 files changed, 71 insertions(+), 3 deletions(-) diff --git a/moto/backends.py b/moto/backends.py index 0cbcf481..4cebe560 100644 --- a/moto/backends.py +++ b/moto/backends.py @@ -5,10 +5,12 @@ from moto.autoscaling import autoscaling_backend from moto.awslambda import lambda_backend from moto.cloudformation import cloudformation_backend from moto.cloudwatch import cloudwatch_backend +from moto.core import moto_api_backend from moto.datapipeline import datapipeline_backend from moto.dynamodb import dynamodb_backend from moto.dynamodb2 import dynamodb_backend2 from moto.ec2 import ec2_backend +from moto.ecs import ecs_backend from moto.elb import elb_backend from moto.emr import emr_backend from moto.events import events_backend @@ -35,11 +37,13 @@ BACKENDS = { 'dynamodb': dynamodb_backend, 'dynamodb2': dynamodb_backend2, 'ec2': ec2_backend, + 'ecs': ecs_backend, 'elb': elb_backend, 'events': events_backend, 'emr': emr_backend, 'glacier': glacier_backend, 'iam': iam_backend, + 'moto_api': moto_api_backend, 'opsworks': opsworks_backend, 'kinesis': kinesis_backend, 'kms': kms_backend, diff --git a/moto/core/__init__.py b/moto/core/__init__.py index 1b909183..664637b7 100644 --- a/moto/core/__init__.py +++ b/moto/core/__init__.py @@ -1,2 +1,2 @@ from __future__ import unicode_literals -from .models import BaseBackend # flake8: noqa +from .models import BaseBackend, moto_api_backend # flake8: noqa diff --git a/moto/core/models.py b/moto/core/models.py index 9675d514..8fac8a99 100644 --- a/moto/core/models.py +++ b/moto/core/models.py @@ -153,6 +153,38 @@ class ResponsesMockAWS(BaseMockAWS): MockAWS = ResponsesMockAWS +class ServerModeMockAWS(BaseMockAWS): + + def reset(self): + import requests + requests.post("http://localhost:8086/moto-api/reset") + + def enable_patching(self): + if self.__class__.nested_count == 1: + # Just started + self.reset() + + from boto3 import client as real_boto3_client, resource as real_boto3_resource + import mock + + def fake_boto3_client(*args, **kwargs): + if 'endpoint_url' not in kwargs: + kwargs['endpoint_url'] = "http://localhost:8086" + return real_boto3_client(*args, **kwargs) + def fake_boto3_resource(*args, **kwargs): + if 'endpoint_url' not in kwargs: + kwargs['endpoint_url'] = "http://localhost:8086" + return real_boto3_resource(*args, **kwargs) + self._client_patcher = mock.patch('boto3.client', fake_boto3_client) + self._resource_patcher = mock.patch('boto3.resource', fake_boto3_resource) + self._client_patcher.start() + self._resource_patcher.start() + + def disable_patching(self): + if self._client_patcher: + self._client_patcher.stop() + self._resource_patcher.stop() + class Model(type): def __new__(self, clsname, bases, namespace): cls = super(Model, self).__new__(self, clsname, bases, namespace) @@ -257,6 +289,9 @@ class base_decorator(object): self.backends = backends def __call__(self, func=None): + if self.mock_backend == MockAWS and os.environ.get('TEST_SERVER_MODE', '0').lower() == 'true': + self.mock_backend = ServerModeMockAWS + if func: return self.mock_backend(self.backends)(func) else: @@ -265,3 +300,18 @@ class base_decorator(object): class deprecated_base_decorator(base_decorator): mock_backend = HttprettyMockAWS + + +class MotoAPIBackend(BaseBackend): + def __init__(self): + super(MotoAPIBackend, self).__init__() + + def reset(self): + from moto.backends import BACKENDS + for name, backend in BACKENDS.items(): + if name == "moto_api": + continue + backend.reset() + self.__init__() + +moto_api_backend = MotoAPIBackend() diff --git a/moto/core/responses.py b/moto/core/responses.py index 05c882ba..9b22b58c 100644 --- a/moto/core/responses.py +++ b/moto/core/responses.py @@ -366,6 +366,14 @@ def metadata_response(request, full_url, headers): return 200, headers, result +class MotoAPIResponse(BaseResponse): + + def reset_response(self, request, full_url, headers): + from .models import moto_api_backend + moto_api_backend.reset() + return 200, {}, json.dumps({"status": "ok"}) + + class _RecursiveDictRef(object): """Store a recursive reference to dict.""" def __init__(self): diff --git a/moto/server.py b/moto/server.py index 321f5a9e..0b5ff7ca 100644 --- a/moto/server.py +++ b/moto/server.py @@ -35,6 +35,9 @@ class DomainDispatcherApplication(object): if self.service: return self.service + if host in BACKENDS: + return host + for backend_name, backend in BACKENDS.items(): for url_base in backend.url_bases: if re.match(url_base, 'http://%s' % host): @@ -43,7 +46,10 @@ class DomainDispatcherApplication(object): raise RuntimeError('Invalid host: "%s"' % host) def get_application(self, environ): - host = environ['HTTP_HOST'].split(':')[0] + if environ.get('PATH_INFO', '').startswith("/moto-api"): + host = "moto_api" + else: + host = environ['HTTP_HOST'].split(':')[0] if host == "localhost": # Fall back to parsing auth header to find service # ['Credential=sdffdsa', '20170220', 'us-east-1', 'sns', 'aws4_request'] diff --git a/moto/sns/urls.py b/moto/sns/urls.py index 769c0c89..518531c5 100644 --- a/moto/sns/urls.py +++ b/moto/sns/urls.py @@ -2,7 +2,7 @@ from __future__ import unicode_literals from .responses import SNSResponse url_bases = [ - "https?://sns.(.+).amazonaws.com" + "https?://sns.(.+).amazonaws.com", ] url_paths = {