knife-vagrant2 0.0.5
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 +51 -0
- data/Gemfile +2 -0
- data/LICENSE +13 -0
- data/README.md +48 -0
- data/Rakefile +2 -0
- data/knife-vagrant2.gemspec +21 -0
- data/lib/chef/knife/vagrant_base.rb +165 -0
- data/lib/chef/knife/vagrant_box.rb +15 -0
- data/lib/chef/knife/vagrant_server_create.rb +423 -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: 1ee941f5425873c296f1813ea350eee29f1c1320
|
4
|
+
data.tar.gz: c7254238b04f65993b8fb7de035b0d581ff62c5d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 21875e807264aaeaaeebd2577c3ef99b2ff921b865be5e341dc988f2f7488d37a2bfb505b9d48807a6f6dd0baca3b0e79cf7b222a2a1bc7ccb966de9f8838d99
|
7
|
+
data.tar.gz: 4508b2332c2c063871df1b3ddd376b61883ef495f7ca311868d0680ce5ac233002513f2f3e8e06e31280f82fd4a331a6402e4041f1ba97b5ea783bc84c517c8c
|
data/.gitignore
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# 0.0.5 (2014-12-11)
|
2
|
+
|
3
|
+
## Changes and new features
|
4
|
+
|
5
|
+
* Added --vmx-customize option to pass arbitrary parameters to VMware providers
|
6
|
+
* Added --vagrant-config option to extend Vagrantfile with custom options
|
7
|
+
|
8
|
+
|
9
|
+
## Fixes
|
10
|
+
|
11
|
+
* Fix missing `ostruct` dependency with newer Chef versions
|
12
|
+
* Fix `--distro` default value change in newer Chef versions
|
13
|
+
|
14
|
+
|
15
|
+
# 0.0.4 (2014-03-14)
|
16
|
+
|
17
|
+
## Changes and new features
|
18
|
+
|
19
|
+
* Added --provider option to use vagrant providers other than virtualbox
|
20
|
+
|
21
|
+
|
22
|
+
# 0.0.3 (2014-01-28)
|
23
|
+
|
24
|
+
## Fixes
|
25
|
+
|
26
|
+
* Fixed error when not using --vb-customize option
|
27
|
+
* Removed unneeded dependency on knife-ec2
|
28
|
+
|
29
|
+
|
30
|
+
# 0.0.2 (2013-12-17)
|
31
|
+
|
32
|
+
## Changes and new features
|
33
|
+
|
34
|
+
* BREAKING: --share-folders option now takes HOST_PATH::GUEST_PATH instead of NAME::GUEST_PATH::HOST_PATH
|
35
|
+
* Added --port-forward option to map host ports to VMs
|
36
|
+
* Added --vb-customize option to pass arbitrary VirtualBox options to Vagrant
|
37
|
+
|
38
|
+
|
39
|
+
# 0.0.1 (2013-12-11)
|
40
|
+
|
41
|
+
## Changes and new features
|
42
|
+
|
43
|
+
* Initial release
|
44
|
+
|
45
|
+
|
46
|
+
# Thanks to our contributors
|
47
|
+
|
48
|
+
* [Jāzeps Baško](https://github.com/jbasko)
|
49
|
+
* [Robert J. Berger](https://github.com/rberger)
|
50
|
+
* [xsunsmile](https://github.com/xsunsmile)
|
51
|
+
* [Mevan Samaratunga](https://github.com/mevansam)
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright 2013-2014 Markus Kern
|
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
@@ -0,0 +1,48 @@
|
|
1
|
+
knife-vagrant2
|
2
|
+
==============
|
3
|
+
|
4
|
+
This plugin gives knife the ability to create, bootstrap, and manage Vagrant instances.
|
5
|
+
|
6
|
+
The plugin is a rewrite of the original [knife-vagrant](https://github.com/garrettux/knife-vagrant) but more closely resembles knife-ec2 behaviour. Specifically it does _not_ use Vagrant's built in Chef provisioner and instead relies on knife to bootstrap the VM. It will work nicely with [knife-solo](https://github.com/matschaffer/knife-solo) and doesn't require a Chef server.
|
7
|
+
|
8
|
+
|
9
|
+
Installation
|
10
|
+
------------
|
11
|
+
If you are using bundler, simply add Chef and knife-vagrant2 to your `Gemfile`:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
gem 'chef'
|
15
|
+
gem 'knife-vagrant2'
|
16
|
+
```
|
17
|
+
|
18
|
+
If you are not using bundler, you can install the gem manually:
|
19
|
+
|
20
|
+
$ gem install knife-vagrant2
|
21
|
+
|
22
|
+
|
23
|
+
Usage
|
24
|
+
-----
|
25
|
+
knife-vagrant2 creates a `/vagrant` subfolder in your project which it uses to manage Vagrant files for all the instances you launch. You should add this folder to your `.gitignore` file so it is never checked into version control.
|
26
|
+
|
27
|
+
To launch a new VM use the `server create` command:
|
28
|
+
|
29
|
+
knife vagrant server create --box-url http://files.vagrantup.com/precise32.box -N db -r role[db]
|
30
|
+
|
31
|
+
This will launch a new VM using the `precise32` box, give the node a Chef name of `db` and then use knife to provision the VM with the `db` role.
|
32
|
+
|
33
|
+
If a box is already installed into vagrant use `--box` instead of `--box-url` to reference it.
|
34
|
+
|
35
|
+
By default knife-vagrant2 picks a private IP address from a predefined pool and assigns it to the VM. You can specify the IP pool using `--subnet` or assign a specfic IP with `--private-ip-address`.
|
36
|
+
|
37
|
+
To map folders between host and VM use `--share-folders NAME::GUEST_PATH::HOST_PATH`.
|
38
|
+
|
39
|
+
After a VM has been created its Chef name is used to reference it in future commands. Most commands map directly to the Vagrant ones:
|
40
|
+
|
41
|
+
knife vagrant server suspend SERVER [SERVER]
|
42
|
+
knife vagrant server resume SERVER [SERVER]
|
43
|
+
knife vagrant server halt SERVER [SERVER]
|
44
|
+
knife vagrant server up SERVER [SERVER]
|
45
|
+
knife vagrant server delete SERVER [SERVER] (options)
|
46
|
+
knife vagrant server list
|
47
|
+
|
48
|
+
All commands can be applied to one or more VMs.
|
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-vagrant2'
|
7
|
+
s.version = Knife::Vagrant::VERSION
|
8
|
+
s.authors = ['Markus Kern']
|
9
|
+
s.email = ['makern@users.noreply.github.com']
|
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,165 @@
|
|
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
|
+
cwd = Dir.getwd()
|
28
|
+
Dir.chdir(File.join(locate_config_value(:vagrant_dir), instance))
|
29
|
+
end
|
30
|
+
|
31
|
+
cmd = "vagrant #{cmd}"
|
32
|
+
output = nil
|
33
|
+
if defined? Bundler
|
34
|
+
# Needed if we are run from inside a bundler environment and vagrant
|
35
|
+
# is installed as global gem. If this causes problems for anyone please
|
36
|
+
# file a bug report.
|
37
|
+
Bundler.with_clean_env do
|
38
|
+
output = fetch_output ? %x(#{cmd}) : system(cmd)
|
39
|
+
end
|
40
|
+
else
|
41
|
+
output = fetch_output ? %x(#{cmd}) : system(cmd)
|
42
|
+
end
|
43
|
+
|
44
|
+
unless no_cwd_change
|
45
|
+
Dir.chdir(cwd)
|
46
|
+
end
|
47
|
+
output
|
48
|
+
end
|
49
|
+
|
50
|
+
def vagrant_instance_state(instance)
|
51
|
+
output = vagrant_exec(instance, 'status', fetch_output: true)
|
52
|
+
state = /Current machine states:.+?default\s+(.+?)\s+\((.+?)\)/m.match(output)
|
53
|
+
unless state
|
54
|
+
ui.warn("Couldn't parse state of instance #{instance}")
|
55
|
+
return ['', '']
|
56
|
+
end
|
57
|
+
return [state[1], state[2]]
|
58
|
+
end
|
59
|
+
|
60
|
+
def vagrant_instance_list
|
61
|
+
# Memoize so we don't have to parse files multiple times
|
62
|
+
if @vagrant_instances
|
63
|
+
return @vagrant_instances
|
64
|
+
end
|
65
|
+
|
66
|
+
vangrant_dir = locate_config_value(:vagrant_dir)
|
67
|
+
@vagrant_instances = []
|
68
|
+
|
69
|
+
unless File.exist? vangrant_dir
|
70
|
+
return @vagrant_instances
|
71
|
+
end
|
72
|
+
|
73
|
+
Dir.foreach(vangrant_dir) { |subdir|
|
74
|
+
vagrant_file = File.join(vangrant_dir, subdir, 'Vagrantfile')
|
75
|
+
if File.exist? vagrant_file
|
76
|
+
instance = { :name => subdir,
|
77
|
+
:vagrant_file => vagrant_file
|
78
|
+
}
|
79
|
+
# Read settings from vagrant file
|
80
|
+
content = IO.read(vagrant_file)
|
81
|
+
instance[:ip_address] = /config\.vm\.network[^,]+,\s*ip:\s*"([0-9\.]+)"/.match(content) { |m| m[1] }
|
82
|
+
unless instance[:ip_address]
|
83
|
+
ui.warn("Couldn't find IP address in #{vagrant_file}. Is it malformed?")
|
84
|
+
end
|
85
|
+
|
86
|
+
instance[:box] = /config\.vm\.box[^=]*=\s*"([^"]+)"/.match(content) { |m| m[1] }
|
87
|
+
unless instance[:box]
|
88
|
+
ui.warn("Couldn't find box in #{vagrant_file}. Is it malformed?")
|
89
|
+
end
|
90
|
+
@vagrant_instances.push(instance)
|
91
|
+
end
|
92
|
+
}
|
93
|
+
@vagrant_instances
|
94
|
+
end
|
95
|
+
|
96
|
+
def write_insecure_key
|
97
|
+
# The private key most vagrant boxes use.
|
98
|
+
insecure_key = <<-EOF
|
99
|
+
-----BEGIN RSA PRIVATE KEY-----
|
100
|
+
MIIEogIBAAKCAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzI
|
101
|
+
w+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoP
|
102
|
+
kcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2
|
103
|
+
hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NO
|
104
|
+
Td0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcW
|
105
|
+
yLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQIBIwKCAQEA4iqWPJXtzZA68mKd
|
106
|
+
ELs4jJsdyky+ewdZeNds5tjcnHU5zUYE25K+ffJED9qUWICcLZDc81TGWjHyAqD1
|
107
|
+
Bw7XpgUwFgeUJwUlzQurAv+/ySnxiwuaGJfhFM1CaQHzfXphgVml+fZUvnJUTvzf
|
108
|
+
TK2Lg6EdbUE9TarUlBf/xPfuEhMSlIE5keb/Zz3/LUlRg8yDqz5w+QWVJ4utnKnK
|
109
|
+
iqwZN0mwpwU7YSyJhlT4YV1F3n4YjLswM5wJs2oqm0jssQu/BT0tyEXNDYBLEF4A
|
110
|
+
sClaWuSJ2kjq7KhrrYXzagqhnSei9ODYFShJu8UWVec3Ihb5ZXlzO6vdNQ1J9Xsf
|
111
|
+
4m+2ywKBgQD6qFxx/Rv9CNN96l/4rb14HKirC2o/orApiHmHDsURs5rUKDx0f9iP
|
112
|
+
cXN7S1uePXuJRK/5hsubaOCx3Owd2u9gD6Oq0CsMkE4CUSiJcYrMANtx54cGH7Rk
|
113
|
+
EjFZxK8xAv1ldELEyxrFqkbE4BKd8QOt414qjvTGyAK+OLD3M2QdCQKBgQDtx8pN
|
114
|
+
CAxR7yhHbIWT1AH66+XWN8bXq7l3RO/ukeaci98JfkbkxURZhtxV/HHuvUhnPLdX
|
115
|
+
3TwygPBYZFNo4pzVEhzWoTtnEtrFueKxyc3+LjZpuo+mBlQ6ORtfgkr9gBVphXZG
|
116
|
+
YEzkCD3lVdl8L4cw9BVpKrJCs1c5taGjDgdInQKBgHm/fVvv96bJxc9x1tffXAcj
|
117
|
+
3OVdUN0UgXNCSaf/3A/phbeBQe9xS+3mpc4r6qvx+iy69mNBeNZ0xOitIjpjBo2+
|
118
|
+
dBEjSBwLk5q5tJqHmy/jKMJL4n9ROlx93XS+njxgibTvU6Fp9w+NOFD/HvxB3Tcz
|
119
|
+
6+jJF85D5BNAG3DBMKBjAoGBAOAxZvgsKN+JuENXsST7F89Tck2iTcQIT8g5rwWC
|
120
|
+
P9Vt74yboe2kDT531w8+egz7nAmRBKNM751U/95P9t88EDacDI/Z2OwnuFQHCPDF
|
121
|
+
llYOUI+SpLJ6/vURRbHSnnn8a/XG+nzedGH5JGqEJNQsz+xT2axM0/W/CRknmGaJ
|
122
|
+
kda/AoGANWrLCz708y7VYgAtW2Uf1DPOIYMdvo6fxIB5i9ZfISgcJ/bbCUkFrhoH
|
123
|
+
+vq/5CIWxCPp0f85R4qxxQ5ihxJ0YDQT9Jpx4TMss4PSavPaBH3RXow5Ohe+bYoQ
|
124
|
+
NE5OgEXk2wVfZczCZpigBKbKZHNYcelXtTt/nP3rsCuGcM4h53s=
|
125
|
+
-----END RSA PRIVATE KEY-----
|
126
|
+
EOF
|
127
|
+
insecure_key
|
128
|
+
|
129
|
+
# Write key to vagrant folder if it's not there yet.
|
130
|
+
key_file = File.join(locate_config_value(:vagrant_dir), 'insecure_key')
|
131
|
+
unless File.exist? key_file
|
132
|
+
ui.msg("Creating #{key_file}")
|
133
|
+
FileUtils.mkdir_p(locate_config_value(:vagrant_dir))
|
134
|
+
File.open(key_file, 'w') { |f| f.write(insecure_key) }
|
135
|
+
File.chmod(0600, key_file)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def locate_config_value(key)
|
140
|
+
key = key.to_sym
|
141
|
+
config[key] || Chef::Config[:knife][key]
|
142
|
+
end
|
143
|
+
|
144
|
+
def msg_pair(label, value, color=:cyan)
|
145
|
+
if value && !value.to_s.empty?
|
146
|
+
puts "#{ui.color(label, color)}: #{value}"
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def colored_vagrant_state(state)
|
151
|
+
case state
|
152
|
+
when 'saved','paused','poweroff', 'stuck', 'aborted', 'gurumeditation', 'inaccessible'
|
153
|
+
ui.color(state, :red)
|
154
|
+
when 'saving'
|
155
|
+
ui.color(state, :yellow)
|
156
|
+
else
|
157
|
+
ui.color(state, :green)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
|
@@ -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,423 @@
|
|
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_customize,
|
161
|
+
:long => "--vmx-customize VMX_PARAMETERS",
|
162
|
+
:description => "List of parameters for the vmware vagrant providers 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 :vagrant_config,
|
170
|
+
:long => "--vagrant-config SETTINGS",
|
171
|
+
:description => "Lines of configuration to be inserted into the Vagrantfile separated by ::"
|
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)
|
220
|
+
customize.split(/::/).collect { |k| "v.vmx [ #{k} ]" }.join("\n") if customize
|
221
|
+
end
|
222
|
+
|
223
|
+
def build_shares(share_folders)
|
224
|
+
share_folders.collect do |share|
|
225
|
+
host, guest = share.chomp.split "::"
|
226
|
+
"config.vm.synced_folder '#{host}', '#{guest}'"
|
227
|
+
end.join("\n")
|
228
|
+
end
|
229
|
+
|
230
|
+
def write_vagrantfile
|
231
|
+
additions = []
|
232
|
+
if @server.use_cachier
|
233
|
+
additions << 'config.cache.auto_detect = true' # enable vagarant-cachier
|
234
|
+
end
|
235
|
+
if @server.vagrant_config
|
236
|
+
additions << @server.vagrant_config.split(/::/)
|
237
|
+
end
|
238
|
+
|
239
|
+
file = <<-EOF
|
240
|
+
Vagrant.configure("2") do |config|
|
241
|
+
config.vm.box = "#{@server.box}"
|
242
|
+
config.vm.box_url = "#{@server.box_url}"
|
243
|
+
config.vm.hostname = "#{@server.name}"
|
244
|
+
|
245
|
+
config.vm.network :private_network, ip: "#{@server.ip_address}"
|
246
|
+
#{build_port_forwards(@server.port_forward)}
|
247
|
+
|
248
|
+
#{build_shares(@server.share_folders)}
|
249
|
+
|
250
|
+
config.vm.provider :virtualbox do |vb|
|
251
|
+
vb.customize [ "modifyvm", :id, "--memory", #{@server.memsize} ]
|
252
|
+
#{build_vb_customize(@server.vb_customize)}
|
253
|
+
end
|
254
|
+
|
255
|
+
config.vm.provider :vmware_fusion do |v|
|
256
|
+
v.vmx["memsize"] = "#{@server.memsize}"
|
257
|
+
#{build_vmx_customize(@server.vmx_customize)}
|
258
|
+
end
|
259
|
+
|
260
|
+
config.vm.provider :vmware_workstation do |v|
|
261
|
+
v.vmx["memsize"] = "#{@server.memsize}"
|
262
|
+
#{build_vmx_customize(@server.vmx_customize)}
|
263
|
+
end
|
264
|
+
|
265
|
+
#{additions.join("\n")}
|
266
|
+
end
|
267
|
+
EOF
|
268
|
+
file
|
269
|
+
|
270
|
+
# Create folder and write Vagrant file
|
271
|
+
instance_dir = File.join(locate_config_value(:vagrant_dir), @server.name)
|
272
|
+
instance_file = File.join(instance_dir, 'Vagrantfile')
|
273
|
+
ui.msg("Creating #{instance_file}")
|
274
|
+
FileUtils.mkdir_p(instance_dir)
|
275
|
+
File.open(instance_file, 'w') { |f| f.write(file) }
|
276
|
+
end
|
277
|
+
|
278
|
+
def bootstrap_node(server,ssh_host)
|
279
|
+
bootstrap = Chef::Knife::Bootstrap.new
|
280
|
+
bootstrap.name_args = [ssh_host]
|
281
|
+
bootstrap.config[:ssh_user] = config[:ssh_user]
|
282
|
+
bootstrap.config[:ssh_port] = config[:ssh_port]
|
283
|
+
bootstrap.config[:ssh_gateway] = config[:ssh_gateway]
|
284
|
+
bootstrap.config[:identity_file] = config[:identity_file] || File.join(locate_config_value(:vagrant_dir), 'insecure_key')
|
285
|
+
bootstrap.config[:chef_node_name] = locate_config_value(:chef_node_name) || server.ip
|
286
|
+
bootstrap.config[:distro] = locate_config_value(:distro) || "chef-full"
|
287
|
+
bootstrap.config[:use_sudo] = true unless config[:ssh_user] == 'root'
|
288
|
+
bootstrap.config[:host_key_verify] = config[:host_key_verify]
|
289
|
+
|
290
|
+
bootstrap.config[:run_list] = config[:run_list]
|
291
|
+
bootstrap.config[:prerelease] = config[:prerelease]
|
292
|
+
bootstrap.config[:bootstrap_version] = locate_config_value(:bootstrap_version)
|
293
|
+
bootstrap.config[:distro] = locate_config_value(:distro)
|
294
|
+
bootstrap.config[:template_file] = locate_config_value(:template_file)
|
295
|
+
bootstrap.config[:environment] = locate_config_value(:environment)
|
296
|
+
bootstrap.config[:prerelease] = config[:prerelease]
|
297
|
+
bootstrap.config[:bootstrap_version] = locate_config_value(:bootstrap_version)
|
298
|
+
bootstrap.config[:first_boot_attributes] = locate_config_value(:json_attributes) || {}
|
299
|
+
bootstrap.config[:encrypted_data_bag_secret] = locate_config_value(:encrypted_data_bag_secret)
|
300
|
+
bootstrap.config[:encrypted_data_bag_secret_file] = locate_config_value(:encrypted_data_bag_secret_file)
|
301
|
+
bootstrap.config[:secret] = locate_config_value(:secret)
|
302
|
+
bootstrap.config[:secret_file] = locate_config_value(:secret_file)
|
303
|
+
# Modify global configuration state to ensure hint gets set by
|
304
|
+
# knife-bootstrap
|
305
|
+
Chef::Config[:knife][:hints] ||= {}
|
306
|
+
Chef::Config[:knife][:hints]["vagrant"] ||= {} # Cargo Cult programming FTW?
|
307
|
+
|
308
|
+
msg_pair("SSH User", bootstrap.config[:ssh_user])
|
309
|
+
msg_pair("SSH identity file", bootstrap.config[:identity_file])
|
310
|
+
bootstrap
|
311
|
+
end
|
312
|
+
|
313
|
+
def validate!
|
314
|
+
unless locate_config_value(:box) || locate_config_value(:box_url)
|
315
|
+
ui.error("You need to either specify --box or --box-url")
|
316
|
+
exit 1
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
def find_available_ip
|
321
|
+
subnet = locate_config_value('subnet')
|
322
|
+
IPAddr.new(subnet).to_range().each { |ip|
|
323
|
+
# 192.168.3.0/24 should yield 192.168.3.2 through 192.168.3.254
|
324
|
+
# 192.168.3.1 cannot be used because virtual box uses it for the router
|
325
|
+
mask = IPAddr::IN4MASK ^ ip.instance_variable_get("@mask_addr")
|
326
|
+
unless [0, 1, mask].include? (ip & mask) or vagrant_instance_list.detect { |i| i[:ip_address] == ip.to_s }
|
327
|
+
return ip.to_s
|
328
|
+
end
|
329
|
+
}
|
330
|
+
ui.error("No unused IP address available in subnet #{subnet}")
|
331
|
+
exit 1
|
332
|
+
end
|
333
|
+
|
334
|
+
def create_server_def
|
335
|
+
server_def = {
|
336
|
+
:box => locate_config_value(:box),
|
337
|
+
:box_url => locate_config_value(:box_url),
|
338
|
+
:memsize => locate_config_value(:memsize),
|
339
|
+
:share_folders => config[:share_folders],
|
340
|
+
:port_forward => config[:port_forward],
|
341
|
+
:use_cachier => config[:use_cachier],
|
342
|
+
:vb_customize => locate_config_value(:vb_customize),
|
343
|
+
:vmx_customize => locate_config_value(:vmx_customize),
|
344
|
+
:vagrant_config => locate_config_value(:vagrant_config)
|
345
|
+
}
|
346
|
+
|
347
|
+
# Get specified IP address for new instance or pick an unused one from the subnet pool.
|
348
|
+
server_def[:ip_address] = config[:ip_address] || find_available_ip
|
349
|
+
|
350
|
+
collision = vagrant_instance_list.detect { |i| i[:ip_address] == server_def[:ip_address] }
|
351
|
+
if collision
|
352
|
+
ui.error("IP address #{server_def[:ip_address]} already in use by instance #{collision[:name]}")
|
353
|
+
exit 1
|
354
|
+
end
|
355
|
+
|
356
|
+
# Derive name for vagrant instance from chef node name or IP
|
357
|
+
server_def[:name] = locate_config_value(:chef_node_name) || server_def[:ip_address]
|
358
|
+
|
359
|
+
# Turn it into and object like thing
|
360
|
+
OpenStruct.new(server_def)
|
361
|
+
end
|
362
|
+
|
363
|
+
def wait_for_sshd(hostname)
|
364
|
+
config[:ssh_gateway] ? wait_for_tunnelled_sshd(hostname) : wait_for_direct_sshd(hostname, config[:ssh_port])
|
365
|
+
end
|
366
|
+
|
367
|
+
def wait_for_tunnelled_sshd(hostname)
|
368
|
+
print(".")
|
369
|
+
print(".") until tunnel_test_ssh(hostname) {
|
370
|
+
sleep @initial_sleep_delay ||= 2
|
371
|
+
puts("done")
|
372
|
+
}
|
373
|
+
end
|
374
|
+
|
375
|
+
def tunnel_test_ssh(hostname, &block)
|
376
|
+
gw_host, gw_user = config[:ssh_gateway].split('@').reverse
|
377
|
+
gw_host, gw_port = gw_host.split(':')
|
378
|
+
gateway = Net::SSH::Gateway.new(gw_host, gw_user, :port => gw_port || 22)
|
379
|
+
status = false
|
380
|
+
gateway.open(hostname, config[:ssh_port]) do |local_tunnel_port|
|
381
|
+
status = tcp_test_ssh('localhost', local_tunnel_port, &block)
|
382
|
+
end
|
383
|
+
status
|
384
|
+
rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ENETUNREACH, IOError
|
385
|
+
sleep 2
|
386
|
+
false
|
387
|
+
rescue Errno::EPERM, Errno::ETIMEDOUT
|
388
|
+
false
|
389
|
+
end
|
390
|
+
|
391
|
+
def wait_for_direct_sshd(hostname, ssh_port)
|
392
|
+
print(".") until tcp_test_ssh(hostname, ssh_port) {
|
393
|
+
sleep @initial_sleep_delay ||= 2
|
394
|
+
puts("done")
|
395
|
+
}
|
396
|
+
end
|
397
|
+
|
398
|
+
def tcp_test_ssh(hostname, ssh_port)
|
399
|
+
tcp_socket = TCPSocket.new(hostname, ssh_port)
|
400
|
+
readable = IO.select([tcp_socket], nil, nil, 5)
|
401
|
+
if readable
|
402
|
+
Chef::Log.debug("sshd accepting connections on #{hostname}, banner is #{tcp_socket.gets}")
|
403
|
+
yield
|
404
|
+
true
|
405
|
+
else
|
406
|
+
false
|
407
|
+
end
|
408
|
+
rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ENETUNREACH, IOError
|
409
|
+
sleep 2
|
410
|
+
false
|
411
|
+
rescue Errno::EPERM, Errno::ETIMEDOUT
|
412
|
+
false
|
413
|
+
# This happens on some mobile phone networks
|
414
|
+
rescue Errno::ECONNRESET
|
415
|
+
sleep 2
|
416
|
+
false
|
417
|
+
ensure
|
418
|
+
tcp_socket && tcp_socket.close
|
419
|
+
end
|
420
|
+
|
421
|
+
end
|
422
|
+
end
|
423
|
+
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-vagrant2
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.5
|
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
|
+
- makern@users.noreply.github.com
|
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-vagrant2.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.2.2
|
86
|
+
signing_key:
|
87
|
+
specification_version: 4
|
88
|
+
summary: Vagrant support for Chef's knife command
|
89
|
+
test_files: []
|