-
Notifications
You must be signed in to change notification settings - Fork 122
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Update README.md to simplify and better align with docs
- Loading branch information
Showing
1 changed file
with
154 additions
and
61 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,94 +1,187 @@ | ||
# The ops library | ||
# The `ops` library | ||
|
||
<!-- The text below is also at the top of ops/__init__.py. Keep in sync! --> | ||
|
||
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: <br> https://juju.is/docs/juju <br> _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: <br> https://charmhub.io/ <br> _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: <br> https://juju.is/docs/sdk <br> _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. |