The Must Gather operator helps collecting must-gather information on a cluster and uploading it to a case. To use the operator, a cluster administrator can create the following MustGather CR:
apiVersion: operator.openshift.io/v1
kind: MustGather
metadata:
name: example-mustgather-basic
spec:
serviceAccountName: must-gather-admin
uploadTarget:
type: SFTP
sftp:
caseID: '02527285'
caseManagementAccountSecretRef:
name: case-management-credsThis request will collect the standard must-gather info and upload it to case #02527285 using the credentials found in the caseManagementCreds secret.
The field audit is false by default unless explicitly set to true.
This will generate the default collection of audit logs as per the collection script: gather_audit_logs
apiVersion: operator.openshift.io/v1
kind: MustGather
metadata:
name: example-mustgather-full
spec:
serviceAccountName: must-gather-admin
gatherSpec:
audit: true
uploadTarget:
type: SFTP
sftp:
caseID: '02527285'
caseManagementAccountSecretRef:
name: case-management-credsThe operator supports obfuscation of must-gather bundles before upload, consistently replacing sensitive data such as IP addresses and MAC addresses. Obfuscation is enabled by setting obfuscate.enabled: true in the CR spec.
Three operational modes are supported:
- Gather + Obfuscate + Upload — collect, redact, then upload via SFTP:
apiVersion: operator.openshift.io/v1
kind: MustGather
metadata:
name: obfuscated-gather
spec:
serviceAccountName: must-gather-admin
obfuscate:
enabled: true
uploadTarget:
type: SFTP
sftp:
caseID: '02527285'
caseManagementAccountSecretRef:
name: case-management-creds- Gather + Obfuscate + PVC — collect and redact, persist to PVC (no upload):
apiVersion: operator.openshift.io/v1
kind: MustGather
metadata:
name: obfuscated-gather-pvc
spec:
serviceAccountName: must-gather-admin
obfuscate:
enabled: true
storage:
pvc:
claim: must-gather-pvc- Obfuscate + Upload from source — redact an existing bundle on a PVC and upload:
apiVersion: operator.openshift.io/v1
kind: MustGather
metadata:
name: obfuscate-existing
spec:
serviceAccountName: must-gather-admin
obfuscate:
enabled: true
source:
pvc:
claim: existing-bundle-pvc
uploadTarget:
type: SFTP
sftp:
caseID: '02527285'
caseManagementAccountSecretRef:
name: case-management-credsA custom obfuscation config can be supplied via obfuscate.obfuscationConfigRef referencing a ConfigMap. If omitted, the built-in default config (replaces IPs and MACs, omits Secrets and ConfigMaps) is used. See examples/ for all variations.
Starting with release 5.0, the must-gather-operator is Generally Available (GA). The OLM channel has changed from tech-preview to stable and the API version has been promoted from operator.openshift.io/v1alpha1 to operator.openshift.io/v1.
If you previously installed the operator via the tech-preview channel, update your Subscription to use the stable channel:
oc patch subscription support-log-gather-operator -n must-gather-operator \
--type merge -p '{"spec":{"channel":"stable"}}'Existing v1alpha1 MustGather CRs continue to work — the CRD serves both versions — but v1alpha1 is deprecated and will be removed in a future release. New CRs should use operator.openshift.io/v1.
Note: This operator may still be unsupported. For development, consider using the
stablechannel as described above. For support, consult the appropriate Red Hat documentation and the OpenShift Operator Life Cycles policy.
When a MustGather Job succeeds or fails, the controller runs cleanup in the same reconciliation pass: it deletes owned Pods and Jobs, and removes the CR's ownerReference from any configured trusted CA ConfigMap (deleting the ConfigMap only if no other owners remain). This behavior applies when retainResourcesOnCompletion is unset or false.
On CR deletion, the finalizer performs this same cleanup only when retention is disabled. Setting retainResourcesOnCompletion: true skips explicit cleanup while the MustGather CR exists; deleting the CR can still trigger Kubernetes garbage collection of owned resources.
| Component | Version / Detail |
|---|---|
| Language | Go 1.26.0 |
| API version | operator.openshift.io/v1 (GA). v1alpha1 deprecated but still served. |
| CRD types | api/v1/mustgather_types.go (primary); api/v1alpha1/ retained for backward compat |
| Framework | controller-runtime v0.21.0 |
| Kubernetes client | client-go v0.33.3 |
| Testing | Ginkgo v2 / Gomega v1.36 |
| Metrics | Prometheus client_golang v1.22, operator-custom-metrics |
| SFTP | pkg/sftp v1.13 |
| Build system | Makefile with openshift-eng boilerplate |
| FIPS | Enabled by default (BoringCrypto) |
must-gather-operator/
├── api/
│ ├── v1/ # GA MustGather CRD types (primary)
│ └── v1alpha1/ # Deprecated types (still served for compat)
├── controllers/mustgather/ # Reconciler, Job template, predicates
├── build/bin/ # Upload shell script (compress + SFTP)
├── config/ # Operator constants, metadata, templates
├── deploy/ # Deployment manifests and CRD YAML
│ └── crds/ # CRD definition
├── pkg/
│ ├── k8sutil/ # Namespace detection utility
│ ├── localmetrics/ # Prometheus metrics definitions
│ └── mustgatherutil/ # Must-gather helper utilities
├── test/
│ ├── e2e/ # End-to-end tests (Ginkgo, -tags e2e)
│ └── library/ # Test helper library
├── harness-evals/
│ ├── evals/ # Evaluation harness tests
│ └── harness-docs/ # Domain model, ADRs, development guides
├── bundle/ # OLM bundle manifests
├── hack/ # Release and OLM registry tooling
├── examples/ # 14 example CRs and supporting resources
├── scripts/ # Build scripts
├── boilerplate/ # openshift-eng boilerplate convention system
├── main.go # Operator entrypoint
└── Makefile # Build targets (delegates to boilerplate)
This project uses the openshift-eng boilerplate Makefile system.
# Build, run tests, and lint (default target)
make
# Run unit tests only
make go-test
# Build the operator binary
make go-build
# Run end-to-end tests (requires a running cluster)
make test-e2e
# Generate deepcopy, OpenAPI, and CRD code
make generate
# Generate CRD and RBAC manifests
make manifests
# Run linting
make lint
# Build container image
make docker-build
# Push container image
make docker-push
# Build and push in one step
make build-push
# Update boilerplate
make boilerplate-updateThis is a cluster-level operator that you can deploy in any namespace; must-gather-operator is recommended.
Here are the instructions to install the latest release creating the manifest directly in OCP.
git clone git@github.com:openshift/must-gather-operator.git; cd must-gather-operator
oc apply -f deploy/crds/operator.openshift.io_mustgathers.yaml
oc new-project must-gather-operator
oc -n must-gather-operator apply -f deployIn order to run, the operator needs a secret to be created by the admin as follows (this assumes the operator is running in the must-gather-operator namespace).
oc create secret generic case-management-creds --from-literal=username=<username> --from-literal=password=<password>Execute the following steps to develop the functionality locally. It is recommended that development be done using a cluster with cluster-admin permissions.
In the operator's Deployment.yaml file, add a variable to the deployment's spec.template.spec.containers.env list called OPERATOR_IMAGE and set the value to your local copy of the image:
env:
- name: OPERATOR_IMAGE
value: "registry.example/repo/image:latest"Then run:
go mod downloadUsing the operator-sdk, run the operator locally:
oc apply -f deploy/crds/operator.openshift.io_mustgathers.yaml
oc new-project must-gather-operator
export DEFAULT_MUST_GATHER_IMAGE='quay.io/openshift/origin-must-gather:latest'
OPERATOR_NAME=must-gather-operator operator-sdk run --verbose --local --namespace ''- AGENTS.md -- Component overview, architecture, reconciliation flow, and AI agent guidance
- harness-evals/harness-docs/ -- Domain model, architectural decisions (ADRs), development and testing guides
- Development Guide — Build, common tasks, env vars, common mistakes
- Testing Guide — Unit tests (fake client + interceptClient), E2E (Ginkgo)
- Architecture — Repo layout, reconciliation flow, Job template
- Domain Model — MustGather CRD fields, validation, lifecycle
- Decision Records — ADRs for immutable spec, two-container Job, extensible upload