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
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.2.14
|
data/bin/collins-shell
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
if ENV.key?('COLLINS_DEBUG') && ENV['COLLINS_DEBUG'] then
|
4
|
+
HTTP_DEBUG = true
|
5
|
+
end
|
6
|
+
|
7
|
+
# Make sure we're running a valid version of ruby
|
8
|
+
if RUBY_VERSION !~ /^1\.9\./ then
|
9
|
+
puts("We require ruby 1.9.2")
|
10
|
+
exit(1)
|
11
|
+
end
|
12
|
+
|
13
|
+
if not ENV.key?('HOME') || ENV['HOME'].empty? then
|
14
|
+
puts("No HOME environment found. Exiting")
|
15
|
+
exit(2)
|
16
|
+
end
|
17
|
+
|
18
|
+
$:.unshift File.join File.dirname(__FILE__), *%w[.. lib]
|
19
|
+
# Allows us to use a dev version of collins-client if needed
|
20
|
+
$:.unshift File.join File.dirname(__FILE__), *%w[.. .. ruby collins-client lib]
|
21
|
+
%w[collins_shell collins_shell/cli].each {|f| require f}
|
22
|
+
|
23
|
+
begin
|
24
|
+
CollinsShell::Cli.start
|
25
|
+
rescue SystemExit => e
|
26
|
+
rescue CollinsShell::ConfigurationError => e
|
27
|
+
cli = CollinsShell::Cli.new
|
28
|
+
cli.say_status("fatal", "your environment is not setup correctly", :red)
|
29
|
+
cli.say_status("message", "#{e.message}")
|
30
|
+
exit(1)
|
31
|
+
rescue Exception => e
|
32
|
+
cli = CollinsShell::Cli.new
|
33
|
+
cli.print_error e
|
34
|
+
exit(2)
|
35
|
+
end
|
36
|
+
exit(0)
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "collins_shell"
|
8
|
+
s.version = "0.2.14"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Blake Matheny"]
|
12
|
+
s.date = "2012-10-31"
|
13
|
+
s.description = "Provides basic CLI for interacting with Collins API"
|
14
|
+
s.email = "bmatheny@tumblr.com"
|
15
|
+
s.executables = ["collins-shell"]
|
16
|
+
s.extra_rdoc_files = [
|
17
|
+
"README.md"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".pryrc",
|
21
|
+
".rvmrc",
|
22
|
+
"Gemfile",
|
23
|
+
"Gemfile.lock",
|
24
|
+
"README.md",
|
25
|
+
"Rakefile",
|
26
|
+
"VERSION",
|
27
|
+
"bin/collins-shell",
|
28
|
+
"collins_shell.gemspec",
|
29
|
+
"lib/collins_shell.rb",
|
30
|
+
"lib/collins_shell/asset.rb",
|
31
|
+
"lib/collins_shell/cli.rb",
|
32
|
+
"lib/collins_shell/console.rb",
|
33
|
+
"lib/collins_shell/console/asset.rb",
|
34
|
+
"lib/collins_shell/console/cache.rb",
|
35
|
+
"lib/collins_shell/console/command_helpers.rb",
|
36
|
+
"lib/collins_shell/console/commands.rb",
|
37
|
+
"lib/collins_shell/console/commands/cat.rb",
|
38
|
+
"lib/collins_shell/console/commands/cd.rb",
|
39
|
+
"lib/collins_shell/console/commands/io.rb",
|
40
|
+
"lib/collins_shell/console/commands/iterators.rb",
|
41
|
+
"lib/collins_shell/console/commands/tail.rb",
|
42
|
+
"lib/collins_shell/console/commands/versions.rb",
|
43
|
+
"lib/collins_shell/console/filesystem.rb",
|
44
|
+
"lib/collins_shell/console/options_helpers.rb",
|
45
|
+
"lib/collins_shell/errors.rb",
|
46
|
+
"lib/collins_shell/ip_address.rb",
|
47
|
+
"lib/collins_shell/ipmi.rb",
|
48
|
+
"lib/collins_shell/monkeypatch.rb",
|
49
|
+
"lib/collins_shell/provision.rb",
|
50
|
+
"lib/collins_shell/state.rb",
|
51
|
+
"lib/collins_shell/tag.rb",
|
52
|
+
"lib/collins_shell/thor.rb",
|
53
|
+
"lib/collins_shell/util.rb",
|
54
|
+
"lib/collins_shell/util/asset_printer.rb",
|
55
|
+
"lib/collins_shell/util/asset_stache.rb",
|
56
|
+
"lib/collins_shell/util/log_printer.rb",
|
57
|
+
"lib/collins_shell/util/printer_util.rb"
|
58
|
+
]
|
59
|
+
s.homepage = "https://github.com/tumblr/collins/tree/master/support/collins-shell"
|
60
|
+
s.licenses = ["APL 2.0"]
|
61
|
+
s.require_paths = ["lib"]
|
62
|
+
s.rubygems_version = "1.8.24"
|
63
|
+
s.summary = "Shell for Collins API"
|
64
|
+
|
65
|
+
if s.respond_to? :specification_version then
|
66
|
+
s.specification_version = 3
|
67
|
+
|
68
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
69
|
+
s.add_runtime_dependency(%q<collins_client>, ["~> 0.2.7"])
|
70
|
+
s.add_runtime_dependency(%q<highline>, ["~> 1.6.15"])
|
71
|
+
s.add_runtime_dependency(%q<mustache>, ["~> 0.99.4"])
|
72
|
+
s.add_runtime_dependency(%q<pry>, ["~> 0.9.9.6"])
|
73
|
+
s.add_runtime_dependency(%q<rubygems-update>, ["~> 1.8.24"])
|
74
|
+
s.add_runtime_dependency(%q<terminal-table>, ["~> 1.4.5"])
|
75
|
+
s.add_runtime_dependency(%q<thor>, ["~> 0.16.0"])
|
76
|
+
else
|
77
|
+
s.add_dependency(%q<collins_client>, ["~> 0.2.7"])
|
78
|
+
s.add_dependency(%q<highline>, ["~> 1.6.15"])
|
79
|
+
s.add_dependency(%q<mustache>, ["~> 0.99.4"])
|
80
|
+
s.add_dependency(%q<pry>, ["~> 0.9.9.6"])
|
81
|
+
s.add_dependency(%q<rubygems-update>, ["~> 1.8.24"])
|
82
|
+
s.add_dependency(%q<terminal-table>, ["~> 1.4.5"])
|
83
|
+
s.add_dependency(%q<thor>, ["~> 0.16.0"])
|
84
|
+
end
|
85
|
+
else
|
86
|
+
s.add_dependency(%q<collins_client>, ["~> 0.2.7"])
|
87
|
+
s.add_dependency(%q<highline>, ["~> 1.6.15"])
|
88
|
+
s.add_dependency(%q<mustache>, ["~> 0.99.4"])
|
89
|
+
s.add_dependency(%q<pry>, ["~> 0.9.9.6"])
|
90
|
+
s.add_dependency(%q<rubygems-update>, ["~> 1.8.24"])
|
91
|
+
s.add_dependency(%q<terminal-table>, ["~> 1.4.5"])
|
92
|
+
s.add_dependency(%q<thor>, ["~> 0.16.0"])
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
@@ -0,0 +1,198 @@
|
|
1
|
+
require 'collins_shell/thor'
|
2
|
+
require 'collins_shell/util'
|
3
|
+
require 'collins_shell/util/asset_printer'
|
4
|
+
require 'thor'
|
5
|
+
require 'thor/group'
|
6
|
+
|
7
|
+
module CollinsShell
|
8
|
+
|
9
|
+
class Asset < Thor
|
10
|
+
include ThorHelper
|
11
|
+
include CollinsShell::Util
|
12
|
+
namespace :asset
|
13
|
+
def self.banner task, namespace = true, subcommand = false
|
14
|
+
"#{basename} #{task.formatted_usage(self, true, subcommand).gsub(':',' ')}"
|
15
|
+
end
|
16
|
+
|
17
|
+
desc 'create', 'create an asset in collins'
|
18
|
+
use_collins_options
|
19
|
+
use_tag_option(true)
|
20
|
+
method_option :ipmi, :type => :boolean, :desc => 'Generate IPMI data'
|
21
|
+
method_option :status, :type => :string, :desc => 'Status of asset'
|
22
|
+
method_option :type, :type => :string, :desc => 'Asset type'
|
23
|
+
def create
|
24
|
+
call_collins get_collins_client, "create asset" do |client|
|
25
|
+
asset = client.create! options.tag, :generate_ipmi => options.ipmi, :status => options.status, :type => options.type
|
26
|
+
print_find_results asset, nil
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
desc 'delete', 'delete an asset in collins (must be cancelled)'
|
31
|
+
use_collins_options
|
32
|
+
use_tag_option(true)
|
33
|
+
method_option :reason, :required => true, :type => :string, :desc => 'Reason to delete asset'
|
34
|
+
def delete
|
35
|
+
call_collins get_collins_client, "delete asset" do |client|
|
36
|
+
if client.delete!(options.tag, :reason => options.reason) then
|
37
|
+
say_success "deleted asset #{options.tag}"
|
38
|
+
else
|
39
|
+
say_error "deleting asset #{options.tag}", :exit => true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
desc 'find', 'find assets using the specified selector'
|
45
|
+
use_collins_options
|
46
|
+
use_selector_option(true)
|
47
|
+
method_option :confirm, :type => :boolean, :default => :true, :desc => 'Require exec confirmation. Defaults to true'
|
48
|
+
method_option :details, :type => :boolean, :desc => 'Output assets how you see them in get'
|
49
|
+
method_option :exec, :type => :string, :desc => 'Execute a command using the data from this asset. Use {{hostname}}, {{ipmi.password}}, etc for substitution'
|
50
|
+
method_option :header, :type => :boolean, :default => true, :desc => 'Display a tag header. Defaults to true'
|
51
|
+
method_option :logs, :type => :boolean, :default => false, :desc => 'Also display asset logs, only used with details (SLOW)'
|
52
|
+
method_option :size, :type => :numeric, :default => 50, :desc => 'Number of results to find. Defaults to 50'
|
53
|
+
method_option :tags, :type => :array, :desc => 'Tags to display of form: tag1 tag2 tag3. e.g. --tags=hostname tag backend_ip_address'
|
54
|
+
method_option :url, :type => :boolean, :default => true, :desc => 'Display a URL along with tags or the default listing'
|
55
|
+
def find
|
56
|
+
client = get_collins_client
|
57
|
+
tags = options.tags || [:stuff]
|
58
|
+
selector = get_selector options.selector, tags, options["size"], options.remote
|
59
|
+
assets = client.find selector
|
60
|
+
if options.details then
|
61
|
+
assets.each do |asset|
|
62
|
+
if not options.quiet then
|
63
|
+
logs = []
|
64
|
+
if options.logs and not options.exec? then
|
65
|
+
logs = client.logs(asset, :size => 5000, :SORT => "DESC").reverse
|
66
|
+
end
|
67
|
+
printer = CollinsShell::AssetPrinter.new asset, self, :separator => '*',
|
68
|
+
:logs => logs,
|
69
|
+
:detailed => !options.exec?
|
70
|
+
puts printer
|
71
|
+
end
|
72
|
+
asset_exec asset, options.exec, options.confirm
|
73
|
+
end
|
74
|
+
else
|
75
|
+
if not options.quiet then
|
76
|
+
print_find_results assets, options.tags, :header => options.header, :url => options.url
|
77
|
+
end
|
78
|
+
assets.each {|asset| asset_exec(asset, options.exec, options.confirm)}
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
desc 'find_similar TAG', 'get similar unallocated assets for a gven asset'
|
83
|
+
use_collins_options
|
84
|
+
method_option :size, :type => :numeric, :default => 50, :desc => 'number of results to find. Defaults to 50'
|
85
|
+
method_option :details, :type => :boolean, :desc => 'Output assets how you see them in get'
|
86
|
+
method_option :sort, :type => :string, :default => "DESC", :desc => 'sort direction, either ASC or DESC'
|
87
|
+
method_option :sort_type, :type => :string, :default => "distribution", :desc => 'sorting type'
|
88
|
+
method_option :only_unallocated, :type => :boolean, :default => true, :desc => 'only return unallocated assets, defaults to true'
|
89
|
+
def find_similar tag
|
90
|
+
call_collins get_collins_client, "similar asset" do |client|
|
91
|
+
as_asset = Collins::Asset.new(tag)
|
92
|
+
assets = client.find_similar as_asset, options["size"], options["sort"], options.sort_type, options.only_unallocated
|
93
|
+
if options.details then
|
94
|
+
assets.each do |asset|
|
95
|
+
printer = CollinsShell::AssetPrinter.new asset, self, :separator => '*'
|
96
|
+
puts printer
|
97
|
+
end
|
98
|
+
else
|
99
|
+
print_find_results assets, options.tags
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
desc 'get TAG', 'get an asset and display its attributes'
|
105
|
+
use_collins_options
|
106
|
+
method_option :confirm, :type => :boolean, :default => :true, :desc => 'Require exec confirmation. Defaults to true'
|
107
|
+
method_option :exec, :type => :string, :desc => 'Execute a command using the data from this asset. Use {{hostname}}, {{ipmi.password}}, etc for substitution'
|
108
|
+
method_option :logs, :type => :boolean, :default => false, :desc => 'Also display asset logs'
|
109
|
+
method_option :remote, :type => :string, :desc => 'Remote location to search. This is a tag in collins corresponding to the datacenter asset'
|
110
|
+
def get tag
|
111
|
+
asset = asset_get tag, options
|
112
|
+
if asset then
|
113
|
+
if not options.quiet then
|
114
|
+
logs = []
|
115
|
+
if options.logs and not options.exec? then
|
116
|
+
logs = call_collins(get_collins_client, "logs") do |client|
|
117
|
+
client.logs(asset, :size => 5000, :sort => "DESC").reverse
|
118
|
+
end
|
119
|
+
end
|
120
|
+
printer = CollinsShell::AssetPrinter.new asset, self, :logs => logs, :detailed => !options.exec?
|
121
|
+
puts printer
|
122
|
+
end
|
123
|
+
asset_exec asset, options.exec, options.confirm
|
124
|
+
else
|
125
|
+
say_error "No such asset #{tag}"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
desc 'set_attribute KEY VALUE', 'set an attribute in collins'
|
130
|
+
use_collins_options
|
131
|
+
use_tag_option
|
132
|
+
use_selector_option
|
133
|
+
method_option :json, :type => :boolean, :default => false, :desc => 'Encode as JSON value. Only works for arrays and hashes.'
|
134
|
+
def set_attribute key, value
|
135
|
+
batch_selector_operation Hash[
|
136
|
+
:remote => options.remote,
|
137
|
+
:operation => "set_attribute",
|
138
|
+
:success_message => proc {|asset| "Set attribute on #{asset.tag}"},
|
139
|
+
:error_message => proc{|asset| "Setting attribute on #{asset.tag}"},
|
140
|
+
:confirmation_message => proc do |assets|
|
141
|
+
"You are about to set #{key}=#{value} on #{assets.length} hosts. ARE YOU SURE?"
|
142
|
+
end
|
143
|
+
] do |client,asset|
|
144
|
+
if options.json then
|
145
|
+
value = JSON.dump(eval(value))
|
146
|
+
end
|
147
|
+
client.set_attribute!(asset, key, value)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
desc 'delete_attribute KEY', 'delete an attribute in collins'
|
152
|
+
use_collins_options
|
153
|
+
use_tag_option
|
154
|
+
use_selector_option
|
155
|
+
def delete_attribute key
|
156
|
+
batch_selector_operation Hash[
|
157
|
+
:remote => options.remote,
|
158
|
+
:operation => "delete_attribute",
|
159
|
+
:success_message => proc {|asset| "Delete attribute on #{asset.tag}"},
|
160
|
+
:error_message => proc{|asset| "Delete attribute on #{asset.tag}"},
|
161
|
+
:confirmation_message => proc do |assets|
|
162
|
+
"You are about to delete #{key} on #{assets.length} hosts. ARE YOU SURE?"
|
163
|
+
end
|
164
|
+
] do |client,asset|
|
165
|
+
client.delete_attribute!(asset, key)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
desc 'set_status', 'set status, state, or both on an asset'
|
170
|
+
use_collins_options
|
171
|
+
use_tag_option
|
172
|
+
use_selector_option
|
173
|
+
method_option :reason, :type => :string, :required => true, :desc => 'Reason for changing status'
|
174
|
+
method_option :state, :type => :string, :required => false, :desc => 'Set state of asset as well'
|
175
|
+
method_option :status, :type => :string, :required => false, :desc => 'Set status of asset'
|
176
|
+
def set_status
|
177
|
+
status = options.status
|
178
|
+
state = options.state
|
179
|
+
reason = options.reason
|
180
|
+
if status.nil? && state.nil? then
|
181
|
+
raise ::Collins::ExpectationFailedError.new("set_status requires either a status or a state")
|
182
|
+
end
|
183
|
+
batch_selector_operation Hash[
|
184
|
+
:remote => options.remote,
|
185
|
+
:operation => "set_status",
|
186
|
+
:success_message => proc {|asset| "Set status to #{status} on #{asset.tag}"},
|
187
|
+
:error_message => proc{|asset| "Setting status on #{asset.tag}"},
|
188
|
+
:confirmation_message => proc do |assets|
|
189
|
+
"You are about to set status to #{status} on #{assets.length} hosts. ARE YOU SURE?"
|
190
|
+
end
|
191
|
+
] do |client,asset|
|
192
|
+
client.set_status!(asset, :reason => reason, :status => status, :state => state)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|
197
|
+
|
198
|
+
end
|
@@ -0,0 +1,185 @@
|
|
1
|
+
require 'collins_shell/asset'
|
2
|
+
require 'collins_shell/console'
|
3
|
+
require 'collins_shell/ip_address'
|
4
|
+
require 'collins_shell/ipmi'
|
5
|
+
require 'collins_shell/provision'
|
6
|
+
require 'collins_shell/state'
|
7
|
+
require 'collins_shell/tag'
|
8
|
+
require 'collins_shell/thor'
|
9
|
+
require 'collins_shell/util'
|
10
|
+
require 'collins_shell/util/log_printer'
|
11
|
+
require 'thor'
|
12
|
+
require 'thor/group'
|
13
|
+
|
14
|
+
# Need these to support latest method
|
15
|
+
require 'rubygems'
|
16
|
+
require 'rubygems/spec_fetcher'
|
17
|
+
|
18
|
+
module CollinsShell
|
19
|
+
|
20
|
+
class Cli < Thor
|
21
|
+
|
22
|
+
include ThorHelper
|
23
|
+
include CollinsShell::Util
|
24
|
+
|
25
|
+
register(CollinsShell::Asset, 'asset', 'asset <command>', 'Asset related commands')
|
26
|
+
register(CollinsShell::Tag, 'tag', 'tag <command>', 'Tag related commands')
|
27
|
+
register(CollinsShell::IpAddress, 'ip_address', 'ip_address <command>', 'IP address related commands')
|
28
|
+
register(CollinsShell::Ipmi, 'ipmi', 'ipmi <command>', 'IPMI related commands')
|
29
|
+
register(CollinsShell::Provision, 'provision', 'provision <command>', 'Provisioning related commands')
|
30
|
+
register(CollinsShell::State, 'state', 'state <command>', 'State management related commands - use with care')
|
31
|
+
|
32
|
+
desc 'latest', 'check if there is a newer version of collins-shell'
|
33
|
+
def latest
|
34
|
+
puts(get_latest_version)
|
35
|
+
end
|
36
|
+
|
37
|
+
desc 'version', 'current version of collins-shell'
|
38
|
+
def version
|
39
|
+
puts("collins-shell #{get_version}")
|
40
|
+
end
|
41
|
+
|
42
|
+
desc 'power_status', 'check power status on an asset'
|
43
|
+
use_collins_options
|
44
|
+
use_tag_option
|
45
|
+
use_selector_option
|
46
|
+
def power_status
|
47
|
+
batch_selector_operation Hash[
|
48
|
+
:remote => options.remote,
|
49
|
+
:operation => "power_status",
|
50
|
+
:success_message => proc {|asset| "Got power status for #{asset.tag}"},
|
51
|
+
:error_message => proc{|asset| "Error getting power status for #{asset.tag}"},
|
52
|
+
:confirmation_message => proc do |assets|
|
53
|
+
"You are about to check the power status of #{assets.length} hosts. ARE YOU SURE?"
|
54
|
+
end
|
55
|
+
] do |client,asset|
|
56
|
+
puts('*'*80)
|
57
|
+
begin
|
58
|
+
status = client.power_status(asset)
|
59
|
+
say_success "Power status of #{asset.tag}: #{status}"
|
60
|
+
rescue Exception => e
|
61
|
+
print_error e, "Unable to check power status of #{asset.tag}", false
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
desc 'power ACTION', 'perform power action (off, on, rebootSoft, rebootHard, etc) on an asset'
|
67
|
+
use_collins_options
|
68
|
+
use_tag_option(true)
|
69
|
+
method_option :reason, :type => :string, :required => true, :desc => 'Reason for reboot'
|
70
|
+
def power action
|
71
|
+
action = Collins::Power.normalize_action(action)
|
72
|
+
call_collins get_collins_client, "power" do |client|
|
73
|
+
client.log! options.tag, options.reason, 'ALERT'
|
74
|
+
if client.power!(options.tag, action) then
|
75
|
+
say_success "power #{action} on #{options.tag}"
|
76
|
+
else
|
77
|
+
say_error "power #{action} on #{options.tag}", :exit => true
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
desc 'log MESSAGE', 'log a message on an asset'
|
83
|
+
use_collins_options
|
84
|
+
use_tag_option
|
85
|
+
use_selector_option
|
86
|
+
method_option :severity, :type => :string, :desc => 'Log severity (EMERGENCY, WARN, etc)'
|
87
|
+
def log message
|
88
|
+
batch_selector_operation Hash[
|
89
|
+
:remote => options.remote,
|
90
|
+
:operation => "log",
|
91
|
+
:success_message => proc {|asset| "Logged to #{asset.tag}"},
|
92
|
+
:error_message => proc{|asset| "Log to #{asset.tag}"},
|
93
|
+
:confirmation_message => proc do |assets|
|
94
|
+
"You are about to log '#{message}' on #{assets.length} hosts. ARE YOU SURE?"
|
95
|
+
end
|
96
|
+
] do |client,asset|
|
97
|
+
client.log!(asset, message, options.severity)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
desc 'logs TAG', 'fetch logs for an asset specified by its tag. Use "all" for all logs'
|
102
|
+
use_collins_options
|
103
|
+
use_page_options(5000)
|
104
|
+
method_option :severity, :type => :array, :desc => 'Severities to include'
|
105
|
+
def logs tag
|
106
|
+
call_collins get_collins_client, "logs" do |client|
|
107
|
+
severity = []
|
108
|
+
if options.severity? then
|
109
|
+
severity = options.severity
|
110
|
+
end
|
111
|
+
params = Hash[
|
112
|
+
:filter => severity.join(';'),
|
113
|
+
:size => options[:size].to_i,
|
114
|
+
:sort => options[:sort]
|
115
|
+
]
|
116
|
+
logs = client.logs tag, params.merge(:all_tag => 'all')
|
117
|
+
logs.reverse! if options[:sort].to_s.downcase == 'desc'
|
118
|
+
printer = CollinsShell::LogPrinter.new(tag, logs)
|
119
|
+
puts printer.render
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
desc 'console', 'drop into the interactive collins shell'
|
124
|
+
use_collins_options
|
125
|
+
def console
|
126
|
+
ensure_password
|
127
|
+
CollinsShell::Console.launch(options)
|
128
|
+
end
|
129
|
+
|
130
|
+
no_tasks do
|
131
|
+
def get_version
|
132
|
+
version_file = File.absolute_path(File.join(File.dirname(__FILE__), '..', '..', 'VERSION'))
|
133
|
+
if File.exists?(version_file) then
|
134
|
+
File.read(version_file)
|
135
|
+
else
|
136
|
+
"0.0.0"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def get_latest_version
|
141
|
+
begin
|
142
|
+
Gem.sources = ["http://repo.tumblr.net:9929"]
|
143
|
+
gem = Gem::SpecFetcher.new
|
144
|
+
shell = gem.fetch(Gem::Dependency.new('collins_shell')).flatten.first
|
145
|
+
rescue Exception => e
|
146
|
+
return "Could not retrieve latest gem info from #{Gem.sources.join(',')}"
|
147
|
+
end
|
148
|
+
if shell.nil? then
|
149
|
+
"Could not retrieve latest gem info from repo.tumblr.net"
|
150
|
+
else
|
151
|
+
my_version = Gem::Version.new(get_version)
|
152
|
+
if shell.version == my_version then
|
153
|
+
"You are running the most recent version of collins-shell: #{my_version.to_s}"
|
154
|
+
elsif shell.version > my_version then
|
155
|
+
"Time to upgrade! You are running collins-shell #{my_version.to_s}, latest is #{shell.version.to_s}"
|
156
|
+
else
|
157
|
+
"You are probably a developer. You are running version #{my_version.to_s}, latest published is #{shell.version.to_s}"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def print_error e, cmd = nil, separator = true
|
163
|
+
cmd = "unable to run command '#{$0} #{ARGV.join(' ')}'" unless cmd
|
164
|
+
say_status("fatal", cmd, :red)
|
165
|
+
say_status("exception", "#{e.message}", :red)
|
166
|
+
is_debug = ARGV.include?("--debug") || ARGV.include?("--trace")
|
167
|
+
if e.is_a?(Collins::RequestError) then
|
168
|
+
puts('*'*80) if separator
|
169
|
+
say_status("details", e.description(is_debug).strip.sub(e.message,""), :red)
|
170
|
+
end
|
171
|
+
if ARGV.include?("--debug") || ARGV.include?("--trace") then
|
172
|
+
say_status("DEBUG", "local backtrace is presented latest to earliest (reverse cronological)")
|
173
|
+
puts("#{e.class.to_s}")
|
174
|
+
e.backtrace.each do |line|
|
175
|
+
file, line, method = line.split(":", 3)
|
176
|
+
puts "\t\t#{method}(#{file}:#{line})"
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end # print_error
|
180
|
+
end # no_tasks
|
181
|
+
|
182
|
+
|
183
|
+
end
|
184
|
+
|
185
|
+
end
|