quixoten-puppetdb-terminus 2.0.0.rc1
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.
- checksums.yaml +7 -0
- data/.gitignore +23 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +202 -0
- data/README.md +29 -0
- data/Rakefile +16 -0
- data/lib/puppet/application/storeconfigs.rb +4 -0
- data/lib/puppet/face/node/deactivate.rb +38 -0
- data/lib/puppet/face/node/status.rb +83 -0
- data/lib/puppet/face/storeconfigs.rb +179 -0
- data/lib/puppet/indirector/catalog/puppetdb.rb +350 -0
- data/lib/puppet/indirector/facts/puppetdb.rb +134 -0
- data/lib/puppet/indirector/facts/puppetdb_apply.rb +25 -0
- data/lib/puppet/indirector/node/puppetdb.rb +22 -0
- data/lib/puppet/indirector/resource/puppetdb.rb +107 -0
- data/lib/puppet/reports/puppetdb.rb +186 -0
- data/lib/puppet/util/puppetdb/blacklist.rb +35 -0
- data/lib/puppet/util/puppetdb/char_encoding.rb +212 -0
- data/lib/puppet/util/puppetdb/command.rb +113 -0
- data/lib/puppet/util/puppetdb/command_names.rb +8 -0
- data/lib/puppet/util/puppetdb/config.rb +112 -0
- data/lib/puppet/util/puppetdb/global_check.rb +31 -0
- data/lib/puppet/util/puppetdb.rb +108 -0
- data/lib/puppetdb/terminus/version.rb +5 -0
- data/lib/puppetdb/terminus.rb +6 -0
- data/lib/puppetdb-terminus.rb +1 -0
- data/lib/quixoten-puppetdb-terminus.rb +1 -0
- data/puppetdb-terminus.gemspec +23 -0
- metadata +99 -0
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'puppet/error'
|
2
|
+
require 'puppet/network/http_pool'
|
3
|
+
require 'puppet/util/puppetdb'
|
4
|
+
require 'puppet/util/puppetdb/command_names'
|
5
|
+
require 'puppet/util/puppetdb/char_encoding'
|
6
|
+
require 'json'
|
7
|
+
|
8
|
+
class Puppet::Util::Puppetdb::Command
|
9
|
+
include Puppet::Util::Puppetdb
|
10
|
+
include Puppet::Util::Puppetdb::CommandNames
|
11
|
+
|
12
|
+
Url = "/v3/commands"
|
13
|
+
|
14
|
+
# Public instance methods
|
15
|
+
|
16
|
+
# Initialize a Command object, for later submission.
|
17
|
+
#
|
18
|
+
# @param command String the name of the command; should be one of the
|
19
|
+
# constants defined in `Puppet::Util::Puppetdb::CommandNames`
|
20
|
+
# @param version Integer the command version number
|
21
|
+
# @param certname The certname that this command operates on (is not
|
22
|
+
# included in the actual submission)
|
23
|
+
# @param payload Object the payload of the command. This object should be a
|
24
|
+
# primitive (numeric type, string, array, or hash) that is natively supported
|
25
|
+
# by JSON serialization / deserialization libraries.
|
26
|
+
def initialize(command, version, certname, payload)
|
27
|
+
@command = command
|
28
|
+
@version = version
|
29
|
+
@certname = certname
|
30
|
+
profile "Format payload" do
|
31
|
+
@payload = self.class.format_payload(command, version, payload)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
attr_reader :command, :version, :certname, :payload
|
36
|
+
|
37
|
+
# Submit the command, returning the result hash.
|
38
|
+
#
|
39
|
+
# @return [Hash <String, String>]
|
40
|
+
def submit
|
41
|
+
checksum = Digest::SHA1.hexdigest(payload)
|
42
|
+
|
43
|
+
for_whom = " for #{certname}" if certname
|
44
|
+
|
45
|
+
begin
|
46
|
+
response = profile "Submit command HTTP post" do
|
47
|
+
http = Puppet::Network::HttpPool.http_instance(config.server, config.port)
|
48
|
+
http.post(Url + "?checksum=#{checksum}", payload, headers)
|
49
|
+
end
|
50
|
+
|
51
|
+
Puppet::Util::Puppetdb.log_x_deprecation_header(response)
|
52
|
+
|
53
|
+
if response.is_a? Net::HTTPSuccess
|
54
|
+
result = JSON.parse(response.body)
|
55
|
+
Puppet.info "'#{command}' command#{for_whom} submitted to PuppetDB with UUID #{result['uuid']}"
|
56
|
+
result
|
57
|
+
else
|
58
|
+
# Newline characters cause an HTTP error, so strip them
|
59
|
+
error = "[#{response.code} #{response.message}] #{response.body.gsub(/[\r\n]/, '')}"
|
60
|
+
if config.soft_write_failure
|
61
|
+
Puppet.err "'#{command}'command#{for_whom} failed during submission to PuppetDB: #{error}"
|
62
|
+
else
|
63
|
+
raise Puppet::Error, error
|
64
|
+
end
|
65
|
+
end
|
66
|
+
rescue => e
|
67
|
+
error = "Failed to submit '#{command}' command#{for_whom} to PuppetDB at #{config.server}:#{config.port}: #{e}"
|
68
|
+
if config.soft_write_failure
|
69
|
+
Puppet.err error
|
70
|
+
else
|
71
|
+
# TODO: Use new exception handling methods from Puppet 3.0 here as soon as
|
72
|
+
# we are able to do so (can't call them yet w/o breaking backwards
|
73
|
+
# compatibility.) We should either be using a nested exception or calling
|
74
|
+
# Puppet::Util::Logging#log_exception or #log_and_raise here; w/o them
|
75
|
+
# we lose context as to where the original exception occurred.
|
76
|
+
puts e, e.backtrace if Puppet[:trace]
|
77
|
+
raise Puppet::Error, error
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
# @!group Private class methods
|
84
|
+
|
85
|
+
# @api private
|
86
|
+
def self.format_payload(command, version, payload)
|
87
|
+
message = {
|
88
|
+
:command => command,
|
89
|
+
:version => version,
|
90
|
+
:payload => payload,
|
91
|
+
}.to_pson
|
92
|
+
|
93
|
+
Puppet::Util::Puppetdb::CharEncoding.utf8_string(message)
|
94
|
+
end
|
95
|
+
|
96
|
+
# @!group Private instance methods
|
97
|
+
|
98
|
+
# @api private
|
99
|
+
def headers
|
100
|
+
{
|
101
|
+
"Accept" => "application/json",
|
102
|
+
"Content-Type" => "application/json",
|
103
|
+
}
|
104
|
+
end
|
105
|
+
|
106
|
+
# @api private
|
107
|
+
def config
|
108
|
+
# Would prefer to pass this to the constructor or acquire it some other
|
109
|
+
# way besides this pseudo-global reference.
|
110
|
+
Puppet::Util::Puppetdb.config
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'puppet/util/puppetdb/command_names'
|
2
|
+
require 'puppet/util/puppetdb/blacklist'
|
3
|
+
|
4
|
+
module Puppet::Util::Puppetdb
|
5
|
+
class Config
|
6
|
+
include Puppet::Util::Puppetdb::CommandNames
|
7
|
+
|
8
|
+
# Public class methods
|
9
|
+
|
10
|
+
def self.load(config_file = nil)
|
11
|
+
defaults = {
|
12
|
+
:server => "puppetdb",
|
13
|
+
:port => 8081,
|
14
|
+
:soft_write_failure => false,
|
15
|
+
:ignore_blacklisted_events => true,
|
16
|
+
}
|
17
|
+
|
18
|
+
config_file ||= File.join(Puppet[:confdir], "puppetdb.conf")
|
19
|
+
|
20
|
+
if File.exists?(config_file)
|
21
|
+
Puppet.debug("Configuring PuppetDB terminuses with config file #{config_file}")
|
22
|
+
content = File.read(config_file)
|
23
|
+
else
|
24
|
+
Puppet.debug("No #{config_file} file found; falling back to default server and port #{defaults[:server]}:#{defaults[:port]}")
|
25
|
+
content = ''
|
26
|
+
end
|
27
|
+
|
28
|
+
result = {}
|
29
|
+
section = nil
|
30
|
+
content.lines.each_with_index do |line,number|
|
31
|
+
# Gotta track the line numbers properly
|
32
|
+
number += 1
|
33
|
+
case line
|
34
|
+
when /^\[(\w+)\s*\]$/
|
35
|
+
section = $1
|
36
|
+
result[section] ||= {}
|
37
|
+
when /^\s*(\w+)\s*=\s*(\S+)\s*$/
|
38
|
+
raise "Setting '#{line}' is illegal outside of section in PuppetDB config #{config_file}:#{number}" unless section
|
39
|
+
result[section][$1] = $2
|
40
|
+
when /^\s*[#;]/
|
41
|
+
# Skip comments
|
42
|
+
when /^\s*$/
|
43
|
+
# Skip blank lines
|
44
|
+
else
|
45
|
+
raise "Unparseable line '#{line}' in PuppetDB config #{config_file}:#{number}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
main_section = result['main'] || {}
|
51
|
+
# symbolize the keys
|
52
|
+
main_section = main_section.inject({}) {|h, (k,v)| h[k.to_sym] = v ; h}
|
53
|
+
# merge with defaults but filter out anything except the legal settings
|
54
|
+
config_hash = defaults.merge(main_section).reject do |k, v|
|
55
|
+
!([:server, :port, :ignore_blacklisted_events, :soft_write_failure].include?(k))
|
56
|
+
end
|
57
|
+
|
58
|
+
config_hash[:server] = config_hash[:server].strip
|
59
|
+
config_hash[:port] = config_hash[:port].to_i
|
60
|
+
config_hash[:ignore_blacklisted_events] =
|
61
|
+
Puppet::Util::Puppetdb.to_bool(config_hash[:ignore_blacklisted_events])
|
62
|
+
config_hash[:soft_write_failure] =
|
63
|
+
Puppet::Util::Puppetdb.to_bool(config_hash[:soft_write_failure])
|
64
|
+
|
65
|
+
self.new(config_hash)
|
66
|
+
rescue => detail
|
67
|
+
puts detail.backtrace if Puppet[:trace]
|
68
|
+
Puppet.warning "Could not configure PuppetDB terminuses: #{detail}"
|
69
|
+
raise
|
70
|
+
end
|
71
|
+
|
72
|
+
# @!group Public instance methods
|
73
|
+
|
74
|
+
def initialize(config_hash = {})
|
75
|
+
@config = config_hash
|
76
|
+
initialize_blacklisted_events()
|
77
|
+
end
|
78
|
+
|
79
|
+
def server
|
80
|
+
config[:server]
|
81
|
+
end
|
82
|
+
|
83
|
+
def port
|
84
|
+
config[:port]
|
85
|
+
end
|
86
|
+
|
87
|
+
def ignore_blacklisted_events?
|
88
|
+
config[:ignore_blacklisted_events]
|
89
|
+
end
|
90
|
+
|
91
|
+
def is_event_blacklisted?(event)
|
92
|
+
@blacklist.is_event_blacklisted? event
|
93
|
+
end
|
94
|
+
|
95
|
+
def soft_write_failure
|
96
|
+
config[:soft_write_failure]
|
97
|
+
end
|
98
|
+
|
99
|
+
# @!group Private instance methods
|
100
|
+
|
101
|
+
# @!attribute [r] count
|
102
|
+
# @api private
|
103
|
+
attr_reader :config
|
104
|
+
|
105
|
+
Blacklist = Puppet::Util::Puppetdb::Blacklist
|
106
|
+
|
107
|
+
# @api private
|
108
|
+
def initialize_blacklisted_events(events = Blacklist::BlacklistedEvents)
|
109
|
+
@blacklist = Blacklist.new(events)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'semver'
|
2
|
+
require 'puppet/version'
|
3
|
+
require 'puppet/error'
|
4
|
+
|
5
|
+
module Puppet::Util::Puppetdb
|
6
|
+
# Global checks for version support and other validations before the terminus
|
7
|
+
# is used.
|
8
|
+
#
|
9
|
+
class GlobalCheck
|
10
|
+
# Validate that the support for the version of Puppet we are running on is
|
11
|
+
# still maintained.
|
12
|
+
#
|
13
|
+
# @param minimum [String] minimum version for operation
|
14
|
+
# @throws [Puppet::Error] raised if current version is unsupported
|
15
|
+
# @api private
|
16
|
+
def self.puppet_version_check(minimum)
|
17
|
+
minimum_version = ::SemVer.new(minimum)
|
18
|
+
puppet_version = ::SemVer.new(Puppet.version)
|
19
|
+
if (puppet_version <=> minimum_version) == -1 then
|
20
|
+
raise Puppet::Error, "You are attempting to use puppetdb-terminus on an unsupported version of Puppet (#{puppet_version}) the minimum supported version is #{minimum_version}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Run all checks
|
25
|
+
#
|
26
|
+
# @throws [Puppet::Error] raised for any validation errors
|
27
|
+
def self.run
|
28
|
+
self.puppet_version_check("3.5.1")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'puppet/util'
|
2
|
+
require 'puppet/util/logging'
|
3
|
+
require 'puppet/util/profiler'
|
4
|
+
require 'puppet/util/puppetdb/global_check'
|
5
|
+
require 'puppet/util/puppetdb/command_names'
|
6
|
+
require 'puppet/util/puppetdb/command'
|
7
|
+
require 'puppet/util/puppetdb/config'
|
8
|
+
require 'digest/sha1'
|
9
|
+
require 'time'
|
10
|
+
require 'fileutils'
|
11
|
+
|
12
|
+
module Puppet::Util::Puppetdb
|
13
|
+
|
14
|
+
def self.server
|
15
|
+
config.server
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.port
|
19
|
+
config.port
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.config
|
23
|
+
@config ||= Puppet::Util::Puppetdb::Config.load
|
24
|
+
@config
|
25
|
+
end
|
26
|
+
|
27
|
+
# This magical stuff is needed so that the indirector termini will make requests to
|
28
|
+
# the correct host/port, because this module gets mixed in to our indirector
|
29
|
+
# termini.
|
30
|
+
module ClassMethods
|
31
|
+
def server
|
32
|
+
Puppet::Util::Puppetdb.server
|
33
|
+
end
|
34
|
+
|
35
|
+
def port
|
36
|
+
Puppet::Util::Puppetdb.port
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.included(child)
|
41
|
+
child.extend ClassMethods
|
42
|
+
end
|
43
|
+
|
44
|
+
# Given an instance of ruby's Time class, this method converts it to a String
|
45
|
+
# that conforms to PuppetDB's wire format for representing a date/time.
|
46
|
+
def self.to_wire_time(time)
|
47
|
+
# The current implementation simply calls iso8601, but having this method
|
48
|
+
# allows us to change that in the future if needed w/o being forced to
|
49
|
+
# update all of the date objects elsewhere in the code.
|
50
|
+
time.iso8601(9)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Convert a value (usually a string) to a boolean
|
54
|
+
def self.to_bool(value)
|
55
|
+
case value
|
56
|
+
when true, "true"; return true
|
57
|
+
when false, "false"; return false
|
58
|
+
else
|
59
|
+
raise ArgumentError.new("invalid value for Boolean: \"#{val}\"")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# @!group Public instance methods
|
64
|
+
|
65
|
+
# Submit a command to PuppetDB.
|
66
|
+
#
|
67
|
+
# @param certname [String] hostname name of puppetdb instance
|
68
|
+
# @param payload [String] payload
|
69
|
+
# @param command_name [String] name of command
|
70
|
+
# @param version [Number] version number of command
|
71
|
+
def submit_command(certname, payload, command_name, version)
|
72
|
+
profile "Submitted command '#{command_name}' version '#{version}'" do
|
73
|
+
command = Puppet::Util::Puppetdb::Command.new(command_name, version, certname, payload)
|
74
|
+
command.submit
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Profile a block of code and log the time it took to execute.
|
79
|
+
#
|
80
|
+
# This outputs logs entries to the Puppet masters logging destination
|
81
|
+
# providing the time it took, a message describing the profiled code
|
82
|
+
# and a leaf location marking where the profile method was called
|
83
|
+
# in the profiled hierachy.
|
84
|
+
#
|
85
|
+
# @param message [String] A description of the profiled event
|
86
|
+
# @param block [Block] The segment of code to profile
|
87
|
+
# @api public
|
88
|
+
def profile(message, &block)
|
89
|
+
message = "PuppetDB: " + message
|
90
|
+
Puppet::Util::Profiler.profile(message, &block)
|
91
|
+
end
|
92
|
+
|
93
|
+
# @!group Private instance methods
|
94
|
+
|
95
|
+
# @api private
|
96
|
+
def config
|
97
|
+
Puppet::Util::Puppetdb.config
|
98
|
+
end
|
99
|
+
|
100
|
+
# @api private
|
101
|
+
def log_x_deprecation_header(response)
|
102
|
+
if warning = response['x-deprecation']
|
103
|
+
Puppet.deprecation_warning "Deprecation from PuppetDB: #{warning}"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
module_function :log_x_deprecation_header
|
107
|
+
|
108
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'puppetdb/terminus'
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'puppetdb-terminus'
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'puppetdb/terminus/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "quixoten-puppetdb-terminus"
|
8
|
+
spec.version = PuppetDB::Terminus::VERSION
|
9
|
+
spec.authors = ["Devin Christensen"]
|
10
|
+
spec.email = ["quixoten@gmail.com"]
|
11
|
+
spec.summary = %q{PuppetDB Terminus}
|
12
|
+
spec.description = %q{PuppetDB Terminus}
|
13
|
+
spec.homepage = "https://github.com/quixoten/puppetdb-terminus"
|
14
|
+
spec.license = "Apache 2.0"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: quixoten-puppetdb-terminus
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2.0.0.rc1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Devin Christensen
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-08-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.6'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: PuppetDB Terminus
|
42
|
+
email:
|
43
|
+
- quixoten@gmail.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- ".gitignore"
|
49
|
+
- Gemfile
|
50
|
+
- LICENSE.txt
|
51
|
+
- README.md
|
52
|
+
- Rakefile
|
53
|
+
- lib/puppet/application/storeconfigs.rb
|
54
|
+
- lib/puppet/face/node/deactivate.rb
|
55
|
+
- lib/puppet/face/node/status.rb
|
56
|
+
- lib/puppet/face/storeconfigs.rb
|
57
|
+
- lib/puppet/indirector/catalog/puppetdb.rb
|
58
|
+
- lib/puppet/indirector/facts/puppetdb.rb
|
59
|
+
- lib/puppet/indirector/facts/puppetdb_apply.rb
|
60
|
+
- lib/puppet/indirector/node/puppetdb.rb
|
61
|
+
- lib/puppet/indirector/resource/puppetdb.rb
|
62
|
+
- lib/puppet/reports/puppetdb.rb
|
63
|
+
- lib/puppet/util/puppetdb.rb
|
64
|
+
- lib/puppet/util/puppetdb/blacklist.rb
|
65
|
+
- lib/puppet/util/puppetdb/char_encoding.rb
|
66
|
+
- lib/puppet/util/puppetdb/command.rb
|
67
|
+
- lib/puppet/util/puppetdb/command_names.rb
|
68
|
+
- lib/puppet/util/puppetdb/config.rb
|
69
|
+
- lib/puppet/util/puppetdb/global_check.rb
|
70
|
+
- lib/puppetdb-terminus.rb
|
71
|
+
- lib/puppetdb/terminus.rb
|
72
|
+
- lib/puppetdb/terminus/version.rb
|
73
|
+
- lib/quixoten-puppetdb-terminus.rb
|
74
|
+
- puppetdb-terminus.gemspec
|
75
|
+
homepage: https://github.com/quixoten/puppetdb-terminus
|
76
|
+
licenses:
|
77
|
+
- Apache 2.0
|
78
|
+
metadata: {}
|
79
|
+
post_install_message:
|
80
|
+
rdoc_options: []
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - ">"
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: 1.3.1
|
93
|
+
requirements: []
|
94
|
+
rubyforge_project:
|
95
|
+
rubygems_version: 2.2.2
|
96
|
+
signing_key:
|
97
|
+
specification_version: 4
|
98
|
+
summary: PuppetDB Terminus
|
99
|
+
test_files: []
|