Welcome to The Operator Framework’s documentation!

ops package

The Charmed Operator Framework.

The Charmed Operator Framework allows the development of operators in a simple and straightforward way, using standard Python structures to allow for clean, maintainable, and reusable code.

A Kubernetes operator is a container that drives lifecycle management, configuration, integration and daily actions for an application. Operators simplify software management and operations. They capture reusable app domain knowledge from experts in a software component that can be shared.

The Charmed Operator Framework extends the “operator pattern” to enable Charmed Operators, packaged as and often referred to as “charms”. Charms are not just for Kubernetes but also operators for traditional Linux or Windows application management. Operators use an Operator Lifecycle Manager (OLM), like Juju, to coordinate their work in a cluster. The system uses Golang for concurrent event processing under the hood, but enables the operators to be written in Python.

Operators should do one thing and do it well. Each operator drives a single application or service and can be composed with other operators to deliver a complex application or service. An operator handles instantiation, scaling, configuration, optimisation, networking, service mesh, observability, and day-2 operations specific to that application.

Full developer documentation is available at https://juju.is/docs/sdk.

Submodules

ops.charm module

Base objects for the Charm, events and metadata.

class ops.charm.HookEvent(handle)[source]

Bases: ops.framework.EventBase

Events raised by Juju to progress a charm’s lifecycle.

Hooks are callback methods of a charm class (a subclass of CharmBase) that are invoked in response to events raised by Juju. These callback methods are the means by which a charm governs the lifecycle of its application.

The HookEvent class is the base of a type hierarchy of events related to the charm’s lifecycle.

HookEvent subtypes are grouped into the following categories

  • Core lifecycle events

  • Relation events

  • Storage events

  • Metric events

class ops.charm.ActionEvent(handle)[source]

Bases: ops.framework.EventBase

Events raised by Juju when an administrator invokes a Juju Action.

This class is the data type of events triggered when an administrator invokes a Juju Action. Callbacks bound to these events may be used for responding to the administrator’s Juju Action request.

To read the parameters for the action, see the instance variable params. To respond with the result of the action, call set_results(). To add progress messages that are visible as the action is progressing use log().

params

The parameters passed to the action.

defer()[source]

Action events are not deferable like other events.

This is because an action runs synchronously and the administrator is waiting for the result.

restore(snapshot)[source]

Used by the operator framework to record the action.

Not meant to be called directly by charm code.

Parameters

snapshot (dict) –

Return type

None

set_results(results)[source]

Report the result of the action.

Parameters

results (Mapping) – The result of the action as a Dict

Return type

None

log(message)[source]

Send a message that a user will see while the action is running.

Parameters

message (str) – The message for the user.

Return type

None

fail(message='')[source]

Report that this action has failed.

Parameters

message (str) – Optional message to record why it has failed.

Return type

None

class ops.charm.InstallEvent(handle)[source]

Bases: ops.charm.HookEvent

Event triggered when a charm is installed.

This event is triggered at the beginning of a charm’s lifecycle. Any associated callback method should be used to perform one-time setup operations, such as installing prerequisite software.

class ops.charm.StartEvent(handle)[source]

Bases: ops.charm.HookEvent

Event triggered immediately after first configuation change.

This event is triggered immediately after the first ConfigChangedEvent. Callback methods bound to the event should be used to ensure that the charm’s software is in a running state. Note that the charm’s software should be configured so as to persist in this state through reboots without further intervention on Juju’s part.

class ops.charm.StopEvent(handle)[source]

Bases: ops.charm.HookEvent

Event triggered when a charm is shut down.

This event is triggered when an application’s removal is requested by the client. The event fires immediately before the end of the unit’s destruction sequence. Callback methods bound to this event should be used to ensure that the charm’s software is not running, and that it will not start again on reboot.

class ops.charm.RemoveEvent(handle)[source]

Bases: ops.charm.HookEvent

Event triggered when a unit is about to be terminated.

This event fires prior to Juju removing the charm and terminating its unit.

class ops.charm.ConfigChangedEvent(handle)[source]

Bases: ops.charm.HookEvent

Event triggered when a configuration change is requested.

This event fires in several different situations.

Any callback method bound to this event cannot assume that the software has already been started; it should not start stopped software, but should (if appropriate) restart running software to take configuration changes into account.

class ops.charm.UpdateStatusEvent(handle)[source]

Bases: ops.charm.HookEvent

Event triggered by a status update request from Juju.

This event is periodically triggered by Juju so that it can provide constant feedback to the administrator about the status of the application the charm is modeling. Any callback method bound to this event should determine the “health” of the application and set the status appropriately.

The interval between update-status events can be configured model-wide, e.g. juju model-config update-status-hook-interval=1m.

class ops.charm.UpgradeCharmEvent(handle)[source]

Bases: ops.charm.HookEvent

Event triggered by request to upgrade the charm.

This event will be triggered when an administrator executes juju upgrade-charm. The event fires after Juju has unpacked the upgraded charm code, and so this event will be handled by the callback method bound to the event in the new codebase. The associated callback method is invoked provided there is no existing error state. The callback method should be used to reconcile current state written by an older version of the charm into whatever form that is needed by the current charm version.

class ops.charm.PreSeriesUpgradeEvent(handle)[source]

Bases: ops.charm.HookEvent

Event triggered to prepare a unit for series upgrade.

This event triggers when an administrator executes juju upgrade-series MACHINE prepare. The event will fire for each unit that is running on the specified machine. Any callback method bound to this event must prepare the charm for an upgrade to the series. This may include things like exporting database content to a version neutral format, or evacuating running instances to other machines.

It can be assumed that only after all units on a machine have executed the callback method associated with this event, the administrator will initiate steps to actually upgrade the series. After the upgrade has been completed, the PostSeriesUpgradeEvent will fire.

class ops.charm.PostSeriesUpgradeEvent(handle)[source]

Bases: ops.charm.HookEvent

Event triggered after a series upgrade.

This event is triggered after the administrator has done a distribution upgrade (or rolled back and kept the same series). It is called in response to juju upgrade-series MACHINE complete. Associated charm callback methods are expected to do whatever steps are necessary to reconfigure their applications for the new series. This may include things like populating the upgraded version of a database. Note however charms are expected to check if the series has actually changed or whether it was rolled back to the original series.

class ops.charm.LeaderElectedEvent(handle)[source]

Bases: ops.charm.HookEvent

Event triggered when a new leader has been elected.

Juju will trigger this event when a new leader unit is chosen for a given application.

This event fires at least once after Juju selects a leader unit. Callback methods bound to this event may take any action required for the elected unit to assert leadership. Note that only the elected leader unit will receive this event.

class ops.charm.LeaderSettingsChangedEvent(handle)[source]

Bases: ops.charm.HookEvent

Event triggered when leader changes any settings.

DEPRECATED NOTICE

This event has been deprecated in favor of using a Peer relation, and having the leader set a value in the Application data bag for that peer relation. (see RelationChangedEvent).

class ops.charm.CollectMetricsEvent(handle)[source]

Bases: ops.charm.HookEvent

Event triggered by Juju to collect metrics.

Juju fires this event every five minutes for the lifetime of the unit. Callback methods bound to this event may use the add_metrics() method of this class to send measurements to Juju.

Note that associated callback methods are currently sandboxed in how they can interact with Juju.

add_metrics(metrics, labels=None)[source]

Record metrics that have been gathered by the charm for this unit.

Parameters
  • metrics (Mapping) – A collection of {key: float} pairs that contains the metrics that have been gathered

  • labels (Optional[Mapping]) – {key:value} strings that can be applied to the metrics that are being gathered

Return type

None

class ops.charm.RelationEvent(handle, relation, app=None, unit=None)[source]

Bases: ops.charm.HookEvent

A base class representing the various relation lifecycle events.

Relation lifecycle events are generated when application units participate in relations. Units can only participate in relations after they have been “started”, and before they have been “stopped”. Within that time window, the unit may participate in several different relations at a time, including multiple relations with the same name.

relation

The Relation involved in this event

app

The remote Application that has triggered this event

unit

The remote unit that has triggered this event. This may be None if the relation event was triggered as an Application level event

snapshot()[source]

Used by the framework to serialize the event to disk.

Not meant to be called by charm code.

Return type

dict

restore(snapshot)[source]

Used by the framework to deserialize the event from disk.

Not meant to be called by charm code.

Parameters

snapshot (dict) –

Return type

None

class ops.charm.RelationCreatedEvent(handle, relation, app=None, unit=None)[source]

Bases: ops.charm.RelationEvent

Event triggered when a new relation is created.

This is triggered when a new relation to another app is added in Juju. This can occur before units for those applications have started. All existing relations should be established before start.

class ops.charm.RelationJoinedEvent(handle, relation, app=None, unit=None)[source]

Bases: ops.charm.RelationEvent

Event triggered when a new unit joins a relation.

This event is triggered whenever a new unit of a related application joins the relation. The event fires only when that remote unit is first observed by the unit. Callback methods bound to this event may set any local unit settings that can be determined using no more than the name of the joining unit and the remote private-address setting, which is always available when the relation is created and is by convention not deleted.

class ops.charm.RelationChangedEvent(handle, relation, app=None, unit=None)[source]

Bases: ops.charm.RelationEvent

Event triggered when relation data changes.

This event is triggered whenever there is a change to the data bucket for a related application or unit. Look at event.relation.data[event.unit/app] to see the new information, where event is the event object passed to the callback method bound to this event.

This event always fires once, after RelationJoinedEvent, and will subsequently fire whenever that remote unit changes its settings for the relation. Callback methods bound to this event should be the only ones that rely on remote relation settings. They should not error if the settings are incomplete, since it can be guaranteed that when the remote unit or application changes its settings, the event will fire again.

The settings that may be queried, or set, are determined by the relation’s interface.

