Skip to content

Core Builders

Builder functions that convert spec models into Kubernetes manifest dictionaries.

Custom Resources

Use ResourceBuilder to create builders for custom Kubernetes resources (CRDs, operators, etc.).

How It Works

ResourceBuilder automatically:

  • Routes name, namespace, labels, annotations to metadata
  • Routes other fields to spec (or top-level for special resources)
  • Transforms nested KubeModel instances to dicts via .to_dict()
  • Uses Pydantic field aliases for camelCase output

Parameters

Parameter Default Description
spec required The specification model instance
api_version required Kubernetes API version (e.g., "v1", "apps/v1")
kind required Resource kind (e.g., "Service", "Deployment")
include_spec True Set False for resources without a spec section (Namespace, ConfigMap, RBAC)
top_level_fields None Field names placed at resource root instead of spec (e.g., {"rules"} for Role)
skip_fields None Field names to skip (for manual handling)

Basic Example

from k8smith import ResourceBuilder, KubeModel
from pydantic import Field

class MyCustomSpec(KubeModel):
    name: str
    namespace: str = "default"
    replicas: int = 1
    custom_field: str = Field(alias="customField")

def build_my_resource(spec: MyCustomSpec) -> dict:
    return ResourceBuilder.build(spec, "example.com/v1", "MyResource")

# Usage
spec = MyCustomSpec(name="my-app", custom_field="value")
manifest = build_my_resource(spec)

Advanced: Resources Without spec Section

Some Kubernetes resources (Namespace, ConfigMap, RBAC) don't have a spec section:

def build_my_config(spec: MyConfigSpec) -> dict:
    return ResourceBuilder.build(
        spec, "v1", "ConfigMap",
        include_spec=False,
        top_level_fields={"data"},
    )

ResourceBuilder

Generic builder for Kubernetes resources.

Handles the common pattern of building K8s resources by: 1. Creating the base structure (apiVersion, kind, metadata, spec) 2. Routing fields to the appropriate location based on field name 3. Auto-transforming nested KubeModel instances to dicts

Examples:

Simple resource (all fields go to spec):

>>> ResourceBuilder.build(spec, "v1", "Service")

Metadata-only resource (no spec section):

>>> ResourceBuilder.build(spec, "v1", "Namespace", include_spec=False)

Resource with top-level fields (RBAC):

>>> ResourceBuilder.build(spec, "rbac.authorization.k8s.io/v1", "Role",
...                       top_level_fields={"rules"})

Resource with custom field handling:

>>> ResourceBuilder.build(spec, "apps/v1", "Deployment",
...                       skip_fields={"selector", "template"})
Source code in src/k8smith/core/builder.py
class ResourceBuilder:
    """Generic builder for Kubernetes resources.

    Handles the common pattern of building K8s resources by:
    1. Creating the base structure (apiVersion, kind, metadata, spec)
    2. Routing fields to the appropriate location based on field name
    3. Auto-transforming nested KubeModel instances to dicts

    Examples:
        Simple resource (all fields go to spec):
        >>> ResourceBuilder.build(spec, "v1", "Service")

        Metadata-only resource (no spec section):
        >>> ResourceBuilder.build(spec, "v1", "Namespace", include_spec=False)

        Resource with top-level fields (RBAC):
        >>> ResourceBuilder.build(spec, "rbac.authorization.k8s.io/v1", "Role",
        ...                       top_level_fields={"rules"})

        Resource with custom field handling:
        >>> ResourceBuilder.build(spec, "apps/v1", "Deployment",
        ...                       skip_fields={"selector", "template"})
    """

    METADATA_FIELDS = {"name", "namespace", "labels", "annotations"}

    @classmethod
    def build(
        cls,
        spec: KubeModel,
        api_version: str,
        kind: str,
        *,
        include_spec: bool = True,
        top_level_fields: set[str] | None = None,
        skip_fields: set[str] | None = None,
    ) -> dict[str, Any]:
        """Build a Kubernetes resource from a spec model.

        Args:
            spec: The specification model (e.g., ServiceSpec, IngressSpec)
            api_version: Kubernetes API version (e.g., "v1", "apps/v1")
            kind: Resource kind (e.g., "Service", "Deployment")
            include_spec: Whether to include a spec section (False for Namespace)
            top_level_fields: Field names that go at resource root, not in spec
                             (e.g., {"rules"} for Role, {"roleRef", "subjects"} for RoleBinding)
            skip_fields: Field names to skip (handled manually by the caller)

        Returns:
            Kubernetes resource as a dict ready for YAML serialization
        """
        resource: dict[str, Any] = {
            "apiVersion": api_version,
            "kind": kind,
            "metadata": {},
        }
        if include_spec:
            resource["spec"] = {}

        top_level_fields = top_level_fields or set()
        skip_fields = skip_fields or set()

        for field_name, field_info in type(spec).model_fields.items():
            if field_name in skip_fields:
                continue

            val = getattr(spec, field_name)
            if val is None:
                continue

            # Get the Kubernetes field name (alias or original)
            key = field_info.alias or field_name

            # Auto-transform nested models to dicts
            val = cls._transform_value(val)

            # Route to the appropriate location
            if field_name in cls.METADATA_FIELDS:
                if val:  # Skip empty labels/annotations
                    resource["metadata"][key] = val
            elif field_name in top_level_fields:
                resource[key] = val
            elif include_spec:
                resource["spec"][key] = val

        return resource

    @classmethod
    def _transform_value(cls, val: Any) -> Any:
        """Transform KubeModel instances to dicts recursively.

        Handles both single KubeModel instances and lists of them.
        """
        if isinstance(val, KubeModel):
            return val.to_dict()
        elif isinstance(val, list) and val and isinstance(val[0], KubeModel):
            return [v.to_dict() for v in val]
        return val

build(spec, api_version, kind, *, include_spec=True, top_level_fields=None, skip_fields=None) classmethod

Build a Kubernetes resource from a spec model.

Parameters:

Name Type Description Default
spec KubeModel

The specification model (e.g., ServiceSpec, IngressSpec)

required
api_version str

Kubernetes API version (e.g., "v1", "apps/v1")

required
kind str

Resource kind (e.g., "Service", "Deployment")

required
include_spec bool

Whether to include a spec section (False for Namespace)

True
top_level_fields set[str] | None

Field names that go at resource root, not in spec (e.g., {"rules"} for Role, {"roleRef", "subjects"} for RoleBinding)

None
skip_fields set[str] | None

Field names to skip (handled manually by the caller)

None

Returns:

Type Description
dict[str, Any]

Kubernetes resource as a dict ready for YAML serialization

Source code in src/k8smith/core/builder.py
@classmethod
def build(
    cls,
    spec: KubeModel,
    api_version: str,
    kind: str,
    *,
    include_spec: bool = True,
    top_level_fields: set[str] | None = None,
    skip_fields: set[str] | None = None,
) -> dict[str, Any]:
    """Build a Kubernetes resource from a spec model.

    Args:
        spec: The specification model (e.g., ServiceSpec, IngressSpec)
        api_version: Kubernetes API version (e.g., "v1", "apps/v1")
        kind: Resource kind (e.g., "Service", "Deployment")
        include_spec: Whether to include a spec section (False for Namespace)
        top_level_fields: Field names that go at resource root, not in spec
                         (e.g., {"rules"} for Role, {"roleRef", "subjects"} for RoleBinding)
        skip_fields: Field names to skip (handled manually by the caller)

    Returns:
        Kubernetes resource as a dict ready for YAML serialization
    """
    resource: dict[str, Any] = {
        "apiVersion": api_version,
        "kind": kind,
        "metadata": {},
    }
    if include_spec:
        resource["spec"] = {}

    top_level_fields = top_level_fields or set()
    skip_fields = skip_fields or set()

    for field_name, field_info in type(spec).model_fields.items():
        if field_name in skip_fields:
            continue

        val = getattr(spec, field_name)
        if val is None:
            continue

        # Get the Kubernetes field name (alias or original)
        key = field_info.alias or field_name

        # Auto-transform nested models to dicts
        val = cls._transform_value(val)

        # Route to the appropriate location
        if field_name in cls.METADATA_FIELDS:
            if val:  # Skip empty labels/annotations
                resource["metadata"][key] = val
        elif field_name in top_level_fields:
            resource[key] = val
        elif include_spec:
            resource["spec"][key] = val

    return resource

Workloads

build_deployment(spec)

Build a Kubernetes Deployment resource.

Note: selector and template are handled manually because: 1. selector must be wrapped as {"matchLabels": ...} in output 2. selector labels must be merged into template.metadata.labels (Kubernetes requires pod labels to match the selector) 3. selector auto-generates from spec.name if not provided These cross-field dependencies can't be expressed in ResourceBuilder.

Parameters:

Name Type Description Default
spec DeploymentSpec

Deployment specification

required

Returns:

Type Description
dict

Kubernetes Deployment resource as a dict

Example

from k8smith.core.models import ( ... Container, DeploymentSpec, PodSpec, PodTemplateSpec, ... ) spec = DeploymentSpec( ... name="web", ... namespace="production", ... replicas=3, ... template=PodTemplateSpec( ... spec=PodSpec( ... containers=[Container(name="web", image="nginx:1.25")] ... ) ... ), ... ) deployment = build_deployment(spec)

Source code in src/k8smith/core/deployment.py
def build_deployment(spec: DeploymentSpec) -> dict:
    """Build a Kubernetes Deployment resource.

    Note: selector and template are handled manually because:
    1. selector must be wrapped as {"matchLabels": ...} in output
    2. selector labels must be merged into template.metadata.labels
       (Kubernetes requires pod labels to match the selector)
    3. selector auto-generates from spec.name if not provided
    These cross-field dependencies can't be expressed in ResourceBuilder.

    Args:
        spec: Deployment specification

    Returns:
        Kubernetes Deployment resource as a dict

    Example:
        >>> from k8smith.core.models import (
        ...     Container, DeploymentSpec, PodSpec, PodTemplateSpec,
        ... )
        >>> spec = DeploymentSpec(
        ...     name="web",
        ...     namespace="production",
        ...     replicas=3,
        ...     template=PodTemplateSpec(
        ...         spec=PodSpec(
        ...             containers=[Container(name="web", image="nginx:1.25")]
        ...         )
        ...     ),
        ... )
        >>> deployment = build_deployment(spec)
    """
    # Build selector and merge into template labels
    selector = spec.selector or {"app.kubernetes.io/name": spec.name}
    template_dict = spec.template.to_dict()
    template_dict.setdefault("metadata", {})
    template_dict["metadata"]["labels"] = {
        **selector,
        **template_dict["metadata"].get("labels", {}),
    }

    # Use ResourceBuilder for everything except selector and template
    resource = ResourceBuilder.build(
        spec, "apps/v1", "Deployment", skip_fields={"selector", "template"}
    )
    resource["spec"]["selector"] = {"matchLabels": selector}
    resource["spec"]["template"] = template_dict

    return resource

build_statefulset(spec)

Build a Kubernetes StatefulSet resource.

Note: selector and template are handled manually because: 1. selector must be wrapped as {"matchLabels": ...} in output 2. selector labels must be merged into template.metadata.labels (Kubernetes requires pod labels to match the selector) 3. selector auto-generates from spec.name if not provided These cross-field dependencies can't be expressed in ResourceBuilder.

Parameters:

Name Type Description Default
spec StatefulSetSpec

StatefulSet specification

required

Returns:

Type Description
dict

Kubernetes StatefulSet resource as a dict

Source code in src/k8smith/core/statefulset.py
def build_statefulset(spec: StatefulSetSpec) -> dict:
    """Build a Kubernetes StatefulSet resource.

    Note: selector and template are handled manually because:
    1. selector must be wrapped as {"matchLabels": ...} in output
    2. selector labels must be merged into template.metadata.labels
       (Kubernetes requires pod labels to match the selector)
    3. selector auto-generates from spec.name if not provided
    These cross-field dependencies can't be expressed in ResourceBuilder.

    Args:
        spec: StatefulSet specification

    Returns:
        Kubernetes StatefulSet resource as a dict
    """
    # Build selector and merge into template labels
    selector = spec.selector or {"app.kubernetes.io/name": spec.name}
    template_dict = spec.template.to_dict()
    template_dict.setdefault("metadata", {})
    template_dict["metadata"]["labels"] = {
        **selector,
        **template_dict["metadata"].get("labels", {}),
    }

    # Use ResourceBuilder for everything except selector and template
    resource = ResourceBuilder.build(
        spec, "apps/v1", "StatefulSet", skip_fields={"selector", "template"}
    )
    resource["spec"]["selector"] = {"matchLabels": selector}
    resource["spec"]["template"] = template_dict

    return resource

build_daemonset(spec)

Build a Kubernetes DaemonSet resource.

Note: selector and template are handled manually because: 1. selector must be wrapped as {"matchLabels": ...} in output 2. selector labels must be merged into template.metadata.labels (Kubernetes requires pod labels to match the selector) 3. selector auto-generates from spec.name if not provided These cross-field dependencies can't be expressed in ResourceBuilder.

Parameters:

Name Type Description Default
spec DaemonSetSpec

DaemonSet specification

required

Returns:

Type Description
dict

Kubernetes DaemonSet resource as a dict

Source code in src/k8smith/core/daemonset.py
def build_daemonset(spec: DaemonSetSpec) -> dict:
    """Build a Kubernetes DaemonSet resource.

    Note: selector and template are handled manually because:
    1. selector must be wrapped as {"matchLabels": ...} in output
    2. selector labels must be merged into template.metadata.labels
       (Kubernetes requires pod labels to match the selector)
    3. selector auto-generates from spec.name if not provided
    These cross-field dependencies can't be expressed in ResourceBuilder.

    Args:
        spec: DaemonSet specification

    Returns:
        Kubernetes DaemonSet resource as a dict
    """
    # Build selector and merge into template labels
    selector = spec.selector or {"app.kubernetes.io/name": spec.name}
    template_dict = spec.template.to_dict()
    template_dict.setdefault("metadata", {})
    template_dict["metadata"]["labels"] = {
        **selector,
        **template_dict["metadata"].get("labels", {}),
    }

    # Use ResourceBuilder for everything except selector and template
    resource = ResourceBuilder.build(
        spec, "apps/v1", "DaemonSet", skip_fields={"selector", "template"}
    )
    resource["spec"]["selector"] = {"matchLabels": selector}
    resource["spec"]["template"] = template_dict

    return resource

build_cronjob(spec)

Build a Kubernetes CronJob resource.

Note: job_template is handled manually because Kubernetes expects the nested structure spec.jobTemplate.spec.template, which can't be expressed through ResourceBuilder's simple field routing.

Parameters:

Name Type Description Default
spec CronJobSpec

CronJob specification

required

Returns:

Type Description
dict

Kubernetes CronJob resource as a dict

Source code in src/k8smith/core/cronjob.py
def build_cronjob(spec: CronJobSpec) -> dict:
    """Build a Kubernetes CronJob resource.

    Note: job_template is handled manually because Kubernetes expects
    the nested structure spec.jobTemplate.spec.template, which can't
    be expressed through ResourceBuilder's simple field routing.

    Args:
        spec: CronJob specification

    Returns:
        Kubernetes CronJob resource as a dict
    """
    resource = ResourceBuilder.build(spec, "batch/v1", "CronJob", skip_fields={"job_template"})
    resource["spec"]["jobTemplate"] = {"spec": {"template": spec.job_template.to_dict()}}

    return resource

