Welcome to The Operator Framework’s documentation!

ops package

The Operator Framework.

Submodules

ops.charm module

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

Bases: ops.framework.EventBase

A base class for events that trigger when a user asks for an Action to be run.

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.

Variables

params – The parameters passed to the action (read by action-get)

defer()[source]

Action events are not deferable like other events.

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

fail(message='')[source]

Report that this action has failed.

Parameters

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

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

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

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

Bases: object

Object containing metadata about an action’s definition.

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

Bases: ops.framework.Object

Base class that represents the Charm overall.

Usually this initialization is done by ops.main.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.

property app

Application that this unit is part of.

property charm_dir

Root directory of the Charm as it is running.

property meta

CharmMeta of this charm.

on

The events that are generated by Juju in response to the lifecycle of an application.

property unit

Unit that this execution is responsible for.

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

Bases: ops.framework.ObjectEvents

The events that are generated by Juju in response to the lifecycle of an application.

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.

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.

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.

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.

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.

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.

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.

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.

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.

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.

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, storage, 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.CollectMetricsEvent(handle)[source]

Bases: ops.charm.HookEvent

Represents the collect-metrics hook from Juju.

Note that events firing during a CollectMetricsEvent are currently sandboxed in how they can interact with Juju. To report metrics use add_metrics().

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 (Mapping) – {key:value} strings that can be applied to the metrics that are being gathered

Return type

None

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

Bases: ops.charm.HookEvent

Represents the config-changed hook from Juju.

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

Bases: ops.framework.EventBase

A base class for events that trigger because of a Juju hook firing.

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

Bases: ops.charm.HookEvent

Represents the install hook from Juju.

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

Bases: ops.charm.HookEvent

Represents the leader-elected hook from Juju.

Juju will trigger this when a new lead unit is chosen for a given application. This represents the leader of the charm information (not necessarily the primary of a running application). The main utility is that charm authors can know that only one unit will be a leader at any given time, so they can do configuration, etc, that would otherwise require coordination between units. (eg, selecting a password for a new relation)

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

Bases: ops.charm.HookEvent

Represents the leader-settings-changed hook from Juju.

Deprecated. This represents when a lead unit would call leader-set to inform the other units of an application that they have new information to handle. This 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.PayloadMeta(name, raw)[source]

Bases: object

Object containing metadata about a payload definition.

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

Bases: ops.charm.HookEvent

Represents the post-series-upgrade hook from Juju.

This is run after the user has done a distribution upgrade (or rolled back and kept the same series). It is called in response to juju upgrade-series MACHINE complete. Charms are expected to do whatever steps are necessary to reconfigure their applications for the new series.

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

Bases: ops.charm.HookEvent

Represents the pre-series-upgrade hook from Juju.

This happens when a user has run juju upgrade-series MACHINE prepare and will fire for each unit that is running on the machine, telling them that the user is preparing to upgrade the Machine’s series (eg trusty->bionic). The charm should take actions to prepare for the upgrade (a database charm would want to write out a version-independent dump of the database, so that when a new version of the database is available in a new series, it can be used.) Once all units on a machine have run pre-series-upgrade, the user will initiate the steps to actually upgrade the machine (eg do-release-upgrade). When the upgrade has been completed, the PostSeriesUpgradeEvent will fire.

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

Bases: ops.charm.RelationEvent

Represents the relation-broken hook from Juju.

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

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

Bases: ops.charm.RelationEvent

Represents the relation-changed hook from Juju.

This 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.

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

Bases: ops.charm.RelationEvent

Represents the relation-created hook from Juju.

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.RelationDepartedEvent(handle, relation, app=None, unit=None)[source]

Bases: ops.charm.RelationEvent

Represents the relation-departed hook from Juju.

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.

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

Bases: ops.charm.HookEvent

A base class representing the various relation lifecycle events.

Charmers should not be creating RelationEvents directly. The events will be generated by the framework from Juju related events. Users can observe them from the various CharmBase.on[relation_name].relation_* events.

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

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

snapshot()[source]

Used by the framework to serialize the event to disk.

Not meant to be called by Charm code.

Return type

dict

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

Bases: ops.charm.RelationEvent

Represents the relation-joined hook from Juju.

This is triggered whenever a new unit of a related application joins the relation. (eg, a unit was added to an existing related app, or a new relation was established with an application that already had units.)

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 one of peer/requires/provides

relation_name

Name of this relation from metadata.yaml

interface_name

Optional definition of the interface protocol.

scope

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

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

Bases: enum.Enum

An enumeration.

is_peer()[source]

Return whether the current role is peer.

A convenience to avoid having to import charm.

Return type

bool

peer = 'peer'
provides = 'provides'
requires = 'requires'
class ops.charm.RemoveEvent(handle)[source]

Bases: ops.charm.HookEvent

Represents the remove hook from Juju.

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

Bases: object

Object containing metadata about a resource definition.

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

Bases: ops.charm.HookEvent

Represents the start hook from Juju.

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

Bases: ops.charm.HookEvent

Represents the stop hook from Juju.

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

Bases: ops.charm.StorageEvent

Represents the storage-attached hook from Juju.

Called when new storage is available for the charm to use.

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

Bases: ops.charm.StorageEvent

Represents the storage-detaching hook from Juju.

Called when storage a charm has been using is going away.

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

Bases: ops.charm.HookEvent

Base class representing Storage related events.

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

Bases: object

Object containing metadata about a storage definition.

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

Bases: ops.charm.HookEvent

Represents the update-status hook from Juju.

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

Bases: ops.charm.HookEvent

Represents the upgrade-charm hook from Juju.

This will be triggered when a user has run juju upgrade-charm. It is run after Juju has unpacked the upgraded charm code, and so this event will be handled with new code.

ops.framework module

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

Bases: 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.BoundStoredState(parent, attr_name)[source]

Bases: object

set_default(**kwargs)[source]

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

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

Bases: ops.framework.EventBase

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

Bases: object

defer()[source]
restore(snapshot)[source]

Restore the value state from the given snapshot.

Subclasses must override to restore their custom state.

snapshot()[source]

Return the snapshot data that should be persisted.

Subclasses must override to save any 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.Framework(storage, charm_dir, meta, model)[source]

Bases: ops.framework.Object

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.

charm_dir = None
close()[source]
commit()[source]
drop_snapshot(handle)[source]
load_snapshot(handle)[source]
meta = None
model = None
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
on
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.

register_type(cls, parent, kind=None)[source]
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.

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.

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

Bases: ops.framework.ObjectEvents

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.

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.

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.

classmethod from_path(path)[source]
property key
property kind
nest(kind, key)[source]
property parent
property path
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.

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

Bases: Exception

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

Bases: object

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
class ops.framework.ObjectEvents(parent=None, key=None)[source]

Bases: ops.framework.Object

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

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.

handle_kind = 'on'
class ops.framework.PreCommitEvent(handle)[source]

Bases: ops.framework.EventBase

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

Bases: object

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

Bases: collections.abc.MutableMapping

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

Bases: collections.abc.MutableSequence

append(value)[source]

S.append(value) – append value to the end of the sequence

insert(index, value)[source]

S.insert(index, value) – insert value before index

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

Bases: collections.abc.MutableSet

add(key)[source]

Add an element.

discard(key)[source]

Remove an element. Do not raise an exception if absent.

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.StoredStateData(parent, attr_name)[source]

Bases: ops.framework.Object

on_commit(event)[source]
restore(snapshot)[source]
snapshot()[source]

ops.jujuversion module

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

Bases: object

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

ops.log module

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]

Do whatever it takes to actually log the specified logging record.

This version is intended to be implemented by subclasses and so raises a NotImplementedError.

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)

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

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

Setup the charm and dispatch the observed event.

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

ops.model module

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.

name = 'active'
class ops.model.Application(name, 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')
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.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, Relation]) –

Return type

ops.model.Binding

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.

name = 'blocked'
class ops.model.ConfigData(backend)[source]

Bases: ops.model.LazyMapping

exception ops.model.InvalidStatusError[source]

Bases: ops.model.ModelError

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

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.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.

name = 'maintenance'
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
unit

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

app

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

relations

Mapping of endpoint to list of Relation answering the question “what am I currently related to”. See also get_relation()

config

A dict of the config for the current application.

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.

storages

Mapping of storage_name to Storage for the storage points defined in metadata.yaml

pod

Used to get access to model.pod.set_spec to set the container specification for Kubernetes charms.

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_binding(binding_key)[source]

Get a network space binding.

Parameters

binding_key (Union[str, 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

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_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

property name

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

This is read from the environment variable JUJU_MODEL_NAME.

exception ops.model.ModelError[source]

Bases: Exception

Base class for exceptions raised when interacting with the Model.

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.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. :param spec: The mapping defining the pod specification :param k8s_resources: Additional kubernetes specific specification.

Returns

None

Parameters
  • spec (Mapping) –

  • k8s_resources (Mapping) –

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 RelationEvent.relation.

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

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.)

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

Bases: collections.abc.Mapping

Map of relation names to lists of Relation instances.

exception ops.model.RelationNotFoundError[source]

Bases: ops.model.ModelError

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

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.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.

classmethod from_name(name, message)[source]
Parameters
  • name (str) –

  • message (str) –

name = None
classmethod register(child)[source]
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
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) –

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.

class ops.model.Unit(name, 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.

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 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')
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.

name = 'unknown'
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.

name = 'waiting'

ops.testing module

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

Bases: object

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 (Type[ops.charm.CharmBase]) – The Charm class that you’ll be testing.

  • meta (Optional[Union[str, TextIO]]) – 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 (Optional[Union[str, TextIO]]) – 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.

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 (Mapping[str, str]) – Optional custom dict to write for the named resource.

Return type

None

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

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 and a relation_changed event.

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

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

  • contents – 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

  • content (AnyStr) –

Return type

None

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 :meth:().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
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

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().

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

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

property framework

Return the Framework that is being driven by this Harness.

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_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_workload_version()[source]

Read the workload version that was set by the unit.

Return type

str

property model

Return the Model that is being driven by this Harness.

populate_oci_resources()[source]

Populate all OCI resources.

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

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

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 (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

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

Indices and tables