puppet 5.5.6 → 5.5.7

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puppet might be problematic. Click here for more details.

Files changed (152) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -1
  3. data/Gemfile.lock +12 -12
  4. data/Rakefile +9 -0
  5. data/lib/puppet/application.rb +5 -0
  6. data/lib/puppet/application/apply.rb +1 -0
  7. data/lib/puppet/application/master.rb +9 -7
  8. data/lib/puppet/application/script.rb +1 -1
  9. data/lib/puppet/defaults.rb +51 -31
  10. data/lib/puppet/etc.rb +20 -0
  11. data/lib/puppet/file_serving/fileset.rb +1 -1
  12. data/lib/puppet/functions.rb +123 -0
  13. data/lib/puppet/functions/new.rb +37 -53
  14. data/lib/puppet/functions/warning.rb +1 -1
  15. data/lib/puppet/loaders.rb +1 -0
  16. data/lib/puppet/parser/functions.rb +3 -1
  17. data/lib/puppet/parser/functions/sprintf.rb +12 -1
  18. data/lib/puppet/pops/evaluator/runtime3_converter.rb +16 -0
  19. data/lib/puppet/pops/evaluator/runtime3_support.rb +3 -4
  20. data/lib/puppet/pops/issues.rb +8 -0
  21. data/lib/puppet/pops/loader/loader.rb +2 -2
  22. data/lib/puppet/pops/loader/loader_paths.rb +3 -1
  23. data/lib/puppet/pops/loader/module_loaders.rb +1 -1
  24. data/lib/puppet/pops/loader/ruby_legacy_function_instantiator.rb +62 -0
  25. data/lib/puppet/pops/loaders.rb +5 -21
  26. data/lib/puppet/pops/parser/heredoc_support.rb +1 -2
  27. data/lib/puppet/pops/parser/lexer2.rb +1 -1
  28. data/lib/puppet/pops/validation/checker4_0.rb +31 -6
  29. data/lib/puppet/pops/validation/validator_factory_4_0.rb +1 -0
  30. data/lib/puppet/property/keyvalue.rb +70 -8
  31. data/lib/puppet/provider/aix_object.rb +483 -0
  32. data/lib/puppet/provider/exec.rb +54 -57
  33. data/lib/puppet/provider/group/aix.rb +40 -115
  34. data/lib/puppet/provider/group/pw.rb +4 -8
  35. data/lib/puppet/provider/group/windows_adsi.rb +7 -4
  36. data/lib/puppet/provider/nameservice.rb +1 -25
  37. data/lib/puppet/provider/nameservice/directoryservice.rb +5 -3
  38. data/lib/puppet/provider/package/portage.rb +2 -2
  39. data/lib/puppet/provider/package/windows.rb +2 -2
  40. data/lib/puppet/provider/package/windows/exe_package.rb +3 -10
  41. data/lib/puppet/provider/package/zypper.rb +1 -1
  42. data/lib/puppet/provider/service/launchd.rb +19 -3
  43. data/lib/puppet/provider/service/windows.rb +49 -40
  44. data/lib/puppet/provider/user/aix.rb +180 -246
  45. data/lib/puppet/provider/user/windows_adsi.rb +9 -1
  46. data/lib/puppet/resource/catalog.rb +1 -5
  47. data/lib/puppet/type/augeas.rb +1 -1
  48. data/lib/puppet/type/exec.rb +16 -14
  49. data/lib/puppet/type/file.rb +2 -2
  50. data/lib/puppet/type/file/source.rb +9 -5
  51. data/lib/puppet/type/group.rb +65 -23
  52. data/lib/puppet/type/k5login.rb +2 -2
  53. data/lib/puppet/type/notify.rb +1 -1
  54. data/lib/puppet/type/package.rb +3 -6
  55. data/lib/puppet/type/resources.rb +12 -2
  56. data/lib/puppet/type/schedule.rb +8 -1
  57. data/lib/puppet/type/selboolean.rb +2 -2
  58. data/lib/puppet/type/selmodule.rb +3 -4
  59. data/lib/puppet/type/service.rb +2 -5
  60. data/lib/puppet/type/tidy.rb +1 -1
  61. data/lib/puppet/type/user.rb +15 -20
  62. data/lib/puppet/type/yumrepo.rb +2 -2
  63. data/lib/puppet/type/zone.rb +2 -2
  64. data/lib/puppet/util.rb +7 -3
  65. data/lib/puppet/util/execution.rb +15 -1
  66. data/lib/puppet/util/posix.rb +15 -0
  67. data/lib/puppet/util/storage.rb +12 -0
  68. data/lib/puppet/util/windows.rb +4 -2
  69. data/lib/puppet/util/windows/adsi.rb +235 -205
  70. data/lib/puppet/util/windows/process.rb +23 -3
  71. data/lib/puppet/util/windows/security.rb +14 -0
  72. data/lib/puppet/util/windows/service.rb +977 -0
  73. data/lib/puppet/util/windows/user.rb +3 -5
  74. data/lib/puppet/version.rb +1 -1
  75. data/locales/ja/puppet.po +705 -374
  76. data/locales/puppet.pot +485 -261
  77. data/man/man5/puppet.conf.5 +36 -15
  78. data/man/man8/puppet-agent.8 +1 -1
  79. data/man/man8/puppet-apply.8 +1 -1
  80. data/man/man8/puppet-ca.8 +1 -1
  81. data/man/man8/puppet-catalog.8 +1 -1
  82. data/man/man8/puppet-cert.8 +1 -1
  83. data/man/man8/puppet-certificate.8 +1 -1
  84. data/man/man8/puppet-certificate_request.8 +1 -1
  85. data/man/man8/puppet-certificate_revocation_list.8 +1 -1
  86. data/man/man8/puppet-config.8 +1 -1
  87. data/man/man8/puppet-describe.8 +1 -1
  88. data/man/man8/puppet-device.8 +1 -1
  89. data/man/man8/puppet-doc.8 +1 -1
  90. data/man/man8/puppet-epp.8 +1 -1
  91. data/man/man8/puppet-facts.8 +1 -1
  92. data/man/man8/puppet-filebucket.8 +1 -1
  93. data/man/man8/puppet-generate.8 +1 -1
  94. data/man/man8/puppet-help.8 +1 -1
  95. data/man/man8/puppet-key.8 +1 -1
  96. data/man/man8/puppet-lookup.8 +1 -1
  97. data/man/man8/puppet-man.8 +1 -1
  98. data/man/man8/puppet-master.8 +1 -1
  99. data/man/man8/puppet-module.8 +1 -1
  100. data/man/man8/puppet-node.8 +1 -1
  101. data/man/man8/puppet-parser.8 +1 -1
  102. data/man/man8/puppet-plugin.8 +1 -1
  103. data/man/man8/puppet-report.8 +1 -1
  104. data/man/man8/puppet-resource.8 +1 -1
  105. data/man/man8/puppet-script.8 +1 -1
  106. data/man/man8/puppet-status.8 +1 -1
  107. data/man/man8/puppet.8 +2 -2
  108. data/spec/fixtures/unit/provider/aix_object/aix_colon_list_real_world_input.out +1 -0
  109. data/spec/fixtures/unit/provider/aix_object/aix_colon_list_real_world_output.out +1 -0
  110. data/spec/fixtures/unit/provider/user/aix/aix_passwd_file.out +32 -0
  111. data/spec/integration/parser/collection_spec.rb +4 -8
  112. data/spec/integration/provider/service/windows_spec.rb +5 -5
  113. data/spec/integration/type/file_spec.rb +6 -6
  114. data/spec/integration/util/windows/adsi_spec.rb +6 -5
  115. data/spec/integration/util/windows/security_spec.rb +10 -7
  116. data/spec/integration/util/windows/user_spec.rb +37 -17
  117. data/spec/spec_helper.rb +0 -1
  118. data/spec/unit/application/apply_spec.rb +41 -2
  119. data/spec/unit/application/master_spec.rb +7 -0
  120. data/spec/unit/application_spec.rb +21 -3
  121. data/spec/unit/defaults_spec.rb +20 -0
  122. data/spec/unit/etc_spec.rb +25 -0
  123. data/spec/unit/file_serving/fileset_spec.rb +11 -11
  124. data/spec/unit/gettext/config_spec.rb +1 -1
  125. data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +6 -6
  126. data/spec/unit/pops/loaders/loaders_spec.rb +40 -7
  127. data/spec/unit/pops/parser/parse_heredoc_spec.rb +16 -0
  128. data/spec/unit/pops/validator/validator_spec.rb +129 -10
  129. data/spec/unit/property/keyvalue_spec.rb +97 -6
  130. data/spec/unit/provider/aix_object_spec.rb +805 -0
  131. data/spec/unit/provider/group/aix_spec.rb +57 -0
  132. data/spec/unit/provider/group/pw_spec.rb +0 -6
  133. data/spec/unit/provider/group/windows_adsi_spec.rb +34 -35
  134. data/spec/unit/provider/nameservice/directoryservice_spec.rb +2 -2
  135. data/spec/unit/provider/package/windows/exe_package_spec.rb +3 -3
  136. data/spec/unit/provider/package/windows_spec.rb +4 -4
  137. data/spec/unit/provider/service/launchd_spec.rb +19 -0
  138. data/spec/unit/provider/service/windows_spec.rb +71 -78
  139. data/spec/unit/provider/user/aix_spec.rb +162 -116
  140. data/spec/unit/provider/user/windows_adsi_spec.rb +4 -4
  141. data/spec/unit/resource/catalog_spec.rb +2 -2
  142. data/spec/unit/ssl/certificate_authority_spec.rb +0 -1
  143. data/spec/unit/type/group_spec.rb +111 -13
  144. data/spec/unit/type/resources_spec.rb +18 -0
  145. data/spec/unit/util/execution_spec.rb +77 -0
  146. data/spec/unit/util/posix_spec.rb +28 -0
  147. data/spec/unit/util/storage_spec.rb +107 -0
  148. data/spec/unit/util/windows/adsi_spec.rb +108 -13
  149. data/spec/unit/util/windows/service_spec.rb +669 -0
  150. metadata +17 -5
  151. data/lib/puppet/provider/aixobject.rb +0 -392
  152. data/spec/unit/provider/aixobject_spec.rb +0 -101
