diff --git a/moto/core/models.py b/moto/core/models.py index 492a0e2ff..055cbbd7e 100644 --- a/moto/core/models.py +++ b/moto/core/models.py @@ -1,9 +1,11 @@ from __future__ import unicode_literals from __future__ import absolute_import +from collections import defaultdict import functools import inspect import re +import six from moto import settings from moto.packages.responses import responses @@ -208,12 +210,38 @@ class Model(type): return dec +model_data = defaultdict(dict) +class InstanceTrackerMeta(type): + def __new__(meta, name, bases, dct): + cls = super(InstanceTrackerMeta, meta).__new__(meta, name, bases, dct) + if name == 'BaseModel': + return cls + + service = cls.__module__.split(".")[1] + if name not in model_data[service]: + model_data[service][name] = cls + cls.instances = [] + return cls + +@six.add_metaclass(InstanceTrackerMeta) +class BaseModel(object): + def __new__(cls, *args, **kwargs): + instance = super(BaseModel, cls).__new__(cls, *args, **kwargs) + cls.instances.append(instance) + return instance + + class BaseBackend(object): def reset(self): self.__dict__ = {} self.__init__() + def get_models(self): + import pdb;pdb.set_trace() + models = getattr(backend.__class__, '__models__', {}) + + @property def _url_module(self): backend_module = self.__class__.__module__ diff --git a/moto/core/responses.py b/moto/core/responses.py index 00e3ba742..ebc4e1743 100644 --- a/moto/core/responses.py +++ b/moto/core/responses.py @@ -12,6 +12,7 @@ from jinja2 import Environment, DictLoader, TemplateNotFound import six from six.moves.urllib.parse import parse_qs, urlparse +from flask import render_template import xmltodict from pkg_resources import resource_filename from werkzeug.exceptions import HTTPException @@ -350,6 +351,32 @@ class MotoAPIResponse(BaseResponse): return 200, {}, json.dumps({"status": "ok"}) return 400, {}, json.dumps({"Error": "Need to POST to reset Moto"}) + def model_data(self, request, full_url, headers): + from moto.core.models import model_data + + results = {} + for service in sorted(model_data): + models = model_data[service] + results[service] = {} + for name in sorted(models): + model = models[name] + results[service][name] = [] + for instance in model.instances: + inst_result = {} + for attr in dir(instance): + if not attr.startswith("_"): + try: + json.dumps(getattr(instance, attr)) + except TypeError: + pass + else: + inst_result[attr] = getattr(instance, attr) + results[service][name].append(inst_result) + return 200, {"Content-Type": "application/javascript"}, json.dumps(results) + + def dashboard(self, request, full_url, headers): + return render_template('dashboard.html') + class _RecursiveDictRef(object): """Store a recursive reference to dict.""" diff --git a/moto/core/urls.py b/moto/core/urls.py index ece486058..4d4906d77 100644 --- a/moto/core/urls.py +++ b/moto/core/urls.py @@ -8,5 +8,7 @@ url_bases = [ response_instance = MotoAPIResponse() url_paths = { + '{0}/moto-api/$': response_instance.dashboard, + '{0}/moto-api/data.json': response_instance.model_data, '{0}/moto-api/reset': response_instance.reset_response, } diff --git a/moto/core/utils.py b/moto/core/utils.py index d26694014..54622d0d7 100644 --- a/moto/core/utils.py +++ b/moto/core/utils.py @@ -122,7 +122,10 @@ class convert_flask_to_httpretty_response(object): result = self.callback(request, request.url, {}) # result is a status, headers, response tuple - status, headers, content = result + if len(result) == 3: + status, headers, content = result + else: + status, headers, content = 200, {}, result response = Response(response=content, status=status, headers=headers) if request.method == "HEAD" and 'content-length' in headers: diff --git a/moto/ec2/models.py b/moto/ec2/models.py index c7467feee..a26aac6a4 100755 --- a/moto/ec2/models.py +++ b/moto/ec2/models.py @@ -13,7 +13,7 @@ from boto.ec2.spotinstancerequest import SpotInstanceRequest as BotoSpotRequest from boto.ec2.launchspecification import LaunchSpecification from moto.core import BaseBackend -from moto.core.models import Model +from moto.core.models import Model, BaseModel from moto.core.utils import iso_8601_datetime_with_milliseconds, camelcase_to_underscores from .exceptions import ( EC2ClientError, @@ -129,7 +129,7 @@ class StateReason(object): self.code = code -class TaggedEC2Resource(object): +class TaggedEC2Resource(BaseModel): def get_tags(self, *args, **kwargs): tags = self.ec2_backend.describe_tags( @@ -2612,7 +2612,7 @@ class InternetGatewayBackend(object): return self.describe_internet_gateways(internet_gateway_ids=igw_ids)[0] -class VPCGatewayAttachment(object): +class VPCGatewayAttachment(BaseModel): def __init__(self, gateway_id, vpc_id): self.gateway_id = gateway_id diff --git a/moto/server.py b/moto/server.py index fcc91ac6c..b70bb99bd 100644 --- a/moto/server.py +++ b/moto/server.py @@ -47,7 +47,7 @@ class DomainDispatcherApplication(object): def get_application(self, environ): path_info = environ.get('PATH_INFO', '') - if path_info.startswith("/moto-api"): + if path_info.startswith("/moto-api") or path_info == "/favicon.ico": host = "moto_api" elif path_info.startswith("/latest/meta-data/"): host = "instance_metadata" diff --git a/moto/sqs/models.py b/moto/sqs/models.py index 2a6fc19b1..60258972b 100644 --- a/moto/sqs/models.py +++ b/moto/sqs/models.py @@ -7,6 +7,7 @@ from xml.sax.saxutils import escape import boto.sqs from moto.core import BaseBackend +from moto.core.models import BaseModel from moto.core.utils import camelcase_to_underscores, get_random_message_id, unix_time, unix_time_millis from .utils import generate_receipt_handle from .exceptions import ( @@ -18,7 +19,7 @@ DEFAULT_ACCOUNT_ID = 123456789012 DEFAULT_SENDER_ID = "AIDAIT2UOQQY3AUEKVGXU" -class Message(object): +class Message(BaseModel): def __init__(self, message_id, body): self.id = message_id @@ -93,7 +94,7 @@ class Message(object): return False -class Queue(object): +class Queue(BaseModel): camelcase_attributes = ['ApproximateNumberOfMessages', 'ApproximateNumberOfMessagesDelayed', 'ApproximateNumberOfMessagesNotVisible', diff --git a/moto/templates/dashboard.html b/moto/templates/dashboard.html new file mode 100644 index 000000000..dc0fd880d --- /dev/null +++ b/moto/templates/dashboard.html @@ -0,0 +1,169 @@ + + + +
+ + + + +