Skip to main content
Version: 3.0

Restore a virtual machine (instance) from snapshot

This guide explains how to use the snapshot-restore.sh script to restore an attached OpenStack volume from one of its Cinder snapshots.

The script prompts you to select a project, server, attached volume, and snapshot. It then stops the server, rolls back the selected Ceph RBD snapshot, and starts the server again. For a complete sample restoration workflow, reference Example output from a complete restore session.

Data loss risk

Restoring a volume from a snapshot overwrites the current volume data. You lose any changes made after the snapshot was created.

Before you begin​

Verify that the host where you run the script has the required OpenStack and Ceph access.

Connect to clusters as root via SSH​

Learn how to use SSH to connect to the root shell of your CubeCOS cluster for administrative tasks.

  1. Open your terminal app.

  2. Connect to your CubeCOS cluster via SSH (Secure Shell) using this command:

    ssh root@<your-cluster-vip>
  3. When prompted, enter your SSH password.

Restore a volume from a snapshot​

  1. Save the script as snapshot-restore.sh. Obtain the script from Full restore script.

  2. Make the script executable.

    Make the restore script executable
    chmod +x snapshot-restore.sh
  3. Run the script.

    Run snapshot-restore.sh
    ./snapshot-restore.sh
  4. Enter the project number where the virtual machine to be restored is located.

    Project selection
    Select a project by number:
    1. admin
    2. _diagnostics
    3. bigstack
    Enter the number: 3
  5. Enter the number of the instance that you want to restore. You can identify instances using either the instance name or the UUID.

    Server selection
    Select a server by number:
    1. vm-snap-restore (52d7f3fa-4d6f-4868-b271-e018c78a061f)
    Enter the number: 1
  6. Enter the number of the volume to restore.

    The root disk that hosts the operating system is usually /dev/sda, while additional data disks are on lower indexes. To identify each volume, navigate to Compute > Instances, select the instance to restore, and then click the Volumes tab to view information about the volumes.

    Volume selection
    Select a volume by number:
    1. d11dfee8-3067-4031-8e4d-da3bc867c913 (Device: /dev/sda)
    2. 684483a5-4bd6-448f-810a-81517d82754f (Device: /dev/sdb)
    Enter the number: 1
  7. Enter the number of the snapshot to restore from.

    Snapshot selection
    Select a snapshot by number:
    1. snapshot for add-data-v3 - Created: 2025-02-06 05:42:57
    2. snapshot for add-data-v1 - Created: 2025-02-06 05:42:11
    3. snapshot for snap-data - Created: 2025-02-06 02:01:19
    Enter the number: 1
  8. Confirm the restore.

    The script displays the selected volume and snapshot IDs and prompts for confirmation:

    Data loss

    Restoring a volume from a snapshot overwrites the current volume data. You lose any changes made after the snapshot was created.

    Restore confirmation prompt
    WARNING: This operation will revert the volume
    (d11dfee8-3067-4031-8e4d-da3bc867c913) to the selected snapshot
    (50927e68-9330-46d6-bf8a-1dac0db8e652).
    The associated server will be SHUTDOWN, and all current disk data will be LOST.
    Type 'YES' to confirm:
    • To proceed, type YES.
    • To cancel, type anything else.

Verify that the server and volume are healthy after the restore​

After the script finishes, verify that the server and the restored volume are healthy.

  1. Check that the server status is Active.
  2. Confirm that the expected volume is still attached and volume status is In-use.
  3. Log in to the server and check the restored data or filesystem state.

Full restore script​

snapshot-restore.sh
#!/bin/bash
source /etc/admin-openrc.sh

# Get the list of project names
projects=($(openstack project list -c Name -f value))

# Display the numbered list
echo "Select a project by number:"
for i in "${!projects[@]}"; do
echo "$((i+1)). ${projects[i]}"
done

# Read user input
read -p "Enter the number: " choice

# Validate input
if [[ $choice -ge 1 && $choice -le ${#projects[@]} ]]; then
project_name=(${projects[$((choice-1))]})
echo "You selected: ${projects[$((choice-1))]}"
else
echo "Invalid choice. Exiting."
exit 1
fi
## - End of Project -

# Get the list of servers (Name and ID)
mapfile -t servers < <(openstack server list --project="$project_name" --long -c Name -c ID -f value)

# Check if there are any servers
if [ ${#servers[@]} -eq 0 ]; then
echo "No servers found for project $project_name."
exit 1
fi

# Display the numbered list
echo "Select a server by number:"
for i in "${!servers[@]}"; do
selected_server_id=$(echo "${servers[i]}" | awk '{print $1}') # Extract server ID
server_name=$(echo "${servers[i]}" | awk '{$1=""; print $0}' | sed 's/^ *//') # Extract server name
echo "$((i+1)). $server_name ($selected_server_id)"
done

# Read user input
read -p "Enter the number: " choice

# Validate input
if [[ $choice -ge 1 && $choice -le ${#servers[@]} ]]; then
selected_server="${servers[$((choice-1))]}"
selected_server_id=$(echo "$selected_server" | awk '{print $1}') # Extract server ID
server_name=$(echo "$selected_server" | awk '{$1=""; print $0}' | sed 's/^ *//') # Extract server name
echo "You selected: $server_name ($selected_server_id)"
else
echo "Invalid choice. Exiting."
exit 1
fi
## - End of Server -

volumes_json=$(openstack server show "$selected_server_id" -c attached_volumes -f json)

# Extract volume IDs
mapfile -t volume_ids < <(echo "$volumes_json" | jq -r '.attached_volumes[].id')

# Check if there are any attached volumes
if [ ${#volume_ids[@]} -eq 0 ]; then
echo "No attached volumes found for server $selected_server_id."
exit 1
fi

# Get details of each attached volume
volume_info=()
for volume_id in "${volume_ids[@]}"; do
volume_json=$(openstack volume show "$volume_id" -c attachments -f json)
device=$(echo "$volume_json" | jq -r '.attachments[0].device')

# Store volume info (ID and device)
volume_info+=("$volume_id $device")
done

# Display numbered list
echo "Select a volume by number:"
for i in "${!volume_info[@]}"; do
volume_id=$(echo "${volume_info[i]}" | awk '{print $1}')
device=$(echo "${volume_info[i]}" | awk '{print $2}')
echo "$((i+1)). $volume_id (Device: $device)"
done

# Get user input
read -p "Enter the number: " choice

# Validate input
if [[ $choice -ge 1 && $choice -le ${#volume_info[@]} ]]; then
selected_volume_id=$(echo "${volume_info[$((choice-1))]}" | awk '{print $1}')
echo "You selected volume: $selected_volume_id"
else
echo "Invalid choice. Exiting."
exit 1
fi

## - End of Volume -

# Get all snapshots for the project "bigstack"
snapshots_json=$(openstack volume snapshot list --project="$project_name" --long -f json)

# Extract snapshots related to the selected volume
mapfile -t snapshot_info < <(echo "$snapshots_json" | jq -c --arg vol "$selected_volume_id" \
'.[] | select(.Volume == $vol) | {name: .Name, id: .ID, created_at: .["Created At"]}')

# Check if there are any snapshots
if [ ${#snapshot_info[@]} -eq 0 ]; then
echo "No snapshots found for volume: $selected_volume_id"
exit 1
fi

# Convert "Created At" to human-readable format and display options
echo "Select a snapshot by number:"
for i in "${!snapshot_info[@]}"; do
name=$(echo "${snapshot_info[i]}" | jq -r '.name') # Extract snapshot name
id=$(echo "${snapshot_info[i]}" | jq -r '.id') # Extract snapshot ID
created_at=$(echo "${snapshot_info[i]}" | jq -r '.created_at') # Extract Created At

# Convert to human-readable format
human_date=$(date -d "$created_at" '+%Y-%m-%d %H:%M:%S' 2>/dev/null)

# If date conversion fails, set a fallback
if [[ -z "$human_date" ]]; then
human_date="Invalid Date"
fi

echo "$((i+1)). $name - Created: $human_date"
done

# Get user selection
read -p "Enter the number: " choice

# Validate input
if [[ $choice -ge 1 && $choice -le ${#snapshot_info[@]} ]]; then
selected_snapshot_id=$(echo "${snapshot_info[$((choice-1))]}" | jq -r '.id') # Extract snapshot ID
echo "You selected snapshot: $selected_snapshot_id"
else
echo "Invalid choice. Exiting."
exit 1
fi

## - End of Snapshot -

# Ask for final confirmation
echo ""
echo "WARNING: This operation will revert the volume ($selected_volume_id) to the selected snapshot ($selected_snapshot_id)."
echo "The associated server will be SHUTDOWN, and all current disk data will be LOST."
echo ""
read -p "Type 'YES' to confirm: " confirmation

# Check if the user entered exactly "YES"
if [[ "$confirmation" != "YES" ]]; then
echo "Operation canceled. No changes were made."
exit 1
fi

# Proceed with the revert operation, ensure the server is SHUTOFF before proceeding
echo "Stopping the server ($selected_server_id)..."
openstack server stop "$selected_server_id"

# Wait until the server is fully stopped
echo "Waiting for server ($selected_server_id) to shut down..."
while true; do
vm_state=$(openstack server show "$selected_server_id" -c vm_state -f value)
if [[ "$vm_state" == "stopped" ]]; then
echo "βœ… Server is now stopped."
break
fi
echo "⏳ Server is still stopping... checking again in 5 seconds."
sleep 5
done

echo "Reverting volume $selected_volume_id to snapshot $selected_snapshot_id..."
rbd snap rollback cinder-volumes/volume-"$selected_volume_id"@snapshot-"$selected_snapshot_id"

echo "Revert operation completed successfully."

echo "Starting the server ($selected_server_id)..."
openstack server start "$selected_server_id"

echo "Server started successfully."

Example output from a complete restore session​

Example restore session
Select a project by number:
1. admin
2. _diagnostics
3. bigstack
Enter the number: 3
You selected: bigstack
Select a server by number:
1. vm-snap-restore (52d7f3fa-4d6f-4868-b271-e018c78a061f)
Enter the number: 1
You selected: vm-snap-restore (52d7f3fa-4d6f-4868-b271-e018c78a061f)
Select a volume by number:
1. d11dfee8-3067-4031-8e4d-da3bc867c913 (Device: /dev/sda)
2. 684483a5-4bd6-448f-810a-81517d82754f (Device: /dev/sdb)
Enter the number: 1
You selected volume: d11dfee8-3067-4031-8e4d-da3bc867c913
Select a snapshot by number:
1. snapshot for add-data-v3 - Created: 2025-02-06 05:42:57
2. snapshot for add-data-v1 - Created: 2025-02-06 05:42:11
3. snapshot for snap-data - Created: 2025-02-06 02:01:19
Enter the number: 1
You selected snapshot: 50927e68-9330-46d6-bf8a-1dac0db8e652

WARNING: This operation will revert the volume
(d11dfee8-3067-4031-8e4d-da3bc867c913) to the selected snapshot
(50927e68-9330-46d6-bf8a-1dac0db8e652).
The associated server will be SHUTDOWN, and all current disk data will be LOST.

Type 'YES' to confirm: YES
Stopping the server (52d7f3fa-4d6f-4868-b271-e018c78a061f)...
Waiting for server (52d7f3fa-4d6f-4868-b271-e018c78a061f) to shut down...
Server is still stopping. Checking again in 5 seconds.
Server is now stopped.
Reverting volume d11dfee8-3067-4031-8e4d-da3bc867c913 to snapshot 50927e68-9330-46d6-bf8a-1dac0db8e652...
Rolling back to snapshot: 100% complete...done.
Revert operation completed successfully.
Starting the server (52d7f3fa-4d6f-4868-b271-e018c78a061f)...
Server started successfully.

Troubleshooting common restore failures​

The script can't list projects​

Confirm that /etc/admin-openrc.sh exists and contains valid OpenStack credentials.

To test authentication:

Test OpenStack authentication
openstack project list

No servers are listed​

Confirm that the selected project contains servers and that your credentials can read them:

List servers in a project
openstack server list --project PROJECT_NAME --long

No attached volumes are found​

Confirm that the selected server has attached volumes:

Show attached server volumes
openstack server show SERVER_ID -c attached_volumes

No snapshots are found​

Confirm that the selected volume has snapshots in the selected project:

List volume snapshots
openstack volume snapshot list --project PROJECT_NAME --long

The server doesn't stop​

Check the server state and hypervisor status:

Check server state
openstack server show SERVER_ID -c status -c vm_state -c OS-EXT-SRV-ATTR:host

Don't run the RBD rollback until the server has stopped.

The rollback fails​

Confirm that the Ceph pool, volume ID, and snapshot ID are correct:

List RBD snapshots for a volume
rbd snap ls cinder-volumes/volume-VOLUME_ID

Then verify that the rollback target exists:

Verify the rollback target
rbd info cinder-volumes/volume-VOLUME_ID@snapshot-SNAPSHOT_ID