hazetug 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|