collins_shell 0.2.14
Sign up to get free protection for your applications and to get access to all the features.
- 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
|