Skip to content

MCO-2413: Image inspection cache - #6306

Merged
openshift-merge-bot[bot] merged 5 commits into
openshift:mainfrom
pablintino:image-inspection-cache
Jul 22, 2026
Merged

MCO-2413: Image inspection cache#6306
openshift-merge-bot[bot] merged 5 commits into
openshift:mainfrom
pablintino:image-inspection-cache

Conversation

@pablintino

@pablintino pablintino commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

- What I did

Added a cache for the image inspection operations in the MCC that use an emptyDir in the pod to store the data.

- How to verify it

TBD

- Description for the changelog

Added a cache for the image inspection operations in the MCC that use an emptyDir in the pod to store the data.

Summary by CodeRabbit

  • New Features
    • Added optional, on-disk image inspection caching to the machine-config-controller (configurable via --streams-cache, default /var/cache/mcc), including periodic eviction that keeps active digests warm.
    • The controller now mounts a dedicated cache directory (/var/cache/mcc) so inspection data can persist across restarts.
  • Bug Fixes
    • Improved image inspection lifecycle handling by creating contexts on demand rather than eagerly.
    • Cache updates now avoid persisting failed or partial inspection results.
  • Tests
    • Updated and expanded unit tests to cover the new caching and retention behavior.

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Pipeline controller notification
This repo is configured to use the pipeline controller. Second-stage tests will be triggered either automatically or after lgtm label is added, depending on the repository configuration. The pipeline controller will automatically detect which contexts are required and will utilize /test Prow commands to trigger the second stage.

For optional jobs, comment /test ? to see a list of all defined jobs. To trigger manually all jobs from second stage use /pipeline required command.

This repository is configured in: LGTM mode

@openshift-ci-robot

openshift-ci-robot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

@pablintino: This pull request references MCO-2413 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "5.0.0" version, but no target version was set.

Details

In response to this:

- What I did

Added a cache for the image inspection operations in the MCC that use an emptyDir in the pod to store the data.

- How to verify it

TBD

- Description for the changelog

Added a cache for the image inspection operations in the MCC that use an emptyDir in the pod to store the data.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jul 15, 2026
@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jul 15, 2026
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

The change adds optional file-backed image inspection caching, lazy system-context creation, digest-based eviction retention, and controller/deployment wiring for cache operation.

Changes

Image inspection caching and controller integration

