Reports
The operator writes two kinds of report, as JSON with a top-level kind, to the destination you choose:
| Report | kind | Written | Holds |
|---|---|---|---|
<name>.mirops | ClusterMirror | On every mirror rebuild, overwriting the last | The cluster's current state: summary, at-risk components and their dependents, per-namespace risk, live problems, add-ons, workloads, the dependency graph, and whether upgrade analysis is on. |
<name>.mirops | UpgradeAnalysis | On every analysis run | The verdict, score breakdown, add-on compatibility, upgrade impact, and the inventory at analysis time. |
They're separate files joined by reference: the mirror report's upgrade.analyses[] lists each analysis and where its report is.
Destinations
spec.source.type selects where the report goes — the same block on a ClusterMirror and an UpgradeAnalysis:
| Type | Where | Key fields |
|---|---|---|
file (default) | Ephemeral file in the operator pod (emptyDir), served over HTTP (:8084). Lost on pod restart. | path |
pvc | In-cluster persistent storage — a PersistentVolumeClaim mounted into the operator. Same as file but survives pod restarts; no cloud needed. | path (mount dir) |
s3 | Amazon S3 — no local replica | bucket, region, key, credentialsSecret |
blob | Azure Blob — no local replica | accountName, containerName, blobName, credentialsSecret |
Remote destinations keep no local replica — the operator writes only to the destination and reads it back on demand (in memory) to serve it, using its own credentials so the connection never leaves the operator.
Which destination for which consumer
Where a report lives determines who can read it:
| Destination | Where it lives | How the CLI reads it |
|---|---|---|
file | Inside the operator pod (ephemeral) | In-cluster only — the HTTP endpoint --source http://mirops-reports.<ns>:8084/reports/<name>.mirops?kind=ClusterMirror. Not on the CLI runner's disk. |
pvc | In-cluster persistent volume | In-cluster only — the HTTP endpoint (above), or mount the same PVC and read the file (--source /mnt/reports/<name>.mirops). Mounting alongside the operator needs ReadWriteMany, or ReadWriteOnce on the same node. |
s3 / blob | Object storage | From anywhere — --source s3://… / azure://…. |
file and pvc reports live inside the cluster, so a CI runner outside the cluster can't reach them. You have two options:
- Use a remote destination (
s3/blob) — the runner reads it directly from anywhere. This is the recommended pattern for external CI. - Pull the files into the pipeline manually — fetch the reports onto the runner (e.g.
kubectl cpthem out of the pod, or download them from the PVC), then read the local copies:mirops scan --source ./default.mirops --upgrade --upgrade-source ./to-1-35.mirops --enforce. The CLI accepts any local path, so however the files get onto the runner, it works.
Naming
Every report is <name>.mirops — a ClusterMirror's and an UpgradeAnalysis's. The content is JSON, and its top-level kind (ClusterMirror / UpgradeAnalysis) says which resource wrote it. For s3/blob you own the object name via key/blobName; leave it empty and it defaults to <name>.mirops. For pvc and the local file destination the report is always <name>.mirops. The extension keeps reports distinct from config files sharing a destination; a mirror and an analysis writing to the same destination need different names.
Over HTTP, the reports service serves /reports/<name>.mirops: add ?kind=ClusterMirror for a mirror's report — without it, the name is an UpgradeAnalysis's.
Operator 0.2.0 wrote a mirror's report as <name>.mirops and served it at /reports/<name>.mirops. Operator 0.2.1 writes and serves <name>.mirops for both.
Failures are surfaced, not hidden
When the operator can't write to (or read back from) a destination, it records the outcome on the CR so it shows in kubectl describe and the UI instead of only the pod logs:
| Status field | Meaning |
|---|---|
status.reportState | written or failed |
status.reportError | The failure message |
status.reportLocation | Where it tried to write |
status.syncError | ClusterMirror only: why the last rebuild or its report failed |
Deleting a ClusterMirror or UpgradeAnalysis never deletes its report from S3/Blob/PVC — there is no cleanup finalizer, so your data is never removed without your action.
Consuming reports
- CLI —
mirops scan --source <mirror report>reads any destination: it judges a change against it with-f, shows a namespace's state with-n, and gates an upgrade with--upgrade-source <analysis report>. See read reports. - Web UI — reads both through the operator's report endpoint.
- Your tools — the report is plain JSON with a stable schema.