Skip to content

Commit 48be8c5

Browse files
authored
Merge pull request #2581 from vincepri/add-tests-etcd-kcp
KCP etcd upgrade: handle conditional update & add tests
2 parents 93bfcf7 + 44bfb43 commit 48be8c5

File tree

3 files changed

+174
-12
lines changed

3 files changed

+174
-12
lines changed

controlplane/kubeadm/internal/kubeadm_config_map.go

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -83,31 +83,55 @@ func (k *kubeadmConfig) UpdateKubernetesVersion(version string) error {
8383
}
8484

8585
// UpdateEtcdMeta sets the local etcd's configuration's image repository and image tag
86-
func (k *kubeadmConfig) UpdateEtcdMeta(imageRepository, imageTag string) error {
86+
func (k *kubeadmConfig) UpdateEtcdMeta(imageRepository, imageTag string) (bool, error) {
8787
data, ok := k.ConfigMap.Data[clusterConfigurationKey]
8888
if !ok {
89-
return errors.Errorf("could not find key %q in kubeadm config", clusterConfigurationKey)
89+
return false, errors.Errorf("could not find key %q in kubeadm config", clusterConfigurationKey)
9090
}
9191
configuration, err := yamlToUnstructured([]byte(data))
9292
if err != nil {
93-
return errors.Wrap(err, "unable to convert YAML to unstructured")
93+
return false, errors.Wrap(err, "unable to convert YAML to unstructured")
9494
}
95-
if imageRepository != "" {
96-
if err := unstructured.SetNestedField(configuration.UnstructuredContent(), imageRepository, "etcd", "local", "imageRepository"); err != nil {
97-
return errors.Wrap(err, "unable to update image repository on kubeadm configmap")
95+
96+
var changed bool
97+
98+
// Handle etcd.local.imageRepository.
99+
imageRepositoryPath := []string{"etcd", "local", "imageRepository"}
100+
currentImageRepository, _, err := unstructured.NestedString(configuration.UnstructuredContent(), imageRepositoryPath...)
101+
if err != nil {
102+
return false, errors.Wrap(err, "unable to retrieve current image repository from kubeadm configmap")
103+
}
104+
if currentImageRepository != imageRepository {
105+
if err := unstructured.SetNestedField(configuration.UnstructuredContent(), imageRepository, imageRepositoryPath...); err != nil {
106+
return false, errors.Wrap(err, "unable to update etcd.local.imageRepository on kubeadm configmap")
98107
}
108+
changed = true
109+
}
110+
111+
// Handle etcd.local.imageTag.
112+
imageTagPath := []string{"etcd", "local", "imageTag"}
113+
currentImageTag, _, err := unstructured.NestedString(configuration.UnstructuredContent(), imageTagPath...)
114+
if err != nil {
115+
return false, errors.Wrap(err, "unable to retrieve current image repository from kubeadm configmap")
99116
}
100-
if imageTag != "" {
101-
if err := unstructured.SetNestedField(configuration.UnstructuredContent(), imageTag, "etcd", "local", "imageTag"); err != nil {
102-
return errors.Wrap(err, "unable to update image repository on kubeadm configmap")
117+
if currentImageTag != imageTag {
118+
if err := unstructured.SetNestedField(configuration.UnstructuredContent(), imageTag, imageTagPath...); err != nil {
119+
return false, errors.Wrap(err, "unable to update etcd.local.imageTag on kubeadm configmap")
103120
}
121+
changed = true
122+
}
123+
124+
// Return early if no changes have been performed.
125+
if !changed {
126+
return changed, nil
104127
}
128+
105129
updated, err := yaml.Marshal(configuration)
106130
if err != nil {
107-
return errors.Wrap(err, "error encoding kubeadm cluster configuration object")
131+
return false, errors.Wrap(err, "error encoding kubeadm cluster configuration object")
108132
}
109133
k.ConfigMap.Data[clusterConfigurationKey] = string(updated)
110-
return nil
134+
return changed, nil
111135
}
112136

113137
// yamlToUnstructured looks inside a config map for a specific key and extracts the embedded YAML into an

controlplane/kubeadm/internal/kubeadm_config_map_test.go

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package internal
1818

1919
import (
20+
"errors"
2021
"testing"
2122

2223
"github.com/onsi/gomega"
@@ -87,3 +88,139 @@ kind: ClusterStatus`,
8788
)),
8889
))
8990
}
91+
92+
func TestUpdateEtcdMeta(t *testing.T) {
93+
94+
tests := []struct {
95+
name string
96+
clusterConfigurationValue string
97+
imageRepository string
98+
imageTag string
99+
expectChanged bool
100+
expectErr error
101+
}{
102+
{
103+
name: "it should set the values, if they were empty",
104+
clusterConfigurationValue: `
105+
apiVersion: kubeadm.k8s.io/v1beta2
106+
kind: ClusterConfiguration
107+
etcd:
108+
local:
109+
dataDir: /var/lib/etcd
110+
`,
111+
imageRepository: "gcr.io/k8s/etcd",
112+
imageTag: "0.10.9",
113+
expectChanged: true,
114+
},
115+
{
116+
name: "it should return false with no error, if there are no changes",
117+
clusterConfigurationValue: `
118+
apiVersion: kubeadm.k8s.io/v1beta2
119+
kind: ClusterConfiguration
120+
etcd:
121+
local:
122+
dataDir: /var/lib/etcd
123+
imageRepository: "gcr.io/k8s/etcd"
124+
imageTag: "0.10.9"
125+
`,
126+
imageRepository: "gcr.io/k8s/etcd",
127+
imageTag: "0.10.9",
128+
expectChanged: false,
129+
},
130+
{
131+
name: "it shouldn't write empty strings",
132+
clusterConfigurationValue: `
133+
apiVersion: kubeadm.k8s.io/v1beta2
134+
kind: ClusterConfiguration
135+
etcd:
136+
local:
137+
dataDir: /var/lib/etcd
138+
`,
139+
imageRepository: "",
140+
imageTag: "",
141+
expectChanged: false,
142+
},
143+
{
144+
name: "it should overwrite imageTag",
145+
clusterConfigurationValue: `
146+
apiVersion: kubeadm.k8s.io/v1beta2
147+
kind: ClusterConfiguration
148+
etcd:
149+
local:
150+
imageTag: 0.10.8
151+
dataDir: /var/lib/etcd
152+
`,
153+
imageTag: "0.10.9",
154+
expectChanged: true,
155+
},
156+
{
157+
name: "it should overwrite imageRepository",
158+
clusterConfigurationValue: `
159+
apiVersion: kubeadm.k8s.io/v1beta2
160+
kind: ClusterConfiguration
161+
etcd:
162+
local:
163+
imageRepository: another-custom-repo
164+
dataDir: /var/lib/etcd
165+
`,
166+
imageRepository: "gcr.io/k8s/etcd",
167+
expectChanged: true,
168+
},
169+
{
170+
name: "it should error if it's not a valid k8s object",
171+
clusterConfigurationValue: `
172+
etcd:
173+
local:
174+
imageRepository: another-custom-repo
175+
dataDir: /var/lib/etcd
176+
`,
177+
expectErr: errors.New("Object 'Kind' is missing"),
178+
},
179+
{
180+
name: "it should error if the current value is a type we don't expect",
181+
clusterConfigurationValue: `
182+
apiVersion: kubeadm.k8s.io/v1beta2
183+
kind: ClusterConfiguration
184+
etcd:
185+
local:
186+
imageRepository: true
187+
dataDir: /var/lib/etcd
188+
`,
189+
expectErr: errors.New(".etcd.local.imageRepository accessor error"),
190+
},
191+
}
192+
193+
for _, test := range tests {
194+
t.Run(test.name, func(t *testing.T) {
195+
g := gomega.NewWithT(t)
196+
197+
kconfig := &kubeadmConfig{
198+
ConfigMap: &corev1.ConfigMap{
199+
Data: map[string]string{
200+
clusterConfigurationKey: test.clusterConfigurationValue,
201+
},
202+
},
203+
}
204+
205+
changed, err := kconfig.UpdateEtcdMeta(test.imageRepository, test.imageTag)
206+
if test.expectErr == nil {
207+
g.Expect(err).ToNot(HaveOccurred())
208+
} else {
209+
g.Expect(err).To(HaveOccurred())
210+
g.Expect(err.Error()).To(gomega.ContainSubstring(test.expectErr.Error()))
211+
}
212+
213+
g.Expect(changed).To(gomega.Equal(test.expectChanged))
214+
if changed {
215+
if test.imageRepository != "" {
216+
g.Expect(kconfig.ConfigMap.Data[clusterConfigurationKey]).To(gomega.ContainSubstring(test.imageRepository))
217+
}
218+
if test.imageTag != "" {
219+
g.Expect(kconfig.ConfigMap.Data[clusterConfigurationKey]).To(gomega.ContainSubstring(test.imageTag))
220+
}
221+
}
222+
223+
})
224+
}
225+
226+
}

controlplane/kubeadm/internal/workload_cluster.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,8 @@ func (w *Workload) UpdateEtcdVersionInKubeadmConfigMap(ctx context.Context, imag
266266
return err
267267
}
268268
config := &kubeadmConfig{ConfigMap: kubeadmConfigMap}
269-
if err := config.UpdateEtcdMeta(imageRepository, imageTag); err != nil {
269+
changed, err := config.UpdateEtcdMeta(imageRepository, imageTag)
270+
if err != nil || !changed {
270271
return err
271272
}
272273
if err := w.Client.Update(ctx, config.ConfigMap); err != nil {

0 commit comments

Comments
 (0)