Services

build_service(spec)

Build a Kubernetes Service resource.

Parameters:

Name Type Description Default
spec ServiceSpec

Service specification

required

Returns:

Type Description
dict

Kubernetes Service resource as a dict

Source code in src/k8smith/core/service.py
def build_service(spec: ServiceSpec) -> dict:
    """Build a Kubernetes Service resource.

    Args:
        spec: Service specification

    Returns:
        Kubernetes Service resource as a dict
    """
    return ResourceBuilder.build(spec, "v1", "Service")

Configuration

build_configmap(spec)

Build a Kubernetes ConfigMap resource.

Parameters:

Name Type Description Default
spec ConfigMapSpec

ConfigMap specification

required

Returns:

Type Description
dict

Kubernetes ConfigMap resource as a dict

Source code in src/k8smith/core/configmap.py
def build_configmap(spec: ConfigMapSpec) -> dict:
    """Build a Kubernetes ConfigMap resource.

    Args:
        spec: ConfigMap specification

    Returns:
        Kubernetes ConfigMap resource as a dict
    """
    return ResourceBuilder.build(
        spec,
        "v1",
        "ConfigMap",
        include_spec=False,
        top_level_fields={"data", "binary_data", "immutable"},
    )

build_secret(spec)

Build a Kubernetes Secret resource.

Parameters:

Name Type Description Default
spec SecretSpec

Secret specification

required

Returns:

Type Description
dict

Kubernetes Secret resource as a dict

Source code in src/k8smith/core/secret.py
def build_secret(spec: SecretSpec) -> dict:
    """Build a Kubernetes Secret resource.

    Args:
        spec: Secret specification

    Returns:
        Kubernetes Secret resource as a dict
    """
    return ResourceBuilder.build(
        spec,
        "v1",
        "Secret",
        include_spec=False,
        top_level_fields={"type", "data", "string_data", "immutable"},
    )

Scaling & Availability

build_hpa(spec)

Build a Kubernetes HorizontalPodAutoscaler resource.

Parameters:

Name Type Description Default
spec HPASpec

HPA specification

required

Returns:

Type Description
dict

Kubernetes HorizontalPodAutoscaler resource as a dict

Source code in src/k8smith/core/hpa.py
def build_hpa(spec: HPASpec) -> dict:
    """Build a Kubernetes HorizontalPodAutoscaler resource.

    Args:
        spec: HPA specification

    Returns:
        Kubernetes HorizontalPodAutoscaler resource as a dict
    """
    return ResourceBuilder.build(spec, "autoscaling/v2", "HorizontalPodAutoscaler")

build_pdb(spec)

Build a Kubernetes PodDisruptionBudget resource.

Note: selector is handled manually because it must be wrapped as {"matchLabels": selector} in the output.

Parameters:

Name Type Description Default
spec PDBSpec

PDB specification

required

Returns:

Type Description
dict

Kubernetes PodDisruptionBudget resource as a dict

Source code in src/k8smith/core/pdb.py
def build_pdb(spec: PDBSpec) -> dict:
    """Build a Kubernetes PodDisruptionBudget resource.

    Note: selector is handled manually because it must be wrapped as
    {"matchLabels": selector} in the output.

    Args:
        spec: PDB specification

    Returns:
        Kubernetes PodDisruptionBudget resource as a dict
    """
    resource = ResourceBuilder.build(
        spec, "policy/v1", "PodDisruptionBudget", skip_fields={"selector"}
    )
    if spec.selector:
        resource["spec"]["selector"] = {"matchLabels": spec.selector}
    return resource

Identity

build_serviceaccount(spec)

Build a Kubernetes ServiceAccount resource.

Parameters:

Name Type Description Default
spec ServiceAccountSpec

ServiceAccount specification

required

Returns:

Type Description
dict

Kubernetes ServiceAccount resource as a dict

Source code in src/k8smith/core/serviceaccount.py
def build_serviceaccount(spec: ServiceAccountSpec) -> dict:
    """Build a Kubernetes ServiceAccount resource.

    Args:
        spec: ServiceAccount specification

    Returns:
        Kubernetes ServiceAccount resource as a dict
    """
    return ResourceBuilder.build(
        spec,
        "v1",
        "ServiceAccount",
        include_spec=False,
        top_level_fields={"automount_service_account_token", "image_pull_secrets"},
    )

build_namespace(spec)

Build a Kubernetes Namespace resource.

Parameters:

Name Type Description Default
spec NamespaceSpec

Namespace specification

required

Returns:

Type Description
dict

Kubernetes Namespace resource as a dict

Source code in src/k8smith/core/namespace.py
def build_namespace(spec: NamespaceSpec) -> dict:
    """Build a Kubernetes Namespace resource.

    Args:
        spec: Namespace specification

    Returns:
        Kubernetes Namespace resource as a dict
    """
    return ResourceBuilder.build(spec, "v1", "Namespace", include_spec=False)

RBAC

build_role(spec)

Build a Kubernetes Role resource.

Parameters:

Name Type Description Default
spec RoleSpec

Role specification

required

Returns:

Type Description
dict

Kubernetes Role resource as a dict

Example

from k8smith.core.models import RoleSpec, PolicyRule spec = RoleSpec( ... name="pod-reader", ... namespace="production", ... rules=[ ... PolicyRule(api_groups=[""], resources=["pods"], verbs=["get", "list", "watch"]), ... ], ... ) role = build_role(spec)

Source code in src/k8smith/core/rbac.py
def build_role(spec: RoleSpec) -> dict:
    """Build a Kubernetes Role resource.

    Args:
        spec: Role specification

    Returns:
        Kubernetes Role resource as a dict

    Example:
        >>> from k8smith.core.models import RoleSpec, PolicyRule
        >>> spec = RoleSpec(
        ...     name="pod-reader",
        ...     namespace="production",
        ...     rules=[
        ...         PolicyRule(api_groups=[""], resources=["pods"], verbs=["get", "list", "watch"]),
        ...     ],
        ... )
        >>> role = build_role(spec)
    """
    return ResourceBuilder.build(
        spec,
        "rbac.authorization.k8s.io/v1",
        "Role",
        include_spec=False,
        top_level_fields={"rules"},
    )

build_clusterrole(spec)

Build a Kubernetes ClusterRole resource.

Parameters:

Name Type Description Default
spec ClusterRoleSpec

ClusterRole specification

required

Returns:

Type Description
dict

Kubernetes ClusterRole resource as a dict

Example

from k8smith.core.models import ClusterRoleSpec, PolicyRule spec = ClusterRoleSpec( ... name="node-reader", ... rules=[ ... PolicyRule( ... api_groups=[""], ... resources=["nodes"], ... verbs=["get", "list", "watch"], ... ), ... ], ... ) cluster_role = build_clusterrole(spec)

Source code in src/k8smith/core/rbac.py
def build_clusterrole(spec: ClusterRoleSpec) -> dict:
    """Build a Kubernetes ClusterRole resource.

    Args:
        spec: ClusterRole specification

    Returns:
        Kubernetes ClusterRole resource as a dict

    Example:
        >>> from k8smith.core.models import ClusterRoleSpec, PolicyRule
        >>> spec = ClusterRoleSpec(
        ...     name="node-reader",
        ...     rules=[
        ...         PolicyRule(
        ...             api_groups=[""],
        ...             resources=["nodes"],
        ...             verbs=["get", "list", "watch"],
        ...         ),
        ...     ],
        ... )
        >>> cluster_role = build_clusterrole(spec)
    """
    return ResourceBuilder.build(
        spec,
        "rbac.authorization.k8s.io/v1",
        "ClusterRole",
        include_spec=False,
        top_level_fields={"rules", "aggregation_rule"},
    )

