chef 11.10.0.alpha.1-x86-mingw32 → 11.10.0.rc.0-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 (131) hide show
  1. data/README.md +57 -36
  2. data/distro/common/html/chef-client.8.html +4 -4
  3. data/distro/common/html/chef-expander.8.html +4 -4
  4. data/distro/common/html/chef-expanderctl.8.html +4 -4
  5. data/distro/common/html/chef-server-webui.8.html +4 -4
  6. data/distro/common/html/chef-server.8.html +4 -4
  7. data/distro/common/html/chef-shell.1.html +4 -4
  8. data/distro/common/html/chef-solo.8.html +4 -4
  9. data/distro/common/html/chef-solr.8.html +5 -5
  10. data/distro/common/html/knife-bootstrap.1.html +4 -4
  11. data/distro/common/html/knife-client.1.html +4 -4
  12. data/distro/common/html/knife-configure.1.html +4 -4
  13. data/distro/common/html/knife-cookbook-site.1.html +4 -4
  14. data/distro/common/html/knife-cookbook.1.html +4 -4
  15. data/distro/common/html/knife-data-bag.1.html +4 -4
  16. data/distro/common/html/knife-environment.1.html +4 -4
  17. data/distro/common/html/knife-exec.1.html +4 -4
  18. data/distro/common/html/knife-index.1.html +4 -4
  19. data/distro/common/html/knife-node.1.html +4 -4
  20. data/distro/common/html/knife-role.1.html +4 -4
  21. data/distro/common/html/knife-search.1.html +4 -4
  22. data/distro/common/html/knife-ssh.1.html +4 -4
  23. data/distro/common/html/knife-status.1.html +4 -4
  24. data/distro/common/html/knife-tag.1.html +4 -4
  25. data/distro/common/html/knife.1.html +4 -4
  26. data/distro/common/man/man1/knife-bootstrap.1 +58 -64
  27. data/distro/common/man/man1/knife-client.1 +19 -22
  28. data/distro/common/man/man1/knife-configure.1 +37 -46
  29. data/distro/common/man/man1/knife-cookbook-site.1 +14 -17
  30. data/distro/common/man/man1/knife-cookbook.1 +15 -18
  31. data/distro/common/man/man1/knife-data-bag.1 +14 -17
  32. data/distro/common/man/man1/knife-delete.1 +38 -47
  33. data/distro/common/man/man1/knife-deps.1 +39 -48
  34. data/distro/common/man/man1/knife-diff.1 +43 -52
  35. data/distro/common/man/man1/knife-download.1 +47 -53
  36. data/distro/common/man/man1/knife-edit.1 +32 -41
  37. data/distro/common/man/man1/knife-environment.1 +14 -17
  38. data/distro/common/man/man1/knife-exec.1 +52 -61
  39. data/distro/common/man/man1/knife-index-rebuild.1 +1 -61
  40. data/distro/common/man/man1/knife-list.1 +47 -59
  41. data/distro/common/man/man1/knife-node.1 +15 -18
  42. data/distro/common/man/man1/knife-raw.1 +28 -46
  43. data/distro/common/man/man1/knife-recipe-list.1 +1 -61
  44. data/distro/common/man/man1/knife-role.1 +19 -25
  45. data/distro/common/man/man1/knife-search.1 +53 -62
  46. data/distro/common/man/man1/knife-show.1 +36 -28
  47. data/distro/common/man/man1/knife-ssh.1 +55 -61
  48. data/distro/common/man/man1/knife-status.1 +34 -43
  49. data/distro/common/man/man1/knife-tag.1 +14 -17
  50. data/distro/common/man/man1/knife-upload.1 +47 -56
  51. data/distro/common/man/man1/knife-user.1 +17 -20
  52. data/distro/common/man/man1/knife-xargs.1 +60 -69
  53. data/lib/chef/application.rb +3 -1
  54. data/lib/chef/application/windows_service.rb +0 -1
  55. data/lib/chef/client.rb +41 -152
  56. data/lib/chef/config.rb +19 -23
  57. data/lib/chef/data_bag.rb +1 -1
  58. data/lib/chef/data_bag_item.rb +1 -1
  59. data/lib/chef/exceptions.rb +8 -0
  60. data/lib/chef/formatters/doc.rb +15 -0
  61. data/lib/chef/formatters/error_inspectors/api_error_formatting.rb +2 -1
  62. data/lib/chef/http.rb +18 -8
  63. data/lib/chef/http/authenticator.rb +4 -0
  64. data/lib/chef/http/cookie_manager.rb +3 -0
  65. data/lib/chef/http/decompressor.rb +4 -0
  66. data/lib/chef/http/json_input.rb +4 -0
  67. data/lib/chef/http/json_output.rb +4 -0
  68. data/lib/chef/http/validate_content_length.rb +94 -0
  69. data/lib/chef/knife.rb +0 -1
  70. data/lib/chef/knife/configure.rb +6 -6
  71. data/lib/chef/knife/cookbook_create.rb +2 -2
  72. data/lib/chef/knife/core/subcommand_loader.rb +49 -3
  73. data/lib/chef/knife/ssh.rb +34 -4
  74. data/lib/chef/mixin/path_sanity.rb +1 -0
  75. data/lib/chef/monologger.rb +1 -2
  76. data/lib/chef/node.rb +7 -0
  77. data/lib/chef/policy_builder.rb +49 -0
  78. data/lib/chef/policy_builder/expand_node_object.rb +230 -0
  79. data/lib/chef/policy_builder/policyfile.rb +338 -0
  80. data/lib/chef/provider/file.rb +15 -5
  81. data/lib/chef/provider/group.rb +6 -2
  82. data/lib/chef/provider/group/windows.rb +12 -2
  83. data/lib/chef/provider/http_request.rb +3 -2
  84. data/lib/chef/provider/package.rb +1 -0
  85. data/lib/chef/provider/package/aix.rb +1 -1
  86. data/lib/chef/provider/service/debian.rb +7 -2
  87. data/lib/chef/resource/file.rb +8 -1
  88. data/lib/chef/resource/package.rb +9 -0
  89. data/lib/chef/resource/service.rb +0 -1
  90. data/lib/chef/rest.rb +2 -0
  91. data/lib/chef/run_context.rb +1 -1
  92. data/lib/chef/util/file_edit.rb +1 -1
  93. data/lib/chef/util/windows/net_group.rb +7 -6
  94. data/lib/chef/version.rb +1 -1
  95. data/lib/chef/win32/version.rb +31 -18
  96. data/spec/data/cookbooks/preseed/templates/default/preseed-template-variables.seed +1 -0
  97. data/spec/functional/resource/file_spec.rb +0 -1
  98. data/spec/functional/resource/group_spec.rb +96 -16
  99. data/spec/functional/resource/package_spec.rb +17 -0
  100. data/spec/functional/resource/user_spec.rb +2 -2
  101. data/spec/functional/win32/versions_spec.rb +39 -0
  102. data/spec/integration/client/client_spec.rb +27 -28
  103. data/spec/spec_helper.rb +2 -0
  104. data/spec/support/platform_helpers.rb +7 -1
  105. data/spec/support/shared/functional/file_resource.rb +83 -43
  106. data/spec/unit/application_spec.rb +7 -5
  107. data/spec/unit/client_spec.rb +10 -3
  108. data/spec/unit/config_spec.rb +0 -30
  109. data/spec/unit/cookbook_spec.rb +1 -0
  110. data/spec/unit/data_bag_item_spec.rb +8 -0
  111. data/spec/unit/data_bag_spec.rb +6 -0
  112. data/spec/unit/http_spec.rb +48 -0
  113. data/spec/unit/knife/core/subcommand_loader_spec.rb +77 -1
  114. data/spec/unit/knife/ssh_spec.rb +107 -0
  115. data/spec/unit/mixin/path_sanity_spec.rb +6 -0
  116. data/spec/unit/mixin/securable_spec.rb +77 -3
  117. data/spec/unit/monologger_spec.rb +45 -0
  118. data/spec/unit/node_spec.rb +16 -0
  119. data/spec/unit/policy_builder/expand_node_object_spec.rb +320 -0
  120. data/spec/unit/policy_builder/policyfile_spec.rb +399 -0
  121. data/spec/unit/policy_builder_spec.rb +26 -0
  122. data/spec/unit/provider/deploy_spec.rb +3 -0
  123. data/spec/unit/provider/group/windows_spec.rb +1 -0
  124. data/spec/unit/provider/http_request_spec.rb +23 -1
  125. data/spec/unit/provider/service/debian_service_spec.rb +50 -19
  126. data/spec/unit/recipe_spec.rb +4 -0
  127. data/spec/unit/resource/package_spec.rb +5 -0
  128. data/spec/unit/rest_spec.rb +375 -278
  129. data/spec/unit/run_context_spec.rb +4 -0
  130. metadata +120 -75
  131. checksums.yaml +0 -7
@@ -352,16 +352,27 @@ class Chef
352
352
  if tempfile.path.nil? || !::File.exists?(tempfile.path)
353
353
  raise "chef-client is confused, trying to deploy a file that has no path or does not exist..."
354
354
  end
355
+
355
356
  # the file? on the next line suppresses the case in why-run when we have a not-file here that would have otherwise been removed
356
357
  if ::File.file?(@new_resource.path) && contents_changed?
357
- diff.diff(@current_resource.path, tempfile.path)
358
- @new_resource.diff( diff.for_reporting ) unless file_created?
359
- description = [ "update content in file #{@new_resource.path} from #{short_cksum(@current_resource.checksum)} to #{short_cksum(checksum(tempfile.path))}" ]
360
- description << diff.for_output
358
+ description = [ "update content in file #{@new_resource.path} from \
359
+ #{short_cksum(@current_resource.checksum)} to #{short_cksum(checksum(tempfile.path))}" ]
360
+
361
+ # Hide the diff output if the resource is marked as a sensitive resource
362
+ if @new_resource.sensitive
363
+ @new_resource.diff("suppressed sensitive resource")
364
+ description << "suppressed sensitive resource"
365
+ else
366
+ diff.diff(@current_resource.path, tempfile.path)
367
+ @new_resource.diff( diff.for_reporting ) unless file_created?
368
+ description << diff.for_output
369
+ end
370
+
361
371
  converge_by(description) do
362
372
  update_file_contents
363
373
  end
364
374
  end
375
+
365
376
  # unlink necessary to clean up in why-run mode
366
377
  tempfile.unlink
367
378
  end
@@ -420,4 +431,3 @@ class Chef
420
431
  end
421
432
  end
422
433
  end
423
-
@@ -91,7 +91,7 @@ class Chef
91
91
  if(@new_resource.append)
92
92
  missing_members = []
93
93
  @new_resource.members.each do |member|
94
- next if @current_resource.members.include?(member)
94
+ next if has_current_group_member?(member)
95
95
  missing_members << member
96
96
  end
97
97
  if missing_members.length > 0
@@ -100,7 +100,7 @@ class Chef
100
100
 
101
101
  members_to_be_removed = []
102
102
  @new_resource.excluded_members.each do |member|
103
- if @current_resource.members.include?(member)
103
+ if has_current_group_member?(member)
104
104
  members_to_be_removed << member
105
105
  end
106
106
  end
@@ -116,6 +116,10 @@ class Chef
116
116
  !@change_desc.empty?
117
117
  end
118
118
 
119
+ def has_current_group_member?(member)
120
+ @current_resource.members.include?(member)
121
+ end
122
+
119
123
  def action_create
120
124
  case @group_exists
121
125
  when false
@@ -59,7 +59,7 @@ class Chef
59
59
  if @new_resource.append
60
60
  members_to_be_added = [ ]
61
61
  @new_resource.members.each do |member|
62
- members_to_be_added << member if !@current_resource.members.include?(member)
62
+ members_to_be_added << member if ! has_current_group_member?(member)
63
63
  end
64
64
 
65
65
  # local_add_members will raise ERROR_MEMBER_IN_ALIAS if a
@@ -68,7 +68,8 @@ class Chef
68
68
 
69
69
  members_to_be_removed = [ ]
70
70
  @new_resource.excluded_members.each do |member|
71
- members_to_be_removed << member if @current_resource.members.include?(member)
71
+ member_sid = local_group_name_to_sid(member)
72
+ members_to_be_removed << member if has_current_group_member?(member)
72
73
  end
73
74
  @net_group.local_delete_members(members_to_be_removed) unless members_to_be_removed.empty?
74
75
  else
@@ -76,10 +77,19 @@ class Chef
76
77
  end
77
78
  end
78
79
 
80
+ def has_current_group_member?(member)
81
+ member_sid = local_group_name_to_sid(member)
82
+ @current_resource.members.include?(member_sid)
83
+ end
84
+
79
85
  def remove_group
80
86
  @net_group.local_delete
81
87
  end
82
88
 
89
+ def local_group_name_to_sid(group_name)
90
+ locally_qualified_name = group_name.include?("\\") ? group_name : "#{ENV['COMPUTERNAME']}\\#{group_name}"
91
+ Chef::ReservedNames::Win32::Security.lookup_account_name(locally_qualified_name)[1].to_s
92
+ end
83
93
  end
84
94
  end
85
95
  end
@@ -36,7 +36,8 @@ class Chef
36
36
  # Send a HEAD request to @new_resource.url, with ?message=@new_resource.message
37
37
  def action_head
38
38
  message = check_message(@new_resource.message)
39
- # returns true from Chef::REST if returns 2XX (Net::HTTPSuccess)
39
+ # CHEF-4762: we expect a nil return value from Chef::HTTP for a "200 Success" response
40
+ # and false for a "304 Not Modified" response
40
41
  modified = @http.head(
41
42
  "#{@new_resource.url}?message=#{message}",
42
43
  @new_resource.headers
@@ -44,7 +45,7 @@ class Chef
44
45
  Chef::Log.info("#{@new_resource} HEAD to #{@new_resource.url} successful")
45
46
  Chef::Log.debug("#{@new_resource} HEAD request response: #{modified}")
46
47
  # :head is usually used to trigger notifications, which converge_by now does
47
- if modified
48
+ if modified != false
48
49
  converge_by("#{@new_resource} HEAD to #{@new_resource.url} returned modified, trigger notifications") {}
49
50
  end
50
51
  end
@@ -202,6 +202,7 @@ class Chef
202
202
  if template_available?(@new_resource.response_file)
203
203
  Chef::Log.debug("#{@new_resource} fetching preseed file via Template")
204
204
  remote_file = Chef::Resource::Template.new(cache_seed_to, run_context)
205
+ remote_file.variables(@new_resource.response_file_variables)
205
206
  elsif cookbook_file_available?(@new_resource.response_file)
206
207
  Chef::Log.debug("#{@new_resource} fetching preseed file via cookbook_file")
207
208
  remote_file = Chef::Resource::CookbookFile.new(cache_seed_to, run_context)
@@ -88,7 +88,7 @@ class Chef
88
88
  status = popen4("installp -L -d #{@new_resource.source}") do |pid, stdin, stdout, stderr|
89
89
  stdout.each_line do |line|
90
90
  case line
91
- when /\w:{Regexp.escape(@new_resource.package_name)}:(.*)/
91
+ when /\w:#{Regexp.escape(@new_resource.package_name)}:(.*)/
92
92
  fields = line.split(":")
93
93
  @candidate_version = fields[2]
94
94
  @new_resource.version(fields[2])
@@ -103,7 +103,7 @@ class Chef
103
103
  priority.each { |runlevel, arguments|
104
104
  Chef::Log.debug("#{@new_resource} runlevel #{runlevel}, action #{arguments[0]}, priority #{arguments[1]}")
105
105
  # if we are in a update-rc.d default startup runlevel && we start in this runlevel
106
- if (2..5).include?(runlevel.to_i) && arguments[0] == :start
106
+ if %w[ 1 2 3 4 5 S ].include?(runlevel) && arguments[0] == :start
107
107
  enabled = true
108
108
  end
109
109
  }
@@ -113,7 +113,12 @@ class Chef
113
113
 
114
114
  # Override method from parent to ensure priority is up-to-date
115
115
  def action_enable
116
- if @current_resource.enabled && @current_resource.priority == @new_resource.priority
116
+ if @new_resource.priority.nil?
117
+ priority_ok = true
118
+ else
119
+ priority_ok = @current_resource.priority == @new_resource.priority
120
+ end
121
+ if @current_resource.enabled and priority_ok
117
122
  Chef::Log.debug("#{@new_resource} already enabled - nothing to do")
118
123
  else
119
124
  converge_by("enable service #{@new_resource}") do
@@ -52,9 +52,9 @@ class Chef
52
52
  @force_unlink = false
53
53
  @manage_symlink_source = nil
54
54
  @diff = nil
55
+ @sensitive = false
55
56
  end
56
57
 
57
-
58
58
  def content(arg=nil)
59
59
  set_or_return(
60
60
  :content,
@@ -119,6 +119,13 @@ class Chef
119
119
  )
120
120
  end
121
121
 
122
+ def sensitive(arg=nil)
123
+ set_or_return(
124
+ :sensitive,
125
+ arg,
126
+ :kind_of => [ TrueClass, FalseClass ]
127
+ )
128
+ end
122
129
  end
123
130
  end
124
131
  end
@@ -36,6 +36,7 @@ class Chef
36
36
  @package_name = name
37
37
  @resource_name = :package
38
38
  @response_file = nil
39
+ @response_file_variables = Hash.new
39
40
  @source = nil
40
41
  @version = nil
41
42
  end
@@ -64,6 +65,14 @@ class Chef
64
65
  )
65
66
  end
66
67
 
68
+ def response_file_variables(arg=nil)
69
+ set_or_return(
70
+ :response_file_variables,
71
+ arg,
72
+ :kind_of => [ Hash ]
73
+ )
74
+ end
75
+
67
76
  def source(arg=nil)
68
77
  set_or_return(
69
78
  :source,
@@ -43,7 +43,6 @@ class Chef
43
43
  @init_command = nil
44
44
  @priority = nil
45
45
  @action = "nothing"
46
- @startup_type = :automatic
47
46
  @supports = { :restart => false, :reload => false, :status => false }
48
47
  @allowed_actions.push(:enable, :disable, :start, :stop, :restart, :reload)
49
48
  end
@@ -32,6 +32,7 @@ require 'chef/http/decompressor'
32
32
  require 'chef/http/json_input'
33
33
  require 'chef/http/json_to_model_output'
34
34
  require 'chef/http/cookie_manager'
35
+ require 'chef/http/validate_content_length'
35
36
  require 'chef/config'
36
37
  require 'chef/exceptions'
37
38
  require 'chef/platform/query_helpers'
@@ -62,6 +63,7 @@ class Chef
62
63
  @decompressor = Decompressor.new(options)
63
64
  @authenticator = Authenticator.new(options)
64
65
 
66
+ @middlewares << ValidateContentLength.new(options)
65
67
  @middlewares << JSONInput.new(options)
66
68
  @middlewares << JSONToModelOutput.new(options)
67
69
  @middlewares << CookieManager.new(options)
@@ -146,7 +146,7 @@ class Chef
146
146
  false
147
147
  else
148
148
  loaded_recipe(cookbook_name, recipe_short_name)
149
-
149
+ node.loaded_recipe(cookbook_name, recipe_short_name)
150
150
  cookbook = cookbook_collection[cookbook_name]
151
151
  cookbook.load_recipe(recipe_short_name, self)
152
152
  end
@@ -33,7 +33,7 @@ class Chef
33
33
  @file_edited = false
34
34
 
35
35
  raise ArgumentError, "File doesn't exist" unless File.exist? @original_pathname
36
- @contents = File.new(@original_pathname).readlines
36
+ @contents = File.new(@original_pathname){ |f| f.readlines }
37
37
  end
38
38
 
39
39
  #search the file line by line and match each line with the given regex
@@ -55,19 +55,20 @@ class Chef::Util::Windows::NetGroup < Chef::Util::Windows
55
55
  nread = 0.chr * PTR_SIZE
56
56
  total = 0.chr * PTR_SIZE
57
57
 
58
- rc = NetLocalGroupGetMembers.call(nil, @name, 1, ptr, -1,
58
+ rc = NetLocalGroupGetMembers.call(nil, @name, 0, ptr, -1,
59
59
  nread, total, handle)
60
60
  if (rc == NERR_Success) || (rc == ERROR_MORE_DATA)
61
61
  ptr = ptr.unpack('L')[0]
62
62
  nread = nread.unpack('i')[0]
63
- members = 0.chr * (nread * (PTR_SIZE * 3)) #nread * sizeof(LOCALGROUP_MEMBERS_INFO_1)
63
+ members = 0.chr * (nread * PTR_SIZE ) #nread * sizeof(LOCALGROUP_MEMBERS_INFO_0)
64
64
  memcpy(members, ptr, members.size)
65
65
 
66
- # 3 pointer fields in LOCALGROUP_MEMBERS_INFO_1, offset 2*PTR_SIZE is lgrmi1_name
66
+ # 1 pointer field in LOCALGROUP_MEMBERS_INFO_0, offset 0 is lgrmi0_sid
67
67
  nread.times do |i|
68
- offset = (i * 3) + 2
69
- member = lpwstr_to_s(members, offset)
70
- group_members << member
68
+ sid_address = members[i * PTR_SIZE, PTR_SIZE].unpack('L')[0]
69
+ sid_ptr = FFI::Pointer.new(sid_address)
70
+ member_sid = Chef::ReservedNames::Win32::Security::SID.new(sid_ptr)
71
+ group_members << member_sid.to_s
71
72
  end
72
73
  NetApiBufferFree(ptr)
73
74
  else
@@ -17,7 +17,7 @@
17
17
 
18
18
  class Chef
19
19
  CHEF_ROOT = File.dirname(File.expand_path(File.dirname(__FILE__)))
20
- VERSION = '11.10.0.alpha.1'
20
+ VERSION = '11.10.0.rc.0'
21
21
  end
22
22
 
23
23
  # NOTE: the Chef::Version class is defined in version_class.rb
@@ -35,20 +35,25 @@ class Chef
35
35
  Win32API.new('user32', 'GetSystemMetrics', 'I', 'I').call(n_index)
36
36
  end
37
37
 
38
+ def self.method_name_from_marketing_name(marketing_name)
39
+ "#{marketing_name.gsub(/\s/, '_').gsub(/\./, '_').downcase}?"
40
+ # "#{marketing_name.gsub(/\s/, '_').gsub(//, '_').downcase}?"
41
+ end
42
+
38
43
  public
39
44
 
40
45
  WIN_VERSIONS = {
41
- "Windows 8.1" => {:major => 6, :minor => 3, :callable => lambda{ @product_type == VER_NT_WORKSTATION }},
42
- "Windows Server 2012 R2" => {:major => 6, :minor => 3, :callable => lambda{ @product_type != VER_NT_WORKSTATION }},
43
- "Windows 8" => {:major => 6, :minor => 2, :callable => lambda{ @product_type == VER_NT_WORKSTATION }},
44
- "Windows Server 2012" => {:major => 6, :minor => 2, :callable => lambda{ @product_type != VER_NT_WORKSTATION }},
45
- "Windows 7" => {:major => 6, :minor => 1, :callable => lambda{ @product_type == VER_NT_WORKSTATION }},
46
- "Windows Server 2008 R2" => {:major => 6, :minor => 1, :callable => lambda{ @product_type != VER_NT_WORKSTATION }},
47
- "Windows Server 2008" => {:major => 6, :minor => 0, :callable => lambda{ @product_type != VER_NT_WORKSTATION }},
48
- "Windows Vista" => {:major => 6, :minor => 0, :callable => lambda{ @product_type == VER_NT_WORKSTATION }},
49
- "Windows Server 2003 R2" => {:major => 5, :minor => 2, :callable => lambda{ get_system_metrics(SM_SERVERR2) != 0 }},
50
- "Windows Home Server" => {:major => 5, :minor => 2, :callable => lambda{ (@suite_mask & VER_SUITE_WH_SERVER) == VER_SUITE_WH_SERVER }},
51
- "Windows Server 2003" => {:major => 5, :minor => 2, :callable => lambda{ get_system_metrics(SM_SERVERR2) == 0 }},
46
+ "Windows 8.1" => {:major => 6, :minor => 3, :callable => lambda{ |product_type, suite_mask| product_type == VER_NT_WORKSTATION }},
47
+ "Windows Server 2012 R2" => {:major => 6, :minor => 3, :callable => lambda {|product_type, suite_mask| product_type != VER_NT_WORKSTATION }},
48
+ "Windows 8" => {:major => 6, :minor => 2, :callable => lambda{ |product_type, suite_mask| product_type == VER_NT_WORKSTATION }},
49
+ "Windows Server 2012" => {:major => 6, :minor => 2, :callable => lambda{ |product_type, suite_mask| product_type != VER_NT_WORKSTATION }},
50
+ "Windows 7" => {:major => 6, :minor => 1, :callable => lambda{ |product_type, suite_mask| product_type == VER_NT_WORKSTATION }},
51
+ "Windows Server 2008 R2" => {:major => 6, :minor => 1, :callable => lambda{ |product_type, suite_mask| product_type != VER_NT_WORKSTATION }},
52
+ "Windows Server 2008" => {:major => 6, :minor => 0, :callable => lambda{ |product_type, suite_mask| product_type != VER_NT_WORKSTATION }},
53
+ "Windows Vista" => {:major => 6, :minor => 0, :callable => lambda{ |product_type, suite_mask| product_type == VER_NT_WORKSTATION }},
54
+ "Windows Server 2003 R2" => {:major => 5, :minor => 2, :callable => lambda{ |product_type, suite_mask| get_system_metrics(SM_SERVERR2) != 0 }},
55
+ "Windows Home Server" => {:major => 5, :minor => 2, :callable => lambda{ |product_type, suite_mask| (suite_mask & VER_SUITE_WH_SERVER) == VER_SUITE_WH_SERVER }},
56
+ "Windows Server 2003" => {:major => 5, :minor => 2, :callable => lambda{ |product_type, suite_mask| get_system_metrics(SM_SERVERR2) == 0 }},
52
57
  "Windows XP" => {:major => 5, :minor => 1},
53
58
  "Windows 2000" => {:major => 5, :minor => 0}
54
59
  }
@@ -77,11 +82,11 @@ class Chef
77
82
 
78
83
  # General Windows checks
79
84
  WIN_VERSIONS.each do |k,v|
80
- method_name = "#{k.gsub(/\s/, '_').downcase}?"
85
+ method_name = method_name_from_marketing_name(k)
81
86
  define_method(method_name) do
82
87
  (@major_version == v[:major]) &&
83
88
  (@minor_version == v[:minor]) &&
84
- (v[:callable] ? v[:callable].call : true)
89
+ (v[:callable] ? v[:callable].call(@product_type, @suite_mask) : true)
85
90
  end
86
91
  marketing_names << [k, method_name]
87
92
  end
@@ -105,11 +110,19 @@ class Chef
105
110
  private
106
111
 
107
112
  def get_version
108
- version = GetVersion()
109
- major = LOBYTE(LOWORD(version))
110
- minor = HIBYTE(LOWORD(version))
111
- build = version < 0x80000000 ? HIWORD(version) : 0
112
- [major, minor, build]
113
+ # Use WMI here because API's like GetVersion return faked
114
+ # version numbers on Windows Server 2012 R2 and Windows 8.1 --
115
+ # WMI always returns the truth. See article at
116
+ # http://msdn.microsoft.com/en-us/library/windows/desktop/ms724439(v=vs.85).aspx
117
+ require 'ruby-wmi'
118
+
119
+ os_info = WMI::Win32_OperatingSystem.find(:first)
120
+ os_version = os_info.send('Version')
121
+
122
+ # The operating system version is a string in the following form
123
+ # that can be split into components based on the '.' delimiter:
124
+ # MajorVersionNumber.MinorVersionNumber.BuildNumber
125
+ os_version.split('.').collect { | version_string | version_string.to_i }
113
126
  end
114
127
 
115
128
  def get_version_ex
@@ -0,0 +1 @@
1
+ chef-integration-test chef-integration-test/sample-var string "<%= @template_variable -%>"
@@ -115,5 +115,4 @@ describe Chef::Resource::File do
115
115
  end
116
116
  end
117
117
  end
118
-
119
118
  end
@@ -38,7 +38,8 @@ describe Chef::Resource::Group, :requires_root_or_running_windows, :not_supporte
38
38
  def user_exist_in_group?(user)
39
39
  case ohai[:platform_family]
40
40
  when "windows"
41
- Chef::Util::Windows::NetGroup.new(group_name).local_get_members.include?(user)
41
+ user_sid = sid_string_from_user(user)
42
+ user_sid.nil? ? false : Chef::Util::Windows::NetGroup.new(group_name).local_get_members.include?(user_sid)
42
43
  else
43
44
  Etc::getgrnam(group_name).mem.include?(user)
44
45
  end
@@ -57,6 +58,25 @@ describe Chef::Resource::Group, :requires_root_or_running_windows, :not_supporte
57
58
  return resource.gid == Etc::getgrnam(resource.name).gid if unix?
58
59
  end
59
60
 
61
+ def sid_string_from_user(user)
62
+ begin
63
+ sid = Chef::ReservedNames::Win32::Security.lookup_account_name(user)
64
+ rescue Chef::Exceptions::Win32APIError
65
+ sid = nil
66
+ end
67
+
68
+ sid.nil? ? nil : sid[1].to_s
69
+ end
70
+
71
+ def windows_domain_user?(user_name)
72
+ domain, user = user_name.split('\\')
73
+
74
+ if user && domain != '.'
75
+ computer_name = ENV['computername']
76
+ domain.downcase != computer_name.downcase
77
+ end
78
+ end
79
+
60
80
  def user(username)
61
81
  usr = Chef::Resource::User.new("#{username}", run_context)
62
82
  if ohai[:platform_family] == "windows"
@@ -66,12 +86,12 @@ describe Chef::Resource::Group, :requires_root_or_running_windows, :not_supporte
66
86
  end
67
87
 
68
88
  def create_user(username)
69
- user(username).run_action(:create)
89
+ user(username).run_action(:create) if ! windows_domain_user?(username)
70
90
  # TODO: User shouldn't exist
71
91
  end
72
92
 
73
93
  def remove_user(username)
74
- user(username).run_action(:remove)
94
+ user(username).run_action(:remove) if ! windows_domain_user?(username)
75
95
  # TODO: User shouldn't exist
76
96
  end
77
97
 
@@ -108,24 +128,24 @@ describe Chef::Resource::Group, :requires_root_or_running_windows, :not_supporte
108
128
  end
109
129
 
110
130
  describe "when append is not set" do
111
- let(:included_members) { ["spec-Eric"] }
131
+ let(:included_members) { [spec_members[1]] }
112
132
 
113
133
  before do
114
- create_user("spec-Eric")
115
- create_user("spec-Gordon")
116
- add_members_to_group(["spec-Gordon"])
134
+ create_user(spec_members[1])
135
+ create_user(spec_members[0])
136
+ add_members_to_group([spec_members[0]])
117
137
  end
118
138
 
119
139
  after do
120
- remove_user("spec-Eric")
121
- remove_user("spec-Gordon")
140
+ remove_user(spec_members[1])
141
+ remove_user(spec_members[0])
122
142
  end
123
143
 
124
144
  it "should remove the existing users and add the new users to the group" do
125
145
  group_resource.run_action(tested_action)
126
146
 
127
- user_exist_in_group?("spec-Eric").should == true
128
- user_exist_in_group?("spec-Gordon").should == false
147
+ user_exist_in_group?(spec_members[1]).should == true
148
+ user_exist_in_group?(spec_members[0]).should == false
129
149
  end
130
150
  end
131
151
 
@@ -160,7 +180,7 @@ describe Chef::Resource::Group, :requires_root_or_running_windows, :not_supporte
160
180
 
161
181
  describe "when group contains some users" do
162
182
  before(:each) do
163
- add_members_to_group([ "spec-Gordon", "spec-Anthony" ])
183
+ add_members_to_group([ spec_members[0], spec_members[2] ])
164
184
  end
165
185
 
166
186
  it "should add the included users and remove excluded users" do
@@ -192,6 +212,42 @@ describe Chef::Resource::Group, :requires_root_or_running_windows, :not_supporte
192
212
  end
193
213
  end
194
214
 
215
+ shared_examples_for "an expected invalid domain error case" do
216
+ let(:invalid_domain_user_name) { "no space\\administrator" }
217
+ let(:nonexistent_domain_user_name) { "xxfakedom\\administrator" }
218
+ before(:each) do
219
+ group_resource.members []
220
+ group_resource.excluded_members []
221
+ group_resource.append(true)
222
+ group_resource.run_action(:create)
223
+ group_should_exist(group_name)
224
+ end
225
+
226
+ describe "when updating membership" do
227
+ it "raises an error for a non well-formed domain name" do
228
+ group_resource.members [invalid_domain_user_name]
229
+ lambda { group_resource.run_action(tested_action) }.should raise_error Chef::Exceptions::Win32APIError
230
+ end
231
+
232
+ it "raises an error for a nonexistent domain" do
233
+ group_resource.members [nonexistent_domain_user_name]
234
+ lambda { group_resource.run_action(tested_action) }.should raise_error Chef::Exceptions::Win32APIError
235
+ end
236
+ end
237
+
238
+ describe "when removing members" do
239
+ it "raises an error for a non well-formed domain name" do
240
+ group_resource.excluded_members [invalid_domain_user_name]
241
+ lambda { group_resource.run_action(tested_action) }.should raise_error Chef::Exceptions::Win32APIError
242
+ end
243
+
244
+ it "raises an error for a nonexistent domain" do
245
+ group_resource.excluded_members [nonexistent_domain_user_name]
246
+ lambda { group_resource.run_action(tested_action) }.should raise_error Chef::Exceptions::Win32APIError
247
+ end
248
+ end
249
+ end
250
+
195
251
  let(:group_name) { "cheftest-#{SecureRandom.random_number(9999)}" }
196
252
  let(:included_members) { nil }
197
253
  let(:excluded_members) { nil }
@@ -274,8 +330,9 @@ downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQ" }
274
330
  end
275
331
 
276
332
  describe "group modify action", :not_supported_on_solaris do
277
- let(:included_members) { ["spec-Gordon", "spec-Eric"] }
278
- let(:excluded_members) { ["spec-Anthony"] }
333
+ let(:spec_members){ ["spec-Gordon", "spec-Eric", "spec-Anthony"] }
334
+ let(:included_members) { [spec_members[0], spec_members[1]] }
335
+ let(:excluded_members) { [spec_members[2]] }
279
336
  let(:tested_action) { :modify }
280
337
 
281
338
  describe "when there is no group" do
@@ -287,11 +344,23 @@ downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQ" }
287
344
  describe "when there is a group" do
288
345
  it_behaves_like "correct group management"
289
346
  end
347
+
348
+ describe "when running on Windows", :windows_only do
349
+ describe "when members are Active Directory domain identities", :windows_domain_joined_only do
350
+ let(:computer_domain) { ohai[:kernel]['cs_info']['domain'].split('.')[0] }
351
+ let(:spec_members){ ["#{computer_domain}\\Domain Admins", "#{computer_domain}\\Domain Users", "#{computer_domain}\\Domain Computers"] }
352
+
353
+ include_examples "correct group management"
354
+ end
355
+
356
+ it_behaves_like "an expected invalid domain error case"
357
+ end
290
358
  end
291
359
 
292
360
  describe "group manage action", :not_supported_on_solaris do
293
- let(:included_members) { ["spec-Gordon", "spec-Eric"] }
294
- let(:excluded_members) { ["spec-Anthony"] }
361
+ let(:spec_members){ ["spec-Gordon", "spec-Eric", "spec-Anthony"] }
362
+ let(:included_members) { [spec_members[0], spec_members[1]] }
363
+ let(:excluded_members) { [spec_members[2]] }
295
364
  let(:tested_action) { :manage }
296
365
 
297
366
  describe "when there is no group" do
@@ -304,6 +373,17 @@ downthestreetalwayshadagoodsmileonhisfacetheoldmanwalkingdownthestreeQQQQQQ" }
304
373
  describe "when there is a group" do
305
374
  it_behaves_like "correct group management"
306
375
  end
376
+
377
+ describe "running on windows", :windows_only do
378
+ describe "when members are Windows domain identities", :windows_domain_joined_only do
379
+ let(:computer_domain) { ohai[:kernel]['cs_info']['domain'].split('.')[0] }
380
+ let(:spec_members){ ["#{computer_domain}\\Domain Admins", "#{computer_domain}\\Domain Users", "#{computer_domain}\\Domain Computers"] }
381
+
382
+ include_examples "correct group management"
383
+ end
384
+
385
+ it_behaves_like "an expected invalid domain error case"
386
+ end
307
387
  end
308
388
 
309
389
  describe "group resource with Usermod provider", :solaris_only do