puppet 6.12.0 → 6.13.0

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 (144) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +12 -12
  3. data/README.md +1 -1
  4. data/ext/project_data.yaml +1 -1
  5. data/lib/puppet.rb +22 -7
  6. data/lib/puppet/application/resource.rb +1 -1
  7. data/lib/puppet/configurer.rb +8 -13
  8. data/lib/puppet/defaults.rb +83 -49
  9. data/lib/puppet/environments.rb +26 -18
  10. data/lib/puppet/face/facts.rb +8 -5
  11. data/lib/puppet/file_system/memory_file.rb +6 -0
  12. data/lib/puppet/file_system/memory_impl.rb +13 -0
  13. data/lib/puppet/file_system/windows.rb +7 -10
  14. data/lib/puppet/http.rb +2 -0
  15. data/lib/puppet/http/client.rb +30 -0
  16. data/lib/puppet/http/errors.rb +2 -0
  17. data/lib/puppet/http/service.rb +61 -2
  18. data/lib/puppet/http/service/compiler.rb +86 -0
  19. data/lib/puppet/http/service/file_server.rb +85 -0
  20. data/lib/puppet/http/service/report.rb +4 -8
  21. data/lib/puppet/http/session.rb +8 -1
  22. data/lib/puppet/indirector/catalog/compiler.rb +10 -0
  23. data/lib/puppet/indirector/file_bucket_file/file.rb +1 -1
  24. data/lib/puppet/indirector/json.rb +1 -1
  25. data/lib/puppet/indirector/msgpack.rb +1 -1
  26. data/lib/puppet/network/http/connection.rb +4 -0
  27. data/lib/puppet/network/http/nocache_pool.rb +1 -0
  28. data/lib/puppet/network/http/pool.rb +5 -1
  29. data/lib/puppet/parser/ast/pops_bridge.rb +6 -11
  30. data/lib/puppet/pops/evaluator/access_operator.rb +2 -2
  31. data/lib/puppet/pops/evaluator/evaluator_impl.rb +1 -1
  32. data/lib/puppet/pops/loader/puppet_plan_instantiator.rb +12 -3
  33. data/lib/puppet/pops/parser/evaluating_parser.rb +5 -7
  34. data/lib/puppet/pops/types/p_object_type_extension.rb +10 -0
  35. data/lib/puppet/pops/types/type_calculator.rb +24 -0
  36. data/lib/puppet/pops/validation/checker4_0.rb +1 -1
  37. data/lib/puppet/pops/validation/tasks_checker.rb +5 -1
  38. data/lib/puppet/provider/aix_object.rb +4 -2
  39. data/lib/puppet/provider/group/aix.rb +1 -0
  40. data/lib/puppet/provider/group/groupadd.rb +52 -24
  41. data/lib/puppet/provider/package/apt.rb +14 -3
  42. data/lib/puppet/provider/package/dnfmodule.rb +9 -2
  43. data/lib/puppet/provider/package/dpkg.rb +14 -7
  44. data/lib/puppet/provider/package/fink.rb +20 -3
  45. data/lib/puppet/provider/package/openbsd.rb +13 -1
  46. data/lib/puppet/provider/package/pkg.rb +18 -5
  47. data/lib/puppet/provider/package/yum.rb +9 -5
  48. data/lib/puppet/provider/user/aix.rb +1 -0
  49. data/lib/puppet/provider/user/directoryservice.rb +30 -5
  50. data/lib/puppet/provider/user/useradd.rb +6 -7
  51. data/lib/puppet/reports/store.rb +1 -1
  52. data/lib/puppet/settings.rb +2 -0
  53. data/lib/puppet/ssl/certificate.rb +2 -1
  54. data/lib/puppet/test/test_helper.rb +4 -0
  55. data/lib/puppet/transaction/resource_harness.rb +1 -1
  56. data/lib/puppet/type/group.rb +2 -2
  57. data/lib/puppet/type/package.rb +63 -9
  58. data/lib/puppet/type/user.rb +2 -2
  59. data/lib/puppet/util/log/destinations.rb +1 -1
  60. data/lib/puppet/util/pidlock.rb +26 -6
  61. data/lib/puppet/util/plist.rb +6 -0
  62. data/lib/puppet/util/storage.rb +0 -1
  63. data/lib/puppet/util/yaml.rb +1 -1
  64. data/lib/puppet/version.rb +1 -1
  65. data/locales/puppet.pot +127 -115
  66. data/man/man5/puppet.conf.5 +21 -7
  67. data/man/man8/puppet-agent.8 +1 -1
  68. data/man/man8/puppet-apply.8 +1 -1
  69. data/man/man8/puppet-catalog.8 +1 -1
  70. data/man/man8/puppet-config.8 +1 -1
  71. data/man/man8/puppet-describe.8 +1 -1
  72. data/man/man8/puppet-device.8 +1 -1
  73. data/man/man8/puppet-doc.8 +1 -1
  74. data/man/man8/puppet-epp.8 +1 -1
  75. data/man/man8/puppet-facts.8 +1 -1
  76. data/man/man8/puppet-filebucket.8 +1 -1
  77. data/man/man8/puppet-generate.8 +1 -1
  78. data/man/man8/puppet-help.8 +1 -1
  79. data/man/man8/puppet-key.8 +1 -1
  80. data/man/man8/puppet-lookup.8 +1 -1
  81. data/man/man8/puppet-man.8 +1 -1
  82. data/man/man8/puppet-module.8 +1 -1
  83. data/man/man8/puppet-node.8 +1 -1
  84. data/man/man8/puppet-parser.8 +1 -1
  85. data/man/man8/puppet-plugin.8 +1 -1
  86. data/man/man8/puppet-report.8 +1 -1
  87. data/man/man8/puppet-resource.8 +1 -1
  88. data/man/man8/puppet-script.8 +1 -1
  89. data/man/man8/puppet-ssl.8 +1 -1
  90. data/man/man8/puppet-status.8 +1 -1
  91. data/man/man8/puppet.8 +2 -2
  92. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_md5/should_fetch_if_not_on_the_local_disk.yml +0 -35
  93. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_md5/should_not_update_if_content_on_disk_is_up-to-date.yml +0 -37
  94. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_md5/should_update_if_content_differs_on_disk.yml +0 -37
  95. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_mtime/should_fetch_if_mtime_is_older_on_disk.yml +0 -35
  96. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_mtime/should_fetch_if_no_header_specified.yml +0 -33
  97. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_mtime/should_fetch_if_not_on_the_local_disk.yml +0 -35
  98. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_mtime/should_not_update_if_mtime_is_newer_on_disk.yml +0 -35
  99. data/spec/integration/configurer_spec.rb +26 -7
  100. data/spec/integration/indirector/facts/facter_spec.rb +4 -0
  101. data/spec/unit/application/apply_spec.rb +2 -12
  102. data/spec/unit/application/resource_spec.rb +2 -2
  103. data/spec/unit/configurer/fact_handler_spec.rb +0 -4
  104. data/spec/unit/configurer_spec.rb +0 -3
  105. data/spec/unit/defaults_spec.rb +1 -1
  106. data/spec/unit/environments_spec.rb +57 -28
  107. data/spec/unit/face/facts_spec.rb +24 -20
  108. data/spec/unit/file_system_spec.rb +16 -2
  109. data/spec/unit/http/client_spec.rb +6 -0
  110. data/spec/unit/http/service/compiler_spec.rb +322 -0
  111. data/spec/unit/http/service/file_server_spec.rb +219 -0
  112. data/spec/unit/http/service/report_spec.rb +8 -1
  113. data/spec/unit/http/service_spec.rb +4 -0
  114. data/spec/unit/http/session_spec.rb +31 -0
  115. data/spec/unit/indirector/catalog/compiler_spec.rb +46 -29
  116. data/spec/unit/network/http/connection_spec.rb +23 -1
  117. data/spec/unit/network/http/nocache_pool_spec.rb +3 -3
  118. data/spec/unit/network/http/pool_spec.rb +32 -0
  119. data/spec/unit/node/facts_spec.rb +2 -1
  120. data/spec/unit/node_spec.rb +7 -4
  121. data/spec/unit/pops/serialization/to_from_hr_spec.rb +6 -1
  122. data/spec/unit/pops/validator/validator_spec.rb +7 -2
  123. data/spec/unit/provider/aix_object_spec.rb +16 -2
  124. data/spec/unit/provider/group/groupadd_spec.rb +167 -56
  125. data/spec/unit/provider/package/apt_spec.rb +13 -2
  126. data/spec/unit/provider/package/aptitude_spec.rb +1 -0
  127. data/spec/unit/provider/package/dnfmodule_spec.rb +22 -0
  128. data/spec/unit/provider/package/dpkg_spec.rb +28 -6
  129. data/spec/unit/provider/package/openbsd_spec.rb +17 -0
  130. data/spec/unit/provider/package/pkg_spec.rb +15 -1
  131. data/spec/unit/provider/package/yum_spec.rb +50 -0
  132. data/spec/unit/provider/user/directoryservice_spec.rb +41 -0
  133. data/spec/unit/provider/user/useradd_spec.rb +13 -8
  134. data/spec/unit/puppet_pal_2pec.rb +3 -0
  135. data/spec/unit/puppet_pal_catalog_spec.rb +3 -0
  136. data/spec/unit/puppet_spec.rb +14 -0
  137. data/spec/unit/ssl/certificate_spec.rb +7 -0
  138. data/spec/unit/transaction/persistence_spec.rb +1 -10
  139. data/spec/unit/type/package_spec.rb +8 -0
  140. data/spec/unit/type/user_spec.rb +0 -1
  141. data/spec/unit/util/pidlock_spec.rb +38 -16
  142. data/spec/unit/util/plist_spec.rb +20 -0
  143. data/spec/unit/util/storage_spec.rb +1 -8
  144. metadata +10 -4
@@ -159,12 +159,33 @@ describe Puppet::Network::HTTP::Connection do
159
159
  end
160
160
 
161
161
  it "should return a 503 response if Retry-After is not convertible to an Integer or RFC 2822 Date" do
162
- stub_request(:get, url).to_return(status: [503, 'Service Unavailable'], headers: {'Retry-After' => 'foo'})
162
+ retry_after('foo')
163
163
 
164
164
  result = subject.get('/foo')
165
165
  expect(result.code).to eq("503")
166
166
  end
167
167
 
168
+ it "should close the connection before sleeping" do
169
+ retry_after('42')
170
+
171
+ http1 = Net::HTTP.new(host, port)
172
+ http1.use_ssl = true
173
+ allow(http1).to receive(:started?).and_return(true)
174
+
175
+ http2 = Net::HTTP.new(host, port)
176
+ http2.use_ssl = true
177
+ allow(http1).to receive(:started?).and_return(true)
178
+
179
+ # The "with_connection" method is required to yield started connections
180
+ pool = Puppet.lookup(:http_pool)
181
+ allow(pool).to receive(:with_connection).and_yield(http1).and_yield(http2)
182
+
183
+ expect(http1).to receive(:finish).ordered
184
+ expect(::Kernel).to receive(:sleep).with(42).ordered
185
+
186
+ subject.get('/foo')
187
+ end
188
+
168
189
  it "should sleep and retry if Retry-After is an Integer" do
169
190
  retry_after('42')
170
191
 
@@ -188,6 +209,7 @@ describe Puppet::Network::HTTP::Connection do
188
209
 
189
210
  it "should sleep for no more than the Puppet runinterval" do
190
211
  retry_after('60')
212
+
191
213
  Puppet[:runinterval] = 30
192
214
 
193
215
  expect(::Kernel).to receive(:sleep).with(30)
@@ -8,7 +8,7 @@ describe Puppet::Network::HTTP::NoCachePool do
8
8
  let(:verifier) { double('verifier', :setup_connection => nil) }
9
9
 
10
10
  it 'yields a started connection' do
11
- http = double('http', start: nil, finish: nil)
11
+ http = double('http', start: nil, finish: nil, started?: true)
12
12
 
13
13
  factory = Puppet::Network::HTTP::Factory.new
14
14
  allow(factory).to receive(:create_connection).and_return(http)
@@ -20,8 +20,8 @@ describe Puppet::Network::HTTP::NoCachePool do
20
20
  end
21
21
 
22
22
  it 'yields a new connection each time' do
23
- http1 = double('http1', start: nil, finish: nil)
24
- http2 = double('http2', start: nil, finish: nil)
23
+ http1 = double('http1', start: nil, finish: nil, started?: true)
24
+ http2 = double('http2', start: nil, finish: nil, started?: true)
25
25
 
26
26
  factory = Puppet::Network::HTTP::Factory.new
27
27
  allow(factory).to receive(:create_connection).and_return(http1, http2)
@@ -63,6 +63,8 @@ describe Puppet::Network::HTTP::Pool do
63
63
 
64
64
  it 'returns the connection to the pool' do
65
65
  conn = create_connection(site)
66
+ expect(conn).to receive(:started?).and_return(true)
67
+
66
68
  pool = create_pool
67
69
  pool.release(site, verifier, conn)
68
70
 
@@ -140,6 +142,7 @@ describe Puppet::Network::HTTP::Pool do
140
142
  it 'releases HTTP connections' do
141
143
  conn = create_connection(site)
142
144
  expect(conn).to receive(:use_ssl?).and_return(false)
145
+ expect(conn).to receive(:started?).and_return(true)
143
146
 
144
147
  pool = create_pool_with_connections(site, conn)
145
148
  expect(pool).to receive(:release).with(site, verifier, conn)
@@ -151,6 +154,7 @@ describe Puppet::Network::HTTP::Pool do
151
154
  conn = create_connection(site)
152
155
  expect(conn).to receive(:use_ssl?).and_return(true)
153
156
  expect(conn).to receive(:verify_mode).and_return(OpenSSL::SSL::VERIFY_PEER)
157
+ expect(conn).to receive(:started?).and_return(true)
154
158
 
155
159
  pool = create_pool_with_connections(site, conn)
156
160
  expect(pool).to receive(:release).with(site, verifier, conn)
@@ -169,6 +173,19 @@ describe Puppet::Network::HTTP::Pool do
169
173
 
170
174
  pool.with_connection(site, verifier) {|c| }
171
175
  end
176
+
177
+ it "doesn't add a closed connection back to the pool" do
178
+ http = Net::HTTP.new(site.addr)
179
+ http.use_ssl = true
180
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
181
+ http.start
182
+
183
+ pool = create_pool_with_connections(site, http)
184
+
185
+ pool.with_connection(site, verifier) {|c| c.finish}
186
+
187
+ expect(pool.pool[site]).to be_empty
188
+ end
172
189
  end
173
190
  end
174
191
 
@@ -258,6 +275,7 @@ describe Puppet::Network::HTTP::Pool do
258
275
 
259
276
  it 'finishes expired connections' do
260
277
  conn = create_connection(site)
278
+ allow(conn).to receive(:started?).and_return(true)
261
279
  expect(conn).to receive(:finish)
262
280
 
263
281
  pool = create_pool_with_expired_connections(site, conn)
@@ -271,6 +289,7 @@ describe Puppet::Network::HTTP::Pool do
271
289
  expect(Puppet).to receive(:log_exception).with(be_a(IOError), "Failed to close connection for #{site}: read timeout")
272
290
 
273
291
  conn = create_connection(site)
292
+ expect(conn).to receive(:started?).and_return(true)
274
293
  expect(conn).to receive(:finish).and_raise(IOError, 'read timeout')
275
294
 
276
295
  pool = create_pool_with_expired_connections(site, conn)
@@ -319,10 +338,23 @@ describe Puppet::Network::HTTP::Pool do
319
338
 
320
339
  it 'closes all cached connections' do
321
340
  conn = create_connection(site)
341
+ allow(conn).to receive(:started?).and_return(true)
322
342
  expect(conn).to receive(:finish)
323
343
 
324
344
  pool = create_pool_with_connections(site, conn)
325
345
  pool.close
326
346
  end
347
+
348
+ it 'allows a connection to be closed multiple times safely' do
349
+ http = Net::HTTP.new(site.addr)
350
+ http.use_ssl = true
351
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
352
+ http.start
353
+
354
+ pool = create_pool
355
+
356
+ expect(pool.close_connection(site, http)).to eq(true)
357
+ expect(pool.close_connection(site, http)).to eq(false)
358
+ end
327
359
  end
328
360
  end
@@ -88,7 +88,8 @@ describe Puppet::Node::Facts, "when indirecting" do
88
88
  @facts.sanitize
89
89
  fact_value = @facts.values['test']
90
90
  expect(fact_value).to eq(an_alien.to_s)
91
- expect(fact_value.encoding).to eq(Encoding::UTF_8)
91
+ # JRuby 9.2.8 reports US-ASCII which is a subset of UTF-8
92
+ expect(fact_value.encoding).to eq(Encoding::UTF_8).or eq(Encoding::US_ASCII)
92
93
  end
93
94
 
94
95
  end
@@ -417,7 +417,9 @@ end
417
417
 
418
418
  describe Puppet::Node, "when generating the list of names to search through" do
419
419
  before do
420
- @node = Puppet::Node.new("foo.domain.com", :parameters => {"hostname" => "yay", "domain" => "domain.com"})
420
+ Puppet[:strict_hostname_checking] = false
421
+ @node = Puppet::Node.new("foo.domain.com",
422
+ :parameters => {"hostname" => "yay", "domain" => "domain.com"})
421
423
  end
422
424
 
423
425
  it "returns an array of names" do
@@ -448,7 +450,6 @@ describe Puppet::Node, "when generating the list of names to search through" do
448
450
 
449
451
  describe "and :node_name is set to 'cert'" do
450
452
  before do
