Skip to content

Commit

Permalink
v0.2.6
Browse files Browse the repository at this point in the history
  • Loading branch information
gabstopper committed Jan 9, 2017
1 parent e09d195 commit 1ed28ab
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 144 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ positional arguments:
optional arguments:
-h, --help show this help message and exit
-y YAML, --yaml YAML Specify yaml configuration file name
-d, --delete Delete a VPC (menu)
-c, --create Create a VPC with NGFW
-d, --delete_vpc Delete a VPC (menu)
-c, --create_vpc Create a VPC with NGFW
-r, --remove Remove NGFW from VPC (menu)
-a, --add Add NGFW to existing VPC (menu)
-l, --list List NGFW installed in VPC (menu)
Expand Down Expand Up @@ -93,13 +93,13 @@ ngfw_launcher.py -y /path/to/config.yml --list
Delete a VPC created using this tool:

```
ngfw_launcher.py -y /path/to/config.yml --delete
ngfw_launcher.py -y /path/to/config.yml --delete_vpc
```

Create a new VPC with NGFW. Note, this requires vpc_subnet, vpc_private and vpc_public settings in
the yaml configuration:

```
ngfw_launcher.py -y /path/to/config.yml --create --verbose
ngfw_launcher.py -y /path/to/config.yml --create_vpc --verbose
```

31 changes: 18 additions & 13 deletions deploy/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,10 @@
select_unused_subnet, select_instance,
select_delete_vpc, get_ec2_client,
authorize_security_group_ingress, create_security_group,
rollback_existing_vpc, validate_aws, select_deploy_style, map_az_to_subnet)
from deploy.ngfw import NGFWConfiguration, validate, get_smc_session
rollback_existing_vpc, validate_aws, select_deploy_style, map_az_to_subnet,
VpcConfigurationError, rollback)
from deploy.ngfw import NGFWConfiguration, validate, get_smc_session,\
del_fw_from_smc
from deploy.validators import prompt_user
from smc.api.exceptions import CreateEngineFailed, NodeCommandFailed
try:
Expand Down Expand Up @@ -118,8 +120,7 @@ def create_vpc_and_ngfw(awscfg, ngfw):
except (botocore.exceptions.ClientError, CreateEngineFailed,
NodeCommandFailed) as e:
logger.error('Caught exception, rolling back: {}'.format(e))
ngfw.rollback()
vpc.rollback()
rollback(vpc.vpc)
return [('Failed deploying VPC', [str(e)])]

def create_inline_ngfw(subnets, public, awscfg, ngfw, queue):
Expand Down Expand Up @@ -184,8 +185,9 @@ def create_inline_ngfw(subnets, public, awscfg, ngfw, queue):
NodeCommandFailed) as e:
logger.error('Caught exception, rolling back: {}'.format(e))
queue.put(('{}, {}:'.format(subnets[0].availability_zone, subnets), [str(e)]))
ngfw.rollback()
rollback_existing_vpc(vpc, subnets)
print("Deleting FW: %s" % ngfw.name)
del_fw_from_smc([ngfw.name])

def create_as_nat_gateway(subnets, public, awscfg, ngfw, queue):

Expand Down Expand Up @@ -215,8 +217,9 @@ def create_as_nat_gateway(subnets, public, awscfg, ngfw, queue):
NodeCommandFailed) as e:
logger.error('Caught exception, rolling back: {}'.format(e))
queue.put(('{}, {}:'.format(subnets[0].availability_zone, subnets), [str(e)]))
ngfw.rollback()
rollback_existing_vpc(vpc, subnets)
print("Deleting FW: %s" % ngfw.name)
del_fw_from_smc([ngfw.name])

def task_runner(ngfw, queue=None, sleep=5, duration=48):
"""
Expand Down Expand Up @@ -304,8 +307,7 @@ def deploy(vpc, ngfw, awscfg):
network.modify_attribute(Groups=[vpc.security_group.id])

# Rename NGFW to AMI instance id (availability zone)
ngfw.engine.rename('{} ({})'.format(instance.id, vpc.availability_zone))
#ngfw.engine.reload() # Refresh engine cache
ngfw.rename('{} ({})'.format(instance.id, vpc.availability_zone))
return ngfw

def main():
Expand All @@ -322,8 +324,8 @@ def main():
group.add_argument('-y', '--yaml', help='Specify yaml configuration file name')
group.add_argument('configure', nargs='?', help='Initial configuration wizard')
actions = parser.add_mutually_exclusive_group()
actions.add_argument('-d', '--delete', action='store_true', help='Delete a VPC (menu)')
actions.add_argument('-c', '--create', action='store_true', help='Create a VPC with NGFW')
actions.add_argument('--delete_vpc', action='store_true', help='Delete a VPC (menu)')
actions.add_argument('--create_vpc', action='store_true', help='Create a VPC with NGFW')
actions.add_argument('-r', '--remove', action='store_true', help='Remove NGFW from VPC (menu)')
actions.add_argument('-a', '--add', action='store_true', help='Add NGFW to existing VPC (menu)')
actions.add_argument('-l', '--list', action='store_true', help='List NGFW installed in VPC (menu)')
Expand Down Expand Up @@ -437,12 +439,15 @@ def main():
print('No unused subnets available.')
return

if args.delete:
if args.delete_vpc:
selection = select_delete_vpc()
vpc = VpcConfiguration(selection).load()
vpc.rollback()
try:
rollback(vpc.vpc)
except VpcConfigurationError as e:
logger.error(e)

if args.create:
if args.create_vpc:
validate_aws(awscfg, vpc_create=True)
start_time = time.time()
results = create_vpc_and_ngfw(awscfg, ngfw)
Expand Down
165 changes: 92 additions & 73 deletions deploy/aws.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@

logger = logging.getLogger(__name__)

class VpcConfigurationError(Exception):
pass

class VpcConfiguration(object):
"""
VpcConfiguration models the data to correlate certain aspects of an
Expand Down Expand Up @@ -86,6 +89,7 @@ def create(cls, vpc_subnet, instance_tenancy='default'):
logger.info('Created VPC: {}'.format(vpc_new.vpc_id))

aws = VpcConfiguration(vpc_new.vpc_id).load()
aws.vpc.create_tags(Tags=create_tag())

internet_gateway = ec2.create_internet_gateway()

Expand Down Expand Up @@ -325,78 +329,6 @@ def launch(self, key_pair, userdata=None,
NetworkInterfaces=interfaces,
UserData=userdata)
return instance[0]

def rollback(self):
"""
In case of failure, convenience to wrap in try/except and remove
the VPC. If there is a running EC2 instance, this will terminate
that instance, remove all other dependencies and delete the VPC.
Typically this is best run when attempting to create the entire
VPC.
"""
for instance in self.vpc.instances.filter(Filters=[{
'Name': 'instance-state-name',
'Values': ['running', 'pending', 'stopped']}]):
logger.info("Terminating instance: {}".format(instance.instance_id))
instance.terminate()
waiter = ec2.meta.client.get_waiter('instance_terminated')
waiter.wait(InstanceIds=[instance.id])
# Network interfaces
for intf in self.vpc.network_interfaces.all():
intf.delete()
# Subnets
for subnet in self.vpc.subnets.all():
subnet.delete()
# Dump route tables
for rt in self.vpc.route_tables.all():
if not rt.associations_attribute:
rt.delete()
else:
for current in rt.associations_attribute:
if not current or current.get('Main') is False:
rt.delete()
# Internet gateway
for igw in self.vpc.internet_gateways.all():
igw.detach_from_vpc(VpcId=self.vpc.vpc_id)
igw.delete()
# Delete security group
try:
grp = list(self.vpc.security_groups.filter(Filters=[{
'Name': 'group-name',
'Values': ['stonesoft-sg']}]))
if grp:
grp[0].delete()
except botocore.exceptions.ClientError as e:
if e.response['Error']['Code'] == 'InvalidGroup.NotFound':
pass
else: raise
self.vpc.delete()
logger.info("Deleted vpc: {}".format(self.vpc.vpc_id))