build_rolebinding(spec)

Build a Kubernetes RoleBinding resource.

Parameters:

Name Type Description Default
spec RoleBindingSpec

RoleBinding specification

required

Returns:

Type Description
dict

Kubernetes RoleBinding resource as a dict

Example

from k8smith.core.models import RoleBindingSpec, RoleBindingSubject, RoleRef spec = RoleBindingSpec( ... name="read-pods", ... namespace="production", ... subjects=[ ... RoleBindingSubject(kind="ServiceAccount", name="my-sa", namespace="production"), ... ], ... role_ref=RoleRef(kind="Role", name="pod-reader"), ... ) binding = build_rolebinding(spec)

Source code in src/k8smith/core/rbac.py
def build_rolebinding(spec: RoleBindingSpec) -> dict:
    """Build a Kubernetes RoleBinding resource.

    Args:
        spec: RoleBinding specification

    Returns:
        Kubernetes RoleBinding resource as a dict

    Example:
        >>> from k8smith.core.models import RoleBindingSpec, RoleBindingSubject, RoleRef
        >>> spec = RoleBindingSpec(
        ...     name="read-pods",
        ...     namespace="production",
        ...     subjects=[
        ...         RoleBindingSubject(kind="ServiceAccount", name="my-sa", namespace="production"),
        ...     ],
        ...     role_ref=RoleRef(kind="Role", name="pod-reader"),
        ... )
        >>> binding = build_rolebinding(spec)
    """
    return ResourceBuilder.build(
        spec,
        "rbac.authorization.k8s.io/v1",
        "RoleBinding",
        include_spec=False,
        top_level_fields={"role_ref", "subjects"},
    )

build_clusterrolebinding(spec)

Build a Kubernetes ClusterRoleBinding resource.

Parameters:

Name Type Description Default
spec ClusterRoleBindingSpec

ClusterRoleBinding specification

required

Returns:

Type Description
dict

Kubernetes ClusterRoleBinding resource as a dict

Example

from k8smith.core.models import ClusterRoleBindingSpec, RoleBindingSubject, RoleRef spec = ClusterRoleBindingSpec( ... name="read-nodes-global", ... subjects=[ ... RoleBindingSubject( ... kind="ServiceAccount", ... name="monitoring", ... namespace="kube-system", ... ), ... ], ... role_ref=RoleRef(kind="ClusterRole", name="node-reader"), ... ) binding = build_clusterrolebinding(spec)

Source code in src/k8smith/core/rbac.py
def build_clusterrolebinding(spec: ClusterRoleBindingSpec) -> dict:
    """Build a Kubernetes ClusterRoleBinding resource.

    Args:
        spec: ClusterRoleBinding specification

    Returns:
        Kubernetes ClusterRoleBinding resource as a dict

    Example:
        >>> from k8smith.core.models import ClusterRoleBindingSpec, RoleBindingSubject, RoleRef
        >>> spec = ClusterRoleBindingSpec(
        ...     name="read-nodes-global",
        ...     subjects=[
        ...         RoleBindingSubject(
        ...             kind="ServiceAccount",
        ...             name="monitoring",
        ...             namespace="kube-system",
        ...         ),
        ...     ],
        ...     role_ref=RoleRef(kind="ClusterRole", name="node-reader"),
        ... )
        >>> binding = build_clusterrolebinding(spec)
    """
    return ResourceBuilder.build(
        spec,
        "rbac.authorization.k8s.io/v1",
        "ClusterRoleBinding",
        include_spec=False,
        top_level_fields={"role_ref", "subjects"},
    )