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.
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.
-
Open your terminal app.
-
Connect to your CubeCOS cluster via SSH (Secure Shell) using this command:
ssh root@<your-cluster-vip> -
When prompted, enter your SSH password.
Restore a volume from a snapshotβ
-
Save the script as
snapshot-restore.sh. Obtain the script from Full restore script. -
Make the script executable.
Make the restore script executablechmod +x snapshot-restore.sh -
Run the script.
Run snapshot-restore.sh./snapshot-restore.sh -
Enter the project number where the virtual machine to be restored is located.
Project selectionSelect a project by number:1. admin2. _diagnostics3. bigstackEnter the number: 3 -
Enter the number of the instance that you want to restore. You can identify instances using either the instance name or the UUID.
Server selectionSelect a server by number:1. vm-snap-restore (52d7f3fa-4d6f-4868-b271-e018c78a061f)Enter the number: 1 -
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 selectionSelect 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 -
Enter the number of the snapshot to restore from.
Snapshot selectionSelect a snapshot by number:1. snapshot for add-data-v3 - Created: 2025-02-06 05:42:572. snapshot for add-data-v1 - Created: 2025-02-06 05:42:113. snapshot for snap-data - Created: 2025-02-06 02:01:19Enter the number: 1 -
Confirm the restore.
The script displays the selected volume and snapshot IDs and prompts for confirmation:
Data lossRestoring a volume from a snapshot overwrites the current volume data. You lose any changes made after the snapshot was created.
Restore confirmation promptWARNING: 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.
- To proceed, type
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.
- Check that the server status is Active.
- Confirm that the expected volume is still attached and volume status is In-use.
- Log in to the server and check the restored data or filesystem state.
Full restore scriptβ
#!/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β
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:
openstack project list
No servers are listedβ
Confirm that the selected project contains servers and that your credentials can read them:
openstack server list --project PROJECT_NAME --long
No attached volumes are foundβ
Confirm that the selected server has attached volumes:
openstack server show SERVER_ID -c attached_volumes
No snapshots are foundβ
Confirm that the selected volume has snapshots in the selected project:
openstack volume snapshot list --project PROJECT_NAME --long
The server doesn't stopβ
Check the server state and hypervisor status:
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:
rbd snap ls cinder-volumes/volume-VOLUME_ID
Then verify that the rollback target exists:
rbd info cinder-volumes/volume-VOLUME_ID@snapshot-SNAPSHOT_ID