blob: 5469e2a4403c4ac266c511eb6aee4cb7e31055e5 [file] [log] [blame]
#!/usr/bin/python
# *****************************************************************************
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
# ******************************************************************************
import argparse
import json
from botocore import exceptions
from dlab.actions_lib import *
from dlab.meta_lib import *
import sys
import boto3
import ipaddress
parser = argparse.ArgumentParser()
parser.add_argument('--vpc_id', type=str, default='')
parser.add_argument('--username', type=str, default='')
parser.add_argument('--infra_tag_name', type=str, default='')
parser.add_argument('--infra_tag_value', type=str, default='')
parser.add_argument('--prefix', type=str, default='')
parser.add_argument('--ssn', type=bool, default=False)
parser.add_argument('--user_subnets_range', type=str, default='')
parser.add_argument('--zone', type=str, default='')
parser.add_argument('--subnet_name', type=str, default='')
args = parser.parse_args()
if __name__ == "__main__":
tag = {"Key": args.infra_tag_name, "Value": args.subnet_name}
tag_name = {"Key": "Name", "Value": args.subnet_name}
try:
if args.user_subnets_range == '' or args.ssn:
ec2 = boto3.resource('ec2')
private_subnet_size = ipaddress.ip_network(u'0.0.0.0/{}'.format(args.prefix)).num_addresses
vpc = ec2.Vpc(args.vpc_id)
vpc_cidr = vpc.cidr_block
first_vpc_ip = int(ipaddress.IPv4Address(vpc_cidr.split('/')[0].decode("utf-8")))
subnets = list(vpc.subnets.all())
subnets_cidr = []
for subnet in subnets:
subnets_cidr.append(subnet.cidr_block)
sortkey = lambda addr:\
(int(addr.split("/")[0].split(".")[0]),
int(addr.split("/")[0].split(".")[1]),
int(addr.split("/")[0].split(".")[2]),
int(addr.split("/")[0].split(".")[3]),
int(addr.split("/")[1]))
sorted_subnets_cidr = sorted(subnets_cidr, key=sortkey)
last_ip = first_vpc_ip
previous_subnet_size = private_subnet_size
for cidr in sorted_subnets_cidr:
first_ip = int(ipaddress.IPv4Address(cidr.split('/')[0].decode("utf-8")))
if first_ip - last_ip < private_subnet_size or previous_subnet_size < private_subnet_size:
subnet_size = ipaddress.ip_network(u'{}'.format(cidr)).num_addresses
last_ip = first_ip + subnet_size - 1
previous_subnet_size = subnet_size
else:
break
dlab_subnet_cidr = ''
if previous_subnet_size < private_subnet_size:
while True:
try:
dlab_subnet_cidr = '{0}/{1}'.format(ipaddress.ip_address(last_ip + 1), args.prefix)
ipaddress.ip_network(dlab_subnet_cidr.decode('utf-8'))
break
except ValueError:
last_ip = last_ip + 2
continue
else:
dlab_subnet_cidr = '{0}/{1}'.format(ipaddress.ip_address(last_ip + 1), args.prefix)
else:
pre_defined_subnet_list = []
subnet_cidr = args.user_subnets_range.split('-')[0].replace(' ', '')
pre_defined_subnet_list.append(subnet_cidr)
while str(subnet_cidr) != args.user_subnets_range.split('-')[1].replace(' ', ''):
subnet = ipaddress.ip_network(u'{}'.format(subnet_cidr))
num_addr = subnet.num_addresses
first_ip = int(ipaddress.IPv4Address(u'{}'.format(subnet.network_address)))
next_subnet = ipaddress.ip_network(u'{}/{}'.format(ipaddress.ip_address(first_ip + num_addr),
args.prefix))
pre_defined_subnet_list.append(next_subnet.compressed)
subnet_cidr = next_subnet
existed_subnet_list = []
client = boto3.client('ec2')
response = client.describe_subnets(Filters=[{'Name': 'vpc-id', 'Values': [args.vpc_id]}]).get('Subnets')
for i in response:
existed_subnet_list.append(i.get('CidrBlock'))
available_subnets = list(set(pre_defined_subnet_list) - set(existed_subnet_list))
if not available_subnets:
print("There is no available subnet to create. Aborting...")
sys.exit(1)
else:
dlab_subnet_cidr = available_subnets[0]
if args.ssn:
subnet_id = get_subnet_by_cidr(dlab_subnet_cidr, args.vpc_id)
subnet_check = get_subnet_by_tag(tag, False, args.vpc_id)
else:
subnet_id = get_subnet_by_cidr(dlab_subnet_cidr, args.vpc_id)
subnet_check = get_subnet_by_tag(tag, args.vpc_id)
if not subnet_check:
if subnet_id == '':
print("Creating subnet {0} in vpc {1} with tag {2}".
format(dlab_subnet_cidr, args.vpc_id, json.dumps(tag)))
subnet_id = create_subnet(args.vpc_id, dlab_subnet_cidr, tag, args.zone)
create_tag(subnet_id, tag_name)
else:
print("REQUESTED SUBNET ALREADY EXISTS. USING CIDR {}".format(subnet_check))
subnet_id = get_subnet_by_cidr(subnet_check)
print("SUBNET_ID: {}".format(subnet_id))
if not args.ssn:
print("Associating route_table with the subnet")
ec2 = boto3.resource('ec2')
if os.environ['conf_duo_vpc_enable'] == 'true':
rt = get_route_table_by_tag(args.infra_tag_value + '-secondary-Tag', args.infra_tag_value)
else:
rt = get_route_table_by_tag(args.infra_tag_name, args.infra_tag_value)
route_table = ec2.RouteTable(rt)
try:
route_table.associate_with_subnet(SubnetId=subnet_id)
if os.environ['conf_duo_vpc_enable'] == 'true':
create_peer_routes(os.environ['aws_peering_id'], args.infra_tag_value)
except exceptions.ClientError as err:
if 'Resource.AlreadyAssociated' in str(err):
print('Other route table is already associted with this subnet. Skipping...')
else:
print("Associating route_table with the subnet")
ec2 = boto3.resource('ec2')
rt = get_route_table_by_tag(args.infra_tag_name, args.infra_tag_value)
route_table = ec2.RouteTable(rt)
route_table.associate_with_subnet(SubnetId=subnet_id)
with open('/tmp/ssn_subnet_id', 'w') as f:
f.write(subnet_id)
except Exception as err:
print('Error: {0}'.format(err))
sys.exit(1)