Skip to content

Commit

Permalink
fix(unit-template): allow generating StackId value #384
Browse files Browse the repository at this point in the history
  • Loading branch information
dhutchison committed Dec 23, 2024
1 parent 3fa58f5 commit fdd70e3
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 4 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,8 @@ The default values for pseudo parameters:
| **NoValue** | "" |
| **Partition** | "aws" |
| Region | "us-east-1" |
| **StackId** | "" |
| **StackName** | "" |
| StackId | (generated based on other values) |
| StackName | "my-cloud-radar-stack" |
| **URLSuffix** | "amazonaws.com" |
_Note: Bold variables are not fully impletmented yet see the [Roadmap](#roadmap)_

Expand Down
19 changes: 17 additions & 2 deletions src/cloud_radar/cf/unit/_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import json
import re
import uuid
from pathlib import Path
from typing import Any, Callable, Dict, Generator, List, Optional, Tuple, Union

Expand All @@ -24,8 +25,8 @@ class Template:
NoValue: str = "" # Not yet implemented
Partition: str = "aws" # Other regions not implemented
Region: str = "us-east-1"
StackId: str = "" # Not yet implemented
StackName: str = "" # Not yet implemented
StackId: str = "" # If left black this will be generated
StackName: str = "my-cloud-radar-stack"
URLSuffix: str = "amazonaws.com" # Other regions not implemented

def __init__(
Expand Down Expand Up @@ -304,6 +305,19 @@ def remove_condtional_resources(self, template: Dict[str, Any]) -> Dict[str, Any

return template

# If the StackId variable is not set, generate a value for it
def _get_populated_stack_id(self) -> str:
if not Template.StackId:
# Not explicitly set, generate a value
unique_uuid = uuid.uuid4()

return (
f"arn:{Template.Partition}:cloudformation:{self.Region}:"
f"{Template.AccountId}:stack/{Template.StackName}/{unique_uuid}"
)

return Template.StackId

def create_stack(
self,
params: Optional[Dict[str, str]] = None,
Expand All @@ -312,6 +326,7 @@ def create_stack(
):
if region:
self.Region = region
self.StackId = self._get_populated_stack_id()

self.render(params, parameters_file=parameters_file)

Expand Down
16 changes: 16 additions & 0 deletions tests/templates/test_stackid.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
AWSTemplateFormatVersion: 2010-09-09
Description: "Creates an S3 bucket to store logs."

Resources:
UniqueBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub
- 'my-test-${stack_region}-${uniqifier}-bucket'
- # AWS::StackId has this format
# arn:aws:cloudformation:us-west-2:123456789012:stack/teststack/51af3dc0-da77-11e4-872e-1234567db123
# Trying to capture the last piece after the '-'
# As stack name could contain "-"s, split on the "/"s first
uniqifier: !Select [ 4, !Split [ "-", !Select [ 2, !Split [ "/", !Ref AWS::StackId ] ] ] ]
# Usually you would refer to AWS:::Region, but trying to test StackId creation works as expected
stack_region: !Select [ 3, !Split [":", !Ref AWS::StackId]]
73 changes: 73 additions & 0 deletions tests/test_cf/test_unit/test_stack_stackid.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Test case that verifies that generation of the value for AWS::StackId works as expected

from pathlib import Path

import pytest

from cloud_radar.cf.unit._template import Template


@pytest.fixture
def template():
template_path = Path(__file__).parent / "../../templates/test_stackid.yaml"

return Template.from_yaml(template_path.resolve(), {})


def test_function_populated_var(template):
expected_value = "arn:aws:cloudformation:us-west-2:123456789012:stack/teststack/51af3dc0-da77-11e4-872e-1234567db123"
Template.StackId = expected_value

actual_value = template._get_populated_stack_id()
assert actual_value == expected_value


def test_function_blank_var(template):
Template.StackId = ""

actual_value = template._get_populated_stack_id()
# Check all except the UUID
assert actual_value.startswith(
f"arn:{Template.Partition}:cloudformation:{Template.Region}:{Template.AccountId}:stack/{Template.StackName}/"
)

# Check the UUID part looks UUID like
unique_uuid = actual_value.split("/")[2]
assert 5 == len(unique_uuid.split("-"))


def test_template_blank_var_stack_region(template):
Template.StackId = ""

stack = template.create_stack({}, region="eu-west-1")

bucket = stack.get_resource("UniqueBucket")
bucket_name = bucket.get_property_value("BucketName")

assert len(bucket_name) == 37
assert bucket_name[:18] == "my-test-eu-west-1-"
assert bucket_name[30:] == "-bucket"


def test_template_blank_var_global_region(template):
Template.StackId = ""

stack = template.create_stack({})

bucket = stack.get_resource("UniqueBucket")
bucket_name = bucket.get_property_value("BucketName")

assert len(bucket_name) == 37
assert bucket_name[:18] == "my-test-us-east-1-"
assert bucket_name[30:] == "-bucket"


def test_template_populated_var(template):
Template.StackId = "arn:aws:cloudformation:us-west-2:123456789012:stack/teststack/51af3dc0-da77-11e4-872e-1234567db123"

stack = template.create_stack({})

bucket = stack.get_resource("UniqueBucket")
bucket_name = bucket.get_property_value("BucketName")

assert "my-test-us-west-2-1234567db123-bucket" == bucket_name

0 comments on commit fdd70e3

Please sign in to comment.