2023-08-18 15:17:00 +00:00
|
|
|
#!/usr/bin/env python3
|
2023-04-26 17:22:52 +00:00
|
|
|
|
|
|
|
# use pyminify: pyminifier --obfuscate-variables $0 > minified_$0
|
|
|
|
|
|
|
|
import sys
|
|
|
|
import boto3
|
|
|
|
import time
|
|
|
|
|
|
|
|
my_tag = 'CustomHostname'
|
|
|
|
|
|
|
|
ec2_client = boto3.client('ec2')
|
|
|
|
|
|
|
|
|
|
|
|
def get_tag(resource, tag_name):
|
|
|
|
try:
|
|
|
|
for tag in resource['Tags']:
|
|
|
|
if tag['Key'] == tag_name:
|
|
|
|
return tag['Value']
|
|
|
|
|
|
|
|
except KeyError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
def enumerate_instances(launchtemplate_id, hostname_format):
|
|
|
|
""" Search for all names in use as well as all instances in flight """
|
|
|
|
in_use = []
|
|
|
|
in_flight = []
|
|
|
|
|
|
|
|
try:
|
|
|
|
# look for other instances sharing the same launch template which works across multiple ASGs eg. kube-control
|
|
|
|
for r in ec2_client.describe_instances(Filters=[{'Name': 'instance-state-name', 'Values': ['pending', 'running', 'stopping', 'stopped']}, {'Name': 'tag:aws:ec2launchtemplate:id', 'Values': [launchtemplate_id]}])['Reservations']:
|
|
|
|
for instance in r["Instances"]:
|
|
|
|
# If an instance already has the tag mark index as used
|
|
|
|
hostname = get_tag(instance, my_tag)
|
|
|
|
if hostname:
|
|
|
|
in_use.append(hostname)
|
|
|
|
else:
|
|
|
|
in_flight.append(instance['InstanceId'])
|
|
|
|
|
|
|
|
except (KeyError, IndexError):
|
|
|
|
pass
|
|
|
|
|
|
|
|
in_flight = sorted(in_flight)
|
|
|
|
|
|
|
|
return in_use, in_flight
|
|
|
|
|
|
|
|
|
|
|
|
# Test format string
|
|
|
|
try:
|
|
|
|
launchtemplate_id = sys.argv[1]
|
|
|
|
my_instance_id = sys.argv[2]
|
|
|
|
hostname_format = sys.argv[3]
|
|
|
|
|
|
|
|
hostname_format.format(1)
|
|
|
|
print("Using {0} as Hostname format string".format(
|
|
|
|
hostname_format), file=sys.stderr)
|
|
|
|
except (IndexError):
|
|
|
|
print("Invalid or missing format string, aborting", file=sys.stderr)
|
|
|
|
sys.exit(0)
|
|
|
|
|
|
|
|
timeout = 0
|
|
|
|
while True:
|
|
|
|
in_use, in_flight = enumerate_instances(launchtemplate_id, hostname_format)
|
|
|
|
|
|
|
|
# Ideally in_flight has only one element, my_instance_id
|
|
|
|
# otherwise we have a race condition
|
|
|
|
# if my_instance_id is the first element in the sorted list we proceed to break the race
|
|
|
|
# otherwise wait for 5 seconds and try again
|
|
|
|
if my_instance_id not in in_flight:
|
|
|
|
print("Seems like instance {0} is already in_use, aborting".format(
|
|
|
|
my_instance_id), file=sys.stderr)
|
|
|
|
break
|
|
|
|
|
|
|
|
if in_flight[0] == my_instance_id:
|
|
|
|
# Now lets find the lowest free index
|
|
|
|
index = 0
|
|
|
|
my_hostname = hostname_format.format(index)
|
|
|
|
for name in sorted(in_use):
|
|
|
|
if name != my_hostname:
|
|
|
|
break
|
|
|
|
index += 1
|
|
|
|
my_hostname = hostname_format.format(index)
|
|
|
|
|
|
|
|
print("Assigning {0} to {1}".format(
|
|
|
|
my_hostname, my_instance_id), file=sys.stderr)
|
|
|
|
|
|
|
|
ec2_client.create_tags(Resources=[str(my_instance_id)], Tags=[
|
|
|
|
{'Key': str(my_tag), 'Value': str(my_hostname)}])
|
|
|
|
print(my_hostname)
|
|
|
|
break
|
|
|
|
|
|
|
|
print("{0} are in flight and we are not the first, {1} are currently in use, retrying...".format(
|
|
|
|
in_flight, in_use), file=sys.stderr)
|
|
|
|
timeout += 2
|
|
|
|
|
|
|
|
if timeout > 300:
|
|
|
|
print("Parallel booting instances did not settle within time limit (300s). Giving up!", file=sys.stderr)
|
|
|
|
break
|
|
|
|
|
|
|
|
time.sleep(2)
|