chef 11.14.6-x86-mingw32 → 11.16.0-x86-mingw32
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/chef/exceptions.rb +4 -0
- data/lib/chef/mixin/windows_architecture_helper.rb +16 -0
- data/lib/chef/platform/query_helpers.rb +5 -1
- data/lib/chef/provider/dsc_script.rb +148 -0
- data/lib/chef/provider/user/dscl.rb +32 -28
- data/lib/chef/providers.rb +1 -0
- data/lib/chef/resource/dsc_script.rb +140 -0
- data/lib/chef/resources.rb +1 -0
- data/lib/chef/util/dsc/configuration_generator.rb +115 -0
- data/lib/chef/util/dsc/lcm_output_parser.rb +133 -0
- data/lib/chef/util/dsc/local_configuration_manager.rb +137 -0
- data/lib/chef/util/dsc/resource_info.rb +26 -0
- data/lib/chef/util/path_helper.rb +2 -2
- data/lib/chef/util/powershell/cmdlet.rb +136 -0
- data/lib/chef/util/powershell/cmdlet_result.rb +46 -0
- data/lib/chef/version.rb +1 -1
- data/spec/functional/resource/dsc_script_spec.rb +337 -0
- data/spec/functional/resource/group_spec.rb +5 -1
- data/spec/functional/util/powershell/cmdlet_spec.rb +114 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/support/platform_helpers.rb +24 -0
- data/spec/unit/platform/query_helpers_spec.rb +23 -0
- data/spec/unit/provider/dsc_script_spec.rb +145 -0
- data/spec/unit/provider/user/dscl_spec.rb +2 -1
- data/spec/unit/resource/dsc_script_spec.rb +127 -0
- data/spec/unit/util/dsc/configuration_generator_spec.rb +171 -0
- data/spec/unit/util/dsc/lcm_output_parser_spec.rb +169 -0
- data/spec/unit/util/dsc/local_configuration_manager_spec.rb +134 -0
- data/spec/unit/util/powershell/cmdlet_spec.rb +106 -0
- metadata +20 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 49b6fe3b7b3cc9463d7faa2c42c063805a8c0622
|
4
|
+
data.tar.gz: bf2edeaa5447924dc2f5d6c4f21409f99e268f03
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: edd6c14fb435fc1c2ee3f19ae061221c3f895b650b77f44f5142c5ba6b0af671e7205535c76a90f23d24c4e96fbd5e45fb1eeb5f7e0a754733274d9e770b8057
|
7
|
+
data.tar.gz: 8f044ddd62016822cc9fdbfd3d80c9d1598b34aff1af8c0274bdfcd5339eebe61bdca9d0bd25c53cb114eded9a62fd45d412752eec5ff6064c2516326e71e986
|
data/lib/chef/exceptions.rb
CHANGED
@@ -117,6 +117,8 @@ class Chef
|
|
117
117
|
class ObsoleteDependencySyntax < ArgumentError; end
|
118
118
|
class InvalidDataBagPath < ArgumentError; end
|
119
119
|
|
120
|
+
class PowershellCmdletException < RuntimeError; end
|
121
|
+
|
120
122
|
# A different version of a cookbook was added to a
|
121
123
|
# VersionedRecipeList than the one already there.
|
122
124
|
class CookbookVersionConflict < ArgumentError ; end
|
@@ -176,6 +178,8 @@ class Chef
|
|
176
178
|
|
177
179
|
class ChildConvergeError < RuntimeError; end
|
178
180
|
|
181
|
+
class NoProviderAvailable < RuntimeError; end
|
182
|
+
|
179
183
|
class MissingRole < RuntimeError
|
180
184
|
NULL = Object.new
|
181
185
|
|
@@ -41,6 +41,22 @@ class Chef
|
|
41
41
|
is_i386_process_on_x86_64_windows?
|
42
42
|
end
|
43
43
|
|
44
|
+
def with_os_architecture(node)
|
45
|
+
wow64_redirection_state = nil
|
46
|
+
|
47
|
+
if wow64_architecture_override_required?(node, node_windows_architecture(node))
|
48
|
+
wow64_redirection_state = disable_wow64_file_redirection(node)
|
49
|
+
end
|
50
|
+
|
51
|
+
begin
|
52
|
+
yield
|
53
|
+
ensure
|
54
|
+
if wow64_redirection_state
|
55
|
+
restore_wow64_file_redirection(node, wow64_redirection_state)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
44
60
|
def node_supports_windows_architecture?(node, desired_architecture)
|
45
61
|
assert_valid_windows_architecture!(desired_architecture)
|
46
62
|
return (node_windows_architecture(node) == :x86_64 ||
|
@@ -0,0 +1,148 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Adam Edwards (<adamed@getchef.com>)
|
3
|
+
#
|
4
|
+
# Copyright:: 2014, Chef Software, Inc.
|
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/util/powershell/cmdlet'
|
20
|
+
require 'chef/util/dsc/configuration_generator'
|
21
|
+
require 'chef/util/dsc/local_configuration_manager'
|
22
|
+
|
23
|
+
class Chef
|
24
|
+
class Provider
|
25
|
+
class DscScript < Chef::Provider
|
26
|
+
def initialize(dsc_resource, run_context)
|
27
|
+
super(dsc_resource, run_context)
|
28
|
+
@dsc_resource = dsc_resource
|
29
|
+
@resource_converged = false
|
30
|
+
@operations = {
|
31
|
+
:set => Proc.new { |config_manager, document|
|
32
|
+
config_manager.set_configuration(document)
|
33
|
+
},
|
34
|
+
:test => Proc.new { |config_manager, document|
|
35
|
+
config_manager.test_configuration(document)
|
36
|
+
}}
|
37
|
+
end
|
38
|
+
|
39
|
+
def action_run
|
40
|
+
if ! @resource_converged
|
41
|
+
converge_by(generate_description) do
|
42
|
+
run_configuration(:set)
|
43
|
+
Chef::Log.info("DSC resource configuration completed successfully")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def load_current_resource
|
49
|
+
@dsc_resources_info = run_configuration(:test)
|
50
|
+
@resource_converged = @dsc_resources_info.all? do |resource|
|
51
|
+
!resource.changes_state?
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def whyrun_supported?
|
56
|
+
true
|
57
|
+
end
|
58
|
+
|
59
|
+
protected
|
60
|
+
|
61
|
+
def run_configuration(operation)
|
62
|
+
config_directory = ::Dir.mktmpdir("chef-dsc-script")
|
63
|
+
configuration_data_path = get_configuration_data_path(config_directory)
|
64
|
+
configuration_flags = get_augmented_configuration_flags(configuration_data_path)
|
65
|
+
|
66
|
+
config_manager = Chef::Util::DSC::LocalConfigurationManager.new(@run_context.node, config_directory)
|
67
|
+
|
68
|
+
begin
|
69
|
+
configuration_document = generate_configuration_document(config_directory, configuration_flags)
|
70
|
+
@operations[operation].call(config_manager, configuration_document)
|
71
|
+
rescue Exception => e
|
72
|
+
Chef::Log.error("DSC operation failed: #{e.message.to_s}")
|
73
|
+
raise e
|
74
|
+
ensure
|
75
|
+
::FileUtils.rm_rf(config_directory)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def get_augmented_configuration_flags(configuration_data_path)
|
80
|
+
updated_flags = nil
|
81
|
+
if configuration_data_path
|
82
|
+
updated_flags = @dsc_resource.flags.nil? ? {} : @dsc_resource.flags.dup
|
83
|
+
Chef::Util::PathHelper.validate_path(configuration_data_path)
|
84
|
+
updated_flags[:configurationdata] = configuration_data_path
|
85
|
+
end
|
86
|
+
updated_flags
|
87
|
+
end
|
88
|
+
|
89
|
+
def generate_configuration_document(config_directory, configuration_flags)
|
90
|
+
shellout_flags = {
|
91
|
+
:cwd => @dsc_resource.cwd,
|
92
|
+
:environment => @dsc_resource.environment,
|
93
|
+
:timeout => @dsc_resource.timeout
|
94
|
+
}
|
95
|
+
|
96
|
+
generator = Chef::Util::DSC::ConfigurationGenerator.new(@run_context.node, config_directory)
|
97
|
+
|
98
|
+
if @dsc_resource.command
|
99
|
+
generator.configuration_document_from_script_path(@dsc_resource.command, configuration_name, configuration_flags, shellout_flags)
|
100
|
+
else
|
101
|
+
# If code is also not provided, we mimic what the other script resources do (execute nothing)
|
102
|
+
Chef::Log.warn("Neither code or command were provided for dsc_resource[#{@dsc_resource.name}].") unless @dsc_resource.code
|
103
|
+
generator.configuration_document_from_script_code(@dsc_resource.code || '', configuration_flags, shellout_flags)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def get_configuration_data_path(config_directory)
|
108
|
+
if @dsc_resource.configuration_data_script
|
109
|
+
@dsc_resource.configuration_data_script
|
110
|
+
elsif @dsc_resource.configuration_data
|
111
|
+
configuration_data_path = "#{config_directory}/chef_dsc_config_data.psd1"
|
112
|
+
::File.open(configuration_data_path, 'wt') do | script |
|
113
|
+
script.write(@dsc_resource.configuration_data)
|
114
|
+
end
|
115
|
+
configuration_data_path
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def configuration_name
|
120
|
+
@dsc_resource.configuration_name || @dsc_resource.name
|
121
|
+
end
|
122
|
+
|
123
|
+
def configuration_friendly_name
|
124
|
+
if @dsc_resource.code
|
125
|
+
@dsc_resource.name
|
126
|
+
else
|
127
|
+
configuration_name
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
|
133
|
+
def generate_description
|
134
|
+
["converge DSC configuration '#{configuration_friendly_name}'"] +
|
135
|
+
@dsc_resources_info.map do |resource|
|
136
|
+
if resource.changes_state?
|
137
|
+
# We ignore the last log message because it only contains the time it took, which looks weird
|
138
|
+
cleaned_messages = resource.change_log[0..-2].map { |c| c.sub(/^#{Regexp.escape(resource.name)}/, '').strip }
|
139
|
+
"converge DSC resource #{resource.name} by #{cleaned_messages.find_all{ |c| c != ''}.join("\n")}"
|
140
|
+
else
|
141
|
+
# This is needed because a dsc script can have resouces that are both converged and not
|
142
|
+
"converge DSC resource #{resource.name} by doing nothing because it is already converged"
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -110,18 +110,18 @@ user password using shadow hash.")
|
|
110
110
|
@current_resource = Chef::Resource::User.new(@new_resource.username)
|
111
111
|
@current_resource.username(@new_resource.username)
|
112
112
|
|
113
|
-
user_info = read_user_info
|
114
|
-
if user_info
|
115
|
-
@current_resource.uid(dscl_get(user_info, :uid))
|
116
|
-
@current_resource.gid(dscl_get(user_info, :gid))
|
117
|
-
@current_resource.home(dscl_get(user_info, :home))
|
118
|
-
@current_resource.shell(dscl_get(user_info, :shell))
|
119
|
-
@current_resource.comment(dscl_get(user_info, :comment))
|
120
|
-
@authentication_authority = dscl_get(user_info, :auth_authority)
|
121
|
-
|
122
|
-
if @new_resource.password && dscl_get(user_info, :password) == "********"
|
113
|
+
@user_info = read_user_info
|
114
|
+
if @user_info
|
115
|
+
@current_resource.uid(dscl_get(@user_info, :uid))
|
116
|
+
@current_resource.gid(dscl_get(@user_info, :gid))
|
117
|
+
@current_resource.home(dscl_get(@user_info, :home))
|
118
|
+
@current_resource.shell(dscl_get(@user_info, :shell))
|
119
|
+
@current_resource.comment(dscl_get(@user_info, :comment))
|
120
|
+
@authentication_authority = dscl_get(@user_info, :auth_authority)
|
121
|
+
|
122
|
+
if @new_resource.password && dscl_get(@user_info, :password) == "********"
|
123
123
|
# A password is set. Let's get the password information from shadow file
|
124
|
-
shadow_hash_binary = dscl_get(user_info, :shadow_hash)
|
124
|
+
shadow_hash_binary = dscl_get(@user_info, :shadow_hash)
|
125
125
|
|
126
126
|
# Calling shell_out directly since we want to give an input stream
|
127
127
|
shadow_hash_xml = convert_binary_plist_to_xml(shadow_hash_binary.string)
|
@@ -158,22 +158,26 @@ user password using shadow hash.")
|
|
158
158
|
|
159
159
|
def create_user
|
160
160
|
dscl_create_user
|
161
|
+
# set_password modifies the plist file of the user directly. So update
|
162
|
+
# the password first before making any modifications to the user.
|
163
|
+
set_password
|
161
164
|
dscl_create_comment
|
162
165
|
dscl_set_uid
|
163
166
|
dscl_set_gid
|
164
167
|
dscl_set_home
|
165
168
|
dscl_set_shell
|
166
|
-
set_password
|
167
169
|
end
|
168
170
|
|
169
171
|
def manage_user
|
172
|
+
# set_password modifies the plist file of the user directly. So update
|
173
|
+
# the password first before making any modifications to the user.
|
174
|
+
set_password if diverged_password?
|
170
175
|
dscl_create_user if diverged?(:username)
|
171
176
|
dscl_create_comment if diverged?(:comment)
|
172
177
|
dscl_set_uid if diverged?(:uid)
|
173
178
|
dscl_set_gid if diverged?(:gid)
|
174
179
|
dscl_set_home if diverged?(:home)
|
175
180
|
dscl_set_shell if diverged?(:shell)
|
176
|
-
set_password if diverged_password?
|
177
181
|
end
|
178
182
|
|
179
183
|
#
|
@@ -339,22 +343,18 @@ user password using shadow hash.")
|
|
339
343
|
:input => shadow_info.to_plist, :live_stream => shadow_info_binary)
|
340
344
|
command.run_command
|
341
345
|
|
346
|
+
if @user_info.nil?
|
347
|
+
# User is just created. read_user_info() will read the fresh information
|
348
|
+
# for the user with a cache flush. However with experimentation we've seen
|
349
|
+
# that dscl cache is not immediately updated after the creation of the user
|
350
|
+
# This is odd and needs to be investigated further.
|
351
|
+
sleep 3
|
352
|
+
@user_info = read_user_info
|
353
|
+
end
|
354
|
+
|
342
355
|
# Replace the shadow info in user's plist
|
343
|
-
user_info
|
344
|
-
|
345
|
-
|
346
|
-
#
|
347
|
-
# Before saving the user's plist file we need to wait for dscl to
|
348
|
-
# update its caches and flush them to disk. In order to achieve this
|
349
|
-
# we need to wait first for our changes to get into the dscl cache
|
350
|
-
# and then flush the cache to disk before saving password into the
|
351
|
-
# plist file. 3 seconds is the minimum experimental value for dscl
|
352
|
-
# cache to be updated. We can get rid of this sleep when we find a
|
353
|
-
# trigger to update dscl cache.
|
354
|
-
#
|
355
|
-
sleep 3
|
356
|
-
shell_out("dscacheutil '-flushcache'")
|
357
|
-
save_user_info(user_info)
|
356
|
+
dscl_set(@user_info, :shadow_hash, shadow_info_binary)
|
357
|
+
save_user_info(@user_info)
|
358
358
|
end
|
359
359
|
|
360
360
|
#
|
@@ -555,6 +555,10 @@ user password using shadow hash.")
|
|
555
555
|
def read_user_info
|
556
556
|
user_info = nil
|
557
557
|
|
558
|
+
# We flush the cache here in order to make sure that we read fresh information
|
559
|
+
# for the user.
|
560
|
+
shell_out("dscacheutil '-flushcache'")
|
561
|
+
|
558
562
|
begin
|
559
563
|
user_plist_file = "#{USER_PLIST_DIRECTORY}/#{@new_resource.username}.plist"
|
560
564
|
user_plist_info = run_plutil("convert xml1 -o - #{user_plist_file}")
|
data/lib/chef/providers.rb
CHANGED
@@ -24,6 +24,7 @@ require 'chef/provider/cron/solaris'
|
|
24
24
|
require 'chef/provider/cron/aix'
|
25
25
|
require 'chef/provider/deploy'
|
26
26
|
require 'chef/provider/directory'
|
27
|
+
require 'chef/provider/dsc_script'
|
27
28
|
require 'chef/provider/env'
|
28
29
|
require 'chef/provider/erl_call'
|
29
30
|
require 'chef/provider/execute'
|
@@ -0,0 +1,140 @@
|
|
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
|
+
require 'chef/exceptions'
|
20
|
+
|
21
|
+
class Chef
|
22
|
+
class Resource
|
23
|
+
class DscScript < Chef::Resource
|
24
|
+
|
25
|
+
provides :dsc_script, :on_platforms => ["windows"]
|
26
|
+
|
27
|
+
def initialize(name, run_context=nil)
|
28
|
+
super
|
29
|
+
@allowed_actions.push(:run)
|
30
|
+
@action = :run
|
31
|
+
if(run_context && Chef::Platform.supports_dsc?(run_context.node))
|
32
|
+
@provider = Chef::Provider::DscScript
|
33
|
+
else
|
34
|
+
raise Chef::Exceptions::NoProviderAvailable,
|
35
|
+
"#{powershell_info_str(run_context)}\nPowershell 4.0 or higher was not detected on your system and is required to use the dsc_script resource."
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def code(arg=nil)
|
40
|
+
if arg && command
|
41
|
+
raise ArgumentError, "Only one of 'code' and 'command' attributes may be specified"
|
42
|
+
end
|
43
|
+
if arg && configuration_name
|
44
|
+
raise ArgumentError, "The 'code' and 'command' attributes may not be used together"
|
45
|
+
end
|
46
|
+
set_or_return(
|
47
|
+
:code,
|
48
|
+
arg,
|
49
|
+
:kind_of => [ String ]
|
50
|
+
)
|
51
|
+
end
|
52
|
+
|
53
|
+
def configuration_name(arg=nil)
|
54
|
+
if arg && code
|
55
|
+
raise ArgumentError, "Attribute `configuration_name` may not be set if `code` is set"
|
56
|
+
end
|
57
|
+
set_or_return(
|
58
|
+
:configuration_name,
|
59
|
+
arg,
|
60
|
+
:kind_of => [ String ]
|
61
|
+
)
|
62
|
+
end
|
63
|
+
|
64
|
+
def command(arg=nil)
|
65
|
+
if arg && code
|
66
|
+
raise ArgumentError, "The 'code' and 'command' attributes may not be used together"
|
67
|
+
end
|
68
|
+
set_or_return(
|
69
|
+
:command,
|
70
|
+
arg,
|
71
|
+
:kind_of => [ String ]
|
72
|
+
)
|
73
|
+
end
|
74
|
+
|
75
|
+
def configuration_data(arg=nil)
|
76
|
+
if arg && configuration_data_script
|
77
|
+
raise ArgumentError, "The 'configuration_data' and 'configuration_data_script' attributes may not be used together"
|
78
|
+
end
|
79
|
+
set_or_return(
|
80
|
+
:configuration_data,
|
81
|
+
arg,
|
82
|
+
:kind_of => [ String ]
|
83
|
+
)
|
84
|
+
end
|
85
|
+
|
86
|
+
def configuration_data_script(arg=nil)
|
87
|
+
if arg && configuration_data
|
88
|
+
raise ArgumentError, "The 'configuration_data' and 'configuration_data_script' attributes may not be used together"
|
89
|
+
end
|
90
|
+
set_or_return(
|
91
|
+
:configuration_data_script,
|
92
|
+
arg,
|
93
|
+
:kind_of => [ String ]
|
94
|
+
)
|
95
|
+
end
|
96
|
+
|
97
|
+
def flags(arg=nil)
|
98
|
+
set_or_return(
|
99
|
+
:flags,
|
100
|
+
arg,
|
101
|
+
:kind_of => [ Hash ]
|
102
|
+
)
|
103
|
+
end
|
104
|
+
|
105
|
+
def cwd(arg=nil)
|
106
|
+
set_or_return(
|
107
|
+
:cwd,
|
108
|
+
arg,
|
109
|
+
:kind_of => [ String ]
|
110
|
+
)
|
111
|
+
end
|
112
|
+
|
113
|
+
def environment(arg=nil)
|
114
|
+
set_or_return(
|
115
|
+
:environment,
|
116
|
+
arg,
|
117
|
+
:kind_of => [ Hash ]
|
118
|
+
)
|
119
|
+
end
|
120
|
+
|
121
|
+
def timeout(arg=nil)
|
122
|
+
set_or_return(
|
123
|
+
:timeout,
|
124
|
+
arg,
|
125
|
+
:kind_of => [ Integer ]
|
126
|
+
)
|
127
|
+
end
|
128
|
+
|
129
|
+
private
|
130
|
+
|
131
|
+
def powershell_info_str(run_context)
|
132
|
+
if run_context && run_context.node[:languages] && run_context.node[:languages][:powershell]
|
133
|
+
install_info = "Powershell #{run_context.node[:languages][:powershell][:version]} was found on the system."
|
134
|
+
else
|
135
|
+
install_info = 'Powershell was not found.'
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|