Skip to content

ssf: add script to start bundle with macadam#1189

Open
anjannath wants to merge 2 commits intocrc-org:release-4.21from
anjannath:ssf-test
Open

ssf: add script to start bundle with macadam#1189
anjannath wants to merge 2 commits intocrc-org:release-4.21from
anjannath:ssf-test

Conversation

@anjannath
Copy link
Copy Markdown
Member

@anjannath anjannath commented Nov 4, 2025

with the self sufficient changes for the bundle
have to make sure it runs well with CRC as well
as via the cloud-init path with an user-data

for crc we have a test in openshift-ci that run
the bundle with CRC once it is generated

this adds a shell script, which we'll run on CI
for every PR to catch any regressions

Assisted-By: Gemini

Needs: cfergeau/podman#37

Summary by CodeRabbit

  • Chores
    • Replaced OpenShift CRC-based CI test setup with macadam-based smoke test workflow for improved testing infrastructure
    • Updated microshift testing configuration
    • Updated default release candidate mirror URL and version retrieval endpoint

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Nov 4, 2025

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

Refactors CI test infrastructure to replace direct CRC invocations with a Macadam-based hypervisor approach. Introduces a comprehensive automation script for VM provisioning, networking setup, and cluster readiness verification, while updating related CI workflows and configuration paths.

Changes

Cohort / File(s) Summary
Macadam Automation Script
run-with-macadam.py
New 565-line Python script automating CRC VM provisioning via Macadam, including config loading, dependency checks, SSH keypair generation, cloud-init creation, disk image extraction, gvproxy integration for DNS/port-forwarding, kubeconfig retrieval, and cluster health checks.
CI Workflow Refactoring
ci.sh
Replaces CRC clone/build sequence with Macadam-based smoke test flow; adds destroy_cluster() function for VM cleanup; introduces CRC_BUNDLE_PATH and PULL_SECRET_PATH environment variables; removes old CRC-specific steps (createdisk.sh invocation, openshift-tests extraction).
Configuration Updates
snc.sh
Updates default MIRROR URL from ocp-dev-preview to ocp and release version retrieval path from candidate/release.txt to candidate-4.20/release.txt.
Microshift Invocation
ci_microshift.sh
Removes MICROSHIFT_PRERELEASE=yes environment flag from microshift.sh invocation.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CI as CI Script
    participant Script as run-with-macadam.py
    participant Dep as Dependencies
    participant SSH as SSH Setup
    participant Macadam as Macadam
    participant VM as VM
    participant GVProxy as GVProxy
    participant API as K8s API
    
    User->>CI: Trigger CI pipeline
    CI->>Script: Execute with env vars
    Script->>Dep: Check zstd, tar, curl, QEMU
    Dep-->>Script: Ensure installed
    Script->>SSH: Generate SSH keypair
    SSH-->>Script: Return key paths
    Script->>Script: Load pull secret & resources
    Script->>Script: Generate cloud-init user-data
    Script->>Script: Extract crc.qcow2 from bundle
    Script->>Macadam: Ensure macadam binary exists
    Script->>Macadam: Start VM with cloud-init
    Macadam->>VM: Provision & boot
    VM-->>Macadam: Ready
    Script->>GVProxy: Configure API server DNS
    Script->>GVProxy: Forward port mappings
    Script->>VM: Wait for SSH readiness
    VM-->>Script: SSH available
    Script->>VM: Retrieve kubeconfig via SSH
    VM-->>Script: kubeconfig data
    Script->>API: Wait for API server readiness
    API-->>Script: Cluster stable
    Script-->>CI: Setup complete
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • gbraad
  • praveenkumar

Poem

🐰 A macadam path for VMs to roam,
Where gvproxy guides them safely home,
SSH keys and cloud-init combine,
With K8s clusters waiting in line,
No CRC clone, just scripts so fine! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Title check ✅ Passed The title 'ssf: add script to start bundle with macadam' directly describes the main change: adding a script for macadam-based bundle startup, which aligns with the primary objective of the PR.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

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 and usage tips.

Tip

You can customize the tone of the review comments and chat replies.

Configure the tone_instructions setting to customize the tone of the review comments and chat replies. For example, you can set the tone to Act like a strict teacher, Act like a pirate and more.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 8

🧹 Nitpick comments (2)
run-with-macadam.sh (2)

284-292: Fragile regex extraction of SSH port from gvproxy.

Similar to the socket path extraction, the sed regex sed -n 's/.*-ssh-port \([0-9]*\).*/\1/p' is brittle. If the command-line format changes, this fails silently.

Verify the format of gvproxy's -ssh-port flag and consider extracting both socket and port using a more robust approach (e.g., structured parsing or environment variables).


277-278: Hard-coded 180-second sleep inflexible for varying infra.

The sleep 180 assumes all VMs take exactly 3 minutes to boot, which may not hold across different hardware or CI runners. For slower infra, the wait is insufficient; for faster infra, it wastes time. Consider polling with timeout instead.

echo "Waiting for VM to start (up to 10 minutes)..."
local timeout=600
local elapsed=0
while [[ $elapsed -lt $timeout ]]; do
    if macadam ssh crc-ng -- exit 0 2>/dev/null; then
        echo "VM is reachable."
        break
    fi
    sleep 5
    ((elapsed += 5))
done
if [[ $elapsed -ge $timeout ]]; then
    die "VM did not become reachable within ${timeout}s."
fi
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2914074 and 8c6368f.

📒 Files selected for processing (1)
  • run-with-macadam.sh (1 hunks)

Comment thread run-with-macadam.sh Outdated
Comment thread run-with-macadam.sh Outdated
Comment thread run-with-macadam.sh Outdated
Comment thread run-with-macadam.sh Outdated
Comment thread run-with-macadam.sh Outdated
Comment thread run-with-macadam.sh Outdated
Comment thread run-with-macadam.sh Outdated
Comment thread run-with-macadam.sh Outdated
Comment thread run-with-macadam.sh Outdated
Comment thread run-with-macadam.sh Outdated
Comment thread run-with-macadam.sh Outdated
Comment thread run-with-macadam.sh Outdated
@praveenkumar
Copy link
Copy Markdown
Member

This script should be added as part of CI run.

Comment thread run-with-macadam.sh Outdated
GVPROXY_SOCKET_PATH=$(echo "${gvproxy_cmd}" | sed -n 's/.*-services unix:\/\/\([^ ]*\).*/\1/p')
if [[ -z "${GVPROXY_SOCKET_PATH}" ]]; then
die "Could not find the gvproxy socket path."
fi
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.

Maybe this is / should be exposed in macadam inspect

Comment thread run-with-macadam.sh Outdated
Comment thread run-with-macadam.sh Outdated
content: '$PASS_DEVELOPER'
permissions: '0644'
- path: /opt/crc/ocp-custom-domain.service.done
permissions: '0644'
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.

This is not related to this PR, but hopefully handling of custom domains can be improved so that this is not needed.

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.

Actually ocp-custom-domain.service has ExecCondition=/usr/local/bin/crc-self-sufficient-env.sh, will it be run with macadam?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

While running with macadam with a cloud-init user-data it is running in self-sufficient mode (i.e CRC_SEFL_SUFFICIENT=1 and systemd services doing the setup)

so this service for domain name change will also run, I think we could add another config variable in the /etc/sysconfig/crc-env to enable/disable it and provide a proper way to control it, for now this is a hack to skip the service

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (6)
run-with-macadam.sh (6)

17-22: cleanup() exits early on macadam failure, blocking file cleanup.

The macadam rm command at line 21 fails if macadam is unavailable or the VM doesn't exist. Since cleanup() runs under set -e, it exits with error status before reaching the rm -f statements, leaving temporary files behind and violating the trap contract.

Apply this diff:

  function cleanup() {
      echo "--- Cleaning up ---"
      rm -f user-data crc.img crc.qcow2 bundle.tar kubeconfig "${PRIV_KEY_PATH}" "${PUB_KEY_PATH}"
-     macadam rm crc-ng --force
+     macadam rm crc-ng --force 2>/dev/null || true
  }

149-164: macadam version not pinned; "latest" tag breaks reproducibility and complicates CI debugging.

Line 151 uses the mutable latest release tag, which allows different CI runs to download different versions. This prevents reproducible builds and complicates root-cause analysis when failures occur. Additionally, lines 155 and 159 invoke sudo without verifying passwordless access; if the CI environment requires a password, the script will hang or fail silently.

Pin the macadam version and verify passwordless sudo:

+ # Ensure passwordless sudo is available for macadam installation
+ if ! sudo -n true 2>/dev/null; then
+     die "This script requires passwordless sudo access to install macadam to /opt/macadam."
+ fi
+
- local version="latest"
+ # Pin to a specific stable version for reproducibility; update when macadam releases compatible changes
+ local version="v0.0.1"  # Replace with current stable version
  local url="https://github.com/crc-org/macadam/releases/download/${version}/macadam-linux-amd64"

Alternatively, install to a user-writable directory (e.g., $HOME/.local/bin) to avoid sudo altogether.


58-72: xtrace disabled but never restored, impairing script debugging.

Line 61 disables xtrace to protect secrets, but there is no corresponding restoration. If the script is invoked with bash -x for debugging, tracing remains disabled for all subsequent code, hindering troubleshooting.

Apply this diff to capture and restore xtrace state:

  function load_resources() {
      # Unset xtrace to prevent secrets from being exposed if the script is run with -x
+     local xtrace_was_set=0
+     if [[ "$-" == *x* ]]; then
+         xtrace_was_set=1
+     fi
      set +x
      echo "--- Loading resources ---"
      if [[ -z "${PULL_SECRET_PATH}" || ! -f "${PULL_SECRET_PATH}" ]]; then
          die "Path to pull secret file must be set via PULL_SECRET_PATH, and the file must exist."
      fi
      if [[ ! -f "${PUB_KEY_PATH}" ]]; then
          die "Public key file not found at ${PUB_KEY_PATH}. This should have been generated."
      fi
  
      PULL_SECRET=$(cat "${PULL_SECRET_PATH}")
      PUB_KEY=$(cat "${PUB_KEY_PATH}")
+     if [[ $xtrace_was_set -eq 1 ]]; then
+         set -x
+     fi
  }

180-182: macadam start failure does not halt execution, causing silent cascade failures.

When macadam start crc-ng fails (line 180), the script only echoes a message and continues. Downstream functions (DNS setup, port forwarding, kubeconfig retrieval) will execute against a non-running VM, causing confusing failures downstream instead of a clear error at the point of failure.

Replace with immediate termination:

- if ! macadam start crc-ng --log-level debug; then
-     echo "Machine didn't come up in time"
- fi
+ if ! macadam start crc-ng --log-level debug; then
+     die "Machine didn't come up in time"
+ fi

230-237: Regex for gvproxy socket path extraction is fundamentally broken.

The sed regex at line 234 ('s/.*-services unix:\/\/\([^ ]*\).*/\1/p') does not match actual gvproxy command-line output. Gvproxy uses --listen unix:///path (double dash, triple slashes), but the regex looks for -services unix:// (single dash, double slashes). This regex will silently fail to extract the socket path, causing the check at line 235 to die with a generic error message that masks the real problem.

Replace with correct extraction targeting the --listen flag:

- GVPROXY_SOCKET_PATH=$(echo "${gvproxy_cmd}" | sed -n 's/.*-services unix:\/\/\([^ ]*\).*/\1/p')
+ GVPROXY_SOCKET_PATH=$(echo "${gvproxy_cmd}" | sed -n 's/.*--listen unix:\/\/\/\([^ ]*\).*/\1/p')

Verify this against actual gvproxy process output (e.g., pgrep -af gvproxy) to confirm the format matches.


74-114: xtrace disabled but never restored; credentials written with world-readable permissions.

Line 79 disables xtrace to protect secrets in the cloud-init heredoc, but it is never restored, compounding the issue from load_resources(). Additionally, sensitive credentials at lines 100–108 (pull-secret, pass_kubeadmin, pass_developer) are written with permissions: '0644', making them world-readable. These should be restricted to 0600 (owner only).

Apply this diff:

  function gen_cloud_init() {
      echo "--- Generating cloud-init user-data ---"
      rm -f user-data
      # Unset xtrace to prevent secrets from being exposed if the script is run with -x
+     local xtrace_was_set=0
+     if [[ "$-" == *x* ]]; then
+         xtrace_was_set=1
+     fi
      set +x
      cat <<EOF >user-data
  #cloud-config
  runcmd:
    - systemctl enable --now kubelet
  write_files:
  - path: /home/core/.ssh/authorized_keys
    content: '$PUB_KEY'
    owner: core
    permissions: '0600'
  - path: /opt/crc/id_rsa.pub
    content: '$PUB_KEY'
    owner: root:root
    permissions: '0644'
  - path: /etc/sysconfig/crc-env
    content: |
      CRC_SELF_SUFFICIENT=1
      CRC_NETWORK_MODE_USER=1
    owner: root:root
    permissions: '0644'
  - path: /opt/crc/pull-secret
    content: |
      $PULL_SECRET
-   permissions: '0644'
+   permissions: '0600'
  - path: /opt/crc/pass_kubeadmin
    content: '$PASS_KUBEADMIN'
-   permissions: '0644'
+   permissions: '0600'
  - path: /opt/crc/pass_developer
    content: '$PASS_DEVELOPER'
-   permissions: '0644'
+   permissions: '0600'
  - path: /opt/crc/ocp-custom-domain.service.done
    permissions: '0644'
  EOF
      USER_DATA_PATH="$(pwd)/user-data"
      echo "cloud-init user-data file created."
+     if [[ $xtrace_was_set -eq 1 ]]; then
+         set -x
+     fi
  }
🧹 Nitpick comments (2)
run-with-macadam.sh (2)

257-298: SSH port extraction relies on fragile regex pattern.

The regex at line 272 ('s/.*-ssh-port \([0-9]*\).*/\1/p') extracts the SSH port from gvproxy command-line output. While this pattern is simpler and likely more robust than the socket path extraction, it still assumes a fixed flag format and no embedded spaces. If gvproxy's command-line interface evolves, this extraction will silently fail. At a minimum, verify this regex against actual pgrep -af gvproxy output for your environment.

Consider validating the extracted port (ensure it's a valid port number between 1–65535) to catch extraction failures early:

if [[ -z "${ssh_port}" || ! "${ssh_port}" =~ ^[0-9]+$ ]] || (( ssh_port < 1 || ssh_port > 65535 )); then
    die "Invalid SSH port extracted from gvproxy: ${ssh_port}"
fi

1-16: Script setup and global variables are well-organized.

The use of set -euo pipefail enables strict error handling. Constants are properly marked readonly, and mutable globals are clearly documented. The default bundle path includes an architecture-specific reference (arm64); consider making this configurable or architecture-agnostic for broader CI portability.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8c6368f and 93712c9.

📒 Files selected for processing (1)
  • run-with-macadam.sh (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-10-02T13:13:28.229Z
Learnt from: kpouget
Repo: crc-org/snc PR: 1168
File: systemd/dnsmasq.sh.template:3-12
Timestamp: 2025-10-02T13:13:28.229Z
Learning: The file `/etc/sysconfig/crc-env` in the crc-org/snc repository contains configuration variables and file paths (e.g., `CRC_PASS_KUBEADMIN_PATH`, `CRC_PUB_KEY_PATH`, `CRC_NETWORK_MODE_USER`, `APPS_DOMAIN`), not the actual secrets. The secrets themselves are stored in separate files referenced by these paths. Sourcing `crc-env` with xtrace enabled does not leak sensitive information.

Applied to files:

  • run-with-macadam.sh
📚 Learning: 2025-10-07T07:03:06.884Z
Learnt from: kpouget
Repo: crc-org/snc PR: 1168
File: systemd/crc-self-sufficient-env.sh:10-17
Timestamp: 2025-10-07T07:03:06.884Z
Learning: In the crc-org/snc repository, the CRC_CLOUD environment variable has been removed from the codebase. The self-sufficient environment check in systemd/crc-self-sufficient-env.sh now only validates CRC_SELF_SUFFICIENT=1, not CRC_CLOUD.

Applied to files:

  • run-with-macadam.sh
🔇 Additional comments (5)
run-with-macadam.sh (5)

31-42: SSH keypair generation is well-implemented.

The function correctly generates a temporary RSA keypair with an empty passphrase, suitable for CI automation. The cleanup function (line 20) properly removes these temporary files on exit.


44-56: Dependency check and installation is straightforward and pragmatic for CI.

The function correctly uses command -v to detect missing dependencies and attempts installation via yum if needed. This is appropriate for CI environments where tools may not be pre-installed.


116-133: Disk image extraction is robust with proper validation.

The function correctly uses tar --zstd to decompress and stream the qcow2 disk image from the bundle. The validation check at line 128 (-s) ensures the file is non-empty, catching extraction failures early.


185-197: Port forwarding via gvproxy HTTP API is well-implemented.

The function correctly uses curl with --unix-socket to communicate with gvproxy and expose the API server port. Error handling is in place with the -f flag.


300-331: Cluster status validation and main orchestration flow are well-structured.

The cluster readiness check uses appropriate timeout and stability thresholds. The main orchestration flow correctly chains dependency checks, resource preparation, VM provisioning, cluster setup, and validation. The trap for cleanup ensures proper resource teardown on exit.

@anjannath anjannath force-pushed the ssf-test branch 2 times, most recently from d3bd852 to 4f7813e Compare November 5, 2025 12:01
@anjannath anjannath self-assigned this Nov 12, 2025
@anjannath anjannath moved this to Work In Progress in Project planning: crc Nov 12, 2025
Comment thread run-with-macadam.sh Outdated
Comment thread run-with-macadam.sh Outdated
@cfergeau
Copy link
Copy Markdown
Contributor

this adds a shell script, which we'll run on CI
for every PR to catch any regressions

Since it’s preferable not to maintain such a shell script in the long run, if we add it to CI, we’ll have to remember to replace it with something else at some point.

@anjannath anjannath moved this from Work In Progress to Hold in Project planning: crc Nov 24, 2025
@anjannath
Copy link
Copy Markdown
Member Author

this adds a shell script, which we'll run on CI
for every PR to catch any regressions

Since it’s preferable not to maintain such a shell script in the long run, if we add it to CI, we’ll have to remember to replace it with something else at some point.

once we have the self sufficient bundle/macadam support with crc (crc-ng) then we can just remove this script, as then test will be with crc itself

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (5)
run-with-macadam.sh (5)

59-72: Restore xtrace setting after loading secrets.

The function disables xtrace at line 61 but never restores it, so tracing remains disabled if the script was invoked with bash -x. This breaks debugging for the remainder of the script execution.

Apply this diff to capture and restore the original trace state:

 function load_resources() {
     # Unset xtrace to prevent secrets from being exposed if the script is run with -x
+    local xtrace_state
+    xtrace_state=$([[ $- == *x* ]] && echo "set -x" || echo "set +x")
     set +x
     echo "--- Loading resources ---"
     if [[ -z "${PULL_SECRET_PATH}" || ! -f "${PULL_SECRET_PATH}" ]]; then
         die "Path to pull secret file must be set via PULL_SECRET_PATH, and the file must exist."
     fi
     if [[ ! -f "${PUB_KEY_PATH}" ]]; then
         die "Public key file not found at ${PUB_KEY_PATH}. This should have been generated."
     fi
 
     PULL_SECRET=$(cat "${PULL_SECRET_PATH}")
     PUB_KEY=$(cat "${PUB_KEY_PATH}")
+    eval "$xtrace_state"
 }

75-117: Restore xtrace and fix credentials file permissions.

Two issues in this function:

  1. Trace restoration (line 79): Like load_resources(), xtrace is disabled but never restored, breaking debugging.
  2. World-readable secrets (lines 100-108): Files containing credentials (pull-secret, pass_kubeadmin, pass_developer) are written with 0644 permissions, making them readable by any user on the system. These should be 0600.

Apply this diff to fix both issues:

 function gen_cloud_init() {
     echo "--- Generating cloud-init user-data ---"
     rm -f user-data
     # Unset xtrace to prevent secrets from being exposed if the script is run with -x
+    local xtrace_state
+    xtrace_state=$([[ $- == *x* ]] && echo "set -x" || echo "set +x")
     set +x
     cat <<EOF >user-data
 #cloud-config
 runcmd:
   - systemctl enable --now kubelet
 write_files:
 - path: /home/core/.ssh/authorized_keys
   content: '$PUB_KEY'
   owner: core
   permissions: '0600'
 - path: /opt/crc/id_rsa.pub
   content: '$PUB_KEY'
   owner: root:root
   permissions: '0644'
 - path: /etc/sysconfig/crc-env
   content: |
     CRC_SELF_SUFFICIENT=1
     CRC_NETWORK_MODE_USER=1
   owner: root:root
   permissions: '0644'
 - path: /opt/crc/pull-secret
   content: |
     $PULL_SECRET
-  permissions: '0644'
+  permissions: '0600'
 - path: /opt/crc/pass_kubeadmin
   content: '$PASS_KUBEADMIN'
-  permissions: '0644'
+  permissions: '0600'
 - path: /opt/crc/pass_developer
   content: '$PASS_DEVELOPER'
-  permissions: '0644'
+  permissions: '0600'
 - path: /opt/crc/ocp-custom-domain.service.done
   permissions: '0644'
 EOF
     USER_DATA_PATH="$(pwd)/user-data"
     if ! cloud-init schema -c "${USER_DATA_PATH}" --annotate; then
         die "Invalid cloud-config generated."
     fi
     echo "cloud-init user-data file created."
+    eval "$xtrace_state"
 }

139-167: Pin macadam version and verify passwordless sudo access.

Two issues in this function:

  1. Mutable version tag (lines 154–155): Using "latest" is not reproducible and can introduce breaking changes between CI runs. Pin to a specific stable release.
  2. Unverified sudo privilege (lines 158–162): The script calls sudo mkdir -p /opt/macadam and sudo mv without checking if passwordless sudo is available. In CI environments where sudo requires a password, this will hang or fail silently.

Apply this diff to pin the version and verify sudo privileges:

     echo "macadam not found, downloading..."
 
-    local version="latest"
+    local version="v0.1.0"  # Pin to a stable version; update when new releases are validated
     local url="https://github.com/crc-org/macadam/releases/download/${version}/macadam-linux-amd64"
 
     echo "Downloading from ${url}"
+    if ! sudo -n true 2>/dev/null; then
+        die "This script requires passwordless sudo access. Please configure sudo NOPASSWD for this user."
+    fi
     sudo mkdir -p /opt/macadam
     if ! curl -fL -o /tmp/macadam "${url}"; then
         die "Failed to download macadam."
     fi
     sudo mv /tmp/macadam /opt/macadam/macadam
     sudo chmod +x /opt/macadam/macadam
 
     export PATH="/opt/macadam:$PATH"
     echo "macadam downloaded to /opt/macadam and added to PATH."

Documentation note: After determining the stable macadam version, update the version variable and document it in the PR description or a configuration file.


198-214: Exit on macadam VM startup failure.

When macadam start fails (line 211), the script logs a message but continues execution, causing downstream operations to silently fail. This should halt the script immediately.

Apply this diff to exit on failure:

 function start_macadam_vm() {
     echo "--- Creating VM ---"
     macadam init \
         "${DISK_IMAGE_PATH}" \
         --disk-size 31 \
         --memory 11264 \
         --name crc-ng \
         --username core \
         --ssh-identity-path "${PRIV_KEY_PATH}" \
         --cpus 6 \
         --cloud-init "${USER_DATA_PATH}" \
         --log-level debug
 
     if ! macadam start crc-ng --log-level debug; then
-        echo "Machine didn't come up in time"
+        die "Machine didn't come up in time"
     fi
 }

274-325: Fix gvproxy socket path extraction regex.

The regex at line 304 is fundamentally broken and will not match actual gvproxy command-line output:

# Current (incorrect):
sed -n 's/.*-services unix:\/\/\([^ ]*\).*/\1/p'

# Expected gvproxy format:
gvproxy --services --listen unix:///tmp/network.sock

Issues:

  • Looks for -services (single dash) but the flag is --services (double dash)
  • Looks for unix:// (two slashes) but the actual format uses unix:/// (three slashes for UNIX socket paths)
  • The regex will fail silently and extract nothing, causing the script to die with a confusing error

Apply this diff to extract the socket path from the correct --listen flag:

     local gvproxy_cmd
     if ! gvproxy_cmd=$(pgrep -af gvproxy); then
         die "The gvproxy process is not running."
     fi
 
-    GVPROXY_SOCKET_PATH=$(echo "${gvproxy_cmd}" | sed -n 's/.*-services unix:\/\/\([^ ]*\).*/\1/p')
+    # Extract the socket path from the --listen flag (format: --listen unix:///path/to/socket)
+    GVPROXY_SOCKET_PATH=$(echo "${gvproxy_cmd}" | sed -n 's/.*--listen unix:\/\/\/\([^ ]*\).*/\1/p')
     if [[ -z "${GVPROXY_SOCKET_PATH}" ]]; then
         die "Could not find the gvproxy socket path."
     fi

For additional robustness, consider validating that the extracted path exists and is a UNIX socket:

if [[ ! -S "${GVPROXY_SOCKET_PATH}" ]]; then
    die "Extracted gvproxy socket path does not exist or is not a UNIX socket: ${GVPROXY_SOCKET_PATH}"
fi
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4f7813e and 2fee6c1.

📒 Files selected for processing (2)
  • ci.sh (1 hunks)
  • run-with-macadam.sh (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-10-02T13:13:28.229Z
Learnt from: kpouget
Repo: crc-org/snc PR: 1168
File: systemd/dnsmasq.sh.template:3-12
Timestamp: 2025-10-02T13:13:28.229Z
Learning: The file `/etc/sysconfig/crc-env` in the crc-org/snc repository contains configuration variables and file paths (e.g., `CRC_PASS_KUBEADMIN_PATH`, `CRC_PUB_KEY_PATH`, `CRC_NETWORK_MODE_USER`, `APPS_DOMAIN`), not the actual secrets. The secrets themselves are stored in separate files referenced by these paths. Sourcing `crc-env` with xtrace enabled does not leak sensitive information.

Applied to files:

  • ci.sh
  • run-with-macadam.sh
📚 Learning: 2025-10-07T07:03:06.884Z
Learnt from: kpouget
Repo: crc-org/snc PR: 1168
File: systemd/crc-self-sufficient-env.sh:10-17
Timestamp: 2025-10-07T07:03:06.884Z
Learning: In the crc-org/snc repository, the CRC_CLOUD environment variable has been removed from the codebase. The self-sufficient environment check in systemd/crc-self-sufficient-env.sh now only validates CRC_SELF_SUFFICIENT=1, not CRC_CLOUD.

Applied to files:

  • ci.sh
  • run-with-macadam.sh
🪛 Shellcheck (0.11.0)
ci.sh

[warning] 59-59: Brace expansions and globs are literal in assignments. Quote it or use an array.

(SC2125)

🔇 Additional comments (8)
run-with-macadam.sh (8)

328-368: Approve kubeconfig retrieval logic.

The kubeconfig retrieval function handles SSH connection establishment, API server readiness, and kubeconfig update with reasonable retry logic and error handling. The ssh-port extraction from gvproxy process arguments follows a sensible pattern and the subsequent certificate rotation wait is appropriate.

Verify that the gvproxy -ssh-port flag format (line 342) matches your gvproxy version's output. If you update the --listen unix:/// extraction logic per the earlier comment, cross-check that all pgrep-based flag extractions are consistent.


371-377: Cluster status check looks good.

The cluster stability verification with appropriate timeouts and error handling is correct.


380-401: Main orchestration flow is logical.

The function properly sets up cleanup via EXIT trap and sequences the provisioning steps in the correct order. The final cluster status validation provides good end-to-end verification.

Verify that all critical issues flagged in earlier comments are resolved before merging, as they directly impact the success of this orchestration pipeline.


18-42: SSH keypair generation and cleanup functions look good.

cleanup() properly handles macadam failures with || true to ensure all cleanup steps complete, and generate_ssh_keypair() correctly generates and validates the temporary SSH keypair.


45-56: Dependency checking and installation is solid.

The ensure_deps() function correctly checks for required tools and attempts installation via yum with appropriate error handling.


120-136: Disk image extraction with validation is correct.

The function properly extracts the disk image from the CRC bundle using tar with zstd decompression and validates that the extraction succeeded by checking file size.


217-253: gvproxy capability verification is comprehensive.

The function properly locates gvproxy, checks for the required capability, sets it if missing, and verifies success with appropriate error messages at each step.


256-271: Port forwarding logic is correct.

The function properly constructs gvproxy API requests to expose the required ports (6443, 443, 80) with proper error handling for each exposure attempt.

Comment thread ci.sh Outdated
Comment thread run-with-macadam.sh Outdated
@anjannath anjannath moved this from Hold to Work In Progress in Project planning: crc Dec 3, 2025
@anjannath
Copy link
Copy Markdown
Member Author

/test e2e-snc

@gbraad
Copy link
Copy Markdown
Collaborator

gbraad commented Dec 8, 2025

I hope we do not replace this with 'crc' itself to test with, as that would re-introduce a dependency on what the script should run with. this exists as a smoke test, not a full test; even if crc would be used, 20 to 30% would still exists from this script, like download, etc. so if it is needed, better go to as python script instead to collect the pieces and feed macadam.

@praveenkumar
Copy link
Copy Markdown
Member

I hope we do not replace this with 'crc' itself to test with, as that would re-introduce a dependency on what the script should run with. this exists as a smoke test, not a full test; even if crc would be used, 20 to 30% would still exists from this script, like download, etc. so if it is needed, better go to as python script instead to collect the pieces and feed macadam.

This is not going to remove crc itself from testing the generating bundle which should be same as before. I think we should first do the smoke test with this script which will download bundle and put is the location then crc test also reuse it. As of now since bundle is generated on same machine where test is going to run so no download needed just the path.

@anjannath
Copy link
Copy Markdown
Member Author

/test e2e-snc

@openshift-ci
Copy link
Copy Markdown

openshift-ci bot commented Feb 5, 2026

@anjannath: No presubmit jobs available for crc-org/[email protected]

Details

In response to this:

/test e2e-snc

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.

@anjannath
Copy link
Copy Markdown
Member Author

/test e2e-snc

@openshift-ci
Copy link
Copy Markdown

openshift-ci bot commented Feb 5, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please ask for approval from anjannath. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found 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

@anjannath anjannath force-pushed the ssf-test branch 2 times, most recently from 235c71f to de5b062 Compare February 6, 2026 04:15
@anjannath
Copy link
Copy Markdown
Member Author

so the script fails at macadam start with:unable to generate qemu command line: "exec: \"qemu-system-x86_64\": executable file not found in $PATH"

@cfergeau
Copy link
Copy Markdown
Contributor

cfergeau commented Feb 6, 2026

If this is running on RHEL, this is expected, we may have forgotten to handle this in macadam.
Create a symlink from /usr/libexec/qemu-kvm to qemu-system-x86_64

@anjannath anjannath force-pushed the ssf-test branch 3 times, most recently from fce0f40 to 91341ca Compare February 18, 2026 05:06
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (5)
run-with-macadam.py (4)

174-174: Unused config parameter.

config is never referenced in this function. Remove it or use _config to signal intent.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@run-with-macadam.py` at line 174, The function generate_ssh_keypair currently
declares an unused parameter config; remove this parameter from the function
signature (and any callers) or rename it to _config to signal intentional
non-use. Update the function definition generate_ssh_keypair(...) and any places
that call it (search for generate_ssh_keypair) so signatures and calls match the
chosen change.

481-484: Unconditional 3-minute sleep before SSH readiness check.

The wait_for_ssh() call on line 489 already polls for SSH. The fixed 180-second sleep adds unnecessary latency when the VM boots faster. Consider reducing or removing it and relying on wait_for_ssh() with a backoff.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@run-with-macadam.py` around lines 481 - 484, The unconditional 180s sleep in
get_kubeconfig is causing unnecessary latency; instead remove (or drastically
reduce) the fixed time.sleep(180) and rely on the existing wait_for_ssh()
polling/backoff logic to detect SSH readiness (or, if needed, replace the long
sleep with a short initial sleep like 5–10s before calling wait_for_ssh()).
Update get_kubeconfig to call wait_for_ssh() directly (or after the short sleep)
so the function uses the exponential/backoff retry behavior rather than a hard
3-minute pause.

386-397: get_gvproxy_socket_path() and get_ssh_port() share identical gvproxy process lookup.

Both functions call pgrep -af gvproxy and parse stdout. Extract the gvproxy command line retrieval into a shared helper to avoid duplication and reduce the chance of one diverging from the other.

Suggested refactor
+def _get_gvproxy_cmdline() -> str:
+    try:
+        result = run_command(["pgrep", "-af", "gvproxy"], capture_output=True)
+    except MacadamError as e:
+        raise MacadamError("The gvproxy process is not running.") from e
+    return result.stdout.strip()
+
 def get_gvproxy_socket_path() -> str:
-    try:
-        result = run_command(["pgrep", "-af", "gvproxy"], capture_output=True)
-    except MacadamError as e:
-        raise MacadamError("The gvproxy process is not running.") from e
-
-    gvproxy_cmd = result.stdout.strip()
+    gvproxy_cmd = _get_gvproxy_cmdline()
     match = re.search(r'-services unix://([^ ]+)', gvproxy_cmd)
     if not match:
         raise MacadamError("Could not find the gvproxy socket path.")
-
     return match.group(1)
 
 ...
 
 def get_ssh_port() -> int:
-    try:
-        result = run_command(["pgrep", "-af", "gvproxy"], capture_output=True)
-    except MacadamError as e:
-        raise MacadamError("The gvproxy process is not running.") from e
-
-    gvproxy_cmd = result.stdout.strip()
+    gvproxy_cmd = _get_gvproxy_cmdline()
     match = re.search(r'-ssh-port (\d+)', gvproxy_cmd)
     if not match:
         raise MacadamError("Could not find the ssh port from gvproxy.")
-
     return int(match.group(1))

Also applies to: 433-444

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@run-with-macadam.py` around lines 386 - 397, Extract the duplicated logic
that runs "pgrep -af gvproxy" and returns/parses the gvproxy command line into a
shared helper (e.g., a function named fetch_gvproxy_cmd or
get_gvproxy_process_cmd) and update get_gvproxy_socket_path and get_ssh_port to
call that helper; the helper should call run_command(["pgrep","-af","gvproxy"],
capture_output=True), raise or rewrap MacadamError with the same contextual
message when the command fails, and return the stdout string so
get_gvproxy_socket_path can run re.search(r'-services unix://([^ ]+)', ...) and
get_ssh_port can parse the port—this removes duplicated pgrep invocation and
centralizes error handling.

106-109: Stale/misleading default bundle path.

The hardcoded fallback crc_vfkit_4.19.3_arm64.crcbundle references a vfkit/arm64 bundle while CI downloads a libvirt/amd64 bundle (version 4.21.0). Although CI sets CRC_BUNDLE_PATH explicitly, this default is confusing and could silently break local dev runs on x86_64.

Suggested fix
     crc_bundle_path_str = os.environ.get(
         "CRC_BUNDLE_PATH",
-        str(Path.home() / "Downloads" / "crc_vfkit_4.19.3_arm64.crcbundle")
+        "",
     )
+    if not crc_bundle_path_str:
+        raise MacadamError("CRC_BUNDLE_PATH environment variable must be set.")
     crc_bundle_path = Path(crc_bundle_path_str)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@run-with-macadam.py` around lines 106 - 109, The default fallback for
CRC_BUNDLE_PATH (variable crc_bundle_path_str) is stale and points to an arm64
vfkit bundle; update the fallback to match CI's libvirt amd64 bundle or choose
per-host architecture: either change the hardcoded fallback string to
"crc_libvirt_4.21.0_amd64.crcbundle" in the Path.home()/Downloads path, or
replace the single hardcoded default with a small platform check
(platform.machine()) that selects the appropriate filename for "amd64" vs
"arm64" so local x86_64 runs don't silently use the wrong bundle; ensure the
variable name crc_bundle_path_str and the env var "CRC_BUNDLE_PATH" are
preserved.
ci.sh (1)

21-33: Remove commented-out code before merging.

Large blocks of commented-out code (old CRC workflow at lines 21–33 and 65–81) should be removed before this leaves WIP status. Git history preserves the old code.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ci.sh` around lines 21 - 33, Remove the large commented-out CRC workflow
blocks (the block starting with the commented shellcheck/snс.sh lines and the
openshift-tests extraction plus createdisk.sh steps, and the other analogous
commented block later in the script) from ci.sh so only active code remains;
delete those commented lines entirely (do not reintroduce them as comments),
leaving any required environment exports or live commands intact, relying on git
history to retain the old workflow.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ci.sh`:
- Around line 59-63: Split the combined export/assignment for CRC_BUNDLE_PATH so
you assign CRC_BUNDLE_PATH="$(pwd)/crc_libvirt_4.21.0_amd64.crcbundle" first and
then export it (avoid export CRC_BUNDLE_PATH=$(pwd)... to surface pwd failures);
keep PULL_SECRET_PATH assignment separate as well; and ensure
run-with-macadam.py is invoked reliably by either adding an executable bit in
the repo (chmod +x run-with-macadam.py) or calling it explicitly with python3
(python3 run-with-macadam.py) instead of relying on the file mode.

In `@run-with-macadam.py`:
- Around line 320-321: The gvproxy download URL is hardcoded to "amd64"; update
the url construction to use the same architecture-detection logic used for the
macadam download (reuse the detected_arch/arch mapping or get_arch() helper)
instead of the literal "amd64" so the asset name matches the host (e.g., use the
mapped arch string when building url =
f"https://github.com/containers/gvisor-tap-vsock/releases/download/{version}/gvproxy-linux-{arch_suffix}").
Ensure you reference the existing version variable and replace the hardcoded
segment with the detected arch variable (the same symbol used for macadam's
download).
- Around line 294-295: The download URL for macadam is hardcoded to the amd64
binary; update the logic in run-with-macadam.py (where version and url are set
and used by ensure_dependencies()) to detect the host CPU arch (e.g., using
platform.machine() or the existing arch detection in ensure_dependencies()) and
choose the correct artifact name (macadam-linux-amd64 for x86_64 / amd64 and
macadam-linux-aarch64 for aarch64) before constructing the URL variable so the
script downloads the matching binary for the host.

In `@snc.sh`:
- Line 47: The OPENSHIFT_RELEASE_VERSION assignment is pulling from the wrong
candidate path (candidate-4.20) on the release-4.21 branch; update the curl URL
in the OPENSHIFT_RELEASE_VERSION variable assignment to fetch the correct
release file (candidate-4.21/release.txt) so the script uses the matching 4.21
release version for the release-4.21 branch.

---

Duplicate comments:
In `@run-with-macadam.py`:
- Around line 349-355: The code currently just prints when the macadam start
command fails; instead detect failure after the run_command(...) call and raise
VMError so execution halts and errors are clearer: in the block following result
= run_command(["macadam", "start", "crc-ng", "--log-level", "debug"],
check=False) check result.returncode != 0 and raise VMError with a descriptive
message that includes result.returncode and the command output
(result.stdout/result.stderr) so downstream SSH/kubeconfig steps don't proceed
on a failed VM start; use the existing VMError class (or import it if missing)
and include the command and outputs in the raised error.
- Around line 446-479: The two infinite polling loops in wait_for_ssh() and
wait_for_api_server() need monotonic deadlines so they don't hang forever:
introduce a deadline using time.monotonic() + timeout (e.g., MAX_SSH_WAIT and
MAX_API_WAIT constants or function params), check elapsed time on each loop
iteration and break/raise a clear exception (or return error) when the deadline
is exceeded, and keep existing sleep/retry logic otherwise; update wait_for_ssh
and wait_for_api_server to use this monotonic deadline check and surface a
helpful error message if timeout occurs.
- Around line 299-305: The download code in the try block for Macadam uses a
fixed /tmp path and urlretrieve (vulnerable to symlink/TOCTOU); replace that by
creating a secure temp file via tempfile.NamedTemporaryFile (or
tempfile.mkstemp) in the block used by the function that downloads macadam,
write the response into that temporary file (ensuring it is closed), then
atomically move it into place with os.replace to /opt/macadam/macadam and set
executable bit (you can keep using run_command for mkdir/chmod/move but ensure
you pass the securely-created temp path), and preserve raising MacadamError from
exceptions; refer to the existing symbols run_command and MacadamError and the
download logic that currently calls urllib.request.urlretrieve.
- Around line 232-241: The secret file entries for "/opt/crc/pull-secret",
"/opt/crc/pass_kubeadmin", and "/opt/crc/pass_developer" are created with
permissions '0644' making them world-readable; update the permissions value for
these three entries to '0600' so only the owner can read/write. Locate the
YAML/file-entry construction in run-with-macadam.py where these path strings
appear and change the permissions field for each corresponding entry from '0644'
to '0600', ensuring the content values remain unchanged.

---

Nitpick comments:
In `@ci.sh`:
- Around line 21-33: Remove the large commented-out CRC workflow blocks (the
block starting with the commented shellcheck/snс.sh lines and the
openshift-tests extraction plus createdisk.sh steps, and the other analogous
commented block later in the script) from ci.sh so only active code remains;
delete those commented lines entirely (do not reintroduce them as comments),
leaving any required environment exports or live commands intact, relying on git
history to retain the old workflow.

In `@run-with-macadam.py`:
- Line 174: The function generate_ssh_keypair currently declares an unused
parameter config; remove this parameter from the function signature (and any
callers) or rename it to _config to signal intentional non-use. Update the
function definition generate_ssh_keypair(...) and any places that call it
(search for generate_ssh_keypair) so signatures and calls match the chosen
change.
- Around line 481-484: The unconditional 180s sleep in get_kubeconfig is causing
unnecessary latency; instead remove (or drastically reduce) the fixed
time.sleep(180) and rely on the existing wait_for_ssh() polling/backoff logic to
detect SSH readiness (or, if needed, replace the long sleep with a short initial
sleep like 5–10s before calling wait_for_ssh()). Update get_kubeconfig to call
wait_for_ssh() directly (or after the short sleep) so the function uses the
exponential/backoff retry behavior rather than a hard 3-minute pause.
- Around line 386-397: Extract the duplicated logic that runs "pgrep -af
gvproxy" and returns/parses the gvproxy command line into a shared helper (e.g.,
a function named fetch_gvproxy_cmd or get_gvproxy_process_cmd) and update
get_gvproxy_socket_path and get_ssh_port to call that helper; the helper should
call run_command(["pgrep","-af","gvproxy"], capture_output=True), raise or
rewrap MacadamError with the same contextual message when the command fails, and
return the stdout string so get_gvproxy_socket_path can run
re.search(r'-services unix://([^ ]+)', ...) and get_ssh_port can parse the
port—this removes duplicated pgrep invocation and centralizes error handling.
- Around line 106-109: The default fallback for CRC_BUNDLE_PATH (variable
crc_bundle_path_str) is stale and points to an arm64 vfkit bundle; update the
fallback to match CI's libvirt amd64 bundle or choose per-host architecture:
either change the hardcoded fallback string to
"crc_libvirt_4.21.0_amd64.crcbundle" in the Path.home()/Downloads path, or
replace the single hardcoded default with a small platform check
(platform.machine()) that selects the appropriate filename for "amd64" vs
"arm64" so local x86_64 runs don't silently use the wrong bundle; ensure the
variable name crc_bundle_path_str and the env var "CRC_BUNDLE_PATH" are
preserved.

Comment thread ci.sh Outdated
Comment thread run-with-macadam.py
Comment on lines +136 to +172
# QEMU system emulator (architecture-specific)
# On RHEL, qemu-kvm is installed at /usr/libexec/qemu-kvm
# macadam expects qemu-system-{arch} to be available
arch = os.uname().machine

if arch == "x86_64":
qemu_binary_name = "qemu-system-x86_64"
qemu_package = "qemu-kvm"
elif arch == "aarch64":
qemu_binary_name = "qemu-system-aarch64"
qemu_package = "qemu-kvm"
else:
raise DependencyError(
f"Unsupported architecture: {arch}. "
f"This script requires x86_64 or aarch64."
)

qemu_kvm_path = Path("/usr/libexec/qemu-kvm")
qemu_symlink_path = Path(f"/usr/bin/{qemu_binary_name}")

# Check if /usr/libexec/qemu-kvm exists
if qemu_kvm_path.exists():
# QEMU is installed, create symlink if needed
if not qemu_symlink_path.exists():
print(f"Creating symlink: {qemu_symlink_path} -> {qemu_kvm_path}")
try:
run_command([
"sudo", "ln", "-sf", str(qemu_kvm_path), str(qemu_symlink_path)
])
print(f"Symlink created successfully.")
except MacadamError as e:
raise DependencyError(
f"Failed to create symlink for {qemu_binary_name}. "
f"Please create it manually: sudo ln -s {qemu_kvm_path} {qemu_symlink_path}"
) from e
else:
print(f"{qemu_binary_name} is already available.")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Missing QEMU installation when /usr/libexec/qemu-kvm doesn't exist.

The qemu_package variable is assigned but never used (Ruff F841). More importantly, if /usr/libexec/qemu-kvm doesn't exist, the function silently does nothing — no installation attempt and no error. The VM will later fail at macadam start with "executable file not found" (exactly the error reported in PR comments).

Suggested fix
     qemu_kvm_path = Path("/usr/libexec/qemu-kvm")
     qemu_symlink_path = Path(f"/usr/bin/{qemu_binary_name}")
 
-    # Check if /usr/libexec/qemu-kvm exists
     if qemu_kvm_path.exists():
-        # QEMU is installed, create symlink if needed
         if not qemu_symlink_path.exists():
             print(f"Creating symlink: {qemu_symlink_path} -> {qemu_kvm_path}")
             try:
                 run_command([
                     "sudo", "ln", "-sf", str(qemu_kvm_path), str(qemu_symlink_path)
                 ])
-                print(f"Symlink created successfully.")
+                print("Symlink created successfully.")
             except MacadamError as e:
                 raise DependencyError(
                     f"Failed to create symlink for {qemu_binary_name}. "
                     f"Please create it manually: sudo ln -s {qemu_kvm_path} {qemu_symlink_path}"
                 ) from e
         else:
             print(f"{qemu_binary_name} is already available.")
+    elif shutil.which(qemu_binary_name) is None:
+        print(f"'{qemu_package}' not found, attempting to install...")
+        try:
+            run_command(["sudo", "yum", "-y", "install", qemu_package])
+        except MacadamError as e:
+            raise DependencyError(
+                f"Failed to install '{qemu_package}'. "
+                f"Please install it manually and try again."
+            ) from e
🧰 Tools
🪛 Ruff (0.15.1)

[error] 146-146: Local variable qemu_package is assigned to but never used

Remove assignment to unused variable qemu_package

(F841)


[warning] 148-151: Avoid specifying long messages outside the exception class

(TRY003)


[error] 165-165: f-string without any placeholders

Remove extraneous f prefix

(F541)


[warning] 167-170: Avoid specifying long messages outside the exception class

(TRY003)

Comment thread run-with-macadam.py
Comment on lines +294 to +295
version = "v0.3.0"
url = f"https://github.com/crc-org/macadam/releases/download/{version}/macadam-linux-amd64"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Architecture mismatch: macadam download is hardcoded to amd64.

ensure_dependencies() supports both x86_64 and aarch64, but the download URL is hardcoded to macadam-linux-amd64. This will silently install the wrong binary on aarch64 hosts.

Suggested fix
     version = "v0.3.0"
-    url = f"https://github.com/crc-org/macadam/releases/download/{version}/macadam-linux-amd64"
+    arch = os.uname().machine
+    binary_arch = "amd64" if arch == "x86_64" else "arm64"
+    url = f"https://github.com/crc-org/macadam/releases/download/{version}/macadam-linux-{binary_arch}"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@run-with-macadam.py` around lines 294 - 295, The download URL for macadam is
hardcoded to the amd64 binary; update the logic in run-with-macadam.py (where
version and url are set and used by ensure_dependencies()) to detect the host
CPU arch (e.g., using platform.machine() or the existing arch detection in
ensure_dependencies()) and choose the correct artifact name (macadam-linux-amd64
for x86_64 / amd64 and macadam-linux-aarch64 for aarch64) before constructing
the URL variable so the script downloads the matching binary for the host.

Comment thread run-with-macadam.py
Comment on lines +320 to +321
version = "v0.8.7"
url = f"https://github.com/containers/gvisor-tap-vsock/releases/download/{version}/gvproxy-linux-amd64"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Architecture mismatch: gvproxy download also hardcoded to amd64.

Same issue as the macadam download — apply the same arch-detection pattern here.

Suggested fix
     version = "v0.8.7"
-    url = f"https://github.com/containers/gvisor-tap-vsock/releases/download/{version}/gvproxy-linux-amd64"
+    arch = os.uname().machine
+    binary_arch = "amd64" if arch == "x86_64" else "arm64"
+    url = f"https://github.com/containers/gvisor-tap-vsock/releases/download/{version}/gvproxy-linux-{binary_arch}"
📝 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
version = "v0.8.7"
url = f"https://github.com/containers/gvisor-tap-vsock/releases/download/{version}/gvproxy-linux-amd64"
version = "v0.8.7"
arch = os.uname().machine
binary_arch = "amd64" if arch == "x86_64" else "arm64"
url = f"https://github.com/containers/gvisor-tap-vsock/releases/download/{version}/gvproxy-linux-{binary_arch}"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@run-with-macadam.py` around lines 320 - 321, The gvproxy download URL is
hardcoded to "amd64"; update the url construction to use the same
architecture-detection logic used for the macadam download (reuse the
detected_arch/arch mapping or get_arch() helper) instead of the literal "amd64"
so the asset name matches the host (e.g., use the mapped arch string when
building url =
f"https://github.com/containers/gvisor-tap-vsock/releases/download/{version}/gvproxy-linux-{arch_suffix}").
Ensure you reference the existing version variable and replace the hardcoded
segment with the detected arch variable (the same symbol used for macadam's
download).

Comment thread snc.sh Outdated
echo "Using release ${OPENSHIFT_RELEASE_VERSION} from OPENSHIFT_VERSION"
else
OPENSHIFT_RELEASE_VERSION="$(curl -L "${MIRROR}"/candidate/release.txt | sed -n 's/^ *Version: *//p')"
OPENSHIFT_RELEASE_VERSION="$(curl -L "${MIRROR}"/candidate-4.20/release.txt | sed -n 's/^ *Version: *//p')"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check current branch and target branch
echo "Current branch and recent commits:"
git branch -a
echo "---"
git log --oneline -10
echo "---"
# Search for all candidate version references in snc.sh
echo "Candidate version references in snc.sh:"
rg -n "candidate-" snc.sh
echo "---"
# Check if there's context around the specific line 47
echo "Context around line 47 in snc.sh:"
sed -n '40,54p' snc.sh

Repository: crc-org/snc

Length of output: 1173


Version mismatch: candidate-4.20 on the release-4.21 branch.

This PR targets release-4.21 but the release version is fetched from candidate-4.20/release.txt. Should this be candidate-4.21?

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@snc.sh` at line 47, The OPENSHIFT_RELEASE_VERSION assignment is pulling from
the wrong candidate path (candidate-4.20) on the release-4.21 branch; update the
curl URL in the OPENSHIFT_RELEASE_VERSION variable assignment to fetch the
correct release file (candidate-4.21/release.txt) so the script uses the
matching 4.21 release version for the release-4.21 branch.

@anjannath anjannath force-pushed the ssf-test branch 5 times, most recently from ef7a3eb to 623e741 Compare February 26, 2026 09:49
@anjannath
Copy link
Copy Markdown
Member Author

/test e2e-snc

@anjannath anjannath force-pushed the ssf-test branch 2 times, most recently from 19577c5 to e896982 Compare March 2, 2026 16:14
anjannath and others added 2 commits March 17, 2026 14:29
Implement a Python script to orchestrate CRC bundle smoke testing with
the macadam hypervisor. The script handles:
- VM lifecycle management (init, start, cleanup)
- Network configuration via gvproxy (DNS zones, port forwarding)
- SSH keypair generation and cloud-init provisioning
- Kubeconfig retrieval and cluster validation

The script uses only Python standard library dependencies for easy
deployment in CI/CD environments.

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
@anjannath anjannath changed the title wip: ssf: add script to start bundle with macadam ssf: add script to start bundle with macadam Mar 17, 2026
@anjannath
Copy link
Copy Markdown
Member Author

/test e2e-snc

@anjannath anjannath moved this from Work In Progress to Ready for review in Project planning: crc Mar 18, 2026
@openshift-ci
Copy link
Copy Markdown

openshift-ci bot commented Mar 18, 2026

@anjannath: The following test 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/e2e-snc 61345e6 link true /test e2e-snc

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

None yet

Projects

Status: Ready for review

Development

Successfully merging this pull request may close these issues.

5 participants