pec2 0.3.2 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +3 -1
- data/exe/bin/pnuke +96 -0
- data/exe/bin/prsync +126 -0
- data/exe/bin/pscp +108 -0
- data/exe/bin/pslurp +129 -0
- data/exe/bin/pssh +118 -0
- data/exe/bin/pssh-askpass +11 -0
- data/exe/man/man1/pnuke.1 +268 -0
- data/exe/man/man1/prsync.1 +299 -0
- data/exe/man/man1/pscp.1 +271 -0
- data/exe/man/man1/pslurp.1 +280 -0
- data/exe/man/man1/pssh.1 +368 -0
- data/exe/psshlib/__init__.py +0 -0
- data/exe/psshlib/askpass_client.py +102 -0
- data/exe/psshlib/askpass_server.py +101 -0
- data/exe/psshlib/cli.py +110 -0
- data/exe/psshlib/color.py +39 -0
- data/exe/psshlib/manager.py +345 -0
- data/exe/psshlib/psshutil.py +108 -0
- data/exe/psshlib/task.py +288 -0
- data/exe/psshlib/version.py +1 -0
- data/lib/pec2/cli.rb +8 -4
- data/lib/pec2/core.rb +1 -1
- data/lib/pec2/version.rb +1 -1
- data/pec2.gemspec +1 -1
- metadata +25 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fb281220d6b29ff7d3fee0f3f981680855d5cc08
|
4
|
+
data.tar.gz: de60d8338782ebc4214835e90aba81d7171b0959
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '08a9d23eb9c518f2fd8edc23f19fc5f5077a83626545c40331e202e680f98606547e9c9ceb666013b4e92f754459f53a88a9f97a4f804c25ad31f4255996baff'
|
7
|
+
data.tar.gz: b65d6d2e8b3f7f6a395e1cbd9d1a75b47d28eb828a1af7d49a33c9391eabe04ef309ca9bb6e8320822e4cfbbdf8baaf30d7e99da816928dcb968f1bc7ae8a26f
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -4,6 +4,8 @@ Run parallel ssh command for ec2.
|
|
4
4
|
|
5
5
|
Commands can run to multiple hosts at once using the ec2 tag.
|
6
6
|
|
7
|
+
required python.
|
8
|
+
|
7
9
|
## Examples
|
8
10
|
|
9
11
|
$ bundle exec pec2 -t Project:project_a Stages:production -c 'hostname'
|
@@ -12,7 +14,7 @@ Commands can run to multiple hosts at once using the ec2 tag.
|
|
12
14
|
|
13
15
|
$ bundle exec pec2 -t Project:project_a Stages:production -c 'sudo hostname' -P -s ${sudo_password}
|
14
16
|
|
15
|
-
## Parallel number control
|
17
|
+
## Parallel number control(150 threads)
|
16
18
|
|
17
19
|
$ bundle exec pec2 -t Project:embulk Stages:production -c 'hostname' -P -p 150
|
18
20
|
|
data/exe/bin/pnuke
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
# -*- Mode: python -*-
|
3
|
+
|
4
|
+
# Copyright (c) 2009-2012, Andrew McNabb
|
5
|
+
# Copyright (c) 2003-2008, Brent N. Chun
|
6
|
+
|
7
|
+
"""Nukes all processes that match pattern running as user on the set of nodes
|
8
|
+
in hosts.txt.
|
9
|
+
"""
|
10
|
+
|
11
|
+
import os
|
12
|
+
import sys
|
13
|
+
|
14
|
+
parent, bindir = os.path.split(os.path.dirname(os.path.abspath(sys.argv[0])))
|
15
|
+
if os.path.exists(os.path.join(parent, 'psshlib')):
|
16
|
+
sys.path.insert(0, parent)
|
17
|
+
|
18
|
+
from psshlib import psshutil
|
19
|
+
from psshlib.task import Task
|
20
|
+
from psshlib.manager import Manager, FatalError
|
21
|
+
from psshlib.cli import common_parser, common_defaults
|
22
|
+
|
23
|
+
_DEFAULT_TIMEOUT = 60
|
24
|
+
|
25
|
+
def option_parser():
|
26
|
+
parser = common_parser()
|
27
|
+
parser.usage = "%prog [OPTIONS] pattern"
|
28
|
+
parser.epilog = "Example: pnuke -h hosts.txt -l irb2 java"
|
29
|
+
return parser
|
30
|
+
|
31
|
+
def parse_args():
|
32
|
+
parser = option_parser()
|
33
|
+
defaults = common_defaults(timeout=_DEFAULT_TIMEOUT)
|
34
|
+
parser.set_defaults(**defaults)
|
35
|
+
opts, args = parser.parse_args()
|
36
|
+
|
37
|
+
if len(args) < 1:
|
38
|
+
parser.error('Pattern not specified.')
|
39
|
+
|
40
|
+
if len(args) > 1:
|
41
|
+
parser.error('Extra arguments given after the pattern.')
|
42
|
+
|
43
|
+
if not opts.host_files and not opts.host_strings:
|
44
|
+
parser.error('Hosts not specified.')
|
45
|
+
|
46
|
+
return opts, args
|
47
|
+
|
48
|
+
def do_pnuke(hosts, pattern, opts):
|
49
|
+
if opts.outdir and not os.path.exists(opts.outdir):
|
50
|
+
os.makedirs(opts.outdir)
|
51
|
+
if opts.errdir and not os.path.exists(opts.errdir):
|
52
|
+
os.makedirs(opts.errdir)
|
53
|
+
manager = Manager(opts)
|
54
|
+
for host, port, user in hosts:
|
55
|
+
cmd = ['ssh', host, '-o', 'NumberOfPasswordPrompts=1']
|
56
|
+
if opts.options:
|
57
|
+
for opt in opts.options:
|
58
|
+
cmd += ['-o', opt]
|
59
|
+
if user:
|
60
|
+
cmd += ['-l', user]
|
61
|
+
if port:
|
62
|
+
cmd += ['-p', port]
|
63
|
+
if opts.extra:
|
64
|
+
cmd.extend(opts.extra)
|
65
|
+
cmd.append('pkill -9 %s' % pattern)
|
66
|
+
t = Task(host, port, user, cmd, opts)
|
67
|
+
manager.add_task(t)
|
68
|
+
try:
|
69
|
+
statuses = manager.run()
|
70
|
+
except FatalError:
|
71
|
+
sys.exit(1)
|
72
|
+
|
73
|
+
if min(statuses) < 0:
|
74
|
+
# At least one process was killed.
|
75
|
+
sys.exit(3)
|
76
|
+
for status in statuses:
|
77
|
+
if status == 255:
|
78
|
+
sys.exit(4)
|
79
|
+
for status in statuses:
|
80
|
+
if status != 0:
|
81
|
+
sys.exit(5)
|
82
|
+
|
83
|
+
if __name__ == "__main__":
|
84
|
+
opts, args = parse_args()
|
85
|
+
pattern = args[0]
|
86
|
+
try:
|
87
|
+
hosts = psshutil.read_host_files(opts.host_files,
|
88
|
+
default_user=opts.user)
|
89
|
+
except IOError:
|
90
|
+
_, e, _ = sys.exc_info()
|
91
|
+
sys.stderr.write('Could not open hosts file: %s\n' % e.strerror)
|
92
|
+
sys.exit(1)
|
93
|
+
if opts.host_strings:
|
94
|
+
for s in opts.host_strings:
|
95
|
+
hosts.extend(psshutil.parse_host_string(s, default_user=opts.user))
|
96
|
+
do_pnuke(hosts, pattern, opts)
|
data/exe/bin/prsync
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
# -*- Mode: python -*-
|
3
|
+
|
4
|
+
# Copyright (c) 2009-2012, Andrew McNabb
|
5
|
+
# Copyright (c) 2003-2008, Brent N. Chun
|
6
|
+
|
7
|
+
"""Parallel rsync to the set of nodes in hosts.txt.
|
8
|
+
|
9
|
+
For each node, we essentially do a rsync -rv -e ssh local user@host:remote.
|
10
|
+
Note that remote must be an absolute path.
|
11
|
+
"""
|
12
|
+
|
13
|
+
import os
|
14
|
+
import re
|
15
|
+
import sys
|
16
|
+
|
17
|
+
parent, bindir = os.path.split(os.path.dirname(os.path.abspath(sys.argv[0])))
|
18
|
+
if os.path.exists(os.path.join(parent, 'psshlib')):
|
19
|
+
sys.path.insert(0, parent)
|
20
|
+
|
21
|
+
from psshlib import psshutil
|
22
|
+
from psshlib.task import Task
|
23
|
+
from psshlib.manager import Manager, FatalError
|
24
|
+
from psshlib.cli import common_parser, common_defaults
|
25
|
+
|
26
|
+
def option_parser():
|
27
|
+
parser = common_parser()
|
28
|
+
parser.usage = "%prog [OPTIONS] local remote"
|
29
|
+
parser.epilog = ("Example: prsync -r -h hosts.txt -l irb2 foo " +
|
30
|
+
"/home/irb2/foo")
|
31
|
+
|
32
|
+
parser.add_option('-r', '--recursive', dest='recursive',
|
33
|
+
action='store_true', help='recusively copy directories (OPTIONAL)')
|
34
|
+
parser.add_option('-a', '--archive', dest='archive', action='store_true',
|
35
|
+
help='use rsync -a (archive mode) (OPTIONAL)')
|
36
|
+
parser.add_option('-z', '--compress', dest='compress', action='store_true',
|
37
|
+
help='use rsync compression (OPTIONAL)')
|
38
|
+
parser.add_option('-S', '--ssh-args', metavar="ARGS", dest='ssh_args',
|
39
|
+
action='store', help='extra arguments for ssh')
|
40
|
+
|
41
|
+
return parser
|
42
|
+
|
43
|
+
def parse_args():
|
44
|
+
parser = option_parser()
|
45
|
+
defaults = common_defaults()
|
46
|
+
parser.set_defaults(**defaults)
|
47
|
+
opts, args = parser.parse_args()
|
48
|
+
|
49
|
+
if len(args) < 1:
|
50
|
+
parser.error('Paths not specified.')
|
51
|
+
|
52
|
+
if len(args) < 2:
|
53
|
+
parser.error('Remote path not specified.')
|
54
|
+
|
55
|
+
if len(args) > 2:
|
56
|
+
parser.error('Extra arguments given after the remote path.')
|
57
|
+
|
58
|
+
if not opts.host_files and not opts.host_strings:
|
59
|
+
parser.error('Hosts not specified.')
|
60
|
+
|
61
|
+
return opts, args
|
62
|
+
|
63
|
+
def do_prsync(hosts, local, remote, opts):
|
64
|
+
if opts.outdir and not os.path.exists(opts.outdir):
|
65
|
+
os.makedirs(opts.outdir)
|
66
|
+
if opts.errdir and not os.path.exists(opts.errdir):
|
67
|
+
os.makedirs(opts.errdir)
|
68
|
+
manager = Manager(opts)
|
69
|
+
for host, port, user in hosts:
|
70
|
+
ssh = ['ssh']
|
71
|
+
if opts.options:
|
72
|
+
for opt in opts.options:
|
73
|
+
ssh += ['-o', opt]
|
74
|
+
if port:
|
75
|
+
ssh += ['-p', port]
|
76
|
+
if opts.ssh_args:
|
77
|
+
ssh += [opts.ssh_args]
|
78
|
+
|
79
|
+
cmd = ['rsync', '-e', ' '.join(ssh)]
|
80
|
+
if opts.verbose:
|
81
|
+
cmd.append('-v')
|
82
|
+
if opts.recursive:
|
83
|
+
cmd.append('-r')
|
84
|
+
if opts.archive:
|
85
|
+
cmd.append('-a')
|
86
|
+
if opts.compress:
|
87
|
+
cmd.append('-z')
|
88
|
+
if opts.extra:
|
89
|
+
cmd.extend(opts.extra)
|
90
|
+
cmd.append(local)
|
91
|
+
if user:
|
92
|
+
cmd.append('%s@%s:%s' % (user, host, remote))
|
93
|
+
else:
|
94
|
+
cmd.append('%s:%s' % (host, remote))
|
95
|
+
t = Task(host, port, user, cmd, opts)
|
96
|
+
manager.add_task(t)
|
97
|
+
try:
|
98
|
+
statuses = manager.run()
|
99
|
+
except FatalError:
|
100
|
+
sys.exit(1)
|
101
|
+
|
102
|
+
if min(statuses) < 0:
|
103
|
+
# At least one process was killed.
|
104
|
+
sys.exit(3)
|
105
|
+
for status in statuses:
|
106
|
+
if status != 0:
|
107
|
+
sys.exit(4)
|
108
|
+
|
109
|
+
if __name__ == "__main__":
|
110
|
+
opts, args = parse_args()
|
111
|
+
local = args[0]
|
112
|
+
remote = args[1]
|
113
|
+
if not re.match("^/", remote):
|
114
|
+
print("Remote path %s must be an absolute path" % remote)
|
115
|
+
sys.exit(3)
|
116
|
+
try:
|
117
|
+
hosts = psshutil.read_host_files(opts.host_files,
|
118
|
+
default_user=opts.user)
|
119
|
+
except IOError:
|
120
|
+
_, e, _ = sys.exc_info()
|
121
|
+
sys.stderr.write('Could not open hosts file: %s\n' % e.strerror)
|
122
|
+
sys.exit(1)
|
123
|
+
if opts.host_strings:
|
124
|
+
for s in opts.host_strings:
|
125
|
+
hosts.extend(psshutil.parse_host_string(s, default_user=opts.user))
|
126
|
+
do_prsync(hosts, local, remote, opts)
|
data/exe/bin/pscp
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
# -*- Mode: python -*-
|
3
|
+
|
4
|
+
# Copyright (c) 2009-2012, Andrew McNabb
|
5
|
+
# Copyright (c) 2003-2008, Brent N. Chun
|
6
|
+
|
7
|
+
"""Parallel scp to the set of nodes in hosts.txt.
|
8
|
+
|
9
|
+
For each node, we essentially do a scp [-r] local user@host:remote. This
|
10
|
+
program also uses the -q (quiet) and -C (compression) options. Note that
|
11
|
+
remote must be an absolute path.
|
12
|
+
"""
|
13
|
+
|
14
|
+
import os
|
15
|
+
import re
|
16
|
+
import sys
|
17
|
+
|
18
|
+
parent, bindir = os.path.split(os.path.dirname(os.path.abspath(sys.argv[0])))
|
19
|
+
if os.path.exists(os.path.join(parent, 'psshlib')):
|
20
|
+
sys.path.insert(0, parent)
|
21
|
+
|
22
|
+
from psshlib import psshutil
|
23
|
+
from psshlib.task import Task
|
24
|
+
from psshlib.manager import Manager, FatalError
|
25
|
+
from psshlib.cli import common_parser, common_defaults
|
26
|
+
|
27
|
+
def option_parser():
|
28
|
+
parser = common_parser()
|
29
|
+
parser.usage = "%prog [OPTIONS] local remote"
|
30
|
+
parser.epilog = ("Example: pscp -h hosts.txt -l irb2 foo.txt " +
|
31
|
+
"/home/irb2/foo.txt")
|
32
|
+
|
33
|
+
parser.add_option('-r', '--recursive', dest='recursive',
|
34
|
+
action='store_true', help='recusively copy directories (OPTIONAL)')
|
35
|
+
|
36
|
+
return parser
|
37
|
+
|
38
|
+
def parse_args():
|
39
|
+
parser = option_parser()
|
40
|
+
defaults = common_defaults()
|
41
|
+
parser.set_defaults(**defaults)
|
42
|
+
opts, args = parser.parse_args()
|
43
|
+
|
44
|
+
if len(args) < 1:
|
45
|
+
parser.error('Paths not specified.')
|
46
|
+
|
47
|
+
if len(args) < 2:
|
48
|
+
parser.error('Remote path not specified.')
|
49
|
+
|
50
|
+
if not opts.host_files and not opts.host_strings:
|
51
|
+
parser.error('Hosts not specified.')
|
52
|
+
|
53
|
+
return opts, args
|
54
|
+
|
55
|
+
def do_pscp(hosts, localargs, remote, opts):
|
56
|
+
if opts.outdir and not os.path.exists(opts.outdir):
|
57
|
+
os.makedirs(opts.outdir)
|
58
|
+
if opts.errdir and not os.path.exists(opts.errdir):
|
59
|
+
os.makedirs(opts.errdir)
|
60
|
+
manager = Manager(opts)
|
61
|
+
for host, port, user in hosts:
|
62
|
+
cmd = ['scp', '-qC']
|
63
|
+
if opts.options:
|
64
|
+
for opt in opts.options:
|
65
|
+
cmd += ['-o', opt]
|
66
|
+
if port:
|
67
|
+
cmd += ['-P', port]
|
68
|
+
if opts.recursive:
|
69
|
+
cmd.append('-r')
|
70
|
+
if opts.extra:
|
71
|
+
cmd.extend(opts.extra)
|
72
|
+
cmd.extend(localargs)
|
73
|
+
if user:
|
74
|
+
cmd.append('%s@%s:%s' % (user, host, remote))
|
75
|
+
else:
|
76
|
+
cmd.append('%s:%s' % (host, remote))
|
77
|
+
t = Task(host, port, user, cmd, opts)
|
78
|
+
manager.add_task(t)
|
79
|
+
try:
|
80
|
+
statuses = manager.run()
|
81
|
+
except FatalError:
|
82
|
+
sys.exit(1)
|
83
|
+
|
84
|
+
if min(statuses) < 0:
|
85
|
+
# At least one process was killed.
|
86
|
+
sys.exit(3)
|
87
|
+
for status in statuses:
|
88
|
+
if status != 0:
|
89
|
+
sys.exit(4)
|
90
|
+
|
91
|
+
if __name__ == "__main__":
|
92
|
+
opts, args = parse_args()
|
93
|
+
localargs = args[0:-1]
|
94
|
+
remote = args[-1]
|
95
|
+
if not re.match("^/", remote):
|
96
|
+
print("Remote path %s must be an absolute path" % remote)
|
97
|
+
sys.exit(3)
|
98
|
+
try:
|
99
|
+
hosts = psshutil.read_host_files(opts.host_files,
|
100
|
+
default_user=opts.user)
|
101
|
+
except IOError:
|
102
|
+
_, e, _ = sys.exc_info()
|
103
|
+
sys.stderr.write('Could not open hosts file: %s\n' % e.strerror)
|
104
|
+
sys.exit(1)
|
105
|
+
if opts.host_strings:
|
106
|
+
for s in opts.host_strings:
|
107
|
+
hosts.extend(psshutil.parse_host_string(s, default_user=opts.user))
|
108
|
+
do_pscp(hosts, localargs, remote, opts)
|
data/exe/bin/pslurp
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
# -*- Mode: python -*-
|
3
|
+
|
4
|
+
# Copyright (c) 2009-2012, Andrew McNabb
|
5
|
+
# Copyright (c) 2003-2008, Brent N. Chun
|
6
|
+
|
7
|
+
"""Parallel scp from the set of nodes in hosts.txt.
|
8
|
+
|
9
|
+
For each node, we essentially do a scp [-r] user@host:remote
|
10
|
+
outdir/<node>/local. This program also uses the -q (quiet) and -C
|
11
|
+
(compression) options. Note that remote must be an absolute path.
|
12
|
+
"""
|
13
|
+
|
14
|
+
import os
|
15
|
+
import re
|
16
|
+
import sys
|
17
|
+
|
18
|
+
parent, bindir = os.path.split(os.path.dirname(os.path.abspath(sys.argv[0])))
|
19
|
+
if os.path.exists(os.path.join(parent, 'psshlib')):
|
20
|
+
sys.path.insert(0, parent)
|
21
|
+
|
22
|
+
from psshlib import psshutil
|
23
|
+
from psshlib.task import Task
|
24
|
+
from psshlib.manager import Manager, FatalError
|
25
|
+
from psshlib.cli import common_parser, common_defaults
|
26
|
+
|
27
|
+
def option_parser():
|
28
|
+
parser = common_parser()
|
29
|
+
parser.usage = "%prog [OPTIONS] remote local"
|
30
|
+
parser.epilog = ("Example: pslurp -h hosts.txt -L /tmp/outdir -l irb2 " +
|
31
|
+
" /home/irb2/foo.txt foo.txt")
|
32
|
+
|
33
|
+
parser.add_option('-r', '--recursive', dest='recursive',
|
34
|
+
action='store_true', help='recusively copy directories (OPTIONAL)')
|
35
|
+
parser.add_option('-L', '--localdir', dest='localdir',
|
36
|
+
help='output directory for remote file copies')
|
37
|
+
|
38
|
+
return parser
|
39
|
+
|
40
|
+
def parse_args():
|
41
|
+
parser = option_parser()
|
42
|
+
defaults = common_defaults()
|
43
|
+
parser.set_defaults(**defaults)
|
44
|
+
opts, args = parser.parse_args()
|
45
|
+
|
46
|
+
if len(args) < 1:
|
47
|
+
parser.error('Paths not specified.')
|
48
|
+
|
49
|
+
if len(args) < 2:
|
50
|
+
parser.error('Local path not specified.')
|
51
|
+
|
52
|
+
if len(args) > 2:
|
53
|
+
parser.error('Extra arguments given after the local path.')
|
54
|
+
|
55
|
+
if not opts.host_files and not opts.host_strings:
|
56
|
+
parser.error('Hosts not specified.')
|
57
|
+
|
58
|
+
return opts, args
|
59
|
+
|
60
|
+
def do_pslurp(hosts, remote, local, opts):
|
61
|
+
if opts.localdir and not os.path.exists(opts.localdir):
|
62
|
+
os.makedirs(opts.localdir)
|
63
|
+
if opts.outdir and not os.path.exists(opts.outdir):
|
64
|
+
os.makedirs(opts.outdir)
|
65
|
+
if opts.errdir and not os.path.exists(opts.errdir):
|
66
|
+
os.makedirs(opts.errdir)
|
67
|
+
for host, port, user in hosts:
|
68
|
+
if opts.localdir:
|
69
|
+
dirname = "%s/%s" % (opts.localdir, host)
|
70
|
+
else:
|
71
|
+
dirname = host
|
72
|
+
if not os.path.exists(dirname):
|
73
|
+
os.mkdir(dirname)
|
74
|
+
manager = Manager(opts)
|
75
|
+
for host, port, user in hosts:
|
76
|
+
if opts.localdir:
|
77
|
+
localpath = "%s/%s/%s" % (opts.localdir, host, local)
|
78
|
+
else:
|
79
|
+
localpath = "%s/%s" % (host, local)
|
80
|
+
cmd = ['scp', '-qC']
|
81
|
+
if opts.options:
|
82
|
+
for opt in opts.options:
|
83
|
+
cmd += ['-o', opt]
|
84
|
+
if port:
|
85
|
+
cmd += ['-P', port]
|
86
|
+
if opts.recursive:
|
87
|
+
cmd.append('-r')
|
88
|
+
if opts.extra:
|
89
|
+
cmd.extend(opts.extra)
|
90
|
+
if user:
|
91
|
+
cmd.append('%s@%s:%s' % (user, host, remote))
|
92
|
+
else:
|
93
|
+
cmd.append('%s:%s' % (host, remote))
|
94
|
+
cmd.append(localpath)
|
95
|
+
t = Task(host, port, user, cmd, opts)
|
96
|
+
manager.add_task(t)
|
97
|
+
try:
|
98
|
+
statuses = manager.run()
|
99
|
+
except FatalError:
|
100
|
+
sys.exit(1)
|
101
|
+
|
102
|
+
if min(statuses) < 0:
|
103
|
+
# At least one process was killed.
|
104
|
+
sys.exit(3)
|
105
|
+
for status in statuses:
|
106
|
+
if status == 255:
|
107
|
+
sys.exit(4)
|
108
|
+
for status in statuses:
|
109
|
+
if status != 0:
|
110
|
+
sys.exit(5)
|
111
|
+
|
112
|
+
if __name__ == "__main__":
|
113
|
+
opts, args = parse_args()
|
114
|
+
remote = args[0]
|
115
|
+
local = args[1]
|
116
|
+
if not re.match("^/", remote):
|
117
|
+
print("Remote path %s must be an absolute path" % remote)
|
118
|
+
sys.exit(3)
|
119
|
+
try:
|
120
|
+
hosts = psshutil.read_host_files(opts.host_files,
|
121
|
+
default_user=opts.user)
|
122
|
+
except IOError:
|
123
|
+
_, e, _ = sys.exc_info()
|
124
|
+
sys.stderr.write('Could not open hosts file: %s\n' % e.strerror)
|
125
|
+
sys.exit(1)
|
126
|
+
if opts.host_strings:
|
127
|
+
for s in opts.host_strings:
|
128
|
+
hosts.extend(psshutil.parse_host_string(s, default_user=opts.user))
|
129
|
+
do_pslurp(hosts, remote, local, opts)
|