Merge #913.
This commit is contained in:
parent
408a70992c
commit
0adebeed24
36 changed files with 669 additions and 58 deletions
|
|
@ -1,5 +1,6 @@
|
|||
from __future__ import unicode_literals
|
||||
from boto.ec2.blockdevicemapping import BlockDeviceType, BlockDeviceMapping
|
||||
from moto.compat import OrderedDict
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
from moto.ec2 import ec2_backends
|
||||
from moto.elb import elb_backends
|
||||
|
|
@ -284,8 +285,8 @@ class FakeAutoScalingGroup(BaseModel):
|
|||
class AutoScalingBackend(BaseBackend):
|
||||
|
||||
def __init__(self, ec2_backend, elb_backend):
|
||||
self.autoscaling_groups = {}
|
||||
self.launch_configurations = {}
|
||||
self.autoscaling_groups = OrderedDict()
|
||||
self.launch_configurations = OrderedDict()
|
||||
self.policies = {}
|
||||
self.ec2_backend = ec2_backend
|
||||
self.elb_backend = elb_backend
|
||||
|
|
|
|||
|
|
@ -40,11 +40,22 @@ class AutoScalingResponse(BaseResponse):
|
|||
|
||||
def describe_launch_configurations(self):
|
||||
names = self._get_multi_param('LaunchConfigurationNames.member')
|
||||
launch_configurations = self.autoscaling_backend.describe_launch_configurations(
|
||||
names)
|
||||
all_launch_configurations = self.autoscaling_backend.describe_launch_configurations(names)
|
||||
marker = self._get_param('NextToken')
|
||||
all_names = [lc.name for lc in all_launch_configurations]
|
||||
if marker:
|
||||
start = all_names.index(marker) + 1
|
||||
else:
|
||||
start = 0
|
||||
max_records = self._get_param('MaxRecords', 50) # the default is 100, but using 50 to make testing easier
|
||||
launch_configurations_resp = all_launch_configurations[start:start + max_records]
|
||||
next_token = None
|
||||
if len(all_launch_configurations) > start + max_records:
|
||||
next_token = launch_configurations_resp[-1].name
|
||||
|
||||
template = self.response_template(
|
||||
DESCRIBE_LAUNCH_CONFIGURATIONS_TEMPLATE)
|
||||
return template.render(launch_configurations=launch_configurations)
|
||||
return template.render(launch_configurations=launch_configurations_resp, next_token=next_token)
|
||||
|
||||
def delete_launch_configuration(self):
|
||||
launch_configurations_name = self.querystring.get(
|
||||
|
|
@ -78,9 +89,22 @@ class AutoScalingResponse(BaseResponse):
|
|||
|
||||
def describe_auto_scaling_groups(self):
|
||||
names = self._get_multi_param("AutoScalingGroupNames.member")
|
||||
groups = self.autoscaling_backend.describe_autoscaling_groups(names)
|
||||
token = self._get_param("NextToken")
|
||||
all_groups = self.autoscaling_backend.describe_autoscaling_groups(names)
|
||||
all_names = [group.name for group in all_groups]
|
||||
if token:
|
||||
start = all_names.index(token) + 1
|
||||
else:
|
||||
start = 0
|
||||
max_records = self._get_param("MaxRecords", 50)
|
||||
if max_records > 100:
|
||||
raise ValueError
|
||||
groups = all_groups[start:start + max_records]
|
||||
next_token = None
|
||||
if max_records and len(all_groups) > start + max_records:
|
||||
next_token = groups[-1].name
|
||||
template = self.response_template(DESCRIBE_AUTOSCALING_GROUPS_TEMPLATE)
|
||||
return template.render(groups=groups)
|
||||
return template.render(groups=groups, next_token=next_token)
|
||||
|
||||
def update_auto_scaling_group(self):
|
||||
self.autoscaling_backend.update_autoscaling_group(
|
||||
|
|
@ -239,6 +263,9 @@ DESCRIBE_LAUNCH_CONFIGURATIONS_TEMPLATE = """<DescribeLaunchConfigurationsRespon
|
|||
</member>
|
||||
{% endfor %}
|
||||
</LaunchConfigurations>
|
||||
{% if next_token %}
|
||||
<NextToken>{{ next_token }}</NextToken>
|
||||
{% endif %}
|
||||
</DescribeLaunchConfigurationsResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>d05a22f8-b690-11e2-bf8e-2113fEXAMPLE</RequestId>
|
||||
|
|
@ -331,6 +358,9 @@ DESCRIBE_AUTOSCALING_GROUPS_TEMPLATE = """<DescribeAutoScalingGroupsResponse xml
|
|||
</member>
|
||||
{% endfor %}
|
||||
</AutoScalingGroups>
|
||||
{% if next_token %}
|
||||
<NextToken>{{ next_token }}</NextToken>
|
||||
{% endif %}
|
||||
</DescribeAutoScalingGroupsResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>0f02a07d-b677-11e2-9eb0-dd50EXAMPLE</RequestId>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import json
|
|||
import uuid
|
||||
|
||||
import boto.cloudformation
|
||||
from moto.compat import OrderedDict
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
|
||||
from .parsing import ResourceMap, OutputMap
|
||||
|
|
@ -121,7 +122,7 @@ class FakeEvent(BaseModel):
|
|||
class CloudFormationBackend(BaseBackend):
|
||||
|
||||
def __init__(self):
|
||||
self.stacks = {}
|
||||
self.stacks = OrderedDict()
|
||||
self.deleted_stacks = {}
|
||||
|
||||
def create_stack(self, name, template, parameters, region_name, notification_arns=None, tags=None, role_arn=None):
|
||||
|
|
@ -152,7 +153,7 @@ class CloudFormationBackend(BaseBackend):
|
|||
return [stack]
|
||||
raise ValidationError(name_or_stack_id)
|
||||
else:
|
||||
return stacks
|
||||
return list(stacks)
|
||||
|
||||
def list_stacks(self):
|
||||
return self.stacks.values()
|
||||
|
|
|
|||
|
|
@ -72,10 +72,20 @@ class CloudFormationResponse(BaseResponse):
|
|||
stack_name_or_id = None
|
||||
if self._get_param('StackName'):
|
||||
stack_name_or_id = self.querystring.get('StackName')[0]
|
||||
token = self._get_param('NextToken')
|
||||
stacks = self.cloudformation_backend.describe_stacks(stack_name_or_id)
|
||||
|
||||
stack_ids = [stack.stack_id for stack in stacks]
|
||||
if token:
|
||||
start = stack_ids.index(token) + 1
|
||||
else:
|
||||
start = 0
|
||||
max_results = 50 # using this to mske testing of paginated stacks more convenient than default 1 MB
|
||||
stacks_resp = stacks[start:start + max_results]
|
||||
next_token = None
|
||||
if len(stacks) > (start + max_results):
|
||||
next_token = stacks_resp[-1].stack_id
|
||||
template = self.response_template(DESCRIBE_STACKS_TEMPLATE)
|
||||
return template.render(stacks=stacks)
|
||||
return template.render(stacks=stacks_resp, next_token=next_token)
|
||||
|
||||
def describe_stack_resource(self):
|
||||
stack_name = self._get_param('StackName')
|
||||
|
|
@ -270,6 +280,9 @@ DESCRIBE_STACKS_TEMPLATE = """<DescribeStacksResponse>
|
|||
</member>
|
||||
{% endfor %}
|
||||
</Stacks>
|
||||
{% if next_token %}
|
||||
<NextToken>{{ next_token }}</NextToken>
|
||||
{% endif %}
|
||||
</DescribeStacksResult>
|
||||
</DescribeStacksResponse>"""
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ from __future__ import unicode_literals
|
|||
|
||||
import datetime
|
||||
import boto.datapipeline
|
||||
from moto.compat import OrderedDict
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
from .utils import get_random_pipeline_id, remove_capitalization_of_dict_keys
|
||||
|
||||
|
|
@ -111,7 +112,7 @@ class Pipeline(BaseModel):
|
|||
class DataPipelineBackend(BaseBackend):
|
||||
|
||||
def __init__(self):
|
||||
self.pipelines = {}
|
||||
self.pipelines = OrderedDict()
|
||||
|
||||
def create_pipeline(self, name, unique_id, **kwargs):
|
||||
pipeline = Pipeline(name, unique_id, **kwargs)
|
||||
|
|
|
|||
|
|
@ -31,12 +31,25 @@ class DataPipelineResponse(BaseResponse):
|
|||
})
|
||||
|
||||
def list_pipelines(self):
|
||||
pipelines = self.datapipeline_backend.list_pipelines()
|
||||
pipelines = list(self.datapipeline_backend.list_pipelines())
|
||||
pipeline_ids = [pipeline.pipeline_id for pipeline in pipelines]
|
||||
max_pipelines = 50
|
||||
marker = self.parameters.get('marker')
|
||||
if marker:
|
||||
start = pipeline_ids.index(marker) + 1
|
||||
else:
|
||||
start = 0
|
||||
pipelines_resp = pipelines[start:start + max_pipelines]
|
||||
has_more_results = False
|
||||
marker = None
|
||||
if start + max_pipelines < len(pipeline_ids) - 1:
|
||||
has_more_results = True
|
||||
marker = pipelines_resp[-1].pipeline_id
|
||||
return json.dumps({
|
||||
"hasMoreResults": False,
|
||||
"marker": None,
|
||||
"hasMoreResults": has_more_results,
|
||||
"marker": marker,
|
||||
"pipelineIdList": [
|
||||
pipeline.to_meta_json() for pipeline in pipelines
|
||||
pipeline.to_meta_json() for pipeline in pipelines_resp
|
||||
]
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -200,6 +200,11 @@ class Table(BaseModel):
|
|||
self.global_indexes = global_indexes if global_indexes else []
|
||||
self.created_at = datetime.datetime.utcnow()
|
||||
self.items = defaultdict(dict)
|
||||
self.table_arn = self._generate_arn(table_name)
|
||||
self.tags = []
|
||||
|
||||
def _generate_arn(self, name):
|
||||
return 'arn:aws:dynamodb:us-east-1:123456789011:table/' + name
|
||||
|
||||
def describe(self, base_key='TableDescription'):
|
||||
results = {
|
||||
|
|
@ -209,11 +214,12 @@ class Table(BaseModel):
|
|||
'TableSizeBytes': 0,
|
||||
'TableName': self.name,
|
||||
'TableStatus': 'ACTIVE',
|
||||
'TableArn': self.table_arn,
|
||||
'KeySchema': self.schema,
|
||||
'ItemCount': len(self),
|
||||
'CreationDateTime': unix_time(self.created_at),
|
||||
'GlobalSecondaryIndexes': [index for index in self.global_indexes],
|
||||
'LocalSecondaryIndexes': [index for index in self.indexes]
|
||||
'LocalSecondaryIndexes': [index for index in self.indexes],
|
||||
}
|
||||
}
|
||||
return results
|
||||
|
|
@ -505,6 +511,18 @@ class DynamoDBBackend(BaseBackend):
|
|||
def delete_table(self, name):
|
||||
return self.tables.pop(name, None)
|
||||
|
||||
def tag_resource(self, table_arn, tags):
|
||||
for table in self.tables:
|
||||
if self.tables[table].table_arn == table_arn:
|
||||
self.tables[table].tags.extend(tags)
|
||||
|
||||
def list_tags_of_resource(self, table_arn):
|
||||
required_table = None
|
||||
for table in self.tables:
|
||||
if self.tables[table].table_arn == table_arn:
|
||||
required_table = self.tables[table]
|
||||
return required_table.tags
|
||||
|
||||
def update_table_throughput(self, name, throughput):
|
||||
table = self.tables[name]
|
||||
table.throughput = throughput
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ class DynamoHandler(BaseResponse):
|
|||
|
||||
def list_tables(self):
|
||||
body = self.body
|
||||
limit = body.get('Limit')
|
||||
limit = body.get('Limit', 100)
|
||||
if body.get("ExclusiveStartTableName"):
|
||||
last = body.get("ExclusiveStartTableName")
|
||||
start = list(dynamodb_backend2.tables.keys()).index(last) + 1
|
||||
|
|
@ -124,6 +124,35 @@ class DynamoHandler(BaseResponse):
|
|||
er = 'com.amazonaws.dynamodb.v20111205#ResourceNotFoundException'
|
||||
return self.error(er)
|
||||
|
||||
def tag_resource(self):
|
||||
tags = self.body['Tags']
|
||||
table_arn = self.body['ResourceArn']
|
||||
dynamodb_backend2.tag_resource(table_arn, tags)
|
||||
return json.dumps({})
|
||||
|
||||
def list_tags_of_resource(self):
|
||||
try:
|
||||
table_arn = self.body['ResourceArn']
|
||||
all_tags = dynamodb_backend2.list_tags_of_resource(table_arn)
|
||||
all_tag_keys = [tag['Key'] for tag in all_tags]
|
||||
marker = self.body.get('NextToken')
|
||||
if marker:
|
||||
start = all_tag_keys.index(marker) + 1
|
||||
else:
|
||||
start = 0
|
||||
max_items = 10 # there is no default, but using 10 to make testing easier
|
||||
tags_resp = all_tags[start:start + max_items]
|
||||
next_marker = None
|
||||
if len(all_tags) > start + max_items:
|
||||
next_marker = tags_resp[-1]['Key']
|
||||
if next_marker:
|
||||
return json.dumps({'Tags': tags_resp,
|
||||
'NextToken': next_marker})
|
||||
return json.dumps({'Tags': tags_resp})
|
||||
except AttributeError:
|
||||
er = 'com.amazonaws.dynamodb.v20111205#ResourceNotFoundException'
|
||||
return self.error(er)
|
||||
|
||||
def update_table(self):
|
||||
name = self.body['TableName']
|
||||
if 'GlobalSecondaryIndexUpdates' in self.body:
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ from boto.ec2.blockdevicemapping import BlockDeviceMapping, BlockDeviceType
|
|||
from boto.ec2.spotinstancerequest import SpotInstanceRequest as BotoSpotRequest
|
||||
from boto.ec2.launchspecification import LaunchSpecification
|
||||
|
||||
from moto.compat import OrderedDict
|
||||
from moto.core import BaseBackend
|
||||
from moto.core.models import Model, BaseModel
|
||||
from moto.core.utils import iso_8601_datetime_with_milliseconds, camelcase_to_underscores
|
||||
|
|
@ -618,7 +619,7 @@ class Instance(TaggedEC2Resource, BotoInstance):
|
|||
class InstanceBackend(object):
|
||||
|
||||
def __init__(self):
|
||||
self.reservations = {}
|
||||
self.reservations = OrderedDict()
|
||||
super(InstanceBackend, self).__init__()
|
||||
|
||||
def get_instance(self, instance_id):
|
||||
|
|
@ -1049,12 +1050,22 @@ class AmiBackend(object):
|
|||
self.amis[ami_id] = ami
|
||||
return ami
|
||||
|
||||
def describe_images(self, ami_ids=(), filters=None):
|
||||
def describe_images(self, ami_ids=(), filters=None, exec_users=None):
|
||||
images = []
|
||||
if exec_users:
|
||||
for ami_id in self.amis:
|
||||
found = False
|
||||
for user_id in exec_users:
|
||||
if user_id in self.amis[ami_id].launch_permission_users:
|
||||
found = True
|
||||
if found:
|
||||
images.append(self.amis[ami_id])
|
||||
if images == []:
|
||||
return images
|
||||
if filters:
|
||||
images = self.amis.values()
|
||||
images = images or self.amis.values()
|
||||
return generic_filter(filters, images)
|
||||
else:
|
||||
images = []
|
||||
for ami_id in ami_ids:
|
||||
if ami_id in self.amis:
|
||||
images.append(self.amis[ami_id])
|
||||
|
|
@ -1766,6 +1777,9 @@ class Snapshot(TaggedEC2Resource):
|
|||
if filter_name == 'encrypted':
|
||||
return str(self.encrypted).lower()
|
||||
|
||||
if filter_name == 'status':
|
||||
return self.status
|
||||
|
||||
filter_value = super(Snapshot, self).get_filter_value(filter_name)
|
||||
|
||||
if filter_value is None:
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
from __future__ import unicode_literals
|
||||
from moto.core.responses import BaseResponse
|
||||
from moto.ec2.utils import instance_ids_from_querystring, image_ids_from_querystring, \
|
||||
filters_from_querystring, sequence_from_querystring
|
||||
filters_from_querystring, sequence_from_querystring, executable_users_from_querystring
|
||||
|
||||
|
||||
class AmisResponse(BaseResponse):
|
||||
|
|
@ -43,8 +43,9 @@ class AmisResponse(BaseResponse):
|
|||
def describe_images(self):
|
||||
ami_ids = image_ids_from_querystring(self.querystring)
|
||||
filters = filters_from_querystring(self.querystring)
|
||||
exec_users = executable_users_from_querystring(self.querystring)
|
||||
images = self.ec2_backend.describe_images(
|
||||
ami_ids=ami_ids, filters=filters)
|
||||
ami_ids=ami_ids, filters=filters, exec_users=exec_users)
|
||||
template = self.response_template(DESCRIBE_IMAGES_RESPONSE)
|
||||
return template.render(images=images)
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ class InstanceResponse(BaseResponse):
|
|||
def describe_instances(self):
|
||||
filter_dict = filters_from_querystring(self.querystring)
|
||||
instance_ids = instance_ids_from_querystring(self.querystring)
|
||||
token = self._get_param("NextToken")
|
||||
if instance_ids:
|
||||
reservations = self.ec2_backend.get_reservations_by_instance_ids(
|
||||
instance_ids, filters=filter_dict)
|
||||
|
|
@ -18,8 +19,18 @@ class InstanceResponse(BaseResponse):
|
|||
reservations = self.ec2_backend.all_reservations(
|
||||
make_copy=True, filters=filter_dict)
|
||||
|
||||
reservation_ids = [reservation.id for reservation in reservations]
|
||||
if token:
|
||||
start = reservation_ids.index(token) + 1
|
||||
else:
|
||||
start = 0
|
||||
max_results = int(self._get_param('MaxResults', 100))
|
||||
reservations_resp = reservations[start:start + max_results]
|
||||
next_token = None
|
||||
if max_results and len(reservations) > (start + max_results):
|
||||
next_token = reservations_resp[-1].id
|
||||
template = self.response_template(EC2_DESCRIBE_INSTANCES)
|
||||
return template.render(reservations=reservations)
|
||||
return template.render(reservations=reservations_resp, next_token=next_token)
|
||||
|
||||
def run_instances(self):
|
||||
min_count = int(self.querystring.get('MinCount', ['1'])[0])
|
||||
|
|
@ -492,6 +503,9 @@ EC2_DESCRIBE_INSTANCES = """<DescribeInstancesResponse xmlns="http://ec2.amazona
|
|||
</item>
|
||||
{% endfor %}
|
||||
</reservationSet>
|
||||
{% if next_token %}
|
||||
<nextToken>{{ next_token }}</nextToken>
|
||||
{% endif %}
|
||||
</DescribeInstancesResponse>"""
|
||||
|
||||
EC2_TERMINATE_INSTANCES = """
|
||||
|
|
|
|||
|
|
@ -190,6 +190,14 @@ def image_ids_from_querystring(querystring_dict):
|
|||
return image_ids
|
||||
|
||||
|
||||
def executable_users_from_querystring(querystring_dict):
|
||||
user_ids = []
|
||||
for key, value in querystring_dict.items():
|
||||
if 'ExecutableBy' in key:
|
||||
user_ids.append(value[0])
|
||||
return user_ids
|
||||
|
||||
|
||||
def route_table_ids_from_querystring(querystring_dict):
|
||||
route_table_ids = []
|
||||
for key, value in querystring_dict.items():
|
||||
|
|
@ -383,7 +391,8 @@ filter_dict_attribute_mapping = {
|
|||
'private-ip-address': 'private_ip',
|
||||
'ip-address': 'public_ip',
|
||||
'availability-zone': 'placement',
|
||||
'architecture': 'architecture'
|
||||
'architecture': 'architecture',
|
||||
'image-id': 'image_id'
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -461,6 +470,9 @@ def filter_internet_gateways(igws, filter_dict):
|
|||
def is_filter_matching(obj, filter, filter_value):
|
||||
value = obj.get_filter_value(filter)
|
||||
|
||||
if not filter_value:
|
||||
return False
|
||||
|
||||
if isinstance(value, six.string_types):
|
||||
if not isinstance(filter_value, list):
|
||||
filter_value = [filter_value]
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ from boto.ec2.elb.policies import (
|
|||
Policies,
|
||||
OtherPolicy,
|
||||
)
|
||||
from moto.compat import OrderedDict
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
from moto.ec2.models import ec2_backends
|
||||
from .exceptions import (
|
||||
|
|
@ -223,7 +224,7 @@ class ELBBackend(BaseBackend):
|
|||
|
||||
def __init__(self, region_name=None):
|
||||
self.region_name = region_name
|
||||
self.load_balancers = {}
|
||||
self.load_balancers = OrderedDict()
|
||||
|
||||
def reset(self):
|
||||
region_name = self.region_name
|
||||
|
|
|
|||
|
|
@ -52,9 +52,21 @@ class ELBResponse(BaseResponse):
|
|||
|
||||
def describe_load_balancers(self):
|
||||
names = self._get_multi_param("LoadBalancerNames.member")
|
||||
load_balancers = self.elb_backend.describe_load_balancers(names)
|
||||
all_load_balancers = list(self.elb_backend.describe_load_balancers(names))
|
||||
marker = self._get_param('Marker')
|
||||
all_names = [balancer.name for balancer in all_load_balancers]
|
||||
if marker:
|
||||
start = all_names.index(marker) + 1
|
||||
else:
|
||||
start = 0
|
||||
page_size = self._get_param('PageSize', 50) # the default is 400, but using 50 to make testing easier
|
||||
load_balancers_resp = all_load_balancers[start:start + page_size]
|
||||
next_marker = None
|
||||
if len(all_load_balancers) > start + page_size:
|
||||
next_marker = load_balancers_resp[-1].name
|
||||
|
||||
template = self.response_template(DESCRIBE_LOAD_BALANCERS_TEMPLATE)
|
||||
return template.render(load_balancers=load_balancers)
|
||||
return template.render(load_balancers=load_balancers_resp, marker=next_marker)
|
||||
|
||||
def delete_load_balancer_listeners(self):
|
||||
load_balancer_name = self._get_param('LoadBalancerName')
|
||||
|
|
@ -493,6 +505,9 @@ DESCRIBE_LOAD_BALANCERS_TEMPLATE = """<DescribeLoadBalancersResponse xmlns="http
|
|||
</member>
|
||||
{% endfor %}
|
||||
</LoadBalancerDescriptions>
|
||||
{% if marker %}
|
||||
<NextMarker>{{ marker }}</NextMarker>
|
||||
{% endif %}
|
||||
</DescribeLoadBalancersResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>f9880f01-7852-629d-a6c3-3ae2-666a409287e6dc0c</RequestId>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import boto.emr
|
|||
import pytz
|
||||
from dateutil.parser import parse as dtparse
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
|
||||
from moto.emr.exceptions import EmrError
|
||||
from .utils import random_instance_group_id, random_cluster_id, random_step_id
|
||||
|
||||
|
||||
|
|
@ -324,7 +324,9 @@ class ElasticMapReduceBackend(BaseBackend):
|
|||
return step
|
||||
|
||||
def get_cluster(self, cluster_id):
|
||||
return self.clusters[cluster_id]
|
||||
if cluster_id in self.clusters:
|
||||
return self.clusters[cluster_id]
|
||||
raise EmrError('ResourceNotFoundException', '', 'error_json')
|
||||
|
||||
def get_instance_groups(self, instance_group_ids):
|
||||
return [
|
||||
|
|
|
|||
|
|
@ -269,7 +269,7 @@ class DeliveryStream(BaseModel):
|
|||
class KinesisBackend(BaseBackend):
|
||||
|
||||
def __init__(self):
|
||||
self.streams = {}
|
||||
self.streams = OrderedDict()
|
||||
self.delivery_streams = {}
|
||||
|
||||
def create_stream(self, stream_name, shard_count, region):
|
||||
|
|
|
|||
|
|
@ -35,10 +35,24 @@ class KinesisResponse(BaseResponse):
|
|||
|
||||
def list_streams(self):
|
||||
streams = self.kinesis_backend.list_streams()
|
||||
stream_names = [stream.stream_name for stream in streams]
|
||||
max_streams = self._get_param('Limit', 10)
|
||||
try:
|
||||
token = self.parameters.get('ExclusiveStartStreamName')
|
||||
except ValueError:
|
||||
token = self._get_param('ExclusiveStartStreamName')
|
||||
if token:
|
||||
start = stream_names.index(token) + 1
|
||||
else:
|
||||
start = 0
|
||||
streams_resp = stream_names[start:start + max_streams]
|
||||
has_more_streams = False
|
||||
if start + max_streams < len(stream_names):
|
||||
has_more_streams = True
|
||||
|
||||
return json.dumps({
|
||||
"HasMoreStreams": False,
|
||||
"StreamNames": [stream.stream_name for stream in streams],
|
||||
"HasMoreStreams": has_more_streams,
|
||||
"StreamNames": streams_resp
|
||||
})
|
||||
|
||||
def delete_stream(self):
|
||||
|
|
|
|||
|
|
@ -88,9 +88,21 @@ class RDSResponse(BaseResponse):
|
|||
|
||||
def describe_db_instances(self):
|
||||
db_instance_identifier = self._get_param('DBInstanceIdentifier')
|
||||
databases = self.backend.describe_databases(db_instance_identifier)
|
||||
all_instances = list(self.backend.describe_databases(db_instance_identifier))
|
||||
marker = self._get_param('Marker')
|
||||
all_ids = [instance.db_instance_identifier for instance in all_instances]
|
||||
if marker:
|
||||
start = all_ids.index(marker) + 1
|
||||
else:
|
||||
start = 0
|
||||
page_size = self._get_param('MaxRecords', 50) # the default is 100, but using 50 to make testing easier
|
||||
instances_resp = all_instances[start:start + page_size]
|
||||
next_marker = None
|
||||
if len(all_instances) > start + page_size:
|
||||
next_marker = instances_resp[-1].db_instance_identifier
|
||||
|
||||
template = self.response_template(DESCRIBE_DATABASES_TEMPLATE)
|
||||
return template.render(databases=databases)
|
||||
return template.render(databases=instances_resp, marker=next_marker)
|
||||
|
||||
def modify_db_instance(self):
|
||||
db_instance_identifier = self._get_param('DBInstanceIdentifier')
|
||||
|
|
@ -187,6 +199,9 @@ DESCRIBE_DATABASES_TEMPLATE = """<DescribeDBInstancesResponse xmlns="http://rds.
|
|||
{{ database.to_xml() }}
|
||||
{% endfor %}
|
||||
</DBInstances>
|
||||
{% if marker %}
|
||||
<Marker>{{ marker }}</Marker>
|
||||
{% endif %}
|
||||
</DescribeDBInstancesResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>01b2685a-b978-11d3-f272-7cd6cce12cc5</RequestId>
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import boto.rds2
|
|||
from jinja2 import Template
|
||||
from re import compile as re_compile
|
||||
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
|
||||
from moto.compat import OrderedDict
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
from moto.core.utils import get_random_hex
|
||||
from moto.ec2.models import ec2_backends
|
||||
|
|
@ -586,7 +587,7 @@ class RDS2Backend(BaseBackend):
|
|||
self.region = region
|
||||
self.arn_regex = re_compile(
|
||||
r'^arn:aws:rds:.*:[0-9]*:(db|es|og|pg|ri|secgrp|snapshot|subgrp):.*$')
|
||||
self.databases = {}
|
||||
self.databases = OrderedDict()
|
||||
self.db_parameter_groups = {}
|
||||
self.option_groups = {}
|
||||
self.security_groups = {}
|
||||
|
|
|
|||
|
|
@ -114,9 +114,21 @@ class RDS2Response(BaseResponse):
|
|||
|
||||
def describe_db_instances(self):
|
||||
db_instance_identifier = self._get_param('DBInstanceIdentifier')
|
||||
databases = self.backend.describe_databases(db_instance_identifier)
|
||||
all_instances = list(self.backend.describe_databases(db_instance_identifier))
|
||||
marker = self._get_param('Marker')
|
||||
all_ids = [instance.db_instance_identifier for instance in all_instances]
|
||||
if marker:
|
||||
start = all_ids.index(marker) + 1
|
||||
else:
|
||||
start = 0
|
||||
page_size = self._get_param('MaxRecords', 50) # the default is 100, but using 50 to make testing easier
|
||||
instances_resp = all_instances[start:start + page_size]
|
||||
next_marker = None
|
||||
if len(all_instances) > start + page_size:
|
||||
next_marker = instances_resp[-1].db_instance_identifier
|
||||
|
||||
template = self.response_template(DESCRIBE_DATABASES_TEMPLATE)
|
||||
return template.render(databases=databases)
|
||||
return template.render(databases=instances_resp, marker=next_marker)
|
||||
|
||||
def modify_db_instance(self):
|
||||
db_instance_identifier = self._get_param('DBInstanceIdentifier')
|
||||
|
|
@ -348,6 +360,9 @@ DESCRIBE_DATABASES_TEMPLATE = """<DescribeDBInstancesResponse xmlns="http://rds.
|
|||
{{ database.to_xml() }}
|
||||
{%- endfor -%}
|
||||
</DBInstances>
|
||||
{% if marker %}
|
||||
<Marker>{{ marker }}</Marker>
|
||||
{% endif %}
|
||||
</DescribeDBInstancesResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>523e3218-afc7-11c3-90f5-f90431260ab4</RequestId>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue