Skip to content

Commit

Permalink
Add Backup resource custom hooks, terminalCodes and e2e tests
Browse files Browse the repository at this point in the history
Part of aws-controllers-k8s/community#803

Description of changes:
- Add custom hooks, terminalCodes to `GlobalTable` 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.
  • Loading branch information
a-hilaly committed Jun 17, 2021
1 parent 6177f8a commit ec50cc9
Show file tree
Hide file tree
Showing 6 changed files with 260 additions and 1 deletion.
5 changes: 5 additions & 0 deletions generator.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ operations:
UpdateGlobalTable:
operation_type: Delete
resource_name: GlobalTable
DescribeBackup:
output_wrapper_field_path: BackupDescription.BackupDetails
resources:
Table:
exceptions:
Expand Down Expand Up @@ -32,3 +34,6 @@ resources:
errors:
404:
code: BackupNotFoundException
hooks:
sdk_read_one_post_set_output:
template_path: hooks/backup/sdk_read_one_post_set_output.go.tpl
60 changes: 60 additions & 0 deletions pkg/resource/backup/hooks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// 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.

package backup

import (
"errors"

ackrequeue "github.com/aws-controllers-k8s/runtime/pkg/requeue"

"github.com/aws-controllers-k8s/dynamodb-controller/apis/v1alpha1"
)

var (
// TerminalStatuses are the status strings that are terminal states for a
// backup.
TerminalStatuses = []v1alpha1.BackupStatus_SDK{}
)

var (
requeueWaitWhileCreating = ackrequeue.NeededAfter(
errors.New("Backup in 'CREATING' state, cannot be modified or deleted."),
ackrequeue.DefaultRequeueAfterDuration,
)
)

// backupHasTerminalStatus returns whether the supplied backup is in a
// terminal state
func backupHasTerminalStatus(r *resource) bool {
if r.ko.Status.BackupStatus == nil {
return false
}
ts := *r.ko.Status.BackupStatus
for _, s := range TerminalStatuses {
if ts == string(s) {
return true
}
}
return false
}

// isBackupCreating returns true if the supplied Dynamodb backup is in the process
// of being created
func isBackupCreating(r *resource) bool {
if r.ko.Status.BackupStatus == nil {
return false
}
dbis := *r.ko.Status.BackupStatus
return dbis == string(v1alpha1.BackupStatus_SDK_CREATING)
}
43 changes: 42 additions & 1 deletion pkg/resource/backup/sdk.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions templates/hooks/backup/sdk_read_one_post_set_output.go.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
if isBackupCreating(&resource{ko}) {
return &resource{ko}, requeueWaitWhileCreating
}
7 changes: 7 additions & 0 deletions test/e2e/resources/backup.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiVersion: dynamodb.services.k8s.aws/v1alpha1
kind: Backup
metadata:
name: $BACKUP_NAME
spec:
backupName: $BACKUP_NAME
tableName: $TABLE_NAME
143 changes: 143 additions & 0 deletions test/e2e/tests/test_backup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
# 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 boto3
import pytest
import time
import logging
from typing import Dict, Tuple

from acktest.resources import random_suffix_name
from acktest.k8s import resource as k8s
from acktest.aws.identity import get_region
from e2e import (
service_marker,
CRD_GROUP,
CRD_VERSION,
load_dynamodb_resource,
wait_for_cr_status,
)
from e2e.replacement_values import REPLACEMENT_VALUES

RESOURCE_PLURAL = "backups"

DELETE_WAIT_AFTER_SECONDS = 10

@pytest.fixture(scope="module")
def dynamodb_client():
return boto3.client("dynamodb")

@pytest.fixture(scope="module")
def dynamodb_table():
resource_name = random_suffix_name("table", 32)

replacements = REPLACEMENT_VALUES.copy()
replacements["TABLE_NAME"] = resource_name

# load resource
resource_data = load_dynamodb_resource(
"table_forums",
additional_replacements=replacements,
)

table_reference = k8s.CustomResourceReference(
CRD_GROUP, CRD_VERSION, "tables",
resource_name, namespace="default",
)

# Create table
k8s.create_custom_resource(table_reference, resource_data)
table_resource = k8s.wait_resource_consumed_by_controller(table_reference)

assert table_resource is not None
assert k8s.get_resource_exists(table_reference)

wait_for_cr_status(
table_reference,
"tableStatus",
"ACTIVE",
10,
30,
)

yield (table_reference, table_resource)

_, deleted = k8s.delete_custom_resource(table_reference)
assert deleted

@service_marker
@pytest.mark.canary
class TestBackup:
def get_backup(self, dynamodb_client, backup_arn: str) -> dict:
try:
resp = dynamodb_client.describe_backup(
BackupArn=backup_arn,
)
return resp["BackupDescription"]

except Exception as e:
logging.debug(e)
return None

def backup_exists(self, dynamodb_client, backup_arn: str) -> bool:
return self.get_backup(dynamodb_client, backup_arn) is not None

def test_smoke(self, dynamodb_client, dynamodb_table):
(_, table_resource) = dynamodb_table
resource_name = random_suffix_name("backup", 32)
table_name = table_resource["spec"]["tableName"]

replacements = REPLACEMENT_VALUES.copy()
replacements["TABLE_NAME"] = table_name
replacements["BACKUP_NAME"] = resource_name

# Load Backup CR
resource_data = load_dynamodb_resource(
"backup",
additional_replacements=replacements,
)
logging.debug(resource_data)

# Create 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)

wait_for_cr_status(
ref,
"backupStatus",
"AVAILABLE",
10,
5,
)

backupArn = k8s.get_resource_arn(cr)
# Check DynamoDB Backup exists
exists = self.backup_exists(dynamodb_client, backupArn)
assert exists

# Delete k8s resource
_, deleted = k8s.delete_custom_resource(ref)
assert deleted is True

time.sleep(DELETE_WAIT_AFTER_SECONDS)

# Check DynamoDB Backup doesn't exists
exists = self.backup_exists(dynamodb_client, backupArn)
assert not exists

0 comments on commit ec50cc9

Please sign in to comment.