Merge pull request #18 from spulec/master

Merge upstream
This commit is contained in:
Bert Blommers 2019-11-19 07:59:33 +00:00 committed by GitHub
commit e9edbab4e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 1161 additions and 52 deletions

View File

@ -171,7 +171,7 @@
- [ ] update_webhook
## apigateway
24% implemented
25% implemented
- [ ] create_api_key
- [ ] create_authorizer
- [ ] create_base_path_mapping
@ -204,7 +204,7 @@
- [ ] delete_request_validator
- [X] delete_resource
- [X] delete_rest_api
- [ ] delete_stage
- [X] delete_stage
- [X] delete_usage_plan
- [X] delete_usage_plan_key
- [ ] delete_vpc_link
@ -687,12 +687,17 @@
## ce
0% implemented
- [ ] get_cost_and_usage
- [ ] get_cost_and_usage_with_resources
- [ ] get_cost_forecast
- [ ] get_dimension_values
- [ ] get_reservation_coverage
- [ ] get_reservation_purchase_recommendation
- [ ] get_reservation_utilization
- [ ] get_rightsizing_recommendation
- [ ] get_savings_plans_coverage
- [ ] get_savings_plans_purchase_recommendation
- [ ] get_savings_plans_utilization
- [ ] get_savings_plans_utilization_details
- [ ] get_tags
- [ ] get_usage_forecast
@ -701,6 +706,7 @@
- [ ] associate_phone_number_with_user
- [ ] associate_phone_numbers_with_voice_connector
- [ ] associate_phone_numbers_with_voice_connector_group
- [ ] batch_create_room_membership
- [ ] batch_delete_phone_number
- [ ] batch_suspend_user
- [ ] batch_unsuspend_user
@ -709,11 +715,15 @@
- [ ] create_account
- [ ] create_bot
- [ ] create_phone_number_order
- [ ] create_room
- [ ] create_room_membership
- [ ] create_voice_connector
- [ ] create_voice_connector_group
- [ ] delete_account
- [ ] delete_events_configuration
- [ ] delete_phone_number
- [ ] delete_room
- [ ] delete_room_membership
- [ ] delete_voice_connector
- [ ] delete_voice_connector_group
- [ ] delete_voice_connector_origination
@ -731,6 +741,7 @@
- [ ] get_phone_number
- [ ] get_phone_number_order
- [ ] get_phone_number_settings
- [ ] get_room
- [ ] get_user
- [ ] get_user_settings
- [ ] get_voice_connector
@ -745,6 +756,8 @@
- [ ] list_bots
- [ ] list_phone_number_orders
- [ ] list_phone_numbers
- [ ] list_room_memberships
- [ ] list_rooms
- [ ] list_users
- [ ] list_voice_connector_groups
- [ ] list_voice_connector_termination_credentials
@ -766,6 +779,8 @@
- [ ] update_global_settings
- [ ] update_phone_number
- [ ] update_phone_number_settings
- [ ] update_room
- [ ] update_room_membership
- [ ] update_user
- [ ] update_user_settings
- [ ] update_voice_connector
@ -1003,6 +1018,7 @@
- [ ] delete_suggester
- [ ] describe_analysis_schemes
- [ ] describe_availability_options
- [ ] describe_domain_endpoint_options
- [ ] describe_domains
- [ ] describe_expressions
- [ ] describe_index_fields
@ -1012,6 +1028,7 @@
- [ ] index_documents
- [ ] list_domain_names
- [ ] update_availability_options
- [ ] update_domain_endpoint_options
- [ ] update_scaling_parameters
- [ ] update_service_access_policies
@ -1028,9 +1045,11 @@
- [ ] delete_trail
- [ ] describe_trails
- [ ] get_event_selectors
- [ ] get_trail
- [ ] get_trail_status
- [ ] list_public_keys
- [ ] list_tags
- [ ] list_trails
- [ ] lookup_events
- [ ] put_event_selectors
- [ ] remove_tags
@ -1252,6 +1271,22 @@
- [ ] update_team_member
- [ ] update_user_profile
## codestar-notifications
0% implemented
- [ ] create_notification_rule
- [ ] delete_notification_rule
- [ ] delete_target
- [ ] describe_notification_rule
- [ ] list_event_types
- [ ] list_notification_rules
- [ ] list_tags_for_resource
- [ ] list_targets
- [ ] subscribe
- [ ] tag_resource
- [ ] unsubscribe
- [ ] untag_resource
- [ ] update_notification_rule
## cognito-identity
28% implemented
- [X] create_identity_pool
@ -1545,10 +1580,13 @@
- [ ] list_queues
- [ ] list_routing_profiles
- [ ] list_security_profiles
- [ ] list_tags_for_resource
- [ ] list_user_hierarchy_groups
- [ ] list_users
- [ ] start_outbound_voice_contact
- [ ] stop_contact
- [ ] tag_resource
- [ ] untag_resource
- [ ] update_contact_attributes
- [ ] update_user_hierarchy
- [ ] update_user_identity_info
@ -1563,6 +1601,31 @@
- [ ] modify_report_definition
- [ ] put_report_definition
## dataexchange
0% implemented
- [ ] cancel_job
- [ ] create_data_set
- [ ] create_job
- [ ] create_revision
- [ ] delete_asset
- [ ] delete_data_set
- [ ] delete_revision
- [ ] get_asset
- [ ] get_data_set
- [ ] get_job
- [ ] get_revision
- [ ] list_data_set_revisions
- [ ] list_data_sets
- [ ] list_jobs
- [ ] list_revision_assets
- [ ] list_tags_for_resource
- [ ] start_job
- [ ] tag_resource
- [ ] untag_resource
- [ ] update_asset
- [ ] update_data_set
- [ ] update_revision
## datapipeline
42% implemented
- [X] activate_pipeline
@ -1586,17 +1649,17 @@
- [ ] validate_pipeline_definition
## datasync
0% implemented
- [ ] cancel_task_execution
22% implemented
- [X] cancel_task_execution
- [ ] create_agent
- [ ] create_location_efs
- [ ] create_location_nfs
- [ ] create_location_s3
- [ ] create_location_smb
- [ ] create_task
- [X] create_task
- [ ] delete_agent
- [ ] delete_location
- [ ] delete_task
- [X] delete_location
- [X] delete_task
- [ ] describe_agent
- [ ] describe_location_efs
- [ ] describe_location_nfs
@ -1609,11 +1672,11 @@
- [ ] list_tags_for_resource
- [ ] list_task_executions
- [ ] list_tasks
- [ ] start_task_execution
- [X] start_task_execution
- [ ] tag_resource
- [ ] untag_resource
- [ ] update_agent
- [ ] update_task
- [X] update_task
## dax
0% implemented
@ -1799,6 +1862,9 @@
- [ ] delete_lifecycle_policy
- [ ] get_lifecycle_policies
- [ ] get_lifecycle_policy
- [ ] list_tags_for_resource
- [ ] tag_resource
- [ ] untag_resource
- [ ] update_lifecycle_policy
## dms
@ -2217,8 +2283,8 @@
- [X] describe_volumes
- [ ] describe_volumes_modifications
- [X] describe_vpc_attribute
- [ ] describe_vpc_classic_link
- [ ] describe_vpc_classic_link_dns_support
- [X] describe_vpc_classic_link
- [X] describe_vpc_classic_link_dns_support
- [ ] describe_vpc_endpoint_connection_notifications
- [ ] describe_vpc_endpoint_connections
- [ ] describe_vpc_endpoint_service_configurations
@ -2237,8 +2303,8 @@
- [ ] disable_ebs_encryption_by_default
- [ ] disable_transit_gateway_route_table_propagation
- [ ] disable_vgw_route_propagation
- [ ] disable_vpc_classic_link
- [ ] disable_vpc_classic_link_dns_support
- [X] disable_vpc_classic_link
- [X] disable_vpc_classic_link_dns_support
- [X] disassociate_address
- [ ] disassociate_client_vpn_target_network
- [ ] disassociate_iam_instance_profile
@ -2250,8 +2316,8 @@
- [ ] enable_transit_gateway_route_table_propagation
- [ ] enable_vgw_route_propagation
- [ ] enable_volume_io
- [ ] enable_vpc_classic_link
- [ ] enable_vpc_classic_link_dns_support
- [X] enable_vpc_classic_link
- [X] enable_vpc_classic_link_dns_support
- [ ] export_client_vpn_client_certificate_revocation_list
- [ ] export_client_vpn_client_configuration
- [ ] export_image
@ -2461,16 +2527,22 @@
## eks
0% implemented
- [ ] create_cluster
- [ ] create_nodegroup
- [ ] delete_cluster
- [ ] delete_nodegroup
- [ ] describe_cluster
- [ ] describe_nodegroup
- [ ] describe_update
- [ ] list_clusters
- [ ] list_nodegroups
- [ ] list_tags_for_resource
- [ ] list_updates
- [ ] tag_resource
- [ ] untag_resource
- [ ] update_cluster_config
- [ ] update_cluster_version
- [ ] update_nodegroup_config
- [ ] update_nodegroup_version
## elasticache
0% implemented
@ -3217,6 +3289,7 @@
- [ ] create_filter
- [ ] create_ip_set
- [ ] create_members
- [ ] create_publishing_destination
- [ ] create_sample_findings
- [ ] create_threat_intel_set
- [ ] decline_invitations
@ -3225,7 +3298,9 @@
- [ ] delete_invitations
- [ ] delete_ip_set
- [ ] delete_members
- [ ] delete_publishing_destination
- [ ] delete_threat_intel_set
- [ ] describe_publishing_destination
- [ ] disassociate_from_master_account
- [ ] disassociate_members
- [ ] get_detector
@ -3244,6 +3319,7 @@
- [ ] list_invitations
- [ ] list_ip_sets
- [ ] list_members
- [ ] list_publishing_destinations
- [ ] list_tags_for_resource
- [ ] list_threat_intel_sets
- [ ] start_monitoring_members
@ -3255,6 +3331,7 @@
- [ ] update_filter
- [ ] update_findings_feedback
- [ ] update_ip_set
- [ ] update_publishing_destination
- [ ] update_threat_intel_set
## health
@ -3267,7 +3344,7 @@
- [ ] describe_events
## iam
62% implemented
65% implemented
- [ ] add_client_id_to_open_id_connect_provider
- [X] add_role_to_instance_profile
- [X] add_user_to_group
@ -3293,7 +3370,7 @@
- [X] delete_access_key
- [X] delete_account_alias
- [X] delete_account_password_policy
- [ ] delete_group
- [X] delete_group
- [ ] delete_group_policy
- [ ] delete_instance_profile
- [X] delete_login_profile
@ -3323,7 +3400,7 @@
- [X] get_access_key_last_used
- [X] get_account_authorization_details
- [X] get_account_password_policy
- [ ] get_account_summary
- [X] get_account_summary
- [ ] get_context_keys_for_custom_policy
- [ ] get_context_keys_for_principal_policy
- [X] get_credential_report
@ -3405,7 +3482,7 @@
- [X] update_signing_certificate
- [ ] update_ssh_public_key
- [X] update_user
- [ ] upload_server_certificate
- [X] upload_server_certificate
- [X] upload_signing_certificate
- [ ] upload_ssh_public_key
@ -3459,7 +3536,7 @@
- [ ] update_assessment_target
## iot
23% implemented
22% implemented
- [ ] accept_certificate_transfer
- [ ] add_thing_to_billing_group
- [X] add_thing_to_thing_group
@ -3544,11 +3621,13 @@
- [X] detach_thing_principal
- [ ] disable_topic_rule
- [ ] enable_topic_rule
- [ ] get_cardinality
- [ ] get_effective_policies
- [ ] get_indexing_configuration
- [ ] get_job_document
- [ ] get_logging_options
- [ ] get_ota_update
- [ ] get_percentiles
- [X] get_policy
- [ ] get_policy_version
- [ ] get_registration_code
@ -4295,6 +4374,15 @@
- [ ] reject_invitation
- [ ] vote_on_proposal
## marketplace-catalog
0% implemented
- [ ] cancel_change_set
- [ ] describe_change_set
- [ ] describe_entity
- [ ] list_change_sets
- [ ] list_entities
- [ ] start_change_set
## marketplace-entitlement
0% implemented
- [ ] get_entitlements
@ -4773,6 +4861,7 @@
## personalize
0% implemented
- [ ] create_batch_inference_job
- [ ] create_campaign
- [ ] create_dataset
- [ ] create_dataset_group
@ -4788,6 +4877,7 @@
- [ ] delete_schema
- [ ] delete_solution
- [ ] describe_algorithm
- [ ] describe_batch_inference_job
- [ ] describe_campaign
- [ ] describe_dataset
- [ ] describe_dataset_group
@ -4799,6 +4889,7 @@
- [ ] describe_solution
- [ ] describe_solution_version
- [ ] get_solution_metrics
- [ ] list_batch_inference_jobs
- [ ] list_campaigns
- [ ] list_dataset_groups
- [ ] list_dataset_import_jobs
@ -4831,6 +4922,7 @@
- [ ] create_email_template
- [ ] create_export_job
- [ ] create_import_job
- [ ] create_journey
- [ ] create_push_template
- [ ] create_segment
- [ ] create_sms_template
@ -4847,6 +4939,7 @@
- [ ] delete_endpoint
- [ ] delete_event_stream
- [ ] delete_gcm_channel
- [ ] delete_journey
- [ ] delete_push_template
- [ ] delete_segment
- [ ] delete_sms_channel
@ -4879,6 +4972,10 @@
- [ ] get_gcm_channel
- [ ] get_import_job
- [ ] get_import_jobs
- [ ] get_journey
- [ ] get_journey_date_range_kpi
- [ ] get_journey_execution_activity_metrics
- [ ] get_journey_execution_metrics
- [ ] get_push_template
- [ ] get_segment
- [ ] get_segment_export_jobs
@ -4890,6 +4987,7 @@
- [ ] get_sms_template
- [ ] get_user_endpoints
- [ ] get_voice_channel
- [ ] list_journeys
- [ ] list_tags_for_resource
- [ ] list_templates
- [ ] phone_number_validate
@ -4913,6 +5011,8 @@
- [ ] update_endpoint
- [ ] update_endpoints_batch
- [ ] update_gcm_channel
- [ ] update_journey
- [ ] update_journey_state
- [ ] update_push_template
- [ ] update_segment
- [ ] update_sms_channel
@ -5661,6 +5761,17 @@
0% implemented
- [ ] invoke_endpoint
## savingsplans
0% implemented
- [ ] create_savings_plan
- [ ] describe_savings_plan_rates
- [ ] describe_savings_plans
- [ ] describe_savings_plans_offering_rates
- [ ] describe_savings_plans_offerings
- [ ] list_tags_for_resource
- [ ] tag_resource
- [ ] untag_resource
## sdb
0% implemented
- [ ] batch_delete_attributes
@ -5954,6 +6065,51 @@
- [X] verify_email_address
- [X] verify_email_identity
## sesv2
0% implemented
- [ ] create_configuration_set
- [ ] create_configuration_set_event_destination
- [ ] create_dedicated_ip_pool
- [ ] create_deliverability_test_report
- [ ] create_email_identity
- [ ] delete_configuration_set
- [ ] delete_configuration_set_event_destination
- [ ] delete_dedicated_ip_pool
- [ ] delete_email_identity
- [ ] get_account
- [ ] get_blacklist_reports
- [ ] get_configuration_set
- [ ] get_configuration_set_event_destinations
- [ ] get_dedicated_ip
- [ ] get_dedicated_ips
- [ ] get_deliverability_dashboard_options
- [ ] get_deliverability_test_report
- [ ] get_domain_deliverability_campaign
- [ ] get_domain_statistics_report
- [ ] get_email_identity
- [ ] list_configuration_sets
- [ ] list_dedicated_ip_pools
- [ ] list_deliverability_test_reports
- [ ] list_domain_deliverability_campaigns
- [ ] list_email_identities
- [ ] list_tags_for_resource
- [ ] put_account_dedicated_ip_warmup_attributes
- [ ] put_account_sending_attributes
- [ ] put_configuration_set_delivery_options
- [ ] put_configuration_set_reputation_options
- [ ] put_configuration_set_sending_options
- [ ] put_configuration_set_tracking_options
- [ ] put_dedicated_ip_in_pool
- [ ] put_dedicated_ip_warmup_attributes
- [ ] put_deliverability_dashboard_option
- [ ] put_email_identity_dkim_attributes
- [ ] put_email_identity_feedback_attributes
- [ ] put_email_identity_mail_from_attributes
- [ ] send_email
- [ ] tag_resource
- [ ] untag_resource
- [ ] update_configuration_set_event_destination
## shield
0% implemented
- [ ] associate_drt_log_bucket
@ -5984,8 +6140,11 @@
- [ ] list_signing_jobs
- [ ] list_signing_platforms
- [ ] list_signing_profiles
- [ ] list_tags_for_resource
- [ ] put_signing_profile
- [ ] start_signing_job
- [ ] tag_resource
- [ ] untag_resource
## sms
0% implemented
@ -6111,7 +6270,7 @@
- [X] untag_queue
## ssm
10% implemented
11% implemented
- [X] add_tags_to_resource
- [ ] cancel_command
- [ ] cancel_maintenance_window_execution
@ -6184,7 +6343,7 @@
- [ ] get_ops_item
- [ ] get_ops_summary
- [X] get_parameter
- [ ] get_parameter_history
- [X] get_parameter_history
- [X] get_parameters
- [X] get_parameters_by_path
- [ ] get_patch_baseline
@ -6233,6 +6392,19 @@
- [ ] update_patch_baseline
- [ ] update_service_setting
## sso
0% implemented
- [ ] get_role_credentials
- [ ] list_account_roles
- [ ] list_accounts
- [ ] logout
## sso-oidc
0% implemented
- [ ] create_token
- [ ] register_client
- [ ] start_device_authorization
## stepfunctions
36% implemented
- [ ] create_activity
@ -6742,6 +6914,7 @@
- [ ] delete_ip_group
- [ ] delete_tags
- [ ] delete_workspace_image
- [ ] deregister_workspace_directory
- [ ] describe_account
- [ ] describe_account_modifications
- [ ] describe_client_properties
@ -6758,10 +6931,14 @@
- [ ] list_available_management_cidr_ranges
- [ ] modify_account
- [ ] modify_client_properties
- [ ] modify_selfservice_permissions
- [ ] modify_workspace_access_properties
- [ ] modify_workspace_creation_properties
- [ ] modify_workspace_properties
- [ ] modify_workspace_state
- [ ] reboot_workspaces
- [ ] rebuild_workspaces
- [ ] register_workspace_directory
- [ ] restore_workspace
- [ ] revoke_ip_rules
- [ ] start_workspaces

View File

@ -46,8 +46,9 @@ try:
except ImportError:
from backports.tempfile import TemporaryDirectory
_stderr_regex = re.compile(r"START|END|REPORT RequestId: .*")
# The lambci container is returning a special escape character for the "RequestID" fields. Unicode 033:
# _stderr_regex = re.compile(r"START|END|REPORT RequestId: .*")
_stderr_regex = re.compile(r"\033\[\d+.*")
_orig_adapter_send = requests.adapters.HTTPAdapter.send
docker_3 = docker.__version__[0] >= "3"
@ -444,7 +445,7 @@ class LambdaFunction(BaseModel):
if exit_code != 0:
raise Exception("lambda invoke failed output: {}".format(output))
# strip out RequestId lines
# strip out RequestId lines (TODO: This will return an additional '\n' in the response)
output = os.linesep.join(
[
line

View File

@ -624,7 +624,7 @@ class BatchBackend(BaseBackend):
def get_job_definition(self, identifier):
"""
Get job defintiion by name or ARN
Get job definitions by name or ARN
:param identifier: Name or ARN
:type identifier: str
@ -643,7 +643,7 @@ class BatchBackend(BaseBackend):
def get_job_definitions(self, identifier):
"""
Get job defintiion by name or ARN
Get job definitions by name or ARN
:param identifier: Name or ARN
:type identifier: str
@ -934,7 +934,7 @@ class BatchBackend(BaseBackend):
self.ecs_backend.delete_cluster(compute_env.ecs_name)
if compute_env.env_type == "MANAGED":
# Delete compute envrionment
# Delete compute environment
instance_ids = [instance.id for instance in compute_env.instances]
self.ec2_backend.terminate_instances(instance_ids)
@ -1195,7 +1195,7 @@ class BatchBackend(BaseBackend):
depends_on=None,
container_overrides=None,
):
# TODO parameters, retries (which is a dict raw from request), job dependancies and container overrides are ignored for now
# TODO parameters, retries (which is a dict raw from request), job dependencies and container overrides are ignored for now
# Look for job definition
job_def = self.get_job_definition(job_def_id)

View File

@ -2444,6 +2444,7 @@ class VPC(TaggedEC2Resource):
self.instance_tenancy = instance_tenancy
self.is_default = "true" if is_default else "false"
self.enable_dns_support = "true"
self.classic_link_enabled = "false"
# This attribute is set to 'true' only for default VPCs
# or VPCs created using the wizard of the VPC console
self.enable_dns_hostnames = "true" if is_default else "false"
@ -2540,6 +2541,32 @@ class VPC(TaggedEC2Resource):
self.cidr_block_association_set[association_id] = association_set
return association_set
def enable_vpc_classic_link(self):
# Check if current cidr block doesn't fall within the 10.0.0.0/8 block, excluding 10.0.0.0/16 and 10.1.0.0/16.
# Doesn't check any route tables, maybe something for in the future?
# See https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/vpc-classiclink.html#classiclink-limitations
network_address = ipaddress.ip_network(self.cidr_block).network_address
if (
network_address not in ipaddress.ip_network("10.0.0.0/8")
or network_address in ipaddress.ip_network("10.0.0.0/16")
or network_address in ipaddress.ip_network("10.1.0.0/16")
):
self.classic_link_enabled = "true"
return self.classic_link_enabled
def disable_vpc_classic_link(self):
self.classic_link_enabled = "false"
return self.classic_link_enabled
def enable_vpc_classic_link_dns_support(self):
self.classic_link_dns_supported = "true"
return self.classic_link_dns_supported
def disable_vpc_classic_link_dns_support(self):
self.classic_link_dns_supported = "false"
return self.classic_link_dns_supported
def disassociate_vpc_cidr_block(self, association_id):
if self.cidr_block == self.cidr_block_association_set.get(
association_id, {}
@ -2670,6 +2697,22 @@ class VPCBackend(object):
else:
raise InvalidParameterValueError(attr_name)
def enable_vpc_classic_link(self, vpc_id):
vpc = self.get_vpc(vpc_id)
return vpc.enable_vpc_classic_link()
def disable_vpc_classic_link(self, vpc_id):
vpc = self.get_vpc(vpc_id)
return vpc.disable_vpc_classic_link()
def enable_vpc_classic_link_dns_support(self, vpc_id):
vpc = self.get_vpc(vpc_id)
return vpc.enable_vpc_classic_link_dns_support()
def disable_vpc_classic_link_dns_support(self, vpc_id):
vpc = self.get_vpc(vpc_id)
return vpc.disable_vpc_classic_link_dns_support()
def modify_vpc_attribute(self, vpc_id, attr_name, attr_value):
vpc = self.get_vpc(vpc_id)
if attr_name in ("enable_dns_support", "enable_dns_hostnames"):

View File

@ -5,6 +5,13 @@ from moto.ec2.utils import filters_from_querystring
class VPCs(BaseResponse):
def _get_doc_date(self):
return (
"2013-10-15"
if "Boto/" in self.headers.get("user-agent", "")
else "2016-11-15"
)
def create_vpc(self):
cidr_block = self._get_param("CidrBlock")
instance_tenancy = self._get_param("InstanceTenancy", if_none="default")
@ -16,11 +23,7 @@ class VPCs(BaseResponse):
instance_tenancy,
amazon_provided_ipv6_cidr_block=amazon_provided_ipv6_cidr_blocks,
)
doc_date = (
"2013-10-15"
if "Boto/" in self.headers.get("user-agent", "")
else "2016-11-15"
)
doc_date = self._get_doc_date()
template = self.response_template(CREATE_VPC_RESPONSE)
return template.render(vpc=vpc, doc_date=doc_date)
@ -50,6 +53,64 @@ class VPCs(BaseResponse):
template = self.response_template(DESCRIBE_VPC_ATTRIBUTE_RESPONSE)
return template.render(vpc_id=vpc_id, attribute=attribute, value=value)
def describe_vpc_classic_link_dns_support(self):
vpc_ids = self._get_multi_param("VpcIds")
filters = filters_from_querystring(self.querystring)
vpcs = self.ec2_backend.get_all_vpcs(vpc_ids=vpc_ids, filters=filters)
doc_date = self._get_doc_date()
template = self.response_template(
DESCRIBE_VPC_CLASSIC_LINK_DNS_SUPPORT_RESPONSE
)
return template.render(vpcs=vpcs, doc_date=doc_date)
def enable_vpc_classic_link_dns_support(self):
vpc_id = self._get_param("VpcId")
classic_link_dns_supported = self.ec2_backend.enable_vpc_classic_link_dns_support(
vpc_id=vpc_id
)
doc_date = self._get_doc_date()
template = self.response_template(ENABLE_VPC_CLASSIC_LINK_DNS_SUPPORT_RESPONSE)
return template.render(
classic_link_dns_supported=classic_link_dns_supported, doc_date=doc_date
)
def disable_vpc_classic_link_dns_support(self):
vpc_id = self._get_param("VpcId")
classic_link_dns_supported = self.ec2_backend.disable_vpc_classic_link_dns_support(
vpc_id=vpc_id
)
doc_date = self._get_doc_date()
template = self.response_template(DISABLE_VPC_CLASSIC_LINK_DNS_SUPPORT_RESPONSE)
return template.render(
classic_link_dns_supported=classic_link_dns_supported, doc_date=doc_date
)
def describe_vpc_classic_link(self):
vpc_ids = self._get_multi_param("VpcId")
filters = filters_from_querystring(self.querystring)
vpcs = self.ec2_backend.get_all_vpcs(vpc_ids=vpc_ids, filters=filters)
doc_date = self._get_doc_date()
template = self.response_template(DESCRIBE_VPC_CLASSIC_LINK_RESPONSE)
return template.render(vpcs=vpcs, doc_date=doc_date)
def enable_vpc_classic_link(self):
vpc_id = self._get_param("VpcId")
classic_link_enabled = self.ec2_backend.enable_vpc_classic_link(vpc_id=vpc_id)
doc_date = self._get_doc_date()
template = self.response_template(ENABLE_VPC_CLASSIC_LINK_RESPONSE)
return template.render(
classic_link_enabled=classic_link_enabled, doc_date=doc_date
)
def disable_vpc_classic_link(self):
vpc_id = self._get_param("VpcId")
classic_link_enabled = self.ec2_backend.disable_vpc_classic_link(vpc_id=vpc_id)
doc_date = self._get_doc_date()
template = self.response_template(DISABLE_VPC_CLASSIC_LINK_RESPONSE)
return template.render(
classic_link_enabled=classic_link_enabled, doc_date=doc_date
)
def modify_vpc_attribute(self):
vpc_id = self._get_param("VpcId")
@ -149,6 +210,56 @@ CREATE_VPC_RESPONSE = """
</vpc>
</CreateVpcResponse>"""
DESCRIBE_VPC_CLASSIC_LINK_DNS_SUPPORT_RESPONSE = """
<DescribeVpcClassicLinkDnsSupportResponse xmlns="http://ec2.amazonaws.com/doc/{{doc_date}}/">
<requestId>7a62c442-3484-4f42-9342-6942EXAMPLE</requestId>
<vpcs>
{% for vpc in vpcs %}
<item>
<vpcId>{{ vpc.id }}</vpcId>
<classicLinkDnsSupported>{{ vpc.classic_link_dns_supported }}</classicLinkDnsSupported>
</item>
{% endfor %}
</vpcs>
</DescribeVpcClassicLinkDnsSupportResponse>"""
ENABLE_VPC_CLASSIC_LINK_DNS_SUPPORT_RESPONSE = """
<EnableVpcClassicLinkDnsSupportResponse xmlns="http://ec2.amazonaws.com/doc/{{doc_date}}/">
<requestId>7a62c442-3484-4f42-9342-6942EXAMPLE</requestId>
<return>{{ classic_link_dns_supported }}</return>
</EnableVpcClassicLinkDnsSupportResponse>"""
DISABLE_VPC_CLASSIC_LINK_DNS_SUPPORT_RESPONSE = """
<DisableVpcClassicLinkDnsSupportResponse xmlns="http://ec2.amazonaws.com/doc/{{doc_date}}/">
<requestId>7a62c442-3484-4f42-9342-6942EXAMPLE</requestId>
<return>{{ classic_link_dns_supported }}</return>
</DisableVpcClassicLinkDnsSupportResponse>"""
DESCRIBE_VPC_CLASSIC_LINK_RESPONSE = """
<DescribeVpcClassicLinkResponse xmlns="http://ec2.amazonaws.com/doc/{{doc_date}}/">
<requestId>7a62c442-3484-4f42-9342-6942EXAMPLE</requestId>
<vpcSet>
{% for vpc in vpcs %}
<item>
<vpcId>{{ vpc.id }}</vpcId>
<classicLinkEnabled>{{ vpc.classic_link_enabled }}</classicLinkEnabled>
</item>
{% endfor %}
</vpcSet>
</DescribeVpcClassicLinkResponse>"""
ENABLE_VPC_CLASSIC_LINK_RESPONSE = """
<EnableVpcClassicLinkResponse xmlns="http://ec2.amazonaws.com/doc/{{doc_date}}/">
<requestId>7a62c442-3484-4f42-9342-6942EXAMPLE</requestId>
<return>{{ classic_link_enabled }}</return>
</EnableVpcClassicLinkResponse>"""
DISABLE_VPC_CLASSIC_LINK_RESPONSE = """
<DisableVpcClassicLinkResponse xmlns="http://ec2.amazonaws.com/doc/{{doc_date}}/">
<requestId>7a62c442-3484-4f42-9342-6942EXAMPLE</requestId>
<return>{{ classic_link_enabled }}</return>
</DisableVpcClassicLinkResponse>"""
DESCRIBE_VPCS_RESPONSE = """
<DescribeVpcsResponse xmlns="http://ec2.amazonaws.com/doc/{{doc_date}}/">
<requestId>7a62c442-3484-4f42-9342-6942EXAMPLE</requestId>

View File

@ -1,5 +1,6 @@
from __future__ import unicode_literals
import base64
import hashlib
import os
import random
import string
@ -475,6 +476,20 @@ class AccessKey(BaseModel):
raise UnformattedGetAttTemplateException()
class SshPublicKey(BaseModel):
def __init__(self, user_name, ssh_public_key_body):
self.user_name = user_name
self.ssh_public_key_body = ssh_public_key_body
self.ssh_public_key_id = "APKA" + random_access_key()
self.fingerprint = hashlib.md5(ssh_public_key_body.encode()).hexdigest()
self.status = "Active"
self.upload_date = datetime.utcnow()
@property
def uploaded_iso_8601(self):
return iso_8601_datetime_without_milliseconds(self.upload_date)
class Group(BaseModel):
def __init__(self, name, path="/"):
self.name = name
@ -536,6 +551,7 @@ class User(BaseModel):
self.policies = {}
self.managed_policies = {}
self.access_keys = []
self.ssh_public_keys = []
self.password = None
self.password_reset_required = False
self.signing_certificates = {}
@ -605,6 +621,33 @@ class User(BaseModel):
"The Access Key with id {0} cannot be found".format(access_key_id)
)
def upload_ssh_public_key(self, ssh_public_key_body):
pubkey = SshPublicKey(self.name, ssh_public_key_body)
self.ssh_public_keys.append(pubkey)
return pubkey
def get_ssh_public_key(self, ssh_public_key_id):
for key in self.ssh_public_keys:
if key.ssh_public_key_id == ssh_public_key_id:
return key
else:
raise IAMNotFoundException(
"The SSH Public Key with id {0} cannot be found".format(
ssh_public_key_id
)
)
def get_all_ssh_public_keys(self):
return self.ssh_public_keys
def update_ssh_public_key(self, ssh_public_key_id, status):
key = self.get_ssh_public_key(ssh_public_key_id)
key.status = status
def delete_ssh_public_key(self, ssh_public_key_id):
key = self.get_ssh_public_key(ssh_public_key_id)
self.ssh_public_keys.remove(key)
def get_cfn_attribute(self, attribute_name):
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
@ -736,6 +779,134 @@ class AccountPasswordPolicy(BaseModel):
)
class AccountSummary(BaseModel):
def __init__(self, iam_backend):
self._iam_backend = iam_backend
self._group_policy_size_quota = 5120
self._instance_profiles_quota = 1000
self._groups_per_user_quota = 10
self._attached_policies_per_user_quota = 10
self._policies_quota = 1500
self._account_mfa_enabled = 0 # Haven't found any information being able to activate MFA for the root account programmatically
self._access_keys_per_user_quota = 2
self._assume_role_policy_size_quota = 2048
self._policy_versions_in_use_quota = 10000
self._global_endpoint_token_version = (
1 # ToDo: Implement set_security_token_service_preferences()
)
self._versions_per_policy_quota = 5
self._attached_policies_per_group_quota = 10
self._policy_size_quota = 6144
self._account_signing_certificates_present = 0 # valid values: 0 | 1
self._users_quota = 5000
self._server_certificates_quota = 20
self._user_policy_size_quota = 2048
self._roles_quota = 1000
self._signing_certificates_per_user_quota = 2
self._role_policy_size_quota = 10240
self._attached_policies_per_role_quota = 10
self._account_access_keys_present = 0 # valid values: 0 | 1
self._groups_quota = 300
@property
def summary_map(self):
return {
"GroupPolicySizeQuota": self._group_policy_size_quota,
"InstanceProfilesQuota": self._instance_profiles_quota,
"Policies": self._policies,
"GroupsPerUserQuota": self._groups_per_user_quota,
"InstanceProfiles": self._instance_profiles,
"AttachedPoliciesPerUserQuota": self._attached_policies_per_user_quota,
"Users": self._users,
"PoliciesQuota": self._policies_quota,
"Providers": self._providers,
"AccountMFAEnabled": self._account_mfa_enabled,
"AccessKeysPerUserQuota": self._access_keys_per_user_quota,
"AssumeRolePolicySizeQuota": self._assume_role_policy_size_quota,
"PolicyVersionsInUseQuota": self._policy_versions_in_use_quota,
"GlobalEndpointTokenVersion": self._global_endpoint_token_version,
"VersionsPerPolicyQuota": self._versions_per_policy_quota,
"AttachedPoliciesPerGroupQuota": self._attached_policies_per_group_quota,
"PolicySizeQuota": self._policy_size_quota,
"Groups": self._groups,
"AccountSigningCertificatesPresent": self._account_signing_certificates_present,
"UsersQuota": self._users_quota,
"ServerCertificatesQuota": self._server_certificates_quota,
"MFADevices": self._mfa_devices,
"UserPolicySizeQuota": self._user_policy_size_quota,
"PolicyVersionsInUse": self._policy_versions_in_use,
"ServerCertificates": self._server_certificates,
"Roles": self._roles,
"RolesQuota": self._roles_quota,
"SigningCertificatesPerUserQuota": self._signing_certificates_per_user_quota,
"MFADevicesInUse": self._mfa_devices_in_use,
"RolePolicySizeQuota": self._role_policy_size_quota,
"AttachedPoliciesPerRoleQuota": self._attached_policies_per_role_quota,
"AccountAccessKeysPresent": self._account_access_keys_present,
"GroupsQuota": self._groups_quota,
}
@property
def _groups(self):
return len(self._iam_backend.groups)
@property
def _instance_profiles(self):
return len(self._iam_backend.instance_profiles)
@property
def _mfa_devices(self):
# Don't know, if hardware devices are also counted here
return len(self._iam_backend.virtual_mfa_devices)
@property
def _mfa_devices_in_use(self):
devices = 0
for user in self._iam_backend.users.values():
devices += len(user.mfa_devices)
return devices
@property
def _policies(self):
customer_policies = [
policy
for policy in self._iam_backend.managed_policies
if not policy.startswith("arn:aws:iam::aws:policy")
]
return len(customer_policies)
@property
def _policy_versions_in_use(self):
attachments = 0
for policy in self._iam_backend.managed_policies.values():
attachments += policy.attachment_count
return attachments
@property
def _providers(self):
providers = len(self._iam_backend.saml_providers) + len(
self._iam_backend.open_id_providers
)
return providers
@property
def _roles(self):
return len(self._iam_backend.roles)
@property
def _server_certificates(self):
return len(self._iam_backend.certificates)
@property
def _users(self):
return len(self._iam_backend.users)
class IAMBackend(BaseBackend):
def __init__(self):
self.instance_profiles = {}
@ -751,6 +922,7 @@ class IAMBackend(BaseBackend):
self.policy_arn_regex = re.compile(r"^arn:aws:iam::[0-9]*:policy/.*$")
self.virtual_mfa_devices = {}
self.account_password_policy = None
self.account_summary = AccountSummary(self)
super(IAMBackend, self).__init__()
def _init_managed_policies(self):
@ -820,7 +992,7 @@ class IAMBackend(BaseBackend):
)
if policy.arn in self.managed_policies:
raise EntityAlreadyExists(
"A policy called {} already exists. Duplicate names are not allowed.".format(
"A policy called {0} already exists. Duplicate names are not allowed.".format(
policy_name
)
)
@ -898,6 +1070,10 @@ class IAMBackend(BaseBackend):
permissions_boundary
),
)
if [role for role in self.get_roles() if role.name == role_name]:
raise EntityAlreadyExists(
"Role with name {0} already exists.".format(role_name)
)
clean_tags = self._tag_verification(tags)
role = Role(
@ -1158,7 +1334,7 @@ class IAMBackend(BaseBackend):
def get_all_server_certs(self, marker=None):
return self.certificates.values()
def upload_server_cert(
def upload_server_certificate(
self, cert_name, cert_body, private_key, cert_chain=None, path=None
):
certificate_id = random_resource_id()
@ -1451,6 +1627,26 @@ class IAMBackend(BaseBackend):
user = self.get_user(user_name)
user.delete_access_key(access_key_id)
def upload_ssh_public_key(self, user_name, ssh_public_key_body):
user = self.get_user(user_name)
return user.upload_ssh_public_key(ssh_public_key_body)
def get_ssh_public_key(self, user_name, ssh_public_key_id):
user = self.get_user(user_name)
return user.get_ssh_public_key(ssh_public_key_id)
def get_all_ssh_public_keys(self, user_name):
user = self.get_user(user_name)
return user.get_all_ssh_public_keys()
def update_ssh_public_key(self, user_name, ssh_public_key_id, status):
user = self.get_user(user_name)
return user.update_ssh_public_key(ssh_public_key_id, status)
def delete_ssh_public_key(self, user_name, ssh_public_key_id):
user = self.get_user(user_name)
return user.delete_ssh_public_key(ssh_public_key_id)
def enable_mfa_device(
self, user_name, serial_number, authentication_code_1, authentication_code_2
):
@ -1737,5 +1933,8 @@ class IAMBackend(BaseBackend):
self.account_password_policy = None
def get_account_summary(self):
return self.account_summary
iam_backend = IAMBackend()

View File

@ -351,7 +351,7 @@ class IamResponse(BaseResponse):
private_key = self._get_param("PrivateKey")
cert_chain = self._get_param("CertificateName")
cert = iam_backend.upload_server_cert(
cert = iam_backend.upload_server_certificate(
cert_name, cert_body, private_key, cert_chain=cert_chain, path=path
)
template = self.response_template(UPLOAD_CERT_TEMPLATE)
@ -590,6 +590,46 @@ class IamResponse(BaseResponse):
template = self.response_template(GENERIC_EMPTY_TEMPLATE)
return template.render(name="DeleteAccessKey")
def upload_ssh_public_key(self):
user_name = self._get_param("UserName")
ssh_public_key_body = self._get_param("SSHPublicKeyBody")
key = iam_backend.upload_ssh_public_key(user_name, ssh_public_key_body)
template = self.response_template(UPLOAD_SSH_PUBLIC_KEY_TEMPLATE)
return template.render(key=key)
def get_ssh_public_key(self):
user_name = self._get_param("UserName")
ssh_public_key_id = self._get_param("SSHPublicKeyId")
key = iam_backend.get_ssh_public_key(user_name, ssh_public_key_id)
template = self.response_template(GET_SSH_PUBLIC_KEY_TEMPLATE)
return template.render(key=key)
def list_ssh_public_keys(self):
user_name = self._get_param("UserName")
keys = iam_backend.get_all_ssh_public_keys(user_name)
template = self.response_template(LIST_SSH_PUBLIC_KEYS_TEMPLATE)
return template.render(keys=keys)
def update_ssh_public_key(self):
user_name = self._get_param("UserName")
ssh_public_key_id = self._get_param("SSHPublicKeyId")
status = self._get_param("Status")
iam_backend.update_ssh_public_key(user_name, ssh_public_key_id, status)
template = self.response_template(UPDATE_SSH_PUBLIC_KEY_TEMPLATE)
return template.render()
def delete_ssh_public_key(self):
user_name = self._get_param("UserName")
ssh_public_key_id = self._get_param("SSHPublicKeyId")
iam_backend.delete_ssh_public_key(user_name, ssh_public_key_id)
template = self.response_template(DELETE_SSH_PUBLIC_KEY_TEMPLATE)
return template.render()
def deactivate_mfa_device(self):
user_name = self._get_param("UserName")
serial_number = self._get_param("SerialNumber")
@ -888,6 +928,12 @@ class IamResponse(BaseResponse):
template = self.response_template(DELETE_ACCOUNT_PASSWORD_POLICY_TEMPLATE)
return template.render()
def get_account_summary(self):
account_summary = iam_backend.get_account_summary()
template = self.response_template(GET_ACCOUNT_SUMMARY_TEMPLATE)
return template.render(summary_map=account_summary.summary_map)
LIST_ENTITIES_FOR_POLICY_TEMPLATE = """<ListEntitiesForPolicyResponse>
<ListEntitiesForPolicyResult>
@ -1690,6 +1736,73 @@ GET_ACCESS_KEY_LAST_USED_TEMPLATE = """
</GetAccessKeyLastUsedResponse>
"""
UPLOAD_SSH_PUBLIC_KEY_TEMPLATE = """<UploadSSHPublicKeyResponse>
<UploadSSHPublicKeyResult>
<SSHPublicKey>
<UserName>{{ key.user_name }}</UserName>
<SSHPublicKeyBody>{{ key.ssh_public_key_body }}</SSHPublicKeyBody>
<SSHPublicKeyId>{{ key.ssh_public_key_id }}</SSHPublicKeyId>
<Fingerprint>{{ key.fingerprint }}</Fingerprint>
<Status>{{ key.status }}</Status>
<UploadDate>{{ key.uploaded_iso_8601 }}</UploadDate>
</SSHPublicKey>
</UploadSSHPublicKeyResult>
<ResponseMetadata>
<RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
</ResponseMetadata>
</UploadSSHPublicKeyResponse>"""
GET_SSH_PUBLIC_KEY_TEMPLATE = """<GetSSHPublicKeyResponse>
<GetSSHPublicKeyResult>
<SSHPublicKey>
<UserName>{{ key.user_name }}</UserName>
<SSHPublicKeyBody>{{ key.ssh_public_key_body }}</SSHPublicKeyBody>
<SSHPublicKeyId>{{ key.ssh_public_key_id }}</SSHPublicKeyId>
<Fingerprint>{{ key.fingerprint }}</Fingerprint>
<Status>{{ key.status }}</Status>
<UploadDate>{{ key.uploaded_iso_8601 }}</UploadDate>
</SSHPublicKey>
</GetSSHPublicKeyResult>
<ResponseMetadata>
<RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
</ResponseMetadata>
</GetSSHPublicKeyResponse>"""
LIST_SSH_PUBLIC_KEYS_TEMPLATE = """<ListSSHPublicKeysResponse>
<ListSSHPublicKeysResult>
<SSHPublicKeys>
{% for key in keys %}
<member>
<UserName>{{ key.user_name }}</UserName>
<SSHPublicKeyId>{{ key.ssh_public_key_id }}</SSHPublicKeyId>
<Status>{{ key.status }}</Status>
<UploadDate>{{ key.uploaded_iso_8601 }}</UploadDate>
</member>
{% endfor %}
</SSHPublicKeys>
<IsTruncated>false</IsTruncated>
</ListSSHPublicKeysResult>
<ResponseMetadata>
<RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
</ResponseMetadata>
</ListSSHPublicKeysResponse>"""
UPDATE_SSH_PUBLIC_KEY_TEMPLATE = """<UpdateSSHPublicKeyResponse>
<UpdateSSHPublicKeyResult>
</UpdateSSHPublicKeyResult>
<ResponseMetadata>
<RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
</ResponseMetadata>
</UpdateSSHPublicKeyResponse>"""
DELETE_SSH_PUBLIC_KEY_TEMPLATE = """<DeleteSSHPublicKeyResponse>
<DeleteSSHPublicKeyResult>
</DeleteSSHPublicKeyResult>
<ResponseMetadata>
<RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
</ResponseMetadata>
</DeleteSSHPublicKeyResponse>"""
CREDENTIAL_REPORT_GENERATING = """
<GenerateCredentialReportResponse>
<GenerateCredentialReportResult>
@ -2261,3 +2374,20 @@ DELETE_ACCOUNT_PASSWORD_POLICY_TEMPLATE = """<DeleteAccountPasswordPolicyRespons
<RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
</ResponseMetadata>
</DeleteAccountPasswordPolicyResponse>"""
GET_ACCOUNT_SUMMARY_TEMPLATE = """<GetAccountSummaryResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/">
<GetAccountSummaryResult>
<SummaryMap>
{% for key, value in summary_map.items() %}
<entry>
<key>{{ key }}</key>
<value>{{ value }}</value>
</entry>
{% endfor %}
</SummaryMap>
</GetAccountSummaryResult>
<ResponseMetadata>
<RequestId>85cb9b90-ac28-11e4-a88d-97964EXAMPLE</RequestId>
</ResponseMetadata>
</GetAccountSummaryResponse>"""

View File

@ -125,7 +125,7 @@ class HTTPrettyRequest(BaseHTTPRequestHandler, BaseClass):
internal `parse_request` method.
It also replaces the `rfile` and `wfile` attributes with StringIO
instances so that we garantee that it won't make any I/O, neighter
instances so that we guarantee that it won't make any I/O, neighter
for writing nor reading.
It has some convenience attributes:

View File

@ -190,7 +190,7 @@ def create_backend_app(service):
index = 2
while endpoint in backend_app.view_functions:
# HACK: Sometimes we map the same view to multiple url_paths. Flask
# requries us to have different names.
# requires us to have different names.
endpoint = original_endpoint + str(index)
index += 1

View File

@ -147,7 +147,7 @@ class SESBackend(BaseBackend):
def __type_of_message__(self, destinations):
"""Checks the destination for any special address that could indicate delivery,
complaint or bounce like in SES simualtor"""
complaint or bounce like in SES simulator"""
alladdress = (
destinations.get("ToAddresses", [])
+ destinations.get("CcAddresses", [])

View File

@ -227,7 +227,7 @@ class Subscription(BaseModel):
return False
for attribute_values in attribute_values:
# Even the offical documentation states a 5 digits of accuracy after the decimal point for numerics, in reality it is 6
# Even the official documentation states a 5 digits of accuracy after the decimal point for numerics, in reality it is 6
# https://docs.aws.amazon.com/sns/latest/dg/sns-subscription-filter-policies.html#subscription-filter-policy-constraints
if int(attribute_values * 1000000) == int(rule * 1000000):
return True
@ -573,7 +573,7 @@ class SNSBackend(BaseBackend):
combinations = 1
for rules in six.itervalues(value):
combinations *= len(rules)
# Even the offical documentation states the total combination of values must not exceed 100, in reality it is 150
# Even the official documentation states the total combination of values must not exceed 100, in reality it is 150
# https://docs.aws.amazon.com/sns/latest/dg/sns-subscription-filter-policies.html#subscription-filter-policy-constraints
if combinations > 150:
raise SNSInvalidParameter(

View File

@ -77,7 +77,7 @@ class SNSResponse(BaseResponse):
transform_value = value["StringValue"]
elif "BinaryValue" in value:
transform_value = value["BinaryValue"]
if not transform_value:
if transform_value == "":
raise InvalidParameterValue(
"The message attribute '{0}' must contain non-empty "
"message attribute value for message attribute "

View File

@ -761,7 +761,7 @@ class SQSBackend(BaseBackend):
new_messages = []
for message in queue._messages:
# Only delete message if it is not visible and the reciept_handle
# Only delete message if it is not visible and the receipt_handle
# matches.
if message.receipt_handle == receipt_handle:
queue.pending_messages.remove(message)

View File

@ -430,7 +430,7 @@ class WorkflowExecution(BaseModel):
)
def fail(self, event_id, details=None, reason=None):
# TODO: implement lenght constraints on details/reason
# TODO: implement length constraints on details/reason
self.execution_status = "CLOSED"
self.close_status = "FAILED"
self.close_timestamp = unix_time()

View File

@ -39,7 +39,7 @@ install_requires = [
"werkzeug",
"PyYAML>=5.1",
"pytz",
"python-dateutil<3.0.0,>=2.1",
"python-dateutil<2.8.1,>=2.1",
"python-jose<4.0.0",
"mock",
"docker>=2.5.1",

View File

@ -162,7 +162,7 @@ if settings.TEST_SERVER_MODE:
conn = boto3.client("lambda", "us-west-2")
conn.create_function(
FunctionName="testFunction",
Runtime="python2.7",
Runtime="python3.7",
Role="test-iam-role",
Handler="lambda_function.lambda_handler",
Code={"ZipFile": get_test_zip_file2()},
@ -184,18 +184,20 @@ if settings.TEST_SERVER_MODE:
vol.id,
vol.state,
vol.size,
json.dumps(in_data),
json.dumps(in_data).replace(
" ", ""
), # Makes the tests pass as the result is missing the whitespace
)
log_result = base64.b64decode(result["LogResult"]).decode("utf-8")
# fix for running under travis (TODO: investigate why it has an extra newline)
# The Docker lambda invocation will return an additional '\n', so need to replace it:
log_result = log_result.replace("\n\n", "\n")
log_result.should.equal(msg)
payload = result["Payload"].read().decode("utf-8")
# fix for running under travis (TODO: investigate why it has an extra newline)
# The Docker lambda invocation will return an additional '\n', so need to replace it:
payload = payload.replace("\n\n", "\n")
payload.should.equal(msg)

View File

@ -11,6 +11,7 @@ from nose.tools import assert_raises
from moto import mock_iam, mock_ec2, mock_s3, mock_sts, mock_elbv2, mock_rds2
from moto.core import set_initial_no_auth_action_count
from moto.iam.models import ACCOUNT_ID
from uuid import uuid4
@mock_iam
@ -71,8 +72,10 @@ def create_user_with_access_key_and_multiple_policies(
def create_group_with_attached_policy_and_add_user(
user_name, policy_document, group_name="test-group", policy_name="policy1"
user_name, policy_document, group_name="test-group", policy_name=None
):
if not policy_name:
policy_name = str(uuid4())
client = boto3.client("iam", region_name="us-east-1")
client.create_group(GroupName=group_name)
policy_arn = client.create_policy(
@ -101,8 +104,10 @@ def create_group_with_multiple_policies_and_add_user(
attached_policy_document,
group_name="test-group",
inline_policy_name="policy1",
attached_policy_name="policy1",
attached_policy_name=None,
):
if not attached_policy_name:
attached_policy_name = str(uuid4())
client = boto3.client("iam", region_name="us-east-1")
client.create_group(GroupName=group_name)
client.put_group_policy(

View File

@ -678,3 +678,150 @@ def test_create_vpc_with_invalid_cidr_range():
"An error occurred (InvalidVpc.Range) when calling the CreateVpc "
"operation: The CIDR '{}' is invalid.".format(vpc_cidr_block)
)
@mock_ec2
def test_enable_vpc_classic_link():
ec2 = boto3.resource("ec2", region_name="us-west-1")
# Create VPC
vpc = ec2.create_vpc(CidrBlock="10.1.0.0/16")
response = ec2.meta.client.enable_vpc_classic_link(VpcId=vpc.id)
assert response.get("Return").should.be.true
@mock_ec2
def test_enable_vpc_classic_link_failure():
ec2 = boto3.resource("ec2", region_name="us-west-1")
# Create VPC
vpc = ec2.create_vpc(CidrBlock="10.90.0.0/16")
response = ec2.meta.client.enable_vpc_classic_link(VpcId=vpc.id)
assert response.get("Return").should.be.false
@mock_ec2
def test_disable_vpc_classic_link():
ec2 = boto3.resource("ec2", region_name="us-west-1")
# Create VPC
vpc = ec2.create_vpc(CidrBlock="10.0.0.0/16")
ec2.meta.client.enable_vpc_classic_link(VpcId=vpc.id)
response = ec2.meta.client.disable_vpc_classic_link(VpcId=vpc.id)
assert response.get("Return").should.be.false
@mock_ec2
def test_describe_classic_link_enabled():
ec2 = boto3.resource("ec2", region_name="us-west-1")
# Create VPC
vpc = ec2.create_vpc(CidrBlock="10.0.0.0/16")
ec2.meta.client.enable_vpc_classic_link(VpcId=vpc.id)
response = ec2.meta.client.describe_vpc_classic_link(VpcIds=[vpc.id])
assert response.get("Vpcs")[0].get("ClassicLinkEnabled").should.be.true
@mock_ec2
def test_describe_classic_link_disabled():
ec2 = boto3.resource("ec2", region_name="us-west-1")
# Create VPC
vpc = ec2.create_vpc(CidrBlock="10.90.0.0/16")
response = ec2.meta.client.describe_vpc_classic_link(VpcIds=[vpc.id])
assert response.get("Vpcs")[0].get("ClassicLinkEnabled").should.be.false
@mock_ec2
def test_describe_classic_link_multiple():
ec2 = boto3.resource("ec2", region_name="us-west-1")
# Create VPC
vpc1 = ec2.create_vpc(CidrBlock="10.90.0.0/16")
vpc2 = ec2.create_vpc(CidrBlock="10.0.0.0/16")
ec2.meta.client.enable_vpc_classic_link(VpcId=vpc2.id)
response = ec2.meta.client.describe_vpc_classic_link(VpcIds=[vpc1.id, vpc2.id])
expected = [
{"VpcId": vpc1.id, "ClassicLinkDnsSupported": False},
{"VpcId": vpc2.id, "ClassicLinkDnsSupported": True},
]
# Ensure response is sorted, because they can come in random order
assert response.get("Vpcs").sort(key=lambda x: x["VpcId"]) == expected.sort(
key=lambda x: x["VpcId"]
)
@mock_ec2
def test_enable_vpc_classic_link_dns_support():
ec2 = boto3.resource("ec2", region_name="us-west-1")
# Create VPC
vpc = ec2.create_vpc(CidrBlock="10.1.0.0/16")
response = ec2.meta.client.enable_vpc_classic_link_dns_support(VpcId=vpc.id)
assert response.get("Return").should.be.true
@mock_ec2
def test_disable_vpc_classic_link_dns_support():
ec2 = boto3.resource("ec2", region_name="us-west-1")
# Create VPC
vpc = ec2.create_vpc(CidrBlock="10.0.0.0/16")
ec2.meta.client.enable_vpc_classic_link_dns_support(VpcId=vpc.id)
response = ec2.meta.client.disable_vpc_classic_link_dns_support(VpcId=vpc.id)
assert response.get("Return").should.be.false
@mock_ec2
def test_describe_classic_link_dns_support_enabled():
ec2 = boto3.resource("ec2", region_name="us-west-1")
# Create VPC
vpc = ec2.create_vpc(CidrBlock="10.0.0.0/16")
ec2.meta.client.enable_vpc_classic_link_dns_support(VpcId=vpc.id)
response = ec2.meta.client.describe_vpc_classic_link_dns_support(VpcIds=[vpc.id])
assert response.get("Vpcs")[0].get("ClassicLinkDnsSupported").should.be.true
@mock_ec2
def test_describe_classic_link_dns_support_disabled():
ec2 = boto3.resource("ec2", region_name="us-west-1")
# Create VPC
vpc = ec2.create_vpc(CidrBlock="10.90.0.0/16")
response = ec2.meta.client.describe_vpc_classic_link_dns_support(VpcIds=[vpc.id])
assert response.get("Vpcs")[0].get("ClassicLinkDnsSupported").should.be.false
@mock_ec2
def test_describe_classic_link_dns_support_multiple():
ec2 = boto3.resource("ec2", region_name="us-west-1")
# Create VPC
vpc1 = ec2.create_vpc(CidrBlock="10.90.0.0/16")
vpc2 = ec2.create_vpc(CidrBlock="10.0.0.0/16")
ec2.meta.client.enable_vpc_classic_link_dns_support(VpcId=vpc2.id)
response = ec2.meta.client.describe_vpc_classic_link_dns_support(
VpcIds=[vpc1.id, vpc2.id]
)
expected = [
{"VpcId": vpc1.id, "ClassicLinkDnsSupported": False},
{"VpcId": vpc2.id, "ClassicLinkDnsSupported": True},
]
# Ensure response is sorted, because they can come in random order
assert response.get("Vpcs").sort(key=lambda x: x["VpcId"]) == expected.sort(
key=lambda x: x["VpcId"]
)

View File

@ -18,6 +18,7 @@ from nose.tools import raises
from datetime import datetime
from tests.helpers import requires_boto_gte
from uuid import uuid4
MOCK_CERT = """-----BEGIN CERTIFICATE-----
@ -1315,6 +1316,122 @@ def test_get_access_key_last_used():
resp["UserName"].should.equal(create_key_response["UserName"])
@mock_iam
def test_upload_ssh_public_key():
iam = boto3.resource("iam", region_name="us-east-1")
client = iam.meta.client
username = "test-user"
iam.create_user(UserName=username)
public_key = MOCK_CERT
resp = client.upload_ssh_public_key(UserName=username, SSHPublicKeyBody=public_key)
pubkey = resp["SSHPublicKey"]
pubkey["SSHPublicKeyBody"].should.equal(public_key)
pubkey["UserName"].should.equal(username)
pubkey["SSHPublicKeyId"].should.have.length_of(20)
assert pubkey["SSHPublicKeyId"].startswith("APKA")
pubkey.should.have.key("Fingerprint")
pubkey["Status"].should.equal("Active")
(
datetime.utcnow() - pubkey["UploadDate"].replace(tzinfo=None)
).seconds.should.be.within(0, 10)
@mock_iam
def test_get_ssh_public_key():
iam = boto3.resource("iam", region_name="us-east-1")
client = iam.meta.client
username = "test-user"
iam.create_user(UserName=username)
public_key = MOCK_CERT
with assert_raises(ClientError):
client.get_ssh_public_key(
UserName=username, SSHPublicKeyId="xxnon-existent-keyxx", Encoding="SSH"
)
resp = client.upload_ssh_public_key(UserName=username, SSHPublicKeyBody=public_key)
ssh_public_key_id = resp["SSHPublicKey"]["SSHPublicKeyId"]
resp = client.get_ssh_public_key(
UserName=username, SSHPublicKeyId=ssh_public_key_id, Encoding="SSH"
)
resp["SSHPublicKey"]["SSHPublicKeyBody"].should.equal(public_key)
@mock_iam
def test_list_ssh_public_keys():
iam = boto3.resource("iam", region_name="us-east-1")
client = iam.meta.client
username = "test-user"
iam.create_user(UserName=username)
public_key = MOCK_CERT
resp = client.list_ssh_public_keys(UserName=username)
resp["SSHPublicKeys"].should.have.length_of(0)
resp = client.upload_ssh_public_key(UserName=username, SSHPublicKeyBody=public_key)
ssh_public_key_id = resp["SSHPublicKey"]["SSHPublicKeyId"]
resp = client.list_ssh_public_keys(UserName=username)
resp["SSHPublicKeys"].should.have.length_of(1)
resp["SSHPublicKeys"][0]["SSHPublicKeyId"].should.equal(ssh_public_key_id)
@mock_iam
def test_update_ssh_public_key():
iam = boto3.resource("iam", region_name="us-east-1")
client = iam.meta.client
username = "test-user"
iam.create_user(UserName=username)
public_key = MOCK_CERT
with assert_raises(ClientError):
client.update_ssh_public_key(
UserName=username, SSHPublicKeyId="xxnon-existent-keyxx", Status="Inactive"
)
resp = client.upload_ssh_public_key(UserName=username, SSHPublicKeyBody=public_key)
ssh_public_key_id = resp["SSHPublicKey"]["SSHPublicKeyId"]
resp["SSHPublicKey"]["Status"].should.equal("Active")
resp = client.update_ssh_public_key(
UserName=username, SSHPublicKeyId=ssh_public_key_id, Status="Inactive"
)
resp = client.get_ssh_public_key(
UserName=username, SSHPublicKeyId=ssh_public_key_id, Encoding="SSH"
)
resp["SSHPublicKey"]["Status"].should.equal("Inactive")
@mock_iam
def test_delete_ssh_public_key():
iam = boto3.resource("iam", region_name="us-east-1")
client = iam.meta.client
username = "test-user"
iam.create_user(UserName=username)
public_key = MOCK_CERT
with assert_raises(ClientError):
client.delete_ssh_public_key(
UserName=username, SSHPublicKeyId="xxnon-existent-keyxx"
)
resp = client.upload_ssh_public_key(UserName=username, SSHPublicKeyBody=public_key)
ssh_public_key_id = resp["SSHPublicKey"]["SSHPublicKeyId"]
resp = client.list_ssh_public_keys(UserName=username)
resp["SSHPublicKeys"].should.have.length_of(1)
resp = client.delete_ssh_public_key(
UserName=username, SSHPublicKeyId=ssh_public_key_id
)
resp = client.list_ssh_public_keys(UserName=username)
resp["SSHPublicKeys"].should.have.length_of(0)
@mock_iam
def test_get_account_authorization_details():
test_policy = json.dumps(
@ -2050,6 +2167,42 @@ def test_create_role_with_permissions_boundary():
conn.list_roles().get("Roles")[0].get("PermissionsBoundary").should.equal(expected)
@mock_iam
def test_create_role_with_same_name_should_fail():
iam = boto3.client("iam", region_name="us-east-1")
test_role_name = str(uuid4())
iam.create_role(
RoleName=test_role_name, AssumeRolePolicyDocument="policy", Description="test"
)
# Create the role again, and verify that it fails
with assert_raises(ClientError) as err:
iam.create_role(
RoleName=test_role_name,
AssumeRolePolicyDocument="policy",
Description="test",
)
err.exception.response["Error"]["Code"].should.equal("EntityAlreadyExists")
err.exception.response["Error"]["Message"].should.equal(
"Role with name {0} already exists.".format(test_role_name)
)
@mock_iam
def test_create_policy_with_same_name_should_fail():
iam = boto3.client("iam", region_name="us-east-1")
test_policy_name = str(uuid4())
policy = iam.create_policy(PolicyName=test_policy_name, PolicyDocument=MOCK_POLICY)
# Create the role again, and verify that it fails
with assert_raises(ClientError) as err:
iam.create_policy(PolicyName=test_policy_name, PolicyDocument=MOCK_POLICY)
err.exception.response["Error"]["Code"].should.equal("EntityAlreadyExists")
err.exception.response["Error"]["Message"].should.equal(
"A policy called {0} already exists. Duplicate names are not allowed.".format(
test_policy_name
)
)
@mock_iam
def test_create_open_id_connect_provider():
client = boto3.client("iam", region_name="us-east-1")
@ -2325,3 +2478,123 @@ def test_delete_account_password_policy_errors():
client.delete_account_password_policy.when.called_with().should.throw(
ClientError, "The account policy with name PasswordPolicy cannot be found."
)
@mock_iam
def test_get_account_summary():
client = boto3.client("iam", region_name="us-east-1")
iam = boto3.resource("iam", region_name="us-east-1")
account_summary = iam.AccountSummary()
account_summary.summary_map.should.equal(
{
"GroupPolicySizeQuota": 5120,
"InstanceProfilesQuota": 1000,
"Policies": 0,
"GroupsPerUserQuota": 10,
"InstanceProfiles": 0,
"AttachedPoliciesPerUserQuota": 10,
"Users": 0,
"PoliciesQuota": 1500,
"Providers": 0,
"AccountMFAEnabled": 0,
"AccessKeysPerUserQuota": 2,
"AssumeRolePolicySizeQuota": 2048,
"PolicyVersionsInUseQuota": 10000,
"GlobalEndpointTokenVersion": 1,
"VersionsPerPolicyQuota": 5,
"AttachedPoliciesPerGroupQuota": 10,
"PolicySizeQuota": 6144,
"Groups": 0,
"AccountSigningCertificatesPresent": 0,
"UsersQuota": 5000,
"ServerCertificatesQuota": 20,
"MFADevices": 0,
"UserPolicySizeQuota": 2048,
"PolicyVersionsInUse": 0,
"ServerCertificates": 0,
"Roles": 0,
"RolesQuota": 1000,
"SigningCertificatesPerUserQuota": 2,
"MFADevicesInUse": 0,
"RolePolicySizeQuota": 10240,
"AttachedPoliciesPerRoleQuota": 10,
"AccountAccessKeysPresent": 0,
"GroupsQuota": 300,
}
)
client.create_instance_profile(InstanceProfileName="test-profile")
client.create_open_id_connect_provider(
Url="https://example.com", ThumbprintList=[],
)
response_policy = client.create_policy(
PolicyName="test-policy", PolicyDocument=MOCK_POLICY
)
client.create_role(RoleName="test-role", AssumeRolePolicyDocument="test policy")
client.attach_role_policy(
RoleName="test-role", PolicyArn=response_policy["Policy"]["Arn"]
)
client.create_saml_provider(
Name="TestSAMLProvider", SAMLMetadataDocument="a" * 1024
)
client.create_group(GroupName="test-group")
client.attach_group_policy(
GroupName="test-group", PolicyArn=response_policy["Policy"]["Arn"]
)
client.create_user(UserName="test-user")
client.attach_user_policy(
UserName="test-user", PolicyArn=response_policy["Policy"]["Arn"]
)
client.enable_mfa_device(
UserName="test-user",
SerialNumber="123456789",
AuthenticationCode1="234567",
AuthenticationCode2="987654",
)
client.create_virtual_mfa_device(VirtualMFADeviceName="test-device")
client.upload_server_certificate(
ServerCertificateName="test-cert",
CertificateBody="cert-body",
PrivateKey="private-key",
)
account_summary.load()
account_summary.summary_map.should.equal(
{
"GroupPolicySizeQuota": 5120,
"InstanceProfilesQuota": 1000,
"Policies": 1,
"GroupsPerUserQuota": 10,
"InstanceProfiles": 1,
"AttachedPoliciesPerUserQuota": 10,
"Users": 1,
"PoliciesQuota": 1500,
"Providers": 2,
"AccountMFAEnabled": 0,
"AccessKeysPerUserQuota": 2,
"AssumeRolePolicySizeQuota": 2048,
"PolicyVersionsInUseQuota": 10000,
"GlobalEndpointTokenVersion": 1,
"VersionsPerPolicyQuota": 5,
"AttachedPoliciesPerGroupQuota": 10,
"PolicySizeQuota": 6144,
"Groups": 1,
"AccountSigningCertificatesPresent": 0,
"UsersQuota": 5000,
"ServerCertificatesQuota": 20,
"MFADevices": 1,
"UserPolicySizeQuota": 2048,
"PolicyVersionsInUse": 3,
"ServerCertificates": 1,
"Roles": 1,
"RolesQuota": 1000,
"SigningCertificatesPerUserQuota": 2,
"MFADevicesInUse": 1,
"RolePolicySizeQuota": 10240,
"AttachedPoliciesPerRoleQuota": 10,
"AccountAccessKeysPresent": 0,
"GroupsQuota": 300,
}
)

View File

@ -173,6 +173,27 @@ def test_publish_to_sqs_msg_attr_byte_value():
)
@mock_sqs
@mock_sns
def test_publish_to_sqs_msg_attr_number_type():
sns = boto3.resource("sns", region_name="us-east-1")
topic = sns.create_topic(Name="test-topic")
sqs = boto3.resource("sqs", region_name="us-east-1")
queue = sqs.create_queue(QueueName="test-queue")
topic.subscribe(Protocol="sqs", Endpoint=queue.attributes["QueueArn"])
topic.publish(
Message="test message",
MessageAttributes={"retries": {"DataType": "Number", "StringValue": "0"}},
)
message = json.loads(queue.receive_messages()[0].body)
message["Message"].should.equal("test message")
message["MessageAttributes"].should.equal(
{"retries": {"Type": "Number", "Value": 0}}
)
@mock_sns
def test_publish_sms():
client = boto3.client("sns", region_name="us-east-1")