Merge pull request #139 from kouk/backendaccess
general support for access to backend models
This commit is contained in:
commit
d2fc7bb7f9
@ -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])()
|
||||||
|
@ -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__()
|
||||||
|
@ -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()
|
||||||
|
|
||||||
|
@ -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 %}
|
||||||
|
@ -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")
|
||||||
|
Loading…
Reference in New Issue
Block a user