Accessing Resources

When using resource bundles, the Kubernetes resources are stored within the resources property of the ResourceBundle. This resources property behaves like a normal Python list, but it has additional functionality for conveniently accessing resources by namespace, kind and name filtering.

Consider a case where we have the following resource definition file:

apiVersion: v1
kind: ConfigMap
metadata:
  name: web-configs
  namespace: alpha

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: settings
  namespace: alpha

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: settings
  namespace: bravo

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: settings
  namespace: charlie

Such that the defined resources are:

alpha namespace:

  • ConfigMap/web-configs
  • ConfigMap/settings

bravo namespace:

  • ConfigMap/settings

charlie namespace:

  • ConfigMap/settings

Using the ResourceBundle.get() method shown elsewhere in the documentation we could retrieve the web-configs resource as:

config_map = bundle.get(name="web-configs", kind="ConfigMap")

but another way to access this resource would be to use the dynamic accessors on the resources object:

config_map = bundle.resources.config_map.web_configs

Here the resources object can be filtered dynamically by kind, which returns a filtered resources object that can be filtered by name.

In the case above where we want to get the settings resource in the charlie namespace, we can add a .within("charlie") filter to the resources object:

settings = bundle.resources.within("charlie").config_map.settings

If the .within("charlie") namespace filter is omitted, the resources object will recognize that there are multiple resources that match the kind = ConfigMap and name = settings and instead return a tuple of all of those resources instead of just a single resource:

for settings in bundle.resources.config_map.settings:
    print(settings.metadata.namespace)

alpha_settings = bundle.resources.config_map.settings[0]

Case Conventions

From the examples above you can see that the dynamic accessors use snake_case. This is to make the accessors match conventional casing inside Python. Internally the values are converted to PascalCase for kind values and kebab-case for name values as are the Kubernetes conventions.

Kubernetes names also allow for the . character, which cannot be represented in a Python variable name. In those cases dictionary-style accessors can be used instead:

job = bundle.resources.job["my.job-name"]

The dictionary-style accessors will also accept PascalCase for kind values. Therefore, the web-configs from the earlier example can be accessed in any of the following ways:

web_configs = bundle.resources.config_map.web_configs
web_configs = bundle.resources["ConfigMap"].web_configs
web_configs = bundle.resources["ConfigMap"]["web-configs"]

# This one works because order is preserved when loading resources and
# the web-configs resource was the first one defined. However, it is usually
# preferred to reference by name instead of relying on order preservation.
web_configs = bundle.resources["ConfigMap"][0]

Advanced Filtering

Ultimately the dynamic accessing of resources is meant to be used in simple cases, while the .get() and .get_many() methods of resource bundles can be used to do the same thing, but also allow for filtering based on metadata labels: