Skip to content

Commit d36fa20

Browse files
Merge pull request #43 from echen-98/maintenance-window
fix update of maintenance window
2 parents 96bcd46 + 8b3fd06 commit d36fa20

File tree

13 files changed

+208
-114
lines changed

13 files changed

+208
-114
lines changed
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
ack_generate_info:
2-
build_date: "2021-07-16T03:54:07Z"
2+
build_date: "2021-07-16T19:55:47Z"
33
build_hash: 7832e9aa4a48565302cd440f4cdf2267f04adfed
44
go_version: go1.15.2 darwin/amd64
55
version: v0.5.0
66
api_directory_checksum: 04701e412e7e4597466c1d56571be2c5de2b1e27
77
api_version: v1alpha1
88
aws_sdk_go_version: ""
99
generator_config_info:
10-
file_checksum: cc29e8be7c6f65ef2f8db75fc3752adbf18590df
10+
file_checksum: 821cc69bbfdafc0bb1302bb609f7b92774448303
1111
original_file_name: generator.yaml
1212
last_modification:
1313
reason: API generation
14-
timestamp: 2021-07-16 03:54:15.20368 +0000 UTC
14+
timestamp: 2021-07-16 19:55:56.542005 +0000 UTC

apis/v1alpha1/generator.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ resources:
6969
template_path: hooks/sdk_delete_post_request.go.tpl
7070
sdk_update_post_build_request:
7171
template_path: hooks/sdk_update_post_build_request.go.tpl
72+
delta_post_compare:
73+
code: "filterDelta(delta, a, b)"
7274
Snapshot:
7375
update_conditions_custom_method_name: CustomUpdateConditions
7476
exceptions:

generator.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ resources:
6969
template_path: hooks/sdk_delete_post_request.go.tpl
7070
sdk_update_post_build_request:
7171
template_path: hooks/sdk_update_post_build_request.go.tpl
72+
delta_post_compare:
73+
code: "filterDelta(delta, a, b)"
7274
Snapshot:
7375
update_conditions_custom_method_name: CustomUpdateConditions
7476
exceptions:

pkg/common/delta.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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 common
15+
16+
import ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare"
17+
18+
// remove the Difference corresponding to the given subject from the delta struct
19+
//TODO: ideally this would have a common implementation in compare/delta.go
20+
func RemoveFromDelta(
21+
delta *ackcompare.Delta,
22+
subject string,
23+
) {
24+
// copy slice
25+
differences := delta.Differences
26+
27+
// identify index of Difference to remove
28+
//TODO: this could require a stricter Path.Equals down the road
29+
var i *int = nil
30+
for j, diff := range differences {
31+
if diff.Path.Contains(subject) {
32+
i = &j
33+
break
34+
}
35+
}
36+
37+
// if found, create a new slice and replace the original
38+
if i != nil {
39+
differences = append(differences[:*i], differences[*i+1:]...)
40+
delta.Differences = differences
41+
}
42+
}

pkg/resource/replication_group/custom_update_api.go

Lines changed: 8 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,13 @@ func (rm *resourceManager) CustomModifyReplicationGroup(
8484
if desired.ko.Spec.AutomaticFailoverEnabled != nil && *desired.ko.Spec.AutomaticFailoverEnabled == false {
8585
latestAutomaticFailoverEnabled := latest.ko.Status.AutomaticFailover != nil && *latest.ko.Status.AutomaticFailover == "enabled"
8686
if latestAutomaticFailoverEnabled != *desired.ko.Spec.AutomaticFailoverEnabled {
87-
return rm.modifyReplicationGroup(ctx, desired, latest)
87+
return rm.modifyReplicationGroup(ctx, desired, latest, delta)
8888
}
8989
}
9090
if desired.ko.Spec.MultiAZEnabled != nil && *desired.ko.Spec.MultiAZEnabled == false {
9191
latestMultiAZEnabled := latest.ko.Status.MultiAZ != nil && *latest.ko.Status.MultiAZ == "enabled"
9292
if latestMultiAZEnabled != *desired.ko.Spec.MultiAZEnabled {
93-
return rm.modifyReplicationGroup(ctx, desired, latest)
93+
return rm.modifyReplicationGroup(ctx, desired, latest, delta)
9494
}
9595
}
9696

@@ -107,7 +107,7 @@ func (rm *resourceManager) CustomModifyReplicationGroup(
107107
return rm.updateShardConfiguration(ctx, desired, latest)
108108
}
109109

110-
return rm.modifyReplicationGroup(ctx, desired, latest)
110+
return rm.modifyReplicationGroup(ctx, desired, latest, delta)
111111
}
112112

113113
// modifyReplicationGroup updates replication group
@@ -118,6 +118,7 @@ func (rm *resourceManager) modifyReplicationGroup(
118118
ctx context.Context,
119119
desired *resource,
120120
latest *resource,
121+
delta *ackcompare.Delta,
121122
) (*resource, error) {
122123
// Method currently handles SecurityGroupIDs, EngineVersion
123124
// Avoid making unnecessary DescribeCacheCluster API call if both fields are nil in spec.
@@ -134,8 +135,8 @@ func (rm *resourceManager) modifyReplicationGroup(
134135

135136
// SecurityGroupIds, EngineVersion
136137
if rm.securityGroupIdsDiffer(desired, latest, latestCacheCluster) ||
137-
rm.engineVersionsDiffer(desired, latest) {
138-
input := rm.newModifyReplicationGroupRequestPayload(desired, latest, latestCacheCluster)
138+
delta.DifferentAt("Spec.EngineVersion") {
139+
input := rm.newModifyReplicationGroupRequestPayload(desired, latest, latestCacheCluster, delta)
139140
resp, respErr := rm.sdkapi.ModifyReplicationGroupWithContext(ctx, input)
140141
rm.metrics.RecordAPICall("UPDATE", "ModifyReplicationGroup", respErr)
141142
if respErr != nil {
@@ -648,6 +649,7 @@ func (rm *resourceManager) newModifyReplicationGroupRequestPayload(
648649
desired *resource,
649650
latest *resource,
650651
latestCacheCluster *svcsdk.CacheCluster,
652+
delta *ackcompare.Delta,
651653
) *svcsdk.ModifyReplicationGroupInput {
652654
input := &svcsdk.ModifyReplicationGroupInput{}
653655

@@ -667,37 +669,14 @@ func (rm *resourceManager) newModifyReplicationGroupRequestPayload(
667669
input.SetSecurityGroupIds(ids)
668670
}
669671

670-
if rm.engineVersionsDiffer(desired, latest) &&
672+
if delta.DifferentAt("Spec.EngineVersion") &&
671673
desired.ko.Spec.EngineVersion != nil {
672674
input.SetEngineVersion(*desired.ko.Spec.EngineVersion)
673675
}
674676

675677
return input
676678
}
677679

678-
/*
679-
engineVersionsDiffer returns true if the desired engine version is different
680-
from the latest observed engine version, and false if they differ or if
681-
the desired EngineVersion is nil
682-
*/
683-
func (rm *resourceManager) engineVersionsDiffer(
684-
desired *resource,
685-
latest *resource,
686-
) bool {
687-
if desired.ko.Spec.EngineVersion == nil {
688-
return false
689-
}
690-
691-
latestEV := ""
692-
if latest.ko.Spec.EngineVersion != nil {
693-
latestEV = *latest.ko.Spec.EngineVersion
694-
}
695-
696-
return *desired.ko.Spec.EngineVersion != latestEV
697-
698-
//TODO: should Delta be used in this function?
699-
}
700-
701680
// This method copies the data from given replicationGroup by populating it into copy of supplied resource
702681
// and returns it.
703682
func (rm *resourceManager) provideUpdatedResource(

pkg/resource/replication_group/custom_update_api_test.go

Lines changed: 0 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -942,57 +942,3 @@ func provideCacheClusterSecurityGroups(IDs ...string) []*svcsdk.SecurityGroupMem
942942
}
943943
return securityGroups
944944
}
945-
946-
// TestEngineVersionsDiffer tests scenarios to check if desired, latest (from cache cluster)
947-
// Engine Version configuration differs.
948-
func TestEngineVersionsDiffer(t *testing.T) {
949-
assert := assert.New(t)
950-
require := require.New(t)
951-
// setup
952-
rm := provideResourceManager()
953-
// Tests
954-
t.Run("NoDiff=NoSpec_NoStatus", func(t *testing.T) {
955-
desiredRG := provideResource()
956-
latestRG := provideResource()
957-
require.Nil(desiredRG.ko.Spec.EngineVersion)
958-
require.Nil(latestRG.ko.Spec.EngineVersion)
959-
differ := rm.engineVersionsDiffer(desiredRG, latestRG)
960-
assert.False(differ)
961-
})
962-
t.Run("NoDiff=OnlyDesiredNil", func(t *testing.T) {
963-
desiredRG := provideResource()
964-
latestRG := provideResource()
965-
latestEV := "test-engine-version"
966-
latestRG.ko.Spec.EngineVersion = &latestEV
967-
require.Nil(desiredRG.ko.Spec.EngineVersion)
968-
require.NotNil(latestRG.ko.Spec.EngineVersion)
969-
differ := rm.engineVersionsDiffer(desiredRG, latestRG)
970-
assert.False(differ)
971-
})
972-
t.Run("NoDiff=Desired_Latest_Match", func(t *testing.T) {
973-
desiredRG := provideResource()
974-
latestRG := provideResource()
975-
latestEV := "test-engine-version"
976-
desiredRG.ko.Spec.EngineVersion = &latestEV
977-
latestRG.ko.Spec.EngineVersion = &latestEV
978-
require.NotNil(desiredRG.ko.Spec.EngineVersion)
979-
require.NotNil(latestRG.ko.Spec.EngineVersion)
980-
differ := rm.engineVersionsDiffer(desiredRG, latestRG)
981-
assert.False(differ)
982-
})
983-
t.Run("Diff=Desired_Latest_Mismatch", func(t *testing.T) {
984-
desiredRG := provideResource()
985-
latestRG := provideResource()
986-
desiredEV := "desired-test-engine-version"
987-
latestEV := "latest-test-engine-version"
988-
989-
desiredRG.ko.Spec.EngineVersion = &desiredEV
990-
latestRG.ko.Spec.EngineVersion = &latestEV
991-
992-
require.NotNil(desiredRG.ko.Spec.EngineVersion)
993-
require.NotNil(latestRG.ko.Spec.EngineVersion)
994-
require.NotEqual(*desiredRG.ko.Spec.EngineVersion, *latestRG.ko.Spec.EngineVersion)
995-
differ := rm.engineVersionsDiffer(desiredRG, latestRG)
996-
assert.True(differ)
997-
})
998-
}

pkg/resource/replication_group/delta.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
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 replication_group
15+
16+
import (
17+
"strings"
18+
"regexp"
19+
20+
ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare"
21+
22+
"github.com/aws-controllers-k8s/elasticache-controller/pkg/common"
23+
)
24+
25+
// remove non-meaningful differences from delta
26+
func filterDelta(
27+
delta *ackcompare.Delta,
28+
desired *resource,
29+
latest *resource,
30+
) {
31+
32+
if delta.DifferentAt("Spec.EngineVersion") {
33+
if desired.ko.Spec.EngineVersion != nil && latest.ko.Spec.EngineVersion != nil {
34+
if engineVersionsMatch(*desired.ko.Spec.EngineVersion, *latest.ko.Spec.EngineVersion) {
35+
common.RemoveFromDelta(delta, "Spec.EngineVersion")
36+
}
37+
}
38+
// TODO: handle the case of a nil difference (especially when desired EV is nil)
39+
}
40+
}
41+
42+
// returns true if desired and latest engine versions match and false otherwise
43+
// precondition: both desiredEV and latestEV are non-nil
44+
// this handles the case where only the major EV is specified, e.g. "6.x" (or similar), but the latest
45+
// version shows the minor version, e.g. "6.0.5"
46+
func engineVersionsMatch(
47+
desiredEV string,
48+
latestEV string,
49+
) bool {
50+
if desiredEV == latestEV {
51+
return true
52+
}
53+
54+
// if the last character of desiredEV is "x", only check for a major version match
55+
last := len(desiredEV) - 1
56+
if desiredEV[last:] == "x" {
57+
// cut off the "x" and replace all occurrences of '.' with '\.' (as '.' is a special regex character)
58+
desired := strings.Replace(desiredEV[:last], ".", "\\.", -1)
59+
r, _ := regexp.Compile(desired + ".*")
60+
return r.MatchString(latestEV)
61+
}
62+
63+
return false
64+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
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 replication_group
15+
16+
import "testing"
17+
import "github.com/stretchr/testify/require"
18+
19+
func TestEngineVersionsMatch(t *testing.T) {
20+
require := require.New(t)
21+
22+
require.True(engineVersionsMatch("6.x", "6.0.5"))
23+
require.False(engineVersionsMatch("13.x", "6.0.6"))
24+
require.True(engineVersionsMatch("5.0.3", "5.0.3"))
25+
require.False(engineVersionsMatch("5.0.3", "5.0.4"))
26+
}

pkg/resource/replication_group/post_set_output.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,13 @@ func (rm *resourceManager) updateSpecFields(
4242
latestCacheCluster, err := rm.describeCacheCluster(ctx, resource)
4343
if err == nil && latestCacheCluster != nil {
4444
setEngineVersion(latestCacheCluster, resource)
45+
setMaintenanceWindow(latestCacheCluster, resource)
4546
}
4647
}
4748

49+
//TODO: for all the fields here, reevaluate if the latest observed state should always be populated,
50+
// even if the corresponding field was not specified in desired
51+
4852
// if ReplicasPerNodeGroup was given in desired.Spec, update ko.Spec with the latest observed value
4953
func setReplicasPerNodeGroup(
5054
respRG *svcsdk.ReplicationGroup,
@@ -72,3 +76,15 @@ func setEngineVersion(
7276
*ko.Spec.EngineVersion = *latestCacheCluster.EngineVersion
7377
}
7478
}
79+
80+
// update maintenance window (if non-nil in API response) regardless of whether it was specified in desired
81+
func setMaintenanceWindow(
82+
latestCacheCluster *svcsdk.CacheCluster,
83+
resource *resource,
84+
) {
85+
ko := resource.ko
86+
if latestCacheCluster.PreferredMaintenanceWindow != nil {
87+
pmw := *latestCacheCluster.PreferredMaintenanceWindow
88+
ko.Spec.PreferredMaintenanceWindow = &pmw
89+
}
90+
}

0 commit comments

Comments
 (0)