virsnap is a CLI snapshot utility for libvirt. The small tool is designed for the automated creation of virtual machine snapshots (e.g. KVM domains). In addition to creating snapshots, the tool allows to remove expired snapshots if there are enough newer snapshots for this virtual machine.
virsnap is a small tool that eases the automated creation and deletion of VM snapshots.
Usage:
virsnap [command]
Available Commands:
clean Remove expired snapshots from the system
create Create a snapshot of one or more virtual machines
export Export a VM by copying the hard drive images to an output directory
help Help about any command
list List snapshots of one or more virtual machines
version Print the version of the software
Flags:
-h, --help help for virsnap
-e, --log-encoding string sets the log encoding (console, json) (default "console")
-l, --log-level string sets the log level (debug, info, warn, error) (default "info")
-u, --socket-url string sets the libvirt socket URL to connect to (default "qemu:///system")
Use "virsnap [command] --help" for more information about a command.
joroec@host:~ $ virsnap list "^examplevm[0-9]*$"
examplevm1 (current state: DOMAIN_PAUSED, 1 snapshots total)
+------------------------+-------------------------------+---------+
| SNAPSHOT | TIME | STATE |
+------------------------+-------------------------------+---------+
| virsnap_heuristic_bose | Thu Jul 11 08:37:50 CEST 2019 | shutoff |
+------------------------+-------------------------------+---------+
examplevm2 (current state: DOMAIN_RUNNING, 2 snapshots total)
+--------------------------+-------------------------------+---------+
| SNAPSHOT | TIME | STATE |
+--------------------------+-------------------------------+---------+
| virsnap_hardcore_galileo | Thu Jul 11 08:39:51 CEST 2019 | running |
| virsnap_angry_hypatia | Thu Jul 11 08:40:15 CEST 2019 | shutoff |
+--------------------------+-------------------------------+---------+
joroec@host:~ $ virsnap list
examplevm1 (current state: DOMAIN_SHUTOFF, 1 snapshots total)
+------------------------+-------------------------------+---------+
| SNAPSHOT | TIME | STATE |
+------------------------+-------------------------------+---------+
| virsnap_heuristic_bose | Thu Jul 11 08:37:50 CEST 2019 | shutoff |
+------------------------+-------------------------------+---------+
examplevm2 (current state: DOMAIN_RUNNING, 2 snapshots total)
+--------------------------+-------------------------------+---------+
| SNAPSHOT | TIME | STATE |
+--------------------------+-------------------------------+---------+
| virsnap_hardcore_galileo | Thu Jul 11 08:39:51 CEST 2019 | running |
| virsnap_angry_hypatia | Thu Jul 11 08:40:15 CEST 2019 | shutoff |
+--------------------------+-------------------------------+---------+
othervm1 (current state: DOMAIN_RUNNING, 1 snapshots total)
+-------------------------+-------------------------------+---------+
| SNAPSHOT | TIME | STATE |
+-------------------------+-------------------------------+---------+
| virsnap_gracious_turing | Thu Jul 11 09:05:36 CEST 2019 | shutoff |
+-------------------------+-------------------------------+---------+
joroec@host:~ $ virsnap create --shutdown --force --verbose "^examplevm2$"
DEBU[0000] Trying to shutdown domain "examplevm2" gracefully.
DEBU[0000] Sending shutdown request to VM "examplevm2".
DEBU[0000] Waiting vor the VM "examplevm2" to shutdown.
DEBU[0065] Beginning creation of snapshot for VM "examplevm2".
INFO[0065] Created snapshot "virsnap_condescending_fermat" for VM "examplevm2".
DEBU[0065] Restoring previous state of vm "examplevm2"
DEBU[0066] Leaving creation of snapshot "virsnap_condescending_fermat" for VM "examplevm2".
The parameter k
specifies the versions to keep:
joroec@host:~ $ virsnap list "^examplevm2$"
examplevm2 (current state: DOMAIN_RUNNING, 4 snapshots total)
+------------------------------+-------------------------------+---------+
| SNAPSHOT | TIME | STATE |
+------------------------------+-------------------------------+---------+
| virsnap_hardcore_galileo | Thu Jul 11 08:39:51 CEST 2019 | running |
| virsnap_angry_hypatia | Thu Jul 11 08:40:15 CEST 2019 | shutoff |
| virsnap_cranky_sammet | Thu Jul 11 09:07:55 CEST 2019 | shutoff |
| virsnap_condescending_fermat | Thu Jul 11 09:09:09 CEST 2019 | shutoff |
+------------------------------+-------------------------------+---------+
joroec@host:~ $ virsnap clean -y -k 2 "^examplevm2$"
INFO[0000] Removing snapshot "virsnap_hardcore_galileo" of VM "examplevm2".
INFO[0000] Removing snapshot "virsnap_angry_hypatia" of VM "examplevm2".
joroec@host:~ $ virsnap list "^examplevm2$"
examplevm2 (current state: DOMAIN_RUNNING, 2 snapshots total)
+------------------------------+-------------------------------+---------+
| SNAPSHOT | TIME | STATE |
+------------------------------+-------------------------------+---------+
| virsnap_cranky_sammet | Thu Jul 11 09:07:55 CEST 2019 | shutoff |
| virsnap_condescending_fermat | Thu Jul 11 09:09:09 CEST 2019 | shutoff |
+------------------------------+-------------------------------+---------+
You need to have rsync
installed on your system to use this feature.
joroec@host:~ $ virsnap export --output-dir "/home/joroe/backup" --snapshot true --log-level debug "^testvm$"
2019-07-29T21:11:54.421+0200 DEBUG Logger initialized
2019-07-29T21:11:54.424+0200 DEBUG starting to shutdown VM testvm
2019-07-29T21:11:54.424+0200 DEBUG Domain 'testvm' is already shutoff.
2019-07-29T21:11:54.424+0200 DEBUG finshed shutdown process of VM testvm
2019-07-29T21:11:54.424+0200 DEBUG Beginning creation of snapshot for VM 'testvm'.
2019-07-29T21:11:54.534+0200 INFO Created snapshot 'virsnap_pensive_kalam' for VM 'testvm'
2019-07-29T21:11:54.534+0200 DEBUG starting export process of VM testvm
sending incremental file list
testvm.qcow2
21,479,622,103 100% 245.01MB/s 0:01:23 (xfr#1, to-chk=0/1)
sent 21,484,866,247 bytes received 35 bytes 254,258,772.57 bytes/sec
total size is 21,479,622,103 speedup is 1.00
2019-07-29T21:13:18.151+0200 INFO Exported VM testvm
2019-07-29T21:13:18.151+0200 DEBUG restoring previous state of vm 'testvm'
2019-07-29T21:13:18.154+0200 DEBUG Domain 'testvm' is already shutoff.
virsnap needs go 1.12+ and uses go modules
for dependency management. For more
information on go modules
, see the corresponding go modules documentation.
First make sure libvirt is installed. You can use your local packet manager or compile it by yourself.
On Ubuntu, you can use apt:
$ sudo apt-get install libvirt-bin libvirt-dev
On macOS, you can use Homebrew:
$ brew install libvirt
To install virsnap, execute the following in your shell:
$ git clone http://github.com/joroec/virsnap
$ cd virsnap
$ go build -o ./bin/virsnap ./cmd/virsnap
$ sudo install ./bin/virsnap /usr/local/bin/virsnap
This will compile and link the virsnap binary and install it into
/usr/local/bin/virsnap
. No other file is installed in system directories.
To remove the tool from your system, execute the following in your shell:
$ sudo rm /usr/local/bin/virsnap
To use virsnap for regular snapshotting your virtual machines, determine your
init system and instruct it to periodically call virsnap. There are exemplary
init configurations in the init
directory of this repository.
Adjust the files init/systemd/virsnap.service
and init/systemd/virsnap.timer
to your needs. After this, copy both files to /etc/systemd/system
.
You can check that your service is found:
$ systemctl status virsnap
● virsnap.service - A CLI snapshot systemd service for libvirt
Loaded: loaded (/etc/systemd/system/virsnap.service; static; vendor preset: enabled)
Active: inactive (dead)
Test a single execution of virsnap if desired:
$ systemctl start virsnap
You can watch the logs with:
$ journalctl -u virsnap
Start periodic execution:
$ systemctl enable virsnap.timer
Check if the timer is activated:
$ systemctl status virsnap.timer
See CONTRIBUTING.md
file.
You should always prefer your distribution's packet manager for installing software. If your packet manager does not offer a suitable packet for golang 1.12, you can install it manually. The following are the commands needed for the manual installation on a Ubuntu 18.04 LTS system.
I prefer to compile software by myself. Alternatively, you can use a release link to download a binary release of golang. You can find the direct link to the current go version at the release page. The following will build golang from source:
Visit the official build guide for more information.
Newer versions of the golang compiler are written completely in golang.
In compiler construction, there is typically a bootstrap version of a compiler
written in another language (e.g. C) to compile the actual compiler. For golang,
this is the release branch release-branch.go1.4
which is a bootstrap compiler
for golang written in C. You need to have a GCC or Clang compiler installed
on your system.
Start with downloading the golang source code:
$ sudo apt-get update && sudo apt-get upgrade
$ git clone https://github.com/golang/go
$ cd go
Now, build the bootstrap compiler:
$ git checkout release-branch.go1.4
$ cd src
$ ./all.bash
...
net/rpc/jsonrpc
Build complete; skipping tests.
To force tests, set GO14TESTS=1 and re-run, but expect some failures.
$ cd ../../
$ cp -r go /tmp/go-bootstrap
Now, change back to the desired release brach and compile the golang compiler:
$ cd go
$ git checkout go1.12.6
$ git clean -df
$ cd src
$ GOROOT_BOOTSTRAP=/tmp/go-bootstrap GOROOT_FINAL=/usr/local/lib/go GOBIN=/usr/local/bin ./make.bash
Building Go cmd/dist using /tmp/go-bootstrap.
Building Go toolchain1 using /tmp/go-bootstrap.
Building Go bootstrap cmd/go (go_bootstrap) using Go toolchain1.
Building Go toolchain2 using go_bootstrap and Go toolchain1.
Building Go toolchain3 using go_bootstrap and Go toolchain2.
Building packages and commands for linux/amd64.
---
Installed Go for linux/amd64 in /home/.../go
Installed commands in /home/.../go/bin
The binaries expect /home/.../go to be copied or moved to /usr/local/lib/go
In the last step, you need to install your newly compiled go compiler to your system:
$ cd ../../
$ sudo cp -r go /usr/local/lib/go
$ sudo ln -s /usr/local/lib/go/bin/go /usr/local/bin/go
$ sudo ln -s /usr/local/lib/go/bin/gofmt /usr/local/bin/gofmt
To clean your system from the intermediate products and repositories, you can execute the following commands:
$ rm -rf /tmp/go-bootstrap
$ rm -rf go
Finally, you can set up your golang workspace:
$ mkdir ~/.go-workspace
and add to your ~/.bash_profile
/ .zshrc
:
export GOPATH=$HOME/.go-workspace
See AUTHORS
file.
MIT License. See LICENSE
file.