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 +43 -0
- data/lib/dm-chef-adapter.rb +1 -0
- data/lib/dm-chef-adapter/adapter.rb +190 -0
- data/lib/dm-chef-adapter/version.rb +1 -0
- metadata +84 -0
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: []
|