mirror of
https://github.com/duncs/clusterssh.git
synced 2025-06-30 00:34:04 +00:00
Compare commits
371 commits
release-4.
...
master
Author | SHA1 | Date | |
---|---|---|---|
![]() |
9431ccc863 | ||
![]() |
cc90a9a3fb | ||
![]() |
fea0b80d48 | ||
![]() |
2d39fe46f3 | ||
![]() |
6967bceb8b | ||
![]() |
a915d3d218 | ||
![]() |
46c9bfc067 | ||
![]() |
4188dc980f | ||
![]() |
4ea91d4e68 | ||
![]() |
b302a7724f | ||
![]() |
387190e8f6 | ||
![]() |
618602f496 | ||
![]() |
cffe20e5ae | ||
![]() |
5eae528662 | ||
![]() |
00d8aa0ebd | ||
![]() |
e11cc83620 | ||
![]() |
70b4731659 | ||
![]() |
4b317108fe | ||
![]() |
0b5b5c8608 | ||
![]() |
5ddb7dbe83 | ||
![]() |
6cbec687bd | ||
![]() |
c3a2336b09 | ||
![]() |
0505630d15 | ||
![]() |
bf6e9d0648 | ||
![]() |
b35f198f08 | ||
![]() |
208889e36d | ||
![]() |
4674b20fb9 | ||
![]() |
276cab7014 | ||
![]() |
82f88450d0 | ||
![]() |
7fe7c69769 | ||
![]() |
6ec912aac2 | ||
![]() |
dab4fa2237 | ||
![]() |
900d0fabb6 | ||
![]() |
e039fef919 | ||
![]() |
805f97cd78 | ||
![]() |
40079d23d9 | ||
![]() |
6529bccdbd | ||
![]() |
dd33799eb7 | ||
![]() |
537c4c2572 | ||
![]() |
2712379084 | ||
![]() |
fb4b90886b | ||
![]() |
40d0bd4b8f | ||
![]() |
73657d2fa3 | ||
![]() |
ee3677dcd9 | ||
![]() |
7095383762 | ||
![]() |
006216faff | ||
![]() |
49828a49d0 | ||
![]() |
2fc4516740 | ||
![]() |
6fbc2a3eab | ||
![]() |
204048ecc5 | ||
![]() |
2f5b717671 | ||
![]() |
30a0817d3c | ||
![]() |
5016a136d6 | ||
![]() |
e5c33c6e13 | ||
![]() |
e857392130 | ||
![]() |
47fd5237f9 | ||
![]() |
27a714ecfa | ||
![]() |
717e7af776 | ||
![]() |
09f2671d8e | ||
![]() |
0acfe66a99 | ||
![]() |
7670b0be39 | ||
![]() |
205bf683bd | ||
![]() |
d3d6e68325 | ||
![]() |
9bbe9fb161 | ||
![]() |
0c6506e378 | ||
![]() |
f5f92105c6 | ||
![]() |
314c91d8c7 | ||
![]() |
915a55b3bd | ||
![]() |
7d515388a2 | ||
![]() |
2e0f63360b | ||
![]() |
15d3e210cf | ||
![]() |
5b827fd163 | ||
![]() |
651c756f55 | ||
![]() |
4599f3df22 | ||
![]() |
f27c42c795 | ||
![]() |
c807b52129 | ||
![]() |
5615bbc5b1 | ||
![]() |
b9731d0e35 | ||
![]() |
0fe831e25f | ||
![]() |
3816e735b1 | ||
![]() |
4dcba4d693 | ||
![]() |
3a7e832855 | ||
![]() |
3d571b2801 | ||
![]() |
7163916a99 | ||
![]() |
e0d062e20a | ||
![]() |
684b5311d5 | ||
![]() |
1c03f947bf | ||
![]() |
c50b6fff14 | ||
![]() |
4a72b1cab3 | ||
![]() |
37ce2b8a0d | ||
![]() |
d8addf58d1 | ||
![]() |
0dbf7c6808 | ||
![]() |
9a4c7714f9 | ||
![]() |
16deb34d14 | ||
![]() |
93432c1580 | ||
![]() |
f2194ecdfa | ||
![]() |
a7e066e48f | ||
![]() |
73bf10ec34 | ||
![]() |
053bd6bbd1 | ||
![]() |
d612300480 | ||
![]() |
2cfc4739b2 | ||
![]() |
df96d66150 | ||
![]() |
80113e96b0 | ||
![]() |
309ec40de0 | ||
![]() |
d9b3de5d55 | ||
![]() |
4a1f0ed5fd | ||
![]() |
d6bd23ef12 | ||
![]() |
f1446f9be3 | ||
![]() |
34f6c3e77d | ||
![]() |
fa01db1a03 | ||
![]() |
d1bc22ee22 | ||
![]() |
cd355f965d | ||
![]() |
2b9b8990b7 | ||
![]() |
3109b4a33a | ||
![]() |
593b241e6a | ||
![]() |
d822ecd81d | ||
![]() |
1805c1c9d4 | ||
![]() |
a3373813db | ||
![]() |
b49a83f9da | ||
![]() |
6f1254b3d8 | ||
![]() |
5cd27cb11f | ||
![]() |
7c9cfb1531 | ||
![]() |
30221a6c31 | ||
![]() |
d64f872b26 | ||
![]() |
ae2e986c6e | ||
![]() |
771f0a18e4 | ||
![]() |
554605d8b0 | ||
![]() |
8e1e3f8afd | ||
![]() |
689343eb24 | ||
![]() |
08fba7cc7f | ||
![]() |
eebbea81b8 | ||
![]() |
fc66ddc34b | ||
![]() |
07f59738e6 | ||
![]() |
7a08f3239e | ||
![]() |
3e3ed2c1cc | ||
![]() |
f9c6120477 | ||
![]() |
a3e8e221e7 | ||
![]() |
4665a23f09 | ||
![]() |
4266c2a06e | ||
![]() |
b9a42101f1 | ||
![]() |
60d67f911b | ||
![]() |
196d7b79bf | ||
![]() |
0fb0ba10c2 | ||
![]() |
be418fa0d0 | ||
![]() |
bc7805ca4c | ||
![]() |
4f93b8fa3e | ||
![]() |
7981edecca | ||
![]() |
41fe0714b5 | ||
![]() |
4fe7b00713 | ||
![]() |
469897d4c5 | ||
![]() |
9f6c000592 | ||
![]() |
29762f2868 | ||
![]() |
067bab1894 | ||
![]() |
142d4ddd66 | ||
![]() |
7974687cfb | ||
![]() |
7822d337f7 | ||
![]() |
54a0a086eb | ||
![]() |
ab1dde0e8c | ||
![]() |
3467c5191d | ||
![]() |
95d7bfbdce | ||
![]() |
eb586e1281 | ||
![]() |
d3b8bc0b0e | ||
![]() |
63b83a176c | ||
![]() |
b7b7ca70ac | ||
![]() |
64b414bdbe | ||
![]() |
c83e9e785f | ||
![]() |
3002314e92 | ||
![]() |
b72b748eff | ||
![]() |
d41c2b0400 | ||
![]() |
55c91fe991 | ||
![]() |
ed829083c2 | ||
![]() |
ede9868d55 | ||
![]() |
9cbd28546a | ||
![]() |
08adb3766b | ||
![]() |
33fa9b9911 | ||
![]() |
0ecf12256d | ||
![]() |
8b8a692b6c | ||
![]() |
08d7fead03 | ||
![]() |
00c4766e20 | ||
![]() |
bce8c79f10 | ||
![]() |
454f30978d | ||
![]() |
754a7137b6 | ||
![]() |
e5622cda99 | ||
![]() |
596ef164d3 | ||
![]() |
658a36b7e6 | ||
![]() |
3b22f44680 | ||
![]() |
69c8480eb9 | ||
![]() |
71817cc0e8 | ||
![]() |
9061154667 | ||
![]() |
dd95e94e7f | ||
![]() |
ceda2524cf | ||
![]() |
1c6a709f3a | ||
![]() |
b0366e8469 | ||
![]() |
6b752e583b | ||
![]() |
babbaa86a3 | ||
![]() |
b330457f99 | ||
![]() |
b9738f7142 | ||
![]() |
c5c2c4fc0e | ||
![]() |
31dcf8d546 | ||
![]() |
7ae92d4c2c | ||
![]() |
0a307da3ac | ||
![]() |
7e55006acd | ||
![]() |
736eaed8c5 | ||
![]() |
8c20689d24 | ||
![]() |
41162764c2 | ||
![]() |
1a103722f3 | ||
![]() |
3d1ae7c38e | ||
![]() |
a2456461f3 | ||
![]() |
dc041e730d | ||
![]() |
7706fdc45e | ||
![]() |
9431f57a60 | ||
![]() |
fb475e27f4 | ||
![]() |
96c73a0080 | ||
![]() |
54499686bf | ||
![]() |
d5fae40c2a | ||
![]() |
e87192db9b | ||
![]() |
0fb709adb8 | ||
![]() |
43d4f1d246 | ||
![]() |
3f79f1ff54 | ||
![]() |
0358721c67 | ||
![]() |
91a2b70b33 | ||
![]() |
1a3d5495d6 | ||
![]() |
ffe6a9d283 | ||
![]() |
3fcc001cca | ||
![]() |
7808bd8e20 | ||
![]() |
4c38c4d1f4 | ||
![]() |
4157d9f3e2 | ||
![]() |
2f26815445 | ||
![]() |
5e8f1b1166 | ||
![]() |
502c3888b0 | ||
![]() |
b4edd6abdb | ||
![]() |
c0f2b8af41 | ||
![]() |
1d492e3ba2 | ||
![]() |
9046e4b088 | ||
![]() |
94d3bca20e | ||
![]() |
e1df115736 | ||
![]() |
595cfab20c | ||
![]() |
efcc12e1d5 | ||
![]() |
dda4297711 | ||
![]() |
b77830dea5 | ||
![]() |
153709b220 | ||
![]() |
5fad534ef0 | ||
![]() |
e83887c9b7 | ||
![]() |
7136c515a6 | ||
![]() |
56d5a163df | ||
![]() |
264391660d | ||
![]() |
b288fa217b | ||
![]() |
3e06edfbe5 | ||
![]() |
ed49237f52 | ||
![]() |
4b02448f0a | ||
![]() |
576ace2e3d | ||
![]() |
f23821af6f | ||
![]() |
61449301d0 | ||
![]() |
b002b1aac2 | ||
![]() |
5fbc452d29 | ||
![]() |
c53eedaf1c | ||
![]() |
ef13feb390 | ||
![]() |
4045bb467b | ||
![]() |
74720d6b2f | ||
![]() |
6f30f9976e | ||
![]() |
fb4d991053 | ||
![]() |
457c3e8e1c | ||
![]() |
e528584eb0 | ||
![]() |
9b21aaaa61 | ||
![]() |
97ec81692a | ||
![]() |
76b8096dcc | ||
![]() |
d684b077fd | ||
![]() |
fdf4d0c1dd | ||
![]() |
4971005d17 | ||
![]() |
02942e7e24 | ||
![]() |
6bf4b932ee | ||
![]() |
f169e544fd | ||
![]() |
3cfb83c0d6 | ||
![]() |
c4211a1ee5 | ||
![]() |
12587955b2 | ||
![]() |
56dfd55d30 | ||
![]() |
5d5634c4cc | ||
![]() |
f8ed9da353 | ||
![]() |
d9446aa28a | ||
![]() |
296580227a | ||
![]() |
c07d283958 | ||
![]() |
9962aa08f8 | ||
![]() |
8aaea928d7 | ||
![]() |
26e783be1c | ||
![]() |
a93b3f3cac | ||
![]() |
f88353d3dd | ||
![]() |
bc45e0cac7 | ||
![]() |
b374754129 | ||
![]() |
93146a023d | ||
![]() |
f22bce3cb1 | ||
![]() |
72668c128f | ||
![]() |
395a35e018 | ||
![]() |
05554f1a1f | ||
![]() |
d424b59228 | ||
![]() |
ee9ec5a366 | ||
![]() |
e7694e836e | ||
![]() |
2e74fd5d3b | ||
![]() |
c0ac1169eb | ||
![]() |
70d2cfcb98 | ||
![]() |
d7d9f83b15 | ||
![]() |
085803c328 | ||
![]() |
c6747288d5 | ||
![]() |
3e2392e9b6 | ||
![]() |
0853d8fee6 | ||
![]() |
d439a777b3 | ||
![]() |
83cfd73a11 | ||
![]() |
858112c072 | ||
![]() |
7efebc30b9 | ||
![]() |
0b9d1dbb97 | ||
![]() |
a0b4514176 | ||
![]() |
8a445a32ba | ||
![]() |
977ae78c6f | ||
![]() |
3987586e3f | ||
![]() |
dbfa2733fd | ||
![]() |
3416ab1288 | ||
![]() |
3cffd71b2f | ||
![]() |
2f9779d8f5 | ||
![]() |
e6ed822a43 | ||
![]() |
e54a8cf2bb | ||
![]() |
36d100d62d | ||
![]() |
97884dd03e | ||
![]() |
666a1c0306 | ||
![]() |
f39ffcb9e4 | ||
![]() |
5c31d13f83 | ||
![]() |
4abbf5e494 | ||
![]() |
c7853ce73a | ||
![]() |
e5c8272520 | ||
![]() |
6113f5d83a | ||
![]() |
5b8cfc9e4d | ||
![]() |
374775bf87 | ||
![]() |
13442fb156 | ||
![]() |
a802b09964 | ||
![]() |
352a2108dc | ||
![]() |
8569cdaca5 | ||
![]() |
be4093f728 | ||
![]() |
b2156d8170 | ||
![]() |
31d831bb0c | ||
![]() |
bdfd32c12d | ||
![]() |
e0b5514341 | ||
![]() |
b33f3ffb13 | ||
![]() |
8990956ad4 | ||
![]() |
ed405b9c98 | ||
![]() |
1edf8088f9 | ||
![]() |
526cc24860 | ||
![]() |
5b71abdcce | ||
![]() |
671c231992 | ||
![]() |
88d4946596 | ||
![]() |
29297fa116 | ||
![]() |
da8dc00d47 | ||
![]() |
305a6f3535 | ||
![]() |
b4f2f56a29 | ||
![]() |
8c56a7a8e1 | ||
![]() |
b54863993d | ||
![]() |
31d2d6dd07 | ||
![]() |
b506891540 | ||
![]() |
61a04ac3d2 | ||
![]() |
155b861e08 | ||
![]() |
74151fe5e0 | ||
![]() |
6924bca28d | ||
![]() |
f8723f2dce | ||
![]() |
437b8c4867 | ||
![]() |
77e3c28624 | ||
![]() |
17cbd36d7c | ||
![]() |
ed2940d92a | ||
![]() |
cfaf930f16 | ||
![]() |
f344270921 | ||
![]() |
cd1abe15b9 | ||
![]() |
161fba4dac | ||
![]() |
ac41ffeb2b | ||
![]() |
58bd88a023 | ||
![]() |
56faa0ac30 |
54 changed files with 7736 additions and 4288 deletions
68
.github/workflows/dzil_tester.yml
vendored
Normal file
68
.github/workflows/dzil_tester.yml
vendored
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
name: CI test builds
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: '*'
|
||||||
|
pull_request:
|
||||||
|
branches: '*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
perl-job:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
perl-version:
|
||||||
|
- 'devel'
|
||||||
|
- 'latest'
|
||||||
|
- '5.40'
|
||||||
|
- '5.38'
|
||||||
|
- '5.36'
|
||||||
|
- '5.34'
|
||||||
|
- '5.32'
|
||||||
|
- '5.30'
|
||||||
|
- '5.28'
|
||||||
|
- '5.26'
|
||||||
|
- '5.24'
|
||||||
|
- '5.22'
|
||||||
|
- '5.20'
|
||||||
|
- '5.18'
|
||||||
|
- '5.16'
|
||||||
|
include:
|
||||||
|
- perl-version: '5.38'
|
||||||
|
os: ubuntu-latest
|
||||||
|
coverage: true
|
||||||
|
container:
|
||||||
|
image: perldocker/perl-tester:${{ matrix.perl-version }}
|
||||||
|
|
||||||
|
name: Perl ${{ matrix.perl-version }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@main
|
||||||
|
- name: Amend PATH
|
||||||
|
run: echo "${GITHUB_WORKSPACE}/t/bin" >> $GITHUB_PATH
|
||||||
|
- name: Current env
|
||||||
|
run: env
|
||||||
|
- name: Perl info
|
||||||
|
run: perl -V
|
||||||
|
- name: CPAN test modules
|
||||||
|
run: cpanm -n Pod::Coverage::TrustPod Test::Perl::Critic Test::Pod::Coverage Test::Pod Test::Trap
|
||||||
|
- name: CPAN build modules
|
||||||
|
run: cpanm -n Tk X11::Protocol X11::Protocol::Other
|
||||||
|
- name: Initial Build
|
||||||
|
run: perl Build.PL
|
||||||
|
- name: Build the MANIFEST
|
||||||
|
run: perl Build manifest
|
||||||
|
- name: Test suite
|
||||||
|
if: ${{ !matrix.coverage }}
|
||||||
|
run: perl Build test
|
||||||
|
env:
|
||||||
|
RELEASE_TESTING: 1
|
||||||
|
AUTHOR_TESTING: 1
|
||||||
|
- name: Coverage tests
|
||||||
|
if: ${{ matrix.coverage }}
|
||||||
|
run: perl Build test
|
||||||
|
env:
|
||||||
|
COVERAGE: 1
|
||||||
|
RELEASE_TESTING: 1
|
||||||
|
AUTHOR_TESTING: 1
|
24
.gitignore
vendored
24
.gitignore
vendored
|
@ -1,11 +1,17 @@
|
||||||
|
/App-*
|
||||||
|
*.bak
|
||||||
|
/bin
|
||||||
|
/blib/
|
||||||
|
/_build/
|
||||||
|
/.build/
|
||||||
|
/Build
|
||||||
|
Build.PL.orig
|
||||||
|
Build.PL.x
|
||||||
|
/cover_db/
|
||||||
|
/Makefile
|
||||||
|
/MANIFEST.bak
|
||||||
|
/MYMETA.json
|
||||||
|
/MYMETA.yml
|
||||||
|
/pm_to_blib
|
||||||
*.swp
|
*.swp
|
||||||
*.tar.gz
|
*.tar.gz
|
||||||
Build
|
|
||||||
MANIFEST.bak
|
|
||||||
MYMETA.json
|
|
||||||
MYMETA.yml
|
|
||||||
Makefile
|
|
||||||
_build/
|
|
||||||
blib/
|
|
||||||
cover_db/
|
|
||||||
pm_to_blib
|
|
||||||
|
|
73
Build.PL
73
Build.PL
|
@ -1,45 +1,38 @@
|
||||||
use strict;
|
use lib 'inc';
|
||||||
use warnings;
|
|
||||||
|
|
||||||
use Module::Build;
|
require Module::Build;
|
||||||
|
|
||||||
my $build = Module::Build->new(
|
my %module_build_args = (
|
||||||
meta_merge => {
|
module_name => 'App::ClusterSSH',
|
||||||
resources => {
|
dist_abstract => "Cluster administration tool",
|
||||||
Repository => [
|
##{ $plugin->get_prereqs(1) ##}
|
||||||
'http://clusterssh.git.sourceforge.net/',
|
##{ $plugin->get_default('share_dir') ##}
|
||||||
'http://github.com/duncs/clusterssh',
|
script_files => [
|
||||||
],
|
'bin/cssh', 'bin/csftp',
|
||||||
bugtracker => 'http://sourceforge.net/tracker/?group_id=89139',
|
'bin/ccon', 'bin/crsh',
|
||||||
homepage => 'http://clusterssh.sourceforge.net/',
|
'bin/ctel', 'bin/clusterssh_bash_completion.dist'
|
||||||
},
|
],
|
||||||
|
PL_files => {
|
||||||
|
'bin_PL/_build_docs' => [
|
||||||
|
'bin/cssh', 'bin/csftp',
|
||||||
|
'bin/ccon', 'bin/crsh',
|
||||||
|
'bin/ctel', 'bin/clusterssh_bash_completion.dist'
|
||||||
|
],
|
||||||
},
|
},
|
||||||
module_name => 'App::ClusterSSH',
|
|
||||||
license => 'perl',
|
|
||||||
dist_author => q{Duncan Ferguson <duncan_j_ferguson@yahoo.co.uk>},
|
|
||||||
dist_version_from => 'lib/App/ClusterSSH.pm',
|
|
||||||
requires => {
|
|
||||||
'version' => '0',
|
|
||||||
'Tk' => '800.022',
|
|
||||||
'X11::Protocol' => '0.56',
|
|
||||||
'Locale::Maketext' => 0,
|
|
||||||
'Exception::Class' => '1.31',
|
|
||||||
'Try::Tiny' => 0,
|
|
||||||
},
|
|
||||||
build_requires => {
|
|
||||||
'Test::Pod::Coverage' => 0,
|
|
||||||
'Test::Pod' => 0,
|
|
||||||
'Test::Trap' => 0,
|
|
||||||
'Readonly' => 0,
|
|
||||||
'File::Which' => 0,
|
|
||||||
'File::Temp' => 0,
|
|
||||||
'Test::DistManifest' => 0,
|
|
||||||
'Test::Differences' => 0,
|
|
||||||
},
|
|
||||||
configure_requires => { 'Module::Build' => 0, },
|
|
||||||
add_to_cleanup => ['App-ClusterSSH-*'],
|
|
||||||
create_makefile_pl => 'traditional',
|
|
||||||
script_files => 'bin',
|
|
||||||
);
|
);
|
||||||
|
|
||||||
$build->create_build_script;
|
unless ( eval { Module::Build->VERSION(0.4004) } ) {
|
||||||
|
my $tr = delete $module_build_args{test_requires};
|
||||||
|
my $br = $module_build_args{build_requires};
|
||||||
|
for my $mod ( keys %$tr ) {
|
||||||
|
if ( exists $br->{$mod} ) {
|
||||||
|
$br->{$mod} = $tr->{$mod} if $tr->{$mod} > $br->{$mod};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$br->{$mod} = $tr->{$mod};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} # end unless Module::Build is 0.4004 or newer
|
||||||
|
|
||||||
|
my $builder = Module::Build->new(%module_build_args);
|
||||||
|
$builder->create_build_script;
|
||||||
|
|
693
Changes
693
Changes
|
@ -1,4 +1,161 @@
|
||||||
2014-01-13 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.02_02
|
Revision history for {{$dist->name}}
|
||||||
|
|
||||||
|
4.18 2024-10-19 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
- Re-release due to poor release upload to CPAN
|
||||||
|
|
||||||
|
4.17 2024-10-16 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
- Swap the hostname lookup macro from DNS to using the system hostname (Github issue #158)
|
||||||
|
- Swap from using Travis-CI to Github Actions
|
||||||
|
- Fix tests on perl 5.38 and 5.40 (Github Issue #153)
|
||||||
|
|
||||||
|
4.16 2020-06-20 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
- Further fix for 'resolve_names' error when adding hosts via the UI
|
||||||
|
- Fix missing space separator for ssh_args (thanks to Petr Vorel)
|
||||||
|
|
||||||
|
4.15 2020-05-18 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
- Include all utilies within each man page
|
||||||
|
- Add in 'command_pre' and 'command_post' configuration options
|
||||||
|
- Fix 'Add Host' menu error finding 'resolved_names'
|
||||||
|
- Ensure lib path is added to range tests to find the libraries
|
||||||
|
- Mark permission test as TODO as it appears to be inconsistent
|
||||||
|
|
||||||
|
4.14 2019-08-21 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
- Include README within the repository, not just created tar.gz files
|
||||||
|
- Add 'autoquit' setting to 'File' menu (Github issue #114)
|
||||||
|
- Correct macro_hostname to be the FQDN of the server where cssh is being run (Github issue #116)
|
||||||
|
- Add in user defined macros
|
||||||
|
|
||||||
|
4.13.2_02 2019-01-14 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
- Fix Getopt-Long minimum version
|
||||||
|
- Fix excess test output when Sort::Naturally isn't installed
|
||||||
|
|
||||||
|
4.13.2_01 2018-11-24 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
- Move all Tk code into its own module as-is
|
||||||
|
- Fix for 'bad pad value "3m"' error when using Tk 804.034
|
||||||
|
- Update to Perl::Tidy 20181117
|
||||||
|
- Convert to using Dist::Zilla
|
||||||
|
|
||||||
|
4.13.2 2018-03-14 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
- Fix for running builds in parallel
|
||||||
|
- Improvements to SUPPORT and REPORTING BUGS sections in documentation
|
||||||
|
|
||||||
|
4.13.1 2018-03-05 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
- Minor update to fix failing tests due to 3rd party perltidy changes
|
||||||
|
|
||||||
|
4.13 2017-12-27 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
- Ensure ssh_args is keep unset if it is emptied in the configuration file
|
||||||
|
- Obey configured console position (Debian bug 758215) (Github issue #100)
|
||||||
|
|
||||||
|
4.12 2017-12-23 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
- Fix 'undefined value' error
|
||||||
|
|
||||||
|
4.11 2017-12-22 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
- Fix for multiple range expansion, as in 'h{a,b}{1,2}' (Github issue #97) (Thanks to lazyfrosch)
|
||||||
|
- Upgrade Perl::Tidy requirement to version 20171214 (Github issue #99) (Thanks to eserte)
|
||||||
|
- Add in 'external command pipe' to allow for some commands being passed in from the command line
|
||||||
|
|
||||||
|
4.10_02 2017-08-08 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
- Include coverage tests in the resources
|
||||||
|
- Include the version of cssh in the utility documentation and README
|
||||||
|
- Fix dashes (-) not being accepted in hostname range expansion (Github issue #89)
|
||||||
|
- Amend ranges to work on ports, FQDN's and IP addresses
|
||||||
|
- Fix bug tracker links in the main documentation (Github issue #92)
|
||||||
|
- New options to specify --rows, --columns and --fillscreen (Github pull request #88) (Thanks to AsharLohmar)
|
||||||
|
|
||||||
|
4.10_01 2017-04-12 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
- Allow 'include' directives when reading SSH configuration files (Github issue #77) (thanks to Azenet)
|
||||||
|
- Generate README when creating the distribution from cssh man page so www.cpan.org and www.metacpan.org can display documentation
|
||||||
|
|
||||||
|
4.09 2017-03-11 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
- Add perl-5.24 Travis-CI automated testing config
|
||||||
|
- Correct a logic bug around the --debug option (Github issue #75)
|
||||||
|
- Fix 'Re-add closed windows' not using the correct username (Github issue #72)
|
||||||
|
- Update copyright year
|
||||||
|
- Make WM decorations algorithm configurable as causes problems on some systems (Debian bug 842965, re Github pull request #66) (thanks to Tony Mancill)
|
||||||
|
|
||||||
|
4.08 2016-10-18 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
- Add perl-5.8, 5.10 and 5.12 to Travis-CI automated testing
|
||||||
|
- Fix building and testing on perl-5.8.9
|
||||||
|
- Improve testing on systems that do not have xterm installed
|
||||||
|
- Take into account WM decorations when tiling (Github pull request #66) (thanks to Andrew Stevenson)
|
||||||
|
- Add option in the config file to hide the menu (Github issue #69)
|
||||||
|
- Add 'unique_servers' into the configuration file to match command line option (Github issue #70)
|
||||||
|
|
||||||
|
4.07 2016-04-30 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
- Fixed tests on systems where bash is not installed in /bin/bash (Github issue #60)
|
||||||
|
- Include link to travis-ci site in release emails for automated build and test reports
|
||||||
|
- Rework hostname expansion to be pure-perl rather than relying on the bash shell (Github issue #53)
|
||||||
|
|
||||||
|
4.06 2016-03-26 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
- Failure to find the terminal binary should not be fatal
|
||||||
|
- Fix processing of '--extra_tag_file' and its configuration item (Github issue #51)
|
||||||
|
- Add bash shell expansion on host names containing a '{' character (Github issue #53)
|
||||||
|
- Fix tests when running on a server without xterm installed (such as Travis CI via GitHub)
|
||||||
|
- Expand $HOME and ~ correctly when looking for files (thanks to Andrew Stevenson)
|
||||||
|
- Typo correction in README (thanks to Ankit Vadehra)
|
||||||
|
|
||||||
|
4.05 2015-11-28 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
- Change default key_quit from 'Control-q' to 'Alt-q' (Github issue #50)
|
||||||
|
- Amend tests to always use C locale as some error messages are hardcoded in English (Github issue #49)
|
||||||
|
|
||||||
|
4.04_01 2015-11-21 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
- Ensure documentation is generated using same perl as the build (Github issue #45)
|
||||||
|
- Pass '--action' through macro parsing (Github issue #42)
|
||||||
|
- Workaround for glitch in KDE where windows can become unmoveable (Github issue #46) (thanks to Brandon Perkins)
|
||||||
|
- Add in '--quiet | -Q ' option to reduce output in certian scenarios
|
||||||
|
- Add in 'csftp' command
|
||||||
|
|
||||||
|
4.04 2015-11-03 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
- Include bash completion script in distribution (Github issue #29)
|
||||||
|
- Allow re-adding closed session (Github issue #27 - thanks to Andrew Stevenson)
|
||||||
|
- Allow sorting windows in natural order (Github issue #28 - thanks to Andrew Stevenson)
|
||||||
|
- Fix links in metadata files to trackers (Github issue #41)
|
||||||
|
- Fix ctel and ccon not working correctly (Github issue #35)
|
||||||
|
- Amend t/10host.t to use a random hostname to prevent clashes (Github issue #23)
|
||||||
|
- Amend copyright message in README to match all other files for the perl license (Github issue #44)
|
||||||
|
|
||||||
|
4.03_06 2015-01-31 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
- Remove references to 'logmsg' preventing the history window from working (thanks to Andrew Stevenson)
|
||||||
|
|
||||||
|
4.03_05 2014-12-20 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
- Fix options parsing tests picked up via cpantesters on different version of perl
|
||||||
|
|
||||||
|
4.03_04 2014-12-12 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
- Do not use system perl but whatever is found in PATH (to stop breaking perlbrew based builds)
|
||||||
|
- Warn when the configured terminal isn't installed/found
|
||||||
|
- Don't show 'Opening to:' when no servers are given
|
||||||
|
|
||||||
|
4.03_03 2014-09-28 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
- Force tests to have English locale when user has something else set (Github issue: 10) (thanks to Emanuele Tomasi)
|
||||||
|
- Skip permissions check test when run as root as the results are invalid (Github issue: 11) (thanks to Deny Dias)
|
||||||
|
- Ensure config file option for ssh_args is not lost when options is not used on command line (Github issue: 14)
|
||||||
|
- New Send menu option to send a numeric value between 1 and 1024 (thanks to cqexbesd)
|
||||||
|
- Remove all history when history window closed (thanks to Bill Rushmore)
|
||||||
|
|
||||||
|
4.03_02 2014-08-10 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
- Fix behaviour when external cluster command is not defined or doesn't exist
|
||||||
|
|
||||||
|
4.03_01 2014-07-09 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
- Amended host parsing to include alternative IPv6 address port definitions, e.g. 1::2::3::4/5567
|
||||||
|
- List available external tags with -L option and also add into 'Add Host' in UI
|
||||||
|
[NOTE: Some options have changed!]
|
||||||
|
- Rework options code
|
||||||
|
|
||||||
|
4.02_05 0000-00-00 Duncan Ferguson <duncan_ferguson@user.sf.net> (unreleased)
|
||||||
|
- Add in 'Set all active' and 'Set half active' host menu options (thanks to Andrew Stevenson)
|
||||||
|
|
||||||
|
4.02_04 2014-05-17 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
- Amend 'Changes' file format to match CPAN specs (see CPAN::Changes)
|
||||||
|
- Correct autoclose short option to what is actually used (Github issue 4) (thanks to Simon Fraser)
|
||||||
|
- Fix 'use_all_a_records' option (Github issue: 5) (thanks to Simon Fraser)
|
||||||
|
- Fix 'title' option (thanks to Barry Roberts)
|
||||||
|
- Fix 'Add host or cluster' window to contain cluster names
|
||||||
|
|
||||||
|
4.02_03 2014-01-31 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
- Fix 'File->Show History' (Sf support request 41)
|
||||||
|
- Amend 'tag-file' short option to 'r' to avoid option clash
|
||||||
|
|
||||||
|
4.02_02 2014-01-13 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
- Fixed macros (%u, %s, %h, %n) not doing multiple replacements
|
- Fixed macros (%u, %s, %h, %n) not doing multiple replacements
|
||||||
- Add in key shortcut for username macro (ALT-u)
|
- Add in key shortcut for username macro (ALT-u)
|
||||||
- Add in key shortcut for local hostname macro (ALT-l)
|
- Add in key shortcut for local hostname macro (ALT-l)
|
||||||
|
@ -7,392 +164,390 @@
|
||||||
- Fixed the default cluster not being opened
|
- Fixed the default cluster not being opened
|
||||||
- Add in toggle for macros
|
- Add in toggle for macros
|
||||||
|
|
||||||
2013-04-16 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.02_01
|
4.02_01 2013-04-16 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
- Refactured file loading code
|
- Refactured file loading code
|
||||||
- Add in 'tags' file handling
|
- Add in 'tags' file handling
|
||||||
- Fix bug whereby cluster files were read in multiple times
|
- Fix bug whereby cluster files were read in multiple times
|
||||||
- Add in resolving tags by external command
|
- Add in resolving tags by external command
|
||||||
- Fix library path on bin/cssh (Sf bug 3610601)
|
- Fix library path on bin/cssh (Sf bug 3610601)
|
||||||
|
|
||||||
2013-03-05 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.01_05
|
4.01_05 2013-03-05 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
- New option (-m, --unique-servers) to remove repeated servers when opening terminals (Thanks to Oliver Meissner)
|
- New option (-m, --unique-servers) to remove repeated servers when opening terminals (Thanks to Oliver Meissner)
|
||||||
- Drop MYMETA.yml and .json files from the distribution
|
- Drop MYMETA.yml and .json files from the distribution
|
||||||
- Do not set default user name to prevent overriding ssh configuration
|
- Do not set default user name to prevent overriding ssh configuration
|
||||||
|
|
||||||
2013-02-26 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.01_04
|
4.01_04 2013-02-26 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
- Fixed 'ccon' not calling the correct command (Sf bug 3605002)
|
- Fixed 'ccon' not calling the correct command (Sf bug 3605002)
|
||||||
- Fixed clusters not being defined correctly within the .clusterssh/config file (Sf bug 3605675)
|
- Fixed clusters not being defined correctly within the .clusterssh/config file (Sf bug 3605675)
|
||||||
|
|
||||||
2013-02-15 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.01_03
|
4.01_03 2013-02-15 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
* Correct documentation for references to $HOME/.clusterssh/config
|
- Correct documentation for references to $HOME/.clusterssh/config
|
||||||
* Re-add user back into the configurartion file
|
- Re-add user back into the configurartion file
|
||||||
* Add in missing newline for some error messages
|
- Add in missing newline for some error messages
|
||||||
* Allow the path to rsh/ssh/telnet to be defined in the configuration file
|
- Allow the path to rsh/ssh/telnet to be defined in the configuration file
|
||||||
* Move .csshrc to .csshrc.DISABLED since it should no longer be used
|
- Move .csshrc to .csshrc.DISABLED since it should no longer be used
|
||||||
* Error emitted when adding a host via the "Hosts" drop-down (Debian bug ID #578208)
|
- Error emitted when adding a host via the "Hosts" drop-down (Debian bug ID #578208)
|
||||||
* Pastes uses a strange keyboard layout (Debian bug ID #364565)
|
- Pastes uses a strange keyboard layout (Debian bug ID #364565)
|
||||||
* Cope with being invoked by 'clusterssh' (Debian bug ID #644368)
|
- Cope with being invoked by 'clusterssh' (Debian bug ID #644368)
|
||||||
* Fix migration of .csshrc when not working as expected (Debian bug ID #673507)
|
- Fix migration of .csshrc when not working as expected (Debian bug ID #673507)
|
||||||
* Remove doc references to 'always_tile' as renamed 'window_tiling' (Debian bug ID #697371)
|
- Remove doc references to 'always_tile' as renamed 'window_tiling' (Debian bug ID #697371)
|
||||||
* Updated manpage whatis entries (patch by Tony Mancill)
|
- Updated manpage whatis entries (patch by Tony Mancill)
|
||||||
* Fix watch line expression to catch 4.x series tarballs (Debian patch LP ID #1076897)
|
- Fix watch line expression to catch 4.x series tarballs (Debian patch LP ID #1076897)
|
||||||
* Allow tests to pass successfully when run as root
|
- Allow tests to pass successfully when run as root
|
||||||
* Fix cssh starting if xterm is not installed (Sf bug 3494988)
|
- Fix cssh starting if xterm is not installed (Sf bug 3494988)
|
||||||
* Set WM_CLASS on windows to 'cssh' (Sf bug 3187736)
|
- Set WM_CLASS on windows to 'cssh' (Sf bug 3187736)
|
||||||
|
|
||||||
2012-12-09 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.01_02
|
4.01_02 2012-12-09 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
* Fix logic when using 'autoclose' on the command line or config file
|
- Fix logic when using 'autoclose' on the command line or config file
|
||||||
* Fix $HOME/.clusterssh/clusters being read in
|
- Fix $HOME/.clusterssh/clusters being read in
|
||||||
* Fix 'ctel', 'crsh' and 'ccon'so they work as expected
|
- Fix 'ctel', 'crsh' and 'ccon'so they work as expected
|
||||||
|
|
||||||
2011-12-09 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.01_01
|
4.01_01 2011-12-09 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
* Include missing files from release tarballs
|
- Include missing files from release tarballs
|
||||||
|
|
||||||
2011-12-03 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.01_00
|
4.01_00 2011-12-03 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
* Start switching code to use Exception::Class
|
- Start switching code to use Exception::Class
|
||||||
* Moved config file from $HOME/.csshrc file to $HOME/.clusterssh directory
|
- Moved config file from $HOME/.csshrc file to $HOME/.clusterssh directory
|
||||||
* Rework config handling into a module
|
- Rework config handling into a module
|
||||||
* Rework cluster handling into a module
|
- Rework cluster handling into a module
|
||||||
* Added 'autoclose' functionality - see docs
|
- Added 'autoclose' functionality - see docs
|
||||||
* Allow "-a 'cmd ; cmd'" to work for multiple remote commands
|
- Allow "-a 'cmd ; cmd'" to work for multiple remote commands
|
||||||
|
|
||||||
2011-07-28 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.00_11
|
4.00_11 2011-07-28 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
* Fix '-l <username>' option (SF bug 3380675)
|
- Fix '-l <username>' option (SF bug 3380675)
|
||||||
|
|
||||||
2011-07-08 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.00_10
|
4.00_10 2011-07-08 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
* Fix 'uninitialised error' message
|
- Fix 'uninitialised error' message
|
||||||
|
|
||||||
2011-06-30 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.00_09
|
4.00_09 2011-06-30 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
* Cater for missing 'pod2text' command (Thanks to Sami Kerola)
|
- Cater for missing 'pod2text' command (Thanks to Sami Kerola)
|
||||||
* Fix 'uninitialised variable' error
|
- Fix 'uninitialised variable' error
|
||||||
* Added 'ccon' command (Thanks to Brandon Perkins)
|
- Added 'ccon' command (Thanks to Brandon Perkins)
|
||||||
|
|
||||||
2011-04-01 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.00_08
|
4.00_08 2011-04-01 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
* Amend all L<xx> links to prevent build breakage on cygwin (Sf bug 3115635)
|
- Amend all L<xx> links to prevent build breakage on cygwin (Sf bug 3115635)
|
||||||
|
|
||||||
2011-01-24 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.00_07
|
4.00_07 2011-01-24 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
* Fix for parsing config files with empty values (Stefan Steiner)
|
- Fix for parsing config files with empty values (Stefan Steiner)
|
||||||
* Reinstate acting on '-l username' option (reported by Ryan Brown)
|
- Reinstate acting on '-l username' option (reported by Ryan Brown)
|
||||||
|
|
||||||
2010-09-20 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.00_06
|
4.00_06 2010-09-20 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
* Fix test error on 5.8.8 (reported by Wei Wang)
|
- Fix test error on 5.8.8 (reported by Wei Wang)
|
||||||
* Added '--list', '-L' to list available cluster tags (idea from Markus Manzke)
|
- Added '--list', '-L' to list available cluster tags (idea from Markus Manzke)
|
||||||
* Fix terminal size only set on last windows (Sf bug 3061999)
|
- Fix terminal size only set on last windows (Sf bug 3061999)
|
||||||
* Added '--use_all_a_records' (Simon Fraser)
|
- Added '--use_all_a_records' (Simon Fraser)
|
||||||
|
|
||||||
2010-06-20 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.00_05
|
4.00_05 2010-06-20 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
|
||||||
* Tidy up pod for whatis errors
|
- Tidy up pod for whatis errors
|
||||||
* Amend copyright years and text to be consistent
|
- Amend copyright years and text to be consistent
|
||||||
* Include missing buld prereq (Test::Trap)
|
- Include missing buld prereq (Test::Trap)
|
||||||
* Correct '--font, -f' in cssh documentation
|
- Correct '--font, -f' in cssh documentation
|
||||||
- Thanks to Tony Mancill for reporting these errors
|
- Thanks to Tony Mancill for reporting these errors
|
||||||
|
|
||||||
2010-06-20 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.00_04
|
4.00_04 2010-06-20 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
|
||||||
* Update MANIFEST file to ensure all correct files are included in release
|
- Update MANIFEST file to ensure all correct files are included in release
|
||||||
|
|
||||||
2010-06-20 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.00_03
|
4.00_03 2010-06-20 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
|
||||||
* Fix silly type in code/tests
|
- Fix silly type in code/tests
|
||||||
|
|
||||||
2010-06-19 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.00_02
|
4.00_02 2010-06-19 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
|
||||||
* Add in bugtracker and homepage resources to Build.PL file
|
- Add in bugtracker and homepage resources to Build.PL file
|
||||||
* Bring new module App::ClusterSSH::Host into play for parsing host strings
|
- Bring new module App::ClusterSSH::Host into play for parsing host strings
|
||||||
* Patch to override font used on command line (Roland Rosenfeld)
|
- Patch to override font used on command line (Roland Rosenfeld)
|
||||||
* Put options in cssh pod into alphabetical order
|
- Put options in cssh pod into alphabetical order
|
||||||
|
|
||||||
2010-01-08 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.00_01
|
4.00_01 2010-01-08 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
|
||||||
* Remove GNU tools and switch to Perl module layout using Module::Build
|
- Remove GNU tools and switch to Perl module layout using Module::Build
|
||||||
|
|
||||||
0000-00-00 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.29 - unreleased
|
3.29 0000-00-00 Duncan Ferguson <duncan_ferguson@user.sf.net> (unreleased)
|
||||||
|
|
||||||
* Handle hostnames containing % properly (Debian bug 543368)
|
- Handle hostnames containing % properly (Debian bug 543368)
|
||||||
- Thanks to Tony Mancill for the patch
|
- Thanks to Tony Mancill for the patch
|
||||||
|
|
||||||
2009-12-19 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.28
|
3.28 2009-12-19 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
|
||||||
* Look for usernames when adding clusters
|
- Look for usernames when adding clusters
|
||||||
- Thanks to Kristian Lyngstol for the patch
|
- Thanks to Kristian Lyngstol for the patch
|
||||||
* Allow username@cluster to override all usernames in the cluster
|
- Allow username@cluster to override all usernames in the cluster
|
||||||
* Account for multiple host definitions within ssh configuration file
|
- Account for multiple host definitions within ssh configuration file
|
||||||
- Thanks to anonymous for the patch
|
- Thanks to anonymous for the patch
|
||||||
* Allow for long line continuation in config files with a backslash
|
- Allow for long line continuation in config files with a backslash
|
||||||
- Thanks to Mike Loseke for the patch
|
- Thanks to Mike Loseke for the patch
|
||||||
* Improve binary search to
|
- Improve binary search to
|
||||||
- ignore directories of the same name, and
|
- ignore directories of the same name, and
|
||||||
- always search for the binary if it is not fully qualified
|
- always search for the binary if it is not fully qualified
|
||||||
- Thanks to Ian Marsh for the patch
|
- Thanks to Ian Marsh for the patch
|
||||||
* Always use the given host name, not the resolved host name, when opening the ssh connection (Debian bug 533406)
|
- Always use the given host name, not the resolved host name, when opening the ssh connection (Debian bug 533406)
|
||||||
|
|
||||||
2009-09-24 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.27
|
3.27 2009-09-24 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
|
||||||
* Add in list of clusters to 'Add Host' window
|
- Add in list of clusters to 'Add Host' window
|
||||||
- thanks for Stanislas Rouvelin for the idea
|
- thanks for Stanislas Rouvelin for the idea
|
||||||
* Fix bug where unresolvable host stopped program running
|
- Fix bug where unresolvable host stopped program running
|
||||||
- thanks to Sami Kerola
|
- thanks to Sami Kerola
|
||||||
* Add in config for auto-tearoff of send and host menus
|
- Add in config for auto-tearoff of send and host menus
|
||||||
- thanks to James Chernikov for the idea
|
- thanks to James Chernikov for the idea
|
||||||
* Add in send menu xml definition file
|
- Add in send menu xml definition file
|
||||||
- thanks to James Chernikov for the idea
|
- thanks to James Chernikov for the idea
|
||||||
|
|
||||||
2009-06-02 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.26-1
|
3.26_1 2009-06-02 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
|
||||||
* Allow user to set a different ConnectTimeout and -o string (Tony Mancill)
|
- Allow user to set a different ConnectTimeout and -o string (Tony Mancill)
|
||||||
* Fix warning from 'mandb' (Tony Mancill)
|
- Fix warning from 'mandb' (Tony Mancill)
|
||||||
* Continue connecting to unresolvable hosts (debian bug 499935) (Tony Mancill)
|
- Continue connecting to unresolvable hosts (debian bug 499935) (Tony Mancill)
|
||||||
* Correct bug with unset default ports (Tony Mancill)
|
- Correct bug with unset default ports (Tony Mancill)
|
||||||
* Rearrange pod documentation to remove extraenous comment (Tony Mancill)
|
- Rearrange pod documentation to remove extraenous comment (Tony Mancill)
|
||||||
* Cope better with IPv6 addresses
|
- Cope better with IPv6 addresses
|
||||||
* Fix bug with passing arguments from command line to comms method binary
|
- Fix bug with passing arguments from command line to comms method binary
|
||||||
* Rework defaultport code
|
- Rework defaultport code
|
||||||
* Add new "-a 'command'" option for running a command in each terminal
|
- Add new "-a 'command'" option for running a command in each terminal
|
||||||
* Fix bug with some host lookups failing
|
- Fix bug with some host lookups failing
|
||||||
* Set window hints on terminals slightly differently to help with tiling
|
- Set window hints on terminals slightly differently to help with tiling
|
||||||
* Reserve 5 pixels on top and left hand side of terminals for better tiling
|
- Reserve 5 pixels on top and left hand side of terminals for better tiling
|
||||||
* Increase reserve of screen from bottom from 40 pixels to 60
|
- Increase reserve of screen from bottom from 40 pixels to 60
|
||||||
* Better notes in docs for screen/terminal reserving
|
- Better notes in docs for screen/terminal reserving
|
||||||
* Minor fixup to docs formatting
|
- Minor fixup to docs formatting
|
||||||
* Correct pasting mechanism into control window
|
- Correct pasting mechanism into control window
|
||||||
* Allow use of long options (swap Getopt::Std to Getopt::Long)
|
- Allow use of long options (swap Getopt::Std to Getopt::Long)
|
||||||
* Remove deprecated '-i' option
|
- Remove deprecated '-i' option
|
||||||
* Deprecate -d and -D, replaced with --debug
|
- Deprecate -d and -D, replaced with --debug
|
||||||
* Allow for configurable max number of hosts within hosts menu before
|
- Allow for configurable max number of hosts within hosts menu before
|
||||||
starting a new column - see .csshrc doc for "max_host_menu_items".
|
starting a new column - see .csshrc doc for "max_host_menu_items".
|
||||||
This is until Tk allows for scrollable menus
|
This is until Tk allows for scrollable menus
|
||||||
* Amend default key_addhost from 'Control-plus' to 'Control-Shift-plus'
|
- Amend default key_addhost from 'Control-plus' to 'Control-Shift-plus'
|
||||||
* Add in a 'default' cluster tag, used when no tags provided on command line
|
- Add in a 'default' cluster tag, used when no tags provided on command line
|
||||||
* Fix Alt-n pasting in a resolved hostname instead of the connection hostname
|
- Fix Alt-n pasting in a resolved hostname instead of the connection hostname
|
||||||
* Disabled unmapping code until such time as a better way of doing it exists
|
- Disabled unmapping code until such time as a better way of doing it exists
|
||||||
- this is due to virtual desktop change triggering a retile
|
- this is due to virtual desktop change triggering a retile
|
||||||
|
|
||||||
2009-03-26 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.25-1
|
3.25_1 2009-03-26 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
|
||||||
* Add patch from David F. Skoll for adding colour to terminals
|
- Add patch from David F. Skoll for adding colour to terminals
|
||||||
* Apply fix from Bogdan Pintea for DNS failing to resolve IPs
|
- Apply fix from Bogdan Pintea for DNS failing to resolve IPs
|
||||||
* Allow the configuration files to be symlinks (debian bug 518196)
|
- Allow the configuration files to be symlinks (debian bug 518196)
|
||||||
* Add an 'EXAMPLES' section to the cssh documentation
|
- Add an 'EXAMPLES' section to the cssh documentation
|
||||||
* List options alphabetically in documentation
|
- List options alphabetically in documentation
|
||||||
* Apply patch from Gerfried Fuchs/Tony Mancill for ports on the command line
|
- Apply patch from Gerfried Fuchs/Tony Mancill for ports on the command line
|
||||||
|
|
||||||
2008-11-14 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.24-1
|
3.24_1 2008-11-14 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
|
||||||
* Do not attempt to re-resolve IP addresses
|
- Do not attempt to re-resolve IP addresses
|
||||||
* Apply patch from Dan Wallis
|
- Apply patch from Dan Wallis
|
||||||
- Add '-C <file>' command to load in specific config file
|
- Add '-C <file>' command to load in specific config file
|
||||||
- Typo correct in pod
|
- Typo correct in pod
|
||||||
- Cope with random/strange config files better
|
- Cope with random/strange config files better
|
||||||
* Correct some minor typos
|
- Correct some minor typos
|
||||||
* Create the .csshrc file if it doesnt already exist and amend pod
|
- Create the .csshrc file if it doesnt already exist and amend pod
|
||||||
* Amend host menu items to be a little more descriptive
|
- Amend host menu items to be a little more descriptive
|
||||||
* Remove 'Catpure Terminal' from Hosts menu as it doesnt do anything useful
|
- Remove 'Catpure Terminal' from Hosts menu as it doesnt do anything useful
|
||||||
|
|
||||||
2008-01-23 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.23-1
|
3.23_1 2008-01-23 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
|
||||||
* Apply bugfix supplied by Jima
|
- Apply bugfix supplied by Jima
|
||||||
- Ensure loading of hosts from user ssh config file is case insensitive
|
- Ensure loading of hosts from user ssh config file is case insensitive
|
||||||
|
|
||||||
2008-01-23 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.22-1
|
3.22_1 2008-01-23 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
|
||||||
* Update X resources class to allow use of terms other than XTerm
|
- Update X resources class to allow use of terms other than XTerm
|
||||||
* Apply patch from Harald Weidner to stop error messages in Debian Etch
|
- Apply patch from Harald Weidner to stop error messages in Debian Etch
|
||||||
* Add in key shortcut (alt-h) to toggle history window
|
- Add in key shortcut (alt-h) to toggle history window
|
||||||
* Tidy up pod a little to highlight notes better
|
- Tidy up pod a little to highlight notes better
|
||||||
* Check terminal_font config for quotes and remove
|
- Check terminal_font config for quotes and remove
|
||||||
* Enable use of "configure --sysconfdir=", defaults to /etc
|
- Enable use of "configure --sysconfdir=", defaults to /etc
|
||||||
* Revise host checking algorithm to take ssh_config files into account
|
- Revise host checking algorithm to take ssh_config files into account
|
||||||
* Revise username check used as part of host id to accept more chars
|
- Revise username check used as part of host id to accept more chars
|
||||||
* Correct year value for previous two entries from 2008 to 2007
|
- Correct year value for previous two entries from 2008 to 2007
|
||||||
|
|
||||||
2007-11-28 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.21-1
|
3.21_1 2007-11-28 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
|
||||||
* Implement a basic history window in the console (option -s)
|
- Implement a basic history window in the console (option -s)
|
||||||
* Fixed bug whereby username@ wasn't being used correctly
|
- Fixed bug whereby username@ wasn't being used correctly
|
||||||
|
|
||||||
2007-11-26 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.20-1
|
3.20_1 2007-11-26 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
|
||||||
* Move source repository from CVS to SVN on sourceforge
|
- Move source repository from CVS to SVN on sourceforge
|
||||||
* Remove last digit of version number since not required with SVN
|
- Remove last digit of version number since not required with SVN
|
||||||
* Add in host menu option to close inactive windows
|
- Add in host menu option to close inactive windows
|
||||||
* Apply bugfixes suppled by Tony Mancill
|
- Apply bugfixes suppled by Tony Mancill
|
||||||
- reset xrm switch in terminal_args
|
- reset xrm switch in terminal_args
|
||||||
- prevent warning messages being printed when keysyms arent found
|
- prevent warning messages being printed when keysyms arent found
|
||||||
- fixes for fvwm
|
- fixes for fvwm
|
||||||
- chekc for child process before sending kill
|
- chekc for child process before sending kill
|
||||||
* Slight rewording of man page
|
- Slight rewording of man page
|
||||||
* Add in option to use telnet as comms command (use 'ctel' to invoke script)
|
- Add in option to use telnet as comms command (use 'ctel' to invoke script)
|
||||||
* Run through perltidy -b -i=2
|
- Run through perltidy -b -i=2
|
||||||
* Appy patches from Klaus Ethgen
|
- Appy patches from Klaus Ethgen
|
||||||
- Client dies when cannot write to pipe
|
- Client dies when cannot write to pipe
|
||||||
- Sleeping and flushing in window manager to allow time to draw windows
|
- Sleeping and flushing in window manager to allow time to draw windows
|
||||||
- Fix pipe reading to not use undefined values
|
- Fix pipe reading to not use undefined values
|
||||||
* Apply patches from Nicolas Simonds
|
- Apply patches from Nicolas Simonds
|
||||||
- allow colons in hostnames
|
- allow colons in hostnames
|
||||||
- allow -o option as per man page
|
- allow -o option as per man page
|
||||||
* Apply patch from Peter Palfrader
|
- Apply patch from Peter Palfrader
|
||||||
- improvement to finding binaries
|
- improvement to finding binaries
|
||||||
* Allow font to be specified on the command line
|
- Allow font to be specified on the command line
|
||||||
* Check for errors around key data gathering
|
- Check for errors around key data gathering
|
||||||
* Add in 'extra_cluster_file' to csshrc
|
- Add in 'extra_cluster_file' to csshrc
|
||||||
|
|
||||||
2006-07-24 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.19.1-1
|
3.19.1_1 2006-07-24 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
|
||||||
- Below is an abridged version of changes - see CVS for more information
|
- Below is an abridged version of changes - see CVS for more information
|
||||||
* Check for failure to connect to X session
|
- Check for failure to connect to X session
|
||||||
* Totally rework character mapping and events to cope with non-QWERTY keyboards
|
- Totally rework character mapping and events to cope with non-QWERTY keyboards
|
||||||
* Rework pasting code to cope with non-QWERTY charatcters
|
- Rework pasting code to cope with non-QWERTY charatcters
|
||||||
* Manpage/help doc updates and corrections
|
- Manpage/help doc updates and corrections
|
||||||
* Check for missing definitions for cluster tags in .csshrc
|
- Check for missing definitions for cluster tags in .csshrc
|
||||||
* Run through perltidy -b -i=2
|
- Run through perltidy -b -i=2
|
||||||
* Apply patch to add in optional port information from D. Dumont
|
- Apply patch to add in optional port information from D. Dumont
|
||||||
* Amend hotkey code to not pick up <ctrl>-<alt> as default clientname shortcut
|
- Amend hotkey code to not pick up <ctrl>-<alt> as default clientname shortcut
|
||||||
* Alter repeat function to improve efficiency
|
- Alter repeat function to improve efficiency
|
||||||
* Rework retiling code
|
- Rework retiling code
|
||||||
* Add "-e <host>" to evaluate terminal and communcation methods
|
- Add "-e <host>" to evaluate terminal and communcation methods
|
||||||
* Add in toggle option on hosts menu
|
- Add in toggle option on hosts menu
|
||||||
* Fix check in find_binary to ensure one is actually found
|
- Fix check in find_binary to ensure one is actually found
|
||||||
* Search $PATH and other standard places for binaries incase $PATH is incomplete
|
- Search $PATH and other standard places for binaries incase $PATH is incomplete
|
||||||
* Amend code to allow getting help when no X display available
|
- Amend code to allow getting help when no X display available
|
||||||
* Allow override of both key and mouse paste key sequences
|
- Allow override of both key and mouse paste key sequences
|
||||||
* Added icons and desktop file
|
- Added icons and desktop file
|
||||||
* Amended clusterssh.spec to cope with icons and desktop file
|
- Amended clusterssh.spec to cope with icons and desktop file
|
||||||
* Improve cluster file import efficiency as was taking faaar too long previously
|
- Improve cluster file import efficiency as was taking faaar too long previously
|
||||||
* Fixed bug whereby when pid's of the xterm changes records were not updated
|
- Fixed bug whereby when pid's of the xterm changes records were not updated
|
||||||
* Do not die when pipe open fails, but continue as others may be connected
|
- Do not die when pipe open fails, but continue as others may be connected
|
||||||
* Remove code that breaks the minimize/maximise stuff;
|
- Remove code that breaks the minimize/maximise stuff;
|
||||||
* Catch X button presses on title bar to close all windows correctly
|
- Catch X button presses on title bar to close all windows correctly
|
||||||
* Delay map event capture at program start to avoid infinite loop
|
- Delay map event capture at program start to avoid infinite loop
|
||||||
* Fix execvp error on Solaris 10
|
- Fix execvp error on Solaris 10
|
||||||
|
|
||||||
2005-11-28 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.18.1-1
|
3.18.1_1 2005-11-28 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
|
||||||
* Correct mask value for backtick (grave) character
|
- Correct mask value for backtick (grave) character
|
||||||
* Add more logging for debug mode
|
- Add more logging for debug mode
|
||||||
* Amend indentation
|
- Amend indentation
|
||||||
* Rerun through perltidy
|
- Rerun through perltidy
|
||||||
* Improve cluster file import efficiency as was taking faaar too long previously
|
- Improve cluster file import efficiency as was taking faaar too long previously
|
||||||
* Fixed bug whereby when pid's of the xterm changes records were not updated
|
- Fixed bug whereby when pid's of the xterm changes records were not updated
|
||||||
* Do not die when pipe open fails, but continue as others may be connected
|
- Do not die when pipe open fails, but continue as others may be connected
|
||||||
* Remove code that breaks the minimize/maximise stuff;
|
- Remove code that breaks the minimize/maximise stuff;
|
||||||
* Catch X button presses on title bar to close all windows correctly
|
- Catch X button presses on title bar to close all windows correctly
|
||||||
* Delay map event capture at program start to avoid infinite loop
|
- Delay map event capture at program start to avoid infinite loop
|
||||||
* Fix execvp error on Solaris 10
|
- Fix execvp error on Solaris 10
|
||||||
* Update to man pages
|
- Update to man pages
|
||||||
|
|
||||||
2005-06-24 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.17.1
|
3.17.1 2005-06-24 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
|
||||||
* Allow _'s in paste text correctly
|
- Allow _'s in paste text correctly
|
||||||
* Bugfix minimise/maximise again
|
- Bugfix minimise/maximise again
|
||||||
* Run through "perltidy -i=4 -ce"
|
- Run through "perltidy -i=4 -ce"
|
||||||
* Unmap all windows in one go instead of one at a time when retiling
|
- Unmap all windows in one go instead of one at a time when retiling
|
||||||
* Add + doc 'console_position'
|
- Add + doc 'console_position'
|
||||||
* Maintain user position of console between maps (i.e. tell window manager
|
- Maintain user position of console between maps (i.e. tell window manager
|
||||||
not to move it)
|
not to move it)
|
||||||
* Note that ssh options are for OpenSSH not for any other ssh version
|
- Note that ssh options are for OpenSSH not for any other ssh version
|
||||||
|
|
||||||
2005-06-13 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.16.1
|
3.16.1 2005-06-13 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
|
||||||
* Allow ignoring of unresolved hosts (i.e. if hostname aliased in
|
- Allow ignoring of unresolved hosts (i.e. if hostname aliased in
|
||||||
ssh config file)
|
ssh config file)
|
||||||
|
|
||||||
2005-06-09 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.15.1
|
3.15.1 2005-06-09 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
|
||||||
* Add and document "-c <clusterfile>"
|
- Add and document "-c <clusterfile>"
|
||||||
* Add and document "-l <username>"
|
- Add and document "-l <username>"
|
||||||
* Add and document "-o <options>"
|
- Add and document "-o <options>"
|
||||||
* Document "-t <title>"
|
- Document "-t <title>"
|
||||||
* Set controlled terminals to have user set size & position (WM_SIZE_HINTS)
|
- Set controlled terminals to have user set size & position (WM_SIZE_HINTS)
|
||||||
* Speed up initial terminal openings
|
- Speed up initial terminal openings
|
||||||
* Remove all key bindings from drop down menus (conflicts with emacs and
|
- Remove all key bindings from drop down menus (conflicts with emacs and
|
||||||
can all be done by other hotkeys anyhow)
|
can all be done by other hotkeys anyhow)
|
||||||
* Allow individual hotkeys to be disabled, instead of all-or-nothing
|
- Allow individual hotkeys to be disabled, instead of all-or-nothing
|
||||||
* Updates to POD
|
- Updates to POD
|
||||||
* Update retile code to avoid flickering windows (& also fix cygwin bug)
|
- Update retile code to avoid flickering windows (& also fix cygwin bug)
|
||||||
* Rename -t to -T to match previous series option
|
- Rename -t to -T to match previous series option
|
||||||
* Added in -t to modify cmd line args for terminals
|
- Added in -t to modify cmd line args for terminals
|
||||||
|
|
||||||
2005-06-04 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.14.1
|
3.14.1 2005-06-04 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
|
||||||
* first cut at terminal opening speed up
|
- first cut at terminal opening speed up
|
||||||
|
|
||||||
2005-05-20 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.13.1
|
3.13.1 2005-05-20 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
|
||||||
* Bugfix for whitespace in config files (missing a char from regexp)
|
- Bugfix for whitespace in config files (missing a char from regexp)
|
||||||
* Allow for minimising/maximising all windows when done on console
|
- Allow for minimising/maximising all windows when done on console
|
||||||
|
|
||||||
2005-05-19 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.12.1
|
3.12.1 2005-05-19 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
|
||||||
* Bugfix for shifted non-alphanumeric keyboard chars not being pasted correctly
|
- Bugfix for shifted non-alphanumeric keyboard chars not being pasted correctly
|
||||||
* Marked version number with 3rd digit to signify beta releases
|
- Marked version number with 3rd digit to signify beta releases
|
||||||
|
|
||||||
2005-05-18 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.11
|
3.11 2005-05-18 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
|
||||||
* Remove trailing whitespace from config file lines
|
- Remove trailing whitespace from config file lines
|
||||||
* Prevent paste events being sent to non-active clients
|
- Prevent paste events being sent to non-active clients
|
||||||
* Allow paste events to send capitalised letters
|
- Allow paste events to send capitalised letters
|
||||||
|
|
||||||
2005-05-17 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.10
|
3.10 2005-05-17 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
|
||||||
* fix for moving atom numbers in font info
|
- fix for moving atom numbers in font info
|
||||||
|
|
||||||
2005-05-11 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.9
|
3.9 2005-05-11 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
|
||||||
* Allow multiple hosts or tags in the "Add Host" text widget
|
- Allow multiple hosts or tags in the "Add Host" text widget
|
||||||
* Retile all windows (if set) after adding a host
|
- Retile all windows (if set) after adding a host
|
||||||
* Do not automatically send a return after hostname (Alt-n)
|
- Do not automatically send a return after hostname (Alt-n)
|
||||||
* Fix bug with sending read hostname instead of internal unique host
|
- Fix bug with sending read hostname instead of internal unique host
|
||||||
name (Alt-n)
|
name (Alt-n)
|
||||||
* Fix bug whereby cannot start cssh without any hosts on cmd-line
|
- Fix bug whereby cannot start cssh without any hosts on cmd-line
|
||||||
* Fix bug where client name was sent to inactive clients
|
- Fix bug where client name was sent to inactive clients
|
||||||
* Fix bug whereby 0's in sent text were ignored
|
- Fix bug whereby 0's in sent text were ignored
|
||||||
|
|
||||||
2005-05-09 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.8
|
3.8 2005-05-09 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
|
||||||
* Remove the need for xlsfonts (perform function by X window calls instead)
|
- Remove the need for xlsfonts (perform function by X window calls instead)
|
||||||
* Debug level output changes
|
- Debug level output changes
|
||||||
* Ensure windows are overlapping in the right places, instead of any order
|
- Ensure windows are overlapping in the right places, instead of any order
|
||||||
* Create config section on window decorations (i.e. title & scroll bars)
|
- Create config section on window decorations (i.e. title & scroll bars)
|
||||||
|
|
||||||
2005-05-05 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.7
|
3.7 2005-05-05 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
|
||||||
* Found ConfigureWindow instead of ResizeMoveWindow
|
- Found ConfigureWindow instead of ResizeMoveWindow
|
||||||
|
|
||||||
2005-05-05 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.6
|
3.6 2005-05-05 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
|
||||||
* Lots of work on window tiling - to fall at last hurdle (No XResizeMoveWindow)
|
- Lots of work on window tiling - to fall at last hurdle (No XResizeMoveWindow)
|
||||||
* Documentation updates
|
- Documentation updates
|
||||||
* Allow -u ouput when binaries havnt been found
|
- Allow -u ouput when binaries havnt been found
|
||||||
* Start coding for capturing an existing terminal window
|
- Start coding for capturing an existing terminal window
|
||||||
* Rebuild hosts menu when all hosts checked, not when each host checked
|
- Rebuild hosts menu when all hosts checked, not when each host checked
|
||||||
* Change debug message output level of keysyms
|
- Change debug message output level of keysyms
|
||||||
* Cater for config of no tiling, but allow to retile in console window anyhow
|
- Cater for config of no tiling, but allow to retile in console window anyhow
|
||||||
|
|
||||||
2005-05-03 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.5
|
3.5 2005-05-03 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
|
||||||
* Remove some old (commented out) code
|
- Remove some old (commented out) code
|
||||||
* Remove some (unnecessary) debug code
|
- Remove some (unnecessary) debug code
|
||||||
* Start coding for window tiling
|
- Start coding for window tiling
|
||||||
* Modify find_binary function to make it more portable
|
- Modify find_binary function to make it more portable
|
||||||
* Output internal vars in "-u -d"
|
- Output internal vars in "-u -d"
|
||||||
* Small mods to docs to take account of all of the above
|
- Small mods to docs to take account of all of the above
|
||||||
|
|
||||||
2005-04-26 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.4
|
3.4 2005-04-26 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
|
||||||
* Changed order of "use POSIX" to put :sys_wait_h first to avoid chance of
|
- Changed order of "use POSIX" to put :sys_wait_h first to avoid chance of
|
||||||
hitting known issue
|
hitting known issue
|
||||||
* Allow for running from cvs dir in config{comms}
|
- Allow for running from cvs dir in config{comms}
|
||||||
* Add "ConnectTimeout=10" to default ssh options
|
- Add "ConnectTimeout=10" to default ssh options
|
||||||
* Add further debug info
|
- Add further debug info
|
||||||
* Add check to ensure hostname can be resolved before attempting connection
|
- Add check to ensure hostname can be resolved before attempting connection
|
||||||
* Modigy zombie reaping to prevent hand on unconnected cx term closing
|
- Modigy zombie reaping to prevent hand on unconnected cx term closing
|
||||||
* Add "autoquit" feature to close ClusterSSH after last client window closes
|
- Add "autoquit" feature to close ClusterSSH after last client window closes
|
||||||
* Also produce man page and include as part of install
|
- Also produce man page and include as part of install
|
||||||
|
|
||||||
2005-04-10 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.3
|
3.3 2005-04-10 Duncan Ferguson <duncan_ferguson@user.sf.net>
|
||||||
|
|
||||||
* src/cssh.pl: Rewritten from scratch
|
- src/cssh.pl: Rewritten from scratch
|
||||||
* Set up to use Gnu Autotools
|
- Set up to use Gnu Autotools
|
||||||
|
|
||||||
$Id$
|
|
||||||
|
|
46
MANIFEST
46
MANIFEST
|
@ -1,46 +0,0 @@
|
||||||
AUTHORS
|
|
||||||
bin/ccon
|
|
||||||
bin/crsh
|
|
||||||
bin/cscp
|
|
||||||
bin/cssh
|
|
||||||
bin/ctel
|
|
||||||
Build.PL
|
|
||||||
Changes
|
|
||||||
lib/App/ClusterSSH.pm
|
|
||||||
lib/App/ClusterSSH/Base.pm
|
|
||||||
lib/App/ClusterSSH/Cluster.pm
|
|
||||||
lib/App/ClusterSSH/Config.pm
|
|
||||||
lib/App/ClusterSSH/Helper.pm
|
|
||||||
lib/App/ClusterSSH/Host.pm
|
|
||||||
lib/App/ClusterSSH/L10N.pm
|
|
||||||
lib/App/ClusterSSH/L10N/en.pm
|
|
||||||
Makefile.PL
|
|
||||||
MANIFEST
|
|
||||||
MANIFEST.SKIP
|
|
||||||
META.json
|
|
||||||
META.yml
|
|
||||||
README
|
|
||||||
t/00-load.t
|
|
||||||
t/01l10n.t
|
|
||||||
t/02base.t
|
|
||||||
t/10host.t
|
|
||||||
t/10host_ssh_config
|
|
||||||
t/15config.t
|
|
||||||
t/15config.t.file1
|
|
||||||
t/15config.t.file2
|
|
||||||
t/15config.t.file3
|
|
||||||
t/20helper.t
|
|
||||||
t/30cluster.cannot_read
|
|
||||||
t/30cluster.file1
|
|
||||||
t/30cluster.file2
|
|
||||||
t/30cluster.file3
|
|
||||||
t/30cluster.t
|
|
||||||
t/30cluster.tag1
|
|
||||||
t/80clusterssh.t
|
|
||||||
t/boilerplate.t
|
|
||||||
t/external_cluster_command
|
|
||||||
t/manifest.t
|
|
||||||
t/pod-coverage.t
|
|
||||||
t/pod.t
|
|
||||||
THANKS
|
|
||||||
TODO
|
|
|
@ -1,16 +0,0 @@
|
||||||
^App-ClusterSSH-.*
|
|
||||||
^blib/
|
|
||||||
^_build/
|
|
||||||
^Build$
|
|
||||||
^cover_db/
|
|
||||||
^.git/
|
|
||||||
^.gitignore
|
|
||||||
^Makefile$
|
|
||||||
^Makefile.old$
|
|
||||||
^MANIFEST\.bak$
|
|
||||||
MYMETA.json
|
|
||||||
MYMETA.yml
|
|
||||||
pm_to_blib
|
|
||||||
.*\.swp$
|
|
||||||
^TOAD$
|
|
||||||
^WIP_TASKS$
|
|
94
META.json
94
META.json
|
@ -1,94 +0,0 @@
|
||||||
{
|
|
||||||
"abstract" : "A container for functions of the ClusterSSH programs",
|
|
||||||
"author" : [
|
|
||||||
"Duncan Ferguson <duncan_j_ferguson@yahoo.co.uk>"
|
|
||||||
],
|
|
||||||
"dynamic_config" : 1,
|
|
||||||
"generated_by" : "Module::Build version 0.4003, CPAN::Meta::Converter version 2.120921",
|
|
||||||
"license" : [
|
|
||||||
"perl_5"
|
|
||||||
],
|
|
||||||
"meta-spec" : {
|
|
||||||
"url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
|
|
||||||
"version" : "2"
|
|
||||||
},
|
|
||||||
"name" : "App-ClusterSSH",
|
|
||||||
"prereqs" : {
|
|
||||||
"build" : {
|
|
||||||
"requires" : {
|
|
||||||
"File::Temp" : "0",
|
|
||||||
"File::Which" : "0",
|
|
||||||
"Readonly" : "0",
|
|
||||||
"Test::Differences" : "0",
|
|
||||||
"Test::DistManifest" : "0",
|
|
||||||
"Test::Pod" : "0",
|
|
||||||
"Test::Pod::Coverage" : "0",
|
|
||||||
"Test::Trap" : "0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"configure" : {
|
|
||||||
"requires" : {
|
|
||||||
"Module::Build" : "0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"runtime" : {
|
|
||||||
"requires" : {
|
|
||||||
"Exception::Class" : "1.31",
|
|
||||||
"Locale::Maketext" : "0",
|
|
||||||
"Tk" : "800.022",
|
|
||||||
"Try::Tiny" : "0",
|
|
||||||
"X11::Protocol" : "0.56",
|
|
||||||
"version" : "0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"provides" : {
|
|
||||||
"App::ClusterSSH" : {
|
|
||||||
"file" : "lib/App/ClusterSSH.pm",
|
|
||||||
"version" : "4.02_02"
|
|
||||||
},
|
|
||||||
"App::ClusterSSH::Base" : {
|
|
||||||
"file" : "lib/App/ClusterSSH/Base.pm",
|
|
||||||
"version" : "0.02"
|
|
||||||
},
|
|
||||||
"App::ClusterSSH::Cluster" : {
|
|
||||||
"file" : "lib/App/ClusterSSH/Cluster.pm",
|
|
||||||
"version" : "0.01"
|
|
||||||
},
|
|
||||||
"App::ClusterSSH::Config" : {
|
|
||||||
"file" : "lib/App/ClusterSSH/Config.pm",
|
|
||||||
"version" : "0.02"
|
|
||||||
},
|
|
||||||
"App::ClusterSSH::Helper" : {
|
|
||||||
"file" : "lib/App/ClusterSSH/Helper.pm",
|
|
||||||
"version" : "0.02"
|
|
||||||
},
|
|
||||||
"App::ClusterSSH::Host" : {
|
|
||||||
"file" : "lib/App/ClusterSSH/Host.pm",
|
|
||||||
"version" : "0.03"
|
|
||||||
},
|
|
||||||
"App::ClusterSSH::L10N" : {
|
|
||||||
"file" : "lib/App/ClusterSSH/L10N.pm",
|
|
||||||
"version" : 0
|
|
||||||
},
|
|
||||||
"App::ClusterSSH::L10N::en" : {
|
|
||||||
"file" : "lib/App/ClusterSSH/L10N/en.pm",
|
|
||||||
"version" : 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"release_status" : "testing",
|
|
||||||
"resources" : {
|
|
||||||
"bugtracker" : {
|
|
||||||
"web" : "http://sourceforge.net/tracker/?group_id=89139"
|
|
||||||
},
|
|
||||||
"homepage" : "http://clusterssh.sourceforge.net/",
|
|
||||||
"license" : [
|
|
||||||
"http://dev.perl.org/licenses/"
|
|
||||||
],
|
|
||||||
"x_Repository" : [
|
|
||||||
"http://clusterssh.git.sourceforge.net/",
|
|
||||||
"http://github.com/duncs/clusterssh"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"version" : "4.02_02"
|
|
||||||
}
|
|
62
META.yml
62
META.yml
|
@ -1,62 +0,0 @@
|
||||||
---
|
|
||||||
abstract: 'A container for functions of the ClusterSSH programs'
|
|
||||||
author:
|
|
||||||
- 'Duncan Ferguson <duncan_j_ferguson@yahoo.co.uk>'
|
|
||||||
build_requires:
|
|
||||||
File::Temp: 0
|
|
||||||
File::Which: 0
|
|
||||||
Readonly: 0
|
|
||||||
Test::Differences: 0
|
|
||||||
Test::DistManifest: 0
|
|
||||||
Test::Pod: 0
|
|
||||||
Test::Pod::Coverage: 0
|
|
||||||
Test::Trap: 0
|
|
||||||
configure_requires:
|
|
||||||
Module::Build: 0
|
|
||||||
dynamic_config: 1
|
|
||||||
generated_by: 'Module::Build version 0.4003, CPAN::Meta::Converter version 2.120921'
|
|
||||||
license: perl
|
|
||||||
meta-spec:
|
|
||||||
url: http://module-build.sourceforge.net/META-spec-v1.4.html
|
|
||||||
version: 1.4
|
|
||||||
name: App-ClusterSSH
|
|
||||||
provides:
|
|
||||||
App::ClusterSSH:
|
|
||||||
file: lib/App/ClusterSSH.pm
|
|
||||||
version: 4.02_02
|
|
||||||
App::ClusterSSH::Base:
|
|
||||||
file: lib/App/ClusterSSH/Base.pm
|
|
||||||
version: 0.02
|
|
||||||
App::ClusterSSH::Cluster:
|
|
||||||
file: lib/App/ClusterSSH/Cluster.pm
|
|
||||||
version: 0.01
|
|
||||||
App::ClusterSSH::Config:
|
|
||||||
file: lib/App/ClusterSSH/Config.pm
|
|
||||||
version: 0.02
|
|
||||||
App::ClusterSSH::Helper:
|
|
||||||
file: lib/App/ClusterSSH/Helper.pm
|
|
||||||
version: 0.02
|
|
||||||
App::ClusterSSH::Host:
|
|
||||||
file: lib/App/ClusterSSH/Host.pm
|
|
||||||
version: 0.03
|
|
||||||
App::ClusterSSH::L10N:
|
|
||||||
file: lib/App/ClusterSSH/L10N.pm
|
|
||||||
version: 0
|
|
||||||
App::ClusterSSH::L10N::en:
|
|
||||||
file: lib/App/ClusterSSH/L10N/en.pm
|
|
||||||
version: 0
|
|
||||||
requires:
|
|
||||||
Exception::Class: 1.31
|
|
||||||
Locale::Maketext: 0
|
|
||||||
Tk: 800.022
|
|
||||||
Try::Tiny: 0
|
|
||||||
X11::Protocol: 0.56
|
|
||||||
version: 0
|
|
||||||
resources:
|
|
||||||
bugtracker: http://sourceforge.net/tracker/?group_id=89139
|
|
||||||
homepage: http://clusterssh.sourceforge.net/
|
|
||||||
license: http://dev.perl.org/licenses/
|
|
||||||
x_Repository:
|
|
||||||
- http://clusterssh.git.sourceforge.net/
|
|
||||||
- http://github.com/duncs/clusterssh
|
|
||||||
version: 4.02_02
|
|
33
Makefile.PL
33
Makefile.PL
|
@ -1,33 +0,0 @@
|
||||||
# Note: this file was auto-generated by Module::Build::Compat version 0.4003
|
|
||||||
use ExtUtils::MakeMaker;
|
|
||||||
WriteMakefile
|
|
||||||
(
|
|
||||||
'NAME' => 'App::ClusterSSH',
|
|
||||||
'VERSION_FROM' => 'lib/App/ClusterSSH.pm',
|
|
||||||
'PREREQ_PM' => {
|
|
||||||
'Exception::Class' => '1.31',
|
|
||||||
'File::Temp' => 0,
|
|
||||||
'File::Which' => 0,
|
|
||||||
'Locale::Maketext' => 0,
|
|
||||||
'Readonly' => 0,
|
|
||||||
'Test::Differences' => 0,
|
|
||||||
'Test::DistManifest' => 0,
|
|
||||||
'Test::Pod' => 0,
|
|
||||||
'Test::Pod::Coverage' => 0,
|
|
||||||
'Test::Trap' => 0,
|
|
||||||
'Tk' => '800.022',
|
|
||||||
'Try::Tiny' => 0,
|
|
||||||
'X11::Protocol' => '0.56',
|
|
||||||
'version' => '0'
|
|
||||||
},
|
|
||||||
'INSTALLDIRS' => 'site',
|
|
||||||
'EXE_FILES' => [
|
|
||||||
'bin/ccon',
|
|
||||||
'bin/crsh',
|
|
||||||
'bin/cscp',
|
|
||||||
'bin/cssh',
|
|
||||||
'bin/ctel'
|
|
||||||
],
|
|
||||||
'PL_FILES' => {}
|
|
||||||
)
|
|
||||||
;
|
|
787
README
787
README
|
@ -1,67 +1,768 @@
|
||||||
App-ClusterSSH
|
NAME
|
||||||
|
cssh - Cluster administration tool
|
||||||
|
|
||||||
The is the Perl application bundle for ClusterSSH (a.k.a cssh), formally
|
VERSION
|
||||||
a GNU tools based project.
|
This documentation is for version: 4.18
|
||||||
|
|
||||||
ClusterSSH is a tool for making the same change on multiple servers at
|
SYNOPSIS
|
||||||
the same time. The 'cssh' command opens an administration console and
|
cssh [-a '<command>'] [-K <seconds>] [-q] [-c '<filename>'] [-x <cols>]
|
||||||
an xterm to all specified hosts. Any text typed into the administration
|
[-C '<filename>'] [--debug [[...] || <INTEGER>]] [-d] [-e
|
||||||
console is replicated to all windows. All windows may also be typed into
|
'<[user@]<host>[:port]>'] [--fillscreen] [-f '<font>'] [-h] [-L '[tag]']
|
||||||
directly.
|
[-H] [-o '<STRING>'] [-p <port>] [-Q] [-y <rows>] [-s] [-r '<filename>']
|
||||||
|
[-t '<STRING>'] [-g] [-T '<title>'] [-u] [-?] [-A] [-l '<username>']
|
||||||
|
[-v]
|
||||||
|
|
||||||
This tool is intended for (but not limited to) cluster administration
|
RELATED
|
||||||
where the same configuration or commands must be run on each node
|
Also see the individual man pages for each of these utilities
|
||||||
within the cluster. Performing these commands all at once via this
|
|
||||||
tool ensures all nodes are kept in sync.
|
|
||||||
|
|
||||||
For more information, go to http://clusterssh.sourceforge.net
|
ccon - Use 'console' as the communication method
|
||||||
|
crsh - Use 'rsh' as the communication method
|
||||||
|
csftp - Use 'sftp' as the communication method
|
||||||
|
ctel - Use 'telnet' as the communication method
|
||||||
|
|
||||||
INSTALLATION
|
DESCRIPTION
|
||||||
|
The command opens an administration console and an xterm to all
|
||||||
|
specified hosts. Any text typed into the administration console is
|
||||||
|
replicated to all windows. All windows may also be typed into directly.
|
||||||
|
|
||||||
To install this module, run the following commands:
|
This tool is intended for (but not limited to) cluster administration
|
||||||
|
where the same configuration or commands must be run on each node within
|
||||||
|
the cluster. Performing these commands all at once via this tool ensures
|
||||||
|
all nodes are kept in sync.
|
||||||
|
|
||||||
perl Build.PL
|
Connections are opened using ssh which must be correctly installed and
|
||||||
./Build
|
configured.
|
||||||
./Build test
|
|
||||||
./Build install
|
|
||||||
|
|
||||||
SUPPORT AND DOCUMENTATION
|
Extra caution should be taken when editing files as lines may not
|
||||||
|
necessarily be in the same order; assuming line 5 is the same across all
|
||||||
|
servers and modifying that is dangerous. It's better to search for the
|
||||||
|
specific line to be changed and double-check all terminals are as
|
||||||
|
expected before changes are committed.
|
||||||
|
|
||||||
After installing, you can find documentation for this module with the
|
Further Notes
|
||||||
perldoc command.
|
Please also see "KNOWN BUGS".
|
||||||
|
|
||||||
perldoc cssh
|
* The dotted line on any sub-menu is a tear-off, i.e. click on it and
|
||||||
|
the sub-menu is turned into its own window.
|
||||||
|
|
||||||
or (if your MANPATH is set up appropriately)
|
* Unchecking a hostname on the Hosts sub-menu will unplug the host
|
||||||
|
from the cluster control window, so any text typed into the console
|
||||||
|
is not sent to that host. Re-selecting it will plug it back in.
|
||||||
|
|
||||||
man cssh
|
* If your window manager menu bars are obscured by terminal windows
|
||||||
|
see the "screen_reserve_XXXXX" options in the
|
||||||
|
$HOME/.clusterssh/config file (see "FILES").
|
||||||
|
|
||||||
You can also look for information at:
|
* If the terminals overlap too much see the "terminal_reserve_XXXXX"
|
||||||
|
options in the $HOME/.clusterssh/config file (see "FILES").
|
||||||
|
|
||||||
Web site and SourceForge project page
|
* When using ClusterSSH on a large number of systems to connect to a
|
||||||
http://clusterssh.sourceforge.net
|
single system using an SSH utility (e.g. you issue a command to to
|
||||||
http://sourceforge.net/projects/clusterssh/
|
copy a file using scp from the remote computers to a single host)
|
||||||
|
and when these connections require authentication (i.e. you are
|
||||||
|
going to authenticate with a password), the sshd daemon at that
|
||||||
|
location may refuse connections after the number "MaxStartups" limit
|
||||||
|
in sshd_config is exceeded. (If this value is not set, it defaults
|
||||||
|
to 10). This is expected behavior; sshd uses this mechanism to
|
||||||
|
prevent DoS attacks from unauthenticated sources. Please tune
|
||||||
|
sshd_config and reload the SSH daemon, or consider using the
|
||||||
|
~/.ssh/authorized_keys mechanism for authentication if you encounter
|
||||||
|
this problem.
|
||||||
|
|
||||||
Project support area
|
* If client windows fail to open, try running:
|
||||||
https://sourceforge.net/projects/clusterssh/support
|
|
||||||
|
|
||||||
AnnoCPAN, Annotated CPAN documentation
|
"cssh -e {single host name}"
|
||||||
http://annocpan.org/dist/App-ClusterSSH
|
|
||||||
|
|
||||||
CPAN Ratings
|
This will test the mechanisms used to open windows to hosts. This
|
||||||
http://cpanratings.perl.org/d/App-ClusterSSH
|
could be due to either the "-xrm" terminal option which enables
|
||||||
|
"AllowSendEvents" (some terminals do not require this option, other
|
||||||
|
terminals have another method for enabling it - see your terminal
|
||||||
|
documentation) or the configuration of "ssh".
|
||||||
|
|
||||||
Search CPAN
|
OPTIONS
|
||||||
http://search.cpan.org/dist/App-ClusterSSH/
|
Some of these options may also be defined within the configuration file.
|
||||||
|
Default options are shown as appropriate.
|
||||||
|
|
||||||
|
--action '<command>', -a '<command>'
|
||||||
|
Run the command in each session, e.g. "-a 'vi /etc/hosts'" to drop
|
||||||
|
straight into a vi session.
|
||||||
|
|
||||||
COPYRIGHT AND LICENCE
|
--autoclose <seconds>, -K <seconds>
|
||||||
|
Number of seconds to wait before closing finished terminal windows.
|
||||||
|
|
||||||
Copyright (C) 1999-2010 Duncan Ferguson
|
--autoquit, -q
|
||||||
|
Toggle automatically quitting after the last client window has
|
||||||
|
closed (overriding the config file).
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
--cluster-file '<filename>', -c '<filename>'
|
||||||
under the terms of either: the GNU General Public License as published
|
Use supplied file as additional cluster file (see also "FILES").
|
||||||
by the Free Software Foundation; or the Artistic License.
|
|
||||||
|
|
||||||
See http://dev.perl.org/licenses/ for more information.
|
--cols <cols>, -x <cols>
|
||||||
|
Number of columns
|
||||||
|
|
||||||
|
--config-file '<filename>', -C '<filename>'
|
||||||
|
Use supplied file as additional configuration file (see also
|
||||||
|
"FILES").
|
||||||
|
|
||||||
|
--debug [[...] || <INTEGER>]
|
||||||
|
Enable debugging. Either a level can be provided or the option can
|
||||||
|
be repeated multiple times. Maximum level is 9.
|
||||||
|
|
||||||
|
--dump-config, -d
|
||||||
|
Dump the current configuration in the same format used by the
|
||||||
|
$HOME/.clusterssh/config file.
|
||||||
|
|
||||||
|
--evaluate '<[user@]<host>[:port]>', -e '<[user@]<host>[:port]>'
|
||||||
|
Display and evaluate the terminal and connection arguments to
|
||||||
|
display any potential errors. The <hostname> is required to aid the
|
||||||
|
evaluation.
|
||||||
|
|
||||||
|
--fillscreen
|
||||||
|
Resize terminal windows to fill the whole available screen
|
||||||
|
|
||||||
|
--font '<font>', -f '<font>'
|
||||||
|
Specify the font to use in the terminal windows. Use standard X font
|
||||||
|
notation such as "5x8".
|
||||||
|
|
||||||
|
--help, -h
|
||||||
|
Show basic help text and exit
|
||||||
|
|
||||||
|
--list '[tag]', -L '[tag]'
|
||||||
|
List available cluster tags. Tag is optional. If a tag is provided
|
||||||
|
then hosts for that tag are listed. NOTE: format of output changes
|
||||||
|
when using "--quiet" or "-Q" option.
|
||||||
|
|
||||||
|
--man, -H
|
||||||
|
Show full help text (the man page) and exit
|
||||||
|
|
||||||
|
--options '<STRING>', -o '<STRING>'
|
||||||
|
Specify arguments to be passed to ssh when making the connection.
|
||||||
|
NOTE: options for ssh should normally be put into the ssh
|
||||||
|
configuration file; see "ssh_config" and $HOME/.ssh/config for more
|
||||||
|
details.
|
||||||
|
|
||||||
|
Default: -x -o ConnectTimeout=10
|
||||||
|
|
||||||
|
--port <port>, -p <port>
|
||||||
|
Specify an alternate port for connections.
|
||||||
|
|
||||||
|
--quiet, -Q
|
||||||
|
Do not output extra text when using some options
|
||||||
|
|
||||||
|
--rows <rows>, -y <rows>
|
||||||
|
Number of rows
|
||||||
|
|
||||||
|
--show-history, -s
|
||||||
|
Show history within console window.
|
||||||
|
|
||||||
|
--tag-file '<filename>', -r '<filename>'
|
||||||
|
Use supplied file as additional tag file (see also "FILES")
|
||||||
|
|
||||||
|
--term-args '<STRING>', -t '<STRING>'
|
||||||
|
Specify arguments to be passed to terminals being used.
|
||||||
|
|
||||||
|
--tile, -g
|
||||||
|
Toggle window tiling (overriding the config file).
|
||||||
|
|
||||||
|
--title '<title>', -T '<title>'
|
||||||
|
Specify the initial part of the title used in the console and client
|
||||||
|
windows.
|
||||||
|
|
||||||
|
--unique-servers, -u
|
||||||
|
Toggle connecting to each host only once when a hostname has been
|
||||||
|
specified multiple times.
|
||||||
|
|
||||||
|
--usage, -?
|
||||||
|
Show synopsis and exit
|
||||||
|
|
||||||
|
--use-all-a-records, -A
|
||||||
|
If a hostname resolves to multiple IP addresses, toggle whether or
|
||||||
|
not to connect to all of them, or just the first one (see also
|
||||||
|
config file entry).
|
||||||
|
|
||||||
|
--username '<username>', -l '<username>'
|
||||||
|
Specify the default username to use for connections (if different
|
||||||
|
from the currently logged in user). NOTE: will be overridden by
|
||||||
|
<user>@<host>.
|
||||||
|
|
||||||
|
--version, -v
|
||||||
|
Show version information and exit
|
||||||
|
|
||||||
|
ARGUMENTS
|
||||||
|
The following arguments are supported:
|
||||||
|
|
||||||
|
[user@]<hostname>[:port] ...
|
||||||
|
Open an xterm to the given hostname and connect to the
|
||||||
|
administration console. The optional port number can be used if the
|
||||||
|
server is not listening on the standard port.
|
||||||
|
|
||||||
|
<tag> ...
|
||||||
|
Open a series of xterms defined by <tag> in one of the supplementary
|
||||||
|
configuration files (see "FILES").
|
||||||
|
|
||||||
|
Note: specifying a username on a cluster tag will override any
|
||||||
|
usernames defined in the cluster.
|
||||||
|
|
||||||
|
KEY SHORTCUTS
|
||||||
|
The following key shortcuts are available within the console window, and
|
||||||
|
all of them may be changed via the configuration files.
|
||||||
|
|
||||||
|
Control-Shift-plus
|
||||||
|
Open the 'Add Host(s) or Cluster(s)' dialogue box. Multiple host or
|
||||||
|
cluster names can be entered, separated by spaces.
|
||||||
|
|
||||||
|
Alt-n
|
||||||
|
Paste in the hostname part of the specific connection string to each
|
||||||
|
client, minus any username or port, e.g.
|
||||||
|
|
||||||
|
"scp /etc/hosts server:files/<Alt-n>.hosts"
|
||||||
|
|
||||||
|
would replace the <Alt-n> with the client's name in each window.
|
||||||
|
|
||||||
|
Alt-l
|
||||||
|
Paste in the hostname of the server cssh is being run on
|
||||||
|
|
||||||
|
Alt-q
|
||||||
|
Quit the program and close all connections and windows.
|
||||||
|
|
||||||
|
Alt-r
|
||||||
|
Retile all the client windows.
|
||||||
|
|
||||||
|
Alt-u
|
||||||
|
Paste in the username for the connection
|
||||||
|
|
||||||
|
Alt-1
|
||||||
|
Alt-2
|
||||||
|
Alt-3
|
||||||
|
Alt-4
|
||||||
|
Run the matching user defined macro on the server and send the
|
||||||
|
output to the client
|
||||||
|
|
||||||
|
EXAMPLES
|
||||||
|
Open up a session to 3 servers
|
||||||
|
$ cssh server1 server2 server3
|
||||||
|
|
||||||
|
Open up a session to a cluster of servers identified by the tag 'farm1'
|
||||||
|
and give the controlling window a specific title, where the tag is
|
||||||
|
defined in one of the default configuration files
|
||||||
|
$ cssh -T 'Web Farm Cluster 1' farm1
|
||||||
|
|
||||||
|
Connect to different servers using different login names. NOTE: this can
|
||||||
|
also be achieved by setting up appropriate options in the configuration
|
||||||
|
files. Do not close the console when the last terminal exits.
|
||||||
|
$ cssh user1@server1 admin@server2
|
||||||
|
|
||||||
|
Open up a cluster defined in a non-default configuration file
|
||||||
|
$ cssh -c $HOME/cssh.extra_clusters db_cluster
|
||||||
|
|
||||||
|
Override the configured/default port to use 2022 instead
|
||||||
|
$ cssh -p 2022 server1 server2
|
||||||
|
|
||||||
|
FILES
|
||||||
|
/etc/clusters, $HOME/.clusterssh/clusters
|
||||||
|
These files contain a list of tags to server names mappings. When
|
||||||
|
any name is used on the command line it is checked to see if it is a
|
||||||
|
tag. If it is a tag, then the tag is replaced with the list of
|
||||||
|
servers. The format is as follows:
|
||||||
|
|
||||||
|
<tag> [user@]<server>[:port] [user@]<server>[:port] [...]
|
||||||
|
|
||||||
|
e.g.
|
||||||
|
|
||||||
|
# List of servers in live
|
||||||
|
live admin1@server1 admin2@server2:2022 server3 server4
|
||||||
|
|
||||||
|
All comments (marked by a #) and blank lines are ignored. Tags may
|
||||||
|
be nested, but be aware of using recursive tags as they are not
|
||||||
|
checked for.
|
||||||
|
|
||||||
|
Servers can be defined using expansion macros:
|
||||||
|
|
||||||
|
"webservers websvr{a,b,c}"
|
||||||
|
|
||||||
|
would be expanded to
|
||||||
|
|
||||||
|
"webservers websvra websvrb websvrc"
|
||||||
|
|
||||||
|
and
|
||||||
|
|
||||||
|
"webservers websvr{6..9}"
|
||||||
|
|
||||||
|
would be expanded to
|
||||||
|
|
||||||
|
"webservers websvr6 websvr7 websvr8 websvr9"
|
||||||
|
|
||||||
|
Extra cluster files may also be specified either as an option on the
|
||||||
|
command line (see "cluster-file") or in the user's
|
||||||
|
$HOME/.clusterssh/config file (see "extra_cluster_file"
|
||||||
|
configuration option).
|
||||||
|
|
||||||
|
NOTE: the last tag read overwrites any pre-existing tag of that
|
||||||
|
name.
|
||||||
|
|
||||||
|
NOTE: there is a special cluster tag called "default" - any tags or
|
||||||
|
hosts included within this tag will be automatically opened if
|
||||||
|
nothing is specified on the command line.
|
||||||
|
|
||||||
|
/etc/tags, $HOME/.clusterssh/tags
|
||||||
|
Very similar to clusters files but the definition is reversed. The
|
||||||
|
format is:
|
||||||
|
|
||||||
|
<host> <tag> [...]
|
||||||
|
|
||||||
|
This allows one host to be specified as a member of a number of
|
||||||
|
tags. This format can be clearer than using clusters files.
|
||||||
|
|
||||||
|
Extra tag files may be specified either as an option (see
|
||||||
|
"tag-file") or within the user's $HOME/.clusterssh/config file (see
|
||||||
|
"extra_tag_file" configuration option).
|
||||||
|
|
||||||
|
NOTE: All tags are added together
|
||||||
|
|
||||||
|
/etc/csshrc & $HOME/.clusterssh/config
|
||||||
|
This file contains configuration overrides - the defaults are as
|
||||||
|
marked. Default options are overwritten first by the global file,
|
||||||
|
and then by the user file.
|
||||||
|
|
||||||
|
NOTE: values for entries do not need to be quoted unless it is
|
||||||
|
required for passing arguments, e.g.
|
||||||
|
|
||||||
|
"terminal_allow_send_events="-xrm '*.VT100.allowSendEvents:true'""
|
||||||
|
|
||||||
|
should be written as
|
||||||
|
|
||||||
|
"terminal_allow_send_events=-xrm '*.VT100.allowSendEvents:true'"
|
||||||
|
|
||||||
|
auto_close = 5
|
||||||
|
Close terminal window after this many seconds. If set to 0 will
|
||||||
|
instead wait on input from the user in each window before
|
||||||
|
closing. See also --autoclose and --no-autoclose
|
||||||
|
|
||||||
|
auto_quit = 1
|
||||||
|
Automatically quit after the last client window closes. Set to 0
|
||||||
|
to disable. See also --autoquit
|
||||||
|
|
||||||
|
auto_wm_decoration_offsets = no
|
||||||
|
Enable or disable alternative algorithm for calculating terminal
|
||||||
|
positioning.
|
||||||
|
|
||||||
|
command_pre =
|
||||||
|
command_post =
|
||||||
|
Add extra commands around the communication method. For example:
|
||||||
|
|
||||||
|
command_pre= . $HOME/virtualenvs/default/bin/active ;
|
||||||
|
command_post= | ct
|
||||||
|
|
||||||
|
would allow for using Python virtual envronments and then piping
|
||||||
|
all shell output through "chromaterm" for syntax highlighting.
|
||||||
|
Note: you must use appropriate command separators/terminators to
|
||||||
|
keep the meaning of the command pipline (such as ";" and "|"
|
||||||
|
between commands).
|
||||||
|
|
||||||
|
These are not put through macro parsing.
|
||||||
|
|
||||||
|
comms = ssh
|
||||||
|
Sets the default communication method (initially taken from the
|
||||||
|
name of the program, but can be overridden here).
|
||||||
|
|
||||||
|
console_position = <null>
|
||||||
|
Set the initial position of the console - if empty then let the
|
||||||
|
window manager decide. Format is '+<x>+<y>', i.e. '+0+0' is top
|
||||||
|
left hand corner of the screen, '+0-70' is bottom left hand side
|
||||||
|
of screen (more or less).
|
||||||
|
|
||||||
|
external_command_mode = 0600
|
||||||
|
File mode bits for the external_command_pipe.
|
||||||
|
|
||||||
|
external_command_pipe = <null>
|
||||||
|
Define the full path to an external command pipe that can be
|
||||||
|
written to for controlling some aspects of ClusterSSH, such as
|
||||||
|
opening sessions to more clusters.
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
|
||||||
|
"open <tag|hostname>" - open new sessions to provided tag or
|
||||||
|
hostname
|
||||||
|
|
||||||
|
"retile" - force window retiling
|
||||||
|
|
||||||
|
e.g.: "echo 'open localhost'" /path/to/external_command_pipe >>
|
||||||
|
|
||||||
|
external_cluster_command = <null>
|
||||||
|
Define the full path to an external command that can be used to
|
||||||
|
resolve tags to host names. This command can be written in any
|
||||||
|
language. The script must accept a list of tags to resolve and
|
||||||
|
output a list of hosts (space separated on a single line). Any
|
||||||
|
tags that cannot be resolved should be returned unchanged.
|
||||||
|
|
||||||
|
A non-0 exit code will be counted as an error, a warning will be
|
||||||
|
printed and output ignored.
|
||||||
|
|
||||||
|
If the external command is given a "-L" option it should output
|
||||||
|
a list of tags (space separated on a single line) it can resolve
|
||||||
|
|
||||||
|
extra_cluster_file = <null>
|
||||||
|
Define an extra cluster file in the format of /etc/clusters.
|
||||||
|
Multiple files can be specified, separated by commas. Both ~ and
|
||||||
|
$HOME are acceptable as a reference to the user's home
|
||||||
|
directory, e.g.
|
||||||
|
|
||||||
|
"extra_cluster_file = ~/clusters, $HOME/clus"
|
||||||
|
|
||||||
|
extra_tag_file = <null>
|
||||||
|
Define an extra tag file in the format of /etc/tags. Multiple
|
||||||
|
files can be specified, separated by commas. Both ~ and $HOME
|
||||||
|
are acceptable as a reference to the user's home directory, e.g.
|
||||||
|
|
||||||
|
"extra_tag_file = ~/tags, $HOME/tags"
|
||||||
|
|
||||||
|
key_addhost = Control-Shift-plus
|
||||||
|
Default key sequence to open AddHost menu. See "KEY SHORTCUTS"
|
||||||
|
for more information.
|
||||||
|
|
||||||
|
hide_menu = 0
|
||||||
|
If set to 1, hide the menu bar (File, Hosts, Send, Help) in the
|
||||||
|
console.
|
||||||
|
|
||||||
|
key_clientname = Alt-n
|
||||||
|
Default key sequence to send cssh client names to client. See
|
||||||
|
"KEY SHORTCUTS" for more information.
|
||||||
|
|
||||||
|
key_localname = Alt-l
|
||||||
|
Default key sequence to send hostname of local server to client.
|
||||||
|
See "KEY SHORTCUTS" for more information.
|
||||||
|
|
||||||
|
key_paste = Control-v
|
||||||
|
Default key sequence to paste text into the console window. See
|
||||||
|
"KEY SHORTCUTS" for more information.
|
||||||
|
|
||||||
|
key_quit = Control-q
|
||||||
|
Default key sequence to quit the program (will terminate all
|
||||||
|
open windows). See "KEY SHORTCUTS" for more information.
|
||||||
|
|
||||||
|
key_retilehosts = Alt-r
|
||||||
|
Default key sequence to retile host windows. See "KEY SHORTCUTS"
|
||||||
|
for more information.
|
||||||
|
|
||||||
|
key_username = Alt-u
|
||||||
|
Default key sequence to send username to client. See "KEY
|
||||||
|
SHORTCUTS" for more information.
|
||||||
|
|
||||||
|
key_user_1 = Alt-1
|
||||||
|
key_user_2 = Alt-2
|
||||||
|
key_user_3 = Alt-3
|
||||||
|
key_user_4 = Alt-4
|
||||||
|
Default key sequence to send user defined macros to client. If
|
||||||
|
the matching macro_user_1 macro is undefined, the sequence is
|
||||||
|
passed straight to the terminal. See "KEY SHORTCUTS" for more
|
||||||
|
information.
|
||||||
|
|
||||||
|
macro_servername = %s
|
||||||
|
macro_hostname = %h
|
||||||
|
macro_username = %u
|
||||||
|
macro_newline = %n
|
||||||
|
macro_version = %v
|
||||||
|
macro_user_1 = %1
|
||||||
|
macro_user_2 = %2
|
||||||
|
macro_user_3 = %3
|
||||||
|
macro_user_4 = %4
|
||||||
|
Change the replacement macro used when either using a 'Send'
|
||||||
|
menu item, or when pasting text into the main console.
|
||||||
|
|
||||||
|
macro_user_1_command =
|
||||||
|
macro_user_2_command =
|
||||||
|
macro_user_3_command =
|
||||||
|
macro_user_4_command =
|
||||||
|
User defined macros - the macro is run through the shell on the
|
||||||
|
server and the output is sent to the client. For example,
|
||||||
|
|
||||||
|
"macro_user_1_command=echo echo macro_user_1"
|
||||||
|
|
||||||
|
would send the text C<echo macro_user_1> into the terminal session.
|
||||||
|
|
||||||
|
"macro_user_1_command=env | grep CSSH"
|
||||||
|
|
||||||
|
would send the CSSH environment variables to the client.
|
||||||
|
|
||||||
|
The following environment variables are set in the shell of the
|
||||||
|
macro process
|
||||||
|
|
||||||
|
"CSSH_SERVERNAME"
|
||||||
|
"CSSH_HOSTNAME"
|
||||||
|
"CSSH_USERNAME"
|
||||||
|
"CSSH_CONNECTION_STRING"
|
||||||
|
"CSSH_CONNECTION_PORT"
|
||||||
|
"CSSH_VERSION"
|
||||||
|
|
||||||
|
macros_enabled = yes
|
||||||
|
Enable or disable macro replacement. Note: this affects all the
|
||||||
|
"macro_*" variables above.
|
||||||
|
|
||||||
|
max_addhost_menu_cluster_items = 6
|
||||||
|
Maximum number of entries in the 'Add Host' menu cluster list
|
||||||
|
before scrollbars are used
|
||||||
|
|
||||||
|
max_host_menu_items = 30
|
||||||
|
Maximum number of hosts to put into the host menu before
|
||||||
|
starting a new column
|
||||||
|
|
||||||
|
menu_host_autotearoff = 0
|
||||||
|
menu_send_autotearoff = 0
|
||||||
|
When set to non-0 will automatically tear-off the host or send
|
||||||
|
menu at program start
|
||||||
|
|
||||||
|
mouse_paste = Button-2 (middle mouse button)
|
||||||
|
Default key sequence to paste text into the console window using
|
||||||
|
the mouse. See "KEY SHORTCUTS" for more information.
|
||||||
|
|
||||||
|
rsh = /path/to/rsh
|
||||||
|
ssh = /path/to/ssh
|
||||||
|
telnet = /path/to/telnet
|
||||||
|
Set the path to the specific binary to use for the communication
|
||||||
|
method, else uses the first match found in $PATH
|
||||||
|
|
||||||
|
rsh_args = <blank>
|
||||||
|
ssh_args = "-x -o ConnectTimeout=10"
|
||||||
|
telnet_args = <blank>
|
||||||
|
Sets any arguments to be used with the communication method
|
||||||
|
(defaults to ssh arguments).
|
||||||
|
|
||||||
|
NOTE: The given defaults are based on OpenSSH, not commercial
|
||||||
|
ssh software.
|
||||||
|
|
||||||
|
NOTE: Any "generic" change to the method (e.g., specifying the
|
||||||
|
ssh port to use) should be done in the medium's own config file
|
||||||
|
(see "ssh_config" and $HOME/.ssh/config).
|
||||||
|
|
||||||
|
screen_reserve_top = 0
|
||||||
|
screen_reserve_bottom = 60
|
||||||
|
screen_reserve_left = 0
|
||||||
|
screen_reserve_right = 0
|
||||||
|
Number of pixels from the screen's side to reserve when
|
||||||
|
calculating screen geometry for tiling. Setting this to
|
||||||
|
something like 50 will help keep cssh from positioning windows
|
||||||
|
over your window manager's menu bar if it draws one at that side
|
||||||
|
of the screen.
|
||||||
|
|
||||||
|
terminal = /path/to/xterm
|
||||||
|
Path to the X-Windows terminal used for the client.
|
||||||
|
|
||||||
|
terminal_args = <blank>
|
||||||
|
Arguments to use when opening terminal windows. Otherwise takes
|
||||||
|
defaults from $HOME/.Xdefaults or $HOME/.Xresources file.
|
||||||
|
|
||||||
|
terminal_chdir = 0
|
||||||
|
When non-0, set the working directory for each terminal as per
|
||||||
|
'terminal_chdir_path'
|
||||||
|
|
||||||
|
terminal_chdir_path = $HOME/.clusterssh/work/%s
|
||||||
|
Path to use as working directory for each terminal when
|
||||||
|
'terminal_chdir' is enabled. The path provided is passed through
|
||||||
|
the macro parser (see the section above on 'macros_enabled'.
|
||||||
|
|
||||||
|
terminal_font = 6x13
|
||||||
|
Font to use in the terminal windows. Use standard X font
|
||||||
|
notation.
|
||||||
|
|
||||||
|
terminal_reserve_top = 5
|
||||||
|
terminal_reserve_bottom = 0
|
||||||
|
terminal_reserve_left = 5
|
||||||
|
terminal_reserve_right = 0
|
||||||
|
Number of pixels from the terminal's side to reserve when
|
||||||
|
calculating screen geometry for tiling. Setting these will help
|
||||||
|
keep cssh from positioning windows over your scroll and title
|
||||||
|
bars or otherwise overlapping the windows too much.
|
||||||
|
|
||||||
|
terminal_colorize = 1
|
||||||
|
If set to 1 (the default), then "-bg" and "-fg" arguments will
|
||||||
|
be added to the terminal invocation command-line. The terminal
|
||||||
|
will be colored in a pseudo-random way based on the host name;
|
||||||
|
while the color of a terminal is not easily predicted, it will
|
||||||
|
always be the same color for a given host name. After a while,
|
||||||
|
you will recognize hosts by their characteristic terminal color.
|
||||||
|
|
||||||
|
terminal_bg_style = dark
|
||||||
|
If set to "dark", the terminal background will be set to black
|
||||||
|
and the foreground to the pseudo-random color. If set to
|
||||||
|
"light", then the foreground will be black and the background
|
||||||
|
the pseudo-random color. If terminal_colorize is "zero", then
|
||||||
|
this option has no effect.
|
||||||
|
|
||||||
|
terminal_size = 80x24
|
||||||
|
Initial size of terminals to use. NOTE: the number of lines (24)
|
||||||
|
will be decreased when resizing terminals for tiling, not the
|
||||||
|
number of characters (80).
|
||||||
|
|
||||||
|
terminal_title_opt = -T
|
||||||
|
Option used with "terminal" to set the title of the window
|
||||||
|
|
||||||
|
terminal_allow_send_events = -xrm '*.VT100.allowSendEvents:true'
|
||||||
|
Option required by the terminal to allow XSendEvents to be
|
||||||
|
received
|
||||||
|
|
||||||
|
title = cssh
|
||||||
|
Title of windows to use for both the console and terminals.
|
||||||
|
|
||||||
|
unmap_on_redraw = no
|
||||||
|
Tell Tk to use the UnmapWindow request before redrawing terminal
|
||||||
|
windows. This defaults to "no" as it causes some problems with
|
||||||
|
the FVWM window manager. If you are experiencing problems with
|
||||||
|
redraws, you can set it to "yes" to allow the window to be
|
||||||
|
unmapped before it is repositioned.
|
||||||
|
|
||||||
|
use_all_a_records = 0
|
||||||
|
If a hostname resolves to multiple IP addresses, set to 1 to
|
||||||
|
connect to all of them, not just the first one found. See also
|
||||||
|
"--use-all-a-records"}
|
||||||
|
|
||||||
|
use_hotkeys = 1
|
||||||
|
Setting to 0 will disable all hotkeys.
|
||||||
|
|
||||||
|
use_natural_sort = 0
|
||||||
|
Windows will normally sort in alphabetical order, i.e.: host1,
|
||||||
|
host11, host2. Setting to this 1 will change the sort order,
|
||||||
|
i.e.: host1, host2, host11. NOTE: You must have the perl module
|
||||||
|
Sort::Naturally installed.
|
||||||
|
|
||||||
|
user = $LOGNAME
|
||||||
|
Sets the default user for running commands on clients.
|
||||||
|
|
||||||
|
window_tiling = 1
|
||||||
|
Perform window tiling (set to 0 to disable)
|
||||||
|
|
||||||
|
window_tiling_direction = right
|
||||||
|
Direction to tile windows, where "right" means starting top left
|
||||||
|
and moving right and then down, and anything else means starting
|
||||||
|
bottom right and moving left and then up
|
||||||
|
|
||||||
|
NOTE: The key shortcut modifiers must be in the form "Control",
|
||||||
|
"Alt" or "Shift", e.g. with the first letter capitalised and the
|
||||||
|
rest lower case. Keys may also be disabled individually by setting
|
||||||
|
to the word "null".
|
||||||
|
|
||||||
|
$HOME/.clusterssh/send_menu
|
||||||
|
This (optional) file contains items to populate the send menu. The
|
||||||
|
default entry could be written as:
|
||||||
|
|
||||||
|
<send_menu>
|
||||||
|
<menu title="Use Macros">
|
||||||
|
<toggle/>
|
||||||
|
<accelerator>ALT-p</accelerator>
|
||||||
|
</menu>
|
||||||
|
<menu title="Remote Hostname">
|
||||||
|
<command>%s</command>
|
||||||
|
<accelerator>ALT-n</accelerator>
|
||||||
|
</menu>
|
||||||
|
<menu title="Local Hostname">
|
||||||
|
<command>%s</command>
|
||||||
|
<accelerator>ALT-l</accelerator>
|
||||||
|
</menu>
|
||||||
|
<menu title="Username">
|
||||||
|
<command>%u</command>
|
||||||
|
<accelerator>ALT-u</accelerator>
|
||||||
|
</menu>
|
||||||
|
<menu title="Test Text">
|
||||||
|
<command>echo "ClusterSSH Version: %v%n</command>
|
||||||
|
</menu>
|
||||||
|
</send_menu>
|
||||||
|
|
||||||
|
Submenus can also be specified as follows:
|
||||||
|
|
||||||
|
<send_menu>
|
||||||
|
<menu title="Default Entries">
|
||||||
|
<detach>yes</detach>
|
||||||
|
<menu title="Hostname">
|
||||||
|
<command>%s</command>
|
||||||
|
<accelerator>ALT-n</accelerator>
|
||||||
|
</menu>
|
||||||
|
</menu>
|
||||||
|
</send_menu>
|
||||||
|
|
||||||
|
Caveats:
|
||||||
|
|
||||||
|
There is currently no strict format checking of this file.
|
||||||
|
The format of the file may change in the future
|
||||||
|
If the file exists, the default entry (Hostname) is not added
|
||||||
|
|
||||||
|
The following replacement macros are available (note: these can be
|
||||||
|
changed in the configuration file):
|
||||||
|
|
||||||
|
%s Hostname part of the specific connection string to each client,
|
||||||
|
minus any username or port
|
||||||
|
|
||||||
|
%u Username part of the connection string to each client
|
||||||
|
|
||||||
|
%h Hostname of server where cssh is being run from
|
||||||
|
|
||||||
|
%n "RETURN" code
|
||||||
|
|
||||||
|
NOTE: requires XML::Simple to be installed
|
||||||
|
|
||||||
|
KNOWN BUGS
|
||||||
|
If you have any ideas about how to fix the below bugs, please get in
|
||||||
|
touch and/or provide a patch.
|
||||||
|
|
||||||
|
* Swapping virtual desktops can cause a redraw of all the terminal
|
||||||
|
windows. This is due to a lack of distinction within Tk between
|
||||||
|
switching desktops and minimising/maximising windows. Until Tk can
|
||||||
|
tell the difference between the two events, there is no fix (apart
|
||||||
|
from rewriting everything directly in X).
|
||||||
|
|
||||||
|
TROUBLESHOOTING
|
||||||
|
If you have issues running cssh, first try:
|
||||||
|
|
||||||
|
"cssh -e [user@]<hostname>[:port]"
|
||||||
|
|
||||||
|
This performs two tests to confirm cssh is able to work properly with
|
||||||
|
the settings provided within the $HOME/.clusterssh/config file (or
|
||||||
|
internal defaults).
|
||||||
|
|
||||||
|
1 Test the terminal window works with the options provided
|
||||||
|
|
||||||
|
2 Test ssh works to a host with the configured arguments
|
||||||
|
|
||||||
|
Configuration options to watch for in ssh are:
|
||||||
|
|
||||||
|
* SSH doesn't understand "-o ConnectTimeout=10" - remove the option
|
||||||
|
from the $HOME/.clusterssh/config file
|
||||||
|
|
||||||
|
* OpenSSH-3.8 using untrusted ssh tunnels - use "-Y" instead of "-X"
|
||||||
|
or use "ForwardX11Trusted yes" in $HOME/.ssh/ssh_config (if you
|
||||||
|
change the default ssh options from "-x" to "-X")
|
||||||
|
|
||||||
|
SUPPORT AND REPORTING BUGS
|
||||||
|
A web site for comments, requests, bug reports and bug fixes/patches is
|
||||||
|
available at: <https://github.com/duncs/clusterssh>
|
||||||
|
|
||||||
|
If you require support, please run the following commands and create an
|
||||||
|
issue via: <https://github.com/duncs/clusterssh/issues>
|
||||||
|
|
||||||
|
"perl -V"
|
||||||
|
|
||||||
|
"perl -MTk -e 'print $Tk::VERSION,$/'"
|
||||||
|
|
||||||
|
"perl -MX11::Protocol -e 'print $X11::Protocol::VERSION,$/'"
|
||||||
|
|
||||||
|
"cat /etc/csshrc $HOME/.clusterssh/config"
|
||||||
|
|
||||||
|
Using the debug option (--debug) will turn on debugging output. Repeat
|
||||||
|
the option to increase the amount of debug. However, if possible please
|
||||||
|
only use this option with one host at a time, e.g. "cssh --debug <host>"
|
||||||
|
due to the amount of output produced (in both main and child windows).
|
||||||
|
|
||||||
|
SEE ALSO
|
||||||
|
<https://github.com/duncs/clusterssh/wiki/>, "ssh", Tk::overview,
|
||||||
|
X11::Protocol, "perl"
|
||||||
|
|
||||||
|
AUTHOR
|
||||||
|
Duncan Ferguson, "<duncan_j_ferguson at yahoo.co.uk>"
|
||||||
|
|
||||||
|
LICENSE AND COPYRIGHT
|
||||||
|
Copyright 1999-2018 Duncan Ferguson.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it
|
||||||
|
under the terms of either: the GNU General Public License as published
|
||||||
|
by the Free Software Foundation; or the Artistic License.
|
||||||
|
|
||||||
|
See http://dev.perl.org/licenses/ for more information.
|
||||||
|
|
||||||
|
|
8
THANKS
8
THANKS
|
@ -41,3 +41,11 @@ Stefan Steiner
|
||||||
Ryan Brown
|
Ryan Brown
|
||||||
Brandon Perkins
|
Brandon Perkins
|
||||||
Oliver Meissner
|
Oliver Meissner
|
||||||
|
Andrew Stevenson (cqexbesd)
|
||||||
|
Emanuele Tomasi
|
||||||
|
Deny Dias
|
||||||
|
Bill Rushmore
|
||||||
|
Ankit Vadehra
|
||||||
|
Azenet
|
||||||
|
Markus Frosch (lazyfrosch)
|
||||||
|
Petr Vorel
|
||||||
|
|
45
TODO
45
TODO
|
@ -1,52 +1,15 @@
|
||||||
Overview of tasks
|
Overview of tasks
|
||||||
=================
|
=================
|
||||||
|
|
||||||
Config file
|
|
||||||
===========
|
|
||||||
|
|
||||||
Convert from file ~/.cssrch to directory ~/.clusterssh
|
|
||||||
For conversion process
|
|
||||||
- clusters in .csshrc should be placed into 'default.cluster'
|
|
||||||
- all other config should go into 'config'
|
|
||||||
- create default menu file
|
|
||||||
|
|
||||||
New feature - if cssh -s symlinked to c_xxx then search for xxx as a cluster
|
|
||||||
file in .clutersshrc and open that
|
|
||||||
|
|
||||||
Getopts usage
|
|
||||||
=============
|
|
||||||
|
|
||||||
Set up similar to Nagios::Plugin where Getopts::Long is subclassed
|
|
||||||
Sort out docs too
|
|
||||||
|
|
||||||
Add in '-l' to list all available tags
|
|
||||||
Add in '-l <tag>' to list all hosts for the given tag
|
|
||||||
Idea from Markus Manzke
|
|
||||||
|
|
||||||
Change way commands generated
|
|
||||||
=============================
|
|
||||||
|
|
||||||
Each script file (cssh, crsh, ctel, ccon, cscp, crsync) should define how
|
|
||||||
the command is created/used and also none-common options
|
|
||||||
|
|
||||||
# Something like the following (needs refinement):
|
|
||||||
|
|
||||||
$app->setup_command(
|
|
||||||
"ssh %PORT% %USER% %HOSTNAME%",
|
|
||||||
{
|
|
||||||
%PORT% => [ $app->getopt->port, "-p %PORT%" ],
|
|
||||||
%USER% => [ $app->getopt->username, "-l %USER%" ],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
Change way terminal windows are created
|
Change way terminal windows are created
|
||||||
=======================================
|
=======================================
|
||||||
|
|
||||||
Set up terminal windows in Tk to embedd termainl session into it, such as with
|
Set up terminal windows in Tk to embed termainal session into it, such
|
||||||
xterm
|
as with xterm:
|
||||||
|
|
||||||
xterm -wid <wid> ....
|
xterm -wid <wid> ....
|
||||||
|
|
||||||
This may limit to terminal thats can reparent into a given window id though.
|
This may limit what terminals can be used, though
|
||||||
|
|
||||||
See also:
|
See also:
|
||||||
http://www.perlmonks.org/?node_id=359764
|
http://www.perlmonks.org/?node_id=359764
|
||||||
|
|
1
bin/ccon
1
bin/ccon
|
@ -1 +0,0 @@
|
||||||
cssh
|
|
1
bin/crsh
1
bin/crsh
|
@ -1 +0,0 @@
|
||||||
cssh
|
|
881
bin/cssh
881
bin/cssh
|
@ -1,881 +0,0 @@
|
||||||
#!/usr/bin/perl
|
|
||||||
use strict;
|
|
||||||
use warnings;
|
|
||||||
|
|
||||||
use FindBin;
|
|
||||||
use lib $FindBin::Bin. '/../lib';
|
|
||||||
use lib $FindBin::Bin. '/../lib/perl5';
|
|
||||||
use App::ClusterSSH;
|
|
||||||
|
|
||||||
my $app = App::ClusterSSH->new();
|
|
||||||
$app->run();
|
|
||||||
|
|
||||||
__END__
|
|
||||||
|
|
||||||
=pod
|
|
||||||
|
|
||||||
=head1 NAME
|
|
||||||
|
|
||||||
cssh, crsh, ctel, ccon - Cluster administration tool
|
|
||||||
|
|
||||||
=head1 SYNOPSIS
|
|
||||||
|
|
||||||
S<< cssh [options] [[user@]<server>[:port]|<tag>] [...] >>
|
|
||||||
S<< crsh [options] [[user@]<server>[:port]|<tag>] [...] >>
|
|
||||||
S<< ctel [options] [<server>[:port]|<tag>] [...] >>
|
|
||||||
S<< ccon [options] [[user@]<server>[:port]|<tag>] [...] >>
|
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
|
||||||
|
|
||||||
The command opens an administration console and an xterm to all specified
|
|
||||||
hosts. Any text typed into the administration console is replicated to
|
|
||||||
all windows. All windows may also be typed into directly.
|
|
||||||
|
|
||||||
This tool is intended for (but not limited to) cluster administration where
|
|
||||||
the same configuration or commands must be run on each node within the
|
|
||||||
cluster. Performing these commands all at once via this tool ensures all
|
|
||||||
nodes are kept in sync.
|
|
||||||
|
|
||||||
Connections are opened via ssh so a correctly installed and configured
|
|
||||||
ssh installation is required. If, however, the program is called by "crsh"
|
|
||||||
then the rsh protocol is used (and the communications channel is insecure),
|
|
||||||
or by "ctel" then telnet is used, or by "ccon" then console is used.
|
|
||||||
|
|
||||||
Extra caution should be taken when editing system files such as
|
|
||||||
/etc/inet/hosts as lines may not necessarily be in the same order. Assuming
|
|
||||||
line 5 is the same across all servers and modifying that is dangerous.
|
|
||||||
Better to search for the specific line to be changed and double-check before
|
|
||||||
changes are committed.
|
|
||||||
|
|
||||||
=head2 Further Notes
|
|
||||||
|
|
||||||
Please also see L</KNOWN BUGS>.
|
|
||||||
|
|
||||||
=over
|
|
||||||
|
|
||||||
=item *
|
|
||||||
|
|
||||||
The dotted line on any sub-menu is a tear-off, i.e. click on it
|
|
||||||
and the sub-menu is turned into its own window.
|
|
||||||
|
|
||||||
=item *
|
|
||||||
|
|
||||||
Unchecking a hostname on the Hosts sub-menu will unplug the host from the
|
|
||||||
cluster control window, so any text typed into the console is not sent to
|
|
||||||
that host. Re-selecting it will plug it back in.
|
|
||||||
|
|
||||||
=item *
|
|
||||||
|
|
||||||
If your window manager menu bars are obscured by terminal windows see
|
|
||||||
the C<screen_reserve_XXXXX> options in the F<$HOME/.clusterssh/config> file (see L</"FILES">).
|
|
||||||
|
|
||||||
=item *
|
|
||||||
|
|
||||||
If the terminals overlap too much see the C<terminal_reserve_XXXXX>
|
|
||||||
options in the F<$HOME/.clusterssh/config> file (see L</"FILES">).
|
|
||||||
|
|
||||||
=item *
|
|
||||||
|
|
||||||
If the code is called as crsh instead of cssh (i.e. a symlink called
|
|
||||||
crsh points to the cssh file or the file is renamed) rsh is used as the
|
|
||||||
communications protocol instead of ssh.
|
|
||||||
|
|
||||||
=item *
|
|
||||||
|
|
||||||
If the code is called as ctel instead of cssh (i.e. a symlink called
|
|
||||||
ctel points to the cssh file or the file is renamed) telnet is used as the
|
|
||||||
communications protocol instead of ssh.
|
|
||||||
|
|
||||||
=item *
|
|
||||||
|
|
||||||
If the code is called as ccon instead of cssh (i.e. a symlink called
|
|
||||||
ccon points to the cssh file or the file is renamed) console is used as the
|
|
||||||
communications protocol instead of ssh.
|
|
||||||
|
|
||||||
=item *
|
|
||||||
|
|
||||||
When using cssh on a large number of systems to connect back to a single
|
|
||||||
system (e.g. you issue a command to the cluster to scp a file from a given
|
|
||||||
location) and when these connections require authentication (i.e. you are
|
|
||||||
going to authenticate with a password), the sshd daemon at that location
|
|
||||||
may refuse connects after the number specified by MaxStartups in
|
|
||||||
sshd_config is exceeded. (If this value is not set, it defaults to 10.)
|
|
||||||
This is expected behavior; sshd uses this mechanism to prevent DoS attacks
|
|
||||||
from unauthenticated sources. Please tune sshd_config and reload the SSH
|
|
||||||
daemon, or consider using the ~/.ssh/authorized_keys mechanism for
|
|
||||||
authentication if you encounter this problem.
|
|
||||||
|
|
||||||
=item *
|
|
||||||
|
|
||||||
If client windows fail to open, try running:
|
|
||||||
|
|
||||||
C<< cssh -e {single host name} >>
|
|
||||||
|
|
||||||
This will test the mechanisms used to open windows to hosts. This could
|
|
||||||
be due to either the C<-xrm> terminal option which enables C<AllowSendEvents>
|
|
||||||
(some terminal do not require this option, other terminals have another
|
|
||||||
method for enabling it - see your terminal documention) or the
|
|
||||||
C<ConnectTimeout> ssh option (see the configuration option C<-o> or file
|
|
||||||
C<$HOME/.clusterssh/config> below to resolve this).
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head1 OPTIONS
|
|
||||||
|
|
||||||
Some of these options may also be defined within the configuration file.
|
|
||||||
Default options are shown as appropriate.
|
|
||||||
|
|
||||||
=over
|
|
||||||
|
|
||||||
=item --action,-a '<command>'
|
|
||||||
|
|
||||||
Run the command in each session, i.e. C<-a 'vi /etc/hosts'> to drop straight
|
|
||||||
into a vi session. NOTE: not all communications methods support this (ssh
|
|
||||||
and rsh should, telnet and console will not).
|
|
||||||
|
|
||||||
=item --autoclose,-A <seconds>
|
|
||||||
|
|
||||||
Number of seconds to wait before closing finished terminal windows.
|
|
||||||
|
|
||||||
=item --autoquit,-q|--no-autoquit,-Q
|
|
||||||
|
|
||||||
Enable|Disable automatically quiting after the last client window has closed
|
|
||||||
(overriding the config file)
|
|
||||||
|
|
||||||
=item --cluster-file,-c <file>
|
|
||||||
|
|
||||||
Use supplied file as additional cluster file (see also L</"FILES">)
|
|
||||||
|
|
||||||
=item --config-file,-C <file>
|
|
||||||
|
|
||||||
Use supplied file as additional configuration file (see also L</"FILES">)
|
|
||||||
|
|
||||||
=item -d
|
|
||||||
|
|
||||||
DEPRECATED. See '--debug'.
|
|
||||||
|
|
||||||
=item -D
|
|
||||||
|
|
||||||
DEPRECATED. See '--debug'.
|
|
||||||
|
|
||||||
=item --debug [number].
|
|
||||||
|
|
||||||
Enable debugging. Either a level can be provided or the option can be
|
|
||||||
repeated multiple times. Maximum level is 4.
|
|
||||||
|
|
||||||
=item --evaluate,-e [user@]<hostname>[:port]
|
|
||||||
|
|
||||||
Display and evaluate the terminal and connection arguments so display any
|
|
||||||
potential errors. The <hostname> is required to aid the evaluation.
|
|
||||||
|
|
||||||
=item --font,-f "5x8"
|
|
||||||
|
|
||||||
Specify the font to use in the terminal windows. Use standard X font notation.
|
|
||||||
|
|
||||||
=item --help,-h|-?
|
|
||||||
|
|
||||||
Show basic help text, and exit
|
|
||||||
|
|
||||||
=item --list, -L
|
|
||||||
|
|
||||||
List available cluster tags.
|
|
||||||
|
|
||||||
=item --man,-H
|
|
||||||
|
|
||||||
Show full help test (the man page), and exit
|
|
||||||
|
|
||||||
=item --master,-M <master>
|
|
||||||
|
|
||||||
The console client program polls master as the primary server, rather than the
|
|
||||||
default set at compile time (typically ``console'').
|
|
||||||
|
|
||||||
=item --options,-o "-x -o ConnectTimeout=10" - for ssh connections
|
|
||||||
|
|
||||||
=item --options,-o "" - for rsh connections
|
|
||||||
|
|
||||||
Specify arguments to be passed to ssh or rsh when making the connection.
|
|
||||||
|
|
||||||
B<NOTE:> any "generic" change to the method (i.e. specifying the ssh port to use)
|
|
||||||
should be done in the medium's own config file (see C<ssh_config> and
|
|
||||||
F<$HOME/.ssh/config>).
|
|
||||||
|
|
||||||
=item --output-config,-u
|
|
||||||
|
|
||||||
Output the current configuration in the same format used by the
|
|
||||||
F<$HOME/.clusterssh/config> file.
|
|
||||||
|
|
||||||
=item --port,-p <port>
|
|
||||||
|
|
||||||
Specify an alternate port for connections.
|
|
||||||
|
|
||||||
=item --show-history,-s
|
|
||||||
|
|
||||||
IN BETA: Show history within console window. This code is still being
|
|
||||||
worked upon, but may help some users.
|
|
||||||
|
|
||||||
=item --tag-file,-c <file>
|
|
||||||
|
|
||||||
Use supplied file as additional tag file (see also L</"FILES">)
|
|
||||||
|
|
||||||
=item --term-args,-t ""
|
|
||||||
|
|
||||||
Specify arguments to be passed to terminals being used
|
|
||||||
|
|
||||||
=item --tile,-g|--no-tile,-G
|
|
||||||
|
|
||||||
Enable|Disable window tiling (overriding the config file)
|
|
||||||
|
|
||||||
=item --title,-T "CSSH"
|
|
||||||
|
|
||||||
Specify the initial part of the title used in the console and client windows
|
|
||||||
|
|
||||||
=item --unique-servers,-m
|
|
||||||
|
|
||||||
Connect to each host only once
|
|
||||||
|
|
||||||
=item --use_all_a_records,-A
|
|
||||||
|
|
||||||
If a hostname resolves to multiple IP addresses, toggle whether or not to
|
|
||||||
connect to all of them, or just the first one (see also config file entry)
|
|
||||||
|
|
||||||
=item --username,-l $LOGNAME
|
|
||||||
|
|
||||||
Specify the default username to use for connections (if different from the
|
|
||||||
currently logged in user). B<NOTE:> will be overridden by <user>@<host>
|
|
||||||
|
|
||||||
=item --version,-v
|
|
||||||
|
|
||||||
Show version information and exit
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head1 ARGUMENTS
|
|
||||||
|
|
||||||
The following arguments are support:
|
|
||||||
|
|
||||||
=over
|
|
||||||
|
|
||||||
=item [user@]<hostname>[:port] ...
|
|
||||||
|
|
||||||
Open an xterm to the given hostname and connect to the administration
|
|
||||||
console. An optional port number can be used if sshd is not listening
|
|
||||||
on standard port (e.g not listening on port 22) and ssh_config cannot be used.
|
|
||||||
|
|
||||||
=item <tag> ...
|
|
||||||
|
|
||||||
Open a series of xterms defined by <tag> in one of the suplimentary
|
|
||||||
configuration files (see L</"FILES">).
|
|
||||||
|
|
||||||
Note: specifying a username on a cluster tag will override any usernames
|
|
||||||
defined in the cluster
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head1 KEY SHORTCUTS
|
|
||||||
|
|
||||||
The following key shortcuts are available within the console window, and all
|
|
||||||
of them may be changed via the configuration files.
|
|
||||||
|
|
||||||
=over
|
|
||||||
|
|
||||||
=item Control-q
|
|
||||||
|
|
||||||
Quit the program and close all connections and windows
|
|
||||||
|
|
||||||
=item Control-+
|
|
||||||
|
|
||||||
Open the 'Add Host(s) or Cluster(s)' dialogue box. Mutiple host or cluster
|
|
||||||
names can be entered, separated by spaces.
|
|
||||||
|
|
||||||
=item Alt-n
|
|
||||||
|
|
||||||
Paste in the hostname part of the specific connection string to each
|
|
||||||
client, minus any username or port, i.e.
|
|
||||||
|
|
||||||
C<< scp /etc/hosts server:files/<Alt-n>.hosts >>
|
|
||||||
|
|
||||||
would replace the <Alt-n> with the client's name in each window
|
|
||||||
|
|
||||||
=item Alt-r
|
|
||||||
|
|
||||||
Retile all the client windows
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head1 EXAMPLES
|
|
||||||
|
|
||||||
=over
|
|
||||||
|
|
||||||
=item Open up a session to 3 servers
|
|
||||||
|
|
||||||
S<$ cssh server1 server2 server3>
|
|
||||||
|
|
||||||
=item Open up a session to a cluster of servers identified by the tag 'farm1'
|
|
||||||
and give the controlling window a specific title, where the cluster is defined
|
|
||||||
in one of the default configuration files
|
|
||||||
|
|
||||||
S<$ cssh -T 'Web Farm Cluster 1' farm1>
|
|
||||||
|
|
||||||
=item Connect to different servers using different login names. NOTE: this can
|
|
||||||
also be achieved by setting up appropriate options in the F<.ssh/config> file.
|
|
||||||
Do not close cssh when last terminal exits.
|
|
||||||
|
|
||||||
S<$ cssh -Q user1@server1 admin@server2>
|
|
||||||
|
|
||||||
=item Open up a cluster defined in a non-default configuration file
|
|
||||||
|
|
||||||
S<$ cssh -c $HOME/cssh.config db_cluster>
|
|
||||||
|
|
||||||
=item Use telnet on port 2022 instead of ssh
|
|
||||||
|
|
||||||
S<$ ctel -p 2022 server1 server2>
|
|
||||||
|
|
||||||
=item Use rsh instead of ssh
|
|
||||||
|
|
||||||
S<$ crsh server1 server2>
|
|
||||||
|
|
||||||
=item Use console with master as the primary server instead of ssh
|
|
||||||
|
|
||||||
S<$ ccon -M master server1 server2>
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head1 FILES
|
|
||||||
|
|
||||||
=over
|
|
||||||
|
|
||||||
=item F</etc/clusters>, F<$HOME/.clusterssh/clusters>
|
|
||||||
|
|
||||||
These files contain a list of tags to server names mappings. When any name
|
|
||||||
is used on the command line it is checked to see if it is a tag.
|
|
||||||
If it is a tag, then the tag is replaced with the list of servers. The
|
|
||||||
formated is as follows:
|
|
||||||
|
|
||||||
S<< <tag> [user@]<server> [user@]<server> [...] >>
|
|
||||||
|
|
||||||
i.e.
|
|
||||||
|
|
||||||
# List of servers in live
|
|
||||||
live admin1@server1 admin2@server2 server3 server4
|
|
||||||
|
|
||||||
All comments (marked by a #) and blank lines are ignored. Tags may be
|
|
||||||
nested, but be aware of using recursive tags as they are not checked for.
|
|
||||||
|
|
||||||
Extra cluster files may also be specified either as an option on the
|
|
||||||
command line (see C<cluster-file>) or in the users F<$HOME/.clusterssh/config>
|
|
||||||
file (see C<extra_cluster_file> configuration option).
|
|
||||||
|
|
||||||
NOTE: the last tag read overwrites any pre-existing tag of that name
|
|
||||||
|
|
||||||
NOTE: there is a special cluster tag called C<default> - any tags or hosts
|
|
||||||
included within this tag will be automatically opened if no other tags
|
|
||||||
are specified on the command line.
|
|
||||||
|
|
||||||
=item F</etc/tags>, F<$HOME/.clusterssh/tags>
|
|
||||||
|
|
||||||
Very similar to F<cluster> files but the definition is reversed. The
|
|
||||||
format is:
|
|
||||||
|
|
||||||
S<< <host> <tag> [...] >>
|
|
||||||
|
|
||||||
This allows one host to be specified as a member of a number of tags. This
|
|
||||||
format can be clearer than using F<clusters> files.
|
|
||||||
|
|
||||||
Extra tag files may be spcieid either an an option (see C<tag-file>) or within
|
|
||||||
the users F<$HOME/.clusterssh/config> file (see C<extra_tag_file>
|
|
||||||
configuration option).
|
|
||||||
|
|
||||||
NOTE: All tags are added together
|
|
||||||
|
|
||||||
=item F</etc/csshrc> & F<$HOME/.clusterssh/config>
|
|
||||||
|
|
||||||
This file contains configuration overrides - the defaults are as marked.
|
|
||||||
Default options are overwritten first by the global file, and then by the
|
|
||||||
user file.
|
|
||||||
|
|
||||||
B<NOTE:> values for entries do not need to be quoted unless it is required
|
|
||||||
for passing arguments, i.e.
|
|
||||||
|
|
||||||
terminal_allow_send_events="-xrm '*.VT100.allowSendEvents:true'"
|
|
||||||
|
|
||||||
should be written as
|
|
||||||
|
|
||||||
terminal_allow_send_events=-xrm '*.VT100.allowSendEvents:true'
|
|
||||||
|
|
||||||
=over
|
|
||||||
|
|
||||||
=item auto_close = 5
|
|
||||||
|
|
||||||
Close terminal window after this many seconds. If set to 0 will instead wait
|
|
||||||
on input from the user in each window before closing. Can be overridden
|
|
||||||
by C<-K> on the command line
|
|
||||||
|
|
||||||
=item auto_quit = yes
|
|
||||||
|
|
||||||
Automatically quit after the last client window closes. Set to anything
|
|
||||||
other than "yes" to disable. Can be overridden by C<-Q> on the command line.
|
|
||||||
|
|
||||||
=item clusters = <blank>
|
|
||||||
|
|
||||||
Define a number of cluster tags in addition to (or to replace) tags defined
|
|
||||||
in the F</etc/clusters> file. The format is:
|
|
||||||
|
|
||||||
clusters = <tag1> <tag2> <tag3>
|
|
||||||
<tag1> = host1 host2 host3
|
|
||||||
<tag2> = user@host4 user@host5 host6
|
|
||||||
<tag3> = <tag1> <tag2>
|
|
||||||
|
|
||||||
As with the F</etc/clusters> file, be sure not to create recursivly nested tags.
|
|
||||||
|
|
||||||
=item comms = ssh
|
|
||||||
|
|
||||||
Sets the default communication method (initially taken from the name of
|
|
||||||
program, but can be overridden here).
|
|
||||||
|
|
||||||
=item console_position = <null>
|
|
||||||
|
|
||||||
Set the initial position of the console - if empty then let the window manager
|
|
||||||
decide. Format is '+<x>+<y>', i.e. '+0+0' is top left hand corner of the screen,
|
|
||||||
'+0-70' is bottom left hand side of screen (more or less).
|
|
||||||
|
|
||||||
=item external_cluster_command = <null>
|
|
||||||
|
|
||||||
Define the full path to an external command that can be used to resolve tags
|
|
||||||
to host names. This command can be written in any language. The script must
|
|
||||||
accept a list of tags to resolve and output a list of hosts on a single line.
|
|
||||||
Any tags that cannot be resolved should be returned unchanged.
|
|
||||||
|
|
||||||
A non-0 exit code will be counted as an error, a warning will be printed and
|
|
||||||
output ignored.
|
|
||||||
|
|
||||||
=item extra_cluster_file = <null>
|
|
||||||
|
|
||||||
Define an extra cluster file in the format of F</etc/clusters>. Multiple
|
|
||||||
files can be specified, seperated by commas. Both ~ and $HOME are acceptable
|
|
||||||
as a to reference the users home directory, i.e.
|
|
||||||
|
|
||||||
extra_cluster_file = ~/clusters, $HOME/clus
|
|
||||||
|
|
||||||
=item ignore_host_errors
|
|
||||||
|
|
||||||
THIS OPTION IS DEPRECATED. It has been left in so current systems continue
|
|
||||||
to function as expected.
|
|
||||||
|
|
||||||
=item key_addhost = Control-Shift-plus
|
|
||||||
|
|
||||||
Default key sequence to open AddHost menu. See below notes on shortcuts.
|
|
||||||
|
|
||||||
=item key_clientname = Alt-n
|
|
||||||
|
|
||||||
Default key sequence to send cssh client names to client. See below notes
|
|
||||||
on shortcuts.
|
|
||||||
|
|
||||||
=item key_localname = Alt-l
|
|
||||||
|
|
||||||
Default key sequence to send hostname of local server to client. See below
|
|
||||||
notes on shortcuts.
|
|
||||||
|
|
||||||
=item key_paste = Control-v
|
|
||||||
|
|
||||||
Default key sequence to paste text into the console window. See below notes
|
|
||||||
on shortcuts.
|
|
||||||
|
|
||||||
=item key_quit = Control-q
|
|
||||||
|
|
||||||
Default key sequence to quit the program (will terminate all open windows).
|
|
||||||
See below notes on shortcuts.
|
|
||||||
|
|
||||||
=item key_retilehosts = Alt-r
|
|
||||||
|
|
||||||
Default key sequence to retile host windows. See below notes on shortcuts.
|
|
||||||
|
|
||||||
=item key_username = Alt-u
|
|
||||||
|
|
||||||
Default key sequence to send username to client. See below notes
|
|
||||||
on shortcuts.
|
|
||||||
|
|
||||||
=item macro_servername = %s
|
|
||||||
|
|
||||||
=item macro_hostname = %h
|
|
||||||
|
|
||||||
=item macro_username = %u
|
|
||||||
|
|
||||||
=item macro_newline = %n
|
|
||||||
|
|
||||||
=item macro_version = %v
|
|
||||||
|
|
||||||
Change the replacement macro used when either using a 'Send' menu item, or when
|
|
||||||
pasting text into the main console.
|
|
||||||
|
|
||||||
=item macros_enabled = yes
|
|
||||||
|
|
||||||
Enable or disable macro replacement. Note: this affects pasting into the
|
|
||||||
main console, items on the 'Send' menu and key_clientname, key_localname, key_servername and key_username.
|
|
||||||
|
|
||||||
=item max_addhost_menu_cluster_items = 6
|
|
||||||
|
|
||||||
Maximum number of entries in the 'Add Host' menu cluster list before
|
|
||||||
scrollbars are used
|
|
||||||
|
|
||||||
=item max_host_menu_items = 30
|
|
||||||
|
|
||||||
Maximum number of hosts to put into the host menu before starting a new column
|
|
||||||
|
|
||||||
=item menu_host_autotearoff = 0
|
|
||||||
|
|
||||||
=item menu_send_autotearoff = 0
|
|
||||||
|
|
||||||
When set to non-0 will automatically tear-off the host or send menu at
|
|
||||||
program start
|
|
||||||
|
|
||||||
=item mouse_paste = Button-2 (middle mouse button)
|
|
||||||
|
|
||||||
Default key sequence to paste text into the console window using the mouse.
|
|
||||||
See below notes on shortcuts.
|
|
||||||
|
|
||||||
=item rsh = rsh
|
|
||||||
|
|
||||||
=item ssh = ssh
|
|
||||||
|
|
||||||
=item telnet = telnet
|
|
||||||
|
|
||||||
Set the path to the specific binary to use for the communication method, else
|
|
||||||
uses the first match found in $PATH
|
|
||||||
|
|
||||||
=item rsh_args = <blank>
|
|
||||||
|
|
||||||
=item ssh_args = "-x -o ConnectTimeout=10"
|
|
||||||
|
|
||||||
=item telnet_args = <blank>
|
|
||||||
|
|
||||||
Sets any arguments to be used with the communication method (defaults to ssh
|
|
||||||
arguments).
|
|
||||||
|
|
||||||
B<NOTE:> The given defaults are based on OpenSSH, not commercial ssh software.
|
|
||||||
|
|
||||||
B<NOTE:> Any "generic" change to the method (i.e. specifying the ssh port to use)
|
|
||||||
should be done in the medium's own config file (see C<ssh_config> and
|
|
||||||
F<$HOME/.ssh/config>).
|
|
||||||
|
|
||||||
=item screen_reserve_top = 0
|
|
||||||
|
|
||||||
=item screen_reserve_bottom = 60
|
|
||||||
|
|
||||||
=item screen_reserve_left = 0
|
|
||||||
|
|
||||||
=item screen_reserve_right = 0
|
|
||||||
|
|
||||||
Number of pixels from the screen side to reserve when calculating screen
|
|
||||||
geometry for tiling. Setting this to something like 50 will help keep cssh
|
|
||||||
from positioning windows over your window manager's menu bar if it draws one
|
|
||||||
at that side of the screen.
|
|
||||||
|
|
||||||
=item rsh = /path/to/rsh
|
|
||||||
|
|
||||||
=item ssh = /path/to/ssh
|
|
||||||
|
|
||||||
Depending on the value of comms, set the path of the communication binary.
|
|
||||||
|
|
||||||
=item terminal = /path/to/terminal
|
|
||||||
|
|
||||||
Path to the x-windows terminal used for the client.
|
|
||||||
|
|
||||||
=item terminal_args = <blank>
|
|
||||||
|
|
||||||
Arguments to use when opening terminal windows. Otherwise takes defaults
|
|
||||||
from F<$HOME/.Xdefaults> or $<$HOME/.Xresources> file.
|
|
||||||
|
|
||||||
=item terminal_font = 6x13
|
|
||||||
|
|
||||||
Font to use in the terminal windows. Use standard X font notation.
|
|
||||||
|
|
||||||
=item terminal_reserve_top = 5
|
|
||||||
|
|
||||||
=item terminal_reserve_bottom = 0
|
|
||||||
|
|
||||||
=item terminal_reserve_left = 5
|
|
||||||
|
|
||||||
=item terminal_reserve_right = 0
|
|
||||||
|
|
||||||
Number of pixels from the terminal side to reserve when calculating screen
|
|
||||||
geometry for tiling. Setting these will help keep cssh from positioning
|
|
||||||
windows over your scroll and title bars or otherwise overlapping the windows
|
|
||||||
too much.
|
|
||||||
|
|
||||||
=item terminal_colorize = 1
|
|
||||||
|
|
||||||
If set to 1 (the default), then "-bg" and "-fg" arguments will be added
|
|
||||||
to the terminal invocation command-line. The terminal will be colored
|
|
||||||
in a pseudo-random way based on the host name; while the color of a terminal
|
|
||||||
is not easily predicted, it will always be the same color for a given host
|
|
||||||
name. After a while, you will recognize hosts by their characteristic
|
|
||||||
terminal color.
|
|
||||||
|
|
||||||
=item terminal_bg_style = dark
|
|
||||||
|
|
||||||
If set to dark, the the terminal background will be set to black and
|
|
||||||
the foreground to the pseudo-random color. If set to light, then the
|
|
||||||
foreground will be black and the background the pseudo-random color. If
|
|
||||||
terminal_colorize is zero, then this option has no effect.
|
|
||||||
|
|
||||||
=item terminal_size = 80x24
|
|
||||||
|
|
||||||
Initial size of terminals to use (note: the number of lines (24) will be
|
|
||||||
decreased when resizing terminals for tiling, not the number of characters (80))
|
|
||||||
|
|
||||||
=item terminal_title_opt = -T
|
|
||||||
|
|
||||||
Option used with C<terminal> to set the title of the window
|
|
||||||
|
|
||||||
=item terminal_allow_send_events = -xrm '*.VT100.allowSendEvents:true'
|
|
||||||
|
|
||||||
Option required by the terminal to allow XSendEvents to be received
|
|
||||||
|
|
||||||
=item title = cssh
|
|
||||||
|
|
||||||
Title of windows to use for both the console and terminals.
|
|
||||||
|
|
||||||
=item unmap_on_redraw = no
|
|
||||||
|
|
||||||
Tell Tk to use the UnmapWindow request before redrawing terminal windows.
|
|
||||||
This defaults to "no" as it causes some problems with the FVWM window
|
|
||||||
manager. If you are experiencing problems with redraws, you can set it to
|
|
||||||
"yes" to allow the window to be unmapped before it is repositioned.
|
|
||||||
|
|
||||||
=item use_all_a_records = no
|
|
||||||
|
|
||||||
If a hostname resolves to multiple IP addresses, set to C<yes> to connect
|
|
||||||
to all of them, not just the first one found.
|
|
||||||
|
|
||||||
=item use_hotkeys = yes
|
|
||||||
|
|
||||||
Setting to anything other than C<yes> will disable all hotkeys.
|
|
||||||
|
|
||||||
=item user = $LOGNAME
|
|
||||||
|
|
||||||
Sets the default user for running commands on clients.
|
|
||||||
|
|
||||||
=item window_tiling = yes
|
|
||||||
|
|
||||||
Perform window tiling (set to C<no> to disable)
|
|
||||||
|
|
||||||
=item window_tiling_direction = right
|
|
||||||
|
|
||||||
Direction to tile windows, where "right" means starting top left and moving
|
|
||||||
right and then down, and anything else means starting bottom right and moving
|
|
||||||
left and then up
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
B<NOTE:> The key shortcut modifiers must be in the form "Control", "Alt", or
|
|
||||||
"Shift", i.e. with the first letter capitalised and the rest lower case. Keys
|
|
||||||
may also be disabled individually by setting to the word "null".
|
|
||||||
|
|
||||||
=item F<$HOME/.csshrc_send_menu>
|
|
||||||
|
|
||||||
This (optional) file contains items to populate the send menu. The
|
|
||||||
default entry could be written as:
|
|
||||||
|
|
||||||
<send_menu>
|
|
||||||
<menu title="Use Macros">
|
|
||||||
<toggle/>
|
|
||||||
<accelerator>ALT-p</accelerator>
|
|
||||||
</dmenu>
|
|
||||||
<menu title="Remote Hostname">
|
|
||||||
<command>%s</command>
|
|
||||||
<accelerator>ALT-n</accelerator>
|
|
||||||
</menu>
|
|
||||||
<menu title="Local Hostname">
|
|
||||||
<command>%s</command>
|
|
||||||
<accelerator>ALT-l</accelerator>
|
|
||||||
</menu>
|
|
||||||
<menu title="Username">
|
|
||||||
<command>%u</command>
|
|
||||||
<accelerator>ALT-u</accelerator>
|
|
||||||
</menu>
|
|
||||||
<menu title="Test Text">
|
|
||||||
<command>echo "ClusterSSH Version: %v%n</command>
|
|
||||||
</menu>
|
|
||||||
</send_menu>
|
|
||||||
|
|
||||||
Submenus can also be specified as follows:
|
|
||||||
|
|
||||||
<send_menu>
|
|
||||||
<menu title="Default Entries">
|
|
||||||
<detach>yes</detach>
|
|
||||||
<menu title="Hostname">
|
|
||||||
<command>%s</command>
|
|
||||||
<accelerator>ALT-n</accelerator>
|
|
||||||
</menu>
|
|
||||||
</menu>
|
|
||||||
</send_menu>
|
|
||||||
|
|
||||||
B<Caveats:>
|
|
||||||
|
|
||||||
=over 4
|
|
||||||
|
|
||||||
=item There is currently no strict format checking of this file.
|
|
||||||
|
|
||||||
=item The format of the file may change in the future
|
|
||||||
|
|
||||||
=item If the file exists the default entry (Hostname) is not added
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
The following replacement macros are available (note: these can be changed in the configuration file):
|
|
||||||
|
|
||||||
=over 4
|
|
||||||
|
|
||||||
=item %s
|
|
||||||
|
|
||||||
Hostname part of the specific connection string to each client, minus any
|
|
||||||
username or port
|
|
||||||
|
|
||||||
=item %u
|
|
||||||
|
|
||||||
Username part of the connection string to each client
|
|
||||||
|
|
||||||
=item %h
|
|
||||||
|
|
||||||
Hostname of server where cssh is being run from
|
|
||||||
|
|
||||||
=item %n
|
|
||||||
|
|
||||||
<RETURN> code
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
B<NOTE:> requires L<XML::Simple> to be installed
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head1 KNOWN BUGS
|
|
||||||
|
|
||||||
=over 4
|
|
||||||
|
|
||||||
=item 1.
|
|
||||||
|
|
||||||
Catering for IPv6 addresses is minimal. This is due to a conflict
|
|
||||||
between IPv6 addresses and port numbers within the same
|
|
||||||
server definition since they both use the same seperator, i.e. is the
|
|
||||||
following just an IPv6 address, or an address + port number of 2323?
|
|
||||||
|
|
||||||
2001:db8::1428:2323
|
|
||||||
|
|
||||||
Exactly - I cannot tell either. the IPv6 address without a port is assumed
|
|
||||||
in those cases where it cannot be determined and a warning is issued.
|
|
||||||
|
|
||||||
Possible work arounds include:
|
|
||||||
|
|
||||||
=over 4
|
|
||||||
|
|
||||||
=item a.
|
|
||||||
|
|
||||||
Use square brackets around the IPv6 address, i.e.
|
|
||||||
[2001:db8::1428]:2323
|
|
||||||
or
|
|
||||||
[2001:db8::1428:2323]
|
|
||||||
as appropriate so there is no ambiguity
|
|
||||||
|
|
||||||
=item b.
|
|
||||||
|
|
||||||
Use the full IPv6 address if also using a port number - the 8th colon
|
|
||||||
is assumed to be the port seperator.
|
|
||||||
|
|
||||||
=item c.
|
|
||||||
|
|
||||||
Define the IPv6 address in your /etc/hosts file, DNS or other name service
|
|
||||||
lookup mechanism and use the hostname instead of the address.
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=item 2.
|
|
||||||
|
|
||||||
Swapping virtual desktops can a redraw of all the terminal windows. This
|
|
||||||
is due to a lack of distinction within Tk between switching desktops and
|
|
||||||
minimising/maximising windows. Until Tk can tell the difference between the
|
|
||||||
two events, there is no fix (apart from rewriting everything directly in X)
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
Anyone with any good ideas to fix the above bugs is more than welcome to get
|
|
||||||
in touch and/or provide a patch.
|
|
||||||
|
|
||||||
=head1 REPORTING BUGS
|
|
||||||
|
|
||||||
=over 2
|
|
||||||
|
|
||||||
=item *
|
|
||||||
|
|
||||||
If you have issues running cssh, first try:
|
|
||||||
|
|
||||||
C<< cssh -e [user@]<hostname>[:port] >>
|
|
||||||
|
|
||||||
This performs two tests to confirm cssh is able to work properly with the
|
|
||||||
settings provided within the F<$HOME/.clusterssh/config> file (or internal defaults).
|
|
||||||
|
|
||||||
1. test the terminal window works with the options provided
|
|
||||||
|
|
||||||
2. test ssh works to a host with the configured arguments
|
|
||||||
|
|
||||||
Configuration options to watch for in ssh are
|
|
||||||
|
|
||||||
- Doesnt understand "-o ConnectTimeout=10" - remove the option
|
|
||||||
in the F<$HOME/.clusterssh/config> file
|
|
||||||
|
|
||||||
- OpenSSH-3.8 using untrusted ssh tunnels - use "-Y" instead of "-X"
|
|
||||||
or use "ForwardX11Trusted yes' in ssh_config (if you change the
|
|
||||||
default ssh options from -x to -X)
|
|
||||||
|
|
||||||
=item *
|
|
||||||
|
|
||||||
If you require support, please run the following commands
|
|
||||||
and post it on the web site in the support/problems forum:
|
|
||||||
|
|
||||||
C<< perl -V >>
|
|
||||||
|
|
||||||
C<< perl -MTk -e 'print $Tk::VERSION,$/' >>
|
|
||||||
|
|
||||||
C<< perl -MX11::Protocol -e 'print $X11::Protocol::VERSION,$/' >>
|
|
||||||
|
|
||||||
C<< cat /etc/csshrc $HOME/.clusterssh/config >>
|
|
||||||
|
|
||||||
=item *
|
|
||||||
|
|
||||||
Use the debug switches (-d, -D, or -dD) will turn on debugging output.
|
|
||||||
However, please only use this option with one host at a time,
|
|
||||||
i.e. "cssh -d <host>" due to the amount of output produced (in both main
|
|
||||||
and child windows).
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head1 SEE ALSO
|
|
||||||
|
|
||||||
L<http://clusterssh.sourceforge.net/>,
|
|
||||||
C<ssh>,
|
|
||||||
L<Tk::overview>,
|
|
||||||
L<X11::Protocol>,
|
|
||||||
C<perl>
|
|
||||||
|
|
||||||
=head1 CREDITS
|
|
||||||
|
|
||||||
A web site for comments, requests, bug reports and bug fixes/patches is
|
|
||||||
available at L<http://clusterssh.sourceforge.net/>
|
|
||||||
|
|
||||||
=head1 AUTHOR
|
|
||||||
|
|
||||||
Duncan Ferguson, C<< <duncan_j_ferguson at yahoo.co.uk> >>
|
|
||||||
|
|
||||||
=head1 LICENSE AND COPYRIGHT
|
|
||||||
|
|
||||||
Copyright 1999-2010 Duncan Ferguson.
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms of either: the GNU General Public License as published
|
|
||||||
by the Free Software Foundation; or the Artistic License.
|
|
||||||
|
|
||||||
See http://dev.perl.org/licenses/ for more information.
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
1;
|
|
1
bin/ctel
1
bin/ctel
|
@ -1 +0,0 @@
|
||||||
cssh
|
|
47
bin_PL/_build_docs
Executable file
47
bin_PL/_build_docs
Executable file
|
@ -0,0 +1,47 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
use 5.008.004;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use FindBin qw($Bin $Script);
|
||||||
|
use File::Basename;
|
||||||
|
|
||||||
|
my $bindir = "bin";
|
||||||
|
|
||||||
|
if ( !-d $bindir ) {
|
||||||
|
mkdir $bindir || die "Could not mkdir $bindir: $!";
|
||||||
|
}
|
||||||
|
|
||||||
|
print "Using perl binary: $^X", $/;
|
||||||
|
print "Using perl version $^V", $/;
|
||||||
|
|
||||||
|
for my $dest (@ARGV) {
|
||||||
|
my $source = $Bin . '/' . basename($dest);
|
||||||
|
|
||||||
|
next if ( $source =~ m/$Script/ );
|
||||||
|
next if ( $source =~ m/\.x$/ );
|
||||||
|
|
||||||
|
print "Generating: $source", $/;
|
||||||
|
|
||||||
|
if ( -f $dest ) {
|
||||||
|
chmod( 0755, $dest ) || die "Could not chmod $dest for removing: $!";
|
||||||
|
}
|
||||||
|
|
||||||
|
open( my $sfh, '<', $source )
|
||||||
|
|| die "Could not open $source for reading: $!";
|
||||||
|
open( my $dfh, '>', $dest ) || die "Could not open $dest for writing: $!";
|
||||||
|
print $dfh $_ while (<$sfh>);
|
||||||
|
close($sfh);
|
||||||
|
|
||||||
|
if ( $source !~ m/clusterssh_bash_completion.dist/ ) {
|
||||||
|
print $dfh "\n\n__END__\n\n";
|
||||||
|
|
||||||
|
my $pod = qx{ $^X $source --generate-pod };
|
||||||
|
die "Failed to generate pod" if ($?);
|
||||||
|
print $dfh $pod;
|
||||||
|
}
|
||||||
|
|
||||||
|
close($dfh);
|
||||||
|
|
||||||
|
chmod( 0555, $dest ) || die "Could not chmod $dest: $!";
|
||||||
|
}
|
25
bin_PL/ccon
Executable file
25
bin_PL/ccon
Executable file
|
@ -0,0 +1,25 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
use 5.008.004;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use FindBin;
|
||||||
|
use lib $FindBin::Bin. '/../lib';
|
||||||
|
use lib $FindBin::Bin. '/../lib/perl5';
|
||||||
|
use App::ClusterSSH;
|
||||||
|
|
||||||
|
my $app = App::ClusterSSH->new();
|
||||||
|
|
||||||
|
#$app->options->add_common_ssh_options;
|
||||||
|
#$app->options->add_common_session_options;
|
||||||
|
|
||||||
|
$app->add_option(
|
||||||
|
spec => 'master|M=s',
|
||||||
|
help => $app->loc(
|
||||||
|
"The console client program polls master as the primary server, rather than the default set at compile time (typically ``console'')."
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
$app->run();
|
||||||
|
|
||||||
|
1;
|
70
bin_PL/clusterssh_bash_completion.dist
Normal file
70
bin_PL/clusterssh_bash_completion.dist
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
# -*- mode: shell-script; sh-basic-offset: 8; indent-tabs-mode: t -*-
|
||||||
|
# ex: ts=8 sw=8 noet filetype=sh
|
||||||
|
#
|
||||||
|
# cssh(1) completion by Aaron Spettl <aaron@spettl.de>, adapted from the
|
||||||
|
# Debian GNU/Linux dput(1) completion by Roland Mas <lolando@debian.org>
|
||||||
|
#
|
||||||
|
# On Debian (and Debian based distributions) drop this file into
|
||||||
|
# /etc/bash_completion.d
|
||||||
|
# and source the /etc/bash_completion script - or just restart bash.
|
||||||
|
|
||||||
|
_cssh ()
|
||||||
|
{
|
||||||
|
local cur prev options paroptions clusters extra_cluster_file_line clusters_line extra_cluster_file
|
||||||
|
|
||||||
|
COMPREPLY=()
|
||||||
|
cur=${COMP_WORDS[COMP_CWORD]}
|
||||||
|
prev=${COMP_WORDS[COMP_CWORD-1]}
|
||||||
|
|
||||||
|
# all options understood by cssh
|
||||||
|
options='-c --cluster-file -C --config-file --debug -e --evaluate \
|
||||||
|
-g --tile -G --no-tile -h --help -H --man -l --username \
|
||||||
|
-o --options -p --port -q --autoquit -Q --no-autoquit \
|
||||||
|
-s --show-history -t --term-args -T --title \
|
||||||
|
-u --output-config -v --version'
|
||||||
|
|
||||||
|
# find the extra cluster file line in the .clusterssh/config or, alternatively, /etc/csshrc
|
||||||
|
extra_cluster_file_line="`grep '^[[:space:]]*extra_cluster_file' $HOME/.clusterssh/config 2> /dev/null`"
|
||||||
|
[ -z "$extra_cluster_file_line" ] && extra_cluster_file_line="`grep '^[[:space:]]*extra_cluster_file' /etc/csshrc 2> /dev/null`"
|
||||||
|
|
||||||
|
# find the clusters line in the .csshrc or, alternatively, /etc/csshrc
|
||||||
|
clusters_line="`grep '^[[:space:]]*clusters' $HOME/.clusterssh/config 2> /dev/null`"
|
||||||
|
[ -z "$clusters_line" ] && clusters_line="`grep '^[[:space:]]*clusters' /etc/csshrc 2> /dev/null`"
|
||||||
|
|
||||||
|
# extract the location of the extra cluster file
|
||||||
|
extra_cluster_file="`echo $extra_cluster_file_line | cut -f 2- -d '='`"
|
||||||
|
[ -n "$extra_cluster_file" ] && extra_cluster_file="`eval echo $extra_cluster_file`"
|
||||||
|
# TODO: don't use eval to expand ~ and $HOME
|
||||||
|
|
||||||
|
# get the names of all defined clusters
|
||||||
|
clusters=$(
|
||||||
|
{
|
||||||
|
[ -n "$clusters_line" ] && echo "$clusters_line" | cut -f 2- -d '=' | tr "$IFS" "\n" || /bin/true
|
||||||
|
[ -n "$extra_cluster_file" ] && sed -e 's/^\([a-z0-9.-]\+\).*$/\1/i' "$extra_cluster_file" 2> /dev/null || /bin/true
|
||||||
|
sed -e 's/^\([a-z0-9.-]\+\).*$/\1/i' /etc/clusters 2> /dev/null || /bin/true
|
||||||
|
sed -e 's/^\([a-z0-9.-]\+\).*$/\1/i' $HOME/.clusterssh/clusters 2> /dev/null || /bin/true
|
||||||
|
} | sort -u)
|
||||||
|
|
||||||
|
# use options and clusters for tab completion, except there isn't yet
|
||||||
|
# at least one character to filter by
|
||||||
|
# reason: don't show options if the user types "cssh <tab><tab>"
|
||||||
|
paroptions="$clusters"
|
||||||
|
[ -n "$cur" ] && paroptions="$paroptions $options"
|
||||||
|
|
||||||
|
case $prev in
|
||||||
|
--cluster-file|-c|--config-file|-C)
|
||||||
|
COMPREPLY=( $( compgen -o filenames -G "$cur*" ) )
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
COMPREPLY=()
|
||||||
|
|
||||||
|
# also use ssh hosts for tab completion if function _known_hosts is present
|
||||||
|
[ "`type -t _known_hosts`" = "function" ] && _known_hosts -a
|
||||||
|
|
||||||
|
COMPREPLY=( "${COMPREPLY[@]}" $( compgen -W "$paroptions" | grep "^$cur") )
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
return 0
|
||||||
|
} &&
|
||||||
|
complete -F _cssh cssh crsh ctel
|
17
bin_PL/crsh
Executable file
17
bin_PL/crsh
Executable file
|
@ -0,0 +1,17 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
use 5.008.004;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use FindBin;
|
||||||
|
use lib $FindBin::Bin. '/../lib';
|
||||||
|
use lib $FindBin::Bin. '/../lib/perl5';
|
||||||
|
use App::ClusterSSH;
|
||||||
|
|
||||||
|
my $app = App::ClusterSSH->new();
|
||||||
|
|
||||||
|
$app->options->add_common_ssh_options;
|
||||||
|
$app->options->add_common_session_options;
|
||||||
|
$app->run();
|
||||||
|
|
||||||
|
1;
|
2
bin/cscp → bin_PL/cscp.x
Executable file → Normal file
2
bin/cscp → bin_PL/cscp.x
Executable file → Normal file
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
#LICENSE: Gnu GPL version 2
|
#LICENSE: GNU GPL version 2
|
||||||
#Author: JT Moree: moreejt@pcxperience.com
|
#Author: JT Moree: moreejt@pcxperience.com
|
||||||
#Copyright: Kahala Corp. 2006
|
#Copyright: Kahala Corp. 2006
|
||||||
#Date: 20061213
|
#Date: 20061213
|
17
bin_PL/csftp
Executable file
17
bin_PL/csftp
Executable file
|
@ -0,0 +1,17 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
use 5.008.004;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use FindBin;
|
||||||
|
use lib $FindBin::Bin. '/../lib';
|
||||||
|
use lib $FindBin::Bin. '/../lib/perl5';
|
||||||
|
use App::ClusterSSH;
|
||||||
|
|
||||||
|
my $app = App::ClusterSSH->new();
|
||||||
|
|
||||||
|
$app->options->add_common_ssh_options;
|
||||||
|
$app->options->add_common_session_options;
|
||||||
|
$app->run();
|
||||||
|
|
||||||
|
1;
|
17
bin_PL/cssh
Executable file
17
bin_PL/cssh
Executable file
|
@ -0,0 +1,17 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
use 5.008.004;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use FindBin;
|
||||||
|
use lib $FindBin::Bin. '/../lib';
|
||||||
|
use lib $FindBin::Bin. '/../lib/perl5';
|
||||||
|
use App::ClusterSSH;
|
||||||
|
|
||||||
|
my $app = App::ClusterSSH->new();
|
||||||
|
|
||||||
|
$app->options->add_common_ssh_options;
|
||||||
|
$app->options->add_common_session_options;
|
||||||
|
$app->run();
|
||||||
|
|
||||||
|
1;
|
13
bin_PL/ctel
Executable file
13
bin_PL/ctel
Executable file
|
@ -0,0 +1,13 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
use 5.008.004;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use FindBin;
|
||||||
|
use lib $FindBin::Bin. '/../lib';
|
||||||
|
use lib $FindBin::Bin. '/../lib/perl5';
|
||||||
|
use App::ClusterSSH;
|
||||||
|
|
||||||
|
my $app = App::ClusterSSH->new();
|
||||||
|
|
||||||
|
$app->run();
|
74
dist.ini
Normal file
74
dist.ini
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
name = App-ClusterSSH
|
||||||
|
author = Duncan Ferguson <duncan_j_ferguson@yahoo.co.uk>
|
||||||
|
license = Perl_5
|
||||||
|
copyright_holder = Duncan Ferguson
|
||||||
|
copyright_year = 2018
|
||||||
|
|
||||||
|
[Git::Check]
|
||||||
|
|
||||||
|
[GatherDir]
|
||||||
|
[MetaYAML]
|
||||||
|
[ModuleBuild::Custom]
|
||||||
|
mb_class = App::ClusterSSH:Build
|
||||||
|
|
||||||
|
[InstallGuide]
|
||||||
|
[License]
|
||||||
|
[PruneCruft]
|
||||||
|
[PruneFiles]
|
||||||
|
match = ^bin/
|
||||||
|
match = \.bak$
|
||||||
|
match = ^Build\.PL\.
|
||||||
|
|
||||||
|
[ManifestSkip]
|
||||||
|
[Manifest]
|
||||||
|
[TestRelease]
|
||||||
|
[ConfirmRelease]
|
||||||
|
[UploadToCPAN]
|
||||||
|
|
||||||
|
; for later
|
||||||
|
;[Twitter]
|
||||||
|
[EmailNotify]
|
||||||
|
to = duncan_j_ferguson@yahoo.co.uk
|
||||||
|
from = duncan_j_ferguson@yahoo.co.uk
|
||||||
|
|
||||||
|
[CheckChangeLog]
|
||||||
|
|
||||||
|
[PerlTidy]
|
||||||
|
perltidyrc = t/perltidyrc
|
||||||
|
|
||||||
|
; Need to decide how to do this automatically at some point
|
||||||
|
[VersionFromModule]
|
||||||
|
;[Git::NextVersion]
|
||||||
|
;[AutoVersion]
|
||||||
|
[AutoPrereqs]
|
||||||
|
[PkgVersion]
|
||||||
|
[NextRelease]
|
||||||
|
[Git::Commit]
|
||||||
|
[Git::Tag]
|
||||||
|
[Git::Push]
|
||||||
|
|
||||||
|
; optional prereqs - only used if they are installed
|
||||||
|
[Prereqs / RuntimeRecommends]
|
||||||
|
Sort::Naturally = 1.03
|
||||||
|
|
||||||
|
; Author prereqs
|
||||||
|
; authordep Pod::Coverage::TrustPod
|
||||||
|
; authordep Test::CPAN::Changes
|
||||||
|
|
||||||
|
[MetaResources]
|
||||||
|
homepage = http://github.com/duncs/clusterssh/wiki
|
||||||
|
bugtracker.web = https://github.com/duncs/clusterssh/issues
|
||||||
|
repository.web = http://github.com/duncs/clusterssh
|
||||||
|
repository.type = git
|
||||||
|
; these two custom ones cause errors
|
||||||
|
;Ci.web = https://travis-ci.org/duncs/clusterssh
|
||||||
|
;Coverage.web = https://coveralls.io/github/duncs/clusterssh
|
||||||
|
|
||||||
|
[ExtraTests]
|
||||||
|
; Disabled for the moment
|
||||||
|
;[Test::Perl::Critic]
|
||||||
|
[PodCoverageTests]
|
||||||
|
[PodSyntaxTests]
|
||||||
|
|
||||||
|
[Run::BeforeBuild]
|
||||||
|
run = bin_PL/cssh --generate-pod | pod2text > README
|
File diff suppressed because it is too large
Load diff
|
@ -1,24 +1,45 @@
|
||||||
package App::ClusterSSH::Base;
|
|
||||||
|
|
||||||
use warnings;
|
use warnings;
|
||||||
use strict;
|
use strict;
|
||||||
|
|
||||||
|
package App::ClusterSSH::Base;
|
||||||
|
|
||||||
|
# ABSTRACT: App::ClusterSSH::Base - Base object provding utility functions
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
use base qw/ App::ClusterSSH::Base /;
|
||||||
|
|
||||||
|
# in object new method
|
||||||
|
sub new {
|
||||||
|
( $class, $arg_ref ) = @_;
|
||||||
|
my $self = $class->SUPER::new($arg_ref);
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
Base object to provide some utility functions on objects - should not be
|
||||||
|
used directly
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
use Carp;
|
use Carp;
|
||||||
use App::ClusterSSH::L10N;
|
use App::ClusterSSH::L10N;
|
||||||
|
|
||||||
use Exception::Class (
|
use Module::Load;
|
||||||
|
|
||||||
|
use Exception::Class 1.31 (
|
||||||
'App::ClusterSSH::Exception',
|
'App::ClusterSSH::Exception',
|
||||||
'App::ClusterSSH::Exception::Config' => {
|
'App::ClusterSSH::Exception::Config' => {
|
||||||
fields => 'unknown_config',
|
fields => 'unknown_config',
|
||||||
},
|
},
|
||||||
'App::ClusterSSH::Exception::Cluster',
|
'App::ClusterSSH::Exception::Cluster',
|
||||||
'App::ClusterSSH::Exception::LoadFile',
|
'App::ClusterSSH::Exception::LoadFile',
|
||||||
|
'App::ClusterSSH::Exception::Helper',
|
||||||
|
'App::ClusterSSH::Exception::Getopt',
|
||||||
);
|
);
|
||||||
|
|
||||||
# Dont use SVN revision as it can cause problems
|
my $debug_level = $ENV{CLUSTERSSH_DEBUG} || 0;
|
||||||
use version;
|
|
||||||
our $VERSION = version->new('0.02');
|
|
||||||
|
|
||||||
my $debug_level = 4;
|
|
||||||
our $language = 'en';
|
our $language = 'en';
|
||||||
our $language_handle;
|
our $language_handle;
|
||||||
our $app_configuration;
|
our $app_configuration;
|
||||||
|
@ -27,14 +48,13 @@ sub new {
|
||||||
my ( $class, %args ) = @_;
|
my ( $class, %args ) = @_;
|
||||||
|
|
||||||
my $config = {
|
my $config = {
|
||||||
lang => 'en',
|
lang => 'en',
|
||||||
debug => 0,
|
|
||||||
%args,
|
%args,
|
||||||
};
|
};
|
||||||
|
|
||||||
my $self = bless $config, $class;
|
my $self = bless $config, $class;
|
||||||
|
|
||||||
$self->set_debug_level( $config->{debug} );
|
$self->set_debug_level( $config->{debug} ) if ( $config->{debug} );
|
||||||
$self->set_lang( $config->{lang} );
|
$self->set_lang( $config->{lang} );
|
||||||
|
|
||||||
$self->debug(
|
$self->debug(
|
||||||
|
@ -85,10 +105,7 @@ sub loc {
|
||||||
|
|
||||||
sub set_lang {
|
sub set_lang {
|
||||||
my ( $self, $lang ) = @_;
|
my ( $self, $lang ) = @_;
|
||||||
$language = $lang;
|
$self->debug( 6, $self->loc( 'Setting language to "[_1]"', $lang ), );
|
||||||
if ($self) {
|
|
||||||
$self->debug( 6, $self->loc( 'Setting language to "[_1]"', $lang ), );
|
|
||||||
}
|
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +130,7 @@ sub debug_level {
|
||||||
return $debug_level;
|
return $debug_level;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub output {
|
sub stdout_output {
|
||||||
my ( $self, @text ) = @_;
|
my ( $self, @text ) = @_;
|
||||||
print @text, $/;
|
print @text, $/;
|
||||||
return $self;
|
return $self;
|
||||||
|
@ -122,7 +139,7 @@ sub output {
|
||||||
sub debug {
|
sub debug {
|
||||||
my ( $self, $level, @text ) = @_;
|
my ( $self, $level, @text ) = @_;
|
||||||
if ( $level <= $debug_level ) {
|
if ( $level <= $debug_level ) {
|
||||||
$self->output(@text);
|
$self->stdout_output(@text);
|
||||||
}
|
}
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
@ -144,9 +161,21 @@ sub config {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $self->{parent}->{config}
|
||||||
|
if $self->{parent}
|
||||||
|
&& ref $self->{parent} eq "HASH"
|
||||||
|
&& $self->{parent}->{config};
|
||||||
|
|
||||||
return $app_configuration;
|
return $app_configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub options {
|
||||||
|
my ($self) = @_;
|
||||||
|
return $self->{parent}->{options}
|
||||||
|
if $self->{parent} && $self->{parent}->{options};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
sub set_config {
|
sub set_config {
|
||||||
my ( $self, $config ) = @_;
|
my ( $self, $config ) = @_;
|
||||||
|
|
||||||
|
@ -184,10 +213,10 @@ sub load_file {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !$args{type} || $args{type} !~ m/cluster|config/ ) {
|
if ( !$args{type} ) {
|
||||||
croak(
|
croak(
|
||||||
App::ClusterSSH::Exception->throw(
|
App::ClusterSSH::Exception->throw(
|
||||||
error => '"type" arg invalid'
|
error => '"type" arg not passed'
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -267,29 +296,38 @@ sub load_file {
|
||||||
return %results;
|
return %results;
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
sub parent {
|
||||||
|
my ($self) = @_;
|
||||||
|
return $self->{parent};
|
||||||
|
}
|
||||||
|
|
||||||
=pod
|
sub sort {
|
||||||
|
my $self = shift;
|
||||||
|
|
||||||
=head1 NAME
|
# if the user has asked for natural sorting we need to include an extra
|
||||||
|
# module
|
||||||
|
my $config = $self->config();
|
||||||
|
|
||||||
App::ClusterSSH::Base - Base object provding utility functions
|
# Make sure the configuration object has been set correctly before
|
||||||
|
# referencing anything
|
||||||
=head1 SYNOPSIS
|
if ( ref $config eq "HASH" && $config->{'use_natural_sort'} ) {
|
||||||
|
eval { Module::Load::load('Sort::Naturally'); };
|
||||||
use base qw/ App::ClusterSSH::Base /;
|
if ($@) {
|
||||||
|
warn(
|
||||||
# in object new method
|
"natural sorting requested but unable to load Sort::Naturally: $@\n"
|
||||||
sub new {
|
);
|
||||||
( $class, $arg_ref ) = @_;
|
}
|
||||||
my $self = $class->SUPER::new($arg_ref);
|
else {
|
||||||
return $self;
|
my $sort = sub { Sort::Naturally::nsort(@_) };
|
||||||
|
return $sort;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
my $sort = sub { sort @_ };
|
||||||
|
return $sort;
|
||||||
|
}
|
||||||
|
|
||||||
Base object to provide some utility functions on objects - should not be
|
1;
|
||||||
used directly
|
|
||||||
|
|
||||||
=head1 METHODS
|
=head1 METHODS
|
||||||
|
|
||||||
|
@ -331,10 +369,19 @@ Using the App::ClusterSSH/L10N/{lang}.pm module convert the given text to
|
||||||
appropriate language. See L<App::ClusterSSH::L10N> for more details. Essentially
|
appropriate language. See L<App::ClusterSSH::L10N> for more details. Essentially
|
||||||
a wrapper to maketext in Locale::Maketext
|
a wrapper to maketext in Locale::Maketext
|
||||||
|
|
||||||
=item $obj->output(@);
|
=item $obj->stdout_output(@);
|
||||||
|
|
||||||
Output text on STDOUT.
|
Output text on STDOUT.
|
||||||
|
|
||||||
|
=item $obj->parent;
|
||||||
|
|
||||||
|
Returned the object that is the parent of this one, if it was set when the
|
||||||
|
object was created
|
||||||
|
|
||||||
|
=item %obj->options;
|
||||||
|
|
||||||
|
Accessor to configured options, if it is set up by this point
|
||||||
|
|
||||||
=item $obj->exit;
|
=item $obj->exit;
|
||||||
|
|
||||||
Stub to allow program to exit neatly from wherever in the code
|
Stub to allow program to exit neatly from wherever in the code
|
||||||
|
@ -348,27 +395,14 @@ hasnt been called
|
||||||
|
|
||||||
Set the config to the given value - croaks if has already been called
|
Set the config to the given value - croaks if has already been called
|
||||||
|
|
||||||
|
=item $sort = $obj->sort
|
||||||
|
|
||||||
|
Code reference used to sort lists; if configured (and installed) use
|
||||||
|
Sort;:Naturally, else use perl sort
|
||||||
|
|
||||||
=item %results = $obj->load_file( filename => '/path/to/file', type => '(cluster|config}' )
|
=item %results = $obj->load_file( filename => '/path/to/file', type => '(cluster|config}' )
|
||||||
|
|
||||||
Load in the specified file and return a hash, parsing the file depending on
|
Load in the specified file and return a hash, parsing the file depending on
|
||||||
wther it is a config file (key = value) or cluster file (key value)
|
wther it is a config file (key = value) or cluster file (key value)
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
=head1 AUTHOR
|
|
||||||
|
|
||||||
Duncan Ferguson, C<< <duncan_j_ferguson at yahoo.co.uk> >>
|
|
||||||
|
|
||||||
=head1 LICENSE AND COPYRIGHT
|
|
||||||
|
|
||||||
Copyright 1999-2010 Duncan Ferguson.
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms of either: the GNU General Public License as published
|
|
||||||
by the Free Software Foundation; or the Artistic License.
|
|
||||||
|
|
||||||
See http://dev.perl.org/licenses/ for more information.
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
1;
|
|
||||||
|
|
|
@ -1,16 +1,24 @@
|
||||||
package App::ClusterSSH::Cluster;
|
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use version;
|
package App::ClusterSSH::Cluster;
|
||||||
our $VERSION = version->new('0.01');
|
|
||||||
|
# ABSTRACT: App::ClusterSSH::Cluster - Object representing cluster configuration
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
Object representing application configuration
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
use Carp;
|
use Carp;
|
||||||
use Try::Tiny;
|
use Try::Tiny 0.28;
|
||||||
use English qw( -no_match_vars );
|
use English qw( -no_match_vars );
|
||||||
|
|
||||||
use base qw/ App::ClusterSSH::Base /;
|
use base qw/ App::ClusterSSH::Base /;
|
||||||
|
use App::ClusterSSH::Range;
|
||||||
|
|
||||||
our $master_object_ref;
|
our $master_object_ref;
|
||||||
|
|
||||||
|
@ -48,14 +56,40 @@ sub get_tag_entries {
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub list_external_clusters {
|
||||||
|
my ( $self, ) = @_;
|
||||||
|
|
||||||
|
my @list = $self->_run_external_clusters('-L');
|
||||||
|
return wantarray
|
||||||
|
? sort @list
|
||||||
|
: scalar @list;
|
||||||
|
}
|
||||||
|
|
||||||
sub get_external_clusters {
|
sub get_external_clusters {
|
||||||
my ( $self, $external_command, @tags ) = @_;
|
my ( $self, @tags ) = @_;
|
||||||
|
|
||||||
|
return $self->_run_external_clusters(@tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _run_external_clusters {
|
||||||
|
my ( $self, @args ) = @_;
|
||||||
|
|
||||||
|
my $external_command = $self->parent->config->{external_cluster_command};
|
||||||
|
|
||||||
|
if ( !$external_command || !-x $external_command ) {
|
||||||
|
$self->debug(
|
||||||
|
1,
|
||||||
|
'Cannot run external cluster command: ',
|
||||||
|
$external_command || ''
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$self->debug( 3, 'Running tags through external command' );
|
$self->debug( 3, 'Running tags through external command' );
|
||||||
$self->debug( 4, 'External command: ', $external_command );
|
$self->debug( 4, 'External command: ', $external_command );
|
||||||
$self->debug( 3, 'Tags: ', join( ',', @tags ) );
|
$self->debug( 3, 'Args ', join( ',', @args ) );
|
||||||
|
|
||||||
my $command = "$external_command @tags";
|
my $command = "$external_command @args";
|
||||||
|
|
||||||
$self->debug( 3, 'Running ', $command );
|
$self->debug( 3, 'Running ', $command );
|
||||||
|
|
||||||
|
@ -88,8 +122,37 @@ sub get_external_clusters {
|
||||||
return @results;
|
return @results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub expand_filename {
|
||||||
|
my ( $self, $filename ) = @_;
|
||||||
|
my $home;
|
||||||
|
|
||||||
|
# try to determine the home directory
|
||||||
|
if ( !defined( $home = $ENV{'HOME'} ) ) {
|
||||||
|
$home = ( getpwuid($>) )[5];
|
||||||
|
}
|
||||||
|
if ( !defined($home) ) {
|
||||||
|
$self->debug( 3, 'No home found so leaving filename ',
|
||||||
|
$filename, ' unexpanded' );
|
||||||
|
return $filename;
|
||||||
|
}
|
||||||
|
$self->debug( 4, 'Using ', $home, ' as home directory' );
|
||||||
|
|
||||||
|
# expand ~ or $HOME
|
||||||
|
my $new_name = $filename;
|
||||||
|
$new_name =~ s!^~/!$home/!g;
|
||||||
|
$new_name =~ s!^\$HOME/!$home/!g;
|
||||||
|
|
||||||
|
$self->debug( 2, 'Expanding ', $filename, ' to ', $new_name )
|
||||||
|
unless ( $filename eq $new_name );
|
||||||
|
|
||||||
|
return $new_name;
|
||||||
|
}
|
||||||
|
|
||||||
sub read_tag_file {
|
sub read_tag_file {
|
||||||
my ( $self, $filename ) = @_;
|
my ( $self, $filename ) = @_;
|
||||||
|
|
||||||
|
$filename = $self->expand_filename($filename);
|
||||||
|
|
||||||
$self->debug( 2, 'Reading tags from file ', $filename );
|
$self->debug( 2, 'Reading tags from file ', $filename );
|
||||||
if ( -f $filename ) {
|
if ( -f $filename ) {
|
||||||
my %hosts
|
my %hosts
|
||||||
|
@ -107,6 +170,9 @@ sub read_tag_file {
|
||||||
|
|
||||||
sub read_cluster_file {
|
sub read_cluster_file {
|
||||||
my ( $self, $filename ) = @_;
|
my ( $self, $filename ) = @_;
|
||||||
|
|
||||||
|
$filename = $self->expand_filename($filename);
|
||||||
|
|
||||||
$self->debug( 2, 'Reading clusters from file ', $filename );
|
$self->debug( 2, 'Reading clusters from file ', $filename );
|
||||||
|
|
||||||
if ( -f $filename ) {
|
if ( -f $filename ) {
|
||||||
|
@ -127,6 +193,8 @@ sub register_host {
|
||||||
my ( $self, $node, @tags ) = @_;
|
my ( $self, $node, @tags ) = @_;
|
||||||
$self->debug( 2, "Registering node $node on tags:", join( ' ', @tags ) );
|
$self->debug( 2, "Registering node $node on tags:", join( ' ', @tags ) );
|
||||||
|
|
||||||
|
@tags = $self->expand_glob( 'node', $node, @tags );
|
||||||
|
|
||||||
foreach my $tag (@tags) {
|
foreach my $tag (@tags) {
|
||||||
if ( $self->{tags}->{$tag} ) {
|
if ( $self->{tags}->{$tag} ) {
|
||||||
$self->{tags}->{$tag}
|
$self->{tags}->{$tag}
|
||||||
|
@ -144,6 +212,11 @@ sub register_host {
|
||||||
sub register_tag {
|
sub register_tag {
|
||||||
my ( $self, $tag, @nodes ) = @_;
|
my ( $self, $tag, @nodes ) = @_;
|
||||||
|
|
||||||
|
#warn "b4 nodes=@nodes";
|
||||||
|
@nodes = $self->expand_glob( 'tag', $tag, @nodes );
|
||||||
|
|
||||||
|
#warn "af nodes=@nodes";
|
||||||
|
|
||||||
$self->debug( 2, "Registering tag $tag: ", join( ' ', @nodes ) );
|
$self->debug( 2, "Registering tag $tag: ", join( ' ', @nodes ) );
|
||||||
|
|
||||||
$self->{tags}->{$tag} = \@nodes;
|
$self->{tags}->{$tag} = \@nodes;
|
||||||
|
@ -151,6 +224,35 @@ sub register_tag {
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub expand_glob {
|
||||||
|
my ( $self, $type, $name, @items ) = @_;
|
||||||
|
|
||||||
|
my @expanded;
|
||||||
|
my $range = App::ClusterSSH::Range->new();
|
||||||
|
|
||||||
|
# skip expanding anything that appears to have nasty metachars
|
||||||
|
if ( !grep {m/[\`\!\$;]/} @items ) {
|
||||||
|
|
||||||
|
$self->debug( 4, "Non-expanded: @items" );
|
||||||
|
|
||||||
|
@items = $range->expand(@items);
|
||||||
|
|
||||||
|
# run glob over anything left incase there are numeric and textual ranges
|
||||||
|
@expanded = map { glob $_ } @items;
|
||||||
|
$self->debug( 4, "Final expansion: @expanded" );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
warn(
|
||||||
|
$self->loc(
|
||||||
|
"Bad characters picked up in [_1] '[_2]': [_3]",
|
||||||
|
$type, $name, join( ' ', @items )
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return @expanded;
|
||||||
|
}
|
||||||
|
|
||||||
sub get_tag {
|
sub get_tag {
|
||||||
my ( $self, $tag ) = @_;
|
my ( $self, $tag ) = @_;
|
||||||
|
|
||||||
|
@ -161,8 +263,7 @@ sub get_tag {
|
||||||
join( ' ', sort @{ $self->{tags}->{$tag} } )
|
join( ' ', sort @{ $self->{tags}->{$tag} } )
|
||||||
);
|
);
|
||||||
|
|
||||||
return
|
return wantarray
|
||||||
wantarray
|
|
||||||
? sort @{ $self->{tags}->{$tag} }
|
? sort @{ $self->{tags}->{$tag} }
|
||||||
: scalar @{ $self->{tags}->{$tag} };
|
: scalar @{ $self->{tags}->{$tag} };
|
||||||
}
|
}
|
||||||
|
@ -173,7 +274,9 @@ sub get_tag {
|
||||||
|
|
||||||
sub list_tags {
|
sub list_tags {
|
||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
return sort keys( %{ $self->{tags} } );
|
return wantarray
|
||||||
|
? sort keys( %{ $self->{tags} } )
|
||||||
|
: scalar keys( %{ $self->{tags} } );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub dump_tags {
|
sub dump_tags {
|
||||||
|
@ -191,18 +294,6 @@ sub dump_tags {
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
||||||
=pod
|
|
||||||
|
|
||||||
=head1 NAME
|
|
||||||
|
|
||||||
App::ClusterSSH::Cluster - Object representing cluster configuration
|
|
||||||
|
|
||||||
=head1 SYNOPSIS
|
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
|
||||||
|
|
||||||
Object representing application configuration
|
|
||||||
|
|
||||||
=head1 METHODS
|
=head1 METHODS
|
||||||
|
|
||||||
=over 4
|
=over 4
|
||||||
|
@ -216,9 +307,13 @@ Create a new object. Object should be common across all invocations.
|
||||||
Read in /etc/clusters, $HOME/.clusterssh/clusters and any other given
|
Read in /etc/clusters, $HOME/.clusterssh/clusters and any other given
|
||||||
file name and register the tags found.
|
file name and register the tags found.
|
||||||
|
|
||||||
=item @resolved_tags=get_external_clusters($path_to_binary, @tags)
|
=item @external_tags=list_external_clusters()
|
||||||
|
|
||||||
Define and use an external script to resolve tags into hostnames.
|
Call an external script suing C<-L> to list available tags
|
||||||
|
|
||||||
|
=item @resolved_tags=get_external_clusters(@tags)
|
||||||
|
|
||||||
|
Use an external script to resolve C<@tags> into hostnames.
|
||||||
|
|
||||||
=item $cluster->get_tag_entries($filename);
|
=item $cluster->get_tag_entries($filename);
|
||||||
|
|
||||||
|
@ -229,6 +324,10 @@ file name and register the tags found.
|
||||||
|
|
||||||
Read in the given cluster file and register the tags found
|
Read in the given cluster file and register the tags found
|
||||||
|
|
||||||
|
=item $cluster->expand_filename($filename);
|
||||||
|
|
||||||
|
Expand ~ or $HOME in a filename
|
||||||
|
|
||||||
=item $cluster->read_tag_file($filename);
|
=item $cluster->read_tag_file($filename);
|
||||||
|
|
||||||
Read in the given tag file and register the tags found
|
Read in the given tag file and register the tags found
|
||||||
|
@ -256,22 +355,8 @@ Return an array of all available tag names
|
||||||
|
|
||||||
Returns a hash of all tag data.
|
Returns a hash of all tag data.
|
||||||
|
|
||||||
|
=item @tags = $cluster->expand_glob( $type, $name, @items );
|
||||||
|
|
||||||
|
Use shell expansion against each item in @items, where $type is either 'node', or 'tag' and $name is the node or tag name. These attributes are presented to the user in the event of an issue with the expanion to track down the source.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
=head1 AUTHOR
|
|
||||||
|
|
||||||
Duncan Ferguson, C<< <duncan_j_ferguson at yahoo.co.uk> >>
|
|
||||||
|
|
||||||
=head1 LICENSE AND COPYRIGHT
|
|
||||||
|
|
||||||
Copyright 1999-2010 Duncan Ferguson.
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms of either: the GNU General Public License as published
|
|
||||||
by the Free Software Foundation; or the Artistic License.
|
|
||||||
|
|
||||||
See http://dev.perl.org/licenses/ for more information.
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
1;
|
|
||||||
|
|
|
@ -1,10 +1,17 @@
|
||||||
package App::ClusterSSH::Config;
|
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use version;
|
package App::ClusterSSH::Config;
|
||||||
our $VERSION = version->new('0.02');
|
|
||||||
|
# ABSTRACT: ClusterSSH::Config - Object representing application configuration
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
Object representing application configuration
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
use Carp;
|
use Carp;
|
||||||
use Try::Tiny;
|
use Try::Tiny;
|
||||||
|
@ -17,7 +24,7 @@ use App::ClusterSSH::Cluster;
|
||||||
|
|
||||||
my $clusters;
|
my $clusters;
|
||||||
my %old_clusters;
|
my %old_clusters;
|
||||||
my @app_specific = (qw/ command title comms method /);
|
my @app_specific = (qw/ command title comms method parent /);
|
||||||
|
|
||||||
# list of config items to not write out when writing the default config
|
# list of config items to not write out when writing the default config
|
||||||
my @ignore_default_config = (qw/ user /);
|
my @ignore_default_config = (qw/ user /);
|
||||||
|
@ -33,7 +40,7 @@ my %default_config = (
|
||||||
terminal_size => "80x24",
|
terminal_size => "80x24",
|
||||||
|
|
||||||
use_hotkeys => "yes",
|
use_hotkeys => "yes",
|
||||||
key_quit => "Control-q",
|
key_quit => "Alt-q",
|
||||||
key_addhost => "Control-Shift-plus",
|
key_addhost => "Control-Shift-plus",
|
||||||
key_clientname => "Alt-n",
|
key_clientname => "Alt-n",
|
||||||
key_history => "Alt-h",
|
key_history => "Alt-h",
|
||||||
|
@ -42,9 +49,14 @@ my %default_config = (
|
||||||
key_macros_enable => "Alt-p",
|
key_macros_enable => "Alt-p",
|
||||||
key_paste => "Control-v",
|
key_paste => "Control-v",
|
||||||
key_username => "Alt-u",
|
key_username => "Alt-u",
|
||||||
|
key_user_1 => "Alt-1",
|
||||||
|
key_user_2 => "Alt-2",
|
||||||
|
key_user_3 => "Alt-3",
|
||||||
|
key_user_4 => "Alt-4",
|
||||||
mouse_paste => "Button-2",
|
mouse_paste => "Button-2",
|
||||||
auto_quit => "yes",
|
auto_quit => "yes",
|
||||||
auto_close => 5,
|
auto_close => 5,
|
||||||
|
use_natural_sort => 0,
|
||||||
window_tiling => "yes",
|
window_tiling => "yes",
|
||||||
window_tiling_direction => "right",
|
window_tiling_direction => "right",
|
||||||
console_position => "",
|
console_position => "",
|
||||||
|
@ -70,9 +82,14 @@ my %default_config = (
|
||||||
telnet_args => "",
|
telnet_args => "",
|
||||||
ssh => 'ssh',
|
ssh => 'ssh',
|
||||||
ssh_args => "",
|
ssh_args => "",
|
||||||
|
sftp => 'sftp',
|
||||||
|
sftp_args => "",
|
||||||
|
|
||||||
|
extra_tag_file => '',
|
||||||
extra_cluster_file => '',
|
extra_cluster_file => '',
|
||||||
external_cluster_command => '',
|
external_cluster_command => '',
|
||||||
|
external_command_mode => '0600',
|
||||||
|
external_command_pipe => '',
|
||||||
|
|
||||||
unmap_on_redraw => "no", # Debian #329440
|
unmap_on_redraw => "no", # Debian #329440
|
||||||
|
|
||||||
|
@ -81,6 +98,9 @@ my %default_config = (
|
||||||
history_height => 10,
|
history_height => 10,
|
||||||
|
|
||||||
command => q{},
|
command => q{},
|
||||||
|
command_pre => q{},
|
||||||
|
command_post => q{},
|
||||||
|
hide_menu => 0,
|
||||||
max_host_menu_items => 30,
|
max_host_menu_items => 30,
|
||||||
|
|
||||||
macros_enabled => 'yes',
|
macros_enabled => 'yes',
|
||||||
|
@ -89,17 +109,35 @@ my %default_config = (
|
||||||
macro_username => '%u',
|
macro_username => '%u',
|
||||||
macro_newline => '%n',
|
macro_newline => '%n',
|
||||||
macro_version => '%v',
|
macro_version => '%v',
|
||||||
|
macro_user_1 => '%1',
|
||||||
|
macro_user_2 => '%2',
|
||||||
|
macro_user_3 => '%3',
|
||||||
|
macro_user_4 => '%4',
|
||||||
|
|
||||||
|
macro_user_1_command => '',
|
||||||
|
macro_user_2_command => '',
|
||||||
|
macro_user_3_command => '',
|
||||||
|
macro_user_4_command => '',
|
||||||
|
hostname_override => '',
|
||||||
|
|
||||||
max_addhost_menu_cluster_items => 6,
|
max_addhost_menu_cluster_items => 6,
|
||||||
menu_send_autotearoff => 0,
|
menu_send_autotearoff => 0,
|
||||||
menu_host_autotearoff => 0,
|
menu_host_autotearoff => 0,
|
||||||
|
|
||||||
|
unique_servers => 0,
|
||||||
use_all_a_records => 0,
|
use_all_a_records => 0,
|
||||||
|
|
||||||
send_menu_xml_file => $ENV{HOME} . '/.csshrc_send_menu',
|
send_menu_xml_file => $ENV{HOME} . '/.clusterssh/send_menu',
|
||||||
|
|
||||||
|
auto_wm_decoration_offsets => "no", # Debian #842965
|
||||||
|
|
||||||
# don't set username here as takes precendence over ssh config
|
# don't set username here as takes precendence over ssh config
|
||||||
user => '',
|
user => '',
|
||||||
|
rows => -1,
|
||||||
|
cols => -1,
|
||||||
|
|
||||||
|
fillscreen => "no",
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
sub new {
|
sub new {
|
||||||
|
@ -112,9 +150,10 @@ sub new {
|
||||||
$comms = 'telnet' if ( $comms eq 'tel' );
|
$comms = 'telnet' if ( $comms eq 'tel' );
|
||||||
$comms = 'console' if ( $comms eq 'con' );
|
$comms = 'console' if ( $comms eq 'con' );
|
||||||
$comms = 'ssh' if ( $comms eq 'lusterssh' );
|
$comms = 'ssh' if ( $comms eq 'lusterssh' );
|
||||||
|
$comms = 'sftp' if ( $comms eq 'sftp' );
|
||||||
|
|
||||||
# list of allowed comms methods
|
# list of allowed comms methods
|
||||||
if ( 'ssh rsh telnet console' !~ m/\b$comms\b/ ) {
|
if ( 'ssh rsh telnet sftp console' !~ m/\b$comms\b/ ) {
|
||||||
$self->{comms} = 'ssh';
|
$self->{comms} = 'ssh';
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -179,12 +218,14 @@ sub validate_args {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
# # Don't search for the path to the binary - assume it is on the path
|
# check the terminal has been found correctly
|
||||||
# # or defined correctly in the config.
|
# looking for the terminal should not be fatal
|
||||||
# if( !-e $self->{ $self->{comms} } )
|
if ( !-e $self->{terminal} ) {
|
||||||
# {
|
eval { $self->{terminal} = $self->find_binary( $self->{terminal} ); };
|
||||||
# $self->{ $self->{comms} } = $self->find_binary( $self->{comms} );
|
if ($@) {
|
||||||
# }
|
warn $@->message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
@ -254,6 +295,15 @@ sub parse_config_file {
|
||||||
if ( $read_config{terminal_font} );
|
if ( $read_config{terminal_font} );
|
||||||
|
|
||||||
$self->validate_args(%read_config);
|
$self->validate_args(%read_config);
|
||||||
|
|
||||||
|
# Look at the user macros and if not set remove the hotkey for them
|
||||||
|
for my $i (qw/ 1 2 3 4 /) {
|
||||||
|
if ( !$self->{"macro_user_${i}_command"} ) {
|
||||||
|
delete $self->{"key_user_${i}"};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub load_configs {
|
sub load_configs {
|
||||||
|
@ -265,7 +315,7 @@ sub load_configs {
|
||||||
$ENV{HOME} . '/.clusterssh/config',
|
$ENV{HOME} . '/.clusterssh/config',
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
$self->parse_config_file($config) if ( -e $config );
|
$self->parse_config_file($config) if ( -e $config && !-d _ );
|
||||||
}
|
}
|
||||||
|
|
||||||
# write out default config file if necesasry
|
# write out default config file if necesasry
|
||||||
|
@ -280,10 +330,22 @@ sub load_configs {
|
||||||
# relative to config directory
|
# relative to config directory
|
||||||
for my $config (@configs) {
|
for my $config (@configs) {
|
||||||
next unless ($config); # can be null when passed from Getopt::Long
|
next unless ($config); # can be null when passed from Getopt::Long
|
||||||
$self->parse_config_file($config) if ( -e $config );
|
$self->parse_config_file($config) if ( -e $config && !-d _ );
|
||||||
|
|
||||||
my $file = $ENV{HOME} . '/.clusterssh/config_' . $config;
|
my $file = $ENV{HOME} . '/.clusterssh/config_' . $config;
|
||||||
$self->parse_config_file($file) if ( -e $file );
|
$self->parse_config_file($file) if ( -e $file && !-d _ );
|
||||||
|
}
|
||||||
|
|
||||||
|
# Override confuration via environment variable using cssh_ prefix
|
||||||
|
# eg: terminal_size => cssh_terminal_size
|
||||||
|
foreach my $config_key ( sort( keys(%default_config) ) ) {
|
||||||
|
my $env_config_key = "cssh_" . $config_key;
|
||||||
|
if ( exists $ENV{ uc($env_config_key) } ) {
|
||||||
|
$env_config_key = uc($env_config_key);
|
||||||
|
}
|
||||||
|
if ( exists $ENV{$env_config_key} ) {
|
||||||
|
$self->{$config_key} = $ENV{$env_config_key};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $self;
|
return $self;
|
||||||
|
@ -387,6 +449,25 @@ sub write_user_config_file {
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# search given directories for the given file
|
||||||
|
sub search_dirs {
|
||||||
|
my ( $self, $file, @directories ) = @_;
|
||||||
|
|
||||||
|
my $path;
|
||||||
|
|
||||||
|
foreach my $dir (@directories) {
|
||||||
|
$self->debug( 3, "Looking for $file in $dir" );
|
||||||
|
|
||||||
|
if ( -f $dir . '/' . $file && -x $dir . '/' . $file ) {
|
||||||
|
$path = $dir . '/' . $file;
|
||||||
|
$self->debug( 2, "Found at $path" );
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
|
||||||
# could use File::Which for some of this but we also search a few other places
|
# could use File::Which for some of this but we also search a few other places
|
||||||
# just in case $PATH isnt set up right
|
# just in case $PATH isnt set up right
|
||||||
sub find_binary {
|
sub find_binary {
|
||||||
|
@ -405,39 +486,39 @@ sub find_binary {
|
||||||
# if not found, strip the path and look again
|
# if not found, strip the path and look again
|
||||||
if ( $binary =~ m!^/! ) {
|
if ( $binary =~ m!^/! ) {
|
||||||
if ( -f $binary ) {
|
if ( -f $binary ) {
|
||||||
$self->debug( 2, "$binary already fully qualified" );
|
$self->debug( 2, "Already have full path to in $binary" );
|
||||||
return $binary;
|
return $binary;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$self->debug( 2, "$binary not found - re-searching" );
|
$self->debug( 2, "Full path for $binary incorrect; searching" );
|
||||||
$binary =~ s!^.*/!!;
|
$binary =~ s!^.*/!!;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
my $path;
|
my $path;
|
||||||
if ( !-x $binary || substr( $binary, 0, 1 ) ne '/' ) {
|
if ( !-x $binary || substr( $binary, 0, 1 ) ne '/' ) {
|
||||||
|
$path = $self->search_dirs( $binary, split( /:/, $ENV{PATH} ) );
|
||||||
|
|
||||||
foreach (
|
# if it is on $PATH then no need to qualitfy the path to it
|
||||||
split( /:/, $ENV{PATH} ), qw!
|
# keep it as it is
|
||||||
/bin
|
if ($path) {
|
||||||
/sbin
|
return $binary;
|
||||||
/usr/sbin
|
|
||||||
/usr/bin
|
|
||||||
/usr/local/bin
|
|
||||||
/usr/local/sbin
|
|
||||||
/opt/local/bin
|
|
||||||
/opt/local/sbin
|
|
||||||
!
|
|
||||||
)
|
|
||||||
{
|
|
||||||
$self->debug( 3, "Looking in $_" );
|
|
||||||
|
|
||||||
if ( -f $_ . '/' . $binary && -x $_ . '/' . $binary ) {
|
|
||||||
$path = $_ . '/' . $binary;
|
|
||||||
$self->debug( 2, "Found at $path" );
|
|
||||||
last;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
$path = $self->search_dirs(
|
||||||
|
$binary, qw!
|
||||||
|
/bin
|
||||||
|
/sbin
|
||||||
|
/usr/sbin
|
||||||
|
/usr/bin
|
||||||
|
/usr/local/bin
|
||||||
|
/usr/local/sbin
|
||||||
|
/opt/local/bin
|
||||||
|
/opt/local/sbin
|
||||||
|
!
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$self->debug( 2, "Already configured OK" );
|
$self->debug( 2, "Already configured OK" );
|
||||||
|
@ -463,7 +544,7 @@ sub dump {
|
||||||
my ( $self, $no_exit, ) = @_;
|
my ( $self, $no_exit, ) = @_;
|
||||||
|
|
||||||
$self->debug( 3, 'Dumping config to STDOUT' );
|
$self->debug( 3, 'Dumping config to STDOUT' );
|
||||||
print( '# Configuration dump produced by "cssh -u"', $/ );
|
print( '# Configuration dump produced by "cssh -d"', $/ );
|
||||||
|
|
||||||
foreach my $key ( sort keys %$self ) {
|
foreach my $key ( sort keys %$self ) {
|
||||||
my $comment = '';
|
my $comment = '';
|
||||||
|
@ -489,18 +570,6 @@ sub dump {
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
||||||
=pod
|
|
||||||
|
|
||||||
=head1 NAME
|
|
||||||
|
|
||||||
ClusterSSH::Config - Object representing application configuration
|
|
||||||
|
|
||||||
=head1 SYNOPSIS
|
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
|
||||||
|
|
||||||
Object representing application configuration
|
|
||||||
|
|
||||||
=head1 METHODS
|
=head1 METHODS
|
||||||
|
|
||||||
=over 4
|
=over 4
|
||||||
|
@ -517,6 +586,10 @@ Read in configuration from given filename
|
||||||
|
|
||||||
Validate and apply all configuration loaded at this point
|
Validate and apply all configuration loaded at this point
|
||||||
|
|
||||||
|
=item $path = $config->search_dirs('<name>', @seaarch_directories);
|
||||||
|
|
||||||
|
Search the given directories for the name given. Return undef if not found.
|
||||||
|
|
||||||
=item $path = $config->find_binary('<name>');
|
=item $path = $config->find_binary('<name>');
|
||||||
|
|
||||||
Locate the binary <name> and return the full path. Doesn't just search
|
Locate the binary <name> and return the full path. Doesn't just search
|
||||||
|
@ -537,21 +610,3 @@ are loaded).
|
||||||
Write currently defined configuration to STDOUT
|
Write currently defined configuration to STDOUT
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
=head1 AUTHOR
|
|
||||||
|
|
||||||
Duncan Ferguson, C<< <duncan_j_ferguson at yahoo.co.uk> >>
|
|
||||||
|
|
||||||
=head1 LICENSE AND COPYRIGHT
|
|
||||||
|
|
||||||
Copyright 1999-2010 Duncan Ferguson.
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms of either: the GNU General Public License as published
|
|
||||||
by the Free Software Foundation; or the Artistic License.
|
|
||||||
|
|
||||||
See http://dev.perl.org/licenses/ for more information.
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
1;
|
|
||||||
|
|
1249
lib/App/ClusterSSH/Getopt.pm
Normal file
1249
lib/App/ClusterSSH/Getopt.pm
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,10 +1,17 @@
|
||||||
package App::ClusterSSH::Helper;
|
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use version;
|
package App::ClusterSSH::Helper;
|
||||||
our $VERSION = version->new('0.02');
|
|
||||||
|
# ABSTRACT: ClusterSSH::Helper - Object representing helper script
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
Object representing application configuration
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
use Carp;
|
use Carp;
|
||||||
use Try::Tiny;
|
use Try::Tiny;
|
||||||
|
@ -22,6 +29,31 @@ sub new {
|
||||||
sub script {
|
sub script {
|
||||||
my ( $self, $config ) = @_;
|
my ( $self, $config ) = @_;
|
||||||
|
|
||||||
|
if ( !defined $config
|
||||||
|
|| !ref $config
|
||||||
|
|| ref $config ne "App::ClusterSSH::Config" )
|
||||||
|
{
|
||||||
|
croak(
|
||||||
|
App::ClusterSSH::Exception::Helper->throw(
|
||||||
|
error => 'No configuration provided or in wrong format',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach my $arg ( "comms", $config->{comms}, $config->{comms} . '_args',
|
||||||
|
'command', 'auto_close' )
|
||||||
|
{
|
||||||
|
if ( !defined $config->{$arg} ) {
|
||||||
|
croak(
|
||||||
|
App::ClusterSSH::Exception::Helper->throw(
|
||||||
|
error => "Config '$arg' not provided",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
my $command_pre = $config->{command_pre} || q{};
|
||||||
|
my $command_post = $config->{command_post} || q{};
|
||||||
my $comms = $config->{ $config->{comms} };
|
my $comms = $config->{ $config->{comms} };
|
||||||
my $comms_args = $config->{ $config->{comms} . '_args' };
|
my $comms_args = $config->{ $config->{comms} . '_args' };
|
||||||
my $config_command = $config->{command};
|
my $config_command = $config->{command};
|
||||||
|
@ -33,66 +65,15 @@ sub script {
|
||||||
: "echo Press RETURN to continue; read IGNORE"
|
: "echo Press RETURN to continue; read IGNORE"
|
||||||
; # : "sleep $autoclose";
|
; # : "sleep $autoclose";
|
||||||
|
|
||||||
# # P = pipe file
|
|
||||||
# # s = server
|
|
||||||
# # u = username
|
|
||||||
# # p = port
|
|
||||||
# # m = ccon master
|
|
||||||
# # c = comms command
|
|
||||||
# # a = command args
|
|
||||||
# # C = command to run
|
|
||||||
# my $lelehelper_script = q{
|
|
||||||
# use strict;
|
|
||||||
# use warnings;
|
|
||||||
# use Getopt::Std;
|
|
||||||
# my %opts;
|
|
||||||
# getopts('PsupmcaC', \%opts);
|
|
||||||
# my $command="$opts{c} $opts{a}";
|
|
||||||
# open(PIPE, ">", $opts{P}) or die("Failed to open pipe: $!\n");
|
|
||||||
# print PIPE "$$:$ENV{WINDOWID}"
|
|
||||||
# or die("Failed to write to pipe: $!\\n");
|
|
||||||
# close(PIPE) or die("Failed to close pipe: $!\\n");
|
|
||||||
# if($opts{s} =~ m/==$/)
|
|
||||||
# {
|
|
||||||
# $opts{s} =~ s/==$//;
|
|
||||||
# warn("\nWARNING: failed to resolve IP address for $opts{s}.\n\n");
|
|
||||||
# sleep 5;
|
|
||||||
# }
|
|
||||||
# if($opts{m}) {
|
|
||||||
# unless("$comms" ne "console") {
|
|
||||||
# $opts{m} = $opts{m} ? "-M $opts{m} " : "";
|
|
||||||
# $opts{c} .= $opts{m};
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
# if($opts{u}) {
|
|
||||||
# unless("$comms" eq "telnet") {
|
|
||||||
# $opts{u} = $opts{u} ? "-l $opts{u} " : "";
|
|
||||||
# $opts{c} .= $opts{u};
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
# if("$comms" eq "telnet") {
|
|
||||||
# $command .= "$opts{s} $opts{p}";
|
|
||||||
# } else {
|
|
||||||
# if ($opts{p}) {
|
|
||||||
# $opts{c} .= "-p $opts{p} $opts{s}";
|
|
||||||
# } else {
|
|
||||||
# $opts{c} .= "$opts{s}";
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
# #$command .= " $command || sleep 5";
|
|
||||||
# warn("Running:$command\n"); # for debug purposes
|
|
||||||
# exec($command);
|
|
||||||
# };
|
|
||||||
|
|
||||||
my $script = <<" HERE";
|
my $script = <<" HERE";
|
||||||
my \$pipe=shift;
|
my \$pipe=shift;
|
||||||
my \$svr=shift;
|
my \$svr=shift;
|
||||||
my \$user=shift;
|
my \$user=shift;
|
||||||
my \$port=shift;
|
my \$port=shift;
|
||||||
my \$mstr=shift;
|
my \$mstr=shift;
|
||||||
my \$command="$comms $comms_args ";
|
my \$command="$command_pre $comms $comms_args ";
|
||||||
open(PIPE, ">", \$pipe) or die("Failed to open pipe: \$!\\n");
|
open(PIPE, ">", \$pipe) or die("Failed to open pipe: \$!\\n");
|
||||||
print PIPE "\$\$:\$ENV{WINDOWID}"
|
print PIPE "\$\$:\$ENV{WINDOWID}"
|
||||||
or die("Failed to write to pipe: $!\\n");
|
or die("Failed to write to pipe: $!\\n");
|
||||||
close(PIPE) or die("Failed to close pipe: $!\\n");
|
close(PIPE) or die("Failed to close pipe: $!\\n");
|
||||||
if(\$svr =~ m/==\$/)
|
if(\$svr =~ m/==\$/)
|
||||||
|
@ -126,8 +107,10 @@ sub script {
|
||||||
if("$config_command") {
|
if("$config_command") {
|
||||||
\$command .= " \\\"$config_command\\\"";
|
\$command .= " \\\"$config_command\\\"";
|
||||||
}
|
}
|
||||||
|
\$command .= "$command_post";
|
||||||
\$command .= " ; $postcommand";
|
\$command .= " ; $postcommand";
|
||||||
warn("Running:\$command\\n"); # for debug purposes
|
# provide some info for debugging purposes
|
||||||
|
warn("Running: \$command\\n");
|
||||||
exec(\$command);
|
exec(\$command);
|
||||||
HERE
|
HERE
|
||||||
|
|
||||||
|
@ -147,18 +130,6 @@ sub script {
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
||||||
=pod
|
|
||||||
|
|
||||||
=head1 NAME
|
|
||||||
|
|
||||||
ClusterSSH::Helper - Object representing helper script
|
|
||||||
|
|
||||||
=head1 SYNOPSIS
|
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
|
||||||
|
|
||||||
Object representing application configuration
|
|
||||||
|
|
||||||
=head1 METHODS
|
=head1 METHODS
|
||||||
|
|
||||||
=over 4
|
=over 4
|
||||||
|
@ -172,21 +143,3 @@ Create a new helper object.
|
||||||
Return the helper script
|
Return the helper script
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
=head1 AUTHOR
|
|
||||||
|
|
||||||
Duncan Ferguson, C<< <duncan_j_ferguson at yahoo.co.uk> >>
|
|
||||||
|
|
||||||
=head1 LICENSE AND COPYRIGHT
|
|
||||||
|
|
||||||
Copyright 1999-2010 Duncan Ferguson.
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms of either: the GNU General Public License as published
|
|
||||||
by the Free Software Foundation; or the Artistic License.
|
|
||||||
|
|
||||||
See http://dev.perl.org/licenses/ for more information.
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
1;
|
|
||||||
|
|
|
@ -1,12 +1,28 @@
|
||||||
package App::ClusterSSH::Host;
|
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use version;
|
package App::ClusterSSH::Host;
|
||||||
our $VERSION = version->new('0.03');
|
|
||||||
|
# ABSTRACT: ClusterSSH::Host - Object representing a host.
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
use ClusterSSH::Host;
|
||||||
|
|
||||||
|
my $host = ClusterSSH::Host->new({
|
||||||
|
hostname => 'hostname',
|
||||||
|
});
|
||||||
|
my $host = ClusterSSH::Host->parse_host_string('username@hostname:1234');
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
Object representing a host. Include details to contact the host such as
|
||||||
|
hostname/ipaddress, username and port.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
use Carp;
|
use Carp;
|
||||||
|
use Net::hostent;
|
||||||
|
|
||||||
use base qw/ App::ClusterSSH::Base /;
|
use base qw/ App::ClusterSSH::Base /;
|
||||||
|
|
||||||
|
@ -25,7 +41,7 @@ sub new {
|
||||||
}
|
}
|
||||||
|
|
||||||
# remove any keys undef values - must be a better way...
|
# remove any keys undef values - must be a better way...
|
||||||
foreach my $remove (qw/ port username /) {
|
foreach my $remove (qw/ port username geometry /) {
|
||||||
if ( !$args{$remove} && grep {/^$remove$/} keys(%args) ) {
|
if ( !$args{$remove} && grep {/^$remove$/} keys(%args) ) {
|
||||||
delete( $args{$remove} );
|
delete( $args{$remove} );
|
||||||
}
|
}
|
||||||
|
@ -36,33 +52,42 @@ sub new {
|
||||||
|
|
||||||
# load in ssh hostname for later use
|
# load in ssh hostname for later use
|
||||||
if ( !%ssh_hostname_for || !$ssh_configs_read{ $self->{ssh_config} } ) {
|
if ( !%ssh_hostname_for || !$ssh_configs_read{ $self->{ssh_config} } ) {
|
||||||
$ssh_configs_read{ $self->{ssh_config} } = 1;
|
$self->read_ssh_file( $self->{ssh_config} );
|
||||||
if ( open( my $ssh_config_fh, '<', $self->{ssh_config} ) ) {
|
|
||||||
while ( my $line = <$ssh_config_fh> ) {
|
|
||||||
chomp $line;
|
|
||||||
next unless ( $line =~ m/^\s*host\s+(.*)/i );
|
|
||||||
|
|
||||||
# account for multiple declarations of hosts
|
$self->debug( 5, 'Have the following ssh hostnames' );
|
||||||
$ssh_hostname_for{$_} = 1 foreach ( split( /\s+/, $1 ) );
|
$self->debug( 5, ' "', $_, '"' )
|
||||||
}
|
foreach ( sort keys %ssh_hostname_for );
|
||||||
close($ssh_config_fh);
|
|
||||||
|
|
||||||
$self->debug( 5, 'Have the following ssh hostnames' );
|
|
||||||
$self->debug( 5, ' "', $_, '"' )
|
|
||||||
foreach ( sort keys %ssh_hostname_for );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$self->debug( 3, 'Unable to read ',
|
|
||||||
$self->{ssh_config}, ': ', $!, $/ );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub get_givenname {
|
sub read_ssh_file($$) {
|
||||||
my ($self) = @_;
|
my ($self) = shift;
|
||||||
return $self->{hostname};
|
my ($filename) = glob(shift);
|
||||||
|
$self->debug( 3, 'Reading SSH file: ', $filename );
|
||||||
|
|
||||||
|
$ssh_configs_read{$filename} = 1;
|
||||||
|
|
||||||
|
if ( open( my $ssh_config_fh, '<', $filename ) ) {
|
||||||
|
while ( my $line = <$ssh_config_fh> ) {
|
||||||
|
chomp $line;
|
||||||
|
|
||||||
|
if ( $line =~ /^\s*include\s+(.+)/i ) {
|
||||||
|
$self->read_ssh_file($1);
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
next unless ( $line =~ m/^\s*host\s+(.*)/i );
|
||||||
|
|
||||||
|
# account for multiple declarations of hosts
|
||||||
|
$ssh_hostname_for{$_} = 1 foreach ( split( /\s+/, $1 ) );
|
||||||
|
}
|
||||||
|
close($ssh_config_fh);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$self->debug( 3, 'Unable to read ', $filename, ': ', $!, $/ );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub get_hostname {
|
sub get_hostname {
|
||||||
|
@ -75,6 +100,19 @@ sub get_username {
|
||||||
return $self->{username} || q{};
|
return $self->{username} || q{};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub get_type {
|
||||||
|
my ($self) = @_;
|
||||||
|
if ( $self->check_ssh_hostname ) {
|
||||||
|
return 'ssh_alias';
|
||||||
|
}
|
||||||
|
return $self->{type} || q{};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_geometry {
|
||||||
|
my ($self) = @_;
|
||||||
|
return $self->{geometry} || q{};
|
||||||
|
}
|
||||||
|
|
||||||
sub set_username {
|
sub set_username {
|
||||||
my ( $self, $new_username ) = @_;
|
my ( $self, $new_username ) = @_;
|
||||||
$self->{username} = $new_username;
|
$self->{username} = $new_username;
|
||||||
|
@ -92,6 +130,18 @@ sub set_port {
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub set_type {
|
||||||
|
my ( $self, $type ) = @_;
|
||||||
|
$self->{type} = $type;
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub set_geometry {
|
||||||
|
my ( $self, $geometry ) = @_;
|
||||||
|
$self->{geometry} = $geometry;
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
sub get_master {
|
sub get_master {
|
||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
return $self->{master} || q{};
|
return $self->{master} || q{};
|
||||||
|
@ -107,21 +157,16 @@ sub get_realname {
|
||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
|
|
||||||
if ( !$self->{realname} ) {
|
if ( !$self->{realname} ) {
|
||||||
if ( $self->{type} && $self->{type} eq 'name' ) {
|
if ( $self->get_type eq 'ssh_alias' ) {
|
||||||
if ( $ssh_hostname_for{ $self->{hostname} } ) {
|
$self->{realname} = $self->{hostname};
|
||||||
$self->{realname} = $self->{hostname};
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
my $gethost_obj = gethostbyname( $self->{hostname} );
|
|
||||||
|
|
||||||
$self->{realname}
|
|
||||||
= defined($gethost_obj)
|
|
||||||
? $gethost_obj->name()
|
|
||||||
: $self->{hostname};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$self->{realname} = $self->{hostname};
|
my $gethost_obj = gethostbyname( $self->{hostname} );
|
||||||
|
|
||||||
|
$self->{realname}
|
||||||
|
= defined($gethost_obj)
|
||||||
|
? $gethost_obj->name()
|
||||||
|
: $self->{hostname};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $self->{realname};
|
return $self->{realname};
|
||||||
|
@ -136,22 +181,27 @@ sub parse_host_string {
|
||||||
# check for bracketed IPv6 addresses
|
# check for bracketed IPv6 addresses
|
||||||
if ($host_string =~ m{
|
if ($host_string =~ m{
|
||||||
\A
|
\A
|
||||||
(?:(.*?)@)? # username@ (optional)
|
(?:(.*?)@)? # username@ (optional)
|
||||||
\[([\w:]*)\] # [<sequence of chars>]
|
\[([\w:]*)\] # [<sequence of chars>]
|
||||||
(?::(\d+))? # :port (optional)
|
(?::(\d+))? # :port (optional)
|
||||||
|
(?:=(\d+\D\d+\D\d+\D\d))? # =geometry (optional)
|
||||||
\z
|
\z
|
||||||
}xms
|
}xms
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
$self->debug(
|
$self->debug(
|
||||||
5,
|
5,
|
||||||
$self->loc( 'bracketed IPv6: u=[_1] h=[_2] p=[_3]', $1, $2, $3 ),
|
$self->loc(
|
||||||
|
'bracketed IPv6: u=[_1] h=[_2] p=[_3] g=[_4]',
|
||||||
|
$1, $2, $3, $4
|
||||||
|
),
|
||||||
);
|
);
|
||||||
return __PACKAGE__->new(
|
return __PACKAGE__->new(
|
||||||
parse_string => $parse_string,
|
parse_string => $parse_string,
|
||||||
username => $1,
|
username => $1,
|
||||||
hostname => $2,
|
hostname => $2,
|
||||||
port => $3,
|
port => $3,
|
||||||
|
geometry => $4,
|
||||||
type => 'ipv6',
|
type => 'ipv6',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -159,58 +209,82 @@ sub parse_host_string {
|
||||||
# check for standard IPv4 host.domain/IP address
|
# check for standard IPv4 host.domain/IP address
|
||||||
if ($host_string =~ m{
|
if ($host_string =~ m{
|
||||||
\A
|
\A
|
||||||
(?:(.*?)@)? # username@ (optional)
|
(?:(.*?)@)? # username@ (optional)
|
||||||
([\w\.-]*) # hostname[.domain[.domain] | 123.123.123.123
|
([\w\.-]*) # hostname[.domain[.domain] | 123.123.123.123
|
||||||
(?::(\d+))? # :port (optional)
|
(?::(\d+))? # :port (optional)
|
||||||
|
(?:=(\d+\D\d+\D\d+\D\d+))? # =geometry (optional)
|
||||||
\z
|
\z
|
||||||
}xms
|
}xms
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
$self->debug( 5,
|
$self->debug(
|
||||||
$self->loc( 'std IPv4: u=[_1] h=[_2] p=[_3]', $1, $2, $3 ),
|
5,
|
||||||
|
$self->loc(
|
||||||
|
'std IPv4: u=[_1] h=[_2] p=[_3] g=[_4]',
|
||||||
|
$1, $2, $3, $4
|
||||||
|
),
|
||||||
);
|
);
|
||||||
return __PACKAGE__->new(
|
return __PACKAGE__->new(
|
||||||
parse_string => $parse_string,
|
parse_string => $parse_string,
|
||||||
username => $1,
|
username => $1,
|
||||||
hostname => $2,
|
hostname => $2,
|
||||||
port => $3,
|
port => $3,
|
||||||
|
geometry => $4,
|
||||||
type => 'ipv4',
|
type => 'ipv4',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
# Check for unbracketed IPv6 addresses as best we can...
|
# Check for unbracketed IPv6 addresses as best we can...
|
||||||
|
my $username = q{};
|
||||||
|
my $geometry = q{};
|
||||||
|
my $port = q{};
|
||||||
|
|
||||||
# first, see if there is a username to grab
|
# first, see if there is a username to grab
|
||||||
my $username = q[];
|
if ( $host_string =~ s/\A(?:(.*?)@)// ) {
|
||||||
if ( $host_string =~ s/\A(?:(.*)@)// ) {
|
|
||||||
|
|
||||||
# catch where @ is in host_string but no text before it
|
# catch where @ is in host_string but no text before it
|
||||||
$username = $1 || q{};
|
$username = $1;
|
||||||
|
}
|
||||||
|
|
||||||
|
# check for any geometry settings
|
||||||
|
if ( $host_string =~ s/(?:=(.*?)$)// ) {
|
||||||
|
$geometry = $1;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check for a '/nnnn' port definition
|
||||||
|
if ( $host_string =~ s!(?:/(\d+)$)!! ) {
|
||||||
|
$port = $1;
|
||||||
}
|
}
|
||||||
|
|
||||||
# use number of colons as a possible indicator
|
# use number of colons as a possible indicator
|
||||||
my $colon_count = $host_string =~ tr/://;
|
my $colon_count = $host_string =~ tr/://;
|
||||||
|
|
||||||
# if there are 7 colons assume its a full IPv6 address
|
# if there are 7 colons assume its a full IPv6 address
|
||||||
|
# if its 8 then assumed full IPv6 address with a port
|
||||||
# also catch localhost address here
|
# also catch localhost address here
|
||||||
if ( $colon_count == 7 || $host_string eq '::1' ) {
|
if ( $colon_count == 7 || $colon_count == 8 || $host_string eq '::1' ) {
|
||||||
|
if ( $colon_count == 8 ) {
|
||||||
|
$host_string =~ s/(?::(\d+?))$//;
|
||||||
|
$port = $1;
|
||||||
|
}
|
||||||
$self->debug(
|
$self->debug(
|
||||||
5,
|
5,
|
||||||
$self->loc(
|
$self->loc(
|
||||||
'IPv6: u=[_1] h=[_2] p=[_3]',
|
'IPv6: u=[_1] h=[_2] p=[_3] g=[_4]',
|
||||||
$username, $host_string, ''
|
$username, $host_string, $port, $geometry,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
return __PACKAGE__->new(
|
return __PACKAGE__->new(
|
||||||
parse_string => $parse_string,
|
parse_string => $parse_string,
|
||||||
username => $username,
|
username => $username,
|
||||||
hostname => $host_string,
|
hostname => $host_string,
|
||||||
port => q{},
|
port => $port,
|
||||||
|
geometry => $geometry,
|
||||||
type => 'ipv6',
|
type => 'ipv6',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if ( $colon_count > 1
|
if ( $colon_count > 1
|
||||||
&& $colon_count < 8
|
&& $colon_count < 8 )
|
||||||
&& $host_string =~ m/:(\d+)$/xsm )
|
|
||||||
{
|
{
|
||||||
warn 'Ambiguous host string: "', $host_string, '"', $/;
|
warn 'Ambiguous host string: "', $host_string, '"', $/;
|
||||||
warn 'Assuming you meant "[', $host_string, ']"?', $/;
|
warn 'Assuming you meant "[', $host_string, ']"?', $/;
|
||||||
|
@ -218,50 +292,20 @@ sub parse_host_string {
|
||||||
$self->debug(
|
$self->debug(
|
||||||
5,
|
5,
|
||||||
$self->loc(
|
$self->loc(
|
||||||
'Ambiguous IPv6 u=[_1] h=[_2] p=[_3]', $username,
|
'Ambiguous IPv6 u=[_1] h=[_2] p=[_3] g=[_4]',
|
||||||
$host_string, ''
|
$username, $host_string, $port, $geometry,
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
#warn "host_string=$host_string";
|
|
||||||
#warn "username=$username";
|
|
||||||
#warn $self->loc('some string to return');
|
|
||||||
#warn 'debug done, returning';
|
|
||||||
|
|
||||||
return __PACKAGE__->new(
|
return __PACKAGE__->new(
|
||||||
parse_string => $parse_string,
|
parse_string => $parse_string,
|
||||||
username => $username,
|
username => $username,
|
||||||
hostname => $host_string,
|
hostname => $host_string,
|
||||||
port => q{},
|
port => $port,
|
||||||
|
geometry => $geometry,
|
||||||
type => 'ipv6',
|
type => 'ipv6',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
my $port = q{};
|
|
||||||
if ( $host_string =~ s/:(\d+)$// ) {
|
|
||||||
$port = $1;
|
|
||||||
}
|
|
||||||
|
|
||||||
my $hostname = $host_string;
|
|
||||||
|
|
||||||
$self->debug(
|
|
||||||
5,
|
|
||||||
$self->loc(
|
|
||||||
'Default parse u=[_1] h=[_2] p=[_3]',
|
|
||||||
$username, $hostname, $port
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
return __PACKAGE__->new(
|
|
||||||
parse_string => $parse_string,
|
|
||||||
username => $username,
|
|
||||||
hostname => $hostname,
|
|
||||||
port => $port,
|
|
||||||
type => 'name',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
# Due to above rules, we'll never get this far anyhow
|
|
||||||
|
|
||||||
# if we got this far, we didnt parse the host_string properly
|
# if we got this far, we didnt parse the host_string properly
|
||||||
croak(
|
croak(
|
||||||
|
@ -280,9 +324,11 @@ sub check_ssh_hostname {
|
||||||
$self->get_hostname );
|
$self->get_hostname );
|
||||||
|
|
||||||
if ( $ssh_hostname_for{ $self->get_hostname } ) {
|
if ( $ssh_hostname_for{ $self->get_hostname } ) {
|
||||||
|
$self->debug( 5, 'Found' );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
$self->debug( 5, 'Not found' );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -297,26 +343,6 @@ use overload (
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
||||||
=pod
|
|
||||||
|
|
||||||
=head1 NAME
|
|
||||||
|
|
||||||
ClusterSSH::Host - Object representing a host.
|
|
||||||
|
|
||||||
=head1 SYNOPSIS
|
|
||||||
|
|
||||||
use ClusterSSH::Host;
|
|
||||||
|
|
||||||
my $host = ClusterSSH::Host->new({
|
|
||||||
hostname => 'hostname',
|
|
||||||
});
|
|
||||||
my $host = ClusterSSH::Host->parse_host_string('username@hostname:1234');
|
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
|
||||||
|
|
||||||
Object representing a host. Include details to contact the host such as
|
|
||||||
hostname/ipaddress, username and port.
|
|
||||||
|
|
||||||
=head1 METHODS
|
=head1 METHODS
|
||||||
|
|
||||||
=over 4
|
=over 4
|
||||||
|
@ -334,6 +360,10 @@ Create a new host object. 'hostname' is a required arg, 'username' and
|
||||||
|
|
||||||
=item $host->get_master
|
=item $host->get_master
|
||||||
|
|
||||||
|
=item $host->get_geometry
|
||||||
|
|
||||||
|
=item $host->get_type
|
||||||
|
|
||||||
Return specific details about the host
|
Return specific details about the host
|
||||||
|
|
||||||
=item $host->set_username
|
=item $host->set_username
|
||||||
|
@ -342,12 +372,16 @@ Return specific details about the host
|
||||||
|
|
||||||
=item $host->set_master
|
=item $host->set_master
|
||||||
|
|
||||||
|
=item $host->set_geometry
|
||||||
|
|
||||||
|
=item $host->set_type
|
||||||
|
|
||||||
Set specific details about the host after its been created.
|
Set specific details about the host after its been created.
|
||||||
|
|
||||||
=item get_realname
|
=item get_realname
|
||||||
|
|
||||||
If the server name provided is not an IP address (either IPv4 or IPv6)
|
If the server name provided is not an IP address (either IPv4 or IPv6)
|
||||||
attempt to resolve it and retun the discovered names.
|
attempt to resolve it and return the discovered names.
|
||||||
|
|
||||||
=item get_givenname
|
=item get_givenname
|
||||||
|
|
||||||
|
@ -363,6 +397,11 @@ Given a host string, returns a host object. Parses hosts such as
|
||||||
Check the objects hostname to see whether or not it may be configured within
|
Check the objects hostname to see whether or not it may be configured within
|
||||||
the users F< $HOME/.ssh/config > configuration file
|
the users F< $HOME/.ssh/config > configuration file
|
||||||
|
|
||||||
|
=item read_ssh_file
|
||||||
|
|
||||||
|
Method to ease reading in ssh configuration files. Used for grabbing
|
||||||
|
hostnames for validation when used in clusters
|
||||||
|
|
||||||
=over 4
|
=over 4
|
||||||
|
|
||||||
=item host
|
=item host
|
||||||
|
@ -387,21 +426,3 @@ the IPv6 address or a port definition?) and assumes it is part of address.
|
||||||
Use brackets to avoid seeing warning.
|
Use brackets to avoid seeing warning.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
=head1 AUTHOR
|
|
||||||
|
|
||||||
Duncan Ferguson, C<< <duncan_j_ferguson at yahoo.co.uk> >>
|
|
||||||
|
|
||||||
=head1 LICENSE AND COPYRIGHT
|
|
||||||
|
|
||||||
Copyright 1999-2010 Duncan Ferguson.
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms of either: the GNU General Public License as published
|
|
||||||
by the Free Software Foundation; or the Artistic License.
|
|
||||||
|
|
||||||
See http://dev.perl.org/licenses/ for more information.
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
1;
|
|
||||||
|
|
|
@ -1,22 +1,9 @@
|
||||||
package App::ClusterSSH::L10N;
|
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use Locale::Maketext 1.01;
|
package App::ClusterSSH::L10N;
|
||||||
use base qw(Locale::Maketext);
|
|
||||||
|
|
||||||
# This projects primary language is English
|
# ABSTRACT: ClusterSSH::L10N - Base translations module
|
||||||
|
|
||||||
our %Lexicon = ( '_AUTO' => 1, );
|
|
||||||
|
|
||||||
1;
|
|
||||||
|
|
||||||
=pod
|
|
||||||
|
|
||||||
=head1 NAME
|
|
||||||
|
|
||||||
ClusterSSH::L10N - Base translations module
|
|
||||||
|
|
||||||
=head1 SYNOPSIS
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
@ -33,22 +20,15 @@ NOTE: the default language of this module is English.
|
||||||
|
|
||||||
=head1 METHODS
|
=head1 METHODS
|
||||||
|
|
||||||
See Locale::Maketext - there are curently no extra methods in this module.
|
See Locale::Maketext - there are currently no extra methods in this module.
|
||||||
|
|
||||||
=head1 AUTHOR
|
|
||||||
|
|
||||||
Duncan Ferguson, C<< <duncan_j_ferguson at yahoo.co.uk> >>
|
|
||||||
|
|
||||||
=head1 LICENSE AND COPYRIGHT
|
|
||||||
|
|
||||||
Copyright 1999-2010 Duncan Ferguson.
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms of either: the GNU General Public License as published
|
|
||||||
by the Free Software Foundation; or the Artistic License.
|
|
||||||
|
|
||||||
See http://dev.perl.org/licenses/ for more information.
|
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
|
use Locale::Maketext 1.01;
|
||||||
|
use base qw(Locale::Maketext);
|
||||||
|
|
||||||
|
# This projects primary language is English
|
||||||
|
|
||||||
|
our %Lexicon = ( '_AUTO' => 1, );
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
|
@ -1,15 +1,6 @@
|
||||||
package App::ClusterSSH::L10N::en;
|
package App::ClusterSSH::L10N::en;
|
||||||
use base 'App::ClusterSSH::L10N';
|
|
||||||
|
|
||||||
%Lexicon = ( '_AUTO' => 1, );
|
# ABSTRACT: App::ClusterSSH::L10N::en - Base English translations module
|
||||||
|
|
||||||
1;
|
|
||||||
|
|
||||||
=pod
|
|
||||||
|
|
||||||
=head1 NAME
|
|
||||||
|
|
||||||
App::ClusterSSH::L10N::en - Base English translations module
|
|
||||||
|
|
||||||
=head1 SYNOPSIS
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
@ -22,24 +13,14 @@ App::ClusterSSH::L10N::en - Base English translations module
|
||||||
L<Locale::Maketext> based translation module for ClusterSSH. See
|
L<Locale::Maketext> based translation module for ClusterSSH. See
|
||||||
L<Locale::Maketext> for more information and usage.
|
L<Locale::Maketext> for more information and usage.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
use base 'App::ClusterSSH::L10N';
|
||||||
|
|
||||||
|
%Lexicon = ( '_AUTO' => 1, );
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
=head1 METHODS
|
=head1 METHODS
|
||||||
|
|
||||||
No method are exported. See L<Locale::Maketext>.
|
No method are exported. See L<Locale::Maketext>.
|
||||||
|
|
||||||
=head1 AUTHOR
|
|
||||||
|
|
||||||
Duncan Ferguson, C<< <duncan_j_ferguson at yahoo.co.uk> >>
|
|
||||||
|
|
||||||
=head1 LICENSE AND COPYRIGHT
|
|
||||||
|
|
||||||
Copyright 1999-2010 Duncan Ferguson.
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms of either: the GNU General Public License as published
|
|
||||||
by the Free Software Foundation; or the Artistic License.
|
|
||||||
|
|
||||||
See http://dev.perl.org/licenses/ for more information.
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
1;
|
|
||||||
|
|
89
lib/App/ClusterSSH/Range.pm
Normal file
89
lib/App/ClusterSSH/Range.pm
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
package App::ClusterSSH::Range;
|
||||||
|
|
||||||
|
# ABSTRACT: Expand ranges such as {0..1} as well as other bsd_glob specs
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
use App::ClusterSSH::Range;
|
||||||
|
my $range=App::ClusterSSH::Range->new();
|
||||||
|
my @list = $range->expand('range{0..5}');
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
Perform string expansion looking for ranges before then finishing off
|
||||||
|
using C<File::Glob::bsd_glob>.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
use File::Glob;
|
||||||
|
|
||||||
|
=head1 METHODS
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item $range = App::ClusterSSH::Range->new();
|
||||||
|
|
||||||
|
Create a new object to perform range processing
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub new {
|
||||||
|
my ( $class, %args ) = @_;
|
||||||
|
my $self = {%args};
|
||||||
|
return bless $self, $class;
|
||||||
|
}
|
||||||
|
|
||||||
|
=item @expanded = $range->expand(@strings);
|
||||||
|
|
||||||
|
Expand the given strings. Ranges are checked for and processed. The
|
||||||
|
resulting string is then put through File::Glob::bsd_glob before being returned.
|
||||||
|
|
||||||
|
Ranges are of the form:
|
||||||
|
|
||||||
|
base{start..stop}
|
||||||
|
a{0..3} => a0 a1 a2 a3
|
||||||
|
b{4..6,9,12..14} => b4 b5 b6 b9 b12 b13 b14
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub expand {
|
||||||
|
my ( $self, @items ) = @_;
|
||||||
|
|
||||||
|
my $range_regexp = qr/[\w-]*:?\{[\w\.,]+\}/;
|
||||||
|
my @newlist;
|
||||||
|
foreach my $item (@items) {
|
||||||
|
if ( $item !~ m/$range_regexp/ ) {
|
||||||
|
push( @newlist, $item );
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
my ( $base, $spec ) = $item =~ m/^(.*?\{(.*?)\}.*?)$/;
|
||||||
|
|
||||||
|
for my $section ( split( /,/, $spec ) ) {
|
||||||
|
my ( $start, $end );
|
||||||
|
|
||||||
|
if ( $section =~ m/\.\./ ) {
|
||||||
|
( $start, $end ) = split( /\.\./, $section, 2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
$start = $section if ( !defined($start) );
|
||||||
|
$end = $start if ( !defined($end) );
|
||||||
|
|
||||||
|
foreach my $number ( $start .. $end ) {
|
||||||
|
( my $changed = $base ) =~ s/\{$spec\}/$number/;
|
||||||
|
push( @newlist, $changed );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
my @text = map { File::Glob::bsd_glob($_) } @newlist;
|
||||||
|
|
||||||
|
return wantarray ? @text : "@text";
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
68
lib/App/ClusterSSH/Window.pm
Normal file
68
lib/App/ClusterSSH/Window.pm
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
package App::ClusterSSH::Window;
|
||||||
|
|
||||||
|
# ABSTRACT: App::ClusterSSH::Window - Base obejct for different types of window module
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
Base object to allow for configuring and using different types of windows libraries
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
=head1 METHODS
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
use Carp;
|
||||||
|
|
||||||
|
use base qw/ App::ClusterSSH::Base /;
|
||||||
|
|
||||||
|
# Module to contain window generic code and pull in specific code from
|
||||||
|
# an appropriate module
|
||||||
|
|
||||||
|
sub import {
|
||||||
|
my ($class) = @_;
|
||||||
|
|
||||||
|
# If we are building or in test here, just exit
|
||||||
|
# as the build servers will not have Tk installed
|
||||||
|
if ( $ENV{AUTHOR_TESTING} || $ENV{RELEASE_TESTING} ) {
|
||||||
|
print STDERR
|
||||||
|
"skipping initialisation; AUTHOR_TESTING or RELEASE_TESTING are set\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Find what windows module we should be using and just overlay it into
|
||||||
|
# this object
|
||||||
|
my $package_name = __PACKAGE__ . '::Tk';
|
||||||
|
( my $package_path = $package_name ) =~ s{::}{/}g;
|
||||||
|
require "$package_path.pm";
|
||||||
|
$package_name->import();
|
||||||
|
|
||||||
|
{
|
||||||
|
no strict 'refs';
|
||||||
|
push @{ __PACKAGE__ . '::ISA' }, $package_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
my %servers;
|
||||||
|
|
||||||
|
=item $obj = App::ClusterSSH::Window->new({});
|
||||||
|
|
||||||
|
Creates object
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub new {
|
||||||
|
my ( $class, %args ) = @_;
|
||||||
|
my $self = $class->SUPER::new(%args);
|
||||||
|
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
2037
lib/App/ClusterSSH/Window/Tk.pm
Normal file
2037
lib/App/ClusterSSH/Window/Tk.pm
Normal file
File diff suppressed because it is too large
Load diff
182
t/02base.t
182
t/02base.t
|
@ -19,12 +19,12 @@ isa_ok( $base, 'App::ClusterSSH::Base' );
|
||||||
|
|
||||||
diag('testing output') if ( $ENV{TEST_VERBOSE} );
|
diag('testing output') if ( $ENV{TEST_VERBOSE} );
|
||||||
trap {
|
trap {
|
||||||
$base->output('testing');
|
$base->stdout_output('testing');
|
||||||
};
|
};
|
||||||
is( $trap->leaveby, 'return', 'returned ok' );
|
is( $trap->leaveby, 'return', 'returned ok' );
|
||||||
is( $trap->die, undef, 'returned ok' );
|
is( $trap->die, undef, 'returned ok' );
|
||||||
is( $trap->stderr, '', 'Expecting no STDERR' );
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
is( $trap->stdout =~ tr/\n//, 1, 'got correct number of print lines' );
|
is( $trap->stdout =~ tr/\n//, 1, 'got correct number of print lines' );
|
||||||
like( $trap->stdout, qr/\Atesting\n\Z/xsm,
|
like( $trap->stdout, qr/\Atesting\n\Z/xsm,
|
||||||
'checking for expected print output' );
|
'checking for expected print output' );
|
||||||
|
|
||||||
|
@ -68,10 +68,10 @@ trap {
|
||||||
$base = App::ClusterSSH::Base->new( debug => 6, );
|
$base = App::ClusterSSH::Base->new( debug => 6, );
|
||||||
};
|
};
|
||||||
isa_ok( $base, 'App::ClusterSSH::Base' );
|
isa_ok( $base, 'App::ClusterSSH::Base' );
|
||||||
is( $trap->leaveby, 'return', 'returned ok' );
|
is( $trap->leaveby, 'return', 'returned ok' );
|
||||||
is( $trap->die, undef, 'returned ok' );
|
is( $trap->die, undef, 'returned ok' );
|
||||||
is( $trap->stderr, '', 'Expecting no STDERR' );
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
is( $trap->stdout =~ tr/\n//, 1, 'got new() debug output lines' );
|
is( $trap->stdout =~ tr/\n//, 1, 'got new() debug output lines' );
|
||||||
like(
|
like(
|
||||||
$trap->stdout,
|
$trap->stdout,
|
||||||
qr/^Setting\slanguage\sto\s"en"/xsm,
|
qr/^Setting\slanguage\sto\s"en"/xsm,
|
||||||
|
@ -83,10 +83,10 @@ trap {
|
||||||
$base = App::ClusterSSH::Base->new( debug => 6, lang => 'en' );
|
$base = App::ClusterSSH::Base->new( debug => 6, lang => 'en' );
|
||||||
};
|
};
|
||||||
isa_ok( $base, 'App::ClusterSSH::Base' );
|
isa_ok( $base, 'App::ClusterSSH::Base' );
|
||||||
is( $trap->leaveby, 'return', 'returned ok' );
|
is( $trap->leaveby, 'return', 'returned ok' );
|
||||||
is( $trap->die, undef, 'returned ok' );
|
is( $trap->die, undef, 'returned ok' );
|
||||||
is( $trap->stderr, '', 'Expecting no STDERR' );
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
is( $trap->stdout =~ tr/\n//, 1, 'got new() debug output lines' );
|
is( $trap->stdout =~ tr/\n//, 1, 'got new() debug output lines' );
|
||||||
like(
|
like(
|
||||||
$trap->stdout,
|
$trap->stdout,
|
||||||
qr/^Setting\slanguage\sto\s"en"/xsm,
|
qr/^Setting\slanguage\sto\s"en"/xsm,
|
||||||
|
@ -98,10 +98,10 @@ trap {
|
||||||
$base = App::ClusterSSH::Base->new( debug => 6, lang => 'rubbish' );
|
$base = App::ClusterSSH::Base->new( debug => 6, lang => 'rubbish' );
|
||||||
};
|
};
|
||||||
isa_ok( $base, 'App::ClusterSSH::Base' );
|
isa_ok( $base, 'App::ClusterSSH::Base' );
|
||||||
is( $trap->leaveby, 'return', 'returned ok' );
|
is( $trap->leaveby, 'return', 'returned ok' );
|
||||||
is( $trap->die, undef, 'returned ok' );
|
is( $trap->die, undef, 'returned ok' );
|
||||||
is( $trap->stderr, '', 'Expecting no STDERR' );
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
is( $trap->stdout =~ tr/\n//, 1, 'got new() debug output lines' );
|
is( $trap->stdout =~ tr/\n//, 1, 'got new() debug output lines' );
|
||||||
like(
|
like(
|
||||||
$trap->stdout,
|
$trap->stdout,
|
||||||
qr/^Setting\slanguage\sto\s"rubbish"/xsm,
|
qr/^Setting\slanguage\sto\s"rubbish"/xsm,
|
||||||
|
@ -109,23 +109,29 @@ like(
|
||||||
);
|
);
|
||||||
|
|
||||||
$base = undef;
|
$base = undef;
|
||||||
|
my $get_config;
|
||||||
trap {
|
trap {
|
||||||
$base = App::ClusterSSH::Base->new( debug => 7, );
|
$base = App::ClusterSSH::Base->new( debug => 7, );
|
||||||
};
|
};
|
||||||
isa_ok( $base, 'App::ClusterSSH::Base' );
|
isa_ok( $base, 'App::ClusterSSH::Base' );
|
||||||
is( $trap->leaveby, 'return', 'returned ok' );
|
is( $trap->leaveby, 'return', 'returned ok' );
|
||||||
is( $trap->die, undef, 'returned ok' );
|
is( $trap->die, undef, 'returned ok' );
|
||||||
is( $trap->stderr, '', 'Expecting no STDERR' );
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
is( $trap->stdout =~ tr/\n//, 3, 'got new() debug output lines' );
|
is( $trap->stdout =~ tr/\n//, 3, 'got new() debug output lines' );
|
||||||
like(
|
like(
|
||||||
$trap->stdout,
|
$trap->stdout,
|
||||||
qr/^Setting\slanguage\sto\s"en".Arguments\sto\sApp::ClusterSSH::Base->new.*debug\s=>\s7,$/xsm,
|
qr/^Setting\slanguage\sto\s"en".Arguments\sto\sApp::ClusterSSH::Base->new.*debug\s=>\s7,$/xsm,
|
||||||
'got expected new() output'
|
'got expected new() output'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
trap {
|
||||||
|
$get_config = $base->config();
|
||||||
|
};
|
||||||
|
$trap->quiet("No issus with config call");
|
||||||
|
is( $get_config, undef, "config set undef as expected" );
|
||||||
|
|
||||||
# config tests
|
# config tests
|
||||||
$base = undef;
|
$base = undef;
|
||||||
my $get_config;
|
|
||||||
my $object;
|
my $object;
|
||||||
trap {
|
trap {
|
||||||
$base = App::ClusterSSH::Base->new( debug => 3, );
|
$base = App::ClusterSSH::Base->new( debug => 3, );
|
||||||
|
@ -136,6 +142,17 @@ is( $trap->die, undef, 'returned ok' );
|
||||||
is( $trap->stderr, '', 'Expecting no STDERR' );
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
|
||||||
|
$base = undef;
|
||||||
|
trap {
|
||||||
|
$base = App::ClusterSSH::Base->new( debug => 3, parent => 'guardian' );
|
||||||
|
};
|
||||||
|
isa_ok( $base, 'App::ClusterSSH::Base' );
|
||||||
|
is( $trap->leaveby, 'return', 'returned ok' );
|
||||||
|
is( $trap->die, undef, 'returned ok' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $base->parent, 'guardian', 'Expecting no STDOUT' );
|
||||||
|
|
||||||
trap {
|
trap {
|
||||||
$get_config = $base->config();
|
$get_config = $base->config();
|
||||||
};
|
};
|
||||||
|
@ -208,4 +225,125 @@ like(
|
||||||
is( $trap->stderr, '', 'Expecting no STDERR' );
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
is( $trap->stdout, '', 'Got expected STDOUT' );
|
is( $trap->stdout, '', 'Got expected STDOUT' );
|
||||||
|
|
||||||
|
# basic checks - validity of config is tested elsewhere
|
||||||
|
my %config;
|
||||||
|
trap {
|
||||||
|
%config = $object->load_file;
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'die', 'died ok' );
|
||||||
|
isa_ok( $trap->die, 'App::ClusterSSH::Exception',
|
||||||
|
'Caught exception object OK' );
|
||||||
|
is( $trap->die,
|
||||||
|
q{"filename" arg not passed},
|
||||||
|
'missing filename arg die message'
|
||||||
|
);
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
is( $trap->stdout, '', 'Got expected STDOUT' );
|
||||||
|
|
||||||
|
trap {
|
||||||
|
%config = $object->load_file( filename => $Bin . '/15config.t.file1' );
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'die', 'died ok' );
|
||||||
|
isa_ok( $trap->die, 'App::ClusterSSH::Exception',
|
||||||
|
'Caught exception object OK' );
|
||||||
|
is( $trap->die, q{"type" arg not passed}, 'missing type arg die message' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
|
||||||
|
my $get_options;
|
||||||
|
|
||||||
|
$base = undef;
|
||||||
|
trap {
|
||||||
|
$base = App::ClusterSSH::Base->new( debug => 3 );
|
||||||
|
};
|
||||||
|
isa_ok( $base, 'App::ClusterSSH::Base' );
|
||||||
|
is( $trap->leaveby, 'return', 'returned ok' );
|
||||||
|
is( $trap->die, undef, 'returned ok' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $base->parent, undef, 'Expecting no parent set' );
|
||||||
|
|
||||||
|
trap {
|
||||||
|
$get_options = $base->options();
|
||||||
|
};
|
||||||
|
$trap->quiet("No extra output");
|
||||||
|
is( $get_options, undef, "options call correctly unset" );
|
||||||
|
|
||||||
|
$base = undef;
|
||||||
|
trap {
|
||||||
|
$base = App::ClusterSSH::Base->new( debug => 3, parent => 'guardian' );
|
||||||
|
};
|
||||||
|
isa_ok( $base, 'App::ClusterSSH::Base' );
|
||||||
|
is( $trap->leaveby, 'return', 'returned ok' );
|
||||||
|
is( $trap->die, undef, 'returned ok' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $base->parent, 'guardian', 'Expecting no STDOUT' );
|
||||||
|
|
||||||
|
trap {
|
||||||
|
$get_options = $base->options();
|
||||||
|
};
|
||||||
|
$trap->quiet("No extra output");
|
||||||
|
is( $get_options, undef, "options call correctly unset" );
|
||||||
|
|
||||||
|
$base = undef;
|
||||||
|
trap {
|
||||||
|
$base = App::ClusterSSH::Base->new(
|
||||||
|
debug => 3,
|
||||||
|
parent => { config => 'set', options => 'set' }
|
||||||
|
);
|
||||||
|
};
|
||||||
|
isa_ok( $base, 'App::ClusterSSH::Base' );
|
||||||
|
is( $trap->leaveby, 'return', 'returned ok' );
|
||||||
|
is( $trap->die, undef, 'returned ok' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( ref( $base->parent ), 'HASH', 'Expecting no STDOUT' );
|
||||||
|
is( $base->parent->{config}, 'set', 'Expecting no STDOUT' );
|
||||||
|
|
||||||
|
trap {
|
||||||
|
$get_options = $base->options();
|
||||||
|
};
|
||||||
|
is( ref($get_options), '', "options call correctly set" );
|
||||||
|
is( $get_options, 'set', "options call hash value correctly set" );
|
||||||
|
$trap->quiet("No extra output");
|
||||||
|
|
||||||
|
my $sort;
|
||||||
|
trap {
|
||||||
|
$sort = $base->sort;
|
||||||
|
};
|
||||||
|
$trap->quiet("No errors getting 'sort'");
|
||||||
|
|
||||||
|
# NOTE: trap doesnt like passing code refs, so recreate here
|
||||||
|
$sort = $base->sort;
|
||||||
|
is( ref($sort), 'CODE', "got results from sort" );
|
||||||
|
my @sorted = $sort->( 4, 8, 1, 5, 3 );
|
||||||
|
my @expected = ( 1, 3, 4, 5, 8 );
|
||||||
|
is_deeply( \@sorted, \@expected, "simple sort results okay" );
|
||||||
|
|
||||||
|
$base = undef;
|
||||||
|
trap {
|
||||||
|
$base = App::ClusterSSH::Base->new(
|
||||||
|
debug => 3,
|
||||||
|
parent => { config => { use_natural_sort => 1 }, options => 'set' }
|
||||||
|
);
|
||||||
|
};
|
||||||
|
isa_ok( $base, 'App::ClusterSSH::Base' );
|
||||||
|
is( $trap->leaveby, 'return', 'returned ok' );
|
||||||
|
is( $trap->die, undef, 'returned ok' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
|
||||||
|
trap {
|
||||||
|
$sort = $base->sort;
|
||||||
|
};
|
||||||
|
|
||||||
|
# May get an error here if Sort::Naturally is not installed
|
||||||
|
# $trap->quiet("No errors getting 'sort'");
|
||||||
|
is( $trap->leaveby, 'return', 'returned ok' );
|
||||||
|
is( $trap->die, undef, 'returned ok' );
|
||||||
|
is( ref($sort), 'CODE', "got results from sort" );
|
||||||
|
@sorted = $sort->( 4, 8, 1, 5, 3 );
|
||||||
|
@expected = ( 1, 3, 4, 5, 8 );
|
||||||
|
is_deeply( \@sorted, \@expected, "simple sort results okay" );
|
||||||
|
|
||||||
done_testing();
|
done_testing();
|
||||||
|
|
439
t/05getopts.t
Normal file
439
t/05getopts.t
Normal file
|
@ -0,0 +1,439 @@
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
# Force use of English in tests for the moment, for those users that
|
||||||
|
# have a different locale set, since errors are hardcoded below
|
||||||
|
use POSIX qw(setlocale locale_h);
|
||||||
|
setlocale( LC_ALL, "C" );
|
||||||
|
|
||||||
|
package Test::ClusterSSH::Mock;
|
||||||
|
|
||||||
|
# generate purpose object used to simplfy testing
|
||||||
|
|
||||||
|
sub new {
|
||||||
|
my ( $class, %args ) = @_;
|
||||||
|
my $config = {
|
||||||
|
comms => 'testing',
|
||||||
|
key_addhost => 'x',
|
||||||
|
key_clientname => 'x',
|
||||||
|
key_localname => 'x',
|
||||||
|
key_quit => 'x',
|
||||||
|
key_retilehosts => 'x',
|
||||||
|
key_username => 'x',
|
||||||
|
%args
|
||||||
|
};
|
||||||
|
return bless $config, $class;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub parent {
|
||||||
|
my ($self) = @_;
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub VERSION {
|
||||||
|
my ($self) = @_;
|
||||||
|
return 'TESTING';
|
||||||
|
}
|
||||||
|
|
||||||
|
sub config {
|
||||||
|
my ($self) = @_;
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub load_configs {
|
||||||
|
my ($self) = @_;
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub config_file {
|
||||||
|
my ($self) = @_;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
|
package main;
|
||||||
|
|
||||||
|
use FindBin qw($Bin);
|
||||||
|
use lib "$Bin/../lib";
|
||||||
|
|
||||||
|
use Test::More;
|
||||||
|
use Test::Trap;
|
||||||
|
|
||||||
|
BEGIN { use_ok('App::ClusterSSH::Getopt') }
|
||||||
|
|
||||||
|
my $getopts;
|
||||||
|
|
||||||
|
my $mock_object = Test::ClusterSSH::Mock->new();
|
||||||
|
|
||||||
|
$getopts = App::ClusterSSH::Getopt->new( parent => $mock_object );
|
||||||
|
isa_ok( $getopts, 'App::ClusterSSH::Getopt' );
|
||||||
|
trap {
|
||||||
|
$getopts->getopts;
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'getops on new object okay' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
is( $trap->die, undef, 'Expecting no die message' );
|
||||||
|
|
||||||
|
$getopts = App::ClusterSSH::Getopt->new( parent => $mock_object );
|
||||||
|
isa_ok( $getopts, 'App::ClusterSSH::Getopt' );
|
||||||
|
|
||||||
|
trap {
|
||||||
|
$getopts->add_option();
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'die', 'adding an empty option failed' );
|
||||||
|
is( $trap->die,
|
||||||
|
q{No "spec" passed to add_option},
|
||||||
|
'empty add_option message'
|
||||||
|
);
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
|
||||||
|
trap {
|
||||||
|
$getopts->add_option( spec => 'option' );
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'adding an empty option failed' );
|
||||||
|
is( $trap->die, undef, 'no error when spec provided' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
trap {
|
||||||
|
$getopts->getopts;
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'getops on object with spec okay' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
is( $trap->die, undef, 'Expecting no die message' );
|
||||||
|
trap {
|
||||||
|
$getopts->option;
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'calling option' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
is( $trap->die, undef, 'Expecting no die message' );
|
||||||
|
is( $getopts->option, undef, 'Expecting no die message' );
|
||||||
|
|
||||||
|
local @ARGV = '--option1';
|
||||||
|
$getopts = App::ClusterSSH::Getopt->new( parent => $mock_object );
|
||||||
|
trap {
|
||||||
|
$getopts->add_option( spec => 'option1' );
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'adding an empty option failed' );
|
||||||
|
is( $trap->die, undef, 'no error when spec provided' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
trap {
|
||||||
|
$getopts->getopts;
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'getops on object with spec okay' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
is( $trap->die, undef, 'Expecting no die message' );
|
||||||
|
trap {
|
||||||
|
$getopts->option1;
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'calling option' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
is( $trap->die, undef, 'Expecting no die message' );
|
||||||
|
is( $getopts->option1, 1, 'Expecting no die message' );
|
||||||
|
|
||||||
|
local @ARGV = ''; # @ARGV is never undef, but an empty string
|
||||||
|
$getopts = App::ClusterSSH::Getopt->new( parent => $mock_object );
|
||||||
|
trap {
|
||||||
|
$getopts->add_option( spec => 'option1', default => 5 );
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'adding an empty option with a default value' );
|
||||||
|
is( $trap->die, undef, 'no error when spec provided' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
trap {
|
||||||
|
$getopts->getopts;
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'getops on object with spec okay' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
is( $trap->die, undef, 'Expecting no die message' );
|
||||||
|
trap {
|
||||||
|
$getopts->option1;
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'calling option' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
is( $trap->die, undef, 'Expecting no die message' );
|
||||||
|
is( $getopts->option1, 5, 'correct default value' );
|
||||||
|
|
||||||
|
local @ARGV = ( '--option1', '8' );
|
||||||
|
$getopts = App::ClusterSSH::Getopt->new( parent => $mock_object );
|
||||||
|
trap {
|
||||||
|
$getopts->add_option( spec => 'option1=i', default => 5, );
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'adding an empty option failed' );
|
||||||
|
is( $trap->die, undef, 'no error when spec provided' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
trap {
|
||||||
|
$getopts->getopts;
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'getops on object with spec okay' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
is( $trap->die, undef, 'Expecting no die message' );
|
||||||
|
trap {
|
||||||
|
$getopts->option1;
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'calling option' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
is( $trap->die, undef, 'Expecting no die message' );
|
||||||
|
is( $getopts->option1, 8, 'default value overridden' );
|
||||||
|
|
||||||
|
@ARGV = ( '--option1', '--option2', 'string', '--option3', '10' );
|
||||||
|
$getopts = App::ClusterSSH::Getopt->new( parent => $mock_object );
|
||||||
|
trap {
|
||||||
|
$getopts->add_option( spec => 'hidden', hidden => 1, no_acessor => 1, );
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'adding an empty option failed' );
|
||||||
|
is( $trap->die, undef, 'no error when spec provided' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
trap {
|
||||||
|
$getopts->add_option( spec => 'option1', help => 'help for 1' );
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'adding an empty option failed' );
|
||||||
|
is( $trap->die, undef, 'no error when spec provided' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
trap {
|
||||||
|
$getopts->add_option( spec => 'option2|o=s', help => 'help for 2' );
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'adding option2 failed' );
|
||||||
|
is( $trap->die, undef, 'no error when spec provided' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
trap {
|
||||||
|
$getopts->add_option(
|
||||||
|
spec => 'option3|alt_opt|O=i',
|
||||||
|
help => 'help for 3',
|
||||||
|
default => 5
|
||||||
|
);
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'adding option3 failed' );
|
||||||
|
is( $trap->die, undef, 'no error when spec provided' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
trap {
|
||||||
|
$getopts->getopts;
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'getops on object with spec okay' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
is( $trap->die, undef, 'Expecting no die message' );
|
||||||
|
trap {
|
||||||
|
$getopts->option1;
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'calling option1' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
is( $trap->die, undef, 'Expecting no die message' );
|
||||||
|
is( $getopts->option1, 1, 'option1 is as expected' );
|
||||||
|
trap {
|
||||||
|
$getopts->option1;
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'calling option2' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
is( $trap->die, undef, 'Expecting no die message' );
|
||||||
|
is( $getopts->option2, 'string', 'option2 is as expected' );
|
||||||
|
trap {
|
||||||
|
$getopts->option3;
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'calling option3' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
is( $trap->die, undef, 'Expecting no die message' );
|
||||||
|
is( $getopts->option3, 10, 'option3 is as expected' );
|
||||||
|
|
||||||
|
$getopts = App::ClusterSSH::Getopt->new( parent => $mock_object );
|
||||||
|
trap {
|
||||||
|
$getopts->add_common_ssh_options;
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'calling option2' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
is( $trap->die, undef, 'Expecting no die message' );
|
||||||
|
trap {
|
||||||
|
$getopts->getopts;
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'getops on object with spec okay' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
is( $trap->die, undef, 'Expecting no die message' );
|
||||||
|
|
||||||
|
$getopts = App::ClusterSSH::Getopt->new( parent => $mock_object );
|
||||||
|
trap {
|
||||||
|
$getopts->add_common_session_options;
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'calling option2' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
is( $trap->die, undef, 'Expecting no die message' );
|
||||||
|
trap {
|
||||||
|
$getopts->getopts;
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'getops on object with spec okay' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
is( $trap->die, undef, 'Expecting no die message' );
|
||||||
|
|
||||||
|
my $pod;
|
||||||
|
@ARGV = ('--generate-pod');
|
||||||
|
$getopts = App::ClusterSSH::Getopt->new( parent => $mock_object );
|
||||||
|
$getopts->add_option(
|
||||||
|
spec => 'long_opt|l=s',
|
||||||
|
help => 'long opt help',
|
||||||
|
default => 'default string'
|
||||||
|
);
|
||||||
|
$getopts->add_option( spec => 'another_long_opt|n=i', );
|
||||||
|
$getopts->add_option( spec => 'a=s', help => 'short option only', );
|
||||||
|
$getopts->add_option( spec => 'long', help => 'long option only', );
|
||||||
|
trap {
|
||||||
|
$getopts->getopts;
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'exit', 'adding an empty option failed' );
|
||||||
|
is( $trap->die, undef, 'no error when spec provided' );
|
||||||
|
ok( defined( $trap->stdout ), 'Expecting no STDOUT' );
|
||||||
|
$pod = $trap->stdout;
|
||||||
|
|
||||||
|
# run pod through a checker at some point as it should be 'clean'
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
is( $trap->die, undef, 'Expecting no die message' );
|
||||||
|
|
||||||
|
@ARGV = ('--help');
|
||||||
|
$getopts = App::ClusterSSH::Getopt->new( parent => $mock_object );
|
||||||
|
trap {
|
||||||
|
$getopts->getopts;
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'exit', 'adding an empty option failed' );
|
||||||
|
is( $trap->die, undef, 'no error when spec provided' );
|
||||||
|
ok( defined( $trap->stdout ), 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
is( $trap->die, undef, 'Expecting no die message' );
|
||||||
|
|
||||||
|
@ARGV = ('-?');
|
||||||
|
$getopts = App::ClusterSSH::Getopt->new( parent => $mock_object );
|
||||||
|
trap {
|
||||||
|
$getopts->getopts;
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'exit', 'adding an empty option failed' );
|
||||||
|
is( $trap->die, undef, 'no error when spec provided' );
|
||||||
|
ok( defined( $trap->stdout ), 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
is( $trap->die, undef, 'Expecting no die message' );
|
||||||
|
|
||||||
|
@ARGV = ('-v');
|
||||||
|
$getopts = App::ClusterSSH::Getopt->new( parent => $mock_object );
|
||||||
|
trap {
|
||||||
|
$getopts->getopts;
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'exit', 'version option exist okay' );
|
||||||
|
is( $trap->die, undef, 'no error when spec provided' );
|
||||||
|
like( $trap->stdout, qr/^Version: /, 'Version string correct' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
is( $trap->die, undef, 'Expecting no die message' );
|
||||||
|
|
||||||
|
@ARGV = ('-@');
|
||||||
|
$getopts = App::ClusterSSH::Getopt->new( parent => $mock_object );
|
||||||
|
trap {
|
||||||
|
$getopts->getopts;
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'exit', 'adding an empty option failed' );
|
||||||
|
is( $trap->die, undef, 'no error when spec provided' );
|
||||||
|
ok( defined( $trap->stdout ), 'Expecting no STDOUT' );
|
||||||
|
like( $trap->stderr, qr{Unknown option: @}, 'Expecting no STDERR' );
|
||||||
|
is( $trap->die, undef, 'Expecting no die message' );
|
||||||
|
|
||||||
|
# test some common options
|
||||||
|
@ARGV = (
|
||||||
|
'--unique-servers', '--title', 'title', '-p',
|
||||||
|
'22', '--autoquit', '--tile', '--autoclose',
|
||||||
|
'10',
|
||||||
|
);
|
||||||
|
$mock_object->{auto_close} = 0;
|
||||||
|
$mock_object->{auto_quit} = 0;
|
||||||
|
$mock_object->{window_tiling} = 0;
|
||||||
|
$mock_object->{show_history} = 0;
|
||||||
|
$mock_object->{use_all_a_records} = 1;
|
||||||
|
$getopts = App::ClusterSSH::Getopt->new( parent => $mock_object, );
|
||||||
|
trap {
|
||||||
|
$getopts->getopts;
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'adding an empty option failed' );
|
||||||
|
is( $trap->die, undef, 'no error when spec provided' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
is( $trap->die, undef, 'Expecting no die message' );
|
||||||
|
is( $mock_object->{auto_close}, 10, 'auto_close set right' );
|
||||||
|
is( $mock_object->{auto_quit}, 1, 'auto_quit set right' );
|
||||||
|
is( $mock_object->{window_tiling}, 1, 'window_tiling set right' );
|
||||||
|
is( $mock_object->{show_history}, 0, 'show_history set right' );
|
||||||
|
is( $mock_object->{use_all_a_records}, 1, 'use_all_a_records set right' );
|
||||||
|
|
||||||
|
@ARGV = (
|
||||||
|
'--unique-servers', '--title', 'title', '-p', '22', '--autoquit',
|
||||||
|
'--tile', '--show-history', '-A',
|
||||||
|
);
|
||||||
|
$getopts = App::ClusterSSH::Getopt->new( parent => $mock_object, );
|
||||||
|
trap {
|
||||||
|
$getopts->getopts;
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'adding an empty option failed' );
|
||||||
|
is( $trap->die, undef, 'no error when spec provided' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
is( $trap->die, undef, 'Expecting no die message' );
|
||||||
|
is( $mock_object->{auto_close}, 10, 'auto_close set right' );
|
||||||
|
is( $mock_object->{auto_quit}, 0, 'auto_quit set right' );
|
||||||
|
is( $mock_object->{window_tiling}, 0, 'window_tiling set right' );
|
||||||
|
is( $mock_object->{show_history}, 1, 'show_history set right' );
|
||||||
|
is( $mock_object->{use_all_a_records}, 0, 'use_all_a_records set right' );
|
||||||
|
|
||||||
|
TODO: {
|
||||||
|
local $TODO = "explitely test for duplicate options";
|
||||||
|
$getopts = App::ClusterSSH::Getopt->new(
|
||||||
|
parent => Test::ClusterSSH::Mock->new() );
|
||||||
|
trap {
|
||||||
|
$getopts->add_option( spec => 'option1' );
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'adding an empty option failed' );
|
||||||
|
is( $trap->die, undef, 'no error when spec provided' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
trap {
|
||||||
|
$getopts->add_option( spec => 'option1' );
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'die', 'adding an empty option failed' );
|
||||||
|
is( $trap->die, "bling bling", 'no error when spec provided' );
|
||||||
|
is( $trap->stdout, 'bling bling', 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, 'bling bling', 'Expecting no STDERR' );
|
||||||
|
trap {
|
||||||
|
$getopts->getopts;
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'getops on object with spec okay' );
|
||||||
|
is( $trap->stdout, '', 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, '', 'Expecting no STDERR' );
|
||||||
|
is( $trap->die, undef, 'Expecting no die message' );
|
||||||
|
}
|
||||||
|
|
||||||
|
@ARGV = ( '--rows', 5, '--cols', 10 );
|
||||||
|
$getopts = App::ClusterSSH::Getopt->new( parent => $mock_object, );
|
||||||
|
trap {
|
||||||
|
$getopts->getopts;
|
||||||
|
};
|
||||||
|
|
||||||
|
$trap->did_return(" ... returned");
|
||||||
|
$trap->quiet(" ... quietly");
|
||||||
|
is( $mock_object->{cols}, 10, 'cols set correctly' );
|
||||||
|
is( $mock_object->{rows}, 5, 'rows set correctly' );
|
||||||
|
|
||||||
|
done_testing;
|
1017
t/10host.t
1017
t/10host.t
File diff suppressed because it is too large
Load diff
2
t/10host_ssh_include
Normal file
2
t/10host_ssh_include
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
include 10host_ssh_config
|
||||||
|
host server_ssh_included
|
139
t/15config.t
139
t/15config.t
|
@ -1,13 +1,24 @@
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
|
# Force use of English in tests for the moment, for those users that
|
||||||
|
# have a different locale set, since errors are hardcoded below
|
||||||
|
use POSIX qw(setlocale locale_h);
|
||||||
|
setlocale( LC_ALL, "C" );
|
||||||
|
|
||||||
use FindBin qw($Bin $Script);
|
use FindBin qw($Bin $Script);
|
||||||
use lib "$Bin/../lib";
|
use lib "$Bin/../lib";
|
||||||
|
|
||||||
|
# fix path for finding our fake xterm on headless systems that do
|
||||||
|
# not have it installed, such as TravisCI via github
|
||||||
|
BEGIN {
|
||||||
|
$ENV{PATH} = $ENV{PATH} . ':' . $Bin . '/bin';
|
||||||
|
}
|
||||||
|
|
||||||
use Test::More;
|
use Test::More;
|
||||||
use Test::Trap;
|
use Test::Trap;
|
||||||
use File::Which qw(which);
|
use File::Which qw(which);
|
||||||
use File::Temp qw(tempdir);
|
use File::Temp qw(tempdir);
|
||||||
use Test::Differences;
|
use Test::Differences;
|
||||||
|
|
||||||
use Readonly;
|
use Readonly;
|
||||||
|
@ -32,7 +43,7 @@ Readonly::Hash my %default_config => {
|
||||||
terminal_size => "80x24",
|
terminal_size => "80x24",
|
||||||
|
|
||||||
use_hotkeys => "yes",
|
use_hotkeys => "yes",
|
||||||
key_quit => "Control-q",
|
key_quit => "Alt-q",
|
||||||
key_addhost => "Control-Shift-plus",
|
key_addhost => "Control-Shift-plus",
|
||||||
key_clientname => "Alt-n",
|
key_clientname => "Alt-n",
|
||||||
key_history => "Alt-h",
|
key_history => "Alt-h",
|
||||||
|
@ -41,6 +52,10 @@ Readonly::Hash my %default_config => {
|
||||||
key_macros_enable => "Alt-p",
|
key_macros_enable => "Alt-p",
|
||||||
key_paste => "Control-v",
|
key_paste => "Control-v",
|
||||||
key_username => "Alt-u",
|
key_username => "Alt-u",
|
||||||
|
key_user_1 => "Alt-1",
|
||||||
|
key_user_2 => "Alt-2",
|
||||||
|
key_user_3 => "Alt-3",
|
||||||
|
key_user_4 => "Alt-4",
|
||||||
mouse_paste => "Button-2",
|
mouse_paste => "Button-2",
|
||||||
auto_quit => "yes",
|
auto_quit => "yes",
|
||||||
auto_close => 5,
|
auto_close => 5,
|
||||||
|
@ -71,9 +86,14 @@ Readonly::Hash my %default_config => {
|
||||||
telnet_args => "",
|
telnet_args => "",
|
||||||
ssh => 'ssh',
|
ssh => 'ssh',
|
||||||
ssh_args => "",
|
ssh_args => "",
|
||||||
|
sftp => 'sftp',
|
||||||
|
sftp_args => "",
|
||||||
|
|
||||||
|
extra_tag_file => "",
|
||||||
extra_cluster_file => "",
|
extra_cluster_file => "",
|
||||||
external_cluster_command => '',
|
external_cluster_command => '',
|
||||||
|
external_command_mode => '0600',
|
||||||
|
external_command_pipe => '',
|
||||||
|
|
||||||
unmap_on_redraw => "no",
|
unmap_on_redraw => "no",
|
||||||
|
|
||||||
|
@ -81,9 +101,14 @@ Readonly::Hash my %default_config => {
|
||||||
history_width => 40,
|
history_width => 40,
|
||||||
history_height => 10,
|
history_height => 10,
|
||||||
|
|
||||||
|
hostname_override => '',
|
||||||
|
|
||||||
command => q{},
|
command => q{},
|
||||||
|
command_pre => q{},
|
||||||
|
command_post => q{},
|
||||||
title => q{15CONFIG.T},
|
title => q{15CONFIG.T},
|
||||||
comms => q{ssh},
|
comms => q{ssh},
|
||||||
|
hide_menu => 0,
|
||||||
max_host_menu_items => 30,
|
max_host_menu_items => 30,
|
||||||
|
|
||||||
macros_enabled => 'yes',
|
macros_enabled => 'yes',
|
||||||
|
@ -92,20 +117,36 @@ Readonly::Hash my %default_config => {
|
||||||
macro_username => '%u',
|
macro_username => '%u',
|
||||||
macro_newline => '%n',
|
macro_newline => '%n',
|
||||||
macro_version => '%v',
|
macro_version => '%v',
|
||||||
|
macro_user_1 => '%1',
|
||||||
|
macro_user_2 => '%2',
|
||||||
|
macro_user_3 => '%3',
|
||||||
|
macro_user_4 => '%4',
|
||||||
|
|
||||||
|
macro_user_1_command => '',
|
||||||
|
macro_user_2_command => '',
|
||||||
|
macro_user_3_command => '',
|
||||||
|
macro_user_4_command => '',
|
||||||
|
|
||||||
max_addhost_menu_cluster_items => 6,
|
max_addhost_menu_cluster_items => 6,
|
||||||
menu_send_autotearoff => 0,
|
menu_send_autotearoff => 0,
|
||||||
menu_host_autotearoff => 0,
|
menu_host_autotearoff => 0,
|
||||||
|
|
||||||
|
unique_servers => 0,
|
||||||
use_all_a_records => 0,
|
use_all_a_records => 0,
|
||||||
|
use_natural_sort => 0,
|
||||||
|
|
||||||
send_menu_xml_file => $ENV{HOME} . '/.csshrc_send_menu',
|
send_menu_xml_file => $ENV{HOME} . '/.clusterssh/send_menu',
|
||||||
|
|
||||||
|
# Debian #842965
|
||||||
|
auto_wm_decoration_offsets => "no",
|
||||||
|
|
||||||
# other bits inheritted from App::ClusterSSH::Base
|
# other bits inheritted from App::ClusterSSH::Base
|
||||||
debug => 0,
|
lang => 'en',
|
||||||
lang => 'en',
|
|
||||||
|
|
||||||
user => '',
|
user => '',
|
||||||
|
rows => -1,
|
||||||
|
cols => -1,
|
||||||
|
|
||||||
|
fillscreen => 'no',
|
||||||
};
|
};
|
||||||
my %expected = %default_config;
|
my %expected = %default_config;
|
||||||
is_deeply( $config, \%expected, 'default config is correct' );
|
is_deeply( $config, \%expected, 'default config is correct' );
|
||||||
|
@ -164,6 +205,9 @@ $expected{screen_reserve_left} = 100;
|
||||||
$expected{screen_reserve_right} = 100;
|
$expected{screen_reserve_right} = 100;
|
||||||
$expected{screen_reserve_top} = 100;
|
$expected{screen_reserve_top} = 100;
|
||||||
$expected{screen_reserve_bottom} = 160;
|
$expected{screen_reserve_bottom} = 160;
|
||||||
|
|
||||||
|
# Note: the parse_config here removes the key_user_x entries
|
||||||
|
delete( $expected{"key_user_$_"} ) for (qw/ 1 2 3 4 /);
|
||||||
trap {
|
trap {
|
||||||
$config = $config->parse_config_file( $file, );
|
$config = $config->parse_config_file( $file, );
|
||||||
};
|
};
|
||||||
|
@ -246,7 +290,7 @@ isa_ok( $config, "App::ClusterSSH::Config" );
|
||||||
is( $trap->stdout, q{}, 'Expecting no STDOUT' );
|
is( $trap->stdout, q{}, 'Expecting no STDOUT' );
|
||||||
is( $trap->stderr, q{}, 'Expecting no STDERR' );
|
is( $trap->stderr, q{}, 'Expecting no STDERR' );
|
||||||
is_deeply( $config, \%expected, 'amended config is correct' );
|
is_deeply( $config, \%expected, 'amended config is correct' );
|
||||||
is( $path, which('ls'), 'Found correct path to "ls"' );
|
is( $path, 'ls', 'Found correct path to "ls"' );
|
||||||
|
|
||||||
# check for a binary already found
|
# check for a binary already found
|
||||||
my $newpath;
|
my $newpath;
|
||||||
|
@ -259,8 +303,8 @@ isa_ok( $config, "App::ClusterSSH::Config" );
|
||||||
is( $trap->stdout, q{}, 'Expecting no STDOUT' );
|
is( $trap->stdout, q{}, 'Expecting no STDOUT' );
|
||||||
is( $trap->stderr, q{}, 'Expecting no STDERR' );
|
is( $trap->stderr, q{}, 'Expecting no STDERR' );
|
||||||
is_deeply( $config, \%expected, 'amended config is correct' );
|
is_deeply( $config, \%expected, 'amended config is correct' );
|
||||||
is( $path, which('ls'), 'Found correct path to "ls"' );
|
is( $path, 'ls', 'Found correct path to "ls"' );
|
||||||
is( $path, $newpath, 'No change made from find_binary' );
|
is( $path, $newpath, 'No change made from find_binary' );
|
||||||
|
|
||||||
# give false path to force another search
|
# give false path to force another search
|
||||||
trap {
|
trap {
|
||||||
|
@ -272,8 +316,8 @@ isa_ok( $config, "App::ClusterSSH::Config" );
|
||||||
is( $trap->stdout, q{}, 'Expecting no STDOUT' );
|
is( $trap->stdout, q{}, 'Expecting no STDOUT' );
|
||||||
is( $trap->stderr, q{}, 'Expecting no STDERR' );
|
is( $trap->stderr, q{}, 'Expecting no STDERR' );
|
||||||
is_deeply( $config, \%expected, 'amended config is correct' );
|
is_deeply( $config, \%expected, 'amended config is correct' );
|
||||||
is( $path, which('ls'), 'Found correct path to "ls"' );
|
is( $path, 'ls', 'Found correct path to "ls"' );
|
||||||
is( $path, $newpath, 'No change made from find_binary' );
|
is( $path, $newpath, 'No change made from find_binary' );
|
||||||
|
|
||||||
note('Checks on loading configs');
|
note('Checks on loading configs');
|
||||||
note('empty dir');
|
note('empty dir');
|
||||||
|
@ -304,6 +348,9 @@ open( my $csshrc, '>', $ENV{HOME} . '/.csshrc' );
|
||||||
print $csshrc 'auto_quit = no', $/;
|
print $csshrc 'auto_quit = no', $/;
|
||||||
close($csshrc);
|
close($csshrc);
|
||||||
$expected{auto_quit} = 'no';
|
$expected{auto_quit} = 'no';
|
||||||
|
|
||||||
|
# Note: the load_configs here removes the key_user_x entries
|
||||||
|
delete( $expected{"key_user_$_"} ) for (qw/ 1 2 3 4 /);
|
||||||
$config = App::ClusterSSH::Config->new();
|
$config = App::ClusterSSH::Config->new();
|
||||||
trap {
|
trap {
|
||||||
$config->load_configs();
|
$config->load_configs();
|
||||||
|
@ -371,9 +418,9 @@ is_deeply( $config, \%expected, 'amended config is correct' );
|
||||||
|
|
||||||
note('no .csshrc warning, .clusterssh dir plus config + extra config');
|
note('no .csshrc warning, .clusterssh dir plus config + extra config');
|
||||||
open( $csshrc, '>', $ENV{HOME} . '/clusterssh.config' );
|
open( $csshrc, '>', $ENV{HOME} . '/clusterssh.config' );
|
||||||
print $csshrc 'terminal = something', $/;
|
print $csshrc 'terminal_args = something', $/;
|
||||||
close($csshrc);
|
close($csshrc);
|
||||||
$expected{terminal} = 'something';
|
$expected{terminal_args} = 'something';
|
||||||
$config = App::ClusterSSH::Config->new();
|
$config = App::ClusterSSH::Config->new();
|
||||||
trap {
|
trap {
|
||||||
$config->load_configs( $ENV{HOME} . '/clusterssh.config' );
|
$config->load_configs( $ENV{HOME} . '/clusterssh.config' );
|
||||||
|
@ -463,7 +510,34 @@ is( $trap->stderr,
|
||||||
'Expecting no STDERR'
|
'Expecting no STDERR'
|
||||||
);
|
);
|
||||||
|
|
||||||
note('check failure to write default config is caught');
|
SKIP: {
|
||||||
|
skip "Test inappropriate when running as root", 5 if $< == 0;
|
||||||
|
note('move of .csshrc failure');
|
||||||
|
$ENV{HOME} = tempdir( CLEANUP => 1 );
|
||||||
|
open( $csshrc, '>', $ENV{HOME} . '/.csshrc' );
|
||||||
|
print $csshrc "Something", $/;
|
||||||
|
close($csshrc);
|
||||||
|
open( $csshrc, '>', $ENV{HOME} . '/.csshrc.DISABLED' );
|
||||||
|
print $csshrc "Something else", $/;
|
||||||
|
close($csshrc);
|
||||||
|
chmod( 0666, $ENV{HOME} . '/.csshrc.DISABLED', $ENV{HOME} );
|
||||||
|
$config = App::ClusterSSH::Config->new();
|
||||||
|
trap {
|
||||||
|
$config->write_user_config_file();
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'die', 'died ok' );
|
||||||
|
isa_ok( $config, "App::ClusterSSH::Config" );
|
||||||
|
is( $trap->stdout, q{}, 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, q{}, 'Expecting no STDERR' );
|
||||||
|
is( $trap->die,
|
||||||
|
q{Unable to create directory $HOME/.clusterssh: Permission denied}
|
||||||
|
. $/,
|
||||||
|
'Expected die msg ' . $trap->stderr
|
||||||
|
);
|
||||||
|
chmod( 0755, $ENV{HOME} . '/.csshrc.DISABLED', $ENV{HOME} );
|
||||||
|
}
|
||||||
|
|
||||||
|
note('check failure to write default config is caught when loading config');
|
||||||
$ENV{HOME} = tempdir( CLEANUP => 1 );
|
$ENV{HOME} = tempdir( CLEANUP => 1 );
|
||||||
mkdir( $ENV{HOME} . '/.clusterssh' );
|
mkdir( $ENV{HOME} . '/.clusterssh' );
|
||||||
mkdir( $ENV{HOME} . '/.clusterssh/config' );
|
mkdir( $ENV{HOME} . '/.clusterssh/config' );
|
||||||
|
@ -484,34 +558,56 @@ is( $trap->stderr,
|
||||||
|
|
||||||
note('Checking dump');
|
note('Checking dump');
|
||||||
$config = App::ClusterSSH::Config->new(
|
$config = App::ClusterSSH::Config->new(
|
||||||
send_menu_xml_file => $ENV{HOME} . '/.csshrc_send_menu' );
|
send_menu_xml_file => $ENV{HOME} . '/.clusterssh/send_menu', );
|
||||||
|
|
||||||
trap {
|
trap {
|
||||||
$config->dump();
|
$config->dump();
|
||||||
};
|
};
|
||||||
my $expected = qq{# Configuration dump produced by "cssh -u"
|
my $expected = qq{# Configuration dump produced by "cssh -d"
|
||||||
auto_close=5
|
auto_close=5
|
||||||
auto_quit=yes
|
auto_quit=yes
|
||||||
|
auto_wm_decoration_offsets=no
|
||||||
|
cols=-1
|
||||||
|
command_post=
|
||||||
|
command_pre=
|
||||||
console=console
|
console=console
|
||||||
console_args=
|
console_args=
|
||||||
console_position=
|
console_position=
|
||||||
debug=0
|
|
||||||
external_cluster_command=
|
external_cluster_command=
|
||||||
|
external_command_mode=0600
|
||||||
|
external_command_pipe=
|
||||||
extra_cluster_file=
|
extra_cluster_file=
|
||||||
|
extra_tag_file=
|
||||||
|
fillscreen=no
|
||||||
|
hide_menu=0
|
||||||
history_height=10
|
history_height=10
|
||||||
history_width=40
|
history_width=40
|
||||||
|
hostname_override=
|
||||||
key_addhost=Control-Shift-plus
|
key_addhost=Control-Shift-plus
|
||||||
key_clientname=Alt-n
|
key_clientname=Alt-n
|
||||||
key_history=Alt-h
|
key_history=Alt-h
|
||||||
key_localname=Alt-l
|
key_localname=Alt-l
|
||||||
key_macros_enable=Alt-p
|
key_macros_enable=Alt-p
|
||||||
key_paste=Control-v
|
key_paste=Control-v
|
||||||
key_quit=Control-q
|
key_quit=Alt-q
|
||||||
key_retilehosts=Alt-r
|
key_retilehosts=Alt-r
|
||||||
|
key_user_1=Alt-1
|
||||||
|
key_user_2=Alt-2
|
||||||
|
key_user_3=Alt-3
|
||||||
|
key_user_4=Alt-4
|
||||||
key_username=Alt-u
|
key_username=Alt-u
|
||||||
lang=en
|
lang=en
|
||||||
macro_hostname=%h
|
macro_hostname=%h
|
||||||
macro_newline=%n
|
macro_newline=%n
|
||||||
macro_servername=%s
|
macro_servername=%s
|
||||||
|
macro_user_1=%1
|
||||||
|
macro_user_1_command=
|
||||||
|
macro_user_2=%2
|
||||||
|
macro_user_2_command=
|
||||||
|
macro_user_3=%3
|
||||||
|
macro_user_3_command=
|
||||||
|
macro_user_4=%4
|
||||||
|
macro_user_4_command=
|
||||||
macro_username=%u
|
macro_username=%u
|
||||||
macro_version=%v
|
macro_version=%v
|
||||||
macros_enabled=yes
|
macros_enabled=yes
|
||||||
|
@ -520,13 +616,16 @@ max_host_menu_items=30
|
||||||
menu_host_autotearoff=0
|
menu_host_autotearoff=0
|
||||||
menu_send_autotearoff=0
|
menu_send_autotearoff=0
|
||||||
mouse_paste=Button-2
|
mouse_paste=Button-2
|
||||||
|
rows=-1
|
||||||
rsh=rsh
|
rsh=rsh
|
||||||
rsh_args=
|
rsh_args=
|
||||||
screen_reserve_bottom=60
|
screen_reserve_bottom=60
|
||||||
screen_reserve_left=0
|
screen_reserve_left=0
|
||||||
screen_reserve_right=0
|
screen_reserve_right=0
|
||||||
screen_reserve_top=0
|
screen_reserve_top=0
|
||||||
send_menu_xml_file=} . $ENV{HOME} . qq{/.csshrc_send_menu
|
send_menu_xml_file=} . $ENV{HOME} . qq{/.clusterssh/send_menu
|
||||||
|
sftp=sftp
|
||||||
|
sftp_args=
|
||||||
show_history=0
|
show_history=0
|
||||||
ssh=ssh
|
ssh=ssh
|
||||||
ssh_args=
|
ssh_args=
|
||||||
|
@ -546,9 +645,11 @@ terminal_reserve_right=0
|
||||||
terminal_reserve_top=5
|
terminal_reserve_top=5
|
||||||
terminal_size=80x24
|
terminal_size=80x24
|
||||||
terminal_title_opt=-T
|
terminal_title_opt=-T
|
||||||
|
unique_servers=0
|
||||||
unmap_on_redraw=no
|
unmap_on_redraw=no
|
||||||
use_all_a_records=0
|
use_all_a_records=0
|
||||||
use_hotkeys=yes
|
use_hotkeys=yes
|
||||||
|
use_natural_sort=0
|
||||||
#user=
|
#user=
|
||||||
window_tiling=yes
|
window_tiling=yes
|
||||||
window_tiling_direction=right
|
window_tiling_direction=right
|
||||||
|
|
|
@ -5,6 +5,7 @@ command=
|
||||||
comms=ssh
|
comms=ssh
|
||||||
console_position=
|
console_position=
|
||||||
extra_cluster_file=
|
extra_cluster_file=
|
||||||
|
extra_tag_file=
|
||||||
history_height=10
|
history_height=10
|
||||||
history_width=40
|
history_width=40
|
||||||
key_addhost=Control-Shift-plus
|
key_addhost=Control-Shift-plus
|
||||||
|
@ -15,6 +16,10 @@ key_paste=Control-v
|
||||||
key_quit=Control-q
|
key_quit=Control-q
|
||||||
key_retilehosts=Alt-r
|
key_retilehosts=Alt-r
|
||||||
key_username=Alt-n
|
key_username=Alt-n
|
||||||
|
key_user_1=Alt-1
|
||||||
|
key_user_2=Alt-2
|
||||||
|
key_user_3=Alt-3
|
||||||
|
key_user_4=Alt-4
|
||||||
max_host_menu_items=30
|
max_host_menu_items=30
|
||||||
method=ssh
|
method=ssh
|
||||||
mouse_paste=Button-2
|
mouse_paste=Button-2
|
||||||
|
|
96
t/20helper.t
96
t/20helper.t
|
@ -1,16 +1,31 @@
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
|
# Force use of English in tests for the moment, for those users that
|
||||||
|
# have a different locale set, since errors are hardcoded below
|
||||||
|
use POSIX qw(setlocale locale_h);
|
||||||
|
setlocale( LC_ALL, "C" );
|
||||||
|
|
||||||
use FindBin qw($Bin $Script);
|
use FindBin qw($Bin $Script);
|
||||||
use lib "$Bin/../lib";
|
use lib "$Bin/../lib";
|
||||||
|
|
||||||
use Test::More;
|
use Test::More;
|
||||||
use Test::Trap;
|
use Test::Trap;
|
||||||
use File::Which qw(which);
|
use File::Which qw(which);
|
||||||
use File::Temp qw(tempdir);
|
use File::Temp qw(tempdir);
|
||||||
|
|
||||||
use Readonly;
|
use Readonly;
|
||||||
|
|
||||||
|
package App::ClusterSSH::Config;
|
||||||
|
|
||||||
|
sub new {
|
||||||
|
my ( $class, %args ) = @_;
|
||||||
|
my $self = {%args};
|
||||||
|
return bless $self, $class;
|
||||||
|
}
|
||||||
|
|
||||||
|
package main;
|
||||||
|
|
||||||
BEGIN {
|
BEGIN {
|
||||||
use_ok("App::ClusterSSH::Helper") || BAIL_OUT('failed to use module');
|
use_ok("App::ClusterSSH::Helper") || BAIL_OUT('failed to use module');
|
||||||
}
|
}
|
||||||
|
@ -20,18 +35,71 @@ my $helper;
|
||||||
$helper = App::ClusterSSH::Helper->new();
|
$helper = App::ClusterSSH::Helper->new();
|
||||||
isa_ok( $helper, 'App::ClusterSSH::Helper' );
|
isa_ok( $helper, 'App::ClusterSSH::Helper' );
|
||||||
|
|
||||||
#note('check failure to write default config is caught');
|
my $script;
|
||||||
#$ENV{HOME} = tempdir( CLEANUP => 1 );
|
|
||||||
#mkdir($ENV{HOME}.'/.clusterssh');
|
trap {
|
||||||
#mkdir($ENV{HOME}.'/.clusterssh/config');
|
$script = $helper->script;
|
||||||
#$config = App::ClusterSSH::Config->new();
|
};
|
||||||
#trap {
|
is( $trap->leaveby, 'die', 'returned ok' );
|
||||||
# $config->load_configs();
|
is( $trap->stdout, q{}, 'Expecting no STDOUT' );
|
||||||
#};
|
is( $trap->stderr, q{}, 'Expecting no STDERR' );
|
||||||
#is( $trap->leaveby, 'return', 'returned ok' );
|
is( $trap->die, 'No configuration provided or in wrong format', 'no config' );
|
||||||
#isa_ok( $config, "App::ClusterSSH::Config" );
|
|
||||||
#isa_ok( $config, "App::ClusterSSH::Config" );
|
trap {
|
||||||
#is( $trap->stdout, q{}, 'Expecting no STDOUT' );
|
$script = $helper->script( something => 'nothing' );
|
||||||
#is( $trap->stderr, q{Unable to write default $HOME/.clusterssh/config: Is a directory}.$/, 'Expecting no STDERR' );
|
};
|
||||||
|
is( $trap->leaveby, 'die', 'returned ok' );
|
||||||
|
is( $trap->stdout, q{}, 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, q{}, 'Expecting no STDERR' );
|
||||||
|
is( $trap->die, 'No configuration provided or in wrong format',
|
||||||
|
'bad format' );
|
||||||
|
|
||||||
|
my $mock_config = App::ClusterSSH::Config->new();
|
||||||
|
trap {
|
||||||
|
$script = $helper->script($mock_config);
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'die', 'returned ok' );
|
||||||
|
is( $trap->stdout, q{}, 'Expecting no STDOUT' );
|
||||||
|
|
||||||
|
# ignore stderr here as it will complain about missing xxx_arg var
|
||||||
|
#is( $trap->stderr, q{}, 'Expecting no STDERR' );
|
||||||
|
is( $trap->die, q{Config 'comms' not provided}, 'missing arg' );
|
||||||
|
|
||||||
|
$mock_config->{comms} = 'method';
|
||||||
|
trap {
|
||||||
|
$script = $helper->script($mock_config);
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'die', 'returned ok' );
|
||||||
|
is( $trap->stdout, q{}, 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, q{}, 'Expecting no STDERR' );
|
||||||
|
is( $trap->die, q{Config 'method' not provided}, 'missing arg' );
|
||||||
|
|
||||||
|
$mock_config->{method} = 'binary';
|
||||||
|
trap {
|
||||||
|
$script = $helper->script($mock_config);
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'die', 'returned ok' );
|
||||||
|
is( $trap->stdout, q{}, 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, q{}, 'Expecting no STDERR' );
|
||||||
|
is( $trap->die, q{Config 'method_args' not provided}, 'missing arg' );
|
||||||
|
|
||||||
|
$mock_config->{method_args} = 'rubbish';
|
||||||
|
$mock_config->{command} = 'echo';
|
||||||
|
$mock_config->{auto_close} = 5;
|
||||||
|
trap {
|
||||||
|
$script = $helper->script($mock_config);
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'returned ok' );
|
||||||
|
is( $trap->stdout, q{}, 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, q{}, 'Expecting no STDERR' );
|
||||||
|
is( $trap->die, undef, 'not died' );
|
||||||
|
|
||||||
|
trap {
|
||||||
|
eval {$script};
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'returned ok' );
|
||||||
|
is( $trap->stdout, q{}, 'Expecting no STDOUT' );
|
||||||
|
is( $trap->stderr, q{}, 'Expecting no STDERR' );
|
||||||
|
is( $trap->die, undef, 'not died' );
|
||||||
|
|
||||||
done_testing();
|
done_testing();
|
||||||
|
|
258
t/30cluster.t
258
t/30cluster.t
|
@ -1,22 +1,64 @@
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
|
# Force use of English in tests for the moment, for those users that
|
||||||
|
# have a different locale set, since errors are hardcoded below
|
||||||
|
use POSIX qw(setlocale locale_h);
|
||||||
|
setlocale( LC_ALL, "C" );
|
||||||
|
|
||||||
use FindBin qw($Bin $Script);
|
use FindBin qw($Bin $Script);
|
||||||
use lib "$Bin/../lib";
|
use lib "$Bin/../lib";
|
||||||
|
|
||||||
use Test::More;
|
use Test::More;
|
||||||
use Test::Trap;
|
use Test::Trap;
|
||||||
use File::Which qw(which);
|
use File::Which qw(which);
|
||||||
use File::Temp qw(tempdir);
|
|
||||||
use English '-no_match_vars';
|
use English '-no_match_vars';
|
||||||
|
|
||||||
use Readonly;
|
use Readonly;
|
||||||
|
|
||||||
BEGIN {
|
package Test::ClusterSSH::Mock;
|
||||||
use_ok("App::ClusterSSH::Cluster") || BAIL_OUT('failed to use module');
|
|
||||||
|
# generate purpose object used to simplfy testing
|
||||||
|
|
||||||
|
sub new {
|
||||||
|
my ( $class, %args ) = @_;
|
||||||
|
my $config = {%args};
|
||||||
|
return bless $config, $class;
|
||||||
}
|
}
|
||||||
|
|
||||||
my $cluster1 = App::ClusterSSH::Cluster->new();
|
sub parent {
|
||||||
|
my ($self) = @_;
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub config {
|
||||||
|
my ($self) = @_;
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub load_configs {
|
||||||
|
my ($self) = @_;
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub config_file {
|
||||||
|
my ($self) = @_;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
|
package main;
|
||||||
|
|
||||||
|
BEGIN {
|
||||||
|
$ENV{PATH} = $ENV{PATH} . ':' . $Bin . '/bin';
|
||||||
|
use_ok("App::ClusterSSH::Cluster") || BAIL_OUT('failed to use module');
|
||||||
|
use_ok("App::ClusterSSH::Config") || BAIL_OUT('failed to use module');
|
||||||
|
}
|
||||||
|
|
||||||
|
my $mock_object = Test::ClusterSSH::Mock->new();
|
||||||
|
|
||||||
|
my $cluster1 = App::ClusterSSH::Cluster->new( parent => $mock_object );
|
||||||
isa_ok( $cluster1, 'App::ClusterSSH::Cluster' );
|
isa_ok( $cluster1, 'App::ClusterSSH::Cluster' );
|
||||||
|
|
||||||
my $cluster2 = App::ClusterSSH::Cluster->new();
|
my $cluster2 = App::ClusterSSH::Cluster->new();
|
||||||
|
@ -42,21 +84,23 @@ isa_ok( $cluster1, 'App::ClusterSSH::Cluster' );
|
||||||
|
|
||||||
# no point running this test as root since root cannot be blocked
|
# no point running this test as root since root cannot be blocked
|
||||||
# from accessing the file
|
# from accessing the file
|
||||||
if ( $EUID != 0 ) {
|
TODO: {
|
||||||
my $no_read = $Bin . '/30cluster.cannot_read';
|
if ( $EUID != 0 ) {
|
||||||
chmod 0000, $no_read;
|
my $no_read = $Bin . '/30cluster.cannot_read';
|
||||||
trap {
|
chmod 0000, $no_read;
|
||||||
$cluster1->read_cluster_file($no_read);
|
trap {
|
||||||
};
|
$cluster1->read_cluster_file($no_read);
|
||||||
chmod 0644, $no_read;
|
};
|
||||||
isa_ok( $trap->die, 'App::ClusterSSH::Exception::LoadFile' );
|
chmod 0644, $no_read;
|
||||||
is( $trap->die,
|
isa_ok( $trap->die, 'App::ClusterSSH::Exception::LoadFile' );
|
||||||
"Unable to read file $no_read: Permission denied",
|
is( $trap->die,
|
||||||
'Error on reading an existing file ok'
|
"Unable to read file $no_read: Permission denied",
|
||||||
);
|
'Error on reading an existing file ok'
|
||||||
}
|
);
|
||||||
else {
|
}
|
||||||
pass('Cannot test for lack of read access when run as root');
|
else {
|
||||||
|
pass('Cannot test for lack of read access when run as root');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$expected{tag1} = ['host1'];
|
$expected{tag1} = ['host1'];
|
||||||
|
@ -88,34 +132,82 @@ is( scalar $cluster1->get_tag('default'),
|
||||||
'Count correct'
|
'Count correct'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
my $tags;
|
||||||
|
trap {
|
||||||
|
$tags = $cluster1->get_tag('does_not_exist');
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'non-existant tag returns correctly' );
|
||||||
|
is( $trap->stdout, '', 'no stdout for non-existant get_tag' );
|
||||||
|
is( $trap->stderr, '', 'no stderr for non-existant get_tag' );
|
||||||
|
is( $tags, undef, 'non-existant tag returns undef' );
|
||||||
|
|
||||||
|
@default_expected
|
||||||
|
= sort qw/ default people tag1 tag2 tag3 tag10 tag20 tag30 tag40 tag50 /;
|
||||||
|
trap {
|
||||||
|
@default = $cluster1->list_tags;
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'list_tags returned okay' );
|
||||||
|
is( $trap->stdout, '', 'no stdout for non-existant get_tag' );
|
||||||
|
is( $trap->stderr, '', 'no stderr for non-existant get_tag' );
|
||||||
|
is_deeply( \@default, \@default_expected, 'tag list correct' );
|
||||||
|
|
||||||
|
my $count;
|
||||||
|
trap {
|
||||||
|
$count = $cluster1->list_tags;
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'list_tags returned okay' );
|
||||||
|
is( $trap->stdout, '', 'no stdout for non-existant get_tag' );
|
||||||
|
is( $trap->stderr, '', 'no stderr for non-existant get_tag' );
|
||||||
|
is_deeply( $count, 10, 'tag list count correct' );
|
||||||
|
|
||||||
# now checks against running an external command
|
# now checks against running an external command
|
||||||
|
|
||||||
my @external_expected;
|
my @external_expected;
|
||||||
|
|
||||||
@external_expected
|
# text fetching external clusters when no command set or runnable
|
||||||
= $cluster1->get_external_clusters("$Bin/external_cluster_command");
|
#$mock_object->{external_cluster_command} = '/tmp/doesnt_exist';
|
||||||
|
trap {
|
||||||
|
@external_expected = $cluster1->_run_external_clusters();
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'non-existant tag returns correctly' );
|
||||||
|
is( $trap->stdout, '', 'no stdout for non-existant get_tag' );
|
||||||
|
is( $trap->stderr, '', 'no stderr for non-existant get_tag' );
|
||||||
|
is( $tags, undef, 'non-existant tag returns undef' );
|
||||||
|
@external_expected = $cluster1->list_external_clusters();
|
||||||
|
is_deeply( \@external_expected, [], 'External command doesnt exist' );
|
||||||
|
is( scalar $cluster1->list_external_clusters,
|
||||||
|
0, 'External command failed tag count' );
|
||||||
|
|
||||||
|
$mock_object->{external_cluster_command} = "$Bin/external_cluster_command";
|
||||||
|
|
||||||
|
@external_expected = $cluster1->list_external_clusters();
|
||||||
|
is_deeply(
|
||||||
|
\@external_expected,
|
||||||
|
[qw/ tag100 tag200 tag300 tag400 /],
|
||||||
|
'External command no args'
|
||||||
|
);
|
||||||
|
is( scalar $cluster1->list_external_clusters,
|
||||||
|
4, 'External command tag count' );
|
||||||
|
|
||||||
|
@external_expected = $cluster1->get_external_clusters();
|
||||||
is_deeply( \@external_expected, [], 'External command no args' );
|
is_deeply( \@external_expected, [], 'External command no args' );
|
||||||
|
|
||||||
@external_expected = $cluster1->get_external_clusters(
|
@external_expected = $cluster1->get_external_clusters("tag1 tag2");
|
||||||
"$Bin/external_cluster_command tag1 tag2");
|
|
||||||
is_deeply( \@external_expected, [qw/tag1 tag2 /],
|
is_deeply( \@external_expected, [qw/tag1 tag2 /],
|
||||||
'External command: 2 args passed through' );
|
'External command: 2 args passed through' );
|
||||||
|
|
||||||
@external_expected = $cluster1->get_external_clusters(
|
@external_expected = $cluster1->get_external_clusters("tag100");
|
||||||
"$Bin/external_cluster_command tag100");
|
|
||||||
is_deeply( \@external_expected, [qw/host100 /],
|
is_deeply( \@external_expected, [qw/host100 /],
|
||||||
'External command: 1 tag expanded to one host' );
|
'External command: 1 tag expanded to one host' );
|
||||||
|
|
||||||
@external_expected = $cluster1->get_external_clusters(
|
@external_expected = $cluster1->get_external_clusters("tag200");
|
||||||
"$Bin/external_cluster_command tag200");
|
|
||||||
is_deeply(
|
is_deeply(
|
||||||
\@external_expected,
|
\@external_expected,
|
||||||
[qw/host200 host205 host210 /],
|
[qw/host200 host205 host210 /],
|
||||||
'External command: 1 tag expanded to 3 hosts and sorted'
|
'External command: 1 tag expanded to 3 hosts and sorted'
|
||||||
);
|
);
|
||||||
|
|
||||||
@external_expected = $cluster1->get_external_clusters(
|
@external_expected = $cluster1->get_external_clusters("tag400");
|
||||||
"$Bin/external_cluster_command tag400");
|
|
||||||
is_deeply(
|
is_deeply(
|
||||||
\@external_expected,
|
\@external_expected,
|
||||||
[ qw/host100 host200 host205 host210 host300 host325 host350 host400 host401 /
|
[ qw/host100 host200 host205 host210 host300 host325 host350 host400 host401 /
|
||||||
|
@ -134,8 +226,7 @@ if ( $ENV{TEST_VERBOSE} ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
trap {
|
trap {
|
||||||
@external_expected = $cluster1->get_external_clusters(
|
@external_expected = $cluster1->get_external_clusters("-x $redirect");
|
||||||
"$Bin/external_cluster_command -x $redirect");
|
|
||||||
};
|
};
|
||||||
like(
|
like(
|
||||||
$trap->die,
|
$trap->die,
|
||||||
|
@ -146,8 +237,7 @@ is( $trap->stdout, '', 'External command: no stdout from perl code' );
|
||||||
is( $trap->stderr, '', 'External command: no stderr from perl code' );
|
is( $trap->stderr, '', 'External command: no stderr from perl code' );
|
||||||
|
|
||||||
trap {
|
trap {
|
||||||
@external_expected = $cluster1->get_external_clusters(
|
@external_expected = $cluster1->get_external_clusters("-q $redirect");
|
||||||
"$Bin/external_cluster_command -q $redirect");
|
|
||||||
};
|
};
|
||||||
like(
|
like(
|
||||||
$trap->die,
|
$trap->die,
|
||||||
|
@ -157,6 +247,108 @@ like(
|
||||||
is( $trap->stdout, '', 'External command: no stdout from perl code' );
|
is( $trap->stdout, '', 'External command: no stdout from perl code' );
|
||||||
is( $trap->stderr, '', 'External command: no stderr from perl code' );
|
is( $trap->stderr, '', 'External command: no stderr from perl code' );
|
||||||
|
|
||||||
|
# check reading of cluster files
|
||||||
|
trap {
|
||||||
|
$cluster1->get_cluster_entries( $Bin . '/30cluster.file3' );
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'exit okay on get_cluster_entries' );
|
||||||
|
is( $trap->stdout, '', 'no stdout for get_cluster_entries' );
|
||||||
|
is( $trap->stderr, '', 'no stderr for get_cluster_entries' );
|
||||||
|
|
||||||
|
# check reading of tag files
|
||||||
|
trap {
|
||||||
|
$cluster1->get_tag_entries( $Bin . '/30cluster.tag1' );
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'exit okay on get_tag_entries' );
|
||||||
|
is( $trap->stdout, '', 'no stdout for get_tag_entries' );
|
||||||
|
is( $trap->stderr, '', 'no stderr for get_tag_entries' );
|
||||||
|
|
||||||
|
# This step is required for using find_binary within the underlying
|
||||||
|
# code of the following methods
|
||||||
|
$cluster1->set_config( App::ClusterSSH::Config->new() );
|
||||||
|
|
||||||
|
# test bash expansion
|
||||||
|
my @expected = ( 'aa', 'ab', 'ac' );
|
||||||
|
$cluster1->register_tag( 'glob1', 'a{a,b,c}' );
|
||||||
|
@got = $cluster2->get_tag('glob1');
|
||||||
|
is_deeply( \@got, \@expected, 'glob1 expansion, words' )
|
||||||
|
or diag explain @got;
|
||||||
|
|
||||||
|
@expected = ( 'ax', 'ay', 'az' );
|
||||||
|
$cluster1->register_tag( 'glob2', 'a{x..z}' );
|
||||||
|
@got = $cluster2->get_tag('glob2');
|
||||||
|
is_deeply( \@got, \@expected, 'glob2 expansion, words' )
|
||||||
|
or diag explain @got;
|
||||||
|
|
||||||
|
@expected = ( 'b1', 'b2', 'b3' );
|
||||||
|
$cluster1->register_tag( 'glob3', 'b{1..3}' );
|
||||||
|
@got = $cluster2->get_tag('glob3');
|
||||||
|
is_deeply( \@got, \@expected, 'glob3 expansion, number range' )
|
||||||
|
or diag explain @got;
|
||||||
|
|
||||||
|
@expected = ( 'ca', 'cb', 'cc', 'd7', 'd8', 'd9' );
|
||||||
|
$cluster1->register_tag( 'glob4', 'c{a..c}', 'd{7..9}' );
|
||||||
|
@got = $cluster2->get_tag('glob4');
|
||||||
|
is_deeply( \@got, \@expected, 'glob4 expansion, mixed' )
|
||||||
|
or diag explain @got;
|
||||||
|
|
||||||
|
# make sure reasonable expansions get through with no nasty metachars
|
||||||
|
# This one does not work due to the way File::Glob works
|
||||||
|
#@expected = ( 'cd..f}', 'c{a..c' );
|
||||||
|
@expected = ( 'c', 'cd..f}' );
|
||||||
|
$cluster1->register_tag( 'glob5', 'c{a..c', 'cd..f}' );
|
||||||
|
@got = $cluster2->get_tag('glob5');
|
||||||
|
is_deeply( \@got, \@expected, 'glob5 expansion, mixed' )
|
||||||
|
or diag explain @got;
|
||||||
|
|
||||||
|
@expected = ();
|
||||||
|
trap {
|
||||||
|
$cluster1->register_tag( 'glob6', 'c{a..c} ; echo NASTY' );
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'didnt die on nasty chars' );
|
||||||
|
is( $trap->die, undef, 'didnt die on nasty chars' );
|
||||||
|
is( $trap->stdout, q{}, 'Expecting no STDOUT' );
|
||||||
|
like(
|
||||||
|
$trap->stderr,
|
||||||
|
qr/Bad characters picked up in tag 'glob6':.*/,
|
||||||
|
'warned on nasty chars'
|
||||||
|
);
|
||||||
|
@got = $cluster2->get_tag('glob6');
|
||||||
|
is_deeply( \@got, \@expected, 'glob6 expansion, nasty chars' )
|
||||||
|
or diag explain @got;
|
||||||
|
|
||||||
|
@expected = ();
|
||||||
|
trap {
|
||||||
|
$cluster1->register_tag( 'glob7', 'c{a..b} `echo NASTY`' );
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'didnt die on nasty chars' );
|
||||||
|
is( $trap->die, undef, 'didnt die on nasty chars' );
|
||||||
|
is( $trap->stdout, q{}, 'Expecting no STDOUT' );
|
||||||
|
like(
|
||||||
|
$trap->stderr,
|
||||||
|
qr/Bad characters picked up in tag 'glob7':.*/,
|
||||||
|
'warned on nasty chars'
|
||||||
|
);
|
||||||
|
@got = $cluster2->get_tag('glob7');
|
||||||
|
is_deeply( \@got, \@expected, 'glob7 expansion, nasty chars' )
|
||||||
|
or diag explain @got;
|
||||||
|
|
||||||
|
@expected = ();
|
||||||
|
trap {
|
||||||
|
$cluster1->register_tag( 'glob8', 'c{a..b} $!', );
|
||||||
|
};
|
||||||
|
is( $trap->leaveby, 'return', 'didnt die on nasty chars' );
|
||||||
|
is( $trap->die, undef, 'didnt die on nasty chars' );
|
||||||
|
is( $trap->stdout, q{}, 'Expecting no STDOUT' );
|
||||||
|
like(
|
||||||
|
$trap->stderr,
|
||||||
|
qr/Bad characters picked up in tag 'glob8':.*/,
|
||||||
|
'warned on nasty chars'
|
||||||
|
);
|
||||||
|
@got = $cluster2->get_tag('glob8');
|
||||||
|
is_deeply( \@got, \@expected, 'glob8 expansion, nasty chars' )
|
||||||
|
or diag explain @got;
|
||||||
|
|
||||||
done_testing();
|
done_testing();
|
||||||
|
|
||||||
sub test_expected {
|
sub test_expected {
|
||||||
|
|
|
@ -1,9 +1,20 @@
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
|
# Force use of English in tests for the moment, for those users that
|
||||||
|
# have a different locale set, since errors are hardcoded below
|
||||||
|
use POSIX qw(setlocale locale_h);
|
||||||
|
setlocale( LC_ALL, "C" );
|
||||||
|
|
||||||
use FindBin qw($Bin $Script);
|
use FindBin qw($Bin $Script);
|
||||||
use lib "$Bin/../lib";
|
use lib "$Bin/../lib";
|
||||||
|
|
||||||
|
# fix path for finding our fake xterm on headless systems that do
|
||||||
|
# not have it installed, such as TravisCI via github
|
||||||
|
BEGIN {
|
||||||
|
$ENV{PATH} = $ENV{PATH} . ':' . $Bin . '/bin';
|
||||||
|
}
|
||||||
|
|
||||||
use Test::More;
|
use Test::More;
|
||||||
use Test::Trap;
|
use Test::Trap;
|
||||||
use File::Which qw(which);
|
use File::Which qw(which);
|
||||||
|
@ -18,4 +29,24 @@ $app = App::ClusterSSH->new();
|
||||||
isa_ok( $app, 'App::ClusterSSH' );
|
isa_ok( $app, 'App::ClusterSSH' );
|
||||||
isa_ok( $app->config, 'App::ClusterSSH::Config' );
|
isa_ok( $app->config, 'App::ClusterSSH::Config' );
|
||||||
|
|
||||||
|
for my $submod (qw/ cluster helper options window /) {
|
||||||
|
trap {
|
||||||
|
$app->$submod;
|
||||||
|
};
|
||||||
|
$trap->quiet("$submod loaded okay");
|
||||||
|
}
|
||||||
|
|
||||||
|
trap {
|
||||||
|
$app->exit_prog;
|
||||||
|
};
|
||||||
|
$trap->quiet("No errors from exit_prog call");
|
||||||
|
|
||||||
|
my @provided = (qw/ one one one two two three four four four /);
|
||||||
|
my @expected = sort (qw/ one two three four /);
|
||||||
|
my @got;
|
||||||
|
trap {
|
||||||
|
@got = sort $app->remove_repeated_servers(@provided);
|
||||||
|
};
|
||||||
|
is_deeply( \@got, \@expected, "Repeated servers removed okay" );
|
||||||
|
|
||||||
done_testing();
|
done_testing();
|
||||||
|
|
8
t/bin/xterm
Executable file
8
t/bin/xterm
Executable file
|
@ -0,0 +1,8 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
|
||||||
|
# small 'fake' script to allow xterm to be found when performing tests
|
||||||
|
# on systems that do not have it
|
||||||
|
|
||||||
|
warn "$_=$ENV{$_}", $/ for ( sort keys %ENV ) if ( $ENV{TEST_VERBOSE} );
|
||||||
|
|
||||||
|
exit 0
|
9
t/changes.t
Normal file
9
t/changes.t
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
use Test::More;
|
||||||
|
|
||||||
|
unless ( $ENV{RELEASE_TESTING} ) {
|
||||||
|
plan( skip_all => "Author tests not required for installation" );
|
||||||
|
}
|
||||||
|
|
||||||
|
eval 'use Test::CPAN::Changes';
|
||||||
|
plan skip_all => 'Test::CPAN::Changes required for this test' if $@;
|
||||||
|
changes_ok();
|
|
@ -1,4 +1,4 @@
|
||||||
#!/usr/bin/perl
|
#!/usr/bin/env perl
|
||||||
#
|
#
|
||||||
# test script for proving external command for fetching tags works
|
# test script for proving external command for fetching tags works
|
||||||
#
|
#
|
||||||
|
@ -7,7 +7,14 @@ use warnings;
|
||||||
use Getopt::Std;
|
use Getopt::Std;
|
||||||
|
|
||||||
my $opt = {};
|
my $opt = {};
|
||||||
getopts( 'qx', $opt );
|
getopts( 'Lqx', $opt );
|
||||||
|
|
||||||
|
my %tag_lookup = (
|
||||||
|
tag100 => [qw/ host100 /],
|
||||||
|
tag200 => [qw/ host200 host210 host205 /],
|
||||||
|
tag300 => [qw/ host300 host350 host325 /],
|
||||||
|
tag400 => [qw/ tag100 tag200 tag300 host400 host401 /],
|
||||||
|
);
|
||||||
|
|
||||||
# if we get '-q' option, force an error
|
# if we get '-q' option, force an error
|
||||||
if ( $opt->{q} ) {
|
if ( $opt->{q} ) {
|
||||||
|
@ -21,12 +28,11 @@ if ( $opt->{x} ) {
|
||||||
exit 5;
|
exit 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
my %tag_lookup = (
|
# '-L' means list out available tags
|
||||||
tag100 => [qw/ host100 /],
|
if ( $opt->{L} ) {
|
||||||
tag200 => [qw/ host200 host210 host205 /],
|
print join( ' ', sort keys %tag_lookup ), $/;
|
||||||
tag300 => [qw/ host300 host350 host325 /],
|
exit 0;
|
||||||
tag400 => [qw/ tag100 tag200 tag300 host400 host401 /],
|
}
|
||||||
);
|
|
||||||
|
|
||||||
my @lookup = @ARGV;
|
my @lookup = @ARGV;
|
||||||
|
|
||||||
|
|
11
t/manifest.t
11
t/manifest.t
|
@ -1,11 +0,0 @@
|
||||||
use Test::More;
|
|
||||||
|
|
||||||
# This is the common idiom for author test modules like this, but see
|
|
||||||
# the full example in examples/checkmanifest.t and, more importantly,
|
|
||||||
# Adam Kennedy's article: http://use.perl.org/~Alias/journal/38822
|
|
||||||
eval 'use Test::DistManifest';
|
|
||||||
if ($@) {
|
|
||||||
plan skip_all => 'Test::DistManifest required to test MANIFEST';
|
|
||||||
}
|
|
||||||
|
|
||||||
manifest_ok( 'MANIFEST', 'MANIFEST.SKIP' );
|
|
4
t/perltidyrc
Normal file
4
t/perltidyrc
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
# perltidy to Perl Best Practices standard
|
||||||
|
-pbp -nst -nse
|
||||||
|
## For use in ~/.perltidyrc
|
||||||
|
# --backup-and-modify-in-place
|
|
@ -2,18 +2,10 @@ use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use Test::More;
|
use Test::More;
|
||||||
|
|
||||||
# Ensure a recent version of Test::Pod::Coverage
|
eval "use Test::Pod::Coverage 1.00";
|
||||||
my $min_tpc = 1.08;
|
plan skip_all => "Test::Pod::Coverage 1.00 required for testing POD coverage"
|
||||||
eval "use Test::Pod::Coverage $min_tpc";
|
|
||||||
plan skip_all =>
|
|
||||||
"Test::Pod::Coverage $min_tpc required for testing POD coverage"
|
|
||||||
if $@;
|
if $@;
|
||||||
|
|
||||||
# Test::Pod::Coverage doesn't require a minimum Pod::Coverage version,
|
plan skip_all => "Skipping coverage tests" unless $ENV{COVERAGE};
|
||||||
# but older versions don't recognize some common documentation styles
|
|
||||||
my $min_pc = 0.18;
|
|
||||||
eval "use Pod::Coverage $min_pc";
|
|
||||||
plan skip_all => "Pod::Coverage $min_pc required for testing POD coverage"
|
|
||||||
if $@;
|
|
||||||
|
|
||||||
all_pod_coverage_ok();
|
all_pod_coverage_ok();
|
||||||
|
|
87
t/range.t
Normal file
87
t/range.t
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use FindBin qw($Bin);
|
||||||
|
use lib "$Bin/../lib";
|
||||||
|
|
||||||
|
use Test::More;
|
||||||
|
use Test::Trap;
|
||||||
|
use Data::Dump;
|
||||||
|
|
||||||
|
require_ok('App::ClusterSSH::Range')
|
||||||
|
|| BAIL_OUT('Failed to use App::ClusterSSH::Range');
|
||||||
|
|
||||||
|
my %tests = (
|
||||||
|
'a' => 'a',
|
||||||
|
'c{a,b}' => 'ca cb',
|
||||||
|
'd{a,b,c}' => 'da db dc',
|
||||||
|
'e{0}' => 'e0',
|
||||||
|
'f{0..3}' => 'f0 f1 f2 f3',
|
||||||
|
'g{0..2,4}' => 'g0 g1 g2 g4',
|
||||||
|
'h{0..2,4..6}' => 'h0 h1 h2 h4 h5 h6',
|
||||||
|
'i{0..1,a}' => 'i0 i1 ia',
|
||||||
|
'j{0..2,a,b,c}' => 'j0 j1 j2 ja jb jc',
|
||||||
|
'k{4..6,a..c}' => 'k4 k5 k6 ka kb kc',
|
||||||
|
'l{0..2,7..9,e..g}' => 'l0 l1 l2 l7 l8 l9 le lf lg',
|
||||||
|
'm{0,1}' => 'm0 m1',
|
||||||
|
'n0..2}' => 'n0..2}',
|
||||||
|
'host{a,b}-test{1,2}' =>
|
||||||
|
'hosta-test1 hosta-test2 hostb-test1 hostb-test2',
|
||||||
|
|
||||||
|
# NOTE: the following are not "as expected" in line with above tests
|
||||||
|
# due to bsd_glob functionality. See output from:
|
||||||
|
# print join(q{ }, bsd_glob("o{a,b,c")).$/
|
||||||
|
'o{a,b,c' => 'o',
|
||||||
|
'p{0..2' => 'p',
|
||||||
|
|
||||||
|
# Reported as bug in github issue #89
|
||||||
|
'q-0{0,1}' => 'q-00 q-01',
|
||||||
|
'q-0{0..1}' => 'q-00 q-01',
|
||||||
|
|
||||||
|
# expand pure ranges
|
||||||
|
'{10..12}' => '10 11 12',
|
||||||
|
|
||||||
|
# expand ports
|
||||||
|
'lh:{22001..22003}' => 'lh:22001 lh:22002 lh:22003',
|
||||||
|
|
||||||
|
# FQDN's
|
||||||
|
'lh{1..3}.dot.com' => 'lh1.dot.com lh2.dot.com lh3.dot.com',
|
||||||
|
|
||||||
|
# IP addresses
|
||||||
|
'127.0.0.{10..12}' => '127.0.0.10 127.0.0.11 127.0.0.12',
|
||||||
|
'127.0.{20..22}.1' => '127.0.20.1 127.0.21.1 127.0.22.1',
|
||||||
|
);
|
||||||
|
|
||||||
|
my $range = App::ClusterSSH::Range->new();
|
||||||
|
isa_ok( $range, 'App::ClusterSSH::Range', 'object created correctly' );
|
||||||
|
|
||||||
|
for my $key ( sort keys %tests ) {
|
||||||
|
my $expected = $tests{$key};
|
||||||
|
my @expected = split / /, $tests{$key};
|
||||||
|
|
||||||
|
my $got;
|
||||||
|
trap {
|
||||||
|
$got = $range->expand($key);
|
||||||
|
};
|
||||||
|
|
||||||
|
is( $trap->stdout, '', "No stdout for scalar $key" );
|
||||||
|
is( $trap->stderr, '', "No stderr for scalar $key" );
|
||||||
|
is( $trap->leaveby, 'return', "correct leaveby for scalar $key" );
|
||||||
|
is( $trap->die, undef, "die is undef for scalar $key" );
|
||||||
|
is( $got, "$expected", "expected return for scalar $key" );
|
||||||
|
|
||||||
|
my @got;
|
||||||
|
trap {
|
||||||
|
@got = $range->expand($key);
|
||||||
|
};
|
||||||
|
|
||||||
|
is( $trap->stdout, '', "No stdout for array $key" );
|
||||||
|
is( $trap->stderr, '', "No stderr for array $key" );
|
||||||
|
is( $trap->leaveby, 'return', "correct leaveby for array $key" );
|
||||||
|
is( $trap->die, undef, "die is undef for array $key" );
|
||||||
|
is_deeply( \@got, \@expected, "expected return for array $key" )
|
||||||
|
|| diag explain \@got;
|
||||||
|
}
|
||||||
|
|
||||||
|
done_testing();
|
Loading…
Add table
Add a link
Reference in a new issue