chef 11.12.0.alpha.1 → 11.12.0.rc.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/chef/api_client/registration.rb +46 -9
- data/lib/chef/application.rb +1 -0
- data/lib/chef/application/client.rb +25 -24
- data/lib/chef/client.rb +34 -0
- data/lib/chef/config.rb +11 -0
- data/lib/chef/cookbook/chefignore.rb +10 -2
- data/lib/chef/cookbook/metadata.rb +31 -3
- data/lib/chef/cookbook/synchronizer.rb +2 -2
- data/lib/chef/cookbook/syntax_check.rb +4 -4
- data/lib/chef/encrypted_data_bag_item.rb +37 -1
- data/lib/chef/exceptions.rb +1 -0
- data/lib/chef/guard_interpreter/default_guard_interpreter.rb +42 -0
- data/lib/chef/guard_interpreter/resource_guard_interpreter.rb +122 -0
- data/lib/chef/http.rb +0 -1
- data/lib/chef/http/decompressor.rb +7 -4
- data/lib/chef/http/simple.rb +5 -0
- data/lib/chef/http/validate_content_length.rb +28 -12
- data/lib/chef/knife.rb +1 -0
- data/lib/chef/knife/client_bulk_delete.rb +48 -9
- data/lib/chef/knife/client_delete.rb +4 -4
- data/lib/chef/knife/cookbook_bulk_delete.rb +1 -1
- data/lib/chef/knife/cookbook_upload.rb +17 -7
- data/lib/chef/knife/core/bootstrap_context.rb +1 -1
- data/lib/chef/knife/core/ui.rb +42 -5
- data/lib/chef/knife/node_run_list_add.rb +31 -2
- data/lib/chef/knife/ssh.rb +44 -31
- data/lib/chef/knife/ssl_check.rb +213 -0
- data/lib/chef/knife/ssl_fetch.rb +145 -0
- data/lib/chef/mixin/deep_merge.rb +13 -5
- data/lib/chef/mixin/shell_out.rb +9 -3
- data/lib/chef/node.rb +23 -4
- data/lib/chef/node/immutable_collections.rb +32 -0
- data/lib/chef/platform/provider_mapping.rb +21 -18
- data/lib/chef/platform/query_helpers.rb +10 -2
- data/lib/chef/policy_builder/expand_node_object.rb +3 -6
- data/lib/chef/provider/cron.rb +25 -3
- data/lib/chef/provider/mount/mount.rb +1 -1
- data/lib/chef/provider/package/dpkg.rb +2 -1
- data/lib/chef/provider/package/windows.rb +80 -0
- data/lib/chef/provider/package/windows/msi.rb +69 -0
- data/lib/chef/provider/powershell_script.rb +19 -6
- data/lib/chef/provider/service/solaris.rb +11 -7
- data/lib/chef/resource.rb +18 -5
- data/lib/chef/resource/conditional.rb +20 -7
- data/lib/chef/resource/cron.rb +18 -2
- data/lib/chef/resource/execute.rb +0 -2
- data/lib/chef/resource/powershell_script.rb +23 -1
- data/lib/chef/resource/script.rb +25 -0
- data/lib/chef/resource/subversion.rb +4 -0
- data/lib/chef/resource/windows_package.rb +79 -0
- data/lib/chef/resource/windows_script.rb +0 -5
- data/lib/chef/resources.rb +1 -0
- data/lib/chef/rest.rb +6 -1
- data/lib/chef/run_context.rb +22 -2
- data/lib/chef/run_context/cookbook_compiler.rb +12 -0
- data/lib/chef/util/editor.rb +92 -0
- data/lib/chef/util/file_edit.rb +22 -54
- data/lib/chef/version.rb +2 -2
- data/lib/chef/win32/api/installer.rb +166 -0
- data/lib/chef/win32/version.rb +8 -0
- data/spec/data/standalone_cookbook/Gemfile +1 -0
- data/spec/data/standalone_cookbook/chefignore +9 -0
- data/spec/data/standalone_cookbook/recipes/default.rb +3 -0
- data/spec/data/standalone_cookbook/vendor/bundle/ruby/2.0.0/gems/multi_json-1.9.0/lib/multi_json.rb +1 -0
- data/spec/functional/resource/powershell_spec.rb +262 -1
- data/spec/functional/win32/versions_spec.rb +3 -3
- data/spec/integration/knife/chefignore_spec.rb +1 -2
- data/spec/integration/knife/raw_spec.rb +8 -13
- data/spec/integration/knife/redirection_spec.rb +6 -14
- data/spec/integration/solo/solo_spec.rb +19 -0
- data/spec/support/shared/functional/windows_script.rb +1 -1
- data/spec/support/shared/integration/app_server_support.rb +42 -0
- data/spec/support/shared/integration/integration_helper.rb +1 -0
- data/spec/support/shared/unit/script_resource.rb +38 -0
- data/spec/unit/api_client/registration_spec.rb +109 -38
- data/spec/unit/application/client_spec.rb +48 -1
- data/spec/unit/cookbook/chefignore_spec.rb +10 -0
- data/spec/unit/cookbook/metadata_spec.rb +45 -1
- data/spec/unit/cookbook/syntax_check_spec.rb +28 -0
- data/spec/unit/cookbook_spec.rb +0 -10
- data/spec/unit/guard_interpreter/resource_guard_interpreter_spec.rb +56 -0
- data/spec/unit/http/simple_spec.rb +32 -0
- data/spec/unit/http/validate_content_length_spec.rb +187 -0
- data/spec/unit/knife/bootstrap_spec.rb +13 -4
- data/spec/unit/knife/client_bulk_delete_spec.rb +123 -38
- data/spec/unit/knife/client_delete_spec.rb +4 -4
- data/spec/unit/knife/cookbook_upload_spec.rb +181 -88
- data/spec/unit/knife/core/bootstrap_context_spec.rb +11 -1
- data/spec/unit/knife/core/ui_spec.rb +109 -38
- data/spec/unit/knife/node_run_list_add_spec.rb +24 -1
- data/spec/unit/knife/ssh_spec.rb +17 -6
- data/spec/unit/knife/ssl_check_spec.rb +187 -0
- data/spec/unit/knife/ssl_fetch_spec.rb +151 -0
- data/spec/unit/mixin/deep_merge_spec.rb +17 -0
- data/spec/unit/node/immutable_collections_spec.rb +55 -0
- data/spec/unit/node_spec.rb +9 -0
- data/spec/unit/platform/query_helpers_spec.rb +32 -0
- data/spec/unit/platform_spec.rb +193 -175
- data/spec/unit/policy_builder/expand_node_object_spec.rb +1 -1
- data/spec/unit/provider/cron_spec.rb +175 -1
- data/spec/unit/provider/mount/mount_spec.rb +33 -3
- data/spec/unit/provider/package/dpkg_spec.rb +4 -0
- data/spec/unit/provider/package/windows/msi_spec.rb +60 -0
- data/spec/unit/provider/package/windows_spec.rb +80 -0
- data/spec/unit/provider/service/macosx_spec.rb +3 -3
- data/spec/unit/provider/service/solaris_smf_service_spec.rb +35 -10
- data/spec/unit/pure_application_spec.rb +32 -0
- data/spec/unit/recipe_spec.rb +4 -0
- data/spec/unit/resource/conditional_spec.rb +13 -12
- data/spec/unit/resource/cron_spec.rb +7 -2
- data/spec/unit/resource/powershell_spec.rb +85 -2
- data/spec/unit/resource/subversion_spec.rb +5 -0
- data/spec/unit/resource/windows_package_spec.rb +74 -0
- data/spec/unit/resource_spec.rb +23 -1
- data/spec/unit/rest_spec.rb +15 -0
- data/spec/unit/run_context/cookbook_compiler_spec.rb +12 -0
- data/spec/unit/run_context_spec.rb +7 -0
- data/spec/unit/util/editor_spec.rb +152 -0
- data/spec/unit/util/file_edit_spec.rb +37 -1
- metadata +41 -30
data/lib/chef/exceptions.rb
CHANGED
@@ -76,6 +76,7 @@ class Chef
|
|
76
76
|
class CookbookNotFoundInRepo < ArgumentError; end
|
77
77
|
class RecipeNotFound < ArgumentError; end
|
78
78
|
class AttributeNotFound < RuntimeError; end
|
79
|
+
class MissingCookbookDependency < StandardError; end # CHEF-5120
|
79
80
|
class InvalidCommandOption < RuntimeError; end
|
80
81
|
class CommandTimeout < RuntimeError; end
|
81
82
|
class RequestedUIDUnavailable < RuntimeError; end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Adam Edwards (<adamed@getchef.com>)
|
3
|
+
# Copyright:: Copyright (c) 2014 Chef Software, Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
class Chef
|
20
|
+
class GuardInterpreter
|
21
|
+
class DefaultGuardInterpreter
|
22
|
+
include Chef::Mixin::ShellOut
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
def initialize(command, opts)
|
27
|
+
@command = command
|
28
|
+
@command_opts = opts
|
29
|
+
end
|
30
|
+
|
31
|
+
public
|
32
|
+
|
33
|
+
def evaluate
|
34
|
+
shell_out(@command, @command_opts).status.success?
|
35
|
+
rescue Chef::Exceptions::CommandTimeout
|
36
|
+
Chef::Log.warn "Command '#{@command}' timed out"
|
37
|
+
false
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
@@ -0,0 +1,122 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Adam Edwards (<adamed@getchef.com>)
|
3
|
+
# Copyright:: Copyright (c) 2014 Opscode, Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
require 'chef/guard_interpreter/default_guard_interpreter'
|
20
|
+
|
21
|
+
class Chef
|
22
|
+
class GuardInterpreter
|
23
|
+
class ResourceGuardInterpreter < DefaultGuardInterpreter
|
24
|
+
|
25
|
+
def initialize(parent_resource, command, opts, &block)
|
26
|
+
super(command, opts)
|
27
|
+
@parent_resource = parent_resource
|
28
|
+
@resource = get_interpreter_resource(parent_resource)
|
29
|
+
end
|
30
|
+
|
31
|
+
def evaluate
|
32
|
+
# Add attributes inherited from the parent class
|
33
|
+
# to the resource
|
34
|
+
merge_inherited_attributes
|
35
|
+
|
36
|
+
# Script resources have a code attribute, which is
|
37
|
+
# what is used to execute the command, so include
|
38
|
+
# that with attributes specified by caller in opts
|
39
|
+
block_attributes = @command_opts.merge({:code => @command})
|
40
|
+
|
41
|
+
# Handles cases like powershell_script where default
|
42
|
+
# attributes are different when used in a guard vs. not. For
|
43
|
+
# powershell_script in particular, this will go away when
|
44
|
+
# the one attribue that causes this changes its default to be
|
45
|
+
# the same after some period to prepare for deprecation
|
46
|
+
if @resource.class.respond_to?(:get_default_attributes)
|
47
|
+
block_attributes = @resource.class.send(:get_default_attributes, @command_opts).merge(block_attributes)
|
48
|
+
end
|
49
|
+
|
50
|
+
resource_block = block_from_attributes(block_attributes)
|
51
|
+
evaluate_action(nil, &resource_block)
|
52
|
+
end
|
53
|
+
|
54
|
+
protected
|
55
|
+
|
56
|
+
def evaluate_action(action=nil, &block)
|
57
|
+
@resource.instance_eval(&block)
|
58
|
+
|
59
|
+
run_action = action || @resource.action
|
60
|
+
|
61
|
+
begin
|
62
|
+
@resource.run_action(run_action)
|
63
|
+
resource_updated = @resource.updated
|
64
|
+
rescue Mixlib::ShellOut::ShellCommandFailed
|
65
|
+
resource_updated = nil
|
66
|
+
end
|
67
|
+
|
68
|
+
resource_updated
|
69
|
+
end
|
70
|
+
|
71
|
+
def get_interpreter_resource(parent_resource)
|
72
|
+
if parent_resource.nil? || parent_resource.node.nil?
|
73
|
+
raise ArgumentError, "Node for guard resource parent must not be nil"
|
74
|
+
end
|
75
|
+
|
76
|
+
resource_class = Chef::Resource.resource_for_node(parent_resource.guard_interpreter, parent_resource.node)
|
77
|
+
|
78
|
+
if resource_class.nil?
|
79
|
+
raise ArgumentError, "Specified guard_interpreter resource #{parent_resource.guard_interpreter.to_s} unknown for this platform"
|
80
|
+
end
|
81
|
+
|
82
|
+
if ! resource_class.ancestors.include?(Chef::Resource::Script)
|
83
|
+
raise ArgumentError, "Specified guard interpreter class #{resource_class} must be a kind of Chef::Resource::Script resource"
|
84
|
+
end
|
85
|
+
|
86
|
+
empty_events = Chef::EventDispatch::Dispatcher.new
|
87
|
+
anonymous_run_context = Chef::RunContext.new(parent_resource.node, {}, empty_events)
|
88
|
+
interpreter_resource = resource_class.new('Guard resource', anonymous_run_context)
|
89
|
+
|
90
|
+
interpreter_resource
|
91
|
+
end
|
92
|
+
|
93
|
+
def block_from_attributes(attributes)
|
94
|
+
Proc.new do
|
95
|
+
attributes.keys.each do |attribute_name|
|
96
|
+
send(attribute_name, attributes[attribute_name]) if respond_to?(attribute_name)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def merge_inherited_attributes
|
102
|
+
inherited_attributes = []
|
103
|
+
|
104
|
+
if @parent_resource.class.respond_to?(:guard_inherited_attributes)
|
105
|
+
inherited_attributes = @parent_resource.class.send(:guard_inherited_attributes)
|
106
|
+
end
|
107
|
+
|
108
|
+
if inherited_attributes && !inherited_attributes.empty?
|
109
|
+
inherited_attributes.each do |attribute|
|
110
|
+
if @parent_resource.respond_to?(attribute) && @resource.respond_to?(attribute)
|
111
|
+
parent_value = @parent_resource.send(attribute)
|
112
|
+
child_value = @resource.send(attribute)
|
113
|
+
if parent_value || child_value
|
114
|
+
@resource.send(attribute, parent_value)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
data/lib/chef/http.rb
CHANGED
@@ -94,16 +94,21 @@ class Chef
|
|
94
94
|
# object you can use to unzip/inflate a streaming response.
|
95
95
|
def stream_response_handler(response)
|
96
96
|
if gzip_disabled?
|
97
|
+
Chef::Log.debug "disable_gzip is set. \
|
98
|
+
Not using #{response[CONTENT_ENCODING]} \
|
99
|
+
and initializing noop stream deflator."
|
97
100
|
NoopInflater.new
|
98
101
|
else
|
99
102
|
case response[CONTENT_ENCODING]
|
100
103
|
when GZIP
|
101
|
-
Chef::Log.debug "
|
104
|
+
Chef::Log.debug "Initializing gzip stream deflator"
|
102
105
|
GzipInflater.new
|
103
106
|
when DEFLATE
|
104
|
-
Chef::Log.debug "
|
107
|
+
Chef::Log.debug "Initializing deflate stream deflator"
|
105
108
|
DeflateInflater.new
|
106
109
|
else
|
110
|
+
Chef::Log.debug "content_encoding = '#{response[CONTENT_ENCODING]}' \
|
111
|
+
initializing noop stream deflator."
|
107
112
|
NoopInflater.new
|
108
113
|
end
|
109
114
|
end
|
@@ -137,5 +142,3 @@ class Chef
|
|
137
142
|
end
|
138
143
|
end
|
139
144
|
end
|
140
|
-
|
141
|
-
|
data/lib/chef/http/simple.rb
CHANGED
@@ -49,22 +49,20 @@ class Chef
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def handle_response(http_response, rest_request, return_value)
|
52
|
-
|
53
|
-
Chef::Log.debug("HTTP server did not include a Content-Length header in response, cannot identify truncated downloads.")
|
54
|
-
return [http_response, rest_request, return_value]
|
55
|
-
end
|
56
|
-
validate(response_content_length(http_response), http_response.body.bytesize)
|
52
|
+
validate(http_response, http_response.body.bytesize) if http_response && http_response.body
|
57
53
|
return [http_response, rest_request, return_value]
|
58
54
|
end
|
59
55
|
|
60
56
|
def handle_stream_complete(http_response, rest_request, return_value)
|
61
|
-
if
|
62
|
-
Chef::Log.debug("HTTP server did not include a Content-Length header in response, cannot idenfity streamed download.")
|
63
|
-
elsif @content_length_counter.nil?
|
57
|
+
if @content_length_counter.nil?
|
64
58
|
Chef::Log.debug("No content-length information collected for the streamed download, cannot identify streamed download.")
|
65
59
|
else
|
66
|
-
validate(
|
60
|
+
validate(http_response, @content_length_counter.content_length)
|
67
61
|
end
|
62
|
+
|
63
|
+
# Make sure the counter is reset since this object might get used
|
64
|
+
# again. See CHEF-5100
|
65
|
+
@content_length_counter = nil
|
68
66
|
return [http_response, rest_request, return_value]
|
69
67
|
end
|
70
68
|
|
@@ -73,7 +71,9 @@ class Chef
|
|
73
71
|
end
|
74
72
|
|
75
73
|
private
|
74
|
+
|
76
75
|
def response_content_length(response)
|
76
|
+
return nil if response['content-length'].nil?
|
77
77
|
if response['content-length'].is_a?(Array)
|
78
78
|
response['content-length'].first.to_i
|
79
79
|
else
|
@@ -81,12 +81,28 @@ class Chef
|
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
84
|
-
def validate(
|
85
|
-
|
86
|
-
|
84
|
+
def validate(http_response, response_length)
|
85
|
+
content_length = response_content_length(http_response)
|
86
|
+
transfer_encoding = http_response['transfer-encoding']
|
87
|
+
content_encoding = http_response['content-encoding']
|
88
|
+
|
89
|
+
if content_length.nil?
|
90
|
+
Chef::Log.debug "HTTP server did not include a Content-Length header in response, cannot identify truncated downloads."
|
91
|
+
return true
|
92
|
+
end
|
93
|
+
|
94
|
+
# if Transfer-Encoding is set the RFC states that we must ignore the Content-Length field
|
95
|
+
# CHEF-5041: some proxies uncompress gzip content, leave the incorrect content-length, but set the transfer-encoding field
|
96
|
+
unless transfer_encoding.nil?
|
97
|
+
Chef::Log.debug "Transfer-Encoding header is set, skipping Content-Length check."
|
98
|
+
return true
|
99
|
+
end
|
100
|
+
|
87
101
|
if response_length != content_length
|
88
102
|
raise Chef::Exceptions::ContentLengthMismatch.new(response_length, content_length)
|
89
103
|
end
|
104
|
+
|
105
|
+
Chef::Log.debug "Content-Length validated correctly."
|
90
106
|
true
|
91
107
|
end
|
92
108
|
end
|
data/lib/chef/knife.rb
CHANGED
@@ -421,6 +421,7 @@ class Chef
|
|
421
421
|
|
422
422
|
# Don't try to load a knife.rb if it wasn't specified.
|
423
423
|
if config[:config_file]
|
424
|
+
Chef::Config.config_file = config[:config_file]
|
424
425
|
fetcher = Chef::ConfigFetcher.new(config[:config_file], Chef::Config.config_file_jail)
|
425
426
|
if fetcher.config_missing?
|
426
427
|
ui.error("Specified config file #{config[:config_file]} does not exist#{Chef::Config.config_file_jail ? " or is not under config file jail #{Chef::Config.config_file_jail}" : ""}!")
|
@@ -27,6 +27,11 @@ class Chef
|
|
27
27
|
require 'chef/json_compat'
|
28
28
|
end
|
29
29
|
|
30
|
+
option :delete_validators,
|
31
|
+
:short => "-D",
|
32
|
+
:long => "--delete-validators",
|
33
|
+
:description => "Force deletion of clients if they're validators"
|
34
|
+
|
30
35
|
banner "knife client bulk delete REGEX (options)"
|
31
36
|
|
32
37
|
def run
|
@@ -38,28 +43,62 @@ class Chef
|
|
38
43
|
|
39
44
|
matcher = /#{name_args[0]}/
|
40
45
|
clients_to_delete = {}
|
46
|
+
validators_to_delete = {}
|
41
47
|
all_clients.each do |name, client|
|
42
48
|
next unless name =~ matcher
|
43
|
-
|
49
|
+
if client.validator
|
50
|
+
validators_to_delete[client.name] = client
|
51
|
+
else
|
52
|
+
clients_to_delete[client.name] = client
|
53
|
+
end
|
44
54
|
end
|
45
55
|
|
46
|
-
if clients_to_delete.empty?
|
56
|
+
if clients_to_delete.empty? && validators_to_delete.empty?
|
47
57
|
ui.info "No clients match the expression /#{name_args[0]}/"
|
48
58
|
exit 0
|
49
59
|
end
|
50
60
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
ui.msg("")
|
55
|
-
ui.confirm("Are you sure you want to delete these clients")
|
61
|
+
check_and_delete_validators(validators_to_delete)
|
62
|
+
check_and_delete_clients(clients_to_delete)
|
63
|
+
end
|
56
64
|
|
57
|
-
|
65
|
+
def check_and_delete_validators(validators)
|
66
|
+
unless validators.empty?
|
67
|
+
unless config[:delete_validators]
|
68
|
+
ui.msg("Following clients are validators and will not be deleted.")
|
69
|
+
print_clients(validators)
|
70
|
+
ui.msg("You must specify --delete-validators to delete the validator clients")
|
71
|
+
else
|
72
|
+
ui.msg("The following validators will be deleted:")
|
73
|
+
print_clients(validators)
|
74
|
+
if ui.confirm_without_exit("Are you sure you want to delete these validators")
|
75
|
+
destroy_clients(validators)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def check_and_delete_clients(clients)
|
82
|
+
unless clients.empty?
|
83
|
+
ui.msg("The following clients will be deleted:")
|
84
|
+
print_clients(clients)
|
85
|
+
ui.confirm("Are you sure you want to delete these clients")
|
86
|
+
destroy_clients(clients)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def destroy_clients(clients)
|
91
|
+
clients.sort.each do |name, client|
|
58
92
|
client.destroy
|
59
93
|
ui.msg("Deleted client #{name}")
|
60
94
|
end
|
61
95
|
end
|
96
|
+
|
97
|
+
def print_clients(clients)
|
98
|
+
ui.msg("")
|
99
|
+
ui.msg(ui.list(clients.keys.sort, :columns_down))
|
100
|
+
ui.msg("")
|
101
|
+
end
|
62
102
|
end
|
63
103
|
end
|
64
104
|
end
|
65
|
-
|
@@ -27,9 +27,9 @@ class Chef
|
|
27
27
|
require 'chef/json_compat'
|
28
28
|
end
|
29
29
|
|
30
|
-
option :
|
31
|
-
:short => "-
|
32
|
-
:long => "--
|
30
|
+
option :delete_validators,
|
31
|
+
:short => "-D",
|
32
|
+
:long => "--delete-validators",
|
33
33
|
:description => "Force deletion of client if it's a validator"
|
34
34
|
|
35
35
|
banner "knife client delete CLIENT (options)"
|
@@ -46,7 +46,7 @@ class Chef
|
|
46
46
|
delete_object(Chef::ApiClient, @client_name, 'client') {
|
47
47
|
object = Chef::ApiClient.load(@client_name)
|
48
48
|
if object.validator
|
49
|
-
unless config[:
|
49
|
+
unless config[:delete_validators]
|
50
50
|
ui.fatal("You must specify --force to delete the validator client #{@client_name}")
|
51
51
|
exit 2
|
52
52
|
end
|
@@ -49,7 +49,7 @@ class Chef
|
|
49
49
|
ui.msg ""
|
50
50
|
|
51
51
|
unless config[:yes]
|
52
|
-
ui.confirm("Do you really want to delete these cookbooks
|
52
|
+
ui.confirm("Do you really want to delete these cookbooks")
|
53
53
|
|
54
54
|
if config[:purge]
|
55
55
|
ui.msg("Files that are common to multiple cookbooks are shared, so purging the files may break other cookbooks.")
|
@@ -93,6 +93,7 @@ class Chef
|
|
93
93
|
end
|
94
94
|
|
95
95
|
assert_environment_valid!
|
96
|
+
warn_about_cookbook_shadowing
|
96
97
|
version_constraints_to_update = {}
|
97
98
|
upload_failures = 0
|
98
99
|
upload_ok = 0
|
@@ -139,6 +140,7 @@ class Chef
|
|
139
140
|
end
|
140
141
|
end
|
141
142
|
|
143
|
+
|
142
144
|
upload_failures += @name_args.length - @cookbooks_to_upload.length
|
143
145
|
|
144
146
|
if upload_failures == 0
|
@@ -199,6 +201,10 @@ class Chef
|
|
199
201
|
end
|
200
202
|
|
201
203
|
def warn_about_cookbook_shadowing
|
204
|
+
# because cookbooks are lazy-loaded, we have to force the loader
|
205
|
+
# to load the cookbooks the user intends to upload here:
|
206
|
+
cookbooks_to_upload
|
207
|
+
|
202
208
|
unless cookbook_repo.merged_cookbooks.empty?
|
203
209
|
ui.warn "* " * 40
|
204
210
|
ui.warn(<<-WARNING)
|
@@ -257,14 +263,18 @@ WARNING
|
|
257
263
|
end
|
258
264
|
|
259
265
|
def check_for_dependencies!(cookbook)
|
260
|
-
# for
|
266
|
+
# for all dependencies, check if the version is on the server, or
|
261
267
|
# the version is in the cookbooks being uploaded. If not, exit and warn the user.
|
262
|
-
cookbook.metadata.dependencies.
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
+
missing_dependencies = cookbook.metadata.dependencies.reject do |cookbook_name, version|
|
269
|
+
check_server_side_cookbooks(cookbook_name, version) || check_uploading_cookbooks(cookbook_name, version)
|
270
|
+
end
|
271
|
+
|
272
|
+
unless missing_dependencies.empty?
|
273
|
+
missing_cookbook_names = missing_dependencies.map { |cookbook_name, version| "'#{cookbook_name}' version '#{version}'"}
|
274
|
+
ui.error "Cookbook #{cookbook.name} depends on cookbooks which are not currently"
|
275
|
+
ui.error "being uploaded and cannot be found on the server."
|
276
|
+
ui.error "The missing cookbook(s) are: #{missing_cookbook_names.join(', ')}"
|
277
|
+
exit 1
|
268
278
|
end
|
269
279
|
end
|
270
280
|
|