class ops.charm.RelationDepartedEvent(handle, relation, app=None, unit=None)[source]

Bases: ops.charm.RelationEvent

Event triggered when a unit leaves a relation.

This is the inverse of the RelationJoinedEvent, representing when a unit is leaving the relation (the unit is being removed, the app is being removed, the relation is being removed). It is fired once for each unit that is going away.

Callback methods bound to this event may be used to remove all references to the departing remote unit, because there’s no guarantee that it’s still part of the system; it’s perfectly probable (although not guaranteed) that the system running that unit has already shut down.

Once all callback methods bound to this event have been run for such a relation, the unit agent will fire the RelationBrokenEvent.

class ops.charm.RelationBrokenEvent(handle, relation, app=None, unit=None)[source]

Bases: ops.charm.RelationEvent

Event triggered when a relation is removed.

If a relation is being removed (juju remove-relation or juju remove-application), once all the units have been removed, this event will fire to signal that the relationship has been fully terminated.

The event indicates that the current relation is no longer valid, and that the charm’s software must be configured as though the relation had never existed. It will only be called after every callback method bound to RelationDepartedEvent has been run. If a callback method bound to this event is being executed, it is gauranteed that no remote units are currently known locally.

class ops.charm.StorageEvent(handle)[source]

Bases: ops.charm.HookEvent

Base class representing storage-related events.

Juju can provide a variety of storage types to a charms. The charms can define several different types of storage that are allocated from Juju. Changes in state of storage trigger sub-types of StorageEvent.

class ops.charm.StorageAttachedEvent(handle)[source]

Bases: ops.charm.StorageEvent

Event triggered when new storage becomes available.

This event is triggered when new storage is available for the charm to use.

Callback methods bound to this event allow the charm to run code when storage has been added. Such methods will be run before the InstallEvent fires, so that the installation routine may use the storage. The name prefix of this hook will depend on the storage key defined in the metadata.yaml file.

class ops.charm.StorageDetachingEvent(handle)[source]

Bases: ops.charm.StorageEvent

Event triggered prior to removal of storage.

This event is triggered when storage a charm has been using is going away.

Callback methods bound to this event allow the charm to run code before storage is removed. Such methods will be run before storage is detached, and always before the StopEvent fires, thereby allowing the charm to gracefully release resources before they are removed and before the unit terminates. The name prefix of the hook will depend on the storage key defined in the metadata.yaml file.

class ops.charm.WorkloadEvent(handle, workload)[source]

Bases: ops.charm.HookEvent

Base class representing workload-related events.

Workload events are generated for all containers that the charm expects in metadata. Workload containers currently only trigger a PebbleReadyEvent.

workload

The Container involved in this event. Workload currently only can be a Container but in future may be other types that represent the specific workload type e.g. a Machine.

snapshot()[source]

Used by the framework to serialize the event to disk.

Not meant to be called by charm code.

Return type

dict

restore(snapshot)[source]

Used by the framework to deserialize the event from disk.

Not meant to be called by charm code.

Parameters

snapshot (dict) –

Return type

None

class ops.charm.PebbleReadyEvent(handle, workload)[source]

Bases: ops.charm.WorkloadEvent

Event triggered when pebble is ready for a workload.

This event is triggered when the Pebble process for a workload/container starts up, allowing the charm to configure how services should be launched.

Callback methods bound to this event allow the charm to run code after a workload has started its Pebble instance and is ready to receive instructions regarding what services should be started. The name prefix of the hook will depend on the container key defined in the metadata.yaml file.

class ops.charm.CharmEvents(parent=None, key=None)[source]

Bases: ops.framework.ObjectEvents

Events generated by Juju pertaining to application lifecycle.

This class is used to create an event descriptor (self.on) attribute for a charm class that inherits from CharmBase. The event descriptor may be used to set up event handlers for corresponding events.

By default the following events will be provided through CharmBase:

self.on.install
self.on.start
self.on.remove
self.on.update_status
self.on.config_changed
self.on.upgrade_charm
self.on.pre_series_upgrade
self.on.post_series_upgrade
self.on.leader_elected
self.on.collect_metrics

In addition to these, depending on the charm’s metadata (metadata.yaml), named relation and storage events may also be defined. These named events are created by CharmBase using charm metadata. The named events may be accessed as self.on[<name>].<relation_or_storage_event>

install

EventSource wraps an event type with a descriptor to facilitate observing and emitting.

It is generally used as:

class SomethingHappened(EventBase):

pass

class SomeObject(Object):

something_happened = EventSource(SomethingHappened)

With that, instances of that type will offer the someobj.something_happened attribute which is a BoundEvent and may be used to emit and observe the event.

start

EventSource wraps an event type with a descriptor to facilitate observing and emitting.

It is generally used as:

class SomethingHappened(EventBase):

pass

class SomeObject(Object):

something_happened = EventSource(SomethingHappened)

With that, instances of that type will offer the someobj.something_happened attribute which is a BoundEvent and may be used to emit and observe the event.

stop

EventSource wraps an event type with a descriptor to facilitate observing and emitting.

It is generally used as:

class SomethingHappened(EventBase):

pass

class SomeObject(Object):

something_happened = EventSource(SomethingHappened)

With that, instances of that type will offer the someobj.something_happened attribute which is a BoundEvent and may be used to emit and observe the event.

remove

EventSource wraps an event type with a descriptor to facilitate observing and emitting.

It is generally used as:

class SomethingHappened(EventBase):

pass

class SomeObject(Object):

something_happened = EventSource(SomethingHappened)

With that, instances of that type will offer the someobj.something_happened attribute which is a BoundEvent and may be used to emit and observe the event.

update_status

EventSource wraps an event type with a descriptor to facilitate observing and emitting.

It is generally used as:

class SomethingHappened(EventBase):

pass

class SomeObject(Object):

something_happened = EventSource(SomethingHappened)

With that, instances of that type will offer the someobj.something_happened attribute which is a BoundEvent and may be used to emit and observe the event.

config_changed

EventSource wraps an event type with a descriptor to facilitate observing and emitting.

It is generally used as:

class SomethingHappened(EventBase):

pass

class SomeObject(Object):

something_happened = EventSource(SomethingHappened)

With that, instances of that type will offer the someobj.something_happened attribute which is a BoundEvent and may be used to emit and observe the event.

upgrade_charm

EventSource wraps an event type with a descriptor to facilitate observing and emitting.

It is generally used as:

class SomethingHappened(EventBase):

pass

class SomeObject(Object):

something_happened = EventSource(SomethingHappened)

With that, instances of that type will offer the someobj.something_happened attribute which is a BoundEvent and may be used to emit and observe the event.

pre_series_upgrade

EventSource wraps an event type with a descriptor to facilitate observing and emitting.

It is generally used as:

class SomethingHappened(EventBase):

pass

class SomeObject(Object):

something_happened = EventSource(SomethingHappened)

With that, instances of that type will offer the someobj.something_happened attribute which is a BoundEvent and may be used to emit and observe the event.

post_series_upgrade

EventSource wraps an event type with a descriptor to facilitate observing and emitting.

It is generally used as:

class SomethingHappened(EventBase):

pass

class SomeObject(Object):

something_happened = EventSource(SomethingHappened)

With that, instances of that type will offer the someobj.something_happened attribute which is a BoundEvent and may be used to emit and observe the event.

leader_elected

EventSource wraps an event type with a descriptor to facilitate observing and emitting.

It is generally used as:

class SomethingHappened(EventBase):

pass

class SomeObject(Object):

something_happened = EventSource(SomethingHappened)

With that, instances of that type will offer the someobj.something_happened attribute which is a BoundEvent and may be used to emit and observe the event.

leader_settings_changed

EventSource wraps an event type with a descriptor to facilitate observing and emitting.

It is generally used as:

class SomethingHappened(EventBase):

pass

class SomeObject(Object):

something_happened = EventSource(SomethingHappened)

With that, instances of that type will offer the someobj.something_happened attribute which is a BoundEvent and may be used to emit and observe the event.

collect_metrics

EventSource wraps an event type with a descriptor to facilitate observing and emitting.

It is generally used as:

class SomethingHappened(EventBase):

pass

class SomeObject(Object):

something_happened = EventSource(SomethingHappened)

With that, instances of that type will offer the someobj.something_happened attribute which is a BoundEvent and may be used to emit and observe the event.

class ops.charm.CharmBase(framework, key=None)[source]

Bases: ops.framework.Object

Base class that represents the charm overall.

CharmBase is used to create a charm. This is done by inheriting from CharmBase and customising the sub class as required. So to create your own charm, say MyCharm, define a charm class and set up the required event handlers (“hooks”) in its constructor:

import logging

from ops.charm import CharmBase
from ops.main import main

logger = logging.getLogger(__name__)

def MyCharm(CharmBase):
    def __init__(self, *args):
        logger.debug('Initializing Charm')

        super().__init__(*args)

        self.framework.observe(self.on.config_changed, self._on_config_changed)
        self.framework.observe(self.on.stop, self._on_stop)
        # ...

if __name__ == "__main__":
    main(MyCharm)

As shown in the example above, a charm class is instantiated by main() rather than charm authors directly instantiating a charm.

Parameters
  • framework (ops.framework.Framework) – The framework responsible for managing the Model and events for this charm.

  • key (Optional) – Ignored; will remove after deprecation period of the signature change.

on

Used to set up event handlers; see CharmEvents.

property app

Application that this unit is part of.

property unit

Unit that this execution is responsible for.

property meta

Metadata of this charm.

property charm_dir

Root directory of the charm as it is running.

property config

A mapping containing the charm’s config and current values.

class ops.charm.CharmMeta(raw={}, actions_raw={})[source]

Bases: object

Object containing the metadata for the charm.

This is read from metadata.yaml and/or actions.yaml. Generally charms will define this information, rather than reading it at runtime. This class is mostly for the framework to understand what the charm has defined.

