commit
51f5b9e036
|
@ -20,6 +20,7 @@ module Vagrant
|
||||||
autoload :HandleBox, "vagrant/action/builtin/handle_box"
|
autoload :HandleBox, "vagrant/action/builtin/handle_box"
|
||||||
autoload :HandleBoxUrl, "vagrant/action/builtin/handle_box_url"
|
autoload :HandleBoxUrl, "vagrant/action/builtin/handle_box_url"
|
||||||
autoload :HandleForwardedPortCollisions, "vagrant/action/builtin/handle_forwarded_port_collisions"
|
autoload :HandleForwardedPortCollisions, "vagrant/action/builtin/handle_forwarded_port_collisions"
|
||||||
|
autoload :IsEnvSet, "vagrant/action/builtin/is_env_set"
|
||||||
autoload :IsState, "vagrant/action/builtin/is_state"
|
autoload :IsState, "vagrant/action/builtin/is_state"
|
||||||
autoload :Lock, "vagrant/action/builtin/lock"
|
autoload :Lock, "vagrant/action/builtin/lock"
|
||||||
autoload :Message, "vagrant/action/builtin/message"
|
autoload :Message, "vagrant/action/builtin/message"
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
module Vagrant
|
||||||
|
module Action
|
||||||
|
module Builtin
|
||||||
|
# This middleware is meant to be used with Call and can check if
|
||||||
|
# a variable in env is set.
|
||||||
|
class IsEnvSet
|
||||||
|
def initialize(app, env, key, **opts)
|
||||||
|
@app = app
|
||||||
|
@logger = Log4r::Logger.new("vagrant::action::builtin::is_env_set")
|
||||||
|
@key = key
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
@logger.debug("Checking if env is set: '#{@key}'")
|
||||||
|
env[:result] = !!env[@key]
|
||||||
|
@logger.debug(" - Result: #{env[:result].inspect}")
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,35 @@
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CommandSnapshot
|
||||||
|
module Command
|
||||||
|
class Delete < Vagrant.plugin("2", :command)
|
||||||
|
def execute
|
||||||
|
options = {}
|
||||||
|
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant snapshot delete [options] [vm-name] <name>"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Delete a snapshot taken previously with snapshot save."
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
if argv.empty? || argv.length > 2
|
||||||
|
raise Vagrant::Errors::CLIInvalidUsage,
|
||||||
|
help: opts.help.chomp
|
||||||
|
end
|
||||||
|
|
||||||
|
name = argv.pop
|
||||||
|
with_target_vms(argv) do |vm|
|
||||||
|
vm.action(:snapshot_delete, snapshot_name: name)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Success, exit status 0
|
||||||
|
0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,47 @@
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CommandSnapshot
|
||||||
|
module Command
|
||||||
|
class List < Vagrant.plugin("2", :command)
|
||||||
|
def execute
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant snapshot list [options] [vm-name]"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "List all snapshots taken for a machine."
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
|
||||||
|
with_target_vms(argv) do |vm|
|
||||||
|
if !vm.id
|
||||||
|
vm.ui.info(I18n.t("vagrant.commands.common.vm_not_created"))
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
if !vm.provider.capability?(:snapshot_list)
|
||||||
|
vm.ui.info(I18n.t("vagrant.commands.snapshot.not_supported"))
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
snapshots = vm.provider.capability(:snapshot_list)
|
||||||
|
if snapshots.empty?
|
||||||
|
vm.ui.output(I18n.t("vagrant.actions.vm.snapshot.list_none"))
|
||||||
|
vm.ui.detail(I18n.t("vagrant.actions.vm.snapshot.list_none_detail"))
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
snapshots.each do |snapshot|
|
||||||
|
vm.ui.output(snapshot, prefix: false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Success, exit status 0
|
||||||
|
0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,28 @@
|
||||||
|
require 'json'
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
require_relative "push_shared"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CommandSnapshot
|
||||||
|
module Command
|
||||||
|
class Pop < Vagrant.plugin("2", :command)
|
||||||
|
include PushShared
|
||||||
|
|
||||||
|
def execute
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant snapshot pop [options] [vm-name]"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Restore state that was pushed with `vagrant snapshot push`."
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
|
||||||
|
return shared_exec(argv, method(:pop))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,33 @@
|
||||||
|
require 'json'
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
require_relative "push_shared"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CommandSnapshot
|
||||||
|
module Command
|
||||||
|
class Push < Vagrant.plugin("2", :command)
|
||||||
|
include PushShared
|
||||||
|
|
||||||
|
def execute
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant snapshot push [options] [vm-name]"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Take a snapshot of the current state of the machine and 'push'"
|
||||||
|
o.separator "it onto the stack of states. You can use `vagrant snapshot pop`"
|
||||||
|
o.separator "to restore back to this state at any time."
|
||||||
|
o.separator ""
|
||||||
|
o.separator "If you use `vagrant snapshot save` or restore at any point after"
|
||||||
|
o.separator "a push, pop will still bring you back to this pushed state."
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
|
||||||
|
return shared_exec(argv, method(:push))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,57 @@
|
||||||
|
require 'json'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CommandSnapshot
|
||||||
|
module Command
|
||||||
|
module PushShared
|
||||||
|
def shared_exec(argv, m)
|
||||||
|
with_target_vms(argv) do |vm|
|
||||||
|
if !vm.id
|
||||||
|
vm.ui.info("Not created. Cannot push snapshot state.")
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
vm.env.lock("machine-snapshot-stack") do
|
||||||
|
m.call(vm)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Success, exit with 0
|
||||||
|
0
|
||||||
|
end
|
||||||
|
|
||||||
|
def push(machine)
|
||||||
|
snapshot_name = "push_#{Time.now.to_i}_#{rand(10000)}"
|
||||||
|
|
||||||
|
# Save the snapshot. This will raise an exception if it fails.
|
||||||
|
machine.action(:snapshot_save, snapshot_name: snapshot_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def pop(machine)
|
||||||
|
# By reverse sorting, we should be able to find the first
|
||||||
|
# pushed snapshot.
|
||||||
|
name = nil
|
||||||
|
snapshots = machine.provider.capability(:snapshot_list)
|
||||||
|
snapshots.sort.reverse.each do |snapshot|
|
||||||
|
if snapshot =~ /^push_\d+_\d+$/
|
||||||
|
name = snapshot
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# If no snapshot was found, we never pushed
|
||||||
|
if !name
|
||||||
|
machine.ui.info(I18n.t("vagrant.commands.snapshot.no_push_snapshot"))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# Restore the snapshot and tell the provider to delete it as well.
|
||||||
|
machine.action(
|
||||||
|
:snapshot_restore,
|
||||||
|
snapshot_name: name,
|
||||||
|
snapshot_delete: true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,35 @@
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CommandSnapshot
|
||||||
|
module Command
|
||||||
|
class Restore < Vagrant.plugin("2", :command)
|
||||||
|
def execute
|
||||||
|
options = {}
|
||||||
|
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant snapshot restore [options] [vm-name] <name>"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Restore a snapshot taken previously with snapshot save."
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
if argv.empty? || argv.length > 2
|
||||||
|
raise Vagrant::Errors::CLIInvalidUsage,
|
||||||
|
help: opts.help.chomp
|
||||||
|
end
|
||||||
|
|
||||||
|
name = argv.pop
|
||||||
|
with_target_vms(argv) do |vm|
|
||||||
|
vm.action(:snapshot_restore, snapshot_name: name)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Success, exit status 0
|
||||||
|
0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,89 @@
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CommandSnapshot
|
||||||
|
module Command
|
||||||
|
class Root < Vagrant.plugin("2", :command)
|
||||||
|
def self.synopsis
|
||||||
|
"manages snapshots: saving, restoring, etc."
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(argv, env)
|
||||||
|
super
|
||||||
|
|
||||||
|
@main_args, @sub_command, @sub_args = split_main_and_subcommand(argv)
|
||||||
|
|
||||||
|
@subcommands = Vagrant::Registry.new
|
||||||
|
@subcommands.register(:save) do
|
||||||
|
require_relative "save"
|
||||||
|
Save
|
||||||
|
end
|
||||||
|
|
||||||
|
@subcommands.register(:restore) do
|
||||||
|
require_relative "restore"
|
||||||
|
Restore
|
||||||
|
end
|
||||||
|
|
||||||
|
@subcommands.register(:delete) do
|
||||||
|
require_relative "delete"
|
||||||
|
Delete
|
||||||
|
end
|
||||||
|
|
||||||
|
@subcommands.register(:list) do
|
||||||
|
require_relative "list"
|
||||||
|
List
|
||||||
|
end
|
||||||
|
|
||||||
|
@subcommands.register(:push) do
|
||||||
|
require_relative "push"
|
||||||
|
Push
|
||||||
|
end
|
||||||
|
|
||||||
|
@subcommands.register(:pop) do
|
||||||
|
require_relative "pop"
|
||||||
|
Pop
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute
|
||||||
|
if @main_args.include?("-h") || @main_args.include?("--help")
|
||||||
|
# Print the help for all the commands.
|
||||||
|
return help
|
||||||
|
end
|
||||||
|
|
||||||
|
# If we reached this far then we must have a subcommand. If not,
|
||||||
|
# then we also just print the help and exit.
|
||||||
|
command_class = @subcommands.get(@sub_command.to_sym) if @sub_command
|
||||||
|
return help if !command_class || !@sub_command
|
||||||
|
@logger.debug("Invoking command class: #{command_class} #{@sub_args.inspect}")
|
||||||
|
|
||||||
|
# Initialize and execute the command class
|
||||||
|
command_class.new(@sub_args, @env).execute
|
||||||
|
end
|
||||||
|
|
||||||
|
# Prints the help out for this command
|
||||||
|
def help
|
||||||
|
opts = OptionParser.new do |opts|
|
||||||
|
opts.banner = "Usage: vagrant snapshot <subcommand> [<args>]"
|
||||||
|
opts.separator ""
|
||||||
|
opts.separator "Available subcommands:"
|
||||||
|
|
||||||
|
# Add the available subcommands as separators in order to print them
|
||||||
|
# out as well.
|
||||||
|
keys = []
|
||||||
|
@subcommands.each { |key, value| keys << key.to_s }
|
||||||
|
|
||||||
|
keys.sort.each do |key|
|
||||||
|
opts.separator " #{key}"
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.separator ""
|
||||||
|
opts.separator "For help on any individual subcommand run `vagrant snapshot <subcommand> -h`"
|
||||||
|
end
|
||||||
|
|
||||||
|
@env.ui.info(opts.help, prefix: false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,40 @@
|
||||||
|
require 'optparse'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CommandSnapshot
|
||||||
|
module Command
|
||||||
|
class Save < Vagrant.plugin("2", :command)
|
||||||
|
def execute
|
||||||
|
options = {}
|
||||||
|
|
||||||
|
opts = OptionParser.new do |o|
|
||||||
|
o.banner = "Usage: vagrant snapshot save [options] [vm-name] <name>"
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Take a snapshot of the current state of the machine. The snapshot"
|
||||||
|
o.separator "can be restored via `vagrant snapshot restore` at any point in the"
|
||||||
|
o.separator "future to get back to this exact machine state."
|
||||||
|
o.separator ""
|
||||||
|
o.separator "Snapshots are useful for experimenting in a machine and being able"
|
||||||
|
o.separator "to rollback quickly."
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the options
|
||||||
|
argv = parse_options(opts)
|
||||||
|
return if !argv
|
||||||
|
if argv.empty? || argv.length > 2
|
||||||
|
raise Vagrant::Errors::CLIInvalidUsage,
|
||||||
|
help: opts.help.chomp
|
||||||
|
end
|
||||||
|
|
||||||
|
name = argv.pop
|
||||||
|
with_target_vms(argv) do |vm|
|
||||||
|
vm.action(:snapshot_save, snapshot_name: name)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Success, exit status 0
|
||||||
|
0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,15 @@
|
||||||
|
require "vagrant"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module CommandSnapshot
|
||||||
|
class Plugin < Vagrant.plugin("2")
|
||||||
|
name "snapshot command"
|
||||||
|
description "The `snapshot` command gives you a way to manage snapshots."
|
||||||
|
|
||||||
|
command("snapshot") do
|
||||||
|
require_relative "command/root"
|
||||||
|
Command::Root
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -42,6 +42,9 @@ module VagrantPlugins
|
||||||
autoload :SaneDefaults, File.expand_path("../action/sane_defaults", __FILE__)
|
autoload :SaneDefaults, File.expand_path("../action/sane_defaults", __FILE__)
|
||||||
autoload :SetName, File.expand_path("../action/set_name", __FILE__)
|
autoload :SetName, File.expand_path("../action/set_name", __FILE__)
|
||||||
autoload :SetupPackageFiles, File.expand_path("../action/setup_package_files", __FILE__)
|
autoload :SetupPackageFiles, File.expand_path("../action/setup_package_files", __FILE__)
|
||||||
|
autoload :SnapshotDelete, File.expand_path("../action/snapshot_delete", __FILE__)
|
||||||
|
autoload :SnapshotRestore, File.expand_path("../action/snapshot_restore", __FILE__)
|
||||||
|
autoload :SnapshotSave, File.expand_path("../action/snapshot_save", __FILE__)
|
||||||
autoload :Suspend, File.expand_path("../action/suspend", __FILE__)
|
autoload :Suspend, File.expand_path("../action/suspend", __FILE__)
|
||||||
|
|
||||||
# Include the built-in modules so that we can use them as top-level
|
# Include the built-in modules so that we can use them as top-level
|
||||||
|
@ -222,6 +225,59 @@ module VagrantPlugins
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.action_snapshot_delete
|
||||||
|
Vagrant::Action::Builder.new.tap do |b|
|
||||||
|
b.use CheckVirtualbox
|
||||||
|
b.use Call, Created do |env, b2|
|
||||||
|
if env[:result]
|
||||||
|
b2.use SnapshotDelete
|
||||||
|
else
|
||||||
|
b2.use MessageNotCreated
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# This is the action that is primarily responsible for saving a snapshot
|
||||||
|
def self.action_snapshot_restore
|
||||||
|
Vagrant::Action::Builder.new.tap do |b|
|
||||||
|
b.use CheckVirtualbox
|
||||||
|
b.use Call, Created do |env, b2|
|
||||||
|
if !env[:result]
|
||||||
|
b2.use MessageNotCreated
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
b2.use CheckAccessible
|
||||||
|
b2.use EnvSet, force_halt: true
|
||||||
|
b2.use action_halt
|
||||||
|
b2.use SnapshotRestore
|
||||||
|
|
||||||
|
b2.use Call, IsEnvSet, :snapshot_delete do |env2, b3|
|
||||||
|
if env2[:result]
|
||||||
|
b3.use action_snapshot_delete
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
b2.use action_start
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# This is the action that is primarily responsible for saving a snapshot
|
||||||
|
def self.action_snapshot_save
|
||||||
|
Vagrant::Action::Builder.new.tap do |b|
|
||||||
|
b.use CheckVirtualbox
|
||||||
|
b.use Call, Created do |env, b2|
|
||||||
|
if env[:result]
|
||||||
|
b2.use SnapshotSave
|
||||||
|
else
|
||||||
|
b2.use MessageNotCreated
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# This is the action that will exec into an SSH shell.
|
# This is the action that will exec into an SSH shell.
|
||||||
def self.action_ssh
|
def self.action_ssh
|
||||||
Vagrant::Action::Builder.new.tap do |b|
|
Vagrant::Action::Builder.new.tap do |b|
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
module VagrantPlugins
|
||||||
|
module ProviderVirtualBox
|
||||||
|
module Action
|
||||||
|
class SnapshotDelete
|
||||||
|
def initialize(app, env)
|
||||||
|
@app = app
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
env[:ui].info(I18n.t(
|
||||||
|
"vagrant.actions.vm.snapshot.deleting",
|
||||||
|
name: env[:snapshot_name]))
|
||||||
|
env[:machine].provider.driver.delete_snapshot(
|
||||||
|
env[:machine].id, env[:snapshot_name]) do |progress|
|
||||||
|
env[:ui].clear_line
|
||||||
|
env[:ui].report_progress(progress, 100, false)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Clear the line one last time since the progress meter doesn't disappear
|
||||||
|
# immediately.
|
||||||
|
env[:ui].clear_line
|
||||||
|
|
||||||
|
env[:ui].success(I18n.t(
|
||||||
|
"vagrant.actions.vm.snapshot.deleted",
|
||||||
|
name: env[:snapshot_name]))
|
||||||
|
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,28 @@
|
||||||
|
module VagrantPlugins
|
||||||
|
module ProviderVirtualBox
|
||||||
|
module Action
|
||||||
|
class SnapshotRestore
|
||||||
|
def initialize(app, env)
|
||||||
|
@app = app
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
env[:ui].info(I18n.t(
|
||||||
|
"vagrant.actions.vm.snapshot.restoring",
|
||||||
|
name: env[:snapshot_name]))
|
||||||
|
env[:machine].provider.driver.restore_snapshot(
|
||||||
|
env[:machine].id, env[:snapshot_name]) do |progress|
|
||||||
|
env[:ui].clear_line
|
||||||
|
env[:ui].report_progress(progress, 100, false)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Clear the line one last time since the progress meter doesn't disappear
|
||||||
|
# immediately.
|
||||||
|
env[:ui].clear_line
|
||||||
|
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,25 @@
|
||||||
|
module VagrantPlugins
|
||||||
|
module ProviderVirtualBox
|
||||||
|
module Action
|
||||||
|
class SnapshotSave
|
||||||
|
def initialize(app, env)
|
||||||
|
@app = app
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
env[:ui].info(I18n.t(
|
||||||
|
"vagrant.actions.vm.snapshot.saving",
|
||||||
|
name: env[:snapshot_name]))
|
||||||
|
env[:machine].provider.driver.create_snapshot(
|
||||||
|
env[:machine].id, env[:snapshot_name])
|
||||||
|
|
||||||
|
env[:ui].success(I18n.t(
|
||||||
|
"vagrant.actions.vm.snapshot.saved",
|
||||||
|
name: env[:snapshot_name]))
|
||||||
|
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -22,6 +22,13 @@ module VagrantPlugins
|
||||||
def self.nic_mac_addresses(machine)
|
def self.nic_mac_addresses(machine)
|
||||||
machine.provider.driver.read_mac_addresses
|
machine.provider.driver.read_mac_addresses
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Returns a list of the snapshots that are taken on this machine.
|
||||||
|
#
|
||||||
|
# @return [Array<String>] Snapshot Name
|
||||||
|
def self.snapshot_list(machine)
|
||||||
|
machine.provider.driver.list_snapshots(machine.id)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -386,7 +386,8 @@ module VagrantPlugins
|
||||||
if errored
|
if errored
|
||||||
raise Vagrant::Errors::VBoxManageError,
|
raise Vagrant::Errors::VBoxManageError,
|
||||||
command: command.inspect,
|
command: command.inspect,
|
||||||
stderr: r.stderr
|
stderr: r.stderr,
|
||||||
|
stdout: r.stdout
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -89,6 +89,7 @@ module VagrantPlugins
|
||||||
:create_host_only_network,
|
:create_host_only_network,
|
||||||
:create_snapshot,
|
:create_snapshot,
|
||||||
:delete,
|
:delete,
|
||||||
|
:delete_snapshot,
|
||||||
:delete_unused_host_only_networks,
|
:delete_unused_host_only_networks,
|
||||||
:discard_saved_state,
|
:discard_saved_state,
|
||||||
:enable_adapters,
|
:enable_adapters,
|
||||||
|
@ -97,6 +98,7 @@ module VagrantPlugins
|
||||||
:forward_ports,
|
:forward_ports,
|
||||||
:halt,
|
:halt,
|
||||||
:import,
|
:import,
|
||||||
|
:list_snapshots,
|
||||||
:read_forwarded_ports,
|
:read_forwarded_ports,
|
||||||
:read_bridged_interfaces,
|
:read_bridged_interfaces,
|
||||||
:read_dhcp_servers,
|
:read_dhcp_servers,
|
||||||
|
@ -113,6 +115,7 @@ module VagrantPlugins
|
||||||
:read_vms,
|
:read_vms,
|
||||||
:reconfig_host_only,
|
:reconfig_host_only,
|
||||||
:remove_dhcp_server,
|
:remove_dhcp_server,
|
||||||
|
:restore_snapshot,
|
||||||
:resume,
|
:resume,
|
||||||
:set_mac_address,
|
:set_mac_address,
|
||||||
:set_name,
|
:set_name,
|
||||||
|
|
|
@ -608,6 +608,85 @@ module VagrantPlugins
|
||||||
execute("showvminfo", uuid)
|
execute("showvminfo", uuid)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def create_snapshot(machine_id, snapshot_name)
|
||||||
|
execute("snapshot", machine_id, "take", snapshot_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete_snapshot(machine_id, snapshot_name)
|
||||||
|
# Start with 0%
|
||||||
|
last = 0
|
||||||
|
total = ""
|
||||||
|
yield 0 if block_given?
|
||||||
|
|
||||||
|
# Snapshot and report the % progress
|
||||||
|
execute("snapshot", machine_id, "delete", snapshot_name) do |type, data|
|
||||||
|
if type == :stderr
|
||||||
|
# Append the data so we can see the full view
|
||||||
|
total << data.gsub("\r", "")
|
||||||
|
|
||||||
|
# Break up the lines. We can't get the progress until we see an "OK"
|
||||||
|
lines = total.split("\n")
|
||||||
|
|
||||||
|
# The progress of the import will be in the last line. Do a greedy
|
||||||
|
# regular expression to find what we're looking for.
|
||||||
|
match = /.+(\d{2})%/.match(lines.last)
|
||||||
|
if match
|
||||||
|
current = match[1].to_i
|
||||||
|
if current > last
|
||||||
|
last = current
|
||||||
|
yield current if block_given?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def list_snapshots(machine_id)
|
||||||
|
output = execute(
|
||||||
|
"snapshot", machine_id, "list", "--machinereadable",
|
||||||
|
retryable: true)
|
||||||
|
|
||||||
|
result = []
|
||||||
|
output.split("\n").each do |line|
|
||||||
|
if line =~ /^SnapshotName.*?="(.+?)"$/i
|
||||||
|
result << $1.to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result.sort
|
||||||
|
rescue Vagrant::Errors::VBoxManageError => e
|
||||||
|
return [] if e.extra_data[:stdout].include?("does not have")
|
||||||
|
raise
|
||||||
|
end
|
||||||
|
|
||||||
|
def restore_snapshot(machine_id, snapshot_name)
|
||||||
|
# Start with 0%
|
||||||
|
last = 0
|
||||||
|
total = ""
|
||||||
|
yield 0 if block_given?
|
||||||
|
|
||||||
|
execute("snapshot", machine_id, "restore", snapshot_name) do |type, data|
|
||||||
|
if type == :stderr
|
||||||
|
# Append the data so we can see the full view
|
||||||
|
total << data.gsub("\r", "")
|
||||||
|
|
||||||
|
# Break up the lines. We can't get the progress until we see an "OK"
|
||||||
|
lines = total.split("\n")
|
||||||
|
|
||||||
|
# The progress of the import will be in the last line. Do a greedy
|
||||||
|
# regular expression to find what we're looking for.
|
||||||
|
match = /.+(\d{2})%/.match(lines.last)
|
||||||
|
if match
|
||||||
|
current = match[1].to_i
|
||||||
|
if current > last
|
||||||
|
last = current
|
||||||
|
yield current if block_given?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -90,6 +90,81 @@ module VagrantPlugins
|
||||||
execute("snapshot", machine_id, "take", snapshot_name)
|
execute("snapshot", machine_id, "take", snapshot_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def delete_snapshot(machine_id, snapshot_name)
|
||||||
|
# Start with 0%
|
||||||
|
last = 0
|
||||||
|
total = ""
|
||||||
|
yield 0 if block_given?
|
||||||
|
|
||||||
|
# Snapshot and report the % progress
|
||||||
|
execute("snapshot", machine_id, "delete", snapshot_name) do |type, data|
|
||||||
|
if type == :stderr
|
||||||
|
# Append the data so we can see the full view
|
||||||
|
total << data.gsub("\r", "")
|
||||||
|
|
||||||
|
# Break up the lines. We can't get the progress until we see an "OK"
|
||||||
|
lines = total.split("\n")
|
||||||
|
|
||||||
|
# The progress of the import will be in the last line. Do a greedy
|
||||||
|
# regular expression to find what we're looking for.
|
||||||
|
match = /.+(\d{2})%/.match(lines.last)
|
||||||
|
if match
|
||||||
|
current = match[1].to_i
|
||||||
|
if current > last
|
||||||
|
last = current
|
||||||
|
yield current if block_given?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def list_snapshots(machine_id)
|
||||||
|
output = execute(
|
||||||
|
"snapshot", machine_id, "list", "--machinereadable",
|
||||||
|
retryable: true)
|
||||||
|
|
||||||
|
result = []
|
||||||
|
output.split("\n").each do |line|
|
||||||
|
if line =~ /^SnapshotName.*?="(.+?)"$/i
|
||||||
|
result << $1.to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result.sort
|
||||||
|
rescue Vagrant::Errors::VBoxManageError => e
|
||||||
|
return [] if e.extra_data[:stdout].include?("does not have")
|
||||||
|
raise
|
||||||
|
end
|
||||||
|
|
||||||
|
def restore_snapshot(machine_id, snapshot_name)
|
||||||
|
# Start with 0%
|
||||||
|
last = 0
|
||||||
|
total = ""
|
||||||
|
yield 0 if block_given?
|
||||||
|
|
||||||
|
execute("snapshot", machine_id, "restore", snapshot_name) do |type, data|
|
||||||
|
if type == :stderr
|
||||||
|
# Append the data so we can see the full view
|
||||||
|
total << data.gsub("\r", "")
|
||||||
|
|
||||||
|
# Break up the lines. We can't get the progress until we see an "OK"
|
||||||
|
lines = total.split("\n")
|
||||||
|
|
||||||
|
# The progress of the import will be in the last line. Do a greedy
|
||||||
|
# regular expression to find what we're looking for.
|
||||||
|
match = /.+(\d{2})%/.match(lines.last)
|
||||||
|
if match
|
||||||
|
current = match[1].to_i
|
||||||
|
if current > last
|
||||||
|
last = current
|
||||||
|
yield current if block_given?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def delete
|
def delete
|
||||||
execute("unregistervm", @uuid, "--delete")
|
execute("unregistervm", @uuid, "--delete")
|
||||||
end
|
end
|
||||||
|
|
|
@ -86,6 +86,81 @@ module VagrantPlugins
|
||||||
execute("snapshot", machine_id, "take", snapshot_name)
|
execute("snapshot", machine_id, "take", snapshot_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def delete_snapshot(machine_id, snapshot_name)
|
||||||
|
# Start with 0%
|
||||||
|
last = 0
|
||||||
|
total = ""
|
||||||
|
yield 0 if block_given?
|
||||||
|
|
||||||
|
# Snapshot and report the % progress
|
||||||
|
execute("snapshot", machine_id, "delete", snapshot_name) do |type, data|
|
||||||
|
if type == :stderr
|
||||||
|
# Append the data so we can see the full view
|
||||||
|
total << data.gsub("\r", "")
|
||||||
|
|
||||||
|
# Break up the lines. We can't get the progress until we see an "OK"
|
||||||
|
lines = total.split("\n")
|
||||||
|
|
||||||
|
# The progress of the import will be in the last line. Do a greedy
|
||||||
|
# regular expression to find what we're looking for.
|
||||||
|
match = /.+(\d{2})%/.match(lines.last)
|
||||||
|
if match
|
||||||
|
current = match[1].to_i
|
||||||
|
if current > last
|
||||||
|
last = current
|
||||||
|
yield current if block_given?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def list_snapshots(machine_id)
|
||||||
|
output = execute(
|
||||||
|
"snapshot", machine_id, "list", "--machinereadable",
|
||||||
|
retryable: true)
|
||||||
|
|
||||||
|
result = []
|
||||||
|
output.split("\n").each do |line|
|
||||||
|
if line =~ /^SnapshotName.*?="(.+?)"$/i
|
||||||
|
result << $1.to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result.sort
|
||||||
|
rescue Vagrant::Errors::VBoxManageError => e
|
||||||
|
return [] if e.extra_data[:stdout].include?("does not have")
|
||||||
|
raise
|
||||||
|
end
|
||||||
|
|
||||||
|
def restore_snapshot(machine_id, snapshot_name)
|
||||||
|
# Start with 0%
|
||||||
|
last = 0
|
||||||
|
total = ""
|
||||||
|
yield 0 if block_given?
|
||||||
|
|
||||||
|
execute("snapshot", machine_id, "restore", snapshot_name) do |type, data|
|
||||||
|
if type == :stderr
|
||||||
|
# Append the data so we can see the full view
|
||||||
|
total << data.gsub("\r", "")
|
||||||
|
|
||||||
|
# Break up the lines. We can't get the progress until we see an "OK"
|
||||||
|
lines = total.split("\n")
|
||||||
|
|
||||||
|
# The progress of the import will be in the last line. Do a greedy
|
||||||
|
# regular expression to find what we're looking for.
|
||||||
|
match = /.+(\d{2})%/.match(lines.last)
|
||||||
|
if match
|
||||||
|
current = match[1].to_i
|
||||||
|
if current > last
|
||||||
|
last = current
|
||||||
|
yield current if block_given?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def delete
|
def delete
|
||||||
execute("unregistervm", @uuid, "--delete")
|
execute("unregistervm", @uuid, "--delete")
|
||||||
end
|
end
|
||||||
|
|
|
@ -33,6 +33,11 @@ module VagrantPlugins
|
||||||
require_relative "cap"
|
require_relative "cap"
|
||||||
Cap
|
Cap
|
||||||
end
|
end
|
||||||
|
|
||||||
|
provider_capability(:virtualbox, :snapshot_list) do
|
||||||
|
require_relative "cap"
|
||||||
|
Cap
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
autoload :Action, File.expand_path("../action", __FILE__)
|
autoload :Action, File.expand_path("../action", __FILE__)
|
||||||
|
|
|
@ -1501,6 +1501,17 @@ en:
|
||||||
Post install message from the '%{name}' plugin:
|
Post install message from the '%{name}' plugin:
|
||||||
|
|
||||||
%{message}
|
%{message}
|
||||||
|
snapshot:
|
||||||
|
not_supported: |-
|
||||||
|
This provider doesn't support snapshots.
|
||||||
|
|
||||||
|
This may be intentional or this may be a bug. If this provider
|
||||||
|
should support snapshots, then please report this as a bug to the
|
||||||
|
maintainer of the provider.
|
||||||
|
no_push_snapshot: |-
|
||||||
|
No pushed snapshot found!
|
||||||
|
|
||||||
|
Use `vagrant snapshot push` to push a snapshot to restore to.
|
||||||
status:
|
status:
|
||||||
aborted: |-
|
aborted: |-
|
||||||
The VM is in an aborted state. This means that it was abruptly
|
The VM is in an aborted state. This means that it was abruptly
|
||||||
|
@ -1765,6 +1776,26 @@ en:
|
||||||
set_name:
|
set_name:
|
||||||
setting_name: |-
|
setting_name: |-
|
||||||
Setting the name of the VM: %{name}
|
Setting the name of the VM: %{name}
|
||||||
|
snapshot:
|
||||||
|
deleting: |-
|
||||||
|
Deleting the snapshot '%{name}'...
|
||||||
|
deleted: |-
|
||||||
|
Snapshot deleted!
|
||||||
|
list_none: |-
|
||||||
|
No snapshots have been taken yet!
|
||||||
|
list_none_detail: |-
|
||||||
|
You can take a snapshot using `vagrant snapshot save`. Note that
|
||||||
|
not all providers support this yet. Once a snapshot is taken, you
|
||||||
|
can list them using this command, and use commands such as
|
||||||
|
`vagrant snapshot restore` to go back to a certain snapshot.
|
||||||
|
restoring: |-
|
||||||
|
Restoring the snapshot '%{name}'...
|
||||||
|
saving: |-
|
||||||
|
Snapshotting the machine as '%{name}'...
|
||||||
|
saved: |-
|
||||||
|
Snapshot saved! You can restore the snapshot at any time by
|
||||||
|
using `vagrant snapshot restore`. You can delete it using
|
||||||
|
`vagrant snapshot delete`.
|
||||||
suspend:
|
suspend:
|
||||||
suspending: Saving VM state and suspending execution...
|
suspending: Saving VM state and suspending execution...
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
require File.expand_path("../../../../../base", __FILE__)
|
||||||
|
|
||||||
|
require Vagrant.source_root.join("plugins/commands/snapshot/command/pop")
|
||||||
|
|
||||||
|
describe VagrantPlugins::CommandSnapshot::Command::Pop do
|
||||||
|
include_context "unit"
|
||||||
|
|
||||||
|
let(:iso_env) do
|
||||||
|
# We have to create a Vagrantfile so there is a root path
|
||||||
|
env = isolated_environment
|
||||||
|
env.vagrantfile("")
|
||||||
|
env.create_vagrant_env
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:guest) { double("guest") }
|
||||||
|
let(:host) { double("host") }
|
||||||
|
let(:machine) { iso_env.machine(iso_env.machine_names[0], :dummy) }
|
||||||
|
|
||||||
|
let(:argv) { [] }
|
||||||
|
|
||||||
|
subject { described_class.new(argv, iso_env) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(subject).to receive(:with_target_vms) { |&block| block.call machine }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "execute" do
|
||||||
|
it "calls snapshot_restore with the last pushed snapshot" do
|
||||||
|
machine.id = "foo"
|
||||||
|
|
||||||
|
allow(machine.provider).to receive(:capability).
|
||||||
|
with(:snapshot_list).and_return(["push_2_0", "push_1_0"])
|
||||||
|
|
||||||
|
expect(machine).to receive(:action) do |name, opts|
|
||||||
|
expect(name).to eq(:snapshot_restore)
|
||||||
|
expect(opts[:snapshot_name]).to eq("push_2_0")
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "isn't an error if no matching snapshot" do
|
||||||
|
machine.id = "foo"
|
||||||
|
|
||||||
|
allow(machine.provider).to receive(:capability).
|
||||||
|
with(:snapshot_list).and_return(["foo"])
|
||||||
|
|
||||||
|
expect(machine).to_not receive(:action)
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,46 @@
|
||||||
|
require File.expand_path("../../../../../base", __FILE__)
|
||||||
|
|
||||||
|
require Vagrant.source_root.join("plugins/commands/snapshot/command/push")
|
||||||
|
|
||||||
|
describe VagrantPlugins::CommandSnapshot::Command::Push do
|
||||||
|
include_context "unit"
|
||||||
|
|
||||||
|
let(:iso_env) do
|
||||||
|
# We have to create a Vagrantfile so there is a root path
|
||||||
|
env = isolated_environment
|
||||||
|
env.vagrantfile("")
|
||||||
|
env.create_vagrant_env
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:guest) { double("guest") }
|
||||||
|
let(:host) { double("host") }
|
||||||
|
let(:machine) { iso_env.machine(iso_env.machine_names[0], :dummy) }
|
||||||
|
|
||||||
|
let(:argv) { [] }
|
||||||
|
|
||||||
|
subject { described_class.new(argv, iso_env) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(subject).to receive(:with_target_vms) { |&block| block.call machine }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "execute" do
|
||||||
|
it "calls snapshot_save with a random snapshot name" do
|
||||||
|
machine.id = "foo"
|
||||||
|
|
||||||
|
expect(machine).to receive(:action) do |name, opts|
|
||||||
|
expect(name).to eq(:snapshot_save)
|
||||||
|
expect(opts[:snapshot_name]).to match(/^push_/)
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "doesn't snapshot a non-existent machine" do
|
||||||
|
machine.id = nil
|
||||||
|
|
||||||
|
expect(machine).to_not receive(:action)
|
||||||
|
expect(subject.execute).to eq(0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,31 @@
|
||||||
|
require "pathname"
|
||||||
|
require "tmpdir"
|
||||||
|
|
||||||
|
require File.expand_path("../../../../base", __FILE__)
|
||||||
|
|
||||||
|
describe Vagrant::Action::Builtin::IsEnvSet do
|
||||||
|
let(:app) { lambda { |env| } }
|
||||||
|
let(:env) { { } }
|
||||||
|
|
||||||
|
describe "#call" do
|
||||||
|
it "sets result to true if it is set" do
|
||||||
|
env[:bar] = true
|
||||||
|
|
||||||
|
subject = described_class.new(app, env, :bar)
|
||||||
|
|
||||||
|
expect(app).to receive(:call).with(env)
|
||||||
|
|
||||||
|
subject.call(env)
|
||||||
|
expect(env[:result]).to be_true
|
||||||
|
end
|
||||||
|
|
||||||
|
it "sets result to false if it isn't set" do
|
||||||
|
subject = described_class.new(app, env, :bar)
|
||||||
|
|
||||||
|
expect(app).to receive(:call).with(env)
|
||||||
|
|
||||||
|
subject.call(env)
|
||||||
|
expect(env[:result]).to be_false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -108,6 +108,7 @@
|
||||||
<li<%= sidebar_current("cli-reload") %>><a href="/v2/cli/reload.html">reload</a></li>
|
<li<%= sidebar_current("cli-reload") %>><a href="/v2/cli/reload.html">reload</a></li>
|
||||||
<li<%= sidebar_current("cli-resume") %>><a href="/v2/cli/resume.html">resume</a></li>
|
<li<%= sidebar_current("cli-resume") %>><a href="/v2/cli/resume.html">resume</a></li>
|
||||||
<li<%= sidebar_current("cli-share") %>><a href="/v2/cli/share.html">share</a></li>
|
<li<%= sidebar_current("cli-share") %>><a href="/v2/cli/share.html">share</a></li>
|
||||||
|
<li<%= sidebar_current("cli-snapshot") %>><a href="/v2/cli/snapshot.html">snapshot</a></li>
|
||||||
<li<%= sidebar_current("cli-ssh") %>><a href="/v2/cli/ssh.html">ssh</a></li>
|
<li<%= sidebar_current("cli-ssh") %>><a href="/v2/cli/ssh.html">ssh</a></li>
|
||||||
<li<%= sidebar_current("cli-ssh_config") %>><a href="/v2/cli/ssh_config.html">ssh-config</a></li>
|
<li<%= sidebar_current("cli-ssh_config") %>><a href="/v2/cli/ssh_config.html">ssh-config</a></li>
|
||||||
<li<%= sidebar_current("cli-status") %>><a href="/v2/cli/status.html">status</a></li>
|
<li<%= sidebar_current("cli-status") %>><a href="/v2/cli/status.html">status</a></li>
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
---
|
||||||
|
page_title: "vagrant snapshot - Command-Line Interface"
|
||||||
|
sidebar_current: "cli-snapshot"
|
||||||
|
---
|
||||||
|
|
||||||
|
# Snapshot
|
||||||
|
|
||||||
|
**Command: `vagrant snapshot`**
|
||||||
|
|
||||||
|
This is the command used to manage snapshots with the guest machine.
|
||||||
|
Snapshots record a point-in-time state of a guest machine. You can then
|
||||||
|
quickly restore to this environment. This lets you experiment and try things
|
||||||
|
and quickly restore back to a previous state.
|
||||||
|
|
||||||
|
Snapshotting is not supported by every provider. If it isn't supported,
|
||||||
|
Vagrant will give you an error message.
|
||||||
|
|
||||||
|
The main functionality of this command is exposed via even more subcommands:
|
||||||
|
|
||||||
|
* `push`
|
||||||
|
* `pop`
|
||||||
|
* `save`
|
||||||
|
* `restore`
|
||||||
|
* `list`
|
||||||
|
* `delete`
|
||||||
|
|
||||||
|
# Snapshot Push
|
||||||
|
|
||||||
|
**Command: `vagrant snapshot push`**
|
||||||
|
|
||||||
|
This takes a snapshot and pushes it onto the snapshot stack.
|
||||||
|
|
||||||
|
This is a shorthand for `vagrant snapshot save` where you don't need
|
||||||
|
to specify a name. When you call the inverse `vagrant snapshot pop`, it will
|
||||||
|
restore the pushed state.
|
||||||
|
|
||||||
|
~> **Warning:** If you are using `push` and `pop`, avoid using `save`
|
||||||
|
and `restore` which are unsafe to mix.
|
||||||
|
|
||||||
|
# Snapshot Pop
|
||||||
|
|
||||||
|
**Command: `vagrant snapshot pop`**
|
||||||
|
|
||||||
|
This command is the inverse of `vagrant snapshot push`: it will restore
|
||||||
|
the pushed state.
|
||||||
|
|
||||||
|
# Snapshot Save
|
||||||
|
|
||||||
|
**Command: `vagrant snapshot save NAME`**
|
||||||
|
|
||||||
|
This command saves a new named snapshot. If this command is used, the
|
||||||
|
`push` and `pop` subcommands cannot be safely used.
|
||||||
|
|
||||||
|
# Snapshot Restore
|
||||||
|
|
||||||
|
**Command: `vagrant snapshot restore NAME`**
|
||||||
|
|
||||||
|
This command restores the named snapshot.
|
||||||
|
|
||||||
|
# Snapshot List
|
||||||
|
|
||||||
|
**Command: `vagrant snapshot list`**
|
||||||
|
|
||||||
|
This command will list all the snapshots taken.
|
||||||
|
|
||||||
|
# Snapshot Delete
|
||||||
|
|
||||||
|
**Command: `vagrant snapshot delete NAME`**
|
||||||
|
|
||||||
|
This command will delete the named snapshot.
|
||||||
|
|
||||||
|
Some providers require all "child" snapshots to be deleted first. Vagrant
|
||||||
|
itself doesn't track what these children are. If this is the case (such
|
||||||
|
as with VirtualBox), then you must be sure to delete the snapshots in the
|
||||||
|
reverse order they were taken.
|
||||||
|
|
||||||
|
This command is typically _much faster_ if the machine is halted prior to
|
||||||
|
snapshotting. If this isn't an option, or isn't ideal, then the deletion
|
||||||
|
can also be done online with most providers.
|
Loading…
Reference in New Issue