@@ -3,9 +3,9 @@ require 'spec_helper'
3
3
 
4
4
  require 'puppet/property/keyvalue'
5
5
 
6
- klass = Puppet::Property::KeyValue
7
6
 
8
- describe klass do
7
+ describe 'Puppet::Property::KeyValue' do
8
+ let(:klass) { Puppet::Property::KeyValue }
9
9
 
10
10
  it "should be a subclass of Property" do
11
11
  expect(klass.superclass).to eq(Puppet::Property)
@@ -17,6 +17,7 @@ describe klass do
17
17
  klass.initvars
18
18
  @resource = stub 'resource', :[]= => nil, :property => nil
19
19
  @property = klass.new(:resource => @resource)
20
+ klass.log_only_changed_or_new_keys = false
20
21
  end
21
22
 
22
23
  it "should have a , as default delimiter" do
@@ -42,6 +43,26 @@ describe klass do
42
43
  expect(["foo=baz;bar=boo", "bar=boo;foo=baz"]).to be_include s
43
44
  end
44
45
 
46
+ describe "when calling hash_to_key_value_s" do
47
+ let(:input) do
48
+ {
49
+ :key1 => "value1",
50
+ :key2 => "value2",
51
+ :key3 => "value3"
52
+ }
53
+ end
54
+
55
+ before(:each) do
56
+ @property.instance_variable_set(:@changed_or_new_keys, [:key1, :key2])
57
+ end
58
+
59
+ it "returns only the changed or new keys if log_only_changed_or_new_keys is set" do
60
+ klass.log_only_changed_or_new_keys = true
61
+
62
+ expect(@property.hash_to_key_value_s(input)).to eql("key1=value1;key2=value2")
63
+ end
64
+ end
65
+
45
66
  describe "when calling inclusive?" do
46
67
  it "should use the membership method to look up on the @resource" do
47
68
  @property.expects(:membership).returns(:key_value_membership)
@@ -103,6 +124,26 @@ describe klass do
103
124
  @property.expects(:inclusive?).returns(false)
104
125
  expect(@property.should).to eq({ :foo => "baz", :bar => "boo", :do => "re", :mi => "fa" })
105
126
  end
127
+
128
+ it "should mark the keys that will change or be added as a result of our Puppet run" do
129
+ @property.should = {
130
+ :key1 => "new_value1",
131
+ :key2 => "value2",
132
+ :key3 => "new_value3",
133
+ :key4 => "value4"
134
+ }
135
+ @property.stubs(:retrieve).returns(
136
+ {
137
+ :key1 => "value1",
138
+ :key2 => "value2",
139
+ :key3 => "value3"
140
+ }
141
+ )
142
+ @property.stubs(:inclusive?).returns(false)
143
+
144
+ @property.should
145
+ expect(@property.instance_variable_get(:@changed_or_new_keys)).to eql([:key1, :key3, :key4])
146
+ end
106
147
  end
107
148
 
108
149
  describe "when calling retrieve" do
@@ -130,9 +171,15 @@ describe klass do
130
171
  end
131
172
  end
132
173
 
133
- describe "when calling hashify" do
134
- it "should return the array hashified" do
135
- expect(@property.hashify(["foo=baz", "bar=boo"])).to eq({ :foo => "baz", :bar => "boo" })
174
+ describe "when calling hashify_should" do
175
+ it "should return the underlying hash if the user passed in a hash" do
176
+ @property.should = { "foo" => "bar" }
177
+ expect(@property.hashify_should).to eql({ :foo => "bar" })
178
+ end
179
+
180
+ it "should hashify the array of key/value pairs if that is what our user passed in" do
181
+ @property.should = [ "foo=baz", "bar=boo" ]
182
+ expect(@property.hashify_should).to eq({ :foo => "baz", :bar => "boo" })
136
183
  end
137
184
  end
138
185
 
@@ -148,7 +195,6 @@ describe klass do
148
195
  end
149
196
 
150
197
  it "should return true if the passed in values is nil" do
151
- @property.should = "foo"
152
198
  @property.safe_insync?(nil) == true
153
199
  end
154
200
 
@@ -166,5 +212,50 @@ describe klass do
166
212
  expect(@property.safe_insync?({ "foo" => "bee", "bar" => "boo" })).to eq(false)
167
213
  end
168
214
  end
215
+
216
+ describe 'when validating a passed-in property value' do
217
+ it 'should raise a Puppet::Error if the property value is anything but a Hash or a String' do
218
+ expect { @property.validate(5) }.to raise_error do |error|
219
+ expect(error).to be_a(Puppet::Error)
220
+ expect(error.message).to match("specified as a hash or an array")
221
+ end
222
+ end
223
+
224
+ it 'should accept a Hash property value' do
225
+ @property.validate({ 'foo' => 'bar' })
226
+ end
227
+
228
+ it "should raise a Puppet::Error if the property value isn't a key/value pair" do
229
+ expect { @property.validate('foo') }.to raise_error do |error|
230
+ expect(error).to be_a(Puppet::Error)
231
+ expect(error.message).to match("separated by '='")
232
+ end
233
+ end
234
+
235
+ it 'should accept a valid key/value pair property value' do
236
+ @property.validate('foo=bar')
237
+ end
238
+ end
239
+
240
+ describe 'when munging a passed-in property value' do
241
+ it 'should return the value as-is if it is a string' do
242
+ expect(@property.munge('foo=bar')).to eql('foo=bar')
243
+ end
244
+
245
+ it 'should stringify + symbolize the keys and stringify the values if it is a hash' do
246
+ input = {
247
+ 1 => 2,
248
+ true => false,
249
+ ' foo ' => 'bar'
250
+ }
251
+ expected_output = {
252
+ :'1' => '2',
253
+ :true => 'false',
254
+ :foo => 'bar'
255
+ }
256
+
257
+ expect(@property.munge(input)).to eql(expected_output)
258
+ end
259
+ end
169
260
  end
170
261
  end
@@ -0,0 +1,805 @@
1
+ require 'spec_helper'
2
+ require 'puppet/provider/aix_object'
3
+
4
+ describe 'Puppet::Provider::AixObject' do
5
+ let(:resource) do
6
+ Puppet::Type.type(:user).new(
7
+ :name => 'test_aix_user',
8
+ :ensure => :present
9
+ )
10
+ end
11
+ let(:klass) { Puppet::Provider::AixObject }
12
+ let(:provider) do
13
+ Puppet::Provider::AixObject.new(resource)
14
+ end
15
+
16
+ # Clear out the class-level + instance-level mappings
17
+ def clear_attributes
18
+ klass.instance_variable_set(:@mappings, nil)
19
+ end
20
+
21
+ before(:each) do
22
+ clear_attributes
23
+ end
24
+
25
+ describe '.mapping' do
26
+ let(:puppet_property) { :uid }
27
+ let(:aix_attribute) { :id }
28
+ let(:info) do
29
+ {
30
+ :puppet_property => puppet_property,
31
+ :aix_attribute => aix_attribute
32
+ }
33
+ end
34
+
35
+ shared_examples 'a mapping' do |from, to|
36
+ context "<#{from}> => <#{to}>" do
37
+ let(:from_suffix) { from.to_s.split("_")[-1] }
38
+ let(:to_suffix) { to.to_s.split("_")[-1] }
39
+ let(:conversion_fn) do
40
+ "convert_#{from_suffix}_value".to_sym
41
+ end
42
+
43
+ it 'creates the mapping for a pure conversion function and defines it' do
44
+ conversion_fn_lambda = "#{from_suffix}_to_#{to_suffix}".to_sym
45
+ info[conversion_fn_lambda] = lambda { |x| x.to_s }
46
+ provider.class.mapping(info)
47
+
48
+ mappings = provider.class.mappings[to]
49
+ expect(mappings).to include(info[from])
50
+
51
+ mapping = mappings[info[from]]
52
+ expect(mapping.public_methods).to include(conversion_fn)
53
+
54
+ expect(mapping.send(conversion_fn, 3)).to eql('3')
55
+ end
56
+
57
+ it 'creates the mapping for an impure conversion function without defining it' do
58
+ conversion_fn_lambda = "#{from_suffix}_to_#{to_suffix}".to_sym
59
+ info[conversion_fn_lambda] = lambda { |provider, x| x.to_s }
60
+ provider.class.mapping(info)
61
+
62
+ mappings = provider.class.mappings[to]
63
+ expect(mappings).to include(info[from])
64
+
65
+ mapping = mappings[info[from]]
66
+ expect(mapping.public_methods).not_to include(conversion_fn)
67
+ end
68
+
69
+ it 'uses the identity function as the conversion function if none is provided' do
70
+ provider.class.mapping(info)
71
+
72
+
73
+ mappings = provider.class.mappings[to]
74
+ expect(mappings).to include(info[from])
75
+
76
+ mapping = mappings[info[from]]
77
+ expect(mapping.public_methods).to include(conversion_fn)
78
+
79
+ expect(mapping.send(conversion_fn, 3)).to eql(3)
80
+ end
81
+ end
82
+ end
83
+
84
+ include_examples 'a mapping',
85
+ :puppet_property,
86
+ :aix_attribute
87
+
88
+ include_examples 'a mapping',
89
+ :aix_attribute,
90
+ :puppet_property
91
+
92
+ it 'sets the AIX attribute to the Puppet property if it is not provided' do
93
+ info[:aix_attribute] = nil
94
+ provider.class.mapping(info)
95
+
96
+ mappings = provider.class.mappings[:puppet_property]
97
+ expect(mappings).to include(info[:puppet_property])
98
+ end
99
+ end
100
+
101
+ describe '.numeric_mapping' do
102
+ let(:info) do
103
+ info_hash = {
104
+ :puppet_property => :uid,
105
+ :aix_attribute => :id
106
+ }
107
+ provider.class.numeric_mapping(info_hash)
108
+
109
+ info_hash
110
+ end
111
+ let(:aix_attribute) do
112
+ provider.class.mappings[:aix_attribute][info[:puppet_property]]
113
+ end
114
+ let(:puppet_property) do
115
+ provider.class.mappings[:puppet_property][info[:aix_attribute]]
116
+ end
117
+
118
+ it 'raises an ArgumentError for a non-numeric Puppet property value' do
119
+ value = 'foo'
120
+ expect do
121
+ aix_attribute.convert_property_value(value)
122
+ end.to raise_error do |error|
123
+ expect(error).to be_a(ArgumentError)
124
+
125
+ expect(error.message).to match(value)
126
+ expect(error.message).to match(info[:puppet_property].to_s)
127
+ end
128
+ end
129
+
130
+ it 'converts the numeric Puppet property to a numeric AIX attribute' do
131
+ expect(aix_attribute.convert_property_value(10)).to eql('10')
132
+ end
133
+
134
+ it 'converts the numeric AIX attribute to a numeric Puppet property' do
135
+ expect(puppet_property.convert_attribute_value('10')).to eql(10)
136
+ end
137
+ end
138
+
139
+ describe '.mk_resource_methods' do
140
+ before(:each) do
141
+ # Add some Puppet properties
142
+ provider.class.mapping(
143
+ puppet_property: :foo,
144
+ aix_attribute: :foo
145
+ )
146
+ provider.class.mapping(
147
+ puppet_property: :bar,
148
+ aix_attribute: :bar
149
+ )
150
+
151
+ provider.class.mk_resource_methods
152
+ end
153
+
154
+ it 'defines the property getters' do
155
+ provider = Puppet::Provider::AixObject.new(resource)
156
+ provider.instance_variable_set(:@object_info, { :foo => 'foo', :baz => 'baz' })
157
+
158
+ (provider.class.mappings[:aix_attribute].keys + [:attributes]).each do |property|
159
+ provider.expects(:get).with(property).returns('value')
160
+
161
+ expect(provider.send(property)).to eql('value')
162
+ end
163
+ end
164
+
165
+ it 'defines the property setters' do
166
+ provider = Puppet::Provider::AixObject.new(resource)
167
+
168
+ value = '15'
169
+ provider.class.mappings[:aix_attribute].keys.each do |property|
170
+ provider.expects(:set).with(property, value)
171
+
172
+ provider.send("#{property}=".to_sym, value)
173
+ end
174
+ end
175
+ end
176
+
177
+ describe '.parse_colon_separated_list' do
178
+ it 'parses a single empty item' do
179
+ input = ''
180
+ output = ['']
181
+
182
+ expect(provider.class.parse_colon_separated_list(input)).to eql(output)
183
+ end
184
+
185
+ it 'parses a single nonempty item' do
186
+ input = 'item'
187
+ output = ['item']
188
+
189
+ expect(provider.class.parse_colon_separated_list(input)).to eql(output)
190
+ end
191
+
192
+ it "parses an escaped ':'" do
193
+ input = '#!:'
194
+ output = [':']
195
+
196
+ expect(provider.class.parse_colon_separated_list(input)).to eql(output)
197
+ end
198
+
199
+ it "parses a single item with an escaped ':'" do
200
+ input = 'fd8c#!:215d#!:178#!:'
201
+ output = ['fd8c:215d:178:']
202
+
203
+ expect(provider.class.parse_colon_separated_list(input)).to eql(output)
204
+ end
205
+
206
+ it "parses multiple items that do not have an escaped ':'" do
207
+ input = "foo:bar baz:buu:1234"
208
+ output = ["foo", "bar baz", "buu", "1234"]
209
+
210
+ expect(provider.class.parse_colon_separated_list(input)).to eql(output)
211
+ end
212
+
213
+ it "parses multiple items some of which have escaped ':'" do
214
+ input = "1234#!:567:foo bar#!:baz:buu#!bob:sally:fd8c#!:215d#!:178"
215
+ output = ["1234:567", "foo bar:baz", "buu#!bob", "sally", 'fd8c:215d:178']
216
+
217
+ expect(provider.class.parse_colon_separated_list(input)).to eql(output)
218
+ end
219
+
220
+ it "parses a list with several empty items" do
221
+ input = "foo:::bar:baz:boo:"
222
+ output = ["foo", "", "", "bar", "baz", "boo", ""]
223
+
224
+ expect(provider.class.parse_colon_separated_list(input)).to eql(output)
225
+ end
226
+
227
+ it "parses a list with an escaped ':' and empty item at the end" do
228
+ input = "foo:bar#!::"
229
+ output = ["foo", "bar:", ""]
230
+
231
+ expect(provider.class.parse_colon_separated_list(input)).to eql(output)
232
+ end
233
+
234
+ it 'parses a real world example' do
235
+ input = File.read(my_fixture('aix_colon_list_real_world_input.out')).chomp
236
+ output = Object.instance_eval(File.read(my_fixture('aix_colon_list_real_world_output.out')))
237
+
238
+ expect(provider.class.parse_colon_separated_list(input)).to eql(output)
239
+ end
240
+ end
241
+
242
+ describe '.parse_aix_objects' do
243
+ # parse_colon_separated_list is well tested, so we don't need to be
244
+ # as strict on the formatting of the output here. Main point of these
245
+ # tests is to capture the 'wholemeal' parsing that's going on, i.e.
246
+ # that we can parse a bunch of objects together.
247
+ let(:output) do
248
+ <<-AIX_OBJECTS
249
+ #name:id:pgrp:groups
250
+ root:0:system:system,bin,sys,security,cron,audit,lp
251
+ #name:id:pgrp:groups:home:gecos
252
+ user:10000:staff:staff:/home/user3:Some User
253
+ AIX_OBJECTS
254
+ end
255
+
256
+ let(:expected_aix_attributes) do
257
+ [
258
+ {
259
+ :name => 'root',
260
+ :attributes => {
261
+ :id => '0',
262
+ :pgrp => 'system',
263
+ :groups => 'system,bin,sys,security,cron,audit,lp',
264
+ }
265
+ },
266
+ {
267
+ :name => 'user',
268
+ :attributes => {
269
+ :id => '10000',
270
+ :pgrp => 'staff',
271
+ :groups => 'staff',
272
+ :home => '/home/user3',
273
+ :gecos => 'Some User'
274
+ }
275
+ }
276
+ ]
277
+ end
278
+
279
+ it 'parses the AIX attributes from the command output' do
280
+ expect(provider.class.parse_aix_objects(output)).to eql(expected_aix_attributes)
281
+ end
282
+ end
283
+
284
+ describe 'list_all' do
285
+ let(:output) do
286
+ <<-OUTPUT
287
+ #name:id
288
+ system:0
289
+ #name:id
290
+ staff:1
291
+ #name:id
292
+ bin:2
293
+ OUTPUT
294
+ end
295
+
296
+ it 'lists all of the objects' do
297
+ lscmd = 'lsgroups'
298
+ provider.class.stubs(:command).with(:list).returns(lscmd)
299
+ provider.class.stubs(:execute).with([lscmd, '-c', '-a', 'id', 'ALL']).returns(output)
300
+
301
+ expected_objects = [
302
+ { :name => 'system', :id => '0' },
303
+ { :name => 'staff', :id => '1' },
304
+ { :name => 'bin', :id => '2' }
305
+ ]
306
+ expect(provider.class.list_all).to eql(expected_objects)
307
+ end
308
+ end
309
+
310
+ describe '.instances' do
311
+ let(:objects) do
312
+ [
313
+ { :name => 'group1', :id => '1' },
314
+ { :name => 'group2', :id => '2' }
315
+ ]
316
+ end
317
+
318
+ it 'returns all of the available instances' do
319
+ provider.class.stubs(:list_all).returns(objects)
320
+
321
+ expect(provider.class.instances.map(&:name)).to eql(['group1', 'group2'])
322
+ end
323
+ end
324
+
325
+ describe '#mappings' do
326
+ # Returns a pair [ instance_level_mapped_object, class_level_mapped_object ]
327
+ def mapped_objects(type, input)
328
+ [
329
+ provider.mappings[type][input],
330
+ provider.class.mappings[type][input]
331
+ ]
332
+ end
333
+
334
+ before(:each) do
335
+ # Create a pure mapping
336
+ provider.class.numeric_mapping(
337
+ puppet_property: :pure_puppet_property,
338
+ aix_attribute: :pure_aix_attribute
339
+ )
340
+
341
+ # Create an impure mapping
342
+ impure_conversion_fn = lambda do |provider, value|
343
+ "Provider instance's name is #{provider.name}"
344
+ end
345
+ provider.class.mapping(
346
+ puppet_property: :impure_puppet_property,
347
+ aix_attribute: :impure_aix_attribute,
348
+ property_to_attribute: impure_conversion_fn,
349
+ attribute_to_property: impure_conversion_fn
350
+ )
351
+ end
352
+
353
+ it 'memoizes the result' do
354
+ provider.instance_variable_set(:@mappings, 'memoized')
355
+ expect(provider.mappings).to eql('memoized')
356
+ end
357
+
358
+ it 'creates the instance-level mappings with the same structure as the class-level one' do
359
+ expect(provider.mappings.keys).to eql(provider.class.mappings.keys)
360
+ provider.mappings.keys.each do |type|
361
+ expect(provider.mappings[type].keys).to eql(provider.class.mappings[type].keys)
362
+ end
363
+ end
364
+
365
+ shared_examples 'uses the right mapped object for a given mapping' do |from_type, to_type|
366
+ context "<#{from_type}> => <#{to_type}>" do
367
+ it 'shares the class-level mapped object for pure mappings' do
368
+ input = "pure_#{from_type}".to_sym
369
+
370
+ instance_level_mapped_object, class_level_mapped_object = mapped_objects(to_type, input)
371
+ expect(instance_level_mapped_object.object_id).to eql(class_level_mapped_object.object_id)
372
+ end
373
+
374
+ it 'dups the class-level mapped object for impure mappings' do
375
+ input = "impure_#{from_type}".to_sym
376
+
377
+ instance_level_mapped_object, class_level_mapped_object = mapped_objects(to_type, input)
378
+ expect(instance_level_mapped_object.object_id).to_not eql(
379
+ class_level_mapped_object.object_id
380
+ )
381
+ end
382
+
383
+ it 'defines the conversion function for impure mappings' do
384
+ from_type_suffix = from_type.to_s.split("_")[-1]
385
+ conversion_fn = "convert_#{from_type_suffix}_value".to_sym
386
+
387
+ input = "impure_#{from_type}".to_sym
388
+ mapped_object, _ = mapped_objects(to_type, input)
389
+
390
+ expect(mapped_object.public_methods).to include(conversion_fn)
391
+ expect(mapped_object.send(conversion_fn, 3)).to match(provider.name)
392
+ end
393
+ end
394
+ end
395
+
396
+ include_examples 'uses the right mapped object for a given mapping',
397
+ :puppet_property,
398
+ :aix_attribute
399
+
400
+ include_examples 'uses the right mapped object for a given mapping',
401
+ :aix_attribute,
402
+ :puppet_property
403
+ end
404
+
405
+ describe '#attributes_to_args' do
406
+ let(:attributes) do
407
+ {
408
+ :attribute1 => 'value1',
409
+ :attribute2 => 'value2'
410
+ }
411
+ end
412
+
413
+ it 'converts the attributes hash to CLI arguments' do
414
+ expect(provider.attributes_to_args(attributes)).to eql(
415
+ ["attribute1=value1", "attribute2=value2"]
416
+ )
417
+ end
418
+ end
419
+
420
+ describe '#ia_module_args' do
421
+ it 'returns no arguments if the ia_load_module parameter is not specified' do
422
+ provider.resource.stubs(:[]).with(:ia_load_module).returns(nil)
423
+ expect(provider.ia_module_args).to eql([])
424
+ end
425
+
426
+ it 'returns the ia_load_module as a CLI argument' do
427
+ provider.resource.stubs(:[]).with(:ia_load_module).returns('module')
428
+ expect(provider.ia_module_args).to eql(['-R', 'module'])
429
+ end
430
+ end
431
+
432
+ describe '#lscmd' do
433
+ it 'returns the lscmd' do
434
+ provider.class.stubs(:command).with(:list).returns('list')
435
+ provider.stubs(:ia_module_args).returns(['ia_module_args'])
436
+
437
+ expect(provider.lscmd).to eql(
438
+ ['list', '-c', 'ia_module_args', provider.resource.name]
439
+ )
440
+ end
441
+ end
442
+
443
+ describe '#addcmd' do
444
+ let(:attributes) do
445
+ {
446
+ :attribute1 => 'value1',
447
+ :attribute2 => 'value2'
448
+ }
449
+ end
450
+
451
+ it 'returns the addcmd passing in the attributes as CLI arguments' do
452
+ provider.class.stubs(:command).with(:add).returns('add')
453
+ provider.stubs(:ia_module_args).returns(['ia_module_args'])
454
+
455
+ expect(provider.addcmd(attributes)).to eql(
456
+ ['add', 'ia_module_args', 'attribute1=value1', 'attribute2=value2', provider.resource.name]
457
+ )
458
+ end
459
+ end
460
+
461
+ describe '#deletecmd' do
462
+ it 'returns the lscmd' do
463
+ provider.class.stubs(:command).with(:delete).returns('delete')
464
+ provider.stubs(:ia_module_args).returns(['ia_module_args'])
465
+
466
+ expect(provider.deletecmd).to eql(
467
+ ['delete', 'ia_module_args', provider.resource.name]
468
+ )
469
+ end
470
+ end
471
+
472
+ describe '#modifycmd' do
473
+ let(:attributes) do
474
+ {
475
+ :attribute1 => 'value1',
476
+ :attribute2 => 'value2'
477
+ }
478
+ end
479
+
480
+ it 'returns the addcmd passing in the attributes as CLI arguments' do
481
+ provider.class.stubs(:command).with(:modify).returns('modify')
482
+ provider.stubs(:ia_module_args).returns(['ia_module_args'])
483
+
484
+ expect(provider.modifycmd(attributes)).to eql(
485
+ ['modify', 'ia_module_args', 'attribute1=value1', 'attribute2=value2', provider.resource.name]
486
+ )
487
+ end
488
+ end
489
+
490
+ describe '#modify_object' do
491
+ let(:new_attributes) do
492
+ {
493
+ :nofiles => 10000,
494
+ :fsize => 30000
495
+ }
496
+ end
497
+
498
+ it 'modifies the AIX object with the new attributes' do
499
+ provider.stubs(:modifycmd).with(new_attributes).returns('modify_cmd')
500
+ provider.expects(:execute).with('modify_cmd')
501
+ provider.expects(:object_info).with(true)
502
+
503
+ provider.modify_object(new_attributes)
504
+ end
505
+ end
506
+
507
+ describe '#get' do
508
+ # Input
509
+ let(:property) { :uid }
510
+
511
+ let!(:object_info) do
512
+ hash = {}
513
+
514
+ provider.instance_variable_set(:@object_info, hash)
515
+ hash
516
+ end
517
+
518
+ it 'returns :absent if the AIX object does not exist' do
519
+ provider.stubs(:exists?).returns(false)
520
+ object_info[property] = 15
521
+
522
+ expect(provider.get(property)).to eql(:absent)
523
+ end
524
+
525
+ it 'returns :absent if the property is not present on the system' do
526
+ provider.stubs(:exists?).returns(true)
527
+
528
+ expect(provider.get(property)).to eql(:absent)
529
+ end
530
+
531
+ it "returns the property's value" do
532
+ provider.stubs(:exists?).returns(true)
533
+ object_info[property] = 15
534
+
535
+ expect(provider.get(property)).to eql(15)
536
+ end
537
+ end
538
+
539
+ describe '#set' do
540
+ # Input
541
+ let(:property) { :uid }
542
+ let(:value) { 10 }
543
+
544
+ # AIX attribute params
545
+ let(:aix_attribute) { :id }
546
+ let(:property_to_attribute) do
547
+ lambda { |x| x.to_s }
548
+ end
549
+
550
+ before(:each) do
551
+ # Add an attribute
552
+ provider.class.mapping(
553
+ puppet_property: property,
554
+ aix_attribute: aix_attribute,
555
+ property_to_attribute: property_to_attribute
556
+ )
557
+ end
558
+
559
+ it "raises a Puppet::Error if it fails to set the property's value" do
560
+ provider.stubs(:modify_object)
561
+ .with({ :id => value.to_s })
562
+ .raises(Puppet::ExecutionFailure, 'failed to modify the AIX object!')
563
+
564
+ expect { provider.set(property, value) }.to raise_error do |error|
565
+ expect(error).to be_a(Puppet::Error)
566
+ end
567
+ end
568
+
569
+ it "sets the given property's value to the passed-in value" do
570
+ provider.expects(:modify_object).with({ :id => value.to_s })
571
+
572
+ provider.set(property, value)
573
+ end
574
+ end
575
+
576
+ describe '#validate_new_attributes' do
577
+ let(:new_attributes) do
578
+ {
579
+ :nofiles => 10000,
580
+ :fsize => 100000
581
+ }
582
+ end
583
+
584
+ it 'raises a Puppet::Error if a specified attributes corresponds to a Puppet property, reporting all of the attribute-property conflicts' do
585
+ provider.class.mapping(puppet_property: :uid, aix_attribute: :id)
586
+ provider.class.mapping(puppet_property: :groups, aix_attribute: :groups)
587
+
588
+ new_attributes[:id] = '25'
589
+ new_attributes[:groups] = 'groups'
590
+
591
+ expect { provider.validate_new_attributes(new_attributes) }.to raise_error do |error|
592
+ expect(error).to be_a(Puppet::Error)
593
+
594
+ expect(error.message).to match("'uid', 'groups'")
595
+ expect(error.message).to match("'id', 'groups'")
596
+ end
597
+ end
598
+ end
599
+
600
+ describe '#attributes=' do
601
+ let(:new_attributes) do
602
+ {
603
+ :nofiles => 10000,
604
+ :fsize => 100000
605
+ }
606
+ end
607
+
608
+ it 'raises a Puppet::Error if one of the specified attributes corresponds to a Puppet property' do
609
+ provider.class.mapping(puppet_property: :uid, aix_attribute: :id)
610
+ new_attributes[:id] = '25'
611
+
612
+ expect { provider.attributes = new_attributes }.to raise_error do |error|
613
+ expect(error).to be_a(Puppet::Error)
614
+
615
+ expect(error.message).to match('uid')
616
+ expect(error.message).to match('id')
617
+ end
618
+ end
619
+
620
+ it 'raises a Puppet::Error if it fails to set the new AIX attributes' do
621
+ provider.stubs(:modify_object)
622
+ .with(new_attributes)
623
+ .raises(Puppet::ExecutionFailure, 'failed to modify the AIX object!')
624
+
625
+ expect { provider.attributes = new_attributes }.to raise_error do |error|
626
+ expect(error).to be_a(Puppet::Error)
627
+
628
+ expect(error.message).to match('failed to modify the AIX object!')
629
+ end
630
+ end
631
+
632
+ it 'sets the new AIX attributes' do
633
+ provider.expects(:modify_object).with(new_attributes)
634
+
635
+ provider.attributes = new_attributes
636
+ end
637
+ end
638
+
639
+ describe '#object_info' do
640
+ before(:each) do
641
+ # Add some Puppet properties
642
+ provider.class.mapping(
643
+ puppet_property: :uid,
644
+ aix_attribute: :id,
645
+ attribute_to_property: lambda { |x| x.to_i },
646
+ )
647
+ provider.class.mapping(
648
+ puppet_property: :groups,
649
+ aix_attribute: :groups
650
+ )
651
+
652
+ # Mock out our lscmd
653
+ provider.stubs(:lscmd).returns("lsuser #{resource[:name]}")
654
+ end
655
+
656
+ it 'memoizes the result' do
657
+ provider.instance_variable_set(:@object_info, {})
658
+ expect(provider.object_info).to eql({})
659
+ end
660
+
661
+ it 'returns nil if the AIX object does not exist' do
662
+ provider.stubs(:execute).with(provider.lscmd).raises(
663
+ Puppet::ExecutionFailure, 'lscmd failed!'
664
+ )
665
+
666
+ expect(provider.object_info).to be_nil
667
+ end
668
+
669
+ it 'collects the Puppet properties' do
670
+ output = 'mock_output'
671
+ provider.stubs(:execute).with(provider.lscmd).returns(output)
672
+
673
+ # Mock the AIX attributes on the system
674
+ mock_attributes = {
675
+ :id => '1',
676
+ :groups => 'foo,bar,baz',
677
+ :attribute1 => 'value1',
678
+ :attribute2 => 'value2'
679
+ }
680
+ provider.class.stubs(:parse_aix_objects)
681
+ .with(output)
682
+ .returns([{ :name => resource.name, :attributes => mock_attributes }])
683
+
684
+ expected_property_values = {
685
+ :uid => 1,
686
+ :groups => 'foo,bar,baz',
687
+ :attributes => {
688
+ :attribute1 => 'value1',
689
+ :attribute2 => 'value2'
690
+ }
691
+ }
692
+ provider.object_info
693
+ expect(provider.instance_variable_get(:@object_info)).to eql(expected_property_values)
694
+ end
695
+ end
696
+
697
+ describe '#exists?' do
698
+ it 'should return true if the AIX object exists' do
699
+ provider.stubs(:object_info).returns({})
700
+ expect(provider.exists?).to be(true)
701
+ end
702
+
703
+ it 'should return false if the AIX object does not exist' do
704
+ provider.stubs(:object_info).returns(nil)
705
+ expect(provider.exists?).to be(false)
706
+ end
707
+ end
708
+
709
+ describe "#create" do
710
+ let(:property_attributes) do
711
+ {}
712
+ end
713
+ def stub_attributes_property(attributes)
714
+ provider.resource.stubs(:should).with(:attributes).returns(attributes)
715
+ end
716
+ def set_property(puppet_property, aix_attribute, property_to_attribute, should_value = nil)
717
+ property_to_attribute ||= lambda { |x| x }
718
+
719
+ provider.class.mapping(
720
+ puppet_property: puppet_property,
721
+ aix_attribute: aix_attribute,
722
+ property_to_attribute: property_to_attribute
723
+ )
724
+ provider.resource.stubs(:should).with(puppet_property).returns(should_value)
725
+
726
+ if should_value
727
+ property_attributes[aix_attribute] = property_to_attribute.call(should_value)
728
+ end
729
+ end
730
+
731
+ before(:each) do
732
+ clear_attributes
733
+
734
+ # Clear out the :attributes property. We will be setting this later.
735
+ stub_attributes_property(nil)
736
+
737
+ # Add some properties
738
+ set_property(:uid, :id, lambda { |x| x.to_s }, 10)
739
+ set_property(:groups, :groups, nil, 'group1,group2,group3')
740
+ set_property(:shell, :shell, nil)
741
+ end
742
+
743
+ it 'raises a Puppet::Error if one of the specified attributes corresponds to a Puppet property' do
744
+ stub_attributes_property({ :id => 15 })
745
+ provider.class.mapping(puppet_property: :uid, aix_attribute: :id)
746
+
747
+ expect { provider.create }.to raise_error do |error|
748
+ expect(error).to be_a(Puppet::Error)
749
+
750
+ expect(error.message).to match('uid')
751
+ expect(error.message).to match('id')
752
+ end
753
+ end
754
+
755
+ it "raises a Puppet::Error if it fails to create the AIX object" do
756
+ provider.stubs(:addcmd)
757
+ provider.stubs(:execute).raises(
758
+ Puppet::ExecutionFailure, "addcmd failed!"
759
+ )
760
+
761
+ expect { provider.create }.to raise_error do |error|
762
+ expect(error).to be_a(Puppet::Error)
763
+
764
+ expect(error.message).to match("not create")
765
+ end
766
+ end
767
+
768
+ it "creates the AIX object with the given AIX attributes + Puppet properties" do
769
+ attributes = { :fsize => 1000 }
770
+ stub_attributes_property(attributes)
771
+
772
+ provider.expects(:addcmd)
773
+ .with(attributes.merge(property_attributes))
774
+ .returns('addcmd')
775
+ provider.expects(:execute).with('addcmd')
776
+
777
+ provider.create
778
+ end
779
+ end
780
+
781
+ describe "#delete" do
782
+ before(:each) do
783
+ provider.stubs(:deletecmd).returns('deletecmd')
784
+ end
785
+
786
+ it "raises a Puppet::Error if it fails to delete the AIX object" do
787
+ provider.stubs(:execute).with(provider.deletecmd).raises(
788
+ Puppet::ExecutionFailure, "deletecmd failed!"
789
+ )
790
+
791
+ expect { provider.delete }.to raise_error do |error|
792
+ expect(error).to be_a(Puppet::Error)
793
+
794
+ expect(error.message).to match("not delete")
795
+ end
796
+ end
797
+
798
+ it "deletes the AIX object" do
799
+ provider.expects(:execute).with(provider.deletecmd)
800
+ provider.expects(:object_info).with(true)
801
+
802
+ provider.delete
803
+ end
804
+ end
805
+ end