The maintainers, tags, terms, series, and extra_bindings attributes are all lists of strings. The requires, provides, peers, relations, storages, resources, and payloads attributes are all mappings of names to instances of the respective RelationMeta, StorageMeta, ResourceMeta, or PayloadMeta.

The relations attribute is a convenience accessor which includes all of the requires, provides, and peers RelationMeta items. If needed, the role of the relation definition can be obtained from its role attribute.

name

The name of this charm

summary

Short description of what this charm does

description

Long description for this charm

maintainers

A list of strings of the email addresses of the maintainers of this charm.

tags

Charm store tag metadata for categories associated with this charm.

terms

Charm store terms that should be agreed to before this charm can be deployed. (Used for things like licensing issues.)

series

The list of supported OS series that this charm can support. The first entry in the list is the default series that will be used by deploy if no other series is requested by the user.

subordinate

True/False whether this charm is intended to be used as a subordinate charm.

min_juju_version

If supplied, indicates this charm needs features that are not available in older versions of Juju.

requires

A dict of {name: RelationMeta } for each ‘requires’ relation.

provides

A dict of {name: RelationMeta } for each ‘provides’ relation.

peers

A dict of {name: RelationMeta } for each ‘peer’ relation.

relations

A dict containing all RelationMeta attributes (merged from other sections)

storages

A dict of {name: StorageMeta} for each defined storage.

resources

A dict of {name: ResourceMeta} for each defined resource.

payloads

A dict of {name: PayloadMeta} for each defined payload.

extra_bindings

A dict of additional named bindings that a charm can use for network configuration.

actions

A dict of {name: ActionMeta} for actions that the charm has defined.

Parameters
  • raw (dict) – a mapping containing the contents of metadata.yaml

  • actions_raw (dict) – a mapping containing the contents of actions.yaml

classmethod from_yaml(metadata, actions=None)[source]

Instantiate a CharmMeta from a YAML description of metadata.yaml.

Parameters
  • metadata (Union[str, TextIO]) – A YAML description of charm metadata (name, relations, etc.) This can be a simple string, or a file-like object. (passed to yaml.safe_load).

  • actions (Optional[Union[str, TextIO]]) – YAML description of Actions for this charm (eg actions.yaml)

class ops.charm.RelationRole(value)[source]

Bases: enum.Enum

An annotation for a charm’s role in a relation.

For each relation a charm’s role may be

  • A Peer

  • A service consumer in the relation (‘requires’)

  • A service provider in the relation (‘provides’)

peer = 'peer'
requires = 'requires'
provides = 'provides'
is_peer()[source]

Return whether the current role is peer.

A convenience to avoid having to import charm.

Return type

bool

class ops.charm.RelationMeta(role, relation_name, raw)[source]

Bases: object

Object containing metadata about a relation definition.

Should not be constructed directly by charm code. Is gotten from one of CharmMeta.peers, CharmMeta.requires, CharmMeta.provides, or CharmMeta.relations.

Parameters
role

This is RelationRole; one of peer/requires/provides

relation_name

Name of this relation from metadata.yaml

interface_name

Optional definition of the interface protocol.

limit

Optional definition of maximum number of connections to this relation endpoint.

scope

“global” (default) or “container” scope based on how the relation should be used.

VALID_SCOPES = ['global', 'container']
class ops.charm.StorageMeta(name, raw)[source]

Bases: object

Object containing metadata about a storage definition.

storage_name

Name of storage

type

Storage type

description

A text description of the storage

read_only

Whether or not the storage is read only

minimum_size

Minimum size of storage

location

Mount point of storage

multiple_range

Range of numeric qualifiers when multiple storage units are used

class ops.charm.ResourceMeta(name, raw)[source]

Bases: object

Object containing metadata about a resource definition.

resource_name

Name of resource

filename

Name of file

description

A text description of resource

class ops.charm.PayloadMeta(name, raw)[source]

Bases: object

Object containing metadata about a payload definition.

payload_name

Name of payload

type

Payload type

class ops.charm.ActionMeta(name, raw=None)[source]

Bases: object

Object containing metadata about an action’s definition.

class ops.charm.ContainerMeta(name, raw)[source]

Bases: object

Metadata about an individual container.

NOTE: this is extremely lightweight right now, and just includes the fields we need for Pebble interaction.

name

Name of container (key in the YAML)

mounts

ContainerStorageMeta mounts available to the container

property mounts

An accessor for the mounts in a container.

Dict keys match key name in StorageMeta

Example:

storage:
  foo:
    type: filesystem
    location: /test
containers:
  bar:
    mounts:
      - storage: foo
      - location: /test/mount
class ops.charm.ContainerStorageMeta(storage, location)[source]

Bases: object

Metadata about storage for an individual container.

storage

a name for the mountpoint, which should exist the keys for StorageMeta for the charm

location

the location storage is mounted at

locations

a list of mountpoints for the key

If multiple locations are specified for the same storage, such as Kubernetes subPath mounts, location will not be an accessible attribute, as it would not be possible to determine which mount point was desired, and locations should be iterated over.

add_location(location)[source]

Add an additional mountpoint to a known storage.

property locations

An accessor for the list of locations for a mount.

ops.framework module

The Operator Framework infrastructure.

class ops.framework.Handle(parent, kind, key)[source]

Bases: object

Handle defines a name for an object in the form of a hierarchical path.

The provided parent is the object (or that object’s handle) that this handle sits under, or None if the object identified by this handle stands by itself as the root of its own hierarchy.

The handle kind is a string that defines a namespace so objects with the same parent and kind will have unique keys.

The handle key is a string uniquely identifying the object. No other objects under the same parent and kind may have the same key.

nest(kind, key)[source]

Create a new handle as child of the current one.

property parent

Return own parent handle.

property kind

Return the handle’s kind.

property key

Return the handle’s key.

property path

Return the handle’s path.

classmethod from_path(path)[source]

Build a handle from the indicated path.

class ops.framework.EventBase(handle)[source]

Bases: object

The base for all the different Events.

Inherit this and override ‘snapshot’ and ‘restore’ methods to build a custom event.

defer()[source]

Defer the event to the future.

Deferring an event from a handler puts that handler into a queue, to be called again the next time the charm is invoked. This invocation may be the result of an action, or any event other than metric events. The queue of events will be dispatched before the new event is processed.

From the above you may deduce, but it’s important to point out:

  • defer() does not interrupt the execution of the current event handler. In almost all cases, a call to defer() should be followed by an explicit return from the handler;

  • the re-execution of the deferred event handler starts from the top of the handler method (not where defer was called);

  • only the handlers that actually called defer() are called again (that is: despite talking about “deferring an event” it is actually the handler/event combination that is deferred); and

  • any deferred events get processed before the event (or action) that caused the current invocation of the charm.

The general desire to call defer() happens when some precondition isn’t yet met. However, care should be exercised as to whether it is better to defer this event so that you see it again, or whether it is better to just wait for the event that indicates the precondition has been met.

For example, if config-changed is fired, and you are waiting for different config, there is no reason to defer the event because there will be a different config-changed event when the config actually changes, rather than checking to see if maybe config has changed prior to every other event that occurs.

Similarly, if you need 2 events to occur before you are ready to proceed (say event A and B). When you see event A, you could chose to defer() it because you haven’t seen B yet. However, that leads to:

  1. event A fires, calls defer()

  2. event B fires, event A handler is called first, still hasn’t seen B happen, so is deferred again. Then B happens, which progresses since it has seen A.

  3. At some future time, event C happens, which also checks if A can proceed.

snapshot()[source]

Return the snapshot data that should be persisted.

Subclasses must override to save any custom state.

restore(snapshot)[source]

Restore the value state from the given snapshot.

Subclasses must override to restore their custom state.

class ops.framework.EventSource(event_type)[source]

Bases: object

EventSource wraps an event type with a descriptor to facilitate observing and emitting.

It is generally used as:

class SomethingHappened(EventBase):

pass

class SomeObject(Object):

something_happened = EventSource(SomethingHappened)

With that, instances of that type will offer the someobj.something_happened attribute which is a BoundEvent and may be used to emit and observe the event.

class ops.framework.BoundEvent(emitter, event_type, event_kind)[source]

Bases: object

Event bound to an Object.

emit(*args, **kwargs)[source]

Emit event to all registered observers.

The current storage state is committed before and after each observer is notified.

class ops.framework.HandleKind[source]

Bases: object

Helper descriptor to define the Object.handle_kind field.

The handle_kind for an object defaults to its type name, but it may be explicitly overridden if desired.

class ops.framework.Object(parent, key)[source]

Bases: object

Base class of all the charm-related objects.

handle_kind

Helper descriptor to define the Object.handle_kind field.

The handle_kind for an object defaults to its type name, but it may be explicitly overridden if desired.

property model

Shortcut for more simple access the model.

class ops.framework.ObjectEvents(parent=None, key=None)[source]

Bases: ops.framework.Object

Convenience type to allow defining .on attributes at class level.

handle_kind = 'on'
classmethod define_event(event_kind, event_type)[source]

Define an event on this type at runtime.

cls: a type to define an event on.

event_kind: an attribute name that will be used to access the

event. Must be a valid python identifier, not be a keyword or an existing attribute.

event_type: a type of the event to define.

events()[source]

Return a mapping of event_kinds to bound_events for all available events.

class ops.framework.PrefixedEvents(emitter, key)[source]

Bases: object

Events to be found in all events using a specific prefix.

class ops.framework.PreCommitEvent(handle)[source]

Bases: ops.framework.EventBase

Events that will be emited first on commit.

class ops.framework.CommitEvent(handle)[source]

Bases: ops.framework.EventBase

Events that will be emited second on commit.

class ops.framework.FrameworkEvents(parent=None, key=None)[source]

Bases: ops.framework.ObjectEvents

Manager of all framework events.

pre_commit

