syndicate/core/groups/meta.py (1,002 lines of code) (raw):

import json import os import click from syndicate.commons.log_helper import get_user_logger from syndicate.core.constants import ( S3_BUCKET_ACL_LIST, API_GW_AUTHORIZER_TYPES, CUSTOM_AUTHORIZER_KEY, EC2_LAUNCH_TEMPLATE_SUPPORTED_IMDS_VERSIONS, EC2_LT_RESOURCE_TAGS, FAILED_RETURN_CODE, OK_RETURN_CODE, ) from syndicate.core.decorators import return_code_manager from syndicate.core.generators.deployment_resources import * from syndicate.core.generators.deployment_resources.api_gateway_generator import \ ApiGatewayAuthorizerGenerator from syndicate.core.generators.deployment_resources.ec2_launch_template_generator import \ EC2LaunchTemplateGenerator from syndicate.core.generators.lambda_function import PROJECT_PATH_PARAM from syndicate.core.helper import ( OrderedGroup, OptionRequiredIf, check_tags, validate_authorizer_name_option, verbose_option, validate_api_gw_path, DictParamType, DeepDictParamType, ) from syndicate.core.helper import ValidRegionParamType from syndicate.core.helper import check_bundle_bucket_name from syndicate.core.helper import resolve_project_path, timeit GENERATE_META_GROUP_NAME = 'meta' dynamodb_type_param = click.Choice(['S', 'N', 'B']) USER_LOG = get_user_logger() @click.group(name=GENERATE_META_GROUP_NAME, cls=OrderedGroup) @return_code_manager @click.option('--project_path', nargs=1, help="Path to the project folder. Default value: the one " "from the current config if it exists. " "Otherwise - the current working directory", callback=resolve_project_path) @click.pass_context def meta(ctx, project_path): """Generates deployment resources templates""" if not os.access(project_path, os.F_OK): USER_LOG.error(f"The provided path {project_path} doesn't exist") return FAILED_RETURN_CODE elif not os.access(project_path, os.W_OK) or not os.access(project_path, os.X_OK): USER_LOG.error(f"Incorrect permissions for the provided path " f"'{project_path}'") return FAILED_RETURN_CODE ctx.ensure_object(dict) ctx.obj[PROJECT_PATH_PARAM] = project_path return OK_RETURN_CODE @meta.command(name='dax_cluster') @return_code_manager @click.option('--resource_name', required=True, type=str, help="Dax cluster name") @click.option('--node_type', required=True, type=str, help="The node type for the nodes in the cluster") @click.option('--iam_role_name', required=True, type=str, help="Role name to access DynamoDB tables") @click.option('--subnet_group_name', required=True, type=str, help='The name of the subnet group to be used for the ' 'replication group') @click.option('--subnet_ids', type=str, multiple=True, help='Subnet ids to create a subnet group from. Don\'t specify ' 'in case of using existing subnet group') @click.option('--cluster_endpoint_encryption_type', type=click.Choice(['NONE', 'TLS']), default='TLS', help='The encryption type of the cluster\'s endpoint. ' 'The default value is \'TLS\'') @click.option('--parameter_group_name', type=str, help='The parameter group to be associated with the DAX cluster') @click.option('--tags', type=DictParamType(), callback=check_tags, help='The resource tags') @verbose_option @click.pass_context @timeit() def dax_cluster(ctx, **kwargs): """Generated dax cluster deployment resource template""" kwargs[PROJECT_PATH_PARAM] = ctx.obj[PROJECT_PATH_PARAM] generator = DaxClusterGenerator(**kwargs) _generate(generator) USER_LOG.info(f'Dax cluster \'{kwargs["resource_name"]}\' was ' f'successfully generated') return OK_RETURN_CODE @meta.command(name='dynamodb') @return_code_manager @click.option('--resource_name', required=True, type=str, help="DynamoDB table name") @click.option('--hash_key_name', required=True, type=str, help="DynamoDB table hash key") @click.option('--hash_key_type', required=True, type=click.Choice(['S', 'N', 'B']), help="DynamoDB hash key type") @click.option('--sort_key_name', type=str, help="DynamoDB sort key. If not specified, the table will have " "only a hash key") @click.option('--sort_key_type', type=dynamodb_type_param, cls=OptionRequiredIf, required_if='sort_key_name', help="Required if sort key name is specified") @click.option('--read_capacity', type=int, help="The maximum number of strongly consistent reads that can" "be performed per second. If not specified, sets the " "default value to 1") @click.option('--write_capacity', type=int, help="The maximum number of writing processes consumed per" "second. If not specified, sets the default value to 1") @click.option('--tags', type=DictParamType(), callback=check_tags, help='The resource tags') @verbose_option @click.pass_context @timeit() def dynamodb(ctx, **kwargs): """Generates dynamoDB deployment resources template""" kwargs[PROJECT_PATH_PARAM] = ctx.obj[PROJECT_PATH_PARAM] generator = DynamoDBGenerator(**kwargs) _generate(generator) USER_LOG.info(f"Table '{kwargs['resource_name']}' was added successfully!") return OK_RETURN_CODE @meta.command(name='dynamodb_global_index') @return_code_manager @click.option('--table_name', required=True, type=str, help="DynamoDB table name to add index to") @click.option('--name', required=True, type=str, help="Index name") @click.option('--index_key_name', required=True, type=str, help="Index hash key") @click.option('--index_key_type', required=True, type=dynamodb_type_param, help='Hash key index type') @click.option('--index_sort_key_name', type=str, help='Index sort key') @click.option('--index_sort_key_type', type=dynamodb_type_param, cls=OptionRequiredIf, required_if='index_sort_key_name', help="Sort key type") @verbose_option @click.pass_context @timeit() def dynamodb_global_index(ctx, **kwargs): """Adds dynamodb global index to existing dynamodb table""" kwargs[PROJECT_PATH_PARAM] = ctx.obj[PROJECT_PATH_PARAM] generator = DynamoDBGlobalIndexGenerator(**kwargs) _generate(generator) USER_LOG.info(f"Global index '{kwargs['name']}' was added successfully") return OK_RETURN_CODE @meta.command(name='dynamodb_autoscaling') @return_code_manager @click.option('--table_name', type=str, required=True, help="DynamoDB table name to add autoscaling to") @click.option('--policy_name', type=str, required=True, help="Autoscaling policy name") @click.option('--min_capacity', type=click.IntRange(min=1), help="Minimum capacity level. If not specified, sets the default" " value to 1") @click.option('--max_capacity', type=click.IntRange(min=1), help="Maximum capacity level. If not specified, sets the default" " value to 10") @click.option('--target_utilization', type=click.IntRange(min=20, max=90), help="Target utilization in autoscaling. If not specified, sets " "the default value to 70 %") @click.option('--scale_in_cooldown', type=click.IntRange(min=0), help="Scaling policy value of in cooldown in seconds. Is not " "specified, sets the default value to 60") @click.option('--scale_out_cooldown', type=click.IntRange(min=0), help="Scaling policy value of out cooldown in seconds. Is not " "specified, sets the default value to 60") @click.option('--dimension', type=str, help="Autoscaling dimension. If not specified, sets the default" "the default value to 'dynamodb:table:ReadCapacityUnits'") @click.option('--role_name', type=str, help="The name of the role, which performs autoscaling. If not " "specified, sets the value to default service linked role: " "'AWSServiceRoleForApplicationAutoScaling_DynamoDBTable'") @verbose_option @click.pass_context @timeit() def dynamodb_autoscaling(ctx, **kwargs): """Adds autoscaling settings to existing dynamodb table""" kwargs[PROJECT_PATH_PARAM] = ctx.obj[PROJECT_PATH_PARAM] generator = DynamoDBAutoscalingGenerator(**kwargs) _generate(generator) USER_LOG.info(f"Autoscaling setting to table '{kwargs['table_name']}' was " f"added successfully") return OK_RETURN_CODE @meta.command(name='s3_bucket') @return_code_manager @click.option('--resource_name', required=True, type=str, help="S3 bucket name", callback=check_bundle_bucket_name) @click.option('--location', type=ValidRegionParamType(), help="The region where the bucket is created, the default value " "is the region set in syndicate config") @click.option('--acl', type=click.Choice(S3_BUCKET_ACL_LIST), help="The channel ACL to be applied to the bucket. If not " "specified, sets the default value to 'private'") @click.option('--block_public_acls', type=bool, required=False, is_eager=True, help='Specifies whether Amazon S3 should block public access ' 'control lists (ACLs) for this bucket and objects in this ' 'bucket. Default value is True') @click.option('--ignore_public_acls', type=bool, required=False, is_eager=True, help='Specifies whether Amazon S3 should ignore public ACLs for ' 'this bucket and objects in this bucket. Default value ' 'is True') @click.option('--block_public_policy', type=bool, required=False, is_eager=True, help='Specifies whether Amazon S3 should block public bucket ' 'policies for this bucket. Default value is True') @click.option('--restrict_public_buckets', type=bool, required=False, is_eager=True, help='Specifies whether Amazon S3 should restrict public bucket ' 'policies for this bucket. Default value is True') @click.option('--static_website_hosting', type=bool, required=False, help='Specifies whether the S3 bucket should be configured for ' 'static WEB site hosting. Default value is False') @click.option('--tags', type=DictParamType(), callback=check_tags, help='The resource tags') @verbose_option @click.pass_context @timeit() def s3_bucket(ctx, **kwargs): """Generates s3 bucket deployment resources template""" kwargs[PROJECT_PATH_PARAM] = ctx.obj[PROJECT_PATH_PARAM] generator = S3Generator(**kwargs) _generate(generator) USER_LOG.info(f"S3 bucket '{kwargs['resource_name']}' was " f"added successfully!") return OK_RETURN_CODE @meta.command(name='api_gateway') @return_code_manager @click.option('--resource_name', required=True, type=str, help="Api gateway name") @click.option('--deploy_stage', required=True, type=str, help="The stage to deploy the API") @click.option('--minimum_compression_size', type=click.IntRange(min=0, max=10 * 1024 * 1024), help="Compression size for api gateway. If not specified, " "compression will be disabled") @click.option('--tags', type=DictParamType(), callback=check_tags, help='The resource tags') @verbose_option @click.pass_context @timeit() def api_gateway(ctx, **kwargs): """Generates api gateway deployment resources template""" kwargs[PROJECT_PATH_PARAM] = ctx.obj[PROJECT_PATH_PARAM] generator = ApiGatewayGenerator(**kwargs) _generate(generator) USER_LOG.info(f"Api gateway '{kwargs['resource_name']}' was " f"added successfully") return OK_RETURN_CODE @meta.command(name='web_socket_api_gateway') @return_code_manager @click.option('--resource_name', required=True, type=str, help="Api gateway name") @click.option('--deploy_stage', required=True, type=str, help="The stage to deploy the API") @click.option('--tags', type=DictParamType(), callback=check_tags, help='The resource tags') @verbose_option @click.pass_context @timeit() def web_socket_api_gateway(ctx, **kwargs): """Generates web socket api gateway deployment resources template""" kwargs[PROJECT_PATH_PARAM] = ctx.obj[PROJECT_PATH_PARAM] generator = WebSocketApiGatewayGenerator(**kwargs) _generate(generator) USER_LOG.info(f"Api gateway '{kwargs['resource_name']}' was " f"added successfully") return OK_RETURN_CODE @meta.command(name='api_gateway_authorizer') @return_code_manager @click.option('--api_name', required=True, type=str, help="Api gateway name to add index to") @click.option('--name', required=True, type=str, help="Authorizer name") @click.option('--type', type=click.Choice(API_GW_AUTHORIZER_TYPES), required=True, help="Authorizer type. 'TOKEN' for a Lambda " "function using a single authorization " "token submitted in a custom header, " "'REQUEST' for a Lambda function using " "incoming request parameters, and " "'COGNITO_USER_POOLS' for using an Amazon " "Cognito user pool") @click.option('--provider_name', type=str, required=True, help="Identity provider name") @verbose_option @click.pass_context @timeit() def api_gateway_authorizer(ctx, **kwargs): """Adds authorizer to an existing api gateway""" kwargs[PROJECT_PATH_PARAM] = ctx.obj[PROJECT_PATH_PARAM] generator = ApiGatewayAuthorizerGenerator(**kwargs) _generate(generator) USER_LOG.info(f"Authorizer '{kwargs['name']}' was added to API gateway " f"'{kwargs['api_name']}' successfully") return OK_RETURN_CODE @meta.command(name='api_gateway_resource') @return_code_manager @click.option('--api_name', required=True, type=str, help="Api gateway name to add index to") @click.option('--path', required=True, callback=validate_api_gw_path, help="Resource path to create") @click.option('--enable_cors', type=bool, help="Enables CORS on the resourcemethod. If not specified, sets" "the default value to False") @verbose_option @click.pass_context @timeit() def api_gateway_resource(ctx, **kwargs): """Adds resource to existing api gateway""" kwargs[PROJECT_PATH_PARAM] = ctx.obj[PROJECT_PATH_PARAM] generator = ApiGatewayResourceGenerator(**kwargs) _generate(generator) USER_LOG.info(f"Resource '{kwargs['path']}' was added to API gateway " f"'{kwargs['api_name']}' successfully") return OK_RETURN_CODE @meta.command(name='api_gateway_resource_method') @return_code_manager @click.option('--api_name', required=True, type=str, help="Api gateway name to add index to") @click.option('--path', required=True, callback=validate_api_gw_path, help="Resource path to create") @click.option('--method', required=True, type=click.Choice(['POST', 'GET', 'DELETE', 'PUT', 'HEAD', 'PATCH', 'ANY']), help="Resource method to add") @click.option('--integration_type', type=str, help="The resource which the method is connected to: " "[lambda|service|http|mock]. If not specified, sets the " "default value to 'mock'") @click.option('--lambda_name', type=str, help="Lambda name. Required if " "integration type is lambda") @click.option('--lambda_region', type=ValidRegionParamType(), help="The region where the lambda is located. If not specified, " "sets the default value from syndicate config") @click.option('--authorization_type', is_eager=True, type=click.Choice(["NONE", "AWS_IAM", CUSTOM_AUTHORIZER_KEY]), help="The method's authorization type. If not specified, sets " "the default value to 'NONE'") @click.option('--authorizer_name', type=str, callback=validate_authorizer_name_option, help="The method's authorizer name can be used only with " "'--authorization_type' 'CUSTOM'") @click.option('--api_key_required', type=bool, help="Specifies whether the method requires a valid API key. " "If not specified, the default value is set to False") @verbose_option @click.pass_context @timeit() def api_gateway_resource_method(ctx, **kwargs): """Adds a method to existing api gateway resource""" if kwargs.get('integration_type') == 'lambda' \ and not kwargs.get('lambda_name'): raise click.MissingParameter( "Lambda name is required if the integration type is 'lambda'", param_type='option', param_hint='lambda_name') kwargs[PROJECT_PATH_PARAM] = ctx.obj[PROJECT_PATH_PARAM] generator = ApiGatewayResourceMethodGenerator(**kwargs) _generate(generator) USER_LOG.info(f"Method '{kwargs['method']}' was added to API gateway " f"resource '{kwargs['path']}' successfully") return OK_RETURN_CODE @meta.command(name='iam_policy') @return_code_manager @click.option('--resource_name', required=True, type=str, help='IAM policy name') @click.option('--policy_content', help='The path to JSON file with IAM policy ' 'content. If not specified, template ' 'value will be set', type=click.File(mode='r')) @click.option('--tags', type=DictParamType(), callback=check_tags, help='The resource tags') @verbose_option @click.pass_context @timeit() def iam_policy(ctx, **kwargs): """Generates IAM policy deployment resources template""" kwargs[PROJECT_PATH_PARAM] = ctx.obj[PROJECT_PATH_PARAM] if kwargs['policy_content']: try: kwargs['policy_content'] = json.load(kwargs['policy_content']) except json.decoder.JSONDecodeError as e: raise click.BadParameter(str(e), param_hint='policy_content') generator = IAMPolicyGenerator(**kwargs) _generate(generator) USER_LOG.info(f"Iam policy '{kwargs['resource_name']}' was " f"added successfully") return OK_RETURN_CODE @meta.command(name='iam_role') @return_code_manager @click.option('--resource_name', required=True, type=str, help="IAM role name") @click.option('--principal_service', required=True, type=str, help="The service which will use the role") @click.option("--predefined_policies", type=str, multiple=True, help="Managed IAM policies list") @click.option("--custom_policies", type=str, multiple=True, help="Customer AWS policies names") @click.option("--allowed_accounts", type=str, multiple=True, help="The list of accounts, which can assume the role") @click.option("--external_id", type=str, help="External ID in role") @click.option("--instance_profile", type=bool, help="If true, instance profile with role name is created") @click.option('--permissions_boundary', type=str, help="The name or the ARN of permissions boundary policy to " "attach to this role") @click.option('--tags', type=DictParamType(), callback=check_tags, help='The resource tags') @verbose_option @click.pass_context @timeit() def iam_role(ctx, **kwargs): """Generates IAM role deployment resources template""" kwargs[PROJECT_PATH_PARAM] = ctx.obj[PROJECT_PATH_PARAM] generator = IAMRoleGenerator(**kwargs) _generate(generator) USER_LOG.info(f"Iam role '{kwargs['resource_name']}' was " f"added successfully") return OK_RETURN_CODE @meta.command(name='kinesis_stream') @return_code_manager @click.option('--resource_name', type=str, required=True, help="Kinesis stream name") @click.option('--shard_count', type=int, required=True, help="Number of shards that the stream uses") @click.option('--tags', type=DictParamType(), callback=check_tags, help='The resource tags') @verbose_option @click.pass_context @timeit() def kinesis_stream(ctx, **kwargs): """Generates kinesis stream deployment resources template""" kwargs[PROJECT_PATH_PARAM] = ctx.obj[PROJECT_PATH_PARAM] generator = KinesisStreamGenerator(**kwargs) _generate(generator) USER_LOG.info(f"Kinesis stream '{kwargs['resource_name']}' was " f"added successfully") return OK_RETURN_CODE @meta.command(name='sns_topic') @return_code_manager @click.option('--resource_name', type=str, required=True, help="SNS topic name") @click.option('--region', type=ValidRegionParamType(allowed_all=True), required=True, help="Where the topic should be deployed") @click.option('--tags', type=DictParamType(), callback=check_tags, help='The resource tags') @verbose_option @click.pass_context @timeit() def sns_topic(ctx, **kwargs): """Generates sns topic deployment resource template""" kwargs[PROJECT_PATH_PARAM] = ctx.obj[PROJECT_PATH_PARAM] generator = SNSTopicGenerator(**kwargs) _generate(generator) USER_LOG.info(f"SNS topic '{kwargs['resource_name']}' was " f"added successfully") return OK_RETURN_CODE @meta.command(name='step_function') @return_code_manager @click.option('--resource_name', type=str, required=True, help="Step function name") @click.option('--iam_role', type=str, required=True, help="IAM role to use for this state machine") @click.option('--tags', type=DictParamType(), callback=check_tags, help='The resource tags') @verbose_option @click.pass_context @timeit() def step_function(ctx, **kwargs): """Generate step function deployment resource template""" kwargs[PROJECT_PATH_PARAM] = ctx.obj[PROJECT_PATH_PARAM] generator = StepFunctionGenerator(**kwargs) _generate(generator) USER_LOG.info(f"Step function '{kwargs['resource_name']}' was " f"added successfully") return OK_RETURN_CODE @meta.command(name='step_function_activity') @return_code_manager @click.option('--resource_name', type=str, required=True, help="Step function activity name") @click.option('--tags', type=DictParamType(), callback=check_tags, help='The resource tags') @verbose_option @click.pass_context @timeit() def step_function_activity(ctx, **kwargs): """Generates step function activity deployment resource template""" kwargs[PROJECT_PATH_PARAM] = ctx.obj[PROJECT_PATH_PARAM] generator = StepFunctionActivityGenerator(**kwargs) _generate(generator) USER_LOG.info(f"Step function activity '{kwargs['resource_name']}' was " f"added successfully") return OK_RETURN_CODE @meta.command(name='ec2_instance') @return_code_manager @click.option('--resource_name', type=str, required=True, help="Instance name") @click.option('--key_name', type=str, required=True, help="SHH key to access the instance") @click.option('--image_id', type=str, required=True, help="Image id to create the instance from") @click.option('--instance_type', type=str, help="Instance type") @click.option('--disable_api_termination', type=bool, help="Api termination protection. Default value is True") @click.option('--security_group_ids', type=str, multiple=True, help="Security group ids") @click.option('--security_group_names', type=str, multiple=True, help="Security group names") @click.option('--availability_zone', type=str, help="Instance availability zone") @click.option('--subnet_id', type=str, cls=OptionRequiredIf, required_if="availability_zone", help="Subnet ID (required if availability zone is set)") @click.option('--userdata_file', type=str, help="File path to userdata (file relative pathname from the" "directory which is set up in the env variable 'SDCT_CONF'") @click.option('--iam_role', type=str, help="Instance IAM role") @click.option('--tags', type=DictParamType(), callback=check_tags, help='The resource tags') @verbose_option @click.pass_context @timeit() def ec2_instance(ctx, **kwargs): """Generates ec2 instance deployment resource template""" kwargs[PROJECT_PATH_PARAM] = ctx.obj[PROJECT_PATH_PARAM] generator = EC2InstanceGenerator(**kwargs) _generate(generator) USER_LOG.info(f"EC2 instance '{kwargs['resource_name']}' was added" f"successfully") return OK_RETURN_CODE @meta.command(name='ec2_launch_template') @return_code_manager @click.option('--resource_name', type=str, required=True, help="Launch template name") @click.option('--image_id', type=str, required=True, help="The ID of the AMI") @click.option('--key_name', type=str, help="The name of the key pair") @click.option('--instance_type', type=str, help="Instance type") @click.option('--security_group_ids', type=str, multiple=True, help="Security group ids") @click.option('--security_group_names', type=str, multiple=True, help="Security group names") @click.option('--userdata_file', type=str, help="File path to userdata (can be specified as a relative " "path to the project path)") @click.option('--iam_role', type=str, help="Instance IAM role") @click.option('--imds_version', type=click.Choice(EC2_LAUNCH_TEMPLATE_SUPPORTED_IMDS_VERSIONS), help="IMDS version") @click.option('--version_description', type=str, help="A description for the version of the launch template") @click.option('--tags', type=DictParamType(), callback=check_tags, help='The ec2 launch template tags') @click.option('--resource_tags', type=DeepDictParamType(), multiple=True, help=f'The resource tags. You can specify tags for the following ' f'{EC2_LT_RESOURCE_TAGS}. To tag a resource after it has ' f'been created') @verbose_option @click.pass_context @timeit() def ec2_launch_template(ctx, **kwargs): """Generates ec2_launch_template deployment resource template""" kwargs[PROJECT_PATH_PARAM] = ctx.obj[PROJECT_PATH_PARAM] if kwargs["resource_tags"]: kwargs["resource_tags"] = \ {k: v for d in kwargs["resource_tags"] for k, v in d.items()} valid_keys = set(EC2_LT_RESOURCE_TAGS) provided_keys = set(kwargs['resource_tags'].keys()) # Check if provided keys are all valid if not provided_keys <= valid_keys: invalid_keys = provided_keys - valid_keys raise ValueError( f"Invalid resource tag keys provided: {invalid_keys}. " f"Allowed keys are: {valid_keys}" ) generator = EC2LaunchTemplateGenerator(**kwargs) _generate(generator) USER_LOG.info(f"ec2_launch_template '{kwargs['resource_name']}' was added " f"successfully") return OK_RETURN_CODE @meta.command(name='sqs_queue') @return_code_manager @click.option('--resource_name', type=str, required=True, help="SQS queue name") @click.option('--region', type=ValidRegionParamType(), help="The region where the queue is deployed. Default value is " "the one from syndicate config") @click.option('--fifo_queue', type=bool, help="If True, the queue is FIFO. Default value is False") @click.option('--visibility_timeout', type=click.IntRange(min=0, max=43200), help="The visibility timeout for the queue. Default value is 30") @click.option('--delay_seconds', type=click.IntRange(min=0, max=900), help="The length of time in seconds for which the delivery " "of all the messages in the queue is delayed. Default " "value is 0") @click.option('--maximum_message_size', type=click.IntRange(min=1024, max=262144), help="The limit of how many bytes a message can contain before " "Amazon SQS rejects it. Default value is 1024") @click.option('--message_retention_period', type=click.IntRange(min=60, max=1209600), help="The length of time in seconds for which Amazon SQS " "retains a message. Default value is 60") @click.option('--receive_message_wait_time_seconds', type=click.IntRange(min=0, max=20), help="The length of time in seconds for which a 'ReceiveMessage'" " action waits for a message to arrive") @click.option('--dead_letter_target_arn', type=str, help="Arn of a dead-letter queue Amazon SQS moves messages " "after the value of maxReceiveCount is exceeded") @click.option('--max_receive_count', type=click.IntRange(min=1, max=1000), help="The number of times a message is delivered to the source " "queue before being moved to the dead-letter queue. " "Required if 'dead_letter_target_arn' is specified", cls=OptionRequiredIf, required_if='dead_letter_target_arn') @click.option('--kms_master_key_id', type=str, help="The id of an AWS-managed customer master key (CMK) for " "Amazon SQS or a custom CMK") @click.option('--kms_data_key_reuse_period_seconds', type=click.IntRange(min=60, max=86400), help="The length of time in seconds for which Amazon SQS can " "reuse a data key to encrypt or decrypt messages before " "calling AWS KMS again") @click.option('--content_based_deduplication', type=bool, help="Enables content-based deduplication") @click.option('--tags', type=DictParamType(), callback=check_tags, help='The resource tags') @verbose_option @click.pass_context @timeit() def sqs_queue(ctx, **kwargs): """Generates sqs queue deployment deployment resource template""" kwargs[PROJECT_PATH_PARAM] = ctx.obj[PROJECT_PATH_PARAM] generator = SQSQueueGenerator(**kwargs) _generate(generator) USER_LOG.info(f"SQS queue '{kwargs['resource_name']}' was added " f"successfully") return OK_RETURN_CODE @meta.command(name="sns_application") @return_code_manager @click.option('--resource_name', type=str, required=True, help="The name of the sns application") @click.option('--platform', required=True, type=click.Choice(['GCM', 'ADM', 'APNS', 'APNS_SANDBOX']), help="SNS application platform") @click.option('--region', type=ValidRegionParamType(), help="The region where the application is deployed. Default " "value is the one from syndicate config") @click.option('--attributes', type=(str, str), multiple=True, help="SNS application attributes") @verbose_option @click.pass_context @timeit() def sns_application(ctx, **kwargs): """Generates sns application deployment resources template""" kwargs[PROJECT_PATH_PARAM] = ctx.obj[PROJECT_PATH_PARAM] generator = SNSApplicationGenerator(**kwargs) _generate(generator) USER_LOG.info(f"SNS application '{kwargs['resource_name']}' was added " f"successfully") return OK_RETURN_CODE @meta.command(name="cognito_user_pool") @return_code_manager @click.option('--resource_name', type=str, required=True, help="Cognito user pool name") # @click.option('--region', type=ValidRegionParamType(), required=True, # help="The region where the user pool is created") @click.option('--auto_verified_attributes', type=click.Choice(['phone_number', 'email']), help="The attributes to be auto-verified. " "Default value is email", multiple=True) @click.option('--sns_caller_arn', type=str, help="The arn of the IAM role in your account which Cognito " "will use to send SMS messages. Required if 'phone_number' " "in 'auto_verified_attributes' is specified") @click.option('--username_attributes', type=click.Choice(['phone_number', 'email']), help="Specifies whether email addresses or phone numbers can " "be specified as usernames when a user signs up. Default " "value is email", multiple=True) @click.option('--custom_attributes', type=(str, str), multiple=True, help="A list of custom attributes: (name type)") @click.option('--tags', type=DictParamType(), callback=check_tags, help='The resource tags') @verbose_option @click.pass_context @timeit() def cognito_user_pool(ctx, **kwargs): """Generates cognito user pool deployment resource template""" if 'phone_number' in kwargs['auto_verified_attributes'] \ and not kwargs.get('sns_caller_arn'): raise click.MissingParameter("Sns caller IAM role arn is required when" " 'phone_number' is specified in " "'auto_verified_attributes'", param_type='option', param_hint='sns_caller_arn') kwargs[PROJECT_PATH_PARAM] = ctx.obj[PROJECT_PATH_PARAM] generator = CognitoUserPoolGenerator(**kwargs) _generate(generator) USER_LOG.info(f"Cognito user pool '{kwargs['resource_name']}' was added " f"successfully") return OK_RETURN_CODE @meta.command(name="cognito_federated_pool") @return_code_manager @click.option('--resource_name', type=str, required=True, help="Cognito federated pool name") @click.option('--auth_role', type=str, help="IAM role for authorized users") @click.option('--unauth_role', type=str, help="IAM role for unauthorized users") @click.option('--open_id_providers', type=str, multiple=True, help="A list of OpenID Connect providers") @click.option('--provider_name', type=str, help="Developer provider name") @click.option('--tags', type=DictParamType(), callback=check_tags, help='The resource tags') @verbose_option @click.pass_context @timeit() def cognito_federated_pool(ctx, **kwargs): """Generates cognito federated pool deployment resource template""" kwargs[PROJECT_PATH_PARAM] = ctx.obj[PROJECT_PATH_PARAM] generator = CognitoFederatedPoolGenerator(**kwargs) _generate(generator) USER_LOG.info(f"Cognito federated pool '{kwargs['resource_name']}' was " f"added successfully") return OK_RETURN_CODE @meta.command(name='batch_compenv') @return_code_manager @click.option('--resource_name', type=str, required=True, help="Batch compute environment name") @click.option('--compute_environment_type', type=click.Choice(['MANAGED', 'UNMANAGED']), help="The type of compute environment. " "Default value is 'MANAGED'") @click.option('--allocation_strategy', type=click.Choice(['BEST_FIT', 'BEST_FIT_PROGRESSIVE', 'SPOT_CAPACITY_OPTIMIZED']), help="The allocation strategy to use for the compute resource " "if not enough instances of the best fitting instance type " "can be allocated") @click.option('--state', type=click.Choice(['ENABLED', 'DISABLED']), help="The state of compute environment") @click.option('--service_role', type=str, help="The full Amazon Resource Name (ARN) of the IAM role that " "allows Batch to make calls to other Amazon Web Services " "services on your behalf. If not specified, role " "'AWSBatchServiceRole' will be taken if it exists, if " "doesn't it'll be created") @click.option('--type', type=click.Choice(['EC2', 'SPOT', 'FARGATE', 'FARGATE_SPOT']), help="The type of compute environment. Default value is EC2") @click.option('--minv_cpus', type=click.IntRange(min=0), help='The minimum number of Amazon EC2 vCPUs that an ' 'environment should maintain. Default value is 0') @click.option('--maxv_cpus', type=click.IntRange(min=1), help="The maximum number of Amazon EC2 vCPUs that a compute " "environment can reach. Default value is 8") @click.option('--desiredv_cpus', type=int, help="The desired number of Amazon EC2 vCPUS in the compute " "environment. Default value is 1") @click.option('--instance_types', type=str, multiple=True, help="The instances types that can be launched. Default value " "is 'optimal'") @click.option('--security_group_ids', type=str, multiple=True, required=True, help="The Amazon EC2 security groups associated with instances " "launched in the compute environment") @click.option('--subnets', type=str, multiple=True, required=True, help="The VPC subnets where the compute resources are launched") @click.option('--instance_role', type=str, help="The Amazon ECS instance profile applied to Amazon EC2 " "instances in a compute environment") @click.option('--tags', type=DictParamType(), callback=check_tags, help='The resource tags') @verbose_option @click.pass_context @timeit() def batch_compenv(ctx, **kwargs): """Generates batch compenv deployment resources template""" if kwargs.get('type') != 'FARGATE': if not kwargs.get('instance_role'): raise click.MissingParameter("'instance_role' is required if " "batch compenv type ISN'T 'FARGATE'", param_type='option', param_hint='instance_role') kwargs[PROJECT_PATH_PARAM] = ctx.obj[PROJECT_PATH_PARAM] generator = BatchCompenvGenerator(**kwargs) _generate(generator) USER_LOG.info(f"Batch compute environment '{kwargs['resource_name']}' was " f"added successfully") return OK_RETURN_CODE @meta.command(name='batch_jobdef') @return_code_manager @click.option('--resource_name', type=str, required=True, help='Batch job definition name') @click.option('--job_definition_type', required=True, type=click.Choice(['container', 'multinode']), help='The type of job definition') @click.option('--image', type=str, help='The image used to start a container. ' 'Default value is \'alpine\'') @click.option('--job_role_arn', type=str, help='The ARN of the IAM role that the container can assume for ' 'AWS permissions') @click.option('--tags', type=DictParamType(), callback=check_tags, help='The resource tags') @verbose_option @click.pass_context @timeit() def batch_jobdef(ctx, **kwargs): """Generates batch job definition deployment resources template""" kwargs[PROJECT_PATH_PARAM] = ctx.obj[PROJECT_PATH_PARAM] generator = BatchJobdefGenerator(**kwargs) _generate(generator) USER_LOG.info(f'Batch job definition \'{kwargs["resource_name"]}\' was ' f'added successfully') return OK_RETURN_CODE @meta.command(name="batch_jobqueue") @return_code_manager @click.option('--resource_name', type=str, required=True, help="Batch job queue name") @click.option('--state', type=click.Choice(["ENABLED", "DISABLED"]), help="The state of the job queue. Default value is 'ENABLED'") @click.option('--priority', type=int, help="The priority of the job queue. " "Default value is 1") @click.option('--compute_environment_order', type=(int, str), multiple=True, help="The set of compute environments mapped to a job queue and " "their order relative to each other. (order, compute_env)") @click.option('--tags', type=DictParamType(), callback=check_tags, help='The resource tags') @verbose_option @click.pass_context @timeit() def batch_jobqueue(ctx, **kwargs): """Generates batch job queue deployment resources template""" kwargs[PROJECT_PATH_PARAM] = ctx.obj[PROJECT_PATH_PARAM] generator = BatchJobqueueGenerator(**kwargs) _generate(generator) USER_LOG.info(f"Batch job queue '{kwargs['resource_name']}' was " f"added successfully") return OK_RETURN_CODE @meta.command(name="cloudwatch_alarm") @return_code_manager @click.option('--resource_name', type=str, required=True, help="Cloudwatch alarm name") @click.option('--metric_name', type=str, required=True, help="The metric's name") @click.option('--namespace', type=str, required=True, help="The namespace for the metric associated with the alarm") @click.option('--description', type=str, help="The description for the alarm") @click.option('--period', type=click.IntRange(min=1), help="The period in seconds over which the specified statistic " "is applied. Valid values are 10, 30 and any multiple" " of 60. Default value is 1200") @click.option('--evaluation_periods', type=click.IntRange(min=1), help="The number of periods over which data is compared to the " "specified threshold. Default value is 1") @click.option('--threshold', type=float, help="The value to compare with the specified statistic. " "Default value is 1.0") @click.option('--comparison_operator', type=click.Choice(['GreaterThanOrEqualToThreshold', 'GreaterThanThreshold', 'LessThanThreshold', 'LessThanOrEqualToThreshold', 'LessThanLowerOrGreaterThanUpperThreshold', 'LessThanLowerThreshold', 'GreaterThanUpperThreshold']), help="An arithmetic operator to use when comparing the specified" " statistic and threshold. The specified statistic value is" " used as the first operand. Default value is " "'GreaterThanOrEqualToThreshold'") @click.option('--statistic', type=click.Choice(["SampleCount", "Average", 'Sum', 'Minimum', 'Maximum']), help="The statistic for the metric associated with the alarm," "other than percentile. For percentile statistic use " "'ExtendedStatistic'. Default value is 'SampleCount'") @click.option('--sns_topics', type=str, multiple=True, help="The sns topics to execute when the alarm goes to an ALARM " "state from any other state") @click.option('--lambdas', type=str, multiple=True, help="The lambdas to execute when the alarm goes to an ALARM " "state from any other state. Use `:` after lambda name to " "specify alias or version") @click.option('--ssm_response_plan', type=str, multiple=True, help="The response plan name to execute when the alarm goes to " "an ALARM state from any other state") @click.option('--evaluate_low_sample_count_percentile', type=click.Choice(["evaluate", "ignore"]), help="Only for percentiles-based alarms. Use 'ignore' and the " "alarm state remains unchanged during periods with " "insufficient data points for statistical significance. If " "'evaluate' is specified (or parameter is omitted), the " "alarm is always assessed and " "may change state regardless of data point availability") @click.option('--datapoints', type=click.IntRange(min=1), help="The number of datapoints that must be breaching to " "trigger the alarm") @click.option('--tags', type=DictParamType(), callback=check_tags, help='The resource tags') @verbose_option @click.pass_context @timeit() def cloudwatch_alarm(ctx, **kwargs): """Generates Cloudwatch alarm deployment resources template""" kwargs[PROJECT_PATH_PARAM] = ctx.obj[PROJECT_PATH_PARAM] generator = CloudWatchAlarmGenerator(**kwargs) _generate(generator) USER_LOG.info(f"Cloudwatch alarm '{kwargs['resource_name']}' was " f"added successfully") return OK_RETURN_CODE @meta.command(name="cloudwatch_event_rule") @return_code_manager @click.option('--resource_name', type=str, required=True, help="Cloudwatch event rule name") @click.option('--rule_type', required=True, help="Cloudwatch event rule type", type=click.Choice(['schedule', 'ec2', 'api_call'])) @click.option('--expression', type=str, help="Rule expression (cron schedule). Valuable only if " "rule_type is 'schedule'") @click.option('--aws_service', type=str, help="The name of AWS service which the rule listens to. " "Required only if rule_type is 'api_call'") @click.option('--region', type=ValidRegionParamType(allowed_all=True), help="The region where the rule is deployed. Default value is " "the one from syndicate config") @click.option('--tags', type=DictParamType(), callback=check_tags, help='The resource tags') @verbose_option @click.pass_context @timeit() def cloudwatch_event_rule(ctx, **kwargs): """Generates Cloudwatch event rule deployment resources template""" kwargs[PROJECT_PATH_PARAM] = ctx.obj[PROJECT_PATH_PARAM] generator = CloudwatchEventRuleGenerator(**kwargs) _generate(generator) USER_LOG.info(f"Cloudwatch event rule '{kwargs['resource_name']}' was " f"added successfully") return OK_RETURN_CODE @meta.command(name="eventbridge_rule") @return_code_manager @click.option('--resource_name', type=str, required=True, help="EventBridge rule name") @click.option('--rule_type', required=True, help="EventBridge rule type", type=click.Choice(['schedule', 'ec2', 'api_call'])) @click.option('--expression', type=str, help="Rule expression (cron schedule). Valuable only if " "rule_type is 'schedule'") @click.option('--aws_service', type=str, help="The name of AWS service which the rule listens to. " "Required only if rule_type is 'api_call'") @click.option('--region', type=ValidRegionParamType(allowed_all=True), help="The region where the rule is deployed. Default value is " "the one from syndicate config") @click.option('--tags', type=DictParamType(), callback=check_tags, help='The resource tags') @verbose_option @click.pass_context @timeit() def eventbridge_rule(ctx, **kwargs): """Generates EventBridge rule deployment resources-template claiming compatibility with Cloudwatch event rule generator""" kwargs[PROJECT_PATH_PARAM] = ctx.obj[PROJECT_PATH_PARAM] generator = EventBridgeRuleGenerator(**kwargs) _generate(generator) USER_LOG.info(f"EventBridge rule '{kwargs['resource_name']}' was " f"added successfully") return OK_RETURN_CODE @meta.command(name="documentdb_cluster") @return_code_manager @click.option('--resource_name', type=str, required=True, help="DocumentDB cluster name") @click.option('--master_username', type=str, required=True, help="DocumentDB login ID for the master user") @click.option('--master_password', type=str, required=True, help="The password for master user") @click.option('--port', type=int, help="The port number on which the instances in the cluster " "accept connections. Default value is 27017") @click.option('--vpc_security_group_ids', type=str, multiple=True, help="A list of EC2 VPC security groups to associate with this " "cluster. Is not specified, default security group is used") @click.option('--availability_zones', type=str, multiple=True, help="A list of Amazon EC2 Availability Zones that instances in " "the cluster can be created in. " "If not specified default is used") @click.option('--tags', type=DictParamType(), callback=check_tags, help='The resource tags') @verbose_option @click.pass_context @timeit() def documentdb_cluster(ctx, **kwargs): """Generates documentdb cluster deployment resources template""" kwargs[PROJECT_PATH_PARAM] = ctx.obj[PROJECT_PATH_PARAM] generator = DocumentDBClusterGenerator(**kwargs) _generate(generator) USER_LOG.info(f"DocumentDB cluster '{kwargs['resource_name']}' was " f"added successfully") return OK_RETURN_CODE @meta.command(name="documentdb_instance") @return_code_manager @click.option('--resource_name', type=str, required=True, help="DocumentDB instance name") @click.option('--cluster_identifier', type=str, required=True, help="The identifier of the cluster that the instance will " "belong to") @click.option('--instance_class', type=str, help="The compute and memory capacity of the instance. Default " "value is 'db.r5.large'") @click.option('--availability_zone', type=str, help="The Amazon EC2 Availability Zone that the instance is " "created in. If not specified a random zone it the " "endpoint's region is set") @click.option('--tags', type=DictParamType(), callback=check_tags, help='The resource tags') @verbose_option @click.pass_context @timeit() def documentdb_instance(ctx, **kwargs): """Generates documentdb instance deployment resources template""" kwargs[PROJECT_PATH_PARAM] = ctx.obj[PROJECT_PATH_PARAM] generator = DocumentDBInstanceGenerator(**kwargs) _generate(generator) USER_LOG.info(f"DocumentDB instance '{kwargs['resource_name']}' was " f"added successfully") return OK_RETURN_CODE def _generate(generator: BaseConfigurationGenerator): """Just some common actions for this module are gathered in here""" try: generator.write() except ValueError as e: raise click.BadParameter(e) except RuntimeError as e: raise click.Abort(e) except Exception as e: raise Exception(f"An unexpected error occurred: {e}")