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
71 changes: 71 additions & 0 deletions .github/actions/report-images/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
name: Report Runtime Configuration
description: |
Queries the live cluster to report all container images and feature flags configured
and running for the Konveyor operator stack. Writes a markdown report to the GitHub Step
Summary and optionally uploads a JSON artifact.

inputs:
namespace:
description: "Namespace where Konveyor is installed"
required: false
default: "konveyor-tackle"
upload_artifact:
description: "Upload the JSON report as a workflow artifact"
required: false
default: "false"
artifact_name:
description: "Name for the uploaded artifact"
required: false
default: "operator-runtime-image-report"
artifact_retention_days:
description: "Number of days to retain the artifact"
required: false
default: "90"

outputs:
json:
description: "The full image report as a JSON string"
value: ${{ steps.report.outputs.json }}

runs:
using: "composite"
steps:
- name: Verify cluster access
shell: bash
run: |
KUBECTL="kubectl"
if ! command -v kubectl &>/dev/null; then
if command -v oc &>/dev/null; then
KUBECTL="oc"
else
echo "::error::Neither kubectl nor oc found in PATH"
exit 1
fi
fi
$KUBECTL get namespace "${{ inputs.namespace }}" >/dev/null

- name: Generate image report
id: report
shell: bash
working-directory: ${{ github.action_path }}/../../..
run: |
hack/runtime-configuration/report.js -n "${{ inputs.namespace }}" >> "$GITHUB_STEP_SUMMARY"

JSON=$(hack/runtime-configuration/report.js -n "${{ inputs.namespace }}" --json)
echo "$JSON" > "$RUNNER_TEMP/report.json"

# Make JSON available as an output (delimiter-based to handle multiline)
EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64)
{
echo "json<<$EOF"
echo "$JSON"
echo "$EOF"
} >> "$GITHUB_OUTPUT"

- name: Upload JSON report
if: ${{ inputs.upload_artifact == 'true' }}
uses: actions/upload-artifact@v4
with:
name: ${{ inputs.artifact_name }}
path: ${{ runner.temp }}/report.json
retention-days: ${{ inputs.artifact_retention_days }}
95 changes: 95 additions & 0 deletions hack/runtime-configuration/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Runtime Configuration Report

Introspects a live cluster running the Konveyor operator and produces a full
report of what is deployed, what images are configured, and how the CRD
instances relate to each other.

## What it looks at

The report queries the following resources in the operator's namespace:

| Resource | What we extract |
|----------|-----------------|
| `Deployment/tackle-operator` | Operator image, version, profile, and the full `RELATED_IMAGE_*` env var catalog |
| `tackles.tackle.konveyor.io` | CR spec (feature flags, image overrides via `*_fqin` fields), CR status conditions |
| `addons.tackle.konveyor.io` | Addon name, container image, task-matching regex |
| `extensions.tackle.konveyor.io` | Extension name, container image (or null → uses generic provider), addon-matching regex, selector |
| `tasks.tackle.konveyor.io` | Task name, priority, dependency list |
| `schemas.tackle.konveyor.io` | Schema name, domain, subject, variant |
| All `Deployments` in namespace | Running container images for drift detection |
| `ClusterServiceVersion` (if OLM) | `relatedImages` declared for disconnected installs |

## What it reports

1. **Operator metadata** — image, version, profile
2. **Tackle CR status** — reconciliation conditions (Ready, Failure, etc.)
3. **Feature flags** — current values vs. defaults, showing which optional
components are active
4. **Image catalog** — every `RELATED_IMAGE_*` env var, enriched with component
names from `known-components-flags-map.json`, marked ACTIVE or INACTIVE
based on feature flags
5. **CR overrides** — any `*_fqin` fields in the Tackle CR spec that override
the operator's default images
6. **Running containers** — actual images deployed in the namespace
7. **Addon CRs** — images and the task regex they serve
8. **Extension CRs** — images (or generic provider fallback), addon binding,
and application selectors
9. **Task CRs** — execution priority and dependency graph
10. **Schema CRs** — registered schema definitions
11. **Task → Addon → Extension relationship graph** — how tasks dispatch to
addons, and which extensions (language providers) attach as sidecars
12. **OLM CSV related images** — if installed via OLM
13. **Image drift detection** — compares configured images against what is
actually running

## Usage

```bash
# Markdown output (default)
node hack/runtime-configuration/report.js

# JSON output
node hack/runtime-configuration/report.js --json

# Custom namespace
node hack/runtime-configuration/report.js -n my-namespace
```

Requires `kubectl` (or `oc`) in PATH and Node.js >= 22. No npm dependencies.

## Files

| File | Purpose |
|------|---------|
| `report.js` | Main script (Node.js, zero dependencies) |
| `report.sh` | Bash equivalent (uses jq) |
| `known-components-flags-map.json` | Maps `RELATED_IMAGE_*` env vars to human-readable names, activation conditions, and deployment prefixes |

