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

View File

@ -46,8 +46,9 @@ try:
except ImportError: except ImportError:
from backports.tempfile import TemporaryDirectory from backports.tempfile import TemporaryDirectory
# 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"START|END|REPORT RequestId: .*")
_stderr_regex = re.compile(r"\033\[\d+.*")
_orig_adapter_send = requests.adapters.HTTPAdapter.send _orig_adapter_send = requests.adapters.HTTPAdapter.send
docker_3 = docker.__version__[0] >= "3" docker_3 = docker.__version__[0] >= "3"
@ -444,7 +445,7 @@ class LambdaFunction(BaseModel):
if exit_code != 0: if exit_code != 0:
raise Exception("lambda invoke failed output: {}".format(output)) 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( output = os.linesep.join(
[ [
line line

View File

@ -624,7 +624,7 @@ class BatchBackend(BaseBackend):
def get_job_definition(self, identifier): 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 :param identifier: Name or ARN
:type identifier: str :type identifier: str
@ -643,7 +643,7 @@ class BatchBackend(BaseBackend):
def get_job_definitions(self, identifier): 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 :param identifier: Name or ARN
:type identifier: str :type identifier: str
@ -934,7 +934,7 @@ class BatchBackend(BaseBackend):
self.ecs_backend.delete_cluster(compute_env.ecs_name) self.ecs_backend.delete_cluster(compute_env.ecs_name)
if compute_env.env_type == "MANAGED": if compute_env.env_type == "MANAGED":
# Delete compute envrionment # Delete compute environment
instance_ids = [instance.id for instance in compute_env.instances] instance_ids = [instance.id for instance in compute_env.instances]
self.ec2_backend.terminate_instances(instance_ids) self.ec2_backend.terminate_instances(instance_ids)
@ -1195,7 +1195,7 @@ class BatchBackend(BaseBackend):
depends_on=None, depends_on=None,
container_overrides=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 # Look for job definition
job_def = self.get_job_definition(job_def_id) job_def = self.get_job_definition(job_def_id)

View File

@ -2444,6 +2444,7 @@ class VPC(TaggedEC2Resource):
self.instance_tenancy = instance_tenancy self.instance_tenancy = instance_tenancy
self.is_default = "true" if is_default else "false" self.is_default = "true" if is_default else "false"
self.enable_dns_support = "true" self.enable_dns_support = "true"
self.classic_link_enabled = "false"
# This attribute is set to 'true' only for default VPCs # This attribute is set to 'true' only for default VPCs
# or VPCs created using the wizard of the VPC console # or VPCs created using the wizard of the VPC console
self.enable_dns_hostnames = "true" if is_default else "false" 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 self.cidr_block_association_set[association_id] = association_set
return 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): def disassociate_vpc_cidr_block(self, association_id):
if self.cidr_block == self.cidr_block_association_set.get( if self.cidr_block == self.cidr_block_association_set.get(
association_id, {} association_id, {}
@ -2670,6 +2697,22 @@ class VPCBackend(object):
else: else:
raise InvalidParameterValueError(attr_name) 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): def modify_vpc_attribute(self, vpc_id, attr_name, attr_value):
vpc = self.get_vpc(vpc_id) vpc = self.get_vpc(vpc_id)
if attr_name in ("enable_dns_support", "enable_dns_hostnames"): 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): 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): def create_vpc(self):
cidr_block = self._get_param("CidrBlock") cidr_block = self._get_param("CidrBlock")
instance_tenancy = self._get_param("InstanceTenancy", if_none="default") instance_tenancy = self._get_param("InstanceTenancy", if_none="default")
@ -16,11 +23,7 @@ class VPCs(BaseResponse):
instance_tenancy, instance_tenancy,
amazon_provided_ipv6_cidr_block=amazon_provided_ipv6_cidr_blocks, amazon_provided_ipv6_cidr_block=amazon_provided_ipv6_cidr_blocks,
) )
doc_date = ( doc_date = self._get_doc_date()
"2013-10-15"
if "Boto/" in self.headers.get("user-agent", "")
else "2016-11-15"
)
template = self.response_template(CREATE_VPC_RESPONSE) template = self.response_template(CREATE_VPC_RESPONSE)
return template.render(vpc=vpc, doc_date=doc_date) return template.render(vpc=vpc, doc_date=doc_date)
@ -50,6 +53,64 @@ class VPCs(BaseResponse):
template = self.response_template(DESCRIBE_VPC_ATTRIBUTE_RESPONSE) template = self.response_template(DESCRIBE_VPC_ATTRIBUTE_RESPONSE)
return template.render(vpc_id=vpc_id, attribute=attribute, value=value) 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): def modify_vpc_attribute(self):
vpc_id = self._get_param("VpcId") vpc_id = self._get_param("VpcId")
@ -149,6 +210,56 @@ CREATE_VPC_RESPONSE = """
</vpc> </vpc>
</CreateVpcResponse>""" </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 = """ DESCRIBE_VPCS_RESPONSE = """
<DescribeVpcsResponse xmlns="http://ec2.amazonaws.com/doc/{{doc_date}}/"> <DescribeVpcsResponse xmlns="http://ec2.amazonaws.com/doc/{{doc_date}}/">
<requestId>7a62c442-3484-4f42-9342-6942EXAMPLE</requestId> <requestId>7a62c442-3484-4f42-9342-6942EXAMPLE</requestId>

View File

@ -1,5 +1,6 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import base64 import base64
import hashlib
import os import os
import random import random
import string import string
@ -475,6 +476,20 @@ class AccessKey(BaseModel):
raise UnformattedGetAttTemplateException() 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): class Group(BaseModel):
def __init__(self, name, path="/"): def __init__(self, name, path="/"):
self.name = name self.name = name
@ -536,6 +551,7 @@ class User(BaseModel):
self.policies = {} self.policies = {}
self.managed_policies = {} self.managed_policies = {}
self.access_keys = [] self.access_keys = []
self.ssh_public_keys = []
self.password = None self.password = None
self.password_reset_required = False self.password_reset_required = False
self.signing_certificates = {} self.signing_certificates = {}
@ -605,6 +621,33 @@ class User(BaseModel):
"The Access Key with id {0} cannot be found".format(access_key_id) "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): def get_cfn_attribute(self, attribute_name):
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException 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): class IAMBackend(BaseBackend):
def __init__(self): def __init__(self):
self.instance_profiles = {} self.instance_profiles = {}
@ -751,6 +922,7 @@ class IAMBackend(BaseBackend):
self.policy_arn_regex = re.compile(r"^arn:aws:iam::[0-9]*:policy/.*$") self.policy_arn_regex = re.compile(r"^arn:aws:iam::[0-9]*:policy/.*$")
self.virtual_mfa_devices = {} self.virtual_mfa_devices = {}
self.account_password_policy = None self.account_password_policy = None
self.account_summary = AccountSummary(self)
super(IAMBackend, self).__init__() super(IAMBackend, self).__init__()
def _init_managed_policies(self): def _init_managed_policies(self):
@ -820,7 +992,7 @@ class IAMBackend(BaseBackend):
) )
if policy.arn in self.managed_policies: if policy.arn in self.managed_policies:
raise EntityAlreadyExists( 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 policy_name
) )
) )
@ -898,6 +1070,10 @@ class IAMBackend(BaseBackend):
permissions_boundary 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) clean_tags = self._tag_verification(tags)
role = Role( role = Role(
@ -1158,7 +1334,7 @@ class IAMBackend(BaseBackend):
def get_all_server_certs(self, marker=None): def get_all_server_certs(self, marker=None):
return self.certificates.values() return self.certificates.values()
def upload_server_cert( def upload_server_certificate(
self, cert_name, cert_body, private_key, cert_chain=None, path=None self, cert_name, cert_body, private_key, cert_chain=None, path=None
): ):
certificate_id = random_resource_id() certificate_id = random_resource_id()
@ -1451,6 +1627,26 @@ class IAMBackend(BaseBackend):
user = self.get_user(user_name) user = self.get_user(user_name)
user.delete_access_key(access_key_id) 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( def enable_mfa_device(
self, user_name, serial_number, authentication_code_1, authentication_code_2 self, user_name, serial_number, authentication_code_1, authentication_code_2
): ):
@ -1737,5 +1933,8 @@ class IAMBackend(BaseBackend):
self.account_password_policy = None self.account_password_policy = None
def get_account_summary(self):
return self.account_summary
iam_backend = IAMBackend() iam_backend = IAMBackend()

View File

@ -351,7 +351,7 @@ class IamResponse(BaseResponse):
private_key = self._get_param("PrivateKey") private_key = self._get_param("PrivateKey")
cert_chain = self._get_param("CertificateName") 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 cert_name, cert_body, private_key, cert_chain=cert_chain, path=path
) )
template = self.response_template(UPLOAD_CERT_TEMPLATE) template = self.response_template(UPLOAD_CERT_TEMPLATE)
@ -590,6 +590,46 @@ class IamResponse(BaseResponse):
template = self.response_template(GENERIC_EMPTY_TEMPLATE) template = self.response_template(GENERIC_EMPTY_TEMPLATE)
return template.render(name="DeleteAccessKey") 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): def deactivate_mfa_device(self):
user_name = self._get_param("UserName") user_name = self._get_param("UserName")
serial_number = self._get_param("SerialNumber") serial_number = self._get_param("SerialNumber")
@ -888,6 +928,12 @@ class IamResponse(BaseResponse):
template = self.response_template(DELETE_ACCOUNT_PASSWORD_POLICY_TEMPLATE) template = self.response_template(DELETE_ACCOUNT_PASSWORD_POLICY_TEMPLATE)
return template.render() 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> LIST_ENTITIES_FOR_POLICY_TEMPLATE = """<ListEntitiesForPolicyResponse>
<ListEntitiesForPolicyResult> <ListEntitiesForPolicyResult>
@ -1690,6 +1736,73 @@ GET_ACCESS_KEY_LAST_USED_TEMPLATE = """
</GetAccessKeyLastUsedResponse> </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 = """ CREDENTIAL_REPORT_GENERATING = """
<GenerateCredentialReportResponse> <GenerateCredentialReportResponse>
<GenerateCredentialReportResult> <GenerateCredentialReportResult>
@ -2261,3 +2374,20 @@ DELETE_ACCOUNT_PASSWORD_POLICY_TEMPLATE = """<DeleteAccountPasswordPolicyRespons
<RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId> <RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
</ResponseMetadata> </ResponseMetadata>
</DeleteAccountPasswordPolicyResponse>""" </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. internal `parse_request` method.
It also replaces the `rfile` and `wfile` attributes with StringIO 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. for writing nor reading.
It has some convenience attributes: It has some convenience attributes:

View File

@ -190,7 +190,7 @@ def create_backend_app(service):
index = 2 index = 2
while endpoint in backend_app.view_functions: while endpoint in backend_app.view_functions:
# HACK: Sometimes we map the same view to multiple url_paths. Flask # 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) endpoint = original_endpoint + str(index)
index += 1 index += 1

View File

@ -147,7 +147,7 @@ class SESBackend(BaseBackend):
def __type_of_message__(self, destinations): def __type_of_message__(self, destinations):
"""Checks the destination for any special address that could indicate delivery, """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 = ( alladdress = (
destinations.get("ToAddresses", []) destinations.get("ToAddresses", [])
+ destinations.get("CcAddresses", []) + destinations.get("CcAddresses", [])

View File

@ -227,7 +227,7 @@ class Subscription(BaseModel):
return False return False
for attribute_values in attribute_values: 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 # 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): if int(attribute_values * 1000000) == int(rule * 1000000):
return True return True
@ -573,7 +573,7 @@ class SNSBackend(BaseBackend):
combinations = 1 combinations = 1
for rules in six.itervalues(value): for rules in six.itervalues(value):
combinations *= len(rules) 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 # https://docs.aws.amazon.com/sns/latest/dg/sns-subscription-filter-policies.html#subscription-filter-policy-constraints
if combinations > 150: if combinations > 150:
raise SNSInvalidParameter( raise SNSInvalidParameter(

View File

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

View File

@ -761,7 +761,7 @@ class SQSBackend(BaseBackend):
new_messages = [] new_messages = []
for message in queue._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. # matches.
if message.receipt_handle == receipt_handle: if message.receipt_handle == receipt_handle:
queue.pending_messages.remove(message) queue.pending_messages.remove(message)

View File

@ -430,7 +430,7 @@ class WorkflowExecution(BaseModel):
) )
def fail(self, event_id, details=None, reason=None): 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.execution_status = "CLOSED"
self.close_status = "FAILED" self.close_status = "FAILED"
self.close_timestamp = unix_time() self.close_timestamp = unix_time()

View File

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

View File

@ -162,7 +162,7 @@ if settings.TEST_SERVER_MODE:
conn = boto3.client("lambda", "us-west-2") conn = boto3.client("lambda", "us-west-2")
conn.create_function( conn.create_function(
FunctionName="testFunction", FunctionName="testFunction",
Runtime="python2.7", Runtime="python3.7",
Role="test-iam-role", Role="test-iam-role",
Handler="lambda_function.lambda_handler", Handler="lambda_function.lambda_handler",
Code={"ZipFile": get_test_zip_file2()}, Code={"ZipFile": get_test_zip_file2()},
@ -184,18 +184,20 @@ if settings.TEST_SERVER_MODE:
vol.id, vol.id,
vol.state, vol.state,
vol.size, 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") 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 = log_result.replace("\n\n", "\n")
log_result.should.equal(msg) log_result.should.equal(msg)
payload = result["Payload"].read().decode("utf-8") 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 = payload.replace("\n\n", "\n")
payload.should.equal(msg) 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 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.core import set_initial_no_auth_action_count
from moto.iam.models import ACCOUNT_ID from moto.iam.models import ACCOUNT_ID
from uuid import uuid4
@mock_iam @mock_iam
@ -71,8 +72,10 @@ def create_user_with_access_key_and_multiple_policies(
def create_group_with_attached_policy_and_add_user( 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 = boto3.client("iam", region_name="us-east-1")
client.create_group(GroupName=group_name) client.create_group(GroupName=group_name)
policy_arn = client.create_policy( policy_arn = client.create_policy(
@ -101,8 +104,10 @@ def create_group_with_multiple_policies_and_add_user(
attached_policy_document, attached_policy_document,
group_name="test-group", group_name="test-group",
inline_policy_name="policy1", 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 = boto3.client("iam", region_name="us-east-1")
client.create_group(GroupName=group_name) client.create_group(GroupName=group_name)
client.put_group_policy( 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 " "An error occurred (InvalidVpc.Range) when calling the CreateVpc "
"operation: The CIDR '{}' is invalid.".format(vpc_cidr_block) "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 datetime import datetime
from tests.helpers import requires_boto_gte from tests.helpers import requires_boto_gte
from uuid import uuid4
MOCK_CERT = """-----BEGIN CERTIFICATE----- MOCK_CERT = """-----BEGIN CERTIFICATE-----
@ -1315,6 +1316,122 @@ def test_get_access_key_last_used():
resp["UserName"].should.equal(create_key_response["UserName"]) 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 @mock_iam
def test_get_account_authorization_details(): def test_get_account_authorization_details():
test_policy = json.dumps( 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) 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 @mock_iam
def test_create_open_id_connect_provider(): def test_create_open_id_connect_provider():
client = boto3.client("iam", region_name="us-east-1") 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( client.delete_account_password_policy.when.called_with().should.throw(
ClientError, "The account policy with name PasswordPolicy cannot be found." 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 @mock_sns
def test_publish_sms(): def test_publish_sms():
client = boto3.client("sns", region_name="us-east-1") client = boto3.client("sns", region_name="us-east-1")