
Security News
Axios Supply Chain Attack Reaches OpenAI macOS Signing Pipeline, Forces Certificate Rotation
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.
VMSnap is a production-ready Node.js tool designed to simplify the process of creating and managing snapshots of KVM domains. Backups generated by VMSnap are incremental, if possible. VMSnap is also capable of performing intelligent backup rotation with configurable retention policies.
This README provides an overview of the project, installation instructions, usage guidelines, and contribution information.
You must have the following on your host OS:
Getting these installed is out of scope for this doc.
The app will let you know if you are missing any required programs when you start running commands with it.
To install VMSnap, follow these steps:
npm install -g vmsnap
You may also choose to install VMSnap by checking the code out and running it locally. To run localy, do the following:
git clone git@github.com:slackdaystudio/vmsnap.git
cd vmsnap
npm install
This usage guide assumes you have installed VMSnap via the npm install -g vmsnap
command. Doing so will install VMSnap which includes a vmsnap bin.
Tip: You may execute the same commands from a local checkout by swapping out the name of the bin for
npm run vmsnap --. For example, to run a status check from a local version you first go to your code checkout and then runnpm run vmsnap -- --domains=vm1,vm2 --status
The following CLI switches are available when invoking VMSnap.
| Switch | Status | Backup | Scrub | Type | Examples/Notes |
|---|---|---|---|---|---|
| domains | ✅ | ✅ | ✅ | string | "vm1" or "vm1,vm2,etc" or "*" |
| status | ✅ | - | - | boolean | Querys the domain(s) |
| backup | - | ✅ | - | boolean | Does an incremental backup (if possible) |
| scrub | - | - | ✅ | boolean | Cleans checkpoints and bitmaps off of the domain |
| output | ✅ | ✅ | - | string | A full path to a directory where backups are placed |
| verbose | ✅ | - | - | boolean | Prints out extra information when running a status check |
| machine | ✅ | - | - | boolean | Removes some output from the status command |
| json | ✅ | - | - | boolean | Outputs the status command is JSON |
| yaml | ✅ | - | - | boolean | Output YAML from the status command (aliased to --yml) |
| raw | - | ✅ | - | boolean | Enables raw disk handling |
| groupBy | ✅ | ✅ | - | string | Defines how backups are grouped on disk (month, quarter, bi-annual or year) |
| prune | - | ✅ | - | boolean | Rotates backups by deleting last periods backup* |
| pretty | ✅ | - | - | boolean | Pretty prints disk sizes (42.6 GB, 120 GB, etc) |
| checkpointName | - | - | ✅ | string | The name of the checkpoint to delete (no effect when scrubType=*) |
| scrubType | - | - | ✅ | string | The type of item to scrub (checkpoint, bitmap, both, or * for ALL) |
*This happens on or after the the middle of the current period (15 days monthly, 45 days quarterly, 90 days bi-annually or 180 yearly)
The default action for VMSnap is to display a status report for VMs supplied.
vmsnap --domains=vm1 --status
Tip: The
--domainsflag also accepts a comma seperated list of domains. You may also pass in "*" to select all found VMs. This is applicable to backing up, scrubbing, or querying VMs.Tip: The
--statusflag may be omited. Leaving it in is useful when constructing backup and scrub commands because you may test the command by querying the status of the domain. If that query works you then swap the--statusflag for the--backupor--scrubflag, as appropriate.
This could return the following information if ran, as an example.
Status for vm1:
Overall status: OK
Checkpoints found for vm1:
virtnbdbackup.0
virtnbdbackup.1
virtnbdbackup.2
Eligible disks found for vm1:
vda
Virtual size: 107374182400
Actual size: 14286573568
Bitmaps found for vda:
virtnbdbackup.0
virtnbdbackup.1
virtnbdbackup.2
Tip: Pass in an
output=/PATH/TO/BACKUP_ROOTflag to see statistics about the backups already saved to disk. VMSnap will perform additional integrity checks using the information it collects.
Machine parsable output is possible with the --json and --yaml flags in
combination with the --machine flag.
For example, running the following command...
vmsnap --domains=vm1 --machine --json
..will produce something like the following.
{"vm1":{"checkpoints":["virtnbdbackup.0","virtnbdbackup.1","virtnbdbackup.2"],"disks":[{"disk":"vda","virtualSize":107374182400,"actualSize":14293934080,"bitmaps":["virtnbdbackup.0","virtnbdbackup.1","virtnbdbackup.2"]}],"overallStatus":0}}
Backups are always incremental unless VMSnap is cutting a new periods first backup. Subsequent backups will be incremental meaning only the changes from the VM will be captured.
Create a snapshot for vm1 and output it to the tmp direcory:
vmsnap --domains=vm1 --output=/tmp --backup
The above command will create a the backup for the domain. This creates a
checkpoint and dirty bitmap on the VM file and deposits the backup to the /tmp
directory.
Tip: Make sure you can read and write to the target directory in
--output
You may also specify the --groupBy flag to tell VMSnap how to group your files
on disk. Look at the table below for more information.
| groupBy Flag | Middle Mark | Sample Folder Name |
|---|---|---|
| month | 15d | vmsnap-backup-monthly-2024-11 |
| quarter | 45d | vmsnap-backup-quarterly-2024-Q4 |
| bi-annual | 90d | vmsnap-backup-bi-annually-2024-p2 |
| year | 180d | vmsnap-backup-yearly-2024 |
Tip: If you do not set the
groupByflag the default period is assumed to be "month."
Note: Pruning is destructive. Be careful when using it and check your backups frequently!
Pruning backups may be done by setting --prune on the backup command.
This flag will automatically delete last periods backup once the middle of the
current backup period comes up.
Pruning provides a sliding window for the given period of +/-50% depending upon
where you are in the backup cycle. For example, setting the groupBy flag to
"month" would mean you would have 2-6 weeks of backups on hand at any given
time.
You can turn on raw disk handling by setting the --raw flag.
Note: These commands are inherently destructive, be careful!
It is occasionally useful to be able to scrub one or more checkpoints or bitmaps from your domain. Doing so is fairly straight forward with VMSnap but please do be cautious.
Use this command to scrub a single bitmap from your backup disks. Keep in mind that bitmaps are stored on a per disk basis. VMSnap will scrub each disk of the bitmap if it find it.
vmsnap --domains=vm1 --scrub --scrubType=bitmap --checkpointName=virtnbdbackup.17
To scrub a domain of ALL checkpoints and bitmaps
vmsnap --domains=vm1 --scrub --scrubType=*
VMSnap maintains enterprise-grade quality standards with comprehensive testing:
# Run all tests
npm test
# Run tests with coverage report
npm run test:coverage
# Run tests in watch mode during development
npm run test:watch
# Run only unit tests
npm run test:unit
VMSnap includes a comprehensive integration test suite that tests real backup operations against actual KVM virtual machines. These tests require a KVM-enabled environment.
libvirtd)libvirt and kvm groups)# Verify KVM is available
ls -la /dev/kvm
# Verify libvirt connection
virsh version
# Run integration tests
npm run test:integration
# Optional: Setup test VMs manually
npm run test:integration:setup
# Optional: Cleanup test environment
npm run test:integration:cleanup
| Test Suite | Tests | Description |
|---|---|---|
backup-operations.test.js | 6 | Single/multiple VM backups, wildcards, selective domains |
incremental-backup.test.js | 7 | Full and incremental backup chains, disk change handling |
rotation-pruning.test.js | 7 | Monthly/quarterly/bi-annual/yearly grouping and pruning |
scrubbing-operations.test.js | 6 | Checkpoint and bitmap cleanup (handles offline VMs) |
status-commands.test.js | 11 | Status output in text/JSON/YAML formats, multiple VMs |
error-scenarios.test.js | 13 | Error handling, invalid inputs, concurrent execution |
Integration tests can run in CI using a self-hosted runner with KVM support:
Set up a self-hosted runner with nested virtualization enabled:
# On the runner host, verify KVM support
egrep -c '(vmx|svm)' /proc/cpuinfo # Should return > 0
# Install required packages (Ubuntu/Debian)
sudo apt-get install -y qemu-kvm libvirt-daemon-system libvirt-clients virtinst qemu-utils
# Install virtnbdbackup
pip3 install virtnbdbackup
# Add runner user to required groups
sudo usermod -aG kvm,libvirt $USER
# Start libvirt
sudo systemctl enable --now libvirtd
Configure the runner following GitHub's self-hosted runner documentation
Update the workflow to use your self-hosted runner:
# In .github/workflows/integration-tests.yml
jobs:
integration-tests:
runs-on: self-hosted # Change from ubuntu-latest
Standard GitHub-hosted runners (ubuntu-latest) don't expose /dev/kvm because nested virtualization is disabled. The integration test workflow automatically detects this and:
This ensures CI doesn't fail while allowing full integration testing on capable environments.
# Lint code
npm run lint
# Format code
npm run format
# Check formatting
npm run check-format
# Build project
npm run build
VMSnap prioritizes security and maintains:
Run security audit:
npm audit
Clone and setup:
git clone git@github.com:slackdaystudio/vmsnap.git
cd vmsnap
npm install
Run in development mode:
# Watch mode for automatic rebuilds
npm run watch
# Run locally without building
npm run vmsnap -- --domains=vm1 --status
Before committing:
npm run lint # Check code style
npm run test # Run all tests
npm run build # Verify build works
vmsnap/
├── libs/ # Core modules
│ ├── general.js # Utility functions, dependency checking, error handling
│ ├── libnbdbackup.js # Main backup orchestration with virtnbdbackup
│ ├── print.js # Output formatting (text, JSON, YAML)
│ ├── qemu-img.js # QEMU image operations & bitmap management
│ ├── serialization.js # Status collection & integrity analysis
│ └── virsh.js # KVM domain & checkpoint management
├── test/
│ ├── unit/ # 188 unit tests across all modules
│ │ └── libs/ # Module-specific unit tests
│ └── integration/ # 50 integration tests with real KVM VMs
│ ├── helpers/ # VM lifecycle management & test assertions
│ │ ├── vm-manager.js # Create/destroy test VMs
│ │ ├── test-assertions.js # Backup verification helpers
│ │ └── cleanup-helpers.js # Environment cleanup
│ ├── setup/ # Shell scripts for test environment
│ └── tests/ # 6 integration test suites
├── dist/ # Built output (generated)
└── vmsnap.js # Main CLI entry point with argument parsing
VMSnap follows a modular architecture with clear separation of concerns:
VMSnap is designed for production environments with emphasis on reliability:
We welcome contributions! VMSnap maintains high standards for code quality, testing, and security.
Fork and setup:
git clone git@github.com:YOUR_USERNAME/vmsnap.git
cd vmsnap
npm install
Create a feature branch:
git checkout -b feature/your-feature-name
Follow development standards:
npm run lint # Code style
npm run test # All tests pass
npm run build # Successful build
npm audit # No security issues
Commit your changes:
git commit -m "feat: add new backup validation feature"
Follow Conventional Commits format.
Push and create PR:
git push origin feature/your-feature-name
Then create a pull request with:
All contributions must maintain our testing standards:
Run the full test suite before submitting:
npm run test:coverage
This project is licensed under the MIT License. See the LICENSE file for details.
🎉 Major Quality & Security Release
New Features:
Integration Test Suite:
Security & Dependencies:
Developer Experience:
Bug Fixes:
Infrastructure:
For any questions or feedback, please open an issue on GitHub.
VMSnap v1.1.0-beta - Production-ready KVM backup solution with 238 tests (188 unit + 50 integration) and enterprise-grade reliability.
FAQs
A Node based backup and backup rotation tool for KVM domains.
We found that vmsnap demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.

Security News
Open source is under attack because of how much value it creates. It has been the foundation of every major software innovation for the last three decades. This is not the time to walk away from it.

Security News
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.