Note: This doc has been superseded by From zero to hero: Write your first Kubernetes charm . Please see that doc instead.
This tutorial will introduce you to writing a Kubernetes charm with the Juju SDK.
Alternative: Video tutorial from Operator Day at KubeCon (May 2021).
Prerequisites:
- A working station, e.g., a laptop.
- Familiarity with OOP in Python.
Contents:
- Create the test environment
- Install the Charmcraft CLI
- Set up your charm project
- Write your charm
- Pack your charm
- Deploy your charm
- Destroy the test environment
- Next steps
Create the test environment
The Juju SDK is currently supported only on Linux. However, you can also use it on macOS or Windows by quickly creating an Ubuntu virtual machine with Multipass. This is also a good option for people who would like an isolated test environment on their existing Linux system.
First, install Multipass: Linux | macOS | Windows.
Then, open a terminal and use Multipass to launch an Ubuntu virtual machine and open a shell in it, as shown below. We’ve called ours tutorial-vm
.
# Launch a VM "tutorial-vm" with 8 GB RAM, 2 CPU cores, and 20 GB disk:
$ multipass launch -n tutorial-vm -m 8g -c 2 -d 20G
Launched: tutorial-vm
# Open a shell inside the VM:
$ multipass shell tutorial-vm
ubuntu@tutorial-vm:~$
Congratulations, your Ubuntu virtual machine is ready! Any command you type after the last terminal prompt will be inside of this virtual machine. Let’s give it a try by running the commands below. If they work, they will not just confirm that your virtual machine is working—they will also configure it so it will work properly in the rest of this tutorial.
# Install 'tree' and 'unzip':
ubuntu@tutorial-vm:~$ sudo apt update && sudo apt install tree unzip
If for whatever reason you need to interrupt this tutorial, we recommend running multipass stop tutorial-vm
to stop the instance and then multipass start tutorial-vm
/ multipass shell tutorial-vm
to start / start and open a shell inside the instance, when you want to resume.
Install the Charmcraft CLI
We’ve got our Ubuntu test environment. We are now ready to install the Juju SDK CLI tool, charmcraft
:
# Configure LXD:
$ lxd init --auto
# Install Charmcraft:
$ sudo snap install charmcraft --classic
Done!
Set up your charm project
We’ve got charmcraft
. Time to set up our charm project!
First, create a directory named after your intended charm. We will call ours hello-world
.
$ mkdir hello-world
Second, navigate inside that directory and run charmcraft init
. As the output indicates, this has created all the directories and files that you will need to write your charm.
$ cd hello-world
$ charmcraft init
Charm operator package file and directory tree initialized.
TODO:
README.md: Describe your charm in a few paragraphs of Markdown
README.md: Provide high-level usage, such as required config or relations
README.md: Provide any relations which are provided or required by your charm
README.md: Include a link to the default image your charm uses
actions.yaml: change this example to suit your needs.
config.yaml: change this example to suit your needs.
metadata.yaml: fill out a display name for the Charmcraft store
metadata.yaml: fill out the charm's description
metadata.yaml: fill out the charm's summary
metadata.yaml: replace with containers for your workload (delete for non-k8s)
metadata.yaml: each container defined above must specify an oci-image resource
src/charm.py: change this example to suit your needs.
src/charm.py: change this example to suit your needs.
src/charm.py: change this example to suit your needs.
You can also verify this by inspecting your charm directory using tree
, as shown below:
$ tree
.
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── actions.yaml
├── charmcraft.yaml
├── config.yaml
├── metadata.yaml
├── requirements-dev.txt
├── requirements.txt
├── run_tests
├── src
│ └── charm.py
└── tests
├── __init__.py
└── test_charm.py
2 directories, 13 files
Congratulations, you are ready to start writing your charm!
Write your charm
In the previous section you used Charmcraft to initialise your charm project. This created a number of files. To build a charm, you will need to start editing some of those files, most crucially src/charm.py
, the metadata.yaml
, and requirements.txt
.
Edit the src/charm.py
file
The first file you’ll want to edit is the src/charm.py
file, which is the place where you put the code for your charm.
To begin with, open src/charm.py
in edit mode.
$ edit src/charm.py
Then, delete all the contents of the file.
The file is pre-populated with scaffolding for creating a Kubernetes charm. However, for educational purposes, it is easiest to start from scratch.
Finally, start writing your own Python code, as follows:
First, add the code below to import the logging
module from Python’s stdlib
library.
#!/usr/bin/env python3
import logging
Then, also add the code below to import the CharmBase
class and, respectively, the main
function from the charm
and, respectively, the main
module of the ops
framework.
ops
is a part of the Juju SDK. It was installed on your system when you installed charmcraft
. See Ops and Ops API reference.
from ops.charm import CharmBase
from ops.main import main
Now, use the logging
module to create a logger.
logger = logging.getLogger(__name__)
Also, start creating your own charm class. This will be a straightforward Python class which inherits from CharmBase
and which we pass to the framework’s main
.
class MyCharm(CharmBase):
In the scope of this class, inside the constructor, register a handler self.on_install
for the self.on.install
event:
def __init__(self, *args):
super().__init__(*args)
self.framework.observe(self.on.install, self.on_install)
Also in the scope of this class, define the on_install
event handler. To keep things simple, just make it log a simple greeting message.
def on_install(self, event):
logger.info("Congratulations, the charm was properly installed!")
Finally, outside of the scope of the class, register the main function, to call your charm.
if __name__ == "__main__":
main(MyCharm)
Expand to see all the code above at once
#!/usr/bin/env python3
import logging
from ops.charm import CharmBase
from ops.main import main
logger = logging.getLogger(__name__)
class MyCharm(CharmBase):
def __init__(self, *args):
super().__init__(*args)
self.framework.observe(self.on.install, self.on_install)
def on_install(self, event):
logger.info("Congratulations, the charm was properly installed!")
if __name__ == "__main__":
main(MyCharm)
Congratulations, you have a minimal functioning version of your src/charm.py
file!
Edit the metadata.yaml
file
The second file you should edit is the metadata.yaml
file. This file is where you put information that will later help the Juju Operator Lifecycle Manager (OLM) to correctly manage your charm.
As before, let’s delete all the pre-existing contents of this file, so you can see the process from scratch.
Now, add the following:
name: hello-world
summary: My first operator from the tutorial
description: |
A very simple charm to demonstrate Charmcraft and the
Python operator framework Ops.
assumes:
- k8s-api
The most important piece here is the assumes
keyword, specifying the k8s-api
. This ensures that our charm will be able to run on Kubernetes.
Edit the requirements.txt
file
Any Python dependencies are declared in the requirements.txt
file. In our example, we only need the Operator Framework (ops
). This dependency is automatically added when you initialize your charm project with charmcraft init
:
$ cat requirements.txt
ops >= 1.4.0
You can add other Pypi dependencies to that file. charmcraft
will keep them up to date as part of the build process.
Pack your charm
Your operator is pure code. To share it with someone else, it helps to have a package for it, which we call a charm. A charm of an operator is like a deb of a binary: a package that can be shared, published and retrieved.
Let’s pack our charm:
$ charmcraft pack
Packing the charm
Created 'hello-world_ubuntu-20.04-amd64.charm'.
Charms packed:
hello-world_ubuntu-20.04-amd64.charm
As the output indicates, the result is a file called hello-world_ubuntu-20.04-amd64.charm
.
This name might vary slightly, depending on your architecture. E.g., for an arm
processor, you will see arm64
rather than amd64
. In the commands below make sure to enter the correct charm name.
Note in particular the .charm
extension. This is really just a zip file of the code and all its dependencies, as well as the metadata. charmcraft pack
just fetches the dependencies, compiles any modules, makes sure you have all the right pieces of metadata, and zips it up for easy distribution.
Take a look inside. You’ll recognise your files, and then a virtual environemnt with the Python dependencies clearly mapped out:
Expand to see the list of files
# Unzip your charm:
$ unzip -l hello-world_ubuntu-20.04-amd64.charm
Archive: hello-world_ubuntu-20.04-amd64.charm
Length Date Time Name
--------- ---------- ----- ----
11358 2022-07-12 15:41 LICENSE
422 2022-07-12 15:41 config.yaml
534 2022-07-12 15:41 README.md
250 2022-07-12 15:51 manifest.yaml
475 2022-07-12 15:41 actions.yaml
102 2022-07-12 15:48 dispatch
188 2022-07-12 15:44 metadata.yaml
102 2022-07-12 15:48 hooks/start
102 2022-07-12 15:48 hooks/install
102 2022-07-12 15:48 hooks/upgrade-charm
126 2022-07-12 15:48 venv/easy_install.py
125 2022-07-12 15:48 venv/pip-20.0.2.dist-info/entry_points.txt
110 2022-07-12 15:48 venv/pip-20.0.2.dist-info/WHEEL
3352 2022-07-12 15:48 venv/pip-20.0.2.dist-info/METADATA
1090 2022-07-12 15:48 venv/pip-20.0.2.dist-info/LICENSE.txt
18528 2022-07-12 15:48 venv/pip-20.0.2.dist-info/RECORD
4 2022-07-12 15:48 venv/pip-20.0.2.dist-info/top_level.txt
4 2022-07-12 15:48 venv/pip-20.0.2.dist-info/INSTALLER
3150 2022-07-12 15:48 venv/setuptools-44.0.0.dist-info/entry_points.txt
21518 2022-07-12 15:48 venv/setuptools-44.0.0.dist-info/AUTHORS.txt
110 2022-07-12 15:48 venv/setuptools-44.0.0.dist-info/WHEEL
3523 2022-07-12 15:48 venv/setuptools-44.0.0.dist-info/METADATA
1090 2022-07-12 15:48 venv/setuptools-44.0.0.dist-info/LICENSE.txt
11941 2022-07-12 15:48 venv/setuptools-44.0.0.dist-info/RECORD
38 2022-07-12 15:48 venv/setuptools-44.0.0.dist-info/top_level.txt
1 2022-07-12 15:48 venv/setuptools-44.0.0.dist-info/zip-safe
4 2022-07-12 15:48 venv/setuptools-44.0.0.dist-info/INSTALLER
239 2022-07-12 15:48 venv/setuptools-44.0.0.dist-info/dependency_links.txt
4883 2022-07-12 15:50 venv/yaml/composer.py
51279 2022-07-12 15:50 venv/yaml/scanner.py
14190 2022-07-12 15:50 venv/yaml/representer.py
9004 2022-07-12 15:50 venv/yaml/resolver.py
2533 2022-07-12 15:50 venv/yaml/error.py
12309 2022-07-12 15:50 venv/yaml/__init__.py
6794 2022-07-12 15:50 venv/yaml/reader.py
2061 2022-07-12 15:50 venv/yaml/loader.py
1440 2022-07-12 15:50 venv/yaml/nodes.py
2573 2022-07-12 15:50 venv/yaml/tokens.py
3851 2022-07-12 15:50 venv/yaml/cyaml.py
28639 2022-07-12 15:50 venv/yaml/constructor.py
25495 2022-07-12 15:50 venv/yaml/parser.py
2837 2022-07-12 15:50 venv/yaml/dumper.py
4165 2022-07-12 15:50 venv/yaml/serializer.py
2445 2022-07-12 15:50 venv/yaml/events.py
43006 2022-07-12 15:50 venv/yaml/emitter.py
25359 2022-07-12 15:50 venv/yaml/__pycache__/emitter.cpython-38.pyc
2306 2022-07-12 15:50 venv/yaml/__pycache__/error.cpython-38.pyc
3417 2022-07-12 15:50 venv/yaml/__pycache__/cyaml.cpython-38.pyc
4941 2022-07-12 15:50 venv/yaml/__pycache__/tokens.cpython-38.pyc
11119 2022-07-12 15:50 venv/yaml/__pycache__/__init__.cpython-38.pyc
1731 2022-07-12 15:50 venv/yaml/__pycache__/nodes.cpython-38.pyc
11930 2022-07-12 15:50 venv/yaml/__pycache__/parser.cpython-38.pyc
4543 2022-07-12 15:50 venv/yaml/__pycache__/reader.cpython-38.pyc
10075 2022-07-12 15:50 venv/yaml/__pycache__/representer.cpython-38.pyc
25277 2022-07-12 15:50 venv/yaml/__pycache__/scanner.cpython-38.pyc
3980 2022-07-12 15:50 venv/yaml/__pycache__/events.cpython-38.pyc
3326 2022-07-12 15:50 venv/yaml/__pycache__/serializer.cpython-38.pyc
1829 2022-07-12 15:50 venv/yaml/__pycache__/dumper.cpython-38.pyc
20828 2022-07-12 15:50 venv/yaml/__pycache__/constructor.cpython-38.pyc
5512 2022-07-12 15:50 venv/yaml/__pycache__/resolver.cpython-38.pyc
2170 2022-07-12 15:50 venv/yaml/__pycache__/loader.cpython-38.pyc
3569 2022-07-12 15:50 venv/yaml/__pycache__/composer.cpython-38.pyc
455 2022-07-12 15:48 venv/pip/__init__.py
632 2022-07-12 15:48 venv/pip/__main__.py
4975 2022-07-12 15:48 venv/pip/_vendor/__init__.py
3037 2022-07-12 15:48 venv/pip/_vendor/__pycache__/__init__.cpython-38.pyc
11605 2022-07-12 15:48 venv/pip/_internal/cache.py
16277 2022-07-12 15:48 venv/pip/_internal/legacy_resolve.py
5490 2022-07-12 15:48 venv/pip/_internal/pep425tags.py
437 2022-07-12 15:48 venv/pip/_internal/main.py
517 2022-07-12 15:48 venv/pip/_internal/__init__.py
8009 2022-07-12 15:48 venv/pip/_internal/self_outdated_check.py
6734 2022-07-12 15:48 venv/pip/_internal/locations.py
10247 2022-07-12 15:48 venv/pip/_internal/exceptions.py
14222 2022-07-12 15:48 venv/pip/_internal/configuration.py
9441 2022-07-12 15:48 venv/pip/_internal/wheel_builder.py
7532 2022-07-12 15:48 venv/pip/_internal/build_env.py
7400 2022-07-12 15:48 venv/pip/_internal/pyproject.py
760 2022-07-12 15:48 venv/pip/_internal/distributions/installed.py
959 2022-07-12 15:48 venv/pip/_internal/distributions/__init__.py
4086 2022-07-12 15:48 venv/pip/_internal/distributions/sdist.py
1294 2022-07-12 15:48 venv/pip/_internal/distributions/wheel.py
1425 2022-07-12 15:48 venv/pip/_internal/distributions/base.py
1208 2022-07-12 15:48 venv/pip/_internal/distributions/__pycache__/installed.cpython-38.pyc
1928 2022-07-12 15:48 venv/pip/_internal/distributions/__pycache__/base.cpython-38.pyc
812 2022-07-12 15:48 venv/pip/_internal/distributions/__pycache__/__init__.cpython-38.pyc
1560 2022-07-12 15:48 venv/pip/_internal/distributions/__pycache__/wheel.cpython-38.pyc
3471 2022-07-12 15:48 venv/pip/_internal/distributions/__pycache__/sdist.cpython-38.pyc
28114 2022-07-12 15:48 venv/pip/_internal/cli/cmdoptions.py
2610 2022-07-12 15:48 venv/pip/_internal/cli/main.py
2819 2022-07-12 15:48 venv/pip/_internal/cli/main_parser.py
132 2022-07-12 15:48 venv/pip/_internal/cli/__init__.py
7948 2022-07-12 15:48 venv/pip/_internal/cli/base_command.py
156 2022-07-12 15:48 venv/pip/_internal/cli/status_codes.py
12463 2022-07-12 15:48 venv/pip/_internal/cli/req_command.py
6547 2022-07-12 15:48 venv/pip/_internal/cli/autocompletion.py
9487 2022-07-12 15:48 venv/pip/_internal/cli/parser.py
975 2022-07-12 15:48 venv/pip/_internal/cli/command_context.py
8289 2022-07-12 15:48 venv/pip/_internal/cli/__pycache__/req_command.cpython-38.pyc
1406 2022-07-12 15:48 venv/pip/_internal/cli/__pycache__/main.cpython-38.pyc
365 2022-07-12 15:48 venv/pip/_internal/cli/__pycache__/status_codes.cpython-38.pyc
236 2022-07-12 15:48 venv/pip/_internal/cli/__pycache__/__init__.cpython-38.pyc
8977 2022-07-12 15:48 venv/pip/_internal/cli/__pycache__/parser.cpython-38.pyc
1311 2022-07-12 15:48 venv/pip/_internal/cli/__pycache__/command_context.cpython-38.pyc
2159 2022-07-12 15:48 venv/pip/_internal/cli/__pycache__/main_parser.cpython-38.pyc
4953 2022-07-12 15:48 venv/pip/_internal/cli/__pycache__/autocompletion.cpython-38.pyc
5847 2022-07-12 15:48 venv/pip/_internal/cli/__pycache__/base_command.cpython-38.pyc
20328 2022-07-12 15:48 venv/pip/_internal/cli/__pycache__/cmdoptions.cpython-38.pyc
617 2022-07-12 15:48 venv/pip/_internal/vcs/__init__.py
5110 2022-07-12 15:48 venv/pip/_internal/vcs/mercurial.py
12292 2022-07-12 15:48 venv/pip/_internal/vcs/subversion.py
14352 2022-07-12 15:48 venv/pip/_internal/vcs/git.py
3957 2022-07-12 15:48 venv/pip/_internal/vcs/bazaar.py
22600 2022-07-12 15:48 venv/pip/_internal/vcs/versioncontrol.py
3747 2022-07-12 15:48 venv/pip/_internal/vcs/__pycache__/bazaar.cpython-38.pyc
8487 2022-07-12 15:48 venv/pip/_internal/vcs/__pycache__/subversion.cpython-38.pyc
448 2022-07-12 15:48 venv/pip/_internal/vcs/__pycache__/__init__.cpython-38.pyc
9559 2022-07-12 15:48 venv/pip/_internal/vcs/__pycache__/git.cpython-38.pyc
4888 2022-07-12 15:48 venv/pip/_internal/vcs/__pycache__/mercurial.cpython-38.pyc
19216 2022-07-12 15:48 venv/pip/_internal/vcs/__pycache__/versioncontrol.cpython-38.pyc
17892 2022-07-12 15:48 venv/pip/_internal/index/collector.py
30 2022-07-12 15:48 venv/pip/_internal/index/__init__.py
37542 2022-07-12 15:48 venv/pip/_internal/index/package_finder.py
14156 2022-07-12 15:48 venv/pip/_internal/index/__pycache__/collector.cpython-38.pyc
190 2022-07-12 15:48 venv/pip/_internal/index/__pycache__/__init__.cpython-38.pyc
25749 2022-07-12 15:48 venv/pip/_internal/index/__pycache__/package_finder.cpython-38.pyc
30442 2022-07-12 15:48 venv/pip/_internal/req/req_install.py
18485 2022-07-12 15:48 venv/pip/_internal/req/req_file.py
14388 2022-07-12 15:48 venv/pip/_internal/req/constructors.py
23609 2022-07-12 15:48 venv/pip/_internal/req/req_uninstall.py
2671 2022-07-12 15:48 venv/pip/_internal/req/__init__.py
8066 2022-07-12 15:48 venv/pip/_internal/req/req_set.py
4723 2022-07-12 15:48 venv/pip/_internal/req/req_tracker.py
10363 2022-07-12 15:48 venv/pip/_internal/req/__pycache__/constructors.cpython-38.pyc
4041 2022-07-12 15:48 venv/pip/_internal/req/__pycache__/req_tracker.cpython-38.pyc
21338 2022-07-12 15:48 venv/pip/_internal/req/__pycache__/req_install.cpython-38.pyc
2194 2022-07-12 15:48 venv/pip/_internal/req/__pycache__/__init__.cpython-38.pyc
12702 2022-07-12 15:48 venv/pip/_internal/req/__pycache__/req_file.cpython-38.pyc
17427 2022-07-12 15:48 venv/pip/_internal/req/__pycache__/req_uninstall.cpython-38.pyc
6021 2022-07-12 15:48 venv/pip/_internal/req/__pycache__/req_set.cpython-38.pyc
3799 2022-07-12 15:48 venv/pip/_internal/models/target_python.py
6827 2022-07-12 15:48 venv/pip/_internal/models/link.py
63 2022-07-12 15:48 venv/pip/_internal/models/__init__.py
1060 2022-07-12 15:48 venv/pip/_internal/models/index.py
679 2022-07-12 15:48 venv/pip/_internal/models/scheme.py
2766 2022-07-12 15:48 venv/pip/_internal/models/wheel.py
2673 2022-07-12 15:48 venv/pip/_internal/models/format_control.py
1150 2022-07-12 15:48 venv/pip/_internal/models/candidate.py
1908 2022-07-12 15:48 venv/pip/_internal/models/selection_prefs.py
3898 2022-07-12 15:48 venv/pip/_internal/models/search_scope.py
1146 2022-07-12 15:48 venv/pip/_internal/models/__pycache__/index.cpython-38.pyc
1596 2022-07-12 15:48 venv/pip/_internal/models/__pycache__/selection_prefs.cpython-38.pyc
224 2022-07-12 15:48 venv/pip/_internal/models/__pycache__/__init__.cpython-38.pyc
3182 2022-07-12 15:48 venv/pip/_internal/models/__pycache__/wheel.cpython-38.pyc
2416 2022-07-12 15:48 venv/pip/_internal/models/__pycache__/format_control.cpython-38.pyc
6659 2022-07-12 15:48 venv/pip/_internal/models/__pycache__/link.cpython-38.pyc
1421 2022-07-12 15:48 venv/pip/_internal/models/__pycache__/candidate.cpython-38.pyc
3253 2022-07-12 15:48 venv/pip/_internal/models/__pycache__/search_scope.cpython-38.pyc
3219 2022-07-12 15:48 venv/pip/_internal/models/__pycache__/target_python.cpython-38.pyc
862 2022-07-12 15:48 venv/pip/_internal/models/__pycache__/scheme.cpython-38.pyc
10180 2022-07-12 15:48 venv/pip/_internal/operations/freeze.py
20942 2022-07-12 15:48 venv/pip/_internal/operations/prepare.py
0 2022-07-12 15:48 venv/pip/_internal/operations/__init__.py
5353 2022-07-12 15:48 venv/pip/_internal/operations/check.py
4566 2022-07-12 15:48 venv/pip/_internal/operations/install/legacy.py
51 2022-07-12 15:48 venv/pip/_internal/operations/install/__init__.py
23012 2022-07-12 15:48 venv/pip/_internal/operations/install/wheel.py
1488 2022-07-12 15:48 venv/pip/_internal/operations/install/editable_legacy.py
224 2022-07-12 15:48 venv/pip/_internal/operations/install/__pycache__/__init__.cpython-38.pyc
14582 2022-07-12 15:48 venv/pip/_internal/operations/install/__pycache__/wheel.cpython-38.pyc
3048 2022-07-12 15:48 venv/pip/_internal/operations/install/__pycache__/legacy.cpython-38.pyc
1302 2022-07-12 15:48 venv/pip/_internal/operations/install/__pycache__/editable_legacy.cpython-38.pyc
0 2022-07-12 15:48 venv/pip/_internal/operations/build/__init__.py
3349 2022-07-12 15:48 venv/pip/_internal/operations/build/wheel_legacy.py
1469 2022-07-12 15:48 venv/pip/_internal/operations/build/wheel.py
3957 2022-07-12 15:48 venv/pip/_internal/operations/build/metadata_legacy.py
1307 2022-07-12 15:48 venv/pip/_internal/operations/build/metadata.py
166 2022-07-12 15:48 venv/pip/_internal/operations/build/__pycache__/__init__.cpython-38.pyc
1306 2022-07-12 15:48 venv/pip/_internal/operations/build/__pycache__/wheel.cpython-38.pyc
2567 2022-07-12 15:48 venv/pip/_internal/operations/build/__pycache__/wheel_legacy.cpython-38.pyc
1208 2022-07-12 15:48 venv/pip/_internal/operations/build/__pycache__/metadata.cpython-38.pyc
3268 2022-07-12 15:48 venv/pip/_internal/operations/build/__pycache__/metadata_legacy.cpython-38.pyc
160 2022-07-12 15:48 venv/pip/_internal/operations/__pycache__/__init__.cpython-38.pyc
5803 2022-07-12 15:48 venv/pip/_internal/operations/__pycache__/freeze.cpython-38.pyc
3656 2022-07-12 15:48 venv/pip/_internal/operations/__pycache__/check.cpython-38.pyc
11162 2022-07-12 15:48 venv/pip/_internal/operations/__pycache__/prepare.cpython-38.pyc
3481 2022-07-12 15:48 venv/pip/_internal/commands/freeze.py
4209 2022-07-12 15:48 venv/pip/_internal/commands/debug.py
3714 2022-07-12 15:48 venv/pip/_internal/commands/__init__.py
7226 2022-07-12 15:48 venv/pip/_internal/commands/configuration.py
5007 2022-07-12 15:48 venv/pip/_internal/commands/download.py
2975 2022-07-12 15:48 venv/pip/_internal/commands/completion.py
7170 2022-07-12 15:48 venv/pip/_internal/commands/wheel.py
10660 2022-07-12 15:48 venv/pip/_internal/commands/list.py
6792 2022-07-12 15:48 venv/pip/_internal/commands/show.py
27286 2022-07-12 15:48 venv/pip/_internal/commands/install.py
1735 2022-07-12 15:48 venv/pip/_internal/commands/hash.py
2983 2022-07-12 15:48 venv/pip/_internal/commands/uninstall.py
1505 2022-07-12 15:48 venv/pip/_internal/commands/check.py
5148 2022-07-12 15:48 venv/pip/_internal/commands/search.py
1181 2022-07-12 15:48 venv/pip/_internal/commands/help.py
6325 2022-07-12 15:48 venv/pip/_internal/commands/__pycache__/show.cpython-38.pyc
2852 2022-07-12 15:48 venv/pip/_internal/commands/__pycache__/__init__.cpython-38.pyc
5246 2022-07-12 15:48 venv/pip/_internal/commands/__pycache__/wheel.cpython-38.pyc
1990 2022-07-12 15:48 venv/pip/_internal/commands/__pycache__/hash.cpython-38.pyc
2929 2022-07-12 15:48 venv/pip/_internal/commands/__pycache__/freeze.cpython-38.pyc
4484 2022-07-12 15:48 venv/pip/_internal/commands/__pycache__/search.cpython-38.pyc
4089 2022-07-12 15:48 venv/pip/_internal/commands/__pycache__/debug.cpython-38.pyc
6575 2022-07-12 15:48 venv/pip/_internal/commands/__pycache__/configuration.cpython-38.pyc
3013 2022-07-12 15:48 venv/pip/_internal/commands/__pycache__/completion.cpython-38.pyc
1186 2022-07-12 15:48 venv/pip/_internal/commands/__pycache__/help.cpython-38.pyc
2694 2022-07-12 15:48 venv/pip/_internal/commands/__pycache__/uninstall.cpython-38.pyc
3921 2022-07-12 15:48 venv/pip/_internal/commands/__pycache__/download.cpython-38.pyc
1312 2022-07-12 15:48 venv/pip/_internal/commands/__pycache__/check.cpython-38.pyc
9042 2022-07-12 15:48 venv/pip/_internal/commands/__pycache__/list.cpython-38.pyc
16661 2022-07-12 15:48 venv/pip/_internal/commands/__pycache__/install.cpython-38.pyc
615 2022-07-12 15:48 venv/pip/_internal/__pycache__/main.cpython-38.pyc
9898 2022-07-12 15:48 venv/pip/_internal/__pycache__/legacy_resolve.cpython-38.pyc
12482 2022-07-12 15:48 venv/pip/_internal/__pycache__/exceptions.cpython-38.pyc
678 2022-07-12 15:48 venv/pip/_internal/__pycache__/__init__.cpython-38.pyc
3584 2022-07-12 15:48 venv/pip/_internal/__pycache__/pep425tags.cpython-38.pyc
10645 2022-07-12 15:48 venv/pip/_internal/__pycache__/configuration.cpython-38.pyc
8700 2022-07-12 15:48 venv/pip/_internal/__pycache__/cache.cpython-38.pyc
6699 2022-07-12 15:48 venv/pip/_internal/__pycache__/wheel_builder.cpython-38.pyc
5493 2022-07-12 15:48 venv/pip/_internal/__pycache__/self_outdated_check.cpython-38.pyc
3732 2022-07-12 15:48 venv/pip/_internal/__pycache__/pyproject.cpython-38.pyc
4492 2022-07-12 15:48 venv/pip/_internal/__pycache__/locations.cpython-38.pyc
7483 2022-07-12 15:48 venv/pip/_internal/__pycache__/build_env.cpython-38.pyc
2394 2022-07-12 15:48 venv/pip/_internal/network/cache.py
1597 2022-07-12 15:48 venv/pip/_internal/network/xmlrpc.py
50 2022-07-12 15:48 venv/pip/_internal/network/__init__.py
1959 2022-07-12 15:48 venv/pip/_internal/network/utils.py
6260 2022-07-12 15:48 venv/pip/_internal/network/download.py
11119 2022-07-12 15:48 venv/pip/_internal/network/auth.py
14702 2022-07-12 15:48 venv/pip/_internal/network/session.py
706 2022-07-12 15:48 venv/pip/_internal/network/__pycache__/utils.cpython-38.pyc
8851 2022-07-12 15:48 venv/pip/_internal/network/__pycache__/session.cpython-38.pyc
1574 2022-07-12 15:48 venv/pip/_internal/network/__pycache__/xmlrpc.cpython-38.pyc
212 2022-07-12 15:48 venv/pip/_internal/network/__pycache__/__init__.cpython-38.pyc
6978 2022-07-12 15:48 venv/pip/_internal/network/__pycache__/auth.cpython-38.pyc
2691 2022-07-12 15:48 venv/pip/_internal/network/__pycache__/cache.cpython-38.pyc
4370 2022-07-12 15:48 venv/pip/_internal/network/__pycache__/download.cpython-38.pyc
13033 2022-07-12 15:48 venv/pip/_internal/utils/logging.py
3035 2022-07-12 15:48 venv/pip/_internal/utils/packaging.py
3942 2022-07-12 15:48 venv/pip/_internal/utils/hashes.py
13911 2022-07-12 15:48 venv/pip/_internal/utils/ui.py
1254 2022-07-12 15:48 venv/pip/_internal/utils/pkg_resources.py
1307 2022-07-12 15:48 venv/pip/_internal/utils/appdirs.py
810 2022-07-12 15:48 venv/pip/_internal/utils/inject_securetransport.py
0 2022-07-12 15:48 venv/pip/_internal/utils/__init__.py
3297 2022-07-12 15:48 venv/pip/_internal/utils/glibc.py
9438 2022-07-12 15:48 venv/pip/_internal/utils/unpacking.py
1350 2022-07-12 15:48 venv/pip/_internal/utils/distutils_args.py
1148 2022-07-12 15:48 venv/pip/_internal/utils/models.py
7302 2022-07-12 15:48 venv/pip/_internal/utils/wheel.py
1481 2022-07-12 15:48 venv/pip/_internal/utils/urls.py
1401 2022-07-12 15:48 venv/pip/_internal/utils/typing.py
1320 2022-07-12 15:48 venv/pip/_internal/utils/encoding.py
5255 2022-07-12 15:48 venv/pip/_internal/utils/filesystem.py
1152 2022-07-12 15:48 venv/pip/_internal/utils/entrypoints.py
8869 2022-07-12 15:48 venv/pip/_internal/utils/compat.py
7768 2022-07-12 15:48 venv/pip/_internal/utils/temp_dir.py
9922 2022-07-12 15:48 venv/pip/_internal/utils/subprocess.py
5070 2022-07-12 15:48 venv/pip/_internal/utils/setuptools_build.py
26085 2022-07-12 15:48 venv/pip/_internal/utils/misc.py
571 2022-07-12 15:48 venv/pip/_internal/utils/filetypes.py
741 2022-07-12 15:48 venv/pip/_internal/utils/marker_files.py
3318 2022-07-12 15:48 venv/pip/_internal/utils/deprecation.py
3396 2022-07-12 15:48 venv/pip/_internal/utils/virtualenv.py
6075 2022-07-12 15:48 venv/pip/_internal/utils/__pycache__/unpacking.cpython-38.pyc
9159 2022-07-12 15:48 venv/pip/_internal/utils/__pycache__/logging.cpython-38.pyc
1247 2022-07-12 15:48 venv/pip/_internal/utils/__pycache__/encoding.cpython-38.pyc
6711 2022-07-12 15:48 venv/pip/_internal/utils/__pycache__/temp_dir.cpython-38.pyc
932 2022-07-12 15:48 venv/pip/_internal/utils/__pycache__/inject_securetransport.cpython-38.pyc
1708 2022-07-12 15:48 venv/pip/_internal/utils/__pycache__/glibc.cpython-38.pyc
556 2022-07-12 15:48 venv/pip/_internal/utils/__pycache__/filetypes.cpython-38.pyc
1299 2022-07-12 15:48 venv/pip/_internal/utils/__pycache__/entrypoints.cpython-38.pyc
155 2022-07-12 15:48 venv/pip/_internal/utils/__pycache__/__init__.cpython-38.pyc
6325 2022-07-12 15:48 venv/pip/_internal/utils/__pycache__/wheel.cpython-38.pyc
1465 2022-07-12 15:48 venv/pip/_internal/utils/__pycache__/urls.cpython-38.pyc
4035 2022-07-12 15:48 venv/pip/_internal/utils/__pycache__/filesystem.cpython-38.pyc
2826 2022-07-12 15:48 venv/pip/_internal/utils/__pycache__/deprecation.cpython-38.pyc
2927 2022-07-12 15:48 venv/pip/_internal/utils/__pycache__/setuptools_build.cpython-38.pyc
3280 2022-07-12 15:48 venv/pip/_internal/utils/__pycache__/virtualenv.cpython-38.pyc
2608 2022-07-12 15:48 venv/pip/_internal/utils/__pycache__/packaging.cpython-38.pyc
928 2022-07-12 15:48 venv/pip/_internal/utils/__pycache__/marker_files.cpython-38.pyc
1139 2022-07-12 15:48 venv/pip/_internal/utils/__pycache__/distutils_args.cpython-38.pyc
1351 2022-07-12 15:48 venv/pip/_internal/utils/__pycache__/appdirs.cpython-38.pyc
1924 2022-07-12 15:48 venv/pip/_internal/utils/__pycache__/models.cpython-38.pyc
4144 2022-07-12 15:48 venv/pip/_internal/utils/__pycache__/hashes.cpython-38.pyc
11802 2022-07-12 15:48 venv/pip/_internal/utils/__pycache__/ui.cpython-38.pyc
5598 2022-07-12 15:48 venv/pip/_internal/utils/__pycache__/subprocess.cpython-38.pyc
23778 2022-07-12 15:48 venv/pip/_internal/utils/__pycache__/misc.cpython-38.pyc
1822 2022-07-12 15:48 venv/pip/_internal/utils/__pycache__/pkg_resources.cpython-38.pyc
1437 2022-07-12 15:48 venv/pip/_internal/utils/__pycache__/typing.cpython-38.pyc
6120 2022-07-12 15:48 venv/pip/_internal/utils/__pycache__/compat.cpython-38.pyc
629 2022-07-12 15:48 venv/pip/__pycache__/__init__.cpython-38.pyc
422 2022-07-12 15:48 venv/pip/__pycache__/__main__.cpython-38.pyc
108349 2022-07-12 15:48 venv/pkg_resources/__init__.py
558 2022-07-12 15:48 venv/pkg_resources/py31compat.py
24701 2022-07-12 15:48 venv/pkg_resources/_vendor/appdirs.py
0 2022-07-12 15:48 venv/pkg_resources/_vendor/__init__.py
30098 2022-07-12 15:48 venv/pkg_resources/_vendor/six.py
232055 2022-07-12 15:48 venv/pkg_resources/_vendor/pyparsing.py
720 2022-07-12 15:48 venv/pkg_resources/_vendor/packaging/__about__.py
1416 2022-07-12 15:48 venv/pkg_resources/_vendor/packaging/_structures.py
513 2022-07-12 15:48 venv/pkg_resources/_vendor/packaging/__init__.py
4355 2022-07-12 15:48 venv/pkg_resources/_vendor/packaging/requirements.py
421 2022-07-12 15:48 venv/pkg_resources/_vendor/packaging/utils.py
8248 2022-07-12 15:48 venv/pkg_resources/_vendor/packaging/markers.py
860 2022-07-12 15:48 venv/pkg_resources/_vendor/packaging/_compat.py
28025 2022-07-12 15:48 venv/pkg_resources/_vendor/packaging/specifiers.py
11556 2022-07-12 15:48 venv/pkg_resources/_vendor/packaging/version.py
466 2022-07-12 15:48 venv/pkg_resources/_vendor/packaging/__pycache__/utils.cpython-38.pyc
2763 2022-07-12 15:48 venv/pkg_resources/_vendor/packaging/__pycache__/_structures.cpython-38.pyc
8919 2022-07-12 15:48 venv/pkg_resources/_vendor/packaging/__pycache__/markers.cpython-38.pyc
19787 2022-07-12 15:48 venv/pkg_resources/_vendor/packaging/__pycache__/specifiers.cpython-38.pyc
707 2022-07-12 15:48 venv/pkg_resources/_vendor/packaging/__pycache__/__about__.cpython-38.pyc
545 2022-07-12 15:48 venv/pkg_resources/_vendor/packaging/__pycache__/__init__.cpython-38.pyc
3878 2022-07-12 15:48 venv/pkg_resources/_vendor/packaging/__pycache__/requirements.cpython-38.pyc
10634 2022-07-12 15:48 venv/pkg_resources/_vendor/packaging/__pycache__/version.cpython-38.pyc
981 2022-07-12 15:48 venv/pkg_resources/_vendor/packaging/__pycache__/_compat.cpython-38.pyc
201634 2022-07-12 15:48 venv/pkg_resources/_vendor/__pycache__/pyparsing.cpython-38.pyc
157 2022-07-12 15:48 venv/pkg_resources/_vendor/__pycache__/__init__.cpython-38.pyc
24430 2022-07-12 15:48 venv/pkg_resources/_vendor/__pycache__/six.cpython-38.pyc
20510 2022-07-12 15:48 venv/pkg_resources/_vendor/__pycache__/appdirs.cpython-38.pyc
2498 2022-07-12 15:48 venv/pkg_resources/extern/__init__.py
2406 2022-07-12 15:48 venv/pkg_resources/extern/__pycache__/__init__.cpython-38.pyc
100356 2022-07-12 15:48 venv/pkg_resources/__pycache__/__init__.cpython-38.pyc
600 2022-07-12 15:48 venv/pkg_resources/__pycache__/py31compat.cpython-38.pyc
48073 2022-07-12 15:50 venv/ops/framework.py
88948 2022-07-12 15:50 venv/ops/pebble.py
16783 2022-07-12 15:50 venv/ops/main.py
2206 2022-07-12 15:50 venv/ops/__init__.py
93183 2022-07-12 15:50 venv/ops/testing.py
95925 2022-07-12 15:50 venv/ops/model.py
41849 2022-07-12 15:50 venv/ops/charm.py
14964 2022-07-12 15:50 venv/ops/storage.py
4189 2022-07-12 15:50 venv/ops/jujuversion.py
0 2022-07-12 15:50 venv/ops/py.typed
2525 2022-07-12 15:50 venv/ops/log.py
46 2022-07-12 15:50 venv/ops/version.py
574 2022-07-12 15:50 venv/ops/_vendor/__init__.py
147 2022-07-12 15:50 venv/ops/_vendor/__pycache__/__init__.cpython-38.pyc
13142 2022-07-12 15:50 venv/ops/_vendor/websocket/_abnf.py
1972 2022-07-12 15:50 venv/ops/_vendor/websocket/_logging.py
2175 2022-07-12 15:50 venv/ops/_vendor/websocket/_exceptions.py
11344 2022-07-12 15:50 venv/ops/_vendor/websocket/_http.py
787 2022-07-12 15:50 venv/ops/_vendor/websocket/__init__.py
5915 2022-07-12 15:50 venv/ops/_vendor/websocket/_handshake.py
3524 2022-07-12 15:50 venv/ops/_vendor/websocket/_utils.py
2135 2022-07-12 15:50 venv/ops/_vendor/websocket/_cookiejar.py
15006 2022-07-12 15:50 venv/ops/_vendor/websocket/_app.py
19358 2022-07-12 15:50 venv/ops/_vendor/websocket/_core.py
4807 2022-07-12 15:50 venv/ops/_vendor/websocket/_url.py
1337 2022-07-12 15:50 venv/ops/_vendor/websocket/_ssl_compat.py
4843 2022-07-12 15:50 venv/ops/_vendor/websocket/_socket.py
5160 2022-07-12 15:50 venv/ops/_vendor/websocket/__pycache__/_handshake.cpython-38.pyc
2412 2022-07-12 15:50 venv/ops/_vendor/websocket/__pycache__/_exceptions.cpython-38.pyc
4021 2022-07-12 15:50 venv/ops/_vendor/websocket/__pycache__/_url.cpython-38.pyc
11942 2022-07-12 15:50 venv/ops/_vendor/websocket/__pycache__/_app.cpython-38.pyc
1544 2022-07-12 15:50 venv/ops/_vendor/websocket/__pycache__/_ssl_compat.cpython-38.pyc
955 2022-07-12 15:50 venv/ops/_vendor/websocket/__pycache__/__init__.cpython-38.pyc
17101 2022-07-12 15:50 venv/ops/_vendor/websocket/__pycache__/_core.cpython-38.pyc
2133 2022-07-12 15:50 venv/ops/_vendor/websocket/__pycache__/_logging.cpython-38.pyc
4119 2022-07-12 15:50 venv/ops/_vendor/websocket/__pycache__/_utils.cpython-38.pyc
10308 2022-07-12 15:50 venv/ops/_vendor/websocket/__pycache__/_abnf.cpython-38.pyc
1726 2022-07-12 15:50 venv/ops/_vendor/websocket/__pycache__/_cookiejar.cpython-38.pyc
7778 2022-07-12 15:50 venv/ops/_vendor/websocket/__pycache__/_http.cpython-38.pyc
3721 2022-07-12 15:50 venv/ops/_vendor/websocket/__pycache__/_socket.cpython-38.pyc
9212 2022-07-12 15:50 venv/ops/lib/__init__.py
7587 2022-07-12 15:50 venv/ops/lib/__pycache__/__init__.cpython-38.pyc
11965 2022-07-12 15:50 venv/ops/__pycache__/main.cpython-38.pyc
79087 2022-07-12 15:50 venv/ops/__pycache__/pebble.cpython-38.pyc
1643 2022-07-12 15:50 venv/ops/__pycache__/__init__.cpython-38.pyc
42989 2022-07-12 15:50 venv/ops/__pycache__/charm.cpython-38.pyc
3556 2022-07-12 15:50 venv/ops/__pycache__/jujuversion.cpython-38.pyc
2438 2022-07-12 15:50 venv/ops/__pycache__/log.cpython-38.pyc
88982 2022-07-12 15:50 venv/ops/__pycache__/model.cpython-38.pyc
71974 2022-07-12 15:50 venv/ops/__pycache__/testing.cpython-38.pyc
155 2022-07-12 15:50 venv/ops/__pycache__/version.cpython-38.pyc
41232 2022-07-12 15:50 venv/ops/__pycache__/framework.cpython-38.pyc
13340 2022-07-12 15:50 venv/ops/__pycache__/storage.cpython-38.pyc
0 2022-07-12 15:50 venv/ops/_private/__init__.py
1104 2022-07-12 15:50 venv/ops/_private/yaml.py
753 2022-07-12 15:50 venv/ops/_private/__pycache__/yaml.cpython-38.pyc
148 2022-07-12 15:50 venv/ops/_private/__pycache__/__init__.cpython-38.pyc
21518 2022-07-12 15:48 venv/pkg_resources-0.0.0.dist-info/AUTHORS.txt
110 2022-07-12 15:48 venv/pkg_resources-0.0.0.dist-info/WHEEL
177 2022-07-12 15:48 venv/pkg_resources-0.0.0.dist-info/METADATA
1090 2022-07-12 15:48 venv/pkg_resources-0.0.0.dist-info/LICENSE.txt
3100 2022-07-12 15:48 venv/pkg_resources-0.0.0.dist-info/RECORD
4 2022-07-12 15:48 venv/pkg_resources-0.0.0.dist-info/INSTALLER
1402 2022-07-12 15:50 venv/_yaml/__init__.py
705 2022-07-12 15:50 venv/_yaml/__pycache__/__init__.cpython-38.pyc
92 2022-07-12 15:50 venv/ops-1.5.0.dist-info/WHEEL
7001 2022-07-12 15:50 venv/ops-1.5.0.dist-info/METADATA
11358 2022-07-12 15:50 venv/ops-1.5.0.dist-info/LICENSE.txt
4246 2022-07-12 15:50 venv/ops-1.5.0.dist-info/RECORD
4 2022-07-12 15:50 venv/ops-1.5.0.dist-info/top_level.txt
4 2022-07-12 15:50 venv/ops-1.5.0.dist-info/INSTALLER
103 2022-07-12 15:50 venv/PyYAML-6.0.dist-info/WHEEL
1101 2022-07-12 15:50 venv/PyYAML-6.0.dist-info/LICENSE
2005 2022-07-12 15:50 venv/PyYAML-6.0.dist-info/METADATA
2564 2022-07-12 15:50 venv/PyYAML-6.0.dist-info/RECORD
11 2022-07-12 15:50 venv/PyYAML-6.0.dist-info/top_level.txt
4 2022-07-12 15:50 venv/PyYAML-6.0.dist-info/INSTALLER
1496 2022-07-12 15:48 venv/setuptools/py27compat.py
218 2022-07-12 15:48 venv/setuptools/_deprecation_warning.py
5264 2022-07-12 15:48 venv/setuptools/monkey.py
218 2022-07-12 15:48 venv/setuptools/script (dev).tmpl
65536 2022-07-12 15:48 venv/setuptools/cli.exe
9597 2022-07-12 15:48 venv/setuptools/build_meta.py
138 2022-07-12 15:48 venv/setuptools/script.tmpl
7283 2022-07-12 15:48 venv/setuptools/__init__.py
2302 2022-07-12 15:48 venv/setuptools/site-patch.py
1330 2022-07-12 15:48 venv/setuptools/py33compat.py
5517 2022-07-12 15:48 venv/setuptools/depends.py
996 2022-07-12 15:48 venv/setuptools/unicode_utils.py
75264 2022-07-12 15:48 venv/setuptools/gui-64.exe
245 2022-07-12 15:48 venv/setuptools/py34compat.py
65536 2022-07-12 15:48 venv/setuptools/gui.exe
46751 2022-07-12 15:48 venv/setuptools/msvc.py
65536 2022-07-12 15:48 venv/setuptools/gui-32.exe
714 2022-07-12 15:48 venv/setuptools/windows_support.py
838 2022-07-12 15:48 venv/setuptools/py31compat.py
14276 2022-07-12 15:48 venv/setuptools/sandbox.py
5337 2022-07-12 15:48 venv/setuptools/installer.py
8455 2022-07-12 15:48 venv/setuptools/wheel.py
1729 2022-07-12 15:48 venv/setuptools/extension.py
6592 2022-07-12 15:48 venv/setuptools/archive_util.py
524 2022-07-12 15:48 venv/setuptools/errors.py
3199 2022-07-12 15:48 venv/setuptools/namespaces.py
787 2022-07-12 15:48 venv/setuptools/launch.py
8493 2022-07-12 15:48 venv/setuptools/ssl_support.py
40605 2022-07-12 15:48 venv/setuptools/package_index.py
49865 2022-07-12 15:48 venv/setuptools/dist.py
5084 2022-07-12 15:48 venv/setuptools/glob.py
2223 2022-07-12 15:48 venv/setuptools/_imp.py
74752 2022-07-12 15:48 venv/setuptools/cli-64.exe
935 2022-07-12 15:48 venv/setuptools/dep_util.py
65536 2022-07-12 15:48 venv/setuptools/cli-32.exe
2013 2022-07-12 15:48 venv/setuptools/lib2to3_ex.py
20575 2022-07-12 15:48 venv/setuptools/config.py
144 2022-07-12 15:48 venv/setuptools/version.py
0 2022-07-12 15:48 venv/setuptools/_vendor/__init__.py
30098 2022-07-12 15:48 venv/setuptools/_vendor/six.py
15130 2022-07-12 15:48 venv/setuptools/_vendor/ordered_set.py
232055 2022-07-12 15:48 venv/setuptools/_vendor/pyparsing.py
744 2022-07-12 15:48 venv/setuptools/_vendor/packaging/__about__.py
1416 2022-07-12 15:48 venv/setuptools/_vendor/packaging/_structures.py
562 2022-07-12 15:48 venv/setuptools/_vendor/packaging/__init__.py
4742 2022-07-12 15:48 venv/setuptools/_vendor/packaging/requirements.py
1520 2022-07-12 15:48 venv/setuptools/_vendor/packaging/utils.py
8268 2022-07-12 15:48 venv/setuptools/_vendor/packaging/markers.py
865 2022-07-12 15:48 venv/setuptools/_vendor/packaging/_compat.py
27778 2022-07-12 15:48 venv/setuptools/_vendor/packaging/specifiers.py
12933 2022-07-12 15:48 venv/setuptools/_vendor/packaging/tags.py
11978 2022-07-12 15:48 venv/setuptools/_vendor/packaging/version.py
1435 2022-07-12 15:48 venv/setuptools/_vendor/packaging/__pycache__/utils.cpython-38.pyc
2760 2022-07-12 15:48 venv/setuptools/_vendor/packaging/__pycache__/_structures.cpython-38.pyc
8927 2022-07-12 15:48 venv/setuptools/_vendor/packaging/__pycache__/markers.cpython-38.pyc
19734 2022-07-12 15:48 venv/setuptools/_vendor/packaging/__pycache__/specifiers.cpython-38.pyc
704 2022-07-12 15:48 venv/setuptools/_vendor/packaging/__pycache__/__about__.cpython-38.pyc
542 2022-07-12 15:48 venv/setuptools/_vendor/packaging/__pycache__/__init__.cpython-38.pyc
3995 2022-07-12 15:48 venv/setuptools/_vendor/packaging/__pycache__/requirements.cpython-38.pyc
10811 2022-07-12 15:48 venv/setuptools/_vendor/packaging/__pycache__/tags.cpython-38.pyc
12065 2022-07-12 15:48 venv/setuptools/_vendor/packaging/__pycache__/version.cpython-38.pyc
978 2022-07-12 15:48 venv/setuptools/_vendor/packaging/__pycache__/_compat.cpython-38.pyc
201631 2022-07-12 15:48 venv/setuptools/_vendor/__pycache__/pyparsing.cpython-38.pyc
154 2022-07-12 15:48 venv/setuptools/_vendor/__pycache__/__init__.cpython-38.pyc
24427 2022-07-12 15:48 venv/setuptools/_vendor/__pycache__/six.cpython-38.pyc
16412 2022-07-12 15:48 venv/setuptools/_vendor/__pycache__/ordered_set.cpython-38.pyc
2439 2022-07-12 15:48 venv/setuptools/command/install_scripts.py
1508 2022-07-12 15:48 venv/setuptools/command/bdist_rpm.py
18185 2022-07-12 15:48 venv/setuptools/command/bdist_egg.py
4484 2022-07-12 15:48 venv/setuptools/command/build_clib.py
5023 2022-07-12 15:48 venv/setuptools/command/install_lib.py
960 2022-07-12 15:48 venv/setuptools/command/dist_info.py
4986 2022-07-12 15:48 venv/setuptools/command/py36compat.py
568 2022-07-12 15:48 venv/setuptools/command/__init__.py
25578 2022-07-12 15:48 venv/setuptools/command/egg_info.py
8088 2022-07-12 15:48 venv/setuptools/command/sdist.py
3195 2022-07-12 15:48 venv/setuptools/command/install_egg_info.py
9602 2022-07-12 15:48 venv/setuptools/command/test.py
628 2022-07-12 15:48 venv/setuptools/command/launcher manifest.xml
637 2022-07-12 15:48 venv/setuptools/command/bdist_wininst.py
2164 2022-07-12 15:48 venv/setuptools/command/rotate.py
13019 2022-07-12 15:48 venv/setuptools/command/build_ext.py
2426 2022-07-12 15:48 venv/setuptools/command/alias.py
89903 2022-07-12 15:48 venv/setuptools/command/easy_install.py
4705 2022-07-12 15:48 venv/setuptools/command/install.py
468 2022-07-12 15:48 venv/setuptools/command/register.py
8184 2022-07-12 15:48 venv/setuptools/command/develop.py
9596 2022-07-12 15:48 venv/setuptools/command/build_py.py
462 2022-07-12 15:48 venv/setuptools/command/upload.py
658 2022-07-12 15:48 venv/setuptools/command/saveopts.py
7311 2022-07-12 15:48 venv/setuptools/command/upload_docs.py
5085 2022-07-12 15:48 venv/setuptools/command/setopt.py
21773 2022-07-12 15:48 venv/setuptools/command/__pycache__/egg_info.cpython-38.pyc
5083 2022-07-12 15:48 venv/setuptools/command/__pycache__/install_lib.cpython-38.pyc
1361 2022-07-12 15:48 venv/setuptools/command/__pycache__/dist_info.cpython-38.pyc
954 2022-07-12 15:48 venv/setuptools/command/__pycache__/bdist_wininst.cpython-38.pyc
1784 2022-07-12 15:48 venv/setuptools/command/__pycache__/bdist_rpm.cpython-38.pyc
2520 2022-07-12 15:48 venv/setuptools/command/__pycache__/rotate.cpython-38.pyc
712 2022-07-12 15:48 venv/setuptools/command/__pycache__/__init__.cpython-38.pyc
889 2022-07-12 15:48 venv/setuptools/command/__pycache__/saveopts.cpython-38.pyc
2437 2022-07-12 15:48 venv/setuptools/command/__pycache__/build_clib.cpython-38.pyc
9895 2022-07-12 15:48 venv/setuptools/command/__pycache__/build_ext.cpython-38.pyc
8475 2022-07-12 15:48 venv/setuptools/command/__pycache__/test.cpython-38.pyc
6501 2022-07-12 15:48 venv/setuptools/command/__pycache__/develop.cpython-38.pyc
2273 2022-07-12 15:48 venv/setuptools/command/__pycache__/install_scripts.cpython-38.pyc
2392 2022-07-12 15:48 venv/setuptools/command/__pycache__/alias.cpython-38.pyc
4537 2022-07-12 15:48 venv/setuptools/command/__pycache__/setopt.cpython-38.pyc
8641 2022-07-12 15:48 venv/setuptools/command/__pycache__/build_py.cpython-38.pyc
66694 2022-07-12 15:48 venv/setuptools/command/__pycache__/easy_install.cpython-38.pyc
7859 2022-07-12 15:48 venv/setuptools/command/__pycache__/sdist.cpython-38.pyc
811 2022-07-12 15:48 venv/setuptools/command/__pycache__/register.cpython-38.pyc
2900 2022-07-12 15:48 venv/setuptools/command/__pycache__/install_egg_info.cpython-38.pyc
784 2022-07-12 15:48 venv/setuptools/command/__pycache__/upload.cpython-38.pyc
14182 2022-07-12 15:48 venv/setuptools/command/__pycache__/bdist_egg.cpython-38.pyc
6140 2022-07-12 15:48 venv/setuptools/command/__pycache__/upload_docs.cpython-38.pyc
4016 2022-07-12 15:48 venv/setuptools/command/__pycache__/install.cpython-38.pyc
4610 2022-07-12 15:48 venv/setuptools/command/__pycache__/py36compat.cpython-38.pyc
2514 2022-07-12 15:48 venv/setuptools/extern/__init__.py
2420 2022-07-12 15:48 venv/setuptools/extern/__pycache__/__init__.cpython-38.pyc
3616 2022-07-12 15:48 venv/setuptools/__pycache__/namespaces.cpython-38.pyc
816 2022-07-12 15:48 venv/setuptools/__pycache__/errors.cpython-38.pyc
5128 2022-07-12 15:48 venv/setuptools/__pycache__/archive_util.cpython-38.pyc
989 2022-07-12 15:48 venv/setuptools/__pycache__/windows_support.cpython-38.pyc
5216 2022-07-12 15:48 venv/setuptools/__pycache__/depends.cpython-38.pyc
39631 2022-07-12 15:48 venv/setuptools/__pycache__/msvc.cpython-38.pyc
819 2022-07-12 15:48 venv/setuptools/__pycache__/dep_util.cpython-38.pyc
15536 2022-07-12 15:48 venv/setuptools/__pycache__/sandbox.cpython-38.pyc
824 2022-07-12 15:48 venv/setuptools/__pycache__/launch.cpython-38.pyc
7768 2022-07-12 15:48 venv/setuptools/__pycache__/__init__.cpython-38.pyc
7383 2022-07-12 15:48 venv/setuptools/__pycache__/wheel.cpython-38.pyc
1408 2022-07-12 15:48 venv/setuptools/__pycache__/py33compat.cpython-38.pyc
1961 2022-07-12 15:48 venv/setuptools/__pycache__/extension.cpython-38.pyc
450 2022-07-12 15:48 venv/setuptools/__pycache__/py34compat.cpython-38.pyc
8495 2022-07-12 15:48 venv/setuptools/__pycache__/build_meta.cpython-38.pyc
1474 2022-07-12 15:48 venv/setuptools/__pycache__/site-patch.cpython-38.pyc
1749 2022-07-12 15:48 venv/setuptools/__pycache__/py27compat.cpython-38.pyc
3733 2022-07-12 15:48 venv/setuptools/__pycache__/glob.cpython-38.pyc
1890 2022-07-12 15:48 venv/setuptools/__pycache__/_imp.cpython-38.pyc
292 2022-07-12 15:48 venv/setuptools/__pycache__/version.cpython-38.pyc
6855 2022-07-12 15:48 venv/setuptools/__pycache__/ssl_support.cpython-38.pyc
42326 2022-07-12 15:48 venv/setuptools/__pycache__/dist.cpython-38.pyc
1151 2022-07-12 15:48 venv/setuptools/__pycache__/unicode_utils.cpython-38.pyc
17896 2022-07-12 15:48 venv/setuptools/__pycache__/config.cpython-38.pyc
4102 2022-07-12 15:48 venv/setuptools/__pycache__/installer.cpython-38.pyc
4644 2022-07-12 15:48 venv/setuptools/__pycache__/monkey.cpython-38.pyc
1191 2022-07-12 15:48 venv/setuptools/__pycache__/py31compat.cpython-38.pyc
2411 2022-07-12 15:48 venv/setuptools/__pycache__/lib2to3_ex.cpython-38.pyc
32970 2022-07-12 15:48 venv/setuptools/__pycache__/package_index.cpython-38.pyc
516 2022-07-12 15:48 venv/setuptools/__pycache__/_deprecation_warning.cpython-38.pyc
281 2022-07-12 15:48 venv/__pycache__/easy_install.cpython-38.pyc
447 2022-07-12 15:44 src/charm.py
--------- -------
5607942 558 files
Congratulations, your Kubernetes charm is ready!
Deploy your charm
You now have a Kubernetes charm. Time to check that it’s functional by deploying it!
First, you’ll need to prepare your Kubernetes cloud. Use MicroK8s to create and configure a small Kubernetes cloud on your local workstation, as shown below. This cloud is by default called microk8s
.
# Install Microk8s from snap:
sudo snap install microk8s --classic --channel=1.24
# Add the 'ubuntu' user to the Microk8s group:
sudo usermod -a -G microk8s ubuntu
# Give the 'ubuntu' user permissions to read the ~/.kube directory:
sudo chown -f -R ubuntu ~/.kube
# Create the 'microk8s' group:
newgrp microk8s
# Enable the necessary Microk8s addons:
microk8s enable hostpath-storage dns
Second, you’ll need to set up the charmed operator lifecycle manager (OLM) juju
, make it aware of your cloud, connect it to your cloud, and prepare a workspace for your cloud. You can achieve all of this in a few lines with the code below:
#Install the Juju CLI client, juju:
$ sudo snap install juju --classic
juju 2.9.32 from Canonicalâś“ installed
# Register your "microk8s" cloud with juju. Not necessary, as juju recognises a MicroK8s cloud automatically, as you can see by running `juju clouds`. (If for any reason this doesn't happen, you can register it manually using `juju add-k8s microk8s`.)
$ juju clouds
Cloud Regions Default Type Credentials Source Description
microk8s 1 localhost k8s 1 built-in A Kubernetes Cluster
# Install a "juju" controller into your "microk8s" cloud. We'll name ours "tutorial-controller".
$ juju bootstrap microk8s tutorial-controller
# Create a workspace, or 'model', on this controller. We'll call ours "tutorial-model".
$ juju add-model tutorial-model
Well done! Everything is now ready for you to deploy your charm!
Before you jump to it, though, you might want to catch any errors as they happen. To that end, switch to a different terminal, open a new shell into your Multipass virtual machine where you installed Juju, and execute the following to see the logging, as shown below:
# Open a shell into the virtual machine that you created earlier, 'tutorial-vm':
$ multipass shell tutorial-vm
ubuntu@tutorial-vm:~$ juju debug-log
controller-0: 22:37:02 INFO juju.worker.apicaller [48d45f] "controller-0" successfully connected to "localhost:17070"
controller-0: 22:37:02 INFO juju.worker.logforwarder config change - log forwarding not enabled
controller-0: 22:37:02 INFO juju.worker.logger logger worker started
controller-0: 22:37:02 INFO juju.worker.pruner.statushistory status history config: max age: 336h0m0s, max collection size 5120M for hello-world (48d45fd3-bc24-467e-8f88-2378dda24211)
controller-0: 22:37:02 INFO juju.worker.pruner.action status history config: max age: 336h0m0s, max collection size 5120M for hello-world (48d45fd3-bc24-467e-8f88-2378dda24211)
Switch back to the original terminal, and let’s deploy our charm:
$ juju deploy ./hello-world_ubuntu-20.04-amd64.charm
You can watch the evolving status of the deployment with:
$ watch --color "juju status --color"
Wait a few moments to allow the Juju OLM to do its magic. If everything has gone successfully, the juju debug-log
terminal should soon display a line very similar to the one below:
unit-hello-world-1: 13:26:10 INFO unit.hello-world/1.juju-log Congratulations, the charm was properly installed!
Destroy the test environment
Once you are done, you can run the code below to stop and delete your Multipass test environment.
# Stop your instance
$ multipass stop tutorial-vm
# Delete your instance permanently
$ multipass delete --purge tutorial-vm
You can also uninstall Multipass to remove any trace of this guide.
Next steps
This tutorial has introduced you to the basic process for building a Kubernetes charm in Juju. But there is a lot more to explore:
If you are wondering… | visit… |
---|---|
“How do I…?” | Juju SDK How-to docs |
“What is…?” | Juju SDK Reference docs |
“Why…?”, “So what?” | Juju SDK Explanation docs |
Finally, if your question is “How can I learn more about deploying charms with Juju?”, consider also the Juju OLM docs!