EventSource wraps an event type with a descriptor to facilitate observing and emitting.

It is generally used as:

class SomethingHappened(EventBase):

pass

class SomeObject(Object):

something_happened = EventSource(SomethingHappened)

With that, instances of that type will offer the someobj.something_happened attribute which is a BoundEvent and may be used to emit and observe the event.

commit

EventSource wraps an event type with a descriptor to facilitate observing and emitting.

It is generally used as:

class SomethingHappened(EventBase):

pass

class SomeObject(Object):

something_happened = EventSource(SomethingHappened)

With that, instances of that type will offer the someobj.something_happened attribute which is a BoundEvent and may be used to emit and observe the event.

exception ops.framework.NoTypeError(handle_path)[source]

Bases: Exception

No class to hold it was found when restoring an event.

class ops.framework.Framework(storage, charm_dir, meta, model)[source]

Bases: ops.framework.Object

Main interface to from the Charm to the Operator Framework internals.

on

Manager of all framework events.

charm_dir = None
meta = None
model = None
set_breakpointhook()[source]

Hook into sys.breakpointhook so the builtin breakpoint() works as expected.

This method is called by main, and is not intended to be called by users of the framework itself outside of perhaps some testing scenarios.

It returns the old value of sys.excepthook.

The breakpoint function is a Python >= 3.7 feature.

This method was added in ops 1.0; before that, it was done as part of the Framework’s __init__.

close()[source]

Close the underlying backends.

commit()[source]

Save changes to the underlying backends.

register_type(cls, parent, kind=None)[source]

Register a type to a handle.

save_snapshot(value)[source]

Save a persistent snapshot of the provided value.

The provided value must implement the following interface:

value.handle = Handle(…) value.snapshot() => {…} # Simple builtin types only. value.restore(snapshot) # Restore custom state from prior snapshot.

load_snapshot(handle)[source]

Load a persistent snapshot.

drop_snapshot(handle)[source]

Discard a persistent snapshot.

observe(bound_event, observer)[source]

Register observer to be called when bound_event is emitted.

The bound_event is generally provided as an attribute of the object that emits the event, and is created in this style:

class SomeObject:
    something_happened = Event(SomethingHappened)

That event may be observed as:

framework.observe(someobj.something_happened, self._on_something_happened)
Raises

RuntimeError – if bound_event or observer are the wrong type.

Parameters
reemit()[source]

Reemit previously deferred events to the observers that deferred them.

Only the specific observers that have previously deferred the event will be notified again. Observers that asked to be notified about events after it’s been first emitted won’t be notified, as that would mean potentially observing events out of order.

breakpoint(name=None)[source]

Add breakpoint, optionally named, at the place where this method is called.

For the breakpoint to be activated the JUJU_DEBUG_AT environment variable must be set to “all” or to the specific name parameter provided, if any. In every other situation calling this method does nothing.

The framework also provides a standard breakpoint named “hook”, that will stop execution when a hook event is about to be handled.

For those reasons, the “all” and “hook” breakpoint names are reserved.

remove_unreferenced_events()[source]

Remove events from storage that are not referenced.

In older versions of the framework, events that had no observers would get recorded but never deleted. This makes a best effort to find these events and remove them from the database.

class ops.framework.StoredStateData(parent, attr_name)[source]

Bases: ops.framework.Object

Manager of the stored data.

snapshot()[source]

Return the current state.

restore(snapshot)[source]

Restore current state to the given snapshot.

on_commit(event)[source]

Save changes to the storage backend.

class ops.framework.BoundStoredState(parent, attr_name)[source]

Bases: object

Stored state data bound to a specific Object.

set_default(**kwargs)[source]

Set the value of any given key if it has not already been set.

class ops.framework.StoredState[source]

Bases: object

A class used to store data the charm needs persisted across invocations.

Example:

class MyClass(Object):
    _stored = StoredState()

Instances of MyClass can transparently save state between invocations by setting attributes on _stored. Initial state should be set with set_default on the bound object, that is:

class MyClass(Object):
    _stored = StoredState()

def __init__(self, parent, key):
    super().__init__(parent, key)
    self._stored.set_default(seen=set())
    self.framework.observe(self.on.seen, self._on_seen)

def _on_seen(self, event):
    self._stored.seen.add(event.uuid)
class ops.framework.StoredDict(stored_data, under)[source]

Bases: collections.abc.MutableMapping

A dict-like object that uses the StoredState as backend.

class ops.framework.StoredList(stored_data, under)[source]

Bases: collections.abc.MutableSequence

A list-like object that uses the StoredState as backend.

insert(index, value)[source]

Insert value before index.

append(value)[source]

Append value to the end of the list.

class ops.framework.StoredSet(stored_data, under)[source]

Bases: collections.abc.MutableSet

A set-like object that uses the StoredState as backend.

add(key)[source]

Add a key to a set.

This has no effect if the key is already present.

discard(key)[source]

Remove a key from a set if it is a member.

If the key is not a member, do nothing.

ops.jujuversion module

A helper to work with the Juju version.

class ops.jujuversion.JujuVersion(version)[source]

Bases: object

Helper to work with the Juju version.

It knows how to parse the JUJU_VERSION environment variable, and exposes different capabilities according to the specific version, allowing also to compare with other versions.

PATTERN = '^\n    (?P<major>\\d{1,9})\\.(?P<minor>\\d{1,9})       # <major> and <minor> numbers are always there\n    ((?:\\.|-(?P<tag>[a-z]+))(?P<patch>\\d{1,9}))? # sometimes with .<patch> or -<tag><patch>\n    (\\.(?P<build>\\d{1,9}))?$                     # and sometimes with a <build> number.\n    '
classmethod from_environ()[source]

Build a JujuVersion from JUJU_VERSION.

Return type

ops.jujuversion.JujuVersion

has_app_data()[source]

Determine whether this juju version knows about app data.

Return type

bool

is_dispatch_aware()[source]

Determine whether this juju version knows about dispatch.

Return type

bool

has_controller_storage()[source]

Determine whether this juju version supports controller-side storage.

Return type

bool

ops.log module

Interface to emit messages to the Juju logging system.

class ops.log.JujuLogHandler(model_backend, level=10)[source]

Bases: logging.Handler

A handler for sending logs to Juju via juju-log.

Initializes the instance - basically setting the formatter to None and the filter list to empty.

emit(record)[source]

Send the specified logging record to the Juju backend.

This method is not used directly by the Operator Framework code, but by logging.Handler itself as part of the logging machinery.

ops.log.setup_root_logging(model_backend, debug=False)[source]

Setup python logging to forward messages to juju-log.

By default, logging is set to DEBUG level, and messages will be filtered by Juju. Charmers can also set their own default log level with:

logging.getLogger().setLevel(logging.INFO)
Parameters
  • model_backend – a ModelBackend to use for juju-log

  • debug – if True, write logs to stderr as well as to juju-log.

ops.main module

Main entry point to the Operator Framework.

ops.main.main(charm_class, use_juju_for_storage=None)[source]

Setup the charm and dispatch the observed event.

The event name is based on the way this executable was called (argv[0]).

Parameters
  • charm_class (Type[ops.charm.CharmBase]) – your charm class.

  • use_juju_for_storage (Optional[bool]) – whether to use controller-side storage. If not specified then kubernetes charms that haven’t previously used local storage and that are running on a new enough Juju default to controller-side storage, otherwise local storage is used.

ops.model module

Representations of Juju’s model, application, unit, and other entities.

class ops.model.Model(meta, backend)[source]

Bases: object

Represents the Juju Model as seen from this unit.

This should not be instantiated directly by Charmers, but can be accessed as self.model from any class that derives from Object.

Parameters
property unit

A Unit that represents the unit that is running this code (eg yourself).

property app

A Application that represents the application this unit is a part of.

property relations

Mapping of endpoint to list of Relation.

Answers the question “what am I currently related to”. See also get_relation().

property config

Return a mapping of config for the current application.

property resources

Access to resources for this charm.

Use model.resources.fetch(resource_name) to get the path on disk where the resource can be found.

property storages

Mapping of storage_name to Storage as defined in metadata.yaml.

property pod

Use model.pod.set_spec to set the container specification for Kubernetes charms.

property name

Return the name of the Model that this unit is running in.

This is read from the environment variable JUJU_MODEL_NAME.

property uuid

Return the identifier of the Model that this unit is running in.

This is read from the environment variable JUJU_MODEL_UUID.

get_unit(unit_name)[source]

Get an arbitrary unit by name.

Internally this uses a cache, so asking for the same unit two times will return the same object.

Parameters

unit_name (str) –

Return type

ops.model.Unit

get_app(app_name)[source]

Get an application by name.

Internally this uses a cache, so asking for the same application two times will return the same object.

Parameters

app_name (str) –

Return type

ops.model.Application

get_relation(relation_name, relation_id=None)[source]

Get a specific Relation instance.

If relation_id is not given, this will return the Relation instance if the relation is established only once or None if it is not established. If this same relation is established multiple times the error TooManyRelatedAppsError is raised.

Parameters
  • relation_name (str) – The name of the endpoint for this charm

  • relation_id (Optional[int]) – An identifier for a specific relation. Used to disambiguate when a given application has more than one relation on a given endpoint.

Raises

TooManyRelatedAppsError – is raised if there is more than one relation to the supplied relation_name and no relation_id was supplied

Return type

ops.model.Relation

get_binding(binding_key)[source]

Get a network space binding.

Parameters

binding_key (Union[str, ops.model.Relation]) – The relation name or instance to obtain bindings for.

Returns

If binding_key is a relation name, the method returns the default binding for that relation. If a relation instance is provided, the method first looks up a more specific binding for that specific relation ID, and if none is found falls back to the default binding for the relation name.

Return type

ops.model.Binding

class ops.model.Application(name, meta, backend, cache)[source]

Bases: object

