commit
adf41244cd
@ -203,26 +203,26 @@
|
|||||||
- [ ] set_load_balancer_policies_for_backend_server
|
- [ ] set_load_balancer_policies_for_backend_server
|
||||||
- [X] set_load_balancer_policies_of_listener
|
- [X] set_load_balancer_policies_of_listener
|
||||||
|
|
||||||
## dynamodb - 36% implemented
|
## dynamodb - 100% implemented (is dynamodbv2)
|
||||||
- [ ] batch_get_item
|
- [X] batch_get_item
|
||||||
- [ ] batch_write_item
|
- [X] batch_write_item
|
||||||
- [X] create_table
|
- [X] create_table
|
||||||
- [X] delete_item
|
- [X] delete_item
|
||||||
- [X] delete_table
|
- [X] delete_table
|
||||||
- [ ] describe_limits
|
- [X] describe_limits
|
||||||
- [ ] describe_table
|
- [X] describe_table
|
||||||
- [ ] describe_time_to_live
|
- [X] describe_time_to_live
|
||||||
- [X] get_item
|
- [X] get_item
|
||||||
- [ ] list_tables
|
- [X] list_tables
|
||||||
- [ ] list_tags_of_resource
|
- [X] list_tags_of_resource
|
||||||
- [X] put_item
|
- [X] put_item
|
||||||
- [X] query
|
- [X] query
|
||||||
- [X] scan
|
- [X] scan
|
||||||
- [ ] tag_resource
|
- [X] tag_resource
|
||||||
- [ ] untag_resource
|
- [X] untag_resource
|
||||||
- [ ] update_item
|
- [X] update_item
|
||||||
- [ ] update_table
|
- [X] update_table
|
||||||
- [ ] update_time_to_live
|
- [X] update_time_to_live
|
||||||
|
|
||||||
## cloudhsmv2 - 0% implemented
|
## cloudhsmv2 - 0% implemented
|
||||||
- [ ] create_cluster
|
- [ ] create_cluster
|
||||||
@ -917,13 +917,13 @@
|
|||||||
- [ ] unpeer_vpc
|
- [ ] unpeer_vpc
|
||||||
- [ ] update_domain_entry
|
- [ ] update_domain_entry
|
||||||
|
|
||||||
## xray - 0% implemented
|
## xray - 100% implemented
|
||||||
- [ ] batch_get_traces
|
- [X] batch_get_traces
|
||||||
- [ ] get_service_graph
|
- [X] get_service_graph
|
||||||
- [ ] get_trace_graph
|
- [X] get_trace_graph
|
||||||
- [ ] get_trace_summaries
|
- [X] get_trace_summaries
|
||||||
- [ ] put_telemetry_records
|
- [X] put_telemetry_records
|
||||||
- [ ] put_trace_segments
|
- [X] put_trace_segments
|
||||||
|
|
||||||
## ec2 - 41% implemented
|
## ec2 - 41% implemented
|
||||||
- [ ] accept_reserved_instances_exchange_quote
|
- [ ] accept_reserved_instances_exchange_quote
|
||||||
@ -1483,10 +1483,10 @@
|
|||||||
- [ ] post_content
|
- [ ] post_content
|
||||||
- [ ] post_text
|
- [ ] post_text
|
||||||
|
|
||||||
## ecs - 74% implemented
|
## ecs - 90% implemented
|
||||||
- [X] create_cluster
|
- [X] create_cluster
|
||||||
- [X] create_service
|
- [X] create_service
|
||||||
- [ ] delete_attributes
|
- [X] delete_attributes
|
||||||
- [X] delete_cluster
|
- [X] delete_cluster
|
||||||
- [X] delete_service
|
- [X] delete_service
|
||||||
- [X] deregister_container_instance
|
- [X] deregister_container_instance
|
||||||
@ -1496,15 +1496,15 @@
|
|||||||
- [X] describe_services
|
- [X] describe_services
|
||||||
- [X] describe_task_definition
|
- [X] describe_task_definition
|
||||||
- [X] describe_tasks
|
- [X] describe_tasks
|
||||||
- [ ] discover_poll_endpoint
|
- [X] discover_poll_endpoint
|
||||||
- [ ] list_attributes
|
- [X] list_attributes
|
||||||
- [X] list_clusters
|
- [X] list_clusters
|
||||||
- [X] list_container_instances
|
- [X] list_container_instances
|
||||||
- [X] list_services
|
- [X] list_services
|
||||||
- [ ] list_task_definition_families
|
- [X] list_task_definition_families
|
||||||
- [X] list_task_definitions
|
- [X] list_task_definitions
|
||||||
- [X] list_tasks
|
- [X] list_tasks
|
||||||
- [ ] put_attributes
|
- [X] put_attributes
|
||||||
- [X] register_container_instance
|
- [X] register_container_instance
|
||||||
- [X] register_task_definition
|
- [X] register_task_definition
|
||||||
- [X] run_task
|
- [X] run_task
|
||||||
@ -1699,17 +1699,17 @@
|
|||||||
- [ ] start_db_instance
|
- [ ] start_db_instance
|
||||||
- [ ] stop_db_instance
|
- [ ] stop_db_instance
|
||||||
|
|
||||||
## acm - 50% implemented
|
## acm - 100% implemented
|
||||||
- [X] add_tags_to_certificate
|
- [X] add_tags_to_certificate
|
||||||
- [X] delete_certificate
|
- [X] delete_certificate
|
||||||
- [ ] describe_certificate
|
- [X] describe_certificate
|
||||||
- [X] get_certificate
|
- [X] get_certificate
|
||||||
- [ ] import_certificate
|
- [X] import_certificate
|
||||||
- [ ] list_certificates
|
- [X] list_certificates
|
||||||
- [ ] list_tags_for_certificate
|
- [X] list_tags_for_certificate
|
||||||
- [X] remove_tags_from_certificate
|
- [X] remove_tags_from_certificate
|
||||||
- [X] request_certificate
|
- [X] request_certificate
|
||||||
- [ ] resend_validation_email
|
- [X] resend_validation_email
|
||||||
|
|
||||||
## elasticache - 0% implemented
|
## elasticache - 0% implemented
|
||||||
- [ ] add_tags_to_resource
|
- [ ] add_tags_to_resource
|
||||||
@ -1853,31 +1853,31 @@
|
|||||||
- [ ] refresh_trusted_advisor_check
|
- [ ] refresh_trusted_advisor_check
|
||||||
- [ ] resolve_case
|
- [ ] resolve_case
|
||||||
|
|
||||||
## lambda - 0% implemented
|
## lambda - 32% implemented
|
||||||
- [ ] add_permission
|
- [ ] add_permission
|
||||||
- [ ] create_alias
|
- [ ] create_alias
|
||||||
- [ ] create_event_source_mapping
|
- [ ] create_event_source_mapping
|
||||||
- [ ] create_function
|
- [X] create_function
|
||||||
- [ ] delete_alias
|
- [ ] delete_alias
|
||||||
- [ ] delete_event_source_mapping
|
- [ ] delete_event_source_mapping
|
||||||
- [ ] delete_function
|
- [X] delete_function
|
||||||
- [ ] get_account_settings
|
- [ ] get_account_settings
|
||||||
- [ ] get_alias
|
- [ ] get_alias
|
||||||
- [ ] get_event_source_mapping
|
- [ ] get_event_source_mapping
|
||||||
- [ ] get_function
|
- [X] get_function
|
||||||
- [ ] get_function_configuration
|
- [ ] get_function_configuration
|
||||||
- [ ] get_policy
|
- [X] get_policy
|
||||||
- [ ] invoke
|
- [X] invoke
|
||||||
- [ ] invoke_async
|
- [ ] invoke_async
|
||||||
- [ ] list_aliases
|
- [ ] list_aliases
|
||||||
- [ ] list_event_source_mappings
|
- [ ] list_event_source_mappings
|
||||||
- [ ] list_functions
|
- [X] list_functions
|
||||||
- [ ] list_tags
|
- [X] list_tags
|
||||||
- [ ] list_versions_by_function
|
- [ ] list_versions_by_function
|
||||||
- [ ] publish_version
|
- [ ] publish_version
|
||||||
- [ ] remove_permission
|
- [ ] remove_permission
|
||||||
- [ ] tag_resource
|
- [X] tag_resource
|
||||||
- [ ] untag_resource
|
- [X] untag_resource
|
||||||
- [ ] update_alias
|
- [ ] update_alias
|
||||||
- [ ] update_event_source_mapping
|
- [ ] update_event_source_mapping
|
||||||
- [ ] update_function_code
|
- [ ] update_function_code
|
||||||
@ -2456,8 +2456,8 @@
|
|||||||
- [ ] update_distribution
|
- [ ] update_distribution
|
||||||
- [ ] update_streaming_distribution
|
- [ ] update_streaming_distribution
|
||||||
|
|
||||||
## elbv2 - 54% implemented
|
## elbv2 - 100% implemented
|
||||||
- [ ] add_tags
|
- [X] add_tags
|
||||||
- [X] create_listener
|
- [X] create_listener
|
||||||
- [X] create_load_balancer
|
- [X] create_load_balancer
|
||||||
- [X] create_rule
|
- [X] create_rule
|
||||||
@ -2467,27 +2467,27 @@
|
|||||||
- [X] delete_rule
|
- [X] delete_rule
|
||||||
- [X] delete_target_group
|
- [X] delete_target_group
|
||||||
- [X] deregister_targets
|
- [X] deregister_targets
|
||||||
- [ ] describe_account_limits
|
- [X] describe_account_limits
|
||||||
- [X] describe_listeners
|
- [X] describe_listeners
|
||||||
- [ ] describe_load_balancer_attributes
|
- [X] describe_load_balancer_attributes
|
||||||
- [X] describe_load_balancers
|
- [X] describe_load_balancers
|
||||||
- [X] describe_rules
|
- [X] describe_rules
|
||||||
- [ ] describe_ssl_policies
|
- [X] describe_ssl_policies
|
||||||
- [ ] describe_tags
|
- [X] describe_tags
|
||||||
- [ ] describe_target_group_attributes
|
- [X] describe_target_group_attributes
|
||||||
- [X] describe_target_groups
|
- [X] describe_target_groups
|
||||||
- [X] describe_target_health
|
- [X] describe_target_health
|
||||||
- [ ] modify_listener
|
- [X] modify_listener
|
||||||
- [ ] modify_load_balancer_attributes
|
- [X] modify_load_balancer_attributes
|
||||||
- [X] modify_rule
|
- [X] modify_rule
|
||||||
- [ ] modify_target_group
|
- [X] modify_target_group
|
||||||
- [ ] modify_target_group_attributes
|
- [X] modify_target_group_attributes
|
||||||
- [X] register_targets
|
- [X] register_targets
|
||||||
- [ ] remove_tags
|
- [X] remove_tags
|
||||||
- [ ] set_ip_address_type
|
- [X] set_ip_address_type
|
||||||
- [X] set_rule_priorities
|
- [X] set_rule_priorities
|
||||||
- [ ] set_security_groups
|
- [X] set_security_groups
|
||||||
- [ ] set_subnets
|
- [X] set_subnets
|
||||||
|
|
||||||
## sdb - 0% implemented
|
## sdb - 0% implemented
|
||||||
- [ ] batch_delete_attributes
|
- [ ] batch_delete_attributes
|
||||||
@ -3089,20 +3089,20 @@
|
|||||||
- [ ] start_configuration_recorder
|
- [ ] start_configuration_recorder
|
||||||
- [ ] stop_configuration_recorder
|
- [ ] stop_configuration_recorder
|
||||||
|
|
||||||
## events - 73% implemented
|
## events - 100% implemented
|
||||||
- [X] delete_rule
|
- [X] delete_rule
|
||||||
- [ ] describe_event_bus
|
- [X] describe_event_bus
|
||||||
- [X] describe_rule
|
- [X] describe_rule
|
||||||
- [X] disable_rule
|
- [X] disable_rule
|
||||||
- [X] enable_rule
|
- [X] enable_rule
|
||||||
- [X] list_rule_names_by_target
|
- [X] list_rule_names_by_target
|
||||||
- [X] list_rules
|
- [X] list_rules
|
||||||
- [X] list_targets_by_rule
|
- [X] list_targets_by_rule
|
||||||
- [ ] put_events
|
- [X] put_events
|
||||||
- [ ] put_permission
|
- [X] put_permission
|
||||||
- [X] put_rule
|
- [X] put_rule
|
||||||
- [X] put_targets
|
- [X] put_targets
|
||||||
- [ ] remove_permission
|
- [X] remove_permission
|
||||||
- [X] remove_targets
|
- [X] remove_targets
|
||||||
- [X] test_event_pattern
|
- [X] test_event_pattern
|
||||||
|
|
||||||
@ -3149,24 +3149,27 @@
|
|||||||
- [ ] put_scaling_policy
|
- [ ] put_scaling_policy
|
||||||
- [ ] register_scalable_target
|
- [ ] register_scalable_target
|
||||||
|
|
||||||
## sqs - 41% implemented
|
## sqs - 100% implemented
|
||||||
- [ ] add_permission
|
- [X] add_permission
|
||||||
- [X] change_message_visibility
|
- [X] change_message_visibility
|
||||||
- [ ] change_message_visibility_batch
|
- [X] change_message_visibility_batch
|
||||||
- [X] create_queue
|
- [X] create_queue
|
||||||
- [X] delete_message
|
- [X] delete_message
|
||||||
- [ ] delete_message_batch
|
- [X] delete_message_batch
|
||||||
- [X] delete_queue
|
- [X] delete_queue
|
||||||
- [ ] get_queue_attributes
|
- [X] get_queue_attributes
|
||||||
- [ ] get_queue_url
|
- [X] get_queue_url
|
||||||
- [ ] list_dead_letter_source_queues
|
- [X] list_dead_letter_source_queues
|
||||||
- [X] list_queues
|
- [X] list_queues
|
||||||
- [X] purge_queue
|
- [X] purge_queue
|
||||||
- [ ] receive_message
|
- [X] receive_message
|
||||||
- [ ] remove_permission
|
- [X] remove_permission
|
||||||
- [X] send_message
|
- [X] send_message
|
||||||
- [ ] send_message_batch
|
- [X] send_message_batch
|
||||||
- [ ] set_queue_attributes
|
- [X] set_queue_attributes
|
||||||
|
- [X] tag_queue
|
||||||
|
- [X] untag_queue
|
||||||
|
- [X] list_queue_tags
|
||||||
|
|
||||||
## iot - 0% implemented
|
## iot - 0% implemented
|
||||||
- [ ] accept_certificate_transfer
|
- [ ] accept_certificate_transfer
|
||||||
|
10
README.md
10
README.md
@ -68,10 +68,12 @@ It gets even better! Moto isn't just for Python code and it isn't just for S3. L
|
|||||||
|------------------------------------------------------------------------------|
|
|------------------------------------------------------------------------------|
|
||||||
| Cloudwatch | @mock_cloudwatch | basic endpoints done |
|
| Cloudwatch | @mock_cloudwatch | basic endpoints done |
|
||||||
|------------------------------------------------------------------------------|
|
|------------------------------------------------------------------------------|
|
||||||
|
| CloudwatchEvents | @mock_events | all endpoints done |
|
||||||
|
|------------------------------------------------------------------------------|
|
||||||
| Data Pipeline | @mock_datapipeline| basic endpoints done |
|
| Data Pipeline | @mock_datapipeline| basic endpoints done |
|
||||||
|------------------------------------------------------------------------------|
|
|------------------------------------------------------------------------------|
|
||||||
| DynamoDB | @mock_dynamodb | core endpoints done |
|
| DynamoDB | @mock_dynamodb | core endpoints done |
|
||||||
| DynamoDB2 | @mock_dynamodb2 | core endpoints + partial indexes |
|
| DynamoDB2 | @mock_dynamodb2 | all endpoints + partial indexes |
|
||||||
|------------------------------------------------------------------------------|
|
|------------------------------------------------------------------------------|
|
||||||
| EC2 | @mock_ec2 | core endpoints done |
|
| EC2 | @mock_ec2 | core endpoints done |
|
||||||
| - AMI | | core endpoints done |
|
| - AMI | | core endpoints done |
|
||||||
@ -86,7 +88,7 @@ It gets even better! Moto isn't just for Python code and it isn't just for S3. L
|
|||||||
|------------------------------------------------------------------------------|
|
|------------------------------------------------------------------------------|
|
||||||
| ELB | @mock_elb | core endpoints done |
|
| ELB | @mock_elb | core endpoints done |
|
||||||
|------------------------------------------------------------------------------|
|
|------------------------------------------------------------------------------|
|
||||||
| ELBv2 | @mock_elbv2 | core endpoints done |
|
| ELBv2 | @mock_elbv2 | all endpoints done |
|
||||||
|------------------------------------------------------------------------------|
|
|------------------------------------------------------------------------------|
|
||||||
| EMR | @mock_emr | core endpoints done |
|
| EMR | @mock_emr | core endpoints done |
|
||||||
|------------------------------------------------------------------------------|
|
|------------------------------------------------------------------------------|
|
||||||
@ -115,7 +117,7 @@ It gets even better! Moto isn't just for Python code and it isn't just for S3. L
|
|||||||
|------------------------------------------------------------------------------|
|
|------------------------------------------------------------------------------|
|
||||||
| S3 | @mock_s3 | core endpoints done |
|
| S3 | @mock_s3 | core endpoints done |
|
||||||
|------------------------------------------------------------------------------|
|
|------------------------------------------------------------------------------|
|
||||||
| SES | @mock_ses | core endpoints done |
|
| SES | @mock_ses | all endpoints done |
|
||||||
|------------------------------------------------------------------------------|
|
|------------------------------------------------------------------------------|
|
||||||
| SNS | @mock_sns | all endpoints done |
|
| SNS | @mock_sns | all endpoints done |
|
||||||
|------------------------------------------------------------------------------|
|
|------------------------------------------------------------------------------|
|
||||||
@ -127,7 +129,7 @@ It gets even better! Moto isn't just for Python code and it isn't just for S3. L
|
|||||||
|------------------------------------------------------------------------------|
|
|------------------------------------------------------------------------------|
|
||||||
| SWF | @mock_swf | basic endpoints done |
|
| SWF | @mock_swf | basic endpoints done |
|
||||||
|------------------------------------------------------------------------------|
|
|------------------------------------------------------------------------------|
|
||||||
| X-Ray | @mock_xray | core endpoints done |
|
| X-Ray | @mock_xray | all endpoints done |
|
||||||
|------------------------------------------------------------------------------|
|
|------------------------------------------------------------------------------|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -34,6 +34,8 @@ ERROR_JSON_RESPONSE = u"""{
|
|||||||
|
|
||||||
|
|
||||||
class RESTError(HTTPException):
|
class RESTError(HTTPException):
|
||||||
|
code = 400
|
||||||
|
|
||||||
templates = {
|
templates = {
|
||||||
'single_error': SINGLE_ERROR_RESPONSE,
|
'single_error': SINGLE_ERROR_RESPONSE,
|
||||||
'error': ERROR_RESPONSE,
|
'error': ERROR_RESPONSE,
|
||||||
@ -54,7 +56,6 @@ class DryRunClientError(RESTError):
|
|||||||
|
|
||||||
|
|
||||||
class JsonRESTError(RESTError):
|
class JsonRESTError(RESTError):
|
||||||
|
|
||||||
def __init__(self, error_type, message, template='error_json', **kwargs):
|
def __init__(self, error_type, message, template='error_json', **kwargs):
|
||||||
super(JsonRESTError, self).__init__(
|
super(JsonRESTError, self).__init__(
|
||||||
error_type, message, template, **kwargs)
|
error_type, message, template, **kwargs)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
from .models import dynamodb_backend2
|
from .models import dynamodb_backends as dynamodb_backends2
|
||||||
|
from ..core.models import base_decorator, deprecated_base_decorator
|
||||||
|
|
||||||
dynamodb_backends2 = {"global": dynamodb_backend2}
|
dynamodb_backend2 = dynamodb_backends2['us-east-1']
|
||||||
mock_dynamodb2 = dynamodb_backend2.decorator
|
mock_dynamodb2 = base_decorator(dynamodb_backends2)
|
||||||
mock_dynamodb2_deprecated = dynamodb_backend2.deprecated_decorator
|
mock_dynamodb2_deprecated = deprecated_base_decorator(dynamodb_backends2)
|
||||||
|
@ -5,9 +5,11 @@ import decimal
|
|||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
import boto3
|
||||||
from moto.compat import OrderedDict
|
from moto.compat import OrderedDict
|
||||||
from moto.core import BaseBackend, BaseModel
|
from moto.core import BaseBackend, BaseModel
|
||||||
from moto.core.utils import unix_time
|
from moto.core.utils import unix_time
|
||||||
|
from moto.core.exceptions import JsonRESTError
|
||||||
from .comparisons import get_comparison_func, get_filter_expression, Op
|
from .comparisons import get_comparison_func, get_filter_expression, Op
|
||||||
|
|
||||||
|
|
||||||
@ -271,6 +273,10 @@ class Table(BaseModel):
|
|||||||
self.items = defaultdict(dict)
|
self.items = defaultdict(dict)
|
||||||
self.table_arn = self._generate_arn(table_name)
|
self.table_arn = self._generate_arn(table_name)
|
||||||
self.tags = []
|
self.tags = []
|
||||||
|
self.ttl = {
|
||||||
|
'TimeToLiveStatus': 'DISABLED' # One of 'ENABLING'|'DISABLING'|'ENABLED'|'DISABLED',
|
||||||
|
# 'AttributeName': 'string' # Can contain this
|
||||||
|
}
|
||||||
|
|
||||||
def _generate_arn(self, name):
|
def _generate_arn(self, name):
|
||||||
return 'arn:aws:dynamodb:us-east-1:123456789011:table/' + name
|
return 'arn:aws:dynamodb:us-east-1:123456789011:table/' + name
|
||||||
@ -577,9 +583,16 @@ class Table(BaseModel):
|
|||||||
|
|
||||||
class DynamoDBBackend(BaseBackend):
|
class DynamoDBBackend(BaseBackend):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, region_name=None):
|
||||||
|
self.region_name = region_name
|
||||||
self.tables = OrderedDict()
|
self.tables = OrderedDict()
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
region_name = self.region_name
|
||||||
|
|
||||||
|
self.__dict__ = {}
|
||||||
|
self.__init__(region_name)
|
||||||
|
|
||||||
def create_table(self, name, **params):
|
def create_table(self, name, **params):
|
||||||
if name in self.tables:
|
if name in self.tables:
|
||||||
return None
|
return None
|
||||||
@ -595,6 +608,11 @@ class DynamoDBBackend(BaseBackend):
|
|||||||
if self.tables[table].table_arn == table_arn:
|
if self.tables[table].table_arn == table_arn:
|
||||||
self.tables[table].tags.extend(tags)
|
self.tables[table].tags.extend(tags)
|
||||||
|
|
||||||
|
def untag_resource(self, table_arn, tag_keys):
|
||||||
|
for table in self.tables:
|
||||||
|
if self.tables[table].table_arn == table_arn:
|
||||||
|
self.tables[table].tags = [tag for tag in self.tables[table].tags if tag['Key'] not in tag_keys]
|
||||||
|
|
||||||
def list_tags_of_resource(self, table_arn):
|
def list_tags_of_resource(self, table_arn):
|
||||||
required_table = None
|
required_table = None
|
||||||
for table in self.tables:
|
for table in self.tables:
|
||||||
@ -796,5 +814,28 @@ class DynamoDBBackend(BaseBackend):
|
|||||||
hash_key, range_key = self.get_keys_value(table, keys)
|
hash_key, range_key = self.get_keys_value(table, keys)
|
||||||
return table.delete_item(hash_key, range_key)
|
return table.delete_item(hash_key, range_key)
|
||||||
|
|
||||||
|
def update_ttl(self, table_name, ttl_spec):
|
||||||
|
table = self.tables.get(table_name)
|
||||||
|
if table is None:
|
||||||
|
raise JsonRESTError('ResourceNotFound', 'Table not found')
|
||||||
|
|
||||||
dynamodb_backend2 = DynamoDBBackend()
|
if 'Enabled' not in ttl_spec or 'AttributeName' not in ttl_spec:
|
||||||
|
raise JsonRESTError('InvalidParameterValue',
|
||||||
|
'TimeToLiveSpecification does not contain Enabled and AttributeName')
|
||||||
|
|
||||||
|
if ttl_spec['Enabled']:
|
||||||
|
table.ttl['TimeToLiveStatus'] = 'ENABLED'
|
||||||
|
else:
|
||||||
|
table.ttl['TimeToLiveStatus'] = 'DISABLED'
|
||||||
|
table.ttl['AttributeName'] = ttl_spec['AttributeName']
|
||||||
|
|
||||||
|
def describe_ttl(self, table_name):
|
||||||
|
table = self.tables.get(table_name)
|
||||||
|
if table is None:
|
||||||
|
raise JsonRESTError('ResourceNotFound', 'Table not found')
|
||||||
|
|
||||||
|
return table.ttl
|
||||||
|
|
||||||
|
|
||||||
|
available_regions = boto3.session.Session().get_available_regions("dynamodb")
|
||||||
|
dynamodb_backends = {region: DynamoDBBackend(region_name=region) for region in available_regions}
|
||||||
|
@ -5,7 +5,7 @@ import re
|
|||||||
|
|
||||||
from moto.core.responses import BaseResponse
|
from moto.core.responses import BaseResponse
|
||||||
from moto.core.utils import camelcase_to_underscores, amzn_request_id
|
from moto.core.utils import camelcase_to_underscores, amzn_request_id
|
||||||
from .models import dynamodb_backend2, dynamo_json_dump
|
from .models import dynamodb_backends, dynamo_json_dump
|
||||||
|
|
||||||
|
|
||||||
class DynamoHandler(BaseResponse):
|
class DynamoHandler(BaseResponse):
|
||||||
@ -24,6 +24,14 @@ class DynamoHandler(BaseResponse):
|
|||||||
def error(self, type_, message, status=400):
|
def error(self, type_, message, status=400):
|
||||||
return status, self.response_headers, dynamo_json_dump({'__type': type_, 'message': message})
|
return status, self.response_headers, dynamo_json_dump({'__type': type_, 'message': message})
|
||||||
|
|
||||||
|
@property
|
||||||
|
def dynamodb_backend(self):
|
||||||
|
"""
|
||||||
|
:return: DynamoDB2 Backend
|
||||||
|
:rtype: moto.dynamodb2.models.DynamoDBBackend
|
||||||
|
"""
|
||||||
|
return dynamodb_backends[self.region]
|
||||||
|
|
||||||
@amzn_request_id
|
@amzn_request_id
|
||||||
def call_action(self):
|
def call_action(self):
|
||||||
self.body = json.loads(self.body or '{}')
|
self.body = json.loads(self.body or '{}')
|
||||||
@ -46,10 +54,10 @@ class DynamoHandler(BaseResponse):
|
|||||||
limit = body.get('Limit', 100)
|
limit = body.get('Limit', 100)
|
||||||
if body.get("ExclusiveStartTableName"):
|
if body.get("ExclusiveStartTableName"):
|
||||||
last = body.get("ExclusiveStartTableName")
|
last = body.get("ExclusiveStartTableName")
|
||||||
start = list(dynamodb_backend2.tables.keys()).index(last) + 1
|
start = list(self.dynamodb_backend.tables.keys()).index(last) + 1
|
||||||
else:
|
else:
|
||||||
start = 0
|
start = 0
|
||||||
all_tables = list(dynamodb_backend2.tables.keys())
|
all_tables = list(self.dynamodb_backend.tables.keys())
|
||||||
if limit:
|
if limit:
|
||||||
tables = all_tables[start:start + limit]
|
tables = all_tables[start:start + limit]
|
||||||
else:
|
else:
|
||||||
@ -74,12 +82,12 @@ class DynamoHandler(BaseResponse):
|
|||||||
global_indexes = body.get("GlobalSecondaryIndexes", [])
|
global_indexes = body.get("GlobalSecondaryIndexes", [])
|
||||||
local_secondary_indexes = body.get("LocalSecondaryIndexes", [])
|
local_secondary_indexes = body.get("LocalSecondaryIndexes", [])
|
||||||
|
|
||||||
table = dynamodb_backend2.create_table(table_name,
|
table = self.dynamodb_backend.create_table(table_name,
|
||||||
schema=key_schema,
|
schema=key_schema,
|
||||||
throughput=throughput,
|
throughput=throughput,
|
||||||
attr=attr,
|
attr=attr,
|
||||||
global_indexes=global_indexes,
|
global_indexes=global_indexes,
|
||||||
indexes=local_secondary_indexes)
|
indexes=local_secondary_indexes)
|
||||||
if table is not None:
|
if table is not None:
|
||||||
return dynamo_json_dump(table.describe())
|
return dynamo_json_dump(table.describe())
|
||||||
else:
|
else:
|
||||||
@ -88,7 +96,7 @@ class DynamoHandler(BaseResponse):
|
|||||||
|
|
||||||
def delete_table(self):
|
def delete_table(self):
|
||||||
name = self.body['TableName']
|
name = self.body['TableName']
|
||||||
table = dynamodb_backend2.delete_table(name)
|
table = self.dynamodb_backend.delete_table(name)
|
||||||
if table is not None:
|
if table is not None:
|
||||||
return dynamo_json_dump(table.describe())
|
return dynamo_json_dump(table.describe())
|
||||||
else:
|
else:
|
||||||
@ -96,15 +104,21 @@ class DynamoHandler(BaseResponse):
|
|||||||
return self.error(er, 'Requested resource not found')
|
return self.error(er, 'Requested resource not found')
|
||||||
|
|
||||||
def tag_resource(self):
|
def tag_resource(self):
|
||||||
tags = self.body['Tags']
|
|
||||||
table_arn = self.body['ResourceArn']
|
table_arn = self.body['ResourceArn']
|
||||||
dynamodb_backend2.tag_resource(table_arn, tags)
|
tags = self.body['Tags']
|
||||||
return json.dumps({})
|
self.dynamodb_backend.tag_resource(table_arn, tags)
|
||||||
|
return ''
|
||||||
|
|
||||||
|
def untag_resource(self):
|
||||||
|
table_arn = self.body['ResourceArn']
|
||||||
|
tags = self.body['TagKeys']
|
||||||
|
self.dynamodb_backend.untag_resource(table_arn, tags)
|
||||||
|
return ''
|
||||||
|
|
||||||
def list_tags_of_resource(self):
|
def list_tags_of_resource(self):
|
||||||
try:
|
try:
|
||||||
table_arn = self.body['ResourceArn']
|
table_arn = self.body['ResourceArn']
|
||||||
all_tags = dynamodb_backend2.list_tags_of_resource(table_arn)
|
all_tags = self.dynamodb_backend.list_tags_of_resource(table_arn)
|
||||||
all_tag_keys = [tag['Key'] for tag in all_tags]
|
all_tag_keys = [tag['Key'] for tag in all_tags]
|
||||||
marker = self.body.get('NextToken')
|
marker = self.body.get('NextToken')
|
||||||
if marker:
|
if marker:
|
||||||
@ -127,17 +141,17 @@ class DynamoHandler(BaseResponse):
|
|||||||
def update_table(self):
|
def update_table(self):
|
||||||
name = self.body['TableName']
|
name = self.body['TableName']
|
||||||
if 'GlobalSecondaryIndexUpdates' in self.body:
|
if 'GlobalSecondaryIndexUpdates' in self.body:
|
||||||
table = dynamodb_backend2.update_table_global_indexes(
|
table = self.dynamodb_backend.update_table_global_indexes(
|
||||||
name, self.body['GlobalSecondaryIndexUpdates'])
|
name, self.body['GlobalSecondaryIndexUpdates'])
|
||||||
if 'ProvisionedThroughput' in self.body:
|
if 'ProvisionedThroughput' in self.body:
|
||||||
throughput = self.body["ProvisionedThroughput"]
|
throughput = self.body["ProvisionedThroughput"]
|
||||||
table = dynamodb_backend2.update_table_throughput(name, throughput)
|
table = self.dynamodb_backend.update_table_throughput(name, throughput)
|
||||||
return dynamo_json_dump(table.describe())
|
return dynamo_json_dump(table.describe())
|
||||||
|
|
||||||
def describe_table(self):
|
def describe_table(self):
|
||||||
name = self.body['TableName']
|
name = self.body['TableName']
|
||||||
try:
|
try:
|
||||||
table = dynamodb_backend2.tables[name]
|
table = self.dynamodb_backend.tables[name]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
er = 'com.amazonaws.dynamodb.v20111205#ResourceNotFoundException'
|
er = 'com.amazonaws.dynamodb.v20111205#ResourceNotFoundException'
|
||||||
return self.error(er, 'Requested resource not found')
|
return self.error(er, 'Requested resource not found')
|
||||||
@ -188,8 +202,7 @@ class DynamoHandler(BaseResponse):
|
|||||||
expected[not_exists_m.group(1)] = {'Exists': False}
|
expected[not_exists_m.group(1)] = {'Exists': False}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = dynamodb_backend2.put_item(
|
result = self.dynamodb_backend.put_item(name, item, expected, overwrite)
|
||||||
name, item, expected, overwrite)
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
er = 'com.amazonaws.dynamodb.v20111205#ConditionalCheckFailedException'
|
er = 'com.amazonaws.dynamodb.v20111205#ConditionalCheckFailedException'
|
||||||
return self.error(er, 'A condition specified in the operation could not be evaluated.')
|
return self.error(er, 'A condition specified in the operation could not be evaluated.')
|
||||||
@ -214,10 +227,10 @@ class DynamoHandler(BaseResponse):
|
|||||||
request = list(table_request.values())[0]
|
request = list(table_request.values())[0]
|
||||||
if request_type == 'PutRequest':
|
if request_type == 'PutRequest':
|
||||||
item = request['Item']
|
item = request['Item']
|
||||||
dynamodb_backend2.put_item(table_name, item)
|
self.dynamodb_backend.put_item(table_name, item)
|
||||||
elif request_type == 'DeleteRequest':
|
elif request_type == 'DeleteRequest':
|
||||||
keys = request['Key']
|
keys = request['Key']
|
||||||
item = dynamodb_backend2.delete_item(table_name, keys)
|
item = self.dynamodb_backend.delete_item(table_name, keys)
|
||||||
|
|
||||||
response = {
|
response = {
|
||||||
"ConsumedCapacity": [
|
"ConsumedCapacity": [
|
||||||
@ -237,7 +250,7 @@ class DynamoHandler(BaseResponse):
|
|||||||
name = self.body['TableName']
|
name = self.body['TableName']
|
||||||
key = self.body['Key']
|
key = self.body['Key']
|
||||||
try:
|
try:
|
||||||
item = dynamodb_backend2.get_item(name, key)
|
item = self.dynamodb_backend.get_item(name, key)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
er = 'com.amazon.coral.validate#ValidationException'
|
er = 'com.amazon.coral.validate#ValidationException'
|
||||||
return self.error(er, 'Validation Exception')
|
return self.error(er, 'Validation Exception')
|
||||||
@ -268,7 +281,7 @@ class DynamoHandler(BaseResponse):
|
|||||||
attributes_to_get = table_request.get('AttributesToGet')
|
attributes_to_get = table_request.get('AttributesToGet')
|
||||||
results["Responses"][table_name] = []
|
results["Responses"][table_name] = []
|
||||||
for key in keys:
|
for key in keys:
|
||||||
item = dynamodb_backend2.get_item(table_name, key)
|
item = self.dynamodb_backend.get_item(table_name, key)
|
||||||
if item:
|
if item:
|
||||||
item_describe = item.describe_attrs(attributes_to_get)
|
item_describe = item.describe_attrs(attributes_to_get)
|
||||||
results["Responses"][table_name].append(
|
results["Responses"][table_name].append(
|
||||||
@ -297,7 +310,7 @@ class DynamoHandler(BaseResponse):
|
|||||||
if key_condition_expression:
|
if key_condition_expression:
|
||||||
value_alias_map = self.body['ExpressionAttributeValues']
|
value_alias_map = self.body['ExpressionAttributeValues']
|
||||||
|
|
||||||
table = dynamodb_backend2.get_table(name)
|
table = self.dynamodb_backend.get_table(name)
|
||||||
|
|
||||||
# If table does not exist
|
# If table does not exist
|
||||||
if table is None:
|
if table is None:
|
||||||
@ -365,7 +378,7 @@ class DynamoHandler(BaseResponse):
|
|||||||
key_conditions = self.body.get('KeyConditions')
|
key_conditions = self.body.get('KeyConditions')
|
||||||
query_filters = self.body.get("QueryFilter")
|
query_filters = self.body.get("QueryFilter")
|
||||||
if key_conditions:
|
if key_conditions:
|
||||||
hash_key_name, range_key_name = dynamodb_backend2.get_table_keys_name(
|
hash_key_name, range_key_name = self.dynamodb_backend.get_table_keys_name(
|
||||||
name, key_conditions.keys())
|
name, key_conditions.keys())
|
||||||
for key, value in key_conditions.items():
|
for key, value in key_conditions.items():
|
||||||
if key not in (hash_key_name, range_key_name):
|
if key not in (hash_key_name, range_key_name):
|
||||||
@ -398,9 +411,10 @@ class DynamoHandler(BaseResponse):
|
|||||||
exclusive_start_key = self.body.get('ExclusiveStartKey')
|
exclusive_start_key = self.body.get('ExclusiveStartKey')
|
||||||
limit = self.body.get("Limit")
|
limit = self.body.get("Limit")
|
||||||
scan_index_forward = self.body.get("ScanIndexForward")
|
scan_index_forward = self.body.get("ScanIndexForward")
|
||||||
items, scanned_count, last_evaluated_key = dynamodb_backend2.query(
|
items, scanned_count, last_evaluated_key = self.dynamodb_backend.query(
|
||||||
name, hash_key, range_comparison, range_values, limit,
|
name, hash_key, range_comparison, range_values, limit,
|
||||||
exclusive_start_key, scan_index_forward, projection_expression, index_name=index_name, **filter_kwargs)
|
exclusive_start_key, scan_index_forward, projection_expression, index_name=index_name, **filter_kwargs
|
||||||
|
)
|
||||||
if items is None:
|
if items is None:
|
||||||
er = 'com.amazonaws.dynamodb.v20111205#ResourceNotFoundException'
|
er = 'com.amazonaws.dynamodb.v20111205#ResourceNotFoundException'
|
||||||
return self.error(er, 'Requested resource not found')
|
return self.error(er, 'Requested resource not found')
|
||||||
@ -442,12 +456,12 @@ class DynamoHandler(BaseResponse):
|
|||||||
limit = self.body.get("Limit")
|
limit = self.body.get("Limit")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
items, scanned_count, last_evaluated_key = dynamodb_backend2.scan(name, filters,
|
items, scanned_count, last_evaluated_key = self.dynamodb_backend.scan(name, filters,
|
||||||
limit,
|
limit,
|
||||||
exclusive_start_key,
|
exclusive_start_key,
|
||||||
filter_expression,
|
filter_expression,
|
||||||
expression_attribute_names,
|
expression_attribute_names,
|
||||||
expression_attribute_values)
|
expression_attribute_values)
|
||||||
except ValueError as err:
|
except ValueError as err:
|
||||||
er = 'com.amazonaws.dynamodb.v20111205#ValidationError'
|
er = 'com.amazonaws.dynamodb.v20111205#ValidationError'
|
||||||
return self.error(er, 'Bad Filter Expression: {0}'.format(err))
|
return self.error(er, 'Bad Filter Expression: {0}'.format(err))
|
||||||
@ -478,12 +492,12 @@ class DynamoHandler(BaseResponse):
|
|||||||
name = self.body['TableName']
|
name = self.body['TableName']
|
||||||
keys = self.body['Key']
|
keys = self.body['Key']
|
||||||
return_values = self.body.get('ReturnValues', '')
|
return_values = self.body.get('ReturnValues', '')
|
||||||
table = dynamodb_backend2.get_table(name)
|
table = self.dynamodb_backend.get_table(name)
|
||||||
if not table:
|
if not table:
|
||||||
er = 'com.amazonaws.dynamodb.v20120810#ConditionalCheckFailedException'
|
er = 'com.amazonaws.dynamodb.v20120810#ConditionalCheckFailedException'
|
||||||
return self.error(er, 'A condition specified in the operation could not be evaluated.')
|
return self.error(er, 'A condition specified in the operation could not be evaluated.')
|
||||||
|
|
||||||
item = dynamodb_backend2.delete_item(name, keys)
|
item = self.dynamodb_backend.delete_item(name, keys)
|
||||||
if item and return_values == 'ALL_OLD':
|
if item and return_values == 'ALL_OLD':
|
||||||
item_dict = item.to_json()
|
item_dict = item.to_json()
|
||||||
else:
|
else:
|
||||||
@ -500,7 +514,7 @@ class DynamoHandler(BaseResponse):
|
|||||||
'ExpressionAttributeNames', {})
|
'ExpressionAttributeNames', {})
|
||||||
expression_attribute_values = self.body.get(
|
expression_attribute_values = self.body.get(
|
||||||
'ExpressionAttributeValues', {})
|
'ExpressionAttributeValues', {})
|
||||||
existing_item = dynamodb_backend2.get_item(name, key)
|
existing_item = self.dynamodb_backend.get_item(name, key)
|
||||||
|
|
||||||
if 'Expected' in self.body:
|
if 'Expected' in self.body:
|
||||||
expected = self.body['Expected']
|
expected = self.body['Expected']
|
||||||
@ -536,9 +550,10 @@ class DynamoHandler(BaseResponse):
|
|||||||
'\s*([=\+-])\s*', '\\1', update_expression)
|
'\s*([=\+-])\s*', '\\1', update_expression)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
item = dynamodb_backend2.update_item(
|
item = self.dynamodb_backend.update_item(
|
||||||
name, key, update_expression, attribute_updates, expression_attribute_names, expression_attribute_values,
|
name, key, update_expression, attribute_updates, expression_attribute_names,
|
||||||
expected)
|
expression_attribute_values, expected
|
||||||
|
)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
er = 'com.amazonaws.dynamodb.v20111205#ConditionalCheckFailedException'
|
er = 'com.amazonaws.dynamodb.v20111205#ConditionalCheckFailedException'
|
||||||
return self.error(er, 'A condition specified in the operation could not be evaluated.')
|
return self.error(er, 'A condition specified in the operation could not be evaluated.')
|
||||||
@ -555,3 +570,26 @@ class DynamoHandler(BaseResponse):
|
|||||||
item_dict['Attributes'] = {}
|
item_dict['Attributes'] = {}
|
||||||
|
|
||||||
return dynamo_json_dump(item_dict)
|
return dynamo_json_dump(item_dict)
|
||||||
|
|
||||||
|
def describe_limits(self):
|
||||||
|
return json.dumps({
|
||||||
|
'AccountMaxReadCapacityUnits': 20000,
|
||||||
|
'TableMaxWriteCapacityUnits': 10000,
|
||||||
|
'AccountMaxWriteCapacityUnits': 20000,
|
||||||
|
'TableMaxReadCapacityUnits': 10000
|
||||||
|
})
|
||||||
|
|
||||||
|
def update_time_to_live(self):
|
||||||
|
name = self.body['TableName']
|
||||||
|
ttl_spec = self.body['TimeToLiveSpecification']
|
||||||
|
|
||||||
|
self.dynamodb_backend.update_ttl(name, ttl_spec)
|
||||||
|
|
||||||
|
return json.dumps({'TimeToLiveSpecification': ttl_spec})
|
||||||
|
|
||||||
|
def describe_time_to_live(self):
|
||||||
|
name = self.body['TableName']
|
||||||
|
|
||||||
|
ttl_spec = self.dynamodb_backend.describe_ttl(name)
|
||||||
|
|
||||||
|
return json.dumps({'TimeToLiveDescription': ttl_spec})
|
||||||
|
@ -4,6 +4,7 @@ from datetime import datetime
|
|||||||
from random import random, randint
|
from random import random, randint
|
||||||
|
|
||||||
import pytz
|
import pytz
|
||||||
|
from moto.core.exceptions import JsonRESTError
|
||||||
from moto.core import BaseBackend, BaseModel
|
from moto.core import BaseBackend, BaseModel
|
||||||
from moto.ec2 import ec2_backends
|
from moto.ec2 import ec2_backends
|
||||||
from copy import copy
|
from copy import copy
|
||||||
@ -148,7 +149,7 @@ class Task(BaseObject):
|
|||||||
resource_requirements, overrides={}, started_by=''):
|
resource_requirements, overrides={}, started_by=''):
|
||||||
self.cluster_arn = cluster.arn
|
self.cluster_arn = cluster.arn
|
||||||
self.task_arn = 'arn:aws:ecs:us-east-1:012345678910:task/{0}'.format(
|
self.task_arn = 'arn:aws:ecs:us-east-1:012345678910:task/{0}'.format(
|
||||||
str(uuid.uuid1()))
|
str(uuid.uuid4()))
|
||||||
self.container_instance_arn = container_instance_arn
|
self.container_instance_arn = container_instance_arn
|
||||||
self.last_status = 'RUNNING'
|
self.last_status = 'RUNNING'
|
||||||
self.desired_status = 'RUNNING'
|
self.desired_status = 'RUNNING'
|
||||||
@ -288,7 +289,7 @@ class ContainerInstance(BaseObject):
|
|||||||
'stringSetValue': [],
|
'stringSetValue': [],
|
||||||
'type': 'STRINGSET'}]
|
'type': 'STRINGSET'}]
|
||||||
self.container_instance_arn = "arn:aws:ecs:us-east-1:012345678910:container-instance/{0}".format(
|
self.container_instance_arn = "arn:aws:ecs:us-east-1:012345678910:container-instance/{0}".format(
|
||||||
str(uuid.uuid1()))
|
str(uuid.uuid4()))
|
||||||
self.pending_tasks_count = 0
|
self.pending_tasks_count = 0
|
||||||
self.remaining_resources = [
|
self.remaining_resources = [
|
||||||
{'doubleValue': 0.0,
|
{'doubleValue': 0.0,
|
||||||
@ -321,6 +322,8 @@ class ContainerInstance(BaseObject):
|
|||||||
'dockerVersion': 'DockerVersion: 1.5.0'
|
'dockerVersion': 'DockerVersion: 1.5.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.attributes = {}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def response_object(self):
|
def response_object(self):
|
||||||
response_object = self.gen_response_object()
|
response_object = self.gen_response_object()
|
||||||
@ -766,6 +769,102 @@ class EC2ContainerServiceBackend(BaseBackend):
|
|||||||
raise Exception("{0} is not a cluster".format(cluster_name))
|
raise Exception("{0} is not a cluster".format(cluster_name))
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def put_attributes(self, cluster_name, attributes=None):
|
||||||
|
if cluster_name is None or cluster_name not in self.clusters:
|
||||||
|
raise JsonRESTError('ClusterNotFoundException', 'Cluster not found', status=400)
|
||||||
|
|
||||||
|
if attributes is None:
|
||||||
|
raise JsonRESTError('InvalidParameterException', 'attributes value is required')
|
||||||
|
|
||||||
|
for attr in attributes:
|
||||||
|
self._put_attribute(cluster_name, attr['name'], attr.get('value'), attr.get('targetId'), attr.get('targetType'))
|
||||||
|
|
||||||
|
def _put_attribute(self, cluster_name, name, value=None, target_id=None, target_type=None):
|
||||||
|
if target_id is None and target_type is None:
|
||||||
|
for instance in self.container_instances[cluster_name].values():
|
||||||
|
instance.attributes[name] = value
|
||||||
|
elif target_type is None:
|
||||||
|
# targetId is full container instance arn
|
||||||
|
try:
|
||||||
|
arn = target_id.rsplit('/', 1)[-1]
|
||||||
|
self.container_instances[cluster_name][arn].attributes[name] = value
|
||||||
|
except KeyError:
|
||||||
|
raise JsonRESTError('TargetNotFoundException', 'Could not find {0}'.format(target_id))
|
||||||
|
else:
|
||||||
|
# targetId is container uuid, targetType must be container-instance
|
||||||
|
try:
|
||||||
|
if target_type != 'container-instance':
|
||||||
|
raise JsonRESTError('TargetNotFoundException', 'Could not find {0}'.format(target_id))
|
||||||
|
|
||||||
|
self.container_instances[cluster_name][target_id].attributes[name] = value
|
||||||
|
except KeyError:
|
||||||
|
raise JsonRESTError('TargetNotFoundException', 'Could not find {0}'.format(target_id))
|
||||||
|
|
||||||
|
def list_attributes(self, target_type, cluster_name=None, attr_name=None, attr_value=None, max_results=None, next_token=None):
|
||||||
|
if target_type != 'container-instance':
|
||||||
|
raise JsonRESTError('InvalidParameterException', 'targetType must be container-instance')
|
||||||
|
|
||||||
|
filters = [lambda x: True]
|
||||||
|
|
||||||
|
# item will be {0 cluster_name, 1 arn, 2 name, 3 value}
|
||||||
|
if cluster_name is not None:
|
||||||
|
filters.append(lambda item: item[0] == cluster_name)
|
||||||
|
if attr_name:
|
||||||
|
filters.append(lambda item: item[2] == attr_name)
|
||||||
|
if attr_name:
|
||||||
|
filters.append(lambda item: item[3] == attr_value)
|
||||||
|
|
||||||
|
all_attrs = []
|
||||||
|
for cluster_name, cobj in self.container_instances.items():
|
||||||
|
for container_instance in cobj.values():
|
||||||
|
for key, value in container_instance.attributes.items():
|
||||||
|
all_attrs.append((cluster_name, container_instance.container_instance_arn, key, value))
|
||||||
|
|
||||||
|
return filter(lambda x: all(f(x) for f in filters), all_attrs)
|
||||||
|
|
||||||
|
def delete_attributes(self, cluster_name, attributes=None):
|
||||||
|
if cluster_name is None or cluster_name not in self.clusters:
|
||||||
|
raise JsonRESTError('ClusterNotFoundException', 'Cluster not found', status=400)
|
||||||
|
|
||||||
|
if attributes is None:
|
||||||
|
raise JsonRESTError('InvalidParameterException', 'attributes value is required')
|
||||||
|
|
||||||
|
for attr in attributes:
|
||||||
|
self._delete_attribute(cluster_name, attr['name'], attr.get('value'), attr.get('targetId'), attr.get('targetType'))
|
||||||
|
|
||||||
|
def _delete_attribute(self, cluster_name, name, value=None, target_id=None, target_type=None):
|
||||||
|
if target_id is None and target_type is None:
|
||||||
|
for instance in self.container_instances[cluster_name].values():
|
||||||
|
if name in instance.attributes and instance.attributes[name] == value:
|
||||||
|
del instance.attributes[name]
|
||||||
|
elif target_type is None:
|
||||||
|
# targetId is full container instance arn
|
||||||
|
try:
|
||||||
|
arn = target_id.rsplit('/', 1)[-1]
|
||||||
|
instance = self.container_instances[cluster_name][arn]
|
||||||
|
if name in instance.attributes and instance.attributes[name] == value:
|
||||||
|
del instance.attributes[name]
|
||||||
|
except KeyError:
|
||||||
|
raise JsonRESTError('TargetNotFoundException', 'Could not find {0}'.format(target_id))
|
||||||
|
else:
|
||||||
|
# targetId is container uuid, targetType must be container-instance
|
||||||
|
try:
|
||||||
|
if target_type != 'container-instance':
|
||||||
|
raise JsonRESTError('TargetNotFoundException', 'Could not find {0}'.format(target_id))
|
||||||
|
|
||||||
|
instance = self.container_instances[cluster_name][target_id]
|
||||||
|
if name in instance.attributes and instance.attributes[name] == value:
|
||||||
|
del instance.attributes[name]
|
||||||
|
except KeyError:
|
||||||
|
raise JsonRESTError('TargetNotFoundException', 'Could not find {0}'.format(target_id))
|
||||||
|
|
||||||
|
def list_task_definition_families(self, family_prefix=None, status=None, max_results=None, next_token=None):
|
||||||
|
for task_fam in self.task_definitions:
|
||||||
|
if family_prefix is not None and not task_fam.startswith(family_prefix):
|
||||||
|
continue
|
||||||
|
|
||||||
|
yield task_fam
|
||||||
|
|
||||||
|
|
||||||
ecs_backends = {}
|
ecs_backends = {}
|
||||||
for region, ec2_backend in ec2_backends.items():
|
for region, ec2_backend in ec2_backends.items():
|
||||||
|
@ -9,6 +9,12 @@ class EC2ContainerServiceResponse(BaseResponse):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def ecs_backend(self):
|
def ecs_backend(self):
|
||||||
|
"""
|
||||||
|
ECS Backend
|
||||||
|
|
||||||
|
:return: ECS Backend object
|
||||||
|
:rtype: moto.ecs.models.EC2ContainerServiceBackend
|
||||||
|
"""
|
||||||
return ecs_backends[self.region]
|
return ecs_backends[self.region]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -34,7 +40,7 @@ class EC2ContainerServiceResponse(BaseResponse):
|
|||||||
cluster_arns = self.ecs_backend.list_clusters()
|
cluster_arns = self.ecs_backend.list_clusters()
|
||||||
return json.dumps({
|
return json.dumps({
|
||||||
'clusterArns': cluster_arns
|
'clusterArns': cluster_arns
|
||||||
# 'nextToken': str(uuid.uuid1())
|
# 'nextToken': str(uuid.uuid4())
|
||||||
})
|
})
|
||||||
|
|
||||||
def describe_clusters(self):
|
def describe_clusters(self):
|
||||||
@ -66,7 +72,7 @@ class EC2ContainerServiceResponse(BaseResponse):
|
|||||||
task_definition_arns = self.ecs_backend.list_task_definitions()
|
task_definition_arns = self.ecs_backend.list_task_definitions()
|
||||||
return json.dumps({
|
return json.dumps({
|
||||||
'taskDefinitionArns': task_definition_arns
|
'taskDefinitionArns': task_definition_arns
|
||||||
# 'nextToken': str(uuid.uuid1())
|
# 'nextToken': str(uuid.uuid4())
|
||||||
})
|
})
|
||||||
|
|
||||||
def describe_task_definition(self):
|
def describe_task_definition(self):
|
||||||
@ -159,7 +165,7 @@ class EC2ContainerServiceResponse(BaseResponse):
|
|||||||
return json.dumps({
|
return json.dumps({
|
||||||
'serviceArns': service_arns
|
'serviceArns': service_arns
|
||||||
# ,
|
# ,
|
||||||
# 'nextToken': str(uuid.uuid1())
|
# 'nextToken': str(uuid.uuid4())
|
||||||
})
|
})
|
||||||
|
|
||||||
def describe_services(self):
|
def describe_services(self):
|
||||||
@ -245,3 +251,62 @@ class EC2ContainerServiceResponse(BaseResponse):
|
|||||||
'failures': [ci.response_object for ci in failures],
|
'failures': [ci.response_object for ci in failures],
|
||||||
'containerInstances': [ci.response_object for ci in container_instances]
|
'containerInstances': [ci.response_object for ci in container_instances]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def put_attributes(self):
|
||||||
|
cluster_name = self._get_param('cluster')
|
||||||
|
attributes = self._get_param('attributes')
|
||||||
|
|
||||||
|
self.ecs_backend.put_attributes(cluster_name, attributes)
|
||||||
|
|
||||||
|
return json.dumps({'attributes': attributes})
|
||||||
|
|
||||||
|
def list_attributes(self):
|
||||||
|
cluster_name = self._get_param('cluster')
|
||||||
|
attr_name = self._get_param('attributeName')
|
||||||
|
attr_value = self._get_param('attributeValue')
|
||||||
|
target_type = self._get_param('targetType')
|
||||||
|
max_results = self._get_param('maxResults')
|
||||||
|
next_token = self._get_param('nextToken')
|
||||||
|
|
||||||
|
results = self.ecs_backend.list_attributes(target_type, cluster_name, attr_name, attr_value, max_results, next_token)
|
||||||
|
# Result will be [item will be {0 cluster_name, 1 arn, 2 name, 3 value}]
|
||||||
|
|
||||||
|
formatted_results = []
|
||||||
|
for _, arn, name, value in results:
|
||||||
|
tmp_result = {
|
||||||
|
'name': name,
|
||||||
|
'targetId': arn
|
||||||
|
}
|
||||||
|
if value is not None:
|
||||||
|
tmp_result['value'] = value
|
||||||
|
formatted_results.append(tmp_result)
|
||||||
|
|
||||||
|
return json.dumps({'attributes': formatted_results})
|
||||||
|
|
||||||
|
def delete_attributes(self):
|
||||||
|
cluster_name = self._get_param('cluster')
|
||||||
|
attributes = self._get_param('attributes')
|
||||||
|
|
||||||
|
self.ecs_backend.delete_attributes(cluster_name, attributes)
|
||||||
|
|
||||||
|
return json.dumps({'attributes': attributes})
|
||||||
|
|
||||||
|
def discover_poll_endpoint(self):
|
||||||
|
# Here are the arguments, this api is used by the ecs client so obviously no decent
|
||||||
|
# documentation. Hence I've responded with valid but useless data
|
||||||
|
# cluster_name = self._get_param('cluster')
|
||||||
|
# instance = self._get_param('containerInstance')
|
||||||
|
return json.dumps({
|
||||||
|
'endpoint': 'http://localhost',
|
||||||
|
'telemetryEndpoint': 'http://localhost'
|
||||||
|
})
|
||||||
|
|
||||||
|
def list_task_definition_families(self):
|
||||||
|
family_prefix = self._get_param('familyPrefix')
|
||||||
|
status = self._get_param('status')
|
||||||
|
max_results = self._get_param('maxResults')
|
||||||
|
next_token = self._get_param('nextToken')
|
||||||
|
|
||||||
|
results = self.ecs_backend.list_task_definition_families(family_prefix, status, max_results, next_token)
|
||||||
|
|
||||||
|
return json.dumps({'families': list(results)})
|
||||||
|
@ -3,8 +3,10 @@ from __future__ import unicode_literals
|
|||||||
import datetime
|
import datetime
|
||||||
import re
|
import re
|
||||||
from moto.compat import OrderedDict
|
from moto.compat import OrderedDict
|
||||||
|
from moto.core.exceptions import RESTError
|
||||||
from moto.core import BaseBackend, BaseModel
|
from moto.core import BaseBackend, BaseModel
|
||||||
from moto.ec2.models import ec2_backends
|
from moto.ec2.models import ec2_backends
|
||||||
|
from moto.acm.models import acm_backends
|
||||||
from .exceptions import (
|
from .exceptions import (
|
||||||
DuplicateLoadBalancerName,
|
DuplicateLoadBalancerName,
|
||||||
DuplicateListenerError,
|
DuplicateListenerError,
|
||||||
@ -40,6 +42,8 @@ class FakeHealthStatus(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class FakeTargetGroup(BaseModel):
|
class FakeTargetGroup(BaseModel):
|
||||||
|
HTTP_CODE_REGEX = re.compile(r'(?:(?:\d+-\d+|\d+),?)+')
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
name,
|
name,
|
||||||
arn,
|
arn,
|
||||||
@ -157,6 +161,7 @@ class FakeListener(BaseModel):
|
|||||||
self.port = port
|
self.port = port
|
||||||
self.ssl_policy = ssl_policy
|
self.ssl_policy = ssl_policy
|
||||||
self.certificate = certificate
|
self.certificate = certificate
|
||||||
|
self.certificates = [certificate] if certificate is not None else []
|
||||||
self.default_actions = default_actions
|
self.default_actions = default_actions
|
||||||
self._non_default_rules = []
|
self._non_default_rules = []
|
||||||
self._default_rule = FakeRule(
|
self._default_rule = FakeRule(
|
||||||
@ -227,6 +232,8 @@ class FakeBackend(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class FakeLoadBalancer(BaseModel):
|
class FakeLoadBalancer(BaseModel):
|
||||||
|
VALID_ATTRS = {'access_logs.s3.enabled', 'access_logs.s3.bucket', 'access_logs.s3.prefix',
|
||||||
|
'deletion_protection.enabled', 'idle_timeout.timeout_seconds'}
|
||||||
|
|
||||||
def __init__(self, name, security_groups, subnets, vpc_id, arn, dns_name, scheme='internet-facing'):
|
def __init__(self, name, security_groups, subnets, vpc_id, arn, dns_name, scheme='internet-facing'):
|
||||||
self.name = name
|
self.name = name
|
||||||
@ -240,6 +247,15 @@ class FakeLoadBalancer(BaseModel):
|
|||||||
self.arn = arn
|
self.arn = arn
|
||||||
self.dns_name = dns_name
|
self.dns_name = dns_name
|
||||||
|
|
||||||
|
self.stack = 'ipv4'
|
||||||
|
self.attrs = {
|
||||||
|
'access_logs.s3.enabled': 'false',
|
||||||
|
'access_logs.s3.bucket': None,
|
||||||
|
'access_logs.s3.prefix': None,
|
||||||
|
'deletion_protection.enabled': 'false',
|
||||||
|
'idle_timeout.timeout_seconds': '60'
|
||||||
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def physical_resource_id(self):
|
def physical_resource_id(self):
|
||||||
return self.arn
|
return self.arn
|
||||||
@ -289,6 +305,26 @@ class ELBv2Backend(BaseBackend):
|
|||||||
self.target_groups = OrderedDict()
|
self.target_groups = OrderedDict()
|
||||||
self.load_balancers = OrderedDict()
|
self.load_balancers = OrderedDict()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ec2_backend(self):
|
||||||
|
"""
|
||||||
|
EC2 backend
|
||||||
|
|
||||||
|
:return: EC2 Backend
|
||||||
|
:rtype: moto.ec2.models.EC2Backend
|
||||||
|
"""
|
||||||
|
return ec2_backends[self.region_name]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def acm_backend(self):
|
||||||
|
"""
|
||||||
|
ACM backend
|
||||||
|
|
||||||
|
:return: ACM Backend
|
||||||
|
:rtype: moto.acm.models.AWSCertificateManagerBackend
|
||||||
|
"""
|
||||||
|
return acm_backends[self.region_name]
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
region_name = self.region_name
|
region_name = self.region_name
|
||||||
self.__dict__ = {}
|
self.__dict__ = {}
|
||||||
@ -296,12 +332,11 @@ class ELBv2Backend(BaseBackend):
|
|||||||
|
|
||||||
def create_load_balancer(self, name, security_groups, subnet_ids, scheme='internet-facing'):
|
def create_load_balancer(self, name, security_groups, subnet_ids, scheme='internet-facing'):
|
||||||
vpc_id = None
|
vpc_id = None
|
||||||
ec2_backend = ec2_backends[self.region_name]
|
|
||||||
subnets = []
|
subnets = []
|
||||||
if not subnet_ids:
|
if not subnet_ids:
|
||||||
raise SubnetNotFoundError()
|
raise SubnetNotFoundError()
|
||||||
for subnet_id in subnet_ids:
|
for subnet_id in subnet_ids:
|
||||||
subnet = ec2_backend.get_subnet(subnet_id)
|
subnet = self.ec2_backend.get_subnet(subnet_id)
|
||||||
if subnet is None:
|
if subnet is None:
|
||||||
raise SubnetNotFoundError()
|
raise SubnetNotFoundError()
|
||||||
subnets.append(subnet)
|
subnets.append(subnet)
|
||||||
@ -395,6 +430,9 @@ class ELBv2Backend(BaseBackend):
|
|||||||
if target_group.name == name:
|
if target_group.name == name:
|
||||||
raise DuplicateTargetGroupName()
|
raise DuplicateTargetGroupName()
|
||||||
|
|
||||||
|
if FakeTargetGroup.HTTP_CODE_REGEX.match(kwargs['matcher']['HttpCode']) is None:
|
||||||
|
raise RESTError('InvalidParameterValue', 'HttpCode must be like 200 | 200-399 | 200,201 ...')
|
||||||
|
|
||||||
arn = "arn:aws:elasticloadbalancing:%s:1:targetgroup/%s/50dc6c495c0c9188" % (self.region_name, name)
|
arn = "arn:aws:elasticloadbalancing:%s:1:targetgroup/%s/50dc6c495c0c9188" % (self.region_name, name)
|
||||||
target_group = FakeTargetGroup(name, arn, **kwargs)
|
target_group = FakeTargetGroup(name, arn, **kwargs)
|
||||||
self.target_groups[target_group.arn] = target_group
|
self.target_groups[target_group.arn] = target_group
|
||||||
@ -642,6 +680,166 @@ class ELBv2Backend(BaseBackend):
|
|||||||
modified_rules.append(given_rule)
|
modified_rules.append(given_rule)
|
||||||
return modified_rules
|
return modified_rules
|
||||||
|
|
||||||
|
def set_ip_address_type(self, arn, ip_type):
|
||||||
|
if ip_type not in ('internal', 'dualstack'):
|
||||||
|
raise RESTError('InvalidParameterValue', 'IpAddressType must be either internal | dualstack')
|
||||||
|
|
||||||
|
balancer = self.load_balancers.get(arn)
|
||||||
|
if balancer is None:
|
||||||
|
raise LoadBalancerNotFoundError()
|
||||||
|
|
||||||
|
if ip_type == 'dualstack' and balancer.scheme == 'internal':
|
||||||
|
raise RESTError('InvalidConfigurationRequest', 'Internal load balancers cannot be dualstack')
|
||||||
|
|
||||||
|
balancer.stack = ip_type
|
||||||
|
|
||||||
|
def set_security_groups(self, arn, sec_groups):
|
||||||
|
balancer = self.load_balancers.get(arn)
|
||||||
|
if balancer is None:
|
||||||
|
raise LoadBalancerNotFoundError()
|
||||||
|
|
||||||
|
# Check all security groups exist
|
||||||
|
for sec_group_id in sec_groups:
|
||||||
|
if self.ec2_backend.get_security_group_from_id(sec_group_id) is None:
|
||||||
|
raise RESTError('InvalidSecurityGroup', 'Security group {0} does not exist'.format(sec_group_id))
|
||||||
|
|
||||||
|
balancer.security_groups = sec_groups
|
||||||
|
|
||||||
|
def set_subnets(self, arn, subnets):
|
||||||
|
balancer = self.load_balancers.get(arn)
|
||||||
|
if balancer is None:
|
||||||
|
raise LoadBalancerNotFoundError()
|
||||||
|
|
||||||
|
subnet_objects = []
|
||||||
|
sub_zone_list = {}
|
||||||
|
for subnet in subnets:
|
||||||
|
try:
|
||||||
|
subnet = self.ec2_backend.get_subnet(subnet)
|
||||||
|
|
||||||
|
if subnet.availability_zone in sub_zone_list:
|
||||||
|
raise RESTError('InvalidConfigurationRequest', 'More than 1 subnet cannot be specified for 1 availability zone')
|
||||||
|
|
||||||
|
sub_zone_list[subnet.availability_zone] = subnet.id
|
||||||
|
subnet_objects.append(subnet)
|
||||||
|
except Exception:
|
||||||
|
raise SubnetNotFoundError()
|
||||||
|
|
||||||
|
if len(sub_zone_list) < 2:
|
||||||
|
raise RESTError('InvalidConfigurationRequest', 'More than 1 availability zone must be specified')
|
||||||
|
|
||||||
|
balancer.subnets = subnet_objects
|
||||||
|
|
||||||
|
return sub_zone_list.items()
|
||||||
|
|
||||||
|
def modify_load_balancer_attributes(self, arn, attrs):
|
||||||
|
balancer = self.load_balancers.get(arn)
|
||||||
|
if balancer is None:
|
||||||
|
raise LoadBalancerNotFoundError()
|
||||||
|
|
||||||
|
for key in attrs:
|
||||||
|
if key not in FakeLoadBalancer.VALID_ATTRS:
|
||||||
|
raise RESTError('InvalidConfigurationRequest', 'Key {0} not valid'.format(key))
|
||||||
|
|
||||||
|
balancer.attrs.update(attrs)
|
||||||
|
return balancer.attrs
|
||||||
|
|
||||||
|
def describe_load_balancer_attributes(self, arn):
|
||||||
|
balancer = self.load_balancers.get(arn)
|
||||||
|
if balancer is None:
|
||||||
|
raise LoadBalancerNotFoundError()
|
||||||
|
|
||||||
|
return balancer.attrs
|
||||||
|
|
||||||
|
def modify_target_group(self, arn, health_check_proto=None, health_check_port=None, health_check_path=None, health_check_interval=None,
|
||||||
|
health_check_timeout=None, healthy_threshold_count=None, unhealthy_threshold_count=None, http_codes=None):
|
||||||
|
target_group = self.target_groups.get(arn)
|
||||||
|
if target_group is None:
|
||||||
|
raise TargetGroupNotFoundError()
|
||||||
|
|
||||||
|
if http_codes is not None and FakeTargetGroup.HTTP_CODE_REGEX.match(http_codes) is None:
|
||||||
|
raise RESTError('InvalidParameterValue', 'HttpCode must be like 200 | 200-399 | 200,201 ...')
|
||||||
|
|
||||||
|
if http_codes is not None:
|
||||||
|
target_group.matcher['HttpCode'] = http_codes
|
||||||
|
if health_check_interval is not None:
|
||||||
|
target_group.healthcheck_interval_seconds = health_check_interval
|
||||||
|
if health_check_path is not None:
|
||||||
|
target_group.healthcheck_path = health_check_path
|
||||||
|
if health_check_port is not None:
|
||||||
|
target_group.healthcheck_port = health_check_port
|
||||||
|
if health_check_proto is not None:
|
||||||
|
target_group.healthcheck_protocol = health_check_proto
|
||||||
|
if health_check_timeout is not None:
|
||||||
|
target_group.healthcheck_timeout_seconds = health_check_timeout
|
||||||
|
if healthy_threshold_count is not None:
|
||||||
|
target_group.healthy_threshold_count = healthy_threshold_count
|
||||||
|
if unhealthy_threshold_count is not None:
|
||||||
|
target_group.unhealthy_threshold_count = unhealthy_threshold_count
|
||||||
|
|
||||||
|
return target_group
|
||||||
|
|
||||||
|
def modify_listener(self, arn, port=None, protocol=None, ssl_policy=None, certificates=None, default_actions=None):
|
||||||
|
for load_balancer in self.load_balancers.values():
|
||||||
|
if arn in load_balancer.listeners:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise ListenerNotFoundError()
|
||||||
|
|
||||||
|
listener = load_balancer.listeners[arn]
|
||||||
|
|
||||||
|
if port is not None:
|
||||||
|
for listener_arn, current_listener in load_balancer.listeners.items():
|
||||||
|
if listener_arn == arn:
|
||||||
|
continue
|
||||||
|
if listener.port == port:
|
||||||
|
raise DuplicateListenerError()
|
||||||
|
|
||||||
|
listener.port = port
|
||||||
|
|
||||||
|
if protocol is not None:
|
||||||
|
if protocol not in ('HTTP', 'HTTPS', 'TCP'):
|
||||||
|
raise RESTError('UnsupportedProtocol', 'Protocol {0} is not supported'.format(protocol))
|
||||||
|
|
||||||
|
# HTTPS checks
|
||||||
|
if protocol == 'HTTPS':
|
||||||
|
# HTTPS
|
||||||
|
|
||||||
|
# Might already be HTTPS so may not provide certs
|
||||||
|
if certificates is None and listener.protocol != 'HTTPS':
|
||||||
|
raise RESTError('InvalidConfigurationRequest', 'Certificates must be provided for HTTPS')
|
||||||
|
|
||||||
|
# Check certificates exist
|
||||||
|
if certificates is not None:
|
||||||
|
default_cert = None
|
||||||
|
all_certs = set() # for SNI
|
||||||
|
for cert in certificates:
|
||||||
|
if cert['is_default'] == 'true':
|
||||||
|
default_cert = cert['certificate_arn']
|
||||||
|
try:
|
||||||
|
self.acm_backend.get_certificate(cert['certificate_arn'])
|
||||||
|
except Exception:
|
||||||
|
raise RESTError('CertificateNotFound', 'Certificate {0} not found'.format(cert['certificate_arn']))
|
||||||
|
|
||||||
|
all_certs.add(cert['certificate_arn'])
|
||||||
|
|
||||||
|
if default_cert is None:
|
||||||
|
raise RESTError('InvalidConfigurationRequest', 'No default certificate')
|
||||||
|
|
||||||
|
listener.certificate = default_cert
|
||||||
|
listener.certificates = list(all_certs)
|
||||||
|
|
||||||
|
listener.protocol = protocol
|
||||||
|
|
||||||
|
if ssl_policy is not None:
|
||||||
|
# Its already validated in responses.py
|
||||||
|
listener.ssl_policy = ssl_policy
|
||||||
|
|
||||||
|
if default_actions is not None:
|
||||||
|
# Is currently not validated
|
||||||
|
listener.default_actions = default_actions
|
||||||
|
|
||||||
|
return listener
|
||||||
|
|
||||||
def _any_listener_using(self, target_group_arn):
|
def _any_listener_using(self, target_group_arn):
|
||||||
for load_balancer in self.load_balancers.values():
|
for load_balancer in self.load_balancers.values():
|
||||||
for listener in load_balancer.listeners.values():
|
for listener in load_balancer.listeners.values():
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
from moto.core.exceptions import RESTError
|
||||||
|
from moto.core.utils import amzn_request_id
|
||||||
from moto.core.responses import BaseResponse
|
from moto.core.responses import BaseResponse
|
||||||
from .models import elbv2_backends
|
from .models import elbv2_backends
|
||||||
from .exceptions import DuplicateTagKeysError
|
from .exceptions import DuplicateTagKeysError
|
||||||
@ -6,12 +8,131 @@ from .exceptions import LoadBalancerNotFoundError
|
|||||||
from .exceptions import TargetGroupNotFoundError
|
from .exceptions import TargetGroupNotFoundError
|
||||||
|
|
||||||
|
|
||||||
class ELBV2Response(BaseResponse):
|
SSL_POLICIES = [
|
||||||
|
{
|
||||||
|
'name': 'ELBSecurityPolicy-2016-08',
|
||||||
|
'ssl_protocols': ['TLSv1', 'TLSv1.1', 'TLSv1.2'],
|
||||||
|
'ciphers': [
|
||||||
|
{'name': 'ECDHE-ECDSA-AES128-GCM-SHA256', 'priority': 1},
|
||||||
|
{'name': 'ECDHE-RSA-AES128-GCM-SHA256', 'priority': 2},
|
||||||
|
{'name': 'ECDHE-ECDSA-AES128-SHA256', 'priority': 3},
|
||||||
|
{'name': 'ECDHE-RSA-AES128-SHA256', 'priority': 4},
|
||||||
|
{'name': 'ECDHE-ECDSA-AES128-SHA', 'priority': 5},
|
||||||
|
{'name': 'ECDHE-RSA-AES128-SHA', 'priority': 6},
|
||||||
|
{'name': 'ECDHE-ECDSA-AES256-GCM-SHA384', 'priority': 7},
|
||||||
|
{'name': 'ECDHE-RSA-AES256-GCM-SHA384', 'priority': 8},
|
||||||
|
{'name': 'ECDHE-ECDSA-AES256-SHA384', 'priority': 9},
|
||||||
|
{'name': 'ECDHE-RSA-AES256-SHA384', 'priority': 10},
|
||||||
|
{'name': 'ECDHE-RSA-AES256-SHA', 'priority': 11},
|
||||||
|
{'name': 'ECDHE-ECDSA-AES256-SHA', 'priority': 12},
|
||||||
|
{'name': 'AES128-GCM-SHA256', 'priority': 13},
|
||||||
|
{'name': 'AES128-SHA256', 'priority': 14},
|
||||||
|
{'name': 'AES128-SHA', 'priority': 15},
|
||||||
|
{'name': 'AES256-GCM-SHA384', 'priority': 16},
|
||||||
|
{'name': 'AES256-SHA256', 'priority': 17},
|
||||||
|
{'name': 'AES256-SHA', 'priority': 18}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'ELBSecurityPolicy-TLS-1-2-2017-01',
|
||||||
|
'ssl_protocols': ['TLSv1.2'],
|
||||||
|
'ciphers': [
|
||||||
|
{'name': 'ECDHE-ECDSA-AES128-GCM-SHA256', 'priority': 1},
|
||||||
|
{'name': 'ECDHE-RSA-AES128-GCM-SHA256', 'priority': 2},
|
||||||
|
{'name': 'ECDHE-ECDSA-AES128-SHA256', 'priority': 3},
|
||||||
|
{'name': 'ECDHE-RSA-AES128-SHA256', 'priority': 4},
|
||||||
|
{'name': 'ECDHE-ECDSA-AES256-GCM-SHA384', 'priority': 5},
|
||||||
|
{'name': 'ECDHE-RSA-AES256-GCM-SHA384', 'priority': 6},
|
||||||
|
{'name': 'ECDHE-ECDSA-AES256-SHA384', 'priority': 7},
|
||||||
|
{'name': 'ECDHE-RSA-AES256-SHA384', 'priority': 8},
|
||||||
|
{'name': 'AES128-GCM-SHA256', 'priority': 9},
|
||||||
|
{'name': 'AES128-SHA256', 'priority': 10},
|
||||||
|
{'name': 'AES256-GCM-SHA384', 'priority': 11},
|
||||||
|
{'name': 'AES256-SHA256', 'priority': 12}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'ELBSecurityPolicy-TLS-1-1-2017-01',
|
||||||
|
'ssl_protocols': ['TLSv1.1', 'TLSv1.2'],
|
||||||
|
'ciphers': [
|
||||||
|
{'name': 'ECDHE-ECDSA-AES128-GCM-SHA256', 'priority': 1},
|
||||||
|
{'name': 'ECDHE-RSA-AES128-GCM-SHA256', 'priority': 2},
|
||||||
|
{'name': 'ECDHE-ECDSA-AES128-SHA256', 'priority': 3},
|
||||||
|
{'name': 'ECDHE-RSA-AES128-SHA256', 'priority': 4},
|
||||||
|
{'name': 'ECDHE-ECDSA-AES128-SHA', 'priority': 5},
|
||||||
|
{'name': 'ECDHE-RSA-AES128-SHA', 'priority': 6},
|
||||||
|
{'name': 'ECDHE-ECDSA-AES256-GCM-SHA384', 'priority': 7},
|
||||||
|
{'name': 'ECDHE-RSA-AES256-GCM-SHA384', 'priority': 8},
|
||||||
|
{'name': 'ECDHE-ECDSA-AES256-SHA384', 'priority': 9},
|
||||||
|
{'name': 'ECDHE-RSA-AES256-SHA384', 'priority': 10},
|
||||||
|
{'name': 'ECDHE-RSA-AES256-SHA', 'priority': 11},
|
||||||
|
{'name': 'ECDHE-ECDSA-AES256-SHA', 'priority': 12},
|
||||||
|
{'name': 'AES128-GCM-SHA256', 'priority': 13},
|
||||||
|
{'name': 'AES128-SHA256', 'priority': 14},
|
||||||
|
{'name': 'AES128-SHA', 'priority': 15},
|
||||||
|
{'name': 'AES256-GCM-SHA384', 'priority': 16},
|
||||||
|
{'name': 'AES256-SHA256', 'priority': 17},
|
||||||
|
{'name': 'AES256-SHA', 'priority': 18}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'ELBSecurityPolicy-2015-05',
|
||||||
|
'ssl_protocols': ['TLSv1', 'TLSv1.1', 'TLSv1.2'],
|
||||||
|
'ciphers': [
|
||||||
|
{'name': 'ECDHE-ECDSA-AES128-GCM-SHA256', 'priority': 1},
|
||||||
|
{'name': 'ECDHE-RSA-AES128-GCM-SHA256', 'priority': 2},
|
||||||
|
{'name': 'ECDHE-ECDSA-AES128-SHA256', 'priority': 3},
|
||||||
|
{'name': 'ECDHE-RSA-AES128-SHA256', 'priority': 4},
|
||||||
|
{'name': 'ECDHE-ECDSA-AES128-SHA', 'priority': 5},
|
||||||
|
{'name': 'ECDHE-RSA-AES128-SHA', 'priority': 6},
|
||||||
|
{'name': 'ECDHE-ECDSA-AES256-GCM-SHA384', 'priority': 7},
|
||||||
|
{'name': 'ECDHE-RSA-AES256-GCM-SHA384', 'priority': 8},
|
||||||
|
{'name': 'ECDHE-ECDSA-AES256-SHA384', 'priority': 9},
|
||||||
|
{'name': 'ECDHE-RSA-AES256-SHA384', 'priority': 10},
|
||||||
|
{'name': 'ECDHE-RSA-AES256-SHA', 'priority': 11},
|
||||||
|
{'name': 'ECDHE-ECDSA-AES256-SHA', 'priority': 12},
|
||||||
|
{'name': 'AES128-GCM-SHA256', 'priority': 13},
|
||||||
|
{'name': 'AES128-SHA256', 'priority': 14},
|
||||||
|
{'name': 'AES128-SHA', 'priority': 15},
|
||||||
|
{'name': 'AES256-GCM-SHA384', 'priority': 16},
|
||||||
|
{'name': 'AES256-SHA256', 'priority': 17},
|
||||||
|
{'name': 'AES256-SHA', 'priority': 18}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'ELBSecurityPolicy-TLS-1-0-2015-04',
|
||||||
|
'ssl_protocols': ['TLSv1', 'TLSv1.1', 'TLSv1.2'],
|
||||||
|
'ciphers': [
|
||||||
|
{'name': 'ECDHE-ECDSA-AES128-GCM-SHA256', 'priority': 1},
|
||||||
|
{'name': 'ECDHE-RSA-AES128-GCM-SHA256', 'priority': 2},
|
||||||
|
{'name': 'ECDHE-ECDSA-AES128-SHA256', 'priority': 3},
|
||||||
|
{'name': 'ECDHE-RSA-AES128-SHA256', 'priority': 4},
|
||||||
|
{'name': 'ECDHE-ECDSA-AES128-SHA', 'priority': 5},
|
||||||
|
{'name': 'ECDHE-RSA-AES128-SHA', 'priority': 6},
|
||||||
|
{'name': 'ECDHE-ECDSA-AES256-GCM-SHA384', 'priority': 7},
|
||||||
|
{'name': 'ECDHE-RSA-AES256-GCM-SHA384', 'priority': 8},
|
||||||
|
{'name': 'ECDHE-ECDSA-AES256-SHA384', 'priority': 9},
|
||||||
|
{'name': 'ECDHE-RSA-AES256-SHA384', 'priority': 10},
|
||||||
|
{'name': 'ECDHE-RSA-AES256-SHA', 'priority': 11},
|
||||||
|
{'name': 'ECDHE-ECDSA-AES256-SHA', 'priority': 12},
|
||||||
|
{'name': 'AES128-GCM-SHA256', 'priority': 13},
|
||||||
|
{'name': 'AES128-SHA256', 'priority': 14},
|
||||||
|
{'name': 'AES128-SHA', 'priority': 15},
|
||||||
|
{'name': 'AES256-GCM-SHA384', 'priority': 16},
|
||||||
|
{'name': 'AES256-SHA256', 'priority': 17},
|
||||||
|
{'name': 'AES256-SHA', 'priority': 18},
|
||||||
|
{'name': 'DES-CBC3-SHA', 'priority': 19}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class ELBV2Response(BaseResponse):
|
||||||
@property
|
@property
|
||||||
def elbv2_backend(self):
|
def elbv2_backend(self):
|
||||||
return elbv2_backends[self.region]
|
return elbv2_backends[self.region]
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
def create_load_balancer(self):
|
def create_load_balancer(self):
|
||||||
load_balancer_name = self._get_param('Name')
|
load_balancer_name = self._get_param('Name')
|
||||||
subnet_ids = self._get_multi_param("Subnets.member")
|
subnet_ids = self._get_multi_param("Subnets.member")
|
||||||
@ -28,6 +149,7 @@ class ELBV2Response(BaseResponse):
|
|||||||
template = self.response_template(CREATE_LOAD_BALANCER_TEMPLATE)
|
template = self.response_template(CREATE_LOAD_BALANCER_TEMPLATE)
|
||||||
return template.render(load_balancer=load_balancer)
|
return template.render(load_balancer=load_balancer)
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
def create_rule(self):
|
def create_rule(self):
|
||||||
lister_arn = self._get_param('ListenerArn')
|
lister_arn = self._get_param('ListenerArn')
|
||||||
_conditions = self._get_list_prefix('Conditions.member')
|
_conditions = self._get_list_prefix('Conditions.member')
|
||||||
@ -52,6 +174,7 @@ class ELBV2Response(BaseResponse):
|
|||||||
template = self.response_template(CREATE_RULE_TEMPLATE)
|
template = self.response_template(CREATE_RULE_TEMPLATE)
|
||||||
return template.render(rules=rules)
|
return template.render(rules=rules)
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
def create_target_group(self):
|
def create_target_group(self):
|
||||||
name = self._get_param('Name')
|
name = self._get_param('Name')
|
||||||
vpc_id = self._get_param('VpcId')
|
vpc_id = self._get_param('VpcId')
|
||||||
@ -64,6 +187,7 @@ class ELBV2Response(BaseResponse):
|
|||||||
healthcheck_timeout_seconds = self._get_param('HealthCheckTimeoutSeconds', '5')
|
healthcheck_timeout_seconds = self._get_param('HealthCheckTimeoutSeconds', '5')
|
||||||
healthy_threshold_count = self._get_param('HealthyThresholdCount', '5')
|
healthy_threshold_count = self._get_param('HealthyThresholdCount', '5')
|
||||||
unhealthy_threshold_count = self._get_param('UnhealthyThresholdCount', '2')
|
unhealthy_threshold_count = self._get_param('UnhealthyThresholdCount', '2')
|
||||||
|
http_codes = self._get_param('Matcher.HttpCode', '200')
|
||||||
|
|
||||||
target_group = self.elbv2_backend.create_target_group(
|
target_group = self.elbv2_backend.create_target_group(
|
||||||
name,
|
name,
|
||||||
@ -77,11 +201,13 @@ class ELBV2Response(BaseResponse):
|
|||||||
healthcheck_timeout_seconds=healthcheck_timeout_seconds,
|
healthcheck_timeout_seconds=healthcheck_timeout_seconds,
|
||||||
healthy_threshold_count=healthy_threshold_count,
|
healthy_threshold_count=healthy_threshold_count,
|
||||||
unhealthy_threshold_count=unhealthy_threshold_count,
|
unhealthy_threshold_count=unhealthy_threshold_count,
|
||||||
|
matcher={'HttpCode': http_codes}
|
||||||
)
|
)
|
||||||
|
|
||||||
template = self.response_template(CREATE_TARGET_GROUP_TEMPLATE)
|
template = self.response_template(CREATE_TARGET_GROUP_TEMPLATE)
|
||||||
return template.render(target_group=target_group)
|
return template.render(target_group=target_group)
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
def create_listener(self):
|
def create_listener(self):
|
||||||
load_balancer_arn = self._get_param('LoadBalancerArn')
|
load_balancer_arn = self._get_param('LoadBalancerArn')
|
||||||
protocol = self._get_param('Protocol')
|
protocol = self._get_param('Protocol')
|
||||||
@ -105,6 +231,7 @@ class ELBV2Response(BaseResponse):
|
|||||||
template = self.response_template(CREATE_LISTENER_TEMPLATE)
|
template = self.response_template(CREATE_LISTENER_TEMPLATE)
|
||||||
return template.render(listener=listener)
|
return template.render(listener=listener)
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
def describe_load_balancers(self):
|
def describe_load_balancers(self):
|
||||||
arns = self._get_multi_param("LoadBalancerArns.member")
|
arns = self._get_multi_param("LoadBalancerArns.member")
|
||||||
names = self._get_multi_param("Names.member")
|
names = self._get_multi_param("Names.member")
|
||||||
@ -124,6 +251,7 @@ class ELBV2Response(BaseResponse):
|
|||||||
template = self.response_template(DESCRIBE_LOAD_BALANCERS_TEMPLATE)
|
template = self.response_template(DESCRIBE_LOAD_BALANCERS_TEMPLATE)
|
||||||
return template.render(load_balancers=load_balancers_resp, marker=next_marker)
|
return template.render(load_balancers=load_balancers_resp, marker=next_marker)
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
def describe_rules(self):
|
def describe_rules(self):
|
||||||
listener_arn = self._get_param('ListenerArn')
|
listener_arn = self._get_param('ListenerArn')
|
||||||
rule_arns = self._get_multi_param('RuleArns.member') if any(k for k in list(self.querystring.keys()) if k.startswith('RuleArns.member')) else None
|
rule_arns = self._get_multi_param('RuleArns.member') if any(k for k in list(self.querystring.keys()) if k.startswith('RuleArns.member')) else None
|
||||||
@ -144,6 +272,7 @@ class ELBV2Response(BaseResponse):
|
|||||||
template = self.response_template(DESCRIBE_RULES_TEMPLATE)
|
template = self.response_template(DESCRIBE_RULES_TEMPLATE)
|
||||||
return template.render(rules=rules_resp, marker=next_marker)
|
return template.render(rules=rules_resp, marker=next_marker)
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
def describe_target_groups(self):
|
def describe_target_groups(self):
|
||||||
load_balancer_arn = self._get_param('LoadBalancerArn')
|
load_balancer_arn = self._get_param('LoadBalancerArn')
|
||||||
target_group_arns = self._get_multi_param('TargetGroupArns.member')
|
target_group_arns = self._get_multi_param('TargetGroupArns.member')
|
||||||
@ -153,6 +282,7 @@ class ELBV2Response(BaseResponse):
|
|||||||
template = self.response_template(DESCRIBE_TARGET_GROUPS_TEMPLATE)
|
template = self.response_template(DESCRIBE_TARGET_GROUPS_TEMPLATE)
|
||||||
return template.render(target_groups=target_groups)
|
return template.render(target_groups=target_groups)
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
def describe_target_group_attributes(self):
|
def describe_target_group_attributes(self):
|
||||||
target_group_arn = self._get_param('TargetGroupArn')
|
target_group_arn = self._get_param('TargetGroupArn')
|
||||||
target_group = self.elbv2_backend.target_groups.get(target_group_arn)
|
target_group = self.elbv2_backend.target_groups.get(target_group_arn)
|
||||||
@ -161,6 +291,7 @@ class ELBV2Response(BaseResponse):
|
|||||||
template = self.response_template(DESCRIBE_TARGET_GROUP_ATTRIBUTES_TEMPLATE)
|
template = self.response_template(DESCRIBE_TARGET_GROUP_ATTRIBUTES_TEMPLATE)
|
||||||
return template.render(attributes=target_group.attributes)
|
return template.render(attributes=target_group.attributes)
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
def describe_listeners(self):
|
def describe_listeners(self):
|
||||||
load_balancer_arn = self._get_param('LoadBalancerArn')
|
load_balancer_arn = self._get_param('LoadBalancerArn')
|
||||||
listener_arns = self._get_multi_param('ListenerArns.member')
|
listener_arns = self._get_multi_param('ListenerArns.member')
|
||||||
@ -171,30 +302,35 @@ class ELBV2Response(BaseResponse):
|
|||||||
template = self.response_template(DESCRIBE_LISTENERS_TEMPLATE)
|
template = self.response_template(DESCRIBE_LISTENERS_TEMPLATE)
|
||||||
return template.render(listeners=listeners)
|
return template.render(listeners=listeners)
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
def delete_load_balancer(self):
|
def delete_load_balancer(self):
|
||||||
arn = self._get_param('LoadBalancerArn')
|
arn = self._get_param('LoadBalancerArn')
|
||||||
self.elbv2_backend.delete_load_balancer(arn)
|
self.elbv2_backend.delete_load_balancer(arn)
|
||||||
template = self.response_template(DELETE_LOAD_BALANCER_TEMPLATE)
|
template = self.response_template(DELETE_LOAD_BALANCER_TEMPLATE)
|
||||||
return template.render()
|
return template.render()
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
def delete_rule(self):
|
def delete_rule(self):
|
||||||
arn = self._get_param('RuleArn')
|
arn = self._get_param('RuleArn')
|
||||||
self.elbv2_backend.delete_rule(arn)
|
self.elbv2_backend.delete_rule(arn)
|
||||||
template = self.response_template(DELETE_RULE_TEMPLATE)
|
template = self.response_template(DELETE_RULE_TEMPLATE)
|
||||||
return template.render()
|
return template.render()
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
def delete_target_group(self):
|
def delete_target_group(self):
|
||||||
arn = self._get_param('TargetGroupArn')
|
arn = self._get_param('TargetGroupArn')
|
||||||
self.elbv2_backend.delete_target_group(arn)
|
self.elbv2_backend.delete_target_group(arn)
|
||||||
template = self.response_template(DELETE_TARGET_GROUP_TEMPLATE)
|
template = self.response_template(DELETE_TARGET_GROUP_TEMPLATE)
|
||||||
return template.render()
|
return template.render()
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
def delete_listener(self):
|
def delete_listener(self):
|
||||||
arn = self._get_param('ListenerArn')
|
arn = self._get_param('ListenerArn')
|
||||||
self.elbv2_backend.delete_listener(arn)
|
self.elbv2_backend.delete_listener(arn)
|
||||||
template = self.response_template(DELETE_LISTENER_TEMPLATE)
|
template = self.response_template(DELETE_LISTENER_TEMPLATE)
|
||||||
return template.render()
|
return template.render()
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
def modify_rule(self):
|
def modify_rule(self):
|
||||||
rule_arn = self._get_param('RuleArn')
|
rule_arn = self._get_param('RuleArn')
|
||||||
_conditions = self._get_list_prefix('Conditions.member')
|
_conditions = self._get_list_prefix('Conditions.member')
|
||||||
@ -217,6 +353,7 @@ class ELBV2Response(BaseResponse):
|
|||||||
template = self.response_template(MODIFY_RULE_TEMPLATE)
|
template = self.response_template(MODIFY_RULE_TEMPLATE)
|
||||||
return template.render(rules=rules)
|
return template.render(rules=rules)
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
def modify_target_group_attributes(self):
|
def modify_target_group_attributes(self):
|
||||||
target_group_arn = self._get_param('TargetGroupArn')
|
target_group_arn = self._get_param('TargetGroupArn')
|
||||||
target_group = self.elbv2_backend.target_groups.get(target_group_arn)
|
target_group = self.elbv2_backend.target_groups.get(target_group_arn)
|
||||||
@ -230,6 +367,7 @@ class ELBV2Response(BaseResponse):
|
|||||||
template = self.response_template(MODIFY_TARGET_GROUP_ATTRIBUTES_TEMPLATE)
|
template = self.response_template(MODIFY_TARGET_GROUP_ATTRIBUTES_TEMPLATE)
|
||||||
return template.render(attributes=attributes)
|
return template.render(attributes=attributes)
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
def register_targets(self):
|
def register_targets(self):
|
||||||
target_group_arn = self._get_param('TargetGroupArn')
|
target_group_arn = self._get_param('TargetGroupArn')
|
||||||
targets = self._get_list_prefix('Targets.member')
|
targets = self._get_list_prefix('Targets.member')
|
||||||
@ -238,6 +376,7 @@ class ELBV2Response(BaseResponse):
|
|||||||
template = self.response_template(REGISTER_TARGETS_TEMPLATE)
|
template = self.response_template(REGISTER_TARGETS_TEMPLATE)
|
||||||
return template.render()
|
return template.render()
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
def deregister_targets(self):
|
def deregister_targets(self):
|
||||||
target_group_arn = self._get_param('TargetGroupArn')
|
target_group_arn = self._get_param('TargetGroupArn')
|
||||||
targets = self._get_list_prefix('Targets.member')
|
targets = self._get_list_prefix('Targets.member')
|
||||||
@ -246,6 +385,7 @@ class ELBV2Response(BaseResponse):
|
|||||||
template = self.response_template(DEREGISTER_TARGETS_TEMPLATE)
|
template = self.response_template(DEREGISTER_TARGETS_TEMPLATE)
|
||||||
return template.render()
|
return template.render()
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
def describe_target_health(self):
|
def describe_target_health(self):
|
||||||
target_group_arn = self._get_param('TargetGroupArn')
|
target_group_arn = self._get_param('TargetGroupArn')
|
||||||
targets = self._get_list_prefix('Targets.member')
|
targets = self._get_list_prefix('Targets.member')
|
||||||
@ -254,6 +394,7 @@ class ELBV2Response(BaseResponse):
|
|||||||
template = self.response_template(DESCRIBE_TARGET_HEALTH_TEMPLATE)
|
template = self.response_template(DESCRIBE_TARGET_HEALTH_TEMPLATE)
|
||||||
return template.render(target_health_descriptions=target_health_descriptions)
|
return template.render(target_health_descriptions=target_health_descriptions)
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
def set_rule_priorities(self):
|
def set_rule_priorities(self):
|
||||||
rule_priorities = self._get_list_prefix('RulePriorities.member')
|
rule_priorities = self._get_list_prefix('RulePriorities.member')
|
||||||
for rule_priority in rule_priorities:
|
for rule_priority in rule_priorities:
|
||||||
@ -262,6 +403,7 @@ class ELBV2Response(BaseResponse):
|
|||||||
template = self.response_template(SET_RULE_PRIORITIES_TEMPLATE)
|
template = self.response_template(SET_RULE_PRIORITIES_TEMPLATE)
|
||||||
return template.render(rules=rules)
|
return template.render(rules=rules)
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
def add_tags(self):
|
def add_tags(self):
|
||||||
resource_arns = self._get_multi_param('ResourceArns.member')
|
resource_arns = self._get_multi_param('ResourceArns.member')
|
||||||
|
|
||||||
@ -281,6 +423,7 @@ class ELBV2Response(BaseResponse):
|
|||||||
template = self.response_template(ADD_TAGS_TEMPLATE)
|
template = self.response_template(ADD_TAGS_TEMPLATE)
|
||||||
return template.render()
|
return template.render()
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
def remove_tags(self):
|
def remove_tags(self):
|
||||||
resource_arns = self._get_multi_param('ResourceArns.member')
|
resource_arns = self._get_multi_param('ResourceArns.member')
|
||||||
tag_keys = self._get_multi_param('TagKeys.member')
|
tag_keys = self._get_multi_param('TagKeys.member')
|
||||||
@ -301,6 +444,7 @@ class ELBV2Response(BaseResponse):
|
|||||||
template = self.response_template(REMOVE_TAGS_TEMPLATE)
|
template = self.response_template(REMOVE_TAGS_TEMPLATE)
|
||||||
return template.render()
|
return template.render()
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
def describe_tags(self):
|
def describe_tags(self):
|
||||||
resource_arns = self._get_multi_param('ResourceArns.member')
|
resource_arns = self._get_multi_param('ResourceArns.member')
|
||||||
resources = []
|
resources = []
|
||||||
@ -320,6 +464,125 @@ class ELBV2Response(BaseResponse):
|
|||||||
template = self.response_template(DESCRIBE_TAGS_TEMPLATE)
|
template = self.response_template(DESCRIBE_TAGS_TEMPLATE)
|
||||||
return template.render(resources=resources)
|
return template.render(resources=resources)
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
|
def describe_account_limits(self):
|
||||||
|
# Supports paging but not worth implementing yet
|
||||||
|
# marker = self._get_param('Marker')
|
||||||
|
# page_size = self._get_param('PageSize')
|
||||||
|
|
||||||
|
limits = {
|
||||||
|
'application-load-balancers': 20,
|
||||||
|
'target-groups': 3000,
|
||||||
|
'targets-per-application-load-balancer': 30,
|
||||||
|
'listeners-per-application-load-balancer': 50,
|
||||||
|
'rules-per-application-load-balancer': 100,
|
||||||
|
'network-load-balancers': 20,
|
||||||
|
'targets-per-network-load-balancer': 200,
|
||||||
|
'listeners-per-network-load-balancer': 50
|
||||||
|
}
|
||||||
|
|
||||||
|
template = self.response_template(DESCRIBE_LIMITS_TEMPLATE)
|
||||||
|
return template.render(limits=limits)
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
|
def describe_ssl_policies(self):
|
||||||
|
names = self._get_multi_param('Names.member.')
|
||||||
|
# Supports paging but not worth implementing yet
|
||||||
|
# marker = self._get_param('Marker')
|
||||||
|
# page_size = self._get_param('PageSize')
|
||||||
|
|
||||||
|
policies = SSL_POLICIES
|
||||||
|
if names:
|
||||||
|
policies = filter(lambda policy: policy['name'] in names, policies)
|
||||||
|
|
||||||
|
template = self.response_template(DESCRIBE_SSL_POLICIES_TEMPLATE)
|
||||||
|
return template.render(policies=policies)
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
|
def set_ip_address_type(self):
|
||||||
|
arn = self._get_param('LoadBalancerArn')
|
||||||
|
ip_type = self._get_param('IpAddressType')
|
||||||
|
|
||||||
|
self.elbv2_backend.set_ip_address_type(arn, ip_type)
|
||||||
|
|
||||||
|
template = self.response_template(SET_IP_ADDRESS_TYPE_TEMPLATE)
|
||||||
|
return template.render(ip_type=ip_type)
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
|
def set_security_groups(self):
|
||||||
|
arn = self._get_param('LoadBalancerArn')
|
||||||
|
sec_groups = self._get_multi_param('SecurityGroups.member.')
|
||||||
|
|
||||||
|
self.elbv2_backend.set_security_groups(arn, sec_groups)
|
||||||
|
|
||||||
|
template = self.response_template(SET_SECURITY_GROUPS_TEMPLATE)
|
||||||
|
return template.render(sec_groups=sec_groups)
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
|
def set_subnets(self):
|
||||||
|
arn = self._get_param('LoadBalancerArn')
|
||||||
|
subnets = self._get_multi_param('Subnets.member.')
|
||||||
|
|
||||||
|
subnet_zone_list = self.elbv2_backend.set_subnets(arn, subnets)
|
||||||
|
|
||||||
|
template = self.response_template(SET_SUBNETS_TEMPLATE)
|
||||||
|
return template.render(subnets=subnet_zone_list)
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
|
def modify_load_balancer_attributes(self):
|
||||||
|
arn = self._get_param('LoadBalancerArn')
|
||||||
|
attrs = self._get_map_prefix('Attributes.member', key_end='Key', value_end='Value')
|
||||||
|
|
||||||
|
all_attrs = self.elbv2_backend.modify_load_balancer_attributes(arn, attrs)
|
||||||
|
|
||||||
|
template = self.response_template(MODIFY_LOADBALANCER_ATTRS_TEMPLATE)
|
||||||
|
return template.render(attrs=all_attrs)
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
|
def describe_load_balancer_attributes(self):
|
||||||
|
arn = self._get_param('LoadBalancerArn')
|
||||||
|
attrs = self.elbv2_backend.describe_load_balancer_attributes(arn)
|
||||||
|
|
||||||
|
template = self.response_template(DESCRIBE_LOADBALANCER_ATTRS_TEMPLATE)
|
||||||
|
return template.render(attrs=attrs)
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
|
def modify_target_group(self):
|
||||||
|
arn = self._get_param('TargetGroupArn')
|
||||||
|
|
||||||
|
health_check_proto = self._get_param('HealthCheckProtocol') # 'HTTP' | 'HTTPS' | 'TCP',
|
||||||
|
health_check_port = self._get_param('HealthCheckPort')
|
||||||
|
health_check_path = self._get_param('HealthCheckPath')
|
||||||
|
health_check_interval = self._get_param('HealthCheckIntervalSeconds')
|
||||||
|
health_check_timeout = self._get_param('HealthCheckTimeoutSeconds')
|
||||||
|
healthy_threshold_count = self._get_param('HealthyThresholdCount')
|
||||||
|
unhealthy_threshold_count = self._get_param('UnhealthyThresholdCount')
|
||||||
|
http_codes = self._get_param('Matcher.HttpCode')
|
||||||
|
|
||||||
|
target_group = self.elbv2_backend.modify_target_group(arn, health_check_proto, health_check_port, health_check_path, health_check_interval,
|
||||||
|
health_check_timeout, healthy_threshold_count, unhealthy_threshold_count, http_codes)
|
||||||
|
|
||||||
|
template = self.response_template(MODIFY_TARGET_GROUP_TEMPLATE)
|
||||||
|
return template.render(target_group=target_group)
|
||||||
|
|
||||||
|
@amzn_request_id
|
||||||
|
def modify_listener(self):
|
||||||
|
arn = self._get_param('ListenerArn')
|
||||||
|
port = self._get_param('Port')
|
||||||
|
protocol = self._get_param('Protocol')
|
||||||
|
ssl_policy = self._get_param('SslPolicy')
|
||||||
|
certificates = self._get_list_prefix('Certificates.member')
|
||||||
|
default_actions = self._get_list_prefix('DefaultActions.member')
|
||||||
|
|
||||||
|
# Should really move SSL Policies to models
|
||||||
|
if ssl_policy is not None and ssl_policy not in [item['name'] for item in SSL_POLICIES]:
|
||||||
|
raise RESTError('SSLPolicyNotFound', 'Policy {0} not found'.format(ssl_policy))
|
||||||
|
|
||||||
|
listener = self.elbv2_backend.modify_listener(arn, port, protocol, ssl_policy, certificates, default_actions)
|
||||||
|
|
||||||
|
template = self.response_template(MODIFY_LISTENER_TEMPLATE)
|
||||||
|
return template.render(listener=listener)
|
||||||
|
|
||||||
def _add_tags(self, resource):
|
def _add_tags(self, resource):
|
||||||
tag_values = []
|
tag_values = []
|
||||||
tag_keys = []
|
tag_keys = []
|
||||||
@ -348,14 +611,14 @@ class ELBV2Response(BaseResponse):
|
|||||||
ADD_TAGS_TEMPLATE = """<AddTagsResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
ADD_TAGS_TEMPLATE = """<AddTagsResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
||||||
<AddTagsResult/>
|
<AddTagsResult/>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>360e81f7-1100-11e4-b6ed-0f30EXAMPLE</RequestId>
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</AddTagsResponse>"""
|
</AddTagsResponse>"""
|
||||||
|
|
||||||
REMOVE_TAGS_TEMPLATE = """<RemoveTagsResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
REMOVE_TAGS_TEMPLATE = """<RemoveTagsResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
||||||
<RemoveTagsResult/>
|
<RemoveTagsResult/>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>360e81f7-1100-11e4-b6ed-0f30EXAMPLE</RequestId>
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</RemoveTagsResponse>"""
|
</RemoveTagsResponse>"""
|
||||||
|
|
||||||
@ -378,11 +641,10 @@ DESCRIBE_TAGS_TEMPLATE = """<DescribeTagsResponse xmlns="http://elasticloadbalan
|
|||||||
</TagDescriptions>
|
</TagDescriptions>
|
||||||
</DescribeTagsResult>
|
</DescribeTagsResult>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>360e81f7-1100-11e4-b6ed-0f30EXAMPLE</RequestId>
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</DescribeTagsResponse>"""
|
</DescribeTagsResponse>"""
|
||||||
|
|
||||||
|
|
||||||
CREATE_LOAD_BALANCER_TEMPLATE = """<CreateLoadBalancerResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
CREATE_LOAD_BALANCER_TEMPLATE = """<CreateLoadBalancerResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
||||||
<CreateLoadBalancerResult>
|
<CreateLoadBalancerResult>
|
||||||
<LoadBalancers>
|
<LoadBalancers>
|
||||||
@ -415,7 +677,7 @@ CREATE_LOAD_BALANCER_TEMPLATE = """<CreateLoadBalancerResponse xmlns="http://ela
|
|||||||
</LoadBalancers>
|
</LoadBalancers>
|
||||||
</CreateLoadBalancerResult>
|
</CreateLoadBalancerResult>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>32d531b2-f2d0-11e5-9192-3fff33344cfa</RequestId>
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</CreateLoadBalancerResponse>"""
|
</CreateLoadBalancerResponse>"""
|
||||||
|
|
||||||
@ -452,7 +714,7 @@ CREATE_RULE_TEMPLATE = """<CreateRuleResponse xmlns="http://elasticloadbalancing
|
|||||||
</Rules>
|
</Rules>
|
||||||
</CreateRuleResult>
|
</CreateRuleResult>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>c5478c83-f397-11e5-bb98-57195a6eb84a</RequestId>
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</CreateRuleResponse>"""
|
</CreateRuleResponse>"""
|
||||||
|
|
||||||
@ -484,7 +746,7 @@ CREATE_TARGET_GROUP_TEMPLATE = """<CreateTargetGroupResponse xmlns="http://elast
|
|||||||
</TargetGroups>
|
</TargetGroups>
|
||||||
</CreateTargetGroupResult>
|
</CreateTargetGroupResult>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>b83fe90e-f2d5-11e5-b95d-3b2c1831fc26</RequestId>
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</CreateTargetGroupResponse>"""
|
</CreateTargetGroupResponse>"""
|
||||||
|
|
||||||
@ -494,11 +756,13 @@ CREATE_LISTENER_TEMPLATE = """<CreateListenerResponse xmlns="http://elasticloadb
|
|||||||
<member>
|
<member>
|
||||||
<LoadBalancerArn>{{ listener.load_balancer_arn }}</LoadBalancerArn>
|
<LoadBalancerArn>{{ listener.load_balancer_arn }}</LoadBalancerArn>
|
||||||
<Protocol>{{ listener.protocol }}</Protocol>
|
<Protocol>{{ listener.protocol }}</Protocol>
|
||||||
{% if listener.certificate %}
|
{% if listener.certificates %}
|
||||||
<Certificates>
|
<Certificates>
|
||||||
|
{% for cert in listener.certificates %}
|
||||||
<member>
|
<member>
|
||||||
<CertificateArn>{{ listener.certificate }}</CertificateArn>
|
<CertificateArn>{{ cert }}</CertificateArn>
|
||||||
</member>
|
</member>
|
||||||
|
{% endfor %}
|
||||||
</Certificates>
|
</Certificates>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<Port>{{ listener.port }}</Port>
|
<Port>{{ listener.port }}</Port>
|
||||||
@ -516,35 +780,35 @@ CREATE_LISTENER_TEMPLATE = """<CreateListenerResponse xmlns="http://elasticloadb
|
|||||||
</Listeners>
|
</Listeners>
|
||||||
</CreateListenerResult>
|
</CreateListenerResult>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>97f1bb38-f390-11e5-b95d-3b2c1831fc26</RequestId>
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</CreateListenerResponse>"""
|
</CreateListenerResponse>"""
|
||||||
|
|
||||||
DELETE_LOAD_BALANCER_TEMPLATE = """<DeleteLoadBalancerResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
DELETE_LOAD_BALANCER_TEMPLATE = """<DeleteLoadBalancerResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
||||||
<DeleteLoadBalancerResult/>
|
<DeleteLoadBalancerResult/>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>1549581b-12b7-11e3-895e-1334aEXAMPLE</RequestId>
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</DeleteLoadBalancerResponse>"""
|
</DeleteLoadBalancerResponse>"""
|
||||||
|
|
||||||
DELETE_RULE_TEMPLATE = """<DeleteRuleResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
DELETE_RULE_TEMPLATE = """<DeleteRuleResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
||||||
<DeleteRuleResult/>
|
<DeleteRuleResult/>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>1549581b-12b7-11e3-895e-1334aEXAMPLE</RequestId>
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</DeleteRuleResponse>"""
|
</DeleteRuleResponse>"""
|
||||||
|
|
||||||
DELETE_TARGET_GROUP_TEMPLATE = """<DeleteTargetGroupResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
DELETE_TARGET_GROUP_TEMPLATE = """<DeleteTargetGroupResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
||||||
<DeleteTargetGroupResult/>
|
<DeleteTargetGroupResult/>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>1549581b-12b7-11e3-895e-1334aEXAMPLE</RequestId>
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</DeleteTargetGroupResponse>"""
|
</DeleteTargetGroupResponse>"""
|
||||||
|
|
||||||
DELETE_LISTENER_TEMPLATE = """<DeleteListenerResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
DELETE_LISTENER_TEMPLATE = """<DeleteListenerResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
||||||
<DeleteListenerResult/>
|
<DeleteListenerResult/>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>1549581b-12b7-11e3-895e-1334aEXAMPLE</RequestId>
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</DeleteListenerResponse>"""
|
</DeleteListenerResponse>"""
|
||||||
|
|
||||||
@ -586,7 +850,7 @@ DESCRIBE_LOAD_BALANCERS_TEMPLATE = """<DescribeLoadBalancersResponse xmlns="http
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</DescribeLoadBalancersResult>
|
</DescribeLoadBalancersResult>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>f9880f01-7852-629d-a6c3-3ae2-666a409287e6dc0c</RequestId>
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</DescribeLoadBalancersResponse>"""
|
</DescribeLoadBalancersResponse>"""
|
||||||
|
|
||||||
@ -626,7 +890,7 @@ DESCRIBE_RULES_TEMPLATE = """<DescribeRulesResponse xmlns="http://elasticloadbal
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</DescribeRulesResult>
|
</DescribeRulesResult>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>74926cf3-f3a3-11e5-b543-9f2c3fbb9bee</RequestId>
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</DescribeRulesResponse>"""
|
</DescribeRulesResponse>"""
|
||||||
|
|
||||||
@ -665,11 +929,10 @@ DESCRIBE_TARGET_GROUPS_TEMPLATE = """<DescribeTargetGroupsResponse xmlns="http:/
|
|||||||
</TargetGroups>
|
</TargetGroups>
|
||||||
</DescribeTargetGroupsResult>
|
</DescribeTargetGroupsResult>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>70092c0e-f3a9-11e5-ae48-cff02092876b</RequestId>
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</DescribeTargetGroupsResponse>"""
|
</DescribeTargetGroupsResponse>"""
|
||||||
|
|
||||||
|
|
||||||
DESCRIBE_TARGET_GROUP_ATTRIBUTES_TEMPLATE = """<DescribeTargetGroupAttributesResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
DESCRIBE_TARGET_GROUP_ATTRIBUTES_TEMPLATE = """<DescribeTargetGroupAttributesResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
||||||
<DescribeTargetGroupAttributesResult>
|
<DescribeTargetGroupAttributesResult>
|
||||||
<Attributes>
|
<Attributes>
|
||||||
@ -682,11 +945,10 @@ DESCRIBE_TARGET_GROUP_ATTRIBUTES_TEMPLATE = """<DescribeTargetGroupAttributesRes
|
|||||||
</Attributes>
|
</Attributes>
|
||||||
</DescribeTargetGroupAttributesResult>
|
</DescribeTargetGroupAttributesResult>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>70092c0e-f3a9-11e5-ae48-cff02092876b</RequestId>
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</DescribeTargetGroupAttributesResponse>"""
|
</DescribeTargetGroupAttributesResponse>"""
|
||||||
|
|
||||||
|
|
||||||
DESCRIBE_LISTENERS_TEMPLATE = """<DescribeLoadBalancersResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
DESCRIBE_LISTENERS_TEMPLATE = """<DescribeLoadBalancersResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
||||||
<DescribeListenersResult>
|
<DescribeListenersResult>
|
||||||
<Listeners>
|
<Listeners>
|
||||||
@ -717,7 +979,7 @@ DESCRIBE_LISTENERS_TEMPLATE = """<DescribeLoadBalancersResponse xmlns="http://el
|
|||||||
</Listeners>
|
</Listeners>
|
||||||
</DescribeListenersResult>
|
</DescribeListenersResult>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>65a3a7ea-f39c-11e5-b543-9f2c3fbb9bee</RequestId>
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</DescribeLoadBalancersResponse>"""
|
</DescribeLoadBalancersResponse>"""
|
||||||
|
|
||||||
@ -732,7 +994,7 @@ CONFIGURE_HEALTH_CHECK_TEMPLATE = """<ConfigureHealthCheckResponse xmlns="http:/
|
|||||||
</HealthCheck>
|
</HealthCheck>
|
||||||
</ConfigureHealthCheckResult>
|
</ConfigureHealthCheckResult>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>f9880f01-7852-629d-a6c3-3ae2-666a409287e6dc0c</RequestId>
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</ConfigureHealthCheckResponse>"""
|
</ConfigureHealthCheckResponse>"""
|
||||||
|
|
||||||
@ -769,7 +1031,7 @@ MODIFY_RULE_TEMPLATE = """<ModifyRuleResponse xmlns="http://elasticloadbalancing
|
|||||||
</Rules>
|
</Rules>
|
||||||
</ModifyRuleResult>
|
</ModifyRuleResult>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>c5478c83-f397-11e5-bb98-57195a6eb84a</RequestId>
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</ModifyRuleResponse>"""
|
</ModifyRuleResponse>"""
|
||||||
|
|
||||||
@ -785,7 +1047,7 @@ MODIFY_TARGET_GROUP_ATTRIBUTES_TEMPLATE = """<ModifyTargetGroupAttributesRespons
|
|||||||
</Attributes>
|
</Attributes>
|
||||||
</ModifyTargetGroupAttributesResult>
|
</ModifyTargetGroupAttributesResult>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>70092c0e-f3a9-11e5-ae48-cff02092876b</RequestId>
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</ModifyTargetGroupAttributesResponse>"""
|
</ModifyTargetGroupAttributesResponse>"""
|
||||||
|
|
||||||
@ -793,7 +1055,7 @@ REGISTER_TARGETS_TEMPLATE = """<RegisterTargetsResponse xmlns="http://elasticloa
|
|||||||
<RegisterTargetsResult>
|
<RegisterTargetsResult>
|
||||||
</RegisterTargetsResult>
|
</RegisterTargetsResult>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>f9880f01-7852-629d-a6c3-3ae2-666a409287e6dc0c</RequestId>
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</RegisterTargetsResponse>"""
|
</RegisterTargetsResponse>"""
|
||||||
|
|
||||||
@ -801,22 +1063,21 @@ DEREGISTER_TARGETS_TEMPLATE = """<DeregisterTargetsResponse xmlns="http://elasti
|
|||||||
<DeregisterTargetsResult>
|
<DeregisterTargetsResult>
|
||||||
</DeregisterTargetsResult>
|
</DeregisterTargetsResult>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>f9880f01-7852-629d-a6c3-3ae2-666a409287e6dc0c</RequestId>
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</DeregisterTargetsResponse>"""
|
</DeregisterTargetsResponse>"""
|
||||||
|
|
||||||
SET_LOAD_BALANCER_SSL_CERTIFICATE = """<SetLoadBalancerListenerSSLCertificateResponse xmlns="http://elasticloadbalan cing.amazonaws.com/doc/2015-12-01/">
|
SET_LOAD_BALANCER_SSL_CERTIFICATE = """<SetLoadBalancerListenerSSLCertificateResponse xmlns="http://elasticloadbalan cing.amazonaws.com/doc/2015-12-01/">
|
||||||
<SetLoadBalancerListenerSSLCertificateResult/>
|
<SetLoadBalancerListenerSSLCertificateResult/>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>83c88b9d-12b7-11e3-8b82-87b12EXAMPLE</RequestId>
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</SetLoadBalancerListenerSSLCertificateResponse>"""
|
</SetLoadBalancerListenerSSLCertificateResponse>"""
|
||||||
|
|
||||||
|
|
||||||
DELETE_LOAD_BALANCER_LISTENERS = """<DeleteLoadBalancerListenersResponse xmlns="http://elasticloadbalan cing.amazonaws.com/doc/2015-12-01/">
|
DELETE_LOAD_BALANCER_LISTENERS = """<DeleteLoadBalancerListenersResponse xmlns="http://elasticloadbalan cing.amazonaws.com/doc/2015-12-01/">
|
||||||
<DeleteLoadBalancerListenersResult/>
|
<DeleteLoadBalancerListenersResult/>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>83c88b9d-12b7-11e3-8b82-87b12EXAMPLE</RequestId>
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</DeleteLoadBalancerListenersResponse>"""
|
</DeleteLoadBalancerListenersResponse>"""
|
||||||
|
|
||||||
@ -848,7 +1109,7 @@ DESCRIBE_ATTRIBUTES_TEMPLATE = """<DescribeLoadBalancerAttributesResponse xmlns
|
|||||||
</LoadBalancerAttributes>
|
</LoadBalancerAttributes>
|
||||||
</DescribeLoadBalancerAttributesResult>
|
</DescribeLoadBalancerAttributesResult>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>83c88b9d-12b7-11e3-8b82-87b12EXAMPLE</RequestId>
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</DescribeLoadBalancerAttributesResponse>
|
</DescribeLoadBalancerAttributesResponse>
|
||||||
"""
|
"""
|
||||||
@ -882,7 +1143,7 @@ MODIFY_ATTRIBUTES_TEMPLATE = """<ModifyLoadBalancerAttributesResponse xmlns="htt
|
|||||||
</LoadBalancerAttributes>
|
</LoadBalancerAttributes>
|
||||||
</ModifyLoadBalancerAttributesResult>
|
</ModifyLoadBalancerAttributesResult>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>83c88b9d-12b7-11e3-8b82-87b12EXAMPLE</RequestId>
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</ModifyLoadBalancerAttributesResponse>
|
</ModifyLoadBalancerAttributesResponse>
|
||||||
"""
|
"""
|
||||||
@ -890,7 +1151,7 @@ MODIFY_ATTRIBUTES_TEMPLATE = """<ModifyLoadBalancerAttributesResponse xmlns="htt
|
|||||||
CREATE_LOAD_BALANCER_POLICY_TEMPLATE = """<CreateLoadBalancerPolicyResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
CREATE_LOAD_BALANCER_POLICY_TEMPLATE = """<CreateLoadBalancerPolicyResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
||||||
<CreateLoadBalancerPolicyResult/>
|
<CreateLoadBalancerPolicyResult/>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>83c88b9d-12b7-11e3-8b82-87b12EXAMPLE</RequestId>
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</CreateLoadBalancerPolicyResponse>
|
</CreateLoadBalancerPolicyResponse>
|
||||||
"""
|
"""
|
||||||
@ -898,7 +1159,7 @@ CREATE_LOAD_BALANCER_POLICY_TEMPLATE = """<CreateLoadBalancerPolicyResponse xmln
|
|||||||
SET_LOAD_BALANCER_POLICIES_OF_LISTENER_TEMPLATE = """<SetLoadBalancerPoliciesOfListenerResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
SET_LOAD_BALANCER_POLICIES_OF_LISTENER_TEMPLATE = """<SetLoadBalancerPoliciesOfListenerResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
||||||
<SetLoadBalancerPoliciesOfListenerResult/>
|
<SetLoadBalancerPoliciesOfListenerResult/>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>07b1ecbc-1100-11e3-acaf-dd7edEXAMPLE</RequestId>
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</SetLoadBalancerPoliciesOfListenerResponse>
|
</SetLoadBalancerPoliciesOfListenerResponse>
|
||||||
"""
|
"""
|
||||||
@ -906,7 +1167,7 @@ SET_LOAD_BALANCER_POLICIES_OF_LISTENER_TEMPLATE = """<SetLoadBalancerPoliciesOfL
|
|||||||
SET_LOAD_BALANCER_POLICIES_FOR_BACKEND_SERVER_TEMPLATE = """<SetLoadBalancerPoliciesForBackendServerResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
SET_LOAD_BALANCER_POLICIES_FOR_BACKEND_SERVER_TEMPLATE = """<SetLoadBalancerPoliciesForBackendServerResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
||||||
<SetLoadBalancerPoliciesForBackendServerResult/>
|
<SetLoadBalancerPoliciesForBackendServerResult/>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>0eb9b381-dde0-11e2-8d78-6ddbaEXAMPLE</RequestId>
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</SetLoadBalancerPoliciesForBackendServerResponse>
|
</SetLoadBalancerPoliciesForBackendServerResponse>
|
||||||
"""
|
"""
|
||||||
@ -929,7 +1190,7 @@ DESCRIBE_TARGET_HEALTH_TEMPLATE = """<DescribeTargetHealthResponse xmlns="http:/
|
|||||||
</TargetHealthDescriptions>
|
</TargetHealthDescriptions>
|
||||||
</DescribeTargetHealthResult>
|
</DescribeTargetHealthResult>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>c534f810-f389-11e5-9192-3fff33344cfa</RequestId>
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</DescribeTargetHealthResponse>"""
|
</DescribeTargetHealthResponse>"""
|
||||||
|
|
||||||
@ -966,6 +1227,186 @@ SET_RULE_PRIORITIES_TEMPLATE = """<SetRulePrioritiesResponse xmlns="http://elast
|
|||||||
</Rules>
|
</Rules>
|
||||||
</SetRulePrioritiesResult>
|
</SetRulePrioritiesResult>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>4d7a8036-f3a7-11e5-9c02-8fd20490d5a6</RequestId>
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</SetRulePrioritiesResponse>"""
|
</SetRulePrioritiesResponse>"""
|
||||||
|
|
||||||
|
DESCRIBE_LIMITS_TEMPLATE = """<DescribeAccountLimitsResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
||||||
|
<DescribeAccountLimitsResult>
|
||||||
|
<Limits>
|
||||||
|
{% for key, value in limits.items() %}
|
||||||
|
<member>
|
||||||
|
<Name>{{ key }}</Name>
|
||||||
|
<Max>{{ value }}</Max>
|
||||||
|
</member>
|
||||||
|
{% endfor %}
|
||||||
|
</Limits>
|
||||||
|
</DescribeAccountLimitsResult>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</DescribeAccountLimitsResponse>"""
|
||||||
|
|
||||||
|
DESCRIBE_SSL_POLICIES_TEMPLATE = """<DescribeSSLPoliciesResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
||||||
|
<DescribeSSLPoliciesResult>
|
||||||
|
<SslPolicies>
|
||||||
|
{% for policy in policies %}
|
||||||
|
<member>
|
||||||
|
<Name>{{ policy['name'] }}</Name>
|
||||||
|
<Ciphers>
|
||||||
|
{% for cipher in policy['ciphers'] %}
|
||||||
|
<member>
|
||||||
|
<Name>{{ cipher['name'] }}</Name>
|
||||||
|
<Priority>{{ cipher['priority'] }}</Priority>
|
||||||
|
</member>
|
||||||
|
{% endfor %}
|
||||||
|
</Ciphers>
|
||||||
|
<SslProtocols>
|
||||||
|
{% for proto in policy['ssl_protocols'] %}
|
||||||
|
<member>{{ proto }}</member>
|
||||||
|
{% endfor %}
|
||||||
|
</SslProtocols>
|
||||||
|
</member>
|
||||||
|
{% endfor %}
|
||||||
|
</SslPolicies>
|
||||||
|
</DescribeSSLPoliciesResult>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</DescribeSSLPoliciesResponse>"""
|
||||||
|
|
||||||
|
SET_IP_ADDRESS_TYPE_TEMPLATE = """<SetIpAddressTypeResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
||||||
|
<SetIpAddressTypeResult>
|
||||||
|
<IpAddressType>{{ ip_type }}</IpAddressType>
|
||||||
|
</SetIpAddressTypeResult>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</SetIpAddressTypeResponse>"""
|
||||||
|
|
||||||
|
SET_SECURITY_GROUPS_TEMPLATE = """<SetSecurityGroupsResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
||||||
|
<SetSecurityGroupsResult>
|
||||||
|
<SecurityGroupIds>
|
||||||
|
{% for group in sec_groups %}
|
||||||
|
<member>{{ group }}</member>
|
||||||
|
{% endfor %}
|
||||||
|
</SecurityGroupIds>
|
||||||
|
</SetSecurityGroupsResult>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</SetSecurityGroupsResponse>"""
|
||||||
|
|
||||||
|
SET_SUBNETS_TEMPLATE = """<SetSubnetsResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
||||||
|
<SetSubnetsResult>
|
||||||
|
<AvailabilityZones>
|
||||||
|
{% for zone_id, subnet_id in subnets %}
|
||||||
|
<member>
|
||||||
|
<SubnetId>{{ subnet_id }}</SubnetId>
|
||||||
|
<ZoneName>{{ zone_id }}</ZoneName>
|
||||||
|
</member>
|
||||||
|
{% endfor %}
|
||||||
|
</AvailabilityZones>
|
||||||
|
</SetSubnetsResult>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</SetSubnetsResponse>"""
|
||||||
|
|
||||||
|
MODIFY_LOADBALANCER_ATTRS_TEMPLATE = """<ModifyLoadBalancerAttributesResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
||||||
|
<ModifyLoadBalancerAttributesResult>
|
||||||
|
<Attributes>
|
||||||
|
{% for key, value in attrs.items() %}
|
||||||
|
<member>
|
||||||
|
{% if value == None %}<Value />{% else %}<Value>{{ value }}</Value>{% endif %}
|
||||||
|
<Key>{{ key }}</Key>
|
||||||
|
</member>
|
||||||
|
{% endfor %}
|
||||||
|
</Attributes>
|
||||||
|
</ModifyLoadBalancerAttributesResult>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</ModifyLoadBalancerAttributesResponse>"""
|
||||||
|
|
||||||
|
DESCRIBE_LOADBALANCER_ATTRS_TEMPLATE = """<DescribeLoadBalancerAttributesResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
||||||
|
<DescribeLoadBalancerAttributesResult>
|
||||||
|
<Attributes>
|
||||||
|
{% for key, value in attrs.items() %}
|
||||||
|
<member>
|
||||||
|
{% if value == None %}<Value />{% else %}<Value>{{ value }}</Value>{% endif %}
|
||||||
|
<Key>{{ key }}</Key>
|
||||||
|
</member>
|
||||||
|
{% endfor %}
|
||||||
|
</Attributes>
|
||||||
|
</DescribeLoadBalancerAttributesResult>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</DescribeLoadBalancerAttributesResponse>"""
|
||||||
|
|
||||||
|
MODIFY_TARGET_GROUP_TEMPLATE = """<ModifyTargetGroupResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
||||||
|
<ModifyTargetGroupResult>
|
||||||
|
<TargetGroups>
|
||||||
|
<member>
|
||||||
|
<TargetGroupArn>{{ target_group.arn }}</TargetGroupArn>
|
||||||
|
<TargetGroupName>{{ target_group.name }}</TargetGroupName>
|
||||||
|
<Protocol>{{ target_group.protocol }}</Protocol>
|
||||||
|
<Port>{{ target_group.port }}</Port>
|
||||||
|
<VpcId>{{ target_group.vpc_id }}</VpcId>
|
||||||
|
<HealthCheckProtocol>{{ target_group.healthcheck_protocol }}</HealthCheckProtocol>
|
||||||
|
<HealthCheckPort>{{ target_group.healthcheck_port }}</HealthCheckPort>
|
||||||
|
<HealthCheckPath>{{ target_group.healthcheck_path }}</HealthCheckPath>
|
||||||
|
<HealthCheckIntervalSeconds>{{ target_group.healthcheck_interval_seconds }}</HealthCheckIntervalSeconds>
|
||||||
|
<HealthCheckTimeoutSeconds>{{ target_group.healthcheck_timeout_seconds }}</HealthCheckTimeoutSeconds>
|
||||||
|
<HealthyThresholdCount>{{ target_group.healthy_threshold_count }}</HealthyThresholdCount>
|
||||||
|
<UnhealthyThresholdCount>{{ target_group.unhealthy_threshold_count }}</UnhealthyThresholdCount>
|
||||||
|
<Matcher>
|
||||||
|
<HttpCode>{{ target_group.matcher['HttpCode'] }}</HttpCode>
|
||||||
|
</Matcher>
|
||||||
|
<LoadBalancerArns>
|
||||||
|
{% for load_balancer_arn in target_group.load_balancer_arns %}
|
||||||
|
<member>{{ load_balancer_arn }}</member>
|
||||||
|
{% endfor %}
|
||||||
|
</LoadBalancerArns>
|
||||||
|
</member>
|
||||||
|
</TargetGroups>
|
||||||
|
</ModifyTargetGroupResult>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</ModifyTargetGroupResponse>"""
|
||||||
|
|
||||||
|
MODIFY_LISTENER_TEMPLATE = """<ModifyListenerResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2015-12-01/">
|
||||||
|
<ModifyListenerResult>
|
||||||
|
<Listeners>
|
||||||
|
<member>
|
||||||
|
<LoadBalancerArn>{{ listener.load_balancer_arn }}</LoadBalancerArn>
|
||||||
|
<Protocol>{{ listener.protocol }}</Protocol>
|
||||||
|
{% if listener.certificates %}
|
||||||
|
<Certificates>
|
||||||
|
{% for cert in listener.certificates %}
|
||||||
|
<member>
|
||||||
|
<CertificateArn>{{ cert }}</CertificateArn>
|
||||||
|
</member>
|
||||||
|
{% endfor %}
|
||||||
|
</Certificates>
|
||||||
|
{% endif %}
|
||||||
|
<Port>{{ listener.port }}</Port>
|
||||||
|
<SslPolicy>{{ listener.ssl_policy }}</SslPolicy>
|
||||||
|
<ListenerArn>{{ listener.arn }}</ListenerArn>
|
||||||
|
<DefaultActions>
|
||||||
|
{% for action in listener.default_actions %}
|
||||||
|
<member>
|
||||||
|
<Type>{{ action.type }}</Type>
|
||||||
|
<TargetGroupArn>{{ action.target_group_arn }}</TargetGroupArn>
|
||||||
|
</member>
|
||||||
|
{% endfor %}
|
||||||
|
</DefaultActions>
|
||||||
|
</member>
|
||||||
|
</Listeners>
|
||||||
|
</ModifyListenerResult>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</ModifyListenerResponse>"""
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
from moto.core.exceptions import JsonRESTError
|
||||||
from moto.core import BaseBackend, BaseModel
|
from moto.core import BaseBackend, BaseModel
|
||||||
|
|
||||||
|
|
||||||
@ -50,6 +51,8 @@ class Rule(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class EventsBackend(BaseBackend):
|
class EventsBackend(BaseBackend):
|
||||||
|
ACCOUNT_ID = re.compile(r'^(\d{1,12}|\*)$')
|
||||||
|
STATEMENT_ID = re.compile(r'^[a-zA-Z0-9-_]{1,64}$')
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.rules = {}
|
self.rules = {}
|
||||||
@ -58,6 +61,8 @@ class EventsBackend(BaseBackend):
|
|||||||
self.rules_order = []
|
self.rules_order = []
|
||||||
self.next_tokens = {}
|
self.next_tokens = {}
|
||||||
|
|
||||||
|
self.permissions = {}
|
||||||
|
|
||||||
def _get_rule_by_index(self, i):
|
def _get_rule_by_index(self, i):
|
||||||
return self.rules.get(self.rules_order[i])
|
return self.rules.get(self.rules_order[i])
|
||||||
|
|
||||||
@ -181,6 +186,17 @@ class EventsBackend(BaseBackend):
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def put_events(self, events):
|
||||||
|
num_events = len(events)
|
||||||
|
|
||||||
|
if num_events < 1:
|
||||||
|
raise JsonRESTError('ValidationError', 'Need at least 1 event')
|
||||||
|
elif num_events > 10:
|
||||||
|
raise JsonRESTError('ValidationError', 'Can only submit 10 events at once')
|
||||||
|
|
||||||
|
# We dont really need to store the events yet
|
||||||
|
return []
|
||||||
|
|
||||||
def remove_targets(self, name, ids):
|
def remove_targets(self, name, ids):
|
||||||
rule = self.rules.get(name)
|
rule = self.rules.get(name)
|
||||||
|
|
||||||
@ -193,5 +209,40 @@ class EventsBackend(BaseBackend):
|
|||||||
def test_event_pattern(self):
|
def test_event_pattern(self):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def put_permission(self, action, principal, statement_id):
|
||||||
|
if action is None or action != 'PutEvents':
|
||||||
|
raise JsonRESTError('InvalidParameterValue', 'Action must be PutEvents')
|
||||||
|
|
||||||
|
if principal is None or self.ACCOUNT_ID.match(principal) is None:
|
||||||
|
raise JsonRESTError('InvalidParameterValue', 'Principal must match ^(\d{1,12}|\*)$')
|
||||||
|
|
||||||
|
if statement_id is None or self.STATEMENT_ID.match(statement_id) is None:
|
||||||
|
raise JsonRESTError('InvalidParameterValue', 'StatementId must match ^[a-zA-Z0-9-_]{1,64}$')
|
||||||
|
|
||||||
|
self.permissions[statement_id] = {'action': action, 'principal': principal}
|
||||||
|
|
||||||
|
def remove_permission(self, statement_id):
|
||||||
|
try:
|
||||||
|
del self.permissions[statement_id]
|
||||||
|
except KeyError:
|
||||||
|
raise JsonRESTError('ResourceNotFoundException', 'StatementId not found')
|
||||||
|
|
||||||
|
def describe_event_bus(self):
|
||||||
|
arn = "arn:aws:events:us-east-1:000000000000:event-bus/default"
|
||||||
|
statements = []
|
||||||
|
for statement_id, data in self.permissions.items():
|
||||||
|
statements.append({
|
||||||
|
'Sid': statement_id,
|
||||||
|
'Effect': 'Allow',
|
||||||
|
'Principal': {'AWS': 'arn:aws:iam::{0}:root'.format(data['principal'])},
|
||||||
|
'Action': 'events:{0}'.format(data['action']),
|
||||||
|
'Resource': arn
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
'Policy': {'Version': '2012-10-17', 'Statement': statements},
|
||||||
|
'Name': 'default',
|
||||||
|
'Arn': arn
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
events_backend = EventsBackend()
|
events_backend = EventsBackend()
|
||||||
|
@ -18,9 +18,17 @@ class EventsHandler(BaseResponse):
|
|||||||
'RoleArn': rule.role_arn
|
'RoleArn': rule.role_arn
|
||||||
}
|
}
|
||||||
|
|
||||||
def load_body(self):
|
@property
|
||||||
decoded_body = self.body
|
def request_params(self):
|
||||||
return json.loads(decoded_body or '{}')
|
if not hasattr(self, '_json_body'):
|
||||||
|
try:
|
||||||
|
self._json_body = json.loads(self.body)
|
||||||
|
except ValueError:
|
||||||
|
self._json_body = {}
|
||||||
|
return self._json_body
|
||||||
|
|
||||||
|
def _get_param(self, param, if_none=None):
|
||||||
|
return self.request_params.get(param, if_none)
|
||||||
|
|
||||||
def error(self, type_, message='', status=400):
|
def error(self, type_, message='', status=400):
|
||||||
headers = self.response_headers
|
headers = self.response_headers
|
||||||
@ -28,8 +36,7 @@ class EventsHandler(BaseResponse):
|
|||||||
return json.dumps({'__type': type_, 'message': message}), headers,
|
return json.dumps({'__type': type_, 'message': message}), headers,
|
||||||
|
|
||||||
def delete_rule(self):
|
def delete_rule(self):
|
||||||
body = self.load_body()
|
name = self._get_param('Name')
|
||||||
name = body.get('Name')
|
|
||||||
|
|
||||||
if not name:
|
if not name:
|
||||||
return self.error('ValidationException', 'Parameter Name is required.')
|
return self.error('ValidationException', 'Parameter Name is required.')
|
||||||
@ -38,8 +45,7 @@ class EventsHandler(BaseResponse):
|
|||||||
return '', self.response_headers
|
return '', self.response_headers
|
||||||
|
|
||||||
def describe_rule(self):
|
def describe_rule(self):
|
||||||
body = self.load_body()
|
name = self._get_param('Name')
|
||||||
name = body.get('Name')
|
|
||||||
|
|
||||||
if not name:
|
if not name:
|
||||||
return self.error('ValidationException', 'Parameter Name is required.')
|
return self.error('ValidationException', 'Parameter Name is required.')
|
||||||
@ -53,8 +59,7 @@ class EventsHandler(BaseResponse):
|
|||||||
return json.dumps(rule_dict), self.response_headers
|
return json.dumps(rule_dict), self.response_headers
|
||||||
|
|
||||||
def disable_rule(self):
|
def disable_rule(self):
|
||||||
body = self.load_body()
|
name = self._get_param('Name')
|
||||||
name = body.get('Name')
|
|
||||||
|
|
||||||
if not name:
|
if not name:
|
||||||
return self.error('ValidationException', 'Parameter Name is required.')
|
return self.error('ValidationException', 'Parameter Name is required.')
|
||||||
@ -65,8 +70,7 @@ class EventsHandler(BaseResponse):
|
|||||||
return '', self.response_headers
|
return '', self.response_headers
|
||||||
|
|
||||||
def enable_rule(self):
|
def enable_rule(self):
|
||||||
body = self.load_body()
|
name = self._get_param('Name')
|
||||||
name = body.get('Name')
|
|
||||||
|
|
||||||
if not name:
|
if not name:
|
||||||
return self.error('ValidationException', 'Parameter Name is required.')
|
return self.error('ValidationException', 'Parameter Name is required.')
|
||||||
@ -80,10 +84,9 @@ class EventsHandler(BaseResponse):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def list_rule_names_by_target(self):
|
def list_rule_names_by_target(self):
|
||||||
body = self.load_body()
|
target_arn = self._get_param('TargetArn')
|
||||||
target_arn = body.get('TargetArn')
|
next_token = self._get_param('NextToken')
|
||||||
next_token = body.get('NextToken')
|
limit = self._get_param('Limit')
|
||||||
limit = body.get('Limit')
|
|
||||||
|
|
||||||
if not target_arn:
|
if not target_arn:
|
||||||
return self.error('ValidationException', 'Parameter TargetArn is required.')
|
return self.error('ValidationException', 'Parameter TargetArn is required.')
|
||||||
@ -94,10 +97,9 @@ class EventsHandler(BaseResponse):
|
|||||||
return json.dumps(rule_names), self.response_headers
|
return json.dumps(rule_names), self.response_headers
|
||||||
|
|
||||||
def list_rules(self):
|
def list_rules(self):
|
||||||
body = self.load_body()
|
prefix = self._get_param('NamePrefix')
|
||||||
prefix = body.get('NamePrefix')
|
next_token = self._get_param('NextToken')
|
||||||
next_token = body.get('NextToken')
|
limit = self._get_param('Limit')
|
||||||
limit = body.get('Limit')
|
|
||||||
|
|
||||||
rules = events_backend.list_rules(prefix, next_token, limit)
|
rules = events_backend.list_rules(prefix, next_token, limit)
|
||||||
rules_obj = {'Rules': []}
|
rules_obj = {'Rules': []}
|
||||||
@ -111,10 +113,9 @@ class EventsHandler(BaseResponse):
|
|||||||
return json.dumps(rules_obj), self.response_headers
|
return json.dumps(rules_obj), self.response_headers
|
||||||
|
|
||||||
def list_targets_by_rule(self):
|
def list_targets_by_rule(self):
|
||||||
body = self.load_body()
|
rule_name = self._get_param('Rule')
|
||||||
rule_name = body.get('Rule')
|
next_token = self._get_param('NextToken')
|
||||||
next_token = body.get('NextToken')
|
limit = self._get_param('Limit')
|
||||||
limit = body.get('Limit')
|
|
||||||
|
|
||||||
if not rule_name:
|
if not rule_name:
|
||||||
return self.error('ValidationException', 'Parameter Rule is required.')
|
return self.error('ValidationException', 'Parameter Rule is required.')
|
||||||
@ -128,13 +129,25 @@ class EventsHandler(BaseResponse):
|
|||||||
return json.dumps(targets), self.response_headers
|
return json.dumps(targets), self.response_headers
|
||||||
|
|
||||||
def put_events(self):
|
def put_events(self):
|
||||||
|
events = self._get_param('Entries')
|
||||||
|
|
||||||
|
failed_entries = events_backend.put_events(events)
|
||||||
|
|
||||||
|
if failed_entries:
|
||||||
|
return json.dumps({
|
||||||
|
'FailedEntryCount': len(failed_entries),
|
||||||
|
'Entries': failed_entries
|
||||||
|
})
|
||||||
|
|
||||||
return '', self.response_headers
|
return '', self.response_headers
|
||||||
|
|
||||||
def put_rule(self):
|
def put_rule(self):
|
||||||
body = self.load_body()
|
name = self._get_param('Name')
|
||||||
name = body.get('Name')
|
event_pattern = self._get_param('EventPattern')
|
||||||
event_pattern = body.get('EventPattern')
|
sched_exp = self._get_param('ScheduleExpression')
|
||||||
sched_exp = body.get('ScheduleExpression')
|
state = self._get_param('State')
|
||||||
|
desc = self._get_param('Description')
|
||||||
|
role_arn = self._get_param('RoleArn')
|
||||||
|
|
||||||
if not name:
|
if not name:
|
||||||
return self.error('ValidationException', 'Parameter Name is required.')
|
return self.error('ValidationException', 'Parameter Name is required.')
|
||||||
@ -156,17 +169,16 @@ class EventsHandler(BaseResponse):
|
|||||||
name,
|
name,
|
||||||
ScheduleExpression=sched_exp,
|
ScheduleExpression=sched_exp,
|
||||||
EventPattern=event_pattern,
|
EventPattern=event_pattern,
|
||||||
State=body.get('State'),
|
State=state,
|
||||||
Description=body.get('Description'),
|
Description=desc,
|
||||||
RoleArn=body.get('RoleArn')
|
RoleArn=role_arn
|
||||||
)
|
)
|
||||||
|
|
||||||
return json.dumps({'RuleArn': rule_arn}), self.response_headers
|
return json.dumps({'RuleArn': rule_arn}), self.response_headers
|
||||||
|
|
||||||
def put_targets(self):
|
def put_targets(self):
|
||||||
body = self.load_body()
|
rule_name = self._get_param('Rule')
|
||||||
rule_name = body.get('Rule')
|
targets = self._get_param('Targets')
|
||||||
targets = body.get('Targets')
|
|
||||||
|
|
||||||
if not rule_name:
|
if not rule_name:
|
||||||
return self.error('ValidationException', 'Parameter Rule is required.')
|
return self.error('ValidationException', 'Parameter Rule is required.')
|
||||||
@ -180,9 +192,8 @@ class EventsHandler(BaseResponse):
|
|||||||
return '', self.response_headers
|
return '', self.response_headers
|
||||||
|
|
||||||
def remove_targets(self):
|
def remove_targets(self):
|
||||||
body = self.load_body()
|
rule_name = self._get_param('Rule')
|
||||||
rule_name = body.get('Rule')
|
ids = self._get_param('Ids')
|
||||||
ids = body.get('Ids')
|
|
||||||
|
|
||||||
if not rule_name:
|
if not rule_name:
|
||||||
return self.error('ValidationException', 'Parameter Rule is required.')
|
return self.error('ValidationException', 'Parameter Rule is required.')
|
||||||
@ -197,3 +208,22 @@ class EventsHandler(BaseResponse):
|
|||||||
|
|
||||||
def test_event_pattern(self):
|
def test_event_pattern(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def put_permission(self):
|
||||||
|
action = self._get_param('Action')
|
||||||
|
principal = self._get_param('Principal')
|
||||||
|
statement_id = self._get_param('StatementId')
|
||||||
|
|
||||||
|
events_backend.put_permission(action, principal, statement_id)
|
||||||
|
|
||||||
|
return ''
|
||||||
|
|
||||||
|
def remove_permission(self):
|
||||||
|
statement_id = self._get_param('StatementId')
|
||||||
|
|
||||||
|
events_backend.remove_permission(statement_id)
|
||||||
|
|
||||||
|
return ''
|
||||||
|
|
||||||
|
def describe_event_bus(self):
|
||||||
|
return json.dumps(events_backend.describe_event_bus())
|
||||||
|
@ -2,6 +2,7 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
import base64
|
import base64
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import json
|
||||||
import re
|
import re
|
||||||
import six
|
import six
|
||||||
import struct
|
import struct
|
||||||
@ -9,6 +10,7 @@ from xml.sax.saxutils import escape
|
|||||||
|
|
||||||
import boto.sqs
|
import boto.sqs
|
||||||
|
|
||||||
|
from moto.core.exceptions import RESTError
|
||||||
from moto.core import BaseBackend, BaseModel
|
from moto.core import BaseBackend, BaseModel
|
||||||
from moto.core.utils import camelcase_to_underscores, get_random_message_id, unix_time, unix_time_millis
|
from moto.core.utils import camelcase_to_underscores, get_random_message_id, unix_time, unix_time_millis
|
||||||
from .utils import generate_receipt_handle
|
from .utils import generate_receipt_handle
|
||||||
@ -166,11 +168,14 @@ class Queue(BaseModel):
|
|||||||
'ReceiveMessageWaitTimeSeconds',
|
'ReceiveMessageWaitTimeSeconds',
|
||||||
'VisibilityTimeout',
|
'VisibilityTimeout',
|
||||||
'WaitTimeSeconds']
|
'WaitTimeSeconds']
|
||||||
|
ALLOWED_PERMISSIONS = ('*', 'ChangeMessageVisibility', 'DeleteMessage', 'GetQueueAttributes',
|
||||||
|
'GetQueueUrl', 'ReceiveMessage', 'SendMessage')
|
||||||
|
|
||||||
def __init__(self, name, region, **kwargs):
|
def __init__(self, name, region, **kwargs):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.visibility_timeout = int(kwargs.get('VisibilityTimeout', 30))
|
self.visibility_timeout = int(kwargs.get('VisibilityTimeout', 30))
|
||||||
self.region = region
|
self.region = region
|
||||||
|
self.tags = {}
|
||||||
|
|
||||||
self._messages = []
|
self._messages = []
|
||||||
|
|
||||||
@ -189,14 +194,42 @@ class Queue(BaseModel):
|
|||||||
self.message_retention_period = int(kwargs.get('MessageRetentionPeriod', 86400 * 4)) # four days
|
self.message_retention_period = int(kwargs.get('MessageRetentionPeriod', 86400 * 4)) # four days
|
||||||
self.queue_arn = 'arn:aws:sqs:{0}:123456789012:{1}'.format(self.region, self.name)
|
self.queue_arn = 'arn:aws:sqs:{0}:123456789012:{1}'.format(self.region, self.name)
|
||||||
self.receive_message_wait_time_seconds = int(kwargs.get('ReceiveMessageWaitTimeSeconds', 0))
|
self.receive_message_wait_time_seconds = int(kwargs.get('ReceiveMessageWaitTimeSeconds', 0))
|
||||||
|
self.permissions = {}
|
||||||
|
|
||||||
# wait_time_seconds will be set to immediate return messages
|
# wait_time_seconds will be set to immediate return messages
|
||||||
self.wait_time_seconds = int(kwargs.get('WaitTimeSeconds', 0))
|
self.wait_time_seconds = int(kwargs.get('WaitTimeSeconds', 0))
|
||||||
|
|
||||||
|
self.redrive_policy = {}
|
||||||
|
self.dead_letter_queue = None
|
||||||
|
|
||||||
|
if 'RedrivePolicy' in kwargs:
|
||||||
|
self._setup_dlq(kwargs['RedrivePolicy'])
|
||||||
|
|
||||||
# Check some conditions
|
# Check some conditions
|
||||||
if self.fifo_queue and not self.name.endswith('.fifo'):
|
if self.fifo_queue and not self.name.endswith('.fifo'):
|
||||||
raise MessageAttributesInvalid('Queue name must end in .fifo for FIFO queues')
|
raise MessageAttributesInvalid('Queue name must end in .fifo for FIFO queues')
|
||||||
|
|
||||||
|
def _setup_dlq(self, policy_json):
|
||||||
|
try:
|
||||||
|
self.redrive_policy = json.loads(policy_json)
|
||||||
|
except ValueError:
|
||||||
|
raise RESTError('InvalidParameterValue', 'Redrive policy does not contain valid json')
|
||||||
|
|
||||||
|
if 'deadLetterTargetArn' not in self.redrive_policy:
|
||||||
|
raise RESTError('InvalidParameterValue', 'Redrive policy does not contain deadLetterTargetArn')
|
||||||
|
if 'maxReceiveCount' not in self.redrive_policy:
|
||||||
|
raise RESTError('InvalidParameterValue', 'Redrive policy does not contain maxReceiveCount')
|
||||||
|
|
||||||
|
for queue in sqs_backends[self.region].queues.values():
|
||||||
|
if queue.queue_arn == self.redrive_policy['deadLetterTargetArn']:
|
||||||
|
self.dead_letter_queue = queue
|
||||||
|
|
||||||
|
if self.fifo_queue and not queue.fifo_queue:
|
||||||
|
raise RESTError('InvalidParameterCombination', 'Fifo queues cannot use non fifo dead letter queues')
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise RESTError('AWS.SimpleQueueService.NonExistentQueue', 'Could not find DLQ for {0}'.format(self.redrive_policy['deadLetterTargetArn']))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_from_cloudformation_json(cls, resource_name, cloudformation_json, region_name):
|
def create_from_cloudformation_json(cls, resource_name, cloudformation_json, region_name):
|
||||||
properties = cloudformation_json['Properties']
|
properties = cloudformation_json['Properties']
|
||||||
@ -382,9 +415,14 @@ class SQSBackend(BaseBackend):
|
|||||||
time.sleep(0.001)
|
time.sleep(0.001)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
messages_to_dlq = []
|
||||||
for message in queue.messages:
|
for message in queue.messages:
|
||||||
if not message.visible:
|
if not message.visible:
|
||||||
continue
|
continue
|
||||||
|
if queue.dead_letter_queue is not None and message.approximate_receive_count >= queue.redrive_policy['maxReceiveCount']:
|
||||||
|
messages_to_dlq.append(message)
|
||||||
|
continue
|
||||||
|
|
||||||
message.mark_received(
|
message.mark_received(
|
||||||
visibility_timeout=visibility_timeout
|
visibility_timeout=visibility_timeout
|
||||||
)
|
)
|
||||||
@ -392,6 +430,10 @@ class SQSBackend(BaseBackend):
|
|||||||
if len(result) >= count:
|
if len(result) >= count:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
for message in messages_to_dlq:
|
||||||
|
queue._messages.remove(message)
|
||||||
|
queue.dead_letter_queue.add_message(message)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def delete_message(self, queue_name, receipt_handle):
|
def delete_message(self, queue_name, receipt_handle):
|
||||||
@ -419,6 +461,49 @@ class SQSBackend(BaseBackend):
|
|||||||
queue = self.get_queue(queue_name)
|
queue = self.get_queue(queue_name)
|
||||||
queue._messages = []
|
queue._messages = []
|
||||||
|
|
||||||
|
def list_dead_letter_source_queues(self, queue_name):
|
||||||
|
dlq = self.get_queue(queue_name)
|
||||||
|
|
||||||
|
queues = []
|
||||||
|
for queue in self.queues.values():
|
||||||
|
if queue.dead_letter_queue is dlq:
|
||||||
|
queues.append(queue)
|
||||||
|
|
||||||
|
return queues
|
||||||
|
|
||||||
|
def add_permission(self, queue_name, actions, account_ids, label):
|
||||||
|
queue = self.get_queue(queue_name)
|
||||||
|
|
||||||
|
if actions is None or len(actions) == 0:
|
||||||
|
raise RESTError('InvalidParameterValue', 'Need at least one Action')
|
||||||
|
if account_ids is None or len(account_ids) == 0:
|
||||||
|
raise RESTError('InvalidParameterValue', 'Need at least one Account ID')
|
||||||
|
|
||||||
|
if not all([item in Queue.ALLOWED_PERMISSIONS for item in actions]):
|
||||||
|
raise RESTError('InvalidParameterValue', 'Invalid permissions')
|
||||||
|
|
||||||
|
queue.permissions[label] = (account_ids, actions)
|
||||||
|
|
||||||
|
def remove_permission(self, queue_name, label):
|
||||||
|
queue = self.get_queue(queue_name)
|
||||||
|
|
||||||
|
if label not in queue.permissions:
|
||||||
|
raise RESTError('InvalidParameterValue', 'Permission doesnt exist for the given label')
|
||||||
|
|
||||||
|
del queue.permissions[label]
|
||||||
|
|
||||||
|
def tag_queue(self, queue_name, tags):
|
||||||
|
queue = self.get_queue(queue_name)
|
||||||
|
queue.tags.update(tags)
|
||||||
|
|
||||||
|
def untag_queue(self, queue_name, tag_keys):
|
||||||
|
queue = self.get_queue(queue_name)
|
||||||
|
for key in tag_keys:
|
||||||
|
try:
|
||||||
|
del queue.tags[key]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
sqs_backends = {}
|
sqs_backends = {}
|
||||||
for region in boto.sqs.regions():
|
for region in boto.sqs.regions():
|
||||||
|
@ -40,12 +40,15 @@ class SQSResponse(BaseResponse):
|
|||||||
queue_name = self.path.split("/")[-1]
|
queue_name = self.path.split("/")[-1]
|
||||||
return queue_name
|
return queue_name
|
||||||
|
|
||||||
def _get_validated_visibility_timeout(self):
|
def _get_validated_visibility_timeout(self, timeout=None):
|
||||||
"""
|
"""
|
||||||
:raises ValueError: If specified visibility timeout exceeds MAXIMUM_VISIBILTY_TIMEOUT
|
:raises ValueError: If specified visibility timeout exceeds MAXIMUM_VISIBILTY_TIMEOUT
|
||||||
:raises TypeError: If visibility timeout was not specified
|
:raises TypeError: If visibility timeout was not specified
|
||||||
"""
|
"""
|
||||||
visibility_timeout = int(self.querystring.get("VisibilityTimeout")[0])
|
if timeout is not None:
|
||||||
|
visibility_timeout = int(timeout)
|
||||||
|
else:
|
||||||
|
visibility_timeout = int(self.querystring.get("VisibilityTimeout")[0])
|
||||||
|
|
||||||
if visibility_timeout > MAXIMUM_VISIBILTY_TIMEOUT:
|
if visibility_timeout > MAXIMUM_VISIBILTY_TIMEOUT:
|
||||||
raise ValueError
|
raise ValueError
|
||||||
@ -119,6 +122,49 @@ class SQSResponse(BaseResponse):
|
|||||||
template = self.response_template(CHANGE_MESSAGE_VISIBILITY_RESPONSE)
|
template = self.response_template(CHANGE_MESSAGE_VISIBILITY_RESPONSE)
|
||||||
return template.render()
|
return template.render()
|
||||||
|
|
||||||
|
def change_message_visibility_batch(self):
|
||||||
|
queue_name = self._get_queue_name()
|
||||||
|
entries = self._get_list_prefix('ChangeMessageVisibilityBatchRequestEntry')
|
||||||
|
|
||||||
|
success = []
|
||||||
|
error = []
|
||||||
|
for entry in entries:
|
||||||
|
try:
|
||||||
|
visibility_timeout = self._get_validated_visibility_timeout(entry['visibility_timeout'])
|
||||||
|
except ValueError:
|
||||||
|
error.append({
|
||||||
|
'Id': entry['id'],
|
||||||
|
'SenderFault': 'true',
|
||||||
|
'Code': 'InvalidParameterValue',
|
||||||
|
'Message': 'Visibility timeout invalid'
|
||||||
|
})
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.sqs_backend.change_message_visibility(
|
||||||
|
queue_name=queue_name,
|
||||||
|
receipt_handle=entry['receipt_handle'],
|
||||||
|
visibility_timeout=visibility_timeout
|
||||||
|
)
|
||||||
|
success.append(entry['id'])
|
||||||
|
except ReceiptHandleIsInvalid as e:
|
||||||
|
error.append({
|
||||||
|
'Id': entry['id'],
|
||||||
|
'SenderFault': 'true',
|
||||||
|
'Code': 'ReceiptHandleIsInvalid',
|
||||||
|
'Message': e.description
|
||||||
|
})
|
||||||
|
except MessageNotInflight as e:
|
||||||
|
error.append({
|
||||||
|
'Id': entry['id'],
|
||||||
|
'SenderFault': 'false',
|
||||||
|
'Code': 'AWS.SimpleQueueService.MessageNotInflight',
|
||||||
|
'Message': e.description
|
||||||
|
})
|
||||||
|
|
||||||
|
template = self.response_template(CHANGE_MESSAGE_VISIBILITY_BATCH_RESPONSE)
|
||||||
|
return template.render(success=success, errors=error)
|
||||||
|
|
||||||
def get_queue_attributes(self):
|
def get_queue_attributes(self):
|
||||||
queue_name = self._get_queue_name()
|
queue_name = self._get_queue_name()
|
||||||
try:
|
try:
|
||||||
@ -288,8 +334,62 @@ class SQSResponse(BaseResponse):
|
|||||||
messages = self.sqs_backend.receive_messages(
|
messages = self.sqs_backend.receive_messages(
|
||||||
queue_name, message_count, wait_time, visibility_timeout)
|
queue_name, message_count, wait_time, visibility_timeout)
|
||||||
template = self.response_template(RECEIVE_MESSAGE_RESPONSE)
|
template = self.response_template(RECEIVE_MESSAGE_RESPONSE)
|
||||||
output = template.render(messages=messages)
|
return template.render(messages=messages)
|
||||||
return output
|
|
||||||
|
def list_dead_letter_source_queues(self):
|
||||||
|
request_url = urlparse(self.uri)
|
||||||
|
queue_name = self._get_queue_name()
|
||||||
|
|
||||||
|
source_queue_urls = self.sqs_backend.list_dead_letter_source_queues(queue_name)
|
||||||
|
|
||||||
|
template = self.response_template(LIST_DEAD_LETTER_SOURCE_QUEUES_RESPONSE)
|
||||||
|
return template.render(queues=source_queue_urls, request_url=request_url)
|
||||||
|
|
||||||
|
def add_permission(self):
|
||||||
|
queue_name = self._get_queue_name()
|
||||||
|
actions = self._get_multi_param('ActionName')
|
||||||
|
account_ids = self._get_multi_param('AWSAccountId')
|
||||||
|
label = self._get_param('Label')
|
||||||
|
|
||||||
|
self.sqs_backend.add_permission(queue_name, actions, account_ids, label)
|
||||||
|
|
||||||
|
template = self.response_template(ADD_PERMISSION_RESPONSE)
|
||||||
|
return template.render()
|
||||||
|
|
||||||
|
def remove_permission(self):
|
||||||
|
queue_name = self._get_queue_name()
|
||||||
|
label = self._get_param('Label')
|
||||||
|
|
||||||
|
self.sqs_backend.remove_permission(queue_name, label)
|
||||||
|
|
||||||
|
template = self.response_template(REMOVE_PERMISSION_RESPONSE)
|
||||||
|
return template.render()
|
||||||
|
|
||||||
|
def tag_queue(self):
|
||||||
|
queue_name = self._get_queue_name()
|
||||||
|
tags = self._get_map_prefix('Tag', key_end='.Key', value_end='.Value')
|
||||||
|
|
||||||
|
self.sqs_backend.tag_queue(queue_name, tags)
|
||||||
|
|
||||||
|
template = self.response_template(TAG_QUEUE_RESPONSE)
|
||||||
|
return template.render()
|
||||||
|
|
||||||
|
def untag_queue(self):
|
||||||
|
queue_name = self._get_queue_name()
|
||||||
|
tag_keys = self._get_multi_param('TagKey')
|
||||||
|
|
||||||
|
self.sqs_backend.untag_queue(queue_name, tag_keys)
|
||||||
|
|
||||||
|
template = self.response_template(UNTAG_QUEUE_RESPONSE)
|
||||||
|
return template.render()
|
||||||
|
|
||||||
|
def list_queue_tags(self):
|
||||||
|
queue_name = self._get_queue_name()
|
||||||
|
|
||||||
|
queue = self.sqs_backend.get_queue(queue_name)
|
||||||
|
|
||||||
|
template = self.response_template(LIST_QUEUE_TAGS_RESPONSE)
|
||||||
|
return template.render(tags=queue.tags)
|
||||||
|
|
||||||
|
|
||||||
CREATE_QUEUE_RESPONSE = """<CreateQueueResponse>
|
CREATE_QUEUE_RESPONSE = """<CreateQueueResponse>
|
||||||
@ -307,7 +407,7 @@ GET_QUEUE_URL_RESPONSE = """<GetQueueUrlResponse>
|
|||||||
<QueueUrl>{{ queue.url(request_url) }}</QueueUrl>
|
<QueueUrl>{{ queue.url(request_url) }}</QueueUrl>
|
||||||
</GetQueueUrlResult>
|
</GetQueueUrlResult>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>470a6f13-2ed9-4181-ad8a-2fdea142988e</RequestId>
|
<RequestId>{{ requestid }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</GetQueueUrlResponse>"""
|
</GetQueueUrlResponse>"""
|
||||||
|
|
||||||
@ -318,13 +418,13 @@ LIST_QUEUES_RESPONSE = """<ListQueuesResponse>
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ListQueuesResult>
|
</ListQueuesResult>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>725275ae-0b9b-4762-b238-436d7c65a1ac</RequestId>
|
<RequestId>{{ requestid }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</ListQueuesResponse>"""
|
</ListQueuesResponse>"""
|
||||||
|
|
||||||
DELETE_QUEUE_RESPONSE = """<DeleteQueueResponse>
|
DELETE_QUEUE_RESPONSE = """<DeleteQueueResponse>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>6fde8d1e-52cd-4581-8cd9-c512f4c64223</RequestId>
|
<RequestId>{{ requestid }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</DeleteQueueResponse>"""
|
</DeleteQueueResponse>"""
|
||||||
|
|
||||||
@ -338,13 +438,13 @@ GET_QUEUE_ATTRIBUTES_RESPONSE = """<GetQueueAttributesResponse>
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</GetQueueAttributesResult>
|
</GetQueueAttributesResult>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>1ea71be5-b5a2-4f9d-b85a-945d8d08cd0b</RequestId>
|
<RequestId>{{ requestid }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</GetQueueAttributesResponse>"""
|
</GetQueueAttributesResponse>"""
|
||||||
|
|
||||||
SET_QUEUE_ATTRIBUTE_RESPONSE = """<SetQueueAttributesResponse>
|
SET_QUEUE_ATTRIBUTE_RESPONSE = """<SetQueueAttributesResponse>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>e5cca473-4fc0-4198-a451-8abb94d02c75</RequestId>
|
<RequestId>{{ requestid }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</SetQueueAttributesResponse>"""
|
</SetQueueAttributesResponse>"""
|
||||||
|
|
||||||
@ -361,7 +461,7 @@ SEND_MESSAGE_RESPONSE = """<SendMessageResponse>
|
|||||||
</MessageId>
|
</MessageId>
|
||||||
</SendMessageResult>
|
</SendMessageResult>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>27daac76-34dd-47df-bd01-1f6e873584a0</RequestId>
|
<RequestId>{{ requestid }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</SendMessageResponse>"""
|
</SendMessageResponse>"""
|
||||||
|
|
||||||
@ -409,7 +509,7 @@ RECEIVE_MESSAGE_RESPONSE = """<ReceiveMessageResponse>
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ReceiveMessageResult>
|
</ReceiveMessageResult>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>b6633655-283d-45b4-aee4-4e84e0ae6afa</RequestId>
|
<RequestId>{{ requestid }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</ReceiveMessageResponse>"""
|
</ReceiveMessageResponse>"""
|
||||||
|
|
||||||
@ -427,13 +527,13 @@ SEND_MESSAGE_BATCH_RESPONSE = """<SendMessageBatchResponse>
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</SendMessageBatchResult>
|
</SendMessageBatchResult>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>ca1ad5d0-8271-408b-8d0f-1351bf547e74</RequestId>
|
<RequestId>{{ requestid }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</SendMessageBatchResponse>"""
|
</SendMessageBatchResponse>"""
|
||||||
|
|
||||||
DELETE_MESSAGE_RESPONSE = """<DeleteMessageResponse>
|
DELETE_MESSAGE_RESPONSE = """<DeleteMessageResponse>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>b5293cb5-d306-4a17-9048-b263635abe42</RequestId>
|
<RequestId>{{ requestid }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</DeleteMessageResponse>"""
|
</DeleteMessageResponse>"""
|
||||||
|
|
||||||
@ -446,22 +546,92 @@ DELETE_MESSAGE_BATCH_RESPONSE = """<DeleteMessageBatchResponse>
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</DeleteMessageBatchResult>
|
</DeleteMessageBatchResult>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>d6f86b7a-74d1-4439-b43f-196a1e29cd85</RequestId>
|
<RequestId>{{ requestid }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</DeleteMessageBatchResponse>"""
|
</DeleteMessageBatchResponse>"""
|
||||||
|
|
||||||
CHANGE_MESSAGE_VISIBILITY_RESPONSE = """<ChangeMessageVisibilityResponse>
|
CHANGE_MESSAGE_VISIBILITY_RESPONSE = """<ChangeMessageVisibilityResponse>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>6a7a282a-d013-4a59-aba9-335b0fa48bed</RequestId>
|
<RequestId>{{ requestid }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</ChangeMessageVisibilityResponse>"""
|
</ChangeMessageVisibilityResponse>"""
|
||||||
|
|
||||||
|
CHANGE_MESSAGE_VISIBILITY_BATCH_RESPONSE = """<ChangeMessageVisibilityBatchResponse>
|
||||||
|
<ChangeMessageVisibilityBatchResult>
|
||||||
|
{% for success_id in success %}
|
||||||
|
<ChangeMessageVisibilityBatchResultEntry>
|
||||||
|
<Id>{{ success_id }}</Id>
|
||||||
|
</ChangeMessageVisibilityBatchResultEntry>
|
||||||
|
{% endfor %}
|
||||||
|
{% for error_dict in errors %}
|
||||||
|
<BatchResultErrorEntry>
|
||||||
|
<Id>{{ error_dict['Id'] }}</Id>
|
||||||
|
<Code>{{ error_dict['Code'] }}</Code>
|
||||||
|
<Message>{{ error_dict['Message'] }}</Message>
|
||||||
|
<SenderFault>{{ error_dict['SenderFault'] }}</SenderFault>
|
||||||
|
</BatchResultErrorEntry>
|
||||||
|
{% endfor %}
|
||||||
|
</ChangeMessageVisibilityBatchResult>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</ChangeMessageVisibilityBatchResponse>"""
|
||||||
|
|
||||||
PURGE_QUEUE_RESPONSE = """<PurgeQueueResponse>
|
PURGE_QUEUE_RESPONSE = """<PurgeQueueResponse>
|
||||||
<ResponseMetadata>
|
<ResponseMetadata>
|
||||||
<RequestId>6fde8d1e-52cd-4581-8cd9-c512f4c64223</RequestId>
|
<RequestId>{{ requestid }}</RequestId>
|
||||||
</ResponseMetadata>
|
</ResponseMetadata>
|
||||||
</PurgeQueueResponse>"""
|
</PurgeQueueResponse>"""
|
||||||
|
|
||||||
|
LIST_DEAD_LETTER_SOURCE_QUEUES_RESPONSE = """<ListDeadLetterSourceQueuesResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/">
|
||||||
|
<ListDeadLetterSourceQueuesResult>
|
||||||
|
{% for queue in queues %}
|
||||||
|
<QueueUrl>{{ queue.url(request_url) }}</QueueUrl>
|
||||||
|
{% endfor %}
|
||||||
|
</ListDeadLetterSourceQueuesResult>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>8ffb921f-b85e-53d9-abcf-d8d0057f38fc</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</ListDeadLetterSourceQueuesResponse>"""
|
||||||
|
|
||||||
|
ADD_PERMISSION_RESPONSE = """<AddPermissionResponse>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</AddPermissionResponse>"""
|
||||||
|
|
||||||
|
REMOVE_PERMISSION_RESPONSE = """<RemovePermissionResponse>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</RemovePermissionResponse>"""
|
||||||
|
|
||||||
|
TAG_QUEUE_RESPONSE = """<TagQueueResponse>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</TagQueueResponse>"""
|
||||||
|
|
||||||
|
UNTAG_QUEUE_RESPONSE = """<UntagQueueResponse>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</UntagQueueResponse>"""
|
||||||
|
|
||||||
|
LIST_QUEUE_TAGS_RESPONSE = """<ListQueueTagsResponse>
|
||||||
|
<ListQueueTagsResult>
|
||||||
|
{% for key, value in tags.items() %}
|
||||||
|
<Tag>
|
||||||
|
<Key>{{ key }}</Key>
|
||||||
|
<Value>{{ value }}</Value>
|
||||||
|
</Tag>
|
||||||
|
{% endfor %}
|
||||||
|
</ListQueueTagsResult>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>{{ request_id }}</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</ListQueueTagsResponse>"""
|
||||||
|
|
||||||
ERROR_TOO_LONG_RESPONSE = """<ErrorResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/">
|
ERROR_TOO_LONG_RESPONSE = """<ErrorResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/">
|
||||||
<Error>
|
<Error>
|
||||||
<Type>Sender</Type>
|
<Type>Sender</Type>
|
||||||
|
@ -4,6 +4,7 @@ import os
|
|||||||
import boto3
|
import boto3
|
||||||
from freezegun import freeze_time
|
from freezegun import freeze_time
|
||||||
import sure # noqa
|
import sure # noqa
|
||||||
|
import uuid
|
||||||
|
|
||||||
from botocore.exceptions import ClientError
|
from botocore.exceptions import ClientError
|
||||||
|
|
||||||
@ -281,11 +282,23 @@ def test_resend_validation_email_invalid():
|
|||||||
def test_request_certificate():
|
def test_request_certificate():
|
||||||
client = boto3.client('acm', region_name='eu-central-1')
|
client = boto3.client('acm', region_name='eu-central-1')
|
||||||
|
|
||||||
|
token = str(uuid.uuid4())
|
||||||
|
|
||||||
resp = client.request_certificate(
|
resp = client.request_certificate(
|
||||||
DomainName='google.com',
|
DomainName='google.com',
|
||||||
|
IdempotencyToken=token,
|
||||||
SubjectAlternativeNames=['google.com', 'www.google.com', 'mail.google.com'],
|
SubjectAlternativeNames=['google.com', 'www.google.com', 'mail.google.com'],
|
||||||
)
|
)
|
||||||
resp.should.contain('CertificateArn')
|
resp.should.contain('CertificateArn')
|
||||||
|
arn = resp['CertificateArn']
|
||||||
|
|
||||||
|
resp = client.request_certificate(
|
||||||
|
DomainName='google.com',
|
||||||
|
IdempotencyToken=token,
|
||||||
|
SubjectAlternativeNames=['google.com', 'www.google.com', 'mail.google.com'],
|
||||||
|
)
|
||||||
|
resp['CertificateArn'].should.equal(arn)
|
||||||
|
|
||||||
|
|
||||||
@mock_acm
|
@mock_acm
|
||||||
def test_request_certificate_no_san():
|
def test_request_certificate_no_san():
|
||||||
|
@ -28,13 +28,13 @@ except ImportError:
|
|||||||
@mock_dynamodb2_deprecated
|
@mock_dynamodb2_deprecated
|
||||||
def test_list_tables():
|
def test_list_tables():
|
||||||
name = 'TestTable'
|
name = 'TestTable'
|
||||||
#{'schema': }
|
# Should make tables properly with boto
|
||||||
dynamodb_backend2.create_table(name, schema=[
|
dynamodb_backend2.create_table(name, schema=[
|
||||||
{u'KeyType': u'HASH', u'AttributeName': u'forum_name'},
|
{u'KeyType': u'HASH', u'AttributeName': u'forum_name'},
|
||||||
{u'KeyType': u'RANGE', u'AttributeName': u'subject'}
|
{u'KeyType': u'RANGE', u'AttributeName': u'subject'}
|
||||||
])
|
])
|
||||||
conn = boto.dynamodb2.connect_to_region(
|
conn = boto.dynamodb2.connect_to_region(
|
||||||
'us-west-2',
|
'us-east-1',
|
||||||
aws_access_key_id="ak",
|
aws_access_key_id="ak",
|
||||||
aws_secret_access_key="sk")
|
aws_secret_access_key="sk")
|
||||||
assert conn.list_tables()["TableNames"] == [name]
|
assert conn.list_tables()["TableNames"] == [name]
|
||||||
@ -43,6 +43,7 @@ def test_list_tables():
|
|||||||
@requires_boto_gte("2.9")
|
@requires_boto_gte("2.9")
|
||||||
@mock_dynamodb2_deprecated
|
@mock_dynamodb2_deprecated
|
||||||
def test_list_tables_layer_1():
|
def test_list_tables_layer_1():
|
||||||
|
# Should make tables properly with boto
|
||||||
dynamodb_backend2.create_table("test_1", schema=[
|
dynamodb_backend2.create_table("test_1", schema=[
|
||||||
{u'KeyType': u'HASH', u'AttributeName': u'name'}
|
{u'KeyType': u'HASH', u'AttributeName': u'name'}
|
||||||
])
|
])
|
||||||
@ -50,7 +51,7 @@ def test_list_tables_layer_1():
|
|||||||
{u'KeyType': u'HASH', u'AttributeName': u'name'}
|
{u'KeyType': u'HASH', u'AttributeName': u'name'}
|
||||||
])
|
])
|
||||||
conn = boto.dynamodb2.connect_to_region(
|
conn = boto.dynamodb2.connect_to_region(
|
||||||
'us-west-2',
|
'us-east-1',
|
||||||
aws_access_key_id="ak",
|
aws_access_key_id="ak",
|
||||||
aws_secret_access_key="sk")
|
aws_secret_access_key="sk")
|
||||||
|
|
||||||
@ -88,12 +89,22 @@ def test_list_table_tags():
|
|||||||
ProvisionedThroughput={'ReadCapacityUnits':5,'WriteCapacityUnits':5})
|
ProvisionedThroughput={'ReadCapacityUnits':5,'WriteCapacityUnits':5})
|
||||||
table_description = conn.describe_table(TableName=name)
|
table_description = conn.describe_table(TableName=name)
|
||||||
arn = table_description['Table']['TableArn']
|
arn = table_description['Table']['TableArn']
|
||||||
tags = [{'Key':'TestTag', 'Value': 'TestValue'}]
|
|
||||||
conn.tag_resource(ResourceArn=arn,
|
# Tag table
|
||||||
Tags=tags)
|
tags = [{'Key': 'TestTag', 'Value': 'TestValue'}, {'Key': 'TestTag2', 'Value': 'TestValue2'}]
|
||||||
|
conn.tag_resource(ResourceArn=arn, Tags=tags)
|
||||||
|
|
||||||
|
# Check tags
|
||||||
resp = conn.list_tags_of_resource(ResourceArn=arn)
|
resp = conn.list_tags_of_resource(ResourceArn=arn)
|
||||||
assert resp["Tags"] == tags
|
assert resp["Tags"] == tags
|
||||||
|
|
||||||
|
# Remove 1 tag
|
||||||
|
conn.untag_resource(ResourceArn=arn, TagKeys=['TestTag'])
|
||||||
|
|
||||||
|
# Check tags
|
||||||
|
resp = conn.list_tags_of_resource(ResourceArn=arn)
|
||||||
|
assert resp["Tags"] == [{'Key': 'TestTag2', 'Value': 'TestValue2'}]
|
||||||
|
|
||||||
|
|
||||||
@requires_boto_gte("2.9")
|
@requires_boto_gte("2.9")
|
||||||
@mock_dynamodb2
|
@mock_dynamodb2
|
||||||
@ -868,3 +879,50 @@ def test_delete_item():
|
|||||||
|
|
||||||
response = table.scan()
|
response = table.scan()
|
||||||
assert response['Count'] == 0
|
assert response['Count'] == 0
|
||||||
|
|
||||||
|
|
||||||
|
@mock_dynamodb2
|
||||||
|
def test_describe_limits():
|
||||||
|
client = boto3.client('dynamodb', region_name='eu-central-1')
|
||||||
|
resp = client.describe_limits()
|
||||||
|
|
||||||
|
resp['AccountMaxReadCapacityUnits'].should.equal(20000)
|
||||||
|
resp['AccountMaxWriteCapacityUnits'].should.equal(20000)
|
||||||
|
resp['TableMaxWriteCapacityUnits'].should.equal(10000)
|
||||||
|
resp['TableMaxReadCapacityUnits'].should.equal(10000)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_dynamodb2
|
||||||
|
def test_set_ttl():
|
||||||
|
client = boto3.client('dynamodb', region_name='us-east-1')
|
||||||
|
|
||||||
|
# Create the DynamoDB table.
|
||||||
|
client.create_table(
|
||||||
|
TableName='test1',
|
||||||
|
AttributeDefinitions=[{'AttributeName': 'client', 'AttributeType': 'S'}, {'AttributeName': 'app', 'AttributeType': 'S'}],
|
||||||
|
KeySchema=[{'AttributeName': 'client', 'KeyType': 'HASH'}, {'AttributeName': 'app', 'KeyType': 'RANGE'}],
|
||||||
|
ProvisionedThroughput={'ReadCapacityUnits': 123, 'WriteCapacityUnits': 123}
|
||||||
|
)
|
||||||
|
|
||||||
|
client.update_time_to_live(
|
||||||
|
TableName='test1',
|
||||||
|
TimeToLiveSpecification={
|
||||||
|
'Enabled': True,
|
||||||
|
'AttributeName': 'expire'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
resp = client.describe_time_to_live(TableName='test1')
|
||||||
|
resp['TimeToLiveDescription']['TimeToLiveStatus'].should.equal('ENABLED')
|
||||||
|
resp['TimeToLiveDescription']['AttributeName'].should.equal('expire')
|
||||||
|
|
||||||
|
client.update_time_to_live(
|
||||||
|
TableName='test1',
|
||||||
|
TimeToLiveSpecification={
|
||||||
|
'Enabled': False,
|
||||||
|
'AttributeName': 'expire'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
resp = client.describe_time_to_live(TableName='test1')
|
||||||
|
resp['TimeToLiveDescription']['TimeToLiveStatus'].should.equal('DISABLED')
|
||||||
|
@ -54,7 +54,7 @@ def test_create_table():
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
conn = boto.dynamodb2.connect_to_region(
|
conn = boto.dynamodb2.connect_to_region(
|
||||||
'us-west-2',
|
'us-east-1',
|
||||||
aws_access_key_id="ak",
|
aws_access_key_id="ak",
|
||||||
aws_secret_access_key="sk"
|
aws_secret_access_key="sk"
|
||||||
)
|
)
|
||||||
@ -425,7 +425,7 @@ def test_get_special_item():
|
|||||||
|
|
||||||
@mock_dynamodb2_deprecated
|
@mock_dynamodb2_deprecated
|
||||||
def test_update_item_remove():
|
def test_update_item_remove():
|
||||||
conn = boto.dynamodb2.connect_to_region("us-west-2")
|
conn = boto.dynamodb2.connect_to_region("us-east-1")
|
||||||
table = Table.create('messages', schema=[
|
table = Table.create('messages', schema=[
|
||||||
HashKey('username')
|
HashKey('username')
|
||||||
])
|
])
|
||||||
@ -452,7 +452,7 @@ def test_update_item_remove():
|
|||||||
|
|
||||||
@mock_dynamodb2_deprecated
|
@mock_dynamodb2_deprecated
|
||||||
def test_update_item_set():
|
def test_update_item_set():
|
||||||
conn = boto.dynamodb2.connect_to_region("us-west-2")
|
conn = boto.dynamodb2.connect_to_region("us-east-1")
|
||||||
table = Table.create('messages', schema=[
|
table = Table.create('messages', schema=[
|
||||||
HashKey('username')
|
HashKey('username')
|
||||||
])
|
])
|
||||||
|
@ -1611,6 +1611,152 @@ def test_update_service_through_cloudformation_should_trigger_replacement():
|
|||||||
len(resp['serviceArns']).should.equal(1)
|
len(resp['serviceArns']).should.equal(1)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_ec2
|
||||||
|
@mock_ecs
|
||||||
|
def test_attributes():
|
||||||
|
# Combined put, list delete attributes into the same test due to the amount of setup
|
||||||
|
ecs_client = boto3.client('ecs', region_name='us-east-1')
|
||||||
|
ec2 = boto3.resource('ec2', region_name='us-east-1')
|
||||||
|
|
||||||
|
test_cluster_name = 'test_ecs_cluster'
|
||||||
|
|
||||||
|
_ = ecs_client.create_cluster(
|
||||||
|
clusterName=test_cluster_name
|
||||||
|
)
|
||||||
|
|
||||||
|
test_instance = ec2.create_instances(
|
||||||
|
ImageId="ami-1234abcd",
|
||||||
|
MinCount=1,
|
||||||
|
MaxCount=1,
|
||||||
|
)[0]
|
||||||
|
|
||||||
|
instance_id_document = json.dumps(
|
||||||
|
ec2_utils.generate_instance_identity_document(test_instance)
|
||||||
|
)
|
||||||
|
|
||||||
|
response = ecs_client.register_container_instance(
|
||||||
|
cluster=test_cluster_name,
|
||||||
|
instanceIdentityDocument=instance_id_document
|
||||||
|
)
|
||||||
|
|
||||||
|
response['containerInstance'][
|
||||||
|
'ec2InstanceId'].should.equal(test_instance.id)
|
||||||
|
full_arn1 = response['containerInstance']['containerInstanceArn']
|
||||||
|
|
||||||
|
test_instance = ec2.create_instances(
|
||||||
|
ImageId="ami-1234abcd",
|
||||||
|
MinCount=1,
|
||||||
|
MaxCount=1,
|
||||||
|
)[0]
|
||||||
|
|
||||||
|
instance_id_document = json.dumps(
|
||||||
|
ec2_utils.generate_instance_identity_document(test_instance)
|
||||||
|
)
|
||||||
|
|
||||||
|
response = ecs_client.register_container_instance(
|
||||||
|
cluster=test_cluster_name,
|
||||||
|
instanceIdentityDocument=instance_id_document
|
||||||
|
)
|
||||||
|
|
||||||
|
response['containerInstance'][
|
||||||
|
'ec2InstanceId'].should.equal(test_instance.id)
|
||||||
|
full_arn2 = response['containerInstance']['containerInstanceArn']
|
||||||
|
partial_arn2 = full_arn2.rsplit('/', 1)[-1]
|
||||||
|
|
||||||
|
full_arn2.should_not.equal(full_arn1) # uuid1 isnt unique enough when the pc is fast ;-)
|
||||||
|
|
||||||
|
# Ok set instance 1 with 1 attribute, instance 2 with another, and all of them with a 3rd.
|
||||||
|
ecs_client.put_attributes(
|
||||||
|
cluster=test_cluster_name,
|
||||||
|
attributes=[
|
||||||
|
{'name': 'env', 'value': 'prod'},
|
||||||
|
{'name': 'attr1', 'value': 'instance1', 'targetId': full_arn1},
|
||||||
|
{'name': 'attr1', 'value': 'instance2', 'targetId': partial_arn2, 'targetType': 'container-instance'}
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
resp = ecs_client.list_attributes(
|
||||||
|
cluster=test_cluster_name,
|
||||||
|
targetType='container-instance'
|
||||||
|
)
|
||||||
|
attrs = resp['attributes']
|
||||||
|
len(attrs).should.equal(4)
|
||||||
|
|
||||||
|
# Tests that the attrs have been set properly
|
||||||
|
len(list(filter(lambda item: item['name'] == 'env', attrs))).should.equal(2)
|
||||||
|
len(list(filter(lambda item: item['name'] == 'attr1' and item['value'] == 'instance1', attrs))).should.equal(1)
|
||||||
|
|
||||||
|
ecs_client.delete_attributes(
|
||||||
|
cluster=test_cluster_name,
|
||||||
|
attributes=[
|
||||||
|
{'name': 'attr1', 'value': 'instance2', 'targetId': partial_arn2, 'targetType': 'container-instance'}
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
resp = ecs_client.list_attributes(
|
||||||
|
cluster=test_cluster_name,
|
||||||
|
targetType='container-instance'
|
||||||
|
)
|
||||||
|
attrs = resp['attributes']
|
||||||
|
len(attrs).should.equal(3)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_ecs
|
||||||
|
def test_poll_endpoint():
|
||||||
|
# Combined put, list delete attributes into the same test due to the amount of setup
|
||||||
|
ecs_client = boto3.client('ecs', region_name='us-east-1')
|
||||||
|
|
||||||
|
# Just a placeholder until someone actually wants useless data, just testing it doesnt raise an exception
|
||||||
|
resp = ecs_client.discover_poll_endpoint(cluster='blah', containerInstance='blah')
|
||||||
|
resp.should.contain('endpoint')
|
||||||
|
resp.should.contain('telemetryEndpoint')
|
||||||
|
|
||||||
|
|
||||||
|
@mock_ecs
|
||||||
|
def test_list_task_definition_families():
|
||||||
|
client = boto3.client('ecs', region_name='us-east-1')
|
||||||
|
client.register_task_definition(
|
||||||
|
family='test_ecs_task',
|
||||||
|
containerDefinitions=[
|
||||||
|
{
|
||||||
|
'name': 'hello_world',
|
||||||
|
'image': 'docker/hello-world:latest',
|
||||||
|
'cpu': 1024,
|
||||||
|
'memory': 400,
|
||||||
|
'essential': True,
|
||||||
|
'environment': [{
|
||||||
|
'name': 'AWS_ACCESS_KEY_ID',
|
||||||
|
'value': 'SOME_ACCESS_KEY'
|
||||||
|
}],
|
||||||
|
'logConfiguration': {'logDriver': 'json-file'}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
)
|
||||||
|
client.register_task_definition(
|
||||||
|
family='alt_test_ecs_task',
|
||||||
|
containerDefinitions=[
|
||||||
|
{
|
||||||
|
'name': 'hello_world',
|
||||||
|
'image': 'docker/hello-world:latest',
|
||||||
|
'cpu': 1024,
|
||||||
|
'memory': 400,
|
||||||
|
'essential': True,
|
||||||
|
'environment': [{
|
||||||
|
'name': 'AWS_ACCESS_KEY_ID',
|
||||||
|
'value': 'SOME_ACCESS_KEY'
|
||||||
|
}],
|
||||||
|
'logConfiguration': {'logDriver': 'json-file'}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
resp1 = client.list_task_definition_families()
|
||||||
|
resp2 = client.list_task_definition_families(familyPrefix='alt')
|
||||||
|
|
||||||
|
len(resp1['families']).should.equal(2)
|
||||||
|
len(resp2['families']).should.equal(1)
|
||||||
|
|
||||||
|
|
||||||
def _fetch_container_instance_resources(container_instance_description):
|
def _fetch_container_instance_resources(container_instance_description):
|
||||||
remaining_resources = {}
|
remaining_resources = {}
|
||||||
registered_resources = {}
|
registered_resources = {}
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
import os
|
||||||
import boto3
|
import boto3
|
||||||
import botocore
|
import botocore
|
||||||
from botocore.exceptions import ClientError
|
from botocore.exceptions import ClientError
|
||||||
from nose.tools import assert_raises
|
from nose.tools import assert_raises
|
||||||
import sure # noqa
|
import sure # noqa
|
||||||
|
|
||||||
from moto import mock_elbv2, mock_ec2
|
from moto import mock_elbv2, mock_ec2, mock_acm
|
||||||
|
from moto.elbv2 import elbv2_backends
|
||||||
|
|
||||||
|
|
||||||
@mock_elbv2
|
@mock_elbv2
|
||||||
@ -1030,3 +1032,373 @@ def test_describe_invalid_target_group():
|
|||||||
# Check error raises correctly
|
# Check error raises correctly
|
||||||
with assert_raises(ClientError):
|
with assert_raises(ClientError):
|
||||||
conn.describe_target_groups(Names=['invalid'])
|
conn.describe_target_groups(Names=['invalid'])
|
||||||
|
|
||||||
|
|
||||||
|
@mock_elbv2
|
||||||
|
def test_describe_account_limits():
|
||||||
|
client = boto3.client('elbv2', region_name='eu-central-1')
|
||||||
|
|
||||||
|
resp = client.describe_account_limits()
|
||||||
|
resp['Limits'][0].should.contain('Name')
|
||||||
|
resp['Limits'][0].should.contain('Max')
|
||||||
|
|
||||||
|
|
||||||
|
@mock_elbv2
|
||||||
|
def test_describe_ssl_policies():
|
||||||
|
client = boto3.client('elbv2', region_name='eu-central-1')
|
||||||
|
|
||||||
|
resp = client.describe_ssl_policies()
|
||||||
|
len(resp['SslPolicies']).should.equal(5)
|
||||||
|
|
||||||
|
resp = client.describe_ssl_policies(Names=['ELBSecurityPolicy-TLS-1-2-2017-01', 'ELBSecurityPolicy-2016-08'])
|
||||||
|
len(resp['SslPolicies']).should.equal(2)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_elbv2
|
||||||
|
@mock_ec2
|
||||||
|
def test_set_ip_address_type():
|
||||||
|
client = boto3.client('elbv2', region_name='us-east-1')
|
||||||
|
ec2 = boto3.resource('ec2', region_name='us-east-1')
|
||||||
|
|
||||||
|
security_group = ec2.create_security_group(
|
||||||
|
GroupName='a-security-group', Description='First One')
|
||||||
|
vpc = ec2.create_vpc(CidrBlock='172.28.7.0/24', InstanceTenancy='default')
|
||||||
|
subnet1 = ec2.create_subnet(
|
||||||
|
VpcId=vpc.id,
|
||||||
|
CidrBlock='172.28.7.192/26',
|
||||||
|
AvailabilityZone='us-east-1a')
|
||||||
|
subnet2 = ec2.create_subnet(
|
||||||
|
VpcId=vpc.id,
|
||||||
|
CidrBlock='172.28.7.192/26',
|
||||||
|
AvailabilityZone='us-east-1b')
|
||||||
|
|
||||||
|
response = client.create_load_balancer(
|
||||||
|
Name='my-lb',
|
||||||
|
Subnets=[subnet1.id, subnet2.id],
|
||||||
|
SecurityGroups=[security_group.id],
|
||||||
|
Scheme='internal',
|
||||||
|
Tags=[{'Key': 'key_name', 'Value': 'a_value'}])
|
||||||
|
arn = response['LoadBalancers'][0]['LoadBalancerArn']
|
||||||
|
|
||||||
|
# Internal LBs cant be dualstack yet
|
||||||
|
with assert_raises(ClientError):
|
||||||
|
client.set_ip_address_type(
|
||||||
|
LoadBalancerArn=arn,
|
||||||
|
IpAddressType='dualstack'
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create internet facing one
|
||||||
|
response = client.create_load_balancer(
|
||||||
|
Name='my-lb2',
|
||||||
|
Subnets=[subnet1.id, subnet2.id],
|
||||||
|
SecurityGroups=[security_group.id],
|
||||||
|
Scheme='internet-facing',
|
||||||
|
Tags=[{'Key': 'key_name', 'Value': 'a_value'}])
|
||||||
|
arn = response['LoadBalancers'][0]['LoadBalancerArn']
|
||||||
|
|
||||||
|
client.set_ip_address_type(
|
||||||
|
LoadBalancerArn=arn,
|
||||||
|
IpAddressType='dualstack'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_elbv2
|
||||||
|
@mock_ec2
|
||||||
|
def test_set_security_groups():
|
||||||
|
client = boto3.client('elbv2', region_name='us-east-1')
|
||||||
|
ec2 = boto3.resource('ec2', region_name='us-east-1')
|
||||||
|
|
||||||
|
security_group = ec2.create_security_group(
|
||||||
|
GroupName='a-security-group', Description='First One')
|
||||||
|
security_group2 = ec2.create_security_group(
|
||||||
|
GroupName='b-security-group', Description='Second One')
|
||||||
|
vpc = ec2.create_vpc(CidrBlock='172.28.7.0/24', InstanceTenancy='default')
|
||||||
|
subnet1 = ec2.create_subnet(
|
||||||
|
VpcId=vpc.id,
|
||||||
|
CidrBlock='172.28.7.192/26',
|
||||||
|
AvailabilityZone='us-east-1a')
|
||||||
|
subnet2 = ec2.create_subnet(
|
||||||
|
VpcId=vpc.id,
|
||||||
|
CidrBlock='172.28.7.192/26',
|
||||||
|
AvailabilityZone='us-east-1b')
|
||||||
|
|
||||||
|
response = client.create_load_balancer(
|
||||||
|
Name='my-lb',
|
||||||
|
Subnets=[subnet1.id, subnet2.id],
|
||||||
|
SecurityGroups=[security_group.id],
|
||||||
|
Scheme='internal',
|
||||||
|
Tags=[{'Key': 'key_name', 'Value': 'a_value'}])
|
||||||
|
arn = response['LoadBalancers'][0]['LoadBalancerArn']
|
||||||
|
|
||||||
|
client.set_security_groups(
|
||||||
|
LoadBalancerArn=arn,
|
||||||
|
SecurityGroups=[security_group.id, security_group2.id]
|
||||||
|
)
|
||||||
|
|
||||||
|
resp = client.describe_load_balancers(LoadBalancerArns=[arn])
|
||||||
|
len(resp['LoadBalancers'][0]['SecurityGroups']).should.equal(2)
|
||||||
|
|
||||||
|
with assert_raises(ClientError):
|
||||||
|
client.set_security_groups(
|
||||||
|
LoadBalancerArn=arn,
|
||||||
|
SecurityGroups=['non_existant']
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_elbv2
|
||||||
|
@mock_ec2
|
||||||
|
def test_set_subnets():
|
||||||
|
client = boto3.client('elbv2', region_name='us-east-1')
|
||||||
|
ec2 = boto3.resource('ec2', region_name='us-east-1')
|
||||||
|
|
||||||
|
security_group = ec2.create_security_group(
|
||||||
|
GroupName='a-security-group', Description='First One')
|
||||||
|
vpc = ec2.create_vpc(CidrBlock='172.28.7.0/24', InstanceTenancy='default')
|
||||||
|
subnet1 = ec2.create_subnet(
|
||||||
|
VpcId=vpc.id,
|
||||||
|
CidrBlock='172.28.7.192/26',
|
||||||
|
AvailabilityZone='us-east-1a')
|
||||||
|
subnet2 = ec2.create_subnet(
|
||||||
|
VpcId=vpc.id,
|
||||||
|
CidrBlock='172.28.7.192/26',
|
||||||
|
AvailabilityZone='us-east-1b')
|
||||||
|
subnet3 = ec2.create_subnet(
|
||||||
|
VpcId=vpc.id,
|
||||||
|
CidrBlock='172.28.7.192/26',
|
||||||
|
AvailabilityZone='us-east-1c')
|
||||||
|
|
||||||
|
response = client.create_load_balancer(
|
||||||
|
Name='my-lb',
|
||||||
|
Subnets=[subnet1.id, subnet2.id],
|
||||||
|
SecurityGroups=[security_group.id],
|
||||||
|
Scheme='internal',
|
||||||
|
Tags=[{'Key': 'key_name', 'Value': 'a_value'}])
|
||||||
|
arn = response['LoadBalancers'][0]['LoadBalancerArn']
|
||||||
|
|
||||||
|
client.set_subnets(
|
||||||
|
LoadBalancerArn=arn,
|
||||||
|
Subnets=[subnet1.id, subnet2.id, subnet3.id]
|
||||||
|
)
|
||||||
|
|
||||||
|
resp = client.describe_load_balancers(LoadBalancerArns=[arn])
|
||||||
|
len(resp['LoadBalancers'][0]['AvailabilityZones']).should.equal(3)
|
||||||
|
|
||||||
|
# Only 1 AZ
|
||||||
|
with assert_raises(ClientError):
|
||||||
|
client.set_subnets(
|
||||||
|
LoadBalancerArn=arn,
|
||||||
|
Subnets=[subnet1.id]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Multiple subnets in same AZ
|
||||||
|
with assert_raises(ClientError):
|
||||||
|
client.set_subnets(
|
||||||
|
LoadBalancerArn=arn,
|
||||||
|
Subnets=[subnet1.id, subnet2.id, subnet2.id]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_elbv2
|
||||||
|
@mock_ec2
|
||||||
|
def test_set_subnets():
|
||||||
|
client = boto3.client('elbv2', region_name='us-east-1')
|
||||||
|
ec2 = boto3.resource('ec2', region_name='us-east-1')
|
||||||
|
|
||||||
|
security_group = ec2.create_security_group(
|
||||||
|
GroupName='a-security-group', Description='First One')
|
||||||
|
vpc = ec2.create_vpc(CidrBlock='172.28.7.0/24', InstanceTenancy='default')
|
||||||
|
subnet1 = ec2.create_subnet(
|
||||||
|
VpcId=vpc.id,
|
||||||
|
CidrBlock='172.28.7.192/26',
|
||||||
|
AvailabilityZone='us-east-1a')
|
||||||
|
subnet2 = ec2.create_subnet(
|
||||||
|
VpcId=vpc.id,
|
||||||
|
CidrBlock='172.28.7.192/26',
|
||||||
|
AvailabilityZone='us-east-1b')
|
||||||
|
|
||||||
|
response = client.create_load_balancer(
|
||||||
|
Name='my-lb',
|
||||||
|
Subnets=[subnet1.id, subnet2.id],
|
||||||
|
SecurityGroups=[security_group.id],
|
||||||
|
Scheme='internal',
|
||||||
|
Tags=[{'Key': 'key_name', 'Value': 'a_value'}])
|
||||||
|
arn = response['LoadBalancers'][0]['LoadBalancerArn']
|
||||||
|
|
||||||
|
client.modify_load_balancer_attributes(
|
||||||
|
LoadBalancerArn=arn,
|
||||||
|
Attributes=[{'Key': 'idle_timeout.timeout_seconds', 'Value': '600'}]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check its 600 not 60
|
||||||
|
response = client.describe_load_balancer_attributes(
|
||||||
|
LoadBalancerArn=arn
|
||||||
|
)
|
||||||
|
idle_timeout = list(filter(lambda item: item['Key'] == 'idle_timeout.timeout_seconds', response['Attributes']))[0]
|
||||||
|
idle_timeout['Value'].should.equal('600')
|
||||||
|
|
||||||
|
|
||||||
|
@mock_elbv2
|
||||||
|
@mock_ec2
|
||||||
|
def test_modify_target_group():
|
||||||
|
client = boto3.client('elbv2', region_name='us-east-1')
|
||||||
|
ec2 = boto3.resource('ec2', region_name='us-east-1')
|
||||||
|
|
||||||
|
vpc = ec2.create_vpc(CidrBlock='172.28.7.0/24', InstanceTenancy='default')
|
||||||
|
|
||||||
|
response = client.create_target_group(
|
||||||
|
Name='a-target',
|
||||||
|
Protocol='HTTP',
|
||||||
|
Port=8080,
|
||||||
|
VpcId=vpc.id,
|
||||||
|
HealthCheckProtocol='HTTP',
|
||||||
|
HealthCheckPort='8080',
|
||||||
|
HealthCheckPath='/',
|
||||||
|
HealthCheckIntervalSeconds=5,
|
||||||
|
HealthCheckTimeoutSeconds=5,
|
||||||
|
HealthyThresholdCount=5,
|
||||||
|
UnhealthyThresholdCount=2,
|
||||||
|
Matcher={'HttpCode': '200'})
|
||||||
|
arn = response.get('TargetGroups')[0]['TargetGroupArn']
|
||||||
|
|
||||||
|
client.modify_target_group(
|
||||||
|
TargetGroupArn=arn,
|
||||||
|
HealthCheckProtocol='HTTPS',
|
||||||
|
HealthCheckPort='8081',
|
||||||
|
HealthCheckPath='/status',
|
||||||
|
HealthCheckIntervalSeconds=10,
|
||||||
|
HealthCheckTimeoutSeconds=10,
|
||||||
|
HealthyThresholdCount=10,
|
||||||
|
UnhealthyThresholdCount=4,
|
||||||
|
Matcher={'HttpCode': '200-399'}
|
||||||
|
)
|
||||||
|
|
||||||
|
response = client.describe_target_groups(
|
||||||
|
TargetGroupArns=[arn]
|
||||||
|
)
|
||||||
|
response['TargetGroups'][0]['Matcher']['HttpCode'].should.equal('200-399')
|
||||||
|
response['TargetGroups'][0]['HealthCheckIntervalSeconds'].should.equal(10)
|
||||||
|
response['TargetGroups'][0]['HealthCheckPath'].should.equal('/status')
|
||||||
|
response['TargetGroups'][0]['HealthCheckPort'].should.equal('8081')
|
||||||
|
response['TargetGroups'][0]['HealthCheckProtocol'].should.equal('HTTPS')
|
||||||
|
response['TargetGroups'][0]['HealthCheckTimeoutSeconds'].should.equal(10)
|
||||||
|
response['TargetGroups'][0]['HealthyThresholdCount'].should.equal(10)
|
||||||
|
response['TargetGroups'][0]['UnhealthyThresholdCount'].should.equal(4)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_elbv2
|
||||||
|
@mock_ec2
|
||||||
|
@mock_acm
|
||||||
|
def test_modify_listener_http_to_https():
|
||||||
|
client = boto3.client('elbv2', region_name='eu-central-1')
|
||||||
|
acm = boto3.client('acm', region_name='eu-central-1')
|
||||||
|
ec2 = boto3.resource('ec2', region_name='eu-central-1')
|
||||||
|
|
||||||
|
security_group = ec2.create_security_group(
|
||||||
|
GroupName='a-security-group', Description='First One')
|
||||||
|
vpc = ec2.create_vpc(CidrBlock='172.28.7.0/24', InstanceTenancy='default')
|
||||||
|
subnet1 = ec2.create_subnet(
|
||||||
|
VpcId=vpc.id,
|
||||||
|
CidrBlock='172.28.7.192/26',
|
||||||
|
AvailabilityZone='eu-central-1a')
|
||||||
|
subnet2 = ec2.create_subnet(
|
||||||
|
VpcId=vpc.id,
|
||||||
|
CidrBlock='172.28.7.192/26',
|
||||||
|
AvailabilityZone='eu-central-1b')
|
||||||
|
|
||||||
|
response = client.create_load_balancer(
|
||||||
|
Name='my-lb',
|
||||||
|
Subnets=[subnet1.id, subnet2.id],
|
||||||
|
SecurityGroups=[security_group.id],
|
||||||
|
Scheme='internal',
|
||||||
|
Tags=[{'Key': 'key_name', 'Value': 'a_value'}])
|
||||||
|
|
||||||
|
load_balancer_arn = response.get('LoadBalancers')[0].get('LoadBalancerArn')
|
||||||
|
|
||||||
|
response = client.create_target_group(
|
||||||
|
Name='a-target',
|
||||||
|
Protocol='HTTP',
|
||||||
|
Port=8080,
|
||||||
|
VpcId=vpc.id,
|
||||||
|
HealthCheckProtocol='HTTP',
|
||||||
|
HealthCheckPort='8080',
|
||||||
|
HealthCheckPath='/',
|
||||||
|
HealthCheckIntervalSeconds=5,
|
||||||
|
HealthCheckTimeoutSeconds=5,
|
||||||
|
HealthyThresholdCount=5,
|
||||||
|
UnhealthyThresholdCount=2,
|
||||||
|
Matcher={'HttpCode': '200'})
|
||||||
|
target_group = response.get('TargetGroups')[0]
|
||||||
|
target_group_arn = target_group['TargetGroupArn']
|
||||||
|
|
||||||
|
# Plain HTTP listener
|
||||||
|
response = client.create_listener(
|
||||||
|
LoadBalancerArn=load_balancer_arn,
|
||||||
|
Protocol='HTTP',
|
||||||
|
Port=80,
|
||||||
|
DefaultActions=[{'Type': 'forward', 'TargetGroupArn': target_group_arn}]
|
||||||
|
)
|
||||||
|
listener_arn = response['Listeners'][0]['ListenerArn']
|
||||||
|
|
||||||
|
response = acm.request_certificate(
|
||||||
|
DomainName='google.com',
|
||||||
|
SubjectAlternativeNames=['google.com', 'www.google.com', 'mail.google.com'],
|
||||||
|
)
|
||||||
|
google_arn = response['CertificateArn']
|
||||||
|
response = acm.request_certificate(
|
||||||
|
DomainName='yahoo.com',
|
||||||
|
SubjectAlternativeNames=['yahoo.com', 'www.yahoo.com', 'mail.yahoo.com'],
|
||||||
|
)
|
||||||
|
yahoo_arn = response['CertificateArn']
|
||||||
|
|
||||||
|
response = client.modify_listener(
|
||||||
|
ListenerArn=listener_arn,
|
||||||
|
Port=443,
|
||||||
|
Protocol='HTTPS',
|
||||||
|
SslPolicy='ELBSecurityPolicy-TLS-1-2-2017-01',
|
||||||
|
Certificates=[
|
||||||
|
{'CertificateArn': google_arn, 'IsDefault': False},
|
||||||
|
{'CertificateArn': yahoo_arn, 'IsDefault': True}
|
||||||
|
],
|
||||||
|
DefaultActions=[
|
||||||
|
{'Type': 'forward', 'TargetGroupArn': target_group_arn}
|
||||||
|
]
|
||||||
|
)
|
||||||
|
response['Listeners'][0]['Port'].should.equal(443)
|
||||||
|
response['Listeners'][0]['Protocol'].should.equal('HTTPS')
|
||||||
|
response['Listeners'][0]['SslPolicy'].should.equal('ELBSecurityPolicy-TLS-1-2-2017-01')
|
||||||
|
len(response['Listeners'][0]['Certificates']).should.equal(2)
|
||||||
|
|
||||||
|
# Check default cert, can't do this in server mode
|
||||||
|
if os.environ.get('TEST_SERVER_MODE', 'false').lower() == 'false':
|
||||||
|
listener = elbv2_backends['eu-central-1'].load_balancers[load_balancer_arn].listeners[listener_arn]
|
||||||
|
listener.certificate.should.equal(yahoo_arn)
|
||||||
|
|
||||||
|
# No default cert
|
||||||
|
with assert_raises(ClientError):
|
||||||
|
client.modify_listener(
|
||||||
|
ListenerArn=listener_arn,
|
||||||
|
Port=443,
|
||||||
|
Protocol='HTTPS',
|
||||||
|
SslPolicy='ELBSecurityPolicy-TLS-1-2-2017-01',
|
||||||
|
Certificates=[
|
||||||
|
{'CertificateArn': google_arn, 'IsDefault': False}
|
||||||
|
],
|
||||||
|
DefaultActions=[
|
||||||
|
{'Type': 'forward', 'TargetGroupArn': target_group_arn}
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Bad cert
|
||||||
|
with assert_raises(ClientError):
|
||||||
|
client.modify_listener(
|
||||||
|
ListenerArn=listener_arn,
|
||||||
|
Port=443,
|
||||||
|
Protocol='HTTPS',
|
||||||
|
SslPolicy='ELBSecurityPolicy-TLS-1-2-2017-01',
|
||||||
|
Certificates=[
|
||||||
|
{'CertificateArn': 'lalala', 'IsDefault': True}
|
||||||
|
],
|
||||||
|
DefaultActions=[
|
||||||
|
{'Type': 'forward', 'TargetGroupArn': target_group_arn}
|
||||||
|
]
|
||||||
|
)
|
||||||
|
@ -3,6 +3,8 @@ import random
|
|||||||
import boto3
|
import boto3
|
||||||
|
|
||||||
from moto.events import mock_events
|
from moto.events import mock_events
|
||||||
|
from botocore.exceptions import ClientError
|
||||||
|
from nose.tools import assert_raises
|
||||||
|
|
||||||
|
|
||||||
RULES = [
|
RULES = [
|
||||||
@ -171,11 +173,36 @@ def test_remove_targets():
|
|||||||
assert(targets_before - 1 == targets_after)
|
assert(targets_before - 1 == targets_after)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
@mock_events
|
||||||
test_list_rules()
|
def test_permissions():
|
||||||
test_describe_rule()
|
client = boto3.client('events', 'eu-central-1')
|
||||||
test_enable_disable_rule()
|
|
||||||
test_list_rule_names_by_target()
|
client.put_permission(Action='PutEvents', Principal='111111111111', StatementId='Account1')
|
||||||
test_list_rules()
|
client.put_permission(Action='PutEvents', Principal='222222222222', StatementId='Account2')
|
||||||
test_list_targets_by_rule()
|
|
||||||
test_remove_targets()
|
resp = client.describe_event_bus()
|
||||||
|
assert len(resp['Policy']['Statement']) == 2
|
||||||
|
|
||||||
|
client.remove_permission(StatementId='Account2')
|
||||||
|
|
||||||
|
resp = client.describe_event_bus()
|
||||||
|
assert len(resp['Policy']['Statement']) == 1
|
||||||
|
assert resp['Policy']['Statement'][0]['Sid'] == 'Account1'
|
||||||
|
|
||||||
|
|
||||||
|
@mock_events
|
||||||
|
def test_put_events():
|
||||||
|
client = boto3.client('events', 'eu-central-1')
|
||||||
|
|
||||||
|
event = {
|
||||||
|
"Source": "com.mycompany.myapp",
|
||||||
|
"Detail": '{"key1": "value3", "key2": "value4"}',
|
||||||
|
"Resources": ["resource1", "resource2"],
|
||||||
|
"DetailType": "myDetailType"
|
||||||
|
}
|
||||||
|
|
||||||
|
client.put_events(Entries=[event])
|
||||||
|
# Boto3 would error if it didn't return 200 OK
|
||||||
|
|
||||||
|
with assert_raises(ClientError):
|
||||||
|
client.put_events(Entries=[event]*20)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
import os
|
||||||
|
|
||||||
import boto
|
import boto
|
||||||
import boto3
|
import boto3
|
||||||
@ -8,14 +9,18 @@ from botocore.exceptions import ClientError
|
|||||||
from boto.exception import SQSError
|
from boto.exception import SQSError
|
||||||
from boto.sqs.message import RawMessage, Message
|
from boto.sqs.message import RawMessage, Message
|
||||||
|
|
||||||
|
from freezegun import freeze_time
|
||||||
import base64
|
import base64
|
||||||
|
import json
|
||||||
import sure # noqa
|
import sure # noqa
|
||||||
import time
|
import time
|
||||||
|
import uuid
|
||||||
|
|
||||||
from moto import settings, mock_sqs, mock_sqs_deprecated
|
from moto import settings, mock_sqs, mock_sqs_deprecated
|
||||||
from tests.helpers import requires_boto_gte
|
from tests.helpers import requires_boto_gte
|
||||||
import tests.backport_assert_raises # noqa
|
import tests.backport_assert_raises # noqa
|
||||||
from nose.tools import assert_raises
|
from nose.tools import assert_raises
|
||||||
|
from nose import SkipTest
|
||||||
|
|
||||||
|
|
||||||
@mock_sqs
|
@mock_sqs
|
||||||
@ -93,8 +98,6 @@ def test_message_send_without_attributes():
|
|||||||
msg.get('MD5OfMessageBody').should.equal(
|
msg.get('MD5OfMessageBody').should.equal(
|
||||||
'58fd9edd83341c29f1aebba81c31e257')
|
'58fd9edd83341c29f1aebba81c31e257')
|
||||||
msg.shouldnt.have.key('MD5OfMessageAttributes')
|
msg.shouldnt.have.key('MD5OfMessageAttributes')
|
||||||
msg.get('ResponseMetadata', {}).get('RequestId').should.equal(
|
|
||||||
'27daac76-34dd-47df-bd01-1f6e873584a0')
|
|
||||||
msg.get('MessageId').should_not.contain(' \n')
|
msg.get('MessageId').should_not.contain(' \n')
|
||||||
|
|
||||||
messages = queue.receive_messages()
|
messages = queue.receive_messages()
|
||||||
@ -118,8 +121,6 @@ def test_message_send_with_attributes():
|
|||||||
'58fd9edd83341c29f1aebba81c31e257')
|
'58fd9edd83341c29f1aebba81c31e257')
|
||||||
msg.get('MD5OfMessageAttributes').should.equal(
|
msg.get('MD5OfMessageAttributes').should.equal(
|
||||||
'235c5c510d26fb653d073faed50ae77c')
|
'235c5c510d26fb653d073faed50ae77c')
|
||||||
msg.get('ResponseMetadata', {}).get('RequestId').should.equal(
|
|
||||||
'27daac76-34dd-47df-bd01-1f6e873584a0')
|
|
||||||
msg.get('MessageId').should_not.contain(' \n')
|
msg.get('MessageId').should_not.contain(' \n')
|
||||||
|
|
||||||
messages = queue.receive_messages()
|
messages = queue.receive_messages()
|
||||||
@ -143,8 +144,6 @@ def test_message_with_complex_attributes():
|
|||||||
'58fd9edd83341c29f1aebba81c31e257')
|
'58fd9edd83341c29f1aebba81c31e257')
|
||||||
msg.get('MD5OfMessageAttributes').should.equal(
|
msg.get('MD5OfMessageAttributes').should.equal(
|
||||||
'8ae21a7957029ef04146b42aeaa18a22')
|
'8ae21a7957029ef04146b42aeaa18a22')
|
||||||
msg.get('ResponseMetadata', {}).get('RequestId').should.equal(
|
|
||||||
'27daac76-34dd-47df-bd01-1f6e873584a0')
|
|
||||||
msg.get('MessageId').should_not.contain(' \n')
|
msg.get('MessageId').should_not.contain(' \n')
|
||||||
|
|
||||||
messages = queue.receive_messages()
|
messages = queue.receive_messages()
|
||||||
@ -755,3 +754,181 @@ def test_delete_message_after_visibility_timeout():
|
|||||||
m1_retrieved.delete()
|
m1_retrieved.delete()
|
||||||
|
|
||||||
assert new_queue.count() == 0
|
assert new_queue.count() == 0
|
||||||
|
|
||||||
|
|
||||||
|
@mock_sqs
|
||||||
|
def test_batch_change_message_visibility():
|
||||||
|
if os.environ.get('TEST_SERVER_MODE', 'false').lower() == 'true':
|
||||||
|
raise SkipTest('Cant manipulate time in server mode')
|
||||||
|
|
||||||
|
with freeze_time("2015-01-01 12:00:00"):
|
||||||
|
sqs = boto3.client('sqs', region_name='us-east-1')
|
||||||
|
resp = sqs.create_queue(
|
||||||
|
QueueName='test-dlr-queue.fifo',
|
||||||
|
Attributes={'FifoQueue': 'true'}
|
||||||
|
)
|
||||||
|
queue_url = resp['QueueUrl']
|
||||||
|
|
||||||
|
sqs.send_message(QueueUrl=queue_url, MessageBody='msg1')
|
||||||
|
sqs.send_message(QueueUrl=queue_url, MessageBody='msg2')
|
||||||
|
sqs.send_message(QueueUrl=queue_url, MessageBody='msg3')
|
||||||
|
|
||||||
|
with freeze_time("2015-01-01 12:01:00"):
|
||||||
|
receive_resp = sqs.receive_message(QueueUrl=queue_url, MaxNumberOfMessages=2)
|
||||||
|
len(receive_resp['Messages']).should.equal(2)
|
||||||
|
|
||||||
|
handles = [item['ReceiptHandle'] for item in receive_resp['Messages']]
|
||||||
|
entries = [{'Id': str(uuid.uuid4()), 'ReceiptHandle': handle, 'VisibilityTimeout': 43200} for handle in handles]
|
||||||
|
|
||||||
|
resp = sqs.change_message_visibility_batch(QueueUrl=queue_url, Entries=entries)
|
||||||
|
len(resp['Successful']).should.equal(2)
|
||||||
|
|
||||||
|
with freeze_time("2015-01-01 14:00:00"):
|
||||||
|
resp = sqs.receive_message(QueueUrl=queue_url, MaxNumberOfMessages=3)
|
||||||
|
len(resp['Messages']).should.equal(1)
|
||||||
|
|
||||||
|
with freeze_time("2015-01-01 16:00:00"):
|
||||||
|
resp = sqs.receive_message(QueueUrl=queue_url, MaxNumberOfMessages=3)
|
||||||
|
len(resp['Messages']).should.equal(1)
|
||||||
|
|
||||||
|
with freeze_time("2015-01-02 12:00:00"):
|
||||||
|
resp = sqs.receive_message(QueueUrl=queue_url, MaxNumberOfMessages=3)
|
||||||
|
len(resp['Messages']).should.equal(3)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_sqs
|
||||||
|
def test_permissions():
|
||||||
|
client = boto3.client('sqs', region_name='us-east-1')
|
||||||
|
|
||||||
|
resp = client.create_queue(
|
||||||
|
QueueName='test-dlr-queue.fifo',
|
||||||
|
Attributes={'FifoQueue': 'true'}
|
||||||
|
)
|
||||||
|
queue_url = resp['QueueUrl']
|
||||||
|
|
||||||
|
client.add_permission(QueueUrl=queue_url, Label='account1', AWSAccountIds=['111111111111'], Actions=['*'])
|
||||||
|
client.add_permission(QueueUrl=queue_url, Label='account2', AWSAccountIds=['222211111111'], Actions=['SendMessage'])
|
||||||
|
|
||||||
|
with assert_raises(ClientError):
|
||||||
|
client.add_permission(QueueUrl=queue_url, Label='account2', AWSAccountIds=['222211111111'], Actions=['SomeRubbish'])
|
||||||
|
|
||||||
|
client.remove_permission(QueueUrl=queue_url, Label='account2')
|
||||||
|
|
||||||
|
with assert_raises(ClientError):
|
||||||
|
client.remove_permission(QueueUrl=queue_url, Label='non_existant')
|
||||||
|
|
||||||
|
|
||||||
|
@mock_sqs
|
||||||
|
def test_tags():
|
||||||
|
client = boto3.client('sqs', region_name='us-east-1')
|
||||||
|
|
||||||
|
resp = client.create_queue(
|
||||||
|
QueueName='test-dlr-queue.fifo',
|
||||||
|
Attributes={'FifoQueue': 'true'}
|
||||||
|
)
|
||||||
|
queue_url = resp['QueueUrl']
|
||||||
|
|
||||||
|
client.tag_queue(
|
||||||
|
QueueUrl=queue_url,
|
||||||
|
Tags={
|
||||||
|
'test1': 'value1',
|
||||||
|
'test2': 'value2',
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
resp = client.list_queue_tags(QueueUrl=queue_url)
|
||||||
|
resp['Tags'].should.contain('test1')
|
||||||
|
resp['Tags'].should.contain('test2')
|
||||||
|
|
||||||
|
client.untag_queue(
|
||||||
|
QueueUrl=queue_url,
|
||||||
|
TagKeys=['test2']
|
||||||
|
)
|
||||||
|
|
||||||
|
resp = client.list_queue_tags(QueueUrl=queue_url)
|
||||||
|
resp['Tags'].should.contain('test1')
|
||||||
|
resp['Tags'].should_not.contain('test2')
|
||||||
|
|
||||||
|
|
||||||
|
@mock_sqs
|
||||||
|
def test_create_fifo_queue_with_dlq():
|
||||||
|
sqs = boto3.client('sqs', region_name='us-east-1')
|
||||||
|
resp = sqs.create_queue(
|
||||||
|
QueueName='test-dlr-queue.fifo',
|
||||||
|
Attributes={'FifoQueue': 'true'}
|
||||||
|
)
|
||||||
|
queue_url1 = resp['QueueUrl']
|
||||||
|
queue_arn1 = sqs.get_queue_attributes(QueueUrl=queue_url1)['Attributes']['QueueArn']
|
||||||
|
|
||||||
|
resp = sqs.create_queue(
|
||||||
|
QueueName='test-dlr-queue',
|
||||||
|
Attributes={'FifoQueue': 'false'}
|
||||||
|
)
|
||||||
|
queue_url2 = resp['QueueUrl']
|
||||||
|
queue_arn2 = sqs.get_queue_attributes(QueueUrl=queue_url2)['Attributes']['QueueArn']
|
||||||
|
|
||||||
|
sqs.create_queue(
|
||||||
|
QueueName='test-queue.fifo',
|
||||||
|
Attributes={
|
||||||
|
'FifoQueue': 'true',
|
||||||
|
'RedrivePolicy': json.dumps({'deadLetterTargetArn': queue_arn1, 'maxReceiveCount': 2})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Cant have fifo queue with non fifo DLQ
|
||||||
|
with assert_raises(ClientError):
|
||||||
|
sqs.create_queue(
|
||||||
|
QueueName='test-queue2.fifo',
|
||||||
|
Attributes={
|
||||||
|
'FifoQueue': 'true',
|
||||||
|
'RedrivePolicy': json.dumps({'deadLetterTargetArn': queue_arn2, 'maxReceiveCount': 2})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_sqs
|
||||||
|
def test_queue_with_dlq():
|
||||||
|
if os.environ.get('TEST_SERVER_MODE', 'false').lower() == 'true':
|
||||||
|
raise SkipTest('Cant manipulate time in server mode')
|
||||||
|
|
||||||
|
sqs = boto3.client('sqs', region_name='us-east-1')
|
||||||
|
|
||||||
|
with freeze_time("2015-01-01 12:00:00"):
|
||||||
|
resp = sqs.create_queue(
|
||||||
|
QueueName='test-dlr-queue.fifo',
|
||||||
|
Attributes={'FifoQueue': 'true'}
|
||||||
|
)
|
||||||
|
queue_url1 = resp['QueueUrl']
|
||||||
|
queue_arn1 = sqs.get_queue_attributes(QueueUrl=queue_url1)['Attributes']['QueueArn']
|
||||||
|
|
||||||
|
resp = sqs.create_queue(
|
||||||
|
QueueName='test-queue.fifo',
|
||||||
|
Attributes={
|
||||||
|
'FifoQueue': 'true',
|
||||||
|
'RedrivePolicy': json.dumps({'deadLetterTargetArn': queue_arn1, 'maxReceiveCount': 2})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
queue_url2 = resp['QueueUrl']
|
||||||
|
|
||||||
|
sqs.send_message(QueueUrl=queue_url2, MessageBody='msg1')
|
||||||
|
sqs.send_message(QueueUrl=queue_url2, MessageBody='msg2')
|
||||||
|
|
||||||
|
with freeze_time("2015-01-01 13:00:00"):
|
||||||
|
resp = sqs.receive_message(QueueUrl=queue_url2, VisibilityTimeout=30, WaitTimeSeconds=0)
|
||||||
|
resp['Messages'][0]['Body'].should.equal('msg1')
|
||||||
|
|
||||||
|
with freeze_time("2015-01-01 13:01:00"):
|
||||||
|
resp = sqs.receive_message(QueueUrl=queue_url2, VisibilityTimeout=30, WaitTimeSeconds=0)
|
||||||
|
resp['Messages'][0]['Body'].should.equal('msg1')
|
||||||
|
|
||||||
|
with freeze_time("2015-01-01 13:02:00"):
|
||||||
|
resp = sqs.receive_message(QueueUrl=queue_url2, VisibilityTimeout=30, WaitTimeSeconds=0)
|
||||||
|
len(resp['Messages']).should.equal(1)
|
||||||
|
|
||||||
|
resp = sqs.receive_message(QueueUrl=queue_url1, VisibilityTimeout=30, WaitTimeSeconds=0)
|
||||||
|
resp['Messages'][0]['Body'].should.equal('msg1')
|
||||||
|
|
||||||
|
# Might as well test list source queues
|
||||||
|
|
||||||
|
resp = sqs.list_dead_letter_source_queues(QueueUrl=queue_url1)
|
||||||
|
resp['queueUrls'][0].should.equal(queue_url2)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user