vagrant-simple_cloud 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +10 -0
  3. data/LICENSE +373 -0
  4. data/Rakefile +21 -0
  5. data/build.sh +31 -0
  6. data/lib/vagrant-simple_cloud/actions/check_state.rb +19 -0
  7. data/lib/vagrant-simple_cloud/actions/create.rb +94 -0
  8. data/lib/vagrant-simple_cloud/actions/destroy.rb +30 -0
  9. data/lib/vagrant-simple_cloud/actions/modify_provision_path.rb +38 -0
  10. data/lib/vagrant-simple_cloud/actions/power_off.rb +35 -0
  11. data/lib/vagrant-simple_cloud/actions/power_on.rb +48 -0
  12. data/lib/vagrant-simple_cloud/actions/rebuild.rb +49 -0
  13. data/lib/vagrant-simple_cloud/actions/reload.rb +45 -0
  14. data/lib/vagrant-simple_cloud/actions/setup_key.rb +58 -0
  15. data/lib/vagrant-simple_cloud/actions/setup_sudo.rb +48 -0
  16. data/lib/vagrant-simple_cloud/actions/setup_user.rb +66 -0
  17. data/lib/vagrant-simple_cloud/actions/shut_down.rb +35 -0
  18. data/lib/vagrant-simple_cloud/actions.rb +164 -0
  19. data/lib/vagrant-simple_cloud/commands/list.rb +93 -0
  20. data/lib/vagrant-simple_cloud/commands/rebuild.rb +29 -0
  21. data/lib/vagrant-simple_cloud/config.rb +69 -0
  22. data/lib/vagrant-simple_cloud/errors.rb +37 -0
  23. data/lib/vagrant-simple_cloud/helpers/client.rb +106 -0
  24. data/lib/vagrant-simple_cloud/helpers/client_service.rb +81 -0
  25. data/lib/vagrant-simple_cloud/helpers/result.rb +40 -0
  26. data/lib/vagrant-simple_cloud/plugin.rb +31 -0
  27. data/lib/vagrant-simple_cloud/provider.rb +102 -0
  28. data/lib/vagrant-simple_cloud/version.rb +5 -0
  29. data/lib/vagrant-simple_cloud.rb +20 -0
  30. data/locales/en.yml +92 -0
  31. data/test/Vagrantfile +14 -0
  32. data/test/scripts/provision.sh +3 -0
  33. data/test/test.sh +12 -0
  34. data/test/test_id_rsa +27 -0
  35. data/test/test_id_rsa.pub +1 -0
  36. data/vagrant-simple_cloud.gemspec +21 -0
  37. metadata +43 -3
