chef 12.5.1 → 12.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +6 -1
- data/README.md +6 -4
- data/Rakefile +1 -4
- data/chef-windows.gemspec +21 -0
- data/chef.gemspec +58 -0
- data/lib/chef/api_client/registration.rb +9 -4
- data/lib/chef/application.rb +3 -84
- data/lib/chef/application/apply.rb +9 -2
- data/lib/chef/application/client.rb +8 -3
- data/lib/chef/application/solo.rb +7 -1
- data/lib/chef/application/windows_service.rb +21 -6
- data/lib/chef/application/windows_service_manager.rb +2 -3
- data/lib/chef/audit/runner.rb +1 -0
- data/lib/chef/chef_class.rb +1 -11
- data/lib/chef/chef_fs/chef_fs_data_store.rb +181 -2
- data/lib/chef/chef_fs/file_system/cookbook_subdir.rb +5 -0
- data/lib/chef/chef_fs/file_system/file_system_entry.rb +11 -7
- data/lib/chef/client.rb +28 -1
- data/lib/chef/cookbook/cookbook_collection.rb +14 -1
- data/lib/chef/cookbook/cookbook_version_loader.rb +1 -1
- data/lib/chef/cookbook/metadata.rb +115 -9
- data/lib/chef/cookbook/remote_file_vendor.rb +1 -1
- data/lib/chef/cookbook_version.rb +6 -2
- data/lib/chef/data_bag.rb +1 -1
- data/lib/chef/data_bag_item.rb +1 -1
- data/lib/chef/digester.rb +5 -1
- data/lib/chef/dsl/chef_provisioning.rb +57 -0
- data/lib/chef/dsl/cheffish.rb +64 -0
- data/lib/chef/dsl/declare_resource.rb +108 -0
- data/lib/chef/dsl/platform_introspection.rb +3 -3
- data/lib/chef/dsl/recipe.rb +3 -73
- data/lib/chef/dsl/resources.rb +27 -1
- data/lib/chef/event_dispatch/base.rb +3 -0
- data/lib/chef/event_dispatch/dispatcher.rb +5 -0
- data/lib/chef/event_dispatch/events_output_stream.rb +8 -0
- data/lib/chef/exceptions.rb +21 -1
- data/lib/chef/file_access_control/unix.rb +12 -12
- data/lib/chef/file_content_management/deploy/cp.rb +2 -2
- data/lib/chef/file_content_management/deploy/mv_unix.rb +4 -4
- data/lib/chef/file_content_management/deploy/mv_windows.rb +1 -1
- data/lib/chef/formatters/base.rb +7 -0
- data/lib/chef/formatters/error_inspectors/compile_error_inspector.rb +2 -2
- data/lib/chef/formatters/indentable_output_stream.rb +5 -0
- data/lib/chef/http.rb +19 -3
- data/lib/chef/http/decompressor.rb +2 -2
- data/lib/chef/json_compat.rb +1 -0
- data/lib/chef/knife.rb +16 -2
- data/lib/chef/knife/bootstrap.rb +55 -10
- data/lib/chef/knife/cookbook_site_install.rb +5 -1
- data/lib/chef/knife/core/bootstrap_context.rb +2 -1
- data/lib/chef/knife/core/node_presenter.rb +1 -1
- data/lib/chef/knife/ssh.rb +30 -16
- data/lib/chef/knife/ssl_check.rb +4 -2
- data/lib/chef/knife/ssl_fetch.rb +3 -2
- data/lib/chef/knife/status.rb +14 -1
- data/lib/chef/log.rb +14 -0
- data/lib/chef/mixin/get_source_from_package.rb +7 -2
- data/lib/chef/mixin/properties.rb +302 -0
- data/lib/chef/mixin/proxified_socket.rb +38 -0
- data/lib/chef/mixin/subclass_directive.rb +37 -0
- data/lib/chef/node.rb +13 -5
- data/lib/chef/platform/query_helpers.rb +14 -3
- data/lib/chef/platform/service_helpers.rb +20 -38
- data/lib/chef/policy_builder/expand_node_object.rb +3 -0
- data/lib/chef/policy_builder/policyfile.rb +1 -0
- data/lib/chef/property.rb +51 -12
- data/lib/chef/provider.rb +40 -35
- data/lib/chef/provider/deploy.rb +1 -1
- data/lib/chef/provider/dsc_resource.rb +54 -20
- data/lib/chef/provider/execute.rb +25 -4
- data/lib/chef/provider/group.rb +1 -1
- data/lib/chef/provider/lwrp_base.rb +1 -0
- data/lib/chef/provider/package.rb +76 -30
- data/lib/chef/provider/package/dpkg.rb +152 -69
- data/lib/chef/provider/package/openbsd.rb +6 -8
- data/lib/chef/provider/package/solaris.rb +2 -0
- data/lib/chef/provider/package/windows.rb +95 -14
- data/lib/chef/provider/package/windows/exe.rb +129 -0
- data/lib/chef/provider/package/windows/msi.rb +37 -13
- data/lib/chef/provider/package/windows/registry_uninstall_entry.rb +89 -0
- data/lib/chef/provider/package/yum.rb +13 -3
- data/lib/chef/provider/powershell_script.rb +3 -0
- data/lib/chef/provider/remote_file/cache_control_data.rb +37 -4
- data/lib/chef/provider/remote_file/http.rb +1 -1
- data/lib/chef/provider/script.rb +1 -0
- data/lib/chef/provider/service.rb +13 -10
- data/lib/chef/provider/service/solaris.rb +43 -17
- data/lib/chef/provider/service/upstart.rb +3 -3
- data/lib/chef/provider/user.rb +1 -1
- data/lib/chef/provider/user/dscl.rb +111 -100
- data/lib/chef/provider/user/windows.rb +5 -3
- data/lib/chef/recipe.rb +3 -5
- data/lib/chef/resource.rb +77 -320
- data/lib/chef/resource/action_class.rb +4 -0
- data/lib/chef/resource/dpkg_package.rb +4 -3
- data/lib/chef/resource/dsc_resource.rb +40 -2
- data/lib/chef/resource/execute.rb +9 -1
- data/lib/chef/resource/ksh.rb +32 -0
- data/lib/chef/resource/lwrp_base.rb +6 -10
- data/lib/chef/resource/package.rb +8 -9
- data/lib/chef/resource/registry_key.rb +1 -1
- data/lib/chef/resource/resource_notification.rb +14 -1
- data/lib/chef/resource/script.rb +1 -1
- data/lib/chef/resource/windows_package.rb +1 -1
- data/lib/chef/resource_builder.rb +14 -7
- data/lib/chef/resource_reporter.rb +6 -0
- data/lib/chef/resources.rb +1 -7
- data/lib/chef/rest.rb +1 -1
- data/lib/chef/run_context.rb +45 -2
- data/lib/chef/run_list/run_list_expansion.rb +47 -0
- data/lib/chef/runner.rb +25 -0
- data/lib/chef/search/query.rb +16 -2
- data/lib/chef/util/diff.rb +2 -2
- data/lib/chef/util/powershell/ps_credential.rb +2 -3
- data/lib/chef/version.rb +1 -1
- data/lib/chef/win32/api/file.rb +51 -1
- data/lib/chef/win32/file.rb +5 -0
- data/lib/chef/win32/file/version_info.rb +93 -0
- data/lib/chef/win32/mutex.rb +1 -1
- data/spec/data/apt/chef-integration-test2-1.0/debian/changelog +5 -0
- data/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2.debhelper.log +45 -0
- data/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2.substvars +1 -0
- data/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/conffiles +1 -0
- data/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/control +10 -0
- data/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/md5sums +1 -0
- data/spec/data/apt/chef-integration-test2-1.0/debian/compat +1 -0
- data/spec/data/apt/chef-integration-test2-1.0/debian/conffiles +1 -0
- data/spec/data/apt/chef-integration-test2-1.0/debian/control +13 -0
- data/spec/data/apt/chef-integration-test2-1.0/debian/copyright +34 -0
- data/spec/data/apt/chef-integration-test2-1.0/debian/files +1 -0
- data/spec/data/apt/chef-integration-test2-1.0/debian/rules +13 -0
- data/spec/data/apt/chef-integration-test2-1.0/debian/source/format +1 -0
- data/spec/data/apt/chef-integration-test2_1.0-1.debian.tar.gz +0 -0
- data/spec/data/apt/chef-integration-test2_1.0-1.dsc +18 -0
- data/spec/data/apt/chef-integration-test2_1.0-1_amd64.build +91 -0
- data/spec/data/apt/chef-integration-test2_1.0-1_amd64.changes +31 -0
- data/spec/data/apt/chef-integration-test2_1.0-1_amd64.deb +0 -0
- data/spec/data/apt/chef-integration-test2_1.0.orig.tar.gz +0 -0
- data/spec/functional/application_spec.rb +1 -1
- data/spec/functional/audit/runner_spec.rb +4 -0
- data/spec/functional/knife/ssh_spec.rb +5 -5
- data/spec/functional/notifications_spec.rb +74 -4
- data/spec/functional/resource/aix_service_spec.rb +2 -2
- data/spec/functional/resource/dpkg_package_spec.rb +339 -0
- data/spec/functional/resource/ifconfig_spec.rb +3 -1
- data/spec/functional/resource/mount_spec.rb +5 -2
- data/spec/functional/resource/package_spec.rb +1 -1
- data/spec/functional/resource/user/windows_spec.rb +8 -0
- data/spec/functional/resource/windows_package_spec.rb +177 -0
- data/spec/functional/win32/version_info_spec.rb +50 -0
- data/spec/integration/client/client_spec.rb +80 -0
- data/spec/integration/knife/download_spec.rb +9 -0
- data/spec/integration/knife/upload_spec.rb +28 -1
- data/spec/integration/recipes/lwrp_inline_resources_spec.rb +93 -23
- data/spec/integration/recipes/resource_action_spec.rb +211 -116
- data/spec/integration/recipes/resource_converge_if_changed_spec.rb +72 -0
- data/spec/integration/solo/solo_spec.rb +34 -0
- data/spec/spec_helper.rb +11 -1
- data/spec/support/platform_helpers.rb +8 -0
- data/spec/support/shared/integration/integration_helper.rb +6 -0
- data/spec/support/shared/unit/execute_resource.rb +5 -0
- data/spec/support/shared/unit/platform_introspector.rb +7 -0
- data/spec/tiny_server.rb +6 -2
- data/spec/unit/api_client/registration_spec.rb +5 -4
- data/spec/unit/application_spec.rb +1 -181
- data/spec/unit/chef_fs/file_system/cookbook_subdir_spec.rb +34 -0
- data/spec/unit/cookbook/metadata_spec.rb +122 -2
- data/spec/unit/http_spec.rb +102 -0
- data/spec/unit/knife/bootstrap_spec.rb +55 -13
- data/spec/unit/knife/core/bootstrap_context_spec.rb +10 -3
- data/spec/unit/knife/ssl_check_spec.rb +7 -3
- data/spec/unit/knife/ssl_fetch_spec.rb +2 -2
- data/spec/unit/knife/status_spec.rb +13 -13
- data/spec/unit/knife_spec.rb +26 -2
- data/spec/unit/lwrp_spec.rb +1 -1
- data/spec/unit/mixin/properties_spec.rb +97 -0
- data/spec/unit/mixin/proxified_socket_spec.rb +94 -0
- data/spec/unit/mixin/subclass_directive_spec.rb +45 -0
- data/spec/unit/node_spec.rb +9 -1
- data/spec/unit/policy_builder/policyfile_spec.rb +2 -0
- data/spec/unit/property/validation_spec.rb +14 -12
- data/spec/unit/property_spec.rb +56 -0
- data/spec/unit/provider/deploy_spec.rb +1 -1
- data/spec/unit/provider/dsc_resource_spec.rb +63 -24
- data/spec/unit/provider/execute_spec.rb +95 -28
- data/spec/unit/provider/package/dpkg_spec.rb +185 -96
- data/spec/unit/provider/package/windows/exe_spec.rb +251 -0
- data/spec/unit/provider/package/windows/msi_spec.rb +94 -10
- data/spec/unit/provider/package/windows_spec.rb +227 -26
- data/spec/unit/provider/package/yum_spec.rb +6 -0
- data/spec/unit/provider/package_spec.rb +495 -366
- data/spec/unit/provider/remote_file/cache_control_data_spec.rb +62 -36
- data/spec/unit/provider/script_spec.rb +2 -2
- data/spec/unit/provider/service/solaris_smf_service_spec.rb +110 -39
- data/spec/unit/provider/service/upstart_service_spec.rb +19 -0
- data/spec/unit/provider/user/dscl_spec.rb +14 -0
- data/spec/unit/provider/user/windows_spec.rb +2 -2
- data/spec/unit/provider/user_spec.rb +9 -0
- data/spec/unit/provider_resolver_spec.rb +6 -30
- data/spec/unit/recipe_spec.rb +46 -20
- data/spec/unit/resource/chef_gem_spec.rb +1 -1
- data/spec/unit/resource/dsc_resource_spec.rb +14 -3
- data/spec/unit/resource/ksh_spec.rb +40 -0
- data/spec/unit/resource/registry_key_spec.rb +2 -2
- data/spec/unit/resource/resource_notification_spec.rb +44 -45
- data/spec/unit/resource_reporter_spec.rb +7 -0
- data/spec/unit/resource_spec.rb +268 -253
- data/spec/unit/rest_spec.rb +2 -2
- data/spec/unit/run_list/run_list_expansion_spec.rb +18 -3
- data/spec/unit/search/query_spec.rb +19 -1
- data/spec/unit/util/powershell/ps_credential_spec.rb +8 -1
- data/spec/unit/windows_service_spec.rb +83 -38
- data/tasks/external_tests.rb +19 -9
- data/tasks/rspec.rb +1 -1
- metadata +64 -15
- data/spec/support/pedant/Gemfile +0 -3
- data/spec/support/pedant/pedant_config.rb +0 -129
- data/spec/support/pedant/run_pedant.rb +0 -63
- data/spec/support/pedant/stickywicket.pem +0 -27
- data/spec/unit/provider/package_spec.rbe +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
#
|
2
2
|
# Author:: Seth Chisamore (<schisamo@opscode.com>)
|
3
|
-
# Copyright:: Copyright (c) 2011
|
3
|
+
# Copyright:: Copyright (c) 2011-2015 Chef Software, Inc.
|
4
4
|
# License:: Apache License, Version 2.0
|
5
5
|
#
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -51,8 +51,7 @@ class Chef
|
|
51
51
|
option :log_location,
|
52
52
|
:short => "-L LOGLOCATION",
|
53
53
|
:long => "--logfile LOGLOCATION",
|
54
|
-
:description => "Set the log file location for chef-service"
|
55
|
-
:default => "#{ENV['SYSTEMDRIVE']}/chef/client.log"
|
54
|
+
:description => "Set the log file location for chef-service"
|
56
55
|
|
57
56
|
option :help,
|
58
57
|
:short => "-h",
|
data/lib/chef/audit/runner.rb
CHANGED
data/lib/chef/chef_class.rb
CHANGED
@@ -205,17 +205,7 @@ class Chef
|
|
205
205
|
# @api private this will likely be removed in favor of an as-yet unwritten
|
206
206
|
# `Chef.log`
|
207
207
|
def log_deprecation(message, location=nil)
|
208
|
-
|
209
|
-
# Pick the first caller that is *not* part of the Chef gem, that's the
|
210
|
-
# thing the user wrote.
|
211
|
-
chef_gem_path = File.expand_path("../..", __FILE__)
|
212
|
-
caller(0..10).each do |c|
|
213
|
-
if !c.start_with?(chef_gem_path)
|
214
|
-
location = c
|
215
|
-
break
|
216
|
-
end
|
217
|
-
end
|
218
|
-
end
|
208
|
+
location ||= Chef::Log.caller_location
|
219
209
|
# `run_context.events` is the primary deprecation target if we're in a
|
220
210
|
# run. If we are not yet in a run, print to `Chef::Log`.
|
221
211
|
if run_context && run_context.events
|
@@ -66,12 +66,65 @@ class Chef
|
|
66
66
|
# - ChefFSDataStore lets cookbooks be uploaded into a temporary memory
|
67
67
|
# storage, and when the cookbook is committed, copies the files onto the
|
68
68
|
# disk in the correct place (/cookbooks/apache2/recipes/default.rb).
|
69
|
+
#
|
69
70
|
# 3. Data bags:
|
70
71
|
# - The Chef server expects data bags in /data/BAG/ITEM
|
71
72
|
# - The repository stores data bags in /data_bags/BAG/ITEM
|
72
73
|
#
|
73
74
|
# 4. JSON filenames are generally NAME.json in the repository (e.g. /nodes/foo.json).
|
74
75
|
#
|
76
|
+
# 5. Org membership:
|
77
|
+
# chef-zero stores user membership in an org as a series of empty files.
|
78
|
+
# If an org has jkeiser and cdoherty as members, chef-zero expects these
|
79
|
+
# files to exist:
|
80
|
+
#
|
81
|
+
# - `users/jkeiser` (content: '{}')
|
82
|
+
# - `users/cdoherty` (content: '{}')
|
83
|
+
#
|
84
|
+
# ChefFS, on the other hand, stores user membership in an org as a single
|
85
|
+
# file, `members.json`, with content:
|
86
|
+
#
|
87
|
+
# ```json
|
88
|
+
# [
|
89
|
+
# { "user": { "username": "jkeiser" } },
|
90
|
+
# { "user": { "username": "cdoherty" } }
|
91
|
+
# ]
|
92
|
+
# ```
|
93
|
+
#
|
94
|
+
# To translate between the two, we need to intercept requests to `users`
|
95
|
+
# like so:
|
96
|
+
#
|
97
|
+
# - `list(users)` -> `get(/members.json)`
|
98
|
+
# - `get(users/NAME)` -> `get(/members.json)`, see if it's in there
|
99
|
+
# - `create(users/NAME)` -> `get(/members.json)`, add name, `set(/members.json)`
|
100
|
+
# - `delete(users/NAME)` -> `get(/members.json)`, remove name, `set(/members.json)`
|
101
|
+
#
|
102
|
+
# 6. Org invitations:
|
103
|
+
# chef-zero stores org membership invitations as a series of empty files.
|
104
|
+
# If an org has invited jkeiser and cdoherty (and they have not yet accepted
|
105
|
+
# the invite), chef-zero expects these files to exist:
|
106
|
+
#
|
107
|
+
# - `association_requests/jkeiser` (content: '{}')
|
108
|
+
# - `association_requests/cdoherty` (content: '{}')
|
109
|
+
#
|
110
|
+
# ChefFS, on the other hand, stores invitations as a single file,
|
111
|
+
# `invitations.json`, with content:
|
112
|
+
#
|
113
|
+
# ```json
|
114
|
+
# [
|
115
|
+
# { "id" => "jkeiser-chef", 'username' => 'jkeiser' },
|
116
|
+
# { "id" => "cdoherty-chef", 'username' => 'cdoherty' }
|
117
|
+
# ]
|
118
|
+
# ```
|
119
|
+
#
|
120
|
+
# To translate between the two, we need to intercept requests to `users`
|
121
|
+
# like so:
|
122
|
+
#
|
123
|
+
# - `list(association_requests)` -> `get(/invitations.json)`
|
124
|
+
# - `get(association_requests/NAME)` -> `get(/invitations.json)`, see if it's in there
|
125
|
+
# - `create(association_requests/NAME)` -> `get(/invitations.json)`, add name, `set(/invitations.json)`
|
126
|
+
# - `delete(association_requests/NAME)` -> `get(/invitations.json)`, remove name, `set(/invitations.json)`
|
127
|
+
#
|
75
128
|
class ChefFSDataStore
|
76
129
|
#
|
77
130
|
# Create a new ChefFSDataStore
|
@@ -83,9 +136,10 @@ class Chef
|
|
83
136
|
# Generally will be a +ChefFS::FileSystem::ChefRepositoryFileSystemRoot+
|
84
137
|
# object, created from +ChefFS::Config.local_fs+.
|
85
138
|
#
|
86
|
-
def initialize(chef_fs)
|
139
|
+
def initialize(chef_fs, chef_config=Chef::Config)
|
87
140
|
@chef_fs = chef_fs
|
88
141
|
@memory_store = ChefZero::DataStore::MemoryStore.new
|
142
|
+
@repo_mode = chef_config[:repo_mode]
|
89
143
|
end
|
90
144
|
|
91
145
|
def publish_description
|
@@ -93,6 +147,7 @@ class Chef
|
|
93
147
|
end
|
94
148
|
|
95
149
|
attr_reader :chef_fs
|
150
|
+
attr_reader :repo_mode
|
96
151
|
|
97
152
|
def create_dir(path, name, *options)
|
98
153
|
if use_memory_store?(path)
|
@@ -108,6 +163,24 @@ class Chef
|
|
108
163
|
end
|
109
164
|
end
|
110
165
|
|
166
|
+
#
|
167
|
+
# If you want to get the contents of /data/x/y from the server,
|
168
|
+
# you say chef_fs.child('data').child('x').child('y').read.
|
169
|
+
# It will make exactly one network request: GET /data/x/y
|
170
|
+
# And that will return 404 if it doesn't exist.
|
171
|
+
#
|
172
|
+
# ChefFS objects do not go to the network until you ask them for data.
|
173
|
+
# This means you can construct a /data/x/y ChefFS entry early.
|
174
|
+
#
|
175
|
+
# Alternative:
|
176
|
+
# chef_fs.child('data') could have done a GET /data preemptively,
|
177
|
+
# allowing it to know whether child('x') was valid (GET /data gives you
|
178
|
+
# a list of data bags). Then child('x') could have done a GET /data/x,
|
179
|
+
# allowing it to know whether child('y') (the item) existed. Finally,
|
180
|
+
# we would do the GET /data/x/y to read the contents. Three network
|
181
|
+
# requests instead of 1.
|
182
|
+
#
|
183
|
+
|
111
184
|
def create(path, name, data, *options)
|
112
185
|
if use_memory_store?(path)
|
113
186
|
@memory_store.create(path, name, data, *options)
|
@@ -115,6 +188,32 @@ class Chef
|
|
115
188
|
elsif path[0] == 'cookbooks' && path.length == 2
|
116
189
|
# Do nothing. The entry gets created when the cookbook is created.
|
117
190
|
|
191
|
+
# create [/organizations/ORG]/users/NAME (with content '{}')
|
192
|
+
# Manipulate the `members.json` file that contains a list of all users
|
193
|
+
elsif is_org? && path == [ 'users' ]
|
194
|
+
update_json('members.json', []) do |members|
|
195
|
+
# Format of each entry: { "user": { "username": "jkeiser" } }
|
196
|
+
if members.any? { |member| member['user']['username'] == name }
|
197
|
+
raise ChefZero::DataStore::DataAlreadyExistsError.new(path, entry)
|
198
|
+
end
|
199
|
+
|
200
|
+
# Actually add the user
|
201
|
+
members << { "user" => { "username" => name } }
|
202
|
+
end
|
203
|
+
|
204
|
+
# create [/organizations/ORG]/association_requests/NAME (with content '{}')
|
205
|
+
# Manipulate the `invitations.json` file that contains a list of all users
|
206
|
+
elsif is_org? && path == [ 'association_requests' ]
|
207
|
+
update_json('invitations.json', []) do |invitations|
|
208
|
+
# Format of each entry: { "id" => "jkeiser-chef", 'username' => 'jkeiser' }
|
209
|
+
if invitations.any? { |member| member['username'] == name }
|
210
|
+
raise ChefZero::DataStore::DataAlreadyExistsError.new(path)
|
211
|
+
end
|
212
|
+
|
213
|
+
# Actually add the user (TODO insert org name??)
|
214
|
+
invitations << { "username" => name }
|
215
|
+
end
|
216
|
+
|
118
217
|
else
|
119
218
|
if !data.is_a?(String)
|
120
219
|
raise "set only works with strings"
|
@@ -142,6 +241,24 @@ class Chef
|
|
142
241
|
raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e)
|
143
242
|
end
|
144
243
|
|
244
|
+
# GET [/organizations/ORG]/users/NAME -> /users/NAME
|
245
|
+
# Manipulates members.json
|
246
|
+
elsif is_org? && path[0] == 'users' && path.length == 2
|
247
|
+
if get_json('members.json', []).any? { |member| member['user']['username'] == path[1] }
|
248
|
+
'{}'
|
249
|
+
else
|
250
|
+
raise ChefZero::DataStore::DataNotFoundError.new(path)
|
251
|
+
end
|
252
|
+
|
253
|
+
# GET [/organizations/ORG]/association_requests/NAME -> /users/NAME
|
254
|
+
# Manipulates invites.json
|
255
|
+
elsif is_org? && path[0] == 'association_requests' && path.length == 2
|
256
|
+
if get_json('invites.json', []).any? { |member| member['user']['username'] == path[1] }
|
257
|
+
'{}'
|
258
|
+
else
|
259
|
+
raise ChefZero::DataStore::DataNotFoundError.new(path)
|
260
|
+
end
|
261
|
+
|
145
262
|
else
|
146
263
|
with_entry(path) do |entry|
|
147
264
|
if path[0] == 'cookbooks' && path.length == 3
|
@@ -209,6 +326,29 @@ class Chef
|
|
209
326
|
def delete(path)
|
210
327
|
if use_memory_store?(path)
|
211
328
|
@memory_store.delete(path)
|
329
|
+
|
330
|
+
# DELETE [/organizations/ORG]/users/NAME
|
331
|
+
# Manipulates members.json
|
332
|
+
elsif is_org? && path[0] == 'users' && path.length == 2
|
333
|
+
update_json('members.json', []) do |members|
|
334
|
+
result = members.reject { |member| member['user']['username'] == path[1] }
|
335
|
+
if result.size == members.size
|
336
|
+
raise ChefZero::DataStore::DataNotFoundError.new(path)
|
337
|
+
end
|
338
|
+
result
|
339
|
+
end
|
340
|
+
|
341
|
+
# DELETE [/organizations/ORG]/users/NAME
|
342
|
+
# Manipulates members.json
|
343
|
+
elsif is_org? && path[0] == 'association_requests' && path.length == 2
|
344
|
+
update_json('invitations.json', []) do |invitations|
|
345
|
+
result = invitations.reject { |invitation| invitation['username'] == path[1] }
|
346
|
+
if result.size == invitations.size
|
347
|
+
raise ChefZero::DataStore::DataNotFoundError.new(path)
|
348
|
+
end
|
349
|
+
result
|
350
|
+
end
|
351
|
+
|
212
352
|
else
|
213
353
|
with_entry(path) do |entry|
|
214
354
|
begin
|
@@ -394,9 +534,22 @@ class Chef
|
|
394
534
|
end
|
395
535
|
end
|
396
536
|
end
|
537
|
+
|
538
|
+
elsif path[0] == 'acls'
|
539
|
+
# /acls/containers|nodes|.../x.json
|
540
|
+
# /acls/organization.json
|
541
|
+
if path.length == 3 || path == [ 'acls', 'organization' ]
|
542
|
+
path = path.dup
|
543
|
+
path[-1] = "#{path[-1]}.json"
|
544
|
+
end
|
545
|
+
|
546
|
+
# /acls/containers|nodes|... do NOT drop into the next elsif, and do
|
547
|
+
# not get .json appended
|
548
|
+
|
549
|
+
# /nodes|clients|.../x.json
|
397
550
|
elsif path.length == 2
|
398
551
|
path = path.dup
|
399
|
-
path[1] = "#{path[1]}.json"
|
552
|
+
path[-1] = "#{path[-1]}.json"
|
400
553
|
end
|
401
554
|
path
|
402
555
|
end
|
@@ -477,6 +630,32 @@ class Chef
|
|
477
630
|
metadata = ChefZero::CookbookData.metadata_from(dir, path[1], nil, [])
|
478
631
|
metadata[:version] || '0.0.0'
|
479
632
|
end
|
633
|
+
|
634
|
+
def update_json(path, default_value)
|
635
|
+
entry = Chef::ChefFS::FileSystem.resolve_path(chef_fs, path)
|
636
|
+
begin
|
637
|
+
input = Chef::JSONCompat.parse(entry.read)
|
638
|
+
output = yield input.dup
|
639
|
+
entry.write(Chef::JSONCompat.to_json_pretty(output)) if output != input
|
640
|
+
rescue Chef::ChefFS::FileSystem::NotFoundError
|
641
|
+
# Send the default value to the caller, and create the entry if the caller updates it
|
642
|
+
output = yield default_value
|
643
|
+
entry.parent.create_child(entry.name, Chef::JSONCompat.to_json_pretty(output)) if output != []
|
644
|
+
end
|
645
|
+
end
|
646
|
+
|
647
|
+
def get_json(path, default_value)
|
648
|
+
entry = Chef::ChefFS::FileSystem.resolve_path(chef_fs, path)
|
649
|
+
begin
|
650
|
+
Chef::JSONCompat.parse(entry.read)
|
651
|
+
rescue Chef::ChefFS::FileSystem::NotFoundError
|
652
|
+
default_value
|
653
|
+
end
|
654
|
+
end
|
655
|
+
|
656
|
+
def is_org?
|
657
|
+
repo_mode == 'hosted_everything'
|
658
|
+
end
|
480
659
|
end
|
481
660
|
end
|
482
661
|
end
|
@@ -72,18 +72,22 @@ class Chef
|
|
72
72
|
end
|
73
73
|
|
74
74
|
def delete(recurse)
|
75
|
-
|
76
|
-
if
|
77
|
-
|
75
|
+
begin
|
76
|
+
if dir?
|
77
|
+
if !recurse
|
78
|
+
raise MustDeleteRecursivelyError.new(self, $!)
|
79
|
+
end
|
80
|
+
FileUtils.rm_r(file_path)
|
81
|
+
else
|
82
|
+
File.delete(file_path)
|
78
83
|
end
|
79
|
-
|
80
|
-
|
81
|
-
File.delete(file_path)
|
84
|
+
rescue Errno::ENOENT
|
85
|
+
raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
|
82
86
|
end
|
83
87
|
end
|
84
88
|
|
85
89
|
def exists?
|
86
|
-
File.exists?(file_path) && parent.can_have_child?(name, dir?)
|
90
|
+
File.exists?(file_path) && (parent.nil? || parent.can_have_child?(name, dir?))
|
87
91
|
end
|
88
92
|
|
89
93
|
def read
|
data/lib/chef/client.rb
CHANGED
@@ -232,6 +232,8 @@ class Chef
|
|
232
232
|
# @return Always returns true.
|
233
233
|
#
|
234
234
|
def run
|
235
|
+
start_profiling
|
236
|
+
|
235
237
|
run_error = nil
|
236
238
|
|
237
239
|
runlock = RunLock.new(Chef::Config.lockfile)
|
@@ -271,7 +273,7 @@ class Chef
|
|
271
273
|
|
272
274
|
if Chef::Config[:why_run] == true
|
273
275
|
# why_run should probably be renamed to why_converge
|
274
|
-
Chef::Log.debug("Not running controls in '
|
276
|
+
Chef::Log.debug("Not running controls in 'why-run' mode - this mode is used to see potential converge changes")
|
275
277
|
elsif Chef::Config[:audit_mode] != :disabled
|
276
278
|
audit_error = run_audits(run_context)
|
277
279
|
end
|
@@ -284,6 +286,9 @@ class Chef
|
|
284
286
|
run_completed_successfully
|
285
287
|
events.run_completed(node)
|
286
288
|
|
289
|
+
# keep this inside the main loop to get exception backtraces
|
290
|
+
end_profiling
|
291
|
+
|
287
292
|
# rebooting has to be the last thing we do, no exceptions.
|
288
293
|
Chef::Platform::Rebooter.reboot_if_needed!(node)
|
289
294
|
rescue Exception => run_error
|
@@ -891,6 +896,28 @@ class Chef
|
|
891
896
|
attr_reader :override_runlist
|
892
897
|
attr_reader :specific_recipes
|
893
898
|
|
899
|
+
def profiling_prereqs!
|
900
|
+
require 'ruby-prof'
|
901
|
+
rescue LoadError
|
902
|
+
raise "You must have the ruby-prof gem installed in order to use --profile-ruby"
|
903
|
+
end
|
904
|
+
|
905
|
+
def start_profiling
|
906
|
+
return unless Chef::Config[:profile_ruby]
|
907
|
+
profiling_prereqs!
|
908
|
+
RubyProf.start
|
909
|
+
end
|
910
|
+
|
911
|
+
def end_profiling
|
912
|
+
return unless Chef::Config[:profile_ruby]
|
913
|
+
profiling_prereqs!
|
914
|
+
path = Chef::FileCache.create_cache_path("graph_profile.out", false)
|
915
|
+
File.open(path, "w+") do |file|
|
916
|
+
RubyProf::GraphPrinter.new(RubyProf.stop).print(file, {})
|
917
|
+
end
|
918
|
+
Chef::Log.warn("Ruby execution profile dumped to #{path}")
|
919
|
+
end
|
920
|
+
|
894
921
|
def empty_directory?(path)
|
895
922
|
!File.exists?(path) || (Dir.entries(path).size <= 2)
|
896
923
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
#--
|
2
2
|
# Author:: Tim Hinderliter (<tim@opscode.com>)
|
3
3
|
# Author:: Christopher Walters (<cw@opscode.com>)
|
4
|
-
# Copyright:: Copyright (c) 2010
|
4
|
+
# Copyright:: Copyright (c) 2010-2015 Chef Software, Inc.
|
5
5
|
# License:: Apache License, Version 2.0
|
6
6
|
#
|
7
7
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -41,5 +41,18 @@ class Chef
|
|
41
41
|
cookbook_versions.each{ |cookbook_name, cookbook_version| self[cookbook_name] = cookbook_version }
|
42
42
|
end
|
43
43
|
|
44
|
+
# Validates that the cookbook metadata allows it to run on this instance.
|
45
|
+
#
|
46
|
+
# Currently checks chef_version and ohai_version in the cookbook metadata
|
47
|
+
# against the running Chef::VERSION and Ohai::VERSION.
|
48
|
+
#
|
49
|
+
# @raises [Chef::Exceptions::CookbookChefVersionMismatch] if the Chef::VERSION fails validation
|
50
|
+
# @raises [Chef::Exceptions::CookbookOhaiVersionMismatch] if the Ohai::VERSION fails validation
|
51
|
+
def validate!
|
52
|
+
each do |cookbook_name, cookbook_version|
|
53
|
+
cookbook_version.metadata.validate_chef_version!
|
54
|
+
cookbook_version.metadata.validate_ohai_version!
|
55
|
+
end
|
56
|
+
end
|
44
57
|
end
|
45
58
|
end
|
@@ -91,7 +91,7 @@ class Chef
|
|
91
91
|
remove_ignored_files
|
92
92
|
|
93
93
|
if empty?
|
94
|
-
Chef::Log.warn "
|
94
|
+
Chef::Log.warn "Found a directory #{cookbook_name} in the cookbook path, but it contains no cookbook files. skipping."
|
95
95
|
end
|
96
96
|
@cookbook_settings
|
97
97
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
# Author:: Adam Jacob (<adam@opscode.com>)
|
3
3
|
# Author:: AJ Christensen (<aj@opscode.com>)
|
4
4
|
# Author:: Seth Falcon (<seth@opscode.com>)
|
5
|
-
# Copyright:: Copyright 2008-
|
5
|
+
# Copyright:: Copyright 2008-2015 Chef Software, Inc.
|
6
6
|
# License:: Apache License, Version 2.0
|
7
7
|
#
|
8
8
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -55,19 +55,23 @@ class Chef
|
|
55
55
|
SOURCE_URL = 'source_url'.freeze
|
56
56
|
ISSUES_URL = 'issues_url'.freeze
|
57
57
|
PRIVACY = 'privacy'.freeze
|
58
|
+
CHEF_VERSIONS = 'chef_versions'.freeze
|
59
|
+
OHAI_VERSIONS = 'ohai_versions'.freeze
|
58
60
|
|
59
61
|
COMPARISON_FIELDS = [ :name, :description, :long_description, :maintainer,
|
60
62
|
:maintainer_email, :license, :platforms, :dependencies,
|
61
63
|
:recommendations, :suggestions, :conflicting, :providing,
|
62
64
|
:replacing, :attributes, :groupings, :recipes, :version,
|
63
|
-
:source_url, :issues_url, :privacy ]
|
65
|
+
:source_url, :issues_url, :privacy, :chef_versions, :ohai_versions ]
|
64
66
|
|
65
|
-
VERSION_CONSTRAINTS = {:depends
|
66
|
-
:recommends
|
67
|
-
:suggests
|
68
|
-
:conflicts
|
69
|
-
:provides
|
70
|
-
:replaces
|
67
|
+
VERSION_CONSTRAINTS = {:depends => DEPENDENCIES,
|
68
|
+
:recommends => RECOMMENDATIONS,
|
69
|
+
:suggests => SUGGESTIONS,
|
70
|
+
:conflicts => CONFLICTING,
|
71
|
+
:provides => PROVIDING,
|
72
|
+
:replaces => REPLACING,
|
73
|
+
:chef_version => CHEF_VERSIONS,
|
74
|
+
:ohai_version => OHAI_VERSIONS }
|
71
75
|
|
72
76
|
include Chef::Mixin::ParamsValidate
|
73
77
|
include Chef::Mixin::FromFile
|
@@ -84,6 +88,11 @@ class Chef
|
|
84
88
|
attr_reader :recipes
|
85
89
|
attr_reader :version
|
86
90
|
|
91
|
+
# @return [Array<Gem::Dependency>] Array of supported Chef versions
|
92
|
+
attr_reader :chef_versions
|
93
|
+
# @return [Array<Gem::Dependency>] Array of supported Ohai versions
|
94
|
+
attr_reader :ohai_versions
|
95
|
+
|
87
96
|
# Builds a new Chef::Cookbook::Metadata object.
|
88
97
|
#
|
89
98
|
# === Parameters
|
@@ -118,6 +127,8 @@ class Chef
|
|
118
127
|
@source_url = ''
|
119
128
|
@issues_url = ''
|
120
129
|
@privacy = false
|
130
|
+
@chef_versions = []
|
131
|
+
@ohai_versions = []
|
121
132
|
|
122
133
|
@errors = []
|
123
134
|
end
|
@@ -386,6 +397,28 @@ class Chef
|
|
386
397
|
@replacing[cookbook]
|
387
398
|
end
|
388
399
|
|
400
|
+
# Metadata DSL to set a valid chef_version. May be declared multiple times
|
401
|
+
# with the result being 'OR'd such that if any statements match, the version
|
402
|
+
# is considered supported. Uses Gem::Requirement for its implementation.
|
403
|
+
#
|
404
|
+
# @param version_args [Array<String>] Version constraint in String form
|
405
|
+
# @return [Array<Gem::Dependency>] Current chef_versions array
|
406
|
+
def chef_version(*version_args)
|
407
|
+
@chef_versions << Gem::Dependency.new('chef', *version_args) unless version_args.empty?
|
408
|
+
@chef_versions
|
409
|
+
end
|
410
|
+
|
411
|
+
# Metadata DSL to set a valid ohai_version. May be declared multiple times
|
412
|
+
# with the result being 'OR'd such that if any statements match, the version
|
413
|
+
# is considered supported. Uses Gem::Requirement for its implementation.
|
414
|
+
#
|
415
|
+
# @param version_args [Array<String>] Version constraint in String form
|
416
|
+
# @return [Array<Gem::Dependency>] Current ohai_versions array
|
417
|
+
def ohai_version(*version_args)
|
418
|
+
@ohai_versions << Gem::Dependency.new('ohai', *version_args) unless version_args.empty?
|
419
|
+
@ohai_versions
|
420
|
+
end
|
421
|
+
|
389
422
|
# Adds a description for a recipe.
|
390
423
|
#
|
391
424
|
# === Parameters
|
@@ -481,6 +514,40 @@ class Chef
|
|
481
514
|
@groupings[name]
|
482
515
|
end
|
483
516
|
|
517
|
+
# Convert an Array of Gem::Dependency objects (chef_version/ohai_version) to an Array.
|
518
|
+
#
|
519
|
+
# Gem::Dependencey#to_s is not useful, and there is no #to_json defined on it or its component
|
520
|
+
# objets, so we have to write our own rendering method.
|
521
|
+
#
|
522
|
+
# [ Gem::Dependency.new(">= 12.5"), Gem::Dependency.new(">= 11.18.0", "< 12.0") ]
|
523
|
+
#
|
524
|
+
# results in:
|
525
|
+
#
|
526
|
+
# [ [ ">= 12.5" ], [ ">= 11.18.0", "< 12.0" ] ]
|
527
|
+
#
|
528
|
+
# @param deps [Array<Gem::Dependency>] Multiple Gem-style version constraints
|
529
|
+
# @return [Array<Array<String>]] Simple object representation of version constraints (for json)
|
530
|
+
def gem_requirements_to_array(*deps)
|
531
|
+
deps.map do |dep|
|
532
|
+
dep.requirement.requirements.map do |op, version|
|
533
|
+
"#{op} #{version}"
|
534
|
+
end.sort
|
535
|
+
end
|
536
|
+
end
|
537
|
+
|
538
|
+
# Convert an Array of Gem::Dependency objects (chef_version/ohai_version) to a hash.
|
539
|
+
#
|
540
|
+
# This is the inverse of #gem_requirements_to_array
|
541
|
+
#
|
542
|
+
# @param what [String] What version constraint we are constructing ('chef' or 'ohai' presently)
|
543
|
+
# @param array [Array<Array<String>]] Simple object representation of version constraints (from json)
|
544
|
+
# @return [Array<Gem::Dependency>] Multiple Gem-style version constraints
|
545
|
+
def gem_requirements_from_array(what, array)
|
546
|
+
array.map do |dep|
|
547
|
+
Gem::Dependency.new(what, *dep)
|
548
|
+
end
|
549
|
+
end
|
550
|
+
|
484
551
|
def to_hash
|
485
552
|
{
|
486
553
|
NAME => self.name,
|
@@ -502,7 +569,9 @@ class Chef
|
|
502
569
|
VERSION => self.version,
|
503
570
|
SOURCE_URL => self.source_url,
|
504
571
|
ISSUES_URL => self.issues_url,
|
505
|
-
PRIVACY => self.privacy
|
572
|
+
PRIVACY => self.privacy,
|
573
|
+
CHEF_VERSIONS => gem_requirements_to_array(*self.chef_versions),
|
574
|
+
OHAI_VERSIONS => gem_requirements_to_array(*self.ohai_versions)
|
506
575
|
}
|
507
576
|
end
|
508
577
|
|
@@ -537,6 +606,8 @@ class Chef
|
|
537
606
|
@source_url = o[SOURCE_URL] if o.has_key?(SOURCE_URL)
|
538
607
|
@issues_url = o[ISSUES_URL] if o.has_key?(ISSUES_URL)
|
539
608
|
@privacy = o[PRIVACY] if o.has_key?(PRIVACY)
|
609
|
+
@chef_versions = gem_requirements_from_array("chef", o[CHEF_VERSIONS]) if o.has_key?(CHEF_VERSIONS)
|
610
|
+
@ohai_versions = gem_requirements_from_array("ohai", o[OHAI_VERSIONS]) if o.has_key?(OHAI_VERSIONS)
|
540
611
|
self
|
541
612
|
end
|
542
613
|
|
@@ -612,8 +683,43 @@ class Chef
|
|
612
683
|
)
|
613
684
|
end
|
614
685
|
|
686
|
+
# Validates that the Ohai::VERSION of the running chef-client matches one of the
|
687
|
+
# configured ohai_version statements in this cookbooks metadata.
|
688
|
+
#
|
689
|
+
# @raises [Chef::Exceptions::CookbookOhaiVersionMismatch] if the cookbook fails validation
|
690
|
+
def validate_ohai_version!
|
691
|
+
unless gem_dep_matches?("ohai", Gem::Version.new(Ohai::VERSION), *ohai_versions)
|
692
|
+
raise Exceptions::CookbookOhaiVersionMismatch.new(Ohai::VERSION, name, version, *ohai_versions)
|
693
|
+
end
|
694
|
+
end
|
695
|
+
|
696
|
+
# Validates that the Chef::VERSION of the running chef-client matches one of the
|
697
|
+
# configured chef_version statements in this cookbooks metadata.
|
698
|
+
#
|
699
|
+
# @raises [Chef::Exceptions::CookbookChefVersionMismatch] if the cookbook fails validation
|
700
|
+
def validate_chef_version!
|
701
|
+
unless gem_dep_matches?("chef", Gem::Version.new(Chef::VERSION), *chef_versions)
|
702
|
+
raise Exceptions::CookbookChefVersionMismatch.new(Chef::VERSION, name, version, *chef_versions)
|
703
|
+
end
|
704
|
+
end
|
705
|
+
|
615
706
|
private
|
616
707
|
|
708
|
+
# Helper to match a gem style version (ohai_version/chef_version) against a set of
|
709
|
+
# Gem::Dependency version constraints. If none are present, it always matches. if
|
710
|
+
# multiple are present, one must match. Returns false if none matches.
|
711
|
+
#
|
712
|
+
# @param what [String] the name of the constraint (e.g. 'chef' or 'ohai')
|
713
|
+
# @param version [String] the version to compare against the constraints
|
714
|
+
# @param deps [Array<Gem::Dependency>] Multiple Gem-style version constraints
|
715
|
+
# @return [Boolean] true if no constraints or a match, false if no match
|
716
|
+
def gem_dep_matches?(what, version, *deps)
|
717
|
+
# always match if we have no chef_version at all
|
718
|
+
return true unless deps.length > 0
|
719
|
+
# match if we match any of the chef_version lines
|
720
|
+
deps.any? { |dep| dep.match?(what, version) }
|
721
|
+
end
|
722
|
+
|
617
723
|
def run_validation
|
618
724
|
if name.nil?
|
619
725
|
@errors = ["The `name' attribute is required in cookbook metadata"]
|