capo-codedeploy 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- capo_codedeploy/__init__.py +70 -0
- capo_codedeploy/_async.py +25 -0
- capo_codedeploy/_auth/_identity.py +16 -0
- capo_codedeploy/_auth/_providers.py +886 -0
- capo_codedeploy/_auth/_signers.py +88 -0
- capo_codedeploy/_auth/_sigv4.py +434 -0
- capo_codedeploy/_auth/_zapros_handler.py +80 -0
- capo_codedeploy/_iter.py +113 -0
- capo_codedeploy/_operations/code_deploy_20141006/add_tags_to_on_premises_instances.py +153 -0
- capo_codedeploy/_operations/code_deploy_20141006/batch_get_application_revisions.py +173 -0
- capo_codedeploy/_operations/code_deploy_20141006/batch_get_applications.py +163 -0
- capo_codedeploy/_operations/code_deploy_20141006/batch_get_deployment_groups.py +178 -0
- capo_codedeploy/_operations/code_deploy_20141006/batch_get_deployment_instances.py +178 -0
- capo_codedeploy/_operations/code_deploy_20141006/batch_get_deployment_targets.py +188 -0
- capo_codedeploy/_operations/code_deploy_20141006/batch_get_deployments.py +158 -0
- capo_codedeploy/_operations/code_deploy_20141006/batch_get_on_premises_instances.py +158 -0
- capo_codedeploy/_operations/code_deploy_20141006/continue_deployment.py +155 -0
- capo_codedeploy/_operations/code_deploy_20141006/create_application.py +175 -0
- capo_codedeploy/_operations/code_deploy_20141006/create_deployment.py +278 -0
- capo_codedeploy/_operations/code_deploy_20141006/create_deployment_config.py +185 -0
- capo_codedeploy/_operations/code_deploy_20141006/create_deployment_group.py +320 -0
- capo_codedeploy/_operations/code_deploy_20141006/delete_application.py +129 -0
- capo_codedeploy/_operations/code_deploy_20141006/delete_deployment_config.py +136 -0
- capo_codedeploy/_operations/code_deploy_20141006/delete_deployment_group.py +167 -0
- capo_codedeploy/_operations/code_deploy_20141006/delete_git_hub_account_token.py +166 -0
- capo_codedeploy/_operations/code_deploy_20141006/delete_resources_by_external_id.py +137 -0
- capo_codedeploy/_operations/code_deploy_20141006/deregister_on_premises_instance.py +126 -0
- capo_codedeploy/_operations/code_deploy_20141006/get_application.py +157 -0
- capo_codedeploy/_operations/code_deploy_20141006/get_application_revision.py +173 -0
- capo_codedeploy/_operations/code_deploy_20141006/get_deployment.py +157 -0
- capo_codedeploy/_operations/code_deploy_20141006/get_deployment_config.py +162 -0
- capo_codedeploy/_operations/code_deploy_20141006/get_deployment_group.py +179 -0
- capo_codedeploy/_operations/code_deploy_20141006/get_deployment_instance.py +177 -0
- capo_codedeploy/_operations/code_deploy_20141006/get_deployment_target.py +182 -0
- capo_codedeploy/_operations/code_deploy_20141006/get_on_premises_instance.py +157 -0
- capo_codedeploy/_operations/code_deploy_20141006/list_application_revisions.py +195 -0
- capo_codedeploy/_operations/code_deploy_20141006/list_applications.py +149 -0
- capo_codedeploy/_operations/code_deploy_20141006/list_deployment_configs.py +147 -0
- capo_codedeploy/_operations/code_deploy_20141006/list_deployment_groups.py +162 -0
- capo_codedeploy/_operations/code_deploy_20141006/list_deployment_instances.py +198 -0
- capo_codedeploy/_operations/code_deploy_20141006/list_deployment_targets.py +188 -0
- capo_codedeploy/_operations/code_deploy_20141006/list_deployments.py +199 -0
- capo_codedeploy/_operations/code_deploy_20141006/list_git_hub_account_token_names.py +157 -0
- capo_codedeploy/_operations/code_deploy_20141006/list_on_premises_instances.py +159 -0
- capo_codedeploy/_operations/code_deploy_20141006/list_tags_for_resource.py +157 -0
- capo_codedeploy/_operations/code_deploy_20141006/put_lifecycle_event_hook_execution_status.py +177 -0
- capo_codedeploy/_operations/code_deploy_20141006/register_application_revision.py +147 -0
- capo_codedeploy/_operations/code_deploy_20141006/register_on_premises_instance.py +166 -0
- capo_codedeploy/_operations/code_deploy_20141006/remove_tags_from_on_premises_instances.py +153 -0
- capo_codedeploy/_operations/code_deploy_20141006/skip_wait_time_for_instance_termination.py +146 -0
- capo_codedeploy/_operations/code_deploy_20141006/stop_deployment.py +172 -0
- capo_codedeploy/_operations/code_deploy_20141006/tag_resource.py +174 -0
- capo_codedeploy/_operations/code_deploy_20141006/untag_resource.py +174 -0
- capo_codedeploy/_operations/code_deploy_20141006/update_application.py +134 -0
- capo_codedeploy/_operations/code_deploy_20141006/update_deployment_group.py +310 -0
- capo_codedeploy/_pagination.py +21 -0
- capo_codedeploy/_protocol/__init__.py +1 -0
- capo_codedeploy/_protocol/errors.py +93 -0
- capo_codedeploy/_protocol/eventstream.py +238 -0
- capo_codedeploy/_protocol/serialize.py +47 -0
- capo_codedeploy/_protocol/xml.py +33 -0
- capo_codedeploy/_rule_engine/__init__.py +0 -0
- capo_codedeploy/_rule_engine/_aws_partition.py +160 -0
- capo_codedeploy/_rule_engine/_endpoint_rule_set.py +138 -0
- capo_codedeploy/_rule_engine/_endpoint_runtime.py +389 -0
- capo_codedeploy/_services/_aws_config.py +160 -0
- capo_codedeploy/_services/_pipeline.py +198 -0
- capo_codedeploy/_services/async_code_deploy.py +3278 -0
- capo_codedeploy/_services/code_deploy.py +3229 -0
- capo_codedeploy/errors/__init__.py +335 -0
- capo_codedeploy/errors/_base.py +94 -0
- capo_codedeploy/errors/alarms_limit_exceeded_exception.py +52 -0
- capo_codedeploy/errors/application_already_exists_exception.py +54 -0
- capo_codedeploy/errors/application_does_not_exist_exception.py +54 -0
- capo_codedeploy/errors/application_limit_exceeded_exception.py +54 -0
- capo_codedeploy/errors/application_name_required_exception.py +54 -0
- capo_codedeploy/errors/arn_not_supported_exception.py +52 -0
- capo_codedeploy/errors/batch_limit_exceeded_exception.py +52 -0
- capo_codedeploy/errors/bucket_name_filter_required_exception.py +54 -0
- capo_codedeploy/errors/deployment_already_completed_exception.py +54 -0
- capo_codedeploy/errors/deployment_config_already_exists_exception.py +54 -0
- capo_codedeploy/errors/deployment_config_does_not_exist_exception.py +54 -0
- capo_codedeploy/errors/deployment_config_in_use_exception.py +54 -0
- capo_codedeploy/errors/deployment_config_limit_exceeded_exception.py +54 -0
- capo_codedeploy/errors/deployment_config_name_required_exception.py +54 -0
- capo_codedeploy/errors/deployment_does_not_exist_exception.py +54 -0
- capo_codedeploy/errors/deployment_group_already_exists_exception.py +54 -0
- capo_codedeploy/errors/deployment_group_does_not_exist_exception.py +54 -0
- capo_codedeploy/errors/deployment_group_limit_exceeded_exception.py +54 -0
- capo_codedeploy/errors/deployment_group_name_required_exception.py +54 -0
- capo_codedeploy/errors/deployment_id_required_exception.py +54 -0
- capo_codedeploy/errors/deployment_is_not_in_ready_state_exception.py +54 -0
- capo_codedeploy/errors/deployment_limit_exceeded_exception.py +54 -0
- capo_codedeploy/errors/deployment_not_started_exception.py +54 -0
- capo_codedeploy/errors/deployment_target_does_not_exist_exception.py +54 -0
- capo_codedeploy/errors/deployment_target_id_required_exception.py +54 -0
- capo_codedeploy/errors/deployment_target_list_size_exceeded_exception.py +56 -0
- capo_codedeploy/errors/description_too_long_exception.py +52 -0
- capo_codedeploy/errors/ecs_service_mapping_limit_exceeded_exception.py +54 -0
- capo_codedeploy/errors/git_hub_account_token_does_not_exist_exception.py +54 -0
- capo_codedeploy/errors/git_hub_account_token_name_required_exception.py +54 -0
- capo_codedeploy/errors/iam_arn_required_exception.py +52 -0
- capo_codedeploy/errors/iam_session_arn_already_registered_exception.py +54 -0
- capo_codedeploy/errors/iam_user_arn_already_registered_exception.py +54 -0
- capo_codedeploy/errors/iam_user_arn_required_exception.py +52 -0
- capo_codedeploy/errors/instance_does_not_exist_exception.py +54 -0
- capo_codedeploy/errors/instance_id_required_exception.py +52 -0
- capo_codedeploy/errors/instance_limit_exceeded_exception.py +54 -0
- capo_codedeploy/errors/instance_name_already_registered_exception.py +54 -0
- capo_codedeploy/errors/instance_name_required_exception.py +54 -0
- capo_codedeploy/errors/instance_not_registered_exception.py +54 -0
- capo_codedeploy/errors/invalid_alarm_config_exception.py +52 -0
- capo_codedeploy/errors/invalid_application_name_exception.py +54 -0
- capo_codedeploy/errors/invalid_arn_exception.py +52 -0
- capo_codedeploy/errors/invalid_auto_rollback_config_exception.py +54 -0
- capo_codedeploy/errors/invalid_auto_scaling_group_exception.py +54 -0
- capo_codedeploy/errors/invalid_blue_green_deployment_configuration_exception.py +60 -0
- capo_codedeploy/errors/invalid_bucket_name_filter_exception.py +54 -0
- capo_codedeploy/errors/invalid_compute_platform_exception.py +54 -0
- capo_codedeploy/errors/invalid_deployed_state_filter_exception.py +54 -0
- capo_codedeploy/errors/invalid_deployment_config_name_exception.py +54 -0
- capo_codedeploy/errors/invalid_deployment_group_name_exception.py +54 -0
- capo_codedeploy/errors/invalid_deployment_id_exception.py +52 -0
- capo_codedeploy/errors/invalid_deployment_instance_type_exception.py +54 -0
- capo_codedeploy/errors/invalid_deployment_status_exception.py +54 -0
- capo_codedeploy/errors/invalid_deployment_style_exception.py +54 -0
- capo_codedeploy/errors/invalid_deployment_target_id_exception.py +54 -0
- capo_codedeploy/errors/invalid_deployment_wait_type_exception.py +54 -0
- capo_codedeploy/errors/invalid_ec2_tag_combination_exception.py +54 -0
- capo_codedeploy/errors/invalid_ec2_tag_exception.py +52 -0
- capo_codedeploy/errors/invalid_ecs_service_exception.py +52 -0
- capo_codedeploy/errors/invalid_external_id_exception.py +52 -0
- capo_codedeploy/errors/invalid_file_exists_behavior_exception.py +54 -0
- capo_codedeploy/errors/invalid_git_hub_account_token_exception.py +54 -0
- capo_codedeploy/errors/invalid_git_hub_account_token_name_exception.py +54 -0
- capo_codedeploy/errors/invalid_iam_session_arn_exception.py +54 -0
- capo_codedeploy/errors/invalid_iam_user_arn_exception.py +52 -0
- capo_codedeploy/errors/invalid_ignore_application_stop_failures_value_exception.py +60 -0
- capo_codedeploy/errors/invalid_input_exception.py +52 -0
- capo_codedeploy/errors/invalid_instance_name_exception.py +52 -0
- capo_codedeploy/errors/invalid_instance_status_exception.py +54 -0
- capo_codedeploy/errors/invalid_instance_type_exception.py +52 -0
- capo_codedeploy/errors/invalid_key_prefix_filter_exception.py +54 -0
- capo_codedeploy/errors/invalid_lifecycle_event_hook_execution_id_exception.py +60 -0
- capo_codedeploy/errors/invalid_lifecycle_event_hook_execution_status_exception.py +60 -0
- capo_codedeploy/errors/invalid_load_balancer_info_exception.py +54 -0
- capo_codedeploy/errors/invalid_minimum_healthy_host_value_exception.py +54 -0
- capo_codedeploy/errors/invalid_next_token_exception.py +52 -0
- capo_codedeploy/errors/invalid_on_premises_tag_combination_exception.py +56 -0
- capo_codedeploy/errors/invalid_operation_exception.py +52 -0
- capo_codedeploy/errors/invalid_registration_status_exception.py +54 -0
- capo_codedeploy/errors/invalid_revision_exception.py +52 -0
- capo_codedeploy/errors/invalid_role_exception.py +52 -0
- capo_codedeploy/errors/invalid_sort_by_exception.py +52 -0
- capo_codedeploy/errors/invalid_sort_order_exception.py +52 -0
- capo_codedeploy/errors/invalid_tag_exception.py +52 -0
- capo_codedeploy/errors/invalid_tag_filter_exception.py +52 -0
- capo_codedeploy/errors/invalid_tags_to_add_exception.py +52 -0
- capo_codedeploy/errors/invalid_target_filter_name_exception.py +54 -0
- capo_codedeploy/errors/invalid_target_group_pair_exception.py +54 -0
- capo_codedeploy/errors/invalid_target_instances_exception.py +54 -0
- capo_codedeploy/errors/invalid_time_range_exception.py +52 -0
- capo_codedeploy/errors/invalid_traffic_routing_configuration_exception.py +58 -0
- capo_codedeploy/errors/invalid_trigger_config_exception.py +54 -0
- capo_codedeploy/errors/invalid_update_outdated_instances_only_value_exception.py +60 -0
- capo_codedeploy/errors/invalid_zonal_deployment_configuration_exception.py +60 -0
- capo_codedeploy/errors/lifecycle_event_already_completed_exception.py +54 -0
- capo_codedeploy/errors/lifecycle_hook_limit_exceeded_exception.py +54 -0
- capo_codedeploy/errors/multiple_iam_arns_provided_exception.py +54 -0
- capo_codedeploy/errors/operation_not_supported_exception.py +54 -0
- capo_codedeploy/errors/resource_arn_required_exception.py +52 -0
- capo_codedeploy/errors/resource_validation_exception.py +52 -0
- capo_codedeploy/errors/revision_does_not_exist_exception.py +54 -0
- capo_codedeploy/errors/revision_required_exception.py +52 -0
- capo_codedeploy/errors/role_required_exception.py +52 -0
- capo_codedeploy/errors/tag_limit_exceeded_exception.py +52 -0
- capo_codedeploy/errors/tag_required_exception.py +52 -0
- capo_codedeploy/errors/tag_set_list_limit_exceeded_exception.py +54 -0
- capo_codedeploy/errors/throttling_exception.py +52 -0
- capo_codedeploy/errors/trigger_targets_limit_exceeded_exception.py +54 -0
- capo_codedeploy/errors/unsupported_action_for_deployment_type_exception.py +58 -0
- capo_codedeploy/py.typed +0 -0
- capo_codedeploy/types/_prelude/blob.py +12 -0
- capo_codedeploy/types/_prelude/timestamp.py +17 -0
- capo_codedeploy/types/add_tags_to_on_premises_instances_input.py +59 -0
- capo_codedeploy/types/additional_deployment_status_info.py +5 -0
- capo_codedeploy/types/alarm.py +28 -0
- capo_codedeploy/types/alarm_configuration.py +51 -0
- capo_codedeploy/types/alarm_list.py +29 -0
- capo_codedeploy/types/alarm_name.py +5 -0
- capo_codedeploy/types/app_spec_content.py +35 -0
- capo_codedeploy/types/application_id.py +5 -0
- capo_codedeploy/types/application_info.py +90 -0
- capo_codedeploy/types/application_name.py +5 -0
- capo_codedeploy/types/application_revision_sort_by.py +18 -0
- capo_codedeploy/types/applications_info_list.py +33 -0
- capo_codedeploy/types/applications_list.py +19 -0
- capo_codedeploy/types/arn.py +5 -0
- capo_codedeploy/types/auto_rollback_configuration.py +50 -0
- capo_codedeploy/types/auto_rollback_event.py +18 -0
- capo_codedeploy/types/auto_rollback_events_list.py +35 -0
- capo_codedeploy/types/auto_scaling_group.py +47 -0
- capo_codedeploy/types/auto_scaling_group_hook.py +5 -0
- capo_codedeploy/types/auto_scaling_group_list.py +35 -0
- capo_codedeploy/types/auto_scaling_group_name.py +5 -0
- capo_codedeploy/types/auto_scaling_group_name_list.py +19 -0
- capo_codedeploy/types/batch_get_application_revisions_input.py +55 -0
- capo_codedeploy/types/batch_get_application_revisions_output.py +56 -0
- capo_codedeploy/types/batch_get_applications_input.py +45 -0
- capo_codedeploy/types/batch_get_applications_output.py +42 -0
- capo_codedeploy/types/batch_get_deployment_groups_input.py +57 -0
- capo_codedeploy/types/batch_get_deployment_groups_output.py +49 -0
- capo_codedeploy/types/batch_get_deployment_instances_input.py +53 -0
- capo_codedeploy/types/batch_get_deployment_instances_output.py +49 -0
- capo_codedeploy/types/batch_get_deployment_targets_input.py +51 -0
- capo_codedeploy/types/batch_get_deployment_targets_output.py +42 -0
- capo_codedeploy/types/batch_get_deployments_input.py +43 -0
- capo_codedeploy/types/batch_get_deployments_output.py +42 -0
- capo_codedeploy/types/batch_get_on_premises_instances_input.py +45 -0
- capo_codedeploy/types/batch_get_on_premises_instances_output.py +42 -0
- capo_codedeploy/types/blue_green_deployment_configuration.py +84 -0
- capo_codedeploy/types/blue_instance_termination_option.py +46 -0
- capo_codedeploy/types/boolean.py +5 -0
- capo_codedeploy/types/bundle_type.py +20 -0
- capo_codedeploy/types/cloud_formation_resource_type.py +5 -0
- capo_codedeploy/types/cloud_formation_target.py +112 -0
- capo_codedeploy/types/commit_id.py +5 -0
- capo_codedeploy/types/compute_platform.py +18 -0
- capo_codedeploy/types/continue_deployment_input.py +49 -0
- capo_codedeploy/types/create_application_input.py +67 -0
- capo_codedeploy/types/create_application_output.py +28 -0
- capo_codedeploy/types/create_deployment_config_input.py +115 -0
- capo_codedeploy/types/create_deployment_config_output.py +30 -0
- capo_codedeploy/types/create_deployment_group_input.py +353 -0
- capo_codedeploy/types/create_deployment_group_output.py +30 -0
- capo_codedeploy/types/create_deployment_input.py +178 -0
- capo_codedeploy/types/create_deployment_output.py +28 -0
- capo_codedeploy/types/delete_application_input.py +31 -0
- capo_codedeploy/types/delete_deployment_config_input.py +35 -0
- capo_codedeploy/types/delete_deployment_group_input.py +45 -0
- capo_codedeploy/types/delete_deployment_group_output.py +42 -0
- capo_codedeploy/types/delete_git_hub_account_token_input.py +30 -0
- capo_codedeploy/types/delete_git_hub_account_token_output.py +30 -0
- capo_codedeploy/types/delete_resources_by_external_id_input.py +28 -0
- capo_codedeploy/types/delete_resources_by_external_id_output.py +18 -0
- capo_codedeploy/types/deployment_config_id.py +5 -0
- capo_codedeploy/types/deployment_config_info.py +134 -0
- capo_codedeploy/types/deployment_config_name.py +5 -0
- capo_codedeploy/types/deployment_configs_list.py +19 -0
- capo_codedeploy/types/deployment_creator.py +23 -0
- capo_codedeploy/types/deployment_group_id.py +5 -0
- capo_codedeploy/types/deployment_group_info.py +420 -0
- capo_codedeploy/types/deployment_group_info_list.py +35 -0
- capo_codedeploy/types/deployment_group_name.py +5 -0
- capo_codedeploy/types/deployment_groups_list.py +19 -0
- capo_codedeploy/types/deployment_id.py +5 -0
- capo_codedeploy/types/deployment_info.py +499 -0
- capo_codedeploy/types/deployment_option.py +17 -0
- capo_codedeploy/types/deployment_overview.py +64 -0
- capo_codedeploy/types/deployment_ready_action.py +17 -0
- capo_codedeploy/types/deployment_ready_option.py +50 -0
- capo_codedeploy/types/deployment_status.py +23 -0
- capo_codedeploy/types/deployment_status_list.py +33 -0
- capo_codedeploy/types/deployment_status_message_list.py +19 -0
- capo_codedeploy/types/deployment_style.py +61 -0
- capo_codedeploy/types/deployment_target.py +115 -0
- capo_codedeploy/types/deployment_target_list.py +33 -0
- capo_codedeploy/types/deployment_target_type.py +19 -0
- capo_codedeploy/types/deployment_type.py +17 -0
- capo_codedeploy/types/deployment_wait_type.py +17 -0
- capo_codedeploy/types/deployments_info_list.py +31 -0
- capo_codedeploy/types/deployments_list.py +17 -0
- capo_codedeploy/types/deregister_on_premises_instance_input.py +33 -0
- capo_codedeploy/types/description.py +5 -0
- capo_codedeploy/types/diagnostics.py +63 -0
- capo_codedeploy/types/duration.py +5 -0
- capo_codedeploy/types/e_tag.py +5 -0
- capo_codedeploy/types/ec2_tag_filter.py +52 -0
- capo_codedeploy/types/ec2_tag_filter_list.py +29 -0
- capo_codedeploy/types/ec2_tag_filter_type.py +18 -0
- capo_codedeploy/types/ec2_tag_set.py +42 -0
- capo_codedeploy/types/ec2_tag_set_list.py +35 -0
- capo_codedeploy/types/ecs_cluster_name.py +5 -0
- capo_codedeploy/types/ecs_service.py +35 -0
- capo_codedeploy/types/ecs_service_list.py +29 -0
- capo_codedeploy/types/ecs_service_name.py +5 -0
- capo_codedeploy/types/ecs_target.py +114 -0
- capo_codedeploy/types/ecs_task_set.py +111 -0
- capo_codedeploy/types/ecs_task_set_count.py +5 -0
- capo_codedeploy/types/ecs_task_set_identifier.py +5 -0
- capo_codedeploy/types/ecs_task_set_list.py +29 -0
- capo_codedeploy/types/ecs_task_set_status.py +5 -0
- capo_codedeploy/types/elb_info.py +28 -0
- capo_codedeploy/types/elb_info_list.py +29 -0
- capo_codedeploy/types/elb_name.py +5 -0
- capo_codedeploy/types/error_code.py +49 -0
- capo_codedeploy/types/error_information.py +43 -0
- capo_codedeploy/types/error_message.py +5 -0
- capo_codedeploy/types/external_id.py +5 -0
- capo_codedeploy/types/file_exists_behavior.py +18 -0
- capo_codedeploy/types/filter_value.py +5 -0
- capo_codedeploy/types/filter_value_list.py +17 -0
- capo_codedeploy/types/generic_revision_info.py +96 -0
- capo_codedeploy/types/get_application_input.py +31 -0
- capo_codedeploy/types/get_application_output.py +40 -0
- capo_codedeploy/types/get_application_revision_input.py +51 -0
- capo_codedeploy/types/get_application_revision_output.py +70 -0
- capo_codedeploy/types/get_deployment_config_input.py +35 -0
- capo_codedeploy/types/get_deployment_config_output.py +42 -0
- capo_codedeploy/types/get_deployment_group_input.py +43 -0
- capo_codedeploy/types/get_deployment_group_output.py +42 -0
- capo_codedeploy/types/get_deployment_input.py +31 -0
- capo_codedeploy/types/get_deployment_instance_input.py +39 -0
- capo_codedeploy/types/get_deployment_instance_output.py +42 -0
- capo_codedeploy/types/get_deployment_output.py +40 -0
- capo_codedeploy/types/get_deployment_target_input.py +39 -0
- capo_codedeploy/types/get_deployment_target_output.py +42 -0
- capo_codedeploy/types/get_on_premises_instance_input.py +31 -0
- capo_codedeploy/types/get_on_premises_instance_output.py +40 -0
- capo_codedeploy/types/git_hub_account_token_name.py +5 -0
- capo_codedeploy/types/git_hub_account_token_name_list.py +19 -0
- capo_codedeploy/types/git_hub_location.py +35 -0
- capo_codedeploy/types/green_fleet_provisioning_action.py +17 -0
- capo_codedeploy/types/green_fleet_provisioning_option.py +42 -0
- capo_codedeploy/types/iam_session_arn.py +5 -0
- capo_codedeploy/types/iam_user_arn.py +5 -0
- capo_codedeploy/types/instance_action.py +17 -0
- capo_codedeploy/types/instance_arn.py +5 -0
- capo_codedeploy/types/instance_count.py +5 -0
- capo_codedeploy/types/instance_id.py +5 -0
- capo_codedeploy/types/instance_info.py +95 -0
- capo_codedeploy/types/instance_info_list.py +29 -0
- capo_codedeploy/types/instance_name.py +5 -0
- capo_codedeploy/types/instance_name_list.py +17 -0
- capo_codedeploy/types/instance_status.py +22 -0
- capo_codedeploy/types/instance_status_list.py +31 -0
- capo_codedeploy/types/instance_summary.py +107 -0
- capo_codedeploy/types/instance_summary_list.py +33 -0
- capo_codedeploy/types/instance_target.py +112 -0
- capo_codedeploy/types/instance_type.py +17 -0
- capo_codedeploy/types/instance_type_list.py +29 -0
- capo_codedeploy/types/instances_list.py +17 -0
- capo_codedeploy/types/key.py +5 -0
- capo_codedeploy/types/lambda_function_alias.py +5 -0
- capo_codedeploy/types/lambda_function_info.py +69 -0
- capo_codedeploy/types/lambda_function_name.py +5 -0
- capo_codedeploy/types/lambda_target.py +114 -0
- capo_codedeploy/types/last_deployment_info.py +74 -0
- capo_codedeploy/types/lifecycle_error_code.py +21 -0
- capo_codedeploy/types/lifecycle_event.py +95 -0
- capo_codedeploy/types/lifecycle_event_hook_execution_id.py +5 -0
- capo_codedeploy/types/lifecycle_event_list.py +31 -0
- capo_codedeploy/types/lifecycle_event_name.py +5 -0
- capo_codedeploy/types/lifecycle_event_status.py +21 -0
- capo_codedeploy/types/lifecycle_message.py +5 -0
- capo_codedeploy/types/list_application_revisions_input.py +111 -0
- capo_codedeploy/types/list_application_revisions_output.py +49 -0
- capo_codedeploy/types/list_applications_input.py +28 -0
- capo_codedeploy/types/list_applications_output.py +49 -0
- capo_codedeploy/types/list_deployment_configs_input.py +28 -0
- capo_codedeploy/types/list_deployment_configs_output.py +49 -0
- capo_codedeploy/types/list_deployment_groups_input.py +40 -0
- capo_codedeploy/types/list_deployment_groups_output.py +58 -0
- capo_codedeploy/types/list_deployment_instances_input.py +82 -0
- capo_codedeploy/types/list_deployment_instances_output.py +47 -0
- capo_codedeploy/types/list_deployment_targets_input.py +57 -0
- capo_codedeploy/types/list_deployment_targets_output.py +45 -0
- capo_codedeploy/types/list_deployments_input.py +93 -0
- capo_codedeploy/types/list_deployments_output.py +47 -0
- capo_codedeploy/types/list_git_hub_account_token_names_input.py +28 -0
- capo_codedeploy/types/list_git_hub_account_token_names_output.py +49 -0
- capo_codedeploy/types/list_on_premises_instances_input.py +68 -0
- capo_codedeploy/types/list_on_premises_instances_output.py +49 -0
- capo_codedeploy/types/list_state_filter_action.py +18 -0
- capo_codedeploy/types/list_tags_for_resource_input.py +38 -0
- capo_codedeploy/types/list_tags_for_resource_output.py +43 -0
- capo_codedeploy/types/listener_arn.py +5 -0
- capo_codedeploy/types/listener_arn_list.py +17 -0
- capo_codedeploy/types/load_balancer_info.py +80 -0
- capo_codedeploy/types/log_tail.py +5 -0
- capo_codedeploy/types/message.py +5 -0
- capo_codedeploy/types/minimum_healthy_hosts.py +50 -0
- capo_codedeploy/types/minimum_healthy_hosts_per_zone.py +50 -0
- capo_codedeploy/types/minimum_healthy_hosts_per_zone_type.py +17 -0
- capo_codedeploy/types/minimum_healthy_hosts_per_zone_value.py +5 -0
- capo_codedeploy/types/minimum_healthy_hosts_type.py +17 -0
- capo_codedeploy/types/minimum_healthy_hosts_value.py +5 -0
- capo_codedeploy/types/next_token.py +5 -0
- capo_codedeploy/types/nullable_boolean.py +5 -0
- capo_codedeploy/types/on_premises_tag_set.py +42 -0
- capo_codedeploy/types/on_premises_tag_set_list.py +31 -0
- capo_codedeploy/types/outdated_instances_strategy.py +17 -0
- capo_codedeploy/types/percentage.py +5 -0
- capo_codedeploy/types/put_lifecycle_event_hook_execution_status_input.py +60 -0
- capo_codedeploy/types/put_lifecycle_event_hook_execution_status_output.py +32 -0
- capo_codedeploy/types/raw_string.py +35 -0
- capo_codedeploy/types/raw_string_content.py +5 -0
- capo_codedeploy/types/raw_string_sha256.py +5 -0
- capo_codedeploy/types/register_application_revision_input.py +58 -0
- capo_codedeploy/types/register_on_premises_instance_input.py +47 -0
- capo_codedeploy/types/registration_status.py +17 -0
- capo_codedeploy/types/related_deployments.py +55 -0
- capo_codedeploy/types/remove_tags_from_on_premises_instances_input.py +61 -0
- capo_codedeploy/types/repository.py +5 -0
- capo_codedeploy/types/revision_info.py +63 -0
- capo_codedeploy/types/revision_info_list.py +29 -0
- capo_codedeploy/types/revision_location.py +114 -0
- capo_codedeploy/types/revision_location_list.py +33 -0
- capo_codedeploy/types/revision_location_type.py +19 -0
- capo_codedeploy/types/role.py +5 -0
- capo_codedeploy/types/rollback_info.py +49 -0
- capo_codedeploy/types/s3_bucket.py +5 -0
- capo_codedeploy/types/s3_key.py +5 -0
- capo_codedeploy/types/s3_location.py +64 -0
- capo_codedeploy/types/script_name.py +5 -0
- capo_codedeploy/types/skip_wait_time_for_instance_termination_input.py +28 -0
- capo_codedeploy/types/sort_order.py +17 -0
- capo_codedeploy/types/stop_deployment_input.py +40 -0
- capo_codedeploy/types/stop_deployment_output.py +43 -0
- capo_codedeploy/types/stop_status.py +17 -0
- capo_codedeploy/types/tag.py +35 -0
- capo_codedeploy/types/tag_filter.py +50 -0
- capo_codedeploy/types/tag_filter_list.py +29 -0
- capo_codedeploy/types/tag_filter_type.py +18 -0
- capo_codedeploy/types/tag_key_list.py +17 -0
- capo_codedeploy/types/tag_list.py +29 -0
- capo_codedeploy/types/tag_resource_input.py +45 -0
- capo_codedeploy/types/tag_resource_output.py +18 -0
- capo_codedeploy/types/target_arn.py +5 -0
- capo_codedeploy/types/target_filter_name.py +17 -0
- capo_codedeploy/types/target_filters.py +40 -0
- capo_codedeploy/types/target_group_info.py +28 -0
- capo_codedeploy/types/target_group_info_list.py +33 -0
- capo_codedeploy/types/target_group_name.py +5 -0
- capo_codedeploy/types/target_group_pair_info.py +79 -0
- capo_codedeploy/types/target_group_pair_info_list.py +35 -0
- capo_codedeploy/types/target_id.py +5 -0
- capo_codedeploy/types/target_id_list.py +17 -0
- capo_codedeploy/types/target_instances.py +78 -0
- capo_codedeploy/types/target_label.py +17 -0
- capo_codedeploy/types/target_status.py +22 -0
- capo_codedeploy/types/time.py +20 -0
- capo_codedeploy/types/time_based_canary.py +37 -0
- capo_codedeploy/types/time_based_linear.py +37 -0
- capo_codedeploy/types/time_range.py +50 -0
- capo_codedeploy/types/timestamp.py +20 -0
- capo_codedeploy/types/traffic_route.py +42 -0
- capo_codedeploy/types/traffic_routing_config.py +80 -0
- capo_codedeploy/types/traffic_routing_type.py +18 -0
- capo_codedeploy/types/traffic_weight.py +5 -0
- capo_codedeploy/types/trigger_config.py +58 -0
- capo_codedeploy/types/trigger_config_list.py +31 -0
- capo_codedeploy/types/trigger_event_type.py +25 -0
- capo_codedeploy/types/trigger_event_type_list.py +35 -0
- capo_codedeploy/types/trigger_name.py +5 -0
- capo_codedeploy/types/trigger_target_arn.py +5 -0
- capo_codedeploy/types/untag_resource_input.py +47 -0
- capo_codedeploy/types/untag_resource_output.py +18 -0
- capo_codedeploy/types/update_application_input.py +38 -0
- capo_codedeploy/types/update_deployment_group_input.py +343 -0
- capo_codedeploy/types/update_deployment_group_output.py +42 -0
- capo_codedeploy/types/value.py +5 -0
- capo_codedeploy/types/version.py +5 -0
- capo_codedeploy/types/version_id.py +5 -0
- capo_codedeploy/types/wait_time_in_mins.py +5 -0
- capo_codedeploy/types/wait_time_in_seconds.py +5 -0
- capo_codedeploy/types/zonal_config.py +63 -0
- capo_codedeploy-0.1.0.dist-info/METADATA +102 -0
- capo_codedeploy-0.1.0.dist-info/RECORD +472 -0
- capo_codedeploy-0.1.0.dist-info/WHEEL +5 -0
- capo_codedeploy-0.1.0.dist-info/licenses/LICENSE +21 -0
- capo_codedeploy-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
"""Endpoint rule-set runtime — hand-written helpers shared by every generated
|
|
2
|
+
``_endpoint_rule_set.py``. Pure, no third-party deps.
|
|
3
|
+
|
|
4
|
+
Functions mirror the Smithy rules-engine standard library:
|
|
5
|
+
https://smithy.io/2.0/additional-specs/rules-engine/standard-library.html
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import re
|
|
11
|
+
from collections.abc import Mapping
|
|
12
|
+
from dataclasses import dataclass, field
|
|
13
|
+
from typing import Any, TypedDict
|
|
14
|
+
from urllib.parse import quote, urlsplit
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass(frozen=True, slots=True)
|
|
18
|
+
class Endpoint:
|
|
19
|
+
"""Resolved endpoint returned by ``resolve()``.
|
|
20
|
+
|
|
21
|
+
Mirrors the rules-engine *Endpoint object*: a ``url`` plus optional
|
|
22
|
+
``properties`` (arbitrary document values) and ``headers`` (multi-value
|
|
23
|
+
map of header name to list of values).
|
|
24
|
+
|
|
25
|
+
Reference:
|
|
26
|
+
https://smithy.io/2.0/additional-specs/rules-engine/specification.html#endpoint-object
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
url: str
|
|
30
|
+
properties: dict[str, Any] = field(default_factory=dict)
|
|
31
|
+
headers: dict[str, list[str]] = field(default_factory=dict)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class EndpointError(Exception):
|
|
35
|
+
"""Raised when no endpoint rule matches or an ``error`` rule fires.
|
|
36
|
+
|
|
37
|
+
Corresponds to the rules-engine *error rule*: terminates evaluation
|
|
38
|
+
with a diagnostic message produced by the rule set.
|
|
39
|
+
|
|
40
|
+
Reference:
|
|
41
|
+
https://smithy.io/2.0/additional-specs/rules-engine/specification.html#error-rule
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
_PLACEHOLDER = re.compile(r"\{([A-Za-z_][A-Za-z0-9_]*)(?:#([A-Za-z0-9_.\[\]]+))?\}")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def interpolate(template: str, params: object, locals_: dict[str, Any]) -> str:
|
|
49
|
+
"""Expand a rules-engine *template string*.
|
|
50
|
+
|
|
51
|
+
Substitutes ``{Name}`` and ``{Name#path.subpath}`` references inside
|
|
52
|
+
``template``. Names resolve against ``locals_`` first (variables bound
|
|
53
|
+
by ``assign`` conditions), then against ``params`` attributes (any
|
|
54
|
+
object with attribute access — a dataclass, plain class, etc.; not a
|
|
55
|
+
dict).
|
|
56
|
+
``#path`` segments walk the resolved value via :func:`get_attr`.
|
|
57
|
+
|
|
58
|
+
Raises :class:`EndpointError` if a referenced name resolves to ``None``.
|
|
59
|
+
|
|
60
|
+
Reference:
|
|
61
|
+
https://smithy.io/2.0/additional-specs/rules-engine/specification.html#template-strings
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
def replace(match: re.Match[str]) -> str:
|
|
65
|
+
name, path = match.group(1), match.group(2)
|
|
66
|
+
|
|
67
|
+
if name in locals_:
|
|
68
|
+
value = locals_[name]
|
|
69
|
+
elif hasattr(params, name):
|
|
70
|
+
value = getattr(params, name)
|
|
71
|
+
else:
|
|
72
|
+
raise EndpointError(f"interpolate: unknown reference '{name}'")
|
|
73
|
+
|
|
74
|
+
if value is None:
|
|
75
|
+
raise EndpointError(f"interpolate: '{name}' is None")
|
|
76
|
+
|
|
77
|
+
if path:
|
|
78
|
+
value = get_attr(value, path)
|
|
79
|
+
|
|
80
|
+
if value is None:
|
|
81
|
+
raise EndpointError(f"interpolate: '{name}#{path}' is None")
|
|
82
|
+
|
|
83
|
+
if isinstance(value, bool):
|
|
84
|
+
return "true" if value else "false"
|
|
85
|
+
return str(value)
|
|
86
|
+
|
|
87
|
+
return _PLACEHOLDER.sub(replace, template)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
_SEGMENT_RE = re.compile(r"([A-Za-z_][A-Za-z0-9_]*|\[-?\d+\])")
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def get_attr(value: Mapping[str, object] | list[str], path: str) -> object:
|
|
94
|
+
"""Rules-engine ``getAttr`` — index into a value by a dotted/bracketed path.
|
|
95
|
+
|
|
96
|
+
Walks segments like ``a.b[0].c`` against dicts (key lookup), objects
|
|
97
|
+
(attribute lookup), and indexable sequences (integer index). Any missing
|
|
98
|
+
key, missing attribute, out-of-range index, or non-indexable cursor
|
|
99
|
+
short-circuits to ``None``.
|
|
100
|
+
|
|
101
|
+
Reference:
|
|
102
|
+
https://smithy.io/2.0/additional-specs/rules-engine/standard-library.html#getattr-function
|
|
103
|
+
"""
|
|
104
|
+
cursor: object = value
|
|
105
|
+
for segment in _SEGMENT_RE.findall(path):
|
|
106
|
+
if cursor is None:
|
|
107
|
+
return None
|
|
108
|
+
|
|
109
|
+
if segment.startswith("["):
|
|
110
|
+
# Array index
|
|
111
|
+
idx = int(segment[1:-1])
|
|
112
|
+
try:
|
|
113
|
+
cursor = cursor[idx] # type: ignore
|
|
114
|
+
except IndexError:
|
|
115
|
+
return None
|
|
116
|
+
except TypeError:
|
|
117
|
+
return None
|
|
118
|
+
except KeyError:
|
|
119
|
+
return None
|
|
120
|
+
else:
|
|
121
|
+
# Field access
|
|
122
|
+
if isinstance(cursor, dict):
|
|
123
|
+
cursor = cursor.get(segment)
|
|
124
|
+
else:
|
|
125
|
+
cursor = getattr(cursor, segment, None)
|
|
126
|
+
|
|
127
|
+
return cursor
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def string_equals(a: Any, b: Any) -> bool:
|
|
131
|
+
"""Rules-engine ``stringEquals`` — strict string equality.
|
|
132
|
+
|
|
133
|
+
Both operands must be Python ``str``; any non-str comparand returns
|
|
134
|
+
``False``.
|
|
135
|
+
|
|
136
|
+
Reference:
|
|
137
|
+
https://smithy.io/2.0/additional-specs/rules-engine/standard-library.html#stringequals-function
|
|
138
|
+
"""
|
|
139
|
+
return isinstance(a, str) and isinstance(b, str) and a == b
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
_HOST_LABEL = re.compile(r"^[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?$")
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def substring(value: Any, start: int, stop: int, reverse: bool) -> str | None:
|
|
146
|
+
"""Rules-engine ``substring`` — slice an ASCII string by ``[start, stop)``.
|
|
147
|
+
|
|
148
|
+
Returns ``None`` when ``value`` is not a string, contains non-ASCII
|
|
149
|
+
code points, or the ``start``/``stop`` indices are negative, equal,
|
|
150
|
+
inverted, or past the end. When ``reverse`` is true, indices count
|
|
151
|
+
from the end of the string toward the start.
|
|
152
|
+
|
|
153
|
+
Reference:
|
|
154
|
+
https://smithy.io/2.0/additional-specs/rules-engine/standard-library.html#substring-function
|
|
155
|
+
"""
|
|
156
|
+
if not isinstance(value, str):
|
|
157
|
+
return None
|
|
158
|
+
if not value.isascii():
|
|
159
|
+
return None
|
|
160
|
+
if start < 0 or stop < 0 or start >= stop:
|
|
161
|
+
return None
|
|
162
|
+
if stop > len(value):
|
|
163
|
+
return None
|
|
164
|
+
if reverse:
|
|
165
|
+
n = len(value)
|
|
166
|
+
return value[n - stop : n - start]
|
|
167
|
+
return value[start:stop]
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def is_valid_host_label(value: Any, allow_subdomains: bool) -> bool:
|
|
171
|
+
"""Rules-engine ``isValidHostLabel`` — validate an RFC 1123 host label.
|
|
172
|
+
|
|
173
|
+
A label is 1–63 chars of ``[A-Za-z0-9-]`` that does not start or end
|
|
174
|
+
with a hyphen. When ``allow_subdomains`` is true, ``value`` may be a
|
|
175
|
+
dot-separated sequence of such labels (every label must be valid).
|
|
176
|
+
|
|
177
|
+
Reference:
|
|
178
|
+
https://smithy.io/2.0/additional-specs/rules-engine/standard-library.html#isvalidhostlabel-function
|
|
179
|
+
"""
|
|
180
|
+
if not isinstance(value, str) or not value:
|
|
181
|
+
return False
|
|
182
|
+
if allow_subdomains:
|
|
183
|
+
labels = value.split(".")
|
|
184
|
+
return bool(labels) and all(_HOST_LABEL.match(label) for label in labels)
|
|
185
|
+
return _HOST_LABEL.match(value) is not None
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def uri_encode(value: str | None) -> str:
|
|
189
|
+
"""Rules-engine ``uriEncode`` — percent-encode per RFC 3986 §2.3.
|
|
190
|
+
|
|
191
|
+
Every character outside the unreserved set ``A-Z a-z 0-9 - _ . ~`` is
|
|
192
|
+
percent-encoded, including ``/``. Non-string input yields ``""``.
|
|
193
|
+
|
|
194
|
+
Reference:
|
|
195
|
+
https://smithy.io/2.0/additional-specs/rules-engine/standard-library.html#uriencode-function
|
|
196
|
+
"""
|
|
197
|
+
if value is None:
|
|
198
|
+
return ""
|
|
199
|
+
return quote(value, safe="-_.~")
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
class ParsedUrl(TypedDict):
|
|
203
|
+
scheme: str
|
|
204
|
+
authority: str
|
|
205
|
+
path: str
|
|
206
|
+
normalizedPath: str
|
|
207
|
+
isIp: bool
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def parse_url(value: str) -> ParsedUrl | None:
|
|
211
|
+
"""Rules-engine ``parseUrl`` — split an HTTP(S) URL into components.
|
|
212
|
+
|
|
213
|
+
Returns a :class:`ParsedUrl` with ``scheme``, ``authority`` (host plus
|
|
214
|
+
optional ``:port``), ``path``, ``normalizedPath`` (``path`` guaranteed
|
|
215
|
+
to end in ``/``), and ``isIp`` (true for IPv4 dotted-quad or IPv6
|
|
216
|
+
hosts). Returns ``None`` when ``value`` is not a string, the scheme is
|
|
217
|
+
not ``http``/``https``, or a query/fragment is present.
|
|
218
|
+
|
|
219
|
+
Reference:
|
|
220
|
+
https://smithy.io/2.0/additional-specs/rules-engine/standard-library.html#parseurl-function
|
|
221
|
+
"""
|
|
222
|
+
|
|
223
|
+
try:
|
|
224
|
+
parts = urlsplit(value)
|
|
225
|
+
|
|
226
|
+
if parts.scheme not in ("http", "https"):
|
|
227
|
+
return None
|
|
228
|
+
|
|
229
|
+
# Smithy parseUrl rejects query strings and fragments.
|
|
230
|
+
if parts.query or parts.fragment:
|
|
231
|
+
return None
|
|
232
|
+
|
|
233
|
+
# urlsplit preserves the raw/encoded path.
|
|
234
|
+
path = parts.path
|
|
235
|
+
|
|
236
|
+
normalized_path = path if path.endswith("/") else f"{path}/"
|
|
237
|
+
|
|
238
|
+
return {
|
|
239
|
+
"scheme": parts.scheme,
|
|
240
|
+
"authority": parts.netloc,
|
|
241
|
+
"path": path,
|
|
242
|
+
"normalizedPath": normalized_path,
|
|
243
|
+
"isIp": _looks_like_ip(parts.hostname or ""),
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
except Exception:
|
|
247
|
+
return None
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def _looks_like_ip(host: str) -> bool:
|
|
251
|
+
if not host:
|
|
252
|
+
return False
|
|
253
|
+
if ":" in host: # IPv6 (urlsplit strips brackets from hostname)
|
|
254
|
+
return True
|
|
255
|
+
parts = host.split(".")
|
|
256
|
+
return len(parts) == 4 and all(p.isdigit() for p in parts)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
class ParsedArn(TypedDict):
|
|
260
|
+
partition: str
|
|
261
|
+
service: str
|
|
262
|
+
region: str
|
|
263
|
+
accountId: str
|
|
264
|
+
resourceId: list[str]
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def aws_parse_arn(arn: Any) -> ParsedArn | None:
|
|
268
|
+
"""AWS rules-engine ``aws.parseArn`` — split an ARN into components.
|
|
269
|
+
|
|
270
|
+
An ARN has the shape ``arn:<partition>:<service>:<region>:<account>:<resource>``.
|
|
271
|
+
Returns a :class:`ParsedArn` with ``partition``, ``service``, ``region``,
|
|
272
|
+
``accountId``, and ``resourceId`` (the trailing resource section split
|
|
273
|
+
on ``:`` and ``/``). Returns ``None`` when ``arn`` is not a string, has
|
|
274
|
+
fewer than six ``:``-separated parts, does not begin with ``arn``, or
|
|
275
|
+
has empty ``partition``/``service``/resource sections. ``region`` and
|
|
276
|
+
``accountId`` may be empty (e.g. IAM ARNs have no region).
|
|
277
|
+
|
|
278
|
+
Reference:
|
|
279
|
+
https://smithy.io/2.0/aws/rules-engine/standard-library.html#aws-parsearn-function
|
|
280
|
+
"""
|
|
281
|
+
if not isinstance(arn, str):
|
|
282
|
+
return None
|
|
283
|
+
parts = arn.split(":", 5)
|
|
284
|
+
if len(parts) != 6:
|
|
285
|
+
return None
|
|
286
|
+
prefix, partition, service, region, account_id, resource = parts
|
|
287
|
+
if prefix != "arn" or not partition or not service or not resource:
|
|
288
|
+
return None
|
|
289
|
+
return {
|
|
290
|
+
"partition": partition,
|
|
291
|
+
"service": service,
|
|
292
|
+
"region": region,
|
|
293
|
+
"accountId": account_id,
|
|
294
|
+
"resourceId": re.split(r"[:/]", resource),
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
_S3_BUCKET_LABEL = re.compile(r"^[a-z0-9][a-z0-9\-]{1,61}[a-z0-9]$")
|
|
299
|
+
_IPV4 = re.compile(r"^(\d{1,3}\.){3}\d{1,3}$")
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def aws_is_virtual_hostable_s3_bucket(value: Any, allow_subdomains: Any) -> bool:
|
|
303
|
+
"""AWS rules-engine ``aws.isVirtualHostableS3Bucket`` — validate an S3
|
|
304
|
+
bucket name for virtual-hosted-style addressing.
|
|
305
|
+
|
|
306
|
+
Returns ``True`` when ``value`` is a DNS-compliant S3 bucket name
|
|
307
|
+
(3–63 chars, lowercase alphanumeric plus hyphens, no leading/trailing
|
|
308
|
+
hyphen, no IPv4-address shape). When ``allow_subdomains`` is true,
|
|
309
|
+
dotted bucket names are accepted and each dot-separated label must
|
|
310
|
+
independently satisfy the same rules.
|
|
311
|
+
|
|
312
|
+
Reference:
|
|
313
|
+
https://smithy.io/2.0/aws/rules-engine/standard-library.html#aws-isvirtualhostables3bucket-function
|
|
314
|
+
"""
|
|
315
|
+
if not isinstance(value, str):
|
|
316
|
+
return False
|
|
317
|
+
if allow_subdomains:
|
|
318
|
+
labels = value.split(".")
|
|
319
|
+
return all(aws_is_virtual_hostable_s3_bucket(label, False) for label in labels)
|
|
320
|
+
if _IPV4.match(value):
|
|
321
|
+
return False
|
|
322
|
+
return _S3_BUCKET_LABEL.match(value) is not None
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
def apply_label(url: str, placeholder: str, value: str) -> str:
|
|
326
|
+
"""Substitute ``placeholder`` in ``url`` with ``value`` — except when the
|
|
327
|
+
rule engine has already embedded ``value`` as a whole host label or path
|
|
328
|
+
segment. In that case, strip the placeholder and collapse any resulting
|
|
329
|
+
``//`` or trailing ``/`` in the path.
|
|
330
|
+
|
|
331
|
+
"Part" = host label (split on ``.``) or path segment (split on ``/``).
|
|
332
|
+
Match is case-sensitive, whole-part only. An empty ``value`` always
|
|
333
|
+
substitutes (never matches).
|
|
334
|
+
"""
|
|
335
|
+
if placeholder not in url:
|
|
336
|
+
return url
|
|
337
|
+
|
|
338
|
+
if not value:
|
|
339
|
+
return url.replace(placeholder, "")
|
|
340
|
+
|
|
341
|
+
try:
|
|
342
|
+
parsed = urlsplit(url)
|
|
343
|
+
# urlsplit.hostname lowercases the value, which would break the
|
|
344
|
+
# case-sensitive membership test below. Extract from netloc manually
|
|
345
|
+
# to preserve the original casing.
|
|
346
|
+
netloc = parsed.netloc or ""
|
|
347
|
+
host = (
|
|
348
|
+
netloc.rsplit(":", 1)[0]
|
|
349
|
+
if ":" in netloc and not netloc.startswith("[")
|
|
350
|
+
else netloc
|
|
351
|
+
)
|
|
352
|
+
path = parsed.path or ""
|
|
353
|
+
except Exception:
|
|
354
|
+
# Parse failure -> fall back to substitution (defensive).
|
|
355
|
+
return url.replace(placeholder, quote(value, safe=""))
|
|
356
|
+
|
|
357
|
+
host_labels = host.split(".") if host and not host.startswith("[") else []
|
|
358
|
+
path_segments = [seg for seg in path.split("/") if seg]
|
|
359
|
+
|
|
360
|
+
# Guard: only strip when the placeholder is in the path portion. If the
|
|
361
|
+
# placeholder appears only in a query string or fragment, a coincidental
|
|
362
|
+
# host/path match must not trigger the strip branch.
|
|
363
|
+
scheme_sep = url.find("://")
|
|
364
|
+
head_end = url.find("/", scheme_sep + 3) if scheme_sep != -1 else -1
|
|
365
|
+
path_portion = url[head_end:] if head_end != -1 else ""
|
|
366
|
+
# Strip query and fragment off the path portion for the placeholder check.
|
|
367
|
+
for sep in ("?", "#"):
|
|
368
|
+
idx = path_portion.find(sep)
|
|
369
|
+
if idx != -1:
|
|
370
|
+
path_portion = path_portion[:idx]
|
|
371
|
+
if placeholder not in path_portion:
|
|
372
|
+
return url.replace(placeholder, quote(value, safe=""))
|
|
373
|
+
|
|
374
|
+
if value in host_labels or value in path_segments:
|
|
375
|
+
# Splice the placeholder out, then collapse the one seam slash our
|
|
376
|
+
# removal may have created. Pre-existing slash duplicates in the
|
|
377
|
+
# URI template are not our concern — we only fix what we caused.
|
|
378
|
+
idx = url.find(placeholder)
|
|
379
|
+
stripped = url[:idx] + url[idx + len(placeholder) :]
|
|
380
|
+
before = stripped[idx - 1] if idx > 0 else ""
|
|
381
|
+
after = stripped[idx] if idx < len(stripped) else ""
|
|
382
|
+
if before == "/" and after == "/":
|
|
383
|
+
stripped = stripped[:idx] + stripped[idx + 1 :]
|
|
384
|
+
# Placeholder at the path's tail leaves a stray trailing ``/``.
|
|
385
|
+
if stripped.endswith("/"):
|
|
386
|
+
stripped = stripped[:-1]
|
|
387
|
+
return stripped
|
|
388
|
+
|
|
389
|
+
return url.replace(placeholder, quote(value, safe=""))
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import configparser
|
|
4
|
+
import functools
|
|
5
|
+
import os
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import TypeVar
|
|
9
|
+
|
|
10
|
+
from capo_codedeploy._services._pipeline import (
|
|
11
|
+
AsyncInterceptor,
|
|
12
|
+
AsyncNextFn,
|
|
13
|
+
AsyncOperationRequest,
|
|
14
|
+
AsyncOperationResponse,
|
|
15
|
+
Interceptor,
|
|
16
|
+
NextFn,
|
|
17
|
+
OperationRequest,
|
|
18
|
+
OperationResponse,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
ENDPOINT_ENV_VAR = "AWS_ENDPOINT_URL_CODE_DEPLOY"
|
|
22
|
+
SERVICE_ID = "code_deploy"
|
|
23
|
+
TInput = TypeVar("TInput")
|
|
24
|
+
TOutput = TypeVar("TOutput")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass(frozen=True)
|
|
28
|
+
class AwsSettings:
|
|
29
|
+
region: str | None
|
|
30
|
+
endpoint: str | None
|
|
31
|
+
use_fips: bool
|
|
32
|
+
use_dual_stack: bool
|
|
33
|
+
max_attempts: int
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _env_bool(name: str) -> bool | None:
|
|
37
|
+
val = os.environ.get(name)
|
|
38
|
+
if val is None:
|
|
39
|
+
return None
|
|
40
|
+
return val.strip().lower() in ("true", "1")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _profile_bool(section: dict[str, str], key: str) -> bool | None:
|
|
44
|
+
val = section.get(key)
|
|
45
|
+
if val is None:
|
|
46
|
+
return None
|
|
47
|
+
return val.strip().lower() in ("true", "1")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def config_file() -> Path:
|
|
51
|
+
raw_cfg = os.environ.get("AWS_CONFIG_FILE")
|
|
52
|
+
return Path(raw_cfg).expanduser() if raw_cfg else Path.home() / ".aws" / "config"
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def active_profile() -> str:
|
|
56
|
+
return (
|
|
57
|
+
os.environ.get("AWS_PROFILE")
|
|
58
|
+
or os.environ.get("AWS_DEFAULT_PROFILE")
|
|
59
|
+
or "default"
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _load_profile(
|
|
64
|
+
profile: str | None = None,
|
|
65
|
+
) -> tuple[dict[str, str], dict[str, dict[str, str]]]:
|
|
66
|
+
profile = profile or active_profile()
|
|
67
|
+
cfg_file = config_file()
|
|
68
|
+
merged: dict[str, str] = {}
|
|
69
|
+
services: dict[str, dict[str, str]] = {}
|
|
70
|
+
if cfg_file.is_file():
|
|
71
|
+
cfg = configparser.ConfigParser(interpolation=None)
|
|
72
|
+
cfg.read(cfg_file)
|
|
73
|
+
key = "default" if profile == "default" else f"profile {profile}"
|
|
74
|
+
if cfg.has_section(key):
|
|
75
|
+
merged.update(dict(cfg.items(key)))
|
|
76
|
+
services_name = merged.get("services")
|
|
77
|
+
if services_name and cfg.has_section(f"services {services_name}"):
|
|
78
|
+
raw = dict(cfg.items(f"services {services_name}"))
|
|
79
|
+
for svc, block in raw.items():
|
|
80
|
+
parsed: dict[str, str] = {}
|
|
81
|
+
for line in block.splitlines():
|
|
82
|
+
stripped = line.strip()
|
|
83
|
+
if "=" in stripped:
|
|
84
|
+
k, _, val = stripped.partition("=")
|
|
85
|
+
parsed[k.strip()] = val.strip()
|
|
86
|
+
services[svc] = parsed
|
|
87
|
+
return merged, services
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@functools.cache
|
|
91
|
+
def load_aws_settings() -> AwsSettings:
|
|
92
|
+
profile, services = _load_profile()
|
|
93
|
+
region = os.environ.get("AWS_REGION") or profile.get("region")
|
|
94
|
+
endpoint = (
|
|
95
|
+
os.environ.get(ENDPOINT_ENV_VAR)
|
|
96
|
+
or os.environ.get("AWS_ENDPOINT_URL")
|
|
97
|
+
or services.get(SERVICE_ID, {}).get("endpoint_url")
|
|
98
|
+
or profile.get("endpoint_url")
|
|
99
|
+
)
|
|
100
|
+
use_fips: bool | None = _env_bool("AWS_USE_FIPS_ENDPOINT")
|
|
101
|
+
if use_fips is None:
|
|
102
|
+
use_fips = _profile_bool(profile, "use_fips_endpoint")
|
|
103
|
+
if use_fips is None:
|
|
104
|
+
use_fips = False
|
|
105
|
+
use_dual_stack: bool | None = _env_bool("AWS_USE_DUALSTACK_ENDPOINT")
|
|
106
|
+
if use_dual_stack is None:
|
|
107
|
+
use_dual_stack = _profile_bool(profile, "use_dualstack_endpoint")
|
|
108
|
+
if use_dual_stack is None:
|
|
109
|
+
use_dual_stack = False
|
|
110
|
+
max_attempts_raw = os.environ.get("AWS_MAX_ATTEMPTS") or profile.get("max_attempts")
|
|
111
|
+
max_attempts = int(max_attempts_raw) if max_attempts_raw else 3
|
|
112
|
+
return AwsSettings(
|
|
113
|
+
region=region,
|
|
114
|
+
endpoint=endpoint,
|
|
115
|
+
use_fips=use_fips,
|
|
116
|
+
use_dual_stack=use_dual_stack,
|
|
117
|
+
max_attempts=max_attempts,
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def aws_config() -> Interceptor[TInput, TOutput]:
|
|
122
|
+
def interceptor(
|
|
123
|
+
request: OperationRequest[TInput], next: NextFn[TInput, TOutput]
|
|
124
|
+
) -> OperationResponse[TOutput]:
|
|
125
|
+
settings = load_aws_settings()
|
|
126
|
+
options = request.options
|
|
127
|
+
if options.region is None:
|
|
128
|
+
options.region = settings.region
|
|
129
|
+
if options.endpoint is None:
|
|
130
|
+
options.endpoint = settings.endpoint
|
|
131
|
+
if options.use_fips is None:
|
|
132
|
+
options.use_fips = settings.use_fips
|
|
133
|
+
if options.use_dual_stack is None:
|
|
134
|
+
options.use_dual_stack = settings.use_dual_stack
|
|
135
|
+
if options.retry_max_attempts is None:
|
|
136
|
+
options.retry_max_attempts = settings.max_attempts
|
|
137
|
+
return next(request)
|
|
138
|
+
|
|
139
|
+
return interceptor
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def aaws_config() -> AsyncInterceptor[TInput, TOutput]:
|
|
143
|
+
async def interceptor(
|
|
144
|
+
request: AsyncOperationRequest[TInput], next: AsyncNextFn[TInput, TOutput]
|
|
145
|
+
) -> AsyncOperationResponse[TOutput]:
|
|
146
|
+
settings = load_aws_settings()
|
|
147
|
+
options = request.options
|
|
148
|
+
if options.region is None:
|
|
149
|
+
options.region = settings.region
|
|
150
|
+
if options.endpoint is None:
|
|
151
|
+
options.endpoint = settings.endpoint
|
|
152
|
+
if options.use_fips is None:
|
|
153
|
+
options.use_fips = settings.use_fips
|
|
154
|
+
if options.use_dual_stack is None:
|
|
155
|
+
options.use_dual_stack = settings.use_dual_stack
|
|
156
|
+
if options.retry_max_attempts is None:
|
|
157
|
+
options.retry_max_attempts = settings.max_attempts
|
|
158
|
+
return await next(request)
|
|
159
|
+
|
|
160
|
+
return interceptor
|