Reference

Objects returned when querying Hikaru itself

class hikaru.CatalogEntry(cls, attrname, path)
attrname

Alias for field number 1

cls

Alias for field number 0

path

Alias for field number 2

CatalogEntry is a namedtuple that is returned as list elements from the find_by_name() method of HikaruBase.

class hikaru.TypeWarning(cls, attrname, path, warning)
attrname

Alias for field number 1

cls

Alias for field number 0

path

Alias for field number 2

warning

Alias for field number 3

TypeWarning is a dataclass that is returned as list elements from the get_type_warnings() method of HikaruBase.

class hikaru.DiffDetail(diff_type: DiffType, cls: Type, formatted_path: str, path: List[str], report: str, value: Any | None = None, other_value: Any | None = None)

The details of a difference found between two Hikaru objects using diff().

This dataclass contains information detailing the nature of the difference between two Hikaru objects. It provides a type of difference (a DiffType value), the class where the difference was found, a formatted_path to the difference a list of path elements that can be used to find the actual value using object_at_path(), additionally the two values of the item being compared.

Additionally, a read-only property named ‘attrname’ will return the name of the attribute where the difference was found. This is the same as path[-1].

property attrname

returns the name of the attribute where the diff was found; same as path[-1]

class hikaru.DiffType(value)

These are the types of diffs that can be detected by diff( ) and reported in the DiffDetail object

The possible values are:

Value:

…means:

ADDED

the other object has a value where self does not for this attribute

REMOVED

the other object has None where self does not for this attribute

VALUE_CHANGED

the other object’s value differs from self’s for this attribute

TYPE_CHANGED

the type of this attribute changed from self to other

LIST_LENGTH_CHANGED

list len between self and other changed for this attributes

INCOMPATIBLE_DIFF

the value of an attribute in self and other are incomparable types

Hikaru modelling base classes

class hikaru.HikaruBase
repopulate_catalog()

re-creates the catalog for this object (and any contained objects) from scratch

If a HikaruBase model gets changed after it was populated from YAML or by Python source code, it may be desirable to re-create the catalogs to inspect the new model. This method causes the old catalogs to be dropped and new catalogs to be loaded with the data currently in the model.

to_dict() dict

Provides a simple transfer to a dictionary representation of self

This method does a simple transcription of self into a dict using hikaru.get_clean_dict().

Returns:

A dict representation of self. Only keys with values are in the resulting dict

dup()

Create a deep copy of self

Returns:

identical instance of self plus any contained instances

find_by_name(name: str, following: str | List | None = None) List[CatalogEntry]

Returns a list of catalog entries for the named field wherever it occurs in the model.

This method returns a list of CatalogEntry instances that match the criteria of the input parameters. At very least, the list will contain all entries for an attribute named ‘name’.

The list of returned items can be further reduced by supplying a value for the ‘following’ argument, which names one or more attributes that must come before the named attribute in order for the entry to be included in the returned list. The ‘following’ argument may be specified as a ‘.’ separated string of attribute names or as a list of strings. These describe the prerequisite attributes that must be on the path to the named attribute, but not necessarily consecutively. By specifying ‘following’ you can essentially establish a context in which you find the named attribute. The attributes named in ‘following’ will be considered in order, but they don’t have to be directly sequential in the model.

Parameters:
  • name – string containing a name for an attribute somewhere in the model, the search for with starts at ‘self’. This must be a legal Python identifier, not an integer.

  • following

    Sequence of strings or a single string with elements separated by ‘.’. These elements must appear somewhere along the path to ‘name’ in order, but not necessarily consecutively. These will serve as a way to specify ‘signposts’ along the way to the desired field. Each element is either an attribute name or an integer for lists to identify which element in the list must be seen before ‘name’. For example, say you had a model of a Pod and wanted all the attributes called ‘name’, but only within a container’s volumeMounts objects. You can get these with the following invocation:

    p.find_by_name('name',
                   following="containers.volumeMounts")
    

    Or suppose you wanted ‘exec’ from anywhere in the lifecycle object of the first container in a pod:

    p.find_by_name('exec',
                   following=['containers', 0, 'lifecycle'])
    

    or:

    p.find_by_name('exec',
                   following="containers.0.lifecycle")
    

    Or suppose you wanted to find all the httpHeaders ‘name’ from in the lifecycle in any container in a pod:

    p.find_by_name('name',
                   following="containers.lifecycle.httpGet")
    

    In the last example, ‘lifecycle’ is an direct attribute of a single container, but ‘httpGet’ is several objects beneath the lifecycle.

Returns:

list of CatalogEntry objects that match the query criteria.

Raises:
  • TypeError – if ‘name’ is not a string, or if ‘following’ is not a string or list

  • ValueError – if ‘following’ is a list and one of the elements is not a str or an int

object_at_path(path: list)

returns the value named by path starting at self

Returns an object or base value by navigating the supplied path starting at ‘self’. The elements of path are either strings representing attribute names or else integers in the case where an attribute name reaches a list (the int is used as an index into the list). Generally, the thing to do is to use the ‘path’ attribute of a returned CatalogEntry from find_by_name()

Parameters:

path – A list of strings or ints.

Returns:

Whatever value is found at the end of the path; this could be another HikaruBase instance or a plain Python object (str, bool, dict, etc).

Raises:
  • RuntimeError – raised if None is found anywhere along the path except at the last element

  • IndexError – raised if a path index value is beyond the end of a list-valued attribute

  • ValueError – if an index for a list can’t be turned into an int

  • AttributeError – raised if any attribute on the path isn’t an attribute of the previous object on the path

classmethod from_yaml(yaml, translate: bool = False)

Create an instance of this HikaruBase subclass from the provided yaml.

This factory method creates a new instance of the class upon which it is invoked and fills the instance with data from supplied yaml object. It is a short-cut to creating an empty instance yourself and then invoking process(yaml) on that instance (this method hides the details of making an empty instance).

This method can fill an instance with suitable YAML object, whether a full document or a fragment of one, as long as the type of the YAML object being processed and the subclass of HikaruBase agree. If a fragment of a object that would otherwise be part of a larger object, the fragment should not have the same indentation as it would as part of the larger document, but instead should be fully “outdented” to the left as if it was the standalone document itself.

Parameters:
  • yaml – a ruamel.yaml YAML instance

  • translate – optional bool, default False. If True, then all attributes that are fetched from the dict are first run through camel_to_pep8 to use the underscore-embedded versions of the attribute names.

Returns:

an instance of a subclass of HikaruBase

classmethod get_empty_instance()

Returns a properly initialized instance with Nones and empty collections

Returns:

and instance of ‘cls’ with all scalar attrs set to None and all collection attrs set to an appropriate empty collection

diff(other) List[DiffDetail]

Compares self to other and returns list of differences and where they are

The diff() method goes field-by-field between two objects looking for differences. Whenever any are found, a DiffDetail object is added to the returned list. The diff is carried out recursively across any containers or inner objects; the path to any differences found is recorded from self to any nested difference.

Note that diff() looks at all fields in the objects, not just ones that have been set.

Parameters:

other – some kind of HikaruBase subclass. If not the same class as self, then a single DiffDetail object is returned describing this and the diff stops.

Returns:

a list of DiffDetail objects that describe all the discovered differences. If the list is empty then the two are equal.

merge(other, overwrite: bool = False, enforce_version=False)

Merges the values of another object of the same type into self

Merge allows you to take the values from another HikaruBase subclass instance of the same type as self and merge them into self. The merge can be done one of two ways:

  • The default is to pull over any non-None fields from other into self. If additional subobjects are in other then new copies of them are put into self (if none exists already), otherwise values are merged into the subobject.

  • If overwrite is True, then every field from other is pulled into self. That means that it is possible that a field in self that previously had a value may become None after a merge with overwrite. Overwrite also implies replacing all contents of dicts and lists in self.

Parameters:
  • other – source of values to merge into self. Must be the same ‘type’ as self, but the interpretation of ‘type’ is governed by the enforce_version parameter (see below).

  • overwrite – optional bool, default False. The default only merges in attributes from other that are non-None. Hence, None attributes in other will never replace actual values in self. If True, then all data is taken from other verbatim, which can result in a loss of attribute values in self.

  • enforce_version – optional bool, default False. The default simply checks to see if self and other have the same class names rather than the same actual class. This allows for merging data from objects from one version of Kubernetes to another. If enforce_version is True, then merge() will check to see both self and other are from the same class. If either of these versions of type checking don’t match, then merge will raise a TypeError.

Raises:

TypeError – if other has an attribute to merge into self that self doesn’t know about, or if checking that the ‘type’ of self and other, or any of their components, results in them not being merge-able.

Returns:

self with values for other merged in

get_type_warnings() List[TypeWarning]

Compares attribute type annotation to actual data; issues warning on mismatches.

This method compares the type of each attribute based on the type annotation against the type of the actual data in the attribute and generates a warning object whenever a mismatch is discovered. The search for mismatches starts at self and recursively searches any HikaruBase objects contained in self.

Note that if get_type_warnings() finds an attribute that is a HikaruBase object of the incorrect type, get_type_warnings() will NOT inspect the incorrect object’s attributes for type correctness. The object itself will be flagged as incorrect, but checking will not continue inside the incorrect object. Other checks will still proceed.

Returns:

a list of TypeWarning namedtuple objects. The fields should be interpreted as follows:

  • cls: the class object that contains the attribute that has a type mismatch

  • attrname: the name of the attribute that has the type mismatch

  • path: a list of strings that indicates from self how to reach the attr

  • warning: a string that contains the text of the warning.

