Skip to content

Commit 6f2baed

Browse files
committed
Merging changes from internal development, mostly focuses around debug handling and session management
1 parent a54b643 commit 6f2baed

File tree

5 files changed

+103
-65
lines changed

5 files changed

+103
-65
lines changed

ec2instanceconnectcli/EC2InstanceConnectCLI.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import logging
12
import sys
23
import time
34
from subprocess import Popen
@@ -86,7 +87,11 @@ def invoke_command(self):
8687
"""
8788
try:
8889
for bundle in self.instance_bundles:
89-
bundle['session'] = self._get_botocore_session(profile_name=bundle['profile'], region=bundle['region'])
90+
session = self._get_botocore_session(profile_name=bundle['profile'], region=bundle['region'])
91+
# enable debug logging on botocore session if command line debug option is set
92+
if self.logger.getEffectiveLevel() == logging.DEBUG:
93+
session.set_debug_logger()
94+
bundle['session'] = session
9095

9196
self.call_ec2()
9297
self.handle_keys()

ec2instanceconnectcli/EC2InstanceConnectLogger.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ class EC2InstanceConnectLogger(object):
55
Common logger for all the EC2InstanceConnect components.
66
"""
77

8-
def __init__(self, verbose=None):
8+
def __init__(self, debug=False):
99
"""
10-
:param verbose: Specifies if debug messages should be enabled
11-
:type verbose: bool or None
10+
:param debug: Specifies if debug messages should be enabled
11+
:type debug: bool
1212
"""
1313
self.logger = logging.getLogger('EC2InstanceConnect')
1414
log_level = logging.ERROR
15-
if verbose:
15+
if debug:
1616
log_level = logging.DEBUG
1717
self.logger.setLevel(log_level)
1818
ch = logging.StreamHandler()

ec2instanceconnectcli/input_parser.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ def parseargs(args, mode='ssh'):
3535
"""
3636

3737
if len(args) < 2:
38-
raise AssertionError('No target was provided')
38+
raise AssertionError('Missing target')
3939
if len(args[1]) < 1:
40-
raise AssertionError('No target was provided')
40+
raise AssertionError('Missing target')
4141

4242
"""
4343
Our flags. As these are via argparse they're free.
@@ -61,8 +61,22 @@ def parseargs(args, mode='ssh'):
6161
# Process the instance & target data to give us an actual picture of what end hosts we're working with
6262
instance_bundles = _parse_instance_bundles(instance_bundles)
6363

64+
#validate instance_bundles
65+
_validate_instance_bundles(instance_bundles, mode)
66+
67+
#validate instance_bundles
68+
_validate_instance_bundles(instance_bundles, mode)
69+
6470
return instance_bundles, flags, command
6571

72+
def _validate_instance_bundles(instance_bundles, mode):
73+
"""
74+
For supported modes ensure that instance_id exists.
75+
"""
76+
for bundle in instance_bundles:
77+
if mode in ['ssh', 'sftp']:
78+
if not INSTANCE_ID_RE.match(bundle['instance_id']):
79+
raise AssertionError('Missing instance_id')
6680

6781
def _parse_command_flags(raw_command, instance_bundles, is_ssh=False):
6882
"""
@@ -123,7 +137,7 @@ def _parse_command_flags(raw_command, instance_bundles, is_ssh=False):
123137

124138
if used == len(raw_command) and len(raw_command) != 1:
125139
# EVERYTHING was a flag or flag value
126-
raise AssertionError('No target was provided')
140+
raise AssertionError('Missing target')
127141

128142
# Target
129143
instance_bundles[0]['target'] = raw_command[command_index]
@@ -152,7 +166,7 @@ def _parse_instance_bundles(instance_bundles):
152166
if '@' in bundle['target']:
153167
if len(bundle['target'].split('@')) > 2:
154168
# Host details includes an @. Invalid.
155-
raise AssertionError('Target DNS or IP address is invalid')
169+
raise AssertionError('Invalid target')
156170
# A user was specified
157171
bundle['username'], bundle['target'] = bundle['target'].split('@')
158172
if ':' in bundle['target']:
@@ -185,13 +199,13 @@ def _parse_instance_bundles(instance_bundles):
185199

186200
# Validate instance ID format
187201
if len(bundle['instance_id']) > 0 and not INSTANCE_ID_RE.match(bundle['instance_id'].lower()):
188-
raise AssertionError('Instance ID {0} is not valid'.format(bundle['instance_id']))
202+
raise AssertionError('Invalid instance_id')
189203

190204
# Validate DNS/IP/hostname/etc
191205
if bundle.get('target', None):
192206
if not _is_valid_target(bundle.get('target', '')):
193207
# It might be an IP
194-
raise AssertionError('Target DNS or IP address is invalid')
208+
raise AssertionError('Invalid target')
195209

196210
return instance_bundles
197211

ec2instanceconnectcli/mops.py

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,9 @@
77
from ec2instanceconnectcli.EC2InstanceConnectLogger import EC2InstanceConnectLogger
88
from ec2instanceconnectcli import input_parser
99

10-
11-
DEFAULT_USER = ''
1210
DEFAULT_INSTANCE = ''
13-
DEFAULT_PORT = 22
1411
DEFAULT_PROFILE = None
1512

16-
1713
def main(program, mode):
1814
"""
1915
Parses system arguments and sets defaults
@@ -25,29 +21,38 @@ def main(program, mode):
2521
:type mode: basestring
2622
"""
2723

28-
parser = argparse.ArgumentParser(description="""Usage:
29-
* mssh [user@]instance_id [-u profile] [-z availability_zone] [standard ssh flags] [command]
30-
* mssh [user@]dns_name -t instance_id [-u profile] [-z availability_zone] [standard ssh flags] [command]
31-
* msftp [user@]instance_id [-u aws_profile] [-z availability_zone] [standard sftp flags]
32-
* msftp [user@]dns_name -t instance_id [-u aws_profile] [-z availability_zone] [standard sftp flags]
33-
As standard for SFTP, the target may be followed by [:file ...] or [:dir[/]]
34-
""")
35-
parser.add_argument('-r', '--region', action='store', help='AWS region', type=str)
36-
parser.add_argument('-z', '--zone', action='store', help='Availability zone', type=str)
37-
parser.add_argument('-v', '--verbose', help='Enable logging', action="store_true")
24+
usage = ""
25+
if mode == "ssh":
26+
usage="""
27+
mssh [-t instance_id] [-u profile] [-z availability_zone] [-r region] [supported ssh flags] target [command]
28+
29+
target => [user@]instance_id | [user@]hostname
30+
[supported ssh flags] => [-l login_name] [-p port]
31+
"""
32+
elif mode == "sftp":
33+
usage="""
34+
msftp [-u aws_profile] [-z availability_zone] [supported sftp flags] target
35+
target => [user@]instance_id[:file ...][:dir[/]] | [user@]hostname[:file ...][:dir[/]]
36+
[supported sftp flags] => [-P port] [-b batchfile]
37+
"""
3838

39-
parser.add_argument('-u', '--profile', action='store', help='AWS Config Profile', type=str, default=DEFAULT_PROFILE)
40-
parser.add_argument('-t', '--instance_id', action='store', help='EC2 Instance ID. Required if target is DNS name or IP address.', type=str, default=DEFAULT_INSTANCE)
39+
parser = argparse.ArgumentParser(usage=usage)
40+
parser.add_argument('-r', '--region', action='store', help='AWS region', type=str, metavar='')
41+
parser.add_argument('-z', '--zone', action='store', help='Availability zone', type=str, metavar='')
42+
parser.add_argument('-u', '--profile', action='store', help='AWS Config Profile', type=str, default=DEFAULT_PROFILE, metavar='')
43+
parser.add_argument('-t', '--instance_id', action='store', help='EC2 Instance ID. Required if target is hostname', type=str, default=DEFAULT_INSTANCE, metavar='')
44+
parser.add_argument('-d', '--debug', action="store_true", help='Turn on debug logging')
4145

46+
args = parser.parse_known_args()
47+
48+
logger = EC2InstanceConnectLogger(args[0].debug)
4249
try:
43-
args = parser.parse_known_args()
44-
except:
50+
instance_bundles, flags, program_command = input_parser.parseargs(args, mode)
51+
except Exception as e:
52+
print(str(e))
4553
parser.print_help()
4654
sys.exit(1)
4755

48-
logger = EC2InstanceConnectLogger(args[0].verbose)
49-
instance_bundles, flags, program_command = input_parser.parseargs(args, mode)
50-
5156
#Generate temp key
5257
cli_key = EC2InstanceConnectKey(logger.get_logger())
5358
cli_command = EC2InstanceConnectCommand(program, instance_bundles, cli_key.get_priv_key_file(), flags, program_command, logger.get_logger())

ec2instanceconnectcli/mputty.py

Lines changed: 47 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@
66
from ec2instanceconnectcli.EC2InstanceConnectLogger import EC2InstanceConnectLogger
77
from ec2instanceconnectcli import input_parser
88

9-
DEFAULT_USER = ''
109
DEFAULT_INSTANCE = ''
11-
DEFAULT_PORT = 22
1210
DEFAULT_PROFILE = None
1311

1412
def main(program, mode):
@@ -22,45 +20,61 @@ def main(program, mode):
2220
:type mode: basestring
2321
"""
2422