def rollback_existing_vpc(vpc, subnets):
"""
If a failure occurs during injection into AWS VPC,
reverse the changes back to original
:param VPCConfiguration vpc: VPCConfiguration instance
:param list ec2.Subnet subnets: subnets for this VPC
"""
subnet_ids = [subnet.id for subnet in subnets]
for rt in list_tagged_rtables(vpc.vpc):
if rt.associations:
for assoc in rt.associations.all():
if assoc.subnet_id in subnet_ids:
logger.info('Removing route tbl assoc: {} for subnet: {}'
.format(assoc.route_table_id, assoc.subnet_id))
assoc.delete()
rt.delete()

for intf in vpc.network_interface:
for _, interface in intf.items():
interface.delete()

if vpc.public_subnet:
vpc.public_subnet.delete()

def authorize_security_group_ingress(security_group, from_cidr_block,
ip_protocol='-1'):
Expand Down Expand Up @@ -705,7 +637,7 @@ def next_available_subnet(az_subnets=None, vpc_cidr=None):

def remove_ngfw_from_vpc(instances):
"""
Instances should all be in the same VPC.
Remove only Stonesoft NGFW and related elements.
Tags are used on subnets, route tables and instances to find stonesoft
related components and stop in the right order. When route tables are
removed, existing subnets will revert to using the Main route table.
Expand Down Expand Up @@ -777,6 +709,93 @@ def remove_ngfw_from_vpc(instances):

logger.info('Completed successfully.')

def rollback(vpc):
"""
In case of failure, convenience to wrap in try/except and remove
the VPC. If there is a running EC2 instance, this will terminate
that instance, remove all other dependencies and delete the VPC.
This will only rollback a VPC that has the stonesoft tag.
:param ec2.Vpc vpc: vpc reference
"""
try:
if vpc.tags:
has_tag = any(tag for tag in vpc.tags if tag.get('Key') == 'stonesoft')
if not has_tag:
raise VpcConfigurationError
else:
raise VpcConfigurationError
except VpcConfigurationError:
raise VpcConfigurationError('Stonesoft tag not found, cannot delete VPC.')

instance_ids = []
for instance in vpc.instances.filter(Filters=[{
'Name': 'instance-state-name',
'Values': ['running', 'pending', 'stopped']}]):
logger.info("Terminating instance: {}".format(instance.instance_id))
instance_ids.append(instance.instance_id)
instance.terminate()
waiter = ec2.meta.client.get_waiter('instance_terminated')
waiter.wait(InstanceIds=[instance.id])
# Network interfaces
for intf in vpc.network_interfaces.all():
intf.delete()
# Subnets
for subnet in vpc.subnets.all():
subnet.delete()
# Dump route tables
for rt in vpc.route_tables.all():
if not rt.associations_attribute:
rt.delete()
else:
for current in rt.associations_attribute:
if not current or current.get('Main') is False:
rt.delete()
# Internet gateway
for igw in vpc.internet_gateways.all():
igw.detach_from_vpc(VpcId=vpc.vpc_id)
igw.delete()
# Delete security group
try:
grp = list(vpc.security_groups.filter(Filters=[{
'Name': 'group-name',
'Values': ['stonesoft-sg']}]))
if grp:
grp[0].delete()
except botocore.exceptions.ClientError as e:
if e.response['Error']['Code'] == 'InvalidGroup.NotFound':
pass
else: raise

vpc.delete()
logger.info("Deleted vpc: {}".format(vpc.vpc_id))
del_fw_from_smc(instance_ids)

def rollback_existing_vpc(vpc, subnets):
"""
If a failure occurs during injection into AWS VPC,
reverse the changes back to original
:param VPCConfiguration vpc: VPCConfiguration instance
:param list ec2.Subnet subnets: subnets for this VPC
"""
subnet_ids = [subnet.id for subnet in subnets]
for rt in list_tagged_rtables(vpc.vpc):
if rt.associations:
for assoc in rt.associations.all():
if assoc.subnet_id in subnet_ids:
logger.info('Removing route tbl assoc: {} for subnet: {}'
.format(assoc.route_table_id, assoc.subnet_id))
assoc.delete()
rt.delete()

for intf in vpc.network_interface:
for _, interface in intf.items():
interface.delete()

if vpc.public_subnet:
vpc.public_subnet.delete()

def validate_aws(awscfg, vpc_create=False):
"""
Validate AWS settings. For any add or create operations, the
Expand Down
Loading

0 comments on commit 1ed28ab

Please sign in to comment.