Note that the first three fields are similar to those from CatalogEntry, however their interpretation is slightly different.

A return of an empty list indicates that there were no TypeWarnings. This DOES NOT indicate that there aren’t errors in usage; for example, if and object may contain one of three alternative objects, this method doesn’t check if that constraint holds true; it only checks that the types of any contained objects are correct.

process(yaml, translate: bool = False) None

extract self’s data items from the supplied yaml object.

Parameters:
  • yaml – a populated dict-like object that contains keys and values that represent the constructs of a Kubernetes YAML file. Supplied by pyyaml or ruamel.yaml. Results in the construction of a set of Hikaru class instances that mirror the structure and contents of the YAML, as well as the population of the type/field catalogs. To ensure proper catalogues, invoke repopulate_catalog() after modifying data or doing multiple sequential parse() calls.

  • translate – optional bool, default False. If True, then all attributes that are fetched from the dict are first run through camel_to_pep8 to use the underscore-embedded versions of the attribute names.

NOTE: it is possible to call parse again, but this will result in

additional fields added to the existing fields, not a replacement of what was previously there. Always parse with an empty instance of the object.

Raises:

TypeError – in the case if the YAML is missing a required property.

as_python_source(assign_to: str | None = None) str

generate a string of Python code that will re-create the object and all contained objects

Parameters:

assign_to – string. If supplied, must be a legal Python variable name. The generated code will be assigned to this variable in the returned string.

Returns:

single string of formatted python code that if run will re- create self.

NOTE: the returned code string will not include any

necessary imports that may be needed to allow the code to actually execute; the caller is expected to supply that boilerplate.

class hikaru.HikaruDocumentBase
get_status()

Returns a status object, if a call resulted in on

It turns out that for certain resources, a delete() operation will result in K8s returning a sort of odd object: a Status resource, but one whose kind and apiVersion properties indicate it is a different type of message altogether. In these instances, Hikaru would try to instantiate the class identified by the kind/apiVersion attributes, but generally not fail as most of the time the pieces that are missing in the received message are optional on the receiving class. However, this doesn’t always happen, and besides, the lack of visible status hides important information. So the following solution was settled on in order to not break existing code: Hikaru now detects if a Status object is being returned, and if so it creates and instance with the received data and stores it in a private variable. The method returns self as usual, but this new method returns the status object if there is one.

If a status object is returned, it remains held by self until it is explicitly cleared with clear_status()

Returns:

None or a Status object if one was present from the previous call.

clear_status()

Clear out any previously held status.

See the docstring for get_status() to understand when Status objects might be available.

This call clears out any held Status so that subsequent calls that don’t generate Status won’t be confused by the presence of a previously received status. It is the responsibility of the user of the object to determine when Status should be cleared out.

class hikaru.crd.HikaruCRDDocumentMixin

HikaruDocumentBase mixin to add support for CRUD methods

This class provides adjunct capabilities to subclasses of HikaruDocumentBase, specifically for generalized CRUD operations on CRD resources.

Add this class to the list of bases for classes meant to be used as the basis for a custom resource definitions. It will provide:

  • create, read, update, delete methods,

  • context manager capabilities,

  • enable using the CRD class in a Watch

NOTE: this mixin only works properly when used with HikaruDocumentBase as

a sibling base class; it shouldn’t be used with HikaruBase

api_call(method: str, url: str, alt_body: HikaruDocumentBase | None = None, field_manager: str | None = None, field_validation: str | None = None, pretty: bool | None = None, dry_run: str | None = None, async_req: bool = False)

Generalized method for calling into the K8s client API for custom objects

This is the generalized call for K8s custom objects. All the CRD CRUD methods use this method to access the underlying functionality of K8s; all behaviors are specified via the parameters. You probably don’t need to access this directly

Parameters:
  • method – str; HTTP method for the call (GET, POST, PUT, etc)

  • url – str; the path portion of the URL for the resource to operate on. The host portion will be supplied by the underlying library based on the configuration supplied to K8s.

  • alt_body – optional HikaruDocumentBase instance. If supplied, it becomes the body o of the request instead of self which is the default.

  • field_manager – optional str; fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint.

  • field_validation

    optional str; fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields, provided that the ServerSideFieldValidation feature gate is also enabled. Valid values are:

    • Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23 and is the default behavior when the ServerSideFieldValidation feature gate is disabled.

    • Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default when the ServerSideFieldValidation feature gate is enabled.

    • Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered.

  • pretty – optional str; if True then the output is pretty printed.

  • dry_run

    optional str; When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are:

    • All: all dry run stages will be processed.

  • async_req – optional bool; if True, the call is async and the result requires the caller to invoke get() on the returned Response object. Default is False, making the call blocking.

Return Response:

if the call was sync, then Response.obj will contain the result, if async, then you must call Response.get() to get the result.

create(field_manager: str | None = None, field_validation: str | None = None, pretty: bool | None = None, dry_run: str | None = None, async_req: bool = False)

Creates a new instance of the CRD embodied by self.

Results in a call to K8s to create a new instance of the CRD containing the data in ‘self’. This requires first that the CRD has been defined to K8s with a CustomResourceDefinition object (or by some other means such as sending the appropriate YAML into K8s). The instance will be created as long as another instance with the same name/scope doesn’t already exist.

Returns a new instance of the resource with additional data filled by K8s. If an async call is done, then a Response object is returned and the new instance can be acquired by calling .get() on that object.

If this object already exists, and ApiError is raised by the K8s libraries.

Parameters:
  • field_manager – optional str; fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint.

  • field_validation

    optional str; fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields, provided that the ServerSideFieldValidation feature gate is also enabled. Valid values are:

    • Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23 and is the default behavior when the ServerSideFieldValidation feature gate is disabled.

    • Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default when the ServerSideFieldValidation feature gate is enabled.

    • Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered.

  • pretty – optional str; if True then the output is pretty printed.

  • dry_run

    optional str; When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are:

    • All: all dry run stages will be processed.

  • async_req – optional bool; if True, the call is async and the result requires the caller to invoke get() on the returned Response object. Default is False, making the call blocking.

read(field_manager: str | None = None, field_validation: str | None = None, pretty: bool | None = None, dry_run: str | None = None, async_req: bool = False)

Reads an existing K8s CRD resource and retuns a populated object

Sends a read request to K8s for an existing CRD based on the data in self. If it doesn’t exist, the K8s libraries raise an error. If it does it returns a new instance that contains all the details of the resource.

Parameters:
  • field_manager – optional str; fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint.

  • field_validation

    optional str; fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields, provided that the ServerSideFieldValidation feature gate is also enabled. Valid values are:

    • Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23 and is the default behavior when the ServerSideFieldValidation feature gate is disabled.

    • Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default when the ServerSideFieldValidation feature gate is enabled.

    • Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered.

  • pretty – optional str; if True then the output is pretty printed.

  • dry_run – optional str; When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed.

  • async_req – optional bool; if True, the call is async and the result requires the caller to invoke get() on the returned Response object. Default is False, making the call blocking.

update(field_manager: str | None = None, field_validation: str | None = None, pretty: bool | None = None, dry_run: str | None = None, async_req: bool = False)

Updates an existing CRD resource.

Takes the data from self and generates and update message to K8s. The updated instance is returned as a new object. If the instance doesn’t exist, the K8s library raises and ApiError.

NOTE: An update can only be performed on an instance that was “read” first. However, when the update

is sent, if the instance has changed in K8s first, the update will fail with a message that the update isn’t on the latest version of the resource. You will need to read the resource again, re-apply the changes, and then call update() once again..

Parameters:
  • field_manager – optional str; fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint.

  • field_validation

    optional str; fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields, provided that the ServerSideFieldValidation feature gate is also enabled. Valid values are:

    • Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23 and is the default behavior when the ServerSideFieldValidation feature gate is disabled.

    • Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default when the ServerSideFieldValidation feature gate is enabled.

    • Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered.

  • pretty – optional str; if True then the output is pretty printed.

  • dry_run

    optional str; When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are:

    • All: all dry run stages will be processed.

  • async_req – optional bool; if True, the call is async and the result requires the caller to invoke get() on the returned Response object. Default is False, making the call blocking.

delete(grace_period_seconds: int | None = None, orphan_dependents: bool | None = None, preconditions=None, propagation_policy: str | None = None, field_manager: str | None = None, field_validation: str | None = None, pretty: bool | None = None, dry_run: str | None = None, async_req: bool = False)

Delete the resource using the DeleteOptions from the current release.

Parameters:
  • grace_period_seconds – The duration in seconds before the object should be deleted. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period for the specified type will be used. Defaults to a per object value if not specified. zero means delete immediately.

  • orphan_dependents – Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7. Should the dependent objects be orphaned. If true/false, the “orphan” finalizer will be added to/removed from the object’s finalizers list. Either this field or PropagationPolicy may be set, but not both.

  • preconditions – optional Preconditions instances. Must be fulfilled before a deletion is carried out. If not possible, a 409 Conflict status will be returned.

  • propagation_policy

    Whether and how garbage collection will be performed. Either this field or OrphanDependents may be set, but not both. The default policy is decided by the existing finalizer set in the metadata.finalizers and the resource-specific default policy. Acceptable values are:

    • ’Orphan’ - orphan the dependents;

    • ’Background’ - allow the garbage collector to delete the dependents in the background;

    • ’Foreground’ - a cascading policy that deletes all dependents in the foreground.

  • field_manager – optional str; fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint.

  • field_validation

    optional str; fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields, provided that the ServerSideFieldValidation feature gate is also enabled. Valid values are:

    • Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23 and is the default behavior when the ServerSideFieldValidation feature gate is disabled.

    • Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default when the ServerSideFieldValidation feature gate is enabled.

    • Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered.

  • pretty – optional str; if True then the output is pretty printed.

  • dry_run

    optional str; When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are:

    • All: all dry run stages will be processed.

  • async_req – optional bool; if True, the call is async and the result requires the caller to invoke get() on the returned Response object. Default is False, making the call blocking.

