Skip to content

Commit e8ed121

Browse files
authored
Bump new version (#93)
1 parent 00e59e0 commit e8ed121

File tree

10 files changed

+153
-113
lines changed

10 files changed

+153
-113
lines changed

CHANGELOG.md

+13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
# ChangeLog
22

3+
## 0.5.0
4+
5+
- HCL version release.
6+
- Bump external-resources-io
7+
- Bump er-terraform-base image
8+
- Improved verssion validations.
9+
10+
## 0.4.x
11+
12+
- First HCL version
13+
- Interim Version to migrate existing resources to HCL
14+
- Parameter group dependency fix
15+
316
## 0.2.0
417

518
- Use Konflux to build the image

Dockerfile

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
FROM quay.io/redhat-services-prod/app-sre-tenant/er-base-terraform-main/er-base-terraform-main:tf-1.6.6-py-3.12-v0.3.0-1@sha256:db5eac3155679679656d200e60c7865851f9a661b85d8a0a94d2815b300be591 AS base
1+
FROM quay.io/redhat-services-prod/app-sre-tenant/er-base-terraform-main/er-base-terraform-main:tf-1.6.6-py-3.12-v0.3.2-1 AS base
22
# keep in sync with pyproject.toml
3-
LABEL konflux.additional-tags="0.4.0"
3+
LABEL konflux.additional-tags="0.5.0"
44

55
FROM base AS builder
66
COPY --from=ghcr.io/astral-sh/uv:0.5.25@sha256:a73176b27709bff700a1e3af498981f31a83f27552116f21ae8371445f0be710 /uv /bin/uv

Makefile

+1-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ format:
88

99
.PHONY: image_tests
1010
image_tests:
11-
# validate_plan.py must exist
12-
[ -f "hooks/pre_plan.py" ]
1311
[ -f "hooks/post_plan.py" ]
1412

1513
.PHONY: code_tests
@@ -22,6 +20,7 @@ code_tests:
2220
.PHONY: terraform_tests
2321
terraform_tests:
2422
terraform fmt -check -diff module/
23+
2524
.PHONY: test
2625
test: image_tests code_tests terraform_tests
2726

er_aws_rds/config.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
from external_resources_io.input import (
2-
create_backend_tf_file,
3-
create_tf_vars_json,
42
parse_model,
53
read_input_from_file,
64
)
5+
from external_resources_io.terraform.generators import (
6+
create_backend_tf_file,
7+
create_tf_vars_json,
8+
)
79

810
from er_aws_rds.input import AppInterfaceInput, TerraformModuleData
911

hooks/post_plan.py

+25-11
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ def resource_creations(self) -> list[ResourceChange]:
6969
if c.change and Action.ActionCreate in c.change.actions
7070
]
7171

72+
@property
73+
def aws_db_instance_creations(self) -> list[ResourceChange]:
74+
"Gets the RDS isntance creations"
75+
return [c for c in self.resource_creations if c.type == "aws_db_instance"]
76+
7277
@property
7378
def aws_db_instance_updates(self) -> list[ResourceChange]:
7479
"Gets the RDS isntance updates"
@@ -79,7 +84,19 @@ def aws_db_instance_deletions(self) -> list[ResourceChange]:
7984
"Gets the RDS instance deletions"
8085
return [c for c in self.resource_deletions if c.type == "aws_db_instance"]
8186

82-
def _validate_major_version_upgrade(self) -> None:
87+
def _validate_version_on_create(self) -> None:
88+
"""Validates the RDS instance desired version (new instance)"""
89+
for u in self.aws_db_instance_creations:
90+
if not u.change or not u.change.after:
91+
continue
92+
engine = u.change.after["engine"]
93+
version = u.change.after["engine_version"]
94+
if not self.aws_api.is_rds_engine_version_available(
95+
engine=engine, version=version
96+
):
97+
self.errors.append(f"{engine} version {version} is not available.")
98+
99+
def _validate_version_upgrade(self) -> None:
83100
for u in self.aws_db_instance_updates:
84101
if not u.change or not u.change.before or not u.change.after:
85102
continue
@@ -94,7 +111,7 @@ def _validate_major_version_upgrade(self) -> None:
94111
"Engine version cannot be updated. "
95112
f"Current_version: {current_version}, "
96113
f"Desired_version: {desired_version}, "
97-
f"Valid update versions: %{valid_update_versions}"
114+
f"Valid update versions: {valid_update_versions}"
98115
)
99116

100117
# Major version upgrade validation
@@ -122,7 +139,7 @@ def _validate_deletion_protection_not_enabled_on_destroy(self) -> None:
122139
)
123140

124141
def _validate_resource_renaming(self) -> None:
125-
# is it a rename?
142+
# This validation was used to migrate resources from CDKTF to HCL
126143
if (
127144
len(self.resource_deletions) != 0
128145
and len(self.resource_creations) != 0
@@ -133,12 +150,11 @@ def _validate_resource_renaming(self) -> None:
133150
):
134151
self.errors.append("Deletions and Creations mismatch")
135152

136-
def validate(self, *, exclude_deletion_protection_test: bool = False) -> bool:
153+
def validate(self) -> bool:
137154
"""Validate method"""
138-
self._validate_major_version_upgrade()
139-
if not exclude_deletion_protection_test:
140-
self._validate_deletion_protection_not_enabled_on_destroy()
141-
self._validate_resource_renaming()
155+
self._validate_version_on_create()
156+
self._validate_version_upgrade()
157+
self._validate_deletion_protection_not_enabled_on_destroy()
142158
return not self.errors
143159

