collins_shell 0.2.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/.pryrc +1 -0
  2. data/.rvmrc +1 -0
  3. data/Gemfile +18 -0
  4. data/Gemfile.lock +59 -0
  5. data/README.md +335 -0
  6. data/Rakefile +64 -0
  7. data/VERSION +1 -0
  8. data/bin/collins-shell +36 -0
  9. data/collins_shell.gemspec +95 -0
  10. data/lib/collins_shell.rb +3 -0
  11. data/lib/collins_shell/asset.rb +198 -0
  12. data/lib/collins_shell/cli.rb +185 -0
  13. data/lib/collins_shell/console.rb +129 -0
  14. data/lib/collins_shell/console/asset.rb +127 -0
  15. data/lib/collins_shell/console/cache.rb +17 -0
  16. data/lib/collins_shell/console/command_helpers.rb +131 -0
  17. data/lib/collins_shell/console/commands.rb +28 -0
  18. data/lib/collins_shell/console/commands/cat.rb +123 -0
  19. data/lib/collins_shell/console/commands/cd.rb +61 -0
  20. data/lib/collins_shell/console/commands/io.rb +26 -0
  21. data/lib/collins_shell/console/commands/iterators.rb +190 -0
  22. data/lib/collins_shell/console/commands/tail.rb +178 -0
  23. data/lib/collins_shell/console/commands/versions.rb +42 -0
  24. data/lib/collins_shell/console/filesystem.rb +121 -0
  25. data/lib/collins_shell/console/options_helpers.rb +8 -0
  26. data/lib/collins_shell/errors.rb +7 -0
  27. data/lib/collins_shell/ip_address.rb +144 -0
  28. data/lib/collins_shell/ipmi.rb +67 -0
  29. data/lib/collins_shell/monkeypatch.rb +60 -0
  30. data/lib/collins_shell/provision.rb +152 -0
  31. data/lib/collins_shell/state.rb +98 -0
  32. data/lib/collins_shell/tag.rb +41 -0
  33. data/lib/collins_shell/thor.rb +209 -0
  34. data/lib/collins_shell/util.rb +120 -0
  35. data/lib/collins_shell/util/asset_printer.rb +265 -0
  36. data/lib/collins_shell/util/asset_stache.rb +32 -0
  37. data/lib/collins_shell/util/log_printer.rb +187 -0
  38. data/lib/collins_shell/util/printer_util.rb +28 -0
  39. metadata +200 -0
data/.pryrc ADDED
@@ -0,0 +1 @@
1
+ Pry.config.default_asset_format = '{{tag}} {{hostname}} {{status}}'
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use ruby-1.9.3
data/Gemfile ADDED
@@ -0,0 +1,18 @@
1
+ source :rubygems
2
+
3
+ Encoding.default_external = Encoding::UTF_8
4
+
5
+ gem 'collins_client', '~> 0.2.7'
6
+ gem 'highline', '~> 1.6.15'
7
+ gem 'mustache', '~> 0.99.4'
8
+ gem 'pry', '~> 0.9.9.6'
9
+ gem 'rubygems-update','~> 1.8.24'
10
+ gem 'terminal-table', '~> 1.4.5'
11
+ gem 'thor', '~> 0.16.0'
12
+
13
+ group :development do
14
+ gem 'jeweler', '~> 1.8.3'
15
+ gem 'redcarpet'
16
+ gem 'rspec', '~> 2.10.0'
17
+ gem 'yard', '~> 0.8'
18
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,59 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ coderay (1.0.8)
5
+ collins_client (0.2.7)
6
+ httparty (~> 0.8.3)
7
+ diff-lcs (1.1.3)
8
+ git (1.2.5)
9
+ highline (1.6.15)
10
+ httparty (0.8.3)
11
+ multi_json (~> 1.0)
12
+ multi_xml
13
+ jeweler (1.8.4)
14
+ bundler (~> 1.0)
15
+ git (>= 1.2.5)
16
+ rake
17
+ rdoc
18
+ json (1.7.5)
19
+ method_source (0.7.1)
20
+ multi_json (1.3.6)
21
+ multi_xml (0.5.1)
22
+ mustache (0.99.4)
23
+ pry (0.9.9.6)
24
+ coderay (~> 1.0.5)
25
+ method_source (~> 0.7.1)
26
+ slop (>= 2.4.4, < 3)
27
+ rake (0.9.2.2)
28
+ rdoc (3.12)
29
+ json (~> 1.4)
30
+ redcarpet (2.2.2)
31
+ rspec (2.10.0)
32
+ rspec-core (~> 2.10.0)
33
+ rspec-expectations (~> 2.10.0)
34
+ rspec-mocks (~> 2.10.0)
35
+ rspec-core (2.10.1)
36
+ rspec-expectations (2.10.0)
37
+ diff-lcs (~> 1.1.3)
38
+ rspec-mocks (2.10.1)
39
+ rubygems-update (1.8.24)
40
+ slop (2.4.4)
41
+ terminal-table (1.4.5)
42
+ thor (0.16.0)
43
+ yard (0.8.3)
44
+
45
+ PLATFORMS
46
+ ruby
47
+
48
+ DEPENDENCIES
49
+ collins_client (~> 0.2.7)
50
+ highline (~> 1.6.15)
51
+ jeweler (~> 1.8.3)
52
+ mustache (~> 0.99.4)
53
+ pry (~> 0.9.9.6)
54
+ redcarpet
55
+ rspec (~> 2.10.0)
56
+ rubygems-update (~> 1.8.24)
57
+ terminal-table (~> 1.4.5)
58
+ thor (~> 0.16.0)
59
+ yard (~> 0.8)
data/README.md ADDED
@@ -0,0 +1,335 @@
1
+ # CollinsShell Description
2
+
3
+ The collins shell is a lightweight application built on top of the
4
+ `collins_client` gem. The `collins_client` gem provides API access to collins,
5
+ the `collins_shell` application provides CLI API access to collins.
6
+
7
+ ## Installation
8
+
9
+ > gem install collins_shell --source=http://repo.tumblr.net:9929
10
+
11
+ ## Setup
12
+
13
+ Collins shell will look for a yaml file at ~/.collins.yaml, passed in via
14
+ `--config=my_collins.yaml`, or passed in via an environment variable like
15
+ `COLLINS=~/my_collins.yaml`. The file should look like:
16
+
17
+ ---
18
+ collins:
19
+ host: "http://somehost:8080"
20
+ username: "user"
21
+ password: "secret"
22
+
23
+ You can also specify the host, username, or options via the `--host`,
24
+ `--username` and `--password` options. If you just specify `--password`
25
+ (without a value), or your configs are missing a password, you will be
26
+ prompted for one.
27
+
28
+ ## Overview
29
+
30
+ There are a few common themes found throughout the collins shell that will
31
+ help you be productive.
32
+
33
+ ### Command Structure
34
+
35
+ collins-shell uses thor under the hood to handle command line dispatching and
36
+ parsing. Arguments to collins-shell consist of commands, subcommands,
37
+ arguments, and options.
38
+
39
+ Supported commands and subcommands are:
40
+
41
+ asset
42
+ create
43
+ delete
44
+ delete_attribute
45
+ find
46
+ get
47
+ set_attribute
48
+ set_status
49
+ console
50
+ ip_address
51
+ allocate
52
+ assets
53
+ delete
54
+ delete_all
55
+ find
56
+ pools
57
+ update
58
+ ipmi
59
+ create
60
+ update
61
+ latest
62
+ log
63
+ logs
64
+ power
65
+ power_status
66
+ provision
67
+ host
68
+ list
69
+ tag
70
+ list
71
+ values
72
+ version
73
+
74
+ All commands are of the form:
75
+
76
+ collins-shell <command> <args> <options>
77
+
78
+ Every command can be described via `help`, e.g. `collins-shell help log` or
79
+ `collins-shell asset help create`. Note that to get help for a subcommand, the
80
+ help directive must come after the command, but before the subcommand.
81
+
82
+ This returns help for the `asset find` subcommand:
83
+
84
+ collins-shell asset help find
85
+
86
+ This returns help for the `asset` command (the `find` subcommand is ignored):
87
+
88
+ collins-shell help asset find
89
+
90
+ A command is something like `log` or `asset find`. Arguments are required
91
+ options, passed to the command without a switch (e.g. `asset get TAG`, `TAG`
92
+ is an argument there). Options are optional, and generally passed like
93
+ `--option` or `--option=value`.
94
+
95
+ ### Universal Options
96
+
97
+ The following options can be specified for every command:
98
+
99
+ --config=CONFIG # YAML configuration file
100
+ --debug # Debug output
101
+ --host=HOST # Collins host (e.g. http://host:port)
102
+ --quiet # Mostly used in conjunction with commands that have an --exec option
103
+ --timeout=SECONDS # Seconds to allow for operation, defaults to 30
104
+ --username=USERNAME # Collins username
105
+ --password=PASSWORD # Collins password
106
+
107
+
108
+ ### Common Options
109
+
110
+ Many options will allow you to specify either a selector (matching many
111
+ assets) or a tag (matching a single asset). A tag is the asset tag, a selector
112
+ is a space separated list of `key:value` pairs that are asset keys and values.
113
+ Some examples are:
114
+
115
+ # Allocated web servers (note that multiple selectors are separated by a space)
116
+ --selector=hostname:'^web.*' status:Allocated
117
+ # Allocated master database servers in the main pool
118
+ --selector=primary_role:database pool:main secondary_role:master status:Allocated
119
+ # Asset with tag 001923
120
+ --tag=001923
121
+
122
+ Note that any time a command will result in changing more than one asset,
123
+ collins-shell will prompt for confirmation.
124
+
125
+ # Multi-Collins Support
126
+
127
+ Collins has a feature called 'multi-collins' that allows multiple collins servers to
128
+ know about each other. This functionality provides a unified view of all assets,
129
+ regardless of which collins server stores a given asset. If you have enabled
130
+ multi-collins, your collins-shell configuration only needs to have credentials and host
131
+ information for one of your collins servers.
132
+
133
+ By default, collins-shell only interacts a single collins server (the one specified in the configuration file). To run commands against all of your collins servers, pass the `--remote` option.
134
+
135
+ One exception to this is `asset get`. `asset get` takes `--remote=TAG` where
136
+ tag is the asset tag of the datacenter that has the asset, e.g.
137
+ `--remote=ewr01` or `--remote=d2`.
138
+
139
+ The following commands support multi-collins:
140
+
141
+ asset find
142
+ asset get (with --remote=DC)
143
+ asset set_attribute
144
+ asset delete_attribute
145
+ asset set_status
146
+ log
147
+
148
+ Because `asset find` supports multi-collins, for any commands that don't (e.g.
149
+ `power_status`, it's trivial to script piping the results of the find to some
150
+ other command.
151
+
152
+ # Usage
153
+
154
+ ## Getting Help
155
+
156
+ Before using any command, check out the help. You can see help for a command
157
+ by running:
158
+
159
+ collins-shell help <command>
160
+
161
+ or
162
+
163
+ collins-shell <sub> help <command>
164
+
165
+ Where `<sub>` is something like `asset`, `ipmi` or `ip_address` and
166
+ `<command>` is something like `create`, `delete` or `get`. For example
167
+
168
+ > collins-shell asset help get
169
+ Usage:
170
+ collins-shell asset get TAG
171
+
172
+ Options:
173
+ --config=CONFIG # YAML configuration file
174
+ --debug # Debug output
175
+ --host=HOST # Collins host (e.g. http://host:port)
176
+ --password=PASSWORD # Collins password
177
+ --quiet # Be quiet when appropriate
178
+ --timeout=N # Collins client timeout
179
+ # Default: 30
180
+ --username=USERNAME # Collins username
181
+ --confirm # Require exec confirmation. Defaults to true
182
+ # Default: true
183
+ --exec=EXEC # Execute a command using the data from this asset. Use {{hostname}}, {{ipmi.password}}, etc for substitution
184
+ --logs # Also display asset logs
185
+ --remote=REMOTE # Remote location to search. This is a tag in collins corresponding to the datacenter asset
186
+
187
+ get an asset and display its attributes
188
+
189
+ ## Examples
190
+
191
+ > collins-shell
192
+ Tasks:
193
+ collins-shell asset <command> # Asset related commands
194
+ collins-shell console # drop into the interactive collins shell
195
+ collins-shell help [TASK] # Describe available tasks or one specific task
196
+ collins-shell ip_address <command> # IP address related commands
197
+ collins-shell ipmi <command> # IPMI related commands
198
+ collins-shell log MESSAGE # log a message on an asset
199
+ collins-shell power ACTION --reason=REASON --tag=TAG # perform power action (off, on, rebootSoft, rebootHard, etc) on an asset
200
+ collins-shell power_status --tag=TAG # check power status on an asset
201
+ collins-shell provision <command> # Provisioning related commands
202
+ collins-shell tag <command> # Tag related commands
203
+ > collins-shell asset
204
+ Tasks:
205
+ collins-shell asset create --tag=TAG # create an asset in collins
206
+ collins-shell asset delete --tag=TAG # delete an asset in collins (must be cancelled)
207
+ collins-shell asset delete_attribute KEY # delete an attribute in collins
208
+ collins-shell asset find --selector=key value # find assets using the specified selector
209
+ collins-shell asset get TAG # get an asset and display its attributes
210
+ collins-shell asset help [COMMAND] # Describe subcommands or one specific subcommand
211
+ collins-shell asset set_attribute KEY VALUE # set an attribute in collins
212
+ collins-shell asset set_status STATUS # set status on an asset
213
+ > collins-shell asset find --selector=status:Allocated 'hostname:^web.*'
214
+ id,tag,status,type,created,updated
215
+ 18,sl-90918,Allocated,Server Node,2012-02-08T00:34:43+00:00,2012-06-09T00:31:39+00:00
216
+ 20,sl-111623,Allocated,Server Node,2012-02-08T00:34:44+00:00,2012-06-09T01:25:35+00:00
217
+ 21,sl-70108,Allocated,Server Node,2012-02-08T00:34:44+00:00,2012-06-09T00:42:16+00:00
218
+ 23,sl-89121,Allocated,Server Node,2012-02-08T00:34:47+00:00,2012-06-09T00:33:31+00:00
219
+
220
+ # Tips and Tricks
221
+
222
+ There are a couple of neat features in the collins shell to be aware of.
223
+
224
+ ## Detailed asset views
225
+
226
+ I have tried to make the shell as consistent with the web UI as possible. Try
227
+ running a command like:
228
+
229
+ collins-shell asset get VALID_TAG_HERE
230
+
231
+ The display should be familiar to people if you've logged into the web UI.
232
+
233
+ ## Asset Logs
234
+
235
+ Adding `--logs` to your `asset get` or `asset find` commands will show logs
236
+ for each asset.
237
+
238
+ ## Making find more useful
239
+
240
+ There are three switches that are useful to know about with the `asset find`
241
+ command.
242
+
243
+ ### awk format
244
+
245
+ If you need to do some kind of post processing on data not found in the
246
+ default find results, you can specify them via the `--tags` option. This will
247
+ give you a comma separated list of tags, one for each asset. For example:
248
+
249
+ collins-shell asset find --selector=hostname:'^web' status:Allocated --tags=hostname addresses
250
+
251
+ Will provide you a list that might look like:
252
+
253
+ hostname,addresses
254
+ web-7c177b48.d2.tumblr.net,10.80.96.243|10.80.96.1|255.255.248.0,192.172.29.80|192.172.29.65|255.255.255.224
255
+ web-a1a316af.d2.tumblr.net,10.80.97.95|10.80.96.1|255.255.248.0,192.172.38.108|192.172.38.97|255.255.255.224
256
+
257
+ The header line tells you the asset tags you are displaying. Each
258
+ line has a comma separated list of values. If a value is an array of some
259
+ sort, values within it are separated by pipes. Easy parsing!
260
+
261
+ If you would prefer not to display the header line, just add `--header=false` to your find command.
262
+
263
+ Note there is one caveat, the current version of collins-shell cannot prompt for authentication
264
+ data if you are passing output to a pipe. In order to pass output to a pipe, you must have your
265
+ collins server and credentials defined in ~/.collins.yaml or pass them to collins-shell on the
266
+ command line.
267
+
268
+ ### Detailed output
269
+
270
+ Try adding `--details` to your `asset find` command to get a detailed asset
271
+ view of each of the assets in the result set.
272
+
273
+ ### Size
274
+
275
+ Setting `--size=N` (e.g. `--size=1000`) will give you that number of results
276
+ or less. The default is 50 results.
277
+
278
+ ## Friendly Sizes
279
+
280
+ If you're querying on the `memory_size_total` or `disk_storage_total`, you can
281
+ use human readable values like `72GB` or `2.18298348411918TB`. Yeah, the disk
282
+ one kind of sucks. But, if you do a `get` or `find --details` you can see what
283
+ the correct query value is.
284
+
285
+ ## Execute commands using asset data
286
+
287
+ Some commands support an `--exec` option that allows you to execute a command
288
+ using the information associated with the asset. An example might be:
289
+
290
+ collins-shell asset get TAG \
291
+ --exec='IPMI_PASSWORD={{ipmi.password}} ipmitool -I lanplus -E -U {{ipmi.username}} -H {{ipmi.address}} sol activate'
292
+
293
+ This will create a console session using IPMI with the asset specified by `TAG`. Any attributes of an asset
294
+ can be specified as `{{attribute}}`, e.g. `{{hostname}}` or `{{addresses.first.address}}`.
295
+
296
+ # The Interactive Shell
297
+
298
+ It is also possible to use collins shell in an interactive mode. You can drop
299
+ into the collins shell console by doing:
300
+
301
+ collins-shell console
302
+
303
+ Be sure to provide your config YAML in the usual way. Once you are in the shell
304
+ you can get a list of global commands by typing `help`. Global commands can be
305
+ used regardless of context. Below is a sample interactive session.
306
+
307
+ collins / > ls /
308
+ ....
309
+ collins / > cd /PRIMARY_ROLE
310
+ collins /PRIMARY_ROLE > ls
311
+ collins /PRIMARY_ROLE > cd DEVEL
312
+ collins /PRIMARY_ROLE/DEVEL > ls --format='{{hostname}} {{status}} {{tag}}' --grep=blake
313
+ collins /PRIMARY_ROLE/DEVEL > cd sl-91016
314
+ collins /PRIMARY_ROLE/DEVEL/sl-91016* > ls
315
+ collins /PRIMARY_ROLE/DEVEL/sl-91016* > cat -b
316
+ collins /PRIMARY_ROLE/DEVEL/sl-91016* > cat /var/log/messages
317
+ collins /PRIMARY_ROLE/DEVEL/sl-91016* > cat /var/log/NOTE
318
+ collins /PRIMARY_ROLE/DEVEL/sl-91016* > asset.created.to_s
319
+ collins /PRIMARY_ROLE/DEVEL/sl-91016* > power?
320
+ collins /PRIMARY_ROLE/DEVEL/sl-91016* > reboot!
321
+ collins /PRIMARY_ROLE/DEVEL/sl-91016* > cd ../sl-102313
322
+ collins /PRIMARY_ROLE/DEVEL/sl-102313* > stat
323
+
324
+ This is all ruby, so you can play with a lot of this data using ruby as you
325
+ would expect. Some examples:
326
+
327
+ collins / > ls /HOSTNAME/.*blake.* | {|array| array.map{|a| [a.tag,a.hostname,a.status]}}
328
+ collins / > hosts = _
329
+ collins / > hosts.select do |host|
330
+ collins / * host[2] == 'Allocated'
331
+ collins / * end.map do |host|
332
+ collins / * [host[0], host[1], collins_client.with_asset(host[0]).power_status]
333
+ collins / * end
334
+
335
+ The above checks the power status of the selected hosts.
data/Rakefile ADDED
@@ -0,0 +1,64 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+ require 'jeweler'
14
+
15
+ jeweler = Jeweler::Tasks.new do |gem|
16
+ gem.name = 'collins_shell'
17
+ gem.homepage = 'https://github.com/tumblr/collins/tree/master/support/collins-shell'
18
+ gem.license = 'APL 2.0'
19
+ gem.summary = %Q{Shell for Collins API}
20
+ gem.description = "Provides basic CLI for interacting with Collins API"
21
+ gem.email = 'bmatheny@tumblr.com'
22
+ gem.authors = ['Blake Matheny']
23
+ gem.files.exclude "spec/**/*"
24
+ gem.files.exclude '.gitignore'
25
+ gem.files.exclude '.rspec'
26
+ gem.add_runtime_dependency 'collins_client', '~> 0.2.7'
27
+ gem.add_runtime_dependency 'highline', '~> 1.6.15'
28
+ gem.add_runtime_dependency 'mustache', '~> 0.99.4'
29
+ gem.add_runtime_dependency 'pry', '~> 0.9.9.6'
30
+ gem.add_runtime_dependency 'rubygems-update', '~> 1.8.24'
31
+ gem.add_runtime_dependency 'terminal-table', '~> 1.4.5'
32
+ gem.add_runtime_dependency 'thor', '~> 0.16.0'
33
+ end
34
+
35
+ task :help do
36
+ puts("rake -T # See available rake tasks")
37
+ puts("rake publish # generate gemspec, build it, push it to repo")
38
+ puts("rake version:bump:patch # Bump patch number")
39
+ puts("rake all # bump patch and publish")
40
+ puts("rake # Run tests")
41
+ end
42
+
43
+ task :publish => [:gemspec, :build] do
44
+ package_abs = jeweler.jeweler.gemspec_helper.gem_path
45
+ package_name = File.basename(package_abs)
46
+
47
+ ["repo.tumblr.net","repo.ewr01.tumblr.net"].each do |host|
48
+ puts("Copying #{package_abs} to #{host} and installing, you may be prompted for your password")
49
+ system "scp #{package_abs} #{host}:"
50
+ system "ssh -t #{host} 'sudo tumblr_gem install #{package_name}'"
51
+ end
52
+ end
53
+
54
+ task :all => ["version:bump:patch", :publish] do
55
+ puts("Done!")
56
+ end
57
+
58
+ task :default => :yard
59
+
60
+ require 'yard'
61
+ YARD::Rake::YardocTask.new do |t|
62
+ t.files = ['lib/**/*.rb']
63
+ t.options = ['--markup', 'markdown']
64
+ end