Represents a named application in the model.

This might be your application, or might be an application that you are related to. Charmers should not instantiate Application objects directly, but should use Model.get_app() if they need a reference to a given application.

name

The name of this application (eg, ‘mysql’). This name may differ from the name of the charm, if the user has deployed it to a different name.

property status

Used to report or read the status of the overall application.

Can only be read and set by the lead unit of the application.

The status of remote units is always Unknown.

Raises
  • RuntimeError – if you try to set the status of another application, or if you try to set the status of this application as a unit that is not the leader.

  • InvalidStatusError – if you try to set the status to something that is not a StatusBase

Example:

self.model.app.status = BlockedStatus('I need a human to come help me')
planned_units()[source]

Get the number of units that Juju has “planned” for this application.

E.g., if an operator ran “juju deploy foo”, then “juju add-unit -n 2 foo”, the planned unit count for foo would be 3.

We deliberately do not attempt to inspect whether these units are actually running or not at present.

This only works for this charm’s application – the unit agent isn’t able to get planned units for other applications in the model.

Return type

int

class ops.model.Unit(name, meta, backend, cache)[source]

Bases: object

Represents a named unit in the model.

This might be your unit, another unit of your application, or a unit of another application that you are related to.

name

The name of the unit (eg, ‘mysql/0’)

app

The Application the unit is a part of.

property status

Used to report or read the status of a specific unit.

The status of any unit other than yourself is always Unknown.

Raises

Example:

self.model.unit.status = MaintenanceStatus('reconfiguring the frobnicators')
is_leader()[source]

Return whether this unit is the leader of its application.

This can only be called for your own unit.

Returns

True if you are the leader, False otherwise

Raises

RuntimeError – if called for a unit that is not yourself

Return type

bool

set_workload_version(version)[source]

Record the version of the software running as the workload.

This shouldn’t be confused with the revision of the charm. This is informative only; shown in the output of ‘juju status’.

Parameters

version (str) –

Return type

None

property containers

Return a mapping of containers indexed by name.

get_container(container_name)[source]

Get a single container by name.

Raises

ModelError – if the named container doesn’t exist

Parameters

container_name (str) –

Return type

ops.model.Container

class ops.model.LazyMapping[source]

Bases: collections.abc.Mapping, abc.ABC

Represents a dict that isn’t populated until it is accessed.

Charm authors should generally never need to use this directly, but it forms the basis for many of the dicts that the framework tracks.

class ops.model.RelationMapping(relations_meta, our_unit, backend, cache)[source]

Bases: collections.abc.Mapping

Map of relation names to lists of Relation instances.

class ops.model.BindingMapping(backend)[source]

Bases: object

Mapping of endpoints to network bindings.

Charm authors should not instantiate this directly, but access it via Model.get_binding()

get(binding_key)[source]

Get a specific Binding for an endpoint/relation.

Not used directly by Charm authors. See Model.get_binding()

Parameters

binding_key (Union[str, ops.model.Relation]) –

Return type

ops.model.Binding

class ops.model.Binding(name, relation_id, backend)[source]

Bases: object

Binding to a network space.

name

The name of the endpoint this binding represents (eg, ‘db’)

property network

The network information for this binding.

class ops.model.Network(network_info)[source]

Bases: object

Network space details.

Charm authors should not instantiate this directly, but should get access to the Network definition from Model.get_binding() and its network attribute.

interfaces

A list of NetworkInterface details. This includes the information about how your application should be configured (eg, what IP addresses should you bind to.) Note that multiple addresses for a single interface are represented as multiple interfaces. (eg, [NetworkInfo('ens1', '10.1.1.1/32'), NetworkInfo('ens1', '10.1.2.1/32']))

ingress_addresses

A list of ipaddress.ip_address objects representing the IP addresses that other units should use to get in touch with you.

egress_subnets

A list of ipaddress.ip_network representing the subnets that other units will see you connecting from. Due to things like NAT it isn’t always possible to narrow it down to a single address, but when it is clear, the CIDRs will be constrained to a single address. (eg, 10.0.0.1/32)

Parameters

network_info (dict) – A dict of network information as returned by network-get.

property bind_address

A single address that your application should bind() to.

For the common case where there is a single answer. This represents a single address from interfaces that can be used to configure where your application should bind() and listen().

property ingress_address

The address other applications should use to connect to your unit.

Due to things like public/private addresses, NAT and tunneling, the address you bind() to is not always the address other people can use to connect() to you. This is just the first address from ingress_addresses.

class ops.model.NetworkInterface(name, address_info)[source]

Bases: object

Represents a single network interface that the charm needs to know about.

Charmers should not instantiate this type directly. Instead use Model.get_binding() to get the network information for a given endpoint.

Parameters
  • name (str) –

  • address_info (dict) –

name

The name of the interface (eg. ‘eth0’, or ‘ens1’)

subnet

An ipaddress.ip_network representation of the IP for the network interface. This may be a single address (eg ‘10.0.1.2/32’)

class ops.model.Relation(relation_name, relation_id, is_peer, our_unit, backend, cache)[source]

Bases: object

Represents an established relation between this application and another application.

This class should not be instantiated directly, instead use Model.get_relation() or ops.charm.RelationEvent.relation. This is principally used by ops.charm.RelationMeta to represent the relationships between charms.

Parameters
  • relation_name (str) –

  • relation_id (int) –

  • is_peer (bool) –

  • our_unit (ops.model.Unit) –

  • backend (_ModelBackend) –

  • cache (_ModelCache) –

name

The name of the local endpoint of the relation (eg ‘db’)

id

The identifier for a particular relation (integer)

app

An Application representing the remote application of this relation. For peer relations this will be the local application.

units

A set of Unit for units that have started and joined this relation.

data

A RelationData holding the data buckets for each entity of a relation. Accessed via eg Relation.data[unit][‘foo’]

class ops.model.RelationData(relation, our_unit, backend)[source]

Bases: collections.abc.Mapping

Represents the various data buckets of a given relation.

Each unit and application involved in a relation has their own data bucket. Eg: {entity: RelationDataContent} where entity can be either a Unit or a Application.

Units can read and write their own data, and if they are the leader, they can read and write their application data. They are allowed to read remote unit and application data.

This class should not be created directly. It should be accessed via Relation.data

Parameters
class ops.model.RelationDataContent(relation, entity, backend)[source]

Bases: ops.model.LazyMapping, collections.abc.MutableMapping

Data content of a unit or application in a relation.

class ops.model.ConfigData(backend)[source]

Bases: ops.model.LazyMapping

Configuration data.

This class should not be created directly. It should be accessed via Model.config.

class ops.model.StatusBase(*args, **kwargs)[source]

Bases: object

Status values specific to applications and units.

To access a status by name, see StatusBase.from_name(), most use cases will just directly use the child class to indicate their status.

Forbid the usage of StatusBase directly.

name = None
classmethod from_name(name, message)[source]

Get the specific Status for the name (or UnknownStatus if not registered).

Parameters
  • name (str) –

  • message (str) –

classmethod register(child)[source]

Register a Status for the child’s name.

class ops.model.UnknownStatus(*args, **kwargs)[source]

Bases: ops.model.StatusBase

The unit status is unknown.

A unit-agent has finished calling install, config-changed and start, but the charm has not called status-set yet.

Forbid the usage of StatusBase directly.

name = 'unknown'
class ops.model.ActiveStatus(*args, **kwargs)[source]

Bases: ops.model.StatusBase

The unit is ready.

The unit believes it is correctly offering all the services it has been asked to offer.

Forbid the usage of StatusBase directly.

name = 'active'
class ops.model.BlockedStatus(*args, **kwargs)[source]

Bases: ops.model.StatusBase

The unit requires manual intervention.

An operator has to manually intervene to unblock the unit and let it proceed.

Forbid the usage of StatusBase directly.

name = 'blocked'
class ops.model.MaintenanceStatus(*args, **kwargs)[source]

Bases: ops.model.StatusBase

The unit is performing maintenance tasks.

The unit is not yet providing services, but is actively doing work in preparation for providing those services. This is a “spinning” state, not an error state. It reflects activity on the unit itself, not on peers or related units.

Forbid the usage of StatusBase directly.

name = 'maintenance'
class ops.model.WaitingStatus(*args, **kwargs)[source]

Bases: ops.model.StatusBase

A unit is unable to progress.

The unit is unable to progress to an active state because an application to which it is related is not running.

Forbid the usage of StatusBase directly.

name = 'waiting'
class ops.model.Resources(names, backend)[source]

Bases: object

Object representing resources for the charm.

Parameters
  • names (Iterable[str]) –

  • backend (_ModelBackend) –

fetch(name)[source]

Fetch the resource from the controller or store.

If successfully fetched, this returns a Path object to where the resource is stored on disk, otherwise it raises a ModelError.

Parameters

name (str) –

Return type

pathlib.Path

class ops.model.Pod(backend)[source]

Bases: object

Represents the definition of a pod spec in Kubernetes models.

Currently only supports simple access to setting the Juju pod spec via set_spec.

Parameters

backend (_ModelBackend) –

set_spec(spec, k8s_resources=None)[source]

Set the specification for pods that Juju should start in kubernetes.

See juju help-tool pod-spec-set for details of what should be passed.

Parameters
  • spec (Mapping) – The mapping defining the pod specification

  • k8s_resources (Optional[Mapping]) – Additional kubernetes specific specification.

Returns

None

class ops.model.StorageMapping(storage_names, backend)[source]

Bases: collections.abc.Mapping

Map of storage names to lists of Storage instances.

Parameters
  • storage_names (Iterable[str]) –

  • backend (_ModelBackend) –

request(storage_name, count=1)[source]

Requests new storage instances of a given name.

Uses storage-add tool to request additional storage. Juju will notify the unit via <storage-name>-storage-attached events when it becomes available.

