Skip to content

fix: default init container imagePullPolicy to IfNotPresent - #1692

Open
dkwon17 wants to merge 1 commit into
devfile:mainfrom
dkwon17:imagepullpolicy
Open

fix: default init container imagePullPolicy to IfNotPresent#1692
dkwon17 wants to merge 1 commit into
devfile:mainfrom
dkwon17:imagepullpolicy

Conversation

@dkwon17

@dkwon17 dkwon17 commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

Assisted-by: Claude Opus 4.6

What does this PR do?

Changes the default imagePullPolicy for DWO-managed init containers (project-clone, and DWOC-defined init containers) from Always to IfNotPresent. The global workspace.imagePullPolicy for user/devfile containers remains Always.

Admins can still override via DWOC (projectClone.imagePullPolicy, or per init container).

What issues does this PR fix or reference?

#1674

Is it tested? How?

Tested with this test plan: https://gist.github.com/dkwon17/9f21c98fae6e9eeecf985cf7c818eaf4

PR Checklist

  • E2E tests pass (when PR is ready, comment /test v8-devworkspace-operator-e2e, v8-che-happy-path to trigger)
    • v8-devworkspace-operator-e2e: DevWorkspace e2e test
    • v8-che-happy-path: Happy path for verification integration with Che

Summary by CodeRabbit

  • Bug Fixes

    • Init containers now default to the IfNotPresent image pull policy when none is specified.
    • Explicit image pull policies remain unchanged.
    • Workspace containers continue using the Always policy.
  • Tests

    • Added coverage for default, configured, and merged image pull policies.

Assisted-by: Claude Opus 4.6

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: David Kwon <dakwon@redhat.com>
@openshift-ci

openshift-ci Bot commented Aug 12, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: dkwon17

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:

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

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The change sets the project-clone default image pull policy to IfNotPresent, applies that policy to unspecified init containers, preserves explicit policies, and adds controller and configuration merge test coverage.

Changes

Init container image pull policy

Layer / File(s) Summary
Policy defaults and controller merge
controllers/workspace/devworkspace_controller.go, pkg/config/defaults.go
Project-clone configuration defaults to IfNotPresent. The controller assigns IfNotPresent to init containers with an empty policy.
Policy behavior validation
controllers/workspace/devworkspace_controller_test.go, pkg/config/sync_test.go
Tests cover default and explicit init-container policies, workspace containers using Always, and preservation of non-empty policies during configuration merging.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related issues

  • Issue 1674: The pull request changes the project-clone default ImagePullPolicy to IfNotPresent, matching this issue’s objective.

Suggested reviewers: akurinnoy, btjd, ibuziuk

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: defaulting init container imagePullPolicy to IfNotPresent.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@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/config/defaults.go`:
- Line 60: Update the public API documentation for
workspace.projectClone.imagePullPolicy in the relevant type definition and
regenerated CRD output to state that an unset value defaults to IfNotPresent,
rather than inheriting workspace.imagePullPolicy. Ensure the generated
documentation matches the API source and explicitly avoids implying that
workspace.imagePullPolicy: Always affects project-clone.
🪄 Autofix

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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 16db8c69-d1eb-4471-974d-0527c92b28e1

📥 Commits

Reviewing files that changed from the base of the PR and between fc00100 and fd8bd97.

📒 Files selected for processing (4)
  • controllers/workspace/devworkspace_controller.go
  • controllers/workspace/devworkspace_controller_test.go
  • pkg/config/defaults.go
  • pkg/config/sync_test.go

Comment thread pkg/config/defaults.go
ContainerSecurityContext: nil, // Set per-platform in setDefaultContainerSecurityContext()
DefaultTemplate: nil,
ProjectCloneConfig: &v1alpha1.ProjectCloneConfig{
ImagePullPolicy: corev1.PullIfNotPresent,

@coderabbitai coderabbitai Bot Aug 12, 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

Update the public fallback documentation.

Line 60 makes an unset workspace.projectClone.imagePullPolicy resolve to IfNotPresent. apis/controller/v1alpha1/devworkspaceoperatorconfig_types.go:395-407 still states that an unset value uses .config.workspace.imagePullPolicy. Update the API and generated CRD documentation so users do not expect workspace.imagePullPolicy: Always to affect project-clone.

🤖 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/config/defaults.go` at line 60, Update the public API documentation for
workspace.projectClone.imagePullPolicy in the relevant type definition and
regenerated CRD output to state that an unset value defaults to IfNotPresent,
rather than inheriting workspace.imagePullPolicy. Ensure the generated
documentation matches the API source and explicitly avoids implying that
workspace.imagePullPolicy: Always affects project-clone.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

devworkspace_controller.go:396 : this else is unreachable after the defaults.go change. workspace.Config comes from ResolveConfigForWorkspace → mergeConfig, which only overwrites
non-empty values, so ProjectCloneConfig.ImagePullPolicy is never "".

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 controllers/workspace/devworkspace_controller.go --items all --match 'ResolveConfigForWorkspace|ImagePullPolicy|InitContainer' || true
ast-grep outline pkg/config --items all --match 'ResolveConfigForWorkspace|mergeConfig' || true

printf '\n--- controller policy references ---\n'
rg -n -C 8 'ProjectCloneConfig\.ImagePullPolicy|ImagePullPolicy' controllers/workspace/devworkspace_controller.go

printf '\n--- configuration resolution and merge references ---\n'
rg -n -C 8 'func\s+(ResolveConfigForWorkspace|mergeConfig)\s*\(' pkg/config

printf '\n--- configuration assignment references ---\n'
rg -n -C 5 'workspace\.Config|\.Config\s*=' controllers pkg --glob '*.go'

printf '\n--- relevant tests ---\n'
rg -n -C 5 'ProjectCloneConfig.*ImagePullPolicy|ImagePullPolicy.*ProjectCloneConfig|PullIfNotPresent' controllers/workspace pkg/config --glob '*_test.go'

Length of output: 67843


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- workspace configuration resolution ---'
sed -n '110,150p' controllers/workspace/devworkspace_controller.go

printf '%s\n' '--- ResolveConfigForWorkspace ---'
sed -n '59,115p' pkg/config/sync.go

printf '%s\n' '--- global configuration initialization and default merge ---'
rg -n -C 10 'defaultConfig|internalConfig|SetGlobalConfig|mergeConfig\(' pkg/config --glob '*.go'

printf '%s\n' '--- mergeConfig ProjectCloneConfig behavior ---'
sed -n '250,430p' pkg/config/sync.go

printf '%s\n' '--- configuration-related tests that establish default merging ---'
rg -n -C 6 'defaultConfig|ProjectCloneConfig|ResolveConfigForWorkspace|mergeConfig' pkg/config --glob '*_test.go'

Length of output: 91908


@rohanKanojia, confirmed.

internalConfig starts from defaultConfig, and mergeConfig does not replace ProjectCloneConfig.ImagePullPolicy with an empty value. ResolveConfigForWorkspace also merges an external configuration over internalConfig.

Therefore, workspace.Config.Workspace.ProjectCloneConfig.ImagePullPolicy is always non-empty. The fallback at devworkspace_controller.go:396-398 is unreachable.

This also confirms the documentation finding. The API documentation must not state that project-clone inherits workspace.imagePullPolicy.


🧬 Code Graph Analysis Results

apis/controller/v1alpha1/devworkspaceoperatorconfig_types.go:395-407

ProjectCloneConfig struct {
	// Image is the container image to use for cloning projects
	Image string `json:"image,omitempty"`
	// ImagePullPolicy configures the imagePullPolicy for the project clone container.
	// If undefined, the general setting .config.workspace.imagePullPolicy is used instead.
	ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitempty"`
	// Resources defines the resource (cpu, memory) limits and requests for the project
	// clone container. To explicitly not specify a limit or request, define the resource
	// quantity as zero ('0')
	Resources *corev1.ResourceRequirements `json:"resources,omitempty"`
	// Env allows defining additional environment variables for the project clone container.
	Env []corev1.EnvVar `json:"env,omitempty"`
}

apis/controller/v1alpha1/devworkspaceoperatorconfig_types.go:167-174

WorkspaceConfig struct {
	// ProjectCloneConfig defines configuration related to the project clone init container
	// that is used to clone git projects into the DevWorkspace.
	ProjectCloneConfig *ProjectCloneConfig `json:"projectClone,omitempty"`
	// RestoreConfig defines configuration related to the workspace restore init container
	// that is used to restore workspace data from a backup image.
	RestoreConfig *RestoreConfig `json:"restore,omitempty"`

apis/controller/v1alpha1/devworkspaceoperatorconfig_types.go:175-181

	// ImagePullPolicy defines the imagePullPolicy used for containers in a DevWorkspace
	// For additional information, see Kubernetes documentation for imagePullPolicy. If
	// not specified, the default value of "Always" is used.
	// +kubebuilder:validation:Enum=IfNotPresent;Always;Never
	ImagePullPolicy string `json:"imagePullPolicy,omitempty"`

✏️ Learnings added
Learnt from: rohanKanojia
Repo: devfile/devworkspace-operator PR: 1692
File: pkg/config/defaults.go:60-60
Timestamp: 2026-08-13T07:01:37.222Z
Learning: In `pkg/config/sync.go`, `internalConfig` is initialized from `defaultConfig`, and `mergeConfig` only overwrites `WorkspaceConfig.ProjectCloneConfig.ImagePullPolicy` when the incoming value is non-empty. `ResolveConfigForWorkspace` merges external DevWorkspaceOperatorConfig values over `internalConfig`. Therefore, after `pkg/config/defaults.go` sets `ProjectCloneConfig.ImagePullPolicy` to `corev1.PullIfNotPresent`, the fallback branch in `controllers/workspace/devworkspace_controller.go` that handles an empty project-clone image pull policy is unreachable.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

You are interacting with an AI system.

@openshift-ci

openshift-ci Bot commented Aug 12, 2026

Copy link
Copy Markdown

@dkwon17: The following tests failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/v14-images fd8bd97 link true /test v14-images
ci/prow/v14-devworkspace-operator-e2e fd8bd97 link true /test v14-devworkspace-operator-e2e
ci/prow/v14-che-happy-path fd8bd97 link true /test v14-che-happy-path

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.

@rohanKanojia

rohanKanojia commented Aug 13, 2026

Copy link
Copy Markdown
Member

I tested all scenarios in test plan and can confirm they work as expected ✔️

Claude pointed out this scenario, do you think it's valid?

DWOC init container default overrides admin-configured imagePullPolicy during strategic merge

The new default at line 427 sets ImagePullPolicy = IfNotPresent on DWOC init containers before they enter MergeInitContainers(). Because corev1.Container.ImagePullPolicy has json:"imagePullPolicy,omitempty", a previously-empty value was omitted from the strategic merge patch JSON, preserving whatever the base init container had. Now IfNotPresent is always serialized into the patch and overrides the base value when the containers share a name.

Steps to reproduce

Step 1. Set projectClone.imagePullPolicy to Always in DWOC, and add a DWOC init container named project-clone (to inject env vars) without explicit imagePullPolicy:

oc patch devworkspaceoperatorconfig devworkspace-operator-config -n "$DWO_NS" \
  --type=merge -p '{
    "config":{
      "workspace":{
        "projectClone":{"imagePullPolicy":"Always"},
        "initContainers":[
          {"name":"project-clone","env":[{"name":"EXTRA_VAR","value":"injected"}]}
        ]
      }
    }
  }'

Step 2. Create a DevWorkspace with a project:

cat <<'EOF' | oc apply -n "$TEST_NS" -f -
kind: DevWorkspace
apiVersion: workspace.devfile.io/v1alpha2
metadata:
  name: test-merge-conflict
spec:
  started: true
  template:
    projects:
      - name: sample
        git:
          remotes:
            origin: "https://github.com/che-samples/web-nodejs-sample.git"
    components:
      - name: dev
        container:
          image: quay.io/devfile/universal-developer-image:latest
          memoryLimit: 512Mi
EOF

Step 3. Wait for the deployment to be created:

while ! oc get deployment -l controller.devfile.io/devworkspace_name=test-merge-conflict \
  -n "$TEST_NS" 2>/dev/null | grep -q .; do sleep 5; done

Step 4. Check the project-clone init container's imagePullPolicy:

oc get deployment -l controller.devfile.io/devworkspace_name=test-merge-conflict -n "$TEST_NS" \
  -o jsonpath='{.items[0].spec.template.spec.initContainers[?(@.name=="project-clone")].imagePullPolicy}'
  • Expected: Always (admin explicitly set projectClone.imagePullPolicy: Always — the DWOC patch only adds env vars)
  • Actual: IfNotPresent (DWOC patch gets defaulted to IfNotPresent at line 427, which overrides the base during strategic merge)

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants