Compare commits

..

No commits in common. "master" and "release-4.02_02" have entirely different histories.

54 changed files with 4308 additions and 7756 deletions

View file

@ -1,68 +0,0 @@
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
View file

@ -1,17 +1,11 @@
/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
*.tar.gz
Build
MANIFEST.bak
MYMETA.json
MYMETA.yml
Makefile
_build/
blib/
cover_db/
pm_to_blib

View file

@ -1,38 +1,45 @@
use lib 'inc';
use strict;
use warnings;
require Module::Build;
use Module::Build;
my %module_build_args = (
module_name => 'App::ClusterSSH',
dist_abstract => "Cluster administration tool",
##{ $plugin->get_prereqs(1) ##}
##{ $plugin->get_default('share_dir') ##}
script_files => [
'bin/cssh', 'bin/csftp',
'bin/ccon', 'bin/crsh',
'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'
],
my $build = Module::Build->new(
meta_merge => {
resources => {
Repository => [
'http://clusterssh.git.sourceforge.net/',
'http://github.com/duncs/clusterssh',
],
bugtracker => 'http://sourceforge.net/tracker/?group_id=89139',
homepage => 'http://clusterssh.sourceforge.net/',
},
},
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',
);
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;
$build->create_build_script;

693
Changes
View file

@ -1,161 +1,4 @@
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>
2014-01-13 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.02_02
- Fixed macros (%u, %s, %h, %n) not doing multiple replacements
- Add in key shortcut for username macro (ALT-u)
- Add in key shortcut for local hostname macro (ALT-l)
@ -164,390 +7,392 @@ Revision history for {{$dist->name}}
- Fixed the default cluster not being opened
- Add in toggle for macros
4.02_01 2013-04-16 Duncan Ferguson <duncan_ferguson@user.sf.net>
2013-04-16 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.02_01
- Refactured file loading code
- Add in 'tags' file handling
- Fix bug whereby cluster files were read in multiple times
- Add in resolving tags by external command
- Fix library path on bin/cssh (Sf bug 3610601)
4.01_05 2013-03-05 Duncan Ferguson <duncan_ferguson@user.sf.net>
2013-03-05 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.01_05
- 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
- Do not set default user name to prevent overriding ssh configuration
4.01_04 2013-02-26 Duncan Ferguson <duncan_ferguson@user.sf.net>
2013-02-26 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.01_04
- Fixed 'ccon' not calling the correct command (Sf bug 3605002)
- Fixed clusters not being defined correctly within the .clusterssh/config file (Sf bug 3605675)
4.01_03 2013-02-15 Duncan Ferguson <duncan_ferguson@user.sf.net>
- Correct documentation for references to $HOME/.clusterssh/config
- Re-add user back into the configurartion file
- Add in missing newline for some error messages
- 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
- 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)
- Cope with being invoked by 'clusterssh' (Debian bug ID #644368)
- 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)
- Updated manpage whatis entries (patch by Tony Mancill)
- Fix watch line expression to catch 4.x series tarballs (Debian patch LP ID #1076897)
- Allow tests to pass successfully when run as root
- Fix cssh starting if xterm is not installed (Sf bug 3494988)
- Set WM_CLASS on windows to 'cssh' (Sf bug 3187736)
2013-02-15 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.01_03
* Correct documentation for references to $HOME/.clusterssh/config
* Re-add user back into the configurartion file
* Add in missing newline for some error messages
* 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
* 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)
* Cope with being invoked by 'clusterssh' (Debian bug ID #644368)
* 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)
* Updated manpage whatis entries (patch by Tony Mancill)
* Fix watch line expression to catch 4.x series tarballs (Debian patch LP ID #1076897)
* Allow tests to pass successfully when run as root
* Fix cssh starting if xterm is not installed (Sf bug 3494988)
* Set WM_CLASS on windows to 'cssh' (Sf bug 3187736)
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 $HOME/.clusterssh/clusters being read in
- Fix 'ctel', 'crsh' and 'ccon'so they work as expected
2012-12-09 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.01_02
* Fix logic when using 'autoclose' on the command line or config file
* Fix $HOME/.clusterssh/clusters being read in
* Fix 'ctel', 'crsh' and 'ccon'so they work as expected
4.01_01 2011-12-09 Duncan Ferguson <duncan_ferguson@user.sf.net>
- Include missing files from release tarballs
2011-12-09 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.01_01
* Include missing files from release tarballs
4.01_00 2011-12-03 Duncan Ferguson <duncan_ferguson@user.sf.net>
- Start switching code to use Exception::Class
- Moved config file from $HOME/.csshrc file to $HOME/.clusterssh directory
- Rework config handling into a module
- Rework cluster handling into a module
- Added 'autoclose' functionality - see docs
- Allow "-a 'cmd ; cmd'" to work for multiple remote commands
2011-12-03 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.01_00
* Start switching code to use Exception::Class
* Moved config file from $HOME/.csshrc file to $HOME/.clusterssh directory
* Rework config handling into a module
* Rework cluster handling into a module
* Added 'autoclose' functionality - see docs
* Allow "-a 'cmd ; cmd'" to work for multiple remote commands
4.00_11 2011-07-28 Duncan Ferguson <duncan_ferguson@user.sf.net>
- Fix '-l <username>' option (SF bug 3380675)
2011-07-28 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.00_11
* Fix '-l <username>' option (SF bug 3380675)
4.00_10 2011-07-08 Duncan Ferguson <duncan_ferguson@user.sf.net>
- Fix 'uninitialised error' message
2011-07-08 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.00_10
* Fix 'uninitialised error' message
4.00_09 2011-06-30 Duncan Ferguson <duncan_ferguson@user.sf.net>
- Cater for missing 'pod2text' command (Thanks to Sami Kerola)
- Fix 'uninitialised variable' error
- Added 'ccon' command (Thanks to Brandon Perkins)
2011-06-30 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.00_09
* Cater for missing 'pod2text' command (Thanks to Sami Kerola)
* Fix 'uninitialised variable' error
* Added 'ccon' command (Thanks to Brandon Perkins)
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)
2011-04-01 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.00_08
* Amend all L<xx> links to prevent build breakage on cygwin (Sf bug 3115635)
4.00_07 2011-01-24 Duncan Ferguson <duncan_ferguson@user.sf.net>
- Fix for parsing config files with empty values (Stefan Steiner)
- Reinstate acting on '-l username' option (reported by Ryan Brown)
2011-01-24 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.00_07
* Fix for parsing config files with empty values (Stefan Steiner)
* Reinstate acting on '-l username' option (reported by Ryan Brown)
4.00_06 2010-09-20 Duncan Ferguson <duncan_ferguson@user.sf.net>
- Fix test error on 5.8.8 (reported by Wei Wang)
- Added '--list', '-L' to list available cluster tags (idea from Markus Manzke)
- Fix terminal size only set on last windows (Sf bug 3061999)
- Added '--use_all_a_records' (Simon Fraser)
2010-09-20 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.00_06
* Fix test error on 5.8.8 (reported by Wei Wang)
* Added '--list', '-L' to list available cluster tags (idea from Markus Manzke)
* Fix terminal size only set on last windows (Sf bug 3061999)
* Added '--use_all_a_records' (Simon Fraser)
4.00_05 2010-06-20 Duncan Ferguson <duncan_ferguson@user.sf.net>
2010-06-20 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.00_05
- Tidy up pod for whatis errors
- Amend copyright years and text to be consistent
- Include missing buld prereq (Test::Trap)
- Correct '--font, -f' in cssh documentation
* Tidy up pod for whatis errors
* Amend copyright years and text to be consistent
* Include missing buld prereq (Test::Trap)
* Correct '--font, -f' in cssh documentation
- Thanks to Tony Mancill for reporting these errors
4.00_04 2010-06-20 Duncan Ferguson <duncan_ferguson@user.sf.net>
2010-06-20 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.00_04
- Update MANIFEST file to ensure all correct files are included in release
* Update MANIFEST file to ensure all correct files are included in release
4.00_03 2010-06-20 Duncan Ferguson <duncan_ferguson@user.sf.net>
2010-06-20 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.00_03
- Fix silly type in code/tests
* Fix silly type in code/tests
4.00_02 2010-06-19 Duncan Ferguson <duncan_ferguson@user.sf.net>
2010-06-19 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.00_02
- Add in bugtracker and homepage resources to Build.PL file
- Bring new module App::ClusterSSH::Host into play for parsing host strings
- Patch to override font used on command line (Roland Rosenfeld)
- Put options in cssh pod into alphabetical order
* Add in bugtracker and homepage resources to Build.PL file
* Bring new module App::ClusterSSH::Host into play for parsing host strings
* Patch to override font used on command line (Roland Rosenfeld)
* Put options in cssh pod into alphabetical order
4.00_01 2010-01-08 Duncan Ferguson <duncan_ferguson@user.sf.net>
2010-01-08 Duncan Ferguson <duncan_ferguson@user.sf.net> - v4.00_01
- Remove GNU tools and switch to Perl module layout using Module::Build
* Remove GNU tools and switch to Perl module layout using Module::Build
3.29 0000-00-00 Duncan Ferguson <duncan_ferguson@user.sf.net> (unreleased)
0000-00-00 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.29 - unreleased
- Handle hostnames containing % properly (Debian bug 543368)
* Handle hostnames containing % properly (Debian bug 543368)
- Thanks to Tony Mancill for the patch
3.28 2009-12-19 Duncan Ferguson <duncan_ferguson@user.sf.net>
2009-12-19 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.28
- Look for usernames when adding clusters
* Look for usernames when adding clusters
- Thanks to Kristian Lyngstol for the patch
- Allow username@cluster to override all usernames in the cluster
- Account for multiple host definitions within ssh configuration file
* Allow username@cluster to override all usernames in the cluster
* Account for multiple host definitions within ssh configuration file
- 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
- Improve binary search to
* Improve binary search to
- ignore directories of the same name, and
- always search for the binary if it is not fully qualified
- 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)
3.27 2009-09-24 Duncan Ferguson <duncan_ferguson@user.sf.net>
2009-09-24 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.27
- 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
- Fix bug where unresolvable host stopped program running
* Fix bug where unresolvable host stopped program running
- 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
- Add in send menu xml definition file
* Add in send menu xml definition file
- thanks to James Chernikov for the idea
3.26_1 2009-06-02 Duncan Ferguson <duncan_ferguson@user.sf.net>
2009-06-02 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.26-1
- Allow user to set a different ConnectTimeout and -o string (Tony Mancill)
- Fix warning from 'mandb' (Tony Mancill)
- Continue connecting to unresolvable hosts (debian bug 499935) (Tony Mancill)
- Correct bug with unset default ports (Tony Mancill)
- Rearrange pod documentation to remove extraenous comment (Tony Mancill)
- Cope better with IPv6 addresses
- Fix bug with passing arguments from command line to comms method binary
- Rework defaultport code
- Add new "-a 'command'" option for running a command in each terminal
- Fix bug with some host lookups failing
- 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
- Increase reserve of screen from bottom from 40 pixels to 60
- Better notes in docs for screen/terminal reserving
- Minor fixup to docs formatting
- Correct pasting mechanism into control window
- Allow use of long options (swap Getopt::Std to Getopt::Long)
- Remove deprecated '-i' option
- Deprecate -d and -D, replaced with --debug
- Allow for configurable max number of hosts within hosts menu before
* Allow user to set a different ConnectTimeout and -o string (Tony Mancill)
* Fix warning from 'mandb' (Tony Mancill)
* Continue connecting to unresolvable hosts (debian bug 499935) (Tony Mancill)
* Correct bug with unset default ports (Tony Mancill)
* Rearrange pod documentation to remove extraenous comment (Tony Mancill)
* Cope better with IPv6 addresses
* Fix bug with passing arguments from command line to comms method binary
* Rework defaultport code
* Add new "-a 'command'" option for running a command in each terminal
* Fix bug with some host lookups failing
* 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
* Increase reserve of screen from bottom from 40 pixels to 60
* Better notes in docs for screen/terminal reserving
* Minor fixup to docs formatting
* Correct pasting mechanism into control window
* Allow use of long options (swap Getopt::Std to Getopt::Long)
* Remove deprecated '-i' option
* Deprecate -d and -D, replaced with --debug
* Allow for configurable max number of hosts within hosts menu before
starting a new column - see .csshrc doc for "max_host_menu_items".
This is until Tk allows for scrollable menus
- 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
- 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
* 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
* 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
- this is due to virtual desktop change triggering a retile
3.25_1 2009-03-26 Duncan Ferguson <duncan_ferguson@user.sf.net>
2009-03-26 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.25-1
- Add patch from David F. Skoll for adding colour to terminals
- Apply fix from Bogdan Pintea for DNS failing to resolve IPs
- Allow the configuration files to be symlinks (debian bug 518196)
- Add an 'EXAMPLES' section to the cssh documentation
- List options alphabetically in documentation
- Apply patch from Gerfried Fuchs/Tony Mancill for ports on the command line
* Add patch from David F. Skoll for adding colour to terminals
* Apply fix from Bogdan Pintea for DNS failing to resolve IPs
* Allow the configuration files to be symlinks (debian bug 518196)
* Add an 'EXAMPLES' section to the cssh documentation
* List options alphabetically in documentation
* Apply patch from Gerfried Fuchs/Tony Mancill for ports on the command line
3.24_1 2008-11-14 Duncan Ferguson <duncan_ferguson@user.sf.net>
2008-11-14 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.24-1
- Do not attempt to re-resolve IP addresses
- Apply patch from Dan Wallis
* Do not attempt to re-resolve IP addresses
* Apply patch from Dan Wallis
- Add '-C <file>' command to load in specific config file
- Typo correct in pod
- Cope with random/strange config files better
- Correct some minor typos
- Create the .csshrc file if it doesnt already exist and amend pod
- Amend host menu items to be a little more descriptive
- Remove 'Catpure Terminal' from Hosts menu as it doesnt do anything useful
* Correct some minor typos
* Create the .csshrc file if it doesnt already exist and amend pod
* Amend host menu items to be a little more descriptive
* Remove 'Catpure Terminal' from Hosts menu as it doesnt do anything useful
3.23_1 2008-01-23 Duncan Ferguson <duncan_ferguson@user.sf.net>
2008-01-23 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.23-1
- Apply bugfix supplied by Jima
* Apply bugfix supplied by Jima
- Ensure loading of hosts from user ssh config file is case insensitive
3.22_1 2008-01-23 Duncan Ferguson <duncan_ferguson@user.sf.net>
2008-01-23 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.22-1
- Update X resources class to allow use of terms other than XTerm
- Apply patch from Harald Weidner to stop error messages in Debian Etch
- Add in key shortcut (alt-h) to toggle history window
- Tidy up pod a little to highlight notes better
- Check terminal_font config for quotes and remove
- Enable use of "configure --sysconfdir=", defaults to /etc
- Revise host checking algorithm to take ssh_config files into account
- Revise username check used as part of host id to accept more chars
- Correct year value for previous two entries from 2008 to 2007
* Update X resources class to allow use of terms other than XTerm
* Apply patch from Harald Weidner to stop error messages in Debian Etch
* Add in key shortcut (alt-h) to toggle history window
* Tidy up pod a little to highlight notes better
* Check terminal_font config for quotes and remove
* Enable use of "configure --sysconfdir=", defaults to /etc
* Revise host checking algorithm to take ssh_config files into account
* Revise username check used as part of host id to accept more chars
* Correct year value for previous two entries from 2008 to 2007
3.21_1 2007-11-28 Duncan Ferguson <duncan_ferguson@user.sf.net>
2007-11-28 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.21-1
- Implement a basic history window in the console (option -s)
- Fixed bug whereby username@ wasn't being used correctly
* Implement a basic history window in the console (option -s)
* Fixed bug whereby username@ wasn't being used correctly
3.20_1 2007-11-26 Duncan Ferguson <duncan_ferguson@user.sf.net>
2007-11-26 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.20-1
- Move source repository from CVS to SVN on sourceforge
- Remove last digit of version number since not required with SVN
- Add in host menu option to close inactive windows
- Apply bugfixes suppled by Tony Mancill
* Move source repository from CVS to SVN on sourceforge
* Remove last digit of version number since not required with SVN
* Add in host menu option to close inactive windows
* Apply bugfixes suppled by Tony Mancill
- reset xrm switch in terminal_args
- prevent warning messages being printed when keysyms arent found
- fixes for fvwm
- chekc for child process before sending kill
- Slight rewording of man page
- Add in option to use telnet as comms command (use 'ctel' to invoke script)
- Run through perltidy -b -i=2
- Appy patches from Klaus Ethgen
* Slight rewording of man page
* Add in option to use telnet as comms command (use 'ctel' to invoke script)
* Run through perltidy -b -i=2
* Appy patches from Klaus Ethgen
- Client dies when cannot write to pipe
- Sleeping and flushing in window manager to allow time to draw windows
- Fix pipe reading to not use undefined values
- Apply patches from Nicolas Simonds
* Apply patches from Nicolas Simonds
- allow colons in hostnames
- allow -o option as per man page
- Apply patch from Peter Palfrader
* Apply patch from Peter Palfrader
- improvement to finding binaries
- Allow font to be specified on the command line
- Check for errors around key data gathering
- Add in 'extra_cluster_file' to csshrc
* Allow font to be specified on the command line
* Check for errors around key data gathering
* Add in 'extra_cluster_file' to csshrc
3.19.1_1 2006-07-24 Duncan Ferguson <duncan_ferguson@user.sf.net>
2006-07-24 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.19.1-1
- Below is an abridged version of changes - see CVS for more information
- Check for failure to connect to X session
- Totally rework character mapping and events to cope with non-QWERTY keyboards
- Rework pasting code to cope with non-QWERTY charatcters
- Manpage/help doc updates and corrections
- Check for missing definitions for cluster tags in .csshrc
- Run through perltidy -b -i=2
- Apply patch to add in optional port information from D. Dumont
- Amend hotkey code to not pick up <ctrl>-<alt> as default clientname shortcut
- Alter repeat function to improve efficiency
- Rework retiling code
- Add "-e <host>" to evaluate terminal and communcation methods
- Add in toggle option on hosts menu
- Fix check in find_binary to ensure one is actually found
- Search $PATH and other standard places for binaries incase $PATH is incomplete
- Amend code to allow getting help when no X display available
- Allow override of both key and mouse paste key sequences
- Added 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
- 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
- Remove code that breaks the minimize/maximise stuff;
- Catch X button presses on title bar to close all windows correctly
- Delay map event capture at program start to avoid infinite loop
- Fix execvp error on Solaris 10
* Check for failure to connect to X session
* Totally rework character mapping and events to cope with non-QWERTY keyboards
* Rework pasting code to cope with non-QWERTY charatcters
* Manpage/help doc updates and corrections
* Check for missing definitions for cluster tags in .csshrc
* Run through perltidy -b -i=2
* Apply patch to add in optional port information from D. Dumont
* Amend hotkey code to not pick up <ctrl>-<alt> as default clientname shortcut
* Alter repeat function to improve efficiency
* Rework retiling code
* Add "-e <host>" to evaluate terminal and communcation methods
* Add in toggle option on hosts menu
* Fix check in find_binary to ensure one is actually found
* Search $PATH and other standard places for binaries incase $PATH is incomplete
* Amend code to allow getting help when no X display available
* Allow override of both key and mouse paste key sequences
* Added 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
* 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
* Remove code that breaks the minimize/maximise stuff;
* Catch X button presses on title bar to close all windows correctly
* Delay map event capture at program start to avoid infinite loop
* Fix execvp error on Solaris 10
3.18.1_1 2005-11-28 Duncan Ferguson <duncan_ferguson@user.sf.net>
2005-11-28 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.18.1-1
- Correct mask value for backtick (grave) character
- Add more logging for debug mode
- Amend indentation
- Rerun through perltidy
- 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
- Do not die when pipe open fails, but continue as others may be connected
- Remove code that breaks the minimize/maximise stuff;
- Catch X button presses on title bar to close all windows correctly
- Delay map event capture at program start to avoid infinite loop
- Fix execvp error on Solaris 10
- Update to man pages
* Correct mask value for backtick (grave) character
* Add more logging for debug mode
* Amend indentation
* Rerun through perltidy
* 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
* Do not die when pipe open fails, but continue as others may be connected
* Remove code that breaks the minimize/maximise stuff;
* Catch X button presses on title bar to close all windows correctly
* Delay map event capture at program start to avoid infinite loop
* Fix execvp error on Solaris 10
* Update to man pages
3.17.1 2005-06-24 Duncan Ferguson <duncan_ferguson@user.sf.net>
2005-06-24 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.17.1
- Allow _'s in paste text correctly
- Bugfix minimise/maximise again
- Run through "perltidy -i=4 -ce"
- Unmap all windows in one go instead of one at a time when retiling
- Add + doc 'console_position'
- Maintain user position of console between maps (i.e. tell window manager
* Allow _'s in paste text correctly
* Bugfix minimise/maximise again
* Run through "perltidy -i=4 -ce"
* Unmap all windows in one go instead of one at a time when retiling
* Add + doc 'console_position'
* Maintain user position of console between maps (i.e. tell window manager
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
3.16.1 2005-06-13 Duncan Ferguson <duncan_ferguson@user.sf.net>
2005-06-13 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.16.1
- 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)
3.15.1 2005-06-09 Duncan Ferguson <duncan_ferguson@user.sf.net>
2005-06-09 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.15.1
- Add and document "-c <clusterfile>"
- Add and document "-l <username>"
- Add and document "-o <options>"
- Document "-t <title>"
- Set controlled terminals to have user set size & position (WM_SIZE_HINTS)
- Speed up initial terminal openings
- Remove all key bindings from drop down menus (conflicts with emacs and
* Add and document "-c <clusterfile>"
* Add and document "-l <username>"
* Add and document "-o <options>"
* Document "-t <title>"
* Set controlled terminals to have user set size & position (WM_SIZE_HINTS)
* Speed up initial terminal openings
* Remove all key bindings from drop down menus (conflicts with emacs and
can all be done by other hotkeys anyhow)
- Allow individual hotkeys to be disabled, instead of all-or-nothing
- Updates to POD
- Update retile code to avoid flickering windows (& also fix cygwin bug)
- Rename -t to -T to match previous series option
- Added in -t to modify cmd line args for terminals
* Allow individual hotkeys to be disabled, instead of all-or-nothing
* Updates to POD
* Update retile code to avoid flickering windows (& also fix cygwin bug)
* Rename -t to -T to match previous series option
* Added in -t to modify cmd line args for terminals
3.14.1 2005-06-04 Duncan Ferguson <duncan_ferguson@user.sf.net>
2005-06-04 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.14.1
- first cut at terminal opening speed up
* first cut at terminal opening speed up
3.13.1 2005-05-20 Duncan Ferguson <duncan_ferguson@user.sf.net>
2005-05-20 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.13.1
- Bugfix for whitespace in config files (missing a char from regexp)
- Allow for minimising/maximising all windows when done on console
* Bugfix for whitespace in config files (missing a char from regexp)
* Allow for minimising/maximising all windows when done on console
3.12.1 2005-05-19 Duncan Ferguson <duncan_ferguson@user.sf.net>
2005-05-19 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.12.1
- Bugfix for shifted non-alphanumeric keyboard chars not being pasted correctly
- Marked version number with 3rd digit to signify beta releases
* Bugfix for shifted non-alphanumeric keyboard chars not being pasted correctly
* Marked version number with 3rd digit to signify beta releases
3.11 2005-05-18 Duncan Ferguson <duncan_ferguson@user.sf.net>
2005-05-18 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.11
- Remove trailing whitespace from config file lines
- Prevent paste events being sent to non-active clients
- Allow paste events to send capitalised letters
* Remove trailing whitespace from config file lines
* Prevent paste events being sent to non-active clients
* Allow paste events to send capitalised letters
3.10 2005-05-17 Duncan Ferguson <duncan_ferguson@user.sf.net>
2005-05-17 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.10
- fix for moving atom numbers in font info
* fix for moving atom numbers in font info
3.9 2005-05-11 Duncan Ferguson <duncan_ferguson@user.sf.net>
2005-05-11 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.9
- Allow multiple hosts or tags in the "Add Host" text widget
- Retile all windows (if set) after adding a host
- Do not automatically send a return after hostname (Alt-n)
- Fix bug with sending read hostname instead of internal unique host
* Allow multiple hosts or tags in the "Add Host" text widget
* Retile all windows (if set) after adding a host
* Do not automatically send a return after hostname (Alt-n)
* Fix bug with sending read hostname instead of internal unique host
name (Alt-n)
- Fix bug whereby cannot start cssh without any hosts on cmd-line
- Fix bug where client name was sent to inactive clients
- Fix bug whereby 0's in sent text were ignored
* Fix bug whereby cannot start cssh without any hosts on cmd-line
* Fix bug where client name was sent to inactive clients
* Fix bug whereby 0's in sent text were ignored
3.8 2005-05-09 Duncan Ferguson <duncan_ferguson@user.sf.net>
2005-05-09 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.8
- Remove the need for xlsfonts (perform function by X window calls instead)
- Debug level output changes
- Ensure windows are overlapping in the right places, instead of any order
- Create config section on window decorations (i.e. title & scroll bars)
* Remove the need for xlsfonts (perform function by X window calls instead)
* Debug level output changes
* Ensure windows are overlapping in the right places, instead of any order
* Create config section on window decorations (i.e. title & scroll bars)
3.7 2005-05-05 Duncan Ferguson <duncan_ferguson@user.sf.net>
2005-05-05 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.7
- Found ConfigureWindow instead of ResizeMoveWindow
* Found ConfigureWindow instead of ResizeMoveWindow
3.6 2005-05-05 Duncan Ferguson <duncan_ferguson@user.sf.net>
2005-05-05 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.6
- Lots of work on window tiling - to fall at last hurdle (No XResizeMoveWindow)
- Documentation updates
- Allow -u ouput when binaries havnt been found
- Start coding for capturing an existing terminal window
- Rebuild hosts menu when all hosts checked, not when each host checked
- Change debug message output level of keysyms
- Cater for config of no tiling, but allow to retile in console window anyhow
* Lots of work on window tiling - to fall at last hurdle (No XResizeMoveWindow)
* Documentation updates
* Allow -u ouput when binaries havnt been found
* Start coding for capturing an existing terminal window
* Rebuild hosts menu when all hosts checked, not when each host checked
* Change debug message output level of keysyms
* Cater for config of no tiling, but allow to retile in console window anyhow
3.5 2005-05-03 Duncan Ferguson <duncan_ferguson@user.sf.net>
2005-05-03 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.5
- Remove some old (commented out) code
- Remove some (unnecessary) debug code
- Start coding for window tiling
- Modify find_binary function to make it more portable
- Output internal vars in "-u -d"
- Small mods to docs to take account of all of the above
* Remove some old (commented out) code
* Remove some (unnecessary) debug code
* Start coding for window tiling
* Modify find_binary function to make it more portable
* Output internal vars in "-u -d"
* Small mods to docs to take account of all of the above
3.4 2005-04-26 Duncan Ferguson <duncan_ferguson@user.sf.net>
2005-04-26 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.4
- 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
- Allow for running from cvs dir in config{comms}
- Add "ConnectTimeout=10" to default ssh options
- Add further debug info
- Add check to ensure hostname can be resolved before attempting connection
- Modigy zombie reaping to prevent hand on unconnected cx term closing
- Add "autoquit" feature to close ClusterSSH after last client window closes
- Also produce man page and include as part of install
* Allow for running from cvs dir in config{comms}
* Add "ConnectTimeout=10" to default ssh options
* Add further debug info
* Add check to ensure hostname can be resolved before attempting connection
* Modigy zombie reaping to prevent hand on unconnected cx term closing
* Add "autoquit" feature to close ClusterSSH after last client window closes
* Also produce man page and include as part of install
3.3 2005-04-10 Duncan Ferguson <duncan_ferguson@user.sf.net>
2005-04-10 Duncan Ferguson <duncan_ferguson@user.sf.net> - v3.3
- src/cssh.pl: Rewritten from scratch
- Set up to use Gnu Autotools
* src/cssh.pl: Rewritten from scratch
* Set up to use Gnu Autotools
$Id$

46
MANIFEST Normal file
View file

@ -0,0 +1,46 @@
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

16
MANIFEST.SKIP Normal file
View file

@ -0,0 +1,16 @@
^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 Normal file
View file

@ -0,0 +1,94 @@
{
"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 Normal file
View file

@ -0,0 +1,62 @@
---
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 Normal file
View file

@ -0,0 +1,33 @@
# 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
View file

@ -1,768 +1,67 @@
NAME
cssh - Cluster administration tool
App-ClusterSSH
VERSION
This documentation is for version: 4.18
The is the Perl application bundle for ClusterSSH (a.k.a cssh), formally
a GNU tools based project.
SYNOPSIS
cssh [-a '<command>'] [-K <seconds>] [-q] [-c '<filename>'] [-x <cols>]
[-C '<filename>'] [--debug [[...] || <INTEGER>]] [-d] [-e
'<[user@]<host>[:port]>'] [--fillscreen] [-f '<font>'] [-h] [-L '[tag]']
[-H] [-o '<STRING>'] [-p <port>] [-Q] [-y <rows>] [-s] [-r '<filename>']
[-t '<STRING>'] [-g] [-T '<title>'] [-u] [-?] [-A] [-l '<username>']
[-v]
ClusterSSH is a tool for making the same change on multiple servers at
the same time. The 'cssh' 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.
RELATED
Also see the individual man pages for each of these utilities
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.
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
For more information, go to http://clusterssh.sourceforge.net
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.
INSTALLATION
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.
To install this module, run the following commands:
Connections are opened using ssh which must be correctly installed and
configured.
perl Build.PL
./Build
./Build test
./Build install
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.
SUPPORT AND DOCUMENTATION
Further Notes
Please also see "KNOWN BUGS".
After installing, you can find documentation for this module with the
perldoc command.
* 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.
perldoc cssh
* 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.
or (if your MANPATH is set up appropriately)
* 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").
man cssh
* If the terminals overlap too much see the "terminal_reserve_XXXXX"
options in the $HOME/.clusterssh/config file (see "FILES").
You can also look for information at:
* When using ClusterSSH on a large number of systems to connect to a
single system using an SSH utility (e.g. you issue a command to to
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.
Web site and SourceForge project page
http://clusterssh.sourceforge.net
http://sourceforge.net/projects/clusterssh/
* If client windows fail to open, try running:
Project support area
https://sourceforge.net/projects/clusterssh/support
"cssh -e {single host name}"
AnnoCPAN, Annotated CPAN documentation
http://annocpan.org/dist/App-ClusterSSH
This will test the mechanisms used to open windows to hosts. This
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".
CPAN Ratings
http://cpanratings.perl.org/d/App-ClusterSSH
OPTIONS
Some of these options may also be defined within the configuration file.
Default options are shown as appropriate.
Search CPAN
http://search.cpan.org/dist/App-ClusterSSH/
--action '<command>', -a '<command>'
Run the command in each session, e.g. "-a 'vi /etc/hosts'" to drop
straight into a vi session.
--autoclose <seconds>, -K <seconds>
Number of seconds to wait before closing finished terminal windows.
COPYRIGHT AND LICENCE
--autoquit, -q
Toggle automatically quitting after the last client window has
closed (overriding the config file).
Copyright (C) 1999-2010 Duncan Ferguson
--cluster-file '<filename>', -c '<filename>'
Use supplied file as additional cluster file (see also "FILES").
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.
--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.
See http://dev.perl.org/licenses/ for more information.

8
THANKS
View file

@ -41,11 +41,3 @@ Stefan Steiner
Ryan Brown
Brandon Perkins
Oliver Meissner
Andrew Stevenson (cqexbesd)
Emanuele Tomasi
Deny Dias
Bill Rushmore
Ankit Vadehra
Azenet
Markus Frosch (lazyfrosch)
Petr Vorel

45
TODO
View file

@ -1,15 +1,52 @@
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
=======================================
Set up terminal windows in Tk to embed termainal session into it, such
as with xterm:
Set up terminal windows in Tk to embedd termainl session into it, such as with
xterm
xterm -wid <wid> ....
This may limit what terminals can be used, though
This may limit to terminal thats can reparent into a given window id though.
See also:
http://www.perlmonks.org/?node_id=359764

0
WIP_TASKS Normal file
View file

1
bin/ccon Symbolic link
View file

@ -0,0 +1 @@
cssh

1
bin/crsh Symbolic link
View file

@ -0,0 +1 @@
cssh

2
bin_PL/cscp.x → bin/cscp Normal file → Executable file
View file

@ -1,6 +1,6 @@
#!/bin/sh
#LICENSE: GNU GPL version 2
#LICENSE: Gnu GPL version 2
#Author: JT Moree: moreejt@pcxperience.com
#Copyright: Kahala Corp. 2006
#Date: 20061213

881
bin/cssh Executable file
View file

@ -0,0 +1,881 @@
#!/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 Symbolic link
View file

@ -0,0 +1 @@
cssh

View file

@ -1,47 +0,0 @@
#!/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: $!";
}

View file

@ -1,25 +0,0 @@
#!/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;

View file

@ -1,70 +0,0 @@
# -*- 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

View file

@ -1,17 +0,0 @@
#!/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;

View file

@ -1,17 +0,0 @@
#!/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;

View file

@ -1,17 +0,0 @@
#!/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;

View file

@ -1,13 +0,0 @@
#!/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();

View file

@ -1,74 +0,0 @@
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

View file

@ -1,45 +1,24 @@
use warnings;
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 warnings;
use strict;
use Carp;
use App::ClusterSSH::L10N;
use Module::Load;
use Exception::Class 1.31 (
use Exception::Class (
'App::ClusterSSH::Exception',
'App::ClusterSSH::Exception::Config' => {
fields => 'unknown_config',
},
'App::ClusterSSH::Exception::Cluster',
'App::ClusterSSH::Exception::LoadFile',
'App::ClusterSSH::Exception::Helper',
'App::ClusterSSH::Exception::Getopt',
);
my $debug_level = $ENV{CLUSTERSSH_DEBUG} || 0;
# Dont use SVN revision as it can cause problems
use version;
our $VERSION = version->new('0.02');
my $debug_level = 4;
our $language = 'en';
our $language_handle;
our $app_configuration;
@ -48,13 +27,14 @@ sub new {
my ( $class, %args ) = @_;
my $config = {
lang => 'en',
lang => 'en',
debug => 0,
%args,
};
my $self = bless $config, $class;
$self->set_debug_level( $config->{debug} ) if ( $config->{debug} );
$self->set_debug_level( $config->{debug} );
$self->set_lang( $config->{lang} );
$self->debug(
@ -105,7 +85,10 @@ sub loc {
sub set_lang {
my ( $self, $lang ) = @_;
$self->debug( 6, $self->loc( 'Setting language to "[_1]"', $lang ), );
$language = $lang;
if ($self) {
$self->debug( 6, $self->loc( 'Setting language to "[_1]"', $lang ), );
}
return $self;
}
@ -130,7 +113,7 @@ sub debug_level {
return $debug_level;
}
sub stdout_output {
sub output {
my ( $self, @text ) = @_;
print @text, $/;
return $self;
@ -139,7 +122,7 @@ sub stdout_output {
sub debug {
my ( $self, $level, @text ) = @_;
if ( $level <= $debug_level ) {
$self->stdout_output(@text);
$self->output(@text);
}
return $self;
}
@ -161,21 +144,9 @@ sub config {
);
}
return $self->{parent}->{config}
if $self->{parent}
&& ref $self->{parent} eq "HASH"
&& $self->{parent}->{config};
return $app_configuration;
}
sub options {
my ($self) = @_;
return $self->{parent}->{options}
if $self->{parent} && $self->{parent}->{options};
return;
}
sub set_config {
my ( $self, $config ) = @_;
@ -213,10 +184,10 @@ sub load_file {
);
}
if ( !$args{type} ) {
if ( !$args{type} || $args{type} !~ m/cluster|config/ ) {
croak(
App::ClusterSSH::Exception->throw(
error => '"type" arg not passed'
error => '"type" arg invalid'
)
);
}
@ -296,38 +267,29 @@ sub load_file {
return %results;
}
sub parent {
my ($self) = @_;
return $self->{parent};
}
1;
sub sort {
my $self = shift;
=pod
# if the user has asked for natural sorting we need to include an extra
# module
my $config = $self->config();
=head1 NAME
# Make sure the configuration object has been set correctly before
# referencing anything
if ( ref $config eq "HASH" && $config->{'use_natural_sort'} ) {
eval { Module::Load::load('Sort::Naturally'); };
if ($@) {
warn(
"natural sorting requested but unable to load Sort::Naturally: $@\n"
);
}
else {
my $sort = sub { Sort::Naturally::nsort(@_) };
return $sort;
}
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;
}
my $sort = sub { sort @_ };
return $sort;
}
=head1 DESCRIPTION
1;
Base object to provide some utility functions on objects - should not be
used directly
=head1 METHODS
@ -369,19 +331,10 @@ Using the App::ClusterSSH/L10N/{lang}.pm module convert the given text to
appropriate language. See L<App::ClusterSSH::L10N> for more details. Essentially
a wrapper to maketext in Locale::Maketext
=item $obj->stdout_output(@);
=item $obj->output(@);
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;
Stub to allow program to exit neatly from wherever in the code
@ -395,14 +348,27 @@ hasnt 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}' )
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)
=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;

View file

@ -1,24 +1,16 @@
package App::ClusterSSH::Cluster;
use strict;
use warnings;
package App::ClusterSSH::Cluster;
# ABSTRACT: App::ClusterSSH::Cluster - Object representing cluster configuration
=head1 SYNOPSIS
=head1 DESCRIPTION
Object representing application configuration
=cut
use version;
our $VERSION = version->new('0.01');
use Carp;
use Try::Tiny 0.28;
use Try::Tiny;
use English qw( -no_match_vars );
use base qw/ App::ClusterSSH::Base /;
use App::ClusterSSH::Range;
our $master_object_ref;
@ -56,40 +48,14 @@ sub get_tag_entries {
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 {
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;
}
my ( $self, $external_command, @tags ) = @_;
$self->debug( 3, 'Running tags through external command' );
$self->debug( 4, 'External command: ', $external_command );
$self->debug( 3, 'Args ', join( ',', @args ) );
$self->debug( 3, 'Tags: ', join( ',', @tags ) );
my $command = "$external_command @args";
my $command = "$external_command @tags";
$self->debug( 3, 'Running ', $command );
@ -122,37 +88,8 @@ sub _run_external_clusters {
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 {
my ( $self, $filename ) = @_;
$filename = $self->expand_filename($filename);
$self->debug( 2, 'Reading tags from file ', $filename );
if ( -f $filename ) {
my %hosts
@ -170,9 +107,6 @@ sub read_tag_file {
sub read_cluster_file {
my ( $self, $filename ) = @_;
$filename = $self->expand_filename($filename);
$self->debug( 2, 'Reading clusters from file ', $filename );
if ( -f $filename ) {
@ -193,8 +127,6 @@ sub register_host {
my ( $self, $node, @tags ) = @_;
$self->debug( 2, "Registering node $node on tags:", join( ' ', @tags ) );
@tags = $self->expand_glob( 'node', $node, @tags );
foreach my $tag (@tags) {
if ( $self->{tags}->{$tag} ) {
$self->{tags}->{$tag}
@ -212,11 +144,6 @@ sub register_host {
sub register_tag {
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->{tags}->{$tag} = \@nodes;
@ -224,35 +151,6 @@ sub register_tag {
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 {
my ( $self, $tag ) = @_;
@ -263,7 +161,8 @@ sub get_tag {
join( ' ', sort @{ $self->{tags}->{$tag} } )
);
return wantarray
return
wantarray
? sort @{ $self->{tags}->{$tag} }
: scalar @{ $self->{tags}->{$tag} };
}
@ -274,9 +173,7 @@ sub get_tag {
sub list_tags {
my ($self) = @_;
return wantarray
? sort keys( %{ $self->{tags} } )
: scalar keys( %{ $self->{tags} } );
return sort keys( %{ $self->{tags} } );
}
sub dump_tags {
@ -294,6 +191,18 @@ sub dump_tags {
1;
=pod
=head1 NAME
App::ClusterSSH::Cluster - Object representing cluster configuration
=head1 SYNOPSIS
=head1 DESCRIPTION
Object representing application configuration
=head1 METHODS
=over 4
@ -307,13 +216,9 @@ Create a new object. Object should be common across all invocations.
Read in /etc/clusters, $HOME/.clusterssh/clusters and any other given
file name and register the tags found.
=item @external_tags=list_external_clusters()
=item @resolved_tags=get_external_clusters($path_to_binary, @tags)
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.
Define and use an external script to resolve tags into hostnames.
=item $cluster->get_tag_entries($filename);
@ -324,10 +229,6 @@ file name 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);
Read in the given tag file and register the tags found
@ -355,8 +256,22 @@ Return an array of all available tag names
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
=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;

View file

@ -1,17 +1,10 @@
package App::ClusterSSH::Config;
use strict;
use warnings;
package App::ClusterSSH::Config;
# ABSTRACT: ClusterSSH::Config - Object representing application configuration
=head1 SYNOPSIS
=head1 DESCRIPTION
Object representing application configuration
=cut
use version;
our $VERSION = version->new('0.02');
use Carp;
use Try::Tiny;
@ -24,7 +17,7 @@ use App::ClusterSSH::Cluster;
my $clusters;
my %old_clusters;
my @app_specific = (qw/ command title comms method parent /);
my @app_specific = (qw/ command title comms method /);
# list of config items to not write out when writing the default config
my @ignore_default_config = (qw/ user /);
@ -40,7 +33,7 @@ my %default_config = (
terminal_size => "80x24",
use_hotkeys => "yes",
key_quit => "Alt-q",
key_quit => "Control-q",
key_addhost => "Control-Shift-plus",
key_clientname => "Alt-n",
key_history => "Alt-h",
@ -49,14 +42,9 @@ my %default_config = (
key_macros_enable => "Alt-p",
key_paste => "Control-v",
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",
auto_quit => "yes",
auto_close => 5,
use_natural_sort => 0,
window_tiling => "yes",
window_tiling_direction => "right",
console_position => "",
@ -82,14 +70,9 @@ my %default_config = (
telnet_args => "",
ssh => 'ssh',
ssh_args => "",
sftp => 'sftp',
sftp_args => "",
extra_tag_file => '',
extra_cluster_file => '',
external_cluster_command => '',
external_command_mode => '0600',
external_command_pipe => '',
unmap_on_redraw => "no", # Debian #329440
@ -98,9 +81,6 @@ my %default_config = (
history_height => 10,
command => q{},
command_pre => q{},
command_post => q{},
hide_menu => 0,
max_host_menu_items => 30,
macros_enabled => 'yes',
@ -109,35 +89,17 @@ my %default_config = (
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',
macro_user_1_command => '',
macro_user_2_command => '',
macro_user_3_command => '',
macro_user_4_command => '',
hostname_override => '',
max_addhost_menu_cluster_items => 6,
menu_send_autotearoff => 0,
menu_host_autotearoff => 0,
unique_servers => 0,
use_all_a_records => 0,
send_menu_xml_file => $ENV{HOME} . '/.clusterssh/send_menu',
auto_wm_decoration_offsets => "no", # Debian #842965
send_menu_xml_file => $ENV{HOME} . '/.csshrc_send_menu',
# don't set username here as takes precendence over ssh config
user => '',
rows => -1,
cols => -1,
fillscreen => "no",
);
sub new {
@ -150,10 +112,9 @@ sub new {
$comms = 'telnet' if ( $comms eq 'tel' );
$comms = 'console' if ( $comms eq 'con' );
$comms = 'ssh' if ( $comms eq 'lusterssh' );
$comms = 'sftp' if ( $comms eq 'sftp' );
# list of allowed comms methods
if ( 'ssh rsh telnet sftp console' !~ m/\b$comms\b/ ) {
if ( 'ssh rsh telnet console' !~ m/\b$comms\b/ ) {
$self->{comms} = 'ssh';
}
else {
@ -218,14 +179,12 @@ sub validate_args {
);
}
# check the terminal has been found correctly
# looking for the terminal should not be fatal
if ( !-e $self->{terminal} ) {
eval { $self->{terminal} = $self->find_binary( $self->{terminal} ); };
if ($@) {
warn $@->message;
}
}
# # Don't search for the path to the binary - assume it is on the path
# # or defined correctly in the config.
# if( !-e $self->{ $self->{comms} } )
# {
# $self->{ $self->{comms} } = $self->find_binary( $self->{comms} );
# }
return $self;
}
@ -295,15 +254,6 @@ sub parse_config_file {
if ( $read_config{terminal_font} );
$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 {
@ -315,7 +265,7 @@ sub load_configs {
$ENV{HOME} . '/.clusterssh/config',
)
{
$self->parse_config_file($config) if ( -e $config && !-d _ );
$self->parse_config_file($config) if ( -e $config );
}
# write out default config file if necesasry
@ -330,22 +280,10 @@ sub load_configs {
# relative to config directory
for my $config (@configs) {
next unless ($config); # can be null when passed from Getopt::Long
$self->parse_config_file($config) if ( -e $config && !-d _ );
$self->parse_config_file($config) if ( -e $config );
my $file = $ENV{HOME} . '/.clusterssh/config_' . $config;
$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};
}
$self->parse_config_file($file) if ( -e $file );
}
return $self;
@ -449,25 +387,6 @@ sub write_user_config_file {
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
# just in case $PATH isnt set up right
sub find_binary {
@ -486,39 +405,39 @@ sub find_binary {
# if not found, strip the path and look again
if ( $binary =~ m!^/! ) {
if ( -f $binary ) {
$self->debug( 2, "Already have full path to in $binary" );
$self->debug( 2, "$binary already fully qualified" );
return $binary;
}
else {
$self->debug( 2, "Full path for $binary incorrect; searching" );
$self->debug( 2, "$binary not found - re-searching" );
$binary =~ s!^.*/!!;
}
}
my $path;
if ( !-x $binary || substr( $binary, 0, 1 ) ne '/' ) {
$path = $self->search_dirs( $binary, split( /:/, $ENV{PATH} ) );
# if it is on $PATH then no need to qualitfy the path to it
# keep it as it is
if ($path) {
return $binary;
}
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
!
);
}
foreach (
split( /:/, $ENV{PATH} ), qw!
/bin
/sbin
/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 {
$self->debug( 2, "Already configured OK" );
@ -544,7 +463,7 @@ sub dump {
my ( $self, $no_exit, ) = @_;
$self->debug( 3, 'Dumping config to STDOUT' );
print( '# Configuration dump produced by "cssh -d"', $/ );
print( '# Configuration dump produced by "cssh -u"', $/ );
foreach my $key ( sort keys %$self ) {
my $comment = '';
@ -570,6 +489,18 @@ sub dump {
1;
=pod
=head1 NAME
ClusterSSH::Config - Object representing application configuration
=head1 SYNOPSIS
=head1 DESCRIPTION
Object representing application configuration
=head1 METHODS
=over 4
@ -586,10 +517,6 @@ Read in configuration from given filename
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>');
Locate the binary <name> and return the full path. Doesn't just search
@ -610,3 +537,21 @@ are loaded).
Write currently defined configuration to STDOUT
=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;

File diff suppressed because it is too large Load diff

View file

@ -1,17 +1,10 @@
package App::ClusterSSH::Helper;
use strict;
use warnings;
package App::ClusterSSH::Helper;
# ABSTRACT: ClusterSSH::Helper - Object representing helper script
=head1 SYNOPSIS
=head1 DESCRIPTION
Object representing application configuration
=cut
use version;
our $VERSION = version->new('0.02');
use Carp;
use Try::Tiny;
@ -29,31 +22,6 @@ sub new {
sub script {
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_args = $config->{ $config->{comms} . '_args' };
my $config_command = $config->{command};
@ -65,15 +33,66 @@ sub script {
: "echo Press RETURN to continue; read IGNORE"
; # : "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 \$pipe=shift;
my \$svr=shift;
my \$user=shift;
my \$port=shift;
my \$mstr=shift;
my \$command="$command_pre $comms $comms_args ";
my \$command="$comms $comms_args ";
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");
close(PIPE) or die("Failed to close pipe: $!\\n");
if(\$svr =~ m/==\$/)
@ -107,10 +126,8 @@ sub script {
if("$config_command") {
\$command .= " \\\"$config_command\\\"";
}
\$command .= "$command_post";
\$command .= " ; $postcommand";
# provide some info for debugging purposes
warn("Running: \$command\\n");
warn("Running:\$command\\n"); # for debug purposes
exec(\$command);
HERE
@ -130,6 +147,18 @@ sub script {
1;
=pod
=head1 NAME
ClusterSSH::Helper - Object representing helper script
=head1 SYNOPSIS
=head1 DESCRIPTION
Object representing application configuration
=head1 METHODS
=over 4
@ -143,3 +172,21 @@ Create a new helper object.
Return the helper script
=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;

View file

@ -1,28 +1,12 @@
package App::ClusterSSH::Host;
use strict;
use warnings;
package App::ClusterSSH::Host;
# 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 version;
our $VERSION = version->new('0.03');
use Carp;
use Net::hostent;
use base qw/ App::ClusterSSH::Base /;
@ -41,7 +25,7 @@ sub new {
}
# remove any keys undef values - must be a better way...
foreach my $remove (qw/ port username geometry /) {
foreach my $remove (qw/ port username /) {
if ( !$args{$remove} && grep {/^$remove$/} keys(%args) ) {
delete( $args{$remove} );
}
@ -52,42 +36,33 @@ sub new {
# load in ssh hostname for later use
if ( !%ssh_hostname_for || !$ssh_configs_read{ $self->{ssh_config} } ) {
$self->read_ssh_file( $self->{ssh_config} );
$ssh_configs_read{ $self->{ssh_config} } = 1;
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 );
$self->debug( 5, 'Have the following ssh hostnames' );
$self->debug( 5, ' "', $_, '"' )
foreach ( sort keys %ssh_hostname_for );
# account for multiple declarations of hosts
$ssh_hostname_for{$_} = 1 foreach ( split( /\s+/, $1 ) );
}
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;
}
sub read_ssh_file($$) {
my ($self) = shift;
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_givenname {
my ($self) = @_;
return $self->{hostname};
}
sub get_hostname {
@ -100,19 +75,6 @@ sub get_username {
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 {
my ( $self, $new_username ) = @_;
$self->{username} = $new_username;
@ -130,18 +92,6 @@ sub set_port {
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 {
my ($self) = @_;
return $self->{master} || q{};
@ -157,16 +107,21 @@ sub get_realname {
my ($self) = @_;
if ( !$self->{realname} ) {
if ( $self->get_type eq 'ssh_alias' ) {
$self->{realname} = $self->{hostname};
if ( $self->{type} && $self->{type} eq 'name' ) {
if ( $ssh_hostname_for{ $self->{hostname} } ) {
$self->{realname} = $self->{hostname};
}
else {
my $gethost_obj = gethostbyname( $self->{hostname} );
$self->{realname}
= defined($gethost_obj)
? $gethost_obj->name()
: $self->{hostname};
}
}
else {
my $gethost_obj = gethostbyname( $self->{hostname} );
$self->{realname}
= defined($gethost_obj)
? $gethost_obj->name()
: $self->{hostname};
$self->{realname} = $self->{hostname};
}
}
return $self->{realname};
@ -181,27 +136,22 @@ sub parse_host_string {
# check for bracketed IPv6 addresses
if ($host_string =~ m{
\A
(?:(.*?)@)? # username@ (optional)
\[([\w:]*)\] # [<sequence of chars>]
(?::(\d+))? # :port (optional)
(?:=(\d+\D\d+\D\d+\D\d))? # =geometry (optional)
(?:(.*?)@)? # username@ (optional)
\[([\w:]*)\] # [<sequence of chars>]
(?::(\d+))? # :port (optional)
\z
}xms
)
{
$self->debug(
5,
$self->loc(
'bracketed IPv6: u=[_1] h=[_2] p=[_3] g=[_4]',
$1, $2, $3, $4
),
$self->loc( 'bracketed IPv6: u=[_1] h=[_2] p=[_3]', $1, $2, $3 ),
);
return __PACKAGE__->new(
parse_string => $parse_string,
username => $1,
hostname => $2,
port => $3,
geometry => $4,
type => 'ipv6',
);
}
@ -209,82 +159,58 @@ sub parse_host_string {
# check for standard IPv4 host.domain/IP address
if ($host_string =~ m{
\A
(?:(.*?)@)? # username@ (optional)
([\w\.-]*) # hostname[.domain[.domain] | 123.123.123.123
(?::(\d+))? # :port (optional)
(?:=(\d+\D\d+\D\d+\D\d+))? # =geometry (optional)
(?:(.*?)@)? # username@ (optional)
([\w\.-]*) # hostname[.domain[.domain] | 123.123.123.123
(?::(\d+))? # :port (optional)
\z
}xms
)
{
$self->debug(
5,
$self->loc(
'std IPv4: u=[_1] h=[_2] p=[_3] g=[_4]',
$1, $2, $3, $4
),
$self->debug( 5,
$self->loc( 'std IPv4: u=[_1] h=[_2] p=[_3]', $1, $2, $3 ),
);
return __PACKAGE__->new(
parse_string => $parse_string,
username => $1,
hostname => $2,
port => $3,
geometry => $4,
type => 'ipv4',
);
}
# 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
if ( $host_string =~ s/\A(?:(.*?)@)// ) {
my $username = q[];
if ( $host_string =~ s/\A(?:(.*)@)// ) {
# catch where @ is in host_string but no text before it
$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;
$username = $1 || q{};
}
# use number of colons as a possible indicator
my $colon_count = $host_string =~ tr/://;
# 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
if ( $colon_count == 7 || $colon_count == 8 || $host_string eq '::1' ) {
if ( $colon_count == 8 ) {
$host_string =~ s/(?::(\d+?))$//;
$port = $1;
}
if ( $colon_count == 7 || $host_string eq '::1' ) {
$self->debug(
5,
$self->loc(
'IPv6: u=[_1] h=[_2] p=[_3] g=[_4]',
$username, $host_string, $port, $geometry,
'IPv6: u=[_1] h=[_2] p=[_3]',
$username, $host_string, ''
),
);
return __PACKAGE__->new(
parse_string => $parse_string,
username => $username,
hostname => $host_string,
port => $port,
geometry => $geometry,
port => q{},
type => 'ipv6',
);
}
if ( $colon_count > 1
&& $colon_count < 8 )
&& $colon_count < 8
&& $host_string =~ m/:(\d+)$/xsm )
{
warn 'Ambiguous host string: "', $host_string, '"', $/;
warn 'Assuming you meant "[', $host_string, ']"?', $/;
@ -292,21 +218,51 @@ sub parse_host_string {
$self->debug(
5,
$self->loc(
'Ambiguous IPv6 u=[_1] h=[_2] p=[_3] g=[_4]',
$username, $host_string, $port, $geometry,
'Ambiguous IPv6 u=[_1] h=[_2] p=[_3]', $username,
$host_string, ''
)
);
#warn "host_string=$host_string";
#warn "username=$username";
#warn $self->loc('some string to return');
#warn 'debug done, returning';
return __PACKAGE__->new(
parse_string => $parse_string,
username => $username,
hostname => $host_string,
port => q{},
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 => $host_string,
hostname => $hostname,
port => $port,
geometry => $geometry,
type => 'ipv6',
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
croak(
App::ClusterSSH::Exception->throw(
@ -324,11 +280,9 @@ sub check_ssh_hostname {
$self->get_hostname );
if ( $ssh_hostname_for{ $self->get_hostname } ) {
$self->debug( 5, 'Found' );
return 1;
}
else {
$self->debug( 5, 'Not found' );
return 0;
}
}
@ -343,6 +297,26 @@ use overload (
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
=over 4
@ -360,10 +334,6 @@ Create a new host object. 'hostname' is a required arg, 'username' and
=item $host->get_master
=item $host->get_geometry
=item $host->get_type
Return specific details about the host
=item $host->set_username
@ -372,16 +342,12 @@ Return specific details about the host
=item $host->set_master
=item $host->set_geometry
=item $host->set_type
Set specific details about the host after its been created.
=item get_realname
If the server name provided is not an IP address (either IPv4 or IPv6)
attempt to resolve it and return the discovered names.
attempt to resolve it and retun the discovered names.
=item get_givenname
@ -397,11 +363,6 @@ 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
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
=item host
@ -426,3 +387,21 @@ the IPv6 address or a port definition?) and assumes it is part of address.
Use brackets to avoid seeing warning.
=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;

View file

@ -1,9 +1,22 @@
package App::ClusterSSH::L10N;
use strict;
use warnings;
package App::ClusterSSH::L10N;
use Locale::Maketext 1.01;
use base qw(Locale::Maketext);
# ABSTRACT: ClusterSSH::L10N - Base translations module
# This projects primary language is English
our %Lexicon = ( '_AUTO' => 1, );
1;
=pod
=head1 NAME
ClusterSSH::L10N - Base translations module
=head1 SYNOPSIS
@ -20,15 +33,22 @@ NOTE: the default language of this module is English.
=head1 METHODS
See Locale::Maketext - there are currently no extra methods in this module.
See Locale::Maketext - there are curently 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
use Locale::Maketext 1.01;
use base qw(Locale::Maketext);
# This projects primary language is English
our %Lexicon = ( '_AUTO' => 1, );
1;

View file

@ -1,6 +1,15 @@
package App::ClusterSSH::L10N::en;
use base 'App::ClusterSSH::L10N';
# ABSTRACT: App::ClusterSSH::L10N::en - Base English translations module
%Lexicon = ( '_AUTO' => 1, );
1;
=pod
=head1 NAME
App::ClusterSSH::L10N::en - Base English translations module
=head1 SYNOPSIS
@ -13,14 +22,24 @@ package App::ClusterSSH::L10N::en;
L<Locale::Maketext> based translation module for ClusterSSH. See
L<Locale::Maketext> for more information and usage.
=cut
use base 'App::ClusterSSH::L10N';
%Lexicon = ( '_AUTO' => 1, );
1;
=head1 METHODS
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;

View file

@ -1,89 +0,0 @@
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;

View file

@ -1,68 +0,0 @@
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;

File diff suppressed because it is too large Load diff

View file

@ -19,12 +19,12 @@ isa_ok( $base, 'App::ClusterSSH::Base' );
diag('testing output') if ( $ENV{TEST_VERBOSE} );
trap {
$base->stdout_output('testing');
$base->output('testing');
};
is( $trap->leaveby, 'return', 'returned ok' );
is( $trap->die, undef, 'returned ok' );
is( $trap->stderr, '', 'Expecting no STDERR' );
is( $trap->stdout =~ tr/\n//, 1, 'got correct number of print lines' );
is( $trap->leaveby, 'return', 'returned ok' );
is( $trap->die, undef, 'returned ok' );
is( $trap->stderr, '', 'Expecting no STDERR' );
is( $trap->stdout =~ tr/\n//, 1, 'got correct number of print lines' );
like( $trap->stdout, qr/\Atesting\n\Z/xsm,
'checking for expected print output' );
@ -68,10 +68,10 @@ trap {
$base = App::ClusterSSH::Base->new( debug => 6, );
};
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 =~ tr/\n//, 1, 'got new() debug output lines' );
is( $trap->leaveby, 'return', 'returned ok' );
is( $trap->die, undef, 'returned ok' );
is( $trap->stderr, '', 'Expecting no STDERR' );
is( $trap->stdout =~ tr/\n//, 1, 'got new() debug output lines' );
like(
$trap->stdout,
qr/^Setting\slanguage\sto\s"en"/xsm,
@ -83,10 +83,10 @@ trap {
$base = App::ClusterSSH::Base->new( debug => 6, lang => 'en' );
};
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 =~ tr/\n//, 1, 'got new() debug output lines' );
is( $trap->leaveby, 'return', 'returned ok' );
is( $trap->die, undef, 'returned ok' );
is( $trap->stderr, '', 'Expecting no STDERR' );
is( $trap->stdout =~ tr/\n//, 1, 'got new() debug output lines' );
like(
$trap->stdout,
qr/^Setting\slanguage\sto\s"en"/xsm,
@ -98,10 +98,10 @@ trap {
$base = App::ClusterSSH::Base->new( debug => 6, lang => 'rubbish' );
};
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 =~ tr/\n//, 1, 'got new() debug output lines' );
is( $trap->leaveby, 'return', 'returned ok' );
is( $trap->die, undef, 'returned ok' );
is( $trap->stderr, '', 'Expecting no STDERR' );
is( $trap->stdout =~ tr/\n//, 1, 'got new() debug output lines' );
like(
$trap->stdout,
qr/^Setting\slanguage\sto\s"rubbish"/xsm,
@ -109,29 +109,23 @@ like(
);
$base = undef;
my $get_config;
trap {
$base = App::ClusterSSH::Base->new( debug => 7, );
};
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 =~ tr/\n//, 3, 'got new() debug output lines' );
is( $trap->leaveby, 'return', 'returned ok' );
is( $trap->die, undef, 'returned ok' );
is( $trap->stderr, '', 'Expecting no STDERR' );
is( $trap->stdout =~ tr/\n//, 3, 'got new() debug output lines' );
like(
$trap->stdout,
qr/^Setting\slanguage\sto\s"en".Arguments\sto\sApp::ClusterSSH::Base->new.*debug\s=>\s7,$/xsm,
'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
$base = undef;
my $get_config;
my $object;
trap {
$base = App::ClusterSSH::Base->new( debug => 3, );
@ -142,17 +136,6 @@ is( $trap->die, undef, 'returned ok' );
is( $trap->stderr, '', 'Expecting no STDERR' );
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 {
$get_config = $base->config();
};
@ -225,125 +208,4 @@ like(
is( $trap->stderr, '', 'Expecting no STDERR' );
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();

View file

@ -1,439 +0,0 @@
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;

1063
t/10host.t

File diff suppressed because it is too large Load diff

View file

@ -1,2 +0,0 @@
include 10host_ssh_config
host server_ssh_included

View file

@ -1,24 +1,13 @@
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" );
use FindBin qw($Bin $Script);
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::Trap;
use File::Which qw(which);
use File::Temp qw(tempdir);
use File::Temp qw(tempdir);
use Test::Differences;
use Readonly;
@ -43,7 +32,7 @@ Readonly::Hash my %default_config => {
terminal_size => "80x24",
use_hotkeys => "yes",
key_quit => "Alt-q",
key_quit => "Control-q",
key_addhost => "Control-Shift-plus",
key_clientname => "Alt-n",
key_history => "Alt-h",
@ -52,10 +41,6 @@ Readonly::Hash my %default_config => {
key_macros_enable => "Alt-p",
key_paste => "Control-v",
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",
auto_quit => "yes",
auto_close => 5,
@ -86,14 +71,9 @@ Readonly::Hash my %default_config => {
telnet_args => "",
ssh => 'ssh',
ssh_args => "",
sftp => 'sftp',
sftp_args => "",
extra_tag_file => "",
extra_cluster_file => "",
external_cluster_command => '',
external_command_mode => '0600',
external_command_pipe => '',
unmap_on_redraw => "no",
@ -101,14 +81,9 @@ Readonly::Hash my %default_config => {
history_width => 40,
history_height => 10,
hostname_override => '',
command => q{},
command_pre => q{},
command_post => q{},
title => q{15CONFIG.T},
comms => q{ssh},
hide_menu => 0,
max_host_menu_items => 30,
macros_enabled => 'yes',
@ -117,36 +92,20 @@ Readonly::Hash my %default_config => {
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',
macro_user_1_command => '',
macro_user_2_command => '',
macro_user_3_command => '',
macro_user_4_command => '',
max_addhost_menu_cluster_items => 6,
menu_send_autotearoff => 0,
menu_host_autotearoff => 0,
unique_servers => 0,
use_all_a_records => 0,
use_natural_sort => 0,
send_menu_xml_file => $ENV{HOME} . '/.clusterssh/send_menu',
# Debian #842965
auto_wm_decoration_offsets => "no",
send_menu_xml_file => $ENV{HOME} . '/.csshrc_send_menu',
# other bits inheritted from App::ClusterSSH::Base
lang => 'en',
user => '',
rows => -1,
cols => -1,
debug => 0,
lang => 'en',
fillscreen => 'no',
user => '',
};
my %expected = %default_config;
is_deeply( $config, \%expected, 'default config is correct' );
@ -205,9 +164,6 @@ $expected{screen_reserve_left} = 100;
$expected{screen_reserve_right} = 100;
$expected{screen_reserve_top} = 100;
$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 {
$config = $config->parse_config_file( $file, );
};
@ -290,7 +246,7 @@ isa_ok( $config, "App::ClusterSSH::Config" );
is( $trap->stdout, q{}, 'Expecting no STDOUT' );
is( $trap->stderr, q{}, 'Expecting no STDERR' );
is_deeply( $config, \%expected, 'amended config is correct' );
is( $path, 'ls', 'Found correct path to "ls"' );
is( $path, which('ls'), 'Found correct path to "ls"' );
# check for a binary already found
my $newpath;
@ -303,8 +259,8 @@ isa_ok( $config, "App::ClusterSSH::Config" );
is( $trap->stdout, q{}, 'Expecting no STDOUT' );
is( $trap->stderr, q{}, 'Expecting no STDERR' );
is_deeply( $config, \%expected, 'amended config is correct' );
is( $path, 'ls', 'Found correct path to "ls"' );
is( $path, $newpath, 'No change made from find_binary' );
is( $path, which('ls'), 'Found correct path to "ls"' );
is( $path, $newpath, 'No change made from find_binary' );
# give false path to force another search
trap {
@ -316,8 +272,8 @@ isa_ok( $config, "App::ClusterSSH::Config" );
is( $trap->stdout, q{}, 'Expecting no STDOUT' );
is( $trap->stderr, q{}, 'Expecting no STDERR' );
is_deeply( $config, \%expected, 'amended config is correct' );
is( $path, 'ls', 'Found correct path to "ls"' );
is( $path, $newpath, 'No change made from find_binary' );
is( $path, which('ls'), 'Found correct path to "ls"' );
is( $path, $newpath, 'No change made from find_binary' );
note('Checks on loading configs');
note('empty dir');
@ -348,9 +304,6 @@ open( my $csshrc, '>', $ENV{HOME} . '/.csshrc' );
print $csshrc 'auto_quit = no', $/;
close($csshrc);
$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();
trap {
$config->load_configs();
@ -418,9 +371,9 @@ is_deeply( $config, \%expected, 'amended config is correct' );
note('no .csshrc warning, .clusterssh dir plus config + extra config');
open( $csshrc, '>', $ENV{HOME} . '/clusterssh.config' );
print $csshrc 'terminal_args = something', $/;
print $csshrc 'terminal = something', $/;
close($csshrc);
$expected{terminal_args} = 'something';
$expected{terminal} = 'something';
$config = App::ClusterSSH::Config->new();
trap {
$config->load_configs( $ENV{HOME} . '/clusterssh.config' );
@ -510,34 +463,7 @@ is( $trap->stderr,
'Expecting no STDERR'
);
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');
note('check failure to write default config is caught');
$ENV{HOME} = tempdir( CLEANUP => 1 );
mkdir( $ENV{HOME} . '/.clusterssh' );
mkdir( $ENV{HOME} . '/.clusterssh/config' );
@ -558,56 +484,34 @@ is( $trap->stderr,
note('Checking dump');
$config = App::ClusterSSH::Config->new(
send_menu_xml_file => $ENV{HOME} . '/.clusterssh/send_menu', );
send_menu_xml_file => $ENV{HOME} . '/.csshrc_send_menu' );
trap {
$config->dump();
};
my $expected = qq{# Configuration dump produced by "cssh -d"
my $expected = qq{# Configuration dump produced by "cssh -u"
auto_close=5
auto_quit=yes
auto_wm_decoration_offsets=no
cols=-1
command_post=
command_pre=
console=console
console_args=
console_position=
debug=0
external_cluster_command=
external_command_mode=0600
external_command_pipe=
extra_cluster_file=
extra_tag_file=
fillscreen=no
hide_menu=0
history_height=10
history_width=40
hostname_override=
key_addhost=Control-Shift-plus
key_clientname=Alt-n
key_history=Alt-h
key_localname=Alt-l
key_macros_enable=Alt-p
key_paste=Control-v
key_quit=Alt-q
key_quit=Control-q
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
lang=en
macro_hostname=%h
macro_newline=%n
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_version=%v
macros_enabled=yes
@ -616,16 +520,13 @@ max_host_menu_items=30
menu_host_autotearoff=0
menu_send_autotearoff=0
mouse_paste=Button-2
rows=-1
rsh=rsh
rsh_args=
screen_reserve_bottom=60
screen_reserve_left=0
screen_reserve_right=0
screen_reserve_top=0
send_menu_xml_file=} . $ENV{HOME} . qq{/.clusterssh/send_menu
sftp=sftp
sftp_args=
send_menu_xml_file=} . $ENV{HOME} . qq{/.csshrc_send_menu
show_history=0
ssh=ssh
ssh_args=
@ -645,11 +546,9 @@ terminal_reserve_right=0
terminal_reserve_top=5
terminal_size=80x24
terminal_title_opt=-T
unique_servers=0
unmap_on_redraw=no
use_all_a_records=0
use_hotkeys=yes
use_natural_sort=0
#user=
window_tiling=yes
window_tiling_direction=right

View file

@ -5,7 +5,6 @@ command=
comms=ssh
console_position=
extra_cluster_file=
extra_tag_file=
history_height=10
history_width=40
key_addhost=Control-Shift-plus
@ -16,10 +15,6 @@ key_paste=Control-v
key_quit=Control-q
key_retilehosts=Alt-r
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
method=ssh
mouse_paste=Button-2

View file

@ -1,31 +1,16 @@
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" );
use FindBin qw($Bin $Script);
use lib "$Bin/../lib";
use Test::More;
use Test::Trap;
use File::Which qw(which);
use File::Temp qw(tempdir);
use File::Temp qw(tempdir);
use Readonly;
package App::ClusterSSH::Config;
sub new {
my ( $class, %args ) = @_;
my $self = {%args};
return bless $self, $class;
}
package main;
BEGIN {
use_ok("App::ClusterSSH::Helper") || BAIL_OUT('failed to use module');
}
@ -35,71 +20,18 @@ my $helper;
$helper = App::ClusterSSH::Helper->new();
isa_ok( $helper, 'App::ClusterSSH::Helper' );
my $script;
trap {
$script = $helper->script;
};
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', 'no config' );
trap {
$script = $helper->script( something => 'nothing' );
};
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' );
#note('check failure to write default config is caught');
#$ENV{HOME} = tempdir( CLEANUP => 1 );
#mkdir($ENV{HOME}.'/.clusterssh');
#mkdir($ENV{HOME}.'/.clusterssh/config');
#$config = App::ClusterSSH::Config->new();
#trap {
# $config->load_configs();
#};
#is( $trap->leaveby, 'return', 'returned ok' );
#isa_ok( $config, "App::ClusterSSH::Config" );
#isa_ok( $config, "App::ClusterSSH::Config" );
#is( $trap->stdout, q{}, 'Expecting no STDOUT' );
#is( $trap->stderr, q{Unable to write default $HOME/.clusterssh/config: Is a directory}.$/, 'Expecting no STDERR' );
done_testing();

View file

@ -1,64 +1,22 @@
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" );
use FindBin qw($Bin $Script);
use lib "$Bin/../lib";
use Test::More;
use Test::Trap;
use File::Which qw(which);
use File::Temp qw(tempdir);
use English '-no_match_vars';
use Readonly;
package Test::ClusterSSH::Mock;
# generate purpose object used to simplfy testing
sub new {
my ( $class, %args ) = @_;
my $config = {%args};
return bless $config, $class;
}
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 );
my $cluster1 = App::ClusterSSH::Cluster->new();
isa_ok( $cluster1, 'App::ClusterSSH::Cluster' );
my $cluster2 = App::ClusterSSH::Cluster->new();
@ -84,23 +42,21 @@ isa_ok( $cluster1, 'App::ClusterSSH::Cluster' );
# no point running this test as root since root cannot be blocked
# from accessing the file
TODO: {
if ( $EUID != 0 ) {
my $no_read = $Bin . '/30cluster.cannot_read';
chmod 0000, $no_read;
trap {
$cluster1->read_cluster_file($no_read);
};
chmod 0644, $no_read;
isa_ok( $trap->die, 'App::ClusterSSH::Exception::LoadFile' );
is( $trap->die,
"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');
}
if ( $EUID != 0 ) {
my $no_read = $Bin . '/30cluster.cannot_read';
chmod 0000, $no_read;
trap {
$cluster1->read_cluster_file($no_read);
};
chmod 0644, $no_read;
isa_ok( $trap->die, 'App::ClusterSSH::Exception::LoadFile' );
is( $trap->die,
"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');
}
$expected{tag1} = ['host1'];
@ -132,82 +88,34 @@ is( scalar $cluster1->get_tag('default'),
'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
my @external_expected;
# text fetching external clusters when no command set or runnable
#$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();
@external_expected
= $cluster1->get_external_clusters("$Bin/external_cluster_command");
is_deeply( \@external_expected, [], 'External command no args' );
@external_expected = $cluster1->get_external_clusters("tag1 tag2");
@external_expected = $cluster1->get_external_clusters(
"$Bin/external_cluster_command tag1 tag2");
is_deeply( \@external_expected, [qw/tag1 tag2 /],
'External command: 2 args passed through' );
@external_expected = $cluster1->get_external_clusters("tag100");
@external_expected = $cluster1->get_external_clusters(
"$Bin/external_cluster_command tag100");
is_deeply( \@external_expected, [qw/host100 /],
'External command: 1 tag expanded to one host' );
@external_expected = $cluster1->get_external_clusters("tag200");
@external_expected = $cluster1->get_external_clusters(
"$Bin/external_cluster_command tag200");
is_deeply(
\@external_expected,
[qw/host200 host205 host210 /],
'External command: 1 tag expanded to 3 hosts and sorted'
);
@external_expected = $cluster1->get_external_clusters("tag400");
@external_expected = $cluster1->get_external_clusters(
"$Bin/external_cluster_command tag400");
is_deeply(
\@external_expected,
[ qw/host100 host200 host205 host210 host300 host325 host350 host400 host401 /
@ -226,7 +134,8 @@ if ( $ENV{TEST_VERBOSE} ) {
}
trap {
@external_expected = $cluster1->get_external_clusters("-x $redirect");
@external_expected = $cluster1->get_external_clusters(
"$Bin/external_cluster_command -x $redirect");
};
like(
$trap->die,
@ -237,7 +146,8 @@ is( $trap->stdout, '', 'External command: no stdout from perl code' );
is( $trap->stderr, '', 'External command: no stderr from perl code' );
trap {
@external_expected = $cluster1->get_external_clusters("-q $redirect");
@external_expected = $cluster1->get_external_clusters(
"$Bin/external_cluster_command -q $redirect");
};
like(
$trap->die,
@ -247,108 +157,6 @@ like(
is( $trap->stdout, '', 'External command: no stdout 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();
sub test_expected {

View file

@ -1,20 +1,9 @@
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" );
use FindBin qw($Bin $Script);
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::Trap;
use File::Which qw(which);
@ -29,24 +18,4 @@ $app = App::ClusterSSH->new();
isa_ok( $app, 'App::ClusterSSH' );
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();

View file

@ -1,8 +0,0 @@
#!/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

View file

@ -1,9 +0,0 @@
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();

View file

@ -1,4 +1,4 @@
#!/usr/bin/env perl
#!/usr/bin/perl
#
# test script for proving external command for fetching tags works
#
@ -7,14 +7,7 @@ use warnings;
use Getopt::Std;
my $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 /],
);
getopts( 'qx', $opt );
# if we get '-q' option, force an error
if ( $opt->{q} ) {
@ -28,11 +21,12 @@ if ( $opt->{x} ) {
exit 5;
}
# '-L' means list out available tags
if ( $opt->{L} ) {
print join( ' ', sort keys %tag_lookup ), $/;
exit 0;
}
my %tag_lookup = (
tag100 => [qw/ host100 /],
tag200 => [qw/ host200 host210 host205 /],
tag300 => [qw/ host300 host350 host325 /],
tag400 => [qw/ tag100 tag200 tag300 host400 host401 /],
);
my @lookup = @ARGV;

11
t/manifest.t Normal file
View file

@ -0,0 +1,11 @@
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' );

View file

@ -1,4 +0,0 @@
# perltidy to Perl Best Practices standard
-pbp -nst -nse
## For use in ~/.perltidyrc
# --backup-and-modify-in-place

View file

@ -2,10 +2,18 @@ use strict;
use warnings;
use Test::More;
eval "use Test::Pod::Coverage 1.00";
plan skip_all => "Test::Pod::Coverage 1.00 required for testing POD coverage"
# Ensure a recent version of Test::Pod::Coverage
my $min_tpc = 1.08;
eval "use Test::Pod::Coverage $min_tpc";
plan skip_all =>
"Test::Pod::Coverage $min_tpc required for testing POD coverage"
if $@;
plan skip_all => "Skipping coverage tests" unless $ENV{COVERAGE};
# Test::Pod::Coverage doesn't require a minimum Pod::Coverage version,
# 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();

View file

@ -1,87 +0,0 @@
#!/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();