onering-agent 0.4.3
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 +15 -0
- data/bin/onering +68 -0
- data/lib/etc/facter.list +19 -0
- data/lib/onering.rb +32 -0
- data/lib/onering/api.rb +322 -0
- data/lib/onering/cli.rb +92 -0
- data/lib/onering/cli/assets.rb +138 -0
- data/lib/onering/cli/automation.rb +62 -0
- data/lib/onering/cli/call.rb +53 -0
- data/lib/onering/cli/devices.rb +98 -0
- data/lib/onering/cli/fact.rb +22 -0
- data/lib/onering/cli/reporter.rb +121 -0
- data/lib/onering/config.rb +62 -0
- data/lib/onering/logger.rb +141 -0
- data/lib/onering/plugins/assets.rb +54 -0
- data/lib/onering/plugins/authentication.rb +35 -0
- data/lib/onering/plugins/automation.rb +70 -0
- data/lib/onering/plugins/reporter.rb +360 -0
- data/lib/onering/util.rb +150 -0
- data/lib/onering/version.rb +8 -0
- metadata +188 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
module Onering
|
2
|
+
module CLI
|
3
|
+
class Fact < Plugin
|
4
|
+
def self.configure(global={})
|
5
|
+
@opts = ::Trollop::options do
|
6
|
+
banner <<-EOS
|
7
|
+
Return the value of an internal fact.
|
8
|
+
|
9
|
+
Usage:
|
10
|
+
onering [global] fact [name]
|
11
|
+
|
12
|
+
EOS
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.run(args)
|
17
|
+
args[0] = :hardwareid if args[0] and args[0] == 'id'
|
18
|
+
return Onering::Util.fact(args[0])
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
module Onering
|
2
|
+
module CLI
|
3
|
+
class Report < Plugin
|
4
|
+
DEFAULT_CACHE_MAXAGE=600
|
5
|
+
|
6
|
+
def self.configure(global={})
|
7
|
+
@global_opts = global
|
8
|
+
@api = Onering::CLI.connect(@global_opts.merge({
|
9
|
+
:autoconnect => false
|
10
|
+
}))
|
11
|
+
|
12
|
+
@opts = ::Trollop::options do
|
13
|
+
banner <<-EOS
|
14
|
+
Generate a system report that can be saved or submitted to a Onering server
|
15
|
+
|
16
|
+
Subcommands:
|
17
|
+
<none>
|
18
|
+
Generate and output the system inventory report.
|
19
|
+
|
20
|
+
get <property> [fallback]
|
21
|
+
Get a specific <property> from the report, return [fallback] if not found.
|
22
|
+
|
23
|
+
save
|
24
|
+
Generate and save the system inventory report to Onering.
|
25
|
+
|
26
|
+
Usage:
|
27
|
+
onering [global] report [options] [subcommands]
|
28
|
+
|
29
|
+
Options:
|
30
|
+
EOS
|
31
|
+
opt :id, "Override the autodetected Hardware ID for this node", :short => '-I', :type => :string
|
32
|
+
opt :fields, "Set the named FIELD to equal VALUE in the format FIELD=VALUE. Can be specified multiple times", :short => '-o', :type => :string, :multi => true
|
33
|
+
opt :save, "Save the report output to the configured Onering server"
|
34
|
+
opt :timeout, "The maximum amount of time to wait for a report to be generated", :type => :integer, :default => 60
|
35
|
+
opt :plugin_timeout, "The maximum amount of time to wait for a report plugin to return data", :type => :integer, :default => 10
|
36
|
+
opt :local, "Do not attempt to contact a remote server for retrieving values not found locally", :type => :boolean, :default => false
|
37
|
+
opt :cachefile, "Use the specified file as a local report cache", :type => :string, :short => '-F'
|
38
|
+
opt :nocache, "Do not attempt to use a cache file for report generation", :type => :boolean, :default => false
|
39
|
+
opt :maxage, "Maxmimum age (in seconds) of the cache before it is automatically regenerated", :type => :integer, :default => DEFAULT_CACHE_MAXAGE
|
40
|
+
|
41
|
+
stop_on %w{get save}
|
42
|
+
end
|
43
|
+
|
44
|
+
# initialize report generator with user options
|
45
|
+
@_reporter = Onering::Reporter.new({
|
46
|
+
:id => @opts[:id],
|
47
|
+
:timeout => @opts[:timeout],
|
48
|
+
:plugin_timeout => @opts[:plugin_timeout],
|
49
|
+
:nocache => @opts[:nocache],
|
50
|
+
:cachefile => @opts[:cachefile],
|
51
|
+
:maxage => @opts[:maxage]
|
52
|
+
}.compact)
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.run(args)
|
56
|
+
# saving, by default, should not use the cache (but should update it to keep it fresh)
|
57
|
+
if @opts[:save] === true or args[0] == 'save'
|
58
|
+
report = _report({
|
59
|
+
:cacheregen => true
|
60
|
+
})
|
61
|
+
else
|
62
|
+
report = _report()
|
63
|
+
end
|
64
|
+
|
65
|
+
# pull overrides from CLI arguments
|
66
|
+
@opts[:fields].each do |field|
|
67
|
+
key, value = field.split('=', 2)
|
68
|
+
Onering::Logger.debug("Override value #{key} from command line argument", "Onering::CLI::Report")
|
69
|
+
|
70
|
+
value = nil if ['null', '', '-'].include?(value.to_s.strip.chomp)
|
71
|
+
report = report.set(key, value)
|
72
|
+
end
|
73
|
+
|
74
|
+
# save if specified
|
75
|
+
if @opts[:save] === true
|
76
|
+
_save(report)
|
77
|
+
|
78
|
+
else
|
79
|
+
sc = args.shift
|
80
|
+
|
81
|
+
case (sc.downcase.to_sym rescue nil)
|
82
|
+
# -----------------------------------------------------------------------------
|
83
|
+
when :save
|
84
|
+
_save(report)
|
85
|
+
return nil
|
86
|
+
|
87
|
+
when :get
|
88
|
+
Onering::Logger.fatal!("Expected at least 1 parameter, got #{args.length}", "Onering::CLI::Report") unless args.length >= 1
|
89
|
+
return @_reporter.get(args[0], args[1], {
|
90
|
+
:data => report,
|
91
|
+
:api => @global_opts,
|
92
|
+
:local => @opts[:local]
|
93
|
+
})
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
return report
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
def self._save(report)
|
102
|
+
@api.connect()
|
103
|
+
@api.assets.save(report['id']) do
|
104
|
+
MultiJson.dump(report)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def self._report(options={})
|
109
|
+
begin
|
110
|
+
Onering::Logger.debug("Gathering local data for report", "Onering::CLI::Report")
|
111
|
+
Onering::Logger.fatal("Reporter not configured. This is a bug", "Onering::CLI::Report") if @_reporter.nil?
|
112
|
+
report = @_reporter.report(options).stringify_keys()
|
113
|
+
|
114
|
+
return report
|
115
|
+
rescue Timeout::Error
|
116
|
+
Onering::Logger.fatal!("Report took too long to generate, exiting...", "Onering::CLI::Report")
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'hashlib'
|
3
|
+
|
4
|
+
module Onering
|
5
|
+
class Config
|
6
|
+
class<<self
|
7
|
+
DEFAULT_CONFIG={}
|
8
|
+
DEFAULT_OPTIONS_FILE=["~/.onering/cli.yml", "~/.onering/key.yml", "/etc/onering/cli.yml", "/etc/onering/key.yml"]
|
9
|
+
|
10
|
+
def load(configfile=nil, config={})
|
11
|
+
if configfile.nil?
|
12
|
+
configfile = []
|
13
|
+
else
|
14
|
+
# recursively grab all .yml files if directory is specified
|
15
|
+
configfile = (File.directory?(configfile) ? Dir.glob(File.join(configfile, "**", "*.yml")).sort : [configfile])
|
16
|
+
end
|
17
|
+
|
18
|
+
# list all existing config files from least specific to most
|
19
|
+
@_configfiles = (configfile + DEFAULT_OPTIONS_FILE).compact.select{|i|
|
20
|
+
(File.exists?(File.expand_path(i)) rescue false)
|
21
|
+
}.reverse
|
22
|
+
|
23
|
+
# merge all config files with more-specific values overriding less-specific ones
|
24
|
+
@_config ||= DEFAULT_CONFIG
|
25
|
+
@_configfiles_seen ||= Set.new()
|
26
|
+
|
27
|
+
# only load files we haven't seen before
|
28
|
+
(@_configfiles - @_configfiles_seen.to_a).each do |i|
|
29
|
+
c = YAML.load(File.read(File.expand_path(i))) rescue {}
|
30
|
+
|
31
|
+
if c and not c.empty?
|
32
|
+
Onering::Logger.info("Loading config file at #{File.expand_path(i) rescue i}", "Onering::Config")
|
33
|
+
@_config.deep_merge!(c)
|
34
|
+
end
|
35
|
+
|
36
|
+
@_configfiles_seen << i
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
# settings specified in the library override everything
|
41
|
+
unless config.empty?
|
42
|
+
Onering::Logger.debug("Merging settings specified in library instantiation", "Onering::Config")
|
43
|
+
@_config.deep_merge!(config.compact)
|
44
|
+
end
|
45
|
+
|
46
|
+
return @_config
|
47
|
+
end
|
48
|
+
|
49
|
+
def get(key, default=nil)
|
50
|
+
@_config.get(key, default)
|
51
|
+
end
|
52
|
+
|
53
|
+
def set(key, value)
|
54
|
+
@_config.set(key, value)
|
55
|
+
end
|
56
|
+
|
57
|
+
def unset(key)
|
58
|
+
@_config.unset(key)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'rainbow'
|
3
|
+
require 'onering/version'
|
4
|
+
|
5
|
+
module Onering
|
6
|
+
class Logger
|
7
|
+
def self.setup(options={})
|
8
|
+
outputfn = options[:destination]
|
9
|
+
@_verbosity = 1
|
10
|
+
|
11
|
+
if options[:destination] == /STDOUT/i
|
12
|
+
options[:destination] = STDOUT
|
13
|
+
|
14
|
+
elsif options[:destination] == /STDERR/i or
|
15
|
+
options[:destination].nil?
|
16
|
+
options[:destination] = STDERR
|
17
|
+
|
18
|
+
elsif File.writable?(options[:destination])
|
19
|
+
options[:destination] = File.open(options[:destination], 'a')
|
20
|
+
|
21
|
+
else
|
22
|
+
options[:destination] = STDERR
|
23
|
+
end
|
24
|
+
|
25
|
+
@_logger = ::Logger.new(options[:destination])
|
26
|
+
@_logger.formatter = (options[:formatter] || proc{|severity, datetime, source, msg|
|
27
|
+
case severity.downcase.to_sym
|
28
|
+
when :fatal then sevtag = '!!'
|
29
|
+
when :error then sevtag = 'EE'
|
30
|
+
when :warn then sevtag = 'WW'
|
31
|
+
when :info then sevtag = 'II'
|
32
|
+
when :debug then sevtag = 'DD'
|
33
|
+
when :output then sevtag = ''
|
34
|
+
else sevtag = '??'
|
35
|
+
end
|
36
|
+
|
37
|
+
if options[:sevtag] == false
|
38
|
+
logline = [(source.nil? ? nil : "[#{source}]"), msg].compact.join(' ')
|
39
|
+
else
|
40
|
+
logline = ["#{sevtag} ", (source.nil? ? nil : "[#{source}]"), msg].compact.join(' ')
|
41
|
+
end
|
42
|
+
|
43
|
+
if options[:destination] === STDOUT or options[:destination] === STDERR
|
44
|
+
case severity.downcase.to_sym
|
45
|
+
when :fatal, :error
|
46
|
+
logline = logline.foreground(:red)
|
47
|
+
when :warn
|
48
|
+
logline = logline.foreground(:yellow)
|
49
|
+
when :info
|
50
|
+
logline = logline.foreground(:green)
|
51
|
+
when :debug, :debug2, :debug3
|
52
|
+
logline = logline.foreground(:blue)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
options[:destination].puts(logline)
|
57
|
+
})
|
58
|
+
|
59
|
+
self.level = (options[:threshold] || :info)
|
60
|
+
|
61
|
+
self.debug("onering-client v#{Onering::Client::VERSION} started") if defined?(Onering::FULL_CLIENT)
|
62
|
+
self.debug("Logger is initialized. Output is #{outputfn || 'stderr'}, threshold: #{options[:threshold]} or worse", (options[:name] || "Onering::Logger"))
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
def self.logger()
|
67
|
+
return @_logger
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.level=(severity)
|
71
|
+
@_logger.sev_threshold = _get_level(severity)
|
72
|
+
@_verbosity = (Integer(severity.to_s[-1]) rescue 1)
|
73
|
+
|
74
|
+
@_logger.sev_threshold
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
def self.log(severity, message, source=nil, verbosity=1)
|
79
|
+
if defined?(@_logger)
|
80
|
+
if @_verbosity >= verbosity
|
81
|
+
@_logger.add(_get_level(severity), message, source)
|
82
|
+
return true
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
return false
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.fatal(message, source=nil, raise_error=false)
|
90
|
+
self.log(:fatal, message, source)
|
91
|
+
raise Onering::Client::FatalError.new(message) if raise_error === true
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.fatal!(message, source=nil)
|
95
|
+
self.fatal(message, source, true)
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.error(message, source=nil)
|
99
|
+
self.log(:error, message, source)
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.warn(message, source=nil)
|
103
|
+
self.log(:warn, message, source)
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.info(message, source=nil)
|
107
|
+
self.log(:info, message, source)
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.debug(message, source=nil)
|
111
|
+
self.log(:debug, message, source)
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.debug2(message, source=nil)
|
115
|
+
self.log(:debug, message, source, 2)
|
116
|
+
end
|
117
|
+
|
118
|
+
def self.debug3(message, source=nil)
|
119
|
+
self.log(:debug, message, source, 3)
|
120
|
+
end
|
121
|
+
|
122
|
+
def self.output(message, source=nil)
|
123
|
+
self.log(:output, message, source)
|
124
|
+
end
|
125
|
+
|
126
|
+
def self._get_level(severity)
|
127
|
+
case severity.to_sym
|
128
|
+
when :fatal
|
129
|
+
return ::Logger::FATAL
|
130
|
+
when :error
|
131
|
+
return ::Logger::ERROR
|
132
|
+
when :warn
|
133
|
+
return ::Logger::WARN
|
134
|
+
when :info
|
135
|
+
return ::Logger::INFO
|
136
|
+
else
|
137
|
+
return ::Logger::DEBUG
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Onering
|
2
|
+
class API
|
3
|
+
class Assets < API
|
4
|
+
def show(id)
|
5
|
+
get("/devices/#{id}").parsed_response
|
6
|
+
end
|
7
|
+
|
8
|
+
def get_field(id, field, fallback=nil)
|
9
|
+
rv = get("/devices/#{id}/get/#{field}")
|
10
|
+
rv = (rv.parsed_response rescue rv.response.body)
|
11
|
+
return fallback if rv.nil? or (rv.is_a?(String) and rv.strip.chomp.empty?)
|
12
|
+
return rv
|
13
|
+
end
|
14
|
+
|
15
|
+
def set_field(id, field, value)
|
16
|
+
rv = get("/devices/#{id}/set/#{field}/#{value}")
|
17
|
+
rv.parsed_response rescue rv.response.body
|
18
|
+
end
|
19
|
+
|
20
|
+
def list(field, options={
|
21
|
+
:unique => true,
|
22
|
+
:sort => true,
|
23
|
+
:filter => nil
|
24
|
+
})
|
25
|
+
qs = {
|
26
|
+
:q => make_filter(options[:filter])
|
27
|
+
} if options[:filter]
|
28
|
+
|
29
|
+
rv = get("/devices/list/#{[*field].join('/')}", {
|
30
|
+
:query => qs
|
31
|
+
}).parsed_response
|
32
|
+
|
33
|
+
rv = rv.uniq if options[:unique]
|
34
|
+
rv = rv.sort if options[:sort]
|
35
|
+
|
36
|
+
return rv
|
37
|
+
end
|
38
|
+
|
39
|
+
def find(filter, options={})
|
40
|
+
get("/devices/find/#{make_filter(filter)}").parsed_response
|
41
|
+
end
|
42
|
+
|
43
|
+
def save(id, data=nil, &block)
|
44
|
+
if block_given?
|
45
|
+
post("/devices/#{id}", {}, &block)
|
46
|
+
else
|
47
|
+
post("/devices/#{id}", {
|
48
|
+
:body => data
|
49
|
+
})
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Onering
|
2
|
+
class API
|
3
|
+
class Auth < API
|
4
|
+
def _check_type(type)
|
5
|
+
raise "Invalid authentication module object '#{type}'" unless %w{
|
6
|
+
users groups capabilities
|
7
|
+
}.include?(type.to_s)
|
8
|
+
end
|
9
|
+
|
10
|
+
def show(type, id='current')
|
11
|
+
_check_type(type)
|
12
|
+
get("#{type}/#{id}").parsed_response
|
13
|
+
end
|
14
|
+
|
15
|
+
def list(type, field='id', options={
|
16
|
+
:unique => true,
|
17
|
+
:sort => true,
|
18
|
+
:filter => nil
|
19
|
+
})
|
20
|
+
_check_type(type)
|
21
|
+
rv = get("#{type}/list").parsed_response.collect{|i| i[field.to_s] }
|
22
|
+
rv = rv.uniq if options[:unique]
|
23
|
+
rv = rv.sort if options[:sort]
|
24
|
+
rv
|
25
|
+
end
|
26
|
+
|
27
|
+
def save(type, id, data)
|
28
|
+
_check_type(type)
|
29
|
+
post("#{type}/#{id}", {
|
30
|
+
:body => data
|
31
|
+
}).parsed_response
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Onering
|
2
|
+
class API
|
3
|
+
class AutomationRequests < API
|
4
|
+
def summary(fields)
|
5
|
+
get("/automation/requests/summary/#{[*fields].join('/')}").parsed_response
|
6
|
+
end
|
7
|
+
|
8
|
+
def find_by_status(status)
|
9
|
+
get("/automation/requests/status/#{status}").parsed_response
|
10
|
+
end
|
11
|
+
|
12
|
+
def show(id)
|
13
|
+
get("/automation/requests/#{id}").parsed_response
|
14
|
+
end
|
15
|
+
|
16
|
+
def requeue(id)
|
17
|
+
get("/automation/requests/#{id}/requeue").parsed_response
|
18
|
+
end
|
19
|
+
|
20
|
+
def flush_queue()
|
21
|
+
get("/automation/requests/flush").parsed_response
|
22
|
+
end
|
23
|
+
|
24
|
+
def purge()
|
25
|
+
get("/automation/requests/purge").parsed_response
|
26
|
+
end
|
27
|
+
|
28
|
+
def requeue_all_failed()
|
29
|
+
get("/automation/requests/requeue").parsed_response
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
# -----------------------------------------------------------------------------
|
35
|
+
class AutomationJobs < API
|
36
|
+
def list()
|
37
|
+
get("/automation/jobs/list").parsed_response
|
38
|
+
end
|
39
|
+
|
40
|
+
def show(name)
|
41
|
+
get("/automation/jobs/#{name}").parsed_response
|
42
|
+
end
|
43
|
+
|
44
|
+
def requests_waiting(name)
|
45
|
+
get("/automation/jobs/#{name}/waiting").parsed_response
|
46
|
+
end
|
47
|
+
|
48
|
+
def run(name, options={}, &block)
|
49
|
+
if block_given?
|
50
|
+
post("/automation/jobs/#{name}/run", {
|
51
|
+
:query => options
|
52
|
+
}, &block).parsed_response
|
53
|
+
else
|
54
|
+
get("/automation/jobs/#{name}/run", {
|
55
|
+
:query => options
|
56
|
+
}).parsed_response
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# -----------------------------------------------------------------------------
|
62
|
+
class AutomationTasks < API
|
63
|
+
def run(name, options={})
|
64
|
+
get("/automation/tasks/#{name}/run", {
|
65
|
+
:query => options
|
66
|
+
}).parsed_response
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|