Skip to content

Commit 00155bf

Browse files
Allow to use image overrides from mounted custerctl-config.yaml file
Signed-off-by: Danil-Grigorev <[email protected]>
1 parent 05d29b5 commit 00155bf

File tree

2 files changed

+126
-6
lines changed

2 files changed

+126
-6
lines changed
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*
2+
Copyright 2024 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 controller
18+
19+
import (
20+
"fmt"
21+
22+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
23+
"k8s.io/client-go/kubernetes/scheme"
24+
25+
appsv1 "k8s.io/api/apps/v1"
26+
corev1 "k8s.io/api/core/v1"
27+
28+
configclient "sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
29+
)
30+
31+
const (
32+
daemonSetKind = "DaemonSet"
33+
)
34+
35+
func imageOverrides(component string, overrides configclient.Client) func(objs []unstructured.Unstructured) ([]unstructured.Unstructured, error) {
36+
imageOverridesWrapper := func(objs []unstructured.Unstructured) ([]unstructured.Unstructured, error) {
37+
if overrides == nil {
38+
return objs, nil
39+
}
40+
41+
return fixImages(objs, func(image string) (string, error) {
42+
return overrides.ImageMeta().AlterImage(component, image)
43+
})
44+
}
45+
46+
return imageOverridesWrapper
47+
}
48+
49+
// fixImages alters images using the give alter func
50+
// NB. The implemented approach is specific for the provider components YAML & for the cert-manager manifest; it is not
51+
// intended to cover all the possible objects used to deploy containers existing in Kubernetes.
52+
func fixImages(objs []unstructured.Unstructured, alterImageFunc func(image string) (string, error)) ([]unstructured.Unstructured, error) {
53+
for i := range objs {
54+
if err := fixDeploymentImages(&objs[i], alterImageFunc); err != nil {
55+
return nil, err
56+
}
57+
if err := fixDaemonSetImages(&objs[i], alterImageFunc); err != nil {
58+
return nil, err
59+
}
60+
}
61+
return objs, nil
62+
}
63+
64+
func fixDeploymentImages(o *unstructured.Unstructured, alterImageFunc func(image string) (string, error)) error {
65+
if o.GetKind() != deploymentKind {
66+
return nil
67+
}
68+
69+
// Convert Unstructured into a typed object
70+
d := &appsv1.Deployment{}
71+
if err := scheme.Scheme.Convert(o, d, nil); err != nil {
72+
return err
73+
}
74+
75+
if err := fixPodSpecImages(&d.Spec.Template.Spec, alterImageFunc); err != nil {
76+
return fmt.Errorf("%w: failed to fix containers in deployment %s", err, d.Name)
77+
}
78+
79+
// Convert typed object back to Unstructured
80+
return scheme.Scheme.Convert(d, o, nil)
81+
}
82+
83+
func fixDaemonSetImages(o *unstructured.Unstructured, alterImageFunc func(image string) (string, error)) error {
84+
if o.GetKind() != daemonSetKind {
85+
return nil
86+
}
87+
88+
// Convert Unstructured into a typed object
89+
d := &appsv1.DaemonSet{}
90+
if err := scheme.Scheme.Convert(o, d, nil); err != nil {
91+
return err
92+
}
93+
94+
if err := fixPodSpecImages(&d.Spec.Template.Spec, alterImageFunc); err != nil {
95+
return fmt.Errorf("%w: failed to fix containers in deamonSet %s", err, d.Name)
96+
}
97+
// Convert typed object back to Unstructured
98+
return scheme.Scheme.Convert(d, o, nil)
99+
}
100+
101+
func fixPodSpecImages(podSpec *corev1.PodSpec, alterImageFunc func(image string) (string, error)) error {
102+
if err := fixContainersImage(podSpec.Containers, alterImageFunc); err != nil {
103+
return fmt.Errorf("%w: failed to fix containers", err)
104+
}
105+
if err := fixContainersImage(podSpec.InitContainers, alterImageFunc); err != nil {
106+
return fmt.Errorf("%w: failed to fix init containers", err)
107+
}
108+
return nil
109+
}
110+
111+
func fixContainersImage(containers []corev1.Container, alterImageFunc func(image string) (string, error)) error {
112+
for j := range containers {
113+
container := &containers[j]
114+
image, err := alterImageFunc(container.Image)
115+
if err != nil {
116+
return fmt.Errorf("%w: failed to fix image for container %s", err, container.Name)
117+
}
118+
container.Image = image
119+
}
120+
return nil
121+
}

internal/controller/phases.go

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -148,12 +148,6 @@ func (p *phaseReconciler) initializePhaseReconciler(ctx context.Context) (reconc
148148
return reconcile.Result{}, err
149149
}
150150

151-
if p.overridesClient != nil {
152-
if imageOverrides, err := p.overridesClient.Variables().Get("images"); err == nil {
153-
reader.Set("images", imageOverrides)
154-
}
155-
}
156-
157151
// Load provider's secret and config url.
158152
p.configClient, err = configclient.New(ctx, "", configclient.InjectReader(reader))
159153
if err != nil {
@@ -468,6 +462,11 @@ func (p *phaseReconciler) fetch(ctx context.Context) (reconcile.Result, error) {
468462
return reconcile.Result{}, wrapPhaseError(err, operatorv1.ComponentsFetchErrorReason, operatorv1.ProviderInstalledCondition)
469463
}
470464

465+
// Apply image overrides to the provider manifests.
466+
if err := repository.AlterComponents(p.components, imageOverrides(p.components.ManifestLabel(), p.overridesClient)); err != nil {
467+
return reconcile.Result{}, wrapPhaseError(err, operatorv1.ComponentsFetchErrorReason, operatorv1.ProviderInstalledCondition)
468+
}
469+
471470
conditions.Set(p.provider, conditions.TrueCondition(operatorv1.ProviderInstalledCondition))
472471

473472
return reconcile.Result{}, nil

0 commit comments

Comments
 (0)