-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathssm.py
More file actions
executable file
·83 lines (64 loc) · 2.3 KB
/
ssm.py
File metadata and controls
executable file
·83 lines (64 loc) · 2.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#!/usr/bin/env python
"""CLI to open an SSH-like session to EC2 instances via AWS SSM."""
import argparse
import pty
import sys
from typing import Any
import boto3
from botocore.exceptions import ClientError, NoCredentialsError
from cursesmenu import CursesMenu
from cursesmenu.items import FunctionItem
def get_running_instances(ec2_client: Any) -> list[dict[str, Any]]:
"""Return a list of running EC2 instances."""
try:
response = ec2_client.describe_instances(
Filters=[{"Name": "instance-state-name", "Values": ["running"]}]
)
except NoCredentialsError:
sys.exit("No AWS credentials found.")
except ClientError as e:
code = e.response["Error"]["Code"]
if code == "AuthFailure":
sys.exit("Not authorized.")
sys.exit(f"AWS error: {code}")
return [
instance
for reservation in response["Reservations"]
for instance in reservation["Instances"]
]
def open_instance_connection(instance_id: str) -> None:
"""Start an SSM session against the given instance."""
pty.spawn(["aws", "ssm", "start-session", "--target", instance_id])
def instance_login(_args: argparse.Namespace) -> None:
ec2_client = boto3.client("ec2")
instances = get_running_instances(ec2_client)
if not instances:
print("No running instances found.")
return
menu = CursesMenu("All instances", "Server")
for instance in instances:
label = f"{instance['InstanceId']} | {instance['PrivateDnsName']}"
menu.append_item(
FunctionItem(
label,
open_instance_connection,
[instance["InstanceId"]],
should_exit=True,
)
)
menu.show()
def build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(description="Open an SSH connection to EC2 instances via SSM.")
subparsers = parser.add_subparsers(dest="command")
login_parser = subparsers.add_parser("login", help="Login to an instance.")
login_parser.set_defaults(func=instance_login)
return parser
def main() -> None:
parser = build_parser()
args = parser.parse_args()
if not hasattr(args, "func"):
parser.print_help()
return
args.func(args)
if __name__ == "__main__":
main()