## Extending for new CRDs

When a new CRD is added to the operator (e.g. a hypothetical
`pipelines.tackle.konveyor.io`):

1. **Add a collector** in the "CRD Collectors" section of `report.js` — a
function that calls `kubectl(...)` and returns `{ kind, items }`.
2. **Register it** in the `CRD_COLLECTORS` object.
3. **Add a renderer** in the "Markdown Renderers" section — a function that
returns a markdown string for that section.
4. **Register it** in the `SECTION_RENDERERS` array.

If the new CRD carries container images governed by feature flags, also add
its `RELATED_IMAGE_*` entry to `known-components-flags-map.json`.

## Updating the component map

When images are added or removed from `helm/templates/deployment.yaml`, update
`known-components-flags-map.json`:

- `components.<ENV_VAR>.component` — human-readable name
- `components.<ENV_VAR>.condition` — `"always"` or a feature flag key
- `components.<ENV_VAR>.deployment_prefix` — prefix of the Deployment name
this image ends up in (used for drift detection), or `null` if it runs as a
task sidecar rather than a long-lived deployment

Any `RELATED_IMAGE_*` env var found on the operator that isn't in the map will
still be reported, flagged as "unmapped" so it's obvious what needs updating.
107 changes: 107 additions & 0 deletions hack/runtime-configuration/known-components-flags-map.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
{
"_comment": "Component map for hack/report-images.sh. Maps RELATED_IMAGE_* env vars to human-readable component names, activation conditions (feature flags), and deployment name prefixes for drift detection. Update this file when images are added/removed from helm/templates/deployment.yaml.",
"components": {
"RELATED_IMAGE_TACKLE_HUB": {
"component": "Hub API Server",
"condition": "always",
"deployment_prefix": "tackle-hub"
},
"RELATED_IMAGE_TACKLE_UI": {
"component": "UI",
"condition": "always",
"deployment_prefix": "tackle-ui"
},
"RELATED_IMAGE_KEYCLOAK_SSO": {
"component": "Keycloak SSO",
"condition": "feature_auth_required",
"deployment_prefix": "tackle-keycloak-sso"
},
"RELATED_IMAGE_TACKLE_POSTGRES": {
"component": "Keycloak PostgreSQL",
"condition": "feature_auth_required",
"deployment_prefix": "tackle-keycloak-postgresql"
},
"RELATED_IMAGE_OAUTH_PROXY": {
"component": "OAuth Proxy",
"condition": "openshift_cluster",
"deployment_prefix": null
},
"RELATED_IMAGE_ADDON_ANALYZER": {
"component": "Analyzer Addon",
"condition": "always",
"deployment_prefix": null
},
"RELATED_IMAGE_ADDON_DISCOVERY": {
"component": "Language Discovery Addon",
"condition": "feature_discovery",
"deployment_prefix": null
},
"RELATED_IMAGE_ADDON_PLATFORM": {
"component": "Platform Addon",
"condition": "always",
"deployment_prefix": null
},
"RELATED_IMAGE_PROVIDER_JAVA": {
"component": "Java Provider",
"condition": "always",
"deployment_prefix": null
},
"RELATED_IMAGE_PROVIDER_GO": {
"component": "Go Provider",
"condition": "always",
"deployment_prefix": null
},
"RELATED_IMAGE_PROVIDER_PYTHON": {
"component": "Python Provider",
"condition": "always",
"deployment_prefix": null
},
"RELATED_IMAGE_PROVIDER_NODEJS": {
"component": "Node.js Provider",
"condition": "always",
"deployment_prefix": null
},
"RELATED_IMAGE_PROVIDER_C_SHARP": {
"component": "C# Provider",
"condition": "always",
"deployment_prefix": null
},
"RELATED_IMAGE_KANTRA": {
"component": "Kantra CLI",
"condition": "always",
"deployment_prefix": null
},
"RELATED_IMAGE_KAI": {
"component": "KAI Solution Server",
"condition": "kai_solution_server_enabled",
"deployment_prefix": "kai"
},
"RELATED_IMAGE_LIGHTSPEED_STACK": {
"component": "LLM Proxy",
"condition": "kai_llm_proxy_enabled",
"deployment_prefix": "llm-proxy"
}
},
"feature_flags": {
"feature_auth_required": {
"default": true,
"description": "Keycloak + PostgreSQL + OAuth Proxy"
},
"feature_discovery": {
"default": true,
"description": "Language Discovery Addon"
},
"kai_solution_server_enabled": {
"default": false,
"description": "KAI Solution Server"
},
"kai_llm_proxy_enabled": {
"default": false,
"description": "LLM Proxy (Lightspeed Stack)"
},
"openshift_cluster": {
"default": false,
"description": "OAuth Proxy sidecar"
}
}
}
Loading
Loading