collins_shell 0.2.14
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/.pryrc +1 -0
- data/.rvmrc +1 -0
- data/Gemfile +18 -0
- data/Gemfile.lock +59 -0
- data/README.md +335 -0
- data/Rakefile +64 -0
- data/VERSION +1 -0
- data/bin/collins-shell +36 -0
- data/collins_shell.gemspec +95 -0
- data/lib/collins_shell.rb +3 -0
- data/lib/collins_shell/asset.rb +198 -0
- data/lib/collins_shell/cli.rb +185 -0
- data/lib/collins_shell/console.rb +129 -0
- data/lib/collins_shell/console/asset.rb +127 -0
- data/lib/collins_shell/console/cache.rb +17 -0
- data/lib/collins_shell/console/command_helpers.rb +131 -0
- data/lib/collins_shell/console/commands.rb +28 -0
- data/lib/collins_shell/console/commands/cat.rb +123 -0
- data/lib/collins_shell/console/commands/cd.rb +61 -0
- data/lib/collins_shell/console/commands/io.rb +26 -0
- data/lib/collins_shell/console/commands/iterators.rb +190 -0
- data/lib/collins_shell/console/commands/tail.rb +178 -0
- data/lib/collins_shell/console/commands/versions.rb +42 -0
- data/lib/collins_shell/console/filesystem.rb +121 -0
- data/lib/collins_shell/console/options_helpers.rb +8 -0
- data/lib/collins_shell/errors.rb +7 -0
- data/lib/collins_shell/ip_address.rb +144 -0
- data/lib/collins_shell/ipmi.rb +67 -0
- data/lib/collins_shell/monkeypatch.rb +60 -0
- data/lib/collins_shell/provision.rb +152 -0
- data/lib/collins_shell/state.rb +98 -0
- data/lib/collins_shell/tag.rb +41 -0
- data/lib/collins_shell/thor.rb +209 -0
- data/lib/collins_shell/util.rb +120 -0
- data/lib/collins_shell/util/asset_printer.rb +265 -0
- data/lib/collins_shell/util/asset_stache.rb +32 -0
- data/lib/collins_shell/util/log_printer.rb +187 -0
- data/lib/collins_shell/util/printer_util.rb +28 -0
- metadata +200 -0
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'terminal-table'
|
2
|
+
require 'pry'
|
3
|
+
|
4
|
+
require 'collins_shell/console/commands'
|
5
|
+
require 'collins_shell/console/filesystem'
|
6
|
+
|
7
|
+
class Pry
|
8
|
+
# We kill the built in completion so we can tell users what things are available
|
9
|
+
module InputCompleter
|
10
|
+
class << self
|
11
|
+
def build_completion_proc(target, commands=[""])
|
12
|
+
proc do |input|
|
13
|
+
commands.map do |cmd|
|
14
|
+
cmd_s = cmd.to_s
|
15
|
+
if cmd_s.include?(":wtf") then
|
16
|
+
"wtf?"
|
17
|
+
else
|
18
|
+
cmd_s
|
19
|
+
end
|
20
|
+
end.select{|s| s.start_with?(input)}.uniq # commands.map
|
21
|
+
end # proc do
|
22
|
+
end # def build_completion_proc
|
23
|
+
end # class << self
|
24
|
+
end # module InputCompleter
|
25
|
+
end # class Pry
|
26
|
+
|
27
|
+
module CollinsShell; module Console
|
28
|
+
|
29
|
+
class << self
|
30
|
+
def run_pry_command command_string, options = {}
|
31
|
+
options = {
|
32
|
+
:show_output => true,
|
33
|
+
:output => Pry.output,
|
34
|
+
:commands => get_pry_commands
|
35
|
+
}.merge!(options)
|
36
|
+
output = options[:show_output] ? options[:output] : StringIO.new
|
37
|
+
pry = Pry.new(
|
38
|
+
:output => output, :input => StringIO.new(command_string),
|
39
|
+
:commands => options[:commands], :prompt => proc{""}, :hooks => Pry::Hooks.new
|
40
|
+
)
|
41
|
+
if options[:binding_stack] then
|
42
|
+
pry.binding_stack = options[:binding_stack]
|
43
|
+
end
|
44
|
+
pry.rep(options[:context])
|
45
|
+
end
|
46
|
+
def launch(options)
|
47
|
+
self.options = options
|
48
|
+
Pry.config.commands = get_pry_commands
|
49
|
+
Pry.config.pager = true
|
50
|
+
Pry.custom_completions = get_pry_custom_completions
|
51
|
+
Pry.config.exception_handler = get_pry_exception_handler
|
52
|
+
target = CollinsShell::Console::Filesystem.new options
|
53
|
+
setup_pry_hooks
|
54
|
+
Pry.start(target, :prompt => get_pry_prompt)
|
55
|
+
end
|
56
|
+
def options=(options)
|
57
|
+
@options = options
|
58
|
+
end
|
59
|
+
def options
|
60
|
+
@options
|
61
|
+
end
|
62
|
+
private
|
63
|
+
def setup_pry_hooks
|
64
|
+
before_message = [
|
65
|
+
'Welcome to the collins console. A few notes:',
|
66
|
+
' - collins-shell interacts with real servers (BE CAREFUL).',
|
67
|
+
' - collins-shell operates in contexts, which the prompt tells you about.',
|
68
|
+
' - collins-shell can be customized to your tastes. Read the docs.',
|
69
|
+
' - Type help at any time for help'
|
70
|
+
].join("\n")
|
71
|
+
Pry.config.hooks.add_hook(:before_session, :session_start) do |out, *|
|
72
|
+
out.puts before_message
|
73
|
+
end
|
74
|
+
Pry.config.hooks.add_hook(:after_session, :session_end) do |out, *|
|
75
|
+
out.puts "Goodbye!"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
def get_pry_prompt
|
79
|
+
get_prompt = proc { |o, waiting|
|
80
|
+
sym = waiting ? "*" : ">"
|
81
|
+
if o.is_a?(CollinsShell::Console::Filesystem) then
|
82
|
+
ext = ""
|
83
|
+
if o.asset? then
|
84
|
+
ext = "*"
|
85
|
+
end
|
86
|
+
"collins #{o.path}#{ext} #{sym} "
|
87
|
+
else
|
88
|
+
"collins-#{o.class} #{sym} "
|
89
|
+
end
|
90
|
+
}
|
91
|
+
[
|
92
|
+
proc { |o, *| get_prompt.call(o, false) },
|
93
|
+
proc { |o, *| get_prompt.call(o, true) }
|
94
|
+
]
|
95
|
+
end
|
96
|
+
def get_pry_custom_completions
|
97
|
+
proc do
|
98
|
+
last = binding_stack.last
|
99
|
+
last = last.eval('self') unless last.nil?
|
100
|
+
if last.is_a?(CollinsShell::Console::Filesystem) then
|
101
|
+
(last.available_commands + commands.commands.keys).flatten
|
102
|
+
else
|
103
|
+
commands.commands.keys
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
def get_pry_exception_handler
|
108
|
+
proc do |output, exception, _pry_|
|
109
|
+
if exception.is_a?(Interrupt) then
|
110
|
+
output.puts ""
|
111
|
+
else
|
112
|
+
cli = CollinsShell::Cli.new [], {}
|
113
|
+
cli.print_error exception, "command failed"
|
114
|
+
output.puts ""
|
115
|
+
bold = Pry::Helpers::Text.bold("type 'bt' or 'wtf?!?' for more context")
|
116
|
+
output.puts bold
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
def get_pry_commands
|
121
|
+
Pry::CommandSet.new do
|
122
|
+
import_from Pry::Commands, "help", "history", "hist", "wtf?", "show-doc", "show-source"
|
123
|
+
alias_command "bt", "wtf?"
|
124
|
+
import CollinsShell::Console::Commands::Default
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
end; end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module CollinsShell; module Console
|
2
|
+
class Asset
|
3
|
+
include CollinsShell::Console::CommandHelpers
|
4
|
+
|
5
|
+
attr_reader :tag
|
6
|
+
def initialize asset
|
7
|
+
@tag = asset
|
8
|
+
@asset_client = collins_client.with_asset(@tag)
|
9
|
+
end
|
10
|
+
def power! action = nil
|
11
|
+
Collins::Option(action).map do |action|
|
12
|
+
action = Collins::Power.normalize_action(action)
|
13
|
+
verifying_response("power #{action}") {
|
14
|
+
@asset_client.power!(action)
|
15
|
+
}
|
16
|
+
end.get_or_else {
|
17
|
+
cput("A power action argument is required. power <action>")
|
18
|
+
}
|
19
|
+
end
|
20
|
+
def reboot! how = "rebootSoft"
|
21
|
+
Collins::Option(how).map do |how|
|
22
|
+
action = Collins::Power.normalize_action(how)
|
23
|
+
verifying_response("reboot") {
|
24
|
+
@asset_client.power!(action)
|
25
|
+
}
|
26
|
+
end.get_or_else {
|
27
|
+
cput("A reboot argument is required. reboot <action>")
|
28
|
+
}
|
29
|
+
end
|
30
|
+
def stat
|
31
|
+
s = <<-STAT
|
32
|
+
Asset: #{underlying.tag}
|
33
|
+
Status: #{underlying.status}
|
34
|
+
Type: #{underlying.type}
|
35
|
+
Hostname: #{Collins::Option(underlying.hostname).get_or_else("(none)")}
|
36
|
+
Created: #{Collins::Option(underlying.created).get_or_else("(none)")}
|
37
|
+
Updated: #{Collins::Option(underlying.updated).get_or_else("(none)")}
|
38
|
+
Deleted: #{Collins::Option(underlying.deleted).get_or_else("(none)")}
|
39
|
+
STAT
|
40
|
+
cput(s)
|
41
|
+
end
|
42
|
+
def set_status! status = nil, reason = nil
|
43
|
+
msg = "set_status request a %s. set_status <status>, <reason>"
|
44
|
+
(raise sprintf(msg, "status")) if status.nil?
|
45
|
+
(raise sprintf(msg, "reason")) if reason.nil?
|
46
|
+
verifying_response("set the status to '#{status}' on") {
|
47
|
+
@asset_client.set_status!(status, reason)
|
48
|
+
}
|
49
|
+
end
|
50
|
+
def log! msg, level = nil
|
51
|
+
(raise "log requires a message. log <message>") if (msg.nil? || msg.to_s.empty?)
|
52
|
+
@asset_client.log!(msg, level)
|
53
|
+
end
|
54
|
+
def logs options = {}
|
55
|
+
@asset_client.logs(options)
|
56
|
+
end
|
57
|
+
def set! key = nil, value = nil, group_id = nil
|
58
|
+
msg = "set requires a %s. set <key>, <value>"
|
59
|
+
(raise sprintf(msg, "key")) if key.nil?
|
60
|
+
(raise sprintf(msg, "value")) if value.nil?
|
61
|
+
case value
|
62
|
+
when String, Symbol, Fixnum, TrueClass, FalseClass then
|
63
|
+
value = value.to_s
|
64
|
+
else
|
65
|
+
raise "value can't be a #{value.class}"
|
66
|
+
end
|
67
|
+
verifying_response("set the key '#{key}' to '#{value}' on") {
|
68
|
+
@asset_client.set_attribute!(key.to_s, value, group_id)
|
69
|
+
}
|
70
|
+
end
|
71
|
+
def rm! key = nil, group_id = nil
|
72
|
+
(raise "rm requires a key. rm <key>") if key.nil?
|
73
|
+
verifying_response("delete the key '#{key}' on") {
|
74
|
+
@asset_client.delete_attribute!(key, group_id)
|
75
|
+
}
|
76
|
+
end
|
77
|
+
def key? key = nil
|
78
|
+
(raise "key? requires a key. key? <key>") if key.nil?
|
79
|
+
@asset_client.get.send("#{key}?".to_sym)
|
80
|
+
end
|
81
|
+
def key key = nil
|
82
|
+
(raise "key requires a key. key <key>") if key.nil?
|
83
|
+
@asset_client.get.send(key.to_sym)
|
84
|
+
end
|
85
|
+
def on?
|
86
|
+
power? == "on"
|
87
|
+
end
|
88
|
+
def power?
|
89
|
+
@asset_client.power_status
|
90
|
+
end
|
91
|
+
def respond_to? meth, include_private = false
|
92
|
+
if meth.to_sym == :asset then
|
93
|
+
true
|
94
|
+
elsif @asset_client.respond_to?(meth) then
|
95
|
+
true
|
96
|
+
else
|
97
|
+
super
|
98
|
+
end
|
99
|
+
end
|
100
|
+
protected
|
101
|
+
def method_missing meth, *args, &block
|
102
|
+
if meth.to_sym == :asset then
|
103
|
+
underlying
|
104
|
+
elsif @asset_client.respond_to?(meth) then
|
105
|
+
@asset_client.send(meth, *args, &block)
|
106
|
+
else
|
107
|
+
super
|
108
|
+
end
|
109
|
+
end
|
110
|
+
def underlying
|
111
|
+
@underlying ||= get_asset(@tag)
|
112
|
+
end
|
113
|
+
def verifying_response message, &block
|
114
|
+
message = "You are about to #{message} asset #{tag}. Are you sure? "
|
115
|
+
if shell_handle.require_yes(message, :red, false) then
|
116
|
+
block.call
|
117
|
+
else
|
118
|
+
cput("Aborted operation")
|
119
|
+
end
|
120
|
+
end
|
121
|
+
def cput message
|
122
|
+
Pry.output.puts(message)
|
123
|
+
end
|
124
|
+
|
125
|
+
end # class CollinsShell::Console::Asset
|
126
|
+
|
127
|
+
end; end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# This is a very basic shared cache class
|
2
|
+
module CollinsShell; module Console; module Cache
|
3
|
+
@@_cache = {}
|
4
|
+
|
5
|
+
def clear_cache
|
6
|
+
@@_cache = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def cache_get_or_else key, &block
|
10
|
+
if @@_cache[key].nil? then
|
11
|
+
@@_cache[key] = block.call
|
12
|
+
else
|
13
|
+
@@_cache[key]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end; end; end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'collins_shell/console/cache'
|
2
|
+
|
3
|
+
module CollinsShell; module Console; module CommandHelpers
|
4
|
+
|
5
|
+
include CollinsShell::Console::Cache
|
6
|
+
|
7
|
+
# @return [Boolean] true if asset associated with specified tag exists
|
8
|
+
def asset_exists? tag
|
9
|
+
m = "asset_exists?(#{tag})"
|
10
|
+
cache_get_or_else(m) {
|
11
|
+
call_collins(m) {|c| c.exists?(tag)}
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [Collins::Asset] associated with the specified tag
|
16
|
+
def get_asset tag
|
17
|
+
m = "get_asset(#{tag})"
|
18
|
+
cache_get_or_else(m) {
|
19
|
+
call_collins(m) {|c| c.get(tag)}
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
# @return [Object] result of calling collins using the specifed block
|
24
|
+
def call_collins operation, &block
|
25
|
+
shell_handle.call_collins(collins_client, operation, &block)
|
26
|
+
end
|
27
|
+
# @return [Collins::Client] A Collins::Client instance
|
28
|
+
def collins_client
|
29
|
+
shell_handle.get_collins_client cli_options
|
30
|
+
end
|
31
|
+
|
32
|
+
# @return [Hash] CLI specified options
|
33
|
+
def cli_options
|
34
|
+
CollinsShell::Console.options
|
35
|
+
end
|
36
|
+
|
37
|
+
# @return [Array<Collins::Asset>,NilClass]
|
38
|
+
def find_one_asset tags_values, details = true
|
39
|
+
find_assets(tags_values, details).first
|
40
|
+
end
|
41
|
+
|
42
|
+
# Given an array of keys and values, return matching assets
|
43
|
+
# @param [Array<String>] tags_values an array where even elements are keys for a search and odd elements are values
|
44
|
+
# @param [Boolean] details If true, return full assets, otherwise return a sorted array of tags
|
45
|
+
# @return [Array<Collins::Asset>,Array<String>]
|
46
|
+
def find_assets tags_values, details
|
47
|
+
q = tags_values.each_slice(2).inject({}) {|h,o| h.update(o[0].to_s.to_sym => o[1])}
|
48
|
+
q.update(:details => details)
|
49
|
+
selector = shell_handle.get_selector(q, nil, 5000)
|
50
|
+
call_collins("find(#{selector})") do |c|
|
51
|
+
if details then
|
52
|
+
c.find(selector)
|
53
|
+
else
|
54
|
+
c.find(selector).map{|a| a.tag}.sort
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# @return [Array<String>,Array<Collins::Asset>] an array of values associated with the specified tag, or the asset associated with that tag if resolve asset is true.
|
60
|
+
def get_tag_values tag, resolve_asset = true
|
61
|
+
m = "get_tag_values(#{tag}, #{resolve_asset.to_s})"
|
62
|
+
cache_get_or_else(m) {
|
63
|
+
call_collins(m) {|c| c.get_tag_values(tag)}.sort
|
64
|
+
}
|
65
|
+
rescue Exception => e
|
66
|
+
if e.is_a?(Collins::RequestError) then
|
67
|
+
if e.code.to_i == 404 then
|
68
|
+
[get_asset(tag)] if resolve_asset
|
69
|
+
else
|
70
|
+
raise e
|
71
|
+
end
|
72
|
+
else
|
73
|
+
[get_asset(tag)] if resolve_asset
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def virtual_tags
|
78
|
+
Collins::Asset::Find.to_a
|
79
|
+
end
|
80
|
+
|
81
|
+
# return known tags including virtual ones (ones not stored, but that can be used as
|
82
|
+
# query parameters
|
83
|
+
def get_all_tags include_virtual = true
|
84
|
+
begin
|
85
|
+
cache_get_or_else("get_all_tags(#{include_virtual.to_s})") {
|
86
|
+
tags = call_collins("get_all_tags"){|c| c.get_all_tags}.map{|t|t.name}
|
87
|
+
if include_virtual then
|
88
|
+
[tags + Collins::Asset::Find.to_a].flatten.sort
|
89
|
+
else
|
90
|
+
tags.sort
|
91
|
+
end
|
92
|
+
}
|
93
|
+
rescue Exception => e
|
94
|
+
puts "Error retrieving tags: #{e}"
|
95
|
+
[]
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Given a possible string tag and the context stack, find the asset tag
|
100
|
+
# @param [NilClass,String] tag a possible tag for use
|
101
|
+
# @param [Array<Binding>] stack the context stack
|
102
|
+
# @return [String,NilClass] Either the given tag, the tag on the top of the context stack, or nil if neither is available
|
103
|
+
def resolve_asset_tag tag, stack
|
104
|
+
Collins::Option(tag).map{|s| s.strip}.filter_not{|s| s.empty?}.get_or_else {
|
105
|
+
tag_from_stack stack
|
106
|
+
}
|
107
|
+
end
|
108
|
+
|
109
|
+
# @return [CollinsShell::Util] a handle on the CLI interface
|
110
|
+
def shell_handle
|
111
|
+
CollinsShell::Asset.new([], cli_options)
|
112
|
+
end
|
113
|
+
|
114
|
+
# @param [Array<Binding>] stack the context stack
|
115
|
+
# @return [NilClass,String] the asset tag at the top of the stack, if it exists
|
116
|
+
def tag_from_stack stack
|
117
|
+
node = stack.last
|
118
|
+
node = node.eval('self') unless node.nil?
|
119
|
+
if node and node.asset? then
|
120
|
+
node.console_asset.tag
|
121
|
+
else
|
122
|
+
nil
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# @return [Boolean] true if in asset context
|
127
|
+
def asset_context? stack
|
128
|
+
!tag_from_stack(stack).nil?
|
129
|
+
end
|
130
|
+
|
131
|
+
end; end; end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'pry'
|
2
|
+
|
3
|
+
require 'collins_shell/console/options_helpers'
|
4
|
+
require 'collins_shell/console/command_helpers'
|
5
|
+
require 'collins_shell/console/commands/cd'
|
6
|
+
require 'collins_shell/console/commands/cat'
|
7
|
+
require 'collins_shell/console/commands/tail'
|
8
|
+
require 'collins_shell/console/commands/io'
|
9
|
+
require 'collins_shell/console/commands/iterators'
|
10
|
+
require 'collins_shell/console/commands/versions'
|
11
|
+
|
12
|
+
# TODO List
|
13
|
+
# * Confirmation for destructive options
|
14
|
+
# * Docs
|
15
|
+
# * Remote
|
16
|
+
# * Testing
|
17
|
+
# * Ssh
|
18
|
+
# * Ping
|
19
|
+
module CollinsShell; module Console; module Commands
|
20
|
+
Default = Pry::CommandSet.new do
|
21
|
+
import CollinsShell::Console::Commands::Cd
|
22
|
+
import CollinsShell::Console::Commands::Cat
|
23
|
+
import CollinsShell::Console::Commands::Tail
|
24
|
+
import CollinsShell::Console::Commands::Io
|
25
|
+
import CollinsShell::Console::Commands::Iterators
|
26
|
+
import CollinsShell::Console::Commands::Versions
|
27
|
+
end
|
28
|
+
end; end; end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'pry'
|
2
|
+
|
3
|
+
module CollinsShell; module Console; module Commands
|
4
|
+
Cat = Pry::CommandSet.new do
|
5
|
+
create_command "cat", "Output data associated with the specified asset" do
|
6
|
+
|
7
|
+
include CollinsShell::Console::CommandHelpers
|
8
|
+
|
9
|
+
group "I/O"
|
10
|
+
|
11
|
+
def options(opt)
|
12
|
+
opt.banner <<-BANNER
|
13
|
+
Usage: cat [-l|--logs] [-b|--brief] [--help]
|
14
|
+
|
15
|
+
Cat the specified asset or log.
|
16
|
+
|
17
|
+
If you are in an asset context, cat does not require the asset tag. In an asset context you can do:
|
18
|
+
cat # no-arg displays current asset
|
19
|
+
cat -b # short-display
|
20
|
+
cat -l # table formatted logs
|
21
|
+
cat /var/log/SEVERITY # display logs of a specified type
|
22
|
+
cat /var/log/messages # all logs
|
23
|
+
If you are not in an asset context, cat requires the tag of the asset you want to display.
|
24
|
+
cat # display this help
|
25
|
+
cat asset-tag # display asset
|
26
|
+
cat -b asset-tag # short-display
|
27
|
+
cat -l asset-tag # table formatted logs
|
28
|
+
cat /var/log/assets/asset-tag # display logs for asset
|
29
|
+
cat /var/log/hosts/hostname # display logs for host with name
|
30
|
+
BANNER
|
31
|
+
opt.on :b, "brief", "Brief output, not detailed"
|
32
|
+
opt.on :l, "logs", "Display logs as well"
|
33
|
+
end
|
34
|
+
|
35
|
+
def process
|
36
|
+
stack = _pry_.binding_stack
|
37
|
+
if args.first.to_s.start_with?('/var/log/') then
|
38
|
+
display_logs args.first, stack
|
39
|
+
else
|
40
|
+
tag = resolve_asset_tag args.first, stack
|
41
|
+
if tag.nil? then
|
42
|
+
run "help", "cat"
|
43
|
+
return
|
44
|
+
end
|
45
|
+
display_asset tag
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Given a logfile specification, parse it and render it
|
50
|
+
def display_logs logfile, stack
|
51
|
+
rejects = ['var', 'log']
|
52
|
+
paths = logfile.split('/').reject{|s| s.empty? || rejects.include?(s)}
|
53
|
+
if paths.size == 2 then
|
54
|
+
display_sub_logs paths[0], paths[1]
|
55
|
+
elsif paths.size == 1 then
|
56
|
+
display_asset_logs tag_from_stack(stack), paths[0]
|
57
|
+
else
|
58
|
+
run "help", "cat"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Render logs of the type `/var/log/assets/TAG` or `/var/log/hosts/HOSTNAME`
|
63
|
+
def display_sub_logs arg1, arg2
|
64
|
+
if arg1 == 'assets' then
|
65
|
+
display_asset_logs arg2, 'messages'
|
66
|
+
elsif arg1 == 'hosts' then
|
67
|
+
asset = find_one_asset(['HOSTNAME', arg2])
|
68
|
+
display_asset_logs asset, 'messages'
|
69
|
+
else
|
70
|
+
output.puts "#{text.bold('Invalid log type:')} Only 'assets' or 'hosts' are valid, found '#{arg1}'"
|
71
|
+
output.puts
|
72
|
+
run "help", "cat"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Render logs for an asset according to type, where type is 'messages' (all) or a severity
|
77
|
+
def display_asset_logs asset_tag, type
|
78
|
+
begin
|
79
|
+
asset = Collins::Util.get_asset_or_tag(asset_tag).tag
|
80
|
+
rescue => e
|
81
|
+
output.puts "#{text.bold('Invalid asset:')} '#{asset_tag}' not valid - #{e}"
|
82
|
+
return
|
83
|
+
end
|
84
|
+
severity = Collins::Api::Logging::Severity
|
85
|
+
severity_level = severity.value_of type
|
86
|
+
if type == 'messages' then
|
87
|
+
get_and_print_logs asset_tag, "ASC"
|
88
|
+
elsif not severity_level.nil? then
|
89
|
+
get_and_print_logs asset_tag, "ASC", severity_level
|
90
|
+
else
|
91
|
+
message = "Only '/var/log/messages' or '/var/log/SEVERITY' are valid here"
|
92
|
+
sevs = severity.to_a.join(', ')
|
93
|
+
output.puts "#{text.bold('Invalid path specified:')}: #{message}"
|
94
|
+
output.puts "Valid severity levels are: #{sevs}"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def display_asset tag
|
99
|
+
if asset_exists? tag then
|
100
|
+
asset = get_asset tag
|
101
|
+
show_logs = opts.logs?
|
102
|
+
show_details = !opts.brief?
|
103
|
+
show_color = Pry.color
|
104
|
+
logs = []
|
105
|
+
logs = call_collins("logs(#{tag})") {|c| c.logs(tag, :size => 5000)} if show_logs
|
106
|
+
printer = CollinsShell::AssetPrinter.new asset, shell_handle, :logs => logs, :detailed => show_details, :color => show_color
|
107
|
+
render_output printer.to_s
|
108
|
+
else
|
109
|
+
output.puts "#{text.bold('No such asset:')} #{tag}"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def get_and_print_logs asset_tag, sort, filter = nil, size = 5000
|
114
|
+
logs = call_collins "logs(#{asset_tag})" do |client|
|
115
|
+
client.logs asset_tag, :sort => sort, :size => size, :filter => filter
|
116
|
+
end
|
117
|
+
printer = CollinsShell::LogPrinter.new asset_tag, logs
|
118
|
+
output.puts printer.to_s
|
119
|
+
end
|
120
|
+
|
121
|
+
end # create_command
|
122
|
+
end # CommandSet
|
123
|
+
end; end; end
|