kubeclient

package
v0.7.9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 3, 2026 License: Apache-2.0 Imports: 30 Imported by: 0

README

Kubeclient — Developer Documentation

This package wraps all Kubernetes client concerns: REST config, typed clientset, dynamic client, the GenericClient interface that the informer factory uses to build typed ListerWatchers, and the typed CRUD operations (Get, Create, Patch) used by constructor reconcilers.

Documents

File What it covers
01-genericclient.md The GenericClient interface, Client implementation, and the ClientProvider registration pattern
02-dynamic.md DynamicListerWatcher — how dynamic (unstructured) CRDs build their ListerWatcher and how namespace scoping works
03-crud.md Get, Create, Patch on KubeClient — typed object operations for constructor reconcilers, GVR derivation via scheme+mapper
04-merge.md MergeFrom and StrategicMergeFrom — building Patch values without importing controller-runtime
05-patch-helpers.md PatchFinalizers, PatchLabels, PatchAnnotations, PatchStatus, PatchSpec — generic reconciler mutation surface, plus context injection (WithKubeclient / FromContext)

Read 01-genericclient.md when adding a new typed client. Read 02-dynamic.md when working with dynamic CRDs or namespace-scoped watch streams. Read 03-crud.md and 04-merge.md when writing or migrating a constructor reconciler. Read 05-patch-helpers.md when working on the generic reconciler or hook functions that need to mutate objects.

Documentation

Overview

pkg/kubeclient/context.go

pkg/kubeclient/dynamic.go

pkg/kubeclient/genericclient.go

pkg/kubeclient/kubeclient.go

pkg/kubeclient/patch_status.go

pkg/kubeclient/provider.go

Index

Constants

View Source
const ContextKey contextKey = "orkestra-kubeclient"

ContextKey is the key used to store and retrieve a KubeClient from a context.

Usage — inject before calling hooks:

ctx = kubeclient.WithKubeclient(ctx, kube)

Usage — retrieve in hook/registry functions:

kube, ok := kubeclient.FromContext(ctx)

Variables

This section is empty.

Functions

func NewFakeClientset

func NewFakeClientset() kubernetes.Interface

New fake client

func WithKubeclient

func WithKubeclient(ctx context.Context, kube KubeClient) context.Context

WithKubeclient returns a new context with the KubeClient stored under ContextKey. Called in GenericReconciler.Reconcile before invoking hook and registry functions.

Types

type CRDInfo

type CRDInfo struct {
	Kind                 string                  // Required by Registry
	Group                string                  // Required if GroupVersion is not specified
	Version              string                  // Required if GroupVersion is not specified
	GroupVersion         *schema.GroupVersion    // Optional (can be used if Group and Version are not specified)
	GroupVersionKind     schema.GroupVersionKind //	Useful for some manipulations
	GroupVersionResource schema.GroupResource
	Plural               string
	Namespaced           bool // Required for cluster-scoped resources
	APIPath              string
	Namespace            string
}

CRDInfo defines what a CRD is

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client definition

func (*Client) List

func (c *Client) List(ctx context.Context, opts metav1.ListOptions) (runtime.Object, error)

A generic client should know how to List and Watch just as the dynamic client List returns runtime.Object - exactly what GenericClient needs!

func (*Client) ListInNamespace added in v0.2.5

func (c *Client) ListInNamespace(ctx context.Context, namespace string, opts metav1.ListOptions) (runtime.Object, error)

ListInNamespace lists resources scoped to the given namespace. Used by the Tier 1 namespace filter when allowedNamespaces has exactly one entry.

func (*Client) Watch

func (c *Client) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error)

Watch returns the watch interface

func (*Client) WatchInNamespace added in v0.2.5

func (c *Client) WatchInNamespace(ctx context.Context, namespace string, opts metav1.ListOptions) (watch.Interface, error)

WatchInNamespace watches resources scoped to the given namespace. Used by the Tier 1 namespace filter when allowedNamespaces has exactly one entry.

type ClientFactory

type ClientFactory func(*Kubeclient) (informer.GenericClient, error)

