chef 12.1.2-x86-mingw32 → 12.2.0.rc.1-x86-mingw32

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.
Files changed (113) hide show
  1. checksums.yaml +7 -0
  2. data/lib/chef/application/client.rb +2 -2
  3. data/lib/chef/audit/audit_reporter.rb +1 -1
  4. data/lib/chef/audit/runner.rb +15 -2
  5. data/lib/chef/client.rb +1 -1
  6. data/lib/chef/config.rb +6 -4
  7. data/lib/chef/dsl/powershell.rb +29 -0
  8. data/lib/chef/exceptions.rb +18 -3
  9. data/lib/chef/formatters/doc.rb +2 -2
  10. data/lib/chef/knife/bootstrap.rb +2 -1
  11. data/lib/chef/knife/bootstrap/templates/chef-full.erb +1 -1
  12. data/lib/chef/knife/core/subcommand_loader.rb +13 -5
  13. data/lib/chef/knife/exec.rb +2 -1
  14. data/lib/chef/knife/ssh.rb +12 -2
  15. data/lib/chef/mixin/params_validate.rb +42 -19
  16. data/lib/chef/mixin/powershell_type_coercions.rb +82 -0
  17. data/lib/chef/mixin/windows_architecture_helper.rb +8 -0
  18. data/lib/chef/node.rb +1 -1
  19. data/lib/chef/platform/provider_mapping.rb +0 -107
  20. data/lib/chef/platform/query_helpers.rb +7 -0
  21. data/lib/chef/provider/batch.rb +2 -0
  22. data/lib/chef/provider/cron.rb +2 -0
  23. data/lib/chef/provider/cron/aix.rb +2 -0
  24. data/lib/chef/provider/cron/unix.rb +2 -0
  25. data/lib/chef/provider/deploy.rb +104 -87
  26. data/lib/chef/provider/dsc_resource.rb +157 -0
  27. data/lib/chef/provider/env.rb +2 -0
  28. data/lib/chef/provider/env/windows.rb +2 -0
  29. data/lib/chef/provider/git.rb +4 -0
  30. data/lib/chef/provider/group.rb +5 -5
  31. data/lib/chef/provider/group/dscl.rb +2 -0
  32. data/lib/chef/provider/group/groupmod.rb +2 -0
  33. data/lib/chef/provider/group/usermod.rb +2 -0
  34. data/lib/chef/provider/group/windows.rb +2 -0
  35. data/lib/chef/provider/mdadm.rb +2 -0
  36. data/lib/chef/provider/mount/windows.rb +2 -0
  37. data/lib/chef/provider/package/homebrew.rb +1 -1
  38. data/lib/chef/provider/package/openbsd.rb +49 -18
  39. data/lib/chef/provider/package/rubygems.rb +7 -2
  40. data/lib/chef/provider/powershell_script.rb +2 -0
  41. data/lib/chef/provider/service/macosx.rb +1 -2
  42. data/lib/chef/provider/user/dscl.rb +7 -1
  43. data/lib/chef/provider/user/windows.rb +2 -0
  44. data/lib/chef/providers.rb +1 -0
  45. data/lib/chef/recipe.rb +2 -0
  46. data/lib/chef/resource.rb +9 -0
  47. data/lib/chef/resource/batch.rb +2 -0
  48. data/lib/chef/resource/cron.rb +3 -3
  49. data/lib/chef/resource/deploy.rb +52 -217
  50. data/lib/chef/resource/dsc_resource.rb +83 -0
  51. data/lib/chef/resource/env.rb +2 -0
  52. data/lib/chef/resource/git.rb +1 -1
  53. data/lib/chef/resource/group.rb +2 -0
  54. data/lib/chef/resource/homebrew_package.rb +1 -1
  55. data/lib/chef/resource/lwrp_base.rb +0 -8
  56. data/lib/chef/resource/mdadm.rb +2 -0
  57. data/lib/chef/resource/mount.rb +2 -0
  58. data/lib/chef/resource/powershell_script.rb +2 -0
  59. data/lib/chef/resource/user.rb +2 -0
  60. data/lib/chef/resources.rb +1 -0
  61. data/lib/chef/run_context.rb +1 -1
  62. data/lib/chef/shell.rb +7 -5
  63. data/lib/chef/util/dsc/resource_store.rb +110 -0
  64. data/lib/chef/util/path_helper.rb +76 -0
  65. data/lib/chef/util/powershell/cmdlet.rb +41 -7
  66. data/lib/chef/util/powershell/cmdlet_result.rb +18 -3
  67. data/lib/chef/util/powershell/ps_credential.rb +38 -0
  68. data/lib/chef/version.rb +1 -1
  69. data/lib/chef/win32/api.rb +2 -0
  70. data/lib/chef/win32/api/crypto.rb +63 -0
  71. data/lib/chef/win32/api/installer.rb +1 -1
  72. data/lib/chef/win32/crypto.rb +49 -0
  73. data/lib/chef/workstation_config_loader.rb +4 -3
  74. data/spec/functional/file_content_management/deploy_strategies_spec.rb +1 -1
  75. data/spec/functional/resource/cookbook_file_spec.rb +1 -1
  76. data/spec/functional/resource/deploy_revision_spec.rb +35 -0
  77. data/spec/functional/resource/directory_spec.rb +1 -1
  78. data/spec/functional/resource/dsc_resource_spec.rb +93 -0
  79. data/spec/functional/resource/env_spec.rb +4 -3
  80. data/spec/functional/resource/file_spec.rb +1 -1
  81. data/spec/functional/resource/powershell_spec.rb +2 -1
  82. data/spec/functional/resource/remote_directory_spec.rb +1 -1
  83. data/spec/functional/resource/remote_file_spec.rb +1 -1
  84. data/spec/functional/resource/template_spec.rb +1 -1
  85. data/spec/functional/resource/user/dscl_spec.rb +1 -2
  86. data/spec/functional/resource/user/useradd_spec.rb +27 -13
  87. data/spec/functional/util/powershell/cmdlet_spec.rb +3 -3
  88. data/spec/functional/win32/crypto_spec.rb +57 -0
  89. data/spec/spec_helper.rb +3 -0
  90. data/spec/support/platform_helpers.rb +14 -0
  91. data/spec/support/shared/functional/securable_resource_with_reporting.rb +5 -5
  92. data/spec/unit/application/client_spec.rb +4 -4
  93. data/spec/unit/audit/audit_reporter_spec.rb +1 -1
  94. data/spec/unit/audit/runner_spec.rb +10 -0
  95. data/spec/unit/config_spec.rb +2 -8
  96. data/spec/unit/knife/bootstrap_spec.rb +20 -8
  97. data/spec/unit/knife/core/subcommand_loader_spec.rb +29 -29
  98. data/spec/unit/mixin/params_validate_spec.rb +75 -61
  99. data/spec/unit/mixin/powershell_type_coercions_spec.rb +72 -0
  100. data/spec/unit/platform/query_helpers_spec.rb +22 -0
  101. data/spec/unit/platform_spec.rb +0 -5
  102. data/spec/unit/provider/dsc_resource_spec.rb +84 -0
  103. data/spec/unit/provider/package/openbsd_spec.rb +105 -17
  104. data/spec/unit/provider/service/macosx_spec.rb +3 -3
  105. data/spec/unit/provider_resolver_spec.rb +132 -0
  106. data/spec/unit/recipe_spec.rb +4 -0
  107. data/spec/unit/resource/deploy_spec.rb +27 -0
  108. data/spec/unit/resource/dsc_resource_spec.rb +85 -0
  109. data/spec/unit/shell_spec.rb +1 -1
  110. data/spec/unit/util/dsc/resource_store.rb +76 -0
  111. data/spec/unit/util/powershell/ps_credential_spec.rb +37 -0
  112. data/spec/unit/workstation_config_loader_spec.rb +1 -1
  113. metadata +175 -226
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4172090a1bea401568ce1a36c82d3c73e03f83aa
4
+ data.tar.gz: a098a84fd70719f4a02cb32bc60f236ca479e43a
5
+ SHA512:
6
+ metadata.gz: a2aa2b79501b758720d2119b4a87ddad983cfe074de8f7d52f92fc1f1e14473208355687ffc9b75c48568ff60989001bceda831e4515f09c66dbfafca85ec06d
7
+ data.tar.gz: 7f3920491e869c05c0b15be8ed6f45eadf7979615fddf969b117e0c8c14c77a72595675d7f6d6ff3848a40baa41fe923d81293b5ee43ecfa4a084c83b1e914e3
@@ -451,9 +451,9 @@ class Chef::Application::Client < Chef::Application
451
451
 
