Skip to main content

Cassandra Medusa backups

v0.1.0

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.

on the runner host
sudo emisar pack install medusa --hash sha256:dce134272b810442ee5fe7b0f3c5a43330538cbd87da497aa21df12fb0d32c1e

Setup

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.

medusa.show_configmedusa.list_backupsmedusa.backup_statusmedusa.verify_backupmedusa.last_complete_backupmedusa.fetch_tokenmapmedusa.report_last_backupmedusa.backup_nodemedusa.purgemedusa.delete_backup

Use Cassandra group access for Medusa's files

Grant access
sudo usermod -aG cassandra emisar
sudo chgrp cassandra /etc/medusa/medusa.ini
sudo chmod 0640 /etc/medusa/medusa.ini
sudo systemctl restart emisar
Verify access
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.

medusa.restore_node

Run the Emisar service as root

Grant access
sudo install -d -m 0755 /etc/systemd/system/emisar.service.d
printf '%s\n' '[Service]' 'User=root' 'Group=root' | sudo tee /etc/systemd/system/emisar.service.d/10-medusa-host-access.conf >/dev/null
sudo systemctl daemon-reload
sudo systemctl restart emisar
Verify access
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.

on the runner host
sudo emisar pack verify medusa

Install and configure a pack walks through the whole sequence on a host.

Actions 11 total

View on GitHub
  • 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.

    Link to this action View source on GitHub
  • 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.

    Link to this action View source on GitHub
  • 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.

    Link to this action View source on GitHub
  • 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.

    Link to this action View source on GitHub
  • 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.

    Link to this action View source on GitHub
  • 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.

    Link to this action View source on GitHub
  • 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.

    Link to this action View source on GitHub
  • 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.

    Link to this action View source on GitHub
  • 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.

    Link to this action View source on GitHub
  • 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.

    Link to this action View source on GitHub
  • 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.

    Link to this action View source on GitHub