batali 0.3.8 → 0.3.10

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 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