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.
  • Version 2.x of ops requires Python 3.8 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://ops.readthedocs.io/en/latest/reference/pebble.html
        """
        # 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 2.23.5

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 2.23.5
File Size Uploaded
ops-2.23.5.tar.gz 538.8 kB Details

Built distribution (wheel)

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

Total release size: 729.9 kB

Release files / ops-2.23.5.tar.gz

Download URL ops-2.23.5.tar.gz
Size 538.8 kB
Tags Source
SHA-256 checksum
How to use checksums
270dc1581ed437205cbb385354e778e9ed302c5a4b89b0ef8a738a16d6516aff
BLAKE2b-256 checksum
How to use checksums
e56c4765feeaffe2a2c6ee4d7de0f06512b2cc84a7f97f5ea19c96db9b4436da
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 Aug 31, 2026.

Transparency log

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

Download URL ops-2.23.5-py3-none-any.whl
Size 191.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d18ccdb56db17c4ee51c4a3dfcb930f09da0fe411ae1551559e0a7b60aa3b1d0
BLAKE2b-256 checksum
How to use checksums
98fba58bca4e7a94bc80d83062f1eebaa912c6381b16a61e8ba17aba4eb05376
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 Aug 31, 2026.

Transparency log

Release history Release notifications | RSS feed

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

This release

2.23.5 This release

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