Skip to content

Commit d2553f7

Browse files
committed
feat: reroute images based on (Cluster)ImageMirrorSets
1 parent bb1c312 commit d2553f7

File tree

3 files changed

+77
-29
lines changed

3 files changed

+77
-29
lines changed

api/kuik/v1alpha1/image_types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ func imageFromReference(reference string) (*Image, error) {
9494
return nil, err
9595
}
9696

97-
registry, image, err := internal.RegistryNameFromReference(reference)
97+
registry, image, err := internal.RegistryAndPathFromReference(reference)
9898
if err != nil {
9999
return nil, err
100100
}

internal/internal.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ func ImageNameFromReference(image string) (string, error) {
2727
return fmt.Sprintf("%016x", h), nil
2828
}
2929

30-
func RegistryNameFromReference(image string) (string, string, error) {
30+
func RegistryAndPathFromReference(image string) (string, string, error) {
3131
named, err := reference.ParseNormalizedNamed(image)
3232
if err != nil {
3333
return "", "", err
@@ -42,7 +42,7 @@ func RegistryMonitorNameFromRegistry(registry string) string {
4242
}
4343

4444
func RegistryMonitorNameFromReference(image string) (string, error) {
45-
registry, _, err := RegistryNameFromReference(image)
45+
registry, _, err := RegistryAndPathFromReference(image)
4646
if err != nil {
4747
return "", err
4848
}

internal/webhook/core/v1/pod_webhook.go

Lines changed: 74 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,9 @@ type AlternativeImage struct {
5151

5252
type Container struct {
5353
*corev1.Container
54-
IsInit bool
55-
Images []AlternativeImage
54+
IsInit bool
55+
Images []AlternativeImage
56+
Alternatives map[string]struct{}
5657
}
5758

5859
var _ webhook.CustomDefaulter = &PodCustomDefaulter{}
@@ -70,6 +71,29 @@ func (d *PodCustomDefaulter) Default(ctx context.Context, obj runtime.Object) er
7071

7172
log.Info("defaulting for Pod")
7273

74+
containers := make([]Container, 0, len(pod.Spec.Containers)+len(pod.Spec.InitContainers))
75+
for i := range pod.Spec.Containers {
76+
containers = append(containers, Container{
77+
Container: &pod.Spec.Containers[i],
78+
Alternatives: map[string]struct{}{},
79+
})
80+
}
81+
for i := range pod.Spec.InitContainers {
82+
containers = append(containers, Container{
83+
Container: &pod.Spec.InitContainers[i],
84+
IsInit: true,
85+
Alternatives: map[string]struct{}{},
86+
})
87+
}
88+
89+
var cismList kuikv1alpha1.ClusterImageSetMirrorList
90+
if err := d.List(ctx, &cismList); err != nil {
91+
return err
92+
}
93+
var ismList kuikv1alpha1.ImageSetMirrorList
94+
if err := d.List(ctx, &ismList); err != nil {
95+
return err
96+
}
7397
var crisList kuikv1alpha1.ClusterReplicatedImageSetList
7498
if err := d.List(ctx, &crisList); err != nil {
7599
return err
@@ -79,6 +103,20 @@ func (d *PodCustomDefaulter) Default(ctx context.Context, obj runtime.Object) er
79103
return err
80104
}
81105

106+
imageSetMirrors := make([]kuikv1alpha1.ImageSetMirror, 0, len(cismList.Items))
107+
for _, cism := range cismList.Items {
108+
imageSetMirrors = append(imageSetMirrors, kuikv1alpha1.ImageSetMirror{
109+
ObjectMeta: cism.ObjectMeta,
110+
Spec: kuikv1alpha1.ImageSetMirrorSpec(cism.Spec),
111+
})
112+
}
113+
for _, ism := range ismList.Items {
114+
if ism.Namespace != pod.Namespace {
115+
continue
116+
}
117+
imageSetMirrors = append(imageSetMirrors, ism)
118+
}
119+
82120
replicatedImageSets := make([]kuikv1alpha1.ReplicatedImageSet, 0, len(crisList.Items))
83121
for _, cris := range crisList.Items {
84122
replicatedImageSets = append(replicatedImageSets, kuikv1alpha1.ReplicatedImageSet{
@@ -93,19 +131,6 @@ func (d *PodCustomDefaulter) Default(ctx context.Context, obj runtime.Object) er
93131
replicatedImageSets = append(replicatedImageSets, ris)
94132
}
95133

96-
containers := make([]Container, 0, len(pod.Spec.Containers)+len(pod.Spec.InitContainers))
97-
for i := range pod.Spec.Containers {
98-
containers = append(containers, Container{
99-
Container: &pod.Spec.Containers[i],
100-
})
101-
}
102-
for i := range pod.Spec.InitContainers {
103-
containers = append(containers, Container{
104-
Container: &pod.Spec.InitContainers[i],
105-
IsInit: true,
106-
})
107-
}
108-
109134
podCredentialSecrets := make([]*kuikv1alpha1.CredentialSecret, 0, len(pod.Spec.ImagePullSecrets))
110135
for _, imagePullSecret := range pod.Spec.ImagePullSecrets {
111136
podCredentialSecrets = append(podCredentialSecrets, &kuikv1alpha1.CredentialSecret{
@@ -115,7 +140,6 @@ func (d *PodCustomDefaulter) Default(ctx context.Context, obj runtime.Object) er
115140
}
116141

117142
podImagePullSecrets := make([]corev1.Secret, len(podCredentialSecrets))
118-
119143
for i, podCredentialSecret := range podCredentialSecrets {
120144
objectKey := client.ObjectKey{Namespace: podCredentialSecret.Namespace, Name: podCredentialSecret.Name}
121145
if err := d.Get(ctx, objectKey, &podImagePullSecrets[i]); err != nil {
@@ -127,9 +151,30 @@ func (d *PodCustomDefaulter) Default(ctx context.Context, obj runtime.Object) er
127151
}
128152
}
129153

154+
for _, ism := range imageSetMirrors {
155+
matcher := regexp.MustCompile(ism.Spec.ImageMatcher)
156+
157+
for i := range containers {
158+
container := &containers[i]
159+
if !matcher.MatchString(container.Image) {
160+
continue
161+
}
162+
163+
container.Images = make([]AlternativeImage, 0, 1+len(ism.Spec.Mirrors))
164+
container.addAlternative(container.Image)
165+
166+
_, imgPath, err := internal.RegistryAndPathFromReference(container.Image)
167+
if err != nil {
168+
return err
169+
}
170+
171+
for _, mirror := range ism.Spec.Mirrors {
172+
container.addAlternative(path.Join(mirror.Registry, mirror.Path, imgPath))
173+
}
174+
}
175+
}
176+
130177
for _, container := range containers {
131-
container.Images = []AlternativeImage{}
132-
imagesIndex := map[string]int{}
133178
for _, ris := range replicatedImageSets {
134179
index := slices.IndexFunc(ris.Spec.Upstreams, func(upstream kuikv1alpha1.ReplicatedUpstream) bool {
135180
// TODO: use a validating admission policy to ensure the regexp is valid
@@ -146,14 +191,8 @@ func (d *PodCustomDefaulter) Default(ctx context.Context, obj runtime.Object) er
146191

147192
for _, upstream := range ris.Spec.Upstreams {
148193
reference := path.Join(upstream.Registry, upstream.Path, suffix)
149-
if _, ok := imagesIndex[reference]; ok {
150-
continue // don't add the same image twice
151-
}
152-
imagesIndex[reference] = len(container.Images)
153-
container.Images = append(container.Images, AlternativeImage{
154-
Reference: reference,
155-
// TODO: handle using CredentialSecret from upstream configuration
156-
})
194+
// TODO: handle using CredentialSecret from upstream configuration
195+
container.addAlternative(reference)
157196
}
158197
}
159198

@@ -203,3 +242,12 @@ func (d *PodCustomDefaulter) checkImageAvailability(ctx context.Context, referen
203242

204243
return err == nil, nil
205244
}
245+
246+
func (c *Container) addAlternative(reference string) {
247+
if _, ok := c.Alternatives[reference]; ok {
248+
return
249+
}
250+
251+
c.Alternatives[reference] = struct{}{}
252+
c.Images = append(c.Images, AlternativeImage{Reference: reference})
253+
}

0 commit comments

Comments
 (0)