ClientFactory accepts kubeclient and returns a generic client The generic client is the hallmark of the whole design konstructRuntime() performs per CRD registration and hands over to ghe informer factory

type ClientProvider

type ClientProvider struct {
	// contains filtered or unexported fields
}

ClientProvider definition for registering new clients

func (*ClientProvider) For

For returns a generic client for a registered object

func (*ClientProvider) Register

func (p *ClientProvider) Register(obj runtime.Object, factory ClientFactory)

Register adds a new object to clients

type DynamicListerWatcher

type DynamicListerWatcher struct {
	// contains filtered or unexported fields
}

DynamicListerWatcher implements cache.ListerWatcher using the dynamic client. Safe to construct before kube.Start() — k.dynamic is resolved at call time.

func (*DynamicListerWatcher) List

List implements cache.ListerWatcher. *unstructured.UnstructuredList satisfies runtime.Object — explicit cast needed because dynamic.ResourceInterface.List returns the concrete type, not the interface.

func (*DynamicListerWatcher) Watch

Watch implements cache.ListerWatcher.

type KubeClient added in v0.4.8

type KubeClient interface {
	Clientset() kubernetes.Interface
	DynamicClient() dynamic.Interface
	Mapper() meta.RESTMapper

	// CRUD — typed object operations for constructor reconcilers.
	// Accepts sigs.k8s.io/controller-runtime/pkg/client.Object so reconcilers
	// migrated from controller-runtime compile without changes to their call sites.
	// GVR is derived from the Go type via the scheme and mapper; callers do not
	// need to specify it explicitly.
	Get(ctx context.Context, namespace, name string, into sigs.Object) error
	Create(ctx context.Context, obj sigs.Object) error
	Patch(ctx context.Context, obj sigs.Object, patch Patch) error

	// Patch helpers — used by the generic reconciler for finalizer, label,
	// annotation, and status updates. Implementations must be idempotent.
	PatchFinalizers(ctx context.Context, obj runtime.Object, finalizers []string) error
	PatchLabels(ctx context.Context, obj runtime.Object, base, desired map[string]string) error
	PatchAnnotations(ctx context.Context, obj runtime.Object, annotations map[string]string) error
	PatchStatus(ctx context.Context, obj domain.Object, statusFields map[string]interface{}) error
}

KubeClient is the interface every registry function depends on. *Kubeclient satisfies this with real clients. *simulate.FakeKubeclient satisfies this with k8s.io/client-go/kubernetes/fake.

func FromContext

func FromContext(ctx context.Context) (KubeClient, bool)

FromContext retrieves the KubeClient from a context. Returns (nil, false) if not present.

type Kubeclient

type Kubeclient struct {
	Info *CRDInfo

	// Testing
	FakeClientset kubernetes.Interface
	// contains filtered or unexported fields
}

Kubeclient defines what a kube client is

func NewForTesting added in v0.3.7

func NewForTesting(cfg *rest.Config, dynamic dynamic.Interface, scheme *runtime.Scheme) *Kubeclient

NewForTesting builds a Kubeclient wired to the given REST config without going through Start(). Used exclusively by integration tests that provide their own envtest config.

func NewKubeclient

func NewKubeclient(kfg *konfig.Konfig, scheme *runtime.Scheme) *Kubeclient

----------------------------------------------------------------------------- Entry point ----------------------------------------------------------------------------- NewKubeclient returns a new Kubeclient with the correct scheme

func (*Kubeclient) ApiextensionsClient

func (k *Kubeclient) ApiextensionsClient() apiextclientset.Interface

ApiextensionsClient returns the apiextensions clientset for CRD operations.

func (*Kubeclient) Clientset

func (k *Kubeclient) Clientset() kubernetes.Interface

Clientset returns the kubernetes interface

func (*Kubeclient) Create added in v0.7.7

func (k *Kubeclient) Create(ctx context.Context, obj sigs.Object) error

Create creates obj in the cluster. Derives the API group and resource from the Go type via the scheme and mapper.

func (*Kubeclient) DynamicClient

func (k *Kubeclient) DynamicClient() dynamic.Interface

Dynamic returns yhe dynamic interface. Useful in 'dynamic' reconciler mode

func (*Kubeclient) DynamicClientFor

func (k *Kubeclient) DynamicClientFor(apiPath, group, version string) (dynamic.Interface, error)

On-demand dynamic client

func (*Kubeclient) Get added in v0.7.7

func (k *Kubeclient) Get(ctx context.Context, namespace, name string, into sigs.Object) error

Get fetches the object identified by namespace/name into into. Derives the API group and resource from the Go type via the scheme and mapper.

func (*Kubeclient) Mapper added in v0.4.6

func (k *Kubeclient) Mapper() meta.RESTMapper

func (*Kubeclient) Name

func (k *Kubeclient) Name() string

Name returns the name of the kubeclient

func (*Kubeclient) NewClient

func (k *Kubeclient) NewClient(objList runtime.Object, info CRDInfo) (*Client, error)

NewClient returns a new client using ths shared client factory

func (*Kubeclient) NewClientProvider

func (k *Kubeclient) NewClientProvider() *ClientProvider

NewClientProvider creates a new provider with the passed in kubeclient At this stage, it only accepts the kubeclient and created the clients map This is because kube is not live yet

func (*Kubeclient) NewDynamicListerWatcher

func (k *Kubeclient) NewDynamicListerWatcher(info CRDInfo, opts ListOptions) cache.ListerWatcher

NewDynamicListerWatcher builds a cache.ListerWatcher for an unstructured CRD. Safe to call before kube.Start() — dynamic client is resolved lazily.

func (*Kubeclient) Patch added in v0.7.7

func (k *Kubeclient) Patch(ctx context.Context, obj sigs.Object, patch Patch) error

Patch applies patch to obj in the cluster. The patch body and type are computed by calling patch.Data(obj). Use kubeclient.MergeFrom or kubeclient.StrategicMergeFrom to build the patch, or pass sigs.MergeFrom / sigs.StrategicMergeFrom directly — they satisfy Patch.

func (*Kubeclient) PatchAnnotations

func (k *Kubeclient) PatchAnnotations(
	ctx context.Context,
	obj runtime.Object,
	annotations map[string]string,
) error

PatchAnnotations merges annotations onto the object by sending a JSON Merge Patch containing only the desired annotation keys. Keys present in annotations are added or updated on the server; keys absent from the patch are left unchanged (not deleted).

This is intentionally a one-way merge: Orkestra's annotation management only ever adds keys (managed-by and managed-since are write-once and never removed). If key deletion is ever needed, mirror the base/desired pattern used by [PatchLabels].

func (*Kubeclient) PatchFinalizers

func (k *Kubeclient) PatchFinalizers(
	ctx context.Context,
	obj runtime.Object,
	finalizers []string,
) error

PatchFinalizers replaces the object's finalizer list with finalizers by sending a minimal JSON Merge Patch that touches only metadata.finalizers. Sending only the changed field avoids resourceVersion conflicts that would arise from patching the full object.

func (*Kubeclient) PatchLabels

func (k *Kubeclient) PatchLabels(
	ctx context.Context,
	obj runtime.Object,
	base, desired map[string]string,
) error

PatchLabels transitions the object's labels from base to desired by sending a JSON Merge Patch. Keys present in base but absent in desired are set to null so the server deletes them. Keys in desired that differ from base are added or updated. Unchanged keys are omitted from the patch body.

base must be a snapshot of the labels as they exist on the server immediately before any in-memory mutations are applied (the controller-runtime MergeFrom pattern). Pass nil for base when the object is brand-new and has no labels.

func (*Kubeclient) PatchSpec

func (k *Kubeclient) PatchSpec(
	ctx context.Context,
	obj domain.Object,
	specFields map[string]interface{},
) error

pkg/kubeclient/patch_spec.go

func (*Kubeclient) PatchStatus

func (k *Kubeclient) PatchStatus(
	ctx context.Context,
	obj domain.Object,
	statusFields map[string]interface{},
) error

PatchStatus applies a merge patch to the /status subresource of a CR.

statusFields is the map of status fields to set — it is merged into the existing status, not replaced entirely. Fields not present in statusFields are left untouched.

The patch is applied to the /status subresource, which requires the CRD to declare:

spec:
  versions:
    - name: v1
      subresources:
        status: {}   # ← this enables the status subresource

If the CRD does not declare a status subresource, the API server returns a 404 "the server could not find the requested resource". Callers should treat this as a non-fatal condition — the CRD simply does not support status updates.

PatchStatus uses merge patch (application/merge-patch+json) rather than strategic merge patch. Merge patch is simpler and sufficient for status updates — we are setting top-level status fields, not merging lists.

Example statusFields:

{
  "conditions": [{"type": "Ready", "status": "True", ...}],
  "observedGeneration": 3,
  "phase": "Running",
  "endpoint": "my-site.default.svc.cluster.local"
}

The API server wraps this in {"status": <statusFields>} before applying. Callers pass only the status contents — not the "status" wrapper key.

func (*Kubeclient) RefreshMapper added in v0.4.6

func (k *Kubeclient) RefreshMapper()

RefreshMapper forces the deferred mapper to refresh its discovery cache. Call this after creating or updating CRDs so RESTMapping will pick them up.

func (*Kubeclient) RestClientFor

func (k *Kubeclient) RestClientFor(apiPath, group, version string) (*rest.RESTClient, error)

On-demand rest client

func (*Kubeclient) RestConfig

func (k *Kubeclient) RestConfig() *rest.Config

RestConfig returns the rest confif for the kube client

func (*Kubeclient) RuntimeParameterCodec

func (k *Kubeclient) RuntimeParameterCodec() runtime.ParameterCodec

func (*Kubeclient) Scheme

func (k *Kubeclient) Scheme() *runtime.Scheme

Scheme returns the runtime scheme for yhe kubeclient

func (*Kubeclient) SharedClientFactory

func (k *Kubeclient) SharedClientFactory(apiPath, group, version string) (*rest.RESTClient, error)

SharedClientFactory provides a simple way to build clients from config

func (*Kubeclient) Shutdown

func (k *Kubeclient) Shutdown(ctx context.Context)

Shutdown is called by orkestra fir graceful shutdown

func (*Kubeclient) Start

func (k *Kubeclient) Start(ctx context.Context) error

Start is called by orkestra.Start() to start kube client

func (*Kubeclient) Started

func (k *Kubeclient) Started() bool

Started is called by orkestra for healthcheck

type ListOptions

type ListOptions struct {
	LabelSelector string
	FieldSelector string
}

type Patch added in v0.7.7

type Patch = sigs.Patch

Patch is sigs.k8s.io/controller-runtime/pkg/client.Patch, re-exported so constructor reconcilers only need to import this package. Values produced by sigs.MergeFrom, sigs.StrategicMergeFrom, and sigs.Apply satisfy this type directly — no adapter or wrapper needed when migrating from controller-runtime.

func MergeFrom added in v0.7.7

func MergeFrom(base sigs.Object) Patch

MergeFrom returns a JSON Merge Patch (RFC 7396) from base to the modified object passed to kube.Patch. Call before mutating the object:

patch := kubeclient.MergeFrom(existing.DeepCopy())
existing.Spec = desired.Spec
return kube.Patch(ctx, existing, patch)

Use for CRDs and any object where replace semantics are correct. For core Kubernetes types with list merge keys, prefer StrategicMergeFrom.

Delegates to sigs.k8s.io/controller-runtime/pkg/client.MergeFrom — the sigs version works here directly if you already import controller-runtime.

func StrategicMergeFrom added in v0.7.7

func StrategicMergeFrom(base sigs.Object) Patch

StrategicMergeFrom returns a Strategic Merge Patch for core Kubernetes types (Deployment, DaemonSet, StatefulSet, etc.) that carry patchMergeKey annotations. The API server merges list entries by key (e.g. containers by name) rather than replacing the entire list. For CRDs, use MergeFrom — the API server has no schema knowledge for custom types.

Delegates to sigs.k8s.io/controller-runtime/pkg/client.StrategicMergeFrom — the sigs version works here directly if you already import controller-runtime.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL