Back up and restore Apache Cassandra nodes with Cassandra Medusa: list backups and read one backup's status, verify the files a backup stored, read the token map it captured, report how old the latest backups are, take full or differential node backups, purge backups past retention or delete one by name, and restore a node in place. Each action runs Medusa on the node it targets; a cluster backup is the same backup name taken on every node.
8 allowed by default
2 need approval by default
1 denied by default
Pack ID
medusa
Vendor
emisar
OS
linux
Actions
11
Required binaries.
Install these binaries on the runner host before using the pack.
medusa
bash
python3
Use this pack with your agent
New to emisar? Start with the
quickstart
to connect one Linux host and verify an action. With a runner connected,
review this pack's actions and host requirements,
then follow installing and verifying a published pack.
Your policy decides which actions run, wait for approval, or are denied.
Connect a CLI agent,
Claude.ai
or
ChatGPT
to discover the installed actions through the same infrastructure MCP.
Install
emisar pack install
fetches this pack, re-validates it, and verifies its content hash against the
--hash
below before copying it into the runner's packs dir. That hash covers the exact bytes
this page was built from, so a tampered copy is rejected. The command reloads a
running daemon itself, so you don't need to restart it manually.
Every action runs the
medusa
CLI on the Cassandra node it targets, with Medusa's own settings from
/etc/medusa/medusa.ini
: storage provider, bucket, prefix, this node's
fqdn
, and retention. Medusa reads storage credentials from that file's
key_file
, or from the provider's default chain (
AWS_ACCESS_KEY_ID
and
AWS_SECRET_ACCESS_KEY
, an instance role, or a GCP service account). It reads the schema and token map from the local node over CQL and takes snapshots through
nodetool
. Built for Medusa 0.27.0 or later on Python 3.11 or 3.12, against Cassandra 4.1 and 5.0.
Environment
Set these on the runner host, then add each name to
execution.inherit_env
so the value reaches the action.
MEDUSA_CQL_USERNAME
CQL role Medusa logs in with, overriding
cql_username
in
medusa.ini
. Create it with
CREATE ROLE medusa WITH PASSWORD = '<password>' AND LOGIN = true
; Medusa only reads the schema and token map, which every login role can read. Add it to the runner's
execution.inherit_env
.
MEDUSA_CQL_PASSWORD
Password for that role, overriding
cql_password
in
medusa.ini
. Add it to the runner's
execution.inherit_env
.
MEDUSA_RESTORE_TEMP_DIR
default /tmp
Directory
medusa.restore_node
downloads the backup into before it stops Cassandra. The download holds every table, including
system_auth
, so create one only root can read (
sudo install -d -m 0700 <dir>
), on the data filesystem with room for this node's whole backup, and add it to the runner's
execution.inherit_env
.
Host access
Copy these setup commands and run them yourself on the runner host.
Read Medusa's configuration and storage credentials, and the Cassandra data directories a backup uploads.
id -nG emisar | tr ' ' '\n' | grep -Fx cassandra
sudo -u emisar test -r /etc/medusa/medusa.ini
Impact:
When
key_file
names a credentials file, give it the same group and mode (
sudo chgrp cassandra <key_file>
and
sudo chmod 0640 <key_file>
). Backups also need the data directories readable by the cassandra group, as the Cassandra packages install them. Every process running as emisar can then read Medusa's storage credentials, which can write and delete every backup under the prefix, the CQL and JMX credentials in
medusa.ini
, Cassandra's configuration, and raw SSTables.
Stop and start Cassandra and replace its data and commit log files.
test "$(systemctl show emisar --property=User --value)" = root
Impact:
Every Emisar action on this runner executes as root. medusa.restore_node then runs the
stop_cmd
and
start_cmd
from
/etc/medusa/medusa.ini
as root, and can replace any table's data on this node.
Notes
Install Medusa on each node with
sudo pip3 install cassandra-medusa
or the
cassandra-medusa
Debian package for Ubuntu jammy or Debian bookworm. See
Medusa's installation guide
.
Write
/etc/medusa/medusa.ini
from Medusa's
medusa-example.ini
, owned by root and writable by no one else: Medusa runs the
stop_cmd
,
start_cmd
,
nodetool_executable
, and
[checks] query
it names. If file logging is on, give
[logging] file
an absolute path.
Storage credentials: point
key_file
at an AWS credentials file (S3 and S3-compatible), a service-account JSON key (GCS), or an Azure JSON key, or leave it unset to use the provider's default chain. For S3, use an IAM user or role with the
MedusaStorageStrategy
policy from
Medusa's S3 guide
. Those credentials can write and delete every backup under the prefix.
Set
ssl_verify = True
for a TLS storage endpoint. Medusa's default skips certificate checks for S3-compatible storage.
Pin
fqdn
in
[storage]
to the name this node has in the token map, which is its address when
resolve_ip_addresses = False
. If the two differ, backups show as incomplete and a restore cannot find this node's tokens.
Medusa supports one
data_file_directories
entry per node. With JMX authentication, set
nodetool_username
and
nodetool_password_file_path
rather than
nodetool_password
, which Medusa before 0.31.0 logs when clearing a snapshot fails.
A failing storage call is retried for about six minutes before Medusa reports it, so a wrong credential or endpoint shows up as a slow failure.
A cluster backup is
medusa.backup_node
with the same
backup_name
on every node, for example from a runbook. The node snapshots are not simultaneous.
medusa.backup_status
shows which nodes finished.
medusa.restore_node
restores every keyspace in the backup, including
system_schema
and
system_auth
, so it also rolls back schema and roles. Restoring a backup older than
gc_grace_seconds
can bring deleted data back once the cluster repairs.
Not exposed:
backup-cluster
and
restore-cluster
reach other nodes over SSH, outside each runner's scope;
purge-decommissioned
can delete every backup when node names change; table-level and sstableloader restores wait for a later version.
Verify it works
Runs medusa.list_backups, a low-risk
read that confirms the pack can reach its target. Run it on the host once the pack
is installed; pack install runs it for
you.
medusa.backup_node
script
medium
Medium: changes state, easily reversible
Back up this Cassandra node with Medusa
Back up this node to the configured storage with `medusa backup-node`: snapshot every keyspace through nodetool, save the schema and token map, upload the SSTables, then clear the snapshot. Differential mode, the default, uploads only files storage does not hold yet and shares the rest with earlier backups; full mode uploads every file again. The same `backup_name` taken on every node forms one cluster backup. Medusa reports success even when the snapshot fails and records an empty or partial backup; this action fails instead and names the backup so `medusa.delete_backup` can remove it.
Arguments
Name
Type
Required
backup_name
string
Yes
mode
string
No
check_hashes
boolean
No
See the action source for defaults, validation, and limits.
medusa.backup_status
script
low
Low: read-only or trivially reversible
Show a Medusa backup's status
Show one backup across the cluster with `medusa status`: whether it is complete, when it started and finished, how many nodes completed, which nodes are incomplete or missing compared with the token map it recorded, and its file count and size. Exits 1 when no backup has that name; `medusa.list_backups` shows the names.
Arguments
Name
Type
Required
backup_name
string
Yes
See the action source for defaults, validation, and limits.
medusa.delete_backup
script
high
High: can disrupt service
Delete a Medusa backup
Delete one named backup from storage with `medusa delete-backup`, for this node only (`current-node`, the default) or for every node that holds it (`all-nodes`). Medusa then deletes this node's files that no remaining backup uses once they are older than `backup_grace_period_in_days`. Exits 1 when no backup has that name; `medusa.list_backups` shows the names.
Arguments
Name
Type
Required
backup_name
string
Yes
scope
string
No
See the action source for defaults, validation, and limits.
medusa.fetch_tokenmap
script
low
Low: read-only or trivially reversible
Show the token map saved in a Medusa backup
Show the token map one backup recorded, each node's name with the tokens it owned at backup time, using `medusa fetch-tokenmap`. The live ring is `cassandra.nodetool_ring`. Exits 1 when no backup has that name.
Arguments
Name
Type
Required
backup_name
string
Yes
See the action source for defaults, validation, and limits.
medusa.last_complete_backup
script
low
Low: read-only or trivially reversible
Show the latest complete Medusa cluster backup
Show the name of the newest backup that every node finished, using `medusa get-last-complete-cluster-backup`. When no backup is complete it prints `Could not find any full backup for the cluster` and still succeeds.
medusa.list_backups
script
low
Low: read-only or trivially reversible
List Medusa backups
List the Medusa backups that include this node, oldest first, with when each started and finished, using `medusa list-backups`. A backup that some node has not finished reads `Incomplete [n of m nodes finished]`. Set `show_all` to list every backup under the configured prefix, including ones this node is not part of. A failing storage call is retried for about six minutes before the error is reported.
Arguments
Name
Type
Required
show_all
boolean
No
See the action source for defaults, validation, and limits.
medusa.purge
script
high
High: can disrupt service
Purge Medusa backups past retention
Delete this node's backups that exceed the retention in `/etc/medusa/medusa.ini` with `medusa purge`: those older than `max_backup_age` days and the oldest beyond `max_backup_count`. A limit of 0 turns it off. Incomplete backups count toward `max_backup_count`, and nothing keeps at least one complete backup. Medusa then deletes this node's files that no remaining backup uses once they are older than `backup_grace_period_in_days`. `medusa.show_config` shows the limits and `medusa.list_backups` shows what exists.
medusa.report_last_backup
script
medium
Medium: changes state, easily reversible
Report how old the latest Medusa backups are
Report this node's latest backup, the cluster's latest complete backup with how long ago it finished, and the latest started backup with the nodes that have not finished or never ran it, its size, and its file count, using `medusa report-last-backup`. Medusa writes the report to its log, so it arrives on stderr. When storage has no latest-backup marker for this node, Medusa rebuilds the backup index, which lists every object under the prefix and connects to the node over CQL. Medusa exits 0 even when the report fails; this action fails instead.
medusa.restore_node
script
critical
Critical: data loss or irreversible
Restore this Cassandra node from a Medusa backup
Restore this node in place from one of its backups with `medusa restore-node --in-place`: download the node's backup, stop Cassandra with the `stop_cmd` in `/etc/medusa/medusa.ini`, empty the commit log, replace every keyspace's data with the backup's, including `system_schema` and `system_auth`, then start Cassandra with `start_cmd` and, with `verify`, wait until it answers. Writes made after the backup are lost on this node, and data deleted longer ago than `gc_grace_seconds` before the backup can return when the cluster repairs. Needs the Emisar service running as root. Fails before downloading anything when it is not root, and fails when the backup holds no data for this node, which Medusa would report as success.
Arguments
Name
Type
Required
backup_name
string
Yes
verify
boolean
No
See the action source for defaults, validation, and limits.
medusa.show_config
script
low
Low: read-only or trivially reversible
Show Medusa's configuration
Show the Medusa version and the settings in `/etc/medusa/medusa.ini` that decide where backups go and how long they stay: storage provider, bucket, prefix, endpoint, TLS checks, this node's `fqdn`, retention limits, and the credential file path, marking each value Medusa takes by default. Values come from an allowlist of Medusa's own keys (Medusa 0.31.1). Passwords, encryption keys, `stop_cmd` and `start_cmd`, and any `MEDUSA_*` or cloud credential environment overrides the runner passes appear by name only. Fails when the `medusa` on PATH is not Cassandra Medusa.
medusa.verify_backup
script
low
Low: read-only or trivially reversible
Verify a Medusa backup's stored files
Check one backup with `medusa verify`: every node finished, and every file in each node's manifest exists in storage with the recorded size, and with the recorded MD5 hash when `check_hashes` is set. It downloads nothing, so it does not prove the backup restores. Exits 1 and prints `Manifest validation: Failed!` when a file is missing or different, or when no backup has that name.
Arguments
Name
Type
Required
backup_name
string
Yes
check_hashes
boolean
No
See the action source for defaults, validation, and limits.