hazetug 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +58 -4
- data/examples/bootstrap-client.erb +82 -0
- data/examples/bootstrap-solo.erb +64 -0
- data/hazetug.gemspec +9 -8
- data/lib/hazetug/cli/bootstrap.rb +10 -7
- data/lib/hazetug/cli.rb +38 -33
- data/lib/hazetug/haze/cloud_server.rb +2 -1
- data/lib/hazetug/haze/linode.rb +1 -1
- data/lib/hazetug/haze.rb +13 -1
- data/lib/hazetug/tug/knife.rb +11 -89
- data/lib/hazetug/tug/knife_base.rb +164 -0
- data/lib/hazetug/tug/solo.rb +90 -0
- data/lib/hazetug/tug.rb +18 -29
- data/lib/hazetug/version.rb +1 -1
- metadata +38 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ebdf9a9772962644f814c2215eb1a788e935a317
|
4
|
+
data.tar.gz: 5886036f41c10cc8a7efb87dbce4a3bc21c20d31
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fbf02d130984ad264c559f943be0b146e84a92ab5999d0390eafab9ff03de631cadf5cf367856c4d1fbb484bb0c547700ece2b5d8c2eeb81706002207acbd5fe
|
7
|
+
data.tar.gz: 5ba4e8ff097d31ec9d3e5685ce3a0bf9c6a8165e65bdb45ecef0f6dc1deb92dd46430e0af17e89bcf1e5bc8ed9e3dddb459570279d2e533f4eeab3fda1e825af
|
data/README.md
CHANGED
@@ -3,7 +3,8 @@
|
|
3
3
|
Cloud provisioner and bootstrapper for DigitalOcean and Linode.
|
4
4
|
Hazetug uses [fog cloud library](http://fog.io) to be able to easily append other cloud computes and *tugs* (bootstraps) hosts using:
|
5
5
|
|
6
|
-
* Knife bootstrap.
|
6
|
+
* Knife bootstrap for chef-client.
|
7
|
+
* Knife bootstrap for chef-solo.
|
7
8
|
|
8
9
|
## Options
|
9
10
|
|
@@ -64,8 +65,6 @@ Hazetug uses [fog cloud library](http://fog.io) to be able to easily append othe
|
|
64
65
|
|
65
66
|
## Knife tug
|
66
67
|
|
67
|
-
### Knife tug bootstrap options
|
68
|
-
|
69
68
|
<table>
|
70
69
|
<tr>
|
71
70
|
<td><b>Option</b></td>
|
@@ -89,6 +88,27 @@ Hazetug uses [fog cloud library](http://fog.io) to be able to easily append othe
|
|
89
88
|
</tr>
|
90
89
|
</table>
|
91
90
|
|
91
|
+
## Solo tug
|
92
|
+
|
93
|
+
<table>
|
94
|
+
<tr>
|
95
|
+
<td><b>Option</b></td>
|
96
|
+
<td><b>Description</b></td>
|
97
|
+
<td><b>Default value</b></td>
|
98
|
+
</tr>
|
99
|
+
<tr>
|
100
|
+
<td><b><i>attributes_json</i></b></td>
|
101
|
+
<td>Hash of attributes prepared for chef-solo run. (It's merged with the run_list).</td>
|
102
|
+
<td><i>{}</i><td>
|
103
|
+
</tr>
|
104
|
+
<tr>
|
105
|
+
<td><b><i>berksfile</i></b></td>
|
106
|
+
<td>Path to Berksfile.</td>
|
107
|
+
<td></td>
|
108
|
+
</tr>
|
109
|
+
</table>
|
110
|
+
|
111
|
+
|
92
112
|
## Installation
|
93
113
|
|
94
114
|
Add this line to your application's Gemfile:
|
@@ -151,7 +171,7 @@ All variables are merged using this 3-level priority.
|
|
151
171
|
|
152
172
|
### Bootstrap using knife
|
153
173
|
|
154
|
-
Help for linode compute is given bellow:
|
174
|
+
Help for the linode compute is given bellow:
|
155
175
|
|
156
176
|
```
|
157
177
|
NAME
|
@@ -169,6 +189,40 @@ COMMAND OPTIONS
|
|
169
189
|
|
170
190
|
All variables are passed to the bootstrap template and are available using the hazetug hash like - `hazetug[:variable_name]`. Amongst variables described here in the options sections, hazetug also passes useful variables such as ***compute_name***, ***public_ip_address***, ***private_ip_address*** if those are available.
|
171
191
|
|
192
|
+
#### Client and Solo modes
|
193
|
+
|
194
|
+
It's possible to use *chef-client* or *chef-solo* to bootstrap a node. The **solo** mode is almost identical with the **client** mode, but with the only difference that it uses **berkshelf** to assist during the bootstrap process. Cookbooks are packaged and uploaded to the remote node and can be used by chef
|
195
|
+
|
196
|
+
You can initiate bootstrap in the solo mode, like the following:
|
197
|
+
<pre>
|
198
|
+
hazetug digitalocean bootstrap solo -b bootstrap.erb solo-task.yaml
|
199
|
+
</pre>
|
200
|
+
|
201
|
+
Solo bootstrap also uses bootstrap.erb, but there's no need to start client or use any data like **validation_key** or **start_chef** helper.
|
202
|
+
|
203
|
+
When defining a task, there additional options **berksfile** and **attributes**
|
204
|
+
|
205
|
+
```yaml
|
206
|
+
...
|
207
|
+
...
|
208
|
+
bootstrap:
|
209
|
+
- name: solo-box
|
210
|
+
location: london
|
211
|
+
flavor: 1gb
|
212
|
+
image: ubuntu-14.04-x64
|
213
|
+
run_list: ["role[api]"]
|
214
|
+
attributes: {
|
215
|
+
"mycookbook": {
|
216
|
+
"settings": {}
|
217
|
+
}
|
218
|
+
}
|
219
|
+
```
|
220
|
+
```
|
221
|
+
|
222
|
+
Merged *attributes* with the *run_list* form the input data for running **chef-solo** they are available inside bootstrap.erb as `hazetug[:attributes_json]`. Berksfile can be set specifically in the bootstrap task list or if it's not set local *Berksfile* is tried by default.
|
223
|
+
|
224
|
+
Another important option which is also available in the *bootstrap.erb* file is `hazetug[:cookbooks_path]` which is path to an archive of cookbooks packaged by Berkshelf.
|
225
|
+
|
172
226
|
#### Examples
|
173
227
|
|
174
228
|
* Provisioning and bootstrapping 5 nodes, each 3 of them will be processed simultaneously:
|
@@ -0,0 +1,82 @@
|
|
1
|
+
<% require 'json' -%>
|
2
|
+
bash -c '
|
3
|
+
|
4
|
+
mkdir -p /etc/chef
|
5
|
+
|
6
|
+
cat > /etc/chef/validation.pem <<'EOP'
|
7
|
+
<%= validation_key %>
|
8
|
+
EOP
|
9
|
+
|
10
|
+
chmod 0600 /etc/chef/validation.pem
|
11
|
+
|
12
|
+
cat > /etc/chef/client.rb <<'EOP'
|
13
|
+
<%= config_content %>
|
14
|
+
EOP
|
15
|
+
|
16
|
+
cat > /etc/chef/first-boot.json <<'EOP'
|
17
|
+
{
|
18
|
+
"run_list": <%= (["role[bootstrap]"] + (hazetug[:bootstrap_list] || [])).to_json %>,
|
19
|
+
"bootstrap": {
|
20
|
+
"set_run_list": <%= (hazetug[:run_list] || []).to_json %>,
|
21
|
+
"set_environment": "<%= hazetug[:chef_environment] %>"
|
22
|
+
}
|
23
|
+
}
|
24
|
+
EOP
|
25
|
+
|
26
|
+
# --------------- Update ubuntu and Install packages
|
27
|
+
|
28
|
+
export DEBIAN_FRONTEND=noninteractive
|
29
|
+
apt-get update && apt-get upgrade -yq
|
30
|
+
apt-get clean
|
31
|
+
apt-get autoremove -yq
|
32
|
+
|
33
|
+
apt-get -yq install curl build-essential
|
34
|
+
|
35
|
+
|
36
|
+
# --------------- Set hostname
|
37
|
+
|
38
|
+
HOSTNAME="<%= hazetug[:name] %>"
|
39
|
+
echo "${HOSTNAME}" > /etc/hostname
|
40
|
+
ip=`/sbin/ifconfig eth0 | grep "\<inet\>" | cut -d ":" -f2 | cut -d " " -f1`
|
41
|
+
echo -e "\n# our own entry\n${ip} ${HOSTNAME} ${HOSTNAME%%.*}" >> /etc/hosts
|
42
|
+
cp /etc/hosts /tmp/hosts.orig
|
43
|
+
cat /tmp/hosts.orig | sed "s/127.0.0.1.*/127.0.0.1 localhost localhost.localdomain/" > /etc/hosts
|
44
|
+
rm /tmp/hosts.orig
|
45
|
+
hostname -F /etc/hostname
|
46
|
+
|
47
|
+
# --------------- Set private network on Linode
|
48
|
+
|
49
|
+
if [ "<%= hazetug[:compute_name] %>" = "linode" ]; then
|
50
|
+
|
51
|
+
cat >> /etc/network/interfaces <<'EOP'
|
52
|
+
|
53
|
+
auto eth0:0
|
54
|
+
iface eth0:0 inet static
|
55
|
+
address <%= hazetug[:private_ip_address] %>
|
56
|
+
netmask 255.255.128.0
|
57
|
+
EOP
|
58
|
+
ifup eth0:0
|
59
|
+
|
60
|
+
fi
|
61
|
+
|
62
|
+
|
63
|
+
# --------------- Install Chef
|
64
|
+
|
65
|
+
curl -L https://get.rvm.io | bash -s <%= hazetug[:rvm_version] || 'stable' %>
|
66
|
+
source /etc/profile.d/rvm.sh
|
67
|
+
|
68
|
+
rvm install <%= hazetug[:ruby_version] || "ruby-2.1.2" %> --autolibs=3
|
69
|
+
rvm use <%= hazetug[:ruby_version] || "ruby-2.1.2" %> --default
|
70
|
+
|
71
|
+
cat >/tmp/chef_gemfile<<EOF
|
72
|
+
source "http://rubygems.org"
|
73
|
+
gem "chef", "<%= hazetug[:chef_version] || "11.14.6" %>"
|
74
|
+
EOF
|
75
|
+
|
76
|
+
bundle install --gemfile /tmp/chef_gemfile
|
77
|
+
rm /tmp/chef_gemfile
|
78
|
+
|
79
|
+
# --------------- Start Chef (bootstrap run)
|
80
|
+
|
81
|
+
echo "<%= start_chef %>"
|
82
|
+
<%= start_chef %>'
|
@@ -0,0 +1,64 @@
|
|
1
|
+
<% require 'json' -%>
|
2
|
+
bash -c '
|
3
|
+
|
4
|
+
mkdir -p /etc/chef
|
5
|
+
|
6
|
+
cat > /etc/chef/first-boot.json <<'EOP'
|
7
|
+
<%= hazetug[:attributes_json] %>
|
8
|
+
EOP
|
9
|
+
|
10
|
+
# --------------- Update ubuntu and Install packages
|
11
|
+
|
12
|
+
export DEBIAN_FRONTEND=noninteractive
|
13
|
+
apt-get update && apt-get upgrade -yq
|
14
|
+
apt-get clean
|
15
|
+
apt-get autoremove -yq
|
16
|
+
|
17
|
+
apt-get -yq install curl build-essential
|
18
|
+
|
19
|
+
|
20
|
+
# --------------- Set hostname
|
21
|
+
|
22
|
+
HOSTNAME="<%= hazetug[:name] %>"
|
23
|
+
echo "${HOSTNAME}" > /etc/hostname
|
24
|
+
ip=`/sbin/ifconfig eth0 | grep "\<inet\>" | cut -d ":" -f2 | cut -d " " -f1`
|
25
|
+
echo -e "\n# our own entry\n${ip} ${HOSTNAME} ${HOSTNAME%%.*}" >> /etc/hosts
|
26
|
+
cp /etc/hosts /tmp/hosts.orig
|
27
|
+
cat /tmp/hosts.orig | sed "s/127.0.0.1.*/127.0.0.1 localhost localhost.localdomain/" > /etc/hosts
|
28
|
+
rm /tmp/hosts.orig
|
29
|
+
hostname -F /etc/hostname
|
30
|
+
|
31
|
+
# --------------- Set private network on Linode
|
32
|
+
|
33
|
+
if [ "<%= hazetug[:compute_name] %>" = "linode" ]; then
|
34
|
+
|
35
|
+
cat >> /etc/network/interfaces <<'EOP'
|
36
|
+
|
37
|
+
auto eth0:0
|
38
|
+
iface eth0:0 inet static
|
39
|
+
address <%= hazetug[:private_ip_address] %>
|
40
|
+
netmask 255.255.128.0
|
41
|
+
EOP
|
42
|
+
ifup eth0:0
|
43
|
+
|
44
|
+
fi
|
45
|
+
|
46
|
+
# --------------- Install Chef
|
47
|
+
|
48
|
+
curl -L https://get.rvm.io | bash -s <%= hazetug[:rvm_version] || 'stable' %>
|
49
|
+
source /etc/profile.d/rvm.sh
|
50
|
+
|
51
|
+
rvm install <%= hazetug[:ruby_version] || "ruby-2.1.2" %> --autolibs=3
|
52
|
+
rvm use <%= hazetug[:ruby_version] || "ruby-2.1.2" %> --default
|
53
|
+
|
54
|
+
cat >/tmp/chef_gemfile<<EOF
|
55
|
+
source "http://rubygems.org"
|
56
|
+
gem "chef", "<%= hazetug[:chef_version] || "11.14.6" %>"
|
57
|
+
EOF
|
58
|
+
|
59
|
+
bundle install --gemfile /tmp/chef_gemfile
|
60
|
+
rm /tmp/chef_gemfile /tmp/chef_gemfile.lock
|
61
|
+
|
62
|
+
# --------------- Start Chef in solo mode
|
63
|
+
|
64
|
+
chef-solo -j /etc/chef/first-boot.json -r <%= hazetug[:cookbooks_file] %>'
|
data/hazetug.gemspec
CHANGED
@@ -7,9 +7,9 @@ Gem::Specification.new do |spec|
|
|
7
7
|
spec.name = "hazetug"
|
8
8
|
spec.version = Hazetug::VERSION
|
9
9
|
spec.authors = ["Denis Barishev"]
|
10
|
-
spec.email = ["
|
10
|
+
spec.email = ["dennybaa@gmail.com"]
|
11
11
|
spec.summary = %q{Cloud provisoner tool}
|
12
|
-
spec.description = %q{
|
12
|
+
spec.description = %q{Provisions and bootstraps nodes using knife}
|
13
13
|
spec.homepage = "https://github.com/dennybaa/hazetug"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
@@ -19,10 +19,11 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
21
|
spec.add_development_dependency "bundler", "~> 1.5"
|
22
|
-
spec.add_development_dependency "rake"
|
23
|
-
spec.add_dependency "psych"
|
24
|
-
spec.add_dependency "fog"
|
25
|
-
spec.add_dependency "chef", "
|
26
|
-
spec.add_dependency "gli"
|
27
|
-
spec.add_dependency "agent"
|
22
|
+
spec.add_development_dependency "rake", "~> 0"
|
23
|
+
spec.add_dependency "psych", "~> 0"
|
24
|
+
spec.add_dependency "fog", "~> 0"
|
25
|
+
spec.add_dependency "chef", "~> 11.0"
|
26
|
+
spec.add_dependency "gli", "~> 2.0"
|
27
|
+
spec.add_dependency "agent", "~> 0"
|
28
|
+
spec.add_dependency "berkshelf", "~> 3.0"
|
28
29
|
end
|
@@ -3,7 +3,6 @@ require 'hazetug/cli/action'
|
|
3
3
|
require 'hazetug/tug'
|
4
4
|
require 'hazetug/task'
|
5
5
|
|
6
|
-
|
7
6
|
class Hazetug
|
8
7
|
class CLI
|
9
8
|
class Bootstrap < Action
|
@@ -26,11 +25,15 @@ class Hazetug
|
|
26
25
|
|
27
26
|
def provision_and_bootstrap(haze, tug, channel, waitgroup)
|
28
27
|
haze.provision
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
28
|
+
if haze.ready?
|
29
|
+
tug.load_haze_config(haze.config_for_tug)
|
30
|
+
|
31
|
+
tug.bootstrap({
|
32
|
+
args: data[:args],
|
33
|
+
opts: data[:opts],
|
34
|
+
gopts: data[:gopts]
|
35
|
+
})
|
36
|
+
end
|
34
37
|
rescue
|
35
38
|
# Exeception will be lost, since we run inside goproc,
|
36
39
|
# ie. as soon as waitgroup is empty all process exit.
|
@@ -62,7 +65,7 @@ class Hazetug
|
|
62
65
|
newconf[:ssh_password] = haze.config[:ssh_password]
|
63
66
|
end
|
64
67
|
|
65
|
-
tug = Hazetug::Tug[data[:tug_name]].new(newconf
|
68
|
+
tug = Hazetug::Tug[data[:tug_name]].new(newconf)
|
66
69
|
block.call(haze, tug)
|
67
70
|
end
|
68
71
|
end
|
data/lib/hazetug/cli.rb
CHANGED
@@ -29,40 +29,45 @@ class Hazetug
|
|
29
29
|
compute_cmd.desc 'Provisions and bootstraps server'
|
30
30
|
compute_cmd.command :bootstrap do |op|
|
31
31
|
|
32
|
-
op.
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
32
|
+
op.flag [:v, :variables], :must_match => Array,
|
33
|
+
:desc => 'Set variable or comma-seperated list of variables (var1_1=hello)'
|
34
|
+
|
35
|
+
op.flag [:n, :number], :default_value => 1,
|
36
|
+
:desc => 'Set number of created nodes, value from yaml is honored'
|
37
|
+
|
38
|
+
op.flag [:c, :concurrency], :default_value => 1,
|
39
|
+
:desc => 'Set concurrency value, i.e. number of hosts bootstraped simultaneously'
|
40
|
+
|
41
|
+
op.flag [:b, :bootstrap], :default_value => 'bootstrap.erb',
|
42
|
+
:desc => "Set path to knife bootstrap.erb file"
|
43
|
+
|
44
|
+
[:knife, :solo].each do |tug_cmd|
|
45
|
+
mode = "#{tug_cmd == :knife ? 'client' : 'solo'}"
|
46
|
+
|
47
|
+
|
48
|
+
op.desc "Bootstraps server using Knife in #{mode} mode"
|
49
|
+
op.arg_name '<task.yaml>'
|
50
|
+
op.command tug_cmd do |tug|
|
51
|
+
|
52
|
+
tug.action do |gopts, opts, args|
|
53
|
+
|
54
|
+
if args.empty?
|
55
|
+
commands[:help].execute({},{},tug.name_for_help)
|
56
|
+
exit 0
|
57
|
+
end
|
58
|
+
|
59
|
+
act = CLI::Action[:bootstrap].new
|
60
|
+
act.pass(
|
61
|
+
tug_name: tug_cmd,
|
62
|
+
compute_name: compute,
|
63
|
+
cli: tug,
|
64
|
+
gopts: gopts,
|
65
|
+
opts: opts,
|
66
|
+
args: args
|
67
|
+
).execute
|
54
68
|
end
|
55
|
-
|
56
|
-
act = CLI::Action[:bootstrap].new
|
57
|
-
act.pass(
|
58
|
-
tug_name: :knife,
|
59
|
-
compute_name: compute,
|
60
|
-
cli: tug,
|
61
|
-
gopts: gopts,
|
62
|
-
opts: opts,
|
63
|
-
args: args
|
64
|
-
).execute
|
65
69
|
end
|
70
|
+
|
66
71
|
end
|
67
72
|
|
68
73
|
end
|
@@ -72,4 +77,4 @@ class Hazetug
|
|
72
77
|
end
|
73
78
|
|
74
79
|
end
|
75
|
-
end
|
80
|
+
end
|
@@ -15,11 +15,12 @@ class Hazetug
|
|
15
15
|
ssh_options[:password] = ssh_opts[:ssh_password]
|
16
16
|
ssh_options[:paranoid] = ssh_opts[:host_key_verify] || false
|
17
17
|
ssh_options[:keys] = ssh_opts[:ssh_keys] || Hazetug.ssh_keys(compute_name)
|
18
|
-
server.username = ssh_opts[:ssh_user]
|
18
|
+
server.username = ssh_opts[:ssh_user] || 'root'
|
19
19
|
server.ssh_port = ssh_opts[:ssh_port]
|
20
20
|
server.ssh_options = ssh_options
|
21
21
|
ui.info "[#{compute_name}] waiting for active ssh on #{server.ssh_ip_address}"
|
22
22
|
server.wait_for(30) { sshable? }
|
23
|
+
@ready = true
|
23
24
|
rescue Fog::Errors::TimeoutError
|
24
25
|
ui.error "[#{compute_name}] ssh failed to #{config[:name]}, ip: #{server.ssh_ip_address}"
|
25
26
|
end
|
data/lib/hazetug/haze/linode.rb
CHANGED
@@ -20,7 +20,7 @@ class Hazetug
|
|
20
20
|
latest = /^Latest #{config[:bits]} bit/
|
21
21
|
{
|
22
22
|
# linode node name can't contain dots
|
23
|
-
:name => config[:name].gsub(
|
23
|
+
:name => config[:name].gsub(/\./,'-'),
|
24
24
|
:data_center => lookup(:location),
|
25
25
|
:flavor => lookup(:flavor),
|
26
26
|
:image => lookup(:image),
|
data/lib/hazetug/haze.rb
CHANGED
@@ -16,7 +16,7 @@ class Hazetug
|
|
16
16
|
@compute = Hazetug::Compute.const_get(compute_name).new
|
17
17
|
@config = configure(config)
|
18
18
|
@server = nil
|
19
|
-
@
|
19
|
+
@ready = false
|
20
20
|
end
|
21
21
|
|
22
22
|
def provision
|
@@ -28,6 +28,10 @@ class Hazetug
|
|
28
28
|
exit(1)
|
29
29
|
end
|
30
30
|
|
31
|
+
def ready?
|
32
|
+
@ready
|
33
|
+
end
|
34
|
+
|
31
35
|
def configure(config)
|
32
36
|
input = config.keys.map(&:to_sym)
|
33
37
|
requires = self.class.requires
|
@@ -67,6 +71,14 @@ class Hazetug
|
|
67
71
|
def private_ip_address
|
68
72
|
end
|
69
73
|
|
74
|
+
def config_for_tug
|
75
|
+
{
|
76
|
+
compute_name: compute_name.downcase,
|
77
|
+
public_ip_address: (public_ip_address || server.ssh_ip_address rescue nil),
|
78
|
+
private_ip_address: private_ip_address
|
79
|
+
}
|
80
|
+
end
|
81
|
+
|
70
82
|
protected
|
71
83
|
|
72
84
|
def provision_server
|
data/lib/hazetug/tug/knife.rb
CHANGED
@@ -1,104 +1,26 @@
|
|
1
1
|
require 'chef/knife/ssh'
|
2
2
|
require 'chef/knife/bootstrap'
|
3
|
-
require 'hazetug/tug'
|
4
|
-
|
5
|
-
# Monkey Patch:)
|
6
|
-
# Extend knife bootstrap context with our data
|
7
|
-
class Chef::Knife::Core::BootstrapContext
|
8
|
-
def hazetug; @config[:hazetug]; end
|
9
|
-
end
|
10
|
-
|
11
|
-
class Chef::Knife::Ssh < Chef::Knife
|
12
|
-
def run
|
13
|
-
extend Chef::Mixin::Command
|
14
|
-
@longest = 0
|
15
|
-
configure_attribute
|
16
|
-
configure_user
|
17
|
-
configure_password
|
18
|
-
configure_identity_file
|
19
|
-
configure_gateway
|
20
|
-
configure_session
|
21
|
-
exit_status = ssh_command(@name_args[1..-1].join(" "))
|
22
|
-
session.close
|
23
|
-
|
24
|
-
exit_status
|
25
|
-
end
|
26
|
-
end
|
3
|
+
require 'hazetug/tug/knife_base'
|
27
4
|
|
28
5
|
class Hazetug
|
29
6
|
class Tug
|
30
|
-
class Knife <
|
7
|
+
class Knife < KnifeBase
|
31
8
|
|
32
|
-
def
|
33
|
-
|
34
|
-
|
35
|
-
:identity_file,
|
36
|
-
:ssh_user,
|
37
|
-
:ssh_password,
|
38
|
-
:host_key_verify
|
39
|
-
].each do |opt|
|
40
|
-
kb.config[opt] = bootstrap_options[opt]
|
41
|
-
end
|
42
|
-
[
|
9
|
+
def initialize(config={}, haze=nil)
|
10
|
+
super
|
11
|
+
@chef_option_list = [
|
43
12
|
:environment,
|
44
13
|
:chef_server_url,
|
45
14
|
:validation_key
|
46
|
-
]
|
47
|
-
Chef::Config[opt] = bootstrap_options[opt]
|
48
|
-
end
|
49
|
-
kb.name_args = [haze.server.ssh_ip_address]
|
50
|
-
kb.run
|
51
|
-
rescue Hazetug::Exception => e
|
52
|
-
ui.error(e.message); 1
|
53
|
-
ensure
|
54
|
-
@kb and @kb.ui.stdout.close
|
15
|
+
]
|
55
16
|
end
|
56
17
|
|
57
|
-
def
|
58
|
-
|
59
|
-
|
60
|
-
Chef::
|
61
|
-
kb = Chef::Knife::Bootstrap.new
|
62
|
-
kb.config[:hazetug] = config
|
63
|
-
kb.ui = Chef::Knife::UI.new(lf, lf, lf, {verbosity: 2})
|
64
|
-
kb
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
def bootstrap_options
|
69
|
-
@bootstrap_options ||= begin
|
70
|
-
template = options[:opts][:bootstrap] || 'bootstrap.erb'
|
71
|
-
validation = config[:chef_validation_key] || 'validation.pem'
|
72
|
-
|
73
|
-
files = [template, validation].map {|f| File.expand_path(f)}
|
74
|
-
notfound = files.select {|f| !File.exist?(f)}
|
75
|
-
notfound.empty? or
|
76
|
-
raise Hazetug::Exception, "File(s) not found: #{notfound.join(', ')}"
|
77
|
-
|
78
|
-
opts = {}
|
79
|
-
opts[:validation_key] = File.expand_path(validation)
|
80
|
-
opts[:template_file] = File.expand_path(template)
|
81
|
-
opts[:ssh_user] = config[:ssh_user] || 'root'
|
82
|
-
opts[:ssh_password] = config[:ssh_password]
|
83
|
-
opts[:environment] = config[:chef_environment]
|
84
|
-
opts[:host_key_verify] = config[:host_key_verify] || false
|
85
|
-
opts[:chef_server_url] = config[:chef_server_url]
|
86
|
-
opts[:identity_file] = preferred_ssh_identity if not opts[:ssh_password]
|
87
|
-
opts
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
def preferred_ssh_identity
|
92
|
-
@preferred_ssh_identity ||= begin
|
93
|
-
compute = Hazetug.leaf_klass_name(haze.class.name).downcase
|
94
|
-
identity = config[:identity_file]
|
95
|
-
key_path = (Hazetug::Config["#{compute}_ssh_keys"] || []).first
|
96
|
-
if identity.nil? && key_path.nil?
|
97
|
-
raise Hazetug::Exception, "identity file not specified, use #{compute}_ssh_keys or identity_file"
|
98
|
-
end
|
99
|
-
identity ||= File.expand_path(key_path)
|
100
|
-
identity
|
18
|
+
def bootstrap_config
|
19
|
+
super
|
20
|
+
@chef_option_list.each do |opt|
|
21
|
+
Chef::Config[opt] = bootstrap_options[opt]
|
101
22
|
end
|
23
|
+
check_bootstrap_files! :validation_key, :template_file
|
102
24
|
end
|
103
25
|
|
104
26
|
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
require 'erubis'
|
2
|
+
require 'chef/knife/ssh'
|
3
|
+
require 'chef/knife/bootstrap'
|
4
|
+
require 'chef/knife/core/bootstrap_context'
|
5
|
+
require 'hazetug/tug'
|
6
|
+
|
7
|
+
# Extend knife bootstrap context with our data.
|
8
|
+
# It's monkey patching, yey :)
|
9
|
+
class Chef::Knife::Bootstrap
|
10
|
+
def render_template(template=nil)
|
11
|
+
context = Chef::Knife::Core::BootstrapContext.new(config, config[:run_list], Chef::Config)
|
12
|
+
@extended_bootstrap_variables.each do |s, v|
|
13
|
+
context.instance_variable_set(s, v)
|
14
|
+
end
|
15
|
+
Erubis::Eruby.new(template).evaluate(context)
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_variable_to_bootstrap_context(variable_sym, value)
|
19
|
+
@extended_bootstrap_variables ||= {}
|
20
|
+
@extended_bootstrap_variables[variable_sym] = value if value
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Chef::Knife::Core::BootstrapContext
|
25
|
+
def hazetug; @hazetug; end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Chef::Knife::Ssh < Chef::Knife
|
29
|
+
def run
|
30
|
+
extend Chef::Mixin::Command
|
31
|
+
@longest = 0
|
32
|
+
configure_attribute
|
33
|
+
configure_user
|
34
|
+
configure_password
|
35
|
+
configure_identity_file
|
36
|
+
configure_gateway
|
37
|
+
configure_session
|
38
|
+
exit_status = ssh_command(@name_args[1..-1].join(" "))
|
39
|
+
session.close
|
40
|
+
|
41
|
+
exit_status
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class Hazetug
|
46
|
+
class Tug
|
47
|
+
class KnifeBase < Tug
|
48
|
+
|
49
|
+
def initialize(config={})
|
50
|
+
super
|
51
|
+
@bootstrap_option_list = [
|
52
|
+
:template_file,
|
53
|
+
:identity_file,
|
54
|
+
:ssh_user,
|
55
|
+
:ssh_password,
|
56
|
+
:host_key_verify
|
57
|
+
]
|
58
|
+
end
|
59
|
+
|
60
|
+
# Bootstraps the remote server using knife bootstrap.
|
61
|
+
def bootstrap_server
|
62
|
+
bootstrap_config
|
63
|
+
|
64
|
+
bootstrap_init
|
65
|
+
bootstrap_run
|
66
|
+
bootstrap_cleanup
|
67
|
+
rescue Hazetug::Exception => e
|
68
|
+
ui.error(e.message); 1
|
69
|
+
ensure
|
70
|
+
knife and knife.ui.stdout.close
|
71
|
+
end
|
72
|
+
|
73
|
+
# Configures knife bootstrap by setting the necessary options.
|
74
|
+
def bootstrap_config
|
75
|
+
knife.add_variable_to_bootstrap_context(:@hazetug, config)
|
76
|
+
|
77
|
+
@bootstrap_option_list.each do |opt|
|
78
|
+
knife.config[opt] = bootstrap_options[opt]
|
79
|
+
end
|
80
|
+
|
81
|
+
# Check ssh identity
|
82
|
+
cred = [
|
83
|
+
hazetug_identity, bootstrap_options[:identity_file],
|
84
|
+
bootstrap_options[:ssh_password]
|
85
|
+
]
|
86
|
+
|
87
|
+
if cred.all?(&:nil?)
|
88
|
+
msg = "No identity (inc. ssh_password) found. Check ssh_password," <<
|
89
|
+
" identity_file options or #{config[:compute_name]}_ssh_keys " <<
|
90
|
+
"hazetug parameter."
|
91
|
+
|
92
|
+
raise Hazetug::Exception, msg
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Pre knife bootstrap hook.
|
97
|
+
def bootstrap_init
|
98
|
+
end
|
99
|
+
|
100
|
+
# After knife bootstrap hook.
|
101
|
+
def bootstrap_cleanup
|
102
|
+
end
|
103
|
+
|
104
|
+
# Initiates knife bootstrap run.
|
105
|
+
def bootstrap_run
|
106
|
+
knife.name_args = [config[:public_ip_address]]
|
107
|
+
knife.run
|
108
|
+
end
|
109
|
+
|
110
|
+
# Initializes knife bootstrap, default output is redirected into file.
|
111
|
+
def knife
|
112
|
+
@knife ||= begin
|
113
|
+
lf = create_log_file
|
114
|
+
Chef::Knife::Bootstrap.load_deps
|
115
|
+
kb = Chef::Knife::Bootstrap.new
|
116
|
+
kb.ui = Chef::Knife::UI.new(lf, lf, lf, {verbosity: 2})
|
117
|
+
kb
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# Extracts bootstrap options from the hazetug configuration.
|
122
|
+
def bootstrap_options
|
123
|
+
@bootstrap_options ||= begin
|
124
|
+
opts = {}
|
125
|
+
|
126
|
+
opts[:ssh_user] = config[:ssh_user] || 'root'
|
127
|
+
opts[:ssh_password] = config[:ssh_password]
|
128
|
+
if opts[:ssh_password].nil?
|
129
|
+
opts[:identity_file] = config[:identity_file] || hazetug_identity
|
130
|
+
end
|
131
|
+
|
132
|
+
template = options[:opts][:bootstrap] || 'bootstrap.erb'
|
133
|
+
validation = config[:chef_validation_key] || 'validation.pem'
|
134
|
+
|
135
|
+
opts[:validation_key] = File.expand_path(validation)
|
136
|
+
opts[:template_file] = File.expand_path(template)
|
137
|
+
opts[:environment] = config[:chef_environment]
|
138
|
+
opts[:host_key_verify] = config[:host_key_verify] || false
|
139
|
+
opts[:chef_server_url] = config[:chef_server_url]
|
140
|
+
opts
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# Lookup ssh identity key(s) in the hazetug configuration.
|
145
|
+
def hazetug_identity
|
146
|
+
@hazetug_identity ||= begin
|
147
|
+
compute = config[:compute_name]
|
148
|
+
key_path = (Hazetug::Config["#{compute}_ssh_keys"] || []).first
|
149
|
+
key_path and File.expand_path(key_path)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# Check if files exist otherwise fail.
|
154
|
+
def check_bootstrap_files!(*list_of_opts)
|
155
|
+
list = list_of_opts.map {|k| bootstrap_options[k]}
|
156
|
+
files = list.map {|f| File.expand_path(f.to_s)}
|
157
|
+
notfound = files.select {|f| !File.exist?(f)}
|
158
|
+
notfound.empty? or
|
159
|
+
raise Hazetug::Exception, "File(s) not found: #{notfound.join(', ')}"
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'chef/knife/ssh'
|
2
|
+
require 'chef/knife/bootstrap'
|
3
|
+
require 'berkshelf'
|
4
|
+
require 'berkshelf/berksfile'
|
5
|
+
require 'json'
|
6
|
+
require 'hazetug/tug/knife_base'
|
7
|
+
|
8
|
+
class Hazetug
|
9
|
+
class Tug
|
10
|
+
class Solo < KnifeBase
|
11
|
+
|
12
|
+
def initialize(config={})
|
13
|
+
super
|
14
|
+
@upload_dest = '/tmp/hazetug-cookbooks.tar.gz'
|
15
|
+
end
|
16
|
+
|
17
|
+
def bootstrap_config
|
18
|
+
super
|
19
|
+
config[:attributes_json] = json_attributes
|
20
|
+
config[:cookbooks_file] = @upload_dest
|
21
|
+
|
22
|
+
check_bootstrap_files! :template_file, :berksfile
|
23
|
+
end
|
24
|
+
|
25
|
+
def bootstrap_init
|
26
|
+
upload_berks_package
|
27
|
+
end
|
28
|
+
|
29
|
+
def bootstrap_cleanup
|
30
|
+
ssh = Fog::SSH.new(config[:public_ip_address], ssh_username, ssh_options)
|
31
|
+
ssh.run("test -f #{@upload_dest} && rm #{@upload_dest}")
|
32
|
+
end
|
33
|
+
|
34
|
+
def berks_package(&block)
|
35
|
+
berks = Berkshelf::Berksfile.from_file(bootstrap_options[:berksfile])
|
36
|
+
|
37
|
+
Dir::Tmpname.create('hazetug-cookbooks') do |path|
|
38
|
+
begin
|
39
|
+
berks.package(path)
|
40
|
+
block.call(path)
|
41
|
+
ensure
|
42
|
+
File.unlink(path) if File.exist?(path)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def upload_berks_package
|
48
|
+
berks_package do |path|
|
49
|
+
scp = Fog::SCP.new(config[:public_ip_address], ssh_username, ssh_options)
|
50
|
+
scp.upload(path, @upload_dest)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def bootstrap_options
|
55
|
+
@bootstrap_options ||= begin
|
56
|
+
opts = super
|
57
|
+
opts[:berksfile] = config[:berksfile] || 'Berksfile'
|
58
|
+
opts
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def json_attributes
|
63
|
+
@json_attributes ||= begin
|
64
|
+
hash = config[:attributes] || {}
|
65
|
+
hash[:run_list] = config[:run_list] || []
|
66
|
+
JSON.pretty_generate(hash)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def ssh_options
|
73
|
+
@ssh_options ||= begin
|
74
|
+
ssh_options = {}
|
75
|
+
ssh_opts = Hazetug::Tug.ssh_options_from(config)
|
76
|
+
ssh_options[:password] = ssh_opts[:ssh_password]
|
77
|
+
ssh_options[:paranoid] = ssh_opts[:host_key_verify] || false
|
78
|
+
ssh_options[:keys] = ssh_opts[:ssh_keys] || Hazetug.ssh_keys(config[:compute_name])
|
79
|
+
ssh_options[:port] = ssh_opts[:ssh_port]
|
80
|
+
ssh_options
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def ssh_username
|
85
|
+
config[:ssh_user] || 'root'
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
data/lib/hazetug/tug.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'hazetug/tug/knife'
|
2
|
+
require 'hazetug/tug/solo'
|
2
3
|
require 'hazetug/ui'
|
3
4
|
require 'chef/mash'
|
4
5
|
|
@@ -12,10 +13,9 @@ class Hazetug
|
|
12
13
|
]
|
13
14
|
LOGDIR = "#{Dir.pwd}/logs"
|
14
15
|
|
15
|
-
attr_reader :
|
16
|
+
attr_reader :config, :options
|
16
17
|
|
17
|
-
def initialize(config={}
|
18
|
-
@haze = haze
|
18
|
+
def initialize(config={})
|
19
19
|
@config = config
|
20
20
|
end
|
21
21
|
|
@@ -24,22 +24,23 @@ class Hazetug
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def bootstrap(options={})
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
else
|
36
|
-
ui.msg "[#{tug_name}] bootstraping server #{haze.config[:name]} done."
|
37
|
-
end
|
27
|
+
@options = options
|
28
|
+
ip = config[:public_ip_address]
|
29
|
+
|
30
|
+
ui.msg "[#{tug_name}] bootstraping server #{config[:name]}, ip: #{ip}"
|
31
|
+
exit_status = bootstrap_server
|
32
|
+
|
33
|
+
if exit_status.is_a?(Fixnum) && exit_status != 0
|
34
|
+
ui.error "[#{tug_name}] bootstraping server #{config[:name]} failed."
|
38
35
|
else
|
39
|
-
ui.
|
36
|
+
ui.msg "[#{tug_name}] bootstraping server #{config[:name]} done."
|
40
37
|
end
|
41
38
|
rescue Hazetug::Exception => e
|
42
|
-
ui.error "[#{
|
39
|
+
ui.error "[#{config[:compute_name]}] #{e.message}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def load_haze_config(hash)
|
43
|
+
@config.merge!(hash)
|
43
44
|
end
|
44
45
|
|
45
46
|
class << self
|
@@ -58,25 +59,13 @@ class Hazetug
|
|
58
59
|
end
|
59
60
|
end
|
60
61
|
|
61
|
-
private
|
62
|
-
|
63
|
-
def haztug_set_variables
|
64
|
-
{
|
65
|
-
compute_name: haze.compute_name.downcase,
|
66
|
-
public_ip_address: (haze.public_ip_address || haze.server.ssh_ip_address rescue nil),
|
67
|
-
private_ip_address: haze.private_ip_address
|
68
|
-
}.each do |key, value|
|
69
|
-
config[key] = value if value
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
62
|
protected
|
74
63
|
|
75
64
|
def create_log_file
|
76
65
|
unless File.directory?(LOGDIR)
|
77
66
|
Dir.mkdir(LOGDIR)
|
78
67
|
end
|
79
|
-
log = File.new("#{LOGDIR}/#{
|
68
|
+
log = File.new("#{LOGDIR}/#{config[:name]}", "w+")
|
80
69
|
log.sync = true
|
81
70
|
log
|
82
71
|
end
|
data/lib/hazetug/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hazetug
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Denis Barishev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-09-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -28,89 +28,103 @@ dependencies:
|
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: psych
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: fog
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - "
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - "
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: chef
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- - "
|
73
|
+
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: 11.
|
75
|
+
version: '11.0'
|
76
76
|
type: :runtime
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- - "
|
80
|
+
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: 11.
|
82
|
+
version: '11.0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: gli
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- - "
|
87
|
+
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '0'
|
89
|
+
version: '2.0'
|
90
90
|
type: :runtime
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- - "
|
94
|
+
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: '0'
|
96
|
+
version: '2.0'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: agent
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
|
-
- - "
|
101
|
+
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
103
|
version: '0'
|
104
104
|
type: :runtime
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- - "
|
108
|
+
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
|
-
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: berkshelf
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '3.0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '3.0'
|
125
|
+
description: Provisions and bootstraps nodes using knife
|
112
126
|
email:
|
113
|
-
-
|
127
|
+
- dennybaa@gmail.com
|
114
128
|
executables:
|
115
129
|
- hazetug
|
116
130
|
extensions: []
|
@@ -122,6 +136,8 @@ files:
|
|
122
136
|
- README.md
|
123
137
|
- Rakefile
|
124
138
|
- bin/hazetug
|
139
|
+
- examples/bootstrap-client.erb
|
140
|
+
- examples/bootstrap-solo.erb
|
125
141
|
- hazetug.gemspec
|
126
142
|
- lib/hazetug.rb
|
127
143
|
- lib/hazetug/cli.rb
|
@@ -137,6 +153,8 @@ files:
|
|
137
153
|
- lib/hazetug/task.rb
|
138
154
|
- lib/hazetug/tug.rb
|
139
155
|
- lib/hazetug/tug/knife.rb
|
156
|
+
- lib/hazetug/tug/knife_base.rb
|
157
|
+
- lib/hazetug/tug/solo.rb
|
140
158
|
- lib/hazetug/ui.rb
|
141
159
|
- lib/hazetug/version.rb
|
142
160
|
homepage: https://github.com/dennybaa/hazetug
|