144160

@@ -157,9 +173,7 @@ def validate(self, *, exclude_deletion_protection_test: bool = False) -> bool:
157173
logger.info("Running RDS terraform plan validation")
158174
parser = TerraformJsonPlanParser(plan_path=terraform_plan_json)
159175
validator = RDSPlanValidator(parser.plan, app_interface_input)
160-
# Excluding this test temporary to migrate from CDKTF
161-
# Remove this once all resources have been migrated to Terraform
162-
if not validator.validate(exclude_deletion_protection_test=True):
176+
if not validator.validate():
163177
logger.error(validator.errors)
164178
sys.exit(1)
165179
else:

hooks/pre_plan.py

-87
This file was deleted.

hooks/utils/aws_api.py

+10
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,16 @@ def get_rds_client(self) -> RDSClient:
2020
"""Gets a boto RDS client"""
2121
return self.session.client("rds", config=self.config)
2222

23+
def is_rds_engine_version_available(self, engine: str, version: str) -> bool:
24+
"""Gets the available versions for an Rds engine"""
25+
data = (
26+
self.get_rds_client()
27+
.describe_db_engine_versions(Engine=engine, EngineVersion=version)
28+
.get("DBEngineVersions", [])
29+
)
30+
31+
return len(data) == 1 and data[0].get("EngineVersion") == version
32+
2333
def get_rds_valid_update_versions(self, engine: str, version: str) -> set[str]:
2434
"""Gets the valid update versions"""
2535
data = self.get_rds_client().describe_db_engine_versions(

pyproject.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
[project]
22
name = "er-aws-rds"
3-
version = "0.1.0"
3+
version = "0.5.0"
44
description = "ERv2 module for managing AWS rds instances"
55
authors = [{ name = "AppSRE", email = "[email protected]" }]
66
license = { text = "Apache 2.0" }
77
readme = "README.md"
88
requires-python = "~= 3.12.0"
99
dependencies = [
1010
"boto3 ~=1.35.47",
11-
"external-resources-io ~=0.4.0",
11+
"external-resources-io ~=0.6.0",
1212
"mypy_boto3_rds ~=1.35.72",
1313
"pip>=25.0",
1414
"pydantic ~=2.10.0",

tests/test_plan_validation.py

+68-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,79 @@
1+
from typing import Any
2+
from unittest.mock import Mock, patch
3+
4+
import boto3
5+
import pytest
16
from external_resources_io.terraform import Action, Plan
27

38
from hooks.post_plan import RDSPlanValidator
9+
from hooks.utils.aws_api import AWSApi
410

511
from .conftest import input_object
612

713

14+
@pytest.fixture
15+
def new_instance_plan() -> dict[str, Any]:
16+
"Return a plan for an rds instance creation"
17+
return {
18+
"resource_changes": [
19+
{
20+
"type": "aws_db_instance",
21+
"change": {
22+
"actions": [Action.ActionCreate],
23+
"before": None,
24+
"after": {
25+
"engine": "postgres",
26+
"engine_version": "16.1",
27+
"deletion_protection": False,
28+
},
29+
"after_unknown": None,
30+
},
31+
}
32+
]
33+
}
34+
35+
36+
@pytest.fixture
37+
def rds_client_mock() -> Mock:
38+
"""Return a mock of the boto3 rds client"""
39+
return Mock(boto3.client("rds", region_name="us-east-1"))
40+
41+
42+
def test_validate_desired_version_ok(
43+
new_instance_plan: dict[str, Any], rds_client_mock: Mock
44+
) -> None:
45+
"""Test engine version available in AWS"""
46+
rds_client_mock.describe_db_engine_versions.return_value = {
47+
"DBEngineVersions": [
48+
{"EngineVersion": "16.1"},
49+
]
50+
}
51+
52+
with patch.object(AWSApi, "get_rds_client", return_value=rds_client_mock):
53+
plan = Plan.model_validate(new_instance_plan)
54+
validator = RDSPlanValidator(plan, input_object())
55+
validator.validate()
56+
assert validator.errors == []
57+
58+
59+
def test_validate_desired_version_nok(
60+
new_instance_plan: dict[str, Any], rds_client_mock: Mock
61+
) -> None:
62+
"""Test engine version not available in AWS"""
63+
rds_client_mock.describe_db_engine_versions.return_value = {
64+
"DBEngineVersions": [
65+
{"EngineVersion": "16.2"},
66+
]
67+
}
68+
with patch.object(AWSApi, "get_rds_client", return_value=rds_client_mock):
69+
plan = Plan.model_validate(new_instance_plan)
70+
validator = RDSPlanValidator(plan, input_object())
71+
validator.validate()
72+
assert validator.errors == ["postgres version 16.1 is not available."]
73+
74+
875
def test_validate_deletion_protection_not_enabled_on_destroy() -> None:
9-
"""Test deletion protection is not enabled on destroy"""
76+
"""Test instance deletion protection is not set when destroying the instance"""
1077
plan = Plan.model_validate({
1178
"resource_changes": [
1279
{

0 commit comments

Comments
 (0)