451
- Puppet[:strict_hostname_checking] = false
452
453
  Puppet[:node_name] = "cert"
453
454
  end
454
455
 
@@ -457,8 +458,11 @@ describe Puppet::Node, "when generating the list of names to search through" do
457
458
  end
458
459
 
459
460
  describe "and strict hostname checking is enabled" do
460
- it "only uses the passed-in key" do
461
+ before do
461
462
  Puppet[:strict_hostname_checking] = true
463
+ end
464
+
465
+ it "only uses the passed-in key" do
462
466
  expect(@node.names).to eq(["foo.domain.com"])
463
467
  end
464
468
  end
@@ -466,7 +470,6 @@ describe Puppet::Node, "when generating the list of names to search through" do
466
470
 
467
471
  describe "and :node_name is set to 'facter'" do
468
472
  before do
469
- Puppet[:strict_hostname_checking] = false
470
473
  Puppet[:node_name] = "facter"
471
474
  end
472
475
 
@@ -296,10 +296,15 @@ module Serialization
296
296
  expect(val2).to be_a(Types::PObjectTypeExtension)
297
297
  expect(val2).to eql(val)
298
298
  end
299
+
300
+ it 'with POjbectTypeExtension type being converted' do
301
+ val = { 'ObjectExtension' => type.create(34) }
302
+ expect(to_converter.convert(val))
303
+ .to eq({"ObjectExtension"=>{"__ptype"=>"MyType", "x"=>34}})
304
+ end
299
305
  end
300
306
  end
301
307
 
302
-
303
308
  it 'Array of rich data' do
304
309
  # Sensitive omitted because it doesn't respond to ==
305
310
  val = [
@@ -486,10 +486,15 @@ describe "validating 4x" do
486
486
  expect(acceptor).to have_issue(Puppet::Pops::Issues::EXPRESSION_NOT_SUPPORTED_WHEN_SCRIPTING)
487
487
  end
488
488
 
489
- it 'produces an error for node expressions' do
489
+ it 'allows node expressions' do
490
490
  acceptor = validate(parse('apply("foo.example.com") { node default {} }'))
491
+ expect(acceptor.error_count).to eql(0)
492
+ end
493
+
494
+ it 'produces an error for node expressions nested in a block' do
495
+ acceptor = validate(parse('apply("foo.example.com") { if true { node default {} } }'))
491
496
  expect(acceptor.error_count).to eql(1)
492
- expect(acceptor).to have_issue(Puppet::Pops::Issues::EXPRESSION_NOT_SUPPORTED_WHEN_SCRIPTING)
497
+ expect(acceptor).to have_issue(Puppet::Pops::Issues::NOT_TOP_LEVEL)
493
498
  end
494
499
 
495
500
  it 'produces an error for resource definitions' do
@@ -418,15 +418,29 @@ bin:2
418
418
  end
419
419
 
420
420
  describe '#ia_module_args' do
421
- it 'returns no arguments if the ia_load_module parameter is not specified' do
421
+ it 'returns no arguments if ia_load_module parameter or forcelocal parameter are not specified' do
422
422
  allow(provider.resource).to receive(:[]).with(:ia_load_module).and_return(nil)
423
+ allow(provider.resource).to receive(:[]).with(:forcelocal).and_return(nil)
423
424
  expect(provider.ia_module_args).to eql([])
424
425
  end
425
426
 
426
- it 'returns the ia_load_module as a CLI argument' do
427
+ it 'returns the ia_load_module as a CLI argument when ia_load_module is specified' do
427
428
  allow(provider.resource).to receive(:[]).with(:ia_load_module).and_return('module')
429
+ allow(provider.resource).to receive(:[]).with(:forcelocal).and_return(nil)
428
430
  expect(provider.ia_module_args).to eql(['-R', 'module'])
429
431
  end
432
+
433
+ it 'returns "files" as a CLI argument when forcelocal is specified' do
434
+ allow(provider.resource).to receive(:[]).with(:ia_load_module).and_return(nil)
435
+ allow(provider.resource).to receive(:[]).with(:forcelocal).and_return(true)
436
+ expect(provider.ia_module_args).to eql(['-R', 'files'])
437
+ end
438
+
439
+ it 'raises argument error when both ia_load_module and forcelocal parameters are set' do
440
+ allow(provider.resource).to receive(:[]).with(:ia_load_module).and_return('files')
441
+ allow(provider.resource).to receive(:[]).with(:forcelocal).and_return(true)
442
+ expect { provider.ia_module_args }.to raise_error(ArgumentError, "Cannot have both 'forcelocal' and 'ia_load_module' at the same time!")
443
+ end
430
444
  end
431
445
 
432
446
  describe '#lscmd' do
@@ -14,10 +14,11 @@ describe Puppet::Type.type(:group).provider(:groupadd) do
14
14
 
15
15
  let(:resource) { Puppet::Type.type(:group).new(:name => 'mygroup', :provider => provider) }
16
16
  let(:provider) { described_class.new(:name => 'mygroup') }
17
+ let(:members) { ['user2', 'user1', 'user3'] }
17
18
 
18
19
  describe "#create" do
19
20
  before do
20
- allow(provider).to receive(:exists?).and_return(false)
21
+ allow(provider).to receive(:exists?).and_return(false)
21
22
  end
22
23
 
23
24
  it "should add -o when allowdupe is enabled and the group is being created" do
@@ -42,77 +43,127 @@ describe Puppet::Type.type(:group).provider(:groupadd) do
42
43
  end
43
44
  end
44
45
 
45
- describe "on systems with the libuser and forcelocal=true" do
46
- before do
47
- described_class.has_feature(:libuser)
48
- resource[:forcelocal] = :true
49
- end
50
-
51
- it "should use lgroupadd instead of groupadd" do
52
- expect(provider).to receive(:execute).with(including('/usr/sbin/lgroupadd'), hash_including(:custom_environment => hash_including('LIBUSER_CONF')))
53
- provider.create
54
- end
46
+ describe "on systems with libuser" do
47
+ describe "with forcelocal=true" do
48
+ before do
49
+ described_class.has_feature(:manages_local_users_and_groups)
50
+ resource[:forcelocal] = :true
51
+ end
55
52
 
56
- it "should NOT pass -o to lgroupadd" do
57
- resource[:allowdupe] = :true
58
- expect(provider).to receive(:execute).with(excluding('-o'), hash_including(:custom_environment => hash_including('LIBUSER_CONF')))
59
- provider.create
53
+ it "should use lgroupadd instead of groupadd" do
54
+ expect(provider).to receive(:execute).with(including('/usr/sbin/lgroupadd'), hash_including(:custom_environment => hash_including('LIBUSER_CONF')))
55
+ provider.create
56
+ end
57
+
58
+ it "should NOT pass -o to lgroupadd" do
59
+ resource[:allowdupe] = :true
60
+ expect(provider).to receive(:execute).with(excluding('-o'), hash_including(:custom_environment => hash_including('LIBUSER_CONF')))
61
+ provider.create
62
+ end
63
+
64
+ it "should raise an exception for duplicate GID if allowdupe is not set and duplicate GIDs exist" do
65
+ resource[:gid] = 505
66
+ allow(provider).to receive(:findgroup).and_return(true)
67
+ expect { provider.create }.to raise_error(Puppet::Error, "GID 505 already exists, use allowdupe to force group creation")
68
+ end
60
69
  end
61
70
 
62
- it "should raise an exception for duplicate GID if allowdupe is not set and duplicate GIDs exist" do
63
- resource[:gid] = 505
64
- allow(provider).to receive(:findgroup).and_return(true)
65
- expect { provider.create }.to raise_error(Puppet::Error, "GID 505 already exists, use allowdupe to force group creation")
66
- end
71
+ describe "with a list of members" do
72
+ before do
73
+ members.each { |m| allow(Etc).to receive(:getpwnam).with(m).and_return(true) }
74
+
75
+ described_class.has_feature(:manages_members)
76
+ resource[:forcelocal] = false
77
+ resource[:members] = members
78
+ end
79
+
80
+ it "should use lgroupmod to add the members" do
81
+ allow(provider).to receive(:execute).with(['/usr/sbin/groupadd', 'mygroup'], hash_including({:failonfail => true, :combine => true, :custom_environment => {}})).and_return(true)
82
+ expect(provider).to receive(:execute).with(['/usr/sbin/lgroupmod', '-M', members.join(','), 'mygroup'], hash_including(:custom_environment => hash_including('LIBUSER_CONF')))
83
+ provider.create
84
+ end
85
+ end
67
86
  end
68
87
  end
69
88
 
70
89
  describe "#modify" do
71
90
  before do
72
- allow(provider).to receive(:exists?).and_return(true)
91
+ allow(provider).to receive(:exists?).and_return(true)
73
92
  end
74
93
 
75
- describe "on systems with the libuser and forcelocal=false" do
76
- before do
77
- described_class.has_feature(:libuser)
78
- resource[:forcelocal] = :false
79
- end
94
+ describe "on systems with libuser" do
95
+ describe "with forcelocal=false" do
96
+ before do
97
+ described_class.has_feature(:manages_local_users_and_groups)
98
+ resource[:forcelocal] = :false
99
+ end
80
100
 
81
- it "should use groupmod" do
82
- expect(provider).to receive(:execute).with(['/usr/sbin/groupmod', '-g', 150, 'mygroup'], hash_including({:failonfail => true, :combine => true, :custom_environment => {}}))
83
- provider.gid = 150
84
- end
101
+ it "should use groupmod" do
102
+ expect(provider).to receive(:execute).with(['/usr/sbin/groupmod', '-g', 150, 'mygroup'], hash_including({:failonfail => true, :combine => true, :custom_environment => {}}))
103
+ provider.gid = 150
104
+ end
85
105
 
86
- it "should pass -o to groupmod" do
87
- resource[:allowdupe] = :true
88
- expect(provider).to receive(:execute).with(['/usr/sbin/groupmod', '-g', 150, '-o', 'mygroup'], hash_including({:failonfail => true, :combine => true, :custom_environment => {}}))
89
- provider.gid = 150
106
+ it "should pass -o to groupmod" do
107
+ resource[:allowdupe] = :true
108
+ expect(provider).to receive(:execute).with(['/usr/sbin/groupmod', '-g', 150, '-o', 'mygroup'], hash_including({:failonfail => true, :combine => true, :custom_environment => {}}))
109
+ provider.gid = 150
110
+ end
90
111
  end
91
- end
92
112
 
93
- describe "on systems with the libuser and forcelocal=true" do
94
- before do
95
- described_class.has_feature(:libuser)
96
- resource[:forcelocal] = :true
97
- end
113
+ describe "with forcelocal=true" do
114
+ before do
115
+ described_class.has_feature(:manages_local_users_and_groups)
116
+ resource[:forcelocal] = :true
117
+ end
98
118
 
99
- it "should use lgroupmod instead of groupmod" do
100
- expect(provider).to receive(:execute).with(['/usr/sbin/lgroupmod', '-g', 150, 'mygroup'], hash_including(:custom_environment => hash_including('LIBUSER_CONF')))
101
- provider.gid = 150
102
- end
119
+ it "should use lgroupmod instead of groupmod" do
120
+ expect(provider).to receive(:execute).with(['/usr/sbin/lgroupmod', '-g', 150, 'mygroup'], hash_including(:custom_environment => hash_including('LIBUSER_CONF')))
121
+ provider.gid = 150
122
+ end
123
+
124
+ it "should NOT pass -o to lgroupmod" do
125
+ resource[:allowdupe] = :true
126
+ expect(provider).to receive(:execute).with(['/usr/sbin/lgroupmod', '-g', 150, 'mygroup'], hash_including(:custom_environment => hash_including('LIBUSER_CONF')))
127
+ provider.gid = 150
128
+ end
103
129
 
104
- it "should NOT pass -o to lgroupmod" do
105
- resource[:allowdupe] = :true
106
- expect(provider).to receive(:execute).with(['/usr/sbin/lgroupmod', '-g', 150, 'mygroup'], hash_including(:custom_environment => hash_including('LIBUSER_CONF')))
107
- provider.gid = 150
130
+ it "should raise an exception for duplicate GID if allowdupe is not set and duplicate GIDs exist" do
131
+ resource[:gid] = 150
132
+ resource[:allowdupe] = :false
133
+ allow(provider).to receive(:findgroup).and_return(true)
134
+ expect { provider.gid = 150 }.to raise_error(Puppet::Error, "GID 150 already exists, use allowdupe to force group creation")
135
+ end
108
136
  end
109
137
 
110
- it "should raise an exception for duplicate GID if allowdupe is not set and duplicate GIDs exist" do
111
- resource[:gid] = 150
112
- resource[:allowdupe] = :false
113
- allow(provider).to receive(:findgroup).and_return(true)
114
- expect { provider.gid = 150 }.to raise_error(Puppet::Error, "GID 150 already exists, use allowdupe to force group creation")
115
- end
138
+ describe "with members=something" do
139
+ before do
140
+ described_class.has_feature(:manages_members)
141
+ allow(Etc).to receive(:getpwnam).and_return(true)
142
+ resource[:members] = members
143
+ end
144
+
145
+ describe "with auth_membership on" do
146
+ before { resource[:auth_membership] = true }
147
+
148
+ it "should purge existing users before adding" do
149
+ allow(provider).to receive(:members).and_return(members)
150
+ expect(provider).to receive(:localmodify).with('-m', members.join(','), 'mygroup')
151
+ provider.modifycmd(:members, ['user1'])
152
+ end
153
+ end
154
+
155
+ describe "with auth_membership off" do
156
+ before { resource[:auth_membership] = false }
157
+
158
+ it "should add to the existing users" do
159
+ new_members = ['user1', 'user2', 'user3', 'user4']
160
+ allow(provider).to receive(:members).and_return(members)
161
+ expect(provider).not_to receive(:localmodify).with('-m', members.join(','), 'mygroup')
162
+ expect(provider).to receive(:execute).with(['/usr/sbin/lgroupmod', '-M', new_members.join(','), 'mygroup'], kind_of(Hash))
163
+ provider.members = new_members
164
+ end
165
+ end
166
+ end
116
167
  end
117
168
  end
118
169
 
@@ -124,6 +175,35 @@ describe Puppet::Type.type(:group).provider(:groupadd) do
124
175
  end
125
176
  end
126
177
 
178
+ describe "#findgroup" do
179
+ before { allow(File).to receive(:read).with('/etc/group').and_return(content) }
180
+
181
+ let(:content) { "sample_group_name:sample_password:sample_gid:sample_user_list" }
182
+ let(:output) do
183
+ {
184
+ group_name: 'sample_group_name',
185
+ password: 'sample_password',
186
+ gid: 'sample_gid',
187
+ user_list: 'sample_user_list',
188
+ }
189
+ end
190
+
191
+ [:group_name, :password, :gid, :user_list].each do |key|
192
+ it "finds a group by #{key} when asked" do
193
+ expect(provider.send(:findgroup, key, "sample_#{key}")).to eq(output)
194
+ end
195
+ end
196
+
197
+ it "returns false when specified key/value pair is not found" do
198
+ expect(provider.send(:findgroup, :group_name, 'invalid_group_name')).to eq(false)
199
+ end
200
+
201
+ it "reads the group file only once per resource" do
202
+ expect(File).to receive(:read).with('/etc/group').once
203
+ 5.times { provider.send(:findgroup, :group_name, 'sample_group_name') }
204
+ end
205
+ end
206
+
127
207
  describe "#delete" do
128
208
  before do
129
209
  allow(provider).to receive(:exists?).and_return(true)
@@ -131,7 +211,7 @@ describe Puppet::Type.type(:group).provider(:groupadd) do
131
211
 
132
212
  describe "on systems with the libuser and forcelocal=false" do
133
213
  before do
134
- described_class.has_feature(:libuser)
214
+ described_class.has_feature(:manages_local_users_and_groups)
135
215
  resource[:forcelocal] = :false
136
216
  end
137
217
 
@@ -143,7 +223,7 @@ describe Puppet::Type.type(:group).provider(:groupadd) do
143
223
 
144
224
  describe "on systems with the libuser and forcelocal=true" do
145
225
  before do
146
- described_class.has_feature(:libuser)
226
+ described_class.has_feature(:manages_local_users_and_groups)
147
227
  resource[:forcelocal] = :true
148
228
  end
149
229
 
@@ -153,4 +233,35 @@ describe Puppet::Type.type(:group).provider(:groupadd) do
153
233
  end
154
234
  end
155
235
  end
236
+
237
+ describe "group type :members property helpers" do
238
+ describe "#member_valid?" do
239
+ it "should return true if a member exists" do
240
+ passwd = Struct::Passwd.new('existinguser', nil, 1100)
241
+ allow(Etc).to receive(:getpwnam).with('existinguser').and_return(passwd)
242
+ expect(provider.member_valid?('existinguser')).to eq(true)
243
+ end
244
+ end
245
+
246
+ describe "#members_to_s" do
247
+ it "should return an empty string on non-array input" do
248
+ [Object.new, {}, 1, :symbol, ''].each do |input|
249
+ expect(provider.members_to_s(input)).to be_empty
250
+ end
251
+ end
252
+
253
+ it "should return an empty string on empty or nil users" do
254
+ expect(provider.members_to_s([])).to be_empty
255
+ expect(provider.members_to_s(nil)).to be_empty
256
+ end
257
+
258
+ it "should return a user string for a single user" do
259
+ expect(provider.members_to_s(['user1'])).to eq('user1')
260
+ end
261
+
262
+ it "should return a user string for multiple users" do
263
+ expect(provider.members_to_s(['user1', 'user2'])).to eq('user1,user2')
264
+ end
265
+ end
266
+ end
156
267
  end