dm-chef-adapter 0.1.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.
data/examples/blog.rb ADDED
@@ -0,0 +1,43 @@
1
+ require 'dm-core'
2
+ require 'dm-chef-adapter'
3
+
4
+ DataMapper.setup(:default,
5
+ :adapter => 'chef',
6
+ :node_name => "localbox",
7
+ :client_key => "/path/to/client/key.pem",
8
+ :chef_server_url => "http://chef.internal.net:4000/"
9
+ )
10
+
11
+ class Post
12
+ include DataMapper::Resource
13
+
14
+ is :chef
15
+
16
+ property :title, String
17
+ property :body, Text
18
+ property :published, Boolean
19
+
20
+ has n, :comments
21
+ end
22
+
23
+ class Comment
24
+ include DataMapper::Resource
25
+
26
+ is :chef
27
+
28
+ property :created_by, String
29
+ property :body, Text
30
+
31
+ belongs_to :post
32
+ end
33
+
34
+ DataMapper.finalize
35
+
36
+ post = Post.new(:title => "Datamapper is Awesome", :body => "Lorem ipsum ...", :published => true);
37
+ comment1 = Comment.new(:created_by => "Me", :body => "I agree")
38
+ post.comments << comment1
39
+ post.save
40
+
41
+
42
+
43
+
@@ -0,0 +1 @@
1
+ require 'dm-chef-adapter/adapter'
@@ -0,0 +1,190 @@
1
+ require 'json'
2
+ require 'chef'
3
+ require 'dm-core'
4
+ require 'uuidtools'
5
+ module DataMapper
6
+ class Property
7
+ class DocId < String
8
+ key true
9
+ writer false
10
+ default ''
11
+ # @api private
12
+ def to_child_key
13
+ Property::String
14
+ end
15
+
16
+ end # class DocId
17
+ end # module Property
18
+ module Is
19
+ module Chef
20
+ def is_chef(options={})
21
+ require 'dm-serializer'
22
+ property :id, DataMapper::Property::DocId
23
+ end
24
+ end
25
+ end
26
+ module Adapters
27
+ class ChefAdapter < AbstractAdapter
28
+ # @api semipublic
29
+ def create(resources)
30
+ resources.collect do |resource|
31
+ if !Chef::DataBag.list.keys.include?(resource.class.storage_name)
32
+ databag = Chef::DataBag.new
33
+ databag.name resource.class.storage_name
34
+ databag.create
35
+ end
36
+ begin
37
+ resource.id = @uuid.sha1_create(
38
+ UUIDTools::UUID_DNS_NAMESPACE,
39
+ ("%10.6f#{resource.class.storage_name}" % Time.now.to_f)
40
+ )
41
+ rescue
42
+ resource.send :instance_variable_set, :@id, resource.key
43
+ end
44
+ if !Chef::DataBag.load(resource.class.storage_name).keys.include?(resource.key.join('_'))
45
+ databag_item = Chef::DataBagItem.new
46
+ databag_item.data_bag resource.class.storage_name
47
+ data = {"id" => resource.key.join('_')}
48
+ data.merge! Chef::JSONCompat.from_json(resource.to_json)
49
+ databag_item.raw_data = data
50
+ #binding.pry
51
+ databag_item.create
52
+ else
53
+ raise "DataBagItem #{resource.class.storage_name}/#{resource.key.join('_')} already exists."
54
+ end
55
+ end.count
56
+ end
57
+
58
+ # @api semipublic
59
+ def read(query)
60
+ records = records_for(query.model.storage_name)
61
+ ret = []
62
+ query.links.reverse.each do |link|
63
+ children = records_for(link.child_model.storage_name)
64
+ parents = records_for(link.parent_model.storage_name)
65
+ children.each do |child|
66
+ parents.each do |parent|
67
+ if child[link.child_key.first.name.to_s] == parent[link.parent_key.first.name.to_s]
68
+ records.each do |record|
69
+ ret << child.merge(record)
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ query.filter_records(ret+records)
76
+ end
77
+
78
+ def update(attributes, collection)
79
+ fields = attributes_as_fields(attributes)
80
+ read(collection.query).each do |doc|
81
+ databag_item = Chef::DataBagItem.load collection.storage_name, doc["id"]
82
+ databag_item.raw_data.merge! Chef::JSONCompat.from_json(fields.to_json)
83
+ databag_item.save
84
+ end
85
+ end
86
+
87
+ # @api semipublic
88
+ def delete(collection)
89
+ read(collection.query).each do |doc|
90
+ databag_item = Chef::DataBagItem.load collection.storage_name, doc["id"]
91
+ databag_item.destroy collection.storage_name, doc["id"]
92
+ end
93
+ end
94
+
95
+ # @api semipublic
96
+ def attributes_as_fields(attributes)
97
+ pairs = attributes.map do |property, value|
98
+ dumped = value.kind_of?(Module) ? value.name : property.dump(value)
99
+ [ property.field, dumped ]
100
+ end
101
+ Hash[pairs]
102
+ end
103
+
104
+ private
105
+
106
+ # @api semipublic
107
+ def initialize(name, opts = {})
108
+ super
109
+ Chef::Config.configuration[:node_name] = opts["node_name"]
110
+ Chef::Config.configuration[:client_key] = opts["client_key"]
111
+ Chef::Config.configuration[:chef_server_url] = opts["chef_server_url"] if !opts["chef_server_url"].nil?
112
+ @chef = Chef::REST.new(Chef::Config[:chef_server_url])
113
+ @uuid = UUIDTools::UUID
114
+ end
115
+
116
+ # Retrieves all records for a model and yields them to a block.
117
+ #
118
+ # The block should make any changes to the records in-place. After
119
+ # the block executes all the records are dumped back to the databag.
120
+ #
121
+ # @param [Model, #to_s] model
122
+ # Used to determine which file to read/write to
123
+ #
124
+ # @yieldparam [Hash]
125
+ # A hash of record.key => record pairs retrieved from the databag
126
+ #
127
+ # @api private
128
+ def update_records(model)
129
+ records = records_for(model)
130
+ result = yield records
131
+ write_records(model, records)
132
+ result
133
+ end
134
+
135
+ # Read all records from a databag for a model
136
+ #
137
+ # @param [#storage_name] model
138
+ # The model/name to retieve records for
139
+ #
140
+ # @api private
141
+ def records_for(model)
142
+ records = []
143
+ databag = chef_databag(model)
144
+ if !databag.nil?
145
+ chef_databag(model).keys.each do |key|
146
+ records << Chef::DataBagItem.load(model, key).raw_data
147
+ end
148
+ end
149
+ records
150
+ end
151
+
152
+ # Writes all records to a databag
153
+ #
154
+ # @param [#storage_name] model
155
+ # The model/name to write the records for
156
+ #
157
+ # @param [Hash] records
158
+ # A hash of record.key => record pairs to be written
159
+ #
160
+ # @api private
161
+ def write_records(model, records)
162
+ item = Chef::DataBagItem.load(model. records["id"])
163
+ item.from_hash records
164
+ item.save
165
+ end
166
+
167
+ # Given a model, gives the databag to be used for record storage
168
+ #
169
+ # @example
170
+ # chef_databag(Article) #=> "Chef::DataBag"
171
+ #
172
+ # @param [#storage_name] model
173
+ # The model to be used to determine the databag.
174
+ #
175
+ # @api private
176
+ def chef_databag(model)
177
+ begin
178
+ Chef::DataBag.load model
179
+ rescue
180
+ nil
181
+ end
182
+ end
183
+
184
+ end # class ChefAdapter
185
+
186
+ const_added(:ChefAdapter)
187
+ end # module Adapters
188
+ Model.append_extensions(Is::Chef)
189
+ end # module DataMapper
190
+
@@ -0,0 +1 @@
1
+ DMCHEFADAPTER_VERSION = "0.1.0"
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dm-chef-adapter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Nick Ethier
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-02-01 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: chef
16
+ requirement: &81217850 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - =
20
+ - !ruby/object:Gem::Version
21
+ version: 0.10.8
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *81217850
25
+ - !ruby/object:Gem::Dependency
26
+ name: dm-core
27
+ requirement: &81217580 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - =
31
+ - !ruby/object:Gem::Version
32
+ version: 1.2.0
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *81217580
36
+ - !ruby/object:Gem::Dependency
37
+ name: dm-serializer
38
+ requirement: &81217290 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - =
42
+ - !ruby/object:Gem::Version
43
+ version: 1.2.1
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *81217290
47
+ description: uses chef databags as a backend for the datamapper ORM
48
+ email:
49
+ - ncethier@gmail.com
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - lib/dm-chef-adapter/version.rb
55
+ - lib/dm-chef-adapter/adapter.rb
56
+ - lib/dm-chef-adapter.rb
57
+ - examples/blog.rb
58
+ homepage: https://github.com/nickethier/dm-chef-adapter
59
+ licenses:
60
+ - Apache License (2.0)
61
+ post_install_message:
62
+ rdoc_options: []
63
+ require_paths:
64
+ - lib
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ! '>='
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubyforge_project:
80
+ rubygems_version: 1.8.10
81
+ signing_key:
82
+ specification_version: 3
83
+ summary: datamapper adapter to use a chef server as a datastore backend
84
+ test_files: []