Layer / File(s) Summary
Cache storage and eviction
pkg/imageutils/inspect_cache.go, pkg/imageutils/reference.go, pkg/imageutils/*_test.go
Adds versioned JSON persistence, digest extraction, merged entries, scheduled eviction, and cache lifecycle tests.
Lazy inspection contexts
pkg/osimagestream/*, pkg/controller/bootstrap/*, cmd/machine-config-osimagestream/*, test/e2e-2of2/*
Creates and cleans up SysContext instances per inspection operation through factory callbacks.
Cached inspection decorator
pkg/osimagestream/cached_inspector.go, pkg/osimagestream/cached_inspector_test.go
Serves cached labels and files for digested images, delegates misses, and caches successful results.
Controller and deployment wiring
cmd/machine-config-controller/start.go, pkg/controller/osimagestream/*, pkg/controller/render/render_controller.go, manifests/machineconfigcontroller/deployment.yaml
Configures cache startup and eviction, retains active digests, and mounts the cache volume.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ControllerRuntime
  participant OSImageStreamController
  participant CachedImagesInspector
  participant FileInspectionCache
  participant RenderController
  ControllerRuntime->>OSImageStreamController: Build OSImageStream
  OSImageStreamController->>CachedImagesInspector: Inspect image pullspecs
  CachedImagesInspector->>FileInspectionCache: Read or write inspection data
  ControllerRuntime->>FileInspectionCache: Start periodic eviction
  FileInspectionCache->>OSImageStreamController: Request retained digests
  FileInspectionCache->>RenderController: Request retained digests
Loading

Possibly related PRs

Suggested reviewers: ptalgulk01, isabella-janssen


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 2 warnings)

Check name Status Explanation Resolution
Stable And Deterministic Test Names ❌ Error TestDigestFromPullspec uses t.Run(tt.input), so the subtest title is the raw pullspec/digest string instead of a stable descriptive name. Rename subtests to fixed labels like 'digest pullspec' or 'tagged pullspec' and keep the actual pullspec value in the test case body.
Docstring Coverage ⚠️ Warning Docstring coverage is 15.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Test Structure And Quality ⚠️ Warning TestImageStreamProviderCVO now calls setupSysContext but never defers sysContext.Cleanup(), unlike sibling e2e tests; that leaks temp files and violates helper cleanup expectations. Add defer sysContext.Cleanup() (or a cleanup helper) in TestImageStreamProviderCVO, and use a timeout-bound context for informer cache syncs.
✅ Passed checks (12 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: adding an image inspection cache, and it is concise.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Microshift Test Compatibility ✅ Passed No new Ginkgo e2e tests were added; the only changed e2e file is a plain Test* and the PR adds no new MicroShift-unsupported APIs or tags.
Single Node Openshift (Sno) Test Compatibility ✅ Passed No new Ginkgo e2e specs were added; the only changed e2e file uses plain Go tests and has no multi-node or HA assumptions.
Topology-Aware Scheduling Compatibility ✅ Passed PASS: The PR adds cache wiring/emptyDir only; no new anti-affinity, topology-spread, replica, or nodeSelector constraints were introduced.
Ote Binary Stdout Contract ✅ Passed No stdout writes appear in process-level entrypoints (main/init/TestMain/BeforeSuite); start.go uses klog with logtostderr, and the only stdout write is a normal CLI output helper.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed PASS: The commit changes only controller/deployment code; no new Ginkgo e2e tests or public-internet dependencies were added.
No-Weak-Crypto ✅ Passed No weak crypto is implemented; the only MD5 hit is a negative test expecting unsupported digest algorithm, and digest helpers only parse image refs.
Container-Privileges ✅ Passed No privileged flags, host namespaces, SYS_ADMIN, or allowPrivilegeEscalation appear in the changed manifest; it uses restricted-v2 SCC and only adds an emptyDir cache mount.
No-Sensitive-Data-In-Logs ✅ Passed New logs only report digests, file paths, and counts; no passwords, tokens, PII, or secrets are logged in the changed code.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@pablintino
pablintino force-pushed the image-inspection-cache branch from 647fd77 to fc94819 Compare July 15, 2026 06:07

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Prompt for all review comments with 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.

Inline comments:
In `@manifests/machineconfigcontroller/deployment.yaml`:
- Around line 30-36: Update the controller container resources to define
measured CPU and memory limits alongside the existing requests, and add an
ephemeral-storage limit as appropriate. Set a sizeLimit on the emptyDir volume
named image-inspection-cache to bound cache growth, ensuring every container in
the deployment has CPU and memory limits.

In `@pkg/imageutils/inspect_cache_test.go`:
- Around line 79-88: Update the eviction tests around cache.StartEviction and
the related cases to remove time.Sleep-based synchronization; invoke
cache.evict() directly for deterministic execution. For min-age scenarios, set
each entry’s CreatedAt explicitly so the tests validate age behavior without
relying on elapsed wall-clock time, preserving the existing eviction assertions.

In `@pkg/imageutils/inspect_cache.go`:
- Around line 66-89: The FileInspectionCache boundary must deep-copy entries to
prevent caller mutations from altering cached state. Update Put to copy the
incoming InspectionCacheEntry, including Labels, Files, and nested byte slices,
before storing or merging it; update Get to return an independent deep copy,
including delegated labels, while preserving locking and persistence behavior.

In `@pkg/osimagestream/cached_inspector.go`:
- Line 43: Update the cache-hit and cache-miss logging in the cached inspector
to log the already-derived digest instead of the raw img pullspec, including the
related log statement around the second referenced location. Preserve the
existing log levels and message context while ensuring private-registry
hostnames are not emitted.

In `@pkg/osimagestream/inspector.go`:
- Around line 81-100: Update both cleanup defers in ImagesInspectorImpl.Inspect
and FetchImageFile to capture and propagate SysContext.Cleanup errors instead of
discarding them. Preserve any existing inspection or file-fetch error while
returning cleanup failures when no earlier error exists, using named return
values or equivalent error-aware deferred cleanup.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: f43885d3-e248-4288-8b45-66ab207bf66e

📥 Commits

Reviewing files that changed from the base of the PR and between 9d62fc7 and 647fd77.

📒 Files selected for processing (18)
  • cmd/machine-config-controller/start.go
  • cmd/machine-config-osimagestream/helpers.go
  • manifests/machineconfigcontroller/deployment.yaml
  • pkg/controller/bootstrap/bootstrap.go
  • pkg/controller/bootstrap/bootstrap_test.go
  • pkg/controller/osimagestream/osimagestream_controller.go
  • pkg/controller/render/render_controller.go
  • pkg/imageutils/inspect_cache.go
  • pkg/imageutils/inspect_cache_test.go
  • pkg/imageutils/reference.go
  • pkg/imageutils/sys_context.go
  • pkg/osimagestream/cached_inspector.go
  • pkg/osimagestream/cached_inspector_test.go
  • pkg/osimagestream/inspector.go
  • pkg/osimagestream/mocks_test.go
  • pkg/osimagestream/osimagestream.go
  • pkg/osimagestream/osimagestream_test.go
  • test/e2e-2of2/osimagestream_test.go

Comment on lines 30 to +36
resources:
requests:
cpu: 20m
memory: 50Mi
volumeMounts:
- mountPath: /var/cache/mcc
name: image-inspection-cache

@coderabbitai coderabbitai Bot Jul 15, 2026

Copy link
Copy Markdown

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

Bound the controller and cache resource usage.

The changed container still has no CPU/memory limits, and the new emptyDir has no sizeLimit. Cache growth can consume node ephemeral storage. Add measured container limits and bound the cache volume, preferably with an accompanying ephemeral-storage limit.

As per path instructions, Kubernetes manifests require “Resource limits (cpu, memory) on every container.”

Also applies to: 83-84

🤖 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 `@manifests/machineconfigcontroller/deployment.yaml` around lines 30 - 36,
Update the controller container resources to define measured CPU and memory
limits alongside the existing requests, and add an ephemeral-storage limit as
appropriate. Set a sizeLimit on the emptyDir volume named image-inspection-cache
to bound cache growth, ensuring every container in the deployment has CPU and
memory limits.

Source: Path instructions

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.

In practice this isn't relevant since the cache would be very light, but let's say that something goes horribly wrong and we do balloon the directory, I think we'd end up getting evicted silently?

Might be worth bounding the emptydir like coderabbit is suggesting, just for additional safety, WDYT

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@yuqi-zhang, agreed. An unbounded emptyDir contributes to node ephemeral-storage pressure; the kubelet can evict the pod when pressure thresholds are crossed. That should be visible in Pod status/events, rather than truly silent, but it is still an avoidable controller disruption and the cache is lost on restart.

Adding a conservative sizeLimit is sensible defense in depth. It bounds the failure to cache writes failing once full instead of allowing the cache to contribute to node-wide pressure. I’d keep this change focused on the new volume and choose the limit from expected cache-entry sizing/observed usage, rather than adding arbitrary CPU or memory limits.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I've added a 128Mi limit, far far over what I'd expect? 10Mi?, but still doable and small, just in case for some reason this gets crazy.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Comment on lines +79 to +88
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
cache.StartEviction(ctx, time.Second, 0)
time.Sleep(2 * time.Second)

assert.Nil(t, cache.Get("sha256:aaa"))
assert.Nil(t, cache.Get("sha256:bbb"))

reloaded := NewFileInspectionCache(path, 0)
assert.Nil(t, reloaded.Get("sha256:aaa"))

@coderabbitai coderabbitai Bot Jul 15, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove timing-dependent sleeps from eviction tests.

These assertions can become flaky under scheduler load, especially the min-age check at exactly one second. Invoke cache.evict() synchronously and set CreatedAt explicitly for min-age scenarios.

Also applies to: 105-117, 125-133

🤖 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 `@pkg/imageutils/inspect_cache_test.go` around lines 79 - 88, Update the
eviction tests around cache.StartEviction and the related cases to remove
time.Sleep-based synchronization; invoke cache.evict() directly for
deterministic execution. For min-age scenarios, set each entry’s CreatedAt
explicitly so the tests validate age behavior without relying on elapsed
wall-clock time, preserving the existing eviction assertions.

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.

Similar to what coderabbit is saying here, is there a way you see to make the tests more deterministic? I agree that using sleep() seems like it could be flaky (although I guess in practice you've tested this and it should be significantly faster than 2 seconds?

Applies to other tests where you use sleep(). Maybe a poll loop with a timeout is better, if there's no deterministic way to test this

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

ast-grep outline pkg/imageutils/inspect_cache.go --items all
printf '\n--- sleep usages in cache tests ---\n'
rg -n -C 8 '\btime\.Sleep\s*\(' pkg/imageutils/inspect_cache_test.go
printf '\n--- eviction implementation ---\n'
rg -n -C 16 '\b(StartEviction|evict)\s*\(' pkg/imageutils/inspect_cache.go
printf '\n--- relevant test range ---\n'
sed -n '70,190p' pkg/imageutils/inspect_cache_test.go

Length of output: 9253


@yuqi-zhang, yes—there is a fully deterministic option here, so a poll loop is not needed for these tests.

Because pkg/imageutils/inspect_cache_test.go is in the imageutils package, it can invoke the unexported cache.evict() method directly. That method performs both the eviction and cache-file persistence synchronously. The three tests are testing eviction semantics, not the goroutine/ticker wiring in StartEviction, so they can remove context, StartEviction, and every time.Sleep call.

For the min-age case, explicitly backdate one entry under cache.mu, then invoke cache.evict():

func TestFileInspectionCache_EvictRespectsMinAge(t *testing.T) {
	path := filepath.Join(t.TempDir(), "cache.json")
	cache := NewFileInspectionCache(path, 2*time.Second)

	require.NoError(t, cache.Put("sha256:fresh", &InspectionCacheEntry{
		Labels: map[string]string{"fresh": "1"},
	}))
	require.NoError(t, cache.Put("sha256:old", &InspectionCacheEntry{
		Labels: map[string]string{"old": "1"},
	}))

	cache.mu.Lock()
	cache.entries["sha256:old"].CreatedAt = time.Now().Add(-3 * time.Second)
	cache.mu.Unlock()

	cache.evict()

	assert.NotNil(t, cache.Get("sha256:fresh"))
	assert.Nil(t, cache.Get("sha256:old"))
}

Likewise, TestFileInspectionCache_EvictNoEvicters and TestFileInspectionCache_EvictRetainsUnion can replace their StartEviction/Sleep setup with one cache.evict() call. This eliminates scheduling variance and cuts several seconds from the test suite.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I've fixed this one with a polling check, as I don't like at all testing/calling non-exported functions like evict.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Comment thread pkg/imageutils/inspect_cache.go
Comment thread pkg/osimagestream/cached_inspector.go Outdated
Comment thread pkg/osimagestream/inspector.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with 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.

Inline comments:
In `@cmd/machine-config-controller/start.go`:
- Around line 287-301: Update createControllers to include renderCtrl in the
slice of controllers it returns, ensuring the controller constructed by
render.New and registered with inspectionCache is passed to runStartCmd and
started via Run.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 04d473bd-677d-44d5-821a-4e7550333fa8

📥 Commits

Reviewing files that changed from the base of the PR and between 647fd77 and fc94819.

📒 Files selected for processing (9)
  • cmd/machine-config-controller/start.go
  • manifests/machineconfigcontroller/deployment.yaml
  • pkg/controller/osimagestream/osimagestream_controller.go
  • pkg/controller/render/render_controller.go
  • pkg/imageutils/inspect_cache.go
  • pkg/imageutils/inspect_cache_test.go
  • pkg/imageutils/reference.go
  • pkg/osimagestream/cached_inspector.go
  • pkg/osimagestream/cached_inspector_test.go
🚧 Files skipped from review as they are similar to previous changes (8)
  • pkg/imageutils/reference.go
  • pkg/imageutils/inspect_cache_test.go
  • manifests/machineconfigcontroller/deployment.yaml
  • pkg/controller/render/render_controller.go
  • pkg/osimagestream/cached_inspector.go
  • pkg/controller/osimagestream/osimagestream_controller.go
  • pkg/imageutils/inspect_cache.go
  • pkg/osimagestream/cached_inspector_test.go

Comment thread cmd/machine-config-controller/start.go
This changes modifies the OSImageStream APIs to replace the requested
SysContext with an interface that allows lazily creating it. This is
necessary for the future cache addition to avoid creating a SysContext
when there's a cache hit.

Signed-off-by: Pablo Rodriguez Nava <git@amail.pablintino.eu>
@pablintino
pablintino force-pushed the image-inspection-cache branch from fc94819 to 8f64c8e Compare July 15, 2026 07:11
@pablintino

Copy link
Copy Markdown
Contributor Author

/pipeline required

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/test e2e-aws-ovn
/test e2e-aws-ovn-upgrade
/test e2e-gcp-op-ocl-part1
/test e2e-gcp-op-ocl-part2
/test e2e-gcp-op-part1
/test e2e-gcp-op-part2
/test e2e-gcp-op-single-node
/test e2e-hypershift

@pablintino
pablintino force-pushed the image-inspection-cache branch from 8f64c8e to 278cd00 Compare July 15, 2026 09:39

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with 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.

Inline comments:
In `@pkg/osimagestream/cached_inspector_test.go`:
- Around line 76-94: Update CachedImagesInspector.Inspect to track all result
indexes for each pullspec instead of overwriting a single resultIndex entry, so
duplicate uncached inputs populate every corresponding result slot. Extend the
tests around TestCachedImagesInspector_MixedHitsAndMisses with a duplicate-input
regression case that verifies all duplicate results are populated correctly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 9e8e8e83-ee7b-42f7-8cff-7037015ffa9f

📥 Commits

Reviewing files that changed from the base of the PR and between 8f64c8e and 278cd00.

📒 Files selected for processing (6)
  • cmd/machine-config-controller/start.go
  • manifests/machineconfigcontroller/deployment.yaml
  • pkg/controller/osimagestream/osimagestream_controller.go
  • pkg/controller/render/render_controller.go
  • pkg/osimagestream/cached_inspector.go
  • pkg/osimagestream/cached_inspector_test.go
🚧 Files skipped from review as they are similar to previous changes (5)
  • manifests/machineconfigcontroller/deployment.yaml
  • pkg/osimagestream/cached_inspector.go
  • pkg/controller/osimagestream/osimagestream_controller.go
  • cmd/machine-config-controller/start.go
  • pkg/controller/render/render_controller.go

Comment thread pkg/osimagestream/cached_inspector_test.go
@pablintino
pablintino force-pushed the image-inspection-cache branch from 278cd00 to 23202b5 Compare July 15, 2026 10:29
@pablintino

Copy link
Copy Markdown
Contributor Author

/pipeline required

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/test e2e-aws-ovn
/test e2e-aws-ovn-upgrade
/test e2e-gcp-op-ocl-part1
/test e2e-gcp-op-ocl-part2
/test e2e-gcp-op-part1
/test e2e-gcp-op-part2
/test e2e-gcp-op-single-node
/test e2e-hypershift

@pablintino

Copy link
Copy Markdown
Contributor Author

/test e2e-gcp-op-part1 e2e-gcp-op-ocl-part1

@pablintino
pablintino force-pushed the image-inspection-cache branch from 23202b5 to 8862d18 Compare July 15, 2026 17:41
@pablintino

Copy link
Copy Markdown
Contributor Author

/pipeline required

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/test e2e-aws-ovn
/test e2e-aws-ovn-upgrade
/test e2e-gcp-op-ocl-part1
/test e2e-gcp-op-ocl-part2
/test e2e-gcp-op-part1
/test e2e-gcp-op-part2
/test e2e-gcp-op-single-node
/test e2e-hypershift

@djoshy

djoshy commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Overall, generally makes sense to me - thanks for breaking down the commits, it was very helpful during the review.

My only nit would be to add a few comments for the Retain() functions added to the main controllers. The simple e2e could perhaps use some explanation since it is not a traditional e2e, but one that is testing just the cache stack we're adding(perhaps that is similar to the other e2es in this package tho?)

/approve

@yuqi-zhang yuqi-zhang left a comment

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.

Mostly lgtm as well (can merge as is if you want). Had a couple of very minor questions/comments

func (ctrl *Controller) Retain(digests []string) []string {
osis, err := ctrl.getExistingOSImageStream()
if err != nil || osis == nil {
return digests

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.

Just to understand this a bit better, we're saying that if we can't get the OSImageSteam object we stop eviction altogether?

Probably fine since if your lister is persistently failing, you probably have a bigger problem than a (relatively small) cache retaining.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Correct, an error shouldn't be permanent, and if so, what you said, there will be other more important issues.

Comment on lines +79 to +88
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
cache.StartEviction(ctx, time.Second, 0)
time.Sleep(2 * time.Second)

assert.Nil(t, cache.Get("sha256:aaa"))
assert.Nil(t, cache.Get("sha256:bbb"))

reloaded := NewFileInspectionCache(path, 0)
assert.Nil(t, reloaded.Get("sha256:aaa"))

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.

Similar to what coderabbit is saying here, is there a way you see to make the tests more deterministic? I agree that using sleep() seems like it could be flaky (although I guess in practice you've tested this and it should be significantly faster than 2 seconds?

Applies to other tests where you use sleep(). Maybe a poll loop with a timeout is better, if there's no deterministic way to test this

Comment on lines 30 to +36
resources:
requests:
cpu: 20m
memory: 50Mi
volumeMounts:
- mountPath: /var/cache/mcc
name: image-inspection-cache

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.

In practice this isn't relevant since the cache would be very light, but let's say that something goes horribly wrong and we do balloon the directory, I think we'd end up getting evicted silently?

Might be worth bounding the emptydir like coderabbit is suggesting, just for additional safety, WDYT

Comment thread pkg/imageutils/inspect_cache.go Outdated
}

dir := filepath.Dir(c.path)
tmp, err := os.CreateTemp(dir, ".inspection-cache-*.tmp")

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.

(suggestion from claude): this can cause puts to silently fail if the directory we're creating this on doesn't exist, can maybe have a defensive os.MkdirAll in the contructor

That said I think you only call this on the /var/cache/mcc which should exist from the mount, so not a big problem

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added a protection that creates the directory. BTW, Claude has suggested a good change: Move my by-hand atomic write to the library the daemon uses. I've done it.

Create a new type in imageutils to cache the labels from inspected
images in disk.

Signed-off-by: Pablo Rodriguez Nava <git@amail.pablintino.eu>
Use the new images cache to create a cache enabled inspector

Signed-off-by: Pablo Rodriguez Nava <git@amail.pablintino.eu>
Signed-off-by: Pablo Rodriguez Nava <git@amail.pablintino.eu>
Signed-off-by: Pablo Rodriguez Nava <git@amail.pablintino.eu>
@pablintino
pablintino force-pushed the image-inspection-cache branch from 8684a46 to a819ff5 Compare July 17, 2026 22:37
@pablintino

Copy link
Copy Markdown
Contributor Author

/pipeline required

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/test e2e-aws-ovn
/test e2e-aws-ovn-upgrade
/test e2e-gcp-op-ocl-part1
/test e2e-gcp-op-ocl-part2
/test e2e-gcp-op-part1
/test e2e-gcp-op-part2
/test e2e-gcp-op-single-node
/test e2e-hypershift

@pablintino

Copy link
Copy Markdown
Contributor Author

/retest-required

@yuqi-zhang yuqi-zhang left a comment

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.

/lgtm

Changes lgtm, thanks!

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label Jul 20, 2026
@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Tests from second stage were triggered manually. Pipeline can be controlled only manually, until HEAD changes. Use command to trigger second stage.

@openshift-ci

openshift-ci Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: djoshy, pablintino, yuqi-zhang

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:
  • OWNERS [djoshy,pablintino,yuqi-zhang]

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@ptalgulk01

Copy link
Copy Markdown
Contributor

4.23 Jobs

  1. https://prow.ci.openshift.org/view/gs/test-platform-results/logs/periodic-ci-openshift-machine-config-operator-release-4.23-periodics-e2e-vsphere-mco-tp-longduration-1of2/2079486593806110720
  2. https://prow.ci.openshift.org/view/gs/test-platform-results/logs/periodic-ci-openshift-machine-config-operator-release-4.23-periodics-e2e-vsphere-mco-tp-longduration-2of2/2079486608570060800
  3. https://prow.ci.openshift.org/view/gs/test-platform-results/logs/periodic-ci-openshift-machine-config-operator-release-4.23-periodics-e2e-aws-mco-fips-proxy-longduration-1of3/2079486622788751360
  4. https://prow.ci.openshift.org/view/gs/test-platform-results/logs/periodic-ci-openshift-machine-config-operator-release-4.23-periodics-e2e-aws-mco-fips-proxy-longduration-2of3/2079486637028413440
  5. https://prow.ci.openshift.org/view/gs/test-platform-results/logs/periodic-ci-openshift-machine-config-operator-release-4.23-periodics-e2e-aws-mco-fips-proxy-longduration-3of3/2079486650945114112

5.0 Jobs

  1. https://prow.ci.openshift.org/view/gs/test-platform-results/logs/periodic-ci-openshift-machine-config-operator-release-5.0-periodics-e2e-vsphere-mco-tp-longduration-1of2/2079486664975060992
  2. https://prow.ci.openshift.org/view/gs/test-platform-results/logs/periodic-ci-openshift-machine-config-operator-release-5.0-periodics-e2e-vsphere-mco-tp-longduration-2of2/2079486678958870528
  3. https://prow.ci.openshift.org/view/gs/test-platform-results/logs/periodic-ci-openshift-machine-config-operator-release-5.0-periodics-e2e-aws-mco-fips-proxy-longduration-1of3/2079486692997206016
  4. https://prow.ci.openshift.org/view/gs/test-platform-results/logs/periodic-ci-openshift-machine-config-operator-release-5.0-periodics-e2e-aws-mco-fips-proxy-longduration-2of3/2079487108124250112
  5. https://prow.ci.openshift.org/view/gs/test-platform-results/logs/periodic-ci-openshift-machine-config-operator-release-5.0-periodics-e2e-aws-mco-fips-proxy-longduration-3of3/2079486722294419456

@pablintino

Copy link
Copy Markdown
Contributor Author

/test e2e-aws-ovn-upgrade

@ptalgulk01

Copy link
Copy Markdown
Contributor

Ran all 10 longduration jobs (5 for 4.23, 5 for 5.0) against the fix.

  • 4.23 aws-fips (3 jobs): All failed at infra level — AWS CloudFormation issue, no tests ran. Not related to this PR.
  • 4.23 vsphere (2 jobs): 6 test failures total — all pre-existing known issues (PolarionID:43278 failing since Jun 15, PolarionID:52520 since Jun 22, others are one-off flakes).
  • 5.0 vsphere (2 jobs): 4 test failures — same known issues as 4.23 plus PolarionID:89097 (4.13 scaleup) which has never passed in any 5.0 build.
  • 5.0 aws-fips (3 jobs): 3 MCO test failures across 3 jobs — all pre-existing. One job (2of3) had zero MCO test failures but was marked failed due to a gather-proxy SSH key issue.

Checked nightly history (last 10 runs per job): These jobs have 0-10% pass rate in nightly. Every failure in this run matches existing nightly failures. No new regressions from this PR. All failures are pre-existing or infra-related.

/verified by @ptalgulk01
/label qe-approved.

@openshift-ci

openshift-ci Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

@ptalgulk01: The label(s) /label qe-approved. cannot be applied. These labels are supported: acknowledge-critical-fixes-only, platform/aws, platform/azure, platform/baremetal, platform/google, platform/libvirt, platform/openstack, ga, tide/merge-method-merge, tide/merge-method-rebase, tide/merge-method-squash, px-approved, docs-approved, qe-approved, ux-approved, no-qe, rebase/manual, cluster-config-api-changed, run-integration-tests, verified, ready-for-human-review, approved, backport-risk-assessed, bugzilla/valid-bug, cherry-pick-approved, jira/skip-dependent-bug-check, jira/valid-bug, ok-to-test, stability-fix-approved, staff-eng-approved. Is this label configured under labels -> additional_labels or labels -> restricted_labels in plugin.yaml?

Details

In response to this:

Ran all 10 longduration jobs (5 for 4.23, 5 for 5.0) against the fix.

  • 4.23 aws-fips (3 jobs): All failed at infra level — AWS CloudFormation issue, no tests ran. Not related to this PR.
  • 4.23 vsphere (2 jobs): 6 test failures total — all pre-existing known issues (PolarionID:43278 failing since Jun 15, PolarionID:52520 since Jun 22, others are one-off flakes).
  • 5.0 vsphere (2 jobs): 4 test failures — same known issues as 4.23 plus PolarionID:89097 (4.13 scaleup) which has never passed in any 5.0 build.
  • 5.0 aws-fips (3 jobs): 3 MCO test failures across 3 jobs — all pre-existing. One job (2of3) had zero MCO test failures but was marked failed due to a gather-proxy SSH key issue.

Checked nightly history (last 10 runs per job): These jobs have 0-10% pass rate in nightly. Every failure in this run matches existing nightly failures. No new regressions from this PR. All failures are pre-existing or infra-related.

/verified by @ptalgulk01
/label qe-approved.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@openshift-ci-robot openshift-ci-robot added the verified Signifies that the PR passed pre-merge verification criteria label Jul 22, 2026
@openshift-ci-robot

Copy link
Copy Markdown
Contributor

@ptalgulk01: This PR has been marked as verified by @ptalgulk01.

Details

In response to this:

Ran all 10 longduration jobs (5 for 4.23, 5 for 5.0) against the fix.

  • 4.23 aws-fips (3 jobs): All failed at infra level — AWS CloudFormation issue, no tests ran. Not related to this PR.
  • 4.23 vsphere (2 jobs): 6 test failures total — all pre-existing known issues (PolarionID:43278 failing since Jun 15, PolarionID:52520 since Jun 22, others are one-off flakes).
  • 5.0 vsphere (2 jobs): 4 test failures — same known issues as 4.23 plus PolarionID:89097 (4.13 scaleup) which has never passed in any 5.0 build.
  • 5.0 aws-fips (3 jobs): 3 MCO test failures across 3 jobs — all pre-existing. One job (2of3) had zero MCO test failures but was marked failed due to a gather-proxy SSH key issue.

Checked nightly history (last 10 runs per job): These jobs have 0-10% pass rate in nightly. Every failure in this run matches existing nightly failures. No new regressions from this PR. All failures are pre-existing or infra-related.

/verified by @ptalgulk01
/label qe-approved.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@ptalgulk01

Copy link
Copy Markdown
Contributor

/label qe-approved

@openshift-ci openshift-ci Bot added the qe-approved Signifies that QE has signed off on this PR label Jul 22, 2026
@openshift-ci-robot

openshift-ci-robot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

@pablintino: This pull request references MCO-2413 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "5.0.0" version, but no target version was set.

Details

In response to this:

- What I did

Added a cache for the image inspection operations in the MCC that use an emptyDir in the pod to store the data.

- How to verify it

TBD

- Description for the changelog

Added a cache for the image inspection operations in the MCC that use an emptyDir in the pod to store the data.

Summary by CodeRabbit

  • New Features
  • Added optional, on-disk image inspection caching to the machine-config-controller (configurable via --streams-cache, default /var/cache/mcc), including periodic eviction that keeps active digests warm.
  • The controller now mounts a dedicated cache directory (/var/cache/mcc) so inspection data can persist across restarts.
  • Bug Fixes
  • Improved image inspection lifecycle handling by creating contexts on demand rather than eagerly.
  • Cache updates now avoid persisting failed or partial inspection results.
  • Tests
  • Updated and expanded unit tests to cover the new caching and retention behavior.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci

openshift-ci Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

@pablintino: all tests passed!

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. lgtm Indicates that a PR is ready to be merged. qe-approved Signifies that QE has signed off on this PR verified Signifies that the PR passed pre-merge verification criteria

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants