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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 146 additions & 0 deletions .github/workflows/podman-smoke.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# .github/workflows/podman-smoke.yml
# ADDITIVE WORKFLOW: Proves Podman build and smoke verification for ngen.
# Leaves existing .github/workflows/ngwpc-cicd.yml and release paths untouched.

name: Podman Build & Smoke (Additive)

on:
workflow_dispatch:
inputs:
push_images:
description: "Push test tags (:podman-test) to GHCR"
required: true
type: boolean
default: false
FORCING_IMAGE_TAG:
description: "Base forcing image tag from GHCR (defaults to 'latest')"
required: false
type: string
default: "latest"
EWTS_REF:
description: "EWTS branch or tag reference (defaults to 'development')"
required: false
type: string
default: "development"
pull_request:
branches:
- development
paths:
- '.github/workflows/podman-smoke.yml'
- 'Dockerfile'
- 'run-ngen.sh'
- 'CMakeLists.txt'
- 'src/**'
- 'include/**'
- 'cmake/**'
- 'data/**'
- '.gitmodules'

permissions:
contents: read
packages: write

jobs:
podman-build-smoke:
name: Podman Build & Smoke (NextGen Engine)
runs-on: ubuntu-24.04
timeout-minutes: 60

steps:
- name: Checkout Repository with Recursive Submodules
uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0

- name: Verify Submodules Status
run: |
echo "Verifying recursive submodules..."
git submodule status --recursive

- name: Verify Preinstalled Podman Environment
run: |
podman version
podman info --format 'OS: {{.Host.Distribution.Distribution}} {{.Host.Distribution.Version}} | Storage: {{.Store.GraphDriverName}}'

- name: Log in to GitHub Container Registry
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | podman login ghcr.io \
-u "${{ github.actor }}" --password-stdin

- name: Build NextGen Engine Image with Podman (Docker Format)
id: build
run: |
set -euo pipefail
ulimit -n 65535 || true
IMAGE_TAG="localhost/ngen:podman-test"
FORCING_TAG="${{ inputs.FORCING_IMAGE_TAG || 'latest' }}"
EWTS_BRANCH="${{ inputs.EWTS_REF || 'development' }}"

echo "Building ${IMAGE_TAG} using Dockerfile with --format docker..."
podman build \
--ulimit nofile=65535:65535 \
--format docker \
--build-arg GHCR_ORG=ngwpc \
--build-arg FORCING_IMAGE="ghcr.io/ngwpc/ngen-bmi-forcing:${FORCING_TAG}" \
--build-arg EWTS_ORG=NGWPC \
--build-arg EWTS_REF="${EWTS_BRANCH}" \
--build-arg CI_COMMIT_REF_NAME="${{ github.ref_name }}" \
-f Dockerfile \
-t "${IMAGE_TAG}" \
.

echo "IMAGE_LOCAL=${IMAGE_TAG}" >> "${GITHUB_ENV}"

- name: Smoke Probe 1 - ngen Binary Usage & Build Information
run: |
set -euo pipefail
echo "Verifying ngen binary usage & build info..."
podman run --rm --entrypoint /ngen-app/ngen/cmake_build/ngen "${IMAGE_LOCAL}"
echo "Verifying run-ngen.sh entrypoint script..."
podman run --rm --entrypoint test "${IMAGE_LOCAL}" -x /ngen-app/bin/run-ngen.sh
echo "Probe 1 Passed: ngen binary and entrypoint executable."

- name: Smoke Probe 2 - Python Environment & Core Module Imports
run: |
set -euo pipefail
echo "Verifying Python version in container..."
podman run --rm --entrypoint /ngen-app/ngen-python/bin/python "${IMAGE_LOCAL}" --version
echo "Verifying scientific Python stack and EWTS package..."
podman run --rm --entrypoint /ngen-app/ngen-python/bin/python "${IMAGE_LOCAL}" \
-c "import numpy, pandas, netCDF4, xarray, ewts; print('Probe 2 Passed: Python scientific stack and EWTS imported successfully.')"
echo "Verifying LSTM module on PYTHONPATH..."
podman run --rm --entrypoint /ngen-app/ngen-python/bin/python "${IMAGE_LOCAL}" \
-c "import lstm; print('Probe 2b Passed: LSTM submodule imported successfully.')"

- name: Smoke Probe 3 - Git Provenance Metadata Check
run: |
set -euo pipefail
echo "Verifying combined Git provenance JSON..."
podman run --rm --entrypoint cat "${IMAGE_LOCAL}" /ngen-app/ngen_git_info.json
podman run --rm --entrypoint test "${IMAGE_LOCAL}" -s /ngen-app/ngen_git_info.json
echo "Probe 3 Passed: Git provenance metadata file verified."

- name: Inspect Built OCI Image
run: |
podman image inspect "${IMAGE_LOCAL}" \
--format 'Image ID: {{.Id}} | Digest: {{.Digest}} | Entrypoint: {{.Config.Entrypoint}} | Cmd: {{.Config.Cmd}}'

- name: Optional GHCR Push (:podman-test only)
if: ${{ inputs.push_images }}
run: |
set -euo pipefail
REPO_LOWER=$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]')
DEST_BASE="ghcr.io/${REPO_LOWER}"
TAG_TEST="${DEST_BASE}:podman-test"
TAG_SHA="${DEST_BASE}:${{ github.sha }}-podman-test"

echo "Publishing test verification tags..."
podman tag "${IMAGE_LOCAL}" "${TAG_TEST}"
podman tag "${IMAGE_LOCAL}" "${TAG_SHA}"

podman push "${TAG_TEST}"
podman push "${TAG_SHA}"

echo "Pushed ${TAG_TEST} and ${TAG_SHA}"
echo "NOTICE: Production aliases (:latest, release tags) remain untouched."
91 changes: 91 additions & 0 deletions PODMAN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Podman Support (Additive Path)

This repository maintains Docker as its primary documented and production CI path. Podman is supported as an **additional** option for local development, rootless execution, and container build/smoke verification.

Existing Docker workflows (`.github/workflows/ngwpc-cicd.yml`) and production release tags remain untouched and active.

---

## Prerequisites

1. **Podman Installation:** Verify that Podman is installed on your workstation or runner:
```bash
podman version
podman info
```
For Ubuntu 24.04+ (Noble) or RHEL 8/9, Podman 4.9+ is recommended.

2. **Git Submodules:** NGen relies on multiple submodules (`t-route`, `cfe`, `noah-owp-modular`, `topmodel`, `LASAM`, `bmi-cxx`, `lstm`, etc.). Clone with recursive submodules, or initialize them before building:
```bash
git submodule update --init --recursive
```

3. **Base Image Access:** The build pulls `ghcr.io/ngwpc/ngen-bmi-forcing:latest` as its base. Ensure you are logged into GHCR if accessing private or internal images:
```bash
podman login ghcr.io
```

---

## Building with Podman

Build the NextGen Engine image directly using the existing `Dockerfile`. Following NOAA-OWP/WRES conventions, use `--format docker` to ensure standard OCI/Docker compatibility:

```bash
podman build \
--ulimit nofile=65535:65535 \
--format docker \
--build-arg GHCR_ORG=ngwpc \
--build-arg FORCING_IMAGE="ghcr.io/ngwpc/ngen-bmi-forcing:latest" \
--build-arg EWTS_ORG=NGWPC \
--build-arg EWTS_REF=development \
-f Dockerfile \
-t local/ngen:podman-test \
.
```

*Note: NGen compiles C, C++, and Fortran models across dozens of submodules with CMake and Boost. The `--ulimit nofile=65535:65535` flag ensures sufficient file descriptors are available during parallel compilation. Modern Podman (via Buildah $\ge$ 1.24) natively manages the cache mounts declared in the Dockerfile (`--mount=type=cache`).*

---

## Smoke Verification

### 1. Test ngen Binary Usage & Build Information
Running the compiled `ngen` binary without arguments prints the framework build configuration (enabled modules, MPI, NetCDF, UDUNITS, Python, Routing, Nexuses) and returns 0:
```bash
podman run --rm --entrypoint /ngen-app/ngen/cmake_build/ngen local/ngen:podman-test
```

Verify that the wrapper entrypoint script is executable:
```bash
podman run --rm --entrypoint test local/ngen:podman-test -x /ngen-app/bin/run-ngen.sh
```

### 2. Verify Python Runtime & Submodule Imports
Verify the container's Python environment, scientific packages, EWTS logging, and LSTM submodule:
```bash
podman run --rm --entrypoint /ngen-app/ngen-python/bin/python local/ngen:podman-test --version

podman run --rm --entrypoint /ngen-app/ngen-python/bin/python local/ngen:podman-test \
-c "import numpy, pandas, netCDF4, xarray, ewts; print('Scientific packages and EWTS healthy')"

podman run --rm --entrypoint /ngen-app/ngen-python/bin/python local/ngen:podman-test \
-c "import lstm; print('LSTM module import healthy')"
```

### 3. Verify Git Provenance Metadata
Inspect the generated provenance metadata combining git information from NGen, EWTS, and all submodules:
```bash
podman run --rm --entrypoint cat local/ngen:podman-test /ngen-app/ngen_git_info.json
podman run --rm --entrypoint test local/ngen:podman-test -s /ngen-app/ngen_git_info.json
```

---

## CI / Automation

* **Workflow:** `.github/workflows/podman-smoke.yml`
* **Triggers:** Manual (`workflow_dispatch`) and automated checks on pull requests modifying NGen engine files (`Dockerfile`, `run-ngen.sh`, `CMakeLists.txt`, `src/**`, `include/**`, `cmake/**`, `data/**`, `.gitmodules`).
* **Runner Environment:** Pinned to `ubuntu-24.04`.
* **Submodules:** Checked out recursively (`submodules: recursive`, `fetch-depth: 0`).
* **Registry Policy:** By default, builds remain local to the runner. When `push_images=true` is dispatched, only `:podman-test` and `:<sha>-podman-test` tags are published to GHCR. Production aliases (`:latest`, branch tags) are never touched.
Loading