blender-chef 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/README.md +62 -2
- data/blender-chef.gemspec +3 -3
- data/lib/blender/discoveries/chef.rb +1 -1
- data/lib/chef/knife/blender.rb +119 -45
- data/spec/blender/knife_spec.rb +13 -8
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 227b93ae896e5908d4a492d8bb0962652810ebcb
|
4
|
+
data.tar.gz: dd20886e6a0cd3691853ea131763cd482b9dfc89
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4f6879284bbb5c572d8f3c4f9f203216e195866a236334381b33f6201893a023be4146cf2f81577e723e3b60d8e67c5614f9557ae790b1c6717b59b5fba5b90d
|
7
|
+
data.tar.gz: 47bf4c4b37718ecd3611f6b9da590eac1682a862979fe016efbc8029cc9aae2187f98d0f8ef81270e7ff2426b9c95ac889984512c36e4686285799882237a4f9
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -14,7 +14,7 @@ fetched from Chef server. Following is an example of dynamically obtaining
|
|
14
14
|
all servers with `db` role, and enlisting their `iptables` rule.
|
15
15
|
|
16
16
|
```ruby
|
17
|
-
require '
|
17
|
+
require 'blender/chef'
|
18
18
|
config(:chef, chef_sever_url: 'https://foo.bar.com', node_name: 'admin', client_key: 'admin.pem')
|
19
19
|
members(search(:chef, 'roles:db'))
|
20
20
|
ssh_task 'sudo iptables -L'
|
@@ -40,6 +40,67 @@ config(:chef, node_name: 'admin', client_key: 'admin.pem')
|
|
40
40
|
members(search(:chef, 'roles:db', attribute: 'ec2_public_ipv4'))
|
41
41
|
```
|
42
42
|
|
43
|
+
### Knife integration
|
44
|
+
|
45
|
+
Blender-chef comes with a knife plugin that allows job or chef recipe or node bootstrapping
|
46
|
+
from command line interface.
|
47
|
+
|
48
|
+
- Blender-mode, for running raw blender jobs
|
49
|
+
Given the following job present in file `jobs/upgrade_chef.rb`
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
ssh_task 'sudo apt-get remove chef --purge'
|
53
|
+
ssh_task 'sudo apt-get remove chef --purge'
|
54
|
+
ssh_task 'wget -c https://opscode-omnibus-packages.s3.amazonaws.com/ubuntu/13.04/x86_64/chef_12.0.3-1_amd64.deb'
|
55
|
+
ssh_task 'sudo dpkg -i chef_12.0.3-1_amd64.deb'
|
56
|
+
ssh_task 'sudo chef-client'
|
57
|
+
```
|
58
|
+
|
59
|
+
It can be executed against all chef nodes having `db` role as:
|
60
|
+
|
61
|
+
```sh
|
62
|
+
knife blend --search 'roles:db' jobs/upgrade_chef.rb
|
63
|
+
```
|
64
|
+
this is equivalent to
|
65
|
+
```sh
|
66
|
+
knife blend --mode blender --search 'roles:db' jobs/upgrade_chef.rb
|
67
|
+
```
|
68
|
+
as blender mode is the default mode.
|
69
|
+
|
70
|
+
- Recipe mode, for running one-off chef recipes against remote nodes using blender
|
71
|
+
Given the following chef recipe present ina local file `recipes/nginx.rb`
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
package 'nginx'
|
75
|
+
service 'nginx' do
|
76
|
+
action [:start, :enable]
|
77
|
+
end
|
78
|
+
```
|
79
|
+
|
80
|
+
It can be executed against all chef nodes having `web` role as:
|
81
|
+
|
82
|
+
```sh
|
83
|
+
knife blend --mode recipe --search 'roles:web' recipes/nginx.rb
|
84
|
+
```
|
85
|
+
In recipe mode blender will treat the input file(s) as chef recipe
|
86
|
+
and build necessary scp and ssh tasks to upload the recipe, execute it
|
87
|
+
and remove the uploaded recipe.
|
88
|
+
|
89
|
+
- Berkshelf mode, for bootstrapping server with chef solo. In this mode blender-chef
|
90
|
+
will assume the specifid file is a Berksfile, and use it to vendor cookbooks, then
|
91
|
+
upload it to the remote server using scp, and finally run chef in localmode against
|
92
|
+
the vendored cookbook directory. In berkshelf mode run list is specified via `--run-list`
|
93
|
+
option.
|
94
|
+
|
95
|
+
```sh
|
96
|
+
knife blend Berksfile --mode berkshelf -h foo.bar.com -i id_rsa --run-list recipe[nginx]
|
97
|
+
```
|
98
|
+
|
99
|
+
Note: You have to install berkshelf explicitly (vie bundler or using raw gem commands).
|
100
|
+
|
101
|
+
|
102
|
+
Additional options are provided to control strategy, ssh credentials etc.
|
103
|
+
|
43
104
|
|
44
105
|
## Supported ruby versions
|
45
106
|
|
@@ -47,7 +108,6 @@ Blender-chef uses Chef 12 (for partial search). For chef 11, use 0.0.1 version o
|
|
47
108
|
|
48
109
|
Blender-chef currently support the following MRI versions:
|
49
110
|
|
50
|
-
* *Ruby 1.9.3*
|
51
111
|
* *Ruby 2.1.0*
|
52
112
|
* *Ruby 2.1.2*
|
53
113
|
|
data/blender-chef.gemspec
CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = 'blender-chef'
|
7
|
-
spec.version = '0.
|
7
|
+
spec.version = '0.2.0'
|
8
8
|
spec.authors = ['Ranjib Dey']
|
9
9
|
spec.email = ['ranjib@pagerduty.com']
|
10
10
|
spec.summary = %q{Chef search based host discovery for blender}
|
@@ -16,8 +16,8 @@ Gem::Specification.new do |spec|
|
|
16
16
|
spec.test_files = spec.files.grep(%r{^spec/})
|
17
17
|
spec.require_paths = ['lib']
|
18
18
|
|
19
|
-
spec.add_dependency 'pd-blender'
|
20
|
-
spec.add_dependency 'chef', '>= 12.
|
19
|
+
spec.add_dependency 'pd-blender', '>= 0.1.0'
|
20
|
+
spec.add_dependency 'chef', '>= 12.1.1'
|
21
21
|
|
22
22
|
spec.add_development_dependency 'bundler'
|
23
23
|
spec.add_development_dependency 'rake'
|
@@ -44,7 +44,7 @@ module Blender
|
|
44
44
|
::Chef::Config[:chef_server_url] = options[:chef_server_url] if options[:chef_server_url]
|
45
45
|
q = ::Chef::Search::Query.new
|
46
46
|
res = q.search(:node, search_term, filter_result: {attribute: attr.split('.')})
|
47
|
-
res.first.collect{|node_data| node_data['
|
47
|
+
res.first.collect{|node_data| node_data['attribute']}
|
48
48
|
end
|
49
49
|
end
|
50
50
|
end
|
data/lib/chef/knife/blender.rb
CHANGED
@@ -53,6 +53,12 @@ class Chef
|
|
53
53
|
long: '--noop',
|
54
54
|
description: 'no-op aka dry-run mode, run blender without executing jobs'
|
55
55
|
|
56
|
+
option :prompt,
|
57
|
+
default: false,
|
58
|
+
boolean: true,
|
59
|
+
long: '--prompt',
|
60
|
+
description: 'Prompt for password'
|
61
|
+
|
56
62
|
option :quiet,
|
57
63
|
default: false,
|
58
64
|
boolean: true,
|
@@ -93,17 +99,16 @@ class Chef
|
|
93
99
|
long: '--identity-file IDENTITY_FILE',
|
94
100
|
description: 'Identity file for SSH authentication'
|
95
101
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
default: false
|
102
|
+
desc = "Run mode. Can be 'blender', 'recipe' or 'berkshelf'\n"
|
103
|
+
desc << "In 'blender' mode input file is treated as a Blender job\n"
|
104
|
+
desc << "In 'recipe' mode input file is treated as an individual recipe and executed using chef-apply\n"
|
105
|
+
desc << "In 'berkshelf' mode input file is treated as a Berksfile. Blender vendors cookbook using berksshelf, scp it and run chef against it in localmode\n"
|
106
|
+
option :mode,
|
107
|
+
long: '--mode MODE',
|
108
|
+
short: '-m MODE',
|
109
|
+
description: desc,
|
110
|
+
default: :blender,
|
111
|
+
proc: lambda{|s| s.to_sym}
|
107
112
|
|
108
113
|
option :chef_apply,
|
109
114
|
long: '--chef-apply',
|
@@ -111,54 +116,123 @@ class Chef
|
|
111
116
|
description: 'chef-apply command to be used (effective only in recipe mode)',
|
112
117
|
default: 'chef-apply'
|
113
118
|
|
119
|
+
option :run_list,
|
120
|
+
long: '--run-list RUN_LIST',
|
121
|
+
short: '-r RUN_LIST',
|
122
|
+
description: 'chef-apply command to be used (effective only in berkshelf mode)'
|
123
|
+
|
124
|
+
option :hosts,
|
125
|
+
long: '--hosts HOST1,HOST2,HOST3',
|
126
|
+
short: '-h HOST1,HOST2,HOST3',
|
127
|
+
description: 'Pass hosts manually (search and attribute option will be ignored)'
|
128
|
+
|
114
129
|
def run
|
115
|
-
ssh_options = {
|
116
|
-
user: config[:user],
|
117
|
-
stdout: $stdout
|
118
|
-
}
|
119
|
-
ssh_options[:stdout] = $stdout if config[:stream]
|
120
|
-
if config[:password]
|
121
|
-
ssh_options[:password] = config[:password]
|
122
|
-
elsif config[:prompt]
|
123
|
-
ssh_options[:password] = ui.ask('SSH password: ') {|q|q.echo = false}
|
124
|
-
end
|
125
|
-
if config[:identity_file]
|
126
|
-
ssh_options[:keys] = Array(config[:identity_file])
|
127
|
-
end
|
128
130
|
scheduler_options = {
|
129
131
|
config_file: config[:blender_config],
|
130
132
|
no_doc: config[:quiet]
|
131
133
|
}
|
134
|
+
|
132
135
|
discovery_options = {
|
133
136
|
attribute: config[:attribute]
|
134
137
|
}
|
138
|
+
|
135
139
|
Blender::Configuration[:noop] = config[:noop]
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
140
|
+
|
141
|
+
if config[:hosts]
|
142
|
+
members = config[:hosts].split(',')
|
143
|
+
else
|
144
|
+
members = Blender::Discovery::Chef.new(discovery_options).search(config[:search])
|
145
|
+
end
|
146
|
+
ssh_config = ssh_options
|
147
|
+
Blender.blend('blender-chef', scheduler_options) do |scheduler|
|
148
|
+
scheduler.strategy(config[:strategy])
|
149
|
+
scheduler.config(:ssh, ssh_config)
|
150
|
+
scheduler.config(:scp, ssh_config)
|
151
|
+
scheduler.members(members)
|
152
|
+
@name_args.each do |file|
|
153
|
+
case config[:mode]
|
154
|
+
when :berkshelf
|
155
|
+
begin
|
156
|
+
require 'berkshelf'
|
157
|
+
rescue LoadError
|
158
|
+
raise RuntimeError, 'You must install berkshelf before using blender-chef in berkshelf mode'
|
148
159
|
end
|
149
|
-
|
150
|
-
scheduler
|
160
|
+
tempdir = Dir.mktmpdir
|
161
|
+
berkshelf_mode(scheduler, tempdir, file)
|
162
|
+
FileUtils.rm_rf(tempdir)
|
163
|
+
when :recipe
|
164
|
+
recipe_mode(scheduler, file)
|
165
|
+
when :blender
|
166
|
+
blender_mode(scheduler, file)
|
167
|
+
else
|
168
|
+
raise ArgumentError, "Unknown mode: '#{config[:mode]}'"
|
151
169
|
end
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def ssh_options
|
175
|
+
opts = {
|
176
|
+
user: config[:user]
|
177
|
+
}
|
178
|
+
if config[:identity_file]
|
179
|
+
opts[:keys] = Array(config[:identity_file])
|
180
|
+
end
|
181
|
+
if config[:stream] or (!config[:quiet])
|
182
|
+
opts[:stdout] = $stdout
|
183
|
+
end
|
184
|
+
if config[:password]
|
185
|
+
opts[:password] = config[:password]
|
186
|
+
elsif config[:prompt]
|
187
|
+
opts[:password] = ui.ask('SSH password: ') {|q|q.echo = false}
|
188
|
+
end
|
189
|
+
opts
|
190
|
+
end
|
191
|
+
|
192
|
+
def berkshelf_mode(scheduler, tempdir, file)
|
193
|
+
run_list = config[:run_list]
|
194
|
+
scheduler.ruby_task 'generate cookbook tarball' do
|
195
|
+
execute do
|
196
|
+
berksfile = Berkshelf::Berksfile.from_file('Berksfile')
|
197
|
+
berksfile.vendor(tempdir)
|
198
|
+
File.open('/tmp/solo.rb', 'w') do |f|
|
199
|
+
f.write("cookbook_path '/tmp/cookbooks'\n")
|
200
|
+
f.write("file_cache_path '/var/cache/chef/cookbooks'\n")
|
159
201
|
end
|
160
202
|
end
|
161
203
|
end
|
204
|
+
scheduler.ssh_task 'nuke old cookbook directory if exist' do
|
205
|
+
execute 'rm -rf /tmp/cookbooks'
|
206
|
+
end
|
207
|
+
scheduler.scp_upload 'upload cookbooks' do
|
208
|
+
from tempdir
|
209
|
+
to '/tmp/cookbooks'
|
210
|
+
recursive true
|
211
|
+
end
|
212
|
+
scheduler.scp_upload '/tmp/solo.rb' do
|
213
|
+
from '/tmp/solo.rb'
|
214
|
+
end
|
215
|
+
scheduler.ssh_task 'create cache directory' do
|
216
|
+
execute 'sudo mkdir -p /var/cache/chef/cookbooks'
|
217
|
+
end
|
218
|
+
scheduler.ssh_task 'run chef solo' do
|
219
|
+
execute "sudo chef-client -z -o #{run_list} -c /tmp/solo.rb --force-logger"
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def recipe_mode(scheduler, file)
|
224
|
+
remote_path = File.join('/tmp', SecureRandom.hex(10))
|
225
|
+
scheduler.scp_upload('upload recipe') do
|
226
|
+
to remote_path
|
227
|
+
from file
|
228
|
+
end
|
229
|
+
scheduler.ssh_task "#{config[:chef_apply]} #{remote_path}"
|
230
|
+
scheduler.ssh_task "rm #{remote_path}"
|
231
|
+
end
|
232
|
+
|
233
|
+
def blender_mode(scheduler, file)
|
234
|
+
job = File.read(file)
|
235
|
+
scheduler.instance_eval(job, __FILE__, __LINE__)
|
162
236
|
end
|
163
237
|
end
|
164
238
|
end
|
data/spec/blender/knife_spec.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
require 'chef/knife/blender'
|
4
|
+
require 'blender/rspec'
|
4
5
|
|
5
6
|
describe Chef::Knife::Blend do
|
6
7
|
before(:each) do
|
@@ -10,20 +11,24 @@ describe Chef::Knife::Blend do
|
|
10
11
|
@knife.config[:passsword] = 'test-password'
|
11
12
|
@knife.config[:search] = 'roles:db'
|
12
13
|
@knife.config[:strategy] = :default
|
13
|
-
@knife.name_args = ["job.rb"]
|
14
14
|
end
|
15
15
|
it '#non recipe mode' do
|
16
|
-
|
17
|
-
|
18
|
-
expect(disco).to receive(:search).and_return(['host1', 'host2'])
|
16
|
+
@knife.name_args = ["job.rb"]
|
17
|
+
stub_search(:chef, 'roles:db').and_return(%w(host1 host2))
|
19
18
|
expect(File).to receive(:read).with('job.rb').and_return('')
|
19
|
+
@knife.config[:mode] = :blender
|
20
20
|
@knife.run
|
21
21
|
end
|
22
22
|
it '#recipe mode' do
|
23
|
-
@knife.
|
24
|
-
|
25
|
-
|
26
|
-
|
23
|
+
@knife.name_args = ["job.rb"]
|
24
|
+
@knife.config[:mode] = :recipe
|
25
|
+
stub_search(:chef, 'roles:db').and_return([])
|
26
|
+
@knife.run
|
27
|
+
end
|
28
|
+
it '#berkshelf mode' do
|
29
|
+
@knife.name_args = ['/path/to/berksfile']
|
30
|
+
@knife.config[:mode] = :recipe
|
31
|
+
stub_search(:chef, 'roles:db').and_return([])
|
27
32
|
@knife.run
|
28
33
|
end
|
29
34
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: blender-chef
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ranjib Dey
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-03-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pd-blender
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 0.1.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 0.1.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: chef
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 12.
|
33
|
+
version: 12.1.1
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 12.
|
40
|
+
version: 12.1.1
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: bundler
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|