Skip to content

Commit f26bf23

Browse files
authored
Invalidate registries configuration cache to allow dynamic config updates without restart (operator-framework#1554)
Signed-off-by: dtfranz <[email protected]>
1 parent 13c9204 commit f26bf23

File tree

5 files changed

+112
-1
lines changed

5 files changed

+112
-1
lines changed

Diff for: catalogd/internal/source/containers_image.go

+4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"github.com/containers/image/v5/oci/layout"
2121
"github.com/containers/image/v5/pkg/blobinfocache/none"
2222
"github.com/containers/image/v5/pkg/compression"
23+
"github.com/containers/image/v5/pkg/sysregistriesv2"
2324
"github.com/containers/image/v5/signature"
2425
"github.com/containers/image/v5/types"
2526
"github.com/go-logr/logr"
@@ -51,6 +52,9 @@ func (i *ContainersImageRegistry) Unpack(ctx context.Context, catalog *catalogdv
5152
return nil, reconcile.TerminalError(fmt.Errorf("error parsing catalog, catalog %s has a nil image source", catalog.Name))
5253
}
5354

55+
// Reload registries cache in case of configuration update
56+
sysregistriesv2.InvalidateCache()
57+
5458
srcCtx, err := i.SourceContextFunc(l)
5559
if err != nil {
5660
return nil, err

Diff for: cmd/operator-controller/main.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,8 @@ func main() {
306306
return nil, fmt.Errorf("could not stat auth file, error: %w", err)
307307
}
308308
return srcContext, nil
309-
}}
309+
},
310+
}
310311

