Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ clickhouse:
tag: "25.8.16.10002.altinitystable"

clickhouseKeeper:
default: {}
default:
images:
keeper:
registry: "docker.io"
repository: "altinity/clickhouse-keeper"
tag: "25.8.16.10002.altinitystable"

generatedSecrets:
- name: session-key
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ clickhouse:
tag: "25.8.16.10002.altinitystable"

clickhouseKeeper:
default: {}
default:
images:
keeper:
registry: "docker.io"
repository: "altinity/clickhouse-keeper"
tag: "25.8.16.10002.altinitystable"

generatedSecrets:
- name: session-key
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/wandb/operator/pkg/utils"
chkv1 "github.com/wandb/operator/pkg/vendored/altinity-clickhouse/clickhouse-keeper.altinity.com/v1"
chiv1 "github.com/wandb/operator/pkg/vendored/altinity-clickhouse/clickhouse.altinity.com/v1"
"github.com/wandb/operator/pkg/wandb/manifest"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand All @@ -19,6 +20,14 @@ import (
ctrl "sigs.k8s.io/controller-runtime"
)

func KeeperImage(img manifest.ImageRef, globalImageRegistry string) string {
if out := img.GetImage(globalImageRegistry); out != "" {
return out
}
// Fallback for older manifests that don't supply the image.
return defaultKeeperImage
}
Comment on lines +23 to +29

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Preserve the fallback when a global registry is configured.

For an older manifest, manifest.ImageRef{} passed to GetImage("myregistry.io") returns "myregistry.io/", so out != "" skips the fallback and produces an invalid image. Even after fixing detection, returning defaultKeeperImage directly would bypass the global registry.

Detect an empty repository before calling GetImage, then apply the same global-registry prefix to the fallback and add a regression test for an empty image with a non-empty global registry.

Proposed fix
 func KeeperImage(img manifest.ImageRef, globalImageRegistry string) string {
+	if img.Repository == "" {
+		return (manifest.ImageRef{Repository: defaultKeeperImage}).GetImage(globalImageRegistry)
+	}
 	if out := img.GetImage(globalImageRegistry); out != "" {
 		return out
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func KeeperImage(img manifest.ImageRef, globalImageRegistry string) string {
if out := img.GetImage(globalImageRegistry); out != "" {
return out
}
// Fallback for older manifests that don't supply the image.
return defaultKeeperImage
}
func KeeperImage(img manifest.ImageRef, globalImageRegistry string) string {
if img.Repository == "" {
return (manifest.ImageRef{Repository: defaultKeeperImage}).GetImage(globalImageRegistry)
}
if out := img.GetImage(globalImageRegistry); out != "" {
return out
}
// Fallback for older manifests that don't supply the image.
return defaultKeeperImage
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/controller/infra/managed/clickhouse/altinity/keeper/spec.go` around
lines 23 - 29, Update KeeperImage to detect an empty manifest image repository
before calling img.GetImage, then return defaultKeeperImage with the configured
global registry prefix applied; preserve the existing GetImage result for
non-empty images. Add a regression test covering manifest.ImageRef{} with a
non-empty global registry and verifying the correctly prefixed fallback image.


// ToKeeperVendorSpec builds the ClickHouseKeeperInstallation CR that coordinates
// ReplicatedMergeTree replication. nsName comes from altinity.KeeperNsName —
// this package never sees the "-chi"-suffixed spec name.
Expand All @@ -28,6 +37,7 @@ func ToKeeperVendorSpec(
spec *apiv2.ManagedClickHouseSpec,
scheme *runtime.Scheme,
nsName types.NamespacedName,
mfst manifest.Manifest,
) (*chkv1.ClickHouseKeeperInstallation, error) {
_, log := logx.WithSlog(ctx, logx.ClickHouse)
if spec == nil {
Expand All @@ -50,7 +60,7 @@ func ToKeeperVendorSpec(
Containers: []corev1.Container{
{
Name: keeperContainerName,
Image: KeeperImage,
Image: KeeperImage(mfst.ClickhouseKeeper["default"].Images["keeper"], wandb.Spec.Global.ImageRegistry),
SecurityContext: keeperContainerSecurityContext(),
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/wandb/operator/pkg/utils"
chkv1 "github.com/wandb/operator/pkg/vendored/altinity-clickhouse/clickhouse-keeper.altinity.com/v1"
chiv1 "github.com/wandb/operator/pkg/vendored/altinity-clickhouse/clickhouse.altinity.com/v1"
"github.com/wandb/operator/pkg/wandb/manifest"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand All @@ -33,7 +34,7 @@ var _ = Describe("Keeper vendor spec", func() {
},
}

chk, err := ToKeeperVendorSpec(context.Background(), wandb, wandb.Spec.ClickHouse[apiv2.DefaultInstanceName].ManagedClickHouse, keeperScheme(), keeperNsName())
chk, err := ToKeeperVendorSpec(context.Background(), wandb, wandb.Spec.ClickHouse[apiv2.DefaultInstanceName].ManagedClickHouse, keeperScheme(), keeperNsName(), manifest.Manifest{})
Expect(err).NotTo(HaveOccurred())
Expect(chk).NotTo(BeNil())
Expect(chk.Name).To(Equal("clickhouse-chk"))
Expand All @@ -48,7 +49,7 @@ var _ = Describe("Keeper vendor spec", func() {

Expect(chk.Spec.Templates.PodTemplates).To(HaveLen(1))
container := chk.Spec.Templates.PodTemplates[0].Spec.Containers[0]
Expect(container.Image).To(Equal(KeeperImage))
Expect(container.Image).To(Equal(KeeperImage(manifest.ImageRef{}, "")))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert the fallback independently of the implementation helper.

The production value and expected value both call KeeperImage, so this test cannot detect incorrect fallback wiring. Compare against defaultKeeperImage (or an explicit contract value) instead.

Proposed fix
-		Expect(container.Image).To(Equal(KeeperImage(manifest.ImageRef{}, "")))
+		Expect(container.Image).To(Equal(defaultKeeperImage))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Expect(container.Image).To(Equal(KeeperImage(manifest.ImageRef{}, "")))
Expect(container.Image).To(Equal(defaultKeeperImage))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/controller/infra/managed/clickhouse/altinity/keeper/spec_test.go` at
line 52, Update the assertion in the relevant keeper spec test to compare
container.Image against defaultKeeperImage (or the explicit expected fallback
value) instead of calling KeeperImage, ensuring the test independently validates
fallback wiring.

Expect(container.Name).To(Equal(keeperContainerName))
Expect(container.Resources.Requests[corev1.ResourceCPU]).To(Equal(resource.MustParse("250m")))

Expand All @@ -60,17 +61,36 @@ var _ = Describe("Keeper vendor spec", func() {
Expect(*sc.RunAsNonRoot).To(BeTrue())
})

It("uses the Keeper image from the server manifest", func() {
wandb := keeperWandb()
wandb.Spec.Global.ImageRegistry = "myregistry.io"
mfst := manifest.Manifest{
ClickhouseKeeper: map[string]manifest.InfraConfig{
"default": {
Images: map[string]manifest.ImageRef{
"keeper": {Registry: "docker.io", Repository: "altinity/clickhouse-keeper", Tag: "25.8"},
},
},
},
}

chk, err := ToKeeperVendorSpec(context.Background(), wandb, wandb.Spec.ClickHouse[apiv2.DefaultInstanceName].ManagedClickHouse, keeperScheme(), keeperNsName(), mfst)
Expect(err).NotTo(HaveOccurred())
Expect(chk.Spec.Templates.PodTemplates[0].Spec.Containers[0].Image).
To(Equal("myregistry.io/docker.io/altinity/clickhouse-keeper:25.8"))
})

It("errors when keeper storage size is unset (no operator defaults)", func() {
wandb := keeperWandb()
wandb.Spec.ClickHouse[apiv2.DefaultInstanceName].ManagedClickHouse.Keeper = apiv2.ClickHouseKeeperSpec{}
_, err := ToKeeperVendorSpec(context.Background(), wandb, wandb.Spec.ClickHouse[apiv2.DefaultInstanceName].ManagedClickHouse, keeperScheme(), keeperNsName())
_, err := ToKeeperVendorSpec(context.Background(), wandb, wandb.Spec.ClickHouse[apiv2.DefaultInstanceName].ManagedClickHouse, keeperScheme(), keeperNsName(), manifest.Manifest{})
Expect(err).To(HaveOccurred())
})

It("omits fixed IDs in OpenShift mode", func() {
utils.SetOpenShiftMode(true)
wandb := keeperWandb()
chk, err := ToKeeperVendorSpec(context.Background(), wandb, wandb.Spec.ClickHouse[apiv2.DefaultInstanceName].ManagedClickHouse, keeperScheme(), keeperNsName())
chk, err := ToKeeperVendorSpec(context.Background(), wandb, wandb.Spec.ClickHouse[apiv2.DefaultInstanceName].ManagedClickHouse, keeperScheme(), keeperNsName(), manifest.Manifest{})
Expect(err).NotTo(HaveOccurred())
sc := chk.Spec.Templates.PodTemplates[0].Spec.SecurityContext
Expect(sc.RunAsUser).To(BeNil())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ const (
// KeeperModuleName is the W&B component label value for Keeper resources.
KeeperModuleName = "clickhouse-keeper"

// KeeperImage pins the Keeper image to the managed ClickHouse server version.
KeeperImage = "altinity/clickhouse-keeper:25.8.16.10002.altinitystable"
// TODO: remove this hardcoded default once all supported manifest versions
// supply clickhouseKeeper.<instance>.images.keeper. Pinned to the managed
// ClickHouse server version.
defaultKeeperImage = "altinity/clickhouse-keeper:25.8.16.10002.altinitystable"

// KeeperClientPort is the ZooKeeper-compatible client port.
KeeperClientPort = 2181
Expand Down
2 changes: 1 addition & 1 deletion internal/controller/reconciler/clickhouse.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ func managedClickHouseWriteState(
}

// Translate the Keeper and ClickHouse CRs; WriteState writes Keeper first.
desiredKeeper, err := keeper.ToKeeperVendorSpec(ctx, wandb, spec, client.Scheme(), altinity.KeeperNsName(spec))
desiredKeeper, err := keeper.ToKeeperVendorSpec(ctx, wandb, spec, client.Scheme(), altinity.KeeperNsName(spec), mfst)
if err != nil {
log.Error(err, "failed to translate Keeper spec to vendor spec")
return []metav1.Condition{
Expand Down
Loading