Skip to content

Commit 589cde3

Browse files
authored
Add Backup resource custom hooks, terminalCodes and e2e tests (#5)
Part of aws-controllers-k8s/community#803 Description of changes: - Add custom hooks, terminalCodes to `Backup` resource in `generator.yaml` - Add e2e tests for `Backup` create and delete operations By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
1 parent 6177f8a commit 589cde3

File tree

6 files changed

+260
-1
lines changed

6 files changed

+260
-1
lines changed

generator.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ operations:
22
UpdateGlobalTable:
33
operation_type: Delete
44
resource_name: GlobalTable
5+
DescribeBackup:
6+
output_wrapper_field_path: BackupDescription.BackupDetails
57
resources:
68
Table:
79
exceptions:
@@ -32,3 +34,6 @@ resources:
3234
errors:
3335
404:
3436
code: BackupNotFoundException
37+
hooks:
38+
sdk_read_one_post_set_output:
39+
template_path: hooks/backup/sdk_read_one_post_set_output.go.tpl

pkg/resource/backup/hooks.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License"). You may
4+
// not use this file except in compliance with the License. A copy of the
5+
// License is located at
6+
//
7+
// http://aws.amazon.com/apache2.0/
8+
//
9+
// or in the "license" file accompanying this file. This file is distributed
10+
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
11+
// express or implied. See the License for the specific language governing
12+
// permissions and limitations under the License.
13+
14+
package backup
15+
16+
import (
17+
"errors"
18+
19+
ackrequeue "github.com/aws-controllers-k8s/runtime/pkg/requeue"
20+
21+
"github.com/aws-controllers-k8s/dynamodb-controller/apis/v1alpha1"
22+
)
23+
24+
var (
25+
// TerminalStatuses are the status strings that are terminal states for a
26+
// backup.
27+
TerminalStatuses = []v1alpha1.BackupStatus_SDK{}
28+
)
29+
30+
var (
31+
requeueWaitWhileCreating = ackrequeue.NeededAfter(
32+
errors.New("Backup in 'CREATING' state, cannot be modified or deleted."),
33+
ackrequeue.DefaultRequeueAfterDuration,
34+
)
35+
)
36+
37+
// backupHasTerminalStatus returns whether the supplied backup is in a
38+
// terminal state
39+
func backupHasTerminalStatus(r *resource) bool {
40+
if r.ko.Status.BackupStatus == nil {
41+
return false
42+
}
43+
ts := *r.ko.Status.BackupStatus
44+
for _, s := range TerminalStatuses {
45+
if ts == string(s) {
46+
return true
47+
}
48+
}
49+
return false
50+
}
51+
52+
// isBackupCreating returns true if the supplied Dynamodb backup is in the process
53+
// of being created
54+
func isBackupCreating(r *resource) bool {
55+
if r.ko.Status.BackupStatus == nil {
56+
return false
57+
}
58+
dbis := *r.ko.Status.BackupStatus
59+
return dbis == string(v1alpha1.BackupStatus_SDK_CREATING)
60+
}

pkg/resource/backup/sdk.go

Lines changed: 42 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
if isBackupCreating(&resource{ko}) {
2+
return &resource{ko}, requeueWaitWhileCreating
3+
}

test/e2e/resources/backup.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
apiVersion: dynamodb.services.k8s.aws/v1alpha1
2+
kind: Backup
3+
metadata:
4+
name: $BACKUP_NAME
5+
spec:
6+
backupName: $BACKUP_NAME
7+
tableName: $TABLE_NAME

test/e2e/tests/test_backup.py

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License"). You may
4+
# not use this file except in compliance with the License. A copy of the
5+
# License is located at
6+
#
7+
# http://aws.amazon.com/apache2.0/
8+
#
9+
# or in the "license" file accompanying this file. This file is distributed
10+
# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
11+
# express or implied. See the License for the specific language governing
12+
# permissions and limitations under the License.
13+
14+
import boto3
15+
import pytest
16+
import time
17+
import logging
18+
from typing import Dict, Tuple
19+
20+
from acktest.resources import random_suffix_name
21+
from acktest.k8s import resource as k8s
22+
from acktest.aws.identity import get_region
23+
from e2e import (
24+
service_marker,
25+
CRD_GROUP,
26+
CRD_VERSION,
27+
load_dynamodb_resource,
28+
wait_for_cr_status,
29+
)
30+
from e2e.replacement_values import REPLACEMENT_VALUES
31+
32+
RESOURCE_PLURAL = "backups"
33+
34+
DELETE_WAIT_AFTER_SECONDS = 10
35+
36+
@pytest.fixture(scope="module")
37+
def dynamodb_client():
38+
return boto3.client("dynamodb")
39+
40+
@pytest.fixture(scope="module")
41+
def dynamodb_table():
42+
resource_name = random_suffix_name("table", 32)
43+
44+
replacements = REPLACEMENT_VALUES.copy()
45+
replacements["TABLE_NAME"] = resource_name
46+
47+
# load resource
48+
resource_data = load_dynamodb_resource(
49+
"table_forums",
50+
additional_replacements=replacements,
51+
)
52+
53+
table_reference = k8s.CustomResourceReference(
54+
CRD_GROUP, CRD_VERSION, "tables",
55+
resource_name, namespace="default",
56+
)
57+
58+
# Create table
59+
k8s.create_custom_resource(table_reference, resource_data)
60+
table_resource = k8s.wait_resource_consumed_by_controller(table_reference)
61+
62+
assert table_resource is not None
63+
assert k8s.get_resource_exists(table_reference)
64+
65+
wait_for_cr_status(
66+
table_reference,
67+
"tableStatus",
68+
"ACTIVE",
69+
10,
70+
30,
71+
)
72+
73+
yield (table_reference, table_resource)
74+
75+
_, deleted = k8s.delete_custom_resource(table_reference)
76+
assert deleted
77+
78+
@service_marker
79+
@pytest.mark.canary
80+
class TestBackup:
81+
def get_backup(self, dynamodb_client, backup_arn: str) -> dict:
82+
try:
83+
resp = dynamodb_client.describe_backup(
84+
BackupArn=backup_arn,
85+
)
86+
return resp["BackupDescription"]
87+
88+
except Exception as e:
89+
logging.debug(e)
90+
return None
91+
92+
def backup_exists(self, dynamodb_client, backup_arn: str) -> bool:
93+
return self.get_backup(dynamodb_client, backup_arn) is not None
94+
95+
def test_smoke(self, dynamodb_client, dynamodb_table):
96+
(_, table_resource) = dynamodb_table
97+
resource_name = random_suffix_name("backup", 32)
98+
table_name = table_resource["spec"]["tableName"]
99+
100+
replacements = REPLACEMENT_VALUES.copy()
101+
replacements["TABLE_NAME"] = table_name
102+
replacements["BACKUP_NAME"] = resource_name
103+
104+
# Load Backup CR
105+
resource_data = load_dynamodb_resource(
106+
"backup",
107+
additional_replacements=replacements,
108+
)
109+
logging.debug(resource_data)
110+
111+
# Create k8s resource
112+
ref = k8s.CustomResourceReference(
113+
CRD_GROUP, CRD_VERSION, RESOURCE_PLURAL,
114+
resource_name, namespace="default",
115+
)
116+
k8s.create_custom_resource(ref, resource_data)
117+
cr = k8s.wait_resource_consumed_by_controller(ref)
118+
119+
assert cr is not None
120+
assert k8s.get_resource_exists(ref)
121+
122+
wait_for_cr_status(
123+
ref,
124+
"backupStatus",
125+
"AVAILABLE",
126+
10,
127+
5,
128+
)
129+
130+
backupArn = k8s.get_resource_arn(cr)
131+
# Check DynamoDB Backup exists
132+
exists = self.backup_exists(dynamodb_client, backupArn)
133+
assert exists
134+
135+
# Delete k8s resource
136+
_, deleted = k8s.delete_custom_resource(ref)
137+
assert deleted is True
138+
139+
time.sleep(DELETE_WAIT_AFTER_SECONDS)
140+
141+
# Check DynamoDB Backup doesn't exists
142+
exists = self.backup_exists(dynamodb_client, backupArn)
143+
assert not exists

0 commit comments

Comments
 (0)