Parameters
  • storage_name (str) –

  • count (int) –

class ops.model.Storage(storage_name, storage_id, backend)[source]

Bases: object

Represents a storage as defined in metadata.yaml.

name

Simple string name of the storage

id

The provider id for storage

property location

Return the location of the storage.

class ops.model.Container(name, backend, pebble_client=None)[source]

Bases: object

Represents a named container in a unit.

This class should not be instantiated directly, instead use Unit.get_container() or Unit.containers.

name

The name of the container from metadata.yaml (eg, ‘postgres’).

property pebble

The low-level ops.pebble.Client instance for this container.

can_connect()[source]

Report whether the Pebble API is reachable in the container.

can_connect() returns a bool that indicates whether the Pebble API is available at the time the method is called. It does not guard against the Pebble API becoming unavailable, and should be treated as a ‘point in time’ status only.

If the Pebble API later fails, serious consideration should be given as to the reason for this.

Example:

container = self.unit.get_container("example")
if container.can_connect():
    try:
        c.pull('/does/not/exist')
    except ProtocolError, PathError:
        # handle it
else:
    event.defer()
Return type

bool

autostart()[source]

Autostart all services marked as startup: enabled.

start(*service_names)[source]

Start given service(s) by name.

Parameters

service_names (str) –

restart(*service_names)[source]

Restart the given service(s) by name.

Parameters

service_names (str) –

stop(*service_names)[source]

Stop given service(s) by name.

Parameters

service_names (str) –

add_layer(label, layer, *, combine=False)[source]

Dynamically add a new layer onto the Pebble configuration layers.

Parameters
  • label (str) – Label for new layer (and label of layer to merge with if combining).

  • layer – A YAML string, configuration layer dict, or pebble.Layer object containing the Pebble layer to add.

  • combine (bool) – If combine is False (the default), append the new layer as the top layer with the given label (must be unique). If combine is True and the label already exists, the two layers are combined into a single one considering the layer override rules; if the layer doesn’t exist, it is added as usual.

get_plan()[source]

Get the current effective pebble configuration.

Return type

ops.pebble.Plan

get_services(*service_names)[source]

Fetch and return a mapping of status information indexed by service name.

If no service names are specified, return status information for all services, otherwise return information for only the given services.

Parameters

service_names (str) –

Return type

ops.model.ServiceInfoMapping

get_service(service_name)[source]

Get status information for a single named service.

Raises model error if service_name is not found.

Parameters

service_name (str) –

Return type

ops.pebble.ServiceInfo

pull(path, *, encoding='utf-8')[source]

Read a file’s content from the remote system.

Parameters
  • path (str) – Path of the file to read from the remote system.

  • encoding (str) – Encoding to use for decoding the file’s bytes to str, or None to specify no decoding.

Returns

A readable file-like object, whose read() method will return str objects decoded according to the specified encoding, or bytes if encoding is None.

Return type

Union[BinaryIO, TextIO]

push(path, source, *, encoding='utf-8', make_dirs=False, permissions=None, user_id=None, user=None, group_id=None, group=None)[source]

Write content to a given file path on the remote system.

Parameters
  • path (str) – Path of the file to write to on the remote system.

  • source (Union[bytes, str, BinaryIO, TextIO]) – Source of data to write. This is either a concrete str or bytes instance, or a readable file-like object.

  • encoding (str) – Encoding to use for encoding source str to bytes, or strings read from source if it is a TextIO type. Ignored if source is bytes or BinaryIO.

  • make_dirs (bool) – If True, create parent directories if they don’t exist.

  • permissions (Optional[int]) – Permissions (mode) to create file with (Pebble default is 0o644).

  • user_id (Optional[int]) – User ID (UID) for file.

  • user (Optional[str]) – Username for file. User’s UID must match user_id if both are specified.

  • group_id (Optional[int]) – Group ID (GID) for file.

  • group (Optional[str]) – Group name for file. Group’s GID must match group_id if both are specified.

list_files(path, *, pattern=None, itself=False)[source]

Return list of directory entries from given path on remote system.

Despite the name, this method returns a list of files and directories, similar to os.listdir() or os.scandir().

Parameters
  • path (str) – Path of the directory to list, or path of the file to return information about.

  • pattern (Optional[str]) – If specified, filter the list to just the files that match, for example *.txt.

  • itself (bool) – If path refers to a directory, return information about the directory itself, rather than its contents.

Return type

List[ops.pebble.FileInfo]

make_dir(path, *, make_parents=False, permissions=None, user_id=None, user=None, group_id=None, group=None)[source]

Create a directory on the remote system with the given attributes.

Parameters
  • path (str) – Path of the directory to create on the remote system.

  • make_parents (bool) – If True, create parent directories if they don’t exist.

  • permissions (Optional[int]) – Permissions (mode) to create directory with (Pebble default is 0o755).

  • user_id (Optional[int]) – User ID (UID) for directory.

  • user (Optional[str]) – Username for directory. User’s UID must match user_id if both are specified.

  • group_id (Optional[int]) – Group ID (GID) for directory.

  • group (Optional[str]) – Group name for directory. Group’s GID must match group_id if both are specified.

remove_path(path, *, recursive=False)[source]

Remove a file or directory on the remote system.

Parameters
  • path (str) – Path of the file or directory to delete from the remote system.

  • recursive (bool) – If True, recursively delete path and everything under it.

class ops.model.ContainerMapping(names, backend)[source]

Bases: collections.abc.Mapping

Map of container names to Container objects.

This is done as a mapping object rather than a plain dictionary so that we can extend it later, and so it’s not mutable.

Parameters
  • names (Iterable[str]) –

  • backend (_ModelBackend) –

class ops.model.ServiceInfoMapping(services)[source]

Bases: collections.abc.Mapping

Map of service names to pebble.ServiceInfo objects.

This is done as a mapping object rather than a plain dictionary so that we can extend it later, and so it’s not mutable.

Parameters

services (Iterable[pebble.ServiceInfo]) –

exception ops.model.ModelError[source]

Bases: Exception

Base class for exceptions raised when interacting with the Model.

exception ops.model.TooManyRelatedAppsError(relation_name, num_related, max_supported)[source]

Bases: ops.model.ModelError

Raised by Model.get_relation() if there is more than one related application.

exception ops.model.RelationDataError[source]

Bases: ops.model.ModelError

Raised by Relation.data[entity][key] = 'foo' if the data is invalid.

This is raised if you’re either trying to set a value to something that isn’t a string, or if you are trying to set a value in a bucket that you don’t have access to. (eg, another application/unit or setting your application data but you aren’t the leader.)

exception ops.model.RelationNotFoundError[source]

Bases: ops.model.ModelError

Backend error when querying juju for a given relation and that relation doesn’t exist.

exception ops.model.InvalidStatusError[source]

Bases: ops.model.ModelError

Raised if trying to set an Application or Unit status to something invalid.

ops.pebble module

Client for the Pebble API (HTTP over Unix socket).

For a command-line interface for local testing, see test/pebble_cli.py.

exception ops.pebble.Error[source]

Bases: Exception

Base class of most errors raised by the Pebble client.

name()[source]

Return a string representation of the model plus class.

message()[source]

Return the message passed as an argument.

exception ops.pebble.TimeoutError[source]

Bases: TimeoutError, ops.pebble.Error

Raised when a polling timeout occurs.

exception ops.pebble.ConnectionError[source]

Bases: ops.pebble.Error

Raised when the Pebble client can’t connect to the socket.

exception ops.pebble.ProtocolError[source]

Bases: ops.pebble.Error

Raised when there’s a higher-level protocol error talking to Pebble.

exception ops.pebble.PathError(kind, message)[source]

Bases: ops.pebble.Error

Raised when there’s an error with a specific path.

This shouldn’t be instantiated directly.

Parameters
  • kind (str) –

  • message (str) –

exception ops.pebble.APIError(body, code, status, message)[source]

Bases: ops.pebble.Error

Raised when an HTTP API error occurs talking to the Pebble server.

This shouldn’t be instantiated directly.

Parameters
  • body (Dict) –

  • code (int) –

  • status (str) –

  • message (str) –

exception ops.pebble.ChangeError(err, change)[source]

Bases: ops.pebble.Error

Raised by actions when a change is ready but has an error.

For example, this happens when you attempt to start an already-started service:

cannot perform the following tasks: - Start service “test” (service “test” was previously started)

This shouldn’t be instantiated directly.

Parameters
class ops.pebble.WarningState(value)[source]

Bases: enum.Enum

Enum of states for get_warnings() select parameter.

ALL = 'all'
PENDING = 'pending'
class ops.pebble.ChangeState(value)[source]

Bases: enum.Enum

Enum of states for get_changes() select parameter.

ALL = 'all'
IN_PROGRESS = 'in-progress'
READY = 'ready'
class ops.pebble.SystemInfo(version)[source]

Bases: object

System information object.

Parameters

version (str) –

classmethod from_dict(d)[source]

Create new SystemInfo object from dict parsed from JSON.

Parameters

d (Dict) –

Return type

ops.pebble.SystemInfo

class ops.pebble.Warning(message, first_added, last_added, last_shown, expire_after, repeat_after)[source]

Bases: object

Warning object.

Parameters
classmethod from_dict(d)[source]

Create new Warning object from dict parsed from JSON.

Parameters

d (Dict) –

Return type

ops.pebble.Warning

class ops.pebble.TaskProgress(label, done, total)[source]

Bases: object

Task progress object.

Parameters
  • label (str) –

  • done (int) –

  • total (int) –

classmethod from_dict(d)[source]

Create new TaskProgress object from dict parsed from JSON.

Parameters

d (Dict) –

Return type

ops.pebble.TaskProgress

class ops.pebble.TaskID[source]

Bases: str

Task ID (a more strongly-typed string).

class ops.pebble.Task(id, kind, summary, status, log, progress, spawn_time, ready_time)[source]

Bases: object

Task object.

Parameters
classmethod from_dict(d)[source]

Create new Task object from dict parsed from JSON.

Parameters

d (Dict) –

Return type

ops.pebble.Task

class ops.pebble.ChangeID[source]

Bases: str

Change ID (a more strongly-typed string).

class ops.pebble.Change(id, kind, summary, status, tasks, ready, err, spawn_time, ready_time)[source]

Bases: object

Change object.

Parameters
classmethod from_dict(d)[source]

Create new Change object from dict parsed from JSON.

Parameters

d (Dict) –

Return type

ops.pebble.Change

class ops.pebble.Plan(raw)[source]

Bases: object

Represents the effective Pebble configuration.

Parameters

raw (str) –

property services

This plan’s services mapping (maps service name to Service).

This property is currently read-only.

to_dict()[source]

Convert this plan to its dict representation.

Return type

Dict[str, Any]

to_yaml()[source]

Return this plan’s YAML representation.

Return type

str

class ops.pebble.Layer(raw=None)[source]

Bases: object

Represents a Pebble configuration layer.

The format of this is not documented, but is captured in code here: https://github.com/canonical/pebble/blob/master/internal/plan/plan.go

Parameters

raw (Union[str, Dict]) –

summary

A summary of the purpose of this layer

description

A long form description of this layer

services

A mapping of name: Service defined by this layer

to_yaml()[source]

Convert this layer to its YAML representation.

Return type

str

to_dict()[source]

Convert this layer to its dict representation.

Return type

Dict[str, Any]

class ops.pebble.Service(name, raw=None)[source]

Bases: object

Represents a service description in a Pebble configuration layer.

Parameters
  • name (str) –

  • raw (Dict) –

to_dict()[source]

Convert this service object to its dict representation.

Return type

Dict

class ops.pebble.ServiceStartup(value)[source]

Bases: enum.Enum

Enum of service startup options.

ENABLED = 'enabled'
DISABLED = 'disabled'
class ops.pebble.ServiceStatus(value)[source]

Bases: enum.Enum

Enum of service statuses.

ACTIVE = 'active'
INACTIVE = 'inactive'
ERROR = 'error'
class ops.pebble.ServiceInfo(name, startup, current)[source]

Bases: object

Service status information.

Parameters
is_running()[source]

Return True if this service is running (in the active state).

Return type

bool

classmethod from_dict(d)[source]

Create new ServiceInfo object from dict parsed from JSON.

Parameters

d (Dict) –

Return type

ops.pebble.ServiceInfo

class ops.pebble.FileType(value)[source]

Bases: enum.Enum

Enum of file types.

FILE = 'file'
DIRECTORY = 'directory'
SOCKET = 'socket'
NAMED_PIPE = 'named-pipe'
DEVICE = 'device'
UNKNOWN = 'unknown'
class ops.pebble.FileInfo(path, name, type, size, permissions, last_modified, user_id, user, group_id, group)[source]

Bases: object

Stat-like information about a single file or directory.

Parameters
classmethod from_dict(d)[source]

Create new FileInfo object from dict parsed from JSON.

Parameters

d (Dict) –

Return type

ops.pebble.FileInfo

class ops.pebble.Client(socket_path=None, opener=None, base_url='http://localhost', timeout=5.0)[source]

Bases: object

Pebble API client.

Initialize a client instance.

Defaults to using a Unix socket at socket_path (which must be specified unless a custom opener is provided).

get_system_info()[source]

Get system info.

Return type

ops.pebble.SystemInfo

get_warnings(select=<WarningState.PENDING: 'pending'>)[source]

Get list of warnings in given state (pending or all).

Parameters

select (ops.pebble.WarningState) –

Return type

List[ops.pebble.Warning]

ack_warnings(timestamp)[source]

Acknowledge warnings up to given timestamp, return number acknowledged.

Parameters

timestamp (datetime.datetime) –

Return type

int

get_changes(select=<ChangeState.IN_PROGRESS: 'in-progress'>, service=None)[source]

Get list of changes in given state, filter by service name if given.

Parameters
Return type

List[ops.pebble.Change]

get_change(change_id)[source]

Get single change by ID.

Parameters

change_id (ops.pebble.ChangeID) –

Return type

ops.pebble.Change

abort_change(change_id)[source]

Abort change with given ID.

Parameters

change_id (ops.pebble.ChangeID) –

Return type

ops.pebble.Change

autostart_services(timeout=30.0, delay=0.1)[source]

Start the startup-enabled services and wait (poll) for them to be started.

Raises ChangeError if one or more of the services didn’t start. If timeout is 0, submit the action but don’t wait; just return the change ID immediately.

Parameters
Return type

ops.pebble.ChangeID

start_services(services, timeout=30.0, delay=0.1)[source]

Start services by name and wait (poll) for them to be started.

Raises ChangeError if one or more of the services didn’t start. If timeout is 0, submit the action but don’t wait; just return the change ID immediately.

Parameters
Return type

ops.pebble.ChangeID

stop_services(services, timeout=30.0, delay=0.1)[source]

Stop services by name and wait (poll) for them to be started.

Raises ChangeError if one or more of the services didn’t stop. If timeout is 0, submit the action but don’t wait; just return the change ID immediately.

Parameters
Return type

ops.pebble.ChangeID

wait_change(change_id, timeout=30.0, delay=0.1)[source]

Wait for the given change to be ready.

If the Pebble server supports the /v1/changes/{id}/wait API endpoint, use that to avoid polling, otherwise poll /v1/changes/{id} every delay seconds.

Parameters
  • change_id (ops.pebble.ChangeID) – Change ID of change to wait for.

  • timeout (float) – Maximum time in seconds to wait for the change to be ready. May be None, in which case wait_change never times out.

  • delay (float) – If polling, this is the delay in seconds between attempts.

Returns

The Change object being waited on.

Raises

TimeoutError – If the maximum timeout is reached.

Return type

ops.pebble.Change

add_layer(label, layer, *, combine=False)[source]

Dynamically add a new layer onto the Pebble configuration layers.

If combine is False (the default), append the new layer as the top layer with the given label. If combine is True and the label already exists, the two layers are combined into a single one considering the layer override rules; if the layer doesn’t exist, it is added as usual.

Parameters
get_plan()[source]

Get the Pebble plan (currently contains only combined services).

Return type

ops.pebble.Plan

get_services(names=None)[source]

Get the service status for the configured services.

If names is specified, only fetch the service status for the services named.

Parameters

names (Optional[List[str]]) –

Return type

List[ops.pebble.ServiceInfo]

pull(path, *, encoding='utf-8')[source]

Read a file’s content from the remote system.

Parameters
  • path (str) – Path of the file to read from the remote system.

  • encoding (str) – Encoding to use for decoding the file’s bytes to str, or None to specify no decoding.

Returns

A readable file-like object, whose read() method will return str objects decoded according to the specified encoding, or bytes if encoding is None.

Return type

Union[BinaryIO, TextIO]

push(path, source, *, encoding='utf-8', make_dirs=False, permissions=None, user_id=None, user=None, group_id=None, group=None)[source]

Write content to a given file path on the remote system.

Parameters
  • path (str) – Path of the file to write to on the remote system.

  • source (Union[bytes, str, BinaryIO, TextIO]) – Source of data to write. This is either a concrete str or bytes instance, or a readable file-like object.

  • encoding (str) – Encoding to use for encoding source str to bytes, or strings read from source if it is a TextIO type. Ignored if source is bytes or BinaryIO.

  • make_dirs (bool) – If True, create parent directories if they don’t exist.

  • permissions (Optional[int]) – Permissions (mode) to create file with (Pebble default is 0o644).

  • user_id (Optional[int]) – User ID (UID) for file.

  • user (Optional[str]) – Username for file. User’s UID must match user_id if both are specified.

  • group_id (Optional[int]) – Group ID (GID) for file.

  • group (Optional[str]) – Group name for file. Group’s GID must match group_id if both are specified.

list_files(path, *, pattern=None, itself=False)[source]

Return list of directory entries from given path on remote system.

Despite the name, this method returns a list of files and directories, similar to os.listdir() or os.scandir().

Parameters
  • path (str) – Path of the directory to list, or path of the file to return information about.

  • pattern (Optional[str]) – If specified, filter the list to just the files that match, for example *.txt.

  • itself (bool) – If path refers to a directory, return information about the directory itself, rather than its contents.

Return type

List[ops.pebble.FileInfo]

make_dir(path, *, make_parents=False, permissions=None, user_id=None, user=None, group_id=None, group=None)[source]

Create a directory on the remote system with the given attributes.

Parameters
  • path (str) – Path of the directory to create on the remote system.

  • make_parents (bool) – If True, create parent directories if they don’t exist.

  • permissions (Optional[int]) – Permissions (mode) to create directory with (Pebble default is 0o755).

  • user_id (Optional[int]) – User ID (UID) for directory.

  • user (Optional[str]) – Username for directory. User’s UID must match user_id if both are specified.

  • group_id (Optional[int]) – Group ID (GID) for directory.

  • group (Optional[str]) – Group name for directory. Group’s GID must match group_id if both are specified.

remove_path(path, *, recursive=False)[source]

Remove a file or directory on the remote system.

Parameters
  • path (str) – Path of the file or directory to delete from the remote system.

  • recursive (bool) – If True, recursively delete path and everything under it.

ops.testing module

Infrastructure to build unittests for Charms using the Operator Framework.

class ops.testing.Harness(charm_cls, *, meta=None, actions=None, config=None)[source]

Bases: Generic[typing.CharmType]

This class represents a way to build up the model that will drive a test suite.

The model that is created is from the viewpoint of the charm that you are testing.

Example:

harness = Harness(MyCharm)
# Do initial setup here
relation_id = harness.add_relation('db', 'postgresql')
# Now instantiate the charm to see events as the model changes
harness.begin()
harness.add_relation_unit(relation_id, 'postgresql/0')
harness.update_relation_data(relation_id, 'postgresql/0', {'key': 'val'})
# Check that charm has properly handled the relation_joined event for postgresql/0
self.assertEqual(harness.charm. ...)
Parameters
  • charm_cls – The Charm class that you’ll be testing.

  • meta – charm.CharmBase is a A string or file-like object containing the contents of metadata.yaml. If not supplied, we will look for a ‘metadata.yaml’ file in the parent directory of the Charm, and if not found fall back to a trivial ‘name: test-charm’ metadata.

  • actions – A string or file-like object containing the contents of actions.yaml. If not supplied, we will look for a ‘actions.yaml’ file in the parent directory of the Charm.

  • config – A string or file-like object containing the contents of config.yaml. If not supplied, we will look for a ‘config.yaml’ file in the parent directory of the Charm.

property charm

Return the instance of the charm class that was passed to __init__.

Note that the Charm is not instantiated until you have called begin().

property model

Return the Model that is being driven by this Harness.

property framework

Return the Framework that is being driven by this Harness.

begin()[source]

Instantiate the Charm and start handling events.

Before calling begin(), there is no Charm instance, so changes to the Model won’t emit events. You must call begin() before charm is valid.

Return type

None

begin_with_initial_hooks()[source]

Called when you want the Harness to fire the same hooks that Juju would fire at startup.

This triggers install, relation-created, config-changed, start, and any relation-joined hooks. Based on what relations have been defined before you called begin(). Note that all of these are fired before returning control to the test suite, so if you want to introspect what happens at each step, you need to fire them directly (eg Charm.on.install.emit()).

To use this with all the normal hooks, you should instantiate the harness, setup any relations that you want active when the charm starts, and then call this method.

Example:

harness = Harness(MyCharm)
# Do initial setup here
# Add storage if needed before begin_with_initial_hooks() is called
storage_id = harness.add_storage('data', count=1)
relation_id = harness.add_relation('db', 'postgresql')
harness.add_relation_unit(relation_id, 'postgresql/0')
harness.update_relation_data(relation_id, 'postgresql/0', {'key': 'val'})
harness.set_leader(True)
harness.update_config({'initial': 'config'})
harness.begin_with_initial_hooks()
# This will cause
# install, db-relation-created('postgresql'), leader-elected, config-changed, start
# db-relation-joined('postrgesql/0'), db-relation-changed('postgresql/0')
# To be fired.
Return type

None

cleanup()[source]

Called by your test infrastructure to cleanup any temporary directories/files/etc.

Currently this only needs to be called if you test with resources. But it is reasonable to always include a testcase.addCleanup(harness.cleanup) just in case.

Return type

None

add_oci_resource(resource_name, contents=None)[source]

Add oci resources to the backend.

This will register an oci resource and create a temporary file for processing metadata about the resource. A default set of values will be used for all the file contents unless a specific contents dict is provided.

Parameters
  • resource_name (str) – Name of the resource to add custom contents to.

  • contents (Optional[Mapping[str, str]]) – Optional custom dict to write for the named resource.

Return type

None

add_resource(resource_name, content)[source]

Add content for a resource to the backend.

This will register the content, so that a call to Model.resources.fetch(resource_name) will return a path to a file containing that content.

Parameters
  • resource_name (str) – The name of the resource being added

  • content (AnyStr) – Either string or bytes content, which will be the content of the filename returned by resource-get. If contents is a string, it will be encoded in utf-8

Return type

None

populate_oci_resources()[source]

Populate all OCI resources.

Return type

None

disable_hooks()[source]

Stop emitting hook events when the model changes.

This can be used by developers to stop changes to the model from emitting events that the charm will react to. Call enable_hooks() to re-enable them.

Return type

None

enable_hooks()[source]

Re-enable hook events from charm.on when the model is changed.

By default hook events are enabled once you call begin(), but if you have used disable_hooks(), this can be used to enable them again.

Return type

None

hooks_disabled()[source]

A context manager to run code with hooks disabled.

Example:

with harness.hooks_disabled():
    # things in here don't fire events
    harness.set_leader(True)
    harness.update_config(unset=['foo', 'bar'])
# things here will again fire events
add_storage(storage_name, count=1)[source]

Declare a new storage device attached to this unit.

To have repeatable tests, each device will be initialized with location set to /<storage_name>N, where N is the counter and will be a number from [0,total_num_disks-1]

Parameters
  • storage_name (str) – The storage backend name on the Charm

  • count (int) – Number of disks being added

Returns

The storage_id created

Return type

int

add_relation(relation_name, remote_app)[source]

Declare that there is a new relation between this app and remote_app.

Parameters
  • relation_name (str) – The relation on Charm that is being related to

  • remote_app (str) – The name of the application that is being related to

Returns

The relation_id created by this add_relation.

Return type

int

remove_relation(relation_id)[source]

Remove a relation.

Parameters

relation_id (int) – The relation ID for the relation to be removed.

Raises

RelationNotFoundError – if relation id is not valid

Return type

None

add_relation_unit(relation_id, remote_unit_name)[source]

Add a new unit to a relation.

Example:

rel_id = harness.add_relation('db', 'postgresql')
harness.add_relation_unit(rel_id, 'postgresql/0')

This will trigger a relation_joined event. This would naturally be followed by a relation_changed event, which you can trigger with update_relation_data(). This separation is artificial in the sense that Juju will always fire the two, but is intended to make testing relations and their data bags slightly more natural.

Parameters
  • relation_id (int) – The integer relation identifier (as returned by add_relation).

  • remote_unit_name (str) – A string representing the remote unit that is being added.

Returns

None

Return type

None

remove_relation_unit(relation_id, remote_unit_name)[source]

Remove a unit from a relation.

Example:

rel_id = harness.add_relation('db', 'postgresql')
harness.add_relation_unit(rel_id, 'postgresql/0')
...
harness.remove_relation_unit(rel_id, 'postgresql/0')

This will trigger a relation_departed event. This would normally be followed by a relation_changed event triggered by Juju. However when using the test harness a relation_changed event must be triggererd using update_relation_data(). This deviation from normal Juju behaviour, facilitates testing by making each step in the charm life cycle explicit.

Parameters
  • relation_id (int) – The integer relation identifier (as returned by add_relation).

  • remote_unit_name (str) – A string representing the remote unit that is being added.

Raises
  • KeyError – if relation_id or remote_unit_name is not valid

  • ValueError – if remote_unit_name is not valid

Return type

None

get_relation_data(relation_id, app_or_unit)[source]

Get the relation data bucket for a single app or unit in a given relation.

This ignores all of the safety checks of who can and can’t see data in relations (eg, non-leaders can’t read their own application’s relation data because there are no events that keep that data up-to-date for the unit).

Parameters
  • relation_id (int) – The relation whose content we want to look at.

  • app_or_unit (str) – The name of the application or unit whose data we want to read

Returns

A dict containing the relation data for app_or_unit or None.

Raises

KeyError – if relation_id doesn’t exist

Return type

Mapping

get_pod_spec()[source]

Return the content of the pod spec as last set by the charm.

This returns both the pod spec and any k8s_resources that were supplied. See the signature of Model.pod.set_spec

Return type

(typing.Mapping, typing.Mapping)

get_container_pebble_plan(container_name)[source]

Return the current Plan that pebble is executing for the given container.

Parameters

container_name (str) – The simple name of the associated container

Returns

The pebble.Plan for this container. You can use ops.pebble.Plan.to_yaml() to get a string form for the content. Will raise KeyError if no pebble client exists for that container name. (should only happen if container is not present in metadata.yaml)

Return type

ops.pebble.Plan

container_pebble_ready(container_name)[source]

Fire the pebble_ready hook for the associated container.

This will do nothing if the begin() has not been called.

Parameters

container_name (str) –

get_workload_version()[source]

Read the workload version that was set by the unit.

Return type

str

set_model_info(name=None, uuid=None)[source]

Set the name and uuid of the Model that this is representing.

This cannot be called once begin() has been called. But it lets you set the value that will be returned by Model.name and Model.uuid.

This is a convenience method to invoke both Harness.set_model_name and Harness.set_model_uuid at once.

Parameters
  • name (Optional[str]) –

  • uuid (Optional[str]) –

Return type

None

set_model_name(name)[source]

Set the name of the Model that this is representing.

This cannot be called once begin() has been called. But it lets you set the value that will be returned by Model.name.

Parameters

name (str) –

Return type

None

set_model_uuid(uuid)[source]

Set the uuid of the Model that this is representing.

This cannot be called once begin() has been called. But it lets you set the value that will be returned by Model.uuid.

Parameters

uuid (str) –

Return type

None

update_relation_data(relation_id, app_or_unit, key_values)[source]

Update the relation data for a given unit or application in a given relation.

This also triggers the relation_changed event for this relation_id.

Parameters
  • relation_id (int) – The integer relation_id representing this relation.

  • app_or_unit (str) – The unit or application name that is being updated. This can be the local or remote application.

  • key_values (Mapping) – Each key/value will be updated in the relation data.

Return type

None

update_config(key_values=None, unset=())[source]

Update the config as seen by the charm.

This will trigger a config_changed event.

Note that the key_values mapping will only add or update configuration items. To remove existing ones, see the unset parameter.

Parameters
  • key_values (Optional[Mapping[str, str]]) – A Mapping of key:value pairs to update in config.

  • unset (Iterable[str]) – An iterable of keys to remove from Config. (Note that this does not currently reset the config values to the default defined in config.yaml.)

Return type

None

set_leader(is_leader=True)[source]

Set whether this unit is the leader or not.

If this charm becomes a leader then leader_elected will be triggered.

Parameters

is_leader (bool) – True/False as to whether this unit is the leader.

Return type

None

Indices and tables