hieracles 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -0
  3. data/Gemfile +2 -0
  4. data/README.md +54 -8
  5. data/bin/hc +12 -6
  6. data/bin/ppdb +42 -0
  7. data/hc.1 +50 -8
  8. data/lib/hieracles.rb +2 -2
  9. data/lib/hieracles/config.rb +31 -19
  10. data/lib/hieracles/format.rb +4 -0
  11. data/lib/hieracles/formats/console.rb +49 -16
  12. data/lib/hieracles/formats/csv.rb +12 -8
  13. data/lib/hieracles/formats/json.rb +19 -6
  14. data/lib/hieracles/formats/plain.rb +24 -3
  15. data/lib/hieracles/formats/rawyaml.rb +4 -0
  16. data/lib/hieracles/formats/yaml.rb +4 -0
  17. data/lib/hieracles/node.rb +55 -10
  18. data/lib/hieracles/notification.rb +31 -0
  19. data/lib/hieracles/options/hc.rb +109 -0
  20. data/lib/hieracles/options/ppdb.rb +32 -0
  21. data/lib/hieracles/optparse.rb +4 -43
  22. data/lib/hieracles/puppetdb.rb +12 -0
  23. data/lib/hieracles/puppetdb/apierror.rb +10 -0
  24. data/lib/hieracles/puppetdb/client.rb +63 -0
  25. data/lib/hieracles/puppetdb/filter.rb +15 -0
  26. data/lib/hieracles/puppetdb/fixsslconnectionadapter.rb +25 -0
  27. data/lib/hieracles/puppetdb/query.rb +79 -0
  28. data/lib/hieracles/puppetdb/request.rb +44 -0
  29. data/lib/hieracles/puppetdb/response.rb +14 -0
  30. data/ppdb.1 +158 -0
  31. data/spec/files/config.yml +2 -0
  32. data/spec/files/config_withdb.yml +9 -0
  33. data/spec/files/facts.json +110 -0
  34. data/spec/files/facts.yaml +103 -0
  35. data/spec/files/hiera_columns.yaml +16 -0
  36. data/spec/files/hiera_deep.yaml +17 -0
  37. data/spec/files/hiera_deeper.yaml +17 -0
  38. data/spec/files/ssl/bad-ca.crt +1 -0
  39. data/spec/files/ssl/bad-cert.crt +1 -0
  40. data/spec/files/ssl/bad-key.pem +1 -0
  41. data/spec/files/ssl/ca.crt +16 -0
  42. data/spec/files/ssl/cert.crt +16 -0
  43. data/spec/files/ssl/key-pass.pem +18 -0
  44. data/spec/files/ssl/key.pem +15 -0
  45. data/spec/lib/config_spec.rb +51 -11
  46. data/spec/lib/format_spec.rb +5 -0
  47. data/spec/lib/formats/console_spec.rb +24 -3
  48. data/spec/lib/formats/csv_spec.rb +15 -0
  49. data/spec/lib/formats/json_spec.rb +22 -2
  50. data/spec/lib/formats/plain_spec.rb +23 -3
  51. data/spec/lib/formats/rawyaml_spec.rb +13 -0
  52. data/spec/lib/formats/yaml_spec.rb +138 -48
  53. data/spec/lib/hiera_spec.rb +0 -1
  54. data/spec/lib/hieracles_spec.rb +8 -0
  55. data/spec/lib/interpolate_spec.rb +49 -0
  56. data/spec/lib/node_spec.rb +50 -9
  57. data/spec/lib/notification_spec.rb +29 -0
  58. data/spec/lib/options/hc_spec.rb +82 -0
  59. data/spec/lib/optparse_spec.rb +7 -7
  60. data/spec/lib/puppetdb/apierror_spec.rb +11 -0
  61. data/spec/lib/puppetdb/client_spec.rb +64 -0
  62. data/spec/lib/puppetdb/fixsslconnectionadapter_spec.rb +107 -0
  63. data/spec/lib/puppetdb/query_spec.rb +39 -0
  64. data/spec/lib/puppetdb/request_spec.rb +61 -0
  65. data/spec/lib/puppetdb/response_spec.rb +13 -0
  66. data/spec/spec_helper.rb +4 -4
  67. metadata +133 -30
  68. data/Rakefile +0 -14
  69. data/hieracles.gemspec +0 -90
  70. data/lib/hieracles/help.rb +0 -38
  71. data/spec/lib/help_spec.rb +0 -8
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hieracles::Interpolate do
4
+ include Hieracles::Interpolate
5
+
6
+ describe ".parse" do
7
+ let(:input) { StringIO.new }
8
+ let(:output) { StringIO.new }
9
+ before { setio input, output }
10
+
11
+ context "when in non-interactive mode" do
12
+ let(:data) { 'something_%{a_var}' }
13
+ context "and has valid value" do
14
+ let(:values) { { a_var: 'value' } }
15
+ let(:expected) { 'something_value' }
16
+ it { expect(parse data, values).to eq expected }
17
+ end
18
+ context "and has invalid value" do
19
+ let(:values) { { b_var: 'novalue' } }
20
+ let(:expected) { 'something_' }
21
+ it { expect(parse data, values).to eq expected }
22
+ end
23
+ context "and has valid value with doublecolumn" do
24
+ let(:data) { 'something_%{::a_var}' }
25
+ let(:values) { { a_var: 'value' } }
26
+ let(:expected) { 'something_value' }
27
+ it { expect(parse data, values).to eq expected }
28
+ end
29
+ end
30
+ context "when in interactive mode" do
31
+ let(:data) { 'something_%{a_var}' }
32
+ context "and has valid value" do
33
+ let(:values) { { a_var: 'value' } }
34
+ let(:expected) { 'something_value' }
35
+ it { expect(parse data, values, true).to eq expected }
36
+ end
37
+ context "and has invalid value" do
38
+ let(:values) { { b_var: 'novalue' } }
39
+ let(:expected) { 'something_value' }
40
+ before { allow(input).to receive(:gets).and_return 'value' }
41
+ it { expect(parse data, values, true).to eq expected }
42
+ end
43
+ end
44
+ end
45
+
46
+ describe ".ask_about" do
47
+ end
48
+
49
+ end
@@ -7,7 +7,8 @@ describe Hieracles::Node do
7
7
  config: 'spec/files/config.yml',
8
8
  hierafile: 'hiera.yaml',
9
9
  encpath: 'enc',
10
- basepath: 'spec/files'
10
+ basepath: 'spec/files',
11
+ usedb: false
11
12
  }
12
13
  }
13
14
 
@@ -193,16 +194,56 @@ describe Hieracles::Node do
193
194
  end
194
195
 
195
196
  describe '.info' do
196
- let(:expected) { {
197
- classes: ['dev'],
198
- fqdn: 'server.example.com',
199
- datacenter: 'equinix',
200
- country: 'fr',
201
- farm: 'dev'
202
- } }
203
- it { expect(node.info).to eq expected }
197
+ context "without calling puppetd" do
198
+ let(:expected) { {
199
+ classes: ['dev'],
200
+ fqdn: 'server.example.com',
201
+ datacenter: 'equinix',
202
+ country: 'fr',
203
+ farm: 'dev'
204
+ } }
205
+ it { expect(node.info).to eq expected }
206
+ end
204
207
  end
208
+ end
209
+ end
205
210
 
211
+ context "with calling puppetd" do
212
+ let(:options) {
213
+ {
214
+ config: 'spec/files/config_withdb.yml',
215
+ hierafile: 'hiera.yaml',
216
+ encpath: 'enc',
217
+ basepath: 'spec/files'
218
+ }
219
+ }
220
+ describe '.info' do
221
+ let(:expected) { {
222
+ classes: ['dev'],
223
+ fqdn: 'server.example.com',
224
+ datacenter: 'equinix',
225
+ country: 'fr',
226
+ farm: 'dev',
227
+ catalog_timestamp: '2015-12-01T23:09:41.540Z'
228
+ } }
229
+ let(:resp_info) {
230
+ Hieracles::Puppetdb::Response.new({ catalog_timestamp: '2015-12-01T23:09:41.540Z'}, 1)
231
+ }
232
+ let(:resp_facts) {
233
+ Hieracles::Puppetdb::Response.new([{ 'name' => 'datacenter', 'value' => 'tahiti' }], 1)
234
+ }
235
+ let(:node) { Hieracles::Node.new 'server.example.com', options }
236
+ before {
237
+ allow_any_instance_of(Hieracles::Puppetdb::Client).
238
+ to receive(:request).
239
+ with("nodes/server.example.com").
240
+ and_return(resp_info)
241
+ allow_any_instance_of(Hieracles::Puppetdb::Client).
242
+ to receive(:request).
243
+ with("nodes/server.example.com/facts").
244
+ and_return(resp_facts)
245
+ }
246
+ it { expect(node.info).to eq expected }
206
247
  end
207
248
  end
208
249
 
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hieracles::Notification do
4
+
5
+ describe '.new' do
6
+ let(:notif) { Hieracles::Notification.new 'a_source', 'a_message'}
7
+ it { expect(notif.level).to eq 'info' }
8
+ it { expect(notif.message).to eq 'a_message' }
9
+ it { expect(notif.source).to eq 'a_source' }
10
+ end
11
+
12
+ describe '.to_hash' do
13
+ let(:notif) { Hieracles::Notification.new 'a_source', 'a_message'}
14
+ before {
15
+ allow(Time).to receive(:new).and_return(Time.new(2015))
16
+ }
17
+ let(:expected) {
18
+ {
19
+ 'source' => 'a_source',
20
+ 'level' => 'info',
21
+ 'message' => 'a_message',
22
+ 'timestamp' => Time.new(2015)
23
+ }
24
+ }
25
+ it { expect(notif.to_hash).to eq expected }
26
+ end
27
+
28
+
29
+ end
@@ -0,0 +1,82 @@
1
+ require 'spec_helper'
2
+ require 'hieracles/options/hc'
3
+
4
+ describe Hieracles::Options::Hc do
5
+ describe '.initialize' do
6
+ context 'with proper arguments' do
7
+ let(:array) { ['arg1', 'arg2', '-c', 'path/to/config-file', '-f', 'thatformat'] }
8
+ let(:expected_payload) { ['arg1', 'arg2'] }
9
+ let(:expected_options) do
10
+ { config: 'path/to/config-file', format: 'thatformat' }
11
+ end
12
+ subject { Hieracles::Options::Hc.new array }
13
+ it "populates payload" do
14
+ expect(subject.payload).to eq expected_payload
15
+ end
16
+ it 'populates options' do
17
+ expect(subject.options).to eq expected_options
18
+ end
19
+ end
20
+
21
+ context 'with proper arguments in random order' do
22
+ let(:array) { ['-c', 'path/to/config-file', 'arg1', 'arg2', '-f', 'thatformat'] }
23
+ let(:expected_payload) { ['arg1', 'arg2'] }
24
+ let(:expected_options) do
25
+ { config: 'path/to/config-file', format: 'thatformat' }
26
+ end
27
+ subject { Hieracles::Options::Hc.new array }
28
+ it "populates payload" do
29
+ expect(subject.payload).to eq expected_payload
30
+ end
31
+ it 'populates options' do
32
+ expect(subject.options).to eq expected_options
33
+ end
34
+ end
35
+
36
+ context 'with funnily ordered arguments' do
37
+ let(:array) { ['arg1', '-u', 'path/to/config-file', 'arg2', '-f', 'thatformat'] }
38
+ let(:expected_payload) { ['arg1', 'arg2'] }
39
+ let(:expected_options) do
40
+ { format: 'thatformat' }
41
+ end
42
+ subject { Hieracles::Options::Hc.new array }
43
+ it "populates payload" do
44
+ expect(subject.payload).to eq expected_payload
45
+ end
46
+ it 'populates options' do
47
+ expect(subject.options).to eq expected_options
48
+ end
49
+ end
50
+
51
+ context 'with arguments in alternative syntax' do
52
+ let(:array) { ['arg1', 'arg2', '-config', 'path/to/config-file', '--format', 'thatformat'] }
53
+ let(:expected_payload) { ['arg1', 'arg2'] }
54
+ let(:expected_options) do
55
+ { config: 'path/to/config-file', format: 'thatformat' }
56
+ end
57
+ subject { Hieracles::Options::Hc.new array }
58
+ it "populates payload" do
59
+ expect(subject.payload).to eq expected_payload
60
+ end
61
+ it 'populates options' do
62
+ expect(subject.options).to eq expected_options
63
+ end
64
+ end
65
+
66
+ context 'with arguments containing boolean element' do
67
+ let(:array) { ['arg1', 'arg2', '-i', '-format', 'thatformat'] }
68
+ let(:expected_payload) { ['arg1', 'arg2'] }
69
+ let(:expected_options) do
70
+ { format: 'thatformat', interactive: true }
71
+ end
72
+ subject { Hieracles::Options::Hc.new array }
73
+ it "populates payload" do
74
+ expect(subject.payload).to eq expected_payload
75
+ end
76
+ it 'populates options' do
77
+ expect(subject.options).to eq expected_options
78
+ end
79
+ end
80
+
81
+ end
82
+ end
@@ -6,13 +6,13 @@ describe Hieracles::Optparse do
6
6
  let(:array) { ['arg1', 'arg2', '-c', 'path/to/config-file', '-f', 'thatformat'] }
7
7
  let(:expected_payload) { ['arg1', 'arg2'] }
8
8
  let(:expected_options) do
9
- { config: 'path/to/config-file', format: 'thatformat' }
9
+ { }
10
10
  end
11
11
  subject { Hieracles::Optparse.new array }
12
12
  it "populates payload" do
13
13
  expect(subject.payload).to eq expected_payload
14
14
  end
15
- it 'populates options' do
15
+ it 'populates no options' do
16
16
  expect(subject.options).to eq expected_options
17
17
  end
18
18
  end
@@ -21,7 +21,7 @@ describe Hieracles::Optparse do
21
21
  let(:array) { ['-c', 'path/to/config-file', 'arg1', 'arg2', '-f', 'thatformat'] }
22
22
  let(:expected_payload) { ['arg1', 'arg2'] }
23
23
  let(:expected_options) do
24
- { config: 'path/to/config-file', format: 'thatformat' }
24
+ { }
25
25
  end
26
26
  subject { Hieracles::Optparse.new array }
27
27
  it "populates payload" do
@@ -36,7 +36,7 @@ describe Hieracles::Optparse do
36
36
  let(:array) { ['arg1', '-u', 'path/to/config-file', 'arg2', '-f', 'thatformat'] }
37
37
  let(:expected_payload) { ['arg1', 'arg2'] }
38
38
  let(:expected_options) do
39
- { format: 'thatformat' }
39
+ { }
40
40
  end
41
41
  subject { Hieracles::Optparse.new array }
42
42
  it "populates payload" do
@@ -51,7 +51,7 @@ describe Hieracles::Optparse do
51
51
  let(:array) { ['arg1', 'arg2', '-config', 'path/to/config-file', '--format', 'thatformat'] }
52
52
  let(:expected_payload) { ['arg1', 'arg2'] }
53
53
  let(:expected_options) do
54
- { config: 'path/to/config-file', format: 'thatformat' }
54
+ { }
55
55
  end
56
56
  subject { Hieracles::Optparse.new array }
57
57
  it "populates payload" do
@@ -65,9 +65,9 @@ describe Hieracles::Optparse do
65
65
 
66
66
  context 'with arguments containing boolean element' do
67
67
  let(:array) { ['arg1', 'arg2', '-i', '-format', 'thatformat'] }
68
- let(:expected_payload) { ['arg1', 'arg2'] }
68
+ let(:expected_payload) { ['arg1', 'arg2', 'thatformat'] }
69
69
  let(:expected_options) do
70
- { format: 'thatformat', interactive: true }
70
+ { }
71
71
  end
72
72
  subject { Hieracles::Optparse.new array }
73
73
  it "populates payload" do
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hieracles::Puppetdb::APIError do
4
+
5
+ describe '.new' do
6
+ let(:response) { Object.new }
7
+ let(:error) { Hieracles::Puppetdb::APIError.new response }
8
+ it { expect(error.response).to eq response }
9
+ end
10
+
11
+ end
@@ -0,0 +1,64 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hieracles::Puppetdb::Client do
4
+
5
+ describe '.new' do
6
+ context 'when no option is passed' do
7
+ let(:client) { Hieracles::Puppetdb::Client.new Hash.new }
8
+ it { expect(client.class.instance_variable_get(:@default_options)[:base_uri]).to eq 'http://localhost:8080/v3' }
9
+ end
10
+ end
11
+
12
+ describe '.setup_if_ssl' do
13
+ let(:basepath) { 'spec/files' }
14
+ let(:options) {
15
+ {
16
+ 'usessl' => true,
17
+ 'key' => File.join(basepath, 'ssl', 'key.pem'),
18
+ 'cert' => File.join(basepath, 'ssl', 'cert.crt'),
19
+ 'ca_file' => File.join(basepath, 'ssl', 'ca.crt')
20
+ }
21
+ }
22
+ let(:client) { Hieracles::Puppetdb::Client.new options }
23
+ it { expect(client.class.instance_variable_get(:@default_options)[:options]).to eq options }
24
+ end
25
+
26
+ describe '.request' do
27
+ context 'with a GET request' do
28
+ let(:client) { Hieracles::Puppetdb::Client.new Hash.new }
29
+ let(:request) { client.request('endpoint', 'get')}
30
+ let(:response) { Hieracles::Puppetdb::Response.new(Hash.new, 0, Array.new) }
31
+ before {
32
+ resp = double
33
+ allow(resp).
34
+ to receive(:code).
35
+ and_return(200)
36
+ allow(resp).
37
+ to receive(:parsed_response).
38
+ and_return('')
39
+ allow(client).
40
+ to receive(:get_request).
41
+ with('endpoint', nil, {}).
42
+ and_return(resp)
43
+ }
44
+ it { expect(request.data).to eq Hash.new }
45
+ it { expect(request.notifications.count).to eq 1 }
46
+ end
47
+ end
48
+
49
+ describe '.get_request' do
50
+ let(:client) { Hieracles::Puppetdb::Client.new Hash.new }
51
+ context 'without query' do
52
+ let(:request) { client.request('endpoint', 'get')}
53
+ before {
54
+ allow(client.class).
55
+ to receive(:get).
56
+ and_return('ha')
57
+ }
58
+ let(:get_request) { client.get_request('endpoint', nil, Hash.new) }
59
+ it { expect(get_request).to eq 'ha' }
60
+ end
61
+ end
62
+
63
+
64
+ end
@@ -0,0 +1,107 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hieracles::Puppetdb::FixSSLConnectionAdapter do
4
+
5
+ let(:uri) { URI "https://localhost" }
6
+ let(:options) { {} }
7
+ let(:adapter) { Hieracles::Puppetdb::FixSSLConnectionAdapter.new uri, options }
8
+ describe '.attach_ssl_certificates' do
9
+
10
+ context "with cert file" do
11
+ context "not found" do
12
+ let(:options) {
13
+ {
14
+ 'cert' => File.expand_path('spec/files/ssl/no-cert.crt'),
15
+ 'key' => File.expand_path('spec/files/ssl/key.pem'),
16
+ 'ca_file' => File.expand_path('spec/files/ssl/ca.crt')
17
+ }
18
+ }
19
+ it { expect { adapter.connection }.to raise_error(IOError, /Cert file .*no-cert.crt not found\./) }
20
+ end
21
+ context "badly formatted" do
22
+ let(:options) {
23
+ {
24
+ 'cert' => File.expand_path('spec/files/ssl/bad-cert.crt'),
25
+ 'key' => File.expand_path('spec/files/ssl/key.pem'),
26
+ 'ca_file' => File.expand_path('spec/files/ssl/ca.crt')
27
+ }
28
+ }
29
+ it { expect { adapter.connection }.to raise_error(OpenSSL::X509::CertificateError) }
30
+ end
31
+ end
32
+
33
+ context "with key file" do
34
+ context "not found" do
35
+ let(:options) {
36
+ {
37
+ 'cert' => File.expand_path('spec/files/ssl/cert.crt'),
38
+ 'key' => File.expand_path('spec/files/ssl/no-key.pem'),
39
+ 'ca_file' => File.expand_path('spec/files/ssl/ca.crt')
40
+ }
41
+ }
42
+ it { expect { adapter.connection }.to raise_error(IOError, /Key file .*no-key.pem not found\./) }
43
+ end
44
+ context "badly formatted" do
45
+ let(:options) {
46
+ {
47
+ 'cert' => File.expand_path('spec/files/ssl/cert.crt'),
48
+ 'key' => File.expand_path('spec/files/ssl/bad-key.pem'),
49
+ 'ca_file' => File.expand_path('spec/files/ssl/ca.crt')
50
+ }
51
+ }
52
+ it { expect { adapter.connection }.to raise_error(OpenSSL::PKey::RSAError) }
53
+ end
54
+ context "with pasword" do
55
+ context "correct" do
56
+ let(:options) {
57
+ {
58
+ 'cert' => File.expand_path('spec/files/ssl/cert.crt'),
59
+ 'key' => File.expand_path('spec/files/ssl/key-pass.pem'),
60
+ 'key_password' => 'good-toto',
61
+ 'ca_file' => File.expand_path('spec/files/ssl/ca.crt')
62
+ }
63
+ }
64
+ it { expect { adapter.connection }.not_to raise_error }
65
+ end
66
+ context "incorrect" do
67
+ let(:options) {
68
+ {
69
+ 'cert' => File.expand_path('spec/files/ssl/cert.crt'),
70
+ 'key' => File.expand_path('spec/files/ssl/key-pass.pem'),
71
+ 'key_password' => 'bad-toto',
72
+ 'ca_file' => File.expand_path('spec/files/ssl/ca.crt')
73
+ }
74
+ }
75
+ it {expect { adapter.connection }.to raise_error(OpenSSL::PKey::RSAError) }
76
+ end
77
+ end
78
+ end
79
+
80
+ context "with CA file" do
81
+ context "not found" do
82
+ let(:options) {
83
+ {
84
+ 'cert' => File.expand_path('spec/files/ssl/cert.crt'),
85
+ 'key' => File.expand_path('spec/files/ssl/key.pem'),
86
+ 'ca_file' => File.expand_path('spec/files/ssl/no-ca.crt')
87
+ }
88
+ }
89
+ it { expect { adapter.connection }.to raise_error(IOError, /CA file .*no-ca.crt not found\./) }
90
+ end
91
+ end
92
+
93
+ context "all correct" do
94
+ let(:options) {
95
+ {
96
+ 'cert' => File.expand_path('spec/files/ssl/cert.crt'),
97
+ 'key' => File.expand_path('spec/files/ssl/key.pem'),
98
+ 'ca_file' => File.expand_path('spec/files/ssl/ca.crt'),
99
+ 'verify_peer' => '1'
100
+ }
101
+ }
102
+ it { expect { adapter.connection }.not_to raise_error }
103
+ end
104
+
105
+ end
106
+
107
+ end