Returns:

Depends on the resource. Often it is an instance of the deleted resource, but may also be an instance of the Status object; what is returned is defined by the swagger spec.

Hikaru Application classes

class hikaru.app.Application

Define a collection of Kubernetes objects that are to be deployed together

The Application class provides a way to define a collection of Kubernetes resources that are to be deployed together to implement the infrastructure for a single application system. It provides a means to define the order in which the resources are to be deployed, and to define dependencies between them. It also provides a set of convenience methods to support the automated inspection of the resources contained within the Application to facilitate the implementation of automated inspection processes for compliance, security, inventory control, forecasting, and other management-level activities commonly needed in organizations that have multiple application systems in production.

The Application class not only can deploy the resources it contains, it can also de -deploy them in the reverse order of deployment. This is useful for performing tear-downs after running operations such as CI/CD pipelines, or for performing clean-up after testing. It can also leverage Hikaru’s diffing capabilities to determine what changes may have occurred to the resources since they were deployed, and can change existing resources to match the desired state.

Application objects can survive partial deployments. This means that if a resource fails to deploy, the Application will still contain the resources that were deployed successfully. This allows for the implementation of a retry mechanism for the failed resource, and for the deployment of the remainder of the resources in the Application. This is useful for implementing idempotent deployments.

Application objects can render their contents as JSON or YAML, and can also render the Python source code that would be needed to create the Application object. This allows for the creation of Application objects from JSON or YAML, and for the serialization of Application objects to JSON or YAML.

Application objects can be created from a single Kubernetes resource, or from a collection of Kubernetes resources. They can also be created from a list of Kubernetes resources, or from a directory containing Kubernetes resource files.

They can also be created from a Helm chart. This is done by creating an Application object from the Helm chart, and then calling the Application’s create() method.

Application objects can also be created by interrogating a Kubernetes cluster to discover the resources that are deployed there that are part of a single application. This is done by creating a shell Application object, and then calling its discover() method, providing it a few details about the application. The Application object will then interrogate the cluster to discover the resources that are part of the application, and add them to itself. It will also discover the dependencies between the resources, and will add those to itself as well. The resulting Application object can then be used to deploy the application to another cluster, perform other operations on the application, or render the object into Hikaru source code.

Application objects can also be versioned, and differences between the version can be generated. This provides a worklist that shows what changes need to be made to the application to bring it up to date with the new version. This is useful for automating update procedures on existing applications.

Application objects may contain references to existing application resources, allowing the representation of integration points between applications. This allows for modeling applications that contain resources that must be deployed as well as those that belong to other applications that are used by the application being modeled. This allows for the creation of a complete model of the application landscape of an organization.

To define an Application, the user creates a subclass of the Application class, and uses the same dataclass techniques used in other Hikaru classes to define the resources that comprise the application.

create(dry_run: str | None = None, client: ApiClient | None = None) bool

Create the resources in the Application

This method will deploy the resources in the Application to the Kubernetes cluster

Parameters:
  • dry_run – optional str, default None. May have the value ‘All’ which indicates to perform a dry run on all processing stages for each resources

  • client – optional ApiClient, default None. You can create your ApiClient object which will be used when contacting Kubernetes, or you can have the K8s client library do it for you by specifying the location of a config file with the KUBECONFIG environment variable.

Returns:

bool; True if all resources were deployed successfully, False otherwise

delete(dry_run: str | None = None, client: ApiClient | None = None) bool

Delete the constituent resources of the application

Delete all of the resources from a previously created Application instance. The deletions are done based on name and namespace parameters for each resource. The Application (subclass) instance must either be the one that was used to create the instance or has been re-created from some external store using one of the external loading class methods (from_dict(), from_yaml(), from_json()).

If this call fails mid-way through the set of resources that comprise the Application, it can safely be called again to delete any remaining resources.

NOTE: when the call completes, tools such as kubectl may still list the resource; this due to K8s resources not being deleted immediately in some cases, but their state should be reflected as “Terminating”.

Parameters:
  • dry_run – optional str, default None. May have the value ‘All’ which indicates to perform a dry run on all processing stages for each resources

  • client – optional ApiClient, default None. You can create your ApiClient object which will be used when contacting Kubernetes, or you can have the K8s client library do it for you by specifying the location of a config file with the KUBECONFIG environment variable.

Returns:

True if the update ran successfully, False otherwise

diff(other) Dict[str, List[DiffDetail]]

Compare this application instance to another

This method compares the resources in this Application instance to those of the supplied instance and returns a report of the differences. The report is a dictionary keyed by the attribute name of the resource in the Application instance. The value is a list of DiffDetail objects, each of which contains the class of the object where the difference was found, the name of the attribute that was different, the kind of difference, some explanatory text, and other supporting data depending on the kind of difference.

It is possible to receive some superfluous differences when comparing a new Application instance and one read from the cluster. This is because the read instance will have some fields that are not present in the new instance, such as the resource version. These differences can be ignored by the caller.

Parameters:

other – an instance of the same Application subclass as this instance

Raises:

TypeError if other is not an instance of the same Application subclass as this instance

dup() Application

Duplicate this Application instance

This method returns a new Application instance that is a duplicate of this instance. The duplicate will have the same values for all attributes as this instance, but will not be the same object. This is useful if you want to create a new Application instance that is a copy of this one, but you want to modify the new instance without affecting this instance.

Given that Applications are dataclasses and custom attributes may be added by implementing the __post_init__() method on a subclass, dup() will only work on the attributes defined as part of the dataclass, not any additional attributes added into a subclass’s __post_init__() method.

To allow for such attributes to be copied, subclasses should provide their own dup() method that calls super().dup() and then copies the additional attributes.

Note: for any dataclass field that is a subclass of HikaruBase (which includes HikaruDocumentBase), the method will use that object’s dup() method to create a duplicate of that field.

Returns:

a new Application instance that is a duplicate of this instance

find_by_name(name: str, following: str | List | None = None) List[CatalogEntry]

Returns a list of catalog entries for the named field wherever it occurs in the Application’s resources.

This is a convenience method that uses the method of the same name from HikaruBase on each of the components of the application object. The returned CatalogEntry objects have a path that includes the name of the attribute in the Application where the item can be found.

See the doc for HikaruBase.find_by_name for complete documentation.

Parameters:
  • name – string containing a name for an attribute somewhere in the model, the search for with starts at ‘self’. This must be a legal Python identifier, not an integer.

  • following – optional sequence of strings or a single string with ‘.’ separators that names path under which search for name should be conducted. See the doc for HikaruBase.find_by_name() for further details.

Returns:

list of CatalogEntry objects that match the query criteria.

Raises:
  • TypeError – if ‘name’ is not a string, or if ‘following’ is not a string or list

  • ValueError – if ‘following’ is a list and one of the elements is not a str or an int

find_uses_of_class(cls: type) List[HikaruDocumentBase]

Search through the app and find all uses of the specified class (or its subclasses)

This method searches through the app’s resources and returns any that are of the specified type (or its subclasses). Searches only work on top-level classes that are subclasses of HikaruDocumentBase; that is, you can search for Pod but not PodSpec.

Parameters:

cls – the class to search for. Must be a subclass of HikaruDocumentSpec

classmethod from_dict(d: dict, target_cls: type | None = None) Application

Create an Application instance from a dict that was previously saved

This class method takes a dict that was previously created by to_dict() and recreates the Application instance that was used to create it. It is able to create an instance of the proper subclass of Application, provided that the package/module are on the PYTHONPATH.

Parameters:
  • d – the dict to recreate the Application instance from. must have been created by a previous call to to_dict().

  • target_cls – optional type, default None. If not None, then the dict is assumed to be of the type specified by target_cls. This allows the class to not be on the PYTHONPATH since the user has provided it (though it probably is). If None, then the class to instatiate will be read from the dict

classmethod from_json(s: str, target_cls: type | None = None) Application

Create an Application instance from a JSON string that was previously saved

This class method takes a JSON string that was previously created by get_json() and recreates the Application instance that was used to create it. It is able to create an instance of the proper subclass of Application, provided that the package/module are on the PYTHONPATH.

Parameters:
  • s – the JSON string to recreate the Application instance from. must have been created by a previous call to get_json().

  • target_cls – optional type, default None. If not None, then the dict is assumed to be of the type specified by target_cls. This allows the class to not be on the PYTHONPATH since the user has provided it (though it probably is). If None, then the class to instatiate will be read from the dict.

classmethod from_yaml(path: str | None = None, stream: TextIO | None = None, yaml: str | None = None, release: str | None = None) Application

Create an Application subclass instance from a YAML string that was previously saved from get_yaml

This class method takes a YAML string that was previously created by get_yaml() and recreates the Application instance that was used to create it. It is able to create an instance of the proper subclass of Application, provided that the package/module are on the PYTHONPATH.

This is expecting a YAML source with a single application document in it. If there are more than one then only the first one will be processed and have an object recreated for it.

The caller must supply one of the path, stream, or yaml arguments, as these are the source of the YAML that will be processed.

Parameters:
  • path – str, optional. If supplied, this is the path to a file containing YAML previously saved with a call to get_yaml().

  • stream – TextIO, optional. If supplied, this is an open file-like object that contains the YAML that is to be processed. The YAML must have been previously saved with a call to get_yaml().

  • yaml – str, optional. If supplied, this is a YAML string to process. The YAML must have been previously saved with a call to get_yaml().

  • release – str, optional. If supplied, this is the release to use when creating the instance. This must be of the form of the name of a model release package such as ‘rel_1_24’. If not supplied, then the default release for this thread will be used.

get_clean_dict() dict

Convert this Application instance to a dict that can then be saved externally

This method takes an Application subclass instance and converts it to a dict in a common format that can be saved to disk and read later to re-create the object.

classmethod get_empty_instance() Application

Return an empty instance of this Application subclass

This method returns an empty instance of this Application subclass. This is useful for understanding the basic struction of an Application and all of its constituent resources. The method relies on each resource’s get_empty_instance() method to return an empty instance of that resource, and then creates an instance of the class with those empty instances as its attributes.

get_empty_instance() in a resource only populate the attributes that are required for the resource to be created. Hence, most of the content of an empty instance will be None, empty lists, dicts, etc.

If a subclass adds additional fields using annotations the class level, get_empty_instance() will attempt to populate those fields with empty instances of the appropriate type. If a

get_json() str

Convert this Application instance to a JSON string that can then be saved externally

This method takes an Application subclass instance and converts it to a JSON string in a common format that can be saved to disk and read later to re-create the object.

get_type_warnings() Dict[str, List[TypeWarning]]

Get all the type warnings for this app and its resources

This method checks the types of all the fields in the app and its resources and returns a list any type mismatches it finds. The list will be empty if there are no type mismatches.

get_yaml() str

Convert this Application instance to a YAML string that can then be saved externally

merge(other: Application, overwrite: bool | None = False, enforce_version: bool | None = False) Application

Merge the data from the supplied Application instance into this instance

This method merges the data from the supplied application instance into self. This is a ‘deep’ merge– each constituent resource in other is merged with the corresponding resource in self. If there is no corresponding resource in self, then the resource from other is added to self, that is, if it is defined on self’s dataclass. Additionally, other must be an instance of the same class as self.

TypeError is raised in any case where the types of the two objects don’t align properly.

When merging data in subclasses of Application, this method only handles the attributes that are defined for the dataclass. Only attributes of HikaruDocumentBase are merged; any other value is the responsibility of the subclass to merge properly, as hikaru_app isn’t able to determine in all cases what a ‘proper’ merge looks like.

If a subclass adds additional attributes using the __post_init__() method, then the subclass should provide its own merge() method which should call super().merge() and then merge the additional attributes the subclass defines.

merge() will NEVER overwrite an instance_id in self with a different value, even if overwrite is True. merge() will pull the instance_id from other and use that if the instance_id in self is None.

The method returns self, so it can be chained with other methods.

Parameters:
  • other – the Application instance to merge into self

  • overwrite – optional bool, default False. The default only merges in attributes from other that are non-None. Hence, None attributes in other will never replace actual values in self. If True, then all data is taken from other verbatim, which can result in a loss of attribute values in self.

  • enforce_version – optional bool, default False. The default simply checks to see if self and other have the same class names rather than the same actual class. This allows for merging data from objects from one version of Kubernetes to another. If enforce_version is True, then merge() will check to see both self and other are from the same class. If either of these versions of type checking don’t match, then merge will raise a TypeError. This is actually enforced at the resource level.

Raises:

TypeError – if other has an attribute to merge into self that self doesn’t know about, or if checking that the ‘type’ of self and other, or any of their components, results in them not being merge-able.

Returns:

self with values for other merged in

object_at_path(path: list)

returns the value named by path starting at self

Returns an object or base value by navigating the supplied path starting at ‘self’. The elements of path are either strings representing attribute names or else integers in the case where an attribute name reaches a list (the int is used as an index into the list). Generally, the thing to do is to use the ‘path’ attribute of a returned CatalogEntry from find_by_name()

Parameters:

path – A list of strings or ints. :return: Whatever value is found at the end of the path; this could be another HikaruBase instance or a plain Python object (str, bool, dict, etc).

Raises:
  • RuntimeError – raised if path[0] is None but there are more elements

  • IndexError – raised if a path index value is beyond the end of a list-valued attribute

  • ValueError – if an index for a list can’t be turned into an int

  • AttributeError – raised if any attribute on the path isn’t an attribute of the previous object on the path

Returns:

a

classmethod read(instance_id: str, client: ApiClient | None = None)

Read the contents of an app instance from K8s based on the instance id

This method returns an instance of an Application subclass based on the instance id of the app. It does this by listing all the existing resources of the app by type that have an instance label whose value matches the supplied instance_id. Further, it can only populate attributes in the class that have an annotation that identifies which attribute from the Application model the resource is from. This is most easily done by querying apps that were created with hikaru-app in the first place, as it ensures that this metadata is put on each resource, but existing resources can be noted manually by setting the following values on these metadata k/v collections:

hikaru_app.get_app_instance_label_key() in metadata.labels: This key is for a value that is shared by all resources that are in the same app instance within a cluster (so should be unique for an app instance in a cluster). So the return value of the function is the key where the value should be stored in metadata.labels for all resources in the same instance of an app.

hikaru_app.get_app_rsrc_attr_annotation_key() in metadata.annotations: The above function returns a key that must appear in a resource’s metadata.annotations k/v store; the value of the key is the name of the attribute on the Application subclass where the resource is defined. For example, if an Application subclass has a class attribute “ns: Namespace”, then the corresponding Namespace resource must have a metadata.annotations with the key returned by get_app_rsrc_attr_annotation_key() and a value of ‘ns’.

LIMITATIONS:

  • Since hikaru-app only models first-order resources, Kubernetes-managed resources derived from the first-order ones will not be part of what’s read. So for example, if an Application subclass contains a Deployment, reading an instance of this Application will only yield the Deployment, not the Pods that Kubernetes may have spun up based on the rules in the deployment.

  • CRDs currently are not supported, so if you use CRDs within your application there’s no way to read them back with this method.

param instance_id:

str; the string value of the application instance’s id; this will be used to locate only resources that are part of the app instance

param client:

optional ApiClient object; used to identify the client to use to contact the cluster. Can be supplied via other usual means, such as telling K8s the location of a config file with credentials.

set_reporter(reporter: Reporter)
update(dry_run: str | None = None, client: ApiClient | None = None) bool

Update all resources in the Application instance

This method iterates over all resources in the Application and invokes ‘update()’ on each. It updates all resources, making no attempt to only update resources that have changed.

Parameters:
  • dry_run – optional str, default None. May have the value ‘All’ which indicates to perform a dry run on all processing stages for each resources

  • client – optional ApiClient, default None. You can create your ApiClient object which will be used when contacting Kubernetes, or you can have the K8s client library do it for you by specifying the location of a config file with the KUBECONFIG environment variable.

Returns:

True if the update ran successfully, False otherwise

class hikaru.app.Reporter(*args, **kwargs)

Reporters are objects that Applications can report progress to during operations

A Reporter is an object that can be used to report progress during the execution of long operations on an Application. It is used to provide feedback to the user about what is happening during the operation, and to provide a means to cancel the operation if desired. It is also used to provide a means to report errors that occur during the operation.

The Reporter class is an abstract base class that defines the interface that concrete Reporter classes must implement. It also provides a default implementation of the interface that can be used as a base class for concrete Reporter classes.

The Reporter class is not intended to be instantiated directly. Instead, it is intended to be used as a base class for concrete Reporter classes that implement the interface defined by the Reporter class.

Users create Reporter derived class instances and pass them to an Application subclass prior to operations such as create(), delete(), and update(). During the execution of these operations, the Application will call the Reporter’s methods to report progress and errors.

advise_plan(app: Application, app_action: str, tranches: List[List[FieldInfo]]) bool | None

Tells the reporter the work to be performed in create or delete CRUD operations

This advisory method is called by the Application instance when a CRUD create or delete is executed on an Application. It is meant to give a Reporter instance early notice (and right of refusal) for a set of work to perform for these operations.

The method is called after the order of work has been determined but before any work starts. It is passed a list of lists (tranches) of FieldInfo objects that identifies the HikaruDocumentBase subclasses that will be involved in the operation, and in what order the work will be carried out. Each inner list contains resources that can be actioned simultaneously, and the outer list sequences the processing of each inner list. So for a value of tranches like:

[ [a], [b, c, d], [e, f] ]

The Application object will first action ‘a’, then ‘b’, ‘c’, and ‘d’ in parallel, and then when all of those are done will then action ‘e’ and ‘f’ in parallel.

If the implementation of advise_plan() returns False, then processing of the CRUD operation is aborted. This provides a means to allow inspection of the plan and to veto its execution. If you run into cases where Hikaru computes an incorrect plan please file a bug report.

Parameters:
  • app – Application; the Application subclass instance the plan is for

  • app_action – str; the type of operation to be performed (create, delete)

  • tranches – list of lists of FieldInfo objects; this is the work that is to be performed and in what order. The outer list sequences the work, and each HikaruDocumentBase resource in an inner list may be processed at the same time. FieldInfo objects describe key details of a field on a dataclass but can also optionally include a reference to the actual instance of the object the field describes. Hence, this method should look at the ‘instance’ attribute of the FieldInfo object for the actual object that will be actioned in the operation. NOTE: the value of ‘instance’ may be None if the field was optional in the dataclass.

Returns:

optional bool. If False, then processing the provided plan is aborted. Any other value allows processing to proceed. Returning None is fine; this will allow processing to continue.

report(app: Application, app_action: str, event_type: str, timestamp: str, attribute_name: str, resource: HikaruDocumentBase, additional_details: dict)

Report an event to the Reporter

This method is called by an Application to report an event to the Reporter. The event_type parameter specifies the type of event being reported, and the event parameter contains the details of the event.

This method is intended to be overridden by concrete Reporter classes.

Parameters:
  • app – the Application instance reporting to this Reporter. This allows multiple Applications to use the same Reporter.

  • app_action – str; identifies what action is being taken on the app: create, read, update, or delete

  • event_type – str; the type of event being reported

  • timestamp – str; a datetime string in ISO 8601 format of when the application generated the event; this may be different from when the Reporter deals with the event

  • attribute_name – str; the name of the attribute from the Application object that this event is for

  • resource – HikaruDocumentBase; the resource that the event is for

  • additional_details

    dict; different for each event type, but not absolutely needed to understand the event. Possible keys/values:

    ’error’: str

    used for RSRC_ERROR

    ’index’: int

    used when the resource is an element of a list; index of the resource being reported on

    ’key’: str

    used when the resource is a value in a dict of resources; string value of the key of the resource

    ’app-operation’: str

    used when the event is for an application operation; one of ‘create’, ‘read’, ‘update’, ‘delete’

    ’manifest’: list of (str, HikaruDocumentBase) tuples

    list of all resources to process; present with APP_START_PROCESSING events

should_abort(app: Application) bool

Returns True if the Application should stop processing resources :return: bool; True if the Application should stop resource processing, False to keep going

class hikaru.app.FieldInfo(name: str, ftype: type, has_default: bool, default: Any | None = None, default_factory: Callable | None = None)

Class used to hold flattened out type info for a dataclass field

Instances of this class are used both internally by Hikaru and are also passed to a user via the Reporter (if one is supplied) to inform them of various activities the Application object is conducting on their behalf.

class hikaru.meta.FieldMetadata(description: str | None = None, enum: List[Any] | None = None, format: str | None = None, minimum: int | float | None = None, exclusive_minimum: bool | None = None, maximum: int | float | None = None, exclusive_maximum: bool | None = None, pattern: str | None = None, multiple_of: int | float | None = None, min_items: int | None = None, max_items: int | None = None, unique_items: bool | None = None, **kwargs)
__init__(description: str | None = None, enum: List[Any] | None = None, format: str | None = None, minimum: int | float | None = None, exclusive_minimum: bool | None = None, maximum: int | float | None = None, exclusive_maximum: bool | None = None, pattern: str | None = None, multiple_of: int | float | None = None, min_items: int | None = None, max_items: int | None = None, unique_items: bool | None = None, **kwargs)

Create a new FieldMetadata object

Creates a new instance that can be provided as the value of the metadata argument to dataclasses.field()

Parameters:
  • description – optional string; if provided, will be established as the description modifier for the field

  • enum – optional list of any type; if provided, will establish the list of valid values for the property. The user should make sure that the type of the values in the enum match the type of the field; Hikaru does no checking in this regard (but the K8s back end probably will).

  • format – optional string; allowed format for the supplied value. Available formats are dependent on the property’s data type. Consult the JSON Schema spec for details.

  • minimum – optional int or float; the minimum value that the property is allowed to assume.

  • exclusive_minimum – optional bool; whether the minimum includes or excludes the minimum itself. If True, the property’s value must be > minimum, if False it may be >= the minimum. It makes no sense to supply this without also specifying the minimum.

  • maximum – optional int or float; the maximum value that the property is allowed to assume.

  • exclusive_maximum – optional bool; whether the maximum includes or excludes the maximum itself. If True, the property’s value must be < maximum, and if False it may be <= maximum. It makes no sense to supply this without also specifying the maximum.

  • pattern – optional string; a regular expression in JSON notation that describes the accepted strings for the property (which must be type string). Usually best specified with a raw string to avoid regex escapes.

  • multiple_of – optional float or int; specifies that the property value must be evenly divisible by the value of this parameter. The type of value should match the type of the property.

  • min_items – optional int; for array parameters, indicates the minimum number of elements that the array must have.

  • max_items – optional int; for array parameters, indicates the maximum number of elements that the array must have.

  • unique_items – optional bool; for array parameters, True indicates that each array element must have a unique value.

class hikaru.Response(k8s_response, codes_with_objects)

Response bundles up the possible responses that can be generated by K8s calls

All Hikaru methods and functions return Response objects, which Hikaru fills out upon receiving a response from the underlying K8s method calls. K8s may return one of two kinds of values: for blocking calls, K8s returns the response code, data object, and headers. For async calls, K8s returns the thread that is processing the call. Hikaru’s Response objects cover both of these possibilities.

Public attributes can be interpreted as follows:

If the call is blocking:

  • code: integer response code from K8s

  • obj: the data returned for the call. May be plain data, or may be an instance of a HikaruDocumentBase subclass, depending on the call.

  • headers: a dict-like object of the response headers

If the call is non-blocking:

  • code, obj, headers: all None UNTIL .get() is called on the Response

    instance, at which point all three are populated as above as well as .get() returning a 3-tuple of (object, code, headers)

Response objects also act as a proxy for the underlying multiprocessing thread object (multiprocessing.pool.ApplyResult) and will forward on the other public methods of that class.

If .get() or any of the other async supporting calls are made on a Response object that was called blocking then they will all return None.

get(timeout=None) tuple

Fetch the results of an async call into K8s.

This method waits for a response to a previously submitted request, either for a specified amount of time or indefinitely, and either raises an exception or returns the delivered response.

Parameters:

timeout – optional float; if supplied, only waits ‘timeout’ seconds for a response until it raises a TimeoutError exception if the response hasn’t arrived. If not supplied, blocks indefinitely.

Returns:

a 3-tuple of (Hikaru object, result code (int), headers). These values are also stored in the public attributes of the instance, so you don’t actually have to capture them upon return if you don’t wish to.

Raises:
  • TimeoutError – if a response has not arrived before the specified timeout has elapsed.

  • RuntimeError – if the reply is the wrong type altogether (should be reported).

May also pass through any other exception.

Hikaru Watchers

class hikaru.watch.WatchEvent(etype: str, obj: HikaruDocumentBase)

Delivery wrapper for an event on a resource received from K8s

Instances of this class are what are yielded from the stream() generator on both Watcher and MultiplexingWatcher. Instances are internally generated by Hikaru’s watch system.

‘etype’ is the type of event, and will be one of ‘ADDED’, ‘MODIFIED’ or ‘DELETED’

‘obj’ is an instance of a HikaruDocumentBase subclass which is instantiated from

event data received from K8s. Besides testing the type of this object, you can also look to obj.kind for a text representation of the ‘kind’ of object the event involves.

In the case of etype MODIFIED, you can use the diff() method to compare the event’s version with a previous version, revealing what has changed.

class hikaru.watch.Watcher(cls: type, namespace: str | None = None, allow_watch_bookmarks: bool | None = None, field_selector: str | None = None, label_selector: str | None = None, resource_version: str | int | None = None, timeout_seconds: int | None = 1, client: ApiClient | None = None, should_translate: bool | None = None)

Provides the basic machinery to watch for events on a K8s resource (kind)

This is the core class used to create objects that can stream events on a single type of K8s resource. It ultimately provides a generator that yields a series of WatchEvent objects for each event received from Kubernetes.

__init__(cls: type, namespace: str | None = None, allow_watch_bookmarks: bool | None = None, field_selector: str | None = None, label_selector: str | None = None, resource_version: str | int | None = None, timeout_seconds: int | None = 1, client: ApiClient | None = None, should_translate: bool | None = None)

Create a watch object for the specified class.

Defines the configuration to use for setting up a watch against a particular kind of K8s resource. After configuration, watching can be initiated by calling the ‘stream()’ method.

NOTE:

The arguments here are largely interpreted according to the ‘list’ operations in the K8s API, with the exception of some additional semantics added by Hikaru; these are noted where appropriate. Not all arguments from those functions are carried through here as some make no sense in the context of a watch.

Parameters:
  • cls – A watchable HikaruDocumentBase subclass (NOT instance). This may be either the class that will be watched and outputted, such as Pod, or the ‘listing’ class for this kind of item, such as PodList. In either case, the listing resource will NOT be returned from stream() (hence, no PodList will ever be in an event), only the listed resource (like Pod).

  • namespace – optional string; namespace for the resource. If not specified, then all resources across all namespaces will be watched and returned from the stream() method. If specified, only resources from the specified namespace will be returned from stream(). NOTE: not all resources support namespaced watches; a TypeError is raised if there is no namespaced support for cls but a namespace value is provided.

  • allow_watch_bookmarks – allowWatch Bookmarks requests watch events with type “BOOKMARK”. Servers that do not implement bookmarks may ignore this flag and bookmarks are sent at the server’s discretion. Clients should not assume bookmarks are returned at any specific interval, nor may they assume the server will send any BOOKMARK event during a session. If this is not a watch, this field is ignored. If the feature gate WatchBookmarks is not enabled in apiserver, this field is ignored.

  • field_selector – A selector to restrict the list of returned objects by their fields. Defaults to everything.

  • label_selector – A selector to restrict the list of returned objects by their labels. Defaults to everything.

  • resource_version – When specified with a watch call, shows changes that occur after that particular version of a resource. Defaults to changes from the beginning of history. When specified for list: - if unset, then the result is returned from remote storage based on quorum-read flag; - if it’s 0, then we simply return what we currently have in cache, no guarantee; - if set to non zero, then the result is at least as fresh as given rv. Hikaru addition you can allow Hikaru to find the oldest available resource_version when you initiate the stream(), but keep in mind that this can result in a fairly long stream of events that may have already been delivered. The the doc for the stream() method for more details.

  • timeout_seconds – Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity. Hikaru additions The stream() method of Watcher normally ignores a timeout of the underlying code and only stops streaming if the Watcher’s stop() method has been invoked. However, Watchers default this value to 1 second in order to allow the underlying code to return and give the Watcher a chance to see if it should quit. This allows for clean exits of the stream with a minimal delay. You may want to adjust this value upwards if you anticipate a large number of Watchers in your system. Setting this to zero will make the underlying call block indefinitely.

  • client – optional; instance of kubernetes.client.api_client.ApiClient

Raises:

TypeError – if the supplied cls parameter doesn’t support the requested type of watch, namespaced or unnamespaced

update_resource_version(new_resource_version: str | int)

Update the value of resource_version to use when initiating a stream

This will only take effect the next time the stream() method is invoked.

Parameters:

new_resource_version – int or numeric string containing a version number; only version after this version will be streamed.

current_resource_version() str

get the current resource version value for stream inintiation

Returns:

string resource version, but can be None if this is a new Watcher, streaming hasn’t begun, and the user didn’t request that the Watcher manage the revision version number.

stop()

Stops the current Watcher and underlying watch mechanism

Stopping will occur as soon as the Watcher itself regains control; if awaiting on the arrival of an event, the streaming operation won’t stop until an event arrives.

stream(manage_resource_version: bool = False, quit_on_timeout: bool = False) Generator[WatchEvent, None, None]

Initiate an event streaming generator that yields WatchEvent objects.

Start yielding a stream of WatchEvents as events are received from K8s. You can use this in a for loop like so:

for we in watcher.stream():
    # do stuff

Iteration will only stop if:

  • There is an uncaught exception in the underlying K8s system

  • There was a timeout in the underlying K8s system and quit_on_timeout is True

  • You invoke the stop() method on the Watcher instance.

Parameters:
  • manage_resource_version – defaults to False. If True, then the Watcher instance will track the highest resource_version observed in the event stream in case the underlying watch is to be used again. This is generally a good idea if you timeout value is 0 or None (no timeout), as it will ensure that subsequent internal calls to the underlying watch mechanism will only ask for events that come after the highest observed version number. It also will start up where you left off if the Watcher has been stopped and re- started. NOTE if you don’t supply an initial resource_version value, then this option will also query K8s for the oldest available resource version and ask for the event stream to start after that point. This is handy as you don’t need to track the resource_version yourself, but can result in a replay of a larger number of events that have previously been seen. You may want this, but you should be aware that this is possible.

  • quit_on_timeout – defaults to False. If True, then when the underlying K8s code times out the generator stops. The default behaviour is for the generator to restart the underlying watch machinery.

Returns:

A generator that will yield WatchEvent instances.

class hikaru.watch.MultiplexingWatcher(exception_callback=None)

A container of Watchers that yields a single stream of events from all Watchers

This class provides an interface similar to Watcher, but allows you to weave together streams from multiple Watchers into a single event stream.

__init__(exception_callback=None)

Create a new MultiplexingWatcher

Parameters:

exception_callback

optional callable. If one of the contained watchers raises an exception and this callable has been provided, then the callable will be called as follows:

exception_callback(mux, watcher, exception)

Where mux is the MultiplexingWatcher instance, watcher is the Watcher that raised the exception, and exception is the Exception object that was raised. The callback can perform whatever action it wishes on mux or watcher based on the information in exception (generally an instance of kubernetes.client.ApiException). The return value from callback will determine how the MultiplexingWatcher will proceed with this watcher. If the value True is returned, the exception is ignored and the watching function is re-started. Any other value will silently cease processing events for this Watcher. If an exception is raised within the callback, this is treated as a non-True return value.

add_watcher(watcher: Watcher)

Add a new Watcher to the set already managed.

You can call this method at any time, even during streaming, however the old watcher may still emit some events before it knows to stop.

NOTE: you can only have a single watcher for one type of resource; for example if you create two Watchers that specify Pod for the cls argument and then call add_watcher() with each in turn, only the second instance will be watched.

Parameters:

watcher – A Watcher instance.

del_watcher(watcher: Watcher)

Delete a watcher

Parameters:

watcher – The watcher to delete.

stop()

Stop the multiplexor and all contained Watchers

stream(manage_resource_version: bool = False, quit_on_timeout: bool = False) Generator[WatchEvent, None, None]

Initiate streaming of events from all contained Watchers

Returns a generator that emits a stream of WatchEvent objects from all contained Watcher objects.

You can use this in a for loop like so:

mux = MultiplexingWatcher()
mux.add_watcher(Watcher(Pod, timeout_seconds=1))
mux.add_watcher(Watcher(Namespace, timeout_seconds=1))
for we in mux.stream():
    # do stuff

Generation will only stop if:

  • There was a timeout in the underlying K8s system and quit_on_timeout is True

  • You invoke the stop() method on the MultiplexingWatcher instance.

Parameters:
  • manage_resource_version – defaults to False. Simply passed through to all contained Watcher instances. See the doc for Watcher.stream() for details on this argument.

  • quit_on_timeout – defaults to False. Simply passed through to all contained Watcher instances. See the doc for Watcher.stream() for details on this argument.

Returns:

A generator that will yield WatchEvent instances from all contained Watchers.

Hikaru functions

hikaru.from_dict(adict: dict, cls: type | None = None, translate: bool | None = False) HikaruBase

Create Hikaru objects from a get_clean_dict() dict

This function can re-create a hierarchy of HikaruBase objects from a dict that was created with get_clean_dict().

If the dict was created from a full Kubernetes document object, such as Pod or Deployment, only the dict argument is required.

If the dict was created from an arbitrary HikaruBase subclass, this function needs to know what kind of thing it is loading; in this case, you must provide the cls parameter so that Hikaru knows what kind of instance you wish to create.

Parameters:
  • adict – a Python dict that was previously created with get_clean_dict()

  • cls – optional; a HikaruBase subclass (not the string name of the class). This should match the kind of object that was dumped into the dict.

  • translate – optional bool, default False. If True, then all attributes that are fetched from the dict are first run through camel_to_pep8 to use the underscore-embedded versions of the attribute names.

Returns:

an instance of a HikaruBase subclass with all attributes and contained objects recreated.

Raises:
  • RuntimeError – if no cls was specified and Hikaru was unable to determine what class to make from the data

  • TypeError – if adict isn’t actually a dict, or if cls isn’t a subclass (not an instance) of HikaruBase

  • ValueError – if no class can be located for the ‘kind’ and ‘apiVersion’ values in the supplied dict.

hikaru.from_json(json_data: str, cls: type | None = None) HikaruBase

Create Hikaru objects from a string of JSON from get_json()

This function can re-create a hierachy of HikaruBase objects from a string of JSON previous returned by a call to get_json().

If the JSON was created from a full Kubernetes document object, such as Pod or Deployment, only the json_data argument is required.

If the JSON was created from an arbitrary HikaruBase subclass, this function needs to know what kind of thing it is loading; in this case, you must provide the cls parameter so that Hikaru knows what kind of instance you wish to create.

Parameters:
  • json_data – string; the value previously returned by get_json() on some HikaruBase subclass instance.

  • cls – optional; a HikaruBase subclass (not the string name of the class). This should match the kind of object that was dumped into the dict.

Returns:

an instance of a HikaruBase subclass with all attributes and contained objects recreated.

hikaru.get_clean_dict(obj: HikaruBase) dict

Turns an instance of a HikaruBase into a dict without values of None

This function returns a Python dict object that represents the hierarchy of objects starting at obj and recusing into any nested objects. The returned dict does not include any key/value pairs where the value of the key is None or empty.

If you wish to instead have a dict with all key/value pairs even when there is no useful value then you should use the dataclasses module’s asdict() function on obj.

Parameters:

obj – some api_version_group of subclass of HikaruBase

Returns:

a dict representation of the obj instance, but if any value in the dict was originally None, that key:value is removed from the returned dict, hence it is a minimal representation

Raises:

TypeError – if the supplied obj is not a HikaruBase (dataclass), or if obj is not an instance of a HikaruBase subclass

hikaru.get_json(obj: HikaruBase) str

Creates a JSON representation of a HikaruBase model

NOTE: current there is no way to go from JSON back to YAML or Python. This

function is must useful for storing a model’s representation in a document database.

Parameters:

obj – instance of a HikaruBase model

Returns:

string containing JSON that represents the information in the model

Raises:

TypeError – if obj is not an instance of a HikaruBase subclass

hikaru.get_processors(path: str | None = None, stream: TextIO | None = None, yaml: str | None = None) List[dict]

Takes a path, stream, or string for a YAML file and returns a list of processors.

This function can accept a number of different parameters that can provide the contents of a YAML file; from this, a YAML parser is created and a processed list of YAML dicts is created and returned. The main use case for this function is to provide input to the from_yaml() method of a HikaruBase subclass.

Only one of path, stream or yaml should be supplied. If yaml is supplied in addition to path or stream, only the yaml parameter is used. If stream and path are supplied, then only stream is used.

Parameters:
  • path – string; path to a Kubernetes YAML file containing one or more docs

  • stream – file-like object; opened on a Kubernetes YAML file containing one or more documents

  • yaml – string; contains Kubernetes YAML, one or more documents

Returns:

List of dicts (or dictionary-like objects) that contain the parsed- out content of the input YAML files.

Raises:

RuntimeError – if none of path, stream or yaml are provided.

hikaru.get_python_source(obj: HikaruBase, assign_to: str | None = None, style: str | None = None) str

returns Python source that will re-create the supplied object

NOTE: this function can be slow, as formatting the code to be PEP8 compliant can take some time for complex code.

Parameters:
  • obj – an instance of HikaruBase

  • assign_to – if supplied, must be a legal Python identifier name, as the returned expression will be assigned to that as a variable.

  • style – optional string, default None, may also be one of ‘black’ or ‘autopep8’. This argument indicates what code formatter, if any, to apply. The default value of None says not to format the code; this will return syntactically correct Python, but it will be an eyesore. However, if you just plan to dynamically execute it how it looks may be of no consequence. The other two formatters return PEP8-compliant formatted Python based on different formatting ‘opinions’. The ‘black’ style produces somewhat more vertically spread-out code that is a bit clearer to read. The ‘autopep8’ formatter is a bit more aggressive in putting more arguments on a single line, so it’s a bit more compact, but can be a little harder to see what’s going on. The ‘black’ formatter is a bit faster than ‘autopep8’, and no formatting is the fastest.

Returns:

Python source code that will re-create the supplied object

Raises:
  • RuntimeError – if an unrecognized style is supplied

  • ImportError – if the hikaru-codegen package hasn’t been installed and the selected code formatter can’t be imported. NOTE: hikaru-codegen ensures that a compatible version# of the formatter is installed, but you can install either black or autopep8 yourself and risk incompatibility.

hikaru.get_yaml(obj: HikaruBase) str

Creates a YAML representation of a HikaruBase model

Parameters:

obj – instance of some HikaruBase subclass

Returns:

big ol’ string of YAML that represents the model

Raises:

TypeError – if the supplied obj is not an instance of a HikaruBase subclass

hikaru.load_full_yaml(path: str | None = None, stream: TextIO | None = None, yaml: str | None = None, release: str | None = None, translate: bool = False) List[HikaruDocumentBase]

Parse/process the indicated Kubernetes yaml file and return a list of Hikaru objects

This function takes one of the supplied sources of Kubernetes YAML, parses it into separate YAML documents, and then processes those into a list of Hikaru objects, one per document.

NOTE: this function only works on complete Kubernetes message documents, and relies on the presence of both ‘apiVersion’ and ‘kind’ being in the top-level object. Other Kubernetes objects represented in ruamel.yaml can be parsed using either the appropriate class’s from_yaml() class method, or from an instance’s process() method, both of which can only accept a ruamel.yaml instance to process.

Only one of path, stream or yaml should be supplied. If yaml is supplied in addition to path or stream, only the yaml parameter is used. If stream and path are supplied, then only stream is used.

Parameters:
  • path – string; path to a yaml file that will be opened, read, and processed

  • stream – return of the open() function, or any file-like (TextIO) object

  • yaml – string; the actual YAML to process

  • release – optional string; if supplied, indicates which release to load classes from. Must be one of the subpackage of hikaru.model, such as rel_1_16 or rel_unversioned. If unspecified, the release specified from hikaru.naming.set_default_release() is used; if that hasn’t been called, then the default from when hikaru was built will be used. NOTE: rel_unversioned is for pre-release models from the github repo of the K8s Python client; use appropriately.

  • translate – option bool, default False. Generally not needed by users of Hikaru, it instructs whether or not camel case identifiers should be turned into PEP8 identifiers (this only happens when True). If you’re doing some odd tests and getting complaints that PEP8-style attributes are missing, you might want to set this to True.

Returns:

list of HikaruDocumentBase subclasses, one for each document in the YAML file

Raises:

RuntimeError – if one of the documents in the input YAML has an unrecognized api_version/kind pair; Hikaru can’t determine what class to instantiate, or if none of the YAML input sources have been specified.

hikaru.process_api_version(api_version: str) Tuple[str, str]

Takes the value of an apiVersion property and returns group and version

Parameters:

api_version – the value of a apiVersion property

Returns:

tuple of two strings: published object group, version. If the group is unspecified it defaults to ‘core’

Raises:

TypeError – if api_version isn’t a string

hikaru.get_default_release() str | None

Returns the currently set default release to use when loading YAML/JSON

Returns:

string; the value of the default release for the current thread. If unknown, the current global default release is returned, whatever the value (possibly None).

hikaru.set_default_release(relname: str)

Sets the default release for the current thread.

NOTE: it is assumed that setting a default release indicates the intent to

create objects from within that release. In anticipation of that, the base module of the release is imported as part of this call.

Parameters:

relname – string; the name of the release to use for this same thread. NOTE: there is no checking that this release package exists!

hikaru.set_global_default_release(relname: str)

Sets the global default release to use to the specified release

This is the release value used if there is no per-thread default release.

NOTE: it is assumed that setting a default release indicates the intent to

create objects from within that release. In anticipation of that, the base module of the release is imported as part of this call.

Parameters:

relname – string; the name of a release module in the model package. NOTE: there is no checking that this release package exists!

hikaru.get_version_kind_class(version: str, kind: str, release: str | None = None) type | None

Return a class for a subclasses of HikaruDocumentBase for a specific K8s version

Parameters:
  • version – string; name of the version in which to look for the object

  • kind – string; value of the ‘kind’ parameter for a document; same as the name of the class that models the document

  • release – optional string; if supplied, indicates which release to load classes from. Must be one of the subpackage of hikaru.model, such as rel_1_16. If unspecified, the release specified from hikaru.naming.set_default_release() is used; if that hasn’t been called, then the default from when hikaru was built will be used.

Returns:

a class object that is a subclass of HikaruDocumentBase

NOTE: this function does lazy loading of modules in order to avoid

dependency loops and speed startup. Hence the first time a kind is requested from a version the function may run a bit longer as it loads up the needed modules and processes its symbols

hikaru.register_version_kind_class(cls: type, version: str, kind: str, release: str | None = None) type | None

Register a class for Hikaru to instantiate based on version/kind

This function allows you to register a dataclass for Hikaru to instantiate whenever it encounters the specified version/kind values in the ‘apiVersion’ and ‘kind’ fields of a YAML, Python dict, or JSON representation of a K8s object. Class must be a subclass of HikaruDocumentBase; either a direct subclass of that class (useful when creating custom operator classes) or a subclass of an existing HikaruDocumentBase subclass such as Pod or Deployment (good if you just want to add some custom methods/data to these classes).

If creating a subclass of an existing class, you need to supply the identical apiVersion and kind values that are used by Hikaru for identifying this original class. A simple way to do this is to just pass references to these class attributes on the base class to the registration call. So for example, if you have a class MyPod which is derived from Pod, you can register it like so:

register_version_kind_class(MyPod, Pod.apiVersion, Pod.kind)

Now when Hikaru needs to create a Pod instance, it will instantiate MyPod instead of Pod.

If you do not specify the release parameter, the registration will be for the default release for the thread. Otherwise, pass in the string name of a release package under hikaru.model, and this class will only be registered for use in the specified release.

Requirements of the ‘cls’ parameter

Besides being a subclass of HikaruDocumentBase, when defining a new class for Hikaru to instantiate, there are a few variations on what you define that are available to you, however there are two constraints that must always be followed:

  1. The module that contains the subclass must include a suitable wild-card import for all the symbols in the model module that you want to base your subclass on. So for example, if you are creating a subclass of Pod, you will run into errors if the module that contains your Pod subclass only has:

    from hikaru.model.rel_1_16.v1 import Pod

    You must instead import all symbols from that release/version:

    from hikaru.model.rel_1_16.v1 import *

  2. The classes must be defined at the top-level within the module.

Further conditions may apply depending on the nature of the subclass you are creating:

If only adding methods to an existing subclass (no new attrs):

If your subclass is only adding methods, then there are no further conditions to meet to define this subclass.

If adding instance attrs that are NOT passed in during instantiation:

If you are adding additional attributes that aren’t passed in from the instance creation call, you should simply implement the __post_init__() method, making sure to call super() with the client argument before adding your new attributes and values:

from hikaru.model.rel_1_17 import *
from typing import Any

class MyPod(Pod):
    def __post_init__(self, client: Any = None):
        super(MyPod, self).__post_init__(client=client)
        # your additional attributes are set up here
        self.x = []
        self.y = {}

If only adding instance attrs that are passed in during instantiation:

It is possible to define such classes, but NOTE: Hikaru will be unable to create instances of these classes that contain anything other than default values, as it has no way to know what values to provide.

In this case, you need to make a new dataclass and use type annotations to declare the new parameters are to be InitVar, which makes the dataclass only use them during init processing, but does not add them to the set of fields managed by the dataclass:

from hikaru.model.rel_1_16 import *
from dataclasses import dataclass, InitVar
from typing import Any

@dataclass
class MyPod(Pod):
    x: InitVar[Any] = None
    y: InitVar[Any] = None

    def __post_init__(self, client: Any = None, x=None, y=None):
        super(MyPod, self).__post_init__(client=client)
        self.x = x
        self.y = y

Note that any new fields will come after the client parameter in the __post_init__() method. NOTE: if you do not use InitVar for these fields, Hikaru will consider them part of the data that is to be sent out or read in from YAML, which may yield unpredictable results or errors.

If declaring a new subclass of HikaruDocumentBase:

You can use this approach when creating a custom operator that will consume a custom YAML document. In this case, you will need to define a dataclass that is a subclass of HikaruDocumentBase that contains all of the fields that you require, including apiVersion and kind (these are critical; more below). Additionally, there’s no client InitVar attribute since that’s used to send messages into the underlying K8s Python client code.

When you do this, Hikaru will then be able to consume a YAML document with the data fields and types you name in your dataclass. You can even specify contained objects within your top level object, and Hikaru will create instances of these contained objects automatically when consuming the YAML.

It is critical that your custom dataclass include the apiVersion and kind fields, as those are what is used when registering your class. So an example of an operator class might look like the following:

from hikaru.model.rel_1_16 import *
from dataclasses import dataclass, InitVar
from typing import Any

# this is contained in the new top-level class, and so is
# derived from HikaruBase
@dataclass
class PostgresSpec(HikaruBase):
    teamId: Optional[str] = None
    numberOfInstances: Optional[int] = 1
    # and so forth

# now our top-level class
@dataclass
class Postgres(HikaruDocumentBase):
    apiVersion: Optional[str] = 'v1'  # or whatever you want
    kind: Optional[str] = 'postgres'
    metadata: Optional[ObjectMeta] = None
    spec: Optional[PostgresSpec] = None

Such a set of classes would then be able to process YAML docs of the following form:

apiVersion: "v1"
kind: postgres
metadata:
  name: acid-minimal-cluster
  namespace: default
spec:
  teamId: "acid"
  numberOfInstances: 2
Parameters:
  • cls – a class object which is a subclass of HikaruDocumentBase

  • version – string; the version you want this class associated with

  • kind – string; the kind of object this is

  • release – optional string; if supplied, the name of the release where cls is to be registered. Otherwise, it will be registered in the release that is default for the calling thread.

Raises:

TypeError – if the provided class is not a subclass of HikaruDocumentBase, or if the class doesn’t have apiVersion or kind attributes

Returns:

If replacing an existing class, the previously registered class is returned. If a new class, then None is returned.

hikaru.rollback_cm(obj)

Rollback a HikaruDocumentBase instance if there’s an error in a with block

This function allows you to mark a HikaruDocumentBase subclass instance as being subject to a rollback if there’s an error in processing the instance inside a with block for which the instance is the context manager. So instead of doing something like this:

with Pod().read(name='something', namespace='something') as p:
    # and so forth

…where you’d need to recover the initial state of p if there was an error, you can instead do this:

with rollback_cm(Pod().read(name='summat', namespace='summat')) as p:
    # and so forth

If an error occurs inside the with block, then p will have the same state after the with block as it did at the start.

If there is no error, the update() method is invoked on p as usual.

Parameters:

obj – an instance of a subclass of HikaruDocumentBase

Returns:

returns the input object which is a context manager.

hikaru.crd.get_crd_schema(cls, jsp_class: type | None = None)

Return a JSONSchemaProps instance suitable for describing this class in a CustomResourceDefinition msg

This function takes a HikaruBase/HikaruDocumentBase subclass (not instance!) and returns a JSONSchemaProps object that describes a schema that reflects the class. The function uses get_default_release() to determine which release to acquire the JSONSchemaProps class from. The user may also manually supply the JSONSchemaProps class to use to return the schema. The returned JSONSchemaProps object can then be used in creating a CustomResourceDefinition.

Only works with a dataclass that is derived from HikaruBase!

Limitations:

  • Cannot handle recursively defined classes (yet), neither direct nor indirect.

  • Cannot handle dicts whose values are anything but strings; if you need more complex types use a nested class.

  • Cannot handle Unions of multiple types.

Parameters:
  • cls – a class object, derived from at least HikaruBase. A schema for this class will be generated and returned as the value of the function.

  • jsp_class – optional type; should be a JSONSchemaProps class object (not instance). By default, this function uses get_default_release() to determine which of the currently supported JSONSchemaProps classes to use to return the schema. This parameter allows the caller to specify a particular release’s class.

hikaru.crd.register_crd_class(crd_cls, plural_name: str, is_namespaced: bool = True)

Registers a CRD class with Hikaru, so it can find the proper class to instantiate on message receipt

Registers your CRD class with Hikaru’s class tracking code so that when a message is received that is associated with your CRD, Hikaru knows what class to instantiate.

The supplied class must be a subclass of HikaruDocumentBase and HikaruCRDDocumentMixin for all features to work properly. Additionally, the class must contain the string attributes apiVersion and kind, as well as a metadata attribute of type ObjectMeta; these are used both by Hikaru and K8s to direct processing of entities sent to/from K8s.

If all requirements are met, after this call CRUD operations and Watch() objects can be used.

NOTE: for CRD classes, you should be using register_crd_schema() instead of

register_version_kind_class() as you normally would for custom classes.

Parameters:
  • crd_cls – A class object that has both HikaruDocumentBase and HikaruCRDDocumentMixin as base classes.

  • plural_name – str; a plural name for your resource in all lower case. This should match the plural entry in the CustomResourceDefinitionNames object inside your CustomResourceDefintion.

  • is_namespaced – bool, defaults to True. If True, then the resource’s instances will be created within a namespace (rather than cluster-wide), and hence the namespace attribute of ObjectMeta must name an existing namespace. If False, no namespace is required, and the resource’s instances will be created within the cluster as a whole.

Returns:

the crd_cls value is returned to the caller.

hikaru.model.defrel.get_default_installed_release() str

Returns the highest numbered installed release which is the default

Returns:

string; the name of the release package that is the highest numbered one currently installed. If none are installed, raises a RuntimeError. The first call inspects the filesystem to find the highest numbered installed release, subsequent calls return the cached value.

hikaru.app.get_label_selector_for_instance_id(instance_id: str) str

Return a string suitable to use as a label selector when reading for resources from a specific app instance

This function returns a string that can be used as the label_selector parameter to a Kubernetes resource list call. This is used when trying to find all the resources of particular type that are part of an Application instance.

Parameters:

instance_id – str; the unique Application instance id for an already-created hikaru-app application

Returns:

string; a label selector expression string it can be combined with other label selectors according to the syntax specified by Kubernetes.

hikaru.app.get_app_instance_label_key() str

This is the key that will be added to a rsrc’s metadata.labels to id all rsrcs that are of the same app instance

Hikaru-app will use the string returned by this function as the key to store the internally generated instance_id that all resources from an instance of an application will share. This key has a default value, but can be changed by setting the key to use with set_app_instance_label key. Regardless of what value is returned, the key will be used in the resource’s metadata.labels key/value store so that it can be queried later.

NOTE: The underlying facility allows for multiple threads with each one supporting a different instance label key. That means when you call this function the key for this thread is returned. If no specific key has been established for this thread then the global key is returned.

hikaru.app.set_app_instance_label_key(newkey: str | None = None)

Set the per-thread key to use to identify all resources that are part of the same app

This function allows you to specify the key that Hikaru-app will use when noting that a resource is part of a particular instance of an Application subclass. Hikaru-app will use this as the key in the resource’s metadata.labels k/v store, and the value will be the id for the Application instance. By default, the key used is a key private to Hikaru-app, but if you want integration with other tools, you may want to use this function to change the key to:

app.kubernetes.io/instance

…as Kubernetes documents this as a standard key to use to identify resources that belong to an instance of an app. You should not modify this key or the associated value with any other tools!

NOTE: This function sets the per-thread value for the instance label key. Any per-thread values take precedence over the global instance key value. If you want to change the global key value then call set_global_app_instance_label_key()

Parameters:

newkey – optional str, defaults to None; string value of the key to use when performing CRUD operations on Hikaru-app applications for the current thread. If this value is an empty string or None, then the per-thread value is deleted and the global app instance label key will subsequently be used for this thread.

hikaru.app.set_global_app_instance_label_key(newkey: str)

Set the global app instance label key to use to identify all resources that are part of the same app, regardless of thread.

This function allows you to specify the key that Hikaru-app will use when noting that a resource is part of a particular instance of an Application subclass. Hikaru-app will use this as the key in the resource’s metadata.labels k/v store, and the value will be the id for the Application instance. By default, the key used is a key private to Hikaru-app, but if you want integration with other tools, you may want to use this function to change the key to:

app.kubernetes.io/instance

…as Kubernetes documents this as a standard key to use to identify resources that belong to an instance of an app. You should not modify this key or the associated value with any other tools!

NOTE: This functions set the global key that will be used whenever there is no thread-specific key to use for this purpose. If a thread-specific key is desired, then call set_app_instance_label_key() from the thread in which you want the custom key to be used.

Parameters:

newkey – str; key for hikaru-app to use when setting values in an Application resource’s metadata.annotations k/v store.

hikaru.app.record_resource_metadata(rsrc: HikaruDocumentBase, instance_id: str, name: str)

Set the instance_id and resource name in the resource’s metadata key/value stores

Hikaru uses this function internally to set the instance_id in the resource’s metadata.labels key/value store and the resource name in the resource’s metadata.annotations key/value store. This is used to identify all resources that are part of the same instance of an application and the name of the resource that is being created, updated, or deleted. This function is not intended to be called by users of hikaru-app, but is provided in case a user wants to use the same mechanism for their own purposes.

Since Hikaru handles the invocation of this normally, users shouldn’t use this function unless they have a specific need. One such need is to gather a set of existing resources into an Application instance by calling this function on a series of resources, providing a constant instance_id and varying values for name that match the attributes of an Application subclass, and then calling update() on each in turn.

Parameters:
  • rsrc – HikaruDocumentBase; the resource to set the metadata on

  • instance_id – str; the unique Application instance id

  • name – str; name of the attributes that the resource is known by within the application

hikaru.app.resource_name_matches_metadata(rsrc: HikaruDocumentBase, name: str) bool

Return True if the resource name matches the metadata annotation

Since we obscure how we store the resource name in the resource’s metadata, this function is provided to test if a specific resource has metadata that matches the name of the resource.

Parameters:
  • rsrc – HikaDocumentBase; the resource to check

  • name – the name of the resource we want to check the metadata against

Returns:

bool; True if the resource name matches the metadata-stored name