collins_shell 0.2.17 → 0.2.18

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.17
1
+ 0.2.18
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "collins_shell"
8
- s.version = "0.2.17"
8
+ s.version = "0.2.18"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Blake Matheny"]
12
- s.date = "2012-12-18"
12
+ s.date = "2013-03-19"
13
13
  s.description = "Provides basic CLI for interacting with Collins API"
14
14
  s.email = "bmatheny@tumblr.com"
15
15
  s.executables = ["collins-shell"]
@@ -49,8 +49,8 @@ module CollinsShell
49
49
  method_option :exec, :type => :string, :desc => 'Execute a command using the data from this asset. Use {{hostname}}, {{ipmi.password}}, etc for substitution'
50
50
  method_option :header, :type => :boolean, :default => true, :desc => 'Display a tag header. Defaults to true'
51
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
52
  method_option :tags, :type => :array, :desc => 'Tags to display of form: tag1 tag2 tag3. e.g. --tags=hostname tag backend_ip_address'
53
+ method_option :threads, :type => :numeric, :default => 1, :desc => 'Number of threads to use for --exec. Defaults to 1.'
54
54
  method_option :url, :type => :boolean, :default => true, :desc => 'Display a URL along with tags or the default listing'
55
55
  def find
56
56
  client = get_collins_client
@@ -69,14 +69,15 @@ module CollinsShell
69
69
  :detailed => !options.exec?
70
70
  puts printer
71
71
  end
72
- asset_exec asset, options.exec, options.confirm
72
+ asset_exec asset, options.exec, options.confirm, options.threads
73
73
  end
74
74
  else
75
75
  if not options.quiet then
76
76
  print_find_results assets, options.tags, :header => options.header, :url => options.url
77
77
  end
78
- assets.each {|asset| asset_exec(asset, options.exec, options.confirm)}
78
+ assets.each {|asset| asset_exec(asset, options.exec, options.confirm, options.threads)}
79
79
  end
80
+ finalize_exec
80
81
  end
81
82
 
82
83
  desc 'find_similar TAG', 'get similar unallocated assets for a gven asset'
@@ -136,6 +137,7 @@ module CollinsShell
136
137
  batch_selector_operation Hash[
137
138
  :remote => options.remote,
138
139
  :operation => "set_attribute",
140
+ :size => options["size"],
139
141
  :success_message => proc {|asset| "Set attribute on #{asset.tag}"},
140
142
  :error_message => proc{|asset| "Setting attribute on #{asset.tag}"},
141
143
  :confirmation_message => proc do |assets|
@@ -172,6 +174,7 @@ module CollinsShell
172
174
  batch_selector_operation Hash[
173
175
  :remote => options.remote,
174
176
  :operation => "set_attributes",
177
+ :size => options["size"],
175
178
  :success_message => proc {|asset| "Set attributes on #{asset.tag}"},
176
179
  :error_message => proc{|asset| "Setting attributes on #{asset.tag}"},
177
180
  :confirmation_message => proc do |assets|
@@ -190,6 +193,7 @@ module CollinsShell
190
193
  batch_selector_operation Hash[
191
194
  :remote => options.remote,
192
195
  :operation => "delete_attribute",
196
+ :size => options["size"],
193
197
  :success_message => proc {|asset| "Delete attribute on #{asset.tag}"},
194
198
  :error_message => proc{|asset| "Delete attribute on #{asset.tag}"},
195
199
  :confirmation_message => proc do |assets|
@@ -217,6 +221,7 @@ module CollinsShell
217
221
  batch_selector_operation Hash[
218
222
  :remote => options.remote,
219
223
  :operation => "set_status",
224
+ :size => options["size"],
220
225
  :success_message => proc {|asset| "Set status to #{status} on #{asset.tag}"},
221
226
  :error_message => proc{|asset| "Setting status on #{asset.tag}"},
222
227
  :confirmation_message => proc do |assets|
@@ -96,6 +96,7 @@ module CollinsShell; module Console; module Commands
96
96
  end
97
97
 
98
98
  def display_asset tag
99
+ tag = tag.gsub(/^\//, '')
99
100
  if asset_exists? tag then
100
101
  asset = get_asset tag
101
102
  show_logs = opts.logs?
@@ -48,6 +48,7 @@ module CollinsShell
48
48
  def use_selector_option required = false
49
49
  method_option :selector, :type => :hash, :required => required, :desc => 'Selector to query collins. Takes the form of --selector=key1:val1 key2:val2 etc'
50
50
  method_option :remote, :type => :boolean, :default => false, :desc => 'Search all collins instances, including remote ones'
51
+ method_option :size, :type => :numeric, :default => 50, :desc => 'Number of results to find. Defaults to 50'
51
52
  end
52
53
 
53
54
  def selector_or_tag
@@ -61,9 +62,16 @@ module CollinsShell
61
62
  end
62
63
 
63
64
  def require_yes message, color = nil, should_exit = true
65
+ def appropriate_answer?(a); na = a.to_s.downcase.strip; na == 'yes' || na == 'no'; end
64
66
  highline = HighLine.new
65
67
  colored_message = set_color(message, color)
66
- answer = ask(colored_message)
68
+ answer = nil
69
+ while !appropriate_answer?(answer) do
70
+ unless answer.nil? then
71
+ say_status "error", "Please type 'yes' or 'no'.", :red
72
+ end
73
+ answer = ask(colored_message)
74
+ end
67
75
  if answer.downcase.strip !~ /^yes$/ then
68
76
  if should_exit then
69
77
  exit(0)
@@ -84,7 +92,7 @@ module CollinsShell
84
92
  require_non_empty(success_message, "success_message not set")
85
93
  require_non_empty(error_message, "error_message not set")
86
94
  require_non_empty(operation, "operation not set")
87
- selector = get_selector selector_or_tag, [], nil, options[:remote]
95
+ selector = get_selector selector_or_tag, [], options[:size], options[:remote]
88
96
  call_collins get_collins_client, operation do |client|
89
97
  assets = client.find selector
90
98
  if assets.length > 1 then
@@ -1,5 +1,6 @@
1
1
  require 'collins_shell/monkeypatch'
2
2
  require 'collins_shell/util/asset_stache'
3
+ require 'open3'
3
4
 
4
5
  module CollinsShell
5
6
  module Util
@@ -50,13 +51,65 @@ module CollinsShell
50
51
  selector
51
52
  end
52
53
 
53
- def asset_exec asset, execs, confirm = true
54
+ def asset_exec asset, execs, confirm = true, threads = 1
54
55
  return unless execs
55
56
  mustache = CollinsShell::Util::AssetStache.new asset
56
57
  rendered = mustache.render "/bin/bash -c '#{execs}'"
57
58
  say_status("exec", rendered, :red)
58
59
  require_yes("Running on #{asset.tag}. ARE YOU SURE?", :red) if confirm
59
- system(rendered)
60
+ if threads < 2 then
61
+ system(rendered)
62
+ else
63
+ run_command_in_thread(rendered, threads)
64
+ end
65
+ end
66
+
67
+ # Should be called after asset_exec
68
+ def finalize_exec
69
+ thread_mgr.threads.each(&:join)
70
+ end
71
+
72
+ # Wraps open threads and provides a synchronized output buffer for concurrently writing output
73
+ def thread_mgr
74
+ @_thread_mgr ||= OpenStruct.new({
75
+ :threads => [],
76
+ :lock => Mutex.new
77
+ })
78
+ end
79
+
80
+ def say_status(status, message, log_status=true)
81
+ thread_mgr.lock.synchronize {
82
+ super
83
+ }
84
+ end
85
+
86
+ # @param [String] syscmd The system command to execute
87
+ # @param [Fixnum] thread_count The numbers of threads to allow running at one time
88
+ def run_command_in_thread syscmd, thread_count
89
+ if thread_mgr.threads.size > thread_count then
90
+ thread_mgr.threads.each(&:join)
91
+ thread_mgr.threads.clear
92
+ else
93
+ thread_mgr.threads << Thread.new(syscmd) do |cmd|
94
+ begin
95
+ stdin, stdout, stderr, thread = Open3.popen3(cmd)
96
+ stdin.close
97
+ o, e = [stdout, stderr].map {|p| begin p.read ensure p.close end}
98
+ unless o.empty? then
99
+ say_status("stdout: #{cmd}", o, :green)
100
+ end
101
+ unless e.empty? then
102
+ say_status("stderr: #{cmd}", e, :red)
103
+ end
104
+ if thread then
105
+ Process.kill('TERM', thread.pid) rescue nil
106
+ thread.kill unless nil
107
+ end
108
+ rescue Exception => e
109
+ say_status("exception: #{cmd}", e.to_s, :red)
110
+ end
111
+ end
112
+ end
60
113
  end
61
114
 
62
115
  def asset_get tag, options
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: collins_shell
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.17
4
+ version: 0.2.18
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-18 00:00:00.000000000 Z
12
+ date: 2013-03-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: collins_client
@@ -184,7 +184,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
184
184
  version: '0'
185
185
  segments:
186
186
  - 0
187
- hash: -728758615218698730
187
+ hash: -4494318623502944839
188
188
  required_rubygems_version: !ruby/object:Gem::Requirement
189
189
  none: false
190
190
  requirements: