batali 0.3.8 → 0.3.10

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 47869001066b08c8d611cdbbcf448769136ea753
4
- data.tar.gz: 12b8059a2dab468f8863e160a4f1eb3855f4702c
3
+ metadata.gz: bc79c37709d9a82123b18ff7f3708d3ab3090747
4
+ data.tar.gz: d71675d5533528818ffdafe8a2b7727ae7d20566
5
5
  SHA512:
6
- metadata.gz: 58c28c8fe207f98343428725755423ed99232222f7e62fd6085897e483d9dcd652bccdae73ff94c6f90de2f80aa439c8d005a8d0f6e18dd23d54704a1ef851bd
7
- data.tar.gz: 8f5ef4ea067923d84b1dcbe139e7e9712d03481f8779d8ca7b954b4ec29201ea4a2aabff4bdc0719e9e33801313d59664febb94cfd67cc11d48a2b7a89308c2b
6
+ metadata.gz: e745bf572287f0c86144b03a55493f0de0f8954762664d5165e2cce579bffb80742af7f22c4ac9881fe06519a459b619f922cb7f8c7390cb3d59f62ca7dfc042
7
+ data.tar.gz: 6dcb427899adfbc5c7d9e7c9b5b2cb1900a52e98e27511c357f4287b53c94a2698c26ffad5d44efab9cf7df2d66d2f74286ebaac93c0e1d74bc75128de531b96
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ # v0.3.10
2
+ * [feature] Chef server manifest sync knife plugin
3
+
1
4
  # v0.3.8
2
5
  * [fix] Generate JSON properly under old implementations
3
6
 
data/README.md CHANGED
@@ -393,6 +393,20 @@ line to your `spec_helper.rb` file:
393
393
  require 'batali/chefspec'
