knife-playground 0.1
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/LICENSE.txt +20 -0
- data/README.md +27 -0
- data/Rakefile +33 -0
- data/VERSION +1 -0
- data/lib/chef/knife/pg.rb +271 -0
- metadata +97 -0
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Sergio Rubio <rubiojr@frameos.org>
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# knife-playground
|
2
|
+
|
3
|
+
Playground for various Opscode Chef Knife plugins
|
4
|
+
|
5
|
+
# Installing
|
6
|
+
|
7
|
+
gem install knife-playground
|
8
|
+
|
9
|
+
# Commands Available
|
10
|
+
|
11
|
+
*knife pg clientnode delete CLIENT*
|
12
|
+
|
13
|
+
Delete client + node from Opscode Chef Server
|
14
|
+
|
15
|
+
knife pg clientnode delete bluepill
|
16
|
+
|
17
|
+
*knife pg gitcook upload Git-URL1 GitURL2 ...*
|
18
|
+
|
19
|
+
Upload a cookbook to a Chef Server downloading it first from a Git repository
|
20
|
+
|
21
|
+
knife pg git cookbook upload git://github.com/rubiojr/yum-stress-cookbook.git
|
22
|
+
|
23
|
+
# Copyright
|
24
|
+
|
25
|
+
Copyright (c) 2011 Sergio Rubio. See LICENSE.txt for
|
26
|
+
further details.
|
27
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
require 'jeweler'
|
5
|
+
Jeweler::Tasks.new do |gem|
|
6
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
7
|
+
gem.version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
8
|
+
gem.name = "knife-playground"
|
9
|
+
gem.homepage = "http://github.com/rubiojr/knife-playground"
|
10
|
+
gem.license = "MIT"
|
11
|
+
gem.summary = %Q{Opscode Knife plugin with useful tools}
|
12
|
+
gem.description = %Q{Misc tools for Opscode Chef Knife}
|
13
|
+
gem.email = "rubiojr@frameos.org"
|
14
|
+
gem.authors = ["Sergio Rubio"]
|
15
|
+
# Include your dependencies below. Runtime dependencies are required when using your gem,
|
16
|
+
# and development dependencies are only needed for development (ie running rake tasks, tests, etc)
|
17
|
+
gem.add_runtime_dependency 'chef', '>= 0.10'
|
18
|
+
gem.add_runtime_dependency 'git'
|
19
|
+
# gem.add_development_dependency 'rspec', '> 1.2.3'
|
20
|
+
end
|
21
|
+
Jeweler::RubygemsDotOrgTasks.new
|
22
|
+
|
23
|
+
task :default => :build
|
24
|
+
|
25
|
+
require 'rdoc/task'
|
26
|
+
Rake::RDocTask.new do |rdoc|
|
27
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
28
|
+
|
29
|
+
rdoc.rdoc_dir = 'rdoc'
|
30
|
+
rdoc.title = "Knife Playground #{version}"
|
31
|
+
rdoc.rdoc_files.include('README*')
|
32
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
33
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1
|
@@ -0,0 +1,271 @@
|
|
1
|
+
require 'chef'
|
2
|
+
|
3
|
+
module KnifePlayground
|
4
|
+
class PgClientnodeDelete < Chef::Knife
|
5
|
+
banner "knife pg clientnode delete CLIENT"
|
6
|
+
|
7
|
+
deps do
|
8
|
+
require 'chef/node'
|
9
|
+
require 'chef/api_client'
|
10
|
+
require 'chef/json_compat'
|
11
|
+
end
|
12
|
+
|
13
|
+
def run
|
14
|
+
@client_name = @name_args[0]
|
15
|
+
if @client_name.nil?
|
16
|
+
show_usage
|
17
|
+
ui.fatal("You must specify a client name")
|
18
|
+
exit 1
|
19
|
+
end
|
20
|
+
ui.info "Deleting CLIENT #{@client_name}..."
|
21
|
+
delete_object(Chef::ApiClient, @client_name)
|
22
|
+
|
23
|
+
@node_name = @name_args[0]
|
24
|
+
if @node_name.nil?
|
25
|
+
show_usage
|
26
|
+
ui.fatal("You must specify a node name")
|
27
|
+
exit 1
|
28
|
+
end
|
29
|
+
ui.info "Deleting NODE #{@node_name}..."
|
30
|
+
delete_object(Chef::Node, @node_name)
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
class PgGitCookbookUpload < Chef::Knife
|
35
|
+
|
36
|
+
CHECKSUM = "checksum"
|
37
|
+
MATCH_CHECKSUM = /[0-9a-f]{32,}/
|
38
|
+
|
39
|
+
deps do
|
40
|
+
require 'chef/exceptions'
|
41
|
+
require 'chef/cookbook_loader'
|
42
|
+
require 'chef/cookbook_uploader'
|
43
|
+
end
|
44
|
+
|
45
|
+
banner "knife pg git cookbook upload [COOKBOOKS...] (options)"
|
46
|
+
|
47
|
+
option :cookbook_path,
|
48
|
+
:short => "-o PATH:PATH",
|
49
|
+
:long => "--cookbook-path PATH:PATH",
|
50
|
+
:description => "A colon-separated path to look for cookbooks in",
|
51
|
+
:proc => lambda { |o| o.split(":") }
|
52
|
+
|
53
|
+
option :freeze,
|
54
|
+
:long => '--freeze',
|
55
|
+
:description => 'Freeze this version of the cookbook so that it cannot be overwritten',
|
56
|
+
:boolean => true
|
57
|
+
|
58
|
+
option :all,
|
59
|
+
:short => "-a",
|
60
|
+
:long => "--all",
|
61
|
+
:description => "Upload all cookbooks, rather than just a single cookbook"
|
62
|
+
|
63
|
+
option :force,
|
64
|
+
:long => '--force',
|
65
|
+
:boolean => true,
|
66
|
+
:description => "Update cookbook versions even if they have been frozen"
|
67
|
+
|
68
|
+
option :environment,
|
69
|
+
:short => '-E',
|
70
|
+
:long => '--environment ENVIRONMENT',
|
71
|
+
:description => "Set ENVIRONMENT's version dependency match the version you're uploading.",
|
72
|
+
:default => nil
|
73
|
+
|
74
|
+
option :depends,
|
75
|
+
:short => "-d",
|
76
|
+
:long => "--include-dependencies",
|
77
|
+
:description => "Also upload cookbook dependencies"
|
78
|
+
|
79
|
+
def run
|
80
|
+
git_urls = @name_args.dup
|
81
|
+
git_urls.each do |n|
|
82
|
+
if n =~ /^git:\/\//
|
83
|
+
@name_args.delete n
|
84
|
+
git_repo = n
|
85
|
+
git_clone(git_repo)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
config[:cookbook_path] ||= Chef::Config[:cookbook_path]
|
90
|
+
|
91
|
+
assert_environment_valid!
|
92
|
+
warn_about_cookbook_shadowing
|
93
|
+
version_constraints_to_update = {}
|
94
|
+
# Get a list of cookbooks and their versions from the server
|
95
|
+
# for checking existence of dependending cookbooks.
|
96
|
+
@server_side_cookbooks = Chef::CookbookVersion.list
|
97
|
+
|
98
|
+
if config[:all]
|
99
|
+
justify_width = cookbook_repo.cookbook_names.map {|name| name.size}.max.to_i + 2
|
100
|
+
cookbook_repo.each do |cookbook_name, cookbook|
|
101
|
+
cookbook.freeze_version if config[:freeze]
|
102
|
+
upload(cookbook, justify_width)
|
103
|
+
version_constraints_to_update[cookbook_name] = cookbook.version
|
104
|
+
end
|
105
|
+
else
|
106
|
+
if @name_args.empty?
|
107
|
+
show_usage
|
108
|
+
ui.error("You must specify the --all flag or at least one cookbook name")
|
109
|
+
exit 1
|
110
|
+
end
|
111
|
+
justify_width = @name_args.map {|name| name.size }.max.to_i + 2
|
112
|
+
@name_args.each do |cookbook_name|
|
113
|
+
begin
|
114
|
+
cookbook = cookbook_repo[cookbook_name]
|
115
|
+
if config[:depends]
|
116
|
+
cookbook.metadata.dependencies.each do |dep, versions|
|
117
|
+
@name_args.push dep
|
118
|
+
end
|
119
|
+
end
|
120
|
+
cookbook.freeze_version if config[:freeze]
|
121
|
+
upload(cookbook, justify_width)
|
122
|
+
version_constraints_to_update[cookbook_name] = cookbook.version
|
123
|
+
rescue Exceptions::CookbookNotFoundInRepo => e
|
124
|
+
ui.error("Could not find cookbook #{cookbook_name} in your cookbook path, skipping it")
|
125
|
+
Log.debug(e)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
ui.info "upload complete"
|
131
|
+
update_version_constraints(version_constraints_to_update) if config[:environment]
|
132
|
+
end
|
133
|
+
|
134
|
+
def cookbook_repo
|
135
|
+
@cookbook_loader ||= begin
|
136
|
+
Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, config[:cookbook_path]) }
|
137
|
+
Chef::CookbookLoader.new(config[:cookbook_path])
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def update_version_constraints(new_version_constraints)
|
142
|
+
new_version_constraints.each do |cookbook_name, version|
|
143
|
+
environment.cookbook_versions[cookbook_name] = "= #{version}"
|
144
|
+
end
|
145
|
+
environment.save
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
def environment
|
150
|
+
@environment ||= config[:environment] ? Environment.load(config[:environment]) : nil
|
151
|
+
end
|
152
|
+
|
153
|
+
def warn_about_cookbook_shadowing
|
154
|
+
unless cookbook_repo.merged_cookbooks.empty?
|
155
|
+
ui.warn "* " * 40
|
156
|
+
ui.warn(<<-WARNING)
|
157
|
+
The cookbooks: #{cookbook_repo.merged_cookbooks.join(', ')} exist in multiple places in your cookbook_path.
|
158
|
+
A composite version of these cookbooks has been compiled for uploading.
|
159
|
+
|
160
|
+
#{ui.color('IMPORTANT:', :red, :bold)} In a future version of Chef, this behavior will be removed and you will no longer
|
161
|
+
be able to have the same version of a cookbook in multiple places in your cookbook_path.
|
162
|
+
WARNING
|
163
|
+
ui.warn "The affected cookbooks are located:"
|
164
|
+
ui.output ui.format_for_display(cookbook_repo.merged_cookbook_paths)
|
165
|
+
ui.warn "* " * 40
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
private
|
170
|
+
|
171
|
+
def git_clone(url, opts = {})
|
172
|
+
repo = File.basename(URI.parse(url).path.split('/').last, '.git')
|
173
|
+
@name_args << repo
|
174
|
+
path = File.join(Chef::Config[:cookbook_path], repo)
|
175
|
+
# Error if previous checkout exist
|
176
|
+
if File.directory?(path + '/.git')
|
177
|
+
ui.info "Cookbook #{repo} already downloaded."
|
178
|
+
else
|
179
|
+
ui.info "Downloading cookbook from #{url}"
|
180
|
+
Git.clone url, path, opts
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def assert_environment_valid!
|
185
|
+
environment
|
186
|
+
rescue Net::HTTPServerException => e
|
187
|
+
if e.response.code.to_s == "404"
|
188
|
+
ui.error "The environment #{config[:environment]} does not exist on the server, aborting."
|
189
|
+
Log.debug(e)
|
190
|
+
exit 1
|
191
|
+
else
|
192
|
+
raise
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def upload(cookbook, justify_width)
|
197
|
+
ui.info("Uploading #{cookbook.name.to_s.ljust(justify_width + 10)} [#{cookbook.version}]")
|
198
|
+
|
199
|
+
check_for_broken_links(cookbook)
|
200
|
+
check_dependencies(cookbook)
|
201
|
+
Chef::CookbookUploader.new(cookbook, config[:cookbook_path], :force => config[:force]).upload_cookbook
|
202
|
+
rescue Net::HTTPServerException => e
|
203
|
+
case e.response.code
|
204
|
+
when "409"
|
205
|
+
ui.error "Version #{cookbook.version} of cookbook #{cookbook.name} is frozen. Use --force to override."
|
206
|
+
Log.debug(e)
|
207
|
+
else
|
208
|
+
raise
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
# if only you people wouldn't put broken symlinks in your cookbooks in
|
213
|
+
# the first place. ;)
|
214
|
+
def check_for_broken_links(cookbook)
|
215
|
+
# MUST!! dup the cookbook version object--it memoizes its
|
216
|
+
# manifest object, but the manifest becomes invalid when you
|
217
|
+
# regenerate the metadata
|
218
|
+
broken_files = cookbook.dup.manifest_records_by_path.select do |path, info|
|
219
|
+
info[CHECKSUM].nil? || info[CHECKSUM] !~ MATCH_CHECKSUM
|
220
|
+
end
|
221
|
+
unless broken_files.empty?
|
222
|
+
broken_filenames = Array(broken_files).map {|path, info| path}
|
223
|
+
ui.error "The cookbook #{cookbook.name} has one or more broken files"
|
224
|
+
ui.info "This is probably caused by broken symlinks in the cookbook directory"
|
225
|
+
ui.info "The broken file(s) are: #{broken_filenames.join(' ')}"
|
226
|
+
exit 1
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
def check_dependencies(cookbook)
|
231
|
+
# for each dependency, check if the version is on the server, or
|
232
|
+
# the version is in the cookbooks being uploaded. If not, exit and warn the user.
|
233
|
+
cookbook.metadata.dependencies.each do |cookbook_name, version|
|
234
|
+
unless check_server_side_cookbooks(cookbook_name, version) || check_uploading_cookbooks(cookbook_name, version)
|
235
|
+
# warn the user and exit
|
236
|
+
ui.error "Cookbook #{cookbook.name} depends on cookbook #{cookbook_name} version #{version},"
|
237
|
+
ui.error "which is not currently being uploaded and cannot be found on the server."
|
238
|
+
exit 1
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
def check_server_side_cookbooks(cookbook_name, version)
|
244
|
+
if @server_side_cookbooks[cookbook_name].nil?
|
245
|
+
false
|
246
|
+
else
|
247
|
+
@server_side_cookbooks[cookbook_name]["versions"].each do |versions_hash|
|
248
|
+
return true if Chef::VersionConstraint.new(version).include?(versions_hash["version"])
|
249
|
+
end
|
250
|
+
false
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
def check_uploading_cookbooks(cookbook_name, version)
|
255
|
+
if config[:all]
|
256
|
+
# check from all local cookbooks in the path
|
257
|
+
unless cookbook_repo[cookbook_name].nil?
|
258
|
+
return Chef::VersionConstraint.new(version).include?(cookbook_repo[cookbook_name].version)
|
259
|
+
end
|
260
|
+
else
|
261
|
+
# check from only those in the command argument
|
262
|
+
if @name_args.include?(cookbook_name)
|
263
|
+
return Chef::VersionConstraint.new(version).include?(cookbook_repo[cookbook_name].version)
|
264
|
+
end
|
265
|
+
end
|
266
|
+
false
|
267
|
+
end
|
268
|
+
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
metadata
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: knife-playground
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 9
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: "0.1"
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Sergio Rubio
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-08-10 00:00:00 Z
|
18
|
+
dependencies:
|
19
|
+
- !ruby/object:Gem::Dependency
|
20
|
+
name: chef
|
21
|
+
prerelease: false
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
+
none: false
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
hash: 31
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
- 10
|
31
|
+
version: "0.10"
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: git
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
hash: 3
|
43
|
+
segments:
|
44
|
+
- 0
|
45
|
+
version: "0"
|
46
|
+
type: :runtime
|
47
|
+
version_requirements: *id002
|
48
|
+
description: Misc tools for Opscode Chef Knife
|
49
|
+
email: rubiojr@frameos.org
|
50
|
+
executables: []
|
51
|
+
|
52
|
+
extensions: []
|
53
|
+
|
54
|
+
extra_rdoc_files:
|
55
|
+
- LICENSE.txt
|
56
|
+
- README.md
|
57
|
+
files:
|
58
|
+
- LICENSE.txt
|
59
|
+
- README.md
|
60
|
+
- Rakefile
|
61
|
+
- VERSION
|
62
|
+
- lib/chef/knife/pg.rb
|
63
|
+
homepage: http://github.com/rubiojr/knife-playground
|
64
|
+
licenses:
|
65
|
+
- MIT
|
66
|
+
post_install_message:
|
67
|
+
rdoc_options: []
|
68
|
+
|
69
|
+
require_paths:
|
70
|
+
- lib
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
hash: 3
|
77
|
+
segments:
|
78
|
+
- 0
|
79
|
+
version: "0"
|
80
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
hash: 3
|
86
|
+
segments:
|
87
|
+
- 0
|
88
|
+
version: "0"
|
89
|
+
requirements: []
|
90
|
+
|
91
|
+
rubyforge_project:
|
92
|
+
rubygems_version: 1.8.5
|
93
|
+
signing_key:
|
94
|
+
specification_version: 3
|
95
|
+
summary: Opscode Knife plugin with useful tools
|
96
|
+
test_files: []
|
97
|
+
|