knife-vagrant3 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/CHANGELOG.md +43 -0
- data/Gemfile +2 -0
- data/LICENSE +13 -0
- data/README.md +4 -0
- data/Rakefile +2 -0
- data/knife-vagrant3.gemspec +21 -0
- data/lib/chef/knife/vagrant_base.rb +173 -0
- data/lib/chef/knife/vagrant_box.rb +15 -0
- data/lib/chef/knife/vagrant_server_create.rb +473 -0
- data/lib/chef/knife/vagrant_server_delete.rb +73 -0
- data/lib/chef/knife/vagrant_server_halt.rb +33 -0
- data/lib/chef/knife/vagrant_server_list.rb +39 -0
- data/lib/chef/knife/vagrant_server_resume.rb +35 -0
- data/lib/chef/knife/vagrant_server_suspend.rb +33 -0
- data/lib/chef/knife/vagrant_server_up.rb +33 -0
- data/lib/knife-vagrant/version.rb +6 -0
- metadata +89 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 903e63d91b1390d43259125945d61be2da6e0d94
|
4
|
+
data.tar.gz: a6639aab2fa6aa981343c1f81331b5a5f763a6d3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ca1a239ff9aa4719786ae503ea52836262d7b80260aa7a32213468279036208fd84a5c5abbadf54a6d64fc96b2b8a12263c8768dea7d9438c620edc6639d3620
|
7
|
+
data.tar.gz: b98869c57ad6d4bd9be1ed25b20f0c67f40985a00803a4216da3788b4778728077e84afae20c0e2ffc7a4e8ce1df00cc289292bc3df6c60a95a92e7bf0cb4d9a
|
data/.gitignore
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# 0.0.5 (unreleased)
|
2
|
+
|
3
|
+
## Changes and new features
|
4
|
+
|
5
|
+
## Fixes
|
6
|
+
|
7
|
+
|
8
|
+
# 0.0.4 (2014-03-14)
|
9
|
+
|
10
|
+
## Changes and new features
|
11
|
+
|
12
|
+
* Added --provider option to use vagrant providers other than virtualbox
|
13
|
+
|
14
|
+
|
15
|
+
# 0.0.3 (2014-01-28)
|
16
|
+
|
17
|
+
## Fixes
|
18
|
+
|
19
|
+
* Fixed error when not using --vb-customize option
|
20
|
+
* Removed unneeded dependency on knife-ec2
|
21
|
+
|
22
|
+
|
23
|
+
# 0.0.2 (2013-12-17)
|
24
|
+
|
25
|
+
## Changes and new features
|
26
|
+
|
27
|
+
* BREAKING: --share-folders option now takes HOST_PATH::GUEST_PATH instead of NAME::GUEST_PATH::HOST_PATH
|
28
|
+
* Added --port-forward option to map host ports to VMs
|
29
|
+
* Added --vb-customize option to pass arbitrary VirtualBox options to Vagrant
|
30
|
+
|
31
|
+
|
32
|
+
# 0.0.1 (2013-12-11)
|
33
|
+
|
34
|
+
## Changes and new features
|
35
|
+
|
36
|
+
* Initial release
|
37
|
+
|
38
|
+
|
39
|
+
# Thanks to our contributors
|
40
|
+
|
41
|
+
* [Jāzeps Baško](https://github.com/jbasko)
|
42
|
+
* [Robert J. Berger](https://github.com/rberger)
|
43
|
+
* [xsunsmile](https://github.com/xsunsmile)
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright 2013 Markus Kern <chef@mkern.fastmail.fm>
|
2
|
+
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
you may not use this file except in compliance with the License.
|
5
|
+
You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
See the License for the specific language governing permissions and
|
13
|
+
limitations under the License.
|
data/README.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path('../lib', __FILE__)
|
3
|
+
require 'knife-vagrant/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'knife-vagrant3'
|
7
|
+
s.version = Knife::Vagrant::VERSION
|
8
|
+
s.authors = ['Markus Kern']
|
9
|
+
s.email = ['chef@mkern.fastmail.fm']
|
10
|
+
s.homepage = 'https://github.com/makern/knife-vagrant2'
|
11
|
+
s.summary = %q{Vagrant support for Chef's knife command}
|
12
|
+
s.description = s.summary
|
13
|
+
s.license = 'Apache 2.0'
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
|
17
|
+
s.add_dependency 'chef', '>= 0.10.10'
|
18
|
+
s.add_development_dependency 'rake'
|
19
|
+
|
20
|
+
s.require_paths = ['lib']
|
21
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
require 'chef/knife'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
module VagrantBase
|
6
|
+
|
7
|
+
# :nodoc:
|
8
|
+
# Would prefer to do this in a rational way, but can't be done b/c of
|
9
|
+
# Mixlib::CLI's design :(
|
10
|
+
def self.included(includer)
|
11
|
+
includer.class_eval do
|
12
|
+
|
13
|
+
option :vagrant_dir,
|
14
|
+
:short => '-D PATH',
|
15
|
+
:long => '--vagrant-dir PATH',
|
16
|
+
:description => "Path to where Vagrant files are stored. Defaults to cwd/vagrant (#{Dir.pwd}/vagrant)",
|
17
|
+
:proc => Proc.new { |key| Chef::Config[:knife][:vagrant_dir] = key },
|
18
|
+
:default => File.join(Dir.pwd, '/vagrant')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def vagrant_exec(instance, cmd, opts = {})
|
23
|
+
fetch_output = opts[:fetch_output] || false
|
24
|
+
no_cwd_change = opts[:no_cwd_change] || false
|
25
|
+
|
26
|
+
unless no_cwd_change
|
27
|
+
|
28
|
+
# Dir.getwd throws an unknown exception when this plugin
|
29
|
+
# is run in a multi-threaded environment
|
30
|
+
begin
|
31
|
+
cwd = Dir.getwd()
|
32
|
+
rescue
|
33
|
+
no_cwd_change = true
|
34
|
+
end
|
35
|
+
|
36
|
+
Dir.chdir(File.join(locate_config_value(:vagrant_dir), instance))
|
37
|
+
end
|
38
|
+
|
39
|
+
cmd = "vagrant #{cmd}"
|
40
|
+
output = nil
|
41
|
+
if defined? Bundler
|
42
|
+
# Needed if we are run from inside a bundler environment and vagrant
|
43
|
+
# is installed as global gem. If this causes problems for anyone please
|
44
|
+
# file a bug report.
|
45
|
+
Bundler.with_clean_env do
|
46
|
+
output = fetch_output ? %x(#{cmd}) : system(cmd)
|
47
|
+
end
|
48
|
+
else
|
49
|
+
output = fetch_output ? %x(#{cmd}) : system(cmd)
|
50
|
+
end
|
51
|
+
|
52
|
+
unless no_cwd_change
|
53
|
+
Dir.chdir(cwd)
|
54
|
+
end
|
55
|
+
output
|
56
|
+
end
|
57
|
+
|
58
|
+
def vagrant_instance_state(instance)
|
59
|
+
output = vagrant_exec(instance, 'status', fetch_output: true)
|
60
|
+
state = /Current machine states:.+?default\s+(.+?)\s+\((.+?)\)/m.match(output)
|
61
|
+
unless state
|
62
|
+
ui.warn("Couldn't parse state of instance #{instance}")
|
63
|
+
return ['', '']
|
64
|
+
end
|
65
|
+
return [state[1], state[2]]
|
66
|
+
end
|
67
|
+
|
68
|
+
def vagrant_instance_list
|
69
|
+
# Memoize so we don't have to parse files multiple times
|
70
|
+
if @vagrant_instances
|
71
|
+
return @vagrant_instances
|
72
|
+
end
|
73
|
+
|
74
|
+
vangrant_dir = locate_config_value(:vagrant_dir)
|
75
|
+
@vagrant_instances = []
|
76
|
+
|
77
|
+
unless File.exist? vangrant_dir
|
78
|
+
return @vagrant_instances
|
79
|
+
end
|
80
|
+
|
81
|
+
Dir.foreach(vangrant_dir) { |subdir|
|
82
|
+
vagrant_file = File.join(vangrant_dir, subdir, 'Vagrantfile')
|
83
|
+
if File.exist? vagrant_file
|
84
|
+
instance = { :name => subdir,
|
85
|
+
:vagrant_file => vagrant_file
|
86
|
+
}
|
87
|
+
# Read settings from vagrant file
|
88
|
+
content = IO.read(vagrant_file)
|
89
|
+
instance[:ip_address] = /config\.vm\.network[^,]+,\s*ip:\s*"([0-9\.]+)"/.match(content) { |m| m[1] }
|
90
|
+
unless instance[:ip_address]
|
91
|
+
ui.warn("Couldn't find IP address in #{vagrant_file}. Is it malformed?")
|
92
|
+
end
|
93
|
+
|
94
|
+
instance[:box] = /config\.vm\.box[^=]*=\s*"([^"]+)"/.match(content) { |m| m[1] }
|
95
|
+
unless instance[:box]
|
96
|
+
ui.warn("Couldn't find box in #{vagrant_file}. Is it malformed?")
|
97
|
+
end
|
98
|
+
@vagrant_instances.push(instance)
|
99
|
+
end
|
100
|
+
}
|
101
|
+
@vagrant_instances
|
102
|
+
end
|
103
|
+
|
104
|
+
def write_insecure_key
|
105
|
+
# The private key most vagrant boxes use.
|
106
|
+
insecure_key = <<-EOF
|
107
|
+
-----BEGIN RSA PRIVATE KEY-----
|
108
|
+
MIIEogIBAAKCAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzI
|
109
|
+
w+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoP
|
110
|
+
kcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2
|
111
|
+
hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NO
|
112
|
+
Td0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcW
|
113
|
+
yLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQIBIwKCAQEA4iqWPJXtzZA68mKd
|
114
|
+
ELs4jJsdyky+ewdZeNds5tjcnHU5zUYE25K+ffJED9qUWICcLZDc81TGWjHyAqD1
|
115
|
+
Bw7XpgUwFgeUJwUlzQurAv+/ySnxiwuaGJfhFM1CaQHzfXphgVml+fZUvnJUTvzf
|
116
|
+
TK2Lg6EdbUE9TarUlBf/xPfuEhMSlIE5keb/Zz3/LUlRg8yDqz5w+QWVJ4utnKnK
|
117
|
+
iqwZN0mwpwU7YSyJhlT4YV1F3n4YjLswM5wJs2oqm0jssQu/BT0tyEXNDYBLEF4A
|
118
|
+
sClaWuSJ2kjq7KhrrYXzagqhnSei9ODYFShJu8UWVec3Ihb5ZXlzO6vdNQ1J9Xsf
|
119
|
+
4m+2ywKBgQD6qFxx/Rv9CNN96l/4rb14HKirC2o/orApiHmHDsURs5rUKDx0f9iP
|
120
|
+
cXN7S1uePXuJRK/5hsubaOCx3Owd2u9gD6Oq0CsMkE4CUSiJcYrMANtx54cGH7Rk
|
121
|
+
EjFZxK8xAv1ldELEyxrFqkbE4BKd8QOt414qjvTGyAK+OLD3M2QdCQKBgQDtx8pN
|
122
|
+
CAxR7yhHbIWT1AH66+XWN8bXq7l3RO/ukeaci98JfkbkxURZhtxV/HHuvUhnPLdX
|
123
|
+
3TwygPBYZFNo4pzVEhzWoTtnEtrFueKxyc3+LjZpuo+mBlQ6ORtfgkr9gBVphXZG
|
124
|
+
YEzkCD3lVdl8L4cw9BVpKrJCs1c5taGjDgdInQKBgHm/fVvv96bJxc9x1tffXAcj
|
125
|
+
3OVdUN0UgXNCSaf/3A/phbeBQe9xS+3mpc4r6qvx+iy69mNBeNZ0xOitIjpjBo2+
|
126
|
+
dBEjSBwLk5q5tJqHmy/jKMJL4n9ROlx93XS+njxgibTvU6Fp9w+NOFD/HvxB3Tcz
|
127
|
+
6+jJF85D5BNAG3DBMKBjAoGBAOAxZvgsKN+JuENXsST7F89Tck2iTcQIT8g5rwWC
|
128
|
+
P9Vt74yboe2kDT531w8+egz7nAmRBKNM751U/95P9t88EDacDI/Z2OwnuFQHCPDF
|
129
|
+
llYOUI+SpLJ6/vURRbHSnnn8a/XG+nzedGH5JGqEJNQsz+xT2axM0/W/CRknmGaJ
|
130
|
+
kda/AoGANWrLCz708y7VYgAtW2Uf1DPOIYMdvo6fxIB5i9ZfISgcJ/bbCUkFrhoH
|
131
|
+
+vq/5CIWxCPp0f85R4qxxQ5ihxJ0YDQT9Jpx4TMss4PSavPaBH3RXow5Ohe+bYoQ
|
132
|
+
NE5OgEXk2wVfZczCZpigBKbKZHNYcelXtTt/nP3rsCuGcM4h53s=
|
133
|
+
-----END RSA PRIVATE KEY-----
|
134
|
+
EOF
|
135
|
+
insecure_key
|
136
|
+
|
137
|
+
# Write key to vagrant folder if it's not there yet.
|
138
|
+
key_file = File.join(locate_config_value(:vagrant_dir), 'insecure_key')
|
139
|
+
unless File.exist? key_file
|
140
|
+
ui.msg("Creating #{key_file}")
|
141
|
+
FileUtils.mkdir_p(locate_config_value(:vagrant_dir))
|
142
|
+
File.open(key_file, 'w') { |f| f.write(insecure_key) }
|
143
|
+
File.chmod(0600, key_file)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def locate_config_value(key)
|
148
|
+
key = key.to_sym
|
149
|
+
config[key] || Chef::Config[:knife][key]
|
150
|
+
end
|
151
|
+
|
152
|
+
def msg_pair(label, value, color=:cyan)
|
153
|
+
if value && !value.to_s.empty?
|
154
|
+
puts "#{ui.color(label, color)}: #{value}"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def colored_vagrant_state(state)
|
159
|
+
case state
|
160
|
+
when 'saved','paused','poweroff', 'stuck', 'aborted', 'gurumeditation', 'inaccessible'
|
161
|
+
ui.color(state, :red)
|
162
|
+
when 'saving'
|
163
|
+
ui.color(state, :yellow)
|
164
|
+
else
|
165
|
+
ui.color(state, :green)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'chef/knife/vagrant_base'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
|
6
|
+
class VagrantBoxList < Knife
|
7
|
+
include Knife::VagrantBase
|
8
|
+
banner "knife vagrant box list"
|
9
|
+
def run
|
10
|
+
vagrant_exec('.', 'box list', no_cwd_change: true)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,473 @@
|
|
1
|
+
require 'chef/knife/vagrant_base'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class VagrantServerCreate < Knife
|
6
|
+
|
7
|
+
include Knife::VagrantBase
|
8
|
+
deps do
|
9
|
+
require 'ostruct'
|
10
|
+
require 'ipaddr'
|
11
|
+
require 'chef/knife/bootstrap'
|
12
|
+
Chef::Knife::Bootstrap.load_deps
|
13
|
+
end
|
14
|
+
|
15
|
+
banner "knife vagrant server create (options)"
|
16
|
+
|
17
|
+
option :box,
|
18
|
+
:short => "-b BOX",
|
19
|
+
:long => "--box BOX",
|
20
|
+
:description => "The vagrant box to use for the server",
|
21
|
+
:proc => Proc.new { |b| Chef::Config[:knife][:box] = b }
|
22
|
+
|
23
|
+
option :box_url,
|
24
|
+
:short => '-U URL',
|
25
|
+
:long => '--box-url URL',
|
26
|
+
:description => 'URL of pre-packaged vbox template. Can be a local path or an HTTP URL.',
|
27
|
+
:proc => Proc.new { |b| Chef::Config[:knife][:box_url] = b }
|
28
|
+
|
29
|
+
option :memsize,
|
30
|
+
:short => '-m MEMORY',
|
31
|
+
:long => '--memsize MEMORY',
|
32
|
+
:description => 'Amount of RAM to allocate to provisioned VM, in MB. Defaults to 1024',
|
33
|
+
:proc => Proc.new { |m| Chef::Config[:knife][:memsize] = m },
|
34
|
+
:default => 1024
|
35
|
+
|
36
|
+
option :share_folders,
|
37
|
+
:short => '-F',
|
38
|
+
:long => '--share-folders SHARES',
|
39
|
+
:description => 'Comma separated list of share folders in the form of HOST_PATH::GUEST_PATH',
|
40
|
+
:proc => lambda { |o| o.split(/[\s,]+/) },
|
41
|
+
:default => []
|
42
|
+
|
43
|
+
option :use_cachier,
|
44
|
+
:short => '-C',
|
45
|
+
:long => '--use-cachier',
|
46
|
+
:description => 'Enables VM to use the vagrant-cachier plugin',
|
47
|
+
:boolean => true,
|
48
|
+
:default => false
|
49
|
+
|
50
|
+
option :chef_node_name,
|
51
|
+
:short => "-N NAME",
|
52
|
+
:long => "--node-name NAME",
|
53
|
+
:description => "The Chef node name for your new node"
|
54
|
+
# :proc => Proc.new { |key| Chef::Config[:knife][:chef_node_name] = key }
|
55
|
+
|
56
|
+
option :ssh_user,
|
57
|
+
:short => "-x USERNAME",
|
58
|
+
:long => "--ssh-user USERNAME",
|
59
|
+
:description => "The ssh username",
|
60
|
+
:default => "vagrant"
|
61
|
+
|
62
|
+
option :ssh_password,
|
63
|
+
:short => "-P PASSWORD",
|
64
|
+
:long => "--ssh-password PASSWORD",
|
65
|
+
:description => "The ssh password"
|
66
|
+
|
67
|
+
option :ssh_port,
|
68
|
+
:short => "-p PORT",
|
69
|
+
:long => "--ssh-port PORT",
|
70
|
+
:description => "The ssh port",
|
71
|
+
:default => "22",
|
72
|
+
:proc => Proc.new { |key| Chef::Config[:knife][:ssh_port] = key }
|
73
|
+
|
74
|
+
option :ssh_gateway,
|
75
|
+
:short => "-w GATEWAY",
|
76
|
+
:long => "--ssh-gateway GATEWAY",
|
77
|
+
:description => "The ssh gateway server",
|
78
|
+
:proc => Proc.new { |key| Chef::Config[:knife][:ssh_gateway] = key }
|
79
|
+
|
80
|
+
option :identity_file,
|
81
|
+
:short => "-i IDENTITY_FILE",
|
82
|
+
:long => "--identity-file IDENTITY_FILE",
|
83
|
+
:description => "The SSH identity file used for authentication"
|
84
|
+
|
85
|
+
option :prerelease,
|
86
|
+
:long => "--prerelease",
|
87
|
+
:description => "Install the pre-release chef gems"
|
88
|
+
|
89
|
+
option :bootstrap_version,
|
90
|
+
:long => "--bootstrap-version VERSION",
|
91
|
+
:description => "The version of Chef to install",
|
92
|
+
:proc => Proc.new { |v| Chef::Config[:knife][:bootstrap_version] = v }
|
93
|
+
|
94
|
+
option :distro,
|
95
|
+
:short => "-d DISTRO",
|
96
|
+
:long => "--distro DISTRO",
|
97
|
+
:description => "Bootstrap a distro using a template; default is 'chef-full'",
|
98
|
+
:default => 'chef-full',
|
99
|
+
:proc => Proc.new { |d| Chef::Config[:knife][:distro] = d }
|
100
|
+
|
101
|
+
option :template_file,
|
102
|
+
:long => "--template-file TEMPLATE",
|
103
|
+
:description => "Full path to location of template to use",
|
104
|
+
:proc => Proc.new { |t| Chef::Config[:knife][:template_file] = t },
|
105
|
+
:default => false
|
106
|
+
|
107
|
+
option :run_list,
|
108
|
+
:short => "-r RUN_LIST",
|
109
|
+
:long => "--run-list RUN_LIST",
|
110
|
+
:description => "Comma separated list of roles/recipes to apply",
|
111
|
+
:proc => lambda { |o| o.split(/[\s,]+/) }
|
112
|
+
|
113
|
+
option :secret,
|
114
|
+
:short => "-s SECRET",
|
115
|
+
:long => "--secret ",
|
116
|
+
:description => "The secret key to use to encrypt data bag item values",
|
117
|
+
:proc => lambda { |s| Chef::Config[:knife][:secret] = s }
|
118
|
+
|
119
|
+
option :secret_file,
|
120
|
+
:long => "--secret-file SECRET_FILE",
|
121
|
+
:description => "A file containing the secret key to use to encrypt data bag item values",
|
122
|
+
:proc => lambda { |sf| Chef::Config[:knife][:secret_file] = sf }
|
123
|
+
|
124
|
+
option :json_attributes,
|
125
|
+
:short => "-j JSON",
|
126
|
+
:long => "--json-attributes JSON",
|
127
|
+
:description => "A JSON string to be added to the first run of chef-client",
|
128
|
+
:proc => lambda { |o| JSON.parse(o) }
|
129
|
+
|
130
|
+
option :subnet,
|
131
|
+
:short => "-s SUBNET",
|
132
|
+
:long => "--subnet SUBNET",
|
133
|
+
:description => "Subnet from which to pick instance IP address. Default: 192.168.67/24",
|
134
|
+
:proc => Proc.new { |key| Chef::Config[:knife][:subnet] = key },
|
135
|
+
:default => '192.168.67.0/24'
|
136
|
+
|
137
|
+
option :ip_address,
|
138
|
+
:short => "-I IP-ADDRESS",
|
139
|
+
:long => "--private-ip-address IP-ADDRESS",
|
140
|
+
:description => "Use this IP address for the new instance"
|
141
|
+
# :proc => Proc.new { |ip| Chef::Config[:knife][:ip_address] = ip }
|
142
|
+
|
143
|
+
option :port_forward,
|
144
|
+
:short => '-f PORTS',
|
145
|
+
:long => '--port-forward PORTS',
|
146
|
+
:description => "Comma separated list of HOST:GUEST ports to forward",
|
147
|
+
:proc => lambda { |o| Hash[o.split(/,/).collect { |a| a.split(/:/) }] },
|
148
|
+
:default => {}
|
149
|
+
|
150
|
+
option :host_key_verify,
|
151
|
+
:long => "--[no-]host-key-verify",
|
152
|
+
:description => "Verify host key, enabled by default.",
|
153
|
+
:boolean => true,
|
154
|
+
:default => true
|
155
|
+
|
156
|
+
option :vb_customize,
|
157
|
+
:long => "--vb-customize VBOXMANAGE_COMMANDS",
|
158
|
+
:description => "List of customize options for the virtualbox vagrant provider separated by ::"
|
159
|
+
|
160
|
+
option :vmx_parameters,
|
161
|
+
:long => "--vmx-parameters VMX_PARAMETERS",
|
162
|
+
:description => "List of parameters for the vmware fusion/workstation vagrant provider separated by::"
|
163
|
+
|
164
|
+
option :provider,
|
165
|
+
:long => "--provider Provider",
|
166
|
+
:description => "The vagrant provider to use for the server",
|
167
|
+
:default => 'virtualbox'
|
168
|
+
|
169
|
+
option :inline_config,
|
170
|
+
:long => "--inline_config snippet",
|
171
|
+
:description => "A snippet of configuration to be inserted into the Vagrantfile."
|
172
|
+
|
173
|
+
def run
|
174
|
+
$stdout.sync = true
|
175
|
+
validate!
|
176
|
+
|
177
|
+
@server = create_server_def
|
178
|
+
|
179
|
+
msg_pair("Instance name", @server.name)
|
180
|
+
msg_pair("Instance IP", @server.ip_address)
|
181
|
+
msg_pair("Box", @server.box || @server.box_url)
|
182
|
+
|
183
|
+
if vagrant_instance_list.detect { |i| i[:name] == @server.name }
|
184
|
+
ui.error("Instance #{@server.name} already exists")
|
185
|
+
exit 1
|
186
|
+
end
|
187
|
+
|
188
|
+
# Create Vagrant file for new instance
|
189
|
+
print "\n#{ui.color("Launching instance", :magenta)}\n"
|
190
|
+
write_vagrantfile
|
191
|
+
cmd = "up --provider #{locate_config_value(:provider)}"
|
192
|
+
vagrant_exec(@server.name, cmd)
|
193
|
+
|
194
|
+
write_insecure_key
|
195
|
+
print "\n#{ui.color("Waiting for sshd", :magenta)}"
|
196
|
+
wait_for_sshd(@server.ip_address)
|
197
|
+
|
198
|
+
print "\n#{ui.color("Bootstraping instance", :magenta)}\n"
|
199
|
+
bootstrap_node(@server,@server.ip_address).run
|
200
|
+
|
201
|
+
|
202
|
+
puts "\n"
|
203
|
+
msg_pair("Instance Name", @server.name)
|
204
|
+
msg_pair("Box", @server.box || @server.box_url)
|
205
|
+
msg_pair("IP Address", @server.ip_address)
|
206
|
+
msg_pair("Environment", locate_config_value(:environment) || '_default')
|
207
|
+
msg_pair("Run List", (config[:run_list] || []).join(', '))
|
208
|
+
msg_pair("JSON Attributes", config[:json_attributes]) unless !config[:json_attributes] || config[:json_attributes].empty?
|
209
|
+
end
|
210
|
+
|
211
|
+
def build_port_forwards(ports)
|
212
|
+
ports.collect { |k, v| "config.vm.network :forwarded_port, host: #{k}, guest: #{v}, host_ip: '127.0.0.1'" }.join("\n")
|
213
|
+
end
|
214
|
+
|
215
|
+
def build_vb_customize(customize)
|
216
|
+
customize.split(/::/).collect { |k| "vb.customize [ #{k} ]" }.join("\n") if customize
|
217
|
+
end
|
218
|
+
|
219
|
+
def build_vmx_customize(customize,instance_dir)
|
220
|
+
vmx_params = ""
|
221
|
+
if customize
|
222
|
+
customize.chomp! if customize.end_with?("\n")
|
223
|
+
disks = {}
|
224
|
+
customize.split(/::/).each do |p|
|
225
|
+
kv = p.split('=')
|
226
|
+
k = kv[0].strip
|
227
|
+
v = kv[1].strip
|
228
|
+
if v
|
229
|
+
if k.start_with?('scsi')
|
230
|
+
ss = k.split('.')
|
231
|
+
disks[ss[0]] ||= {}
|
232
|
+
case ss[1]
|
233
|
+
when 'fileName'
|
234
|
+
if v.start_with?('/')
|
235
|
+
disks[ss[0]]['fileName'] = v
|
236
|
+
else
|
237
|
+
v = File.expand_path(v,instance_dir)
|
238
|
+
disks[ss[0]]['fileName'] = v
|
239
|
+
end
|
240
|
+
when 'fileSize'
|
241
|
+
disks[ss[0]]['fileSize'] = v
|
242
|
+
next
|
243
|
+
end
|
244
|
+
end
|
245
|
+
vmx_params += "v.vmx[\"#{k}\"] = \"#{v}\"\n"
|
246
|
+
end
|
247
|
+
end
|
248
|
+
if locate_config_value(:provider).start_with?('vmware')
|
249
|
+
# Create extra disks as unlike virtual box vmware-fusion/workstation
|
250
|
+
# will not create disks automatically based on configuration params
|
251
|
+
disks.each_value do |f|
|
252
|
+
vdiskmgr = %x(which vmware-vdiskmanager)
|
253
|
+
vdiskmgr = "/Applications/VMware Fusion.app/Contents/Library/vmware-vdiskmanager" if vdiskmgr.empty?
|
254
|
+
if File.exist?(vdiskmgr)
|
255
|
+
disk = f['fileName']
|
256
|
+
%x("#{vdiskmgr}" -c -t 0 -s #{f['fileSize']} -a ide #{disk}) unless File.exist?(f['fileName'])
|
257
|
+
unless File.exist?(disk)
|
258
|
+
ui.error("Disk #{disk} could not be created.")
|
259
|
+
exit 1
|
260
|
+
end
|
261
|
+
else
|
262
|
+
ui.error("Unable to determine path to vmware-vdiskmanager to create the requested additional disk.")
|
263
|
+
exit 1
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
vmx_params
|
269
|
+
end
|
270
|
+
|
271
|
+
def build_shares(share_folders)
|
272
|
+
share_folders.collect do |share|
|
273
|
+
host, guest = share.chomp.split "::"
|
274
|
+
"config.vm.synced_folder '#{host}', '#{guest}'"
|
275
|
+
end.join("\n")
|
276
|
+
end
|
277
|
+
|
278
|
+
def write_vagrantfile
|
279
|
+
|
280
|
+
# Create folder and write Vagrant file
|
281
|
+
instance_dir = File.join(locate_config_value(:vagrant_dir), @server.name)
|
282
|
+
FileUtils.mkdir_p(instance_dir)
|
283
|
+
|
284
|
+
additions = []
|
285
|
+
if @server.use_cachier
|
286
|
+
additions << 'config.cache.auto_detect = true' # enable vagarant-cachier
|
287
|
+
end
|
288
|
+
if @server.inline_config
|
289
|
+
additions << @server.inline_config
|
290
|
+
end
|
291
|
+
|
292
|
+
file = <<-EOF
|
293
|
+
Vagrant.configure("2") do |config|
|
294
|
+
config.vm.box = "#{@server.box}"
|
295
|
+
config.vm.box_url = "#{@server.box_url}"
|
296
|
+
config.vm.hostname = "#{@server.name}"
|
297
|
+
|
298
|
+
config.vm.network :private_network, ip: "#{@server.ip_address}"
|
299
|
+
#{build_port_forwards(@server.port_forward)}
|
300
|
+
|
301
|
+
#{build_shares(@server.share_folders)}
|
302
|
+
|
303
|
+
config.vm.provider :virtualbox do |vb|
|
304
|
+
vb.customize [ "modifyvm", :id, "--memory", #{@server.memsize} ]
|
305
|
+
#{build_vb_customize(@server.vb_customize)}
|
306
|
+
end
|
307
|
+
|
308
|
+
config.vm.provider :vmware_fusion do |v|
|
309
|
+
v.vmx["memsize"] = "#{@server.memsize}"
|
310
|
+
#{build_vmx_customize(@server.vmx_parameters,instance_dir)}
|
311
|
+
end
|
312
|
+
|
313
|
+
config.vm.provider :vmware_workstation do |v|
|
314
|
+
v.vmx["memsize"] = "#{@server.memsize}"
|
315
|
+
#{build_vmx_customize(@server.vmx_parameters,instance_dir)}
|
316
|
+
end
|
317
|
+
|
318
|
+
#{additions.join("\n")}
|
319
|
+
end
|
320
|
+
EOF
|
321
|
+
file
|
322
|
+
|
323
|
+
instance_file = File.join(instance_dir, 'Vagrantfile')
|
324
|
+
ui.msg("Creating #{instance_file}")
|
325
|
+
File.open(instance_file, 'w') { |f| f.write(file) }
|
326
|
+
end
|
327
|
+
|
328
|
+
def bootstrap_node(server,ssh_host)
|
329
|
+
bootstrap = Chef::Knife::Bootstrap.new
|
330
|
+
bootstrap.name_args = [ssh_host]
|
331
|
+
bootstrap.config[:ssh_user] = config[:ssh_user]
|
332
|
+
bootstrap.config[:ssh_port] = config[:ssh_port]
|
333
|
+
bootstrap.config[:ssh_gateway] = config[:ssh_gateway]
|
334
|
+
bootstrap.config[:identity_file] = config[:identity_file] || File.join(locate_config_value(:vagrant_dir), 'insecure_key')
|
335
|
+
bootstrap.config[:chef_node_name] = locate_config_value(:chef_node_name) || server.ip
|
336
|
+
bootstrap.config[:distro] = locate_config_value(:distro) || "chef-full"
|
337
|
+
bootstrap.config[:use_sudo] = true unless config[:ssh_user] == 'root'
|
338
|
+
bootstrap.config[:host_key_verify] = config[:host_key_verify]
|
339
|
+
|
340
|
+
bootstrap.config[:run_list] = config[:run_list]
|
341
|
+
bootstrap.config[:prerelease] = config[:prerelease]
|
342
|
+
bootstrap.config[:bootstrap_version] = locate_config_value(:bootstrap_version)
|
343
|
+
bootstrap.config[:distro] = locate_config_value(:distro)
|
344
|
+
bootstrap.config[:template_file] = locate_config_value(:template_file)
|
345
|
+
bootstrap.config[:environment] = locate_config_value(:environment)
|
346
|
+
bootstrap.config[:prerelease] = config[:prerelease]
|
347
|
+
bootstrap.config[:bootstrap_version] = locate_config_value(:bootstrap_version)
|
348
|
+
bootstrap.config[:first_boot_attributes] = locate_config_value(:json_attributes) || {}
|
349
|
+
bootstrap.config[:encrypted_data_bag_secret] = locate_config_value(:encrypted_data_bag_secret)
|
350
|
+
bootstrap.config[:encrypted_data_bag_secret_file] = locate_config_value(:encrypted_data_bag_secret_file)
|
351
|
+
bootstrap.config[:secret] = locate_config_value(:secret)
|
352
|
+
bootstrap.config[:secret_file] = locate_config_value(:secret_file)
|
353
|
+
# Modify global configuration state to ensure hint gets set by
|
354
|
+
# knife-bootstrap
|
355
|
+
Chef::Config[:knife][:hints] ||= {}
|
356
|
+
Chef::Config[:knife][:hints]["vagrant"] ||= {} # Cargo Cult programming FTW?
|
357
|
+
|
358
|
+
msg_pair("SSH User", bootstrap.config[:ssh_user])
|
359
|
+
msg_pair("SSH identity file", bootstrap.config[:identity_file])
|
360
|
+
bootstrap
|
361
|
+
end
|
362
|
+
|
363
|
+
def validate!
|
364
|
+
unless locate_config_value(:box) || locate_config_value(:box_url)
|
365
|
+
ui.error("You need to either specify --box or --box-url")
|
366
|
+
exit 1
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
def find_available_ip
|
371
|
+
subnet = locate_config_value('subnet')
|
372
|
+
IPAddr.new(subnet).to_range().each { |ip|
|
373
|
+
# 192.168.3.0/24 should yield 192.168.3.2 through 192.168.3.254
|
374
|
+
# 192.168.3.1 cannot be used because virtual box uses it for the router
|
375
|
+
mask = IPAddr::IN4MASK ^ ip.instance_variable_get("@mask_addr")
|
376
|
+
unless [0, 1, mask].include? (ip & mask) or vagrant_instance_list.detect { |i| i[:ip_address] == ip.to_s }
|
377
|
+
return ip.to_s
|
378
|
+
end
|
379
|
+
}
|
380
|
+
ui.error("No unused IP address available in subnet #{subnet}")
|
381
|
+
exit 1
|
382
|
+
end
|
383
|
+
|
384
|
+
def create_server_def
|
385
|
+
server_def = {
|
386
|
+
:box => locate_config_value(:box),
|
387
|
+
:box_url => locate_config_value(:box_url),
|
388
|
+
:memsize => locate_config_value(:memsize),
|
389
|
+
:share_folders => config[:share_folders],
|
390
|
+
:port_forward => config[:port_forward],
|
391
|
+
:use_cachier => config[:use_cachier],
|
392
|
+
:vb_customize => locate_config_value(:vb_customize),
|
393
|
+
:vmx_parameters => locate_config_value(:vmx_parameters),
|
394
|
+
:inline_config => config[:inline_config]
|
395
|
+
}
|
396
|
+
|
397
|
+
# Get specified IP address for new instance or pick an unused one from the subnet pool.
|
398
|
+
server_def[:ip_address] = config[:ip_address] || find_available_ip
|
399
|
+
|
400
|
+
collision = vagrant_instance_list.detect { |i| i[:ip_address] == server_def[:ip_address] }
|
401
|
+
if collision
|
402
|
+
ui.error("IP address #{server_def[:ip_address]} already in use by instance #{collision[:name]}")
|
403
|
+
exit 1
|
404
|
+
end
|
405
|
+
|
406
|
+
# Derive name for vagrant instance from chef node name or IP
|
407
|
+
server_def[:name] = locate_config_value(:chef_node_name) || server_def[:ip_address]
|
408
|
+
|
409
|
+
# Turn it into and object like thing
|
410
|
+
OpenStruct.new(server_def)
|
411
|
+
end
|
412
|
+
|
413
|
+
def wait_for_sshd(hostname)
|
414
|
+
config[:ssh_gateway] ? wait_for_tunnelled_sshd(hostname) : wait_for_direct_sshd(hostname, config[:ssh_port])
|
415
|
+
end
|
416
|
+
|
417
|
+
def wait_for_tunnelled_sshd(hostname)
|
418
|
+
print(".")
|
419
|
+
print(".") until tunnel_test_ssh(hostname) {
|
420
|
+
sleep @initial_sleep_delay ||= 2
|
421
|
+
puts("done")
|
422
|
+
}
|
423
|
+
end
|
424
|
+
|
425
|
+
def tunnel_test_ssh(hostname, &block)
|
426
|
+
gw_host, gw_user = config[:ssh_gateway].split('@').reverse
|
427
|
+
gw_host, gw_port = gw_host.split(':')
|
428
|
+
gateway = Net::SSH::Gateway.new(gw_host, gw_user, :port => gw_port || 22)
|
429
|
+
status = false
|
430
|
+
gateway.open(hostname, config[:ssh_port]) do |local_tunnel_port|
|
431
|
+
status = tcp_test_ssh('localhost', local_tunnel_port, &block)
|
432
|
+
end
|
433
|
+
status
|
434
|
+
rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ENETUNREACH, IOError
|
435
|
+
sleep 2
|
436
|
+
false
|
437
|
+
rescue Errno::EPERM, Errno::ETIMEDOUT
|
438
|
+
false
|
439
|
+
end
|
440
|
+
|
441
|
+
def wait_for_direct_sshd(hostname, ssh_port)
|
442
|
+
print(".") until tcp_test_ssh(hostname, ssh_port) {
|
443
|
+
sleep @initial_sleep_delay ||= 2
|
444
|
+
puts("done")
|
445
|
+
}
|
446
|
+
end
|
447
|
+
|
448
|
+
def tcp_test_ssh(hostname, ssh_port)
|
449
|
+
tcp_socket = TCPSocket.new(hostname, ssh_port)
|
450
|
+
readable = IO.select([tcp_socket], nil, nil, 5)
|
451
|
+
if readable
|
452
|
+
Chef::Log.debug("sshd accepting connections on #{hostname}, banner is #{tcp_socket.gets}")
|
453
|
+
yield
|
454
|
+
true
|
455
|
+
else
|
456
|
+
false
|
457
|
+
end
|
458
|
+
rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ENETUNREACH, IOError
|
459
|
+
sleep 2
|
460
|
+
false
|
461
|
+
rescue Errno::EPERM, Errno::ETIMEDOUT
|
462
|
+
false
|
463
|
+
# This happens on some mobile phone networks
|
464
|
+
rescue Errno::ECONNRESET
|
465
|
+
sleep 2
|
466
|
+
false
|
467
|
+
ensure
|
468
|
+
tcp_socket && tcp_socket.close
|
469
|
+
end
|
470
|
+
|
471
|
+
end
|
472
|
+
end
|
473
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'chef/knife/vagrant_base'
|
2
|
+
|
3
|
+
# These two are needed for the '--purge' deletion case
|
4
|
+
require 'chef/node'
|
5
|
+
require 'chef/api_client'
|
6
|
+
|
7
|
+
class Chef
|
8
|
+
class Knife
|
9
|
+
class VagrantServerDelete < Knife
|
10
|
+
|
11
|
+
include Knife::VagrantBase
|
12
|
+
|
13
|
+
banner "knife vagrant server delete SERVER [SERVER] (options)"
|
14
|
+
|
15
|
+
attr_reader :server
|
16
|
+
|
17
|
+
option :purge,
|
18
|
+
:short => "-P",
|
19
|
+
:long => "--purge",
|
20
|
+
:boolean => true,
|
21
|
+
:default => false,
|
22
|
+
:description => "Destroy corresponding node and client on the Chef Server, in addition to destroying the Vagrant node itself."
|
23
|
+
|
24
|
+
# Extracted from Chef::Knife.delete_object, because it has a
|
25
|
+
# confirmation step built in... By specifying the '--purge'
|
26
|
+
# flag (and also explicitly confirming the server destruction!)
|
27
|
+
# the user is already making their intent known. It is not
|
28
|
+
# necessary to make them confirm two more times.
|
29
|
+
def destroy_item(klass, name, type_name)
|
30
|
+
begin
|
31
|
+
object = klass.load(name)
|
32
|
+
object.destroy
|
33
|
+
ui.warn("Deleted #{type_name} #{name}")
|
34
|
+
rescue Net::HTTPServerException
|
35
|
+
ui.warn("Could not find a #{type_name} named #{name} to delete!")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def run
|
40
|
+
|
41
|
+
@name_args.each do |name|
|
42
|
+
instance = vagrant_instance_list.detect { |i| i[:name] == name }
|
43
|
+
unless instance
|
44
|
+
ui.error("No instance named #{name}")
|
45
|
+
next
|
46
|
+
end
|
47
|
+
|
48
|
+
msg_pair("Instance Name", instance[:name])
|
49
|
+
msg_pair("Box", instance[:box])
|
50
|
+
msg_pair("Vagrant File", instance[:vagrant_file])
|
51
|
+
msg_pair("IP Address", instance[:ip_address])
|
52
|
+
|
53
|
+
puts "\n"
|
54
|
+
confirm("Do you really want to delete this instance")
|
55
|
+
|
56
|
+
vagrant_exec(instance[:name], 'destroy -f')
|
57
|
+
instance_dir = File.join(locate_config_value(:vagrant_dir), instance[:name])
|
58
|
+
FileUtils.rm_rf(instance_dir)
|
59
|
+
|
60
|
+
ui.warn("Deleted instance #{instance[:name]}")
|
61
|
+
|
62
|
+
if config[:purge]
|
63
|
+
destroy_item(Chef::Node, instance[:name], "node")
|
64
|
+
destroy_item(Chef::ApiClient, instance[:name], "client")
|
65
|
+
else
|
66
|
+
ui.warn("Corresponding node and client for the #{instance[:name]} instance were not deleted and remain registered with the Chef Server")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'chef/knife/vagrant_base'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class VagrantServerHalt < Knife
|
6
|
+
|
7
|
+
include Knife::VagrantBase
|
8
|
+
|
9
|
+
banner "knife vagrant server halt SERVER [SERVER]"
|
10
|
+
|
11
|
+
def run
|
12
|
+
$stdout.sync = true
|
13
|
+
|
14
|
+
@name_args.each do |instance|
|
15
|
+
unless vagrant_instance_list.detect { |i| i[:name] == instance }
|
16
|
+
ui.error("No instance named #{instance}")
|
17
|
+
next
|
18
|
+
end
|
19
|
+
|
20
|
+
state, provider = vagrant_instance_state(instance)
|
21
|
+
|
22
|
+
unless state == 'running' or state == 'saved'
|
23
|
+
ui.error("Instance #{instance} needs to be running or suspended for halt. Current state is #{colored_vagrant_state(state)}")
|
24
|
+
next
|
25
|
+
end
|
26
|
+
|
27
|
+
vagrant_exec(instance, 'halt')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'chef/knife/vagrant_base'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class VagrantServerList < Knife
|
6
|
+
|
7
|
+
include Knife::VagrantBase
|
8
|
+
|
9
|
+
banner "knife vagrant server list"
|
10
|
+
|
11
|
+
def run
|
12
|
+
$stdout.sync = true
|
13
|
+
|
14
|
+
server_list = [
|
15
|
+
ui.color('Instance Name', :bold),
|
16
|
+
ui.color('IP Address', :bold),
|
17
|
+
ui.color('Box', :bold),
|
18
|
+
ui.color('Provider', :bold),
|
19
|
+
ui.color('State', :bold)
|
20
|
+
].flatten.compact
|
21
|
+
|
22
|
+
output_column_count = server_list.length
|
23
|
+
|
24
|
+
vagrant_instance_list.each do |server|
|
25
|
+
server_list << server[:name]
|
26
|
+
server_list << server[:ip_address]
|
27
|
+
server_list << server[:box]
|
28
|
+
|
29
|
+
state, provider = vagrant_instance_state(server[:name])
|
30
|
+
server_list << provider
|
31
|
+
server_list << colored_vagrant_state(state)
|
32
|
+
end
|
33
|
+
|
34
|
+
puts ui.list(server_list, :uneven_columns_across, output_column_count)
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'chef/knife/vagrant_base'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class VagrantServerResume < Knife
|
6
|
+
|
7
|
+
include Knife::VagrantBase
|
8
|
+
|
9
|
+
banner "knife vagrant server resume SERVER [SERVER]"
|
10
|
+
|
11
|
+
def run
|
12
|
+
$stdout.sync = true
|
13
|
+
|
14
|
+
@name_args.each do |instance|
|
15
|
+
unless vagrant_instance_list.detect { |i| i[:name] == instance }
|
16
|
+
ui.error("No instance named #{instance}")
|
17
|
+
next
|
18
|
+
end
|
19
|
+
|
20
|
+
state, provider = vagrant_instance_state(instance)
|
21
|
+
|
22
|
+
# saved: VirtualBox
|
23
|
+
# suspended: VMWare Fusion
|
24
|
+
unless state == 'saved' or state == 'suspended'
|
25
|
+
ui.error("Instance #{instance} needs to be suspended for resume. Current state is #{colored_vagrant_state(state)}")
|
26
|
+
next
|
27
|
+
end
|
28
|
+
|
29
|
+
vagrant_exec(instance, 'resume')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'chef/knife/vagrant_base'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class VagrantServerSuspend < Knife
|
6
|
+
|
7
|
+
include Knife::VagrantBase
|
8
|
+
|
9
|
+
banner "knife vagrant server suspend SERVER [SERVER]"
|
10
|
+
|
11
|
+
def run
|
12
|
+
$stdout.sync = true
|
13
|
+
|
14
|
+
@name_args.each do |instance|
|
15
|
+
unless vagrant_instance_list.detect { |i| i[:name] == instance }
|
16
|
+
ui.error("No instance named #{instance}")
|
17
|
+
next
|
18
|
+
end
|
19
|
+
|
20
|
+
state, provider = vagrant_instance_state(instance)
|
21
|
+
|
22
|
+
unless state == 'running'
|
23
|
+
ui.error("Instance #{instance} needs to be running for suspend. Current state is #{colored_vagrant_state(state)}")
|
24
|
+
next
|
25
|
+
end
|
26
|
+
|
27
|
+
vagrant_exec(instance, 'suspend')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'chef/knife/vagrant_base'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class VagrantServerUp < Knife
|
6
|
+
|
7
|
+
include Knife::VagrantBase
|
8
|
+
|
9
|
+
banner "knife vagrant server up SERVER [SERVER]"
|
10
|
+
|
11
|
+
def run
|
12
|
+
$stdout.sync = true
|
13
|
+
|
14
|
+
@name_args.each do |instance|
|
15
|
+
unless vagrant_instance_list.detect { |i| i[:name] == instance }
|
16
|
+
ui.error("No instance named #{instance}")
|
17
|
+
next
|
18
|
+
end
|
19
|
+
|
20
|
+
state, provider = vagrant_instance_state(instance)
|
21
|
+
|
22
|
+
unless state == 'poweroff'
|
23
|
+
ui.error("Instance #{instance} needs to be powered off for up. Current state is #{colored_vagrant_state(state)}")
|
24
|
+
next
|
25
|
+
end
|
26
|
+
|
27
|
+
vagrant_exec(instance, 'up')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
metadata
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: knife-vagrant3
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Markus Kern
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-12-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: chef
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.10.10
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.10.10
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: Vagrant support for Chef's knife command
|
42
|
+
email:
|
43
|
+
- chef@mkern.fastmail.fm
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- ".gitignore"
|
49
|
+
- CHANGELOG.md
|
50
|
+
- Gemfile
|
51
|
+
- LICENSE
|
52
|
+
- README.md
|
53
|
+
- Rakefile
|
54
|
+
- knife-vagrant3.gemspec
|
55
|
+
- lib/chef/knife/vagrant_base.rb
|
56
|
+
- lib/chef/knife/vagrant_box.rb
|
57
|
+
- lib/chef/knife/vagrant_server_create.rb
|
58
|
+
- lib/chef/knife/vagrant_server_delete.rb
|
59
|
+
- lib/chef/knife/vagrant_server_halt.rb
|
60
|
+
- lib/chef/knife/vagrant_server_list.rb
|
61
|
+
- lib/chef/knife/vagrant_server_resume.rb
|
62
|
+
- lib/chef/knife/vagrant_server_suspend.rb
|
63
|
+
- lib/chef/knife/vagrant_server_up.rb
|
64
|
+
- lib/knife-vagrant/version.rb
|
65
|
+
homepage: https://github.com/makern/knife-vagrant2
|
66
|
+
licenses:
|
67
|
+
- Apache 2.0
|
68
|
+
metadata: {}
|
69
|
+
post_install_message:
|
70
|
+
rdoc_options: []
|
71
|
+
require_paths:
|
72
|
+
- lib
|
73
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
requirements: []
|
84
|
+
rubyforge_project:
|
85
|
+
rubygems_version: 2.4.3
|
86
|
+
signing_key:
|
87
|
+
specification_version: 4
|
88
|
+
summary: Vagrant support for Chef's knife command
|
89
|
+
test_files: []
|