Skip to content

Commit 663ee64

Browse files
joelanfordtmshort
authored andcommitted
pkg/configmap: sort configmap data by key when loading bundle (#1630)
This functionality is used by OLMv0 to construct an `api.Bundle` object that is needed to create install plan steps, which are eventually put into the installplan.status.plan field. It is important to have deterministic ordering of slice fields in Kubernetes APIs to avoid constant re-reconciliation and/or false positive change detection. Specifically in the case of InstallPlan steps, the order of the steps does have _some_ semantic requirements (CSV, then CRDs, then everything else). The problem is that if "everything else" is in a random order, the order of the resulting steps will still have non-determinism. If we have deterministic order of steps, OLM may be able to resolve a class of bugs related to unnecessary creation of multiple install plans that would otherwise be identical. Signed-off-by: Joe Lanford <[email protected]> Upstream-repository: operator-registry Upstream-commit: e80f8925c8da9161270ad0389c088a29146eb81e
1 parent e68eb94 commit 663ee64

File tree

3 files changed

+16
-4
lines changed

3 files changed

+16
-4
lines changed

staging/operator-registry/pkg/configmap/configmap.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package configmap
33
import (
44
"errors"
55
"fmt"
6+
"maps"
7+
"slices"
68
"strings"
79

810
"github.com/sirupsen/logrus"
@@ -68,7 +70,9 @@ func loadBundle(entry *logrus.Entry, cm *corev1.ConfigMap) (*api.Bundle, map[str
6870
}
6971

7072
// Add kube resources to the bundle.
71-
for name, content := range data {
73+
// Sort keys by name to guarantee consistent ordering of bundle objects.
74+
for _, name := range slices.Sorted(maps.Keys(data)) {
75+
content := data[name]
7276
reader := strings.NewReader(content)
7377
logger := entry.WithFields(logrus.Fields{
7478
"key": name,

staging/operator-registry/pkg/configmap/configmap_test.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,9 @@ func TestLoad(t *testing.T) {
6262

6363
unst, err := unstructuredlib.FromString(csvGot)
6464
require.NoError(t, err)
65-
assert.True(t, unst.GetName() == "first" || unst.GetName() == "second")
65+
66+
// The last CSV (by lexicographical sort of configmap data keys) always wins.
67+
assert.Equal(t, "second", unst.GetName())
6668
},
6769
},
6870
{
@@ -167,7 +169,9 @@ func TestLoadWriteRead(t *testing.T) {
167169
bundleObjects, err := unstructuredlib.FromBundle(bundle)
168170
require.NoError(t, err)
169171

170-
assert.ElementsMatch(t, expectedObjects, bundleObjects)
172+
// Assert that the order of manifests from the original manifests
173+
// directory is preserved (by lexicographical sorting by filename)
174+
assert.Equal(t, expectedObjects, bundleObjects)
171175
})
172176
}
173177
}

vendor/github.com/operator-framework/operator-registry/pkg/configmap/configmap.go

Lines changed: 5 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)