452
452
  def audit_mode_experimental_message
453
453
  msg = if Chef::Config[:audit_mode] == :audit_only
454
- "Chef-client has been configured to skip converge and run only audits."
454
+ "Chef-client has been configured to skip converge and only audit."
455
455
  else
456
- "Chef-client has been configured to run audits after it converges."
456
+ "Chef-client has been configured to audit after it converges."
457
457
  end
458
458
  msg += " Audit mode is an experimental feature currently under development. API changes may occur. Use at your own risk."
459
459
  msg += audit_mode_settings_explaination
@@ -105,7 +105,7 @@ class Chef
105
105
  end
106
106
 
107
107
  unless run_status
108
- Chef::Log.debug("Run failed before audits were initialized, not sending audit report to server")
108
+ Chef::Log.debug("Run failed before audit mode was initialized, not sending audit report to server")
109
109
  return
110
110
  end
111
111
 
@@ -45,6 +45,10 @@ class Chef
45
45
  RSpec.world.reporter.examples.size
46
46
  end
47
47
 
48
+ def exclusion_pattern
49
+ Regexp.new(".+[\\\/]lib[\\\/]chef[\\\/]")
50
+ end
51
+
48
52
  private
49
53
  # Prepare to run audits:
50
54
  # - Require files
@@ -75,11 +79,15 @@ class Chef
75
79
  require 'rspec'
