Skip to content

Commit a946a32

Browse files
Enhance delete workflow
Signed-off-by: Carlos Eduardo Arango Gutierrez <[email protected]>
1 parent 8968eb8 commit a946a32

11 files changed

Lines changed: 228 additions & 166 deletions

File tree

.github/workflows/e2e.yml

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,27 @@ jobs:
2828
runs-on: pdx01-arc-runners
2929
if: ${{ github.event.workflow_run.conclusion == 'success' }} && ${{ github.event.workflow_run.event == 'push' }}
3030
steps:
31-
- uses: actions/checkout@v4
32-
name: Checkout code
31+
- name: Checkout code
32+
uses: actions/checkout@v4
33+
3334
- name: Install Go
3435
uses: actions/setup-go@v5
3536
with:
3637
go-version: 'stable'
3738
check-latest: true
39+
3840
- name: Install dependencies
39-
run: sudo apt-get update && sudo apt-get install -y make
41+
run: |
42+
sudo apt-get update
43+
sudo apt-get install -y make
44+
make ginkgo
45+
4046
- name: Run e2e-aws tests
41-
run: make -f tests/Makefile e2e-aws
47+
run: ./hack/e2e_tests.sh aws
48+
4249
- name: Run e2e-vsphere tests
43-
run: make -f tests/Makefile e2e-vsphere
50+
run: ./hack/e2e_tests.sh vsphere
51+
4452
- name: Archive test logs
4553
if: ${{ failure() }}
4654
uses: actions/upload-artifact@v4

Makefile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ GO_SRC := $(shell find . -type f -name '*.go' -not -path "./vendor/*")
1717
BINARY_NAME ?= holodeck
1818

1919
VERSION := 0.0.1
20+
GINKGO_VERSION ?= $(shell $(GO_CMD) list -m -f '{{.Version}}' github.com/onsi/ginkgo/v2)
2021

2122
IMAGE_REGISTRY ?= ghcr.io/arangogutierrez
2223
IMAGE_TAG_NAME ?= $(VERSION)
@@ -67,3 +68,8 @@ controller-gen: ## Download controller-gen locally if necessary.
6768
.PHONY: manifests
6869
manifests: controller-gen
6970
$(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases
71+
72+
GINKGO = $(PROJECT_DIR)/bin/ginkgo
73+
.PHONY: ginkgo
74+
ginkgo: ## Download ginkgo locally if necessary.
75+
@GOBIN=$(PROJECT_DIR)/bin GO111MODULE=on $(GO_CMD) install github.com/onsi/ginkgo/v2/ginkgo@$(GINKGO_VERSION)

hack/e2e_tests.sh

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#!/usr/bin/env bash
2+
3+
# Copyright 2022 The Kubernetes Authors.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
set -o errexit
18+
set -o nounset
19+
set -o pipefail
20+
21+
SOURCE_DIR="$(cd "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
22+
ROOT_DIR="$SOURCE_DIR/.."
23+
24+
GINKGO="$ROOT_DIR"/bin/ginkgo
25+
GINKGO_ARGS=${GINKGO_ARGS:-}
26+
27+
CI=${CI:-"true"}
28+
29+
LOG_ARTIFACT_DIR=${LOG_ARTIFACT_DIR:-${ROOT_DIR}/e2e_logs}
30+
ENV_FILE=${ENV_FILE:-}
31+
GINKGO_FOCUS=${GINKGO_FOCUS:-}
32+
33+
if [ "$1" == "aws" ]; then
34+
ENV_FILE=${ROOT_DIR}/tests/test_aws.yml
35+
GINKGO_FOCUS=${GINKGO_FOCUS:-"AWS"}
36+
elif [ "$1" == "vsphere" ]; then
37+
ENV_FILE=${ROOT_DIR}/tests/test_vsphere.yml
38+
GINKGO_FOCUS=${GINKGO_FOCUS:-"VSPHERE"}
39+
fi
40+
41+
# Set all ENV variables for e2e tests
42+
export LOG_ARTIFACT_DIR ENV_FILE GINKGO_FOCUS CI
43+
44+
# shellcheck disable=SC2086
45+
$GINKGO $GINKGO_ARGS -v --focus $GINKGO_FOCUS ./tests/...

pkg/provider/aws/create.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,34 +30,38 @@ import (
3030
// VPC, Subnet, Internet Gateway, Route Table, Security Group
3131
func (p *Provider) Create() error {
3232
cache := new(AWS)
33-
defer p.dumpCache(cache)
3433

3534
p.updateProgressingCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Creating AWS resources")
3635

3736
if err := p.createVPC(cache); err != nil {
3837
p.updateDegradedCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Error creating VPC")
3938
return fmt.Errorf("error creating VPC: %v", err)
4039
}
40+
p.updateProgressingCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "VPC created")
4141

4242
if err := p.createSubnet(cache); err != nil {
4343
p.updateDegradedCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Error creating subnet")
4444
return fmt.Errorf("error creating subnet: %v", err)
4545
}
46+
p.updateProgressingCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Subnet created")
4647

4748
if err := p.createInternetGateway(cache); err != nil {
4849
p.updateDegradedCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Error creating Internet Gateway")
4950
return fmt.Errorf("error creating Internet Gateway: %v", err)
5051
}
52+
p.updateProgressingCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Internet Gateway created")
5153

5254
if err := p.createRouteTable(cache); err != nil {
5355
p.updateDegradedCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Error creating route table")
5456
return fmt.Errorf("error creating route table: %v", err)
5557
}
58+
p.updateProgressingCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Route Table created")
5659

5760
if err := p.createSecurityGroup(cache); err != nil {
5861
p.updateDegradedCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Error creating security group")
5962
return fmt.Errorf("error creating security group: %v", err)
6063
}
64+
p.updateProgressingCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Security Group created")
6165

6266
if err := p.createEC2Instance(cache); err != nil {
6367
p.updateDegradedCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Creating", "Error creating EC2 instance")

pkg/provider/aws/delete.go

Lines changed: 122 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package aws
1818

1919
import (
2020
"context"
21+
"errors"
2122
"fmt"
2223
"time"
2324

@@ -30,7 +31,6 @@ func (p *Provider) Delete() error {
3031
if err != nil {
3132
return fmt.Errorf("error retrieving cache: %v", err)
3233
}
33-
p.updateProgressingCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Destroying", "Destroying AWS resources")
3434

3535
if err := p.delete(cache); err != nil {
3636
return fmt.Errorf("error destroying AWS resources: %v", err)
@@ -41,99 +41,159 @@ func (p *Provider) Delete() error {
4141

4242
func (p *Provider) delete(cache *AWS) error {
4343
var err error
44+
4445
// Delete the EC2 instance
46+
p.updateProgressingCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Destroying", "Deleting EC2 instance")
4547
if cache.Instanceid == "" {
4648
p.log.Warning("No instance found to delete")
4749
} else {
48-
terminateInstancesInput := &ec2.TerminateInstancesInput{
49-
InstanceIds: []string{cache.Instanceid},
50-
}
51-
_, err := p.ec2.TerminateInstances(context.Background(), terminateInstancesInput)
52-
if err != nil {
53-
return fmt.Errorf("error deleting instance: %v", err)
50+
// call deleteEC2 3 times to ensure the instance is deleted or until it returns nil
51+
for i := 0; i < 3; i++ {
52+
err = p.deleteEC2(cache)
53+
if err == nil {
54+
break
55+
}
56+
57+
if i == 2 {
58+
p.updateDegradedCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Destroying", "Error deleting EC2 instance")
59+
return fmt.Errorf("error deleting EC2 instance: %v", err)
60+
}
5461
}
62+
}
5563

56-
p.log.Wg.Add(1)
57-
go p.log.Loading("Waiting for instance %s to be terminated", cache.Instanceid)
58-
59-
waiterOptions := []func(*ec2.InstanceTerminatedWaiterOptions){
60-
func(o *ec2.InstanceTerminatedWaiterOptions) {
61-
o.MaxDelay = 10 * time.Minute
62-
o.MinDelay = 5 * time.Second
63-
},
64-
}
65-
wait := ec2.NewInstanceTerminatedWaiter(p.ec2, waiterOptions...)
66-
if err := wait.Wait(context.Background(), &ec2.DescribeInstancesInput{
67-
InstanceIds: []string{cache.Instanceid},
68-
}, 10*time.Minute, waiterOptions...); err != nil {
69-
p.fail()
70-
return fmt.Errorf("error waiting for instance to be terminated: %v", err)
64+
// Delete the VPC
65+
p.updateProgressingCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Destroying", "Deleting VPC resources")
66+
for i := 0; i < 3; i++ {
67+
err = p.deleteVPC(cache)
68+
if err == nil {
69+
break
7170
}
7271

73-
// Delete the security group
74-
deleteSecurityGroup := &ec2.DeleteSecurityGroupInput{
75-
GroupId: &cache.SecurityGroupid,
76-
}
77-
_, err = p.ec2.DeleteSecurityGroup(context.Background(), deleteSecurityGroup)
78-
if err != nil {
79-
p.fail()
80-
return fmt.Errorf("error deleting security group: %v", err)
72+
if i == 2 {
73+
p.updateDegradedCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Destroying", "Error deleting VPC resources")
74+
return fmt.Errorf("error deleting VPC resources: %v", err)
8175
}
76+
}
77+
78+
return nil
79+
}
8280

83-
p.done()
81+
func (p *Provider) deleteEC2(cache *AWS) error {
82+
terminateInstancesInput := &ec2.TerminateInstancesInput{
83+
InstanceIds: []string{cache.Instanceid},
84+
}
85+
_, err := p.ec2.TerminateInstances(context.Background(), terminateInstancesInput)
86+
if err != nil {
87+
return fmt.Errorf("error deleting instance: %v", err)
8488
}
8589

8690
p.log.Wg.Add(1)
87-
go p.log.Loading("Deleting VPC resources")
88-
// Delete the subnet
89-
deleteSubnet := &ec2.DeleteSubnetInput{
90-
SubnetId: &cache.Subnetid,
91+
go p.log.Loading("Waiting for instance %s to be terminated", cache.Instanceid)
92+
93+
waiterOptions := []func(*ec2.InstanceTerminatedWaiterOptions){
94+
func(o *ec2.InstanceTerminatedWaiterOptions) {
95+
o.MaxDelay = 10 * time.Minute
96+
o.MinDelay = 5 * time.Second
97+
},
9198
}
92-
_, err = p.ec2.DeleteSubnet(context.Background(), deleteSubnet)
93-
if err != nil {
99+
wait := ec2.NewInstanceTerminatedWaiter(p.ec2, waiterOptions...)
100+
if err := wait.Wait(context.Background(), &ec2.DescribeInstancesInput{
101+
InstanceIds: []string{cache.Instanceid},
102+
}, 10*time.Minute, waiterOptions...); err != nil {
94103
p.fail()
95-
return fmt.Errorf("error deleting subnet: %v", err)
104+
return fmt.Errorf("error waiting for instance to be terminated: %v", err)
96105
}
97106

98-
// Delete the route tables
99-
deleteRouteTable := &ec2.DeleteRouteTableInput{
100-
RouteTableId: &cache.RouteTable,
107+
// Delete the security group
108+
deleteSecurityGroup := &ec2.DeleteSecurityGroupInput{
109+
GroupId: &cache.SecurityGroupid,
101110
}
102-
_, err = p.ec2.DeleteRouteTable(context.Background(), deleteRouteTable)
111+
_, err = p.ec2.DeleteSecurityGroup(context.Background(), deleteSecurityGroup)
103112
if err != nil {
104113
p.fail()
105-
return fmt.Errorf("error deleting route table: %v", err)
114+
return fmt.Errorf("error deleting security group: %v", err)
106115
}
107116

108-
// Detach the Internet Gateway
109-
detachInternetGateway := &ec2.DetachInternetGatewayInput{
110-
InternetGatewayId: &cache.InternetGwid,
111-
VpcId: &cache.Vpcid,
117+
p.done()
118+
return nil
119+
}
120+
121+
func (p *Provider) deleteVPC(cache *AWS) error {
122+
var err error
123+
124+
// Delete the VPC
125+
p.log.Wg.Add(1)
126+
go p.log.Loading("Deleting VPC resources")
127+
p.updateProgressingCondition(*p.Environment.DeepCopy(), cache, "v1alpha1.Destroying", "Deleting VPC resources")
128+
// Delete the subnet
129+
if cache.Subnetid == "" {
130+
p.log.Warning("No subnet found to delete")
131+
} else {
132+
deleteSubnet := &ec2.DeleteSubnetInput{
133+
SubnetId: &cache.Subnetid,
134+
}
135+
_, err = p.ec2.DeleteSubnet(context.Background(), deleteSubnet)
136+
if err != nil {
137+
err = errors.Join(err, fmt.Errorf("error deleting subnet: %v", err))
138+
}
112139
}
113-
_, err = p.ec2.DetachInternetGateway(context.Background(), detachInternetGateway)
114-
if err != nil {
115-
p.fail()
116-
return fmt.Errorf("error detaching Internet Gateway: %v", err)
140+
141+
// Delete the route tables
142+
if cache.RouteTable == "" {
143+
p.log.Warning("No route table found to delete")
144+
} else {
145+
deleteRouteTable := &ec2.DeleteRouteTableInput{
146+
RouteTableId: &cache.RouteTable,
147+
}
148+
_, err = p.ec2.DeleteRouteTable(context.Background(), deleteRouteTable)
149+
if err != nil {
150+
err = errors.Join(err, fmt.Errorf("error deleting route table: %v", err))
151+
}
117152
}
118153

119-
// Delete the Internet Gateway
120-
deleteInternetGatewayInput := &ec2.DeleteInternetGatewayInput{
121-
InternetGatewayId: &cache.InternetGwid,
154+
// Detach the Internet Gateway
155+
if cache.InternetGwid == "" {
156+
p.log.Warning("No Internet Gateway found to delete")
157+
} else {
158+
detachInternetGateway := &ec2.DetachInternetGatewayInput{
159+
InternetGatewayId: &cache.InternetGwid,
160+
VpcId: &cache.Vpcid,
161+
}
162+
_, err = p.ec2.DetachInternetGateway(context.Background(), detachInternetGateway)
163+
if err != nil {
164+
err = errors.Join(err, fmt.Errorf("error detaching Internet Gateway: %v", err))
165+
}
122166
}
123-
_, err = p.ec2.DeleteInternetGateway(context.Background(), deleteInternetGatewayInput)
124-
if err != nil {
125-
p.fail()
126-
return fmt.Errorf("error deleting Internet Gateway: %v", err)
167+
168+
// Delete the Internet Gateway
169+
if cache.InternetGwid == "" {
170+
p.log.Warning("No Internet Gateway found to delete")
171+
} else {
172+
deleteInternetGatewayInput := &ec2.DeleteInternetGatewayInput{
173+
InternetGatewayId: &cache.InternetGwid,
174+
}
175+
_, err = p.ec2.DeleteInternetGateway(context.Background(), deleteInternetGatewayInput)
176+
if err != nil {
177+
err = errors.Join(err, fmt.Errorf("error deleting Internet Gateway: %v", err))
178+
}
127179
}
128180

129181
// Delete the VPC
130-
dVpc := &ec2.DeleteVpcInput{
131-
VpcId: &cache.Vpcid,
182+
if cache.Vpcid == "" {
183+
p.log.Warning("No VPC found to delete")
184+
} else {
185+
dVpc := &ec2.DeleteVpcInput{
186+
VpcId: &cache.Vpcid,
187+
}
188+
_, err = p.ec2.DeleteVpc(context.Background(), dVpc)
189+
if err != nil {
190+
err = errors.Join(err, fmt.Errorf("error deleting VPC: %v", err))
191+
}
132192
}
133-
_, err = p.ec2.DeleteVpc(context.Background(), dVpc)
193+
134194
if err != nil {
135195
p.fail()
136-
return fmt.Errorf("error deleting VPC: %v", err)
196+
return err
137197
}
138198

139199
p.done()

0 commit comments

Comments
 (0)