Package: ops
TheopslibraryTheopslibrary is a Python framework for developing and testing Kubernetes and machinecharms. While charms can be written in any language,opsdefines the latest standard, and charmers are encouraged to use Python withopsfor all charms. The library is an official component of the Charm SDK, itself a part ofthe Juju universe.opsisavailable on PyPI.The latest version ofopsrequires Python 3.8 or above.JujuLearn how to quickly deploy, integrate, and manage charms on any cloud with Juju.It's as simple asjuju deploy foo,juju integrate foo bar, and so on -- on any cloud.CharmhubSample our existing charms on Charmhub.A charm can be a cluster (OpenStack,Kubernetes), a data platform (PostgreSQL,MongoDB, etc.), an observability stack (Canonical Observability Stack), an MLOps solution (Kubeflow), and so much more.:point_right:Charm SDKWrite your own charm!Juju is written in Go, but our SDK supports easy charm development in Python.Give it a tryLet's useopsto build a Kubernetes charm:Set upSeeCharm SDK | Set up an Ubuntucharm-devVM with Multipass.Choose the MicroK8s track.Write your charmOn your Multipass VM, create a charm directory and use Charmcraft to initialise your charm file structure:mkdir ops-example
cd ops-example
charmcraft initThis 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.pyThings to note:Thecharmcraft.yamlfile shows that what we have is an example charm calledops-example, which uses an OCI image resourcehttpbinfromkennethreitz/httpbin.Therequirements.txtfile lists the version ofopsto use.Thesrc/charm.pyfile importsopsand usesopsconstructs to create a charm classOpsExampleCharm, observe Juju events, and pair them to event handlers:importopsclassOpsExampleCharm(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 andenvironment configuration for your specific workload.Learn more about interacting with Pebble at at https://juju.is/docs/sdk/pebble."""# Get a reference the container attribute on the PebbleReadyEventcontainer=event.workload# Add initial Pebble config layer using the Pebble APIcontainer.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 in the SDK docs:# https://juju.is/docs/sdk/constructs#heading--statusesself.unit.status=ops.ActiveStatus()See more:ops.PebbleReadyEventThetests/unit/test_charm.pyfile importsops.testingand uses it to set up a testing harness:importops.testingclassTestCharm(unittest.TestCase):defsetUp(self):self.harness=ops.testing.Harness(OpsExampleCharm)self.addCleanup(self.harness.cleanup)self.harness.begin()deftest_httpbin_pebble_ready(self):# Expected plan after Pebble ready with default configexpected_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"},}},}# Simulate the container coming up and emission of pebble-ready eventself.harness.container_pebble_ready("httpbin")# Get the plan now we've run PebbleReadyupdated_plan=self.harness.get_container_pebble_plan("httpbin").to_dict()# Check we've got the plan we expectedself.assertEqual(expected_plan,updated_plan)# Check the service was startedservice=self.harness.model.unit.get_container("httpbin").get_service("httpbin")self.assertTrue(service.is_running())# Ensure we set an ActiveStatus with no messageself.assertEqual(self.harness.model.unit.status,ops.ActiveStatus())See more:ops.testing.HarnessExplore further, start editing the files, or skip ahead and pack the charm:charmcraft packIf you didn't take any wrong turn or simply left the charm exactly as it was, this has created a file calledops-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 themetadata.yamlto deploy your example charm to your local MicroK8s cloud:juju deploy ./ops-example_ubuntu-22.04-amd64.charm --resource httpbin-image=kennethreitz/httpbinCongratulations, you’ve just built your first Kubernetes charm usingops!Clean upSeeCharm SDK | Clean up.Next stepsLearn moreRead ouruser documentation, which includes other guides showingopsin actionDig into theopsAPI referenceChat with usRead ourCode of conductand:Join our chat:MattermostJoin our forum:DiscourseFile an issueReport anopsbug usingGitHub issuesRaise a generalhttps://juju.is/docsdocumentation issue onGitHub | juju/docsMake your markRead ourdocumentation contributor guidelinesand help improve a docRead ourcodebase contributor guidelinesand help improve the codebaseWrite a charm and publish it onCharmhub