# index.html.md
# Charmed Apache Cassandra documentation
#### WARNING
The charm is under active development and is not yet published on Charmhub.
APIs, configuration options, and integration endpoints may change.
Charmed Apache Cassandra is an open-source **Juju charm** that automates the deployment, scaling,
configuration and operations of [Apache Cassandra](https://cassandra.apache.org/) clusters across clouds,
virtual machines and bare metal, using the [Juju](https://juju.is/) orchestration framework.
[Apache Cassandra](https://cassandra.apache.org/) is a free and open-source database management system
designed to handle large volumes of data across multiple commodity servers, providing high availability
with no single point of failure.
The charm aims to simplify Cassandra operations from
[Day 0 to Day 2](https://codilime.com/blog/day-0-day-1-day-2-the-software-lifecycle-in-the-cloud-age/),
offering secure defaults, integration interfaces, and lifecycle automation.
## In this documentation
This documentation contains only basic information and will be expanded later.
- **Tutorial** takes you step-by-step from bootstrapping a controller to deploying, securing, and scaling a cluster.
- **How-to guides** cover deploying and scaling a cluster, enabling TLS encryption, and setting up monitoring.
- **Reference** contains contact information.
## How this documentation is organized
This documentation uses the [Diátaxis](https://diataxis.fr/) documentation structure.
- The Tutorial takes you step-by-step through the initial Charmed Apache Cassandra setup and usage.
- How-to guides assume you have basic familiarity with Apache Cassandra and Juju.
## Project and community
Charmed Apache Cassandra is a member of the Ubuntu family.
It’s an open source project that warmly welcomes community contributions,
suggestions, fixes and constructive feedback.
- [Juju](https://juju.is/)
- [Charmhub](https://charmhub.io/)
- [Apache Cassandra](https://cassandra.apache.org/)
- [Canonical Data solutions](https://canonical.com/data)
- [Report issues](https://github.com/canonical/cassandra-operator/issues)
- [Contribute](https://github.com/canonical/cassandra-operator/blob/main/CONTRIBUTING.md)
## License and trademarks
Apache®, Apache Cassandra®, and the Apache Cassandra logo are either registered trademarks or trademarks
of the Apache Software Foundation in the United States and/or other countries.
The Charmed Apache Cassandra operator is free software, distributed under the Apache Software License,
version 2.0.
See [LICENSE](https://github.com/canonical/cassandra-operator/blob/main/LICENSE)
for more information.
# index.html.md
# How-to guides
These guides provide step-by-step instructions for common operational tasks with Charmed Apache Cassandra.
## Deployment
- [How to deploy Charmed Apache Cassandra](https://canonical.com/data/cassandra/docs/latest//how-to/deploy.md) - Deploy a cluster and connect to it with `cqlsh`
## Operations
- [How to manage units](https://canonical.com/data/cassandra/docs/latest//how-to/manage-units.md) - Scale the cluster up and down and verify the cluster topology
## Security
- [How to enable TLS encryption](https://canonical.com/data/cassandra/docs/latest//how-to/encryption.md) - Enable TLS encryption for secure communications between nodes
- [How to manage passwords](https://canonical.com/data/cassandra/docs/latest//how-to/manage-passwords.md) - Retrieve and rotate the `operator` password
## Observability
- [How to set up monitoring](https://canonical.com/data/cassandra/docs/latest//how-to/monitoring.md) - Set up monitoring with the Canonical Observability Stack (COS)
# index.html.md
# How to deploy Charmed Apache Cassandra
This guide walks you through deploying the **IAAS/VM** operator with the Juju CLI and verifying
the deployment by connecting to the cluster. You will:
1. Set up a Juju controller
2. Set up a Juju model
3. Deploy Charmed Apache Cassandra
4. Verify the deployment by connecting to the cluster
If you already have a Juju controller and a Juju model, you can skip the associated steps.
## Juju controller setup
Make sure you have a Juju controller accessible from your local environment using the
[Juju client snap](https://snapcraft.io/juju).
List available controllers:
```shell
juju list-controllers
```
Make sure that the controller’s back-end cloud is **not** Kubernetes-based.
To retrieve the cloud list:
```shell
juju list-clouds
```
To switch to another controller if needed:
```shell
juju switch
```
If there are no suitable controllers, create a new one:
```shell
juju bootstrap
```
where `` is the cloud to deploy the controller to (for example, `localhost` for a LXD
cloud). For more information on how to set up a new cloud, see the
[How to manage clouds](https://canonical.com/juju/docs/juju-cli/latest/howto/manage-clouds/index.html)
guide in Juju documentation.
## Juju model setup
Switch to an existing Juju model:
```shell
juju switch
```
Or create a new Juju model:
```shell
juju add-model
```
## Deploy Charmed Apache Cassandra
#### NOTE
Charmed Apache Cassandra is still under active development and is only available on the `5/edge`
channel. Due to the lack of a stable release it is not yet recommended for production environments.
To deploy Charmed Apache Cassandra:
```shell
juju deploy cassandra -n --config profile= --channel 5/edge
```
The charm supports two profiles:
* `production` (default) — tunes Cassandra for maximum performance, allocating up to 8 GB RAM per
unit for the Java heap. More RAM might be needed for read caches, bloom filters, etc.
* `testing` — minimises resource requirements for very small, non-production test and staging
clusters
To maintain high availability of the data, `3+` units are recommended.
#### WARNING
Typical `production` profile servers need at least 32 GB of ECC RAM per unit.
See [Apache Cassandra documentation](https://cassandra.apache.org/doc/stable/cassandra/managing/operating/hardware.html) for more details.
To change the profile on a running deployment:
```shell
juju config cassandra profile=testing
```
Monitor the status of the deployment:
```shell
watch juju status
```
During bootstrap, units briefly show maintenance and waiting statuses such as
`installing Cassandra`, `waiting for Cassandra to start`, and `waiting for cluster to start`.
The deployment should be complete once all the units show `active` and `idle` status.
## Test by connecting
Authentication is enabled by default. To retrieve the password for the default `operator` user:
```shell
juju show-secret --reveal "cassandra-peers..app" --format json \
| jq -r '.[].content.Data."operator-password"'
```
Once you have the password, connect to the cluster.
Install `cqlsh` locally:
```shell
sudo snap install cqlsh
```
Then connect to the cluster:
```shell
cqlsh -u operator -p ""
```
Alternatively, the `charmed-cassandra` snap bundles the same client as `charmed-cassandra.cqlsh`.
Output example
```text
[cqlsh 5.0.1 | Cassandra 5.0.5 | CQL spec 3.4.7 | Native protocol v5]
Use HELP for help.
operator@cqlsh>
```
If you want to test it further, run some commands in the cqlsh prompt:
```text
operator@cqlsh> CREATE KEYSPACE hello
... WITH replication = {
... 'class': 'SimpleStrategy',
... 'replication_factor': 1
... };
operator@cqlsh> DESCRIBE KEYSPACE hello;
CREATE KEYSPACE hello WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'} AND durable_writes = true;
```
# index.html.md
# How to set up monitoring
This guide includes step-by-step instructions on how to set up monitoring with the
[Canonical Observability Stack](https://charmhub.io/topics/canonical-observability-stack).
Additionally, the charm provides integration with the [Canonical Observability Stack](https://documentation.ubuntu.com/observability/).
## Enable monitoring
Deploy the `cos-lite` bundle in a Kubernetes environment. This can be done by following the
[deployment tutorial](https://documentation.ubuntu.com/observability/track-3.0/tutorial/cos-lite-microk8s-sandbox/).
Since the Charmed Apache Cassandra is deployed directly on a cloud infrastructure environment, it is needed to offer the endpoints of the COS relations.
The [offers-overlay](https://github.com/canonical/cos-lite-bundle/blob/main/overlays/offers-overlay.yaml)
can be used, and this step is shown in the COS tutorial.
#### NOTE
If you use [microk8s](https://microk8s.io/) with the strictly confined Juju snap, make sure to install the
**strictly confined** microk8s snap (e.g. from the `1.35-strict/stable` channel). The classic microk8s snap
is not supported by Juju.
### Offer interfaces via the COS controller
Switch to COS K8s environment and offer COS interfaces to be cross-model related with Charmed Apache Cassandra VM model:
```shell
juju switch :
juju offer grafana:grafana-dashboard grafana-dashboards
juju offer loki:logging loki-logging
juju offer prometheus:receive-remote-write prometheus-receive-remote-write
```
### Consume offers via the Apache Cassandra model
Switch back to the Charmed Apache Cassandra model, find offers and relate with them:
```shell
juju switch :
juju find-offers :
```
A similar output should appear, if `k8s` is the K8s controller name and `COS` the model where `cos-lite` has been deployed:
```shell
Store URL Access Interfaces
k8s admin/cos.grafana-dashboards admin grafana_dashboard:grafana-dashboard
k8s admin/cos.loki-logging admin loki_push_api:logging
k8s admin/cos.prometheus-receive-remote-write admin prometheus-receive-remote-write:receive-remote-write
...
```
Consume offers to be reachable in the current model:
```shell
juju consume :admin/.prometheus-receive-remote-write
juju consume :admin/.loki-logging
juju consume :admin/.grafana-dashboards
```
Now, deploy `grafana-agent` (subordinate charm) and relate it with Charmed Apache Cassandra:
```shell
juju deploy grafana-agent
juju integrate cassandra:cos-agent grafana-agent
```
Finally, relate `grafana-agent` with consumed COS offers:
```shell
juju integrate grafana-agent grafana-dashboards
juju integrate grafana-agent loki-logging
juju integrate grafana-agent prometheus-receive-remote-write
```
Wait for all components to settle down on a `active/idle` state on both models, e.g. `` and ``.
After this is complete, the monitoring COS stack should be up and running and ready to be used.
### Connect Grafana web interface
To connect to the Grafana web interface, follow the [Browse dashboards](https://documentation.ubuntu.com/observability/track-3.0/tutorial/cos-lite-microk8s-sandbox/#browse-dashboards) section of the “Getting started with COS Lite on MicroK8s” tutorial.
```shell
juju run grafana/leader get-admin-password --model :
```
## Alerts and dashboards
This guide shows you how to integrate an existing set of rules and/or dashboards to your Charmed Apache Cassandra deployment to be consumed with the [Canonical Observability Stack (COS)](https://documentation.ubuntu.com/observability/).
To do so, we will sync resources stored in a git repository to COS Lite.
### Prerequisites
Deploy the `cos-lite` bundle in a Kubernetes environment and integrate Charmed Apache Cassandra to the COS offers, as shown in the [How to Enable Monitoring](#how-to-monitoring-enable-monitoring) guide.
This guide will refer to the models that charms are deployed into as:
* `` for the model containing observability charms (and deployed on K8s)
* `` for the model containing Charmed Apache Cassandra and other optional charms (e.g. TLS-certificates operators, `grafana-agent`, `data-integrator`, etc.).
### Create a repository with a custom monitoring setup
Create an empty git repository, or in an existing one, save your alert rules and dashboard models under the ``, `` and `` folders.
If you want a primer to rule writing, refer to the [Prometheus documentation](https://prometheus.io/docs/prometheus/latest/configuration/alerting_rules/).
Then, push your changes to the remote repository.
### Deploy the COS configuration charm
Deploy the [COS configuration](https://charmhub.io/cos-configuration-k8s) charm in the `` model:
```shell
juju deploy cos-configuration-k8s cos-config \
--config git_repo= \
--config git_branch=
```
The COS configuration charm keeps the monitoring stack in sync with our repository, by forwarding resources to Prometheus, Loki and Grafana.
Refer to the [documentation](https://charmhub.io/cos-configuration-k8s/configure) for all configuration options, including how to access a private repository.
\\\\
Adding, updating or deleting an alert rule or a dashboard in the repository will be reflected in the monitoring stack.
#### NOTE
You need to manually refresh `cos-config`’s local repository with the *sync-now* action if you do not want to wait for the next [update-status event](https://documentation.ubuntu.com/juju/3.6/reference/hook/#update-status) to pull the latest changes.
### Forward the rules and dashboards
The path to the resource folders can be set after deployment:
```shell
juju config cos-config \
prometheus_alert_rules_path= \
loki_alert_rules_path= \
grafana_dashboards_path=
```
Then, integrate the charm with the COS operators to forward the rules and dashboards:
```shell
juju integrate cos-config:prometheus-config prometheus:metrics-endpoint
juju integrate cos-config:grafana-dashboards grafana:grafana-dashboard
juju integrate cos-config:loki-config loki:logging
```
After this is complete, the monitoring COS stack should be up and ready to fire alerts based on our rules. As for the dashboards, they should be available in the Grafana interface.
### Pre‑built dashboards and alerting rules
This repository already contains a set of ready‑to‑use monitoring assets:
* **Grafana dashboard:** `src/grafana_dashboards/grafana-dashboard.json`
* **Loki alerting rules:** `src/alert_rules/loki/loki_alerts.yaml`
* **Prometheus alerting rules:** `src/alert_rules/prometheus/prometheus_alerts.yaml`
Point the corresponding `*_path` configuration options to these files (or their parent directories) if you would like COS to pick them up automatically.
### Conclusion
In this guide, we enabled monitoring on a Charmed Apache Cassandra deployment and integrated alert rules and dashboards by syncing a git repository to the COS stack.
# index.html.md
# How to enable TLS encryption
This guide includes step-by-step instructions on how to enable TLS encryption for peer-to-peer
and client-to-node communication in a Charmed Apache Cassandra cluster.
This charm implements the **Requirer** side of the [tls-certificates](https://charmhub.io/integrations/tls-certificates) relation. Therefore, any charm implementing the **Provider** side could be used.
All units within a cluster share the same CA certificate file, but each unit has a distinct private key.
## Prerequisites
For this guide, we will need an active Charmed Apache Cassandra application.
Follow the [How to deploy Charmed Apache Cassandra](https://canonical.com/data/cassandra/docs/latest//how-to/deploy.md#how-to-deploy) guide to set up the environment.
## Enable TLS encryption for peer-to-peer communication
To enable peer-to-peer TLS encryption, you should first deploy a TLS certificates Provider charm.
For this guide, we will be using the `self-signed-certificates` charm.
#### WARNING
Using self-signed certificates is not recommended for production systems.
Instead follow your organisations best-practices for managing TLS certificates.
Please refer to [this post](https://charmhub.io/topics/security-with-x-509-certificates)
for an overview of the TLS certificates Providers charms and some guidance on how to choose
the right charm for your use case.
To deploy the `self-signed-certificates` application:
```shell
juju deploy self-signed-certificates --channel=edge --config ca-common-name="Test CA"
```
To enable peer-to-peer TLS encryption with Charmed Apache Cassandra, integrate the Charmed Apache Cassandra application to the `tls-certificates` provider application via the `peer-certificates` relation interface:
```shell
juju integrate cassandra:peer-certificates self-signed-certificates
```
While certificates are being issued and distributed, units show waiting and maintenance statuses such as `waiting for internal TLS setup` and `waiting for peer tls rotation to complete`. Once the process completes, units return to `active/idle`.
## Enable TLS encryption for client-to-node communication
To enable client-to-node TLS encryption, integrate the Charmed Apache Cassandra application to the `tls-certificates` provider application via the `client-certificates` relation interface:
```shell
juju integrate cassandra:client-certificates self-signed-certificates
```
While certificates are being issued and distributed, units show waiting and maintenance statuses such as `waiting for TLS setup` and `waiting for client tls rotation to complete`. Once the process completes, units return to `active/idle`.
## Connect to the cluster
Authentication is enabled by default.
To retrieve the password for the default `operator` user:
```shell
juju show-secret --reveal "cassandra-peers..app" --format json \
| jq -r '.[].content.Data."operator-password"'
```
### Verify client TLS
First, attempt to connect **without specifying TLS certificates**:
```shell
cqlsh -u operator -p ""
```
This should result in an error:
```text
Warning: Using a password on the command line interface can be insecure.
Recommendation: use the credentials file to securely provide the password.
Connection error: ('Unable to connect to any servers',
{':9042': ConnectionResetError(104, 'Connection reset by peer')})
```
This confirms that Apache Cassandra requires a secure TLS connection.
### Retrieving the root CA
Fetch the root CA from the self-signed certificate operator:
```shell
juju run self-signed-certificates/0 get-ca-certificate --format json \
| jq -r '."self-signed-certificates/0".results."ca-certificate"' > ca.cert
```
The CA needs to be used to verify the certificate provided by the Apache Cassandra servers in the TLS handshake.
### Connecting using `cqlsh`
First of all, install the `charmed-cassandra` snap in the local environment
```shell
sudo snap install charmed-cassandra --edge
```
The `charmed-cassandra` snap bundles also the `cqlsh` client to be used to connect to the Apache Cassandra endpoint. Since the snap is strictly confined, the `ca.cert` file needs to be copied to a location that is readable by the snap processes, e.g. `/var/snap/charmed-cassandra/current/etc/cassandra/` where configuration files are generally stored.
In the same location, also create a `cqlshrc` configuration file for `cqlsh`:
```ini
[authentication]
username = operator
password =
[connection]
hostname =
port = 9042
[ssl]
certfile = /var/snap/charmed-cassandra/current/etc/cassandra/ca.cert
validate = true
```
#### NOTE
Make sure the `cqlshrc` file is only readable by your user, otherwise `cqlsh` will refuse to use the credentials stored in it:
```shell
sudo chown $USER /var/snap/charmed-cassandra/current/etc/cassandra/cqlshrc
sudo chmod 600 /var/snap/charmed-cassandra/current/etc/cassandra/cqlshrc
```
Connect to Apache Cassandra with:
```shell
charmed-cassandra.cqlsh --ssl --cqlshrc /var/snap/charmed-cassandra/current/etc/cassandra/cqlshrc
```
The `cqlsh` client should connect and show the prompt where CQL queries can be run.
## (Optional) Rotate certificates
When the TLS certificates Provider charm renews the certificates (for example, when they are close to expiry, or when the CA is rotated), the Cassandra charm picks up the new certificates automatically.
During the rotation, units show maintenance statuses such as `waiting for peer tls rotation to complete` or `waiting for client tls rotation to complete`, and return to `active/idle` once the new certificates are in place. No manual action is required.
## Disable TLS encryption
To disable TLS encryption, remove the relations with the `tls-certificates` provider application:
```shell
juju remove-relation cassandra:peer-certificates self-signed-certificates
juju remove-relation cassandra:client-certificates self-signed-certificates
```
#### NOTE
Removing the relations causes a rolling restart of the units as they switch back to unencrypted communication.
# index.html.md
# How to manage units
This guide includes step-by-step instructions on how to scale a Charmed Apache Cassandra cluster
by adding or removing units, and how to verify the cluster topology.
For general Juju unit management process, see the [Juju documentation](https://canonical.com/juju/docs/juju-cli/3.6/howto/manage-units/).
The charm automates most of the node management operations, ensuring that the cluster topology remains consistent and data is replicated correctly.
## Scaling
### Add units
To scale-out the Charmed Apache Cassandra application, add more units:
```shell
juju add-unit cassandra -n
```
See the `juju add-unit` [command reference](https://canonical.com/juju/docs/juju-cli/latest/reference/juju-cli/list-of-juju-cli-commands/add-unit/).
The implementation of `add-unit` allows adding multiple units at once, but unit initialization occurs one at a time: each new unit bootstraps and joins the cluster before the next one starts. Expect the total time to grow linearly with the number of added units.
Monitor the progress with:
```shell
juju status
```
New units show `waiting for cluster to start` while they join, and become `active/idle` once they are full members of the cluster.
### Remove units
To decrease the number of Apache Cassandra nodes, remove some existing units from the Charmed Apache Cassandra application:
```shell
juju remove-unit
```
See the `juju remove-unit` [command reference](https://canonical.com/juju/docs/juju-cli/latest/reference/juju-cli/list-of-juju-cli-commands/remove-unit/).
#### NOTE
Only one unit can be removed at a time. Support for removing multiple units simultaneously is not yet available.
#### CAUTION
Before removing a unit, check the replication factor of your keyspaces. If removing the unit brings the number of nodes below the replication factor of a keyspace, that keyspace may become unavailable or lose data.
A Cassandra cluster is also called a *ring*: a peer-to-peer set of nodes where every node is equal and can serve the same functionality as any other. For more details, see the
[Cassandra architecture documentation](https://cassandra.apache.org/doc/latest/cassandra/architecture/dynamo.html).
During removal, the charm decommissions the node: data stored on the removed unit is streamed to the remaining nodes before the node leaves the ring, so no data is lost.
## Admin utility scripts
Apache Cassandra ships with the `nodetool` utility to do various administrative tasks such as checking the cluster status, draining a node, or repairing keyspaces.
The most important commands are exposed via the [Charmed Apache Cassandra snap](https://snapcraft.io/charmed-cassandra), accessible via `charmed-cassandra.nodetool `.
To run the commands, you need to provide authentication information. The `nodetool` credentials are stored on every unit and can be used by running the commands within the unit itself, e.g. via the `juju ssh` command:
```shell
juju ssh cassandra/0 sudo snap run charmed-cassandra.nodetool \
-u charmed-operator -pw "$(juju show-secret --reveal cassandra-peers.cassandra.app --format json | jq -r '.[].content.Data."nodetool-password"')" \
status
```
#### NOTE
The `nodetool` username is always `charmed-operator` — a separate internal user, distinct from the `operator` CQL user used to connect with `cqlsh`. The password is stored in the `nodetool-password` field of the `cassandra-peers` application secret.
### Cluster status
To check the state of the Cassandra ring, run `charmed-cassandra.nodetool status` on any unit:
```shell
juju ssh cassandra/0 sudo snap run charmed-cassandra.nodetool \
-u charmed-operator -pw "$(juju show-secret --reveal cassandra-peers.cassandra.app --format json | jq -r '.[].content.Data."nodetool-password"')" \
status
```
The output lists every node in the cluster with its state (`UN` means up and normal), address, and load:
```text
Datacenter: datacenter1
=======================
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
-- Address Load Tokens Owns (effective) Host ID Rack
UN 10.166.144.10 1.2 MiB 16 100.0% 1f3f0e1e-... rack1
UN 10.166.144.11 1.1 MiB 16 100.0% 9a2b7c4d-... rack1
UN 10.166.144.12 1.3 MiB 16 100.0% 5e8d1a2c-... rack1
```
### Recover from a lost node
If a unit’s machine is lost or permanently fails, remove the unit with `juju remove-unit` as above. The charm also automatically removes nodes that are down and unknown to the cluster, and repairs the `system_auth` keyspace to keep authentication data consistent across the remaining nodes.
# index.html.md
# How to manage passwords
This guide shows how to retrieve the current password for the default `operator` user and
how to rotate it.
Authentication is enabled by default in Charmed Apache Cassandra.
The charm automatically generates the initial password and stores it in a Juju secret.
## Prerequisites
* A running Charmed Apache Cassandra deployment — see [How to deploy Charmed Apache Cassandra](https://canonical.com/data/cassandra/docs/latest//how-to/deploy.md#how-to-deploy).
## Retrieve the operator password
The password for the default `operator` user is stored in the application secret of the `cassandra-peers` relation:
```shell
juju show-secret --reveal "cassandra-peers..app" --format json \
| jq -r '.[].content.Data."operator-password"'
```
## Rotate the operator password
The charm supports password rotation for the default `operator` user by leveraging **Juju secrets**.
1. Check the current password:
```shell
juju show-secret --reveal cassandra-peers.cassandra.app | grep operator
# operator-password: a474ikLqA7KscI49zuH1O03bDTI42yJX
```
2. Create a new Juju secret with the updated password:
```shell
juju add-secret mypass operator=abcd123456
# secret:d2te3fe3rarc4b9fuj70
```
3. Grant Cassandra access to the new secret:
```shell
juju grant-secret mypass cassandra
```
4. Update Cassandra to use the new secret:
```shell
juju config cassandra system-users=secret:d2te3fe3rarc4b9fuj70
```
5. Verify that the password has been rotated:
```shell
juju show-secret --reveal cassandra-peers.cassandra.app | grep operator
# operator-password: abcd123456
```
#### NOTE
Once rotated, all clients must use the new password to connect.
# index.html.md
# Contact
#### NOTE
This charm and its documentation are work in progress (WIP).
Communication channels may evolve as the project matures.
Stay connected with the Charmed Apache Cassandra team
and the broader Canonical Data & Juju communities.
See below for our contact information.
Contact Canonical Data Platform team in
[Matrix](https://matrix.to/#/#charmhub-data-platform:ubuntu.com).
Report your ideas/issues on GitHub:
- Charm issues: [https://github.com/canonical/cassandra-operator/issues](https://github.com/canonical/cassandra-operator/issues)
- Snap packaging: [https://github.com/canonical/charmed-cassandra-snap/issues](https://github.com/canonical/charmed-cassandra-snap/issues)
When filing an issue, please include:
- Charm / packaging artifact version
- Juju version & substrate (cloud / VM / LXD / Kubernetes)
- Reproduction steps & expected vs actual behavior
- Logs or relevant command output (`juju status`, `juju debug-log`) where possible
## Useful links
More resources:
- [Canonical Data Fabric](https://ubuntu.com/data/)
- [Git sources](https://github.com/canonical/cassandra-operator)
- [Canonical Data on Launchpad](https://launchpad.net/~data-platform)
- [Canonical Data on Matrix](https://matrix.to/#/#charmhub-data-platform:ubuntu.com)
# index.html.md
# 1. Set up the environment
This is a part of the [Charmed Apache Cassandra Tutorial](https://canonical.com/data/cassandra/docs/latest//tutorial/index.md).
For this tutorial, we need to set up the environment with two main components, plus some extra
command-line tooling:
- [LXD](https://github.com/canonical/lxd) - a system container and virtual machine manager that
provides the local cloud our cluster runs on
- [Juju](https://github.com/juju/juju) - lets us deploy and manage Charmed Apache Cassandra and
related applications
- [jq](https://github.com/jqlang/jq) - a command-line JSON processor used to parse command output
## Prepare the cloud
The fastest, simplest way to get started with Charmed Apache Cassandra is to set up a local LXD
cloud. Each Cassandra node runs inside an LXD container managed by Juju. While this tutorial covers
the basics of LXD, you can [learn more about LXD here](https://canonical.com/lxd/docs/stable-5.21/).
LXD comes pre-installed on Ubuntu 24.04 LTS. Verify that LXD is installed by entering the command
`which lxd`. This will output `/snap/bin/lxd` or, on some systems, `/usr/sbin/lxd`.
Although LXD is already installed, we need to run `lxd init` to perform post-installation tasks. For
this tutorial the default parameters are preferred, and the network bridge should be set to have no
IPv6 addresses since Juju does not support IPv6 addresses with LXD:
```shell
lxd init --auto
lxc network set lxdbr0 ipv6.address none
```
You can list all LXD containers by entering the command `lxc list`. At this point of the tutorial
none should exist, so you will only see this output:
```text
+------+-------+------+------+------+-----------+
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |
+------+-------+------+------+------+-----------+
```
## Install and prepare Juju
[Juju](https://juju.is/) is an Operator Lifecycle Manager (OLM) for clouds, bare metal, LXD and
Kubernetes. We will use it to deploy and manage Charmed Apache Cassandra. As with LXD, Juju is
installed from a snap package:
```shell
sudo snap install juju --channel 3.6/stable
```
Install `jq`, a JSON processor used to parse Juju output in later steps:
```shell
sudo snap install jq
```
## Bootstrap a Juju controller
Juju already has built-in knowledge of LXD and how it works, so there is no additional cloud setup
needed. A Juju controller will be created, which will in turn manage the operations of Charmed Apache
Cassandra.
All we need to do is bootstrap a Juju controller named `overlord` onto the `localhost` (LXD) cloud.
This bootstrapping process can take several minutes depending on the resources available on your
machine:
```shell
juju bootstrap localhost overlord
```
The Juju controller runs inside its own LXD container. To verify this, check the list of containers:
```shell
lxc list
```
Output example
```text
+---------------+---------+-----------------------+------+-----------+-----------+
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |
+---------------+---------+-----------------------+------+-----------+-----------+
| juju- | RUNNING | 10.166.144.1 (eth0) | | CONTAINER | 0 |
+---------------+---------+-----------------------+------+-----------+-----------+
```
where `` is a unique combination of numbers and letters such as `9d7e4e-0`.
## Create a model
A controller can manage multiple models. A model hosts applications such as Charmed Apache Cassandra.
Create a model named `tutorial`:
```shell
juju add-model tutorial
```
Check the status of the model you just created:
```shell
juju status
```
Output example
```text
Model Controller Cloud/Region Version SLA Timestamp
tutorial overlord localhost/localhost 3.6.29 unsupported 12:10:54Z
Model "admin/tutorial" is empty.
```
With the environment ready, we can move on to deploying Charmed Apache Cassandra.
# index.html.md
# 4. Integrate with a client application
This is a part of the [Charmed Apache Cassandra Tutorial](https://canonical.com/data/cassandra/docs/latest//tutorial/index.md).
The recommended way to create and manage client users is through another charm: the
[Data Integrator Charm](https://charmhub.io/data-integrator). This lets us encode users directly in
the Juju model, and generate scoped credentials and a dedicated keyspace automatically using a
relation, without ever touching the admin `operator` user.
#### NOTE
Relations, which the Juju documentation also calls
[integrations](https://canonical.com/juju/docs/juju-cli/3.6/reference/relation/), let two charms
exchange information and interact with one another. Creating a relation between Charmed Apache
Cassandra and the Data Integrator automatically generates a username and password, creates a
keyspace, and assigns the relevant permissions on that keyspace. This is the simplest way to create
and manage client users in Charmed Apache Cassandra.
## The Data Integrator charm
The [Data Integrator charm](https://charmhub.io/data-integrator) is a bare-bones charm for the
central management of database and messaging users. It supports many data products (Apache
Cassandra, MongoDB, MySQL, PostgreSQL, Apache Kafka, OpenSearch, and more) with a consistent and
robust user experience.
Deploy the Data Integrator and tell it which keyspace to request through the `keyspace-name`
configuration option:
```shell
juju deploy data-integrator --config keyspace-name=tutorial_app
```
The charm starts in a `blocked` state with a message such as `Please relate the data-integrator with the desired product`. This is expected, as it has nothing to integrate with yet.
To create the user and keyspace, integrate the Data Integrator with Charmed Apache Cassandra:
```shell
juju integrate data-integrator cassandra
```
Wait for the status to become `active`/`idle` using `watch juju status --color`.
Output example
```text
Model Controller Cloud/Region Version SLA Timestamp
tutorial overlord localhost/localhost 3.6.29 unsupported 13:02:41Z
App Version Status Scale Charm Channel Rev Exposed Message
cassandra 5.0.5 active 3 cassandra 5/edge 42 no
data-integrator active 1 data-integrator latest/stable 362 no
self-signed-certificates active 1 self-signed-certificates 1/stable 317 no
Unit Workload Agent Machine Public address Ports Message
cassandra/0* active idle 0 10.166.144.10 9042/tcp
cassandra/1 active idle 1 10.166.144.11 9042/tcp
cassandra/2 active idle 2 10.166.144.12 9042/tcp
data-integrator/0* active idle 3 10.166.144.13
self-signed-certificates/0* active idle 4 10.166.144.14
```
## Retrieve the credentials
Once the integration is set, retrieve the generated credentials with the `get-credentials` action:
```shell
juju run data-integrator/leader get-credentials
```
This outputs something like:
```yaml
cassandra:
endpoints: 10.166.144.10,10.166.144.11,10.166.144.12
password: 3xHk9fRpQ2vLmN8sT4wZ
tls-ca: |-
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
username: user_6xRzpv4iGLMqVsok_relation_6
ok: "True"
```
Note the values for `username`, `password`, and `endpoints`. These credentials belong to a user that
is scoped to the `tutorial_app` keyspace only. This is exactly how a real client application would
obtain its credentials, and because the user is scoped, it cannot touch data in other keyspaces or
perform cluster-wide administration.
#### NOTE
Because TLS is enabled from the previous chapter, the credentials also include a `tls-ca` field (shown
truncated above) carrying the CA a client needs to trust the cluster.
## Rotate or remove the user
Credentials are managed entirely through the relation. To rotate them, remove and re-add the
integration:
```shell
juju remove-relation data-integrator cassandra
juju integrate data-integrator cassandra
```
Running `get-credentials` again returns a new username and password. To remove the user and its
access entirely, simply remove the relation:
```shell
juju remove-relation data-integrator cassandra
```
#### NOTE
Removing the relation revokes the generated user, but it does not delete the keyspace or any data in
it. The `tutorial_app` keyspace remains in the cluster until you drop it explicitly.
## What’s next?
The Data Integrator shows how client applications receive scoped credentials. In the next section we
will switch to the admin `operator` user and use `cqlsh` directly to create our own keyspace and work
with data, giving us full control over the replication factor for the scaling exercises that follow.
# index.html.md
# Tutorial
The Charmed Apache Cassandra Operator delivers automated operations management from
[Day 0 to Day 2](https://codilime.com/blog/day-0-day-1-day-2-the-software-lifecycle-in-the-cloud-age/)
on the [Apache Cassandra](https://cassandra.apache.org/) distributed database. It is an open source,
end-to-end, production-ready data platform [on top of Juju](https://juju.is/).
As a first step, this tutorial shows you how to get Charmed Apache Cassandra up and running, but it
does not stop there. Through this tutorial you will learn a range of operations, from deploying a
cluster to enabling TLS encryption, integrating client applications, working with data using the
`cqlsh` command-line client, and scaling the cluster in and out while keeping your data safe.
This tutorial targets the **VM** charm `cassandra` running on a local LXD cloud.
#### NOTE
Charmed Apache Cassandra is under active development and is currently published on the `5/edge`
channel only. It is not yet recommended for production environments.
In this tutorial, we will walk through how to:
- Set up your local environment using LXD and Juju, and bootstrap a controller
- Deploy Charmed Apache Cassandra with only a few commands
- Enable TLS encryption for peer-to-peer and client-to-node communication
- Create a scoped client user automatically through a relation with the Data Integrator charm
- Create a keyspace and read and write data using the `cqlsh` client
- Scale the cluster out and in, and confirm that data is replicated and preserved
- Clean up your environment safely
While this tutorial intends to guide and teach you as you deploy Charmed Apache Cassandra, it will be
most beneficial if you already have familiarity with:
- Basic Unix shell commands
- General database concepts such as replication, keyspaces, and user management
## Minimum requirements
Before we start, make sure your machine meets the following requirements:
- Ubuntu 24.04 LTS (Noble) or later
- 8 GB of RAM
- 2 CPU cores
- At least 20 GB of available storage
- Access to the internet for downloading the required snaps and charms
#### NOTE
This tutorial uses the `testing` profile, which tunes Cassandra for a minimal resource footprint so
that a multi-node cluster fits comfortably on a single developer machine. Production deployments
should use the default `production` profile on dedicated hosts.
## Step-by-step guide
Here is an overview of the steps required, with links to the individual tutorials that deal with
each one:
- [Set up the environment](https://canonical.com/data/cassandra/docs/latest//tutorial/environment.md#tutorial-environment)
- [Deploy Charmed Apache Cassandra](https://canonical.com/data/cassandra/docs/latest//tutorial/deploy.md#tutorial-deploy)
- [Enable encryption](https://canonical.com/data/cassandra/docs/latest//tutorial/enable-encryption.md#tutorial-enable-encryption)
- [Integrate with a client application](https://canonical.com/data/cassandra/docs/latest//tutorial/integrate-with-client-applications.md#tutorial-integrate-with-client-applications)
- [Manage data with cqlsh](https://canonical.com/data/cassandra/docs/latest//tutorial/manage-data.md#tutorial-manage-data)
- [Scale your cluster](https://canonical.com/data/cassandra/docs/latest//tutorial/scale.md#tutorial-scale)
- [Clean up your environment](https://canonical.com/data/cassandra/docs/latest//tutorial/cleanup.md#tutorial-cleanup)
# index.html.md
# 2. Deploy Apache Cassandra
This is a part of the [Charmed Apache Cassandra Tutorial](https://canonical.com/data/cassandra/docs/latest//tutorial/index.md#tutorial-index).
To deploy Charmed Apache Cassandra, all you need to do is run the following command, which fetches
[Apache Cassandra](https://charmhub.io/cassandra) from [Charmhub](https://charmhub.io/) and deploys
it to your model.
For this tutorial we will deploy a cluster of three nodes using the `testing` profile, which keeps
the resource footprint small. Three or more nodes are recommended to keep data highly available:
```shell
juju deploy cassandra -n 3 --config profile=testing --channel 5/edge
```
Juju will now fetch Charmed Apache Cassandra and begin deploying it to your LXD cloud. You can track
the progress by running:
```shell
watch juju status --color
```
During bootstrap, units pass through several transient maintenance and waiting statuses, such as
`installing Cassandra`, `waiting for internal TLS setup`, `waiting for cluster to start`, `waiting for Cassandra to start`, and `repairing system_auth keyspace`. This process can take several minutes
depending on the resources available on your machine.
Wait until all units show `active`/`idle` status:
Output example
```text
Model Controller Cloud/Region Version SLA Timestamp
tutorial overlord localhost/localhost 3.6.29 unsupported 12:31:09Z
App Version Status Scale Charm Channel Rev Exposed Message
cassandra 5.0.5 active 3 cassandra 5/edge 42 no
Unit Workload Agent Machine Public address Ports Message
cassandra/0* active idle 0 10.166.144.10 9042/tcp
cassandra/1 active idle 1 10.166.144.11 9042/tcp
cassandra/2 active idle 2 10.166.144.12 9042/tcp
Machine State Address Inst id Base AZ Message
0 started 10.166.144.10 juju-9d7e4e-0 ubuntu@24.04 Running
1 started 10.166.144.11 juju-9d7e4e-1 ubuntu@24.04 Running
2 started 10.166.144.12 juju-9d7e4e-2 ubuntu@24.04 Running
```
To exit the `watch` screen, press `Ctrl+C`.
Each node exposes the Apache Cassandra native transport protocol on port `9042`, which is the port
`cqlsh` and client applications use to connect.
## Access the cluster
Authentication is enabled by default. The charm automatically generates a password for the built-in
`operator` user and stores it in a Juju secret.
All sensitive configuration data used by Charmed Apache Cassandra, such as passwords and TLS
certificates, is stored in Juju secrets. See the
[Juju secrets documentation](https://canonical.com/juju/docs/juju-cli/3.6/reference/secret/) for more
information.
The `operator` password lives in the application secret of the `cassandra-peers` relation. The secret
label follows the pattern `cassandra-peers..app`, so for our `cassandra` application
it is `cassandra-peers.cassandra.app`. Retrieve the password with:
```shell
juju show-secret --reveal cassandra-peers.cassandra.app --format json \
| jq -r '.[].content.Data."operator-password"'
```
This prints the current `operator` password, for example:
```text
a474ikLqA7KscI49zuH1O03bDTI42yJX
```
Make note of this value, we will use it to connect in the next steps.
## Connect with cqlsh
`cqlsh` is the official command-line client for Apache Cassandra. The
[`charmed-cassandra`](https://snapcraft.io/charmed-cassandra) snap bundles `cqlsh` (as well as the
`nodetool` admin utility we use later), so install it locally:
```shell
sudo snap install charmed-cassandra --edge
```
Retrieve the address of a unit (here `cassandra/0`) with `juju show-unit`, parsing it out with `jq`
and storing it in a variable:
```shell
CASSANDRA_IP=$(juju show-unit cassandra/0 --format json | jq -r '."cassandra/0"."public-address"')
```
Connect as the `operator` user, passing in that address:
```shell
charmed-cassandra.cqlsh "$CASSANDRA_IP" -u operator -p ""
```
Output example
```text
[cqlsh 6.1.0 | Cassandra 5.0.5 | CQL spec 3.4.7 | Native protocol v5]
Use HELP for help.
operator@cqlsh>
```
You now have an interactive CQL shell connected to the cluster. To confirm the cluster is healthy,
list the keyspaces that ship with Cassandra:
```text
operator@cqlsh> DESCRIBE KEYSPACES;
system_auth system_schema system system_distributed
system_views system_traces system_virtual_schema
```
Leave the shell for now by typing `exit`:
```text
operator@cqlsh> exit
```
## What’s next?
So far we have connected over an unencrypted channel. In a real deployment, traffic between nodes and
between clients and nodes should be encrypted. In the next section we will enable TLS encryption
across the cluster.
# index.html.md
# 3. Enable encryption
This is a part of the [Charmed Apache Cassandra Tutorial](https://canonical.com/data/cassandra/docs/latest//tutorial/index.md).
[TLS](https://en.wikipedia.org/wiki/Transport_Layer_Security) encrypts data exchanged between
applications, securing it as it travels over the network. Typically, enabling TLS within a highly
available database, and between the database and its clients, requires domain-specific knowledge and
a high level of expertise. Fortunately, that knowledge has been encoded into Charmed Apache
Cassandra, so configuring TLS requires minimal effort on your end.
Juju relations are particularly useful for enabling TLS. Charmed Apache Cassandra implements the
**Requirer** side of the [tls-certificates](https://charmhub.io/integrations/tls-certificates)
relation, so any charm implementing the **Provider** side can supply certificates. The relation
centralises certificate management, handling provisioning, requests, and renewal, and lets you use
different providers such as self-signed certificates or external services like Let’s Encrypt.
Charmed Apache Cassandra supports two separate TLS channels, each exposed as its own relation
endpoint:
- `peer-certificates` - encrypts peer-to-peer traffic between the nodes in the cluster
- `client-certificates` - encrypts client-to-node traffic, for example connections from `cqlsh`
#### NOTE
In this tutorial we distribute [self-signed certificates](https://en.wikipedia.org/wiki/Self-signed_certificate)
signed by a single root CA. This is for testing and demonstration only. Self-signed certificates are
not recommended for a production cluster. For guidance on choosing a provider, see the
[Security with X.509 certificates](https://charmhub.io/topics/security-with-x-509-certificates) page.
## Deploy a certificate provider
Before enabling TLS on Charmed Apache Cassandra, deploy the `self-signed-certificates` charm:
```shell
juju deploy self-signed-certificates --channel 1/stable --config ca-common-name="Tutorial CA"
```
Wait for the charm to settle into an `active`/`idle` state, as shown by `juju status`.
## Enable peer-to-peer encryption
To encrypt traffic between the cluster nodes, integrate Charmed Apache Cassandra with the certificate
provider over the `peer-certificates` endpoint:
```shell
juju integrate cassandra:peer-certificates self-signed-certificates
```
While certificates are being issued and distributed, units show waiting and maintenance statuses such
as `waiting for internal TLS setup` and `waiting for peer tls rotation to complete`. Once the process
completes, the units return to `active`/`idle`.
## Enable client-to-node encryption
To encrypt traffic between clients and the cluster, integrate over the `client-certificates`
endpoint:
```shell
juju integrate cassandra:client-certificates self-signed-certificates
```
Again the units briefly show statuses such as `waiting for TLS setup` and `waiting for client tls rotation to complete` before returning to `active`/`idle`.
## Reconnect with cqlsh over SSL
Now that client-to-node encryption is enabled, the cluster rejects plaintext connections. If you try
to connect the way we did in the previous chapter, it fails:
```shell
charmed-cassandra.cqlsh "$CASSANDRA_IP" -u operator -p ""
```
```text
Connection error: ('Unable to connect to any servers',
{'10.166.144.10:9042': ConnectionResetError(104, 'Connection reset by peer')})
```
This confirms that Apache Cassandra now requires a secure TLS connection.
### Retrieve the root CA
`cqlsh` needs the root CA to verify the certificate the Cassandra nodes present during the TLS
handshake. Fetch it from the `self-signed-certificates` charm.
Since the `charmed-cassandra` snap is strictly confined, the CA must live in a location the snap can
read. Write it directly into the snap’s configuration directory:
```shell
juju run self-signed-certificates/0 get-ca-certificate --format json \
| jq -r '."self-signed-certificates/0".results."ca-certificate"' \
| sudo tee /var/snap/charmed-cassandra/current/etc/cassandra/ca.cert
```
### Create a cqlshrc file
In the same directory, create a `cqlshrc` configuration file that tells `cqlsh` which credentials to
use and where to find the CA. Retrieve the `operator` password again if you need it:
```shell
juju show-secret --reveal cassandra-peers.cassandra.app --format json \
| jq -r '.[].content.Data."operator-password"'
```
Then create `/var/snap/charmed-cassandra/current/etc/cassandra/cqlshrc` with the following content,
substituting the password and the `` address captured earlier:
```ini
[authentication]
username = operator
password =
[connection]
hostname =
port = 9042
[ssl]
certfile = /var/snap/charmed-cassandra/current/etc/cassandra/ca.cert
validate = true
```
`cqlsh` refuses to use a `cqlshrc` that other users can read, so restrict its permissions to your
user only:
```shell
sudo chown $USER /var/snap/charmed-cassandra/current/etc/cassandra/cqlshrc
sudo chmod 600 /var/snap/charmed-cassandra/current/etc/cassandra/cqlshrc
```
### Connect
Connect to the cluster over TLS by pointing `cqlsh` at the `cqlshrc` file and passing the `--ssl`
flag:
```shell
charmed-cassandra.cqlsh --ssl \
--cqlshrc /var/snap/charmed-cassandra/current/etc/cassandra/cqlshrc
```
Output example
```text
[cqlsh 6.1.0 | Cassandra 5.0.5 | CQL spec 3.4.7 | Native protocol v5]
Use HELP for help.
operator@cqlsh>
```
The connection now succeeds over an encrypted channel. The `hostname` set in `cqlshrc` is the default
target, but you can always connect to a specific node by passing its address as a positional
argument, which is handy once the cluster has more nodes:
```shell
charmed-cassandra.cqlsh --ssl "$CASSANDRA_IP" \
--cqlshrc /var/snap/charmed-cassandra/current/etc/cassandra/cqlshrc
```
Leave the shell with `exit`. We will reuse this `cqlshrc` file for every `cqlsh` command in the rest
of the tutorial.
#### NOTE
If you ever want to go back to unencrypted connections, remove the relations with
`juju remove-relation cassandra:client-certificates self-signed-certificates` and
`juju remove-relation cassandra:peer-certificates self-signed-certificates`. This triggers a rolling
restart as the units switch back to plaintext communication.
## What’s next?
The cluster is now secured. In the next section we will integrate a client application to generate a
scoped user and a dedicated keyspace automatically through a relation.
# index.html.md
# 7. Clean up your environment
This is a part of the [Charmed Apache Cassandra Tutorial](https://canonical.com/data/cassandra/docs/latest//tutorial/index.md).
In this tutorial we deployed Charmed Apache Cassandra, enabled TLS encryption, integrated a client
application, worked with data using `cqlsh`, and scaled the cluster in and out. This final section
shows how to tear everything down safely.
## Remove the tutorial model
#### CAUTION
Removing a Juju model destroys every application in it along with their storage. This deletes all the
data we created. Only do this when you are finished with the tutorial.
To remove Charmed Apache Cassandra and everything else in the `tutorial` model:
```shell
juju destroy-model tutorial --destroy-storage --no-prompt
```
This removes all applications in the model (Charmed Apache Cassandra, the Data Integrator, and the
self-signed certificates provider). Your Juju controller and any other models remain intact for future
use.
## (Optional) Remove the client snap
If you no longer need the `cqlsh` and `nodetool` clients locally, remove the `charmed-cassandra` snap.
This also removes the `ca.cert` and `cqlshrc` files we created under its configuration directory:
```shell
sudo snap remove charmed-cassandra --purge
```
## (Optional) Remove Juju and the cloud
If you do not need Juju anymore and want to free up additional resources, you can remove the Juju
controller and Juju itself.
#### CAUTION
Removing the Juju controller as shown below means you lose access to any other applications and models
hosted on it.
Check the list of controllers:
```shell
juju controllers
```
Remove the controller created in this tutorial:
```shell
juju destroy-controller overlord --destroy-all-models --destroy-storage
```
To remove Juju altogether:
```shell
sudo snap remove juju --purge
```
### Clean up LXD
If you also want to remove the LXD containers and free up all resources, list any remaining
containers:
```shell
lxc list
```
Delete unnecessary containers:
```shell
lxc delete --force
```
If you want to uninstall LXD completely:
```shell
sudo snap remove lxd --purge
```
#### WARNING
Only remove LXD if you are not using it for other purposes. LXD may be managing other containers or
virtual machines on your system.
## What’s next?
In this tutorial we deployed Apache Cassandra, secured it with TLS, created users and data, and scaled
the cluster while keeping data safe. If you are looking for what to do next, you can:
- Read the [how-to guides](https://canonical.com/data/cassandra/docs/latest//how-to/index.md#how-to-index) for deploying, scaling, securing, and monitoring a cluster
- Explore other Charmed offerings from
[Canonical’s Data Platform team](https://canonical.com/data)
- [Report](https://github.com/canonical/cassandra-operator/issues) any problems you encountered
- [Give us your feedback](https://matrix.to/#/#charmhub-data-platform:ubuntu.com)
- [Contribute to the code base](https://github.com/canonical/cassandra-operator)
# index.html.md
# 6. Scale your cluster
This is a part of the [Charmed Apache Cassandra Tutorial](https://canonical.com/data/cassandra/docs/latest//tutorial/index.md).
One of the main reasons to run Apache Cassandra is its ability to scale horizontally while keeping
data available. In this section we scale the cluster out, confirm the data we wrote earlier has been
replicated to the new node, add more data, then scale back in and confirm nothing was lost.
A Cassandra cluster is also called a *ring*: a peer-to-peer set of nodes where every node is equal.
When nodes are added or removed, the charm drives the operation while Apache Cassandra itself
automatically redistributes (streams) the data, so the ring stays balanced and the replication
factor is honoured.
## Inspect the ring
The `nodetool` utility reports the state of the ring. It uses a separate internal user,
`charmed-operator`, whose password is in the `nodetool-password` field of the `cassandra-peers`
secret. Run it on any unit through `juju ssh`:
```shell
juju ssh cassandra/0 sudo snap run charmed-cassandra.nodetool \
-u charmed-operator -pw "$(juju show-secret --reveal cassandra-peers.cassandra.app --format json | jq -r '.[].content.Data."nodetool-password"')" \
status
```
Output example
```text
Datacenter: datacenter1
=======================
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
-- Address Load Tokens Owns (effective) Host ID Rack
UN 10.166.144.10 120.5 KiB 16 100.0% 1f3f0e1e-... rack1
UN 10.166.144.11 118.9 KiB 16 100.0% 9a2b7c4d-... rack1
UN 10.166.144.12 121.2 KiB 16 100.0% 5e8d1a2c-... rack1
```
`UN` means the node is **U**p and in the **N**ormal state. With three nodes and a replication factor
of `3`, each node owns `100.0%` of the data.
## Scale out
Add a fourth node to the cluster:
```shell
juju add-unit cassandra -n 1
```
Monitor the progress with `watch juju status --color`. The new unit shows `waiting for cluster to start` while it bootstraps and joins the ring, then becomes `active`/`idle`. As it joins, Cassandra
streams data to it automatically.
Output example
```text
App Version Status Scale Charm Channel Rev Exposed Message
cassandra 5.0.5 active 4 cassandra 5/edge 42 no
Unit Workload Agent Machine Public address Ports Message
cassandra/0* active idle 0 10.166.144.10 9042/tcp
cassandra/1 active idle 1 10.166.144.11 9042/tcp
cassandra/2 active idle 2 10.166.144.12 9042/tcp
cassandra/3 active idle 5 10.166.144.15 9042/tcp
```
Run `nodetool status` again, and you will see the fourth node in the ring, carrying its own share of
the load, which confirms that data was streamed to it:
```shell
juju ssh cassandra/0 sudo snap run charmed-cassandra.nodetool \
-u charmed-operator -pw "$(juju show-secret --reveal cassandra-peers.cassandra.app --format json | jq -r '.[].content.Data."nodetool-password"')" \
status
```
Output example
```text
Datacenter: datacenter1
=======================
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
-- Address Load Tokens Owns (effective) Host ID Rack
UN 10.166.144.10 135.1 KiB 16 73.8% 1f3f0e1e-... rack1
UN 10.166.144.11 132.7 KiB 16 76.2% 9a2b7c4d-... rack1
UN 10.166.144.12 134.4 KiB 16 74.9% 5e8d1a2c-... rack1
UN 10.166.144.15 98.3 KiB 16 75.1% b7c3f9a1-... rack1
```
With four nodes and a replication factor of `3`, each node now owns roughly `75%` of the data instead
of `100%`.
## Verify data was replicated
To prove the new node serves our data, connect `cqlsh` **directly to the new node’s address** by
passing it as a positional argument (this overrides the `hostname` in `cqlshrc`). Capture the new
unit’s address the same way as before:
```shell
NEW_CASSANDRA_IP=$(juju show-unit cassandra/3 --format json | jq -r '."cassandra/3"."public-address"')
```
```shell
charmed-cassandra.cqlsh --ssl "$NEW_CASSANDRA_IP" \
--cqlshrc /var/snap/charmed-cassandra/current/etc/cassandra/cqlshrc
```
Read the rows we wrote earlier:
```text
operator@cqlsh> SELECT * FROM tutorial.members;
id | name | race
----+---------+--------
1 | frodo | hobbit
2 | gandalf | maia
3 | aragorn | human
(3 rows)
```
The data we inserted on a three-node cluster is now available from the brand-new fourth node.
## Add more data
While still connected (to any node), insert another row:
```text
operator@cqlsh> INSERT INTO tutorial.members (id, name, race) VALUES (4, 'legolas', 'elf');
operator@cqlsh> SELECT * FROM tutorial.members;
id | name | race
----+---------+--------
1 | frodo | hobbit
2 | gandalf | maia
3 | aragorn | human
4 | legolas | elf
(4 rows)
```
Leave the shell with `exit`.
## Scale in
Now remove the fourth node. The charm *decommissions* it, streaming its data to the remaining nodes
before it leaves the ring, so no data is lost:
```shell
juju remove-unit cassandra/3
```
#### CAUTION
Before removing a unit, check the replication factor of your keyspaces. If removing a unit would bring
the number of nodes below a keyspace’s replication factor, that keyspace may lose data or become
unavailable. Here we go from four nodes back to three, which still satisfies our replication factor of
`3`.
#### NOTE
Only one unit can be removed at a time. During removal, units show statuses related to
decommissioning while data is streamed off the departing node.
Wait for the cluster to return to three `active`/`idle` units, then check the ring again. The fourth
node is gone and the three remaining nodes again own `100.0%` of the data:
```shell
juju ssh cassandra/0 sudo snap run charmed-cassandra.nodetool \
-u charmed-operator -pw "$(juju show-secret --reveal cassandra-peers.cassandra.app --format json | jq -r '.[].content.Data."nodetool-password"')" \
status
```
## Verify data was preserved
Connect to one of the remaining nodes and read the table:
```shell
charmed-cassandra.cqlsh --ssl "$CASSANDRA_IP" \
--cqlshrc /var/snap/charmed-cassandra/current/etc/cassandra/cqlshrc
```
```text
operator@cqlsh> SELECT * FROM tutorial.members;
id | name | race
----+---------+--------
1 | frodo | hobbit
2 | gandalf | maia
3 | aragorn | human
4 | legolas | elf
(4 rows)
```
All four rows are still there, including the one we added while the cluster had four nodes. Scaling in
preserved the data. Leave the shell with `exit`.
## What’s next?
You have now scaled the cluster out and in while keeping your data safe. In the final section we will
clean up the environment.
# index.html.md
# 5. Manage data with cqlsh
This is a part of the [Charmed Apache Cassandra Tutorial](https://canonical.com/data/cassandra/docs/latest//tutorial/index.md).
In this section we use the admin `operator` user and the `cqlsh` client to create a keyspace, define a
table, and write and read some data. We keep this `cqlsh` session handy for the scaling exercises in
the next chapter.
All the commands below connect over TLS using the `cqlshrc` file we created in the
[encryption chapter](https://canonical.com/data/cassandra/docs/latest//tutorial/enable-encryption.md#tutorial-enable-encryption). Open a shell:
```shell
charmed-cassandra.cqlsh --ssl \
--cqlshrc /var/snap/charmed-cassandra/current/etc/cassandra/cqlshrc
```
You should land at the `operator@cqlsh>` prompt.
## Create a keyspace
A keyspace is the top-level container for data in Cassandra, roughly analogous to a database in a
relational system. Crucially, the keyspace defines how data is replicated across the nodes in the
cluster through its *replication factor*.
Create a keyspace called `tutorial` with a replication factor of `3`. With three nodes in the cluster,
this means every node holds a full copy of the data:
```text
operator@cqlsh> CREATE KEYSPACE tutorial
... WITH replication = {
... 'class': 'SimpleStrategy',
... 'replication_factor': 3
... };
```
Confirm it was created:
```text
operator@cqlsh> DESCRIBE KEYSPACE tutorial;
CREATE KEYSPACE tutorial WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '3'} AND durable_writes = true;
```
#### NOTE
Setting the replication factor equal to the number of nodes is convenient for this tutorial because
it guarantees that each node holds every row. In production you typically keep the replication factor
fixed (for example, `3`) while the cluster grows, so that data is spread across a subset of nodes
rather than copied to all of them.
## Create a table
Switch into the new keyspace and create a simple table to store a list of members of the Fellowship:
```text
operator@cqlsh> USE tutorial;
operator@cqlsh:tutorial> CREATE TABLE members (
... id int PRIMARY KEY,
... name text,
... race text
... );
```
## Add data
Insert a few rows:
```text
operator@cqlsh:tutorial> INSERT INTO members (id, name, race) VALUES (1, 'frodo', 'hobbit');
operator@cqlsh:tutorial> INSERT INTO members (id, name, race) VALUES (2, 'gandalf', 'maia');
operator@cqlsh:tutorial> INSERT INTO members (id, name, race) VALUES (3, 'aragorn', 'human');
```
## Read data
Read the rows back:
```text
operator@cqlsh:tutorial> SELECT * FROM members;
id | name | race
----+---------+--------
1 | frodo | hobbit
2 | gandalf | maia
3 | aragorn | human
(3 rows)
```
#### NOTE
`SELECT *` without a `WHERE` clause scans every partition across the whole cluster. It is fine on
this tiny tutorial table, but on a production deployment it is an expensive operation that should be
avoided. Real queries normally restrict the rows they read, for example with `WHERE id = 1`.
The data is now stored in the cluster and, thanks to the replication factor of `3`, replicated to
every node. We can demonstrate this with the `CONSISTENCY ALL` setting, which forces a read to
contact *every* replica and only succeed if they all respond. Since each node holds a full copy, the
read still returns all three rows:
```text
operator@cqlsh:tutorial> CONSISTENCY ALL;
Consistency level set to ALL.
operator@cqlsh:tutorial> SELECT * FROM members;
id | name | race
----+---------+--------
1 | frodo | hobbit
2 | gandalf | maia
3 | aragorn | human
(3 rows)
```
Reset the consistency level back to the default before moving on:
```text
operator@cqlsh:tutorial> CONSISTENCY QUORUM;
Consistency level set to QUORUM.
```
Leave the shell with `exit`.
## What’s next?
In the next section we will scale the cluster out and confirm that our data is automatically
replicated to the new node, add more data, then scale back in and confirm that nothing is lost.
# index.html.md
# Tutorial
The Charmed Apache Cassandra Operator delivers automated operations management from
[Day 0 to Day 2](https://codilime.com/blog/day-0-day-1-day-2-the-software-lifecycle-in-the-cloud-age/)
on the [Apache Cassandra](https://cassandra.apache.org/) distributed database. It is an open source,
end-to-end, production-ready data platform [on top of Juju](https://juju.is/).
As a first step, this tutorial shows you how to get Charmed Apache Cassandra up and running, but it
does not stop there. Through this tutorial you will learn a range of operations, from deploying a
cluster to enabling TLS encryption, integrating client applications, working with data using the
`cqlsh` command-line client, and scaling the cluster in and out while keeping your data safe.
This tutorial targets the **VM** charm `cassandra` running on a local LXD cloud.
#### NOTE
Charmed Apache Cassandra is under active development and is currently published on the `5/edge`
channel only. It is not yet recommended for production environments.
In this tutorial, we will walk through how to:
- Set up your local environment using LXD and Juju, and bootstrap a controller
- Deploy Charmed Apache Cassandra with only a few commands
- Enable TLS encryption for peer-to-peer and client-to-node communication
- Create a scoped client user automatically through a relation with the Data Integrator charm
- Create a keyspace and read and write data using the `cqlsh` client
- Scale the cluster out and in, and confirm that data is replicated and preserved
- Clean up your environment safely
While this tutorial intends to guide and teach you as you deploy Charmed Apache Cassandra, it will be
most beneficial if you already have familiarity with:
- Basic Unix shell commands
- General database concepts such as replication, keyspaces, and user management
## Minimum requirements
Before we start, make sure your machine meets the following requirements:
- Ubuntu 24.04 LTS (Noble) or later
- 8 GB of RAM
- 2 CPU cores
- At least 20 GB of available storage
- Access to the internet for downloading the required snaps and charms
#### NOTE
This tutorial uses the `testing` profile, which tunes Cassandra for a minimal resource footprint so
that a multi-node cluster fits comfortably on a single developer machine. Production deployments
should use the default `production` profile on dedicated hosts.