Querying and Watching Resources
Find, filter, and monitor Kubernetes and OpenShift resources in your cluster — whether you need to list all pods by label, check if a resource exists, watch for real-time changes, or inspect status and conditions.
Prerequisites
openshift-python-wrapperinstalled (see Installing and Creating Your First Resource)- A connected
DynamicClientinstance (see Connecting to Clusters)
Quick Example
from ocp_resources.pod import Pod
from ocp_resources.resource import get_client
client = get_client()
# List all pods in a namespace
for pod in Pod.get(client=client, namespace="my-namespace"):
print(f"{pod.name} — {pod.status}")
Listing Resources
Every resource class provides a get() class method that returns a generator of resource objects. The method accepts standard Kubernetes query parameters as keyword arguments.
List all resources of a type
from ocp_resources.namespace import Namespace
for ns in Namespace.get(client=client):
print(ns.name)
Filter by namespace
Namespaced resources (like Pod, Service, ConfigMap) accept a namespace keyword:
from ocp_resources.pod import Pod
for pod in Pod.get(client=client, namespace="default"):
print(pod.name)
Filter by label selector
Use label_selector with standard Kubernetes label selector syntax:
from ocp_resources.pod import Pod
# Single label
for pod in Pod.get(client=client, namespace="my-app", label_selector="app=nginx"):
print(pod.name)
# Multiple labels (comma-separated)
for pod in Pod.get(client=client, label_selector="app=nginx,tier=frontend"):
print(pod.name)
Filter by field selector
Use field_selector with standard Kubernetes field selector syntax:
from ocp_resources.pod import Pod
# Find pods on a specific node
for pod in Pod.get(client=client, field_selector="spec.nodeName=worker-1"):
print(pod.name)
# Find pods by status phase
for pod in Pod.get(client=client, namespace="default", field_selector="status.phase=Running"):
print(pod.name)
Get raw resource objects
By default, get() returns wrapper objects. Pass raw=True to get the underlying ResourceInstance or ResourceField objects directly:
from ocp_resources.pod import Pod
for pod in Pod.get(client=client, namespace="default", raw=True):
# Returns raw ResourceField objects instead of Pod instances
print(pod.metadata.name, pod.status.phase)
List all cluster resources
To iterate over every resource type in the cluster:
from ocp_resources.resource import Resource
for resource in Resource.get_all_cluster_resources(client=client):
print(f"{resource.kind}: {resource.metadata.name}")
# Filter with label selector
for resource in Resource.get_all_cluster_resources(client=client, label_selector="my-label=value"):
print(f"{resource.kind}: {resource.metadata.name}")
get() Method Reference
@classmethod
def get(
cls,
client: DynamicClient | None = None,
singular_name: str = "",
exceptions_dict: dict[type[Exception], list[str]] = DEFAULT_CLUSTER_RETRY_EXCEPTIONS,
raw: bool = False,
*args,
**kwargs,
) -> Generator
| Parameter | Type | Description |
|---|---|---|
client |
DynamicClient |
Kubernetes dynamic client (required) |
singular_name |
str |
Resource kind in lowercase; used when multiple resources match the same kind |
raw |
bool |
If True, return raw ResourceInstance/ResourceField objects instead of wrapper instances |
exceptions_dict |
dict |
Exceptions to retry on during API calls |
**kwargs |
Passed through to the Kubernetes API: namespace, label_selector, field_selector, limit, resource_version, timeout_seconds, etc. |
Returns: A generator yielding resource objects.
Checking Resource Existence
The exists property queries the API server and returns the resource instance if it exists, or None if it does not.
from ocp_resources.namespace import Namespace
ns = Namespace(client=client, name="my-namespace")
if ns.exists:
print("Namespace exists")
else:
print("Namespace not found")
Require existence at initialization
Use ensure_exists=True to raise ResourceNotFoundError immediately if the resource is not found:
from ocp_resources.pod import Pod
# Raises ResourceNotFoundError if the pod doesn't exist
pod = Pod(client=client, name="my-pod", namespace="default", ensure_exists=True)
Tip: Use
ensure_exists=Truewhen you need a reference to a resource that must already be on the cluster, such as a pre-existing ConfigMap or Secret.
Getting the Resource Instance
The instance property fetches the full live resource from the API server:
pod = Pod(client=client, name="my-pod", namespace="default")
# Get the full resource instance
inst = pod.instance
print(inst.metadata.name)
print(inst.metadata.uid)
print(inst.metadata.resourceVersion)
# Convert to a plain dictionary
resource_dict = pod.instance.to_dict()
Note: Each access to
.instancemakes an API call. Cache the result in a local variable if you need multiple fields from the same snapshot.
Retrieving Labels
The labels property returns the resource's labels:
ns = Namespace(client=client, name="my-namespace")
print(ns.labels) # {'kubernetes.io/metadata.name': 'my-namespace', ...}
# Check a specific label
if "app" in ns.labels:
print(f"App label: {ns.labels['app']}")
Retrieving Resource Status
Status phase
The status property returns the current phase (e.g., Running, Pending, Active):
from ocp_resources.namespace import Namespace
ns = Namespace(client=client, name="my-namespace")
print(ns.status) # "Active"
Each resource class defines status constants you can compare against:
from ocp_resources.pod import Pod
pod = Pod(client=client, name="my-pod", namespace="default")
if pod.status == Pod.Status.RUNNING:
print("Pod is running")
Common status constants available on all resources:
| Constant | Value |
|---|---|
Status.RUNNING |
"Running" |
Status.PENDING |
"Pending" |
Status.SUCCEEDED |
"Succeeded" |
Status.FAILED |
"Failed" |
Status.ACTIVE |
"Active" |
Status.TERMINATING |
"Terminating" |
Status.COMPLETED |
"Completed" |
Status.ERROR |
"Error" |
Condition messages
Use get_condition_message() to retrieve the message for a specific condition type:
pod = Pod(client=client, name="my-pod", namespace="default")
# Get message for a condition type
msg = pod.get_condition_message(condition_type="Ready")
print(msg)
# Optionally filter by condition status
msg = pod.get_condition_message(
condition_type="Ready",
condition_status="False",
)
print(msg) # Returns empty string if status doesn't match
Signature:
def get_condition_message(
self,
condition_type: str,
condition_status: str = "",
) -> str
| Parameter | Type | Description |
|---|---|---|
condition_type |
str |
The condition type to look up (e.g., "Ready", "Available") |
condition_status |
str |
If provided, only return the message when the condition has this status |
Returns: The condition message string, or "" if not found or status doesn't match.
Condition constants
Resources provide built-in condition constants:
from ocp_resources.pod import Pod
pod = Pod(client=client, name="my-pod", namespace="default")
# Use condition constants
msg = pod.get_condition_message(
condition_type=Pod.Condition.READY,
condition_status=Pod.Condition.Status.TRUE,
)
Common condition constants:
| Constant | Value |
|---|---|
Condition.READY |
"Ready" |
Condition.AVAILABLE |
"Available" |
Condition.PROGRESSING |
"Progressing" |
Condition.DEGRADED |
"Degraded" |
Condition.UPGRADEABLE |
"Upgradeable" |
Condition.Status.TRUE |
"True" |
Condition.Status.FALSE |
"False" |
Condition.Status.UNKNOWN |
"Unknown" |
Watching for Changes
Watch a specific resource
The watcher() method streams events for a specific resource instance:
from ocp_resources.pod import Pod
pod = Pod(client=client, name="my-pod", namespace="default")
for event in pod.watcher(timeout=60):
print(f"Event type: {event['type']}") # ADDED, MODIFIED, DELETED
print(f"Object: {event['object'].metadata.name}")
print(f"Raw: {event['raw_object']}")
Signature:
def watcher(
self,
timeout: int,
resource_version: str = "",
) -> Generator[dict[str, Any], None, None]
| Parameter | Type | Description |
|---|---|---|
timeout |
int |
How long to watch (in seconds) |
resource_version |
str |
Only receive events newer than this version. Defaults to the resource version at creation time. |
Each yielded event is a dict with these keys:
| Key | Description |
|---|---|
type |
Event type: "ADDED", "MODIFIED", or "DELETED" |
object |
A ResourceInstance wrapping the resource |
raw_object |
A plain dict representing the resource |
Querying Events
Stream events for a resource
The events() method watches Kubernetes events associated with a resource:
from ocp_resources.pod import Pod
pod = Pod(client=client, name="my-pod", namespace="default")
for event in pod.events(timeout=30):
print(f"Reason: {event.object.reason}")
print(f"Message: {event.object.message}")
Signature:
def events(
self,
name: str = "",
label_selector: str = "",
field_selector: str = "",
resource_version: str = "",
timeout: int = 240,
) -> Generator
| Parameter | Type | Description |
|---|---|---|
name |
str |
Filter by event name |
label_selector |
str |
Filter by labels (comma-separated key=value) |
field_selector |
str |
Additional field filters (merged with auto-generated involvedObject.name filter) |
resource_version |
str |
Only return events newer than this version |
timeout |
int |
Watch timeout in seconds (default: 240) |
# Example: filter for Warning events with a specific reason
for event in pod.events(
field_selector="type==Warning,reason==BackOff",
timeout=10,
):
print(event.object.message)
List existing events (non-streaming)
Use Event.list() to get a snapshot of existing events without streaming:
from ocp_resources.event import Event
# List Warning events from the last 5 minutes
events = Event.list(
client=client,
namespace="my-namespace",
field_selector="type==Warning",
)
for event in events:
print(f"{event.reason}: {event.message}")
# List events from the last 10 minutes
events = Event.list(
client=client,
namespace="my-namespace",
since_seconds=600,
)
Signature:
@classmethod
def Event.list(
cls,
client: DynamicClient,
namespace: str | None = None,
field_selector: str | None = None,
label_selector: str | None = None,
since_seconds: int = 300,
) -> list
Events are returned sorted by timestamp (most recent first).
Delete events
Clean up events before tests to avoid false positives:
from ocp_resources.event import Event
Event.delete_events(
client=client,
namespace="my-namespace",
field_selector="reason=AnEventReason",
)
Advanced Usage
Handling resources with duplicate API groups
Some resource kinds exist in multiple API groups. Use singular_name to disambiguate:
The DNS kind exists in two API groups, so class-generator writes one module per group:
ocp_resources.dns_config_openshift_io—config.openshift.io/v1ocp_resources.dns_operator_openshift_io—operator.openshift.io/v1
from ocp_resources.dns_config_openshift_io import DNS
# When a kind exists in multiple API groups, pass singular_name
for dns in DNS.get(client=client, singular_name="dns"):
print(dns.name)
Using full_api() for low-level access
The full_api() method returns the raw Kubernetes API resource object, giving you direct access to the API:
ns = Namespace(client=client, name="my-namespace")
api = ns.full_api()
# Use the API directly for custom queries
result = api.get(
label_selector="app=nginx",
field_selector="status.phase=Active",
limit=10,
)
full_api() accepts these keyword arguments:
| Parameter | Description |
|---|---|
pretty |
Pretty-print output |
_continue |
Continuation token for paginated results |
field_selector |
Filter by fields |
label_selector |
Filter by labels |
limit |
Maximum number of results |
resource_version |
Filter by resource version |
timeout_seconds |
Server-side timeout |
watch |
Enable watch mode |
Converting resources to YAML
ns = Namespace(client=client, name="my-namespace")
print(ns.to_yaml())
Wait for conditions and status
For polling-based waiting (e.g., wait until a pod is Running or a condition is True), see Waiting for Resource Conditions and Status.
Querying during tests with the fake client
You can use all querying methods with the fake client for unit testing:
from ocp_resources.resource import get_client
from ocp_resources.namespace import Namespace
client = get_client(fake=True)
ns = Namespace(client=client, name="test-ns")
ns.deploy()
# All query methods work the same way
assert ns.exists
assert ns.instance
assert ns.status == Namespace.Status.ACTIVE
# Listing works too
for ns in Namespace.get(client=client):
print(ns.name)
See Testing Without a Cluster Using the Fake Client for details.
Troubleshooting
ResourceNotFoundError when using ensure_exists=True
The resource does not exist on the cluster. Verify the name, namespace, and that the resource has been created before initializing the wrapper.
NotImplementedError: Couldn't find <Kind> in <api_group>
The resource kind is not available on your cluster. This typically means the CRD has not been installed or the API group is incorrect.
get() returns no results
- Verify the
namespaceis correct (omit it for cluster-scoped resources). - Check your
label_selectorandfield_selectorsyntax — use==for equality (e.g.,field_selector="status.phase==Running"). - Ensure the client has permissions to list the resource type.
status property raises AttributeError
Not all resources have a status.phase field. Access instance.status directly to inspect what status fields are available for your resource type.