25-
parser = argparse.ArgumentParser(description="""Usage:
26-
* mssh-putty [user@]instance_id [-u profile] [-r region] [-z availability_zone] [-i identity_file_ppk] [standard ssh flags] [command]
27-
* mssh-putty [user@]dns_name -t instance_id [-u profile] [-r region] [-z availability_zone] [-i identity_file_ppk] [standard ssh flags] [command]
28-
* msftp-putty [user@]instance_id [-u profile] [-r region] [-z availability_zone] [-i identity_file_ppk] [standard sftp flags]
29-
* msftp-putty [user@]dns_name -t instance_id [-u profile] [-r region] [-z availability_zone] [-i identity_file_ppk] [standard sftp flags]
30-
""")
31-
parser.add_argument('-r', '--region', action='store', help='AWS region', type=str)
32-
parser.add_argument('-z', '--zone', action='store', help='Availability zone', type=str)
33-
parser.add_argument('-v', '--verbose', help='Enable logging', action="store_true")
34-
parser.add_argument('-i', '--identity', action='store', help="Required. Identity file in ppk format", type=str)
35-
parser.add_argument('-u', '--profile', action='store', help='AWS Config Profile', type=str, default=DEFAULT_PROFILE)
36-
parser.add_argument('-t', '--instance_id', action='store', help='EC2 Instance ID. Required if target is DNS name or IP address.', type=str, default=DEFAULT_INSTANCE)
23+
usage = ""
24+
if mode == "ssh":
25+
usage = """
26+
mssh-putty [-t instance_id] [-u profile] [-r region] [-z availability_zone] [-i identity_file_ppk] [supported putty flags] target
3727
38-
try:
39-
args = parser.parse_known_args()
40-
except:
41-
parser.print_help()
42-
sys.exit(1)
28+
target => [user@]instance_id | [user@]dns_name
29+
[supported putty flags] => [-l login_name] [ -P port] [-m remote_command_file]
30+
"""
31+
elif mode == "sftp":
32+
usage = """
33+
msftp-putty [-t instance_id] [-u profile] [-r region] [-z availability_zone] [-i identity_file_ppk] [supported psftp flags] target
34+
35+
target => [user@]instance_id | [user@]dns_name
36+
[supported psftp flags] => [-l login_name] [ -P port] [-bc] [-b batchfile]
37+
"""
38+
39+
parser = argparse.ArgumentParser(usage=usage)
40+
parser.add_argument('-r', '--region', action='store', help='AWS region', type=str, metavar='')
41+
parser.add_argument('-z', '--zone', action='store', help='Availability zone', type=str, metavar='')
42+
parser.add_argument('-i', '--identity', action='store', help="Required. Identity file in ppk format", type=str, required=True, metavar='')
43+
parser.add_argument('-u', '--profile', action='store', help='AWS Config Profile', type=str, default=DEFAULT_PROFILE, metavar='')
44+
parser.add_argument('-t', '--instance_id', action='store', help='EC2 Instance ID. Required if target is hostname', type=str, default=DEFAULT_INSTANCE, metavar='')
45+
parser.add_argument('-d', '--debug', action="store_true", help='Turn on debug logging')
46+
47+
args = parser.parse_known_args()
4348

4449
#Read public key from ppk file.
4550
#Public key is unencrypted and in rsa format.
4651
pub_key_lines = []
47-
with open(args[0].identity, 'r') as f:
48-
pub_key_lines = f.readlines()
52+
pub_key = "ssh-rsa "
53+
try:
54+
with open(args[0].identity, 'r') as f:
55+
pub_key_lines = f.readlines()
4956

50-
#Validate that the identity file format is ppk.
51-
if pub_key_lines[0].find("PuTTY-User-Key-File-") == -1:
52-
print("Not a valid Putty key.")
53-
sys.exit(1)
57+
#Validate that the identity file format is ppk.
58+
if pub_key_lines[0].find("PuTTY-User-Key-File-") == -1:
59+
print("Not a valid Putty key.")
60+
sys.exit(1)
5461

55-
#public key starts from 4th line in ppk file.
56-
line_len = int(pub_key_lines[3].split(':')[1].strip())
57-
pub_key_lines = pub_key_lines[4:(4+line_len)]
58-
pub_key = "ssh-rsa "
59-
for pub_key_line in pub_key_lines:
60-
pub_key += pub_key_line[:-1]
62+
#public key starts from 4th line in ppk file.
63+
line_len = int(pub_key_lines[3].split(':')[1].strip())
64+
pub_key_lines = pub_key_lines[4:(4+line_len)]
65+
for pub_key_line in pub_key_lines:
66+
pub_key += pub_key_line[:-1]
67+
except Exception as e:
68+
print(str(e))
69+
sys.exit(1)
6170

62-
logger = EC2InstanceConnectLogger(args[0].verbose)
63-
instance_bundles, flags, program_command = input_parser.parseargs(args, mode)
71+
logger = EC2InstanceConnectLogger(args[0].debug)
72+
try:
73+
instance_bundles, flags, program_command = input_parser.parseargs(args, mode)
74+
except Exception as e:
75+
print(str(e))
76+
parser.print_help()
77+
sys.exit(1)
6478

6579
cli_command = EC2InstanceConnectCommand(program, instance_bundles, args[0].identity, flags, program_command, logger.get_logger())
6680
cli_command.get_command()

0 commit comments

Comments
 (0)