vpc-tools.py 6.99 KB
Newer Older
e0d committed
1 2 3
"""VPC Tools.

Usage:
4
    vpc-tools.py ssh-config (vpc <vpc_id> | stack-name <stack_name>) [(identity-file <identity_file>)] user <user> [(config-file <config_file>)] [(strict-host-check <strict_host_check>)] [(jump-box <jump_box>)]
e0d committed
5 6 7 8 9 10 11 12 13 14
    vpc-tools.py (-h --help)
    vpc-tools.py (-v --version)

Options:
    -h --help       Show this screen.
    -v --version    Show version.

"""
import boto
from docopt import docopt
15
from vpcutil import vpc_for_stack_name
16 17
from vpcutil import stack_name_for_vpc
from collections import defaultdict
e0d committed
18 19 20 21


VERSION="vpc tools 0.1"
DEFAULT_USER="ubuntu"
22
DEFAULT_HOST_CHECK="ask"
e0d committed
23

John Jarvis committed
24 25 26 27 28 29
BASTION_CONFIG = """Host {jump_box}
    HostName {ip}
    ForwardAgent yes
    User {user}
    StrictHostKeyChecking {strict_host_check}
    {identity_line}
e0d committed
30 31
    """

John Jarvis committed
32 33
HOST_CONFIG = """# Instance ID: {instance_id}
Host {name}
34
    ProxyCommand ssh -q {config_file} -W %h:%p {jump_box}
John Jarvis committed
35 36 37 38 39 40 41
    HostName {ip}
    ForwardAgent yes
    User {user}
    StrictHostKeyChecking {strict_host_check}
    {identity_line}
    """

42 43 44 45 46 47 48 49 50 51
DIRECT_HOST_CONFIG = """# Instance ID: {instance_id}
Host {name}
    HostName {ip}
    ForwardAgent yes
    User {user}
    StrictHostKeyChecking {strict_host_check}
    {identity_line}
    """


John Jarvis committed
52 53 54 55 56 57 58
BASTION_HOST_CONFIG = """# Instance ID: {instance_id}
Host {name}
    HostName {ip}
    ForwardAgent yes
    User {user}
    StrictHostKeyChecking {strict_host_check}
    {identity_line}
e0d committed
59 60 61
    """


John Jarvis committed
62

e0d committed
63 64 65 66 67 68
def dispatch(args):

    if args.get("ssh-config"):
        _ssh_config(args)

def _ssh_config(args):
69 70
    if args.get("vpc"):
      vpc_id = args.get("<vpc_id>")
71
      stack_name = stack_name_for_vpc(vpc_id)
72 73 74 75
    elif args.get("stack-name"):
      stack_name = args.get("<stack_name>")
      vpc_id = vpc_for_stack_name(stack_name)
    else:
Feanil Patel committed
76
      raise Exception("No vpc_id or stack_name provided.")
e0d committed
77 78 79

    vpc = boto.connect_vpc()

80 81 82 83 84 85
    identity_file = args.get("<identity_file>", None)
    if identity_file:
        identity_line = "IdentityFile {}".format(identity_file)
    else:
        identity_line = ""

86
    user = args.get("<user>")
87
    config_file = args.get("<config_file>")
88
    strict_host_check = args.get("<strict_host_check>")
89 90 91 92

    if not user:
      user = DEFAULT_USER

93 94 95
    if not strict_host_check:
      strict_host_check = DEFAULT_HOST_CHECK

96 97 98
    if config_file:
      config_file = "-F {}".format(config_file)
    else:
99
      config_file = ""
e0d committed
100

101 102 103 104 105
    if args.get("jump-box"):
        jump_box = args.get("<jump_box>")
    else:
        jump_box = "{stack_name}-bastion".format(stack_name=stack_name)

106 107
    friendly = "{stack_name}-{logical_id}-{instance_number}"
    id_type_counter = defaultdict(int)
e0d committed
108 109 110 111 112 113

    reservations = vpc.get_all_instances(filters={'vpc-id' : vpc_id})

    for reservation in reservations:
        for instance in reservation.instances:

114 115 116 117
            if 'play' in instance.tags:
                logical_id = instance.tags['play']
            elif 'role' in instance.tags:
                # deprecated, use "play" instead
118 119
                logical_id = instance.tags['role']
            elif 'group' in instance.tags:
120
                logical_id = instance.tags['group']
Feanil Patel committed
121
            elif 'aws:cloudformation:logical-id' in instance.tags:
122
                logical_id = instance.tags['aws:cloudformation:logical-id']
Feanil Patel committed
123 124
            else:
                continue
125 126
            instance_number = id_type_counter[logical_id]
            id_type_counter[logical_id] += 1
e0d committed
127

128
            if logical_id == "BastionHost" or logical_id == 'bastion':
e0d committed
129

John Jarvis committed
130
                print BASTION_CONFIG.format(
e0d committed
131 132 133
                    jump_box=jump_box,
                    ip=instance.ip_address,
                    user=user,
134 135
                    strict_host_check=strict_host_check,
                    identity_line=identity_line)
e0d committed
136

John Jarvis committed
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
                print BASTION_HOST_CONFIG.format(
                    name=instance.private_ip_address,
                    ip=instance.ip_address,
                    user=user,
                    instance_id=instance.id,
                    strict_host_check=strict_host_check,
                    identity_line=identity_line)

                #duplicating for convenience with ansible
                name = friendly.format(stack_name=stack_name,
                                       logical_id=logical_id,
                                       instance_number=instance_number)

                print BASTION_HOST_CONFIG.format(
                    name=name,
                    ip=instance.ip_address,
                    user=user,
                    strict_host_check=strict_host_check,
                    instance_id=instance.id,
                    identity_line=identity_line)

            else:
                # Print host config even for the bastion box because that is how
                # ansible accesses it.
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
                if jump_box == "none":
                    print DIRECT_HOST_CONFIG.format(
                        name=instance.private_ip_address,
                        ip=instance.private_ip_address,
                        user=user,
                        config_file=config_file,
                        strict_host_check=strict_host_check,
                        instance_id=instance.id,
                        identity_line=identity_line)

                    #duplicating for convenience with ansible
                    name = friendly.format(stack_name=stack_name,
                                           logical_id=logical_id,
                                           instance_number=instance_number)

                    print DIRECT_HOST_CONFIG.format(
                        name=name,
                        ip=instance.private_ip_address,
                        user=user,
                        config_file=config_file,
                        strict_host_check=strict_host_check,
                        instance_id=instance.id,
                        identity_line=identity_line)

                else:
                    print HOST_CONFIG.format(
                        name=instance.private_ip_address,
                        jump_box=jump_box,
                        ip=instance.private_ip_address,
                        user=user,
                        config_file=config_file,
                        strict_host_check=strict_host_check,
                        instance_id=instance.id,
                        identity_line=identity_line)

                    #duplicating for convenience with ansible
                    name = friendly.format(stack_name=stack_name,
                                           logical_id=logical_id,
                                           instance_number=instance_number)

                    print HOST_CONFIG.format(
                        name=name,
                        jump_box=jump_box,
                        ip=instance.private_ip_address,
                        user=user,
                        config_file=config_file,
                        strict_host_check=strict_host_check,
                        instance_id=instance.id,
                        identity_line=identity_line)
e0d committed
210 211 212

if __name__ == '__main__':
    args = docopt(__doc__, version=VERSION)
213
    dispatch(args)