blender-chef 0.1.0 → 0.2.0
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/.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
|