@@ -0,0 +1,48 @@
1
+ require 'vagrant-simple_cloud/helpers/client'
2
+
3
+ module VagrantPlugins
4
+ module SimpleCloud
5
+ module Actions
6
+ class PowerOn
7
+ include Helpers::Client
8
+
9
+ def initialize(app, env)
10
+ @app = app
11
+ @machine = env[:machine]
12
+ @client = client
13
+ @logger = Log4r::Logger.new('vagrant::simple_cloud::power_on')
14
+ end
15
+
16
+ def call(env)
17
+ # submit power on droplet request
18
+ result = @client.post("/v2/vps/#{@machine.id}/actions", {
19
+ :type => 'power_on'
20
+ })
21
+
22
+ # wait for request to complete
23
+ env[:ui].info I18n.t('vagrant_simple_cloud.info.powering_on')
24
+ @client.wait_for_event(env, result['action']['id'])
25
+
26
+ # refresh droplet state with provider
27
+ Provider.droplet(@machine, :refresh => true)
28
+
29
+ # wait for ssh to be ready
30
+ switch_user = @machine.provider_config.setup?
31
+ user = @machine.config.ssh.username
32
+ @machine.config.ssh.username = 'root' if switch_user
33
+
34
+ retryable(:tries => 120, :sleep => 10) do
35
+ next if env[:interrupted]
36
+ raise 'not ready' if !@machine.communicate.ready?
37
+ end
38
+
39
+ @machine.config.ssh.username = user
40
+
41
+ @app.call(env)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+
@@ -0,0 +1,49 @@
1
+ require 'vagrant-simple_cloud/helpers/client'
2
+
3
+ module VagrantPlugins
4
+ module SimpleCloud
5
+ module Actions
6
+ class Rebuild
7
+ include Helpers::Client
8
+ include Vagrant::Util::Retryable
9
+
10
+ def initialize(app, env)
11
+ @app = app
12
+ @machine = env[:machine]
13
+ @client = client
14
+ @logger = Log4r::Logger.new('vagrant::simple_cloud::rebuild')
15
+ end
16
+
17
+ def call(env)
18
+
19
+ # submit rebuild request
20
+ result = @client.post("/v2/vps/#{@machine.id}/actions", {
21
+ :type => 'rebuild',
22
+ :image => @machine.provider_config.image
23
+ })
24
+
25
+ # wait for request to complete
26
+ env[:ui].info I18n.t('vagrant_simple_cloud.info.rebuilding')
27
+ @client.wait_for_event(env, result['action']['id'])
28
+
29
+ # refresh droplet state with provider
30
+ Provider.droplet(@machine, :refresh => true)
31
+
32
+ # wait for ssh to be ready
33
+ switch_user = @machine.provider_config.setup?
34
+ user = @machine.config.ssh.username
35
+ @machine.config.ssh.username = 'root' if switch_user
36
+
37
+ retryable(:tries => 120, :sleep => 10) do
38
+ next if env[:interrupted]
39
+ raise 'not ready' if !@machine.communicate.ready?
40
+ end
41
+
42
+ @machine.config.ssh.username = user
43
+
44
+ @app.call(env)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,45 @@
1
+ require 'vagrant-simple_cloud/helpers/client'
2
+
3
+ module VagrantPlugins
4
+ module SimpleCloud
5
+ module Actions
6
+ class Reload
7
+ include Helpers::Client
8
+
9
+ def initialize(app, env)
10
+ @app = app
11
+ @machine = env[:machine]
12
+ @client = client
13
+ @logger = Log4r::Logger.new('vagrant::simple_cloud::reload')
14
+ end
15
+
16
+ def call(env)
17
+ # submit reboot droplet request
18
+ result = @client.post("/v2/vps/#{@machine.id}/actions", {
19
+ :type => 'reboot'
20
+ })
21
+
22
+ # wait for request to complete
23
+ env[:ui].info I18n.t('vagrant_simple_cloud.info.reloading')
24
+ @client.wait_for_event(env, result['action']['id'])
25
+
26
+ # wait for ssh to be ready
27
+ switch_user = @machine.provider_config.setup?
28
+ user = @machine.config.ssh.username
29
+ @machine.config.ssh.username = 'root' if switch_user
30
+
31
+ retryable(:tries => 120, :sleep => 10) do
32
+ next if env[:interrupted]
33
+ raise 'not ready' if !@machine.communicate.ready?
34
+ end
35
+
36
+ @machine.config.ssh.username = user
37
+
38
+ @app.call(env)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+
@@ -0,0 +1,58 @@
1
+ require 'vagrant-simple_cloud/helpers/client'
2
+
3
+ module VagrantPlugins
4
+ module SimpleCloud
5
+ module Actions
6
+ class SetupKey
7
+ include Helpers::Client
8
+
9
+ def initialize(app, env)
10
+ @app = app
11
+ @machine = env[:machine]
12
+ @client = client
13
+ @logger = Log4r::Logger.new('vagrant::simple_cloud::setup_key')
14
+ end
15
+
16
+ # TODO check the content of the key to see if it has changed
17
+ def call(env)
18
+ ssh_key_name = @machine.provider_config.ssh_key_name
19
+
20
+ begin
21
+ # assigns existing ssh key id to env for use by other commands
22
+ env[:ssh_key_id] = @client
23
+ .request('/v2/account/keys')
24
+ .find_id(:ssh_keys, :name => ssh_key_name)
25
+
26
+ env[:ui].info I18n.t('vagrant_simple_cloud.info.using_key', {
27
+ :name => ssh_key_name
28
+ })
29
+ rescue Errors::ResultMatchError
30
+ env[:ssh_key_id] = create_ssh_key(ssh_key_name, env)
31
+ end
32
+
33
+ @app.call(env)
34
+ end
35
+
36
+ private
37
+
38
+ def create_ssh_key(name, env)
39
+ # assumes public key exists on the same path as private key with .pub ext
40
+ path = @machine.config.ssh.private_key_path
41
+ path = path[0] if path.is_a?(Array)
42
+ path = File.expand_path(path, @machine.env.root_path)
43
+ pub_key = SimpleCloud.public_key(path)
44
+
45
+ env[:ui].info I18n.t('vagrant_simple_cloud.info.creating_key', {
46
+ :name => name
47
+ })
48
+
49
+ result = @client.post('/v2/account/keys', {
50
+ :name => name,
51
+ :public_key => pub_key
52
+ })
53
+ result['ssh_key']['id']
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,48 @@
1
+ module VagrantPlugins
2
+ module SimpleCloud
3
+ module Actions
4
+ class SetupSudo
5
+ def initialize(app, env)
6
+ @app = app
7
+ @machine = env[:machine]
8
+ @logger = Log4r::Logger.new('vagrant::simple_cloud::setup_sudo')
9
+ end
10
+
11
+ def call(env)
12
+ # check if setup is enabled
13
+ return @app.call(env) unless @machine.provider_config.setup?
14
+
15
+ # override ssh username to root
16
+ user = @machine.config.ssh.username
17
+ @machine.config.ssh.username = 'root'
18
+
19
+ # check for guest name available in Vagrant 1.2 first
20
+ guest_name = @machine.guest.name if @machine.guest.respond_to?(:name)
21
+ guest_name ||= @machine.guest.to_s.downcase
22
+
23
+ case guest_name
24
+ when /debian/
25
+ if @machine.provider_config.image =~ /^debian-8/
26
+ env[:ui].info I18n.t('vagrant_simple_cloud.info.late_sudo_install_deb8')
27
+ @machine.communicate.execute(<<-'BASH')
28
+ if [ ! -x /usr/bin/sudo ] ; then apt-get update -y && apt-get install -y sudo ; fi
29
+ BASH
30
+ end
31
+ when /redhat/
32
+ env[:ui].info I18n.t('vagrant_simple_cloud.info.modifying_sudo')
33
+
34
+ # disable tty requirement for sudo
35
+ @machine.communicate.execute(<<-'BASH')
36
+ sed -i'.bk' -e 's/\(Defaults\s\+requiretty\)/# \1/' /etc/sudoers
37
+ BASH
38
+ end
39
+
40
+ # reset ssh username
41
+ @machine.config.ssh.username = user
42
+
43
+ @app.call(env)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,66 @@
1
+ module VagrantPlugins
2
+ module SimpleCloud
3
+ module Actions
4
+ class SetupUser
5
+ def initialize(app, env)
6
+ @app = app
7
+ @machine = env[:machine]
8
+ @logger = Log4r::Logger.new('vagrant::simple_cloud::setup_user')
9
+ end
10
+
11
+ def call(env)
12
+ # check if setup is enabled
13
+ return @app.call(env) unless @machine.provider_config.setup?
14
+
15
+ # check if a username has been specified
16
+ return @app.call(env) unless @machine.config.ssh.username
17
+
18
+ # override ssh username to root temporarily
19
+ user = @machine.config.ssh.username
20
+ @machine.config.ssh.username = 'root'
21
+
22
+ env[:ui].info I18n.t('vagrant_simple_cloud.info.creating_user', {
23
+ :user => user
24
+ })
25
+
26
+ # create user account
27
+ @machine.communicate.execute(<<-BASH)
28
+ if ! (grep ^#{user}: /etc/passwd); then
29
+ useradd -m -s /bin/bash #{user};
30
+ fi
31
+ BASH
32
+
33
+ # grant user sudo access with no password requirement
34
+ @machine.communicate.execute(<<-BASH)
35
+ if ! (grep #{user} /etc/sudoers); then
36
+ echo "#{user} ALL=(ALL:ALL) NOPASSWD: ALL" >> /etc/sudoers;
37
+ else
38
+ sed -i -e "/#{user}/ s/=.*/=(ALL:ALL) NOPASSWD: ALL/" /etc/sudoers;
39
+ fi
40
+ BASH
41
+
42
+ # create the .ssh directory in the users home
43
+ @machine.communicate.execute("su #{user} -c 'mkdir -p ~/.ssh'")
44
+
45
+ # add the specified key to the authorized keys file
46
+ path = @machine.config.ssh.private_key_path
47
+ path = path[0] if path.is_a?(Array)
48
+ path = File.expand_path(path, @machine.env.root_path)
49
+ pub_key = SimpleCloud.public_key(path)
50
+ @machine.communicate.execute(<<-BASH)
51
+ if ! grep '#{pub_key}' /home/#{user}/.ssh/authorized_keys; then
52
+ echo '#{pub_key}' >> /home/#{user}/.ssh/authorized_keys;
53
+ fi
54
+
55
+ chown -R #{user} /home/#{user}/.ssh;
56
+ BASH
57
+
58
+ # reset username
59
+ @machine.config.ssh.username = user
60
+
61
+ @app.call(env)
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,35 @@
1
+ require 'vagrant-simple_cloud/helpers/client'
2
+
3
+ module VagrantPlugins
4
+ module SimpleCloud
5
+ module Actions
6
+ class ShutDown
7
+ include Helpers::Client
8
+
9
+ def initialize(app, env)
10
+ @app = app
11
+ @machine = env[:machine]
12
+ @client = client
13
+ @logger = Log4r::Logger.new('vagrant::simple_cloud::shut_down')
14
+ end
15
+
16
+ def call(env)
17
+ # submit shutdown droplet request
18
+ result = @client.post("/v2/vps/#{@machine.id}/actions", {
19
+ :type => 'shutdown'
20
+ })
21
+
22
+ # wait for request to complete
23
+ env[:ui].info I18n.t('vagrant_simple_cloud.info.shutting_down')
24
+ @client.wait_for_event(env, result['action']['id'])
25
+
26
+ # refresh droplet state with provider
27
+ Provider.droplet(@machine, :refresh => true)
28
+
29
+ @app.call(env)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+
@@ -0,0 +1,164 @@
1
+ require 'vagrant-simple_cloud/actions/check_state'
2
+ require 'vagrant-simple_cloud/actions/create'
3
+ require 'vagrant-simple_cloud/actions/destroy'
4
+ require 'vagrant-simple_cloud/actions/shut_down'
5
+ require 'vagrant-simple_cloud/actions/power_off'
6
+ require 'vagrant-simple_cloud/actions/power_on'
7
+ require 'vagrant-simple_cloud/actions/rebuild'
8
+ require 'vagrant-simple_cloud/actions/reload'
9
+ require 'vagrant-simple_cloud/actions/setup_user'
10
+ require 'vagrant-simple_cloud/actions/setup_sudo'
11
+ require 'vagrant-simple_cloud/actions/setup_key'
12
+ require 'vagrant-simple_cloud/actions/modify_provision_path'
13
+
14
+ module VagrantPlugins
15
+ module SimpleCloud
16
+ module Actions
17
+ include Vagrant::Action::Builtin
18
+
19
+ def self.destroy
20
+ return Vagrant::Action::Builder.new.tap do |builder|
21
+ builder.use ConfigValidate
22
+ builder.use Call, CheckState do |env, b|
23
+ case env[:machine_state]
24
+ when :not_created
25
+ env[:ui].info I18n.t('vagrant_simple_cloud.info.not_created')
26
+ else
27
+ b.use Call, DestroyConfirm do |env2, b2|
28
+ if env2[:result]
29
+ b2.use Destroy
30
+ b2.use ProvisionerCleanup if defined?(ProvisionerCleanup)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ def self.ssh
39
+ return Vagrant::Action::Builder.new.tap do |builder|
40
+ builder.use ConfigValidate
41
+ builder.use Call, CheckState do |env, b|
42
+ case env[:machine_state]
43
+ when :active
44
+ b.use SSHExec
45
+ when :off
46
+ env[:ui].info I18n.t('vagrant_simple_cloud.info.off')
47
+ when :not_created
48
+ env[:ui].info I18n.t('vagrant_simple_cloud.info.not_created')
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ def self.ssh_run
55
+ return Vagrant::Action::Builder.new.tap do |builder|
56
+ builder.use ConfigValidate
57
+ builder.use Call, CheckState do |env, b|
58
+ case env[:machine_state]
59
+ when :active
60
+ b.use SSHRun
61
+ when :off
62
+ env[:ui].info I18n.t('vagrant_simple_cloud.info.off')
63
+ when :not_created
64
+ env[:ui].info I18n.t('vagrant_simple_cloud.info.not_created')
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ def self.provision
71
+ return Vagrant::Action::Builder.new.tap do |builder|
72
+ builder.use ConfigValidate
73
+ builder.use Call, CheckState do |env, b|
74
+ case env[:machine_state]
75
+ when :active
76
+ b.use Provision
77
+ b.use ModifyProvisionPath
78
+ b.use SyncedFolders
79
+ when :off
80
+ env[:ui].info I18n.t('vagrant_simple_cloud.info.off')
81
+ when :not_created
82
+ env[:ui].info I18n.t('vagrant_simple_cloud.info.not_created')
83
+ end
84
+ end
85
+ end
86
+ end
87
+
88
+ def self.up
89
+ return Vagrant::Action::Builder.new.tap do |builder|
90
+ builder.use ConfigValidate
91
+ builder.use Call, CheckState do |env, b|
92
+ case env[:machine_state]
93
+ when :active
94
+ env[:ui].info I18n.t('vagrant_simple_cloud.info.already_active')
95
+ when :off
96
+ b.use PowerOn
97
+ b.use provision
98
+ when :not_created
99
+ b.use SetupKey
100
+ b.use Create
101
+ b.use SetupSudo
102
+ b.use SetupUser
103
+ b.use provision
104
+ end
105
+ end
106
+ end
107
+ end
108
+
109
+ def self.halt
110
+ return Vagrant::Action::Builder.new.tap do |builder|
111
+ builder.use ConfigValidate
112
+ builder.use Call, CheckState do |env, b|
113
+ case env[:machine_state]
114
+ when :active
115
+ if env[:force_halt]
116
+ b.use PowerOff
117
+ else
118
+ b.use ShutDown
119
+ end
120
+ when :off
121
+ env[:ui].info I18n.t('vagrant_simple_cloud.info.already_off')
122
+ when :not_created
123
+ env[:ui].info I18n.t('vagrant_simple_cloud.info.not_created')
124
+ end
125
+ end
126
+ end
127
+ end
128
+
129
+ def self.reload
130
+ return Vagrant::Action::Builder.new.tap do |builder|
131
+ builder.use ConfigValidate
132
+ builder.use Call, CheckState do |env, b|
133
+ case env[:machine_state]
134
+ when :active
135
+ b.use Reload
136
+ b.use provision
137
+ when :off
138
+ env[:ui].info I18n.t('vagrant_simple_cloud.info.off')
139
+ when :not_created
140
+ env[:ui].info I18n.t('vagrant_simple_cloud.info.not_created')
141
+ end
142
+ end
143
+ end
144
+ end
145
+
146
+ def self.rebuild
147
+ return Vagrant::Action::Builder.new.tap do |builder|
148
+ builder.use ConfigValidate
149
+ builder.use Call, CheckState do |env, b|
150
+ case env[:machine_state]
151
+ when :active, :off
152
+ b.use Rebuild
153
+ b.use SetupSudo
154
+ b.use SetupUser
155
+ b.use provision
156
+ when :not_created
157
+ env[:ui].info I18n.t('vagrant_simple_cloud.info.not_created')
158
+ end
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,93 @@
1
+ require 'optparse'
2
+ require 'vagrant-simple_cloud/helpers/client'
3
+
4
+ module VagrantPlugins
5
+ module SimpleCloud
6
+ module Commands
7
+ class List < Vagrant.plugin('2', :command)
8
+ def self.synopsis
9
+ "list available images and regions from SimpleCloud"
10
+ end
11
+
12
+ def execute
13
+ @token = nil
14
+
15
+ @opts = OptionParser.new do |o|
16
+ o.banner = 'Usage: vagrant simplecloud-list [options] <images|regions|sizes> <token>'
17
+
18
+ o.on("-r", "--[no-]regions", "show the regions when listing images") do |r|
19
+ @regions = r
20
+ end
21
+ o.on("-h", "--help", "Displays help") do
22
+ puts o
23
+ return 0
24
+ end
25
+ end
26
+
27
+ argv = parse_options(@opts)
28
+ @token = argv[1]
29
+
30
+ if @token.nil?
31
+ usage
32
+ return 1
33
+ end
34
+
35
+ case argv[0]
36
+ when "images"
37
+ result = query('/v2/images')
38
+ images = Array(result["images"])
39
+ if @regions
40
+ images_table = images.map do |image|
41
+ '%-50s %-20s %-20s %-50s' % ["#{image['distribution']} #{image['name']}", image['slug'], image['id'], image['regions'].join(', ')]
42
+ end
43
+ @env.ui.info I18n.t('vagrant_simple_cloud.info.images_with_regions', images: images_table.sort.join("\r\n"))
44
+ else
45
+ images_table = images.map do |image|
46
+ '%-50s %-30s %-30s' % ["#{image['distribution']} #{image['name']}", image['slug'], image['id']]
47
+ end
48
+ @env.ui.info I18n.t('vagrant_simple_cloud.info.images', images: images_table.sort.join("\r\n"))
49
+ end
50
+ when "regions"
51
+ result = query('/v2/regions')
52
+ regions = Array(result["regions"])
53
+ regions_table = regions.map { |region| '%-30s %-12s' % [region['name'], region['slug']] }
54
+ @env.ui.info I18n.t('vagrant_simple_cloud.info.regions', regions: regions_table.sort.join("\r\n"))
55
+ when "sizes"
56
+ result = query('/v2/sizes')
57
+ sizes = Array(result["sizes"])
58
+ sizes_table = sizes.map { |size| '%-15s %-15s %-12s' % ["#{size['memory']}", size['vcpus'], size['slug']] }
59
+ @env.ui.info I18n.t('vagrant_simple_cloud.info.sizes', sizes: sizes_table.sort_by{|s| s['memory']}.join("\r\n"))
60
+ else
61
+ usage
62
+ return 1
63
+ end
64
+
65
+ 0
66
+ rescue Faraday::Error::ConnectionFailed, RuntimeError => e
67
+ @env.ui.error I18n.t('vagrant_simple_cloud.info.list_error', message: e.message)
68
+ 1
69
+ end
70
+
71
+ def query(path)
72
+ connection = Faraday.new({
73
+ :url => "https://api.simplecloud.ru/"
74
+ })
75
+
76
+ result = connection.get(path, per_page: 100) do |req|
77
+ req.headers['Authorization'] = "Bearer #{@token}"
78
+ end
79
+
80
+ case result.status
81
+ when 200 then JSON.parse(result.body)
82
+ when 401 then raise("unauthorized access — is the token correct?")
83
+ else raise("call returned with status #{result.status}")
84
+ end
85
+ end
86
+
87
+ def usage
88
+ @env.ui.info(@opts)
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,29 @@
1
+ require 'optparse'
2
+
3
+ module VagrantPlugins
4
+ module SimpleCloud
5
+ module Commands
6
+ class Rebuild < Vagrant.plugin('2', :command)
7
+
8
+ # Show description when `vagrant list-commands` is triggered
9
+ def self.synopsis
10
+ "plugin: vagrant-simple_cloud: destroys and ups the vm with the same ip address"
11
+ end
12
+
13
+ def execute
14
+ opts = OptionParser.new do |o|
15
+ o.banner = 'Usage: vagrant rebuild [vm-name]'
16
+ end
17
+
18
+ argv = parse_options(opts)
19
+
20
+ with_target_vms(argv) do |machine|
21
+ machine.action(:rebuild)
22
+ end
23
+
24
+ 0
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end