chef 12.1.2 → 12.2.0.rc.1

Sign up to get free protection for your applications and to get access to all the features.
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 +159 -186
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 974fbc6557ce616bcb34afd11c9b58d30c34e970
4
+ data.tar.gz: 3fc7eb696f927b957afdea89416867246a4fd2df
5
+ SHA512:
6
+ metadata.gz: b156b70d1156ddfb3740af6cb945208f090eacbac9158ad96c915fa185915ec1be1fc67b7bb9112fc0cd8513cccf1f33fcac059b6cd8dbced5dac8c7bf0e69e6
7
+ data.tar.gz: 359c5ff443632400ed5861a8353e6070821c0096463e933f7c21d7bd3c7d48aa5715689f7831ea9a4b864d9245a3ae34abd5d17c51f20dded540200b75d99056
@@ -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