dm-chef-adapter 0.1.0

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