puppet 6.13.0 → 6.14.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 (118) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +7 -13
  3. data/Gemfile.lock +6 -6
  4. data/README.md +15 -22
  5. data/lib/puppet.rb +1 -1
  6. data/lib/puppet/application/agent.rb +9 -11
  7. data/lib/puppet/application/describe.rb +7 -5
  8. data/lib/puppet/application/device.rb +2 -2
  9. data/lib/puppet/application/filebucket.rb +14 -1
  10. data/lib/puppet/application/ssl.rb +1 -1
  11. data/lib/puppet/configurer.rb +30 -41
  12. data/lib/puppet/configurer/plugin_handler.rb +10 -1
  13. data/lib/puppet/defaults.rb +7 -1
  14. data/lib/puppet/face/plugin.rb +1 -1
  15. data/lib/puppet/functions/eyaml_lookup_key.rb +13 -8
  16. data/lib/puppet/http.rb +1 -0
  17. data/lib/puppet/http/client.rb +69 -34
  18. data/lib/puppet/http/resolver/server_list.rb +2 -2
  19. data/lib/puppet/http/resolver/settings.rb +1 -1
  20. data/lib/puppet/http/resolver/srv.rb +1 -1
  21. data/lib/puppet/http/response.rb +6 -1
  22. data/lib/puppet/http/service.rb +30 -11
  23. data/lib/puppet/http/service/ca.rb +8 -8
  24. data/lib/puppet/http/service/compiler.rb +41 -10
  25. data/lib/puppet/http/service/file_server.rb +40 -20
  26. data/lib/puppet/http/service/report.rb +12 -15
  27. data/lib/puppet/http/session.rb +39 -1
  28. data/lib/puppet/indirector/catalog/rest.rb +33 -0
  29. data/lib/puppet/indirector/facts/rest.rb +41 -0
  30. data/lib/puppet/indirector/file_content/rest.rb +30 -0
  31. data/lib/puppet/indirector/file_metadata/rest.rb +50 -0
  32. data/lib/puppet/indirector/node/rest.rb +23 -0
  33. data/lib/puppet/indirector/report/rest.rb +19 -0
  34. data/lib/puppet/indirector/rest.rb +6 -0
  35. data/lib/puppet/indirector/status/rest.rb +17 -0
  36. data/lib/puppet/loaders.rb +6 -0
  37. data/lib/puppet/network/http/base_pool.rb +1 -1
  38. data/lib/puppet/network/http/pool.rb +6 -1
  39. data/lib/puppet/provider/group/groupadd.rb +9 -4
  40. data/lib/puppet/runtime.rb +8 -1
  41. data/lib/puppet/settings.rb +2 -0
  42. data/lib/puppet/settings/http_extra_headers_setting.rb +25 -0
  43. data/lib/puppet/ssl/state_machine.rb +4 -0
  44. data/lib/puppet/test/test_helper.rb +3 -1
  45. data/lib/puppet/type/file.rb +13 -0
  46. data/lib/puppet/type/file/source.rb +47 -58
  47. data/lib/puppet/version.rb +1 -1
  48. data/locales/puppet.pot +167 -160
  49. data/man/man5/puppet.conf.5 +11 -3
  50. data/man/man8/puppet-agent.8 +6 -6
  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 +2 -2
  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 +17 -2
  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 +1 -1
  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 +2 -2
  73. data/man/man8/puppet-status.8 +1 -1
  74. data/man/man8/puppet.8 +2 -2
  75. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_md5/should_fetch_if_not_on_the_local_disk.yml +1 -67
  76. 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 +1 -69
  77. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_md5/should_update_if_content_differs_on_disk.yml +1 -69
  78. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_mtime/should_fetch_if_mtime_is_older_on_disk.yml +1 -67
  79. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_mtime/should_fetch_if_no_header_specified.yml +1 -65
  80. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_mtime/should_fetch_if_not_on_the_local_disk.yml +1 -67
  81. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_mtime/should_not_update_if_mtime_is_newer_on_disk.yml +1 -67
  82. data/spec/integration/faces/plugin_spec.rb +3 -1
  83. data/spec/integration/http/client_spec.rb +11 -0
  84. data/spec/integration/network/http_pool_spec.rb +9 -1
  85. data/spec/unit/application/describe_spec.rb +88 -50
  86. data/spec/unit/configurer/plugin_handler_spec.rb +36 -19
  87. data/spec/unit/configurer_spec.rb +16 -14
  88. data/spec/unit/face/plugin_spec.rb +12 -10
  89. data/spec/unit/functions/lookup_spec.rb +13 -0
  90. data/spec/unit/http/client_spec.rb +172 -1
  91. data/spec/unit/http/resolver_spec.rb +14 -2
  92. data/spec/unit/http/response_spec.rb +69 -0
  93. data/spec/unit/http/service/ca_spec.rb +28 -9
  94. data/spec/unit/http/service/compiler_spec.rb +151 -24
  95. data/spec/unit/http/service/file_server_spec.rb +65 -8
  96. data/spec/unit/http/service/report_spec.rb +17 -8
  97. data/spec/unit/http/service_spec.rb +92 -3
  98. data/spec/unit/http/session_spec.rb +104 -1
  99. data/spec/unit/indirector/catalog/rest_spec.rb +59 -2
  100. data/spec/unit/indirector/facts/rest_spec.rb +79 -24
  101. data/spec/unit/indirector/file_content/rest_spec.rb +53 -2
  102. data/spec/unit/indirector/file_metadata/rest_spec.rb +109 -2
  103. data/spec/unit/indirector/node/rest_spec.rb +57 -2
  104. data/spec/unit/indirector/report/rest_spec.rb +58 -51
  105. data/spec/unit/indirector/resource/ral_spec.rb +7 -8
  106. data/spec/unit/indirector/status/rest_spec.rb +43 -2
  107. data/spec/unit/network/http/pool_spec.rb +57 -11
  108. data/spec/unit/provider/group/groupadd_spec.rb +22 -8
  109. data/spec/unit/settings/autosign_setting_spec.rb +1 -1
  110. data/spec/unit/settings/http_extra_headers_spec.rb +64 -0
  111. data/spec/unit/ssl/state_machine_spec.rb +10 -0
  112. data/spec/unit/transaction_spec.rb +0 -2
  113. data/spec/unit/type/file/ensure_spec.rb +1 -2
  114. data/spec/unit/type/file/source_spec.rb +86 -35
  115. data/spec/unit/util/at_fork_spec.rb +1 -0
  116. data/spec/unit/util/pidlock_spec.rb +36 -24
  117. metadata +7 -3
  118. data/COMMITTERS.md +0 -244
@@ -3,42 +3,97 @@ require 'spec_helper'
3
3
  require 'puppet/indirector/facts/rest'
4
4
 
5
5
  describe Puppet::Node::Facts::Rest do
6
- it "should be a sublcass of Puppet::Indirector::REST" do
7
- expect(Puppet::Node::Facts::Rest.superclass).to equal(Puppet::Indirector::REST)
6
+ let(:certname) { 'ziggy' }
7
+ let(:uri) { %r{/puppet/v3/facts/ziggy} }
8
+ let(:facts) { Puppet::Node::Facts.new(certname, test_fact: 'test value') }
9
+
10
+ before do
11
+ Puppet[:server] = 'compiler.example.com'
12
+ Puppet[:masterport] = 8140
13
+
14
+ described_class.indirection.terminus_class = :rest
8
15
  end
9
16
 
10
- let(:model) { Puppet::Node::Facts }
11
- before(:each) { model.indirection.terminus_class = :rest }
17
+ describe '#find' do
18
+ let(:formatter) { Puppet::Network::FormatHandler.format(:json) }
19
+
20
+ def facts_response(facts)
21
+ { body: formatter.render(facts), headers: {'Content-Type' => formatter.mime } }
22
+ end
23
+
24
+ it 'finds facts' do
25
+ stub_request(:get, uri).to_return(**facts_response(facts))
26
+
27
+ expect(described_class.indirection.find(certname)).to be_a(Puppet::Node::Facts)
28
+ end
29
+
30
+ it "serializes the environment" do
31
+ stub_request(:get, uri)
32
+ .with(query: hash_including('environment' => 'outerspace'))
33
+ .to_return(**facts_response(facts))
34
+
35
+ described_class.indirection.find(certname, environment: Puppet::Node::Environment.remote('outerspace'))
36
+ end
37
+
38
+ it 'returns nil if the facts do not exist' do
39
+ stub_request(:get, uri).to_return(status: 404, headers: { 'Content-Type' => 'application/json' }, body: "{}")
40
+
41
+ expect(described_class.indirection.find(certname)).to be_nil
42
+ end
43
+
44
+ it 'raises if fail_on_404 is specified' do
45
+ stub_request(:get, uri).to_return(status: 404, headers: { 'Content-Type' => 'application/json' }, body: "{}")
46
+
47
+ expect{
48
+ described_class.indirection.find(certname, fail_on_404: true)
49
+ }.to raise_error(Puppet::Error, %r{Find /puppet/v3/facts/ziggy resulted in 404 with the message: {}})
50
+ end
51
+
52
+ it 'raises Net::HTTPError on 500' do
53
+ stub_request(:get, uri).to_return(status: 500)
12
54
 
13
- def mock_response(code, body, content_type='text/plain', encoding=nil)
14
- obj = double('http response', :code => code.to_s, :body => body)
15
- allow(obj).to receive(:[]).with('content-type').and_return(content_type)
16
- allow(obj).to receive(:[]).with('content-encoding').and_return(encoding)
17
- allow(obj).to receive(:[]).with(Puppet::Network::HTTP::HEADER_PUPPET_VERSION).and_return(Puppet.version)
18
- obj
55
+ expect{
56
+ described_class.indirection.find(certname)
57
+ }.to raise_error(Net::HTTPError, %r{Error 500 on SERVER: })
58
+ end
19
59
  end
20
60
 
21
61
  describe '#save' do
22
- subject { model.indirection.terminus(:rest) }
62
+ it 'returns nil on success' do
63
+ stub_request(:put, %r{/puppet/v3/facts})
64
+ .to_return(status: 200, headers: { 'Content-Type' => 'application/json'}, body: '')
23
65
 
24
- let(:connection) { double('mock http connection', :verify_callback= => nil) }
25
- let(:node_name) { 'puppet.node.test' }
26
- let(:data) { model.new(node_name, {test_fact: 'test value'}) }
27
- let(:request) { Puppet::Indirector::Request.new(:facts, :save, node_name, data) }
66
+ expect(described_class.indirection.save(facts)).to be_nil
67
+ end
68
+
69
+ it "serializes the environment" do
70
+ stub_request(:put, uri)
71
+ .with(query: hash_including('environment' => 'outerspace'))
72
+ .to_return(status: 200, headers: { 'Content-Type' => 'application/json'}, body: '')
73
+
74
+ described_class.indirection.save(facts, nil, environment: Puppet::Node::Environment.remote('outerspace'))
75
+ end
28
76
 
29
- before :each do
30
- allow(subject).to receive(:network).and_return(connection)
77
+ it 'raises if options are specified' do
78
+ expect {
79
+ described_class.indirection.save(facts, nil, foo: :bar)
80
+ }.to raise_error(ArgumentError, /PUT does not accept options/)
31
81
  end
32
82
 
33
- context 'when a 404 response is received' do
34
- let(:response) { mock_response(404, '{}', 'test/json') }
83
+ it 'raises with HTTP 404' do
84
+ stub_request(:put, %r{/puppet/v3/facts}).to_return(status: 404)
85
+
86
+ expect {
87
+ described_class.indirection.save(facts)
88
+ }.to raise_error(Net::HTTPError, /Error 404 on SERVER/)
89
+ end
35
90
 
36
- before(:each) { expect(connection).to receive(:put).and_return(response) }
91
+ it 'raises with HTTP 500' do
92
+ stub_request(:put, %r{/puppet/v3/facts}).to_return(status: 500)
37
93
 
38
- it 'riases with HTTP 404' do
39
- expect{ subject.save(request) }.to raise_error(Net::HTTPError,
40
- /Error 404 on SERVER/)
41
- end
94
+ expect {
95
+ described_class.indirection.save(facts)
96
+ }.to raise_error(Net::HTTPError, /Error 500 on SERVER/)
42
97
  end
43
98
  end
44
99
  end
@@ -3,9 +3,60 @@ require 'spec_helper'
3
3
  require 'puppet/indirector/file_content/rest'
4
4
 
5
5
  describe Puppet::Indirector::FileContent::Rest do
6
- it "should add the node's cert name to the arguments"
6
+ let(:certname) { 'ziggy' }
7
+ let(:uri) { %r{/puppet/v3/file_content/:mount/path/to/file} }
8
+ let(:key) { "puppet:///:mount/path/to/file" }
7
9
 
8
- it "should set the content type to text/plain"
10
+ before :each do
11
+ described_class.indirection.terminus_class = :rest
12
+ end
13
+
14
+ def file_content_response
15
+ {body: "some content", headers: { 'Content-Type' => 'application/octet-stream' } }
16
+ end
17
+
18
+ it "returns content as a binary string" do
19
+ stub_request(:get, uri).to_return(status: 200, **file_content_response)
20
+
21
+ file_content = described_class.indirection.find(key)
22
+ expect(file_content.content.encoding).to eq(Encoding::BINARY)
23
+ expect(file_content.content).to eq('some content')
24
+ end
25
+
26
+ it "URL encodes special characters" do
27
+ stub_request(:get, %r{/puppet/v3/file_content/:mount/path%20to%20file}).to_return(status: 200, **file_content_response)
28
+
29
+ described_class.indirection.find('puppet:///:mount/path to file')
30
+ end
31
+
32
+ it "returns nil if the content doesn't exist" do
33
+ stub_request(:get, uri).to_return(status: 404)
34
+
35
+ expect(described_class.indirection.find(key)).to be_nil
36
+ end
37
+
38
+ it "raises if fail_on_404 is true" do
39
+ stub_request(:get, uri).to_return(status: 404, headers: { 'Content-Type' => 'application/json'}, body: "{}")
40
+
41
+ expect {
42
+ described_class.indirection.find(key, fail_on_404: true)
43
+ }.to raise_error(Puppet::Error, %r{Find /puppet/v3/file_content/:mount/path/to/file resulted in 404 with the message: {}})
44
+ end
45
+
46
+ it "raises an error on HTTP 500" do
47
+ stub_request(:get, uri).to_return(status: 500, headers: { 'Content-Type' => 'application/json'}, body: "{}")
48
+
49
+ expect {
50
+ described_class.indirection.find(key)
51
+ }.to raise_error(Net::HTTPError, %r{Error 500 on SERVER: })
52
+ end
53
+
54
+ it "connects to a specific host" do
55
+ stub_request(:get, %r{https://example.com:8140/puppet/v3/file_content/:mount/path/to/file})
56
+ .to_return(status: 200, **file_content_response)
57
+
58
+ described_class.indirection.find("puppet://example.com:8140/:mount/path/to/file")
59
+ end
9
60
 
10
61
  it "should use the :fileserver SRV service" do
11
62
  expect(Puppet::Indirector::FileContent::Rest.srv_service).to eq(:fileserver)
@@ -3,8 +3,115 @@ require 'spec_helper'
3
3
  require 'puppet/indirector/file_metadata'
4
4
  require 'puppet/indirector/file_metadata/rest'
5
5
 
6
- describe "Puppet::Indirector::Metadata::Rest" do
7
- it "should add the node's cert name to the arguments"
6
+ describe Puppet::Indirector::FileMetadata::Rest do
7
+ let(:certname) { 'ziggy' }
8
+ let(:formatter) { Puppet::Network::FormatHandler.format(:json) }
9
+
10
+ before :each do
11
+ described_class.indirection.terminus_class = :rest
12
+ end
13
+
14
+ def metadata_response(metadata)
15
+ { body: formatter.render(metadata), headers: {'Content-Type' => formatter.mime } }
16
+ end
17
+
18
+ context "when finding" do
19
+ let(:uri) { %r{/puppet/v3/file_metadata/:mount/path/to/file} }
20
+ let(:key) { "puppet:///:mount/path/to/file" }
21
+ let(:metadata) { Puppet::FileServing::Metadata.new('/path/to/file') }
22
+
23
+ it "returns file metadata" do
24
+ stub_request(:get, uri)
25
+ .to_return(status: 200, **metadata_response(metadata))
26
+
27
+ result = described_class.indirection.find(key)
28
+ expect(result.path).to eq('/path/to/file')
29
+ end
30
+
31
+ it "URL encodes special characters" do
32
+ stub_request(:get, %r{/puppet/v3/file_metadata/:mount/path%20to%20file})
33
+ .to_return(status: 200, **metadata_response(metadata))
34
+
35
+ described_class.indirection.find('puppet:///:mount/path to file')
36
+ end
37
+
38
+ it "returns nil if the content doesn't exist" do
39
+ stub_request(:get, uri).to_return(status: 404)
40
+
41
+ expect(described_class.indirection.find(key)).to be_nil
42
+ end
43
+
44
+ it "raises if fail_on_404 is true" do
45
+ stub_request(:get, uri).to_return(status: 404, headers: { 'Content-Type' => 'application/json'}, body: "{}")
46
+
47
+ expect {
48
+ described_class.indirection.find(key, fail_on_404: true)
49
+ }.to raise_error(Puppet::Error, %r{Find /puppet/v3/file_metadata/:mount/path/to/file resulted in 404 with the message: {}})
50
+ end
51
+
52
+ it "raises an error on HTTP 500" do
53
+ stub_request(:get, uri).to_return(status: 500, headers: { 'Content-Type' => 'application/json'}, body: "{}")
54
+
55
+ expect {
56
+ described_class.indirection.find(key)
57
+ }.to raise_error(Net::HTTPError, %r{Error 500 on SERVER: })
58
+ end
59
+
60
+ it "connects to a specific host" do
61
+ stub_request(:get, %r{https://example.com:8140/puppet/v3/file_metadata/:mount/path/to/file})
62
+ .to_return(status: 200, **metadata_response(metadata))
63
+
64
+ described_class.indirection.find("puppet://example.com:8140/:mount/path/to/file")
65
+ end
66
+ end
67
+
68
+ context "when searching" do
69
+ let(:uri) { %r{/puppet/v3/file_metadatas/:mount/path/to/dir} }
70
+ let(:key) { "puppet:///:mount/path/to/dir" }
71
+ let(:metadatas) { [Puppet::FileServing::Metadata.new('/path/to/dir')] }
72
+
73
+ it "returns an array of file metadata" do
74
+ stub_request(:get, uri)
75
+ .to_return(status: 200, **metadata_response(metadatas))
76
+
77
+ result = described_class.indirection.search(key)
78
+ expect(result.first.path).to eq('/path/to/dir')
79
+ end
80
+
81
+ it "URL encodes special characters" do
82
+ stub_request(:get, %r{/puppet/v3/file_metadatas/:mount/path%20to%20dir})
83
+ .to_return(status: 200, **metadata_response(metadatas))
84
+
85
+ described_class.indirection.search('puppet:///:mount/path to dir')
86
+ end
87
+
88
+ it "returns an empty array if the metadata doesn't exist" do
89
+ stub_request(:get, uri).to_return(status: 404)
90
+
91
+ expect(described_class.indirection.search(key)).to eq([])
92
+ end
93
+
94
+ it "returns an empty array if the metadata doesn't exist and fail_on_404 is true" do
95
+ stub_request(:get, uri).to_return(status: 404, headers: { 'Content-Type' => 'application/json'}, body: "{}")
96
+
97
+ expect(described_class.indirection.search(key, fail_on_404: true)).to eq([])
98
+ end
99
+
100
+ it "raises an error on HTTP 500" do
101
+ stub_request(:get, uri).to_return(status: 500, headers: { 'Content-Type' => 'application/json'}, body: "{}")
102
+
103
+ expect {
104
+ described_class.indirection.search(key)
105
+ }.to raise_error(Net::HTTPError, %r{Error 500 on SERVER: })
106
+ end
107
+
108
+ it "connects to a specific host" do
109
+ stub_request(:get, %r{https://example.com:8140/puppet/v3/file_metadatas/:mount/path/to/dir})
110
+ .to_return(status: 200, **metadata_response(metadatas))
111
+
112
+ described_class.indirection.search("puppet://example.com:8140/:mount/path/to/dir")
113
+ end
114
+ end
8
115
 
9
116
  it "should use the :fileserver SRV service" do
10
117
  expect(Puppet::Indirector::FileMetadata::Rest.srv_service).to eq(:fileserver)
@@ -3,9 +3,64 @@ require 'spec_helper'
3
3
  require 'puppet/indirector/node/rest'
4
4
 
5
5
  describe Puppet::Node::Rest do
6
- before do
7
- @searcher = Puppet::Node::Rest.new
6
+ let(:certname) { 'ziggy' }
7
+ let(:uri) { %r{/puppet/v3/node/ziggy} }
8
+ let(:formatter) { Puppet::Network::FormatHandler.format(:json) }
9
+ let(:node) { Puppet::Node.new(certname) }
10
+
11
+ before :each do
12
+ Puppet[:server] = 'compiler.example.com'
13
+ Puppet[:masterport] = 8140
14
+
15
+ described_class.indirection.terminus_class = :rest
16
+ end
17
+
18
+ def node_response(node)
19
+ { body: formatter.render(node), headers: {'Content-Type' => formatter.mime } }
8
20
  end
9
21
 
22
+ it 'finds a node' do
23
+ stub_request(:get, uri).to_return(**node_response(node))
24
+
25
+ expect(described_class.indirection.find(certname)).to be_a(Puppet::Node)
26
+ end
27
+
28
+ it "serializes the environment" do
29
+ stub_request(:get, uri)
30
+ .with(query: hash_including('environment' => 'outerspace'))
31
+ .to_return(**node_response(node))
32
+
33
+ described_class.indirection.find(certname, environment: Puppet::Node::Environment.remote('outerspace'))
34
+ end
35
+
36
+ it 'preserves the node environment_name as a symbol' do
37
+ env = Puppet::Node::Environment.remote('outerspace')
38
+ node = Puppet::Node.new(certname, environment: env)
39
+
40
+ stub_request(:get, uri).to_return(**node_response(node))
10
41
 
42
+ expect(described_class.indirection.find(certname).environment_name).to eq(:outerspace)
43
+ end
44
+
45
+ it 'returns nil if the node does not exist' do
46
+ stub_request(:get, uri).to_return(status: 404, headers: { 'Content-Type' => 'application/json' }, body: "{}")
47
+
48
+ expect(described_class.indirection.find(certname)).to be_nil
49
+ end
50
+
51
+ it 'raises if fail_on_404 is specified' do
52
+ stub_request(:get, uri).to_return(status: 404, headers: { 'Content-Type' => 'application/json' }, body: "{}")
53
+
54
+ expect{
55
+ described_class.indirection.find(certname, fail_on_404: true)
56
+ }.to raise_error(Puppet::Error, %r{Find /puppet/v3/node/ziggy resulted in 404 with the message: {}})
57
+ end
58
+
59
+ it 'raises Net::HTTPError on 500' do
60
+ stub_request(:get, uri).to_return(status: 500)
61
+
62
+ expect{
63
+ described_class.indirection.find(certname)
64
+ }.to raise_error(Net::HTTPError, %r{Error 500 on SERVER: })
65
+ end
11
66
  end
@@ -3,8 +3,21 @@ require 'spec_helper'
3
3
  require 'puppet/indirector/report/rest'
4
4
 
5
5
  describe Puppet::Transaction::Report::Rest do
6
- it "should be a subclass of Puppet::Indirector::REST" do
7
- expect(Puppet::Transaction::Report::Rest.superclass).to equal(Puppet::Indirector::REST)
6
+ let(:certname) { 'ziggy' }
7
+ let(:uri) { %r{/puppet/v3/report/ziggy} }
8
+ let(:formatter) { Puppet::Network::FormatHandler.format(:json) }
9
+ let(:report) do
10
+ report = Puppet::Transaction::Report.new
11
+ report.host = certname
12
+ report
13
+ end
14
+
15
+ before(:each) do
16
+ described_class.indirection.terminus_class = :rest
17
+ end
18
+
19
+ def report_response
20
+ { body: formatter.render(["store", "http"]), headers: {'Content-Type' => formatter.mime } }
8
21
  end
9
22
 
10
23
  it "should use the :report_server setting in preference to :server" do
@@ -22,71 +35,65 @@ describe Puppet::Transaction::Report::Rest do
22
35
  expect(Puppet::Transaction::Report::Rest.srv_service).to eq(:report)
23
36
  end
24
37
 
25
- let(:model) { Puppet::Transaction::Report }
26
- let(:terminus_class) { Puppet::Transaction::Report::Rest }
27
- let(:terminus) { model.indirection.terminus(:rest) }
28
- let(:indirection) { model.indirection }
38
+ it "saves a report " do
39
+ stub_request(:put, uri)
40
+ .to_return(status: 200, **report_response)
29
41
 
30
- before(:each) do
31
- Puppet::Transaction::Report.indirection.terminus_class = :rest
42
+ described_class.indirection.save(report)
32
43
  end
33
44
 
34
- def mock_response(code, body, content_type='text/plain', encoding=nil)
35
- obj = double('http 200 ok', :code => code.to_s, :body => body)
36
- allow(obj).to receive(:[]).with('content-type').and_return(content_type)
37
- allow(obj).to receive(:[]).with('content-encoding').and_return(encoding)
38
- allow(obj).to receive(:[]).with(Puppet::Network::HTTP::HEADER_PUPPET_VERSION).and_return(Puppet.version)
39
- obj
45
+ it "serializes the environment" do
46
+ stub_request(:put, uri)
47
+ .with(query: hash_including('environment' => 'outerspace'))
48
+ .to_return(**report_response)
49
+
50
+ described_class.indirection.save(report, nil, environment: Puppet::Node::Environment.remote('outerspace'))
40
51
  end
41
52
 
42
- def save_request(key, instance, options={})
43
- Puppet::Indirector::Request.new(:report, :find, key, instance, options)
53
+ it "deserializes the response as an array of report processor names" do
54
+ stub_request(:put, %r{/puppet/v3/report})
55
+ .to_return(status: 200, **report_response)
56
+
57
+ expect(described_class.indirection.save(report)).to eq(["store", "http"])
44
58
  end
45
59
 
46
- describe "#save" do
47
- let(:response) { mock_response(200, 'body') }
48
- let(:connection) { double('mock http connection', :put => response, :verify_callback= => nil) }
49
- let(:instance) { model.new('the thing', 'some contents') }
50
- let(:request) { save_request(instance.name, instance) }
51
- let(:body) { ["store", "http"].to_pson }
60
+ it "returns nil if the node does not exist" do
61
+ stub_request(:put, uri)
62
+ .to_return(status: 404, headers: { 'Content-Type' => 'application/json' }, body: "{}")
52
63
 
53
- before :each do
54
- allow(terminus).to receive(:network).and_return(connection)
55
- end
64
+ expect(described_class.indirection.save(report)).to be_nil
65
+ end
56
66
 
57
- it "deserializes the response as an array of report processor names" do
58
- response = mock_response('200', body, 'text/pson')
59
- expect(connection).to receive(:put).and_return(response)
67
+ it "parses charset from response content-type" do
68
+ stub_request(:put, uri)
69
+ .to_return(status: 200, body: JSON.dump(["store"]), headers: { 'Content-Type' => 'application/json;charset=utf-8' })
60
70
 
61
- expect(terminus.save(request)).to eq(["store", "http"])
62
- end
71
+ expect(described_class.indirection.save(report)).to eq(["store"])
72
+ end
63
73
 
64
- describe "when handling the response" do
65
- describe "when the server major version is less than 5" do
66
- it "raises if the save fails and we're not using pson" do
67
- Puppet[:preferred_serialization_format] = "json"
74
+ describe "when the server major version is less than 5" do
75
+ it "raises if the save fails and we're not using pson" do
76
+ Puppet[:preferred_serialization_format] = "json"
68
77
 
69
- response = mock_response('500', '{}', 'text/pson')
70
- allow(response).to receive(:[]).with(Puppet::Network::HTTP::HEADER_PUPPET_VERSION).and_return("4.10.1")
71
- expect(connection).to receive(:put).and_return(response)
78
+ stub_request(:put, uri)
79
+ .to_return(status: 500,
80
+ headers: { 'Content-Type' => 'text/pson', Puppet::Network::HTTP::HEADER_PUPPET_VERSION => '4.10.1' })
72
81
 
73
- expect {
74
- terminus.save(request)
75
- }.to raise_error(Puppet::Error, /Server version 4.10.1 does not accept reports in 'json'/)
76
- end
82
+ expect {
83
+ described_class.indirection.save(report)
84
+ }.to raise_error(Puppet::Error, /To submit reports to a server running puppetserver 4.10.1, set preferred_serialization_format to pson/)
85
+ end
77
86
 
78
- it "raises with HTTP 500 if the save fails and we're already using pson" do
79
- Puppet[:preferred_serialization_format] = "pson"
87
+ it "raises with HTTP 500 if the save fails and we're already using pson" do
88
+ Puppet[:preferred_serialization_format] = "pson"
80
89
 
81
- response = mock_response('500', '{}', 'text/pson')
82
- allow(response).to receive(:[]).with(Puppet::Network::HTTP::HEADER_PUPPET_VERSION).and_return("4.10.1")
83
- expect(connection).to receive(:put).and_return(response)
90
+ stub_request(:put, uri)
91
+ .to_return(status: 500,
92
+ headers: { 'Content-Type' => 'text/pson', Puppet::Network::HTTP::HEADER_PUPPET_VERSION => '4.10.1' })
84
93
 
85
- expect {
86
- terminus.save(request)
87
- }.to raise_error(Net::HTTPError, /Error 500 on SERVER/)
88
- end
89
- end
94
+ expect {
95
+ described_class.indirection.save(report)
96
+ }.to raise_error(Net::HTTPError, /Error 500 on SERVER/)
90
97
  end
91
98
  end
92
99
  end