76
80
  require 'rspec/its'
77
81
  require 'specinfra'
82
+ require 'specinfra/helper'
83
+ require 'specinfra/helper/set'
78
84
  require 'serverspec/helper'
79
85
  require 'serverspec/matcher'
80
86
  require 'serverspec/subject'
81
87
  require 'chef/audit/audit_event_proxy'
82
88
  require 'chef/audit/rspec_formatter'
89
+
90
+ Specinfra::Backend::Cmd.send(:include, Specinfra::Helper::Set)
83
91
  end
84
92
 
85
93
  # Configure RSpec just the way we like it:
@@ -96,6 +104,7 @@ class Chef
96
104
  RSpec.configure do |c|
97
105
  c.color = Chef::Config[:color]
98
106
  c.expose_dsl_globally = false
107
+ c.backtrace_exclusion_patterns << exclusion_pattern
99
108
  end
100
109
  end
101
110
 
@@ -131,9 +140,13 @@ class Chef
131
140
  end
132
141
  end
133
142
 
134
- # Set up the backend for Specinfra/Serverspec. :exec is the local system.
143
+ # Set up the backend for Specinfra/Serverspec. :exec is the local system; on Windows, it is :cmd
135
144
  def configure_specinfra
136
- Specinfra.configuration.backend = :exec
145
+ if Chef::Platform.windows?
146
+ Specinfra.configuration.backend = :cmd
147
+ else
148
+ Specinfra.configuration.backend = :exec
149
+ end
137
150
  end
138
151
 
139
152
  # Iterates through the control groups registered to this run_context, builds an
@@ -451,7 +451,7 @@ class Chef
451
451
 
452
452
  if Chef::Config[:why_run] == true
453
453
  # why_run should probably be renamed to why_converge
454
- Chef::Log.debug("Not running audits in 'why_run' mode - this mode is used to see potential converge changes")
454
+ Chef::Log.debug("Not running controls in 'why_run' mode - this mode is used to see potential converge changes")
455
455
  elsif Chef::Config[:audit_mode] != :disabled
456
456
  audit_error = run_audits(run_context)
457
457
  end
@@ -497,7 +497,8 @@ class Chef
497
497
  default(:syntax_check_cache_path) { cache_options[:path] }
498
498
 
499
499
  # Deprecated:
500
- default(:cache_options) { { :path => PathHelper.join(file_cache_path, "checksums") } }
500
+ # Move this to the default value of syntax_cache_path when this is removed.
501
+ default(:cache_options) { { :path => PathHelper.join(config_dir, "syntaxcache") } }
501
502
 
502
503
  # Whether errors should be raised for deprecation warnings. When set to
503
504
  # `false` (the default setting), a warning is emitted but code using
@@ -570,11 +571,12 @@ class Chef
570
571
  end
571
572
 
572
573
  def self.windows_home_path
573
- env['SYSTEMDRIVE'] + env['HOMEPATH'] if env['SYSTEMDRIVE'] && env['HOMEPATH']
574
+ Chef::Log.deprecation("Chef::Config.windows_home_path is now deprecated. Consider using Chef::Util::PathHelper.home instead.")
575
+ PathHelper.home
574
576
  end
575
577
 
576
578
  # returns a platform specific path to the user home dir if set, otherwise default to current directory.
577
- default( :user_home ) { env['HOME'] || windows_home_path || env['USERPROFILE'] || Dir.pwd }
579
+ default( :user_home ) { PathHelper.home || Dir.pwd }
578
580
 
579
581
  # Enable file permission fixup for selinux. Fixup will be done
580
582
  # only if selinux is enabled in the system.
@@ -627,7 +629,7 @@ class Chef
627
629
  #
628
630
  default :no_lazy_load, true
629
631
 
630
- # Default for the chef_gem compile_time attribute. Nil is the same as false but will emit
632
+ # Default for the chef_gem compile_time attribute. Nil is the same as true but will emit
631
633
  # warnings on every use of chef_gem prompting the user to be explicit. If the user sets this to
632
634
  # true then the user will get backcompat behavior but with a single nag warning that cookbooks
633
635
  # may break with this setting in the future. The false setting is the recommended setting and
@@ -0,0 +1,29 @@
1
+ #
2
+ # Author:: Jay Mundrawala (<jdm@chef.io>)
3
+ # Copyright:: Copyright (c) 2015 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/util/powershell/ps_credential'
20
+
21
+ class Chef
22
+ module DSL
23
+ module Powershell
24
+ def ps_credential(username='placeholder', password)
25
+ Chef::Util::Powershell::PSCredential.new(username, password)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -399,18 +399,18 @@ class Chef
399
399
 
400
400
  class AuditControlGroupDuplicate < RuntimeError
401
401
  def initialize(name)
402
- super "Audit control group with name '#{name}' has already been defined"
402
+ super "Control group with name '#{name}' has already been defined"
403
403
  end
404
404
  end
405
405
  class AuditNameMissing < RuntimeError; end
406
406
  class NoAuditsProvided < RuntimeError
407
407
  def initialize
408
- super "You must provide a block with audits"
408
+ super "You must provide a block with controls"
409
409
  end
410
410
  end
411
411
  class AuditsFailed < RuntimeError
412
412
  def initialize(num_failed, num_total)
413
- super "Audit phase found failures - #{num_failed}/#{num_total} audits failed"
413
+ super "Audit phase found failures - #{num_failed}/#{num_total} controls failed"
414
414
  end
415
415
  end
416
416
 
@@ -442,5 +442,20 @@ class Chef
442
442
  super "PID file and lockfile are not permitted to match. Specify a different location with --pid or --lockfile"
443
443
  end
444
444
  end
445
+
446
+ class MultipleDscResourcesFound < RuntimeError
447
+ attr_reader :resources_found
448
+ def initialize(resources_found)
449
+ @resources_found = resources_found
450
+ matches_info = @resources_found.each do |r|
451
+ if r['Module'].nil?
452
+ "Resource #{r['Name']} was found in #{r['Module']['Name']}"
453
+ else
454
+ "Resource #{r['Name']} is a binary resource"
455
+ end
456
+ end
457
+ super "Found multiple matching resources. #{matches_info.join("\n")}"
458
+ end
459
+ end
445
460
  end
446
461
  end
@@ -47,7 +47,7 @@ class Chef
47
47
  else
48
48
  puts_line "Chef Client finished, #{@updated_resources}/#{total_resources} resources updated in #{elapsed_time} seconds"
49
49
  if total_audits > 0
50
- puts_line " #{successful_audits}/#{total_audits} Audits succeeded"
50
+ puts_line " #{successful_audits}/#{total_audits} controls succeeded"
51
51
  end
52
52
  end
53
53
  end
