Skip to content

Commit

Permalink
docs: Add charm architecture documentation (#19)
Browse files Browse the repository at this point in the history
* add charm architecture documentation

* Apply suggestions from code review

Co-authored-by: Erin Conley <[email protected]>

* use lower-case for tmate

* add section explaining why this is a machine charm

* refer to the spec

* Apply suggestions from code review

Co-authored-by: Erin Conley <[email protected]>

---------

Co-authored-by: Erin Conley <[email protected]>
  • Loading branch information
cbartz and erinecon authored Feb 20, 2025
1 parent 798d19d commit a9f0e47
Showing 1 changed file with 103 additions and 0 deletions.
103 changes: 103 additions & 0 deletions docs/explanation/charm-architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Charm architecture

The tmate-ssh-server-operator operates [tmate-ssh-server](https://github.com/tmate-io/tmate-ssh-server),
which is the server side of [tmate](https://tmate.io/), an open-source terminal multiplexer
that provides instant terminal sharing capabilities.
The tmate-ssh-server application is built from source as an OCI image and runs as a systemd service on the machine.

The charm provides the necessary connection details for a tmate client to connect to the tmate-ssh-server service
via integration data.


```mermaid
C4Container
title Container diagram for tmate SSH Server
Container_Boundary(c1, "tmate SSH Server") {
Container(tmatessh, "tmate SSH Server", "", "Provides sharing a remote session")
}
Container_Boundary(c2, "tmate Client Charm") {
Container(clientcharm, "tmate Client Charm", "", "Charm managing tmate client workload.")
}
System_Ext(tmateclient, "tmate Client", "Client that shares their terminal session")
System_Ext(collaborator, "Collaborator", "Another client who wants access to the terminal")
Rel(tmatessh, clientcharm, "provides connection details")
Rel(clientcharm, tmateclient, "init client with connection details")
Rel(tmateclient, tmatessh, "init session via SSH")
Rel(collaborator, tmatessh, "join session via SSH")
UpdateRelStyle(tmatessh, clientcharm, $offsetY="30", $offsetX="-70")
UpdateRelStyle(clientcharm, tmateclient, $offsetY="80", $offsetX="150")
UpdateRelStyle(tmateclient, tmatessh, $offsetY="-30", $offsetX="10")
UpdateRelStyle(collaborator, tmatessh, $offsetY="-30", $offsetX="80")
```

### Why is this a machine charm?

The OCI image for tmate-ssh-server requires certain kernel capabilities to run ([SYS_ADMIN](https://github.com/tmate-io/tmate-ssh-server/issues/73#issuecomment-762756632)).
At design time, due to the limitations of a Juju Kubernetes charm, the container was unable to receive the capability.
Furthermore, providing SSH ingress for machine charms is easier to achieve than for K8s charms. Hence, it was decided to make tmate-ssh-server a machine charm.

See [[specification] ISD099 Tmate charm for Github Runners](https://discourse.charmhub.io/t/specification-isd099-tmate-charm-for-github-runners/16837)
for more information.
## OCI images

We use [Rockcraft](https://canonical-rockcraft.readthedocs-hosted.com/en/latest/) to build OCI images for tmate-ssh-server.
The images are defined in [tmate-ssh-server_rock](https://github.com/canonical/tmate-ssh-server-operator/tree/main/tmate-ssh-server_rock).
They are published to the [Github Container registry](https://github.com/canonical/tmate-ssh-server-operator/pkgs/container/tmate-ssh-server).


## Juju events

The following Juju [events](https://juju.is/docs/sdk/event) are observed and handled by the charm as follows:

1. [install](https://canonical-juju.readthedocs-hosted.com/en/latest/user/reference/hook/#install): The charm is installed on the machine. The charm tests if a unit ip is assigned, otherwise the event is deferred. Afterwards,
the charm installs the necessary tmate-ssh-server dependencies, setups ssh keys and installs a systemd service that runs the tmate-ssh-server OCI image. The integration data is updated with the relevant server connection details (equivalent of `tmate.conf` configuration file),
which can be used by a tmate client to connect to the server.
2. [update-status](https://canonical-juju.readthedocs-hosted.com/en/latest/user/reference/hook/#update-status): This is a regular status check. The charm
checks if the tmate ssh server is still running and restarts it if it is not.
3. `get-server-config-action`: This is an [action event](https://canonical-juju.readthedocs-hosted.com/en/latest/user/reference/hook/#action-actiont) triggered by the user
to get the current server connection configuration (`tmate.conf`), which can be used by a tmate client to connect to the server.
5. `ssh-debug-relation-joined`: This is a [relation joined event](https://canonical-juju.readthedocs-hosted.com/en/latest/user/reference/hook/#endpoint-relation-joined) that fires when
a unit joins an integration. It inserts the relevant server connection details into the integration data, which can be used by a tmate client to connect to the server.

> See more about events in the Juju docs: [Hook](https://canonical-juju.readthedocs-hosted.com/en/latest/user/reference/hook)

## Charm code overview

The `src/charm.py` is the default entry point for a charm and has the `TmateSSHServerOperatorCharm` Python class which inherits from CharmBase. CharmBase is the base class
from which all charms are formed, defined by [Ops](https://juju.is/docs/sdk/ops) (Python framework for developing charms).

> See more in the Juju docs: [Charm](https://canonical-juju.readthedocs-hosted.com/en/latest/user/reference/charm/)
The `__init__` method guarantees that the charm observes all events relevant to its operation and handles them.

Take, for example, when the charm gets deployed.

1. User runs the command:
```bash
juju deploy tmate-ssh-server
```
2. An `install` event is emitted.
3. In the `__init__` method is defined how to handle this event like this:
```python
self.framework.observe(self.on.install, self._on_install)
```
4. The method `_on_install`, for its turn, will take the necessary actions such as installing the tmate-ssh-server software.


The code is structured according to the best practices described in [Managing charm complexity](https://discourse.charmhub.io/t/specification-isd014-managing-charm-complexity/11619).
Therefore, in addition to `src/charm.py`, there are other modules in the charm that are responsible for specific tasks:

- observe changes to the ssh-debug integration
- manage the state of the charm
- abstracting interactions with the tmate-ssh-server application

0 comments on commit a9f0e47

Please sign in to comment.