knife_cookbook_sync 0.0.1 → 0.0.2
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.
- data/CHANGELOG.md +11 -0
- data/README.md +2 -2
- data/lib/chef/knife/cookbook_sync.rb +43 -51
- data/lib/knife_cookbook_sync/version.rb +1 -1
- metadata +3 -2
data/CHANGELOG.md
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
0.0.2
|
2
|
+
=====
|
3
|
+
* honor knife.rb configuration of cookbook path
|
4
|
+
* add a quiet option (-q). dry run is unaffected.
|
5
|
+
* check if the cookbook exists before loading it. vastly improves upload performance for new cookbooks.
|
6
|
+
* exploit recent threaded upload improvements in Chef API: 0.1s slower than knife cookbook upload for all new content (worst case for sync).
|
7
|
+
|
8
|
+
0.0.1
|
9
|
+
=====
|
10
|
+
|
11
|
+
* First public release.
|
data/README.md
CHANGED
@@ -7,7 +7,7 @@ production work with careful coordination with an external cookbook resolver.
|
|
7
7
|
|
8
8
|
Here's the meat. `knife cookbook sync` vs `knife cookbook upload` with a
|
9
9
|
pre-uploaded corpus of 39 cookbooks, using the standard unix `time` utility to
|
10
|
-
benchmark on MRI 1.9.3-p327:
|
10
|
+
benchmark on MRI 1.9.3-p327 and chef 10.16.2:
|
11
11
|
|
12
12
|
* `knife cookbook sync -a`: 1.31s user 0.15s system 72% cpu **2.020 total**
|
13
13
|
* `knife cookbook upload -a`: 1.34s user 0.15s system 15% cpu **9.684 total**
|
@@ -18,7 +18,7 @@ to be uploaded, and only uploads what's different.
|
|
18
18
|
|
19
19
|
This means it **does not check versions and dependencies**. It cheats, so you
|
20
20
|
should be sure you have your ducks in a row before uploading by using a
|
21
|
-
cookbook resolver. This only matters for
|
21
|
+
cookbook resolver. This only matters for determining what to upload -- cookbooks
|
22
22
|
uploaded with `knife cookbook sync` are no different otherwise (and in fact use
|
23
23
|
chef's own cookbook uploading tooling to do it).
|
24
24
|
|
@@ -1,7 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
Thread.abort_on_exception = true
|
4
|
-
|
5
3
|
module Knife
|
6
4
|
class CookbookSync < Chef::Knife
|
7
5
|
|
@@ -12,6 +10,7 @@ module Knife
|
|
12
10
|
require 'chef/cookbook_loader'
|
13
11
|
require 'chef/cookbook_uploader'
|
14
12
|
require 'chef/cookbook_version'
|
13
|
+
require 'chef/log'
|
15
14
|
end
|
16
15
|
|
17
16
|
banner "knife cookbook sync [COOKBOOKS...]"
|
@@ -31,36 +30,53 @@ module Knife
|
|
31
30
|
option :cookbook_path,
|
32
31
|
:short => '-o [COOKBOOK PATH]',
|
33
32
|
:long => '--cookbook-path [COOKBOOK PATH]',
|
34
|
-
:default => %w[cookbooks site-cookbooks],
|
35
33
|
:description => "The path that cookbooks should be loaded from (path:path)",
|
36
34
|
:proc => proc { |x| x.split(":") }
|
37
|
-
|
35
|
+
|
36
|
+
option :quiet,
|
37
|
+
:short => '-q',
|
38
|
+
:long => '--quiet',
|
39
|
+
:description => "Make less noise",
|
40
|
+
:default => false
|
41
|
+
|
42
|
+
def make_noise(&block)
|
43
|
+
force_make_noise(&block) if block and !config[:quiet]
|
44
|
+
end
|
45
|
+
|
46
|
+
def force_make_noise(&block)
|
47
|
+
@print_mutex.synchronize(&block) if block
|
48
|
+
end
|
38
49
|
|
39
50
|
def distill_manifest(cookbook)
|
40
51
|
files = { }
|
41
52
|
cookbook.manifest.values.select { |x| x.kind_of?(Array) }.flatten.each { |f| files[f['path']] = f['checksum'] }
|
42
53
|
# don't check metadata.json since json output is indeterministic, metadata.rb should be all that's needed anw
|
43
|
-
files.delete('metadata.json')
|
54
|
+
files.delete('metadata.json')
|
44
55
|
return files
|
45
56
|
end
|
46
57
|
|
47
58
|
def sync_cookbooks(cookbooks, cl)
|
48
|
-
|
59
|
+
log_level = Chef::Log.level
|
60
|
+
|
61
|
+
# mutes the CookbookVersion noise when the cookbook doesn't exist on the server.
|
62
|
+
Chef::Log.level = :fatal
|
49
63
|
|
50
|
-
|
64
|
+
to_upload = Queue.new
|
51
65
|
|
52
|
-
cookbooks.each do |cookbook|
|
66
|
+
cookbooks.map(&:to_s).each do |cookbook|
|
53
67
|
Thread.new do
|
54
|
-
upload = false
|
55
|
-
|
68
|
+
upload = false
|
69
|
+
|
70
|
+
make_noise do
|
56
71
|
ui.msg "Checking cookbook '#{cookbook}' for sync necessity"
|
57
72
|
end
|
58
73
|
|
59
|
-
remote_cookbook = Chef::CookbookVersion.
|
74
|
+
remote_cookbook = Chef::CookbookVersion.available_versions(cookbook) &&
|
75
|
+
(Chef::CookbookVersion.load(cookbook.to_s) rescue nil)
|
60
76
|
local_cookbook = cl[cookbook.to_s] rescue nil
|
61
77
|
|
62
78
|
unless local_cookbook
|
63
|
-
|
79
|
+
make_noise do
|
64
80
|
ui.fatal "Cookbook '#{cookbook}' does not exist locally."
|
65
81
|
end
|
66
82
|
exit 1
|
@@ -85,57 +101,33 @@ module Knife
|
|
85
101
|
end
|
86
102
|
|
87
103
|
if upload
|
88
|
-
|
104
|
+
make_noise do
|
89
105
|
ui.msg "sync necessary; uploading '#{cookbook}'"
|
90
106
|
end
|
91
107
|
|
92
|
-
|
93
|
-
|
94
|
-
begin
|
95
|
-
#
|
96
|
-
# XXX
|
97
|
-
#
|
98
|
-
# For some godawful reason, if we use the local_cookbook referenced
|
99
|
-
# above, the MD5 sums are off.
|
100
|
-
#
|
101
|
-
# So we reload the cookbooks here because it seems to work, with an
|
102
|
-
# optional retry if the chef server is being pissy.
|
103
|
-
#
|
104
|
-
cl = Chef::CookbookLoader.new(Chef::Config[:cookbook_path])
|
105
|
-
|
106
|
-
if config[:dry_run]
|
107
|
-
print_mutex.synchronize do
|
108
|
-
ui.warn "dry run: would sync '#{cookbook}'"
|
109
|
-
end
|
110
|
-
else
|
111
|
-
Chef::CookbookUploader.new(cl[cookbook], Chef::Config[:cookbook_path]).upload_cookbooks
|
112
|
-
end
|
113
|
-
|
114
|
-
uploaded = true
|
115
|
-
rescue Exception => e
|
116
|
-
print_mutex.synchronize do
|
117
|
-
ui.error "Failed to upload; retrying up to #{retries_left} times"
|
118
|
-
end
|
119
|
-
|
120
|
-
retries_left -= 1
|
121
|
-
if retries_left > 0
|
122
|
-
retry
|
123
|
-
else
|
124
|
-
raise e
|
125
|
-
end
|
126
|
-
end
|
108
|
+
to_upload << cl[cookbook]
|
127
109
|
end
|
128
110
|
end
|
129
111
|
end
|
130
112
|
|
131
|
-
Thread.list.reject { |x| x == Thread.current }.each(&:join)
|
113
|
+
Thread.list.reject { |x| x == Thread.current }.each(&:join) # wait for threads to settle
|
114
|
+
|
115
|
+
cookbooks_to_upload = []
|
116
|
+
loop { cookbooks_to_upload << to_upload.shift(true) } rescue nil
|
117
|
+
|
118
|
+
Chef::Log.level = log_level # restore log level now that we're done checking
|
119
|
+
Chef::CookbookUploader.new(cookbooks_to_upload, Chef::Config[:cookbook_path]).upload_cookbooks
|
132
120
|
|
133
121
|
# exit with an exit status of 5 if we've uploaded anything.
|
134
|
-
exit
|
122
|
+
exit cookbooks_to_upload.empty? ? 0 : 5
|
135
123
|
end
|
136
124
|
|
137
125
|
def run
|
138
|
-
|
126
|
+
Thread.abort_on_exception = true
|
127
|
+
|
128
|
+
@print_mutex = Mutex.new
|
129
|
+
|
130
|
+
Chef::Config[:cookbook_path] = config[:cookbook_path] if config[:cookbook_path]
|
139
131
|
|
140
132
|
Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest) }
|
141
133
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: knife_cookbook_sync
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-01-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: chef
|
@@ -35,6 +35,7 @@ extensions: []
|
|
35
35
|
extra_rdoc_files: []
|
36
36
|
files:
|
37
37
|
- .gitignore
|
38
|
+
- CHANGELOG.md
|
38
39
|
- Gemfile
|
39
40
|
- LICENSE.txt
|
40
41
|
- README.md
|