@@ -59,7 +59,7 @@ class Chef
59
59
  else
60
60
  puts_line "Chef Client failed. #{@updated_resources} resources updated in #{elapsed_time} seconds"
61
61
  if total_audits > 0
62
- puts_line " #{successful_audits} Audits succeeded"
62
+ puts_line " #{successful_audits} controls succeeded"
63
63
  end
64
64
  end
65
65
  end
@@ -21,6 +21,7 @@ require 'chef/knife/data_bag_secret_options'
21
21
  require 'erubis'
22
22
  require 'chef/knife/bootstrap/chef_vault_handler'
23
23
  require 'chef/knife/bootstrap/client_builder'
24
+ require 'chef/util/path_helper'
24
25
 
25
26
  class Chef
26
27
  class Knife
@@ -268,7 +269,7 @@ class Chef
268
269
  bootstrap_files = []
269
270
  bootstrap_files << File.join(File.dirname(__FILE__), 'bootstrap/templates', "#{template}.erb")
270
271
  bootstrap_files << File.join(Knife.chef_config_dir, "bootstrap", "#{template}.erb") if Chef::Knife.chef_config_dir
271
- bootstrap_files << File.join(ENV['HOME'], '.chef', 'bootstrap', "#{template}.erb") if ENV['HOME']
272
+ Chef::Util::PathHelper.home('.chef', 'bootstrap', "#{template}.erb") {|p| bootstrap_files << p}
272
273
  bootstrap_files << Gem.find_files(File.join("chef","knife","bootstrap","#{template}.erb"))
273
274
  bootstrap_files.flatten!
274
275
 
@@ -22,7 +22,7 @@ exists() {
22
22
  <% if knife_config[:bootstrap_install_command] %>
23
23
  <%= knife_config[:bootstrap_install_command] %>
24
24
  <% else %>
25
- install_sh="<%= knife_config[:bootstrap_url] ? knife_config[:bootstrap_url] : "https://www.chef.io/chef/install.sh" %>"
25
+ install_sh="<%= knife_config[:bootstrap_url] ? knife_config[:bootstrap_url] : "https://www.opscode.com/chef/install.sh" %>"
26
26
  if ! exists /usr/bin/chef-client; then
27
27
  echo "Installing Chef Client..."
28
28
  if exists wget; then
@@ -28,9 +28,15 @@ class Chef
28
28
  attr_reader :chef_config_dir
29
29
  attr_reader :env
30
30
 
31
- def initialize(chef_config_dir, env=ENV)
32
- @chef_config_dir, @env = chef_config_dir, env
31
+ def initialize(chef_config_dir, env=nil)
32
+ @chef_config_dir = chef_config_dir
33
33
  @forced_activate = {}
34
+
35
+ # Deprecated and un-used instance variable.
36
+ @env = env
37
+ unless env.nil?
38
+ Chef::Log.deprecation("The env argument to Chef::Knife::SubcommandLoader is deprecated. If you are using env to inject/mock HOME, consider mocking Chef::Util::PathHelper.home instead.")
39
+ end
34
40
  end
35
41
 
36
42
  # Load all the sub-commands
@@ -49,7 +55,9 @@ class Chef
49
55
  end
50
56
 
51
57
  # finally search ~/.chef/plugins/knife/*.rb
52
- user_specific_files.concat Dir.glob(File.join(Chef::Util::PathHelper.escape_glob(env['HOME'], '.chef', 'plugins', 'knife'), '*.rb')) if env['HOME']
58
+ Chef::Util::PathHelper.home('.chef', 'plugins', 'knife') do |p|
59
+ user_specific_files.concat Dir.glob(File.join(Chef::Util::PathHelper.escape_glob(p), '*.rb'))
60
+ end
53
61
 
54
62
  user_specific_files
55
63
  end
@@ -140,7 +148,7 @@ class Chef
140
148
  end
141
149
 
142
150
  def have_plugin_manifest?
143
- ENV["HOME"] && File.exist?(plugin_manifest_path)
151
+ plugin_manifest_path && File.exist?(plugin_manifest_path)
144
152
  end
145
153
 
146
154
  def plugin_manifest
@@ -148,7 +156,7 @@ class Chef
148
156
  end
149
157
 
150
158
  def plugin_manifest_path
151
- File.join(ENV['HOME'], '.chef', 'plugin_manifest.json')
159
+ Chef::Util::PathHelper.home('.chef', 'plugin_manifest.json')
152
160
  end
153
161
 
154
162
  private
@@ -17,6 +17,7 @@
17
17
  #
18
18
 
19
19
  require 'chef/knife'
20
+ require 'chef/util/path_helper'
20
21
 
21
22
  class Chef::Knife::Exec < Chef::Knife
22
23
 
@@ -42,7 +43,7 @@ class Chef::Knife::Exec < Chef::Knife
42
43
 
43
44
  # Default script paths are chef-repo/.chef/scripts and ~/.chef/scripts
44
45
  config[:script_path] << File.join(Chef::Knife.chef_config_dir, 'scripts') if Chef::Knife.chef_config_dir
45
- config[:script_path] << File.join(ENV['HOME'], '.chef', 'scripts') if ENV['HOME']
46
+ Chef::Util::PathHelper.home('.chef', 'scripts') { |p| config[:script_path] << p }
46
47
 
47
48
  scripts = Array(name_args)
48
49
  context = Object.new
@@ -31,6 +31,7 @@ class Chef
31
31
  require 'chef/search/query'
32
32
  require 'chef/mixin/shell_out'
33
33
  require 'chef/mixin/command'
34
+ require 'chef/util/path_helper'
34
35
  require 'mixlib/shellout'
35
36
  end
36
37
 
@@ -103,6 +104,13 @@ class Chef
103
104
  :boolean => true,
104
105
  :default => true
105
106
 
107
+ option :on_error,
108
+ :short => '-e',
109
+ :long => '--exit-on-error',
110
+ :description => "Immediately exit if an error is encountered",
111
+ :boolean => true,
112
+ :proc => Proc.new { :raise }
113
+
106
114
  def session
107
115
  config[:on_error] ||= :skip
108
116
  ssh_error_handler = Proc.new do |server|
@@ -335,8 +343,10 @@ class Chef
335
343
 
336
344
  def screen
337
345
  tf = Tempfile.new("knife-ssh-screen")
338
- if File.exist? "#{ENV["HOME"]}/.screenrc"
339
- tf.puts("source #{ENV["HOME"]}/.screenrc")
346
+ Chef::Util::PathHelper.home('.screenrc') do |screenrc_path|
347
+ if File.exist? screenrc_path
348
+ tf.puts("source #{screenrc_path}")
349
+ end
340
350
  end
341
351
  tf.puts("caption always '%-Lw%{= BW}%50>%n%f* %t%{-}%+Lw%<'")
342
352
  tf.puts("hardstatus alwayslastline 'knife ssh #{@name_args[0]}'")
@@ -81,34 +81,58 @@ class Chef
81
81
  DelayedEvaluator.new(&block)
82
82
  end
83
83
 
84
- def set_or_return(symbol, arg, validation)
84
+ NULL_ARG = Object.new
85
+
86
+ def nillable_set_or_return(symbol, arg, validation)
85
87
  iv_symbol = "@#{symbol.to_s}".to_sym
86
- if arg == nil && self.instance_variable_defined?(iv_symbol) == true
87
- ivar = self.instance_variable_get(iv_symbol)
88
- if(ivar.is_a?(DelayedEvaluator))
89
- validate({ symbol => ivar.call }, { symbol => validation })[symbol]
88
+ if NULL_ARG.equal?(arg)
89
+ if self.instance_variable_defined?(iv_symbol) == true
90
+ get_ivar(iv_symbol, symbol, validation)
90
91
  else
91
- ivar
92
+ # on access we create the iv and set it to nil for back-compat
93
+ set_ivar(iv_symbol, symbol, nil, validation)
92
94
  end
93
95
  else
94
- if(arg.is_a?(DelayedEvaluator))
95
- val = arg
96
- else
97
- val = validate({ symbol => arg }, { symbol => validation })[symbol]
96
+ set_ivar(iv_symbol, symbol, arg, validation)
97
+ end
98
+ end
98
99
 
99
- # Handle the case where the "default" was a DelayedEvaluator. In
100
- # this case, the block yields an optional parameter of +self+,
101
- # which is the equivalent of "new_resource"
102
- if val.is_a?(DelayedEvaluator)
103
- val = val.call(self)
104
- end
105
- end
106
- self.instance_variable_set(iv_symbol, val)
100
+ def set_or_return(symbol, arg, validation)
101
+ iv_symbol = "@#{symbol.to_s}".to_sym
102
+ if arg == nil && self.instance_variable_defined?(iv_symbol) == true
103
+ get_ivar(iv_symbol, symbol, validation)
104
+ else
105
+ set_ivar(iv_symbol, symbol, arg, validation)
107
106
  end
108
107
  end
109
108
 
110
109
  private
111
110
 
111
+ def get_ivar(iv_symbol, symbol, validation)
112
+ ivar = self.instance_variable_get(iv_symbol)
113
+ if(ivar.is_a?(DelayedEvaluator))
114
+ validate({ symbol => ivar.call }, { symbol => validation })[symbol]
115
+ else
116
+ ivar
117
+ end
118
+ end
119
+
120
+ def set_ivar(iv_symbol, symbol, arg, validation)
121
+ if(arg.is_a?(DelayedEvaluator))
122
+ val = arg
123
+ else
124
+ val = validate({ symbol => arg }, { symbol => validation })[symbol]
125
+
126
+ # Handle the case where the "default" was a DelayedEvaluator. In
127
+ # this case, the block yields an optional parameter of +self+,
128
+ # which is the equivalent of "new_resource"
129
+ if val.is_a?(DelayedEvaluator)
130
+ val = val.call(self)
131
+ end
132
+ end
133
+ self.instance_variable_set(iv_symbol, val)
134
+ end
135
+
112
136
  # Return the value of a parameter, or nil if it doesn't exist.
113
137
  def _pv_opts_lookup(opts, key)
114
138
  if opts.has_key?(key.to_s)
@@ -239,4 +263,3 @@ class Chef
239
263
  end
240
264
  end
241
265
  end
242
-
@@ -0,0 +1,82 @@
1
+ #
2
+ # Author:: Adam Edwards (<adamed@opscode.com>)
3
+ # Author:: Jay Mundrawala (<jdm@chef.io>)
4
+ # Copyright:: Copyright (c) 2015 Chef Software, Inc.
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ class Chef
21
+ module Mixin
22
+ module PowershellTypeCoercions
23
+
24
+ def type_coercions
25
+ @type_coercions ||= {
26
+ Fixnum => { :type => lambda { |x| x.to_s }},
27
+ Float => { :type => lambda { |x| x.to_s }},
28
+ FalseClass => { :type => lambda { |x| '$false' }},
29
+ TrueClass => { :type => lambda { |x| '$true' }},
30
+ Hash => {:type => Proc.new { |x| translate_hash(x)}},
31
+ Array => {:type => Proc.new { |x| translate_array(x)}}
32
+ }
33
+ end
34
+
35
+ def translate_type(value)
36
+ translation = type_coercions[value.class]
37
+
38
+ if translation
39
+ translation[:type].call(value)
40
+ elsif value.respond_to? :to_psobject
41
+ "(#{value.to_psobject})"
42
+ else
43
+ safe_string(value.to_s)
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def translate_hash(x)
50
+ translated = x.inject([]) do |memo, (k,v)|
51
+ memo << "#{k}=#{translate_type(v)}"
52
+ end
53
+ "@{#{translated.join(';')}}"
54
+ end
55
+
56
+ def translate_array(x)
57
+ translated = x.map do |v|
58
+ translate_type(v)
59
+ end
60
+ "@(#{translated.join(',')})"
61
+ end
62
+
63
+ def unsafe?(s)
64
+ ["'", '#', '`', '"'].any? do |x|
65
+ s.include? x
66
+ end
67
+ end
68
+
69
+ def safe_string(s)
70
+ # do we need to worry about binary data?
71
+ if unsafe?(s)
72
+ encoded_str = Base64.strict_encode64(s.encode("UTF-8"))
73
+ "([System.Text.Encoding]::UTF8.GetString("\
74
+ "[System.Convert]::FromBase64String('#{encoded_str}')"\
75
+ "))"
76
+ else
77
+ "'#{s}'"
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end