dm-puppetdb-adapter 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: dc43764da2ab76ebf53855bdc93cf7f11d6fb6b9
4
+ data.tar.gz: 9fbaf2dbab49f1b7b62e1bd0bb976d846034600f
5
+ SHA512:
6
+ metadata.gz: 057bec1165d3c9588b6ad4316bb51ecd54ffe9cc83db02dd39b3002e9e87614f933756c6d4802015ab217cca2a6b942013038e6558fdc595f36dba81ac62d824
7
+ data.tar.gz: a0247bbcb3e0c2c1c5a721d0b9191ec79e7a3c597a52b55cff830eb3774f23a3c8a60a5cfb308172b81c23535980c2664ee8b9c9fbf3e8de8b16e90b40b1dc2e
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # encoding: utf-8
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,5 @@
1
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
2
+
3
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
4
+
5
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = "dm-puppetdb-adapter"
5
+ gem.version = %x{git describe --tags}.split('-')[0..1].join('.')
6
+ gem.platform = Gem::Platform::RUBY
7
+ gem.authors = ["Erik Dalén"]
8
+ gem.email = ["erik.gustav.dalen@gmail.com"]
9
+ gem.homepage = "https://github.com/dalen/dm-puppetdbadapter"
10
+ gem.summary = %q{PuppetDB adapter for DataMapper}
11
+ gem.description = gem.summary
12
+ gem.license = 'MIT License (Expat)'
13
+
14
+ gem.files = `git ls-files`.split("\n")
15
+ gem.test_files = `git ls-files -- {test,spec,features,examples}/*`.split("\n")
16
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ gem.extra_rdoc_files = %w[LICENSE]
18
+ gem.require_paths = [ "lib" ]
19
+
20
+ gem.add_dependency 'json'
21
+ gem.add_dependency 'puppet', '~> 3'
22
+ gem.add_dependency 'dm-types'
23
+
24
+ gem.add_development_dependency 'rake'
25
+ end
@@ -0,0 +1,124 @@
1
+ require 'json'
2
+ require 'puppet'
3
+ require 'puppet/network/http_pool'
4
+ require 'uri'
5
+
6
+ require 'dm-core'
7
+
8
+ module DataMapper
9
+ module Adapters
10
+ class PuppetdbAdapter < AbstractAdapter
11
+ attr_accessor :http, :host, :port, :ssl
12
+
13
+ def read(query)
14
+ puts query.inspect
15
+ model = query.model
16
+
17
+ pdbquery = build_query(query)
18
+ puts pdbquery.inspect
19
+ query.filter_records(puppetdb_get(model.storage_name(model.repository_name), build_query(query)))
20
+ end
21
+
22
+ private
23
+
24
+ def initialize(name, options = {})
25
+ super
26
+
27
+ Puppet.initialize_settings unless Puppet[:confdir]
28
+
29
+ # Set some defaults
30
+ @host = @options[:host] || 'puppetdb'
31
+ @port = @options[:port] || 443
32
+ @ssl = @options[:ssl] || true
33
+ @http = Puppet::Network::HttpPool.http_instance(@host, @port, @ssl)
34
+ end
35
+
36
+ ##
37
+ # contruct a puppetdb query from a datamapper query
38
+ def build_query(query)
39
+ conditions = query.conditions
40
+ if conditions.empty?
41
+ nil
42
+ elsif conditions.one?
43
+ puppetdb_condition(conditions.first)
44
+ else
45
+ q = ['and', *conditions.map do |c|
46
+ puppetdb_condition c
47
+ end.compact ]
48
+ # In case we couldn't build any query from the contained
49
+ # conditions return nil instead of a empty and
50
+ return q.last if q.count == 2
51
+ return nil if q.count < 2
52
+ q
53
+ end
54
+ end
55
+
56
+ ##
57
+ # return puppetdb syntax for a condition
58
+ def puppetdb_condition(c)
59
+ case c
60
+ when DataMapper::Query::Conditions::NullOperation
61
+ nil
62
+ when DataMapper::Query::Conditions::AbstractOperation
63
+ q = [c.class.slug.to_s, *c.operands.map { |o| puppetdb_condition o }.compact]
64
+ # In case we couldn't build any query from the contained
65
+ # conditions return nil instead of a empty and
66
+ return nil if q.count < 2
67
+ q
68
+ end
69
+
70
+ # We can only do comparison on certain fields
71
+ # on the server side
72
+ if c.subject.model.respond_to? :server_fields
73
+ return nil unless c.subject.model.server_fields.include? c.subject.name
74
+ end
75
+
76
+ case c
77
+ when DataMapper::Query::Conditions::EqualToComparison
78
+ ['=', c.subject.field, format_value(c.value)]
79
+ when DataMapper::Query::Conditions::RegexpComparison
80
+ ['~', c.subject.field, format_value(c.value)]
81
+ when DataMapper::Query::Conditions::LessThanComparison
82
+ ['<', c.subject.field, format_value(c.value)]
83
+ when DataMapper::Query::Conditions::GreaterThanComparison
84
+ ['>', c.subject.field, format_value(c.value)]
85
+ # The following comparison operators aren't supported by PuppetDB
86
+ # So we emulate them
87
+ when DataMapper::Query::Conditions::LikeComparison
88
+ ['~', c.subject.field, c.value.gsub('%', '.*')]
89
+ when DataMapper::Query::Conditions::LessThanOrEqualToComparison
90
+ ['or', ['=', c.subject.field, format_value(c.value)], ['<', c.subject.field, format_value(c.value)]]
91
+ when DataMapper::Query::Conditions::GreaterThanOrEqualToComparison
92
+ ['or', ['=', c.subject.field, format_value(c.value)], ['>', c.subject.field, format_value(c.value)]]
93
+ when DataMapper::Query::Conditions::InclusionComparison
94
+ ['or', ['=', c.subject.field, format_value(c.value.first)], ['>', c.subject.field, format_value(c.value.first)], ['<', c.subject.field, format_value(c.value.last)], ['=', c.subject.field, format_value(c.value.last)]]
95
+ end
96
+ end
97
+
98
+ ##
99
+ # format a value in a query
100
+ # especially make sure timestamps have correct format
101
+ def format_value(value)
102
+ if value.is_a? Date or value.is_a? Time
103
+ value.strftime('%FT%T.%LZ')
104
+ else
105
+ value
106
+ end
107
+ end
108
+
109
+ def puppetdb_get(path, query=nil)
110
+ uri = "/#{path}?query="
111
+ uri += URI.escape query.to_json.to_s unless query.nil?
112
+ resp = @http.get(uri, { "Accept" => "application/json" })
113
+ raise RuntimeError, "PuppetDB query error: [#{resp.code}] #{resp.msg}, endpoint: #{path}, query: #{query.to_json}" unless resp.kind_of?(Net::HTTPSuccess)
114
+ # Do a ugly hack because Hash and Array
115
+ # properties aren't supported so we preserve them as JSON
116
+ JSON.parse(resp.body).collect do |i|
117
+ i.each do |k,v|
118
+ i[k] = v.to_json if v.is_a? Hash or v.is_a? Array
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,33 @@
1
+ class Event
2
+ include DataMapper::Resource
3
+
4
+ storage_names[:default] = 'experimental/events'
5
+
6
+ property :old_value, Text, :field => 'old-value'
7
+ property :new_value, Text, :field => 'new-value'
8
+ property :property, String, :length => 40, :key => true
9
+ property :message, Text
10
+ property :status, String, :length => 40
11
+ property :timestamp, DateTime
12
+ property :resource_type, Text, :field => 'resource-type', :key => true
13
+ property :resource_title, Text, :field => 'resource-title', :key => true
14
+
15
+ belongs_to :node, :model => 'Node', :child_key => :certname
16
+ belongs_to :report, :model => 'Report', :key => true
17
+
18
+ @server_fields = [
19
+ :certname,
20
+ :report,
21
+ :status,
22
+ :timestamp,
23
+ :resource_type,
24
+ :resource_title,
25
+ :property,
26
+ :new_value,
27
+ :old_value,
28
+ :message,
29
+ ]
30
+ class << self
31
+ attr_reader :server_fields
32
+ end
33
+ end
@@ -0,0 +1,15 @@
1
+ class Fact
2
+ include DataMapper::Resource
3
+
4
+ storage_names[:default] = 'v2/facts'
5
+
6
+ property :name, Text, :key => true
7
+ property :value, Text
8
+
9
+ belongs_to :node, :model => 'Node', :child_key => :certname, :key => true
10
+
11
+ @server_fields = [:name, :value, :certname]
12
+ class << self
13
+ attr_reader :server_fields
14
+ end
15
+ end
@@ -0,0 +1,19 @@
1
+ class Node
2
+ include DataMapper::Resource
3
+
4
+ storage_names[:default] = 'v2/nodes'
5
+
6
+ property :name, Text, :key => true
7
+ property :deactivated, DateTime
8
+ property :catalog_timestamp, DateTime
9
+ property :report_timestamp, DateTime
10
+
11
+ has n, :facts, :model => 'Fact', :child_key => [ :certname ]
12
+ has n, :events, :model => 'Event', :child_key => [ :certname ]
13
+ has n, :reports, :model => 'Report', :child_key => [ :certname ]
14
+
15
+ @server_fields = [:name]
16
+ class << self
17
+ attr_reader :server_fields
18
+ end
19
+ end
@@ -0,0 +1,22 @@
1
+ class Report
2
+ include DataMapper::Resource
3
+
4
+ storage_names[:default] = 'experimental/reports'
5
+
6
+ property :id, String, :length => 40, :key => true
7
+ property :end_time, DateTime, :field => 'end-time'
8
+ property :start_time, DateTime, :field => 'start-time'
9
+ property :receive_time, DateTime, :field => 'receive-time'
10
+ property :configuration_version, String, :length => 255, :field => 'configuraion-version'
11
+ property :report_format, Integer, :field => 'report-format'
12
+ property :puppet_version, String, :length => 255, :field => 'puppet-version'
13
+
14
+ belongs_to :node, :model => 'Node', :child_key => :certname
15
+
16
+ has n, :events, :model => 'Event', :child_key => [ :report ]
17
+
18
+ @server_fields = [ :certname ]
19
+ class << self
20
+ attr_reader :server_fields
21
+ end
22
+ end
@@ -0,0 +1,30 @@
1
+ require 'dm-types'
2
+
3
+ class Resource
4
+ include DataMapper::Resource
5
+
6
+ storage_names[:default] = 'v2/resources'
7
+
8
+ property :parameters, Json
9
+ property :sourceline, Integer
10
+ property :sourcefile, Text
11
+ property :exported, Boolean, :required => true
12
+ property :type, Text, :required => true, :key => true
13
+ property :title, Text, :required => true, :key => true
14
+ property :tags, Json, :required => true
15
+
16
+ belongs_to :node, :model => 'Node', :child_key => :certname, :key => true
17
+ @server_fields = [
18
+ :tag,
19
+ :certname,
20
+ :parameters,
21
+ :type,
22
+ :title,
23
+ :exported,
24
+ :sourcefile,
25
+ :sourceline,
26
+ ]
27
+ class << self
28
+ attr_reader :server_fields
29
+ end
30
+ end
@@ -0,0 +1,6 @@
1
+ # Load all PuppetDB models
2
+ require 'dm-puppetdb-adapter/models/node'
3
+ require 'dm-puppetdb-adapter/models/resource'
4
+ require 'dm-puppetdb-adapter/models/fact'
5
+ require 'dm-puppetdb-adapter/models/report'
6
+ require 'dm-puppetdb-adapter/models/event'
@@ -0,0 +1 @@
1
+ require 'dm-puppetdb-adapter/adapter'
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dm-puppetdb-adapter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Erik Dalén
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-06-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: json
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: puppet
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '3'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: dm-types
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: PuppetDB adapter for DataMapper
70
+ email:
71
+ - erik.gustav.dalen@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files:
75
+ - LICENSE
76
+ files:
77
+ - Gemfile
78
+ - LICENSE
79
+ - dm-puppetdb-adapter.gemspec
80
+ - lib/dm-puppetdb-adapter.rb
81
+ - lib/dm-puppetdb-adapter/adapter.rb
82
+ - lib/dm-puppetdb-adapter/models.rb
83
+ - lib/dm-puppetdb-adapter/models/event.rb
84
+ - lib/dm-puppetdb-adapter/models/fact.rb
85
+ - lib/dm-puppetdb-adapter/models/node.rb
86
+ - lib/dm-puppetdb-adapter/models/report.rb
87
+ - lib/dm-puppetdb-adapter/models/resource.rb
88
+ homepage: https://github.com/dalen/dm-puppetdbadapter
89
+ licenses:
90
+ - MIT License (Expat)
91
+ metadata: {}
92
+ post_install_message:
93
+ rdoc_options: []
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - '>='
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - '>='
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ requirements: []
107
+ rubyforge_project:
108
+ rubygems_version: 2.0.3
109
+ signing_key:
110
+ specification_version: 4
111
+ summary: PuppetDB adapter for DataMapper
112
+ test_files: []