394
394
  ```
395
395
 
396
+ ## Chef Server Sync
397
+
398
+ Batali includes a knife plugin to sync cookbooks defined within the local
399
+ `batali.manifest` file with the cookbooks available from on the Chef server.
400
+
401
+ ```
402
+ $ knife batali sync
403
+ ```
404
+
405
+ This command will remove any cookbooks on the Chef server that are not found
406
+ within the `batali.manifest` file. If cookbooks are defined within the
407
+ `batali.manifest` file that have not been uploaded to the Chef server, those
408
+ cookbooks will be uploaded.
409
+
396
410
  # Info
397
411
 
398
412
  * Repository: https://github.com/hw-labs/batali
@@ -1,4 +1,4 @@
1
1
  module Batali
2
2
  # Current version
3
- VERSION = Gem::Version.new('0.3.8')
3
+ VERSION = Gem::Version.new('0.3.10')
4
4
  end
@@ -0,0 +1,221 @@
1
+ require 'batali'
2
+
3
+ class Chef
4
+ class Knife
5
+ class BataliSync < Knife
6
+
7
+ banner 'knife batali sync'
8
+
9
+ option(:blacklist,
10
+ :short => '-B COOKBOOK_NAME[,COOKBOOK_NAME]',
11
+ :long => '--blacklist COOKBOOK_NAME[,COOKBOOK_NAME]',
12
+ :description => 'Cookbooks to ignore from sync',
13
+ :proc => lambda{|val|
14
+ Chef::Config[:knife][:batali_blacklist] ||= []
15
+ Chef::Config[:knife][:batali_blacklist] += val.split(',')
16
+ }
17
+ )
18
+
19
+ option(:details,
20
+ :long => '--[no-]details',
21
+ :boolean => true,
22
+ :default => true,
23
+ :description => 'Show details of cookbooks to be removed / added'
24
+ )
25
+
26
+ option(:show_remaining,
27
+ :long => '--[no-]show-remaining',
28
+ :description => 'Display cookbook details of expected final server state',
29
+ :boolean => true,
30
+ :default => false,
31
+ :proc => lambda{|val|
32
+ Chef::Config[:knife][:batali_show_remaining] = val
33
+ }
34
+ )
35
+
36
+ option(:dry_run,
37
+ :long => '--[no-]dry-run',
38
+ :description => 'Display information but perform no action',
39
+ :boolean => true,
40
+ :default => false
41
+ )
42
+
43
+ def run
44
+ Chef::Config[:knife][:batali_blacklist] ||= []
45
+ config[:verbose] = config[:verbosity].to_i > 0
46
+ ui.info "#{ui.color('[Batali]', :green, :bold)}: Chef Server Batali Manifest Sync"
47
+ valid_cookbooks = run_task('Generating valid cookbook versions from manifest') do
48
+ generate_manifest_cookbooks
49
+ end
50
+ remote_cookbooks = run_task('Generating remote cookbook versions from chef server') do
51
+ generate_remote_cookbooks
52
+ end
53
+ to_remove = run_task('Building cookbook removal list') do
54
+ locate_removals(
55
+ :manifest => valid_cookbooks,
56
+ :server => remote_cookbooks
57
+ )
58
+ end
59
+ to_add = run_task('Building cookbook upload list') do
60
+ locate_additions(
61
+ :manifest => valid_cookbooks,
62
+ :server => remote_cookbooks
63
+ )
64
+ end
65
+ if(to_add.empty? && to_remove.empty?)
66
+ ui.info "#{ui.color('[Batali]', :green, :bold)}: Chef Server Batali Manifest Sync - #{ui.color('No Changes Detected!', :green, :bold)}"
67
+ else
68
+ display_sync_info(
69
+ :additions => to_add,
70
+ :removals => to_remove,
71
+ :manifest => valid_cookbooks
72
+ )
73
+ unless(config[:dry_run])
74
+ ui.confirm 'Sync remote cookbooks with Batali manifest'
75
+ remove_cookbooks(to_remove) unless to_remove.empty?
76
+ add_cookbooks(to_add) unless to_add.empty?
77
+ ui.info "#{ui.color('[Batali]', :green, :bold)}: Chef Server Batali Manifest Sync - #{ui.color('Sync Complete!', :green, :bold)}"
78
+ else
79
+ ui.warn 'Dry run requested. No action taken.'
80
+ end
81
+ end
82
+ end
83
+
84
+ def remove_cookbooks(ckbks)
85
+ run_task('Removing cookbooks') do
86
+ ckbks.each do |c_name, vers|
87
+ vers.each do |version|
88
+ if(config[:verbose])
89
+ ui.warn "Deleting cookbook #{c_name} @ #{version}"
90
+ end
91
+ rest.delete("/cookbooks/#{c_name}/#{version}")
92
+ end
93
+ end
94
+ end
95
+ end
96
+
97
+ def add_cookbooks(ckbks)
98
+ Batali::Command::Install.new({}, []).execute!
99
+ ui.info "#{ui.color('[Batali]', :green, :bold)}: Adding cookbooks to Chef server."
100
+ Knife::Upload.load_deps
101
+ ckbks.each do |c_name, vers|
102
+ vers.each do |version|
103
+ c_path = [
104
+ File.join('cookbooks', c_name),
105
+ File.join('cookbooks', "#{c_name}-#{version}")
106
+ ].detect do |_path|
107
+ File.directory?(_path)
108
+ end
109
+ uploader = Knife::Upload.new
110
+ uploader.configure_chef
111
+ uploader.config = config
112
+ uploader.name_args = [c_path]
113
+ if(config[:verbose])
114
+ ui.warn "Unloading cookbook #{c_name} @ #{version} - `#{c_path}`"
115
+ end
116
+ uploader.run
117
+ end
118
+ end
119
+ ui.info "#{ui.color('[Batali]', :green, :bold)}: Chef server cookbook additions complete."
120
+ end
121
+
122
+ def display_sync_info(opts)
123
+ num_remove = ui.color(opts[:removals].size.to_s, :red, :bold)
124
+ num_add = ui.color(opts[:additions].size.to_s, :green, :bold)
125
+ ui.info "#{ui.color('[Batali]', :green, :bold)}: Removals - #{num_remove} Additions: #{num_add}"
126
+ if(config[:details])
127
+ unless(opts[:removals].empty?)
128
+ ui.info "#{ui.color('[Batali]', :green, :bold)}: Cookbooks to be #{ui.color('removed', :red, :bold)}:"
129
+ opts[:removals].sort.each do |name, versions|
130
+ vers = versions.map do |v|
131
+ Gem::Version.new(v)
132
+ end.sort.map(&:to_s).join(', ')
133
+ ui.info " #{ui.color(name, :red, :bold)}: #{ui.color(vers, :red)}"
134
+ end
135
+ end
136
+ unless(opts[:additions].empty?)
137
+ ui.info "#{ui.color('[Batali]', :green, :bold)}: Cookbooks to be #{ui.color('added', :green, :bold)}:"
138
+ opts[:additions].sort.each do |name, versions|
139
+ vers = versions.map do |v|
140
+ Gem::Version.new(v)
141
+ end.sort.map(&:to_s).join(', ')
142
+ ui.info " #{ui.color(name, :green, :bold)}: #{ui.color(vers, :green)}"
143
+ end
144
+ end
145
+ if(Chef::Config[:knife][:batali_show_remaining])
146
+ ui.info "#{ui.color('[Batali]', :green, :bold)}: Final list of cookbooks to be available on the chef server:"
147
+ opts[:manifest].sort.each do |name, versions|
148
+ vers = versions.map do |v|
149
+ Gem::Version.new(v)
150
+ end.sort.map(&:to_s).join(', ')
151
+ ui.info " #{ui.color(name, :bold)}: #{vers}"
152
+ end
153
+ end
154
+ end
155
+ end
156
+
157
+ def locate_removals(opts)
158
+ Smash.new.tap do |rm|
159
+ opts[:server].each do |c_name, c_versions|
160
+ kills = c_versions - opts[:manifest].fetch(c_name, [])
161
+ unless(kills.empty?)
162
+ rm[c_name] = kills
163
+ end
164
+ end
165
+ end
166
+ end
167
+
168
+ def locate_additions(opts)
169
+ Smash.new.tap do |add|
170
+ opts[:manifest].each do |c_name, c_versions|
171
+ adds = c_versions - opts[:server].fetch(c_name, [])
172
+ unless(adds.empty?)
173
+ add[c_name] = adds
174
+ end
175
+ end
176
+ end
177
+ end
178
+
179
+ def generate_manifest_cookbooks
180
+ path = File.join(Dir.pwd, 'batali.manifest')
181
+ unless(File.exists?(path))
182
+ raise "Failed to locate batali manifest at: #{path}"
183
+ end
184
+ manifest = Batali::Manifest.build(path)
185
+ Smash.new.tap do |ckbks|
186
+ manifest.cookbook.each do |c|
187
+ next if Chef::Config[:knife][:batali_blacklist].include?(c.name)
188
+ ckbks[c.name] ||= []
189
+ ckbks[c.name] << c.version.to_s
190
+ end
191
+ end
192
+ end
193
+
194
+ def generate_remote_cookbooks
195
+ Smash.new.tap do |ckbks|
196
+ rest.get('cookbooks?num_versions=all').map do |c_name, meta|
197
+ next if Chef::Config[:knife][:batali_blacklist].include?(c_name)
198
+ ckbks[c_name] = []
199
+ meta['versions'].each do |info|
200
+ ckbks[c_name] << info['version']
201
+ end
202
+ end
203
+ end
204
+ end
205
+
206
+ def run_task(task)
207
+ ui.stdout.print "#{ui.color('[Batali]', :green, :bold)}: #{task}... "
208
+ begin
209
+ value = yield if block_given?
210
+ ui.info ui.color('complete', :green)
211
+ value
212
+ rescue => e
213
+ ui.info ui.color('failed', :red, :bold)
214
+ puts e.backtrace.join("\n")
215
+ raise e
216
+ end
217
+ end
218
+
219
+ end
220
+ end
221
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: batali
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.8
4
+ version: 0.3.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Roberts
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-16 00:00:00.000000000 Z
11
+ date: 2015-12-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: attribute_struct
@@ -214,6 +214,7 @@ files:
214
214
  - lib/batali/unit_loader.rb
215
215
  - lib/batali/utility.rb
216
216
  - lib/batali/version.rb
217
+ - lib/chef/knife/batali_sync.rb
217
218
  homepage: https://github.com/hw-labs/batali
218
219
  licenses:
219
220
  - Apache 2.0