chef-api 0.2.0

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 (48) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +20 -0
  3. data/.travis.yml +14 -0
  4. data/Gemfile +12 -0
  5. data/LICENSE +201 -0
  6. data/README.md +264 -0
  7. data/Rakefile +1 -0
  8. data/chef-api.gemspec +25 -0
  9. data/lib/chef-api/boolean.rb +6 -0
  10. data/lib/chef-api/configurable.rb +78 -0
  11. data/lib/chef-api/connection.rb +466 -0
  12. data/lib/chef-api/defaults.rb +130 -0
  13. data/lib/chef-api/error_collection.rb +44 -0
  14. data/lib/chef-api/errors.rb +35 -0
  15. data/lib/chef-api/logger.rb +160 -0
  16. data/lib/chef-api/proxy.rb +72 -0
  17. data/lib/chef-api/resource.rb +16 -0
  18. data/lib/chef-api/resources/base.rb +951 -0
  19. data/lib/chef-api/resources/client.rb +85 -0
  20. data/lib/chef-api/resources/collection_proxy.rb +217 -0
  21. data/lib/chef-api/resources/cookbook.rb +24 -0
  22. data/lib/chef-api/resources/cookbook_version.rb +23 -0
  23. data/lib/chef-api/resources/data_bag.rb +136 -0
  24. data/lib/chef-api/resources/data_bag_item.rb +35 -0
  25. data/lib/chef-api/resources/environment.rb +16 -0
  26. data/lib/chef-api/resources/node.rb +17 -0
  27. data/lib/chef-api/resources/principal.rb +11 -0
  28. data/lib/chef-api/resources/role.rb +16 -0
  29. data/lib/chef-api/resources/user.rb +11 -0
  30. data/lib/chef-api/schema.rb +112 -0
  31. data/lib/chef-api/util.rb +119 -0
  32. data/lib/chef-api/validator.rb +16 -0
  33. data/lib/chef-api/validators/base.rb +82 -0
  34. data/lib/chef-api/validators/required.rb +11 -0
  35. data/lib/chef-api/validators/type.rb +23 -0
  36. data/lib/chef-api/version.rb +3 -0
  37. data/lib/chef-api.rb +76 -0
  38. data/locales/en.yml +89 -0
  39. data/spec/integration/resources/client_spec.rb +8 -0
  40. data/spec/integration/resources/environment_spec.rb +8 -0
  41. data/spec/integration/resources/node_spec.rb +8 -0
  42. data/spec/integration/resources/role_spec.rb +8 -0
  43. data/spec/spec_helper.rb +26 -0
  44. data/spec/support/chef_server.rb +115 -0
  45. data/spec/support/shared/chef_api_resource.rb +91 -0
  46. data/spec/unit/resources/base_spec.rb +47 -0
  47. data/spec/unit/resources/client_spec.rb +69 -0
  48. metadata +128 -0
@@ -0,0 +1,115 @@
1
+ require 'chef_zero/server'
2
+
3
+ module RSpec
4
+ class ChefServer
5
+ module DSL
6
+ def chef_server
7
+ RSpec::ChefServer
8
+ end
9
+ end
10
+
11
+ class << self
12
+ def method_missing(m, *args, &block)
13
+ instance.send(m, *args, &block)
14
+ end
15
+ end
16
+
17
+ require 'singleton'
18
+ include Singleton
19
+
20
+ #
21
+ #
22
+ #
23
+ def initialize
24
+ @server = ChefZero::Server.new({
25
+ port: port,
26
+ log_level: :fatal,
27
+ generate_real_keys: false,
28
+ })
29
+
30
+ ChefAPI.endpoint = @server.url
31
+ ChefAPI.key = ChefZero::PRIVATE_KEY
32
+ end
33
+
34
+ #
35
+ #
36
+ #
37
+ def start
38
+ @server.start_background(1)
39
+ end
40
+
41
+ #
42
+ # Clear all the information in the server. This hook is run after each
43
+ # example group, giving the appearance of an "empty" Chef Server for
44
+ # each test.
45
+ #
46
+ def clear
47
+ @server.clear_data
48
+ end
49
+
50
+ #
51
+ # Stop the server (since it might not be running)
52
+ #
53
+ def stop
54
+ @server.stop if @server.running?
55
+ end
56
+
57
+ #
58
+ #
59
+ #
60
+ def load_data(key, id, data = {})
61
+ @server.load_data({ key.to_s => { id => JSON.fast_generate(data) } })
62
+ end
63
+
64
+ #
65
+ #
66
+ #
67
+ [
68
+ ['clients', 'client'],
69
+ ['cookbooks', 'cookbook'],
70
+ ['environments', 'environment'],
71
+ ['nodes', 'node'],
72
+ ['roles', 'role'],
73
+ ].each do |plural, singular|
74
+ define_method(plural) do
75
+ @server.data_store.list([plural])
76
+ end
77
+
78
+ define_method(singular) do |id|
79
+ JSON.parse(@server.data_store.get([plural, id]))
80
+ end
81
+
82
+ define_method("create_#{singular}") do |id, data = {}|
83
+ load_data(plural, id, data)
84
+ end
85
+
86
+ define_method("has_#{singular}?") do |id|
87
+ send(plural).include?(id)
88
+ end
89
+ end
90
+
91
+ private
92
+
93
+ #
94
+ # A randomly assigned, open port for run the Chef Zero server.
95
+ #
96
+ # @return [Fixnum]
97
+ #
98
+ def port
99
+ return @port if @port
100
+
101
+ @server = TCPServer.new('127.0.0.1', 0)
102
+ @port = @server.addr[1].to_i
103
+ @server.close
104
+
105
+ return @port
106
+ end
107
+ end
108
+ end
109
+
110
+
111
+ RSpec.configure do |config|
112
+ config.before(:suite) { RSpec::ChefServer.start }
113
+ config.after(:each) { RSpec::ChefServer.clear }
114
+ config.after(:suite) { RSpec::ChefServer.stop }
115
+ end
@@ -0,0 +1,91 @@
1
+ shared_examples_for 'a Chef API resource' do |type, options = {}|
2
+ let(:resource_id) { "my_#{type}" }
3
+
4
+ describe '.fetch' do
5
+ it 'returns nil when the resource does not exist' do
6
+ expect(described_class.fetch('not_real')).to be_nil
7
+ end
8
+
9
+ it 'returns the resource' do
10
+ chef_server.send("create_#{type}", resource_id)
11
+ expect(described_class.fetch(resource_id).name).to eq(resource_id)
12
+ end
13
+ end
14
+
15
+ describe '.build' do
16
+ it 'builds a resource' do
17
+ instance = described_class.build(name: resource_id)
18
+ expect(instance).to be_a(described_class)
19
+ end
20
+
21
+ it 'does not create a remote resource' do
22
+ described_class.build(name: resource_id)
23
+ expect(chef_server).to_not send("have_#{type}", resource_id)
24
+ end
25
+ end
26
+
27
+ describe '.create' do
28
+ it 'creates a new remote resource' do
29
+ described_class.create(name: resource_id)
30
+ expect(chef_server).to send("have_#{type}", resource_id)
31
+ end
32
+
33
+ it 'raises an exception when the resource already exists' do
34
+ chef_server.send("create_#{type}", resource_id)
35
+ expect {
36
+ described_class.create(name: resource_id)
37
+ }.to raise_error(ChefAPI::Error::ResourceAlreadyExists)
38
+ end
39
+ end
40
+
41
+ describe '.exists?' do
42
+ it 'returns false when the resource does not exist' do
43
+ expect(described_class.exists?(resource_id)).to be_false
44
+ end
45
+
46
+ it 'returns true when the resource exists' do
47
+ chef_server.send("create_#{type}", resource_id)
48
+ expect(described_class.exists?(resource_id)).to be_true
49
+ end
50
+ end
51
+
52
+ describe '.destroy' do
53
+ it "destroys the #{type} with the given ID" do
54
+ chef_server.send("create_#{type}", resource_id)
55
+ described_class.delete(resource_id)
56
+
57
+ expect(chef_server).to_not send("have_#{type}", resource_id)
58
+ end
59
+
60
+ it 'does not raise an exception if the record does not exist' do
61
+ expect { described_class.delete(resource_id) }.to_not raise_error
62
+ end
63
+ end
64
+
65
+ describe '.update' do
66
+ it 'updates an existing resource' do
67
+ chef_server.send("create_#{type}", resource_id)
68
+
69
+ options[:update].each do |key, value|
70
+ described_class.update(resource_id, key => value)
71
+ expect(chef_server.send(type, resource_id)[key.to_s]).to eq(value)
72
+ end
73
+ end
74
+
75
+ it 'raises an exception when the resource does not exist' do
76
+ expect {
77
+ described_class.update(resource_id)
78
+ }.to raise_error(ChefAPI::Error::ResourceNotFound)
79
+ end
80
+ end
81
+
82
+ describe '.count' do
83
+ it 'returns the total number of resources' do
84
+ 5.times do |i|
85
+ chef_server.send("create_#{type}", "#{resource_id}_#{i}")
86
+ end
87
+
88
+ expect(described_class.count).to be >= 5
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ module ChefAPI
4
+ describe Resource::Base do
5
+ before do
6
+ # Unset all instance variables (which are actually cached on the parent
7
+ # class) to prevent caching.
8
+ described_class.instance_variables.each do |instance_variable|
9
+ described_class.send(:remove_instance_variable, instance_variable)
10
+ end
11
+ end
12
+
13
+ describe '.schema' do
14
+ it 'sets the schema for the class' do
15
+ block = Proc.new {}
16
+ described_class.schema(&block)
17
+ expect(described_class.schema).to be_a(Schema)
18
+ end
19
+ end
20
+
21
+ describe '.collection_path' do
22
+ it 'raises an exception if the collection name is not set' do
23
+ expect { described_class.collection_path }.to raise_error
24
+ end
25
+
26
+ it 'sets the collection name' do
27
+ described_class.collection_path('bacons')
28
+ expect(described_class.collection_path).to eq('bacons')
29
+ end
30
+
31
+ it 'converts the symbol to a string' do
32
+ described_class.collection_path(:bacons)
33
+ expect(described_class.collection_path).to eq('bacons')
34
+ end
35
+ end
36
+
37
+ describe '.build' do
38
+ it 'creates a new instance' do
39
+ described_class.stub(:new)
40
+ described_class.stub(:schema).and_return(double(attributes: {}))
41
+
42
+ expect(described_class).to receive(:new).with({foo: 'bar'}, {})
43
+ described_class.build(foo: 'bar')
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,69 @@
1
+ require 'spec_helper'
2
+
3
+ module ChefAPI
4
+ describe Resource::Client do
5
+ describe '.from_file' do
6
+ it 'raises a permission error when Ruby cannot read the file' do
7
+ File.stub(:read).and_raise(Errno::EACCES)
8
+ expect {
9
+ described_class.from_file('client.pem')
10
+ }.to raise_error(Error::InsufficientFilePermissions)
11
+ end
12
+
13
+ it 'raises an error when the file does not exist' do
14
+ File.stub(:read).and_raise(Errno::ENOENT)
15
+ expect {
16
+ described_class.from_file('client.pem')
17
+ }.to raise_error(Error::FileNotFound)
18
+ end
19
+ end
20
+
21
+ describe '.initialize' do
22
+ it 'converts an x509 certificate to a public key' do
23
+ certificate = <<-EOH.gsub(/^ {10}/, '')
24
+ -----BEGIN CERTIFICATE-----
25
+ MIIDOjCCAqOgAwIBAgIEkT9umDANBgkqhkiG9w0BAQUFADCBnjELMAkGA1UEBhMC
26
+ VVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxFjAUBgNV
27
+ BAoMDU9wc2NvZGUsIEluYy4xHDAaBgNVBAsME0NlcnRpZmljYXRlIFNlcnZpY2Ux
28
+ MjAwBgNVBAMMKW9wc2NvZGUuY29tL2VtYWlsQWRkcmVzcz1hdXRoQG9wc2NvZGUu
29
+ Y29tMCAXDTEzMDYwNzE3NDcxNloYDzIxMDIwNzIyMTc0NzE2WjCBnTEQMA4GA1UE
30
+ BxMHU2VhdHRsZTETMBEGA1UECBMKV2FzaGluZ3RvbjELMAkGA1UEBhMCVVMxHDAa
31
+ BgNVBAsTE0NlcnRpZmljYXRlIFNlcnZpY2UxFjAUBgNVBAoTDU9wc2NvZGUsIElu
32
+ Yy4xMTAvBgNVBAMUKFVSSTpodHRwOi8vb3BzY29kZS5jb20vR1VJRFMvY2xpZW50
33
+ X2d1aWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCko42znqDzryvE
34
+ aB1DBHLFpjLZ7aWrTJQJJUvQhMFTE/1nisa+1bw8MvOYnGDSp2j6V7XJsJgZFsAW
35
+ 7w5TTBHrYRAz0Boi+uaQ3idqfGI5na/dRt2MqFnwJYqvm7z+LeeYbGlXFNnhUInt
36
+ OjZD6AtrvuTGAEVdyIznsOMsLun/KWy9zG0+C+6vCnxGga+Z+xZ56JrBvWoWeIjG
37
+ kO0J6E3uqyzAC8FwN6xnyaHNlvODE+40MuioVJ52oLikTwaVe3T+vSJQoCu1lz7c
38
+ AbdszAhDW2p+GVvBBjAXLNi/w27heDQKBQOS+6tHJAX3WeFj0xgE5Bryae67E0q8
39
+ hM4WPL6PAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAWlBQBu8kzhSA4TuHJNyngRAJ
40
+ WXHus2brJZHaaZYMbzZMq+lklMbdw8NZBay+qVqN/latgQ7fjY9RSSdhCTeSITyw
41
+ gn8s3zeFS7C6nwrzYNAQXTRJZoSgn32hgZoD1H0LjW5vcoqiYZOHvX3EOySboS09
42
+ bAELUrq85D+uVns9C5A=
43
+ -----END CERTIFICATE-----
44
+ EOH
45
+
46
+ instance = described_class.new(certificate: certificate)
47
+ expect(instance.public_key).to eq <<-EOH.gsub(/^ {10}/, '')
48
+ -----BEGIN PUBLIC KEY-----
49
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApKONs56g868rxGgdQwRy
50
+ xaYy2e2lq0yUCSVL0ITBUxP9Z4rGvtW8PDLzmJxg0qdo+le1ybCYGRbAFu8OU0wR
51
+ 62EQM9AaIvrmkN4nanxiOZ2v3UbdjKhZ8CWKr5u8/i3nmGxpVxTZ4VCJ7To2Q+gL
52
+ a77kxgBFXciM57DjLC7p/ylsvcxtPgvurwp8RoGvmfsWeeiawb1qFniIxpDtCehN
53
+ 7qsswAvBcDesZ8mhzZbzgxPuNDLoqFSedqC4pE8GlXt0/r0iUKArtZc+3AG3bMwI
54
+ Q1tqfhlbwQYwFyzYv8Nu4Xg0CgUDkvurRyQF91nhY9MYBOQa8mnuuxNKvITOFjy+
55
+ jwIDAQAB
56
+ -----END PUBLIC KEY-----
57
+ EOH
58
+ end
59
+ end
60
+
61
+ describe '#regenerate_keys' do
62
+ it 'raises an error if the client is not persisted to the server' do
63
+ expect {
64
+ described_class.new.regenerate_keys
65
+ }.to raise_error(Error::CannotRegenerateKey)
66
+ end
67
+ end
68
+ end
69
+ end
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: chef-api
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Seth Vargo
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-02-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: i18n
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '0.6'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '0.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: mixlib-authentication
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ description: A tiny Chef API client with minimal dependencies
42
+ email:
43
+ - sethvargo@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - .gitignore
49
+ - .travis.yml
50
+ - Gemfile
51
+ - LICENSE
52
+ - README.md
53
+ - Rakefile
54
+ - chef-api.gemspec
55
+ - lib/chef-api.rb
56
+ - lib/chef-api/boolean.rb
57
+ - lib/chef-api/configurable.rb
58
+ - lib/chef-api/connection.rb
59
+ - lib/chef-api/defaults.rb
60
+ - lib/chef-api/error_collection.rb
61
+ - lib/chef-api/errors.rb
62
+ - lib/chef-api/logger.rb
63
+ - lib/chef-api/proxy.rb
64
+ - lib/chef-api/resource.rb
65
+ - lib/chef-api/resources/base.rb
66
+ - lib/chef-api/resources/client.rb
67
+ - lib/chef-api/resources/collection_proxy.rb
68
+ - lib/chef-api/resources/cookbook.rb
69
+ - lib/chef-api/resources/cookbook_version.rb
70
+ - lib/chef-api/resources/data_bag.rb
71
+ - lib/chef-api/resources/data_bag_item.rb
72
+ - lib/chef-api/resources/environment.rb
73
+ - lib/chef-api/resources/node.rb
74
+ - lib/chef-api/resources/principal.rb
75
+ - lib/chef-api/resources/role.rb
76
+ - lib/chef-api/resources/user.rb
77
+ - lib/chef-api/schema.rb
78
+ - lib/chef-api/util.rb
79
+ - lib/chef-api/validator.rb
80
+ - lib/chef-api/validators/base.rb
81
+ - lib/chef-api/validators/required.rb
82
+ - lib/chef-api/validators/type.rb
83
+ - lib/chef-api/version.rb
84
+ - locales/en.yml
85
+ - spec/integration/resources/client_spec.rb
86
+ - spec/integration/resources/environment_spec.rb
87
+ - spec/integration/resources/node_spec.rb
88
+ - spec/integration/resources/role_spec.rb
89
+ - spec/spec_helper.rb
90
+ - spec/support/chef_server.rb
91
+ - spec/support/shared/chef_api_resource.rb
92
+ - spec/unit/resources/base_spec.rb
93
+ - spec/unit/resources/client_spec.rb
94
+ homepage: https://github.com/sethvargo/chef-api
95
+ licenses:
96
+ - Apache 2.0
97
+ metadata: {}
98
+ post_install_message:
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - '>='
105
+ - !ruby/object:Gem::Version
106
+ version: '1.9'
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - '>='
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ requirements: []
113
+ rubyforge_project:
114
+ rubygems_version: 2.2.1
115
+ signing_key:
116
+ specification_version: 4
117
+ summary: A Chef API client in Ruby
118
+ test_files:
119
+ - spec/integration/resources/client_spec.rb
120
+ - spec/integration/resources/environment_spec.rb
121
+ - spec/integration/resources/node_spec.rb
122
+ - spec/integration/resources/role_spec.rb
123
+ - spec/spec_helper.rb
124
+ - spec/support/chef_server.rb
125
+ - spec/support/shared/chef_api_resource.rb
126
+ - spec/unit/resources/base_spec.rb
127
+ - spec/unit/resources/client_spec.rb
128
+ has_rdoc: