Skip to content

Commit 7db8e56

Browse files
Resolve files with duplicate content, add tests
Signed-off-by: Danil-Grigorev <[email protected]>
1 parent 4a773f8 commit 7db8e56

File tree

7 files changed

+350
-48
lines changed

7 files changed

+350
-48
lines changed

cmd/plugin/cmd/init_test.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,6 @@ func TestInitProviders(t *testing.T) {
265265
opts: &initOptions{
266266
coreProvider: "cluster-api:capi-system:v1.8.0",
267267
infrastructureProviders: []string{
268-
"cluster-api:capi-system:v1.8.0",
269268
"aws:capa-operator-system",
270269
"docker:capd-operator-system",
271270
},

cmd/plugin/cmd/preload.go

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -207,42 +207,49 @@ func runPreLoad() error {
207207
configMaps = append(configMaps, configMap)
208208
}
209209

210-
errors := []error{}
211-
212-
if !loadOpts.existing {
213-
for _, cm := range configMaps {
214-
out, err := yaml.Marshal(cm)
215-
if err != nil {
216-
return fmt.Errorf("cannot serialize provider config map: %w", err)
217-
}
218-
219-
fmt.Printf("---\n%s", string(out))
210+
for _, cm := range configMaps {
211+
out, err := yaml.Marshal(cm)
212+
if err != nil {
213+
return fmt.Errorf("cannot serialize provider config map: %w", err)
220214
}
221215

222-
return nil
216+
fmt.Printf("---\n%s", string(out))
223217
}
224218

225-
client, err := CreateKubeClient(loadOpts.kubeconfig, "")
226-
if err != nil {
227-
return fmt.Errorf("cannot create a client: %w", err)
219+
if loadOpts.existing {
220+
client, err := CreateKubeClient(loadOpts.kubeconfig, "")
221+
if err != nil {
222+
return fmt.Errorf("cannot create a client: %w", err)
223+
}
224+
if _, err := preloadExisting(ctx, client); err != nil {
225+
return err
226+
}
228227
}
229228

229+
return nil
230+
}
231+
232+
// preloadExisting uses existing cluster kubeconfig to list providers and create configmaps with components for each provider.
233+
func preloadExisting(ctx context.Context, cl client.Client) ([]*corev1.ConfigMap, error) {
234+
errors := []error{}
235+
configMaps := []*corev1.ConfigMap{}
236+
230237
for _, list := range operatorv1.ProviderLists {
231-
maps, err := fetchProviders(ctx, client, list.(genericProviderList))
238+
maps, err := fetchProviders(ctx, cl, list.(genericProviderList))
232239
configMaps = append(configMaps, maps...)
233240
errors = append(errors, err)
234241
}
235242

236243
for _, cm := range configMaps {
237244
out, err := yaml.Marshal(cm)
238245
if err != nil {
239-
return fmt.Errorf("cannot serialize provider config map: %w", err)
246+
return nil, fmt.Errorf("cannot serialize provider config map: %w", err)
240247
}
241248

242249
fmt.Printf("---\n%s", string(out))
243250
}
244251

245-
return kerrors.NewAggregate(errors)
252+
return configMaps, kerrors.NewAggregate(errors)
246253
}
247254

248255
func fetchProviders(ctx context.Context, cl client.Client, providerList genericProviderList) ([]*corev1.ConfigMap, error) {

cmd/plugin/cmd/preload_test.go

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
/*
2+
Copyright 2025 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package cmd
18+
19+
import (
20+
"cmp"
21+
"os"
22+
"path"
23+
"testing"
24+
25+
. "github.com/onsi/gomega"
26+
corev1 "k8s.io/api/core/v1"
27+
"k8s.io/apimachinery/pkg/types"
28+
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
29+
ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
30+
31+
operatorv1 "sigs.k8s.io/cluster-api-operator/api/v1alpha2"
32+
"sigs.k8s.io/cluster-api-operator/internal/controller/genericprovider"
33+
)
34+
35+
type publishProvider struct {
36+
configMapName string
37+
provider genericprovider.GenericProvider
38+
metadataKey string
39+
componentsKey string
40+
metadataData []byte
41+
componentsData []byte
42+
}
43+
44+
type publishOptions struct {
45+
ociUrl string
46+
providers []publishProvider
47+
}
48+
49+
func TestPreloadCommand(t *testing.T) {
50+
tests := []struct {
51+
name string
52+
customURL string
53+
publishOpts *publishOptions
54+
existingProviders []genericprovider.GenericProvider
55+
expectedConfigMaps int
56+
wantErr bool
57+
}{
58+
{
59+
name: "no providers",
60+
wantErr: false,
61+
},
62+
{
63+
name: "builtin core provider with OCI override",
64+
publishOpts: &publishOptions{
65+
ociUrl: "ttl.sh/cluster-api-operator-manifests-1:1m",
66+
providers: []publishProvider{{
67+
configMapName: "core-cluster-api-v1.9.3",
68+
provider: generateGenericProvider(clusterctlv1.CoreProviderType, "cluster-api", "default", "v1.9.3", "", ""),
69+
metadataKey: "metadata.yaml",
70+
metadataData: []byte("metadata"),
71+
componentsKey: "components.yaml",
72+
componentsData: []byte("components"),
73+
}},
74+
},
75+
expectedConfigMaps: 1,
76+
},
77+
{
78+
name: "multiple providers with OCI override",
79+
publishOpts: &publishOptions{
80+
ociUrl: "ttl.sh/cluster-api-operator-manifests-2:1m",
81+
providers: []publishProvider{{
82+
configMapName: "core-cluster-api-v1.9.3",
83+
provider: generateGenericProvider(clusterctlv1.CoreProviderType, "cluster-api", "default", "v1.9.3", "", ""),
84+
metadataKey: "core-cluster-api-v1.9.3-metadata.yaml",
85+
metadataData: []byte("metadata"),
86+
componentsKey: "core-cluster-api-v1.9.3-components.yaml",
87+
componentsData: []byte("components"),
88+
}, {
89+
configMapName: "infrastructure-docker-v1.9.3",
90+
provider: generateGenericProvider(clusterctlv1.InfrastructureProviderType, "docker", "default", "v1.9.3", "", ""),
91+
metadataKey: "infrastructure-docker-v1.9.3-metadata.yaml",
92+
metadataData: []byte("metadata"),
93+
componentsKey: "infrastructure-docker-v1.9.3-components.yaml",
94+
componentsData: []byte("components"),
95+
}},
96+
},
97+
expectedConfigMaps: 2,
98+
},
99+
{
100+
name: "custom url infra provider",
101+
existingProviders: []genericprovider.GenericProvider{
102+
func() genericprovider.GenericProvider {
103+
p := generateGenericProvider(clusterctlv1.InfrastructureProviderType, "docker", "default", "v1.9.3", "", "")
104+
spec := p.GetSpec()
105+
spec.FetchConfig = &operatorv1.FetchConfiguration{
106+
URL: "https://github.com/kubernetes-sigs/cluster-api/releases/latest/core-components.yaml",
107+
}
108+
p.SetSpec(spec)
109+
return p
110+
}(),
111+
},
112+
expectedConfigMaps: 1,
113+
},
114+
{
115+
name: "regular core and infra provider",
116+
existingProviders: []genericprovider.GenericProvider{
117+
generateGenericProvider(clusterctlv1.CoreProviderType, "cluster-api", "default", "v1.9.3", "", ""),
118+
generateGenericProvider(clusterctlv1.InfrastructureProviderType, "docker", "default", "v1.9.3", "", ""),
119+
},
120+
expectedConfigMaps: 2,
121+
},
122+
{
123+
name: "OCI override with incorrect metadata key",
124+
publishOpts: &publishOptions{
125+
ociUrl: "ttl.sh/cluster-api-operator-manifests-3:1m",
126+
providers: []publishProvider{{
127+
configMapName: "core-cluster-api-v1.9.3",
128+
provider: generateGenericProvider(clusterctlv1.CoreProviderType, "cluster-api", "default", "v1.9.3", "", ""),
129+
metadataKey: "incorrect-metadata.yaml",
130+
metadataData: []byte("test"),
131+
componentsKey: "components.yaml",
132+
componentsData: []byte("test"),
133+
}},
134+
},
135+
wantErr: true,
136+
},
137+
{
138+
name: "OCI override with incorrect components key",
139+
publishOpts: &publishOptions{
140+
ociUrl: "ttl.sh/cluster-api-operator-manifests-4:1m",
141+
providers: []publishProvider{{
142+
configMapName: "core-cluster-api-v1.9.3",
143+
provider: generateGenericProvider(clusterctlv1.CoreProviderType, "cluster-api", "default", "v1.9.3", "", ""),
144+
metadataKey: "metadata.yaml",
145+
metadataData: []byte("test"),
146+
componentsKey: "incorrect-components.yaml",
147+
componentsData: []byte("test"),
148+
}},
149+
},
150+
wantErr: true,
151+
},
152+
}
153+
for _, tt := range tests {
154+
t.Run(tt.name, func(t *testing.T) {
155+
g := NewWithT(t)
156+
157+
dir, err := os.MkdirTemp("", "manifests")
158+
defer func() {
159+
g.Expect(os.RemoveAll(dir)).To(Succeed())
160+
}()
161+
g.Expect(err).To(Succeed())
162+
163+
opts := cmp.Or(tt.publishOpts, &publishOptions{})
164+
if tt.publishOpts != nil && opts.ociUrl != "" {
165+
for _, provider := range opts.providers {
166+
err = os.WriteFile(path.Join(dir, provider.metadataKey), provider.metadataData, 0o777)
167+
g.Expect(err).To(Succeed())
168+
err = os.WriteFile(path.Join(dir, provider.componentsKey), provider.componentsData, 0o777)
169+
g.Expect(err).To(Succeed())
170+
}
171+
172+
g.Expect(publish(ctx, dir, opts.ociUrl)).To(Succeed())
173+
174+
for _, data := range opts.providers {
175+
spec := data.provider.GetSpec()
176+
spec.FetchConfig = &operatorv1.FetchConfiguration{
177+
OCI: opts.ociUrl,
178+
}
179+
data.provider.SetSpec(spec)
180+
g.Expect(env.Client.Create(ctx, data.provider)).To(Succeed())
181+
}
182+
}
183+
184+
resources := []ctrlclient.Object{}
185+
for _, provider := range tt.existingProviders {
186+
resources = append(resources, provider)
187+
}
188+
189+
for _, data := range opts.providers {
190+
resources = append(resources, data.provider)
191+
}
192+
193+
defer func() {
194+
g.Expect(env.CleanupAndWait(ctx, resources...)).To(Succeed())
195+
}()
196+
197+
for _, genericProvider := range tt.existingProviders {
198+
g.Expect(env.Client.Create(ctx, genericProvider)).To(Succeed())
199+
}
200+
201+
configMaps, testErr := preloadExisting(ctx, env)
202+
203+
maps := map[types.NamespacedName]*corev1.ConfigMap{}
204+
for _, cm := range configMaps {
205+
maps[ctrlclient.ObjectKeyFromObject(cm)] = cm
206+
}
207+
208+
if tt.wantErr {
209+
g.Expect(testErr).To(HaveOccurred())
210+
} else {
211+
g.Expect(testErr).NotTo(HaveOccurred())
212+
for _, data := range opts.providers {
213+
cm := maps[types.NamespacedName{
214+
Namespace: data.provider.GetNamespace(),
215+
Name: data.configMapName,
216+
}]
217+
218+
g.Expect(cm.Data["metadata"]).To(Equal(string(data.metadataData)))
219+
g.Expect(cm.Data["components"]).To(Equal(string(data.componentsData)))
220+
}
221+
g.Expect(tt.expectedConfigMaps).To(Equal(len(configMaps)))
222+
}
223+
})
224+
}
225+
}

0 commit comments

Comments
 (0)