puppet 6.25.1 → 6.28.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 (112) hide show
  1. checksums.yaml +4 -4
  2. data/CODEOWNERS +1 -1
  3. data/Gemfile +2 -2
  4. data/Gemfile.lock +101 -34
  5. data/lib/puppet/agent.rb +47 -11
  6. data/lib/puppet/application/agent.rb +2 -12
  7. data/lib/puppet/application/lookup.rb +74 -24
  8. data/lib/puppet/concurrent/thread_local_singleton.rb +5 -3
  9. data/lib/puppet/configurer.rb +8 -14
  10. data/lib/puppet/defaults.rb +13 -3
  11. data/lib/puppet/face/generate.rb +2 -0
  12. data/lib/puppet/file_serving/metadata.rb +3 -0
  13. data/lib/puppet/file_system/file_impl.rb +7 -7
  14. data/lib/puppet/file_system/jruby.rb +1 -1
  15. data/lib/puppet/file_system/windows.rb +4 -4
  16. data/lib/puppet/file_system.rb +1 -1
  17. data/lib/puppet/functions/next.rb +18 -1
  18. data/lib/puppet/functions/tree_each.rb +0 -1
  19. data/lib/puppet/functions/versioncmp.rb +6 -2
  20. data/lib/puppet/generate/type.rb +9 -0
  21. data/lib/puppet/http/client.rb +22 -2
  22. data/lib/puppet/node.rb +1 -1
  23. data/lib/puppet/pops/parser/code_merger.rb +4 -4
  24. data/lib/puppet/pops/parser/egrammar.ra +2 -0
  25. data/lib/puppet/pops/parser/eparser.rb +813 -794
  26. data/lib/puppet/pops/serialization/to_data_converter.rb +6 -18
  27. data/lib/puppet/provider/package/puppetserver_gem.rb +7 -16
  28. data/lib/puppet/provider/package/windows/exe_package.rb +30 -1
  29. data/lib/puppet/provider/package/windows/package.rb +2 -1
  30. data/lib/puppet/provider/package/windows.rb +14 -1
  31. data/lib/puppet/provider/service/init.rb +5 -4
  32. data/lib/puppet/provider/user/directoryservice.rb +5 -0
  33. data/lib/puppet/ssl/ssl_provider.rb +75 -19
  34. data/lib/puppet/ssl/state_machine.rb +13 -17
  35. data/lib/puppet/ssl/verifier.rb +6 -0
  36. data/lib/puppet/transaction/persistence.rb +22 -12
  37. data/lib/puppet/type/exec.rb +1 -1
  38. data/lib/puppet/type/file/data_sync.rb +1 -1
  39. data/lib/puppet/type/user.rb +43 -38
  40. data/lib/puppet/util/json.rb +17 -0
  41. data/lib/puppet/util/log.rb +7 -2
  42. data/lib/puppet/util/monkey_patches.rb +6 -2
  43. data/lib/puppet/util/package.rb +25 -16
  44. data/lib/puppet/util/yaml.rb +21 -2
  45. data/lib/puppet/util.rb +1 -2
  46. data/lib/puppet/version.rb +1 -1
  47. data/lib/puppet.rb +2 -14
  48. data/locales/puppet.pot +5 -10454
  49. data/man/man5/puppet.conf.5 +21 -2
  50. data/man/man8/puppet-agent.8 +1 -1
  51. data/man/man8/puppet-apply.8 +1 -1
  52. data/man/man8/puppet-catalog.8 +1 -1
  53. data/man/man8/puppet-config.8 +1 -1
  54. data/man/man8/puppet-describe.8 +1 -1
  55. data/man/man8/puppet-device.8 +1 -1
  56. data/man/man8/puppet-doc.8 +1 -1
  57. data/man/man8/puppet-epp.8 +1 -1
  58. data/man/man8/puppet-facts.8 +1 -1
  59. data/man/man8/puppet-filebucket.8 +1 -1
  60. data/man/man8/puppet-generate.8 +1 -1
  61. data/man/man8/puppet-help.8 +1 -1
  62. data/man/man8/puppet-key.8 +1 -1
  63. data/man/man8/puppet-lookup.8 +9 -6
  64. data/man/man8/puppet-man.8 +1 -1
  65. data/man/man8/puppet-module.8 +1 -1
  66. data/man/man8/puppet-node.8 +1 -1
  67. data/man/man8/puppet-parser.8 +1 -1
  68. data/man/man8/puppet-plugin.8 +1 -1
  69. data/man/man8/puppet-report.8 +1 -1
  70. data/man/man8/puppet-resource.8 +1 -1
  71. data/man/man8/puppet-script.8 +1 -1
  72. data/man/man8/puppet-ssl.8 +1 -1
  73. data/man/man8/puppet-status.8 +1 -1
  74. data/man/man8/puppet.8 +2 -2
  75. data/spec/fixtures/unit/forge/bacula.json +1 -1
  76. data/spec/integration/application/agent_spec.rb +108 -0
  77. data/spec/integration/application/lookup_spec.rb +81 -50
  78. data/spec/integration/application/resource_spec.rb +6 -2
  79. data/spec/integration/http/client_spec.rb +51 -4
  80. data/spec/lib/puppet_spec/https.rb +1 -1
  81. data/spec/lib/puppet_spec/puppetserver.rb +39 -2
  82. data/spec/shared_contexts/l10n.rb +5 -0
  83. data/spec/unit/agent_spec.rb +28 -2
  84. data/spec/unit/application/agent_spec.rb +26 -16
  85. data/spec/unit/application/lookup_spec.rb +131 -10
  86. data/spec/unit/concurrent/thread_local_singleton_spec.rb +39 -0
  87. data/spec/unit/configurer_spec.rb +124 -61
  88. data/spec/unit/daemon_spec.rb +2 -11
  89. data/spec/unit/face/generate_spec.rb +64 -0
  90. data/spec/unit/file_system_spec.rb +34 -4
  91. data/spec/unit/forge/module_release_spec.rb +3 -3
  92. data/spec/unit/functions/versioncmp_spec.rb +40 -4
  93. data/spec/unit/http/client_spec.rb +18 -0
  94. data/spec/unit/node_spec.rb +6 -0
  95. data/spec/unit/pops/parser/parse_containers_spec.rb +2 -2
  96. data/spec/unit/pops/serialization/to_from_hr_spec.rb +0 -58
  97. data/spec/unit/pops/validator/validator_spec.rb +5 -0
  98. data/spec/unit/provider/package/puppetserver_gem_spec.rb +2 -2
  99. data/spec/unit/provider/package/windows/exe_package_spec.rb +17 -0
  100. data/spec/unit/provider/service/gentoo_spec.rb +6 -5
  101. data/spec/unit/provider/service/init_spec.rb +15 -9
  102. data/spec/unit/provider/service/openwrt_spec.rb +21 -29
  103. data/spec/unit/provider/service/redhat_spec.rb +3 -2
  104. data/spec/unit/ssl/ssl_provider_spec.rb +75 -1
  105. data/spec/unit/ssl/state_machine_spec.rb +1 -0
  106. data/spec/unit/transaction/persistence_spec.rb +51 -0
  107. data/spec/unit/type/user_spec.rb +0 -45
  108. data/spec/unit/util/json_spec.rb +126 -0
  109. data/spec/unit/util/windows_spec.rb +23 -0
  110. data/spec/unit/util/yaml_spec.rb +54 -29
  111. data/tasks/generate_cert_fixtures.rake +5 -4
  112. metadata +9 -3
@@ -19,16 +19,52 @@ describe "the versioncmp function" do
19
19
  let(:type_parser) { Puppet::Pops::Types::TypeParser.singleton }
20
20
 
21
21
  it 'should raise an Error if there is less than 2 arguments' do
22
- expect { versioncmp('a,b') }.to raise_error(/expects 2 arguments, got 1/)
22
+ expect { versioncmp('a,b') }.to raise_error(/expects between 2 and 3 arguments, got 1/)
23
23
  end
24
24
 
25
- it 'should raise an Error if there is more than 2 arguments' do
26
- expect { versioncmp('a,b','foo', 'bar') }.to raise_error(/expects 2 arguments, got 3/)
25
+ it 'should raise an Error if there is more than 3 arguments' do
26
+ expect { versioncmp('a,b','foo', false, 'bar') }.to raise_error(/expects between 2 and 3 arguments, got 4/)
27
27
  end
28
28
 
29
29
  it "should call Puppet::Util::Package.versioncmp (included in scope)" do
30
- expect(Puppet::Util::Package).to receive(:versioncmp).with('1.2', '1.3').and_return(-1)
30
+ expect(Puppet::Util::Package).to receive(:versioncmp).with('1.2', '1.3', false).and_return(-1)
31
31
 
32
32
  expect(versioncmp('1.2', '1.3')).to eq(-1)
33
33
  end
34
+
35
+ context "when ignore_trailing_zeroes is true" do
36
+ it "should equate versions with 2 elements and dots but with unnecessary zero" do
37
+ expect(versioncmp("10.1.0", "10.1", true)).to eq(0)
38
+ end
39
+
40
+ it "should equate versions with 1 element and dot but with unnecessary zero" do
41
+ expect(versioncmp("11.0", "11", true)).to eq(0)
42
+ end
43
+
44
+ it "should equate versions with 1 element and dot but with unnecessary zeros" do
45
+ expect(versioncmp("11.00", "11", true)).to eq(0)
46
+ end
47
+
48
+ it "should equate versions with dots and iregular zeroes" do
49
+ expect(versioncmp("11.0.00", "11", true)).to eq(0)
50
+ end
51
+
52
+ it "should equate versions with dashes" do
53
+ expect(versioncmp("10.1-0", "10.1.0-0", true)).to eq(0)
54
+ end
55
+
56
+ it "should compare versions with dashes after normalization" do
57
+ expect(versioncmp("10.1-1", "10.1.0-0", true)).to eq(1)
58
+ end
59
+
60
+ it "should not normalize versions if zeros are not trailing" do
61
+ expect(versioncmp("1.1", "1.0.1", true)).to eq(1)
62
+ end
63
+ end
64
+
65
+ context "when ignore_trailing_zeroes is false" do
66
+ it "should not equate versions if zeros are not trailing" do
67
+ expect(versioncmp("1.1", "1.0.1")).to eq(1)
68
+ end
69
+ end
34
70
  end
@@ -120,6 +120,24 @@ describe Puppet::HTTP::Client do
120
120
 
121
121
  client.close
122
122
  end
123
+
124
+ it 'reloads the default ssl context' do
125
+ expect(client.pool).to receive(:with_connection) do |_, verifier|
126
+ expect(verifier.ssl_context).to_not equal(puppet_context)
127
+ end
128
+
129
+ client.close
130
+ client.connect(uri)
131
+ end
132
+
133
+ it 'reloads the default system ssl context' do
134
+ expect(client.pool).to receive(:with_connection) do |_, verifier|
135
+ expect(verifier.ssl_context).to_not equal(system_context)
136
+ end
137
+
138
+ client.close
139
+ client.connect(uri, options: {include_system_store: true})
140
+ end
123
141
  end
124
142
 
125
143
  context "for GET requests" do
@@ -40,6 +40,12 @@ describe Puppet::Node do
40
40
  expect(node.environment.name).to eq(:bar)
41
41
  end
42
42
 
43
+ it "sets environment_name with the correct environment name" do
44
+ node = Puppet::Node.new("foo")
45
+ node.environment = Puppet::Node::Environment.remote('www123')
46
+ expect(node.environment_name).to eq(:www123)
47
+ end
48
+
43
49
  it "allows its environment to be set by parameters after initialization" do
44
50
  node = Puppet::Node.new("foo")
45
51
  node.parameters["environment"] = :bar
@@ -106,7 +106,7 @@ describe "egrammar parsing containers" do
106
106
 
107
107
  context 'it should allow keywords as attribute names' do
108
108
  ['and', 'case', 'class', 'default', 'define', 'else', 'elsif', 'if', 'in', 'inherits', 'node', 'or',
109
- 'undef', 'unless', 'type', 'attr', 'function', 'private'].each do |keyword|
109
+ 'undef', 'unless', 'type', 'attr', 'function', 'private', 'plan', 'apply'].each do |keyword|
110
110
  it "such as #{keyword}" do
111
111
  expect { parse("class x ($#{keyword}){} class { x: #{keyword} => 1 }") }.to_not raise_error
112
112
  end
@@ -178,7 +178,7 @@ describe "egrammar parsing containers" do
178
178
 
179
179
  context 'it should allow keywords as attribute names' do
180
180
  ['and', 'case', 'class', 'default', 'define', 'else', 'elsif', 'if', 'in', 'inherits', 'node', 'or',
181
- 'undef', 'unless', 'type', 'attr', 'function', 'private'].each do |keyword|
181
+ 'undef', 'unless', 'type', 'attr', 'function', 'private', 'plan', 'apply'].each do |keyword|
182
182
  it "such as #{keyword}" do
183
183
  expect {parse("define x ($#{keyword}){} x { y: #{keyword} => 1 }")}.to_not raise_error
184
184
  end
@@ -559,29 +559,6 @@ module Serialization
559
559
  expect(warnings).to eql(["['key'] contains the special value default. It will be converted to the String 'default'"])
560
560
  end
561
561
  end
562
- context 'and force_symbol set to true' do
563
- let(:to_converter) { ToDataConverter.new(:rich_data => false, :force_symbol => true) }
564
-
565
- it 'A Hash with Symbol values is converted to hash with Symbol values' do
566
- val = { 'one' => :one, 'two' => :two }
567
- Puppet::Util::Log.with_destination(Puppet::Test::LogCollector.new(logs)) do
568
-
569
- # write and read methods does not work here as we cannot force Symbols in Json.
570
- # and a hash with symbol values cannot be an instance of Types::TypeFactory.data.
571
- # Using YAML for this instead
572
- io.reopen
573
- value = to_converter.convert(val)
574
- io << [value].to_yaml
575
- io.rewind
576
-
577
- val2 = from_converter.convert(YAML::load(io.read)[0])
578
-
579
- expect(val2).to be_a(Hash)
580
- expect(val2).to eql({ 'one' => :one, 'two' => :two })
581
- end
582
- expect(warnings).to be_empty
583
- end
584
- end
585
562
  end
586
563
 
587
564
  context 'with rich_data is set to true' do
@@ -655,41 +632,6 @@ module Serialization
655
632
  end.to raise_error(/Cannot create a Pcore::TimestampType from a (Fixnum|Integer)/)
656
633
  end
657
634
  end
658
-
659
- context 'when data is unknown' do
660
- let(:to_converter) { ToDataConverter.new(:message_prefix => 'Test Hash') }
661
- let(:logs) { [] }
662
- let(:warnings) { logs.select { |log| log.level == :warning }.map { |log| log.message } }
663
- let(:val) { Class.new }
664
-
665
- context 'and :silence_warnings undefined or set to false' do
666
- it 'convert the unknown data to string with warnings' do
667
- Puppet::Util::Log.with_destination(Puppet::Test::LogCollector.new(logs)) do
668
- write(val)
669
- val2 = read
670
- expect(val2).to be_a(String)
671
- expect(val2).to match(/Class/)
672
- end
673
- expect(warnings).to eql([
674
- "Test Hash contains a #{val.class} value. It will be converted to the String '#{val.to_s}'"])
675
- end
676
- end
677
-
678
- context 'and :silence_warnings undefined or set to true' do
679
- let(:to_converter) { ToDataConverter.new(:message_prefix => 'Test Hash', :silence_warnings => true) }
680
-
681
- it 'convert the unknown data to string without warnings if silence_warnings set to true' do
682
- val = Class.new
683
- Puppet::Util::Log.with_destination(Puppet::Test::LogCollector.new(logs)) do
684
- write(val)
685
- val2 = read
686
- expect(val2).to be_a(String)
687
- expect(val2).to match(/Class/)
688
- end
689
- expect(warnings).to be_empty
690
- end
691
- end
692
- end
693
635
  end
694
636
  end
695
637
  end
@@ -432,6 +432,11 @@ describe "validating 4x" do
432
432
  expect(acceptor.error_count).to eql(0)
433
433
  end
434
434
 
435
+ it 'allows apply to be used as a resource attribute name' do
436
+ acceptor = validate(parse('apply("foo.example.com") { sometype { "resourcetitle": apply => "applyvalue" } }'))
437
+ expect(acceptor.error_count).to eql(0)
438
+ end
439
+
435
440
  it 'accepts multiple arguments' do
436
441
  acceptor = validate(parse('apply(["foo.example.com"], { "other" => "args" }) { }'))
437
442
  expect(acceptor.error_count).to eql(0)
@@ -105,9 +105,9 @@ describe Puppet::Type.type(:package).provider(:puppetserver_gem) do
105
105
 
106
106
  describe ".gemlist" do
107
107
  context "listing installed packages" do
108
- it "uses the puppet rubygems library to list local gems" do
108
+ it "uses the puppet_gem provider_command to list local gems" do
109
109
  expected = { name: 'world_airports', provider: :puppetserver_gem, ensure: ['1.1.3'] }
110
- expect(described_class).to receive(:execute_rubygems_list_command).with(nil).and_return(File.read(my_fixture('gem-list-local-packages')))
110
+ expect(described_class).to receive(:execute_rubygems_list_command).with(['gem', 'list', '--local']).and_return(File.read(my_fixture('gem-list-local-packages')))
111
111
  expect(described_class.gemlist({ local: true })).to include(expected)
112
112
  end
113
113
  end
@@ -1,5 +1,6 @@
1
1
  require 'spec_helper'
2
2
  require 'puppet/provider/package/windows/exe_package'
3
+ require 'puppet/provider/package/windows'
3
4
 
4
5
  describe Puppet::Provider::Package::Windows::ExePackage do
5
6
  let (:name) { 'Git version 1.7.11' }
@@ -71,10 +72,26 @@ describe Puppet::Provider::Package::Windows::ExePackage do
71
72
 
72
73
  context '#install_command' do
73
74
  it 'should install using the source' do
75
+ allow(Puppet::FileSystem).to receive(:exist?).with(source).and_return(true)
74
76
  cmd = described_class.install_command({:source => source})
75
77
 
76
78
  expect(cmd).to eq(source)
77
79
  end
80
+
81
+ it 'should raise error when URI is invalid' do
82
+ web_source = 'https://www.t e s t.test/test.exe'
83
+
84
+ expect do
85
+ described_class.install_command({:source => web_source, :name => name})
86
+ end.to raise_error(Puppet::Error, /Error when installing #{name}:/)
87
+ end
88
+
89
+ it 'should download package from source file before installing', if: Puppet::Util::Platform.windows? do
90
+ web_source = 'https://www.test.test/test.exe'
91
+ stub_request(:get, web_source).to_return(status: 200, body: 'package binaries')
92
+ cmd = described_class.install_command({:source => web_source})
93
+ expect(File.read(cmd)).to eq('package binaries')
94
+ end
78
95
  end
79
96
 
80
97
  context '#uninstall_command' do
@@ -10,8 +10,8 @@ describe 'Puppet::Type::Service::Provider::Gentoo',
10
10
 
11
11
  before :each do
12
12
  allow(Puppet::Type.type(:service)).to receive(:defaultprovider).and_return(provider_class)
13
- allow(FileTest).to receive(:file?).with('/sbin/rc-update').and_return(true)
14
- allow(FileTest).to receive(:executable?).with('/sbin/rc-update').and_return(true)
13
+ allow(Puppet::FileSystem).to receive(:file?).with('/sbin/rc-update').and_return(true)
14
+ allow(Puppet::FileSystem).to receive(:executable?).with('/sbin/rc-update').and_return(true)
15
15
  allow(Facter).to receive(:value).with(:operatingsystem).and_return('Gentoo')
16
16
  allow(Facter).to receive(:value).with(:osfamily).and_return('Gentoo')
17
17
 
@@ -52,13 +52,14 @@ describe 'Puppet::Type::Service::Provider::Gentoo',
52
52
  end
53
53
 
54
54
  it "should get a list of services from /etc/init.d but exclude helper scripts" do
55
- expect(FileTest).to receive(:directory?).with('/etc/init.d').and_return(true)
55
+ allow(Puppet::FileSystem).to receive(:directory?).and_call_original
56
+ allow(Puppet::FileSystem).to receive(:directory?).with('/etc/init.d').and_return(true)
56
57
  expect(Dir).to receive(:entries).with('/etc/init.d').and_return(initscripts)
57
58
  (initscripts - helperscripts).each do |script|
58
- expect(FileTest).to receive(:executable?).with("/etc/init.d/#{script}").and_return(true)
59
+ expect(Puppet::FileSystem).to receive(:executable?).with("/etc/init.d/#{script}").and_return(true)
59
60
  end
60
61
  helperscripts.each do |script|
61
- expect(FileTest).not_to receive(:executable?).with("/etc/init.d/#{script}")
62
+ expect(Puppet::FileSystem).not_to receive(:executable?).with("/etc/init.d/#{script}")
62
63
  end
63
64
 
64
65
  allow(Puppet::FileSystem).to receive(:symlink?).and_return(false)
@@ -85,14 +85,20 @@ describe 'Puppet::Type::Service::Provider::Init',
85
85
  @services = ['one', 'two', 'three', 'four', 'umountfs']
86
86
  allow(Dir).to receive(:entries).and_call_original
87
87
  allow(Dir).to receive(:entries).with('tmp').and_return(@services)
88
- expect(FileTest).to receive(:directory?).with('tmp').and_return(true)
89
- allow(FileTest).to receive(:executable?).and_return(true)
88
+ allow(Puppet::FileSystem).to receive(:directory?).and_call_original
89
+ allow(Puppet::FileSystem).to receive(:directory?).with('tmp').and_return(true)
90
+ allow(Puppet::FileSystem).to receive(:executable?).and_return(true)
90
91
  end
91
92
 
92
93
  it "should return instances for all services" do
93
94
  expect(provider_class.instances.map(&:name)).to eq(@services)
94
95
  end
95
96
 
97
+ it "should omit directories from the service list" do
98
+ expect(Puppet::FileSystem).to receive(:directory?).with('tmp/four').and_return(true)
99
+ expect(provider_class.instances.map(&:name)).to eq(@services - ['four'])
100
+ end
101
+
96
102
  it "should omit an array of services from exclude list" do
97
103
  exclude = ['two', 'four']
98
104
  expect(provider_class.get_services(provider_class.defpath, exclude).map(&:name)).to eq(@services - exclude)
@@ -140,9 +146,9 @@ describe 'Puppet::Type::Service::Provider::Init',
140
146
 
141
147
  describe "when checking valid paths" do
142
148
  it "should discard paths that do not exist" do
143
- expect(File).to receive(:directory?).with(paths[0]).and_return(false)
149
+ expect(Puppet::FileSystem).to receive(:directory?).with(paths[0]).and_return(false)
144
150
  expect(Puppet::FileSystem).to receive(:exist?).with(paths[0]).and_return(false)
145
- expect(File).to receive(:directory?).with(paths[1]).and_return(true)
151
+ expect(Puppet::FileSystem).to receive(:directory?).with(paths[1]).and_return(true)
146
152
 
147
153
  expect(provider.paths).to eq([paths[1]])
148
154
  end
@@ -150,7 +156,7 @@ describe 'Puppet::Type::Service::Provider::Init',
150
156
  it "should discard paths that are not directories" do
151
157
  paths.each do |path|
152
158
  expect(Puppet::FileSystem).to receive(:exist?).with(path).and_return(true)
153
- expect(File).to receive(:directory?).with(path).and_return(false)
159
+ expect(Puppet::FileSystem).to receive(:directory?).with(path).and_return(false)
154
160
  end
155
161
  expect(provider.paths).to be_empty
156
162
  end
@@ -158,7 +164,7 @@ describe 'Puppet::Type::Service::Provider::Init',
158
164
 
159
165
  describe "when searching for the init script" do
160
166
  before :each do
161
- paths.each {|path| expect(File).to receive(:directory?).with(path).and_return(true) }
167
+ paths.each {|path| expect(Puppet::FileSystem).to receive(:directory?).with(path).and_return(true) }
162
168
  end
163
169
 
164
170
  it "should be able to find the init script in the service path" do
@@ -191,9 +197,9 @@ describe 'Puppet::Type::Service::Provider::Init',
191
197
 
192
198
  describe "if the init script is present" do
193
199
  before :each do
194
- allow(File).to receive(:directory?).and_call_original
195
- allow(File).to receive(:directory?).with("/service/path").and_return(true)
196
- allow(File).to receive(:directory?).with("/alt/service/path").and_return(true)
200
+ allow(Puppet::FileSystem).to receive(:directory?).and_call_original
201
+ allow(Puppet::FileSystem).to receive(:directory?).with("/service/path").and_return(true)
202
+ allow(Puppet::FileSystem).to receive(:directory?).with("/alt/service/path").and_return(true)
197
203
  allow(Puppet::FileSystem).to receive(:exist?).with("/service/path/myservice").and_return(true)
198
204
  end
199
205
 
@@ -2,63 +2,56 @@ require 'spec_helper'
2
2
 
3
3
  describe 'Puppet::Type::Service::Provider::Openwrt',
4
4
  unless: Puppet::Util::Platform.windows? || Puppet::Util::Platform.jruby? do
5
+
5
6
  let(:provider_class) { Puppet::Type.type(:service).provider(:openwrt) }
6
7
 
7
8
  let(:resource) do
8
- resource = double('resource')
9
- allow(resource).to receive(:[]).and_return(nil)
10
- allow(resource).to receive(:[]).with(:name).and_return("myservice")
11
- allow(resource).to receive(:[]).with(:path).and_return(["/etc/init.d"])
12
-
13
- resource
9
+ Puppet::Type.type(:service).new(
10
+ :name => 'myservice',
11
+ :path => '/etc/init.d',
12
+ :hasrestart => true,
13
+ )
14
14
  end
15
15
 
16
16
  let(:provider) do
17
17
  provider = provider_class.new
18
- allow(provider).to receive(:get).with(:hasstatus).and_return(false)
19
-
18
+ provider.resource = resource
20
19
  provider
21
20
  end
22
21
 
23
22
  before :each do
24
- allow(resource).to receive(:provider).and_return(provider)
25
- provider.resource = resource
26
-
27
- allow(FileTest).to receive(:file?).with('/etc/rc.common').and_return(true)
28
- allow(FileTest).to receive(:executable?).with('/etc/rc.common').and_return(true)
23
+ resource.provider = provider
29
24
 
30
25
  # All OpenWrt tests operate on the init script directly. It must exist.
31
- allow(File).to receive(:directory?).and_call_original
32
- allow(File).to receive(:directory?).with('/etc/init.d').and_return(true)
26
+ allow(Puppet::FileSystem).to receive(:directory?).and_call_original
27
+ allow(Puppet::FileSystem).to receive(:directory?).with('/etc/init.d').and_return(true)
33
28
 
34
29
  allow(Puppet::FileSystem).to receive(:exist?).with('/etc/init.d/myservice').and_return(true)
35
- allow(FileTest).to receive(:file?).and_call_original
36
- allow(FileTest).to receive(:file?).with('/etc/init.d/myservice').and_return(true)
37
- allow(FileTest).to receive(:executable?).with('/etc/init.d/myservice').and_return(true)
30
+ allow(Puppet::FileSystem).to receive(:file?).and_call_original
31
+ allow(Puppet::FileSystem).to receive(:file?).with('/etc/init.d/myservice').and_return(true)
32
+ allow(Puppet::FileSystem).to receive(:executable?).with('/etc/init.d/myservice').and_return(true)
38
33
  end
39
34
 
40
- operatingsystem = 'openwrt'
41
- it "should be the default provider on #{operatingsystem}" do
42
- expect(Facter).to receive(:value).with(:operatingsystem).and_return(operatingsystem)
35
+ it "should be the default provider on 'openwrt'" do
36
+ expect(Facter).to receive(:value).with(:operatingsystem).and_return('openwrt')
43
37
  expect(provider_class.default?).to be_truthy
44
38
  end
45
39
 
46
40
  # test self.instances
47
41
  describe "when getting all service instances" do
48
- let(:services) {['dnsmasq', 'dropbear', 'firewall', 'led', 'puppet', 'uhttpd' ]}
42
+ let(:services) { ['dnsmasq', 'dropbear', 'firewall', 'led', 'puppet', 'uhttpd' ] }
49
43
 
50
44
  before :each do
51
45
  allow(Dir).to receive(:entries).and_call_original
52
46
  allow(Dir).to receive(:entries).with('/etc/init.d').and_return(services)
53
- allow(FileTest).to receive(:directory?).and_return(true)
54
- allow(FileTest).to receive(:executable?).and_return(true)
47
+ allow(Puppet::FileSystem).to receive(:executable?).and_return(true)
55
48
  end
56
49
 
57
50
  it "should return instances for all services" do
58
51
  services.each do |inst|
59
52
  expect(provider_class).to receive(:new).with(hash_including(:name => inst, :path => '/etc/init.d')).and_return("#{inst}_instance")
60
53
  end
61
- results = services.collect {|x| "#{x}_instance"}
54
+ results = services.collect { |x| "#{x}_instance"}
62
55
  expect(provider_class.instances).to eq(results)
63
56
  end
64
57
  end
@@ -82,14 +75,13 @@ describe 'Puppet::Type::Service::Provider::Openwrt',
82
75
 
83
76
  describe "when running #{method}" do
84
77
  it "should use any provided explicit command" do
85
- allow(resource).to receive(:[]).with(method).and_return("/user/specified/command")
86
- expect(provider).to receive(:execute).with(["/user/specified/command"], any_args)
78
+ resource[method] = '/user/specified/command'
79
+ expect(provider).to receive(:execute).with(['/user/specified/command'], any_args)
87
80
  provider.send(method)
88
81
  end
89
82
 
90
83
  it "should execute the init script with #{method} when no explicit command is provided" do
91
- allow(resource).to receive(:[]).with("has#{method}".intern).and_return(:true)
92
- expect(provider).to receive(:execute).with(['/etc/init.d/myservice', method ], any_args)
84
+ expect(provider).to receive(:execute).with(['/etc/init.d/myservice', method], any_args)
93
85
  provider.send(method)
94
86
  end
95
87
  end
@@ -50,8 +50,9 @@ describe 'Puppet::Type::Service::Provider::Redhat',
50
50
  @services = ['one', 'two', 'three', 'four', 'kudzu', 'functions', 'halt', 'killall', 'single', 'linuxconf', 'boot', 'reboot']
51
51
  @not_services = ['functions', 'halt', 'killall', 'single', 'linuxconf', 'reboot', 'boot']
52
52
  allow(Dir).to receive(:entries).and_return(@services)
53
- allow(FileTest).to receive(:directory?).and_return(true)
54
- allow(FileTest).to receive(:executable?).and_return(true)
53
+ allow(Puppet::FileSystem).to receive(:directory?).and_call_original
54
+ allow(Puppet::FileSystem).to receive(:directory?).with('/etc/init.d').and_return(true)
55
+ allow(Puppet::FileSystem).to receive(:executable?).and_return(true)
55
56
  end
56
57
 
57
58
  it "should return instances for all services" do
@@ -113,12 +113,21 @@ describe Puppet::SSL::SSLProvider do
113
113
  }.to raise_error(/can't modify frozen/)
114
114
  end
115
115
 
116
- it 'trusts system ca store' do
116
+ it 'trusts system ca store by default' do
117
117
  expect_any_instance_of(OpenSSL::X509::Store).to receive(:set_default_paths)
118
118
 
119
119
  subject.create_system_context(cacerts: [])
120
120
  end
121
121
 
122
+ it 'trusts an external ca store' do
123
+ path = tmpfile('system_cacerts')
124
+ File.write(path, cert_fixture('ca.pem').to_pem)
125
+
126
+ expect_any_instance_of(OpenSSL::X509::Store).to receive(:add_file).with(path)
127
+
128
+ subject.create_system_context(cacerts: [], path: path)
129
+ end
130
+
122
131
  it 'verifies peer' do
123
132
  sslctx = subject.create_system_context(cacerts: [])
124
133
  expect(sslctx.verify_peer).to eq(true)
@@ -135,6 +144,47 @@ describe Puppet::SSL::SSLProvider do
135
144
  expect(sslctx.private_key).to be_nil
136
145
  end
137
146
 
147
+ it 'includes the client cert and private key when requested' do
148
+ Puppet[:hostcert] = fixtures('ssl/signed.pem')
149
+ Puppet[:hostprivkey] = fixtures('ssl/signed-key.pem')
150
+ sslctx = subject.create_system_context(cacerts: [], include_client_cert: true)
151
+ expect(sslctx.client_cert).to be_an(OpenSSL::X509::Certificate)
152
+ expect(sslctx.private_key).to be_an(OpenSSL::PKey::RSA)
153
+ end
154
+
155
+ it 'ignores non-existent client cert and private key when requested' do
156
+ Puppet[:certname] = 'doesnotexist'
157
+ sslctx = subject.create_system_context(cacerts: [], include_client_cert: true)
158
+ expect(sslctx.client_cert).to be_nil
159
+ expect(sslctx.private_key).to be_nil
160
+ end
161
+
162
+ it 'warns if the client cert does not exist' do
163
+ Puppet[:certname] = 'missingcert'
164
+ Puppet[:hostprivkey] = fixtures('ssl/signed-key.pem')
165
+
166
+ expect(Puppet).to receive(:warning).with("Client certificate for 'missingcert' does not exist")
167
+ subject.create_system_context(cacerts: [], include_client_cert: true)
168
+ end
169
+
170
+ it 'warns if the private key does not exist' do
171
+ Puppet[:certname] = 'missingkey'
172
+ Puppet[:hostcert] = fixtures('ssl/signed.pem')
173
+
174
+ expect(Puppet).to receive(:warning).with("Private key for 'missingkey' does not exist")
175
+ subject.create_system_context(cacerts: [], include_client_cert: true)
176
+ end
177
+
178
+ it 'raises if client cert and private key are mismatched' do
179
+ Puppet[:hostcert] = fixtures('ssl/signed.pem')
180
+ Puppet[:hostprivkey] = fixtures('ssl/127.0.0.1-key.pem')
181
+
182
+ expect {
183
+ subject.create_system_context(cacerts: [], include_client_cert: true)
184
+ }.to raise_error(Puppet::SSL::SSLError,
185
+ "The certificate for 'CN=signed' does not match its private key")
186
+ end
187
+
138
188
  it 'trusts additional system certs' do
139
189
  path = tmpfile('system_cacerts')
140
190
  File.write(path, cert_fixture('ca.pem').to_pem)
@@ -448,6 +498,18 @@ describe Puppet::SSL::SSLProvider do
448
498
  sslctx = subject.create_context(**config)
449
499
  expect(sslctx.verify_peer).to eq(true)
450
500
  end
501
+
502
+ it 'does not trust the system ca store by default' do
503
+ expect_any_instance_of(OpenSSL::X509::Store).to receive(:set_default_paths).never
504
+
505
+ subject.create_context(**config)
506
+ end
507
+
508
+ it 'trusts the system ca store' do
509
+ expect_any_instance_of(OpenSSL::X509::Store).to receive(:set_default_paths)
510
+
511
+ subject.create_context(**config.merge(include_system_store: true))
512
+ end
451
513
  end
452
514
 
453
515
  context 'when loading an ssl context' do
@@ -528,6 +590,18 @@ describe Puppet::SSL::SSLProvider do
528
590
  subject.load_context(password: 'wrongpassword')
529
591
  }.to raise_error(Puppet::SSL::SSLError, /Failed to load private key for host 'signed': Could not parse PKey/)
530
592
  end
593
+
594
+ it 'does not trust the system ca store by default' do
595
+ expect_any_instance_of(OpenSSL::X509::Store).to receive(:set_default_paths).never
596
+
597
+ subject.load_context
598
+ end
599
+
600
+ it 'trusts the system ca store' do
601
+ expect_any_instance_of(OpenSSL::X509::Store).to receive(:set_default_paths)
602
+
603
+ subject.load_context(include_system_store: true)
604
+ end
531
605
  end
532
606
 
533
607
  context 'when verifying requests' do
@@ -27,6 +27,7 @@ describe Puppet::SSL::StateMachine, unless: Puppet::Util::Platform.jruby? do
27
27
  let(:refused_message) { %r{Connection refused|No connection could be made because the target machine actively refused it} }
28
28
 
29
29
  before(:each) do
30
+ Puppet[:daemonize] = false
30
31
  Puppet[:ssl_lockfile] = tmpfile('ssllock')
31
32
  allow(Kernel).to receive(:sleep)
32
33
  end
@@ -138,6 +138,57 @@ describe Puppet::Transaction::Persistence do
138
138
  persistence = Puppet::Transaction::Persistence.new
139
139
  expect(persistence.load.dig("File[/tmp/audit]", "parameters", "mtime", "system_value")).to contain_exactly(be_a(Time))
140
140
  end
141
+
142
+ it 'should load Regexp' do
143
+ write_state_file(<<~END)
144
+ system_value:
145
+ - !ruby/regexp /regexp/
146
+ END
147
+
148
+ persistence = Puppet::Transaction::Persistence.new
149
+ expect(persistence.load.dig("system_value")).to contain_exactly(be_a(Regexp))
150
+ end
151
+
152
+ it 'should load semantic puppet version' do
153
+ write_state_file(<<~END)
154
+ system_value:
155
+ - !ruby/object:SemanticPuppet::Version
156
+ major: 1
157
+ minor: 0
158
+ patch: 0
159
+ prerelease:
160
+ build:
161
+ END
162
+
163
+ persistence = Puppet::Transaction::Persistence.new
164
+ expect(persistence.load.dig("system_value")).to contain_exactly(be_a(SemanticPuppet::Version))
165
+ end
166
+
167
+ it 'should load puppet time related objects' do
168
+ write_state_file(<<~END)
169
+ system_value:
170
+ - !ruby/object:Puppet::Pops::Time::Timestamp
171
+ nsecs: 1638316135955087259
172
+ - !ruby/object:Puppet::Pops::Time::TimeData
173
+ nsecs: 1495789430910161286
174
+ - !ruby/object:Puppet::Pops::Time::Timespan
175
+ nsecs: 1495789430910161286
176
+ END
177
+
178
+ persistence = Puppet::Transaction::Persistence.new
179
+ expect(persistence.load.dig("system_value")).to contain_exactly(be_a(Puppet::Pops::Time::Timestamp), be_a(Puppet::Pops::Time::TimeData), be_a(Puppet::Pops::Time::Timespan))
180
+ end
181
+
182
+ it 'should load binary objects' do
183
+ write_state_file(<<~END)
184
+ system_value:
185
+ - !ruby/object:Puppet::Pops::Types::PBinaryType::Binary
186
+ binary_buffer: ''
187
+ END
188
+
189
+ persistence = Puppet::Transaction::Persistence.new
190
+ expect(persistence.load.dig("system_value")).to contain_exactly(be_a(Puppet::Pops::Types::PBinaryType::Binary))
191
+ end
141
192
  end
142
193
  end
143
194