Skip to content

Commit 9b10dc2

Browse files
authored
Add Update functionality for VPC.CIDRBlocks (#85)
Issue #, if available: aws-controllers-k8s/community#1198 Description of changes: Enables associating multiple IPv4 CIDR Blocks to a single VPC By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
1 parent 2dc7d8e commit 9b10dc2

File tree

12 files changed

+139
-6
lines changed

12 files changed

+139
-6
lines changed
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
ack_generate_info:
2-
build_date: "2022-09-06T18:39:23Z"
2+
build_date: "2022-09-06T20:17:17Z"
33
build_hash: 87477ae8ca8ac6ddb8c565bbd910cc7e30f55ed0
44
go_version: go1.18.1
55
version: v0.19.3
6-
api_directory_checksum: 6b7708a8cacb471891466f5851f248e0e895f2c2
6+
api_directory_checksum: 3960da50b98c36b05635d3abbfd129ae7bb48e32
77
api_version: v1alpha1
88
aws_sdk_go_version: v1.42.0
99
generator_config_info:
10-
file_checksum: 9586b277b014daec6188d09741c607c96b1201fb
10+
file_checksum: b17fda4c7e3ae9446dd568f3be1f08d70ce15588
1111
original_file_name: generator.yaml
1212
last_modification:
1313
reason: API generation

apis/v1alpha1/generator.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ resources:
429429
CIDRBlocks:
430430
custom_field:
431431
list_of: String
432+
is_required: true
432433
EnableDNSSupport:
433434
from:
434435
operation: ModifyVpcAttribute

apis/v1alpha1/vpc.go

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/ec2.services.k8s.aws_vpcs.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ spec:
9090
type: string
9191
type: object
9292
type: array
93+
required:
94+
- cidrBlocks
9395
type: object
9496
status:
9597
description: VPCStatus defines the observed state of VPC

generator.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ resources:
429429
CIDRBlocks:
430430
custom_field:
431431
list_of: String
432+
is_required: true
432433
EnableDNSSupport:
433434
from:
434435
operation: ModifyVpcAttribute

helm/crds/ec2.services.k8s.aws_vpcs.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ spec:
9090
type: string
9191
type: object
9292
type: array
93+
required:
94+
- cidrBlocks
9395
type: object
9496
status:
9597
description: VPCStatus defines the observed state of VPC

pkg/resource/vpc/hook.go

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package vpc
1616
import (
1717
"context"
1818

19+
svcapitypes "github.com/aws-controllers-k8s/ec2-controller/apis/v1alpha1"
1920
ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare"
2021
ackrtlog "github.com/aws-controllers-k8s/runtime/pkg/runtime/log"
2122
svcsdk "github.com/aws/aws-sdk-go/service/ec2"
@@ -128,6 +129,93 @@ func (rm *resourceManager) syncDNSHostnamesAttribute(
128129
return nil
129130
}
130131

132+
// computeStringPDifference uses the underlying string value
133+
// to discern which elements are in slice `a` that aren't in slice `b`
134+
// and vice-versa
135+
func computeStringPDifference(a, b []*string) (aNotB, bNotA []*string) {
136+
mapOfB := map[string]struct{}{}
137+
for _, elemB := range b {
138+
mapOfB[*elemB] = struct{}{}
139+
}
140+
mapOfA := map[string]struct{}{}
141+
for _, elemA := range a {
142+
mapOfA[*elemA] = struct{}{}
143+
}
144+
145+
for _, elemA := range a {
146+
if _, found := mapOfB[*elemA]; !found {
147+
aNotB = append(aNotB, elemA)
148+
}
149+
}
150+
for _, elemB := range b {
151+
if _, found := mapOfB[*elemB]; !found {
152+
bNotA = append(bNotA, elemB)
153+
}
154+
}
155+
156+
return aNotB, bNotA
157+
}
158+
159+
// syncCIDRBlocks analyzes desired and latest
160+
// IPv4 CIDRBlocks and executes API calls to
161+
// Associate/Disassociate CIDRs as needed
162+
func (rm *resourceManager) syncCIDRBlocks(
163+
ctx context.Context,
164+
desired *resource,
165+
latest *resource,
166+
) (err error) {
167+
rlog := ackrtlog.FromContext(ctx)
168+
exit := rlog.Trace("rm.syncCIDRBlocks")
169+
defer exit(err)
170+
171+
desiredCIDRs := desired.ko.Spec.CIDRBlocks
172+
latestCIDRs := latest.ko.Spec.CIDRBlocks
173+
latestCIDRStates := latest.ko.Status.CIDRBlockAssociationSet
174+
toAddCIDRs, toDeleteCIDRs := computeStringPDifference(desiredCIDRs, latestCIDRs)
175+
176+
// extract associationID for the DisassociateVpcCidr request
177+
for _, cidr := range toDeleteCIDRs {
178+
input := &svcsdk.DisassociateVpcCidrBlockInput{}
179+
for _, cidrAssociation := range latestCIDRStates {
180+
if *cidr == *cidrAssociation.CIDRBlock {
181+
input.AssociationId = cidrAssociation.AssociationID
182+
_, err = rm.sdkapi.DisassociateVpcCidrBlockWithContext(ctx, input)
183+
rm.metrics.RecordAPICall("UPDATE", "DisassociateVpcCidrBlock", err)
184+
if err != nil {
185+
return err
186+
}
187+
}
188+
}
189+
}
190+
191+
for _, cidr := range toAddCIDRs {
192+
input := &svcsdk.AssociateVpcCidrBlockInput{
193+
VpcId: latest.ko.Status.VPCID,
194+
CidrBlock: cidr,
195+
}
196+
_, err = rm.sdkapi.AssociateVpcCidrBlockWithContext(ctx, input)
197+
rm.metrics.RecordAPICall("UPDATE", "AssociateVpcCidrBlock", err)
198+
if err != nil {
199+
return err
200+
}
201+
}
202+
203+
return nil
204+
}
205+
206+
// setSpecCIDRs sets Spec.CIDRBlocks using the CIDRs in
207+
// Status.CIDRBlockAssociationSet, which is set via sdkCreate/sdkFind
208+
func (rm *resourceManager) setSpecCIDRs(
209+
ko *svcapitypes.VPC,
210+
) {
211+
ko.Spec.CIDRBlocks = nil
212+
if ko.Status.CIDRBlockAssociationSet != nil {
213+
for _, cidrAssoc := range ko.Status.CIDRBlockAssociationSet {
214+
ko.Spec.CIDRBlocks = append(ko.Spec.CIDRBlocks, cidrAssoc.CIDRBlock)
215+
}
216+
}
217+
}
218+
131219
func (rm *resourceManager) createAttributes(
132220
ctx context.Context,
133221
r *resource,
@@ -161,6 +249,12 @@ func (rm *resourceManager) customUpdate(
161249
// the original Kubernetes object we passed to the function
162250
ko := desired.ko.DeepCopy()
163251

252+
if delta.DifferentAt("Spec.CIDRBlocks") {
253+
if err := rm.syncCIDRBlocks(ctx, desired, latest); err != nil {
254+
return nil, err
255+
}
256+
}
257+
164258
if delta.DifferentAt("Spec.EnableDNSSupport") {
165259
if err := rm.syncDNSSupportAttribute(ctx, desired); err != nil {
166260
return nil, err
@@ -182,7 +276,7 @@ func (rm *resourceManager) customUpdate(
182276
// CIDR block defined in the resource's Spec
183277
func applyPrimaryCIDRBlockInCreateRequest(r *resource,
184278
input *svcsdk.CreateVpcInput) {
185-
if r.ko.Spec.CIDRBlocks != nil && len(r.ko.Spec.CIDRBlocks) > 0 {
279+
if len(r.ko.Spec.CIDRBlocks) > 0 {
186280
input.CidrBlock = r.ko.Spec.CIDRBlocks[0]
187281
}
188282
}

pkg/resource/vpc/sdk.go

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

templates/hooks/vpc/sdk_create_post_set_output.go.tpl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
rm.setSpecCIDRs(ko)
12
err = rm.createAttributes(ctx, &resource{ko})
23
if err != nil {
34
return nil, err

templates/hooks/vpc/sdk_read_many_post_set_output.go.tpl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
rm.setSpecCIDRs(ko)
12
if dnsAttrs, err := rm.getDNSAttributes(ctx, *ko.Status.VPCID); err != nil {
23
return nil, err
34
} else {

0 commit comments

Comments
 (0)