From 0296abf91710767978a47f0554ce00c50c6fc22a Mon Sep 17 00:00:00 2001 From: Ryan Jung Date: Mon, 3 Feb 2025 10:51:00 -0700 Subject: [PATCH 1/5] Minor changelog edit --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1d3cfd..9199490 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,7 +55,7 @@ - Overhauled documentation. - Only docstrings have changed with this version. - - No actual code changes have been altered. + - No actual code changes have been made. ## v0.0.2 From 96fc87da33edb8b569976295d73eb5e36197b17a Mon Sep 17 00:00:00 2001 From: Ryan Jung Date: Mon, 10 Feb 2025 16:30:58 -0700 Subject: [PATCH 2/5] Deprecate outputs; document resources --- docs/getting-started.rst | 13 +++++++++++-- tb_pulumi/__init__.py | 24 +++++++++++++++++------- tb_pulumi/ci.py | 18 +++++++++++++++++- 3 files changed, 45 insertions(+), 10 deletions(-) diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 297a874..707ac92 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -239,11 +239,20 @@ So you want to develop a new pattern to stamp out? Here's what you'll need to do tracked in the project (and other things). * Any resources you create must have the ``parent=self`` ``pulumi.ResourceOption`` set. Set an appropriate ``depends_on`` value. - * At the end of the ``__init__`` function, you must call ``self.finish()``, passing in a dictionary of ``outputs`` - and one of ``resources`` (see :py:meth:`tb_pulumi.ThunderbirdComponentResource.finish`). For + * At the end of the ``__init__`` function, you must call ``self.finish()``, passing in a dictionary of ``resources`` + (see :py:meth:`tb_pulumi.ThunderbirdComponentResource.finish`). For :py:class:`tb_pulumi.monitoring.MonitoringGroup` derivatives, call this at the end of the :py:meth:`tb_pulumi.monitoring.MonitoringGroup.monitor` function instead. +The ``finish`` function also supports an ``outputs`` option, a dict containing outputs to register with Pulumi using +their ``register_outputs`` function. However, +`Pulumi's documentation `_` +is unclear on the purpose of this, you cannot access these outputs programmatically, and the +`Pulumi developers also don't know `_ why you +should call it. Its only purpose is within the CLI tool, as simple output at the end of the run. As such, we will stop +allowing this in a future version, opting to make the ``register_outputs`` call with an empty dict, as is common among +Pulumi developers. + Troubleshooting --------------- diff --git a/tb_pulumi/__init__.py b/tb_pulumi/__init__.py index 95fe9ea..c396174 100644 --- a/tb_pulumi/__init__.py +++ b/tb_pulumi/__init__.py @@ -17,6 +17,9 @@ #: Type alias representing valid types to be found among a ThunderbirdPulumiProject's resources type Flattenable = dict | list | ThunderbirdComponentResource | pulumi.Output | pulumi.Resource +FINISH_OUTPUTS_DEPRECATION_MESSAGE = """Calling ThunderbirdComponentResource.finish with the "outputs" parameter is DEPRECATED. This parameter will be + removed in a future version.""" + class ThunderbirdPulumiProject: """A collection of related Pulumi resources upon which we can take bulk/collective actions. This class enforces some @@ -153,18 +156,25 @@ def __init__( self.resources: dict = {} #: Resources which are members of this ComponentResource. - def finish(self, outputs: dict[str, Any], resources: dict[str, pulumi.Resource | list[pulumi.Resource]]): - """Registers the provided ``outputs`` as Pulumi outputs for the module. Also stores the mapping of ``resources`` - internally as the ``resources`` member where they can be acted on collectively by a - ``ThunderbirdPulumiProject``. Any implementation of this class should call this function at the end of its - ``__init__`` function to ensure its state is properly represented. + def finish(self, outputs: dict[str, Any] = {}, resources: dict[str, Flattenable] = {}): + """Stores the mapping of ``resources`` internally as the ``resources`` member of this component resource's + ``ThunderbirdPulumiProject``, where they can be acted on collectively. Any implementation of this class should + call this function at the end of its ``__init__`` function to ensure its state is properly represented. + + Values in ``resources`` should be of a type compatible with the :py:data:`Flattenable` custom type. + + :param outputs: Dict of outputs to register with Pulumi's ``register_outputs`` function. This parameter is + deprecated and will be removed in a future version. Defaults to {}. + :type outputs: dict[str, Any], optional - Values in ``resources`` should be either a Resource or derivative (such as a ThunderbirdComponentResource). - Alternatively, supply a list or dict of such. + :param resources: Dict of Pulumi resources this component reosurce contains. Defaults to {}. + :type resources: dict[str, Flattenable], optional """ # Register resources internally; register outputs with Pulumi self.resources = resources + if len(outputs) > 0: + pulumi.warn(FINISH_OUTPUTS_DEPRECATION_MESSAGE) self.register_outputs(outputs) # Register resources within the project if not excluded diff --git a/tb_pulumi/ci.py b/tb_pulumi/ci.py index 7c41f97..9d796c8 100644 --- a/tb_pulumi/ci.py +++ b/tb_pulumi/ci.py @@ -14,6 +14,22 @@ class AwsAutomationUser(tb_pulumi.ThunderbirdComponentResource): Because CI processes affect resources built across multiple environments (which can also be interpreted as multiple Pulumi stacks), these items are only created in a single stack. + Produces the following ``resources``: + + - *user* - `aws.iam.User `_ to run CI operations. + - *access_key* - `aws.iam.AccessKey `_ for + that user's authentication. + - *secret* - :py:class:`tb_pulumi.secrets.SecretsManagerSecret` where the access key data is stored. + - *ecr_image_push_policy* - `aws.iam.Policy `_ + defining permissions required to push container images to an ECR repository. + - *s3_upload_policy* - `aws.iam.Policy `_ + defining permissions required to upload files to S3 buckets. + - *s3_full_access_policy* - `aws.iam.Policy `_ + defining complete, unfettered access to S3 buckets and their contents. + - *fargate_deployment_policy* - `aws.iam.Policy `_ + defining permissions needed to deploy images to a Fargate service. + + :param name: Name of the IAM user to create. :type name: str @@ -70,6 +86,7 @@ class AwsAutomationUser(tb_pulumi.ThunderbirdComponentResource): :param opts: Additional pulumi.ResourceOptions to apply to these resources. Defaults to None. :type opts: pulumi.ResourceOptions, optional + """ def __init__( @@ -306,7 +323,6 @@ def __init__( ) self.finish( - outputs={'user_name': user.name}, resources={ 'user': user, 'access_key': access_key, From 5773a6c54d90644db79f6132b1cc45d23216c94b Mon Sep 17 00:00:00 2001 From: Ryan Jung Date: Tue, 11 Feb 2025 06:02:34 -0700 Subject: [PATCH 3/5] Update cloudfront docs --- tb_pulumi/cloudfront.py | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/tb_pulumi/cloudfront.py b/tb_pulumi/cloudfront.py index 841bd0a..acc7c67 100644 --- a/tb_pulumi/cloudfront.py +++ b/tb_pulumi/cloudfront.py @@ -16,6 +16,31 @@ class CloudFrontS3Service(tb_pulumi.ThunderbirdComponentResource): """Serve the static contents of an S3 bucket over a CloudFront Distribution. + Produces the following ``resources``: + + - *service_bucket* - `aws.s3.Bucket `_ in which to + store the static content to be served over the CloudFront Distribution. + - *logging_bucket* - `aws.s3.Bucket `_ in which to + store the access logs for the service bucket. + - *logging_bucket_ownership* - `aws.s3.BucketOwnershipControls + `_ which allow CloudFront to + upload logs into the logging bucket. + - *logging_bucket_acl* - `aws.s3.BucketAclV2 + `_ allowing CloudFront to control the + logging bucket via the AWS account's canonical user. + - *origin_access_control* - `aws.cloudfront.OriginAccessControl + `_ allowing the CloudFront + Distribution to service the service bucket's content via CDN. + - *cloudfront_distribution* - `aws.cloudfront.Distribution + `_ that serves the service bucket + content over a CDN and produces output logs in the logging bucket. + - *service_bucket_policy* - `aws.s3.BucketPolicy + `_ allowing the CloudFront Distribution + read access to the objects in the service bucket. + - *invalidation_policy* - `aws.iam.Policy `_ + that allows an IAM entity to create cache invalidations in the CloudFront Distribution, which must be done when + the contents of the service bucket are updated. + :param name: A string identifying this set of resources. :type name: str @@ -233,11 +258,6 @@ def __init__( ) self.finish( - outputs={ - 'service_bucket': service_bucket.id, - 'logging_bucket': logging_bucket.id, - 'cloudfront_domain': cloudfront_distribution.domain_name, - }, resources={ 'service_bucket': service_bucket, 'logging_bucket': logging_bucket, From 827cccf8777f5a2a128da2204c82c58a45c37316 Mon Sep 17 00:00:00 2001 From: Ryan Jung Date: Tue, 11 Feb 2025 14:51:14 -0700 Subject: [PATCH 4/5] Update docs to include resources; remove outputs --- tb_pulumi/__init__.py | 4 ++-- tb_pulumi/ci.py | 29 +++++++++++++---------- tb_pulumi/cloudfront.py | 45 ++++++++++++++++++------------------ tb_pulumi/cloudwatch.py | 45 +++++++++++++++++++++--------------- tb_pulumi/ec2.py | 35 ++++++++++++++++++++++------ tb_pulumi/fargate.py | 40 ++++++++++++++++++++++++++++---- tb_pulumi/monitoring.py | 20 +++++++--------- tb_pulumi/network.py | 51 +++++++++++++++++++++++++++++++++-------- tb_pulumi/rds.py | 38 +++++++++++++++++++++++++----- tb_pulumi/secrets.py | 21 ++++++++++++++--- 10 files changed, 232 insertions(+), 96 deletions(-) diff --git a/tb_pulumi/__init__.py b/tb_pulumi/__init__.py index c396174..e1d50d4 100644 --- a/tb_pulumi/__init__.py +++ b/tb_pulumi/__init__.py @@ -17,8 +17,8 @@ #: Type alias representing valid types to be found among a ThunderbirdPulumiProject's resources type Flattenable = dict | list | ThunderbirdComponentResource | pulumi.Output | pulumi.Resource -FINISH_OUTPUTS_DEPRECATION_MESSAGE = """Calling ThunderbirdComponentResource.finish with the "outputs" parameter is DEPRECATED. This parameter will be - removed in a future version.""" +FINISH_OUTPUTS_DEPRECATION_MESSAGE = """Calling ThunderbirdComponentResource.finish with the "outputs" parameter is + DEPRECATED. This parameter will be removed in a future version.""" class ThunderbirdPulumiProject: diff --git a/tb_pulumi/ci.py b/tb_pulumi/ci.py index 9d796c8..35dcead 100644 --- a/tb_pulumi/ci.py +++ b/tb_pulumi/ci.py @@ -16,18 +16,23 @@ class AwsAutomationUser(tb_pulumi.ThunderbirdComponentResource): Produces the following ``resources``: - - *user* - `aws.iam.User `_ to run CI operations. - - *access_key* - `aws.iam.AccessKey `_ for - that user's authentication. - - *secret* - :py:class:`tb_pulumi.secrets.SecretsManagerSecret` where the access key data is stored. - - *ecr_image_push_policy* - `aws.iam.Policy `_ - defining permissions required to push container images to an ECR repository. - - *s3_upload_policy* - `aws.iam.Policy `_ - defining permissions required to upload files to S3 buckets. - - *s3_full_access_policy* - `aws.iam.Policy `_ - defining complete, unfettered access to S3 buckets and their contents. - - *fargate_deployment_policy* - `aws.iam.Policy `_ - defining permissions needed to deploy images to a Fargate service. + - *user* - `aws.iam.User `_ to run CI + operations. + - *access_key* - `aws.iam.AccessKey `_ for + that user's authentication. + - *secret* - :py:class:`tb_pulumi.secrets.SecretsManagerSecret` where the access key data is stored. + - *ecr_image_push_policy* - `aws.iam.Policy `_ + defining permissions required to push container images to an ECR repository, but only if + ``enable_ecr_image_push`` is ``True``. + - *s3_upload_policy* - `aws.iam.Policy `_ + defining permissions required to upload files to S3 buckets, but only if ``enable_s3_bucket_upload`` is + ``True``. + - *s3_full_access_policy* - `aws.iam.Policy + `_ defining complete, unfettered access to + S3 buckets and their contents, but only if ``enable_full_s3_access`` is ``True``. + - *fargate_deployment_policy* - `aws.iam.Policy + `_ defining permissions needed to deploy + images to a Fargate service, but only if ``enable_fargate_deployments`` is ``True``. :param name: Name of the IAM user to create. diff --git a/tb_pulumi/cloudfront.py b/tb_pulumi/cloudfront.py index acc7c67..d84db9a 100644 --- a/tb_pulumi/cloudfront.py +++ b/tb_pulumi/cloudfront.py @@ -18,28 +18,29 @@ class CloudFrontS3Service(tb_pulumi.ThunderbirdComponentResource): Produces the following ``resources``: - - *service_bucket* - `aws.s3.Bucket `_ in which to - store the static content to be served over the CloudFront Distribution. - - *logging_bucket* - `aws.s3.Bucket `_ in which to - store the access logs for the service bucket. - - *logging_bucket_ownership* - `aws.s3.BucketOwnershipControls - `_ which allow CloudFront to - upload logs into the logging bucket. - - *logging_bucket_acl* - `aws.s3.BucketAclV2 - `_ allowing CloudFront to control the - logging bucket via the AWS account's canonical user. - - *origin_access_control* - `aws.cloudfront.OriginAccessControl - `_ allowing the CloudFront - Distribution to service the service bucket's content via CDN. - - *cloudfront_distribution* - `aws.cloudfront.Distribution - `_ that serves the service bucket - content over a CDN and produces output logs in the logging bucket. - - *service_bucket_policy* - `aws.s3.BucketPolicy - `_ allowing the CloudFront Distribution - read access to the objects in the service bucket. - - *invalidation_policy* - `aws.iam.Policy `_ - that allows an IAM entity to create cache invalidations in the CloudFront Distribution, which must be done when - the contents of the service bucket are updated. + - *service_bucket* - `aws.s3.Bucket `_ in + which to store the static content to be served over the CloudFront Distribution. + - *logging_bucket* - `aws.s3.Bucket `_ in + which to store the access logs for the service bucket. + - *logging_bucket_ownership* - `aws.s3.BucketOwnershipControls + `_ which allow CloudFront + to upload logs into the logging bucket. + - *logging_bucket_acl* - `aws.s3.BucketAclV2 + `_ allowing CloudFront to control the + logging bucket via the AWS account's canonical user. + - *origin_access_control* - `aws.cloudfront.OriginAccessControl + `_ allowing the + CloudFront Distribution to serve the service bucket's content via CDN. + - *cloudfront_distribution* - `aws.cloudfront.Distribution + `_ that serves the service + bucket content over a CDN and produces output logs in the logging bucket. + - *service_bucket_policy* - `aws.s3.BucketPolicy + `_ allowing the CloudFront + Distribution read access to the objects in the service bucket. + - *invalidation_policy* - `aws.iam.Policy `_ + that allows an IAM entity to create cache invalidations in the CloudFront Distribution, which must be done + when the contents of the service bucket are updated. This is not attached to any entities; it exists for + developer use when setting up CI flows. :param name: A string identifying this set of resources. :type name: str diff --git a/tb_pulumi/cloudwatch.py b/tb_pulumi/cloudwatch.py index 4323735..be39f80 100644 --- a/tb_pulumi/cloudwatch.py +++ b/tb_pulumi/cloudwatch.py @@ -9,8 +9,18 @@ class CloudWatchMonitoringGroup(tb_pulumi.monitoring.MonitoringGroup): - """A ``MonitoringGroup`` that monitors AWS-based resources using AWS's CloudWatch service. This creates an SNS topic - to send its alarms on. + """A ``MonitoringGroup`` that monitors AWS-based resources using AWS's CloudWatch service and sends alerts using + SNS-to-email. + + Produces the following ``resources``: + + - *sns_topic* - `aws.sns.Topic `_ to notify + when an alarm in this monitoring group is triggered. + - *sns_subscriptions* - A list of `aws.sns.TopicSubscription + `_s, one for each entry in + ``notify_emails``. + - *alarms* - A list of alarms contained in this monitoring group. These may be any kind of alarm in the + `aws.cloudwatch `_ library. :param name: The name of the ``CloudWatchMonitoringGroup`` resource. :type name: str @@ -101,7 +111,6 @@ def monitor(self, outputs): ) self.finish( - outputs={'sns_topic_arn': sns_topic.arn}, resources={'sns_topic': sns_topic, 'sns_subscriptions': subscriptions, 'alarms': alarms}, ) @@ -164,15 +173,15 @@ class AlbAlarmGroup(tb_pulumi.monitoring.AlarmGroup): """A set of alarms for Application Load Balancers. Contains the following configurable alarms: - ``alb_5xx``: Alarms on the number of HTTP responses sourced within the load balancer with status codes in the - 500-599 range, indicating a count of internal server errors. This metric concerns the load balancer itself, - and does not contain any response codes generated by the targets. Defaults to alarming on 10 errors in 1 - minute. + 500-599 range, indicating a count of internal server errors. This metric concerns the load balancer itself, + and does not contain any response codes generated by the targets. Defaults to alarming on 10 errors in 1 + minute. - ``target_5xx``: Alarms on the number of HTTP responses sourced within the load balancer's targets with status - codes in the 500-599 range, indicating a count of internal server errors. This metric concerns the - applications the load balancer points to, and does not contain any response codes generated by the load - balancer itself. Defaults to alarming on 10 errors in 1 minute. + codes in the 500-599 range, indicating a count of internal server errors. This metric concerns the + applications the load balancer points to, and does not contain any response codes generated by the load + balancer itself. Defaults to alarming on 10 errors in 1 minute. - ``response_time``: Alarms on the average response time of HTTP requests. Defaults to alarming if the average - response time over a minute is longer than 1 second. + response time over a minute is longer than 1 second. Further detail on these metrics and others can be found within `Amazon's ALB metrics documentation `_. @@ -306,7 +315,7 @@ class AlbTargetGroupAlarmGroup(tb_pulumi.monitoring.AlarmGroup): """A set of alarms for ALB target groups. Contains the following configurable alarms: - ``unhealthy_hosts``: Alarms on the number of unhealthy hosts in a target group. Defaults to alarm when the - average of unhealthy hosts is over 1 in 1 minute. + average of unhealthy hosts is over 1 in 1 minute. Further detail on these metrics and others can be found within `Amazon's Target Group metric documentation `_. @@ -422,8 +431,8 @@ class CloudFrontDistributionAlarmGroup(tb_pulumi.monitoring.AlarmGroup): """A set of alarms for CloudFront distributions. Contains the following configurable alarms: - ``distro_4xx``: Alarms on the rate of HTTP responses with status codes in the 400-499 range, indicating an - elevated number of calls to invalid files. This value is reported as a percentage of all responses. Defaults - to alarm on at least 10% 4xx codes in 1 minute. + elevated number of calls to invalid files. This value is reported as a percentage of all responses. Defaults + to alarm on at least 10% 4xx codes in 1 minute. Further details about these metrics and more can be found in `Amazon's CloudFront distribution documentation `_. @@ -498,9 +507,9 @@ def __init__( class CloudFrontFunctionAlarmGroup(tb_pulumi.monitoring.AlarmGroup): """A set of alarms for CloudFront functions. Contains the following configurable alarms: - - ``cpu_utilization``: Alarms when the function's compute utilization is excessive. This value is reported as a - percentage of its allotted CPU. Defaults to alarm when the function's CPU usage has been over 80% on average for - 1 minute. + - ``cpu_utilization``: Alarms when the function's compute utilization is excessive. This value is reported as a + percentage of its allotted CPU. Defaults to alarm when the function's CPU usage has been over 80% on average + for 1 minute. Further details about these metrics and more can be found in `Amazon's CloudFront Functions documentation `_. @@ -578,9 +587,9 @@ class EcsServiceAlarmGroup(tb_pulumi.monitoring.AlarmGroup): """A set of alarms for ECS services. Contains the following configurable alarms: - ``cpu_utilization``: Alarms on the overall CPU usage of the entire service, all tasks combined. Threshold is a - percentage. + percentage. - ``memory_utilization``: Alarms on the overall memory usage of the entire service, all tasks combined. - Threshold is a percentage. + Threshold is a percentage. Further detail on these metrics and more can be found on `Amazon's documentation _`. diff --git a/tb_pulumi/ec2.py b/tb_pulumi/ec2.py index 848df8e..56ca3cf 100644 --- a/tb_pulumi/ec2.py +++ b/tb_pulumi/ec2.py @@ -17,6 +17,20 @@ class NetworkLoadBalancer(tb_pulumi.ThunderbirdComponentResource): """Construct a NetworkLoadBalancer to route TCP traffic to a collection of backends. This targets backend services by IP address, connecting a frontend listening port to a backend port on the round-robin load balanced targets. + Produces the following ``resources``: + + - *security_group_with_rules* - :py:class:`tb_pulumi.network.SecurityGroupWithRules` defining ingress and egress + rules for the NLB. + - *nlb* - `aws.lb.LoadBalancer `_ with a + ``load_balancer_type`` of ``network``. + - *target_group* - `aws.lb.TargetGroup `_ + containing the IPs the NLB is balancing. + - *target_group_attachments* - List of `aws.lb.TargetGroupAttachments + `_, one for each IP address + registered with the NLB. + - *listener* - `aws.lb.Listener `_ for the + NLB. + :param name: A string identifying this set of resources. :type name: str @@ -178,7 +192,6 @@ def __init__( ) self.finish( - outputs={'dns_name': nlb.dns_name}, resources={ 'security_group_with_rules': security_group_with_rules, 'nlb': nlb, @@ -192,6 +205,13 @@ def __init__( class SshableInstance(tb_pulumi.ThunderbirdComponentResource): """Builds an EC2 instance which can be accessed with SSH from somewhere on the Internet. + Produces the following ``resources``: + + - *instance* - The `aws.ec2.Instance `_. + - *keypair* - :py:class:`tb_pulumi.ec2.SshKeyPair` used for authenticating to the instance. + - *security_group* - :py:class:`tb_pulumi.network.SecurityGroupWithRules` defining network access to the + instance. + :param name: A string identifying this set of resources. :type name: str @@ -302,10 +322,6 @@ def __init__( ) self.finish( - outputs={ - 'instance_dns': instance.public_dns, - 'instance_ip': instance.public_ip, - }, resources={ 'instance': instance, 'keypair': keypair, @@ -322,6 +338,13 @@ class SshKeyPair(tb_pulumi.ThunderbirdComponentResource): ONE TIME. Each ``pulumi up/preview`` command generates a new keypair, which generates new secret versions (and if this is attached to an instance downstream, it triggers the recreation of that instance). + Produces the following ``resources``: + + - *keypair* - `aws.ec2.KeyPair `_ containing + the keypair content. + - *private_key_secret* :py:class:`tb_pulumi.secrets.SecretsManagerSecret` containing the private key data. + - *public_key_secret* :py:class:`tb_pulumi.secrets.SecretsManagerSecret` containing the public key data. + :param name: A string identifying this set of resources. :type name: str @@ -404,9 +427,7 @@ def __init__( ) self.finish( - outputs={'keypair': keypair.id}, resources={ - 'private_key': private_key if not public_key else None, 'keypair': keypair, 'private_key_secret': private_key_secret if not public_key else None, 'public_key_secret': public_key_secret if not public_key else None, diff --git a/tb_pulumi/fargate.py b/tb_pulumi/fargate.py index 67339d2..da03f51 100644 --- a/tb_pulumi/fargate.py +++ b/tb_pulumi/fargate.py @@ -13,6 +13,27 @@ class FargateClusterWithLogging(tb_pulumi.ThunderbirdComponentResource): """Builds a Fargate cluster running a variable number of tasks. Logs from these tasks will be sent to CloudWatch. + Produces the following ``resources``: + + - *cluster* - The `aws.ecs.Cluster `_. + - *log_group* - `aws.cloudwatch.LogGroup + `_ where these tasks send their + logs. + - *log_key* - `aws.kms.Key `_ used to encrypt + log contents. + - *fargate_service_alb* - :py:class:`tb_pulumi.fargate.FargateServiceAlb` balancing traffic between these tasks. + - *policy_exec* - `aws.iam.Policy `_ allowing + the service access to other resources needed to launch tasks. + - *policy_log_sending* - `aws.iam.Policy `_ + allowing tasks to send logs to their log group. + - *service* - `aws.ecs.Service `_ managing + the tasks. + - *task_role* - `aws.iam.Role `_ used for + executing tasks in this cluster. + - *task_definition* - `aws.ecs.TaskDefinition + `_ describing the properties of the + tasks being managed. + :param name: A string identifying this set of resources. :type name: str @@ -303,10 +324,6 @@ def __init__( ) self.finish( - outputs={ - 'cluster_id': cluster.id, - 'service_id': service.id, - }, resources={ 'cluster': cluster, 'log_group': log_group, @@ -392,6 +409,19 @@ class FargateServiceAlb(tb_pulumi.ThunderbirdComponentResource): services. ECS does not allow reuse of a single ALB with multiple listeners, so if there are multiple services, multiple ALBs will be constructed. + Produces the following ``resources``: + + - *albs* - Dict where the keys match the keys of the ``services`` parameter and the values are the + `aws.lb.LoadBalancers `_ created for + those services. + - *listeners* - Dict where the keys match the keys of the ``services`` parameter and the values are the + `aws.lb.Listeners `_ created for the + load balancers for those services. + - *target_groups* - Dict where the keys match the keys of the ``services`` parameter and the values are the + `aws.lb.TargetGroups `_ created for the + listeners for those services. Importantly, Fargate services manage their own targets, so this module does not + track any target group attachments. + :param name: A string identifying this set of resources. :type name: str @@ -518,4 +548,4 @@ def __init__( opts=pulumi.ResourceOptions(parent=self, depends_on=[albs[svc_name]]), ) - self.finish(outputs={}, resources={'albs': albs, 'listeners': listeners, 'target_groups': target_groups}) + self.finish(resources={'albs': albs, 'listeners': listeners, 'target_groups': target_groups}) diff --git a/tb_pulumi/monitoring.py b/tb_pulumi/monitoring.py index 6a5a731..31be6a0 100644 --- a/tb_pulumi/monitoring.py +++ b/tb_pulumi/monitoring.py @@ -29,21 +29,17 @@ class MonitoringGroup(tb_pulumi.ThunderbirdComponentResource): :param config: A configuration dictionary. The specific format and content of this dictionary is defined in part by classes extending this class. However, the dictionary should be configured in the following broad way, with - downstream monitoring groups defining the specifics of the monitor configs: + downstream monitoring groups defining the specifics of the monitor configs (shown here as YAML): - .. code-block:: javascript + .. code-block:: yaml :linenos: - { - "alarms": { - "name-of-the-resource-being-monitored": { - "monitor_name": { - "enabled": False - // Downstream monitoring groups tell you what else goes right here - } - } - } - } + --- + alarms: + name-of-the-resource-being-monitored: + monitor_name: + enabled: False + # Downstream monitoring groups tell you what else goes right here This config defines override settings for alarms whose default configurations are insufficient for a specific use case. Since each resource can have multiple alarms associated with it, the ``"alarm"`` dict's keys should be diff --git a/tb_pulumi/network.py b/tb_pulumi/network.py index 9c80b37..e866d25 100644 --- a/tb_pulumi/network.py +++ b/tb_pulumi/network.py @@ -8,6 +8,35 @@ class MultiCidrVpc(tb_pulumi.ThunderbirdComponentResource): """Builds a VPC with configurable network space. + Produces the following ``resources``: + + - *endpoint_sg* - If the ``endpoint_interfaces`` or ``endpoint_gateways`` parameters are provided, this is a + :py:class:`tb_pulumi.network.SecurityGroupWithRules` used to define traffic through these endpoints. + - *gateways* - If there are any ``endpoint_gateways`` defined, this is a list of `aws.ec2.VpcEndpoints + `_ with a ``vpc_endpoint_type`` of + ``Gateway``. + - *interfaces* - If there are any ``endpoint_interfaces`` defined, this is a list of `aws.ec2.VpcEndpoints + `_ with a ``vpc_endpoint_type`` of + ``Interface``. + - *internet_gateway* - If ``enable_internet_gateway`` is ``True``, this is the `aws.ec2.InternetGateway + `_. + - *nat_eip* - If ``enable_nat_gateway`` is ``True``, this is the `aws.ec2.Eip + `_ used for the NAT Gateway. + - *nat_gateway* - If ``enable_nat_gateway`` is ``True``, this is the `aws.ec2.NatGateway + `_. + - *route_table_subnet_associations* - List of `aws.ec2.RouteTableAssociations + `_ associating the subnets + to the VPC's default route table, enabling traffic among those subnets. + - *subnets* - List of `aws.ec2.Subnets `_ in + this VPC. + - *subnet_ig_route* - If ``enable_internet_gateway`` and ``egress_via_internet_gateway`` are both ``True``, + this is the `aws.ec2.Route `_ that enables + outbound traffic through the Internet Gateway. + - *subnet_ng_route* - If ``enable_nat_gateway`` and ``egress_via_nat_gateway`` are both ``True``, this is the + `aws.ec2.Route `_ that enables outbound + traffic through the NAT Gateway. + - *vpc* - The `aws.ec2.Vpc `_. + :param name: A string identifying this set of resources. :type name: str @@ -235,10 +264,6 @@ def __init__( ) self.finish( - outputs={ - 'subnets': [subnet.id for subnet in subnet_rs], - 'vpc': vpc.id, - }, resources={ 'endpoint_sg': endpoint_sg if len(endpoint_interfaces + endpoint_gateways) > 0 else None, 'gateways': gateways, @@ -258,6 +283,15 @@ def __init__( class SecurityGroupWithRules(tb_pulumi.ThunderbirdComponentResource): """Builds a security group and sets rules for it. + Produces the following ``resources``: + + - *egress_rules* - List of `aws.ec2.SecurityGroupRules + `_ describing outbound traffic. + - *ingress_rules* - List of `aws.ec2.SecurityGroupRules + `_ describing inbound traffic. + - *sg* - The `aws.ec2.SecurityGroup `_ + containing these rules. + :param name: A string identifying this set of resources. :type name: str @@ -319,29 +353,28 @@ def __init__( egress_rules = [] ingress_ruledefs = rules['ingress'] - for idx, rule in enumerate(ingress_ruledefs): + for rule in ingress_ruledefs: rule.update({'type': 'ingress', 'security_group_id': sg.id}) ingress_rules.append( aws.ec2.SecurityGroupRule( - f'{name}-ingress-{idx}', + f'{name}-ingress-{rule["to_port"]}', opts=pulumi.ResourceOptions(parent=self, depends_on=[sg]), **rule, ) ) egress_ruledefs = rules['egress'] - for idx, rule in enumerate(egress_ruledefs): + for rule in egress_ruledefs: rule.update({'type': 'egress', 'security_group_id': sg.id}) egress_rules.append( aws.ec2.SecurityGroupRule( - f'{name}-egress-{idx}', + f'{name}-egress-{rule["to_port"]}', opts=pulumi.ResourceOptions(parent=self, depends_on=[sg]), **rule, ) ) self.finish( - outputs={'sg': sg.id}, resources={ 'egress_rules': egress_rules, 'ingress_rules': ingress_rules, diff --git a/tb_pulumi/rds.py b/tb_pulumi/rds.py index 758eb40..cc7c093 100644 --- a/tb_pulumi/rds.py +++ b/tb_pulumi/rds.py @@ -16,6 +16,37 @@ class RdsDatabaseGroup(tb_pulumi.ThunderbirdComponentResource): """Using RDS, construct a primary database and zero or more read replicas. A Network Load Balancer (NLB) is created to spread load across the read replicas. + Produces the following ``resources``: + + - *instances* - A list of `aws.rds.Instances + `_ in the group. The zeroth index will + always be the primary/writer instance. If there are any replica/reader instances, those will follow. + - *jumphost* - If ``build_jumphost`` is ``True``, this is the :py:class:`tb_pulumi.ec2.SshableInstance` to be + used to access the DBs. + - *key* - `aws.kms.Key `_ used to encrypt + database storage. + - *load_balancer* - :py:class:`tb_pulumi.ec2.NetworkLoadBalancer` routing traffic to the read databases. + - *parameter_group* - `aws.rds.ParameterGroup + `_ defining how these databases + operate. + - *password* - `pulumi_random.RandomPassword + `_ for the database. + - *secret* - :py:class:`tb_pulumi.secrets.SecretsManagerSecret` storing the password within AWS. + - *security_group* - :py:class:`tb_pulumi.network.SecurityGroupWithRules` defining access to the database. + - *ssm_param_db_name* - `aws.ssm.Parameter + `_ containing the database name. + - *ssm_param_db_write_host* - `aws.ssm.Parameter + `_ containing the write instance's + hostname. + - *ssm_param_port* - `aws.ssm.Parameter + `_ containing the database port. + - *ssm_param_read_host* - `aws.ssm.Parameter + `_ containing the hostname of the read + traffic load balancer. + - *subnet_group* - `aws.rds.SubnetGroup + `_, a logical grouping of subnets in + which to build database instances. + :param name: A string identifying this set of resources. :type name: str @@ -452,11 +483,6 @@ def __init__( ) self.finish( - outputs={ - 'password_secret': password.id, - 'primary_address': primary.address, - 'replica_addresses': [inst.address for inst in instances[1:]], - }, resources={ 'instances': instances, 'jumphost': jumphost if build_jumphost else None, @@ -474,7 +500,7 @@ def __init__( }, ) - def __ssm_param(self, name, param_name, value, depends_on: list[pulumi.Output] = None): + def __ssm_param(self, name, param_name, value, depends_on: list[pulumi.Output] = None) -> aws.ssm.Parameter: """Build an SSM Parameter.""" return aws.ssm.Parameter( name, diff --git a/tb_pulumi/secrets.py b/tb_pulumi/secrets.py index 133bea2..b6260a2 100644 --- a/tb_pulumi/secrets.py +++ b/tb_pulumi/secrets.py @@ -9,7 +9,15 @@ class SecretsManagerSecret(tb_pulumi.ThunderbirdComponentResource): - """Stores a value as a Secrets Manager secret. + """Stores a value as a Secrets Manager secret, which is composed of a "Secret" and a "SecretVersion". + + Produces the following ``resources``: + + - *secret* - `aws.secretsmanager.Secret + `_ describing secret metadata. + - *version* - `aws.secretsmanager.SecretVersion + `_ containing the actual + secret data. :param name: A string identifying this set of resources. :type name: str @@ -72,12 +80,20 @@ def __init__( opts=pulumi.ResourceOptions(parent=self, depends_on=[secret]), ) - self.finish(outputs={'secret_id': secret.id}, resources={'secret': secret, 'version': version}) + self.finish(resources={'secret': secret, 'version': version}) class PulumiSecretsManager(tb_pulumi.ThunderbirdComponentResource): """Builds a set of AWS SecretsManager Secrets based on specific secrets in Pulumi's config. + Produces the following ``resources``: + + - *secrets* - List of :py:class:`tb_pulumi.secrets.SecretsManagerSecret` s storing Pulumi config secrets in AWS. + - *policy* - `aws.iam.Policy + `_ granting access to the + secrets managed by this module. This doesn't get attached to any entities, but is intended for use in things + like CI flows or ECS task execution roles. + :param name: A string identifying this set of resources. :type name: str @@ -156,6 +172,5 @@ def __init__( ) self.finish( - outputs={'policy_id': policy.policy_id, 'secret_ids': [secret.id for secret in secrets]}, resources={'secrets': secrets, 'policy': policy}, ) From 8a9e459a41096b20ff6f7ba779a0c3d6fcec68f3 Mon Sep 17 00:00:00 2001 From: Chris Aquino Date: Tue, 18 Feb 2025 16:38:45 -0500 Subject: [PATCH 5/5] Minor edits; adds concrete example regarding conventions (#107) * Minor edits; adds concrete example regarding conventions * typo * Fixes `code-block` issues * Update docs related to Pulumi Types * Lint * point out `stack select` pattern in a ..note:: --------- Co-authored-by: Ryan Jung --- docs/getting-started.rst | 153 ++++++++++++++++++++++++++++++--------- tb_pulumi/ci.py | 7 +- tb_pulumi/cloudfront.py | 4 +- tb_pulumi/cloudwatch.py | 25 +++++-- tb_pulumi/ec2.py | 12 ++- tb_pulumi/fargate.py | 8 +- tb_pulumi/network.py | 8 +- tb_pulumi/rds.py | 4 +- tb_pulumi/secrets.py | 8 +- 9 files changed, 176 insertions(+), 53 deletions(-) diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 707ac92..4fc5f4f 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -22,7 +22,7 @@ To use this module, you'll need to get through this checklist first: * Understand the `basic concepts of Pulumi `_, particularly `Resources `_ and `Component Resources `_. -* `Configure awscli `_ with +* Provide an `awscli configuration `_ with your credentials and default region. (You do not have to install awscli, though you can `read how to here `_. Some of these docs refer to helpful awscli commands.) The Pulumi AWS provider relies on the same configuration, @@ -54,7 +54,7 @@ This will... If you are using an S3 bucket to privately store your state, you'll need to make sure you have configured your AWSCLI tool with an account that has permission to manipulate that bucket. Prefix your bucket name with `s3://` to use as your -`pulumi_login_url` value (f/ex: `s3://acme-awesomeapi-pulumi`). If you will use Pulumi Cloud, use +`pulumi_login_url` value (e.g.,: `s3://acme-awesomeapi-pulumi`). If you will use Pulumi Cloud, use `https://api.pulumi.com`. If you have a `self-hosted Pulumi Cloud API `_, you may specify your custom URL here. @@ -104,9 +104,9 @@ to handle this is to include an organization name in your bucket name. As a temp Repo setup ^^^^^^^^^^ -You probably already have a code repo with your application code in it. If not, create such a repo. +You probably already have a repository with your application code in it. If not, create one now. -Create a directory there called ``pulumi`` and create a new project and stack in it. You'll need the name of the S3 +Create a subdirectory called ``pulumi`` and create a new project and stack in it. You'll need the name of the S3 bucket or cloud host from the previous step here. If you are operating in an AWS region other than what is set as your default for AWSCLI, be sure to ``export AWS_REGION=us-east-1`` or whatever else you may need to do to override that. @@ -142,7 +142,15 @@ run: source ./venv/bin/activate pip install -U -r requirements.txt -You can now develop Python Pulumi code in that directory, referring to this module with imports such as these: +You can now develop Python Pulumi code in that directory, as shown in the following section. + +Use this module +^^^^^^^^^^^^^^^ + +When you issue ``pulumi`` commands (like "up" and "preview" and so on), it looks for a ``__main__.py`` file in your +current directory and executes the code in that file. + +``__main__.py` imports and uses the ``tb_pulumi`` module: .. code-block:: python @@ -152,35 +160,114 @@ You can now develop Python Pulumi code in that directory, referring to this modu from tb_pulumi import (ec2, fargate, secrets) - -Use this module -^^^^^^^^^^^^^^^ - -When you issue ``pulumi`` commands (like "up" and "preview" and so on), it looks for a ``__main__.py`` file in your -current directory and executes the code in that file. To use this module, you'll import it into that file and write up -some code and configuration files. - - Create a config file """""""""""""""""""" -It is assumed that a config file will exist at ``config.$STACK.yaml`` where ``$STACK`` is the currently selected Pulumi -stack. This file must contain a mapping of names of config settings to their desired values. Currently, only one such -setting is formally recognized. That is ``resources``. - -This is a mostly arbitary mapping that you will have to interpret on your own. This allows for flexibility, but we -recommend some conventions here. Namely: - -* ``resources`` should be a mapping where the keys are the Pulumi type-strings for the resources they are configuring. - For example, if you want to build a VPC with several subnets, you might use the ``tb_pulumi.network.MultiCidrVpc`` - class. Following this convention, that should be accompanied by a ``tb:network:MultiCidrVpc`` key in this mapping. -* The values these keys map to should themselves be mappings. This provides a convention where more than one of each - pattern are configurable. The keys here should be arbitrary but unique identifiers for the resources being configured. - F/ex: ``backend`` or ``api``. -* The values these keys map to should be a mapping where each key/value combo is a valid configuration option for the - resources being built. The full listing of these values can be found by browsing the :py:mod:`tb_pulumi` - documentation. A barebones example can be found in our `sample config - `_. +Create a config file for each stack, i.e., ``config.$STACK.yaml`` (where ``$STACK`` maps to a Pulumi stack/application +environment). This file maps parameters for tb_pulumi resources to their desired values. Currently, only the +``resources`` setting is formally recognized. + +.. note:: + + When you run ``pulumi stack select $STACK``, these two files become active: + ``Pulumi.$STACK.yaml`` and ``config.$STACK.yaml``. + If you're already familiar with Pulumi, you might recognize that this + patterns follows Pulumi's conventions. + + +Let's look at an example tb_pulumi configuration file. + +.. code-block:: yaml + + resources: + tb:network:MultiCidrVpc: + vpc: + cidr_block: 10.0.0.0/16 + egress_via_internet_gateway: True + enable_dns_hostnames: True + enable_internet_gateway: True + endpoint_interfaces: + - ecr.api + - ecr.dkr + - logs + - secretsmanager + subnets: + us-east-2a: + - 10.0.101.0/24 + us-east-2b: + - 10.0.102.0/24 + us-east-2c: + - 10.0.103.0/24 + +At the top-level is the ``resources`` key. Nested inside are configurations for kinds of resources. This resource uses +the ``tb_pulumi.network.MultiCidrVpc`` class. + +.. note:: + We recommend using resource key names that are named after the Pulumi Types for each resource. These are documented + alongside each class in the :py:mod:`tb_pulumi` module. + +The Pulumi Type for a ``MultiCidrVpc`` is ``tb:network:MultiCidrVpc``, so we have chosen that as a name under which we +define our MultiCidrVpc configs. We call this one particular config ``vpc`` (you normally need only one, though this +convention allows for as many as you like). + +Next, we see a resource named ``tb:fargate:FargateClusterWithLogging``: + +.. code-block:: yaml + + tb:fargate:FargateClusterWithLogging: + backend: + assign_public_ip: True + ecr_resources: + - arn:aws:ecr:us-east-2:1234567890123:repository/rockroll* + health_check_grace_period_seconds: 60 + internal: False + api: + assign_public_ip: True + ecr_resources: + - arn:aws:ecr:us-east-2:1234567890124:repository/rockrollapi* + health_check_grace_period_seconds: 60 + internal: False + +It configures two Fargate clusters named ``backend`` and an ``api``. + +Note that the specific names ``backend`` and ``api`` are reusable for other resources, such as these security groups: + +.. code-block:: yaml + + tb:network:SecurityGroupWithRules: + backend: + rules: + ingress: + - cidr_blocks: ["0.0.0.0/0"] + description: TLS port for the load balancer + protocol: tcp + from_port: 443 + to_port: 443 + egress: + - cidr_blocks: ["0.0.0.0/0"] + description: Outbound traffic + protocol: tcp + from_port: 0 + to_port: 65535 + api: + rules: + ingress: + - description: Private backend port + protocol: tcp + from_port: 8080 + to_port: 8080 + egress: + - cidr_blocks: ["0.0.0.0/0"] + description: Outbound traffic + protocol: tcp + from_port: 0 + to_port: 65535 + +The only other requirement is that you provide valid options and values in your configuration. The full listing of these +values can be found by browsing the :py:mod:`tb_pulumi` documentation. + +A barebones example can be found in our `sample config +`_. Define a ThunderbirdPulumiProject @@ -218,7 +305,7 @@ So you want to develop a new pattern to stamp out? Here's what you'll need to do * Determine the best place to put the code. Is there an existing module that fits the bill? * Determine the Pulumi type string for it. This goes: ``org:module:class``. The ``org`` should be unique to your organization. For Thunderbird projects, it should be ``tb``. The ``module`` will be the Python submodule you're - placing the new class in (f/ex, classes in ``network.py`` should use ``network`` here). The ``class`` is whatever + placing the new class in (e.g., classes in ``network.py`` should use ``network`` here). The ``class`` is whatever you've called the class. * Design the class following these guidelines: * The constructor should always accept, before any other arguments, the following positional options: @@ -288,4 +375,4 @@ Shells other than Bash Setup instructions in these docs are designed for use with the Bourne Again SHell (Bash). Pulumi also seems to make some assumptions like this when it installs itself. Pulumi will install itself into a hidden folder in your home directory: ``~/.pulumi/bin``. You may need to add this to your ``$PATH`` to avoid having to make the explicit reference with every -``pulumi`` command. \ No newline at end of file +``pulumi`` command. diff --git a/tb_pulumi/ci.py b/tb_pulumi/ci.py index 35dcead..8c7914a 100644 --- a/tb_pulumi/ci.py +++ b/tb_pulumi/ci.py @@ -7,7 +7,9 @@ class AwsAutomationUser(tb_pulumi.ThunderbirdComponentResource): - """Creates an IAM user, then creates a keypair for it. The keypair data is stored in Secrets Manager. Several + """**Pulumi Type:** ``tb:ci:AutomationUser`` + + Creates an IAM user, then creates a keypair for it. The keypair data is stored in Secrets Manager. Several options, documented below, exist to provide some common permission sets for build and deployment patterns used in these modules. Additional policies can be added arbitrarily to expand these permissions. @@ -91,7 +93,6 @@ class AwsAutomationUser(tb_pulumi.ThunderbirdComponentResource): :param opts: Additional pulumi.ResourceOptions to apply to these resources. Defaults to None. :type opts: pulumi.ResourceOptions, optional - """ def __init__( @@ -112,7 +113,7 @@ def __init__( opts: pulumi.ResourceOptions = None, **kwargs, ): - super().__init__('tb:ci:Automationuser', name=name, project=project, opts=opts, **kwargs) + super().__init__('tb:ci:AutomationUser', name=name, project=project, opts=opts, **kwargs) if project.stack == active_stack: user = aws.iam.User( diff --git a/tb_pulumi/cloudfront.py b/tb_pulumi/cloudfront.py index d84db9a..336fc3c 100644 --- a/tb_pulumi/cloudfront.py +++ b/tb_pulumi/cloudfront.py @@ -14,7 +14,9 @@ class CloudFrontS3Service(tb_pulumi.ThunderbirdComponentResource): - """Serve the static contents of an S3 bucket over a CloudFront Distribution. + """**Pulumi Type:** ``tb:cloudfront:CloudFrontS3Service`` + + Serve the static contents of an S3 bucket over a CloudFront Distribution. Produces the following ``resources``: diff --git a/tb_pulumi/cloudwatch.py b/tb_pulumi/cloudwatch.py index be39f80..b5bb152 100644 --- a/tb_pulumi/cloudwatch.py +++ b/tb_pulumi/cloudwatch.py @@ -9,7 +9,9 @@ class CloudWatchMonitoringGroup(tb_pulumi.monitoring.MonitoringGroup): - """A ``MonitoringGroup`` that monitors AWS-based resources using AWS's CloudWatch service and sends alerts using + """**Pulumi Type:** ``tb:cloudwatch:CloudWatchMonitoringGroup`` + + A ``MonitoringGroup`` that monitors AWS-based resources using AWS's CloudWatch service and sends alerts using SNS-to-email. Produces the following ``resources``: @@ -170,7 +172,9 @@ def __build_alarm_group(self, lb_type: str): class AlbAlarmGroup(tb_pulumi.monitoring.AlarmGroup): - """A set of alarms for Application Load Balancers. Contains the following configurable alarms: + """**Pulumi Type:** ``tb:cloudwatch:AlbAlarmGroup`` + + A set of alarms for Application Load Balancers. Contains the following configurable alarms: - ``alb_5xx``: Alarms on the number of HTTP responses sourced within the load balancer with status codes in the 500-599 range, indicating a count of internal server errors. This metric concerns the load balancer itself, @@ -312,7 +316,9 @@ def __init__( class AlbTargetGroupAlarmGroup(tb_pulumi.monitoring.AlarmGroup): - """A set of alarms for ALB target groups. Contains the following configurable alarms: + """**Pulumi Type:** ``tb:cloudwatch:CloudFrontDistributionAlarmGroup`` + + A set of alarms for ALB target groups. Contains the following configurable alarms: - ``unhealthy_hosts``: Alarms on the number of unhealthy hosts in a target group. Defaults to alarm when the average of unhealthy hosts is over 1 in 1 minute. @@ -428,7 +434,10 @@ def __unhealthy_hosts_metric_alarm( class CloudFrontDistributionAlarmGroup(tb_pulumi.monitoring.AlarmGroup): - """A set of alarms for CloudFront distributions. Contains the following configurable alarms: + """**Pulumi type:** ``tb:cloudwatch:CloudFrontDistributionAlarmGroup`` + + A set of alarms for CloudFront distributions. Contains the following configurable alarms: + - ``distro_4xx``: Alarms on the rate of HTTP responses with status codes in the 400-499 range, indicating an elevated number of calls to invalid files. This value is reported as a percentage of all responses. Defaults @@ -505,7 +514,9 @@ def __init__( class CloudFrontFunctionAlarmGroup(tb_pulumi.monitoring.AlarmGroup): - """A set of alarms for CloudFront functions. Contains the following configurable alarms: + """**Pulumi Type:** ``tb:cloudwatch:CloudFrontFunctionAlarmGroup`` + + A set of alarms for CloudFront functions. Contains the following configurable alarms: - ``cpu_utilization``: Alarms when the function's compute utilization is excessive. This value is reported as a percentage of its allotted CPU. Defaults to alarm when the function's CPU usage has been over 80% on average @@ -584,7 +595,9 @@ def __init__( class EcsServiceAlarmGroup(tb_pulumi.monitoring.AlarmGroup): - """A set of alarms for ECS services. Contains the following configurable alarms: + """**Pulumi Type:** ``tb:cloudwatch:EcsServiceAlarmGroup`` + + A set of alarms for ECS services. Contains the following configurable alarms: - ``cpu_utilization``: Alarms on the overall CPU usage of the entire service, all tasks combined. Threshold is a percentage. diff --git a/tb_pulumi/ec2.py b/tb_pulumi/ec2.py index 56ca3cf..8cc4269 100644 --- a/tb_pulumi/ec2.py +++ b/tb_pulumi/ec2.py @@ -14,7 +14,9 @@ class NetworkLoadBalancer(tb_pulumi.ThunderbirdComponentResource): - """Construct a NetworkLoadBalancer to route TCP traffic to a collection of backends. This targets backend services + """**Pulumi Type:** ``tb:ec2:NetworkLoadBalancer`` + + Construct a NetworkLoadBalancer to route TCP traffic to a collection of backends. This targets backend services by IP address, connecting a frontend listening port to a backend port on the round-robin load balanced targets. Produces the following ``resources``: @@ -203,7 +205,9 @@ def __init__( class SshableInstance(tb_pulumi.ThunderbirdComponentResource): - """Builds an EC2 instance which can be accessed with SSH from somewhere on the Internet. + """**Pulumi Type:** ``tb:ec2:SshableInstance`` + + Builds an EC2 instance which can be accessed with SSH from somewhere on the Internet. Produces the following ``resources``: @@ -331,7 +335,9 @@ def __init__( class SshKeyPair(tb_pulumi.ThunderbirdComponentResource): - """Builds an SSH keypair and stores its values in Secrets Manager. + """**Pulumi Type:** ``tb:ec2:SshKeyPair`` + + Builds an SSH keypair and stores its values in Secrets Manager. You should usually specify the ``public_key`` when using this module. If you do not, Pulumi will generate a new key for you. However, at the moment, it appears there's no way to have Pulumi generate a private key ONE TIME and ONLY diff --git a/tb_pulumi/fargate.py b/tb_pulumi/fargate.py index da03f51..a0ce0c2 100644 --- a/tb_pulumi/fargate.py +++ b/tb_pulumi/fargate.py @@ -10,7 +10,9 @@ class FargateClusterWithLogging(tb_pulumi.ThunderbirdComponentResource): - """Builds a Fargate cluster running a variable number of tasks. Logs from these tasks will be + """**Pulumi Type:** ``tb:fargate:FargateClusterWithLogging`` + + Builds a Fargate cluster running a variable number of tasks. Logs from these tasks will be sent to CloudWatch. Produces the following ``resources``: @@ -405,7 +407,9 @@ def task_definition( class FargateServiceAlb(tb_pulumi.ThunderbirdComponentResource): - """Builds an ALB with all of its constituent components to serve traffic for a set of ECS + """**Pulumi Type:** ``tb:fargate:FargateServiceAlb`` + + Builds an ALB with all of its constituent components to serve traffic for a set of ECS services. ECS does not allow reuse of a single ALB with multiple listeners, so if there are multiple services, multiple ALBs will be constructed. diff --git a/tb_pulumi/network.py b/tb_pulumi/network.py index e866d25..7d794f4 100644 --- a/tb_pulumi/network.py +++ b/tb_pulumi/network.py @@ -6,7 +6,9 @@ class MultiCidrVpc(tb_pulumi.ThunderbirdComponentResource): - """Builds a VPC with configurable network space. + """**Pulumi Type:** ``tb:network:MultiCidrVpc`` + + Builds a VPC with configurable network space. Produces the following ``resources``: @@ -281,7 +283,9 @@ def __init__( class SecurityGroupWithRules(tb_pulumi.ThunderbirdComponentResource): - """Builds a security group and sets rules for it. + """**Pulumi Type:** ``tb:network:SecurityGroupWithRules`` + + Builds a security group and sets rules for it. Produces the following ``resources``: diff --git a/tb_pulumi/rds.py b/tb_pulumi/rds.py index cc7c093..9ae471f 100644 --- a/tb_pulumi/rds.py +++ b/tb_pulumi/rds.py @@ -13,7 +13,9 @@ class RdsDatabaseGroup(tb_pulumi.ThunderbirdComponentResource): - """Using RDS, construct a primary database and zero or more read replicas. A Network Load Balancer (NLB) is + """**Pulumi Type:** ``tb:rds:RdsDatabaseGroup`` + + Using RDS, construct a primary database and zero or more read replicas. A Network Load Balancer (NLB) is created to spread load across the read replicas. Produces the following ``resources``: diff --git a/tb_pulumi/secrets.py b/tb_pulumi/secrets.py index b6260a2..4331d85 100644 --- a/tb_pulumi/secrets.py +++ b/tb_pulumi/secrets.py @@ -9,7 +9,9 @@ class SecretsManagerSecret(tb_pulumi.ThunderbirdComponentResource): - """Stores a value as a Secrets Manager secret, which is composed of a "Secret" and a "SecretVersion". + """**Pulumi Type:** ``tb:secrets:SecretsManagerSecret`` + + Stores a value as a Secrets Manager secret, which is composed of a "Secret" and a "SecretVersion". Produces the following ``resources``: @@ -84,7 +86,9 @@ def __init__( class PulumiSecretsManager(tb_pulumi.ThunderbirdComponentResource): - """Builds a set of AWS SecretsManager Secrets based on specific secrets in Pulumi's config. + """**Pulumi Type:** ``tb:secrets:PulumiSecretsManager`` + + Builds a set of AWS SecretsManager Secrets based on specific secrets in Pulumi's config. Produces the following ``resources``: