Skip to content

Commit

Permalink
simple smoke test for RDS DB subnet group
Browse files Browse the repository at this point in the history
This also includes a quick fix to tests/e2e/run-tests.sh that was
referring to the wrong variable name.

``
[jaypipes@thelio community]$ TEST_HELM_CHARTS=false make kind-test SERVICE=rds AWS_ROLE_ARN=$ROLE_ARN
checking AWS credentials ... ok.
creating kind cluster ack-test-7444685b-c9f2a7d8 ... ok.
<snip>
loading the images into the cluster ... ok.
loading CRD manifests for rds into the cluster ... ok.
loading RBAC manifests for rds into the cluster ... ok.
loading service controller Deployment for rds into the cluster ...ok.
generating AWS temporary credentials and adding to env vars map ... ok.
======================================================================================================
To poke around your test cluster manually:
export KUBECONFIG=/home/jaypipes/go/src/github.com/aws-controllers-k8s/community/scripts/lib/../../build/tmp-ack-test-7444685b-c9f2a7d8/kubeconfig
kubectl get pods -A
======================================================================================================
running python tests in Docker...
running python tests locally...
INFO:root:Created VPC vpc-02d017b23f7443c8e
INFO:root:Created VPC Subnet subnet-0c2e1b19c1bd32133 in AZ us-west-2a
INFO:root:Created VPC Subnet subnet-0f5a98b367898b437 in AZ us-west-2b
INFO:root:Wrote bootstrap to /root/tests/rds/bootstrap.yaml
============================================================================================================ test session starts ============================================================================================================
platform linux -- Python 3.8.8, pytest-6.1.2, py-1.9.0, pluggy-0.13.1
rootdir: /root/tests
plugins: forked-1.3.0, xdist-2.2.0
[gw0] Python 3.8.8 (default, Feb 19 2021, 18:07:06)  -- [GCC 8.3.0]
[gw1] Python 3.8.8 (default, Feb 19 2021, 18:07:06)  -- [GCC 8.3.0]
[gw2] Python 3.8.8 (default, Feb 19 2021, 18:07:06)  -- [GCC 8.3.0]
[gw3] Python 3.8.8 (default, Feb 19 2021, 18:07:06)  -- [GCC 8.3.0]
[gw6] Python 3.8.8 (default, Feb 19 2021, 18:07:06)  -- [GCC 8.3.0]
[gw5] Python 3.8.8 (default, Feb 19 2021, 18:07:06)  -- [GCC 8.3.0]
[gw4] Python 3.8.8 (default, Feb 19 2021, 18:07:06)  -- [GCC 8.3.0]
[gw7] Python 3.8.8 (default, Feb 19 2021, 18:07:06)  -- [GCC 8.3.0]
gw0 [1] / gw1 [1] / gw2 [1] / gw3 [1] / gw4 [1] / gw5 [1] / gw6 [1] / gw7 [1]
scheduling tests via LoadFileScheduling

rds/tests/test_db_subnet_group.py::TestDBSubnetgroup::test_create_delete_2az
[gw0] [100%] PASSED rds/tests/test_db_subnet_group.py::TestDBSubnetgroup::test_create_delete_2az

============================================================================================================ 1 passed in 37.52s =============================================================================================================
INFO:root:Deleted VPC Subnet subnet-0c2e1b19c1bd32133
INFO:root:Deleted VPC Subnet subnet-0f5a98b367898b437
INFO:root:Deleted VPC vpc-02d017b23f7443c8e
To resume test with the same cluster use: " TMP_DIR=/home/jaypipes/go/src/github.com/aws-controllers-k8s/community/scripts/lib/../../build/tmp-ack-test-7444685b-c9f2a7d8
    AWS_SERVICE_DOCKER_IMG=aws-controllers-k8s:rds-v0.0.2-78-ge78e3cd-dirty "
[jaypipes@thelio community]$
```

Issue aws-controllers-k8s#237
  • Loading branch information
jaypipes committed Mar 22, 2021
1 parent e78e3cd commit 688e884
Show file tree
Hide file tree
Showing 9 changed files with 387 additions and 4 deletions.
21 changes: 21 additions & 0 deletions test/e2e/rds/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You may
# not use this file except in compliance with the License. A copy of the
# License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is distributed
# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
# express or implied. See the License for the specific language governing
# permissions and limitations under the License.

import pytest

SERVICE_NAME = "rds"
CRD_GROUP = "rds.services.k8s.aws"
CRD_VERSION = "v1alpha1"

# PyTest marker for the current service
service_marker = pytest.mark.service(arg=SERVICE_NAME)
40 changes: 40 additions & 0 deletions test/e2e/rds/bootstrap_resources.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You may
# not use this file except in compliance with the License. A copy of the
# License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is distributed
# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
# express or implied. See the License for the specific language governing
# permissions and limitations under the License.

"""Declares the structure of the bootstrapped resources and provides a loader
for them.
"""

from rds import SERVICE_NAME
from common.resources import read_bootstrap_config
from dataclasses import dataclass

VPC_CIDR = "10.0.81.0/27"
SUBNET_AZ1_CIDR = "10.0.81.0/28"
SUBNET_AZ2_CIDR = "10.0.81.16/28"

@dataclass
class TestBootstrapResources:
VPCID: str
SubnetAZ1: str
SubnetAZ2: str

_bootstrap_resources = None

def get_bootstrap_resources():
global _bootstrap_resources
if _bootstrap_resources is None:
_bootstrap_resources = TestBootstrapResources(
**read_bootstrap_config(SERVICE_NAME),
)
return _bootstrap_resources
19 changes: 19 additions & 0 deletions test/e2e/rds/replacement_values.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You may
# not use this file except in compliance with the License. A copy of the
# License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is distributed
# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
# express or implied. See the License for the specific language governing
# permissions and limitations under the License.

"""Stores the values used by each of the integration tests for replacing the
RDS-specific test variables.
"""

REPLACEMENT_VALUES = {
}
13 changes: 13 additions & 0 deletions test/e2e/rds/resources/db_subnet_group_2az.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
apiVersion: rds.services.k8s.aws/v1alpha1
kind: DBSubnetGroup
metadata:
name: $DB_SUBNET_GROUP_NAME
spec:
name: $DB_SUBNET_GROUP_NAME
description: $DB_SUBNET_GROUP_DESC
subnetIDs:
- $SUBNET_AZ1
- $SUBNET_AZ2
tags:
- key: key1
value: value1
110 changes: 110 additions & 0 deletions test/e2e/rds/service_bootstrap.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You may
# not use this file except in compliance with the License. A copy of the
# License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is distributed
# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
# express or implied. See the License for the specific language governing
# permissions and limitations under the License.
"""Bootstraps the resources required to run the SageMaker integration tests.
"""

import boto3
import logging
import time

from common.aws import get_aws_account_id, get_aws_region, duplicate_s3_contents
from rds.bootstrap_resources import (
TestBootstrapResources,
VPC_CIDR,
SUBNET_AZ1_CIDR,
SUBNET_AZ2_CIDR,
)


def create_vpc() -> str:
region = get_aws_region()
ec2 = boto3.client("ec2", region_name=region)

logging.debug(f"Creating VPC with CIDR {VPC_CIDR}")

resp = ec2.create_vpc(
CidrBlock=VPC_CIDR,
)
vpc_id = resp['Vpc']['VpcId']

# TODO(jaypipes): Put a proper waiter here...
time.sleep(3)

vpcs = ec2.describe_vpcs(VpcIds=[vpc_id])
if len(vpcs['Vpcs']) != 1:
raise RuntimeError(
f"failed to describe VPC we just created '{vpc_id}'",
)

vpc = vpcs['Vpcs'][0]
vpc_state = vpc['State']
if vpc_state != "available":
raise RuntimeError(
f"VPC we just created '{vpc_id}' is not available. current state: {vpc_state}",
)

logging.info(f"Created VPC {vpc_id}")

return vpc_id


def create_subnet(vpc_id: str, az_id: str, cidr: str) -> str:
region = get_aws_region()
ec2 = boto3.client("ec2", region_name=region)

logging.debug(f"Creating subnet with CIDR {cidr} in AZ {az_id}")

resp = ec2.create_subnet(
VpcId=vpc_id,
AvailabilityZone=az_id,
CidrBlock=cidr,
)
subnet_id = resp['Subnet']['SubnetId']

# TODO(jaypipes): Put a proper waiter here...
time.sleep(3)

subnets = ec2.describe_subnets(SubnetIds=[subnet_id])
if len(subnets['Subnets']) != 1:
raise RuntimeError(
f"failed to describe subnet we just created '{subnet_id}'",
)

subnet = subnets['Subnets'][0]
subnet_state = subnet['State']
if subnet_state != "available":
raise RuntimeError(
f"Subnet we just created '{subnet_id}' is not available. current state: {subnet_state}",
)

logging.info(f"Created VPC Subnet {subnet_id} in AZ {az_id}")

return subnet_id


def service_bootstrap() -> dict:
logging.getLogger().setLevel(logging.INFO)
region = get_aws_region()

vpc_id = create_vpc()
az1 = f"{region}a"
subnet_az1_id = create_subnet(vpc_id, az1, SUBNET_AZ1_CIDR)
az2 = f"{region}b"
subnet_az2_id = create_subnet(vpc_id, az2, SUBNET_AZ2_CIDR)


return TestBootstrapResources(
vpc_id,
subnet_az1_id,
subnet_az2_id,
).__dict__
61 changes: 61 additions & 0 deletions test/e2e/rds/service_cleanup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You may
# not use this file except in compliance with the License. A copy of the
# License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is distributed
# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
# express or implied. See the License for the specific language governing
# permissions and limitations under the License.

"""Cleans up the resources created by the bootstrapping process.
"""

import boto3
import logging
from common.aws import get_aws_region
from rds.bootstrap_resources import TestBootstrapResources


def delete_subnet(subnet_id: str):
region = get_aws_region()
ec2 = boto3.client("ec2", region_name=region)

ec2.delete_subnet(SubnetId=subnet_id)

logging.info(f"Deleted VPC Subnet {subnet_id}")


def delete_vpc(vpc_id: str):
region = get_aws_region()
ec2 = boto3.client("ec2", region_name=region)

ec2.delete_vpc(VpcId=vpc_id)

logging.info(f"Deleted VPC {vpc_id}")


def service_cleanup(config: dict):
logging.getLogger().setLevel(logging.INFO)

resources = TestBootstrapResources(
**config
)

try:
delete_subnet(resources.SubnetAZ1)
except:
logging.exception(f"Unable to delete VPC subnet {resources.SubnetAZ1}")

try:
delete_subnet(resources.SubnetAZ2)
except:
logging.exception(f"Unable to delete VPC subnet {resources.SubnetAZ2}")

try:
delete_vpc(resources.VPCID)
except:
logging.exception(f"Unable to delete VPC {resources.VPCID}")
12 changes: 12 additions & 0 deletions test/e2e/rds/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You may
# not use this file except in compliance with the License. A copy of the
# License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is distributed
# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
# express or implied. See the License for the specific language governing
# permissions and limitations under the License.
109 changes: 109 additions & 0 deletions test/e2e/rds/tests/test_db_subnet_group.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You may
# not use this file except in compliance with the License. A copy of the
# License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is distributed
# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
# express or implied. See the License for the specific language governing
# permissions and limitations under the License.

"""Integration tests for the RDS API DBSubnetGroup resource
"""

import boto3
import datetime
import logging
import time
from typing import Dict

import pytest

from rds import SERVICE_NAME, service_marker, CRD_GROUP, CRD_VERSION
from rds.bootstrap_resources import get_bootstrap_resources
from rds.replacement_values import REPLACEMENT_VALUES
from common.resources import load_resource_file, random_suffix_name
from common import k8s

RESOURCE_PLURAL = 'dbsubnetgroups'

DELETE_WAIT_AFTER_SECONDS = 20
CREATE_INTERVAL_SLEEP_SECONDS = 15
# Time to wait before we get to an expected RUNNING state.
# In my experience, it regularly takes more than 6 minutes to create a
# single-instance RabbitMQ broker...
CREATE_TIMEOUT_SECONDS = 600


@pytest.fixture(scope="module")
def rds_client():
return boto3.client('rds')


@service_marker
@pytest.mark.canary
class TestDBSubnetgroup:
def test_create_delete_2az(self, rds_client):
resource_name = "my-subnet-group"
resource_desc = "my-subnet-group description"

br_resources = get_bootstrap_resources()

replacements = REPLACEMENT_VALUES.copy()
replacements["DB_SUBNET_GROUP_NAME"] = resource_name
replacements["DB_SUBNET_GROUP_DESC"] = resource_desc
replacements["SUBNET_AZ1"] = br_resources.SubnetAZ1
replacements["SUBNET_AZ2"] = br_resources.SubnetAZ2

resource_data = load_resource_file(
SERVICE_NAME,
"db_subnet_group_2az",
additional_replacements=replacements,
)
logging.debug(resource_data)

# Create the k8s resource
ref = k8s.CustomResourceReference(
CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL,
resource_name, namespace="default",
)
k8s.create_custom_resource(ref, resource_data)
cr = k8s.wait_resource_consumed_by_controller(ref)

assert cr is not None
assert k8s.get_resource_exists(ref)

# Let's check that the DB subnet group appears in RDS
aws_res = rds_client.describe_db_subnet_groups(DBSubnetGroupName=resource_name)
assert aws_res is not None
assert len(aws_res['DBSubnetGroups']) == 1

now = datetime.datetime.now()
timeout = now + datetime.timedelta(seconds=CREATE_TIMEOUT_SECONDS)

# TODO(jaypipes): Move this into generic AWS-side waiter
while aws_res['DBSubnetGroups'][0]['SubnetGroupStatus'] != "Complete":
if datetime.datetime.now() >= timeout:
raise Exception("failed to find DB subnet group in Complete status before timeout")
time.sleep(CREATE_INTERVAL_SLEEP_SECONDS)
aws_res = rds_client.describe_db_subnet_groups(DBSubnetGroupName=resource_name)
assert aws_res is not None
assert len(aws_res['DBSubnetGroups']) == 1

# Delete the k8s resource on teardown of the module
k8s.delete_custom_resource(ref)

time.sleep(DELETE_WAIT_AFTER_SECONDS)

# DB subnet group should no longer appear in RDS
res_found = False
try:
aws_res = rds_client.describe_db_subnet_groups(DBSubnetGroupName=resource_name)
res_found = True
except rds_client.exceptions.DBSubnetGroupNotFoundFault:
pass

assert res_found is False
Loading

0 comments on commit 688e884

Please sign in to comment.