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