tmux-connector 0.9.7 → 1.0.8

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/README.md CHANGED
@@ -2,8 +2,28 @@
2
2
 
3
3
  Manage multiple servers using SSH and [tmux].
4
4
 
5
+ For the demo and short intro, read [this blog post][blog-post].
6
+
7
+
8
+ - [Features](#features)
9
+ - [Quick tease](#quick-tease)
10
+ - [CLI description](#cli-description)
11
+ - [Send command](#send-command)
12
+ - [Configuration](#configuration)
13
+ - [Sessions without configuration files](#sessions-without-configuration-files)
14
+ - [Requirements](#requirements)
15
+ - [Installation](#installation)
16
+ - [Installing tmux](#installing-tmux)
17
+ - [Tips](#tips)
18
+ - [SSH config files](#ssh-config-files)
19
+ - [Tmux configuration](#tmux-configuration)
20
+ - [Sending the commands](#sending-the-commands)
21
+ - [Contributing](#contributing)
22
+ - [Comments, ideas or if you feel like chatting](#comments-ideas-or-if-you-feel-like-chatting)
23
+
24
+
25
+ ## Features
5
26
 
6
- ## Features:
7
27
  * connect to multiple servers at once
8
28
  * expressive layouts customizable for different server groups available
9
29
  * issue commands to all servers or just a selected (custom) subgroup
@@ -51,6 +71,11 @@ Manage multiple servers using SSH and [tmux].
51
71
 
52
72
  - resume (recreate) 's#3' session, even after computer restart
53
73
 
74
+ `tcon start -q "dev.node-staging-[[42,]]"`
75
+
76
+ - starts quick session (no config file); selects all 'node' servers that have
77
+ index of at least 42
78
+
54
79
 
55
80
  ## CLI description
56
81
 
@@ -63,12 +88,13 @@ even after computer restarts. Complex sessions with different layouts for
63
88
  different kinds of servers can be easily created.
64
89
 
65
90
  Usage:
66
- tcon start <config-file> [--ssh-config=<file>]
67
- [--session-name=<name>] [--purpose=<description>]
91
+ tcon start ( <config-file> | --quick-session=<qs-args> )
92
+ [--ssh-config=<file>] [--session-name=<name>]
93
+ [--purpose=<description>]
68
94
  tcon resume <session-name>
69
95
  tcon delete (<session-name> | --all)
70
96
  tcon list
71
- tcon send <session-name> (<command> | --command-file=<file>)
97
+ tcon send <session-name> ( <command> | --command-file=<file> )
72
98
  [ --server-filter=<filter> | --group-filter=<regex>
73
99
  | --filter=<regex> | --window=<index> ]
74
100
  [--verbose]
@@ -76,35 +102,39 @@ Usage:
76
102
  tcon --version
77
103
 
78
104
  Options:
79
- <config-file> Path to configuration file. Configuration file
80
- describes how new session is started. YAML format.
81
- <session-name> Name that identifies the session. Must be unique.
82
- <command> Command to be executed on remote server[s].
83
- <regex> String that represents valid Ruby regex.
84
- <index> 0-based index.
85
- <filter> Filter consisting of a valid ruby regex and
86
- optionally of a special predicate.
87
- For more information see README file.
88
- -s --ssh-config=file Path to ssh config file [default: ~/.ssh/config].
89
- -n --session-name=name Name of the session to be used in the tcon command.
90
- -p --purpose=description Description of session's purpose.
91
- --all Delete all existing sessions.
92
- -f --server-filter=filter Filter to select a subset of the servers via
93
- host names.
94
- -g --group-filter=regex Filter to select a subset of the servers via
95
- group membership.
96
- -r --filter=regex Filter to select a subset of the servers via
97
- host names or group membership.
98
- Combines --server-filter and --group-filter.
99
- -w --window=index Select a window via (0-based) index.
100
- -c --command-file=file File containing the list of commands to be
101
- executed on remote server[s].
102
- -v --verbose Report how many servers were affected by the send
103
- command.
104
- -h --help Show this screen.
105
- --version Show version.
105
+ <config-file> Path to configuration file. Configuration file
106
+ describes how new session is started. YAML.
107
+ <qs-args> Arguments needed to start a quick session.
108
+ <session-name> Name to identify the session. Must be unique.
109
+ <command> Command to be executed on remote server[s].
110
+ <regex> String that represents valid Ruby regex.
111
+ <index> 0-based index.
112
+ <filter> Filter consisting of a valid ruby regex and
113
+ optionally of a special predicate.
114
+ For more information see README file.
115
+ -q --quick-session=qs-args Start the seesion without a configuration file.
116
+ Specify necessary argumenst instead.
117
+ -s --ssh-config=file Path to ssh config file. [default: ~/.ssh/config]
118
+ -n --session-name=name Name of the session.
119
+ -p --purpose=description Description of session's purpose.
120
+ --all Delete all existing sessions.
121
+ -f --server-filter=filter Filter to select a subset of the servers via
122
+ host names.
123
+ -g --group-filter=regex Filter to select a subset of the servers via
124
+ group membership.
125
+ -r --filter=regex Filter to select a subset of the servers via
126
+ host names or group membership.
127
+ Combines --server-filter and --group-filter.
128
+ -w --window=index Select a window via (0-based) index.
129
+ -c --command-file=file File containing the list of commands to be
130
+ executed on remote server[s].
131
+ -v --verbose Report how many servers were affected by the
132
+ send command.
133
+ -h --help Show this screen.
134
+ --version Show version.
106
135
  ~~~
107
136
 
137
+
108
138
  ### Send command
109
139
 
110
140
  Send command sends user specified command(s) to chosen panes.
@@ -162,14 +192,10 @@ tcon send production -f 'worker' 'tail -f /var/log/syslog'
162
192
  tcon send production -f 'worker :: <,3]; 7; <9,13>' 'C-c'
163
193
  ~~~
164
194
 
165
- ## Configuration
166
195
 
167
- To use this gem, you need to create a configuration file. This shouldn't be
168
- that hard and here I provide exhaustive details about configuration files.
196
+ ## Configuration
169
197
 
170
- (If there is enough interest, in future versions there could be a special
171
- command to simplify generation of configuration files. To accelerate the
172
- process, open an issue or drop me an email: ivan@<< username >>.com)
198
+ To use this gem, you usually need to create a configuration file.
173
199
 
174
200
  Let's get to it.
175
201
 
@@ -248,6 +274,9 @@ hostless:
248
274
  merge-groups:
249
275
  misc: ['cache', 'db', 'mongodb']
250
276
  lbs: ['haproxy', 'nginx']
277
+ group-ranges:
278
+ cache: [1, 4]
279
+ node: [125, 131]
251
280
  multiple-hosts:
252
281
  regexes:
253
282
  - !ruby-regexp '(nginx|haproxy)-'
@@ -283,7 +312,7 @@ Host dev.database-staging-1
283
312
  ~~~
284
313
 
285
314
  and the following regex is used:
286
- ~~~
315
+ ~~~yaml
287
316
  regex: !ruby-regexp '^(\w+)\.(\w+)-([\w-]+)-(\d+)$'
288
317
  ~~~
289
318
 
@@ -345,7 +374,7 @@ Hostless panes can be used to:
345
374
  layout purposes) together. This can be used to group a few servers that are
346
375
  unique in type or small in numbers. E.g. grouping different DB servers.
347
376
 
348
- ~~~
377
+ ~~~yaml
349
378
  lbs: ['haproxy', 'nginx']
350
379
  ~~~
351
380
  In this example two different kinds of loadbalancers are grouped together.
@@ -355,6 +384,21 @@ original and merge-group name.
355
384
 
356
385
  Hostless groups can also be merged.
357
386
 
387
+ * * *
388
+ (optional) field __'group-ranges'__ contains groups that should be limited to
389
+ specific ranges of servers. Ranges are defined by lower and upper limits, both inclusive.
390
+ They are enforced on sort values (defined by aforementioned 'sort-by' field).
391
+
392
+ If the following group ranges were defined:
393
+ ~~~yaml
394
+ group-ranges:
395
+ cache: [1, 4]
396
+ node: [125, 131]
397
+ ~~~
398
+ Only cache servers with sort ids 1, 2, 3 or 4 would be included in the session.
399
+ Similarly for node servers, only servers with ids between 125 and 131 would be
400
+ included.
401
+
358
402
  * * *
359
403
  (optional) field __'multiple-hosts'__ contains __'regexes'__ and __'counts'__
360
404
  fields. With those, some hosts can have multiple connections established, not
@@ -401,6 +445,43 @@ Take a look at [`spec/fixtures/configs.yml`][configs] for some configuration
401
445
  possibilities (sections under 'input' fields).
402
446
 
403
447
 
448
+ ## Sessions without configuration files
449
+
450
+ As mentioned in previous section, normally you need the configuration file to
451
+ start the session.
452
+
453
+ This is not true for some smaller sessions where you can directly specify all
454
+ necessary configuration in command line when starting the session.
455
+
456
+ You can use `--quick-session` (or `-q`) to start a quick session. Quick
457
+ session arguments must conform to the following format:
458
+ ~~~
459
+ "<regex>[[<lower-limit>,<upper-limit>]]<additional-arguments>"
460
+ ~~~
461
+ where:
462
+
463
+ * `<regex>` is similar to 'regex' filed in configuration file, but without the
464
+ sorting part (which is presumably last part of the full regex)
465
+ * `<lower-limit>` and `<upper-limit>` are optional elements and define range of
466
+ valid servers. Range is enforced on sorting part (which is not part of
467
+ previous regex, but presumably comes after it)
468
+ * `<optional-additional-arguments>` is list of optional arguments. This list
469
+ starts with ' :: ' and consists of key-value pairs separated by semicolon.
470
+ Currently only `h` and `v` arguments are supported. Format:
471
+ `:: h <max-horizontal-panes>; v <max-vertical-panes>`
472
+
473
+ Examples:
474
+
475
+ - `tcon start -q "dev.node-staging-[[1,24]]"`
476
+ - `tcon start -q "dev.node-staging-[[42,]]"`
477
+ - `tcon start -q "dev.node-staging-[[,]]"`
478
+ - `tcon start -q "dev.node-staging-[[,42]] :: h 2; v 2"`
479
+
480
+ Example with more complex regex (selects 2 kinds of servers):
481
+
482
+ - `tcon start -q "dev.(nginx|haproxy)-staging-[[10,30]] :: h 2; v 2"`
483
+
484
+
404
485
  ## Requirements
405
486
  To be able to use the gem you should have ruby 1.9+ and tmux installed on a *nix
406
487
  (Mac OS X, Linux, ...) machine. (Windows: here be dragons)
@@ -463,6 +544,19 @@ user, and so configure tmux to use Vim-like bindings to switch panes. For more
463
544
  information, check my [dotfiles].
464
545
 
465
546
 
547
+ ### Sending the commands
548
+
549
+ You need to run the send command from somewhere. There are (at least) 2
550
+ options:
551
+
552
+ * have a controller pane (or the whole window) inside the tcon session
553
+ - a pane not connected to a server to issue the commands to other panes
554
+ * have a separate terminal pane for issuing the send commands
555
+ - I'm a iTerm2 user, and so I split the window vertically: much bigger
556
+ top pane for the tcon session, and a smaller bottom pane to issue the
557
+ send commands
558
+
559
+
466
560
  ## Contributing
467
561
 
468
562
  1. Fork it
@@ -480,9 +574,6 @@ comments (all other are welcome too). Just _drop me a line_. :)
480
574
 
481
575
  ## Comments, ideas or if you feel like chatting
482
576
 
483
- Take a look at `TODO.md` file (in the repository) for ideas about additional
484
- features in new versions.
485
-
486
577
  ivan@<< username >>.com
487
578
 
488
579
  I'd be happy to hear from you.
@@ -490,6 +581,7 @@ I'd be happy to hear from you.
490
581
  Also, visit my [homepage].
491
582
 
492
583
 
584
+ [blog-post]: http://www.ikusalic.com/blog/2013/06/18/managing-multiple-servers-with-tcon/
493
585
  [configs]: /spec/fixtures/configs.yml
494
586
  [docopt]: https://github.com/docopt/docopt
495
587
  [tmux]: http://en.wikipedia.org/wiki/Tmux
@@ -12,12 +12,13 @@ even after computer restarts. Complex sessions with different layouts for
12
12
  different kinds of servers can be easily created.
13
13
 
14
14
  Usage:
15
- tcon start <config-file> [--ssh-config=<file>]
16
- [--session-name=<name>] [--purpose=<description>]
15
+ tcon start ( <config-file> | --quick-session=<qs-args> )
16
+ [--ssh-config=<file>] [--session-name=<name>]
17
+ [--purpose=<description>]
17
18
  tcon resume <session-name>
18
19
  tcon delete (<session-name> | --all)
19
20
  tcon list
20
- tcon send <session-name> (<command> | --command-file=<file>)
21
+ tcon send <session-name> ( <command> | --command-file=<file> )
21
22
  [ --server-filter=<filter> | --group-filter=<regex>
22
23
  | --filter=<regex> | --window=<index> ]
23
24
  [--verbose]
@@ -25,33 +26,36 @@ Usage:
25
26
  tcon --version
26
27
 
27
28
  Options:
28
- <config-file> Path to configuration file. Configuration file
29
- describes how new session is started. YAML format.
30
- <session-name> Name that identifies the session. Must be unique.
31
- <command> Command to be executed on remote server[s].
32
- <regex> String that represents valid Ruby regex.
33
- <index> 0-based index.
34
- <filter> Filter consisting of a valid ruby regex and
35
- optionally of a special predicate.
36
- For more information see README file.
37
- -s --ssh-config=file Path to ssh config file [default: ~/.ssh/config].
38
- -n --session-name=name Name of the session to be used in the tcon command.
39
- -p --purpose=description Description of session's purpose.
40
- --all Delete all existing sessions.
41
- -f --server-filter=filter Filter to select a subset of the servers via
42
- host names.
43
- -g --group-filter=regex Filter to select a subset of the servers via
44
- group membership.
45
- -r --filter=regex Filter to select a subset of the servers via
46
- host names or group membership.
47
- Combines --server-filter and --group-filter.
48
- -w --window=index Select a window via (0-based) index.
49
- -c --command-file=file File containing the list of commands to be
50
- executed on remote server[s].
51
- -v --verbose Report how many servers were affected by the send
52
- command.
53
- -h --help Show this screen.
54
- --version Show version.
29
+ <config-file> Path to configuration file. Configuration file
30
+ describes how new session is started. YAML.
31
+ <qs-args> Arguments needed to start a quick session.
32
+ <session-name> Name to identify the session. Must be unique.
33
+ <command> Command to be executed on remote server[s].
34
+ <regex> String that represents valid Ruby regex.
35
+ <index> 0-based index.
36
+ <filter> Filter consisting of a valid ruby regex and
37
+ optionally of a special predicate.
38
+ For more information see README file.
39
+ -q --quick-session=qs-args Start the seesion without a configuration file.
40
+ Specify necessary argumenst instead.
41
+ -s --ssh-config=file Path to ssh config file. [default: ~/.ssh/config]
42
+ -n --session-name=name Name of the session.
43
+ -p --purpose=description Description of session's purpose.
44
+ --all Delete all existing sessions.
45
+ -f --server-filter=filter Filter to select a subset of the servers via
46
+ host names.
47
+ -g --group-filter=regex Filter to select a subset of the servers via
48
+ group membership.
49
+ -r --filter=regex Filter to select a subset of the servers via
50
+ host names or group membership.
51
+ Combines --server-filter and --group-filter.
52
+ -w --window=index Select a window via (0-based) index.
53
+ -c --command-file=file File containing the list of commands to be
54
+ executed on remote server[s].
55
+ -v --verbose Report how many servers were affected by the
56
+ send command.
57
+ -h --help Show this screen.
58
+ --version Show version.
55
59
  HERE
56
60
 
57
61
  def self.main(input_args)
@@ -13,14 +13,18 @@ module TmuxConnector
13
13
  attr_reader :session
14
14
 
15
15
  def initialize(args)
16
- @config = TmuxConnector.get_config args['<config-file>']
16
+ if args['<config-file>']
17
+ @config = TmuxConnector.get_config args['<config-file>']
18
+ elsif args['--quick-session']
19
+ @config = quick_session_to_config args['--quick-session']
20
+ end
17
21
 
18
22
  ssh_hostnames = SSHConfig.get_hosts(args['--ssh-config'], config['reject-regex'])
19
23
  @hosts = ssh_hostnames.reduce([]) do |acc, name|
20
24
  ( acc << Host.new(name, config) ) rescue nil
21
25
  acc
22
26
  end
23
- raise "no hosts matching given configuration found, check your configuration file" if hosts.empty?
27
+ raise "no hosts matching given configuration found, check your configuration" if hosts.empty?
24
28
 
25
29
  generate_groups
26
30
  generate_merge_rules
@@ -35,6 +39,62 @@ module TmuxConnector
35
39
 
36
40
  private
37
41
 
42
+ def quick_session_to_config(quick_args)
43
+ quick_regex = /(?<regex>.+)\[\[(?<first>[^,]*),\s*(?<second>[^\]]*)\]\]( :: (?<args>.+))?/
44
+ str_regex, first, last, additiona_args = quick_args.match(quick_regex)[1 .. -1]
45
+
46
+ first = "" if first =~ /^\s*$/
47
+ second = "" if second =~ /^\s*$/
48
+
49
+ conf = generate_fake_config str_regex
50
+ TmuxConnector.process_config! conf
51
+ apply_additional_arguments! conf, additiona_args
52
+
53
+ conf['group-ranges'] = {
54
+ TmuxConnector::QUICK_GROUP_ID => [first, last]
55
+ }
56
+
57
+ return conf
58
+ rescue
59
+ raise 'quick session argument parsing failed'
60
+ end
61
+
62
+ def generate_fake_config(str_regex)
63
+ return {
64
+ 'regex' => "(#{ str_regex })(.+)",
65
+ 'regex-parts-to' => {
66
+ 'group-by' => [0],
67
+ 'sort-by' => [-1]
68
+ }
69
+ }
70
+ end
71
+
72
+ def apply_additional_arguments!(conf, args)
73
+ return if args.nil?
74
+
75
+ args_delimiter = /;\s*/
76
+
77
+ options = args.split(args_delimiter).reduce({}) do |acc, e|
78
+ k, v = e.split
79
+ acc[k] = v
80
+ acc
81
+ end
82
+
83
+ begin
84
+ h, v = Integer(options['h'], 10), Integer(options['v'], 10)
85
+ conf['layout'] = {
86
+ 'default' => {
87
+ 'custom' => {
88
+ 'max-horizontal' => h,
89
+ 'max-vertical' => v,
90
+ 'panes-flow' => 'horizontal'
91
+ }
92
+ }
93
+ }
94
+ rescue
95
+ end
96
+ end
97
+
38
98
  def generate_groups()
39
99
  @groups = hosts.reduce({}) do |acc, e|
40
100
  acc[e.group_id] ||= []
@@ -1,4 +1,6 @@
1
1
  module TmuxConnector
2
+ QUICK_GROUP_ID = 'quick_group_id'
3
+
2
4
  class Host
3
5
  attr_accessor :sort_value
4
6
 
@@ -15,6 +17,7 @@ module TmuxConnector
15
17
  @sort_value = config['regex-parts-to']['sort-by'].map { |i| groups[i] }.join '-'
16
18
  @group_id = config['regex-parts-to']['group-by'].map { |i| groups[i] }.join '-'
17
19
 
20
+ check_range! config['group-ranges']
18
21
  @count = get_count config
19
22
  end
20
23
 
@@ -24,6 +27,22 @@ module TmuxConnector
24
27
 
25
28
  private
26
29
 
30
+ def check_range!(ranges)
31
+ return if ranges.nil?
32
+
33
+ range = ranges[group_id] || ranges[TmuxConnector::QUICK_GROUP_ID]
34
+ if range
35
+ a, b = range.map(&:to_s)
36
+ x = sort_value
37
+
38
+ numbers_only = [a, b, x].all? { |e| e =~ /^[-+]?[0-9]*$/ }
39
+ a, b, x = [a, b, x].map { |e| Integer(e, 10) rescue nil } if numbers_only
40
+
41
+ raise if a && x < a
42
+ raise if b && x > b
43
+ end
44
+ end
45
+
27
46
  def create_display_name(groups, config)
28
47
  if config['name']
29
48
  parts = []
@@ -1,3 +1,3 @@
1
1
  module TmuxConnector
2
- VERSION = "0.9.7"
2
+ VERSION = "1.0.8"
3
3
  end
@@ -55,5 +55,9 @@ describe "Configuration file" do
55
55
  it_should_behave_like "config test", 'hostless'
56
56
  it_should_behave_like "config test", 'hostless-merge'
57
57
  end
58
+
59
+ describe "group intervals" do
60
+ it_should_behave_like "config test", 'group-intervals'
61
+ end
58
62
  end
59
63
  end
@@ -48,6 +48,18 @@ merge:
48
48
  misc: ['repo', 'mongodb', 'sshforwarder']
49
49
  lbs: ['loadbalancer', 'ngx']
50
50
 
51
+ group-intervals:
52
+ input:
53
+ <<: *input-min
54
+ group-intervals:
55
+ lxc: [199, 243]
56
+ ngx: [11, 42]
57
+ expected:
58
+ <<: *expected-min
59
+ group-intervals:
60
+ lxc: [199, 243]
61
+ ngx: [11, 42]
62
+
51
63
  layout-default:
52
64
  input:
53
65
  <<: *input-min
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tmux-connector
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.7
4
+ version: 1.0.8
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: 2013-06-17 00:00:00.000000000 Z
12
+ date: 2013-07-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: docopt
@@ -60,7 +60,6 @@ files:
60
60
  - LICENSE.txt
61
61
  - README.md
62
62
  - Rakefile
63
- - TODO.md
64
63
  - bin/tcon
65
64
  - lib/tmux-connector.rb
66
65
  - lib/tmux-connector/command_handler.rb
data/TODO.md DELETED
@@ -1,12 +0,0 @@
1
- possible features for new version:
2
- * ensure it works with zsh
3
- * generate default config via just regex(es)
4
- * add strict config file validation
5
- * add window (via option) that won't connect to nay server
6
- - for tcon commands and regular actions on local machine
7
- * startup command
8
-
9
- code related:
10
- * add specs
11
- * test with ruby 2.0
12
- * refactoring