Merge pull request #139 from kouk/backendaccess

general support for access to backend models
This commit is contained in:
Steve Pulec 2014-08-02 10:43:35 -04:00
commit d2fc7bb7f9
5 changed files with 102 additions and 40 deletions

View File

@ -25,3 +25,10 @@ BACKENDS = {
'sts': sts_backend, 'sts': sts_backend,
'route53': route53_backend 'route53': route53_backend
} }
def get_model(name):
for backend in BACKENDS.values():
models = getattr(backend.__class__, '__models__', {})
if name in models:
return getattr(backend, models[name])()

View File

@ -65,8 +65,28 @@ class MockAWS(object):
return wrapper return wrapper
class BaseBackend(object): class Model(type):
def __new__(self, clsname, bases, namespace):
cls = super(Model, self).__new__(self, clsname, bases, namespace)
cls.__models__ = {}
for name, value in namespace.iteritems():
model = getattr(value, "__returns_model__", False)
if model is not False:
cls.__models__[model] = name
for base in bases:
cls.__models__.update(getattr(base, "__models__", {}))
return cls
@staticmethod
def prop(model_name):
""" decorator to mark a class method as returning model values """
def dec(f):
f.__returns_model__ = model_name
return f
return dec
class BaseBackend(object):
def reset(self): def reset(self):
self.__dict__ = {} self.__dict__ = {}
self.__init__() self.__init__()

View File

