hieracles 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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