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.
@@ -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