text: #!/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.
  #
  # ******************************************************************************
  
  from fabric.api import *
  from fabric.contrib.files import exists
  import argparse
  import boto3
  import traceback
  import sys
  import json
  import time
  import string
  import random
  from ConfigParser import SafeConfigParser
  
  parser = argparse.ArgumentParser()
  parser.add_argument('--service_base_name', required=True, type=str, default='',
                      help='unique name for repository environment')
  parser.add_argument('--aws_access_key', type=str, default='', help='AWS Access Key ID')
  parser.add_argument('--aws_secret_access_key', type=str, default='', help='AWS Secret Access Key')
  parser.add_argument('--vpc_id', type=str, default='', help='AWS VPC ID')
  parser.add_argument('--vpc_cidr', type=str, default='172.31.0.0/16', help='Cidr of VPC')
  parser.add_argument('--subnet_id', type=str, default='', help='AWS Subnet ID')
  parser.add_argument('--subnet_cidr', type=str, default='172.31.0.0/24', help='Cidr of subnet')
  parser.add_argument('--sg_id', type=str, default='', help='AWS VPC ID')
  parser.add_argument('--billing_tag', type=str, default='product:dlab', help='Tag in format: "Key1:Value1"')
  parser.add_argument('--additional_tags', type=str, default='', help='Tags in format: "Key1:Value1;Key2:Value2"')
  parser.add_argument('--tag_resource_id', type=str, default='dlab', help='The name of user tag')
  parser.add_argument('--allowed_ip_cidr', type=str, default='', help='Comma-separated CIDR of IPs which will have '
                                                                      'access to the instance')
  parser.add_argument('--key_name', type=str, default='', help='Key name (WITHOUT ".pem")')
  parser.add_argument('--key_path', type=str, default='', help='Key path')
  parser.add_argument('--instance_type', type=str, default='t2.medium', help='Instance shape')
  parser.add_argument('--region', required=True, type=str, default='', help='AWS region name')
  parser.add_argument('--elastic_ip', type=str, default='', help='Elastic IP address')
  parser.add_argument('--network_type', type=str, default='public', help='Network type: public or private')
  parser.add_argument('--hosted_zone_name', type=str, default='', help='Name of hosted zone')
  parser.add_argument('--hosted_zone_id', type=str, default='', help='ID of hosted zone')
  parser.add_argument('--subdomain', type=str, default='', help='Subdomain name')
  parser.add_argument('--efs_enabled', type=str, default='False', help="True - use AWS EFS, False - don't use AWS EFS")
  parser.add_argument('--efs_id', type=str, default='', help="ID of AWS EFS")
  parser.add_argument('--primary_disk_size', type=str, default='30', help="Disk size of primary volume")
  parser.add_argument('--additional_disk_size', type=str, default='50', help="Disk size of additional volume")
  parser.add_argument('--dlab_conf_file_path', type=str, default='', help="Full path to DLab conf file")
  parser.add_argument('--nexus_admin_password', type=str, default='', help="Password for Nexus admin user")
  parser.add_argument('--nexus_service_user_name', type=str, default='dlab-nexus', help="Nexus service user name")
  parser.add_argument('--nexus_service_user_password', type=str, default='', help="Nexus service user password")
  parser.add_argument('--action', required=True, type=str, default='', help='Action: create or terminate')
  args = parser.parse_args()
  
  
  def id_generator(size=10, with_digits=True):
      if with_digits:
          chars = string.digits + string.ascii_letters
      else:
          chars = string.ascii_letters
      return ''.join(random.choice(chars) for _ in range(size))
  
  
  def vpc_exist(return_id=False):
      try:
          vpc_created = False
          for vpc in ec2_resource.vpcs.filter(Filters=[{'Name': 'tag-key', 'Values': [tag_name]},
                                                       {'Name': 'tag-value', 'Values': [args.service_base_name]}]):
              if return_id:
                  return vpc.id
              vpc_created = True
          return vpc_created
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with getting AWS VPC: {}'.format(str(err)))
          raise Exception
  
  
  def create_vpc(vpc_cidr):
      try:
          tag = {"Key": tag_name, "Value": args.service_base_name}
          name_tag = {"Key": "Name", "Value": args.service_base_name + '-vpc'}
          vpc = ec2_resource.create_vpc(CidrBlock=vpc_cidr)
          create_tag(vpc.id, tag)
          create_tag(vpc.id, name_tag)
          return vpc.id
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with creating AWS VPC: {}'.format(str(err)))
          raise Exception
  
  
  def enable_vpc_dns(vpc_id):
      try:
          ec2_client.modify_vpc_attribute(VpcId=vpc_id,
                                          EnableDnsHostnames={'Value': True})
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with modifying AWS VPC attributes: {}'.format(str(err)))
          raise Exception
  
  
  def create_rt(vpc_id):
      try:
          tag = {"Key": tag_name, "Value": args.service_base_name}
          name_tag = {"Key": "Name", "Value": args.service_base_name + '-rt'}
          route_table = []
          rt = ec2_client.create_route_table(VpcId=vpc_id)
          rt_id = rt.get('RouteTable').get('RouteTableId')
          route_table.append(rt_id)
          print('Created AWS Route-Table with ID: {}'.format(rt_id))
          create_tag(route_table, json.dumps(tag))
          create_tag(route_table, json.dumps(name_tag))
          ig = ec2_client.create_internet_gateway()
          ig_id = ig.get('InternetGateway').get('InternetGatewayId')
          route_table = list()
          route_table.append(ig_id)
          create_tag(route_table, json.dumps(tag))
          create_tag(route_table, json.dumps(name_tag))
          ec2_client.attach_internet_gateway(InternetGatewayId=ig_id, VpcId=vpc_id)
          ec2_client.create_route(DestinationCidrBlock='0.0.0.0/0', RouteTableId=rt_id, GatewayId=ig_id)
          return rt_id
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with creating AWS Route Table: {}'.format(str(err)))
          raise Exception
  
  
  def remove_vpc(vpc_id):
      try:
          ec2_client.delete_vpc(VpcId=vpc_id)
          print("AWS VPC {} has been removed".format(vpc_id))
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with removing AWS VPC: {}'.format(str(err)))
          raise Exception
  
  
  def create_tag(resource, tag, with_tag_res_id=True):
      try:
          tags_list = list()
          if type(tag) == dict:
              resource_name = tag.get('Value')
              resource_tag = tag
          else:
              resource_name = json.loads(tag).get('Value')
              resource_tag = json.loads(tag)
          if type(resource) != list:
              resource = [resource]
          tags_list.append(resource_tag)
          if with_tag_res_id:
              tags_list.append(
                  {
                      'Key': args.tag_resource_id,
                      'Value': args.service_base_name + ':' + resource_name
                  }
              )
              tags_list.append(
                  {
                      'Key': args.billing_tag.split(':')[0],
                      'Value': args.billing_tag.split(':')[1]
                  }
              )
          if args.additional_tags:
              for tag in args.additional_tags.split(';'):
                  tags_list.append(
                      {
                          'Key': tag.split(':')[0],
                          'Value': tag.split(':')[1]
                      }
                  )
          ec2_client.create_tags(
              Resources=resource,
              Tags=tags_list
          )
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with setting tag: {}'.format(str(err)))
          raise Exception
  
  
  def create_efs_tag():
      try:
          tag = {"Key": tag_name, "Value": args.service_base_name}
          name_tag = {"Key": "Name", "Value": args.service_base_name + '-efs'}
          efs_client.create_tags(
              FileSystemId=args.efs_id,
              Tags=[
                  tag,
                  name_tag
              ]
          )
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with setting EFS tag: {}'.format(str(err)))
          raise Exception
  
  
  def create_subnet(vpc_id, subnet_cidr):
      try:
          tag = {"Key": tag_name, "Value": "{}".format(args.service_base_name)}
          name_tag = {"Key": "Name", "Value": "{}-subnet".format(args.service_base_name)}
          subnet = ec2_resource.create_subnet(VpcId=vpc_id, CidrBlock=subnet_cidr)
          create_tag(subnet.id, tag)
          create_tag(subnet.id, name_tag)
          subnet.reload()
          print('AWS Subnet has been created')
          return subnet.id
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with creating AWS Subnet: {}'.format(str(err)))
          raise Exception
  
  
  def remove_subnet():
      try:
          subnets = ec2_resource.subnets.filter(
              Filters=[{'Name': 'tag:{}'.format(tag_name), 'Values': [args.service_base_name]}])
          if subnets:
              for subnet in subnets:
                  ec2_client.delete_subnet(SubnetId=subnet.id)
                  print("The AWS subnet {} has been deleted successfully".format(subnet.id))
          else:
              print("There are no private AWS subnets to delete")
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with removing AWS Subnet: {}'.format(str(err)))
          raise Exception
  
  
  def get_route_table_by_tag(tag_value):
      try:
          route_tables = ec2_client.describe_route_tables(
              Filters=[{'Name': 'tag:{}'.format(tag_name), 'Values': ['{}'.format(tag_value)]}])
          rt_id = route_tables.get('RouteTables')[0].get('RouteTableId')
          return rt_id
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with getting AWS Route tables: {}'.format(str(err)))
          raise Exception
  
  
  def create_security_group(security_group_name, vpc_id, ingress, egress, tag, name_tag):
      try:
          group = ec2_resource.create_security_group(GroupName=security_group_name, Description='security_group_name',
                                                     VpcId=vpc_id)
          time.sleep(10)
          create_tag(group.id, tag)
          create_tag(group.id, name_tag)
          try:
              group.revoke_egress(IpPermissions=[{"IpProtocol": "-1", "IpRanges": [{"CidrIp": "0.0.0.0/0"}],
                                                  "UserIdGroupPairs": [], "PrefixListIds": []}])
          except:
              print("Mentioned rule does not exist")
          for rule in ingress:
              group.authorize_ingress(IpPermissions=[rule])
          for rule in egress:
              group.authorize_egress(IpPermissions=[rule])
          return group.id
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with creating AWS security group: {}'.format(str(err)))
          raise Exception
  
  
  def get_vpc_cidr_by_id(vpc_id):
      try:
          cidr_list = list()
          for vpc in ec2_client.describe_vpcs(VpcIds=[vpc_id]).get('Vpcs'):
              for cidr_set in vpc.get('CidrBlockAssociationSet'):
                  cidr_list.append(cidr_set.get('CidrBlock'))
              return cidr_list
          return ''
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with getting AWS VPC CIDR: {}'.format(str(err)))
          raise Exception
  
  
  def format_sg(sg_rules):
      try:
          formatted_sg_rules = list()
          for rule in sg_rules:
              if rule['IpRanges']:
                  for ip_range in rule['IpRanges']:
                      formatted_rule = dict()
                      for key in rule.keys():
                          if key == 'IpRanges':
                              formatted_rule['IpRanges'] = [ip_range]
                          else:
                              formatted_rule[key] = rule[key]
                      if formatted_rule not in formatted_sg_rules:
                          formatted_sg_rules.append(formatted_rule)
              else:
                  formatted_sg_rules.append(rule)
          return formatted_sg_rules
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with formating AWS SG rules: {}'.format(str(err)))
          raise Exception
  
  
  def remove_sgroups():
      try:
          sgs = ec2_resource.security_groups.filter(
              Filters=[{'Name': 'tag:{}'.format(tag_name), 'Values': [args.service_base_name]}])
          if sgs:
              for sg in sgs:
                  ec2_client.delete_security_group(GroupId=sg.id)
                  print("The AWS security group {} has been deleted successfully".format(sg.id))
          else:
              print("There are no AWS security groups to delete")
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with removing AWS SG: {}'.format(str(err)))
          raise Exception
  
  
  def create_instance():
      try:
          user_data = ''
          ami_id = get_ami_id('ubuntu/images/hvm-ssd/ubuntu-xenial-16.04-amd64-server-20160907.1')
          instances = ec2_resource.create_instances(ImageId=ami_id, MinCount=1, MaxCount=1,
                                                    BlockDeviceMappings=[
                                                        {
                                                            "DeviceName": "/dev/sda1",
                                                            "Ebs":
                                                                {
                                                                    "VolumeSize": int(args.primary_disk_size)
                                                                }
                                                        },
                                                        {
                                                            "DeviceName": "/dev/sdb",
                                                            "Ebs":
                                                                {
                                                                    "VolumeSize": int(args.additional_disk_size)
                                                                }
                                                        }],
                                                    KeyName=args.key_name,
                                                    SecurityGroupIds=[args.sg_id],
                                                    InstanceType=args.instance_type,
                                                    SubnetId=args.subnet_id,
                                                    UserData=user_data)
          for instance in instances:
              print("Waiting for instance {} become running.".format(instance.id))
              instance.wait_until_running()
              tag = {'Key': 'Name', 'Value': args.service_base_name + '-repository'}
              instance_tag = {"Key": tag_name, "Value": args.service_base_name}
              create_tag(instance.id, tag)
              create_tag(instance.id, instance_tag)
              tag_intance_volume(instance.id, args.service_base_name + '-repository', instance_tag)
              return instance.id
          return ''
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with creating AWS EC2 instance: {}'.format(str(err)))
          raise Exception
  
  
  def tag_intance_volume(instance_id, node_name, instance_tag):
      try:
          volume_list = get_instance_attr(instance_id, 'block_device_mappings')
          counter = 0
          instance_tag_value = instance_tag.get('Value')
          for volume in volume_list:
              if counter == 1:
                  volume_postfix = '-volume-secondary'
              else:
                  volume_postfix = '-volume-primary'
              tag = {'Key': 'Name',
                     'Value': node_name + volume_postfix}
              volume_tag = instance_tag
              volume_tag['Value'] = instance_tag_value + volume_postfix
              volume_id = volume.get('Ebs').get('VolumeId')
              create_tag(volume_id, tag)
              create_tag(volume_id, volume_tag)
              counter += 1
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with tagging AWS EC2 instance volumes: {}'.format(str(err)))
          raise Exception
  
  
  def get_instance_attr(instance_id, attribute_name):
      try:
          instances = ec2_resource.instances.filter(
              Filters=[{'Name': 'instance-id', 'Values': [instance_id]},
                       {'Name': 'instance-state-name', 'Values': ['running']}])
          for instance in instances:
              return getattr(instance, attribute_name)
          return ''
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with getting AWS EC2 instance attributes: {}'.format(str(err)))
          raise Exception
  
  
  def get_ami_id(ami_name):
      try:
          image_id = ''
          response = ec2_client.describe_images(
              Filters=[
                  {
                      'Name': 'name',
                      'Values': [ami_name]
                  },
                  {
                      'Name': 'virtualization-type', 'Values': ['hvm']
                  },
                  {
                      'Name': 'state', 'Values': ['available']
                  },
                  {
                      'Name': 'root-device-name', 'Values': ['/dev/sda1']
                  },
                  {
                      'Name': 'root-device-type', 'Values': ['ebs']
                  },
                  {
                      'Name': 'architecture', 'Values': ['x86_64']
                  }
              ])
          response = response.get('Images')
          for i in response:
              image_id = i.get('ImageId')
          if image_id == '':
              raise Exception("Unable to find AWS AMI id with name: " + ami_name)
          return image_id
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with getting AWS AMI ID: {}'.format(str(err)))
          raise Exception
  
  
  def remove_route_tables():
      try:
          rtables = ec2_client.describe_route_tables(Filters=[{'Name': 'tag-key', 'Values': [tag_name]}]).get('RouteTables')
          for rtable in rtables:
              if rtable:
                  rtable_associations = rtable.get('Associations')
                  rtable = rtable.get('RouteTableId')
                  for association in rtable_associations:
                      ec2_client.disassociate_route_table(AssociationId=association.get('RouteTableAssociationId'))
                      print("Association {} has been removed".format(association.get('RouteTableAssociationId')))
                  ec2_client.delete_route_table(RouteTableId=rtable)
                  print("AWS Route table {} has been removed".format(rtable))
              else:
                  print("There are no AWS route tables to remove")
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with removing AWS Route Tables: {}'.format(str(err)))
          raise Exception
  
  
  def remove_ec2():
      try:
          inst = ec2_resource.instances.filter(
              Filters=[{'Name': 'instance-state-name', 'Values': ['running', 'stopped', 'pending', 'stopping']},
                       {'Name': 'tag:{}'.format(tag_name), 'Values': ['{}'.format(args.service_base_name)]}])
          instances = list(inst)
          if instances:
              for instance in instances:
                  ec2_client.terminate_instances(InstanceIds=[instance.id])
                  waiter = ec2_client.get_waiter('instance_terminated')
                  waiter.wait(InstanceIds=[instance.id])
                  print("The instance {} has been terminated successfully".format(instance.id))
          else:
              print("There are no instances with '{}' tag to terminate".format(tag_name))
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with removing EC2 instances: {}'.format(str(err)))
          raise Exception
  
  
  def remove_internet_gateways(vpc_id, tag_value):
      try:
          ig_id = ''
          response = ec2_client.describe_internet_gateways(
              Filters=[
                  {'Name': 'tag-key', 'Values': [tag_name]},
                  {'Name': 'tag-value', 'Values': [tag_value]}]).get('InternetGateways')
          for i in response:
              ig_id = i.get('InternetGatewayId')
          ec2_client.detach_internet_gateway(InternetGatewayId=ig_id, VpcId=vpc_id)
          print("AWS Internet gateway {0} has been detached from VPC {1}".format(ig_id, vpc_id))
          ec2_client.delete_internet_gateway(InternetGatewayId=ig_id)
          print("AWS Internet gateway {} has been deleted successfully".format(ig_id))
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with removing AWS Internet gateways: {}'.format(str(err)))
          raise Exception
  
  
  def enable_auto_assign_ip(subnet_id):
      try:
          ec2_client.modify_subnet_attribute(MapPublicIpOnLaunch={'Value': True}, SubnetId=subnet_id)
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with enabling auto-assign of public IP addresses: {}'.format(str(err)))
          raise Exception
  
  
  def subnet_exist(return_id=False):
      try:
          subnet_created = False
          if args.vpc_id:
              filters = [{'Name': 'tag-key', 'Values': [tag_name]},
                         {'Name': 'tag-value', 'Values': [args.service_base_name]},
                         {'Name': 'vpc-id', 'Values': [args.vpc_id]}]
          else:
              filters = [{'Name': 'tag-key', 'Values': [tag_name]},
                         {'Name': 'tag-value', 'Values': [args.service_base_name]}]
          for subnet in ec2_resource.subnets.filter(Filters=filters):
              if return_id:
                  return subnet.id
              subnet_created = True
          return subnet_created
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with getting AWS Subnet: {}'.format(str(err)))
          raise Exception
  
  
  def sg_exist(return_id=False):
      try:
          sg_created = False
          for security_group in ec2_resource.security_groups.filter(
                  Filters=[{'Name': 'group-name', 'Values': [args.service_base_name + "-sg"]}]):
              if return_id:
                  return security_group.id
              sg_created = True
          return sg_created
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with getting AWS Security group: {}'.format(str(err)))
          raise Exception
  
  
  def ec2_exist(return_id=False):
      try:
          ec2_created = False
          instances = ec2_resource.instances.filter(
              Filters=[{'Name': 'tag:Name', 'Values': [args.service_base_name + '-repository']},
                       {'Name': 'instance-state-name', 'Values': ['running', 'pending', 'stopping', 'stopped']}])
          for instance in instances:
              if return_id:
                  return instance.id
              ec2_created = True
          return ec2_created
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with getting AWS EC2 instance: {}'.format(str(err)))
          raise Exception
  
  
  def allocate_elastic_ip():
      try:
          tag = {"Key": tag_name, "Value": "{}".format(args.service_base_name)}
          name_tag = {"Key": "Name", "Value": "{}-eip".format(args.service_base_name)}
          allocation_id = ec2_client.allocate_address(Domain='vpc').get('AllocationId')
          create_tag(allocation_id, tag)
          create_tag(allocation_id, name_tag)
          print('AWS Elastic IP address has been allocated')
          return allocation_id
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with creating AWS Elastic IP: {}'.format(str(err)))
          raise Exception
  
  
  def release_elastic_ip():
      try:
          allocation_id = elastic_ip_exist(True)
          ec2_client.release_address(AllocationId=allocation_id)
          print("AWS Elastic IP address has been released.")
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with removing AWS Elastic IP: {}'.format(str(err)))
          raise Exception
  
  
  def associate_elastic_ip(instance_id, allocation_id):
      try:
          ec2_client.associate_address(InstanceId=instance_id, AllocationId=allocation_id).get('AssociationId')
          print("AWS Elastic IP address has been associated.")
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with associating AWS Elastic IP: {}'.format(str(err)))
          raise Exception
  
  
  def disassociate_elastic_ip(association_id):
      try:
          ec2_client.disassociate_address(AssociationId=association_id)
          print("AWS Elastic IP address has been disassociated.")
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with disassociating AWS Elastic IP: {}'.format(str(err)))
          raise Exception
  
  
  def elastic_ip_exist(return_id=False, return_parameter='AllocationId'):
      try:
          elastic_ip_created = False
          elastic_ips = ec2_client.describe_addresses(
              Filters=[
                  {'Name': 'tag-key', 'Values': [tag_name]},
                  {'Name': 'tag-value', 'Values': [args.service_base_name]}
              ]
          ).get('Addresses')
          for elastic_ip in elastic_ips:
              if return_id:
                  return elastic_ip.get(return_parameter)
              elastic_ip_created = True
          return elastic_ip_created
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with getting AWS Elastic IP: {}'.format(str(err)))
          raise Exception
  
  
  def create_route_53_record(hosted_zone_id, hosted_zone_name, subdomain, ip_address):
      try:
          route53_client.change_resource_record_sets(
              HostedZoneId=hosted_zone_id,
              ChangeBatch={
                  'Changes': [
                      {
                          'Action': 'CREATE',
                          'ResourceRecordSet': {
                              'Name': "{}.{}".format(subdomain, hosted_zone_name),
                              'Type': 'A',
                              'TTL': 300,
                              'ResourceRecords': [
                                  {
                                      'Value': ip_address
                                  }
                              ]
                          }
                      }
                  ]
              }
          )
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with creating AWS Route53 record: {}'.format(str(err)))
          raise Exception
  
  
  def remove_route_53_record(hosted_zone_id, hosted_zone_name, subdomain):
      try:
          for record_set in route53_client.list_resource_record_sets(
                  HostedZoneId=hosted_zone_id).get('ResourceRecordSets'):
              if record_set['Name'] == "{}.{}.".format(subdomain, hosted_zone_name):
                  for record in record_set['ResourceRecords']:
                      route53_client.change_resource_record_sets(
                          HostedZoneId=hosted_zone_id,
                          ChangeBatch={
                              'Changes': [
                                  {
                                      'Action': 'DELETE',
                                      'ResourceRecordSet': {
                                          'Name': record_set['Name'],
                                          'Type': 'A',
                                          'TTL': 300,
                                          'ResourceRecords': [
                                              {
                                                  'Value': record['Value']
                                              }
                                          ]
                                      }
                                  }
                              ]
                          }
                      )
          print("AWS Route53 record has been removed.")
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with removing AWS Route53 record: {}'.format(str(err)))
          raise Exception
  
  
  def get_instance_ip_address_by_id(instance_id, ip_address_type):
      try:
          instances = ec2_resource.instances.filter(
              Filters=[{'Name': 'instance-id', 'Values': [instance_id]},
                       {'Name': 'instance-state-name', 'Values': ['running']}])
          for instance in instances:
              return getattr(instance, ip_address_type)
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with getting AWS EC2 instance IP address: {}'.format(str(err)))
          raise Exception
  
  
  def create_efs():
      try:
          token = id_generator(10, False)
          efs = efs_client.create_file_system(
              CreationToken=token,
              PerformanceMode='generalPurpose',
              Encrypted=True
          )
          while efs_client.describe_file_systems(
                  FileSystemId=efs.get('FileSystemId')).get('FileSystems')[0].get('LifeCycleState') != 'available':
              time.sleep(5)
          return efs.get('FileSystemId')
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with creating AWS EFS: {}'.format(str(err)))
          raise Exception
  
  
  def create_mount_target(efs_sg_id):
      try:
          mount_target_id = efs_client.create_mount_target(
              FileSystemId=args.efs_id,
              SubnetId=args.subnet_id,
              SecurityGroups=[
                  efs_sg_id
              ]
          ).get('MountTargetId')
          while efs_client.describe_mount_targets(
                  MountTargetId=mount_target_id).get('MountTargets')[0].get('LifeCycleState') != 'available':
              time.sleep(10)
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with creating AWS mount target: {}'.format(str(err)))
          raise Exception
  
  
  def efs_exist(return_id=False):
      try:
          efs_created = False
          for efs in efs_client.describe_file_systems().get('FileSystems'):
              if efs.get('Name') == args.service_base_name + '-efs':
                  if return_id:
                      return efs.get('FileSystemId')
                  efs_created = True
          return efs_created
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with getting AWS EFS: {}'.format(str(err)))
          raise Exception
  
  
  def remove_efs():
      try:
          efs_id = efs_exist(True)
          mount_targets = efs_client.describe_mount_targets(FileSystemId=efs_id).get('MountTargets')
          for mount_target in mount_targets:
              efs_client.delete_mount_target(MountTargetId=mount_target.get('MountTargetId'))
          while efs_client.describe_file_systems(
                  FileSystemId=efs_id).get('FileSystems')[0].get('NumberOfMountTargets') != 0:
              time.sleep(5)
          efs_client.delete_file_system(FileSystemId=efs_id)
          while efs_exist():
              time.sleep(5)
          print('AWS EFS has been deleted')
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with removing AWS EFS: {}'.format(str(err)))
          raise Exception
  
  
  def ensure_ssh_user(initial_user):
      try:
          if not exists('/home/{}/.ssh_user_ensured'.format(initial_user)):
              sudo('useradd -m -G sudo -s /bin/bash {0}'.format(configuration['conf_os_user']))
              sudo('echo "{} ALL = NOPASSWD:ALL" >> /etc/sudoers'.format(configuration['conf_os_user']))
              sudo('mkdir /home/{}/.ssh'.format(configuration['conf_os_user']))
              sudo('chown -R {0}:{0} /home/{1}/.ssh/'.format(initial_user, configuration['conf_os_user']))
              sudo('cat /home/{0}/.ssh/authorized_keys > /home/{1}/.ssh/authorized_keys'.format(
                  initial_user, configuration['conf_os_user']))
              sudo('chown -R {0}:{0} /home/{0}/.ssh/'.format(configuration['conf_os_user']))
              sudo('chmod 700 /home/{0}/.ssh'.format(configuration['conf_os_user']))
              sudo('chmod 600 /home/{0}/.ssh/authorized_keys'.format(configuration['conf_os_user']))
              sudo('mkdir /home/{}/.ensure_dir'.format(configuration['conf_os_user']))
              sudo('touch /home/{}/.ssh_user_ensured'.format(initial_user))
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with creating dlab-user: {}'.format(str(err)))
          raise Exception
  
  
  def install_java():
      try:
          if not exists('/home/{}/.ensure_dir/java_ensured'.format(configuration['conf_os_user'])):
              sudo('apt-get update')
              sudo('apt-get install -y default-jdk ')
              sudo('touch /home/{}/.ensure_dir/java_ensured'.format(configuration['conf_os_user']))
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with installing Java: {}'.format(str(err)))
          raise Exception
  
  
  def install_groovy():
      try:
          if not exists('/home/{}/.ensure_dir/groovy_ensured'.format(configuration['conf_os_user'])):
              sudo('apt-get install -y unzip')
              sudo('mkdir /usr/local/groovy')
              sudo('wget https://bintray.com/artifact/download/groovy/maven/apache-groovy-binary-{0}.zip -O \
                    /tmp/apache-groovy-binary-{0}.zip'.format(groovy_version))
              sudo('unzip /tmp/apache-groovy-binary-{}.zip -d \
                    /usr/local/groovy'.format(groovy_version))
              sudo('ln -s /usr/local/groovy/groovy-{} \
                    /usr/local/groovy/latest'.format(groovy_version))
              sudo('touch /home/{}/.ensure_dir/groovy_ensured'.format(configuration['conf_os_user']))
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with installing Groovy: {}'.format(str(err)))
          raise Exception
  
  
  def nexus_service_waiter():
      nexus_started = False
      checks_count = 0
      with hide('running'):
          while not nexus_started and checks_count < 200:
              print('Waiting nexus to be started...')
              time.sleep(5)
              result = sudo('nmap -p 8443 localhost | grep closed > /dev/null ; echo $?')
              result = result[:1]
              if result == '1':
                  nexus_started = True
              else:
                  checks_count += 1
      if not nexus_started and checks_count >= 200:
          print('Error: Unable to start Nexus. Aborting...')
          sys.exit(1)
  
      
  def install_nexus():
      try:
          if not exists('/home/{}/.ensure_dir/nexus_ensured'.format(configuration['conf_os_user'])):
              if args.efs_enabled == 'False':
                  mounting_disks()
              else:
                  mount_efs()
              sudo('apt-get install -y maven nmap python-pip')
              sudo('pip2 install -UI pip')
              sudo('pip2 install -U fabric==1.14.0')
              sudo('mkdir -p /opt/nexus')
              sudo('wget https://sonatype-download.global.ssl.fastly.net/nexus/{0}/nexus-{1}-unix.tar.gz -O \
                    /opt/nexus-{1}-unix.tar.gz'.format(
                    nexus_version.split('.')[0], nexus_version))
              sudo('tar -zhxvf /opt/nexus-{}-unix.tar.gz -C /opt/'.format(
                    nexus_version))
              sudo('mv /opt/nexus-{}/* /opt/nexus/'.format(nexus_version))
              sudo('mv /opt/nexus-{}/.[!.]* /opt/nexus/'.format(
                    nexus_version))
              sudo('rm -rf /opt/nexus-{}'.format(nexus_version))
              sudo('useradd nexus')
              sudo('echo \"run_as_user="nexus"\" > /opt/nexus/bin/nexus.rc')
              create_keystore()
              put('templates/jetty-https.xml', '/tmp/jetty-https.xml')
              sudo('sed -i "s/KEYSTORE_PASSWORD/{}/g" /tmp/jetty-https.xml'.format(keystore_pass))
              sudo('cp -f /tmp/jetty-https.xml /opt/nexus/etc/jetty/')
              put('templates/nexus.service', '/tmp/nexus.service')
              if args.efs_enabled == 'False':
                  sudo('sed -i "s|EFS_SERVICE||g" /tmp/nexus.service')
              else:
                  sudo('sed -i "s|EFS_SERVICE|mount-efs-sequentially.service|g" /tmp/nexus.service')
              sudo('cp /tmp/nexus.service /etc/systemd/system/')
              put('files/nexus.properties', '/tmp/nexus.properties')
              sudo('mkdir -p /opt/sonatype-work/nexus3/etc')
              sudo('cp -f /tmp/nexus.properties /opt/sonatype-work/nexus3/etc/nexus.properties')
              sudo('chown -R nexus:nexus /opt/nexus /opt/sonatype-work')
              sudo('systemctl daemon-reload')
              sudo('systemctl start nexus')
              nexus_service_waiter()
              sudo('systemctl enable nexus')
              put('templates/configureNexus.groovy', '/tmp/configureNexus.groovy')
              sudo('sed -i "s/REGION/{}/g" /tmp/configureNexus.groovy'.format(args.region))
              sudo('sed -i "s/ADMIN_PASSWORD/{}/g" /tmp/configureNexus.groovy'.format(args.nexus_admin_password))
              sudo('sed -i "s/SERVICE_USER_NAME/{}/g" /tmp/configureNexus.groovy'.format(args.nexus_service_user_name))
              sudo('sed -i "s/SERVICE_USER_PASSWORD/{}/g" /tmp/configureNexus.groovy'.format(
                  args.nexus_service_user_password))
              sudo('wget http://repo.{}.amazonaws.com/2017.09/main/mirror.list -O /tmp/main_mirror.list'.format(
                  args.region))
              sudo('wget http://repo.{}.amazonaws.com/2017.09/updates/mirror.list -O /tmp/updates_mirror.list'.format(
                  args.region))
              amazon_main_repo = sudo("cat /tmp/main_mirror.list  | grep {} | sed 's/$basearch//g'".format(args.region))
              amazon_updates_repo = sudo("cat /tmp/updates_mirror.list  | grep {} | sed 's/$basearch//g'".format(
                  args.region))
              sudo('sed -i "s|AMAZON_MAIN_URL|{}|g" /tmp/configureNexus.groovy'.format(amazon_main_repo))
              sudo('sed -i "s|AMAZON_UPDATES_URL|{}|g" /tmp/configureNexus.groovy'.format(amazon_updates_repo))
              sudo('rm -f /tmp/main_mirror.list')
              sudo('rm -f /tmp/updates_mirror.list')
              put('scripts/addUpdateScript.groovy', '/tmp/addUpdateScript.groovy')
              script_executed = False
              while not script_executed:
                  try:
                      sudo('/usr/local/groovy/latest/bin/groovy /tmp/addUpdateScript.groovy -u "admin" -p "admin123" \
                            -n "configureNexus" -f "/tmp/configureNexus.groovy" -h "http://localhost:8081"')
                      script_executed = True
                  except:
                      time.sleep(10)
                      pass
              sudo('curl -u admin:admin123 -X POST --header \'Content-Type: text/plain\' \
                     http://localhost:8081/service/rest/v1/script/configureNexus/run')
              sudo('systemctl stop nexus')
              sudo('git clone https://github.com/sonatype-nexus-community/nexus-repository-apt')
              with cd('nexus-repository-apt'):
                  sudo('mvn')
              apt_plugin_version = sudo('find nexus-repository-apt/ -name "nexus-repository-apt-*.jar" '
                                        '-printf "%f\\n" | grep -v "sources"').replace('nexus-repository-apt-',
                                                                                       '').replace('.jar', '')
              compress_plugin_version = sudo('find /opt/nexus/ -name "commons-compress-*.jar" '
                                             '-printf "%f\\n" ').replace('commons-compress-', '').replace('.jar', '')
              xz_plugin_version = sudo('find /opt/nexus/ -name "xz-*.jar" '
                                       '-printf "%f\\n" ').replace('xz-', '').replace('.jar', '')
              sudo('mkdir -p /opt/nexus/system/net/staticsnow/nexus-repository-apt/{0}/'.format(apt_plugin_version))
              apt_plugin_jar_path = sudo('find nexus-repository-apt/ -name "nexus-repository-apt-{0}.jar"'.format(
                  apt_plugin_version))
              sudo('cp -f {0} /opt/nexus/system/net/staticsnow/nexus-repository-apt/{1}/'.format(
                  apt_plugin_jar_path, apt_plugin_version
              ))
              sudo('sed -i "$ d" /opt/nexus/system/org/sonatype/nexus/assemblies/nexus-core-feature/{0}/'
                   'nexus-core-feature-{0}-features.xml'.format(nexus_version))
              sudo('''echo '<feature name="nexus-repository-apt" description="net.staticsnow:nexus-repository-apt" '''
                   '''version="{1}">' >> /opt/nexus/system/org/sonatype/nexus/assemblies/nexus-core-feature/{0}/'''
                   '''nexus-core-feature-{0}-features.xml'''.format(nexus_version, apt_plugin_version))
              sudo('''echo '<details>net.staticsnow:nexus-repository-apt</details>' >> '''
                   '''/opt/nexus/system/org/sonatype/nexus/assemblies/nexus-core-feature/{0}/'''
                   '''nexus-core-feature-{0}-features.xml'''.format(nexus_version))
              sudo('''echo '<bundle>mvn:net.staticsnow/nexus-repository-apt/{1}</bundle>' >> '''
                   '''/opt/nexus/system/org/sonatype/nexus/assemblies/nexus-core-feature/{0}/'''
                   '''nexus-core-feature-{0}-features.xml'''.format(nexus_version, apt_plugin_version))
              sudo('''echo '<bundle>mvn:org.apache.commons/commons-compress/{1}</bundle>' >> '''
                   '''/opt/nexus/system/org/sonatype/nexus/assemblies/nexus-core-feature/{0}/'''
                   '''nexus-core-feature-{0}-features.xml'''.format(nexus_version, compress_plugin_version))
              sudo('''echo '<bundle>mvn:org.tukaani/xz/{1}</bundle>' >> '''
                   '''/opt/nexus/system/org/sonatype/nexus/assemblies/nexus-core-feature/{0}/'''
                   '''nexus-core-feature-{0}-features.xml'''.format(nexus_version, xz_plugin_version))
              sudo('''echo '</feature>' >> '''
                   '''/opt/nexus/system/org/sonatype/nexus/assemblies/nexus-core-feature/{0}/'''
                   '''nexus-core-feature-{0}-features.xml'''.format(nexus_version))
              sudo('''echo '</features>' >> '''
                   '''/opt/nexus/system/org/sonatype/nexus/assemblies/nexus-core-feature/{0}/'''
                   '''nexus-core-feature-{0}-features.xml'''.format(nexus_version))
              sudo('''sed -i 's|<feature prerequisite=\"true\" dependency=\"false\">wrap</feature>|'''
                   '''<feature prerequisite=\"true\" dependency=\"false\">wrap</feature>\\n'''
                   '''<feature prerequisite=\"false\" dependency=\"false\">nexus-repository-apt</feature>|g' '''
                   '''/opt/nexus/system/org/sonatype/nexus/assemblies/nexus-core-feature/{0}/nexus-core-feature-'''
                   '''{0}-features.xml'''.format(nexus_version))
              sudo('git clone https://github.com/sonatype-nexus-community/nexus-repository-r.git')
              with cd('nexus-repository-r'):
                  sudo('mvn clean install')
              r_plugin_version = sudo('find nexus-repository-r/ -name "nexus-repository-r-*.jar" '
                                      '-printf "%f\\n" | grep -v "sources"').replace('nexus-repository-r-', '').replace(
                  '.jar', '')
              sudo('mkdir -p /opt/nexus/system/org/sonatype/nexus/plugins/nexus-repository-r/{}/'.format(
                  r_plugin_version))
              r_plugin_jar_path = sudo('find nexus-repository-r/ -name "nexus-repository-r-{0}.jar"'.format(
                  r_plugin_version))
              sudo('cp -f {0} /opt/nexus/system/org/sonatype/nexus/plugins/nexus-repository-r/{1}/'.format(
                  r_plugin_jar_path, r_plugin_version
              ))
              sudo('sed -i "$ d" /opt/nexus/system/com/sonatype/nexus/assemblies/nexus-oss-feature/{0}/'
                   'nexus-oss-feature-{0}-features.xml'.format(nexus_version))
              sudo('''echo '<feature name="nexus-repository-r" description="org.sonatype.nexus.plugins:'''
                   '''nexus-repository-r" version="{1}">' >> /opt/nexus/system/com/sonatype/nexus/assemblies/'''
                   '''nexus-oss-feature/{0}/nexus-oss-feature-{0}-features.xml'''.format(nexus_version, r_plugin_version))
              sudo('''echo '<details>org.sonatype.nexus.plugins:nexus-repository-r</details>' >> '''
                   '''/opt/nexus/system/com/sonatype/nexus/assemblies/nexus-oss-feature/{0}/'''
                   '''nexus-oss-feature-{0}-features.xml'''.format(nexus_version))
              sudo('''echo '<bundle>mvn:org.sonatype.nexus.plugins/nexus-repository-r/{1}</bundle>' >> '''
                   '''/opt/nexus/system/com/sonatype/nexus/assemblies/nexus-oss-feature/{0}/'''
                   '''nexus-oss-feature-{0}-features.xml'''.format(nexus_version, r_plugin_version))
              sudo('''echo '</feature>' >> '''
                   '''/opt/nexus/system/com/sonatype/nexus/assemblies/nexus-oss-feature/{0}/'''
                   '''nexus-oss-feature-{0}-features.xml'''.format(nexus_version))
              sudo('''echo '</features>' >> '''
                   '''/opt/nexus/system/com/sonatype/nexus/assemblies/nexus-oss-feature/{0}/'''
                   '''nexus-oss-feature-{0}-features.xml'''.format(nexus_version))
              sudo('''sed -i 's|<feature prerequisite=\"true\" dependency=\"false\">wrap</feature>|'''
                   '''<feature prerequisite=\"true\" dependency=\"false\">wrap</feature>\\n'''
                   '''<feature version=\"{1}\" prerequisite=\"false\" dependency=\"false\">'''
                   '''nexus-repository-r</feature>|g' '''
                   '''/opt/nexus/system/com/sonatype/nexus/assemblies/nexus-oss-feature/{0}/'''
                   '''nexus-oss-feature-{0}-features.xml'''.format(nexus_version, r_plugin_version))
              sudo('chown -R nexus:nexus /opt/nexus')
              sudo('systemctl start nexus')
              nexus_service_waiter()
              put('templates/addCustomRepository.groovy', '/tmp/addCustomRepository.groovy')
              sudo('sed -i "s|REGION|{0}|g" /tmp/addCustomRepository.groovy'.format(args.region))
              script_executed = False
              while not script_executed:
                  try:
                      sudo('/usr/local/groovy/latest/bin/groovy /tmp/addUpdateScript.groovy -u "admin" -p "{}" '
                           '-n "addCustomRepository" -f "/tmp/addCustomRepository.groovy" -h '
                           '"http://localhost:8081"'.format(args.nexus_admin_password))
                      script_executed = True
                  except:
                      time.sleep(10)
                      pass
              sudo('curl -u admin:{} -X POST --header \'Content-Type: text/plain\' '
                   'http://localhost:8081/service/rest/v1/script/addCustomRepository/run'.format(
                    args.nexus_admin_password))
              sudo('echo "admin:{}" > /opt/nexus/credentials'.format(args.nexus_admin_password))
              sudo('echo "{0}:{1}" >> /opt/nexus/credentials'.format(args.nexus_service_user_name,
                                                                     args.nexus_service_user_password))
              put('templates/updateRepositories.groovy', '/opt/nexus/updateRepositories.groovy', use_sudo=True)
              put('scripts/update_amazon_repositories.py', '/opt/nexus/update_amazon_repositories.py', use_sudo=True)
              sudo('sed -i "s|NEXUS_PASSWORD|{}|g" /opt/nexus/update_amazon_repositories.py'.format(
                   args.nexus_admin_password))
              sudo('touch /var/log/amazon_repo_update.log')
              sudo('echo "0 0 * * * root /usr/bin/python /opt/nexus/update_amazon_repositories.py --region {} >> '
                   '/var/log/amazon_repo_update.log" >> /etc/crontab'.format(args.region))
              sudo('touch /home/{}/.ensure_dir/nexus_ensured'.format(configuration['conf_os_user']))
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with installing Nexus: {}'.format(str(err)))
          raise Exception
  
  
  def install_nginx():
      try:
          if not exists('/home/{}/.ensure_dir/nginx_ensured'.format(configuration['conf_os_user'])):
              hostname = sudo('hostname')
              sudo('apt-get install -y nginx')
              sudo('rm -f /etc/nginx/conf.d/* /etc/nginx/sites-enabled/default')
              put('templates/nexus.conf', '/tmp/nexus.conf')
              if args.hosted_zone_id and args.hosted_zone_name and args.subdomain:
                  sudo('sed -i "s|SUBDOMAIN|{}|g" /tmp/nexus.conf'.format(args.subdomain))
                  sudo('sed -i "s|HOSTZONE|{}|g" /tmp/nexus.conf'.format(args.hosted_zone_name))
              else:
                  sudo('sed -i "s|SUBDOMAIN.HOSTZONE|{}|g" /tmp/nexus.conf'.format(hostname))
              sudo('sed -i "s|REGION|{}|g" /tmp/nexus.conf'.format(args.region))
              sudo('cp /tmp/nexus.conf /etc/nginx/conf.d/nexus.conf'.format(args.subdomain, args.hosted_zone_name))
              sudo('systemctl restart nginx')
              sudo('systemctl enable nginx')
              sudo('touch /home/{}/.ensure_dir/nginx_ensured'.format(configuration['conf_os_user']))
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Error with installing Nginx: {}'.format(str(err)))
          raise Exception
  
  
  def mounting_disks():
      try:
          if not exists('/home/{}/.ensure_dir/additional_disk_mounted'.format(configuration['conf_os_user'])):
              sudo('mkdir -p /opt/sonatype-work')
              disk_name = sudo("lsblk | grep disk | awk '{print $1}' | sort | tail -n 1 | tr '\\n' ',' | sed 's|.$||g'")
              sudo('bash -c \'echo -e "o\nn\np\n1\n\n\nw" | fdisk /dev/{}\' '.format(disk_name))
              sudo('sleep 10')
              partition_name = sudo("lsblk -r | grep part | grep {} | awk {} | sort | tail -n 1 | "
                                    "tr '\\n' ',' | sed 's|.$||g'".format(disk_name, "'{print $1}'"))
              sudo('mkfs.ext4 -F -q /dev/{}'.format(partition_name))
              sudo('mount /dev/{0} /opt/sonatype-work'.format(partition_name))
              sudo('bash -c "echo \'/dev/{} /opt/sonatype-work ext4 errors=remount-ro 0 1\' >> /etc/fstab"'.format(
                  partition_name))
              sudo('touch /home/{}/.ensure_dir/additional_disk_mounted'.format(configuration['conf_os_user']))
      except Exception as err:
          traceback.print_exc(file=sys.stdout)
          print('Failed to mount additional volume: {}'.format(str(err)))
          raise Exception
  
  
  def mount_efs():
      try:
          if not exists('/home/{}/.ensure_dir/efs_mounted'.format(configuration['conf_os_user'])):
              sudo('mkdir -p /opt/sonatype-work')
              sudo('apt-get -y install binutils')
              with cd('/tmp/'):
                  sudo('git clone https://github.com/aws/efs-utils')
              with cd('/tmp/efs-utils'):
                  sudo('./build-deb.sh')
                  sudo('apt-get -y install ./build/amazon-efs-utils*deb')
              sudo('sed -i "s/stunnel_check_cert_hostname.*/stunnel_check_cert_hostname = false/g" '
                   '/etc/amazon/efs/efs-utils.conf')
              sudo('sed -i "s/stunnel_check_cert_validity.*/stunnel_check_cert_validity = false/g" '
                   '/etc/amazon/efs/efs-utils.conf')
              sudo('mount -t efs -o tls {}:/ /opt/sonatype-work'.format(
                  args.efs_id))
              sudo('bash -c "echo \'{}:/ /opt/sonatype-work efs tls,_netdev 0 0\' >> '
                   '/etc/fstab"'.format(args.efs_id))
              put('files/mount-efs-sequentially.service', '/tmp/mount-efs-sequentially.service')
              sudo('cp /tmp/mount-efs-sequentially.service /etc/systemd/system/')
              sudo('systemctl daemon-reload')
              sudo('systemctl enable mount-efs-sequentially.service')
              sudo('touch /home/{}/.ensure_dir/efs_mounted'.format(configuration['conf_os_user']))
      except Exception as err:
          traceback.print_exc()
          print('Failed to mount additional volume: ', str(err))
          sys.exit(1)
  
  
  def configure_ssl():
      try:
          if not exists('/home/{}/.ensure_dir/ssl_ensured'.format(configuration['conf_os_user'])):
              hostname = sudo('hostname')
              private_ip = sudo('curl http://169.254.169.254/latest/meta-data/local-ipv4')
              subject_alt_name = 'subjectAltName = IP:{}'.format(private_ip)
              if args.network_type == 'public':
                  public_ip = sudo('curl http://169.254.169.254/latest/meta-data/public-ipv4')
                  subject_alt_name += ',IP:{}'.format(public_ip)
              sudo('cp /etc/ssl/openssl.cnf /tmp/openssl.cnf')
              sudo('echo "[ subject_alt_name ]" >> /tmp/openssl.cnf')
              sudo('echo "{}" >> /tmp/openssl.cnf'.format(subject_alt_name))
              sudo('openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout /etc/ssl/certs/repository.key '
                   '-out /etc/ssl/certs/repository.crt -subj "/C=US/ST=US/L=US/O=dlab/CN={}" -config '
                   '/tmp/openssl.cnf -extensions subject_alt_name'.format(hostname))
              sudo('openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048')
              sudo('touch /home/{}/.ensure_dir/ssl_ensured'.format(configuration['conf_os_user']))
      except Exception as err:
          traceback.print_exc()
          print('Failed to mount additional volume: ', str(err))
          sys.exit(1)
  
  
  def set_hostname():
      try:
          if not exists('/home/{}/.ensure_dir/hostname_set'.format(configuration['conf_os_user'])):
              if args.hosted_zone_id and args.hosted_zone_name and args.subdomain:
                  hostname = '{0}.{1}'.format(args.subdomain, args.hosted_zone_name)
              else:
                  if args.network_type == 'public':
                      hostname = sudo('curl http://169.254.169.254/latest/meta-data/public-hostname')
                  else:
                      hostname = sudo('curl http://169.254.169.254/latest/meta-data/hostname')
              sudo('hostnamectl set-hostname {0}'.format(hostname))
              sudo('touch /home/{}/.ensure_dir/hostname_set'.format(configuration['conf_os_user']))
      except Exception as err:
          traceback.print_exc()
          print('Failed to mount additional volume: ', str(err))
          sys.exit(1)
  
  
  def create_keystore():
      try:
          if not exists('/home/{}/.ensure_dir/keystore_created'.format(configuration['conf_os_user'])):
              sudo('openssl pkcs12 -export -in /etc/ssl/certs/repository.crt -inkey /etc/ssl/certs/repository.key '
                   '-out wildcard.p12 -passout pass:{}'.format(keystore_pass))
              sudo('keytool -importkeystore  -deststorepass {0} -destkeypass {0} -srckeystore wildcard.p12 -srcstoretype '
                   'PKCS12 -srcstorepass {0} -destkeystore /opt/nexus/etc/ssl/keystore.jks'.format(keystore_pass))
              sudo('touch /home/{}/.ensure_dir/keystore_created'.format(configuration['conf_os_user']))
      except Exception as err:
          traceback.print_exc()
          print('Failed to create keystore: ', str(err))
          sys.exit(1)
  
  
  def download_packages():
      try:
          if not exists('/home/{}/.ensure_dir/packages_downloaded'.format(configuration['conf_os_user'])):
              packages_urls = [
                  'https://pkg.jenkins.io/debian/jenkins-ci.org.key',
                  'http://mirrors.sonic.net/apache/maven/maven-{0}/{1}/binaries/apache-maven-{1}-bin.zip'.format(
                      maven_version.split('.')[0], maven_version),
                  'https://nodejs.org/dist/v8.15.0/node-v8.15.0.tar.gz',
                  'https://github.com/sass/node-sass/releases/download/v4.11.0/linux-x64-57_binding.node',
                  'http://nginx.org/download/nginx-{}.tar.gz'.format(configuration['reverse_proxy_nginx_version']),
                  'http://www.scala-lang.org/files/archive/scala-{}.deb'.format(configuration['notebook_scala_version']),
                  'https://archive.apache.org/dist/spark/spark-{0}/spark-{0}-bin-hadoop{1}.tgz'.format(
                      configuration['notebook_spark_version'], configuration['notebook_hadoop_version']),
                  'https://repo1.maven.org/maven2/org/apache/hadoop/hadoop-aws/{0}/hadoop-aws-{0}.jar'.format('2.7.4'),
                  'https://repo1.maven.org/maven2/com/amazonaws/aws-java-sdk/{0}/aws-java-sdk-{0}.jar'.format('1.7.4'),
                  #'https://maven.twttr.com/com/hadoop/gplcompression/hadoop-lzo/{0}/hadoop-lzo-{0}.jar'.format('0.4.20'),
                  'http://central.maven.org/maven2/org/scalanlp/breeze_{0}/{1}/breeze_{0}-{1}.jar'.format('2.11', '0.12'),
                  'http://central.maven.org/maven2/org/scalanlp/breeze-natives_{0}/{1}/breeze-natives_{0}-{1}.jar'.format(
                      '2.11', '0.12'),
                  'http://central.maven.org/maven2/org/scalanlp/breeze-viz_{0}/{1}/breeze-viz_{0}-{1}.jar'.format(
                      '2.11', '0.12'),
                  'http://central.maven.org/maven2/org/scalanlp/breeze-macros_{0}/{1}/breeze-macros_{0}-{1}.jar'.format(
                      '2.11', '0.12'),
                  'http://central.maven.org/maven2/org/scalanlp/breeze-parent_{0}/{1}/breeze-parent_{0}-{1}.jar'.format(
                      '2.11', '0.12'),
                  'http://central.maven.org/maven2/org/jfree/jfreechart/{0}/jfreechart-{0}.jar'.format('1.0.19'),
                  'http://central.maven.org/maven2/org/jfree/jcommon/{0}/jcommon-{0}.jar'.format('1.0.24'),
                  '--no-check-certificate https://brunelvis.org/jar/spark-kernel-brunel-all-{0}.jar'.format('2.3'),
                  'http://archive.apache.org/dist/incubator/toree/0.2.0-incubating/toree-pip/toree-0.2.0.tar.gz',
                  'https://download2.rstudio.org/rstudio-server-{}-amd64.deb'.format(
                      configuration['notebook_rstudio_version']),
                  'http://us.download.nvidia.com/XFree86/Linux-x86_64/{0}/NVIDIA-Linux-x86_64-{0}.run'.format(
                      configuration['notebook_nvidia_version']),
                  'https://developer.nvidia.com/compute/cuda/{0}/prod/local_installers/{1}'.format(
                      cuda_version_deeplearning, cuda_deeplearingn_file_name),
                  'https://developer.nvidia.com/compute/cuda/{0}/prod/local_installers/{1}'.format(
                      configuration['notebook_cuda_version'], configuration['notebook_cuda_file_name']),
                  'http://developer.download.nvidia.com/compute/redist/cudnn/v{0}/{1}'.format(
                      cudnn_version_deeplearning, cudnn_file_name_deeplearning),
                  'http://developer.download.nvidia.com/compute/redist/cudnn/v{0}/{1}'.format(
                      configuration['notebook_cudnn_version'], configuration['notebook_cudnn_file_name']),
                  'https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-{}-cp27-none-'
                  'linux_x86_64.whl'.format(tensorflow_version_deeplearning),
                  'https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-{}-cp35-cp35m-'
                  'linux_x86_64.whl'.format(tensorflow_version_deeplearning),
                  'https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-{}-cp27-none-'
                  'linux_x86_64.whl'.format(configuration['notebook_tensorflow_version']),
                  'https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-{}-cp35-cp35m-'
                  'linux_x86_64.whl'.format(configuration['notebook_tensorflow_version']),
                  'https://cmake.org/files/v{1}/cmake-{0}.tar.gz'.format(
                      configuration['notebook_cmake_version'],
                      configuration['notebook_cmake_version'].split('.')[0] +
                      "." + configuration['notebook_cmake_version'].split('.')[1]),
                  'https://cntk.ai/PythonWheel/GPU/cntk-{}-cp27-cp27mu-linux_x86_64.whl'.format(
                      configuration['notebook_cntk_version']),
                  'https://cntk.ai/PythonWheel/GPU/cntk-{}-cp35-cp35m-linux_x86_64.whl'.format(
                      configuration['notebook_cntk_version']),
                  'https://www.python.org/ftp/python/{0}/Python-{0}.tgz'.format(python3_version),
                  'http://archive.apache.org/dist/zeppelin/zeppelin-{0}/zeppelin-{0}-bin-netinst.tgz'.format(
                      configuration['notebook_zeppelin_version']),
                  'http://archive.cloudera.com/beta/livy/livy-server-{}.zip'.format(
                      configuration['notebook_livy_version']),
                  'https://dl.bintray.com/spark-packages/maven/tapanalyticstoolkit/spark-tensorflow-connector/'
                  '1.0.0-s_2.11/spark-tensorflow-connector-1.0.0-s_2.11.jar',
                  'https://archive.apache.org/dist/incubator/toree/0.2.0-incubating/toree/'
                  'toree-0.2.0-incubating-bin.tar.gz',
                  'https://repo1.maven.org/maven2/org/apache/toree/toree-assembly/0.2.0-incubating/'
                  'toree-assembly-0.2.0-incubating.jar',
                  'https://cran.r-project.org/src/contrib/Archive/keras/keras_{}.tar.gz'.format(
                      configuration['notebook_keras_version'])
              ]
              packages_list = list()
              for package in packages_urls:
                  package_name = package.split('/')[-1]
                  packages_list.append({'url': package, 'name': package_name})
              run('mkdir packages')
              with cd('packages'):
                  for package in packages_list:
                      run('wget {0}'.format(package['url']))
                      run('curl -v -u admin:{2} -F "raw.directory=/" -F '
                          '"raw.asset1=@/home/{0}/packages/{1}" '
                          '-F "raw.asset1.filename={1}"  '
                          '"http://localhost:8081/service/rest/v1/components?repository=packages"'.format(
                           configuration['conf_os_user'], package['name'], args.nexus_admin_password))
              sudo('touch /home/{}/.ensure_dir/packages_downloaded'.format(configuration['conf_os_user']))
      except Exception as err:
          traceback.print_exc()
          print('Failed to download packages: ', str(err))
          sys.exit(1)
  
  
  def install_docker():
      try:
          if not exists('/home/{}/.ensure_dir/docker_installed'.format(configuration['conf_os_user'])):
              sudo('curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -')
              sudo('add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) '
                   'stable"')
              sudo('apt-get update')
              sudo('apt-cache policy docker-ce')
              sudo('apt-get install -y docker-ce={}~ce-0~ubuntu'.format(configuration['ssn_docker_version']))
              sudo('usermod -a -G docker ' + configuration['conf_os_user'])
              sudo('update-rc.d docker defaults')
              sudo('update-rc.d docker enable')
              sudo('touch /home/{}/.ensure_dir/docker_installed'.format(configuration['conf_os_user']))
      except Exception as err:
          traceback.print_exc()
          print('Failed to install docker: ', str(err))
          sys.exit(1)
  
  
  def prepare_images():
      try:
          if not exists('/home/{}/.ensure_dir/images_prepared'.format(configuration['conf_os_user'])):
              put('files/Dockerfile', '/tmp/Dockerfile')
              with cd('/tmp/'):
                  sudo('docker build --file Dockerfile -t pre-base .')
              sudo('docker login -u {0} -p {1} localhost:8083'.format(args.nexus_service_user_name,
                                                                      args.nexus_service_user_password))
              sudo('docker tag pre-base localhost:8083/dlab-pre-base')
              sudo('docker push localhost:8083/dlab-pre-base')
              sudo('touch /home/{}/.ensure_dir/images_prepared'.format(configuration['conf_os_user']))
      except Exception as err:
          traceback.print_exc()
          print('Failed to download packages: ', str(err))
          sys.exit(1)
  
  
  def install_squid():
      try:
          if not exists('/home/{}/.ensure_dir/squid_installed'.format(configuration['conf_os_user'])):
              sudo('apt-get -y install squid')
              put('templates/squid.conf', '/etc/squid/', use_sudo=True)
              replace_string = ''
              for cidr in get_vpc_cidr_by_id(args.vpc_id):
                  replace_string += 'acl AWS_VPC_CIDR src {}\\n'.format(cidr)
              sudo('sed -i "s|VPC_CIDRS|{}|g" /etc/squid/squid.conf'.format(replace_string))
              replace_string = ''
              for cidr in args.allowed_ip_cidr.split(','):
                  replace_string += 'acl AllowedCIDRS src {}\\n'.format(cidr)
              sudo('sed -i "s|ALLOWED_CIDRS|{}|g" /etc/squid/squid.conf'.format(replace_string))
              sudo('systemctl enable squid')
              sudo('systemctl restart squid')
              sudo('touch /home/{}/.ensure_dir/squid_installed'.format(configuration['conf_os_user']))
      except Exception as err:
          traceback.print_exc()
          print('Failed to download packages: ', str(err))
          sys.exit(1)
  
  
  if __name__ == "__main__":
      if args.aws_access_key and args.aws_secret_access_key:
          ec2_resource = boto3.resource('ec2', region_name=args.region, aws_access_key_id=args.aws_access_key,
                                        aws_secret_access_key=args.aws_secret_access_key)
          ec2_client = boto3.client('ec2', region_name=args.region, aws_access_key_id=args.aws_access_key,
                                    aws_secret_access_key=args.aws_secret_access_key)
          efs_client = boto3.client('efs', region_name=args.region, aws_access_key_id=args.aws_access_key,
                                    aws_secret_access_key=args.aws_secret_access_key)
          route53_client = boto3.client('route53', aws_access_key_id=args.aws_access_key,
                                        aws_secret_access_key=args.aws_secret_access_key)
      else:
          ec2_resource = boto3.resource('ec2', region_name=args.region)
          ec2_client = boto3.client('ec2', region_name=args.region)
          efs_client = boto3.client('efs', region_name=args.region)
          route53_client = boto3.client('route53')
      tag_name = args.service_base_name + '-Tag'
      pre_defined_vpc = True
      pre_defined_subnet = True
      pre_defined_sg = True
      pre_defined_efs = True
      if args.action != 'terminate' and args.dlab_conf_file_path == '':
          print('Please provide argument --dlab_conf_file_path ! Aborting... ')
          sys.exit(1)
      configuration = dict()
      config = SafeConfigParser()
      config.read(args.dlab_conf_file_path)
      for section in config.sections():
          for option in config.options(section):
              varname = "{0}_{1}".format(section, option)
              configuration[varname] = config.get(section, option)
      groovy_version = '2.5.1'
      nexus_version = '3.15.2-01'
      maven_version = '3.5.4'
      cuda_version_deeplearning = '8.0'
      cuda_deeplearingn_file_name = 'cuda_8.0.44_linux-run'
      cudnn_version_deeplearning = '6.0'
      cudnn_file_name_deeplearning = 'cudnn-8.0-linux-x64-v6.0.tgz'
      tensorflow_version_deeplearning = '1.4.0'
      python3_version = '3.4.0'
      if args.nexus_admin_password == '':
          args.nexus_admin_password = id_generator()
      if args.nexus_service_user_password == '':
          args.nexus_service_user_password = id_generator()
      keystore_pass = id_generator()
      if args.action == 'terminate':
          if args.hosted_zone_id and args.hosted_zone_name and args.subdomain:
              remove_route_53_record(args.hosted_zone_id, args.hosted_zone_name, args.subdomain)
          if elastic_ip_exist():
              try:
                  association_id = elastic_ip_exist(True, 'AssociationId')
                  disassociate_elastic_ip(association_id)
              except:
                  print("AWS Elastic IP address isn't associated with instance or there is an error "
                        "with disassociating it")
              release_elastic_ip()
          if ec2_exist():
              remove_ec2()
          if efs_exist():
              remove_efs()
          if sg_exist():
              remove_sgroups()
          if subnet_exist():
              remove_subnet()
          if vpc_exist():
              args.vpc_id = vpc_exist(True)
              remove_internet_gateways(args.vpc_id, args.service_base_name)
              remove_route_tables()
              remove_vpc(args.vpc_id)
      elif args.action == 'create':
          if not args.vpc_id and not vpc_exist():
              try:
                  print('[CREATING AWS VPC]')
                  args.vpc_id = create_vpc(args.vpc_cidr)
                  enable_vpc_dns(args.vpc_id)
                  rt_id = create_rt(args.vpc_id)
                  pre_defined_vpc = False
              except:
                  remove_internet_gateways(args.vpc_id, args.service_base_name)
                  remove_route_tables()
                  remove_vpc(args.vpc_id)
                  sys.exit(1)
          elif not args.vpc_id and vpc_exist():
              args.vpc_id = vpc_exist(True)
              pre_defined_vpc = False
          print('AWS VPC ID: {}'.format(args.vpc_id))
          if not args.subnet_id and not subnet_exist():
              try:
                  print('[CREATING AWS SUBNET]')
                  args.subnet_id = create_subnet(args.vpc_id, args.subnet_cidr)
                  if args.network_type == 'public':
                      enable_auto_assign_ip(args.subnet_id)
                  print("[ASSOCIATING ROUTE TABLE WITH THE SUBNET]")
                  rt = get_route_table_by_tag(args.service_base_name)
                  route_table = ec2_resource.RouteTable(rt)
                  route_table.associate_with_subnet(SubnetId=args.subnet_id)
                  pre_defined_subnet = False
              except:
                  try:
                      remove_subnet()
                  except:
                      print("AWS Subnet hasn't been created or there is an error with removing it")
                  if not pre_defined_vpc:
                      remove_internet_gateways(args.vpc_id, args.service_base_name)
                      remove_route_tables()
                      remove_vpc(args.vpc_id)
                  sys.exit(1)
          if not args.subnet_id and subnet_exist():
              args.subnet_id = subnet_exist(True)
              pre_defined_subnet = False
          print('AWS Subnet ID: {}'.format(args.subnet_id))
          if not args.sg_id and not sg_exist():
              try:
                  print('[CREATING AWS SECURITY GROUP]')
                  allowed_ip_cidr = list()
                  for cidr in args.allowed_ip_cidr.split(','):
                      allowed_ip_cidr.append({"CidrIp": cidr.replace(' ', '')})
                  allowed_vpc_cidr_ip_ranges = list()
                  for cidr in get_vpc_cidr_by_id(args.vpc_id):
                      allowed_vpc_cidr_ip_ranges.append({"CidrIp": cidr})
                  ingress = format_sg([
                      {
                          "PrefixListIds": [],
                          "FromPort": 80,
                          "IpRanges": allowed_ip_cidr,
                          "ToPort": 80, "IpProtocol": "tcp", "UserIdGroupPairs": []
                      },
                      {
                          "PrefixListIds": [],
                          "FromPort": 22,
                          "IpRanges": allowed_ip_cidr,
                          "ToPort": 22, "IpProtocol": "tcp", "UserIdGroupPairs": []
                      },
                      {
                          "PrefixListIds": [],
                          "FromPort": 443,
                          "IpRanges": allowed_ip_cidr,
                          "ToPort": 443, "IpProtocol": "tcp", "UserIdGroupPairs": []
                      },
                      {
                          "PrefixListIds": [],
                          "FromPort": 8082,
                          "IpRanges": allowed_ip_cidr,
                          "ToPort": 8082, "IpProtocol": "tcp", "UserIdGroupPairs": []
                      },
                      {
                          "PrefixListIds": [],
                          "FromPort": 8181,
                          "IpRanges": allowed_ip_cidr,
                          "ToPort": 8181, "IpProtocol": "tcp", "UserIdGroupPairs": []
                      },
                      {
                          "PrefixListIds": [],
                          "FromPort": 8083,
                          "IpRanges": allowed_ip_cidr,
                          "ToPort": 8083, "IpProtocol": "tcp", "UserIdGroupPairs": []
                      },
                      {
                          "PrefixListIds": [],
                          "FromPort": 8083,
                          "IpRanges": allowed_vpc_cidr_ip_ranges,
                          "ToPort": 8083, "IpProtocol": "tcp", "UserIdGroupPairs": []
                      },
                      {
                          "PrefixListIds": [],
                          "FromPort": 3128,
                          "IpRanges": allowed_ip_cidr,
                          "ToPort": 3128, "IpProtocol": "tcp", "UserIdGroupPairs": []
                      },
                      {
                          "PrefixListIds": [],
                          "FromPort": 3128,
                          "IpRanges": allowed_vpc_cidr_ip_ranges,
                          "ToPort": 3128, "IpProtocol": "tcp", "UserIdGroupPairs": []
                      },
                      {
                          "PrefixListIds": [],
                          "FromPort": 80,
                          "IpRanges": allowed_vpc_cidr_ip_ranges,
                          "ToPort": 80, "IpProtocol": "tcp", "UserIdGroupPairs": []
                      },
                      {
                          "PrefixListIds": [],
                          "FromPort": 443,
                          "IpRanges": allowed_vpc_cidr_ip_ranges,
                          "ToPort": 443, "IpProtocol": "tcp", "UserIdGroupPairs": []
                      },
                      {
                          "PrefixListIds": [],
                          "FromPort": 8082,
                          "IpRanges": allowed_vpc_cidr_ip_ranges,
                          "ToPort": 8082, "IpProtocol": "tcp", "UserIdGroupPairs": []
                      },
                      {
                          "PrefixListIds": [],
                          "FromPort": 8181,
                          "IpRanges": allowed_vpc_cidr_ip_ranges,
                          "ToPort": 8181, "IpProtocol": "tcp", "UserIdGroupPairs": []
                      }
                  ])
                  egress = format_sg([
                      {"IpProtocol": "-1", "IpRanges": [{"CidrIp": '0.0.0.0/0'}], "UserIdGroupPairs": [],
                       "PrefixListIds": []}
                  ])
                  tag = {"Key": tag_name, "Value": args.service_base_name}
                  name_tag = {"Key": "Name", "Value": args.service_base_name + "-sg"}
                  args.sg_id = create_security_group(args.service_base_name + '-sg', args.vpc_id, ingress, egress, tag,
                                                     name_tag)
                  pre_defined_sg = False
              except:
                  try:
                      remove_sgroups()
                  except:
                      print("AWS Security Group hasn't been created or there is an error with removing it")
                      pass
                  if not pre_defined_subnet:
                      remove_subnet()
                  if not pre_defined_vpc:
                      remove_internet_gateways(args.vpc_id, args.service_base_name)
                      remove_route_tables()
                      remove_vpc(args.vpc_id)
                  sys.exit(1)
          if not args.sg_id and sg_exist():
              args.sg_id = sg_exist(True)
              pre_defined_sg = False
          print('AWS Security Group ID: {}'.format(args.sg_id))
  
          if args.efs_enabled == 'True':
              if not args.efs_id and not efs_exist():
                  try:
                      print('[CREATING AWS EFS]')
                      allowed_ip_cidr = list()
                      for cidr in args.allowed_ip_cidr.split(','):
                          allowed_ip_cidr.append({"CidrIp": cidr.replace(' ', '')})
                      allowed_vpc_cidr_ip_ranges = list()
                      for cidr in get_vpc_cidr_by_id(args.vpc_id):
                          allowed_vpc_cidr_ip_ranges.append({"CidrIp": cidr})
                      ingress = format_sg([
                          {
                              "PrefixListIds": [],
                              "FromPort": 2049,
                              "IpRanges": allowed_ip_cidr,
                              "ToPort": 2049, "IpProtocol": "tcp", "UserIdGroupPairs": []
                          },
                          {
                              "PrefixListIds": [],
                              "FromPort": 2049,
                              "IpRanges": allowed_vpc_cidr_ip_ranges,
                              "ToPort": 2049, "IpProtocol": "tcp", "UserIdGroupPairs": []
                          }
                      ])
                      egress = format_sg([
                          {"IpProtocol": "-1", "IpRanges": [{"CidrIp": '0.0.0.0/0'}], "UserIdGroupPairs": [],
                           "PrefixListIds": []}
                      ])
                      tag = {"Key": tag_name, "Value": args.service_base_name}
                      name_tag = {"Key": "Name", "Value": args.service_base_name + "-efs-sg"}
                      efs_sg_id = create_security_group(args.service_base_name + '-efs-sg', args.vpc_id, ingress, egress,
                                                        tag, name_tag)
                      args.efs_id = create_efs()
                      mount_target_id = create_mount_target(efs_sg_id)
                      pre_defined_efs = False
                      create_efs_tag()
                  except:
                      try:
                          remove_efs()
                      except:
                          print("AWS EFS hasn't been created or there is an error with removing it")
                      if not pre_defined_sg:
                          remove_sgroups()
                      if not pre_defined_subnet:
                          remove_subnet()
                      if not pre_defined_vpc:
                          remove_internet_gateways(args.vpc_id, args.service_base_name)
                          remove_route_tables()
                          remove_vpc(args.vpc_id)
                      sys.exit(1)
              if not args.efs_id and efs_exist():
                  args.efs_id = efs_exist(True)
                  pre_defined_efs = False
              print('AWS EFS ID: {}'.format(args.efs_id))
  
          if not ec2_exist():
              try:
                  print('[CREATING AWS EC2 INSTANCE]')
                  ec2_id = create_instance()
              except:
                  try:
                      remove_ec2()
                  except:
                      print("AWS EC2 instance hasn't been created or there is an error with removing it")
                  if not pre_defined_efs:
                      remove_efs()
                  if not pre_defined_sg:
                      remove_sgroups()
                  if not pre_defined_subnet:
                      remove_subnet()
                  if not pre_defined_vpc:
                      remove_internet_gateways(args.vpc_id, args.service_base_name)
                      remove_route_tables()
                      remove_vpc(args.vpc_id)
                  sys.exit(1)
          else:
              ec2_id = ec2_exist(True)
  
          if args.network_type == 'public':
              if not elastic_ip_exist():
                  try:
                      print('[ALLOCATING AWS ELASTIC IP ADDRESS]')
                      allocate_elastic_ip()
                  except:
                      try:
                          release_elastic_ip()
                      except:
                          print("AWS Elastic IP address hasn't been created or there is an error with removing it")
                      remove_ec2()
                      if not pre_defined_efs:
                          remove_efs()
                      if not pre_defined_sg:
                          remove_sgroups()
                      if not pre_defined_subnet:
                          remove_subnet()
                      if not pre_defined_vpc:
                          remove_internet_gateways(args.vpc_id, args.service_base_name)
                          remove_route_tables()
                          remove_vpc(args.vpc_id)
                      sys.exit(1)
              try:
                  print('[ASSOCIATING AWS ELASTIC IP ADDRESS TO EC2 INSTANCE]')
                  allocation_id = elastic_ip_exist(True)
                  associate_elastic_ip(ec2_id, allocation_id)
                  time.sleep(30)
              except:
                  try:
                      association_id = elastic_ip_exist(True, 'AssociationId')
                      disassociate_elastic_ip(association_id)
                  except:
                      print("AWS Elastic IP address hasn't been associated or there is an error with disassociating it")
                  release_elastic_ip()
                  remove_ec2()
                  if not pre_defined_efs:
                      remove_efs()
                  if not pre_defined_sg:
                      remove_sgroups()
                  if not pre_defined_subnet:
                      remove_subnet()
                  if not pre_defined_vpc:
                      remove_internet_gateways(args.vpc_id, args.service_base_name)
                      remove_route_tables()
                      remove_vpc(args.vpc_id)
                  sys.exit(1)
  
          if args.network_type == 'public':
              ec2_ip_address = get_instance_ip_address_by_id(ec2_id, 'public_ip_address')
          else:
              ec2_ip_address = get_instance_ip_address_by_id(ec2_id, 'private_ip_address')
  
          if args.hosted_zone_id and args.hosted_zone_name and args.subdomain:
              try:
                  print('[CREATING AWS ROUTE53 RECORD]')
                  create_route_53_record(args.hosted_zone_id, args.hosted_zone_name, args.subdomain, ec2_ip_address)
              except:
                  try:
                      remove_route_53_record(args.hosted_zone_id, args.hosted_zone_name, args.subdomain)
                  except:
                      print("AWS Route53 record hasn't been created or there is an error with removing it")
                  if args.network_type == 'public':
                      association_id = elastic_ip_exist(True, 'AssociationId')
                      disassociate_elastic_ip(association_id)
                      release_elastic_ip()
                  remove_ec2()
                  if not pre_defined_efs:
                      remove_efs()
                  if not pre_defined_sg:
                      remove_sgroups()
                  if not pre_defined_subnet:
                      remove_subnet()
                  if not pre_defined_vpc:
                      remove_internet_gateways(args.vpc_id, args.service_base_name)
                      remove_route_tables()
                      remove_vpc(args.vpc_id)
                  sys.exit(1)
  
          print("CONFIGURE CONNECTIONS")
          env['connection_attempts'] = 100
          env.key_filename = [args.key_path + args.key_name + '.pem']
          env.host_string = 'ubuntu@' + ec2_ip_address
          print("CONFIGURE LOCAL REPOSITORY")
          try:
              print('CREATING DLAB-USER')
              ensure_ssh_user('ubuntu')
              env.host_string = configuration['conf_os_user'] + '@' + ec2_ip_address
  
              print('SETTING HOSTNAME')
              set_hostname()
  
              print('INSTALLING JAVA')
              install_java()
  
              print('INSTALLING GROOVY')
              install_groovy()
  
              print('CONFIGURING SSL CERTS')
              configure_ssl()
  
              print('INSTALLING NEXUS')
              install_nexus()
  
              print('INSTALLING NGINX')
              install_nginx()
  
              print('DOWNLOADING REQUIRED PACKAGES')
              download_packages()
  
              print('INSTALLING DOCKER')
              install_docker()
  
              print('PREPARING DLAB DOCKER IMAGES')
              prepare_images()
  
              print('INSTALLING SQUID')
              install_squid()
  
              if args.hosted_zone_id and args.hosted_zone_name and args.subdomain:
                  nexus_host = "{0}.{1}".format(args.subdomain, args.hosted_zone_name)
              else:
                  nexus_host = ec2_ip_address
  
              print('[SUMMARY]')
              print("AWS VPC ID: {0}".format(args.vpc_id))
              print("AWS Subnet ID: {0}".format(args.subnet_id))
              print("AWS Security Group ID: {0}".format(args.sg_id))
              print("AWS EC2 ID: {0}".format(ec2_id))
              print("AWS EC2 IP address: {0}".format(ec2_ip_address))
              print("SSL certificate path: /etc/ssl/certs/repository.crt")
              print("Service user credentials: {0}/{1}".format(args.nexus_service_user_name,
                                                               args.nexus_service_user_password))
              print("PyPi repository URL: https://{0}/repository/pypi".format(nexus_host))
              print("Maven-central repository URL: https://{0}/repository/maven-central".format(nexus_host))
              print("Maven-bintray repository URL: https://{0}/repository/maven-bintray".format(nexus_host))
              print("Docker-internal repository URL: {0}:8083".format(nexus_host))
              print("Docker repository URL: https://{0}/repository/docker".format(nexus_host))
              print("Jenkins repository URL: https://{0}/repository/jenkins".format(nexus_host))
              print("Mongo repository URL: https://{0}/repository/mongo".format(nexus_host))
              print("Packages repository URL: https://{0}/repository/packages".format(nexus_host))
              print("NPM repository URL: https://{0}/repository/npm".format(nexus_host))
              print("Ubuntu repository URL: https://{0}/repository/ubuntu".format(nexus_host))
              print("Ubuntu-security repository URL: https://{0}/repository/ubuntu-security".format(nexus_host))
              print("Ubuntu-bintray repository URL: https://{0}/repository/ubuntu-bintray".format(nexus_host))
              print("Ubuntu-canonical repository URL: https://{0}/repository/ubuntu-canonical".format(nexus_host))
              print("Rrutter repository URL: https://{0}/repository/rrutter".format(nexus_host))
              print("R repository URL: https://{0}/repository/r".format(nexus_host))
              print("Amazon-main repository URL: https://{0}/repository/amazon-main".format(nexus_host))
              print("Amazon-updates repository URL: https://{0}/repository/amazon-updates".format(nexus_host))
              print("Squid proxy: {0}:3128".format(nexus_host))
              if args.efs_id:
                  print('AWS EFS ID: {}'.format(args.efs_id))
              if args.hosted_zone_id and args.hosted_zone_name and args.subdomain:
                  print("DNS name: {0}".format(args.subdomain + '.' + args.hosted_zone_name))
          except:
              if args.hosted_zone_id and args.hosted_zone_name and args.subdomain:
                  remove_route_53_record(args.hosted_zone_id, args.hosted_zone_name, args.subdomain)
              if args.network_type == 'public':
                  association_id = elastic_ip_exist(True, 'AssociationId')
                  disassociate_elastic_ip(association_id)
                  release_elastic_ip()
              remove_ec2()
              if not pre_defined_efs:
                  remove_efs()
              if not pre_defined_sg:
                  remove_sgroups()
              if not pre_defined_subnet:
                  remove_subnet()
              if not pre_defined_vpc:
                  remove_internet_gateways(args.vpc_id, args.service_base_name)
                  remove_route_tables()
                  remove_vpc(args.vpc_id)
              sys.exit(1)
  
      else:
          print('Invalid action: {}'.format(args.action))
  