@ -3,8 +3,11 @@ import itertools
from collections import defaultdict from collections import defaultdict
from boto.ec2.instance import Instance as BotoInstance, Reservation from boto.ec2.instance import Instance as BotoInstance, Reservation
from boto.ec2.spotinstancerequest import SpotInstanceRequest as BotoSpotRequest
from boto.ec2.launchspecification import LaunchSpecification
from moto.core import BaseBackend from moto.core import BaseBackend
from moto.core.models import Model
from .exceptions import ( from .exceptions import (
InvalidIdError, InvalidIdError,
DependencyViolationError, DependencyViolationError,
@ -937,42 +940,46 @@ class VPCGatewayAttachmentBackend(object):
return attachment return attachment
class SpotInstanceRequest(object): class SpotInstanceRequest(BotoSpotRequest):
def __init__(self, spot_request_id, price, image_id, type, valid_from, def __init__(self, spot_request_id, price, image_id, type, valid_from,
valid_until, launch_group, availability_zone_group, key_name, valid_until, launch_group, availability_zone_group, key_name,
security_groups, user_data, instance_type, placement, kernel_id, security_groups, user_data, instance_type, placement, kernel_id,
ramdisk_id, monitoring_enabled, subnet_id): ramdisk_id, monitoring_enabled, subnet_id, **kwargs):
super(SpotInstanceRequest, self).__init__(**kwargs)
ls = LaunchSpecification()
self.launch_specification = ls
self.id = spot_request_id self.id = spot_request_id
self.state = "open" self.state = "open"
self.price = price self.price = price
self.image_id = image_id
self.type = type self.type = type
self.valid_from = valid_from self.valid_from = valid_from
self.valid_until = valid_until self.valid_until = valid_until
self.launch_group = launch_group self.launch_group = launch_group
self.availability_zone_group = availability_zone_group self.availability_zone_group = availability_zone_group
self.key_name = key_name self.user_data = user_data # NOT
self.user_data = user_data ls.kernel = kernel_id
self.instance_type = instance_type ls.ramdisk = ramdisk_id
self.placement = placement ls.image_id = image_id
self.kernel_id = kernel_id ls.key_name = key_name
self.ramdisk_id = ramdisk_id ls.instance_type = instance_type
self.monitoring_enabled = monitoring_enabled ls.placement = placement
self.subnet_id = subnet_id ls.monitored = monitoring_enabled
ls.subnet_id = subnet_id
self.security_groups = []
if security_groups: if security_groups:
for group_name in security_groups: for group_name in security_groups:
group = ec2_backend.get_security_group_from_name(group_name) group = ec2_backend.get_security_group_from_name(group_name)
if group: if group:
self.security_groups.append(group) ls.groups.append(group)
else: else:
# If not security groups, add the default # If not security groups, add the default
default_group = ec2_backend.get_security_group_from_name("default") default_group = ec2_backend.get_security_group_from_name("default")
self.security_groups.append(default_group) ls.groups.append(default_group)
class SpotRequestBackend(object): class SpotRequestBackend(object):
__metaclass__ = Model
def __init__(self): def __init__(self):
self.spot_instance_requests = {} self.spot_instance_requests = {}
super(SpotRequestBackend, self).__init__() super(SpotRequestBackend, self).__init__()
@ -995,6 +1002,7 @@ class SpotRequestBackend(object):
requests.append(request) requests.append(request)
return requests return requests
@Model.prop('SpotInstanceRequest')
def describe_spot_instance_requests(self): def describe_spot_instance_requests(self):
return self.spot_instance_requests.values() return self.spot_instance_requests.values()

View File

@ -95,27 +95,27 @@ REQUEST_SPOT_INSTANCES_TEMPLATE = """<RequestSpotInstancesResponse xmlns="http:/
</status> </status>
<availabilityZoneGroup>{{ request.availability_zone_group }}</availabilityZoneGroup> <availabilityZoneGroup>{{ request.availability_zone_group }}</availabilityZoneGroup>
<launchSpecification> <launchSpecification>
<imageId>{{ request.image_id }}</imageId> <imageId>{{ request.launch_specification.image_id }}</imageId>
<keyName>{{ request.key_name }}</keyName> <keyName>{{ request.launch_specification.key_name }}</keyName>
<groupSet> <groupSet>
{% for group in request.security_groups %} {% for group in request.launch_specification.groups %}
<item> <item>
<groupId>{{ group.id }}</groupId> <groupId>{{ group.id }}</groupId>
<groupName>{{ group.name }}</groupName> <groupName>{{ group.name }}</groupName>
</item> </item>
{% endfor %} {% endfor %}
</groupSet> </groupSet>
<kernelId>{{ request.kernel_id }}</kernelId> <kernelId>{{ request.launch_specification.kernel }}</kernelId>
<ramdiskId>{{ request.ramdisk_id }}</ramdiskId> <ramdiskId>{{ request.launch_specification.ramdisk }}</ramdiskId>
<subnetId>{{ request.subnet_id }}</subnetId> <subnetId>{{ request.launch_specification.subnet_id }}</subnetId>
<instanceType>{{ request.instance_type }}</instanceType> <instanceType>{{ request.launch_specification.instance_type }}</instanceType>
<blockDeviceMapping/> <blockDeviceMapping/>
<monitoring> <monitoring>
<enabled>{{ request.monitoring_enabled }}</enabled> <enabled>{{ request.launch_specification.monitored }}</enabled>
</monitoring> </monitoring>
<ebsOptimized>{{ request.ebs_optimized }}</ebsOptimized> <ebsOptimized>{{ request.launch_specification.ebs_optimized }}</ebsOptimized>
<PlacementRequestType> <PlacementRequestType>
<availabilityZone>{{ request.placement }}</availabilityZone> <availabilityZone>{{ request.launch_specification.placement }}</availabilityZone>
<groupName></groupName> <groupName></groupName>
</PlacementRequestType> </PlacementRequestType>
</launchSpecification> </launchSpecification>
@ -151,36 +151,36 @@ DESCRIBE_SPOT_INSTANCES_TEMPLATE = """<DescribeSpotInstanceRequestsResponse xmln
<availabilityZoneGroup>{{ request.availability_zone_group }}</availabilityZoneGroup> <availabilityZoneGroup>{{ request.availability_zone_group }}</availabilityZoneGroup>
{% endif %} {% endif %}
<launchSpecification> <launchSpecification>
<imageId>{{ request.image_id }}</imageId> <imageId>{{ request.launch_specification.image_id }}</imageId>
{% if request.key_name %} {% if request.launch_specification.key_name %}
<keyName>{{ request.key_name }}</keyName> <keyName>{{ request.launch_specification.key_name }}</keyName>
{% endif %} {% endif %}
<groupSet> <groupSet>
{% for group in request.security_groups %} {% for group in request.launch_specification.groups %}
<item> <item>
<groupId>{{ group.id }}</groupId> <groupId>{{ group.id }}</groupId>
<groupName>{{ group.name }}</groupName> <groupName>{{ group.name }}</groupName>
</item> </item>
{% endfor %} {% endfor %}
</groupSet> </groupSet>
{% if request.kernel_id %} {% if request.launch_specification.kernel %}
<kernelId>{{ request.kernel_id }}</kernelId> <kernelId>{{ request.launch_specification.kernel }}</kernelId>
{% endif %} {% endif %}
{% if request.ramdisk_id %} {% if request.launch_specification.ramdisk %}
<ramdiskId>{{ request.ramdisk_id }}</ramdiskId> <ramdiskId>{{ request.launch_specification.ramdisk }}</ramdiskId>
{% endif %} {% endif %}
{% if request.subnet_id %} {% if request.launch_specification.subnet_id %}
<subnetId>{{ request.subnet_id }}</subnetId> <subnetId>{{ request.launch_specification.subnet_id }}</subnetId>
{% endif %} {% endif %}
<instanceType>{{ request.instance_type }}</instanceType> <instanceType>{{ request.launch_specification.instance_type }}</instanceType>
<blockDeviceMapping/> <blockDeviceMapping/>
<monitoring> <monitoring>
<enabled>{{ request.monitoring_enabled }}</enabled> <enabled>{{ request.launch_specification.monitored }}</enabled>
</monitoring> </monitoring>
<ebsOptimized>{{ request.ebs_optimized }}</ebsOptimized> <ebsOptimized>{{ request.launch_specification.ebs_optimized }}</ebsOptimized>
{% if request.placement %} {% if request.launch_specification.placement %}
<PlacementRequestType> <PlacementRequestType>
<availabilityZone>{{ request.placement }}</availabilityZone> <availabilityZone>{{ request.launch_specification.placement }}</availabilityZone>
<groupName></groupName> <groupName></groupName>
</PlacementRequestType> </PlacementRequestType>
{% endif %} {% endif %}

View File

@ -4,6 +4,7 @@ import boto
import sure # noqa import sure # noqa
from moto import mock_ec2 from moto import mock_ec2
from moto.backends import get_model
from moto.core.utils import iso_8601_datetime from moto.core.utils import iso_8601_datetime
@ -97,3 +98,29 @@ def test_cancel_spot_instance_request():
requests = conn.get_all_spot_instance_requests() requests = conn.get_all_spot_instance_requests()
requests.should.have.length_of(0) requests.should.have.length_of(0)
@mock_ec2
def test_request_spot_instances_fulfilled():
"""
Test that moto correctly fullfills a spot instance request
"""
conn = boto.connect_ec2()
request = conn.request_spot_instances(
price=0.5, image_id='ami-abcd1234',
)
requests = conn.get_all_spot_instance_requests()
requests.should.have.length_of(1)
request = requests[0]
request.state.should.equal("open")
get_model('SpotInstanceRequest')[0].state = 'active'
requests = conn.get_all_spot_instance_requests()
requests.should.have.length_of(1)
request = requests[0]
request.state.should.equal("active")