Skip to main content

The ops library

CI Status

The ops library is a Python framework for developing and testing Kubernetes and machine charms. While charms can be written in any language, ops defines the latest standard, and charmers are encouraged to use Python with ops for all charms. The library is an official component of the Charm SDK, itself a part of the Juju universe.

  • ops is available on PyPI.
  • The latest version of ops requires Python 3.10 or above.
  • Read our docs for tutorials, how-to guides, the library reference, and more.

Give it a try

Let's use ops to build a Kubernetes charm:

Set up

See Juju | Set things up.
Choose the automatic track and MicroK8s.

Write your charm

On your Multipass VM, create a charm directory and use Charmcraft to initialise your charm file structure:

mkdir ops-example
cd ops-example
charmcraft init

This has created a standard charm directory structure:

$ ls -R
.:
CONTRIBUTING.md  README.md        pyproject.toml    src    tox.ini
LICENSE          charmcraft.yaml  requirements.txt  tests

./src:
charm.py

./tests:
integration  unit

./tests/integration:
test_charm.py

./tests/unit:
test_charm.py

Things to note:

  • The charmcraft.yaml file shows that what we have is an example charm called ops-example, which uses an OCI image resource httpbin from kennethreitz/httpbin.

  • The requirements.txt file lists the version of ops to use.

  • The src/charm.py file imports ops and uses ops constructs to create a charm class OpsExampleCharm, observe Juju events, and pair them to event handlers:

import ops


class OpsExampleCharm(ops.CharmBase):
    """Charm the service."""

    def __init__(self, *args):
        super().__init__(*args)
        self.framework.observe(self.on['httpbin'].pebble_ready, self._on_httpbin_pebble_ready)
        self.framework.observe(self.on.config_changed, self._on_config_changed)

    def _on_httpbin_pebble_ready(self, event: ops.PebbleReadyEvent):
        """Define and start a workload using the Pebble API.

        Change this example to suit your needs. You'll need to specify the right entrypoint and
        environment configuration for your specific workload.

        Learn more about interacting with Pebble at
            https://canonical.com/juju/docs/ops/latest/reference/pebble/
        """
        # Get a reference the container attribute on the PebbleReadyEvent
        container = event.workload
        # Add initial Pebble config layer using the Pebble API
        container.add_layer('httpbin', self._pebble_layer, combine=True)
        # Make Pebble reevaluate its plan, ensuring any services are started if enabled.
        container.replan()
        # Learn more about statuses at
        # https://documentation.ubuntu.com/juju/3.6/reference/status/
        self.unit.status = ops.ActiveStatus()

See more: ops.PebbleReadyEvent

  • The tests/unit/test_charm.py file imports ops.testing and uses it to set up a unit test:
import ops
from ops import testing

from charm import OpsExampleCharm


def test_httpbin_pebble_ready():
    # Arrange:
    ctx = testing.Context(OpsExampleCharm)
    container = testing.Container('httpbin', can_connect=True)
    state_in = testing.State(containers={container})

    # Act:
    state_out = ctx.run(ctx.on.pebble_ready(container), state_in)

    # Assert:
    updated_plan = state_out.get_container(container.name).plan
    expected_plan = {
        'services': {
            'httpbin': {
                'override': 'replace',
                'summary': 'httpbin',
                'command': 'gunicorn -b 0.0.0.0:80 httpbin:app -k gevent',
                'startup': 'enabled',
                'environment': {'GUNICORN_CMD_ARGS': '--log-level info'},
            }
        },
    }
    assert expected_plan == updated_plan
    assert (
        state_out.get_container(container.name).service_statuses['httpbin']
        == ops.pebble.ServiceStatus.ACTIVE
    )
    assert state_out.unit_status == testing.ActiveStatus()

See more: ops.testing

Explore further, start editing the files, or skip ahead and pack the charm:

charmcraft pack

If you didn't take any wrong turn or simply left the charm exactly as it was, this has created a file called ops-example_ubuntu-22.04-amd64.charm (the architecture bit may be different depending on your system's architecture). Use this name and the resource from the metadata.yaml to deploy your example charm to your local MicroK8s cloud:

juju deploy ./ops-example_ubuntu-22.04-amd64.charm --resource httpbin-image=kennethreitz/httpbin

Congratulations, you’ve just built your first Kubernetes charm using ops!

Clean up

See Juju | Tear things down.
Choose the automatic track.

Next steps

Metadata

Release files for ops 3.9.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ops 3.9.0
File Size Uploaded
ops-3.9.0.tar.gz 420.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ops 3.9.0
File Interpreter ABI Platform
ops-3.9.0-py3-none-any.whl Python 3 none any Details

Total release size: 639.6 kB

Release files / ops-3.9.0.tar.gz

Download URL ops-3.9.0.tar.gz
Size 420.4 kB
Tags Source
SHA-256 checksum
How to use checksums
f8fd7fa05359e9fc057663b1a652602f5803db0b37e1bbfe9b63971c54e4b3b3
BLAKE2b-256 checksum
How to use checksums
0f03d87306f7e704a0f75f461d40d6141bfbd1ea38ba329ca0e88f6c3a20cfd5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.

Transparency log

Release files / ops-3.9.0-py3-none-any.whl

Download URL ops-3.9.0-py3-none-any.whl
Size 219.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2dc7a77edae408886ccd348be590df0e03589dfe5e3e115e238d5746850eed0c
BLAKE2b-256 checksum
How to use checksums
7f2ffaf83b14fd88c0e5ae26a4f5eb66f06f708fe322223823acfd45f8d32594
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

3.9.0 This release

2 release files

3.8.3

2 release files

3.8.2

2 release files

3.8.1

2 release files

3.8.0

2 release files

3.7.1

2 release files

3.7.0

2 release files

3.6.0

2 release files

3.5.2

2 release files

3.5.1

2 release files

3.5.0

2 release files

3.4.0

2 release files

3.3.1

2 release files

3.3.0

2 release files

3.2.0

2 release files

3.1.0

2 release files

3.0.0

2 release files

2.23.5

2 release files

2.23.4

2 release files

2.23.2

2 release files

2.23.1

2 release files

2.23.0

2 release files

2.22.0

2 release files

2.21.0

2 release files

2.20.0

2 release files

2.19.4

2 release files

2.19.0

2 release files

2.18.0

2 release files

2.17.1

2 release files

2.17.0

2 release files

2.16.0

2 release files

2.15.0

2 release files

2.14.1

2 release files

2.14.0

2 release files

2.12.0

2 release files

2.11.0

2 release files

2.10.0

2 release files

2.9.0

2 release files

2.8.0

2 release files

2.7.0

2 release files

2.6.0

2 release files

2.5.1

2 release files

2.5.0

2 release files

2.4.1

2 release files

2.4.0

2 release files

2.3.0

2 release files

2.2.0

2 release files

2.1.1

2 release files

2.1.0

2 release files

2.0.0

2 release files

1.5.5

2 release files

1.5.4

2 release files

1.5.3

2 release files

1.5.2

2 release files

1.5.1

2 release files

1.5.0

2 release files

1.4.0

2 release files

1.3.0

2 release files

1.2.0

2 release files

1.1.0

2 release files

1.0.1

2 release files

1.0.0

2 release files

0.10.0

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.4.7

1 release file

0.4.6

1 release file

0.4.5

1 release file

0.4.4

1 release file

0.4.3

1 release file

0.4.2

1 release file

0.2.1

1 release file

0.2.0

1 release file

0.1.0

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page