311312
clusterExtensionFinalizers := crfinalizer.NewFinalizers()
312313
if err := clusterExtensionFinalizers.Register(controllers.ClusterExtensionCleanupUnpackCacheFinalizer, finalizers.FinalizerFunc(func(ctx context.Context, obj client.Object) (crfinalizer.Result, error) {

Diff for: internal/rukpak/source/containers_image.go

+10
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"github.com/containers/image/v5/oci/layout"
1818
"github.com/containers/image/v5/pkg/blobinfocache/none"
1919
"github.com/containers/image/v5/pkg/compression"
20+
"github.com/containers/image/v5/pkg/sysregistriesv2"
2021
"github.com/containers/image/v5/signature"
2122
"github.com/containers/image/v5/types"
2223
"github.com/go-logr/logr"
@@ -43,10 +44,14 @@ func (i *ContainersImageRegistry) Unpack(ctx context.Context, bundle *BundleSour
4344
return nil, reconcile.TerminalError(fmt.Errorf("error parsing bundle, bundle %s has a nil image source", bundle.Name))
4445
}
4546

47+
// Reload registries cache in case of configuration update
48+
sysregistriesv2.InvalidateCache()
49+
4650
srcCtx, err := i.SourceContextFunc(l)
4751
if err != nil {
4852
return nil, err
4953
}
54+
5055
//////////////////////////////////////////////////////
5156
//
5257
// Resolve a canonical reference for the image.
@@ -254,6 +259,11 @@ func (i *ContainersImageRegistry) unpackImage(ctx context.Context, unpackPath st
254259
if err != nil {
255260
return fmt.Errorf("error creating image source: %w", err)
256261
}
262+
defer func() {
263+
if err := layoutSrc.Close(); err != nil {
264+
panic(err)
265+
}
266+
}()
257267

258268
if err := os.MkdirAll(unpackPath, 0700); err != nil {
259269
return fmt.Errorf("error creating unpack directory: %w", err)

Diff for: test/e2e/cluster_extension_install_test.go

+76
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,82 @@ func TestClusterExtensionInstallRegistry(t *testing.T) {
357357
}
358358
}
359359

360+
func TestClusterExtensionInstallRegistryDynamic(t *testing.T) {
361+
// NOTE: Like 'TestClusterExtensionInstallRegistry', this test also requires extra configuration in /etc/containers/registries.conf
362+
packageName := "dynamic"
363+
364+
t.Log("When a cluster extension is installed from a catalog")
365+
t.Log("When the extension bundle format is registry+v1")
366+
367+
clusterExtension, extensionCatalog, sa, ns := testInit(t)
368+
defer testCleanup(t, extensionCatalog, clusterExtension, sa, ns)
369+
defer getArtifactsOutput(t)
370+
371+
clusterExtension.Spec = ocv1.ClusterExtensionSpec{
372+
Source: ocv1.SourceConfig{
373+
SourceType: "Catalog",
374+
Catalog: &ocv1.CatalogSource{
375+
PackageName: packageName,
376+
Selector: &metav1.LabelSelector{
377+
MatchLabels: map[string]string{"olm.operatorframework.io/metadata.name": extensionCatalog.Name},
378+
},
379+
},
380+
},
381+
Namespace: ns.Name,
382+
ServiceAccount: ocv1.ServiceAccountReference{
383+
Name: sa.Name,
384+
},
385+
}
386+
t.Log("It updates the registries.conf file contents")
387+
cm := corev1.ConfigMap{
388+
ObjectMeta: metav1.ObjectMeta{
389+
Name: "e2e-registries-conf",
390+
Namespace: "olmv1-system",
391+
},
392+
Data: map[string]string{
393+
"registries.conf": `[[registry]]
394+
prefix = "dynamic-registry.operator-controller-e2e.svc.cluster.local:5000"
395+
location = "docker-registry.operator-controller-e2e.svc.cluster.local:5000"`,
396+
},
397+
}
398+
require.NoError(t, c.Update(context.Background(), &cm))
399+
400+
t.Log("It resolves the specified package with correct bundle path")
401+
t.Log("By creating the ClusterExtension resource")
402+
require.NoError(t, c.Create(context.Background(), clusterExtension))
403+
404+
t.Log("By eventually reporting a successful resolution and bundle path")
405+
require.EventuallyWithT(t, func(ct *assert.CollectT) {
406+
assert.NoError(ct, c.Get(context.Background(), types.NamespacedName{Name: clusterExtension.Name}, clusterExtension))
407+
}, 2*time.Minute, pollInterval)
408+
409+
// Give the check 2 minutes instead of the typical 1 for the pod's
410+
// files to update from the configmap change.
411+
// The theoretical max time is the kubelet sync period of 1 minute +
412+
// ConfigMap cache TTL of 1 minute = 2 minutes
413+
t.Log("By eventually reporting progressing as True")
414+
require.EventuallyWithT(t, func(ct *assert.CollectT) {
415+
assert.NoError(ct, c.Get(context.Background(), types.NamespacedName{Name: clusterExtension.Name}, clusterExtension))
416+
cond := apimeta.FindStatusCondition(clusterExtension.Status.Conditions, ocv1.TypeProgressing)
417+
if assert.NotNil(ct, cond) {
418+
assert.Equal(ct, metav1.ConditionTrue, cond.Status)
419+
assert.Equal(ct, ocv1.ReasonSucceeded, cond.Reason)
420+
}
421+
}, 2*time.Minute, pollInterval)
422+
423+
t.Log("By eventually installing the package successfully")
424+
require.EventuallyWithT(t, func(ct *assert.CollectT) {
425+
assert.NoError(ct, c.Get(context.Background(), types.NamespacedName{Name: clusterExtension.Name}, clusterExtension))
426+
cond := apimeta.FindStatusCondition(clusterExtension.Status.Conditions, ocv1.TypeInstalled)
427+
if assert.NotNil(ct, cond) {
428+
assert.Equal(ct, metav1.ConditionTrue, cond.Status)
429+
assert.Equal(ct, ocv1.ReasonSucceeded, cond.Reason)
430+
assert.Contains(ct, cond.Message, "Installed bundle")
431+
assert.NotEmpty(ct, clusterExtension.Status.Install.Bundle)
432+
}
433+
}, pollDuration, pollInterval)
434+
}
435+
360436
func TestClusterExtensionInstallRegistryMultipleBundles(t *testing.T) {
361437
t.Log("When a cluster extension is installed from a catalog")
362438

Diff for: testdata/images/catalogs/test-catalog/v1/configs/catalog.yaml

+20
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,23 @@ properties:
6969
value:
7070
packageName: test-mirrored
7171
version: 1.2.0
72+
---
73+
schema: olm.package
74+
name: dynamic
75+
defaultChannel: beta
76+
---
77+
schema: olm.channel
78+
name: beta
79+
package: dynamic
80+
entries:
81+
- name: dynamic-operator.1.2.0
82+
---
83+
schema: olm.bundle
84+
name: dynamic-operator.1.2.0
85+
package: dynamic
86+
image: dynamic-registry.operator-controller-e2e.svc.cluster.local:5000/bundles/registry-v1/test-operator:v1.0.0
87+
properties:
88+
- type: olm.package
89+
value:
90+
packageName: dynamic
91+
version: 1.2.0

0 commit comments

Comments
 (0)