From 2e3997df835878927edcbdc32fdd1a30a9c56b27 Mon Sep 17 00:00:00 2001 From: Teodora Mihoc Date: Fri, 20 Oct 2023 17:29:36 +0200 Subject: [PATCH] Update README.md to simplify and better align with docs --- README.md | 215 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 154 insertions(+), 61 deletions(-) diff --git a/README.md b/README.md index b8cd27a96..b48588995 100644 --- a/README.md +++ b/README.md @@ -1,94 +1,187 @@ -# The ops library +# The `ops` library - -The ops library is a Python framework ([`available on PyPI`](https://pypi.org/project/ops/)) for developing -and testing [Juju](https://juju.is/) charms in a consistent way, using standard Python constructs -to allow for clean, maintainable, and reusable code. +The `ops` library is a Python framework for developing and testing charms in a consistent way, using standard Python constructs to allow for clean, maintainable, and reusable code. It is an official component of the Charm SDK, itself a crucial part of the Juju universe. -A charm is an operator -- business logic encapsulated in a reusable software -package that automates every aspect of an application's life. +> ✔️ `ops` is ([`available on PyPI`](https://pypi.org/project/ops/)). +> +> ⚠️ The latest version of `ops` requires Python 3.8 or above. +> +> 🥇 While charms can be written in any language, `ops` defines the latest standard. All new charms are encouraged to use it. -Charms written with ops support Kubernetes using Juju's "sidecar charm" -pattern, as well as charms that deploy to Linux-based machines and containers. -Charms should do one thing and do it well. Each charm drives a single -application and can be integrated with other charms to deliver a complex -system. A charm handles creating the application in addition to scaling, -configuration, optimisation, networking, service mesh, observability, and other -day-2 operations specific to the application. -The ops library is part of the Charm SDK (the other part being Charmcraft). -Full developer documentation for the Charm SDK is available at -https://juju.is/docs/sdk. +|||| +|-|-|- | +|| Learn about Juju! | Start deploying charms:
https://juju.is/docs/juju
_Juju is declarative, model-driven, and has native support for integrations and scaling, on any cloud. You want to deploy `foo`? Run `juju deploy foo`! You wish to integrate `foo` and `bar`? Run `juju integrate foo bar`!_ | +|||| +|| Get better at Juju! | Take advantage of the charm ecosystem:
https://charmhub.io/
_Quickly deploy a cluster ([OpenStack](https://charmhub.io/openstack-base), [Kubernetes](https://charmhub.io/charmed-kubernetes)), a database ([PostgreSQL](https://charmhub.io/postgresql-k8s), [MongoDB](https://charmhub.io/mongodb), etc.), an observability stack ([Canonical Observability Stack](https://charmhub.io/cos-lite)), an MLOps solution ([Kubeflow](https://charmhub.io/kubeflow)), and so much more!_ | +|||| +|:point_right:| **Make Juju your own!** | Write your own charm:
https://juju.is/docs/sdk
_Juju is written in Go, but our SDK supports easy charm development in Python!_ | -To learn more about Juju, visit https://juju.is/docs/olm. +## Give it a try! +Let's use `ops` to build a Kubernetes charm! -## Pure Python +### Set up -The framework provides a standardised Python object model that represents the -application graph, as well as an event-handling mechanism for distributed -system coordination and communication. +You will need Charmcraft, a Kubernetes cloud, and Juju. The quickest way is to use a Multipass VM launched with the `charm-dev` blueprint. -The latest version of ops requires Python 3.8 or above. +Install Multipass: [Linux](https://multipass.run/docs/installing-on-linux) | [macOS](https://multipass.run/docs/installing-on-macos) | [Windows](https://multipass.run/docs/installing-on-windows). On Linux: -Juju itself is written in Go for efficient concurrency even in large -deployments. Charms can be written in any language, however, we recommend using -Python with this framework to make development easier and more standardised. -All new charms at Canonical are written using it. +``` +sudo snap install multipass +``` + +Use Multipass to launch an Ubuntu VM with the `charm-dev` blueprint: + +``` +multipass launch --cpus 4 --memory 8G --disk 30G --name tutorial-vm charm-dev +``` + +Open a shell into the VM: + +``` +multipass shell tutorial-vm +``` + +Verify that you have Charmcraft, MicroK8s, and Juju: + +``` +snap list # should show all three +``` + +Verify that Juju recognizes MicroK8s as a localhost cloud: + +``` +juju clouds # should show both +``` + +Bootstrap a Juju controller into the MicroK8s cloud: + +``` +juju bootstrap microk8s tutorial-controller +``` + +Add a workspace, or 'model': + +``` +juju add-model tutorial-model +``` + +### Write your charm +Create a charm directory and use Charmcraft to initialise your charm file structure: -## Getting started +``` +mkdir my-new-charm; cd my-new-charm; charmcraft init +``` +This has created a standard charm directory structure. Poke around. -A package of operator code is called a charmed operator or simply "charm". -You'll use [charmcraft](https://juju.is/docs/sdk/install-charmcraft) to -register your charm name and publish it when you are ready. You can follow one -of our [charming tutorials](https://juju.is/docs/sdk/tutorials) to get started -writing your first charm. +Note that the `metadata.yaml` file shows that what we have is an example charm called `my-new-charm`, which uses an OCI image resource `httpbin` from `kennethreitz/httpbin`. +Note that the `requirements.txt` file lists a version of `ops`. -## Testing your charms +Note that the `src/charm.py` file imports `ops` and uses `ops` constructs to create a charm class `MyNewCharmCharm`, observe Juju events, and pair them to event handlers: + +``` +... +import ops +... +class MyNewCharmCharm(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 at https://juju.is/docs/sdk/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 in the SDK docs: + # https://juju.is/docs/sdk/constructs#heading--statuses + self.unit.status = ops.ActiveStatus() +... +``` -The framework provides a testing harness, so you can ensure that your charm -does the right thing in different scenarios, without having to create -a full deployment. Our [API documentation](https://ops.readthedocs.io/en/latest/#module-ops.testing) -has the details, including this example: +> See more: [`ops.PebbleReadyEvent`](https://ops.readthedocs.io/en/latest/index.html#ops.PebbleReadyEvent) -```python +Note that the `tests/test_charm.py` file imports `ops.testing` and uses it to set up a testing harness: + +``` +... +import ops.testing +... class TestCharm(unittest.TestCase): - def test_foo(self): - harness = Harness(MyCharm) - self.addCleanup(harness.cleanup) # always clean up after ourselves + def setUp(self): + self.harness = ops.testing.Harness(MyNewCharmCharm) + self.addCleanup(self.harness.cleanup) + self.harness.begin() +... +``` - # Instantiate the charm and trigger events that Juju would on startup - harness.begin_with_initial_hooks() +> See more: [`ops.testing.Harness`](https://ops.readthedocs.io/en/latest/#ops.testing.Harness) - # Update charm config and trigger config-changed - harness.update_config({'log_level': 'warn'}) - # Check that charm properly handled config-changed, for example, - # the charm added the correct Pebble layer - plan = harness.get_container_pebble_plan('prometheus') - self.assertIn('--log.level=warn', plan.services['prometheus'].command) +Explore further, start editing the files, or skip ahead and pack charm: + +``` +charmcraft pack ``` +If you didn't take any wrong turn or simply left the charm exactly as it was, this should work and yield a file called `my-new-charm_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 ./my-new-charm_ubuntu-22.04-amd64.charm --resource httpbin-image=kennethreitz/httpbin +``` + +Congratulations, you’ve just built your first Kubernetes charm using Ops! + +### Clean up + +Delete your Multipass VM: + +``` +multipass delete --purge my-vm +``` + +Uninstall Multipass: [Linux](https://multipass.run/docs/installing-on-linux) | [macOS](https://multipass.run/docs/installing-on-macos) | [Windows](https://multipass.run/docs/installing-on-windows). On Linux: + +``` +snap remove multipass +``` -## Talk to us +## Next steps -If you need help, have ideas, or would just like to chat with us, reach out on -the Charmhub [Mattermost]. +### Learn more +- Read our [user docs](https://juju.is/docs/sdk/ops) (which include links to the [API reference](https://ops.readthedocs.io/en/latest/) and other guides showing Ops in action) -We also pay attention to the Charmhub [Discourse]. +### Chat with us -And of course you can deep dive into the [API reference]. +Read our [Code of conduct](https://ubuntu.com/community/code-of-conduct) and: +- Join our chat: [Mattermost](https://chat.charmhub.io/charmhub/channels/charm-dev) +- Join our forum: [Discourse](https://discourse.charmhub.io/) + +### File an issue -[Discourse]: https://discourse.charmhub.io/ -[API reference]: https://ops.readthedocs.io/ -[Mattermost]: https://chat.charmhub.io/charmhub/channels/charm-dev +- Report an `ops` bug on [GitHub](https://github.com/canonical/operator/issues) +- Raise a general https://juju.is/docs documentation issue on [GitHub | juju/docs](https://github.com/juju/docs) +### Make your mark -## Development of the framework +- Read our [documentation contributor guidelines](https://discourse.charmhub.io/t/documentation-guidelines-for-contributors/1245) and help improve a doc +- Read our [codebase contributor guidelines](HACKING.md) and help improve the codebase +- Write a charm and publish it on [Charmhub](https://charmhub.io/) -See [HACKING.md](HACKING.md) for details on dev environments, testing, and so -on.