Skip to content

Commit

Permalink
- Removed CodeDeployConfiguration Name to allow CF to replace resourc…
Browse files Browse the repository at this point in the history
…e when HOST_COUNT is changed.

- Removed string value from Port numbers
- Removed duplicate NACLAZ3 entries
- Added -l --cfn-lint argument to perform extra CloudFormation error detection
  • Loading branch information
gitwater committed Jan 25, 2022
1 parent 7d8a805 commit 27e5b76
Show file tree
Hide file tree
Showing 11 changed files with 90 additions and 78 deletions.
1 change: 0 additions & 1 deletion src/paco/cftemplates/codedeploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,6 @@ def __init__(
CodeDeployConfiguration:
Type: AWS::CodeDeploy::DeploymentConfig
Properties:
DeploymentConfigName: !Ref ResourceNamePrefix
MinimumHealthyHosts:
Type: !Ref CodeDeployConfigType
Value: !Ref CodeDeployConfigValue
Expand Down
4 changes: 2 additions & 2 deletions src/paco/cftemplates/security_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ def create_group_rules(self, sg_group_id, sg_name, sg_config, template):
rule_name = self.create_cfn_logical_id(sg_name + sg_rule_hash + sg_rule_type + sg_rule_config.name)
# FromPort and ToPort
if sg_rule_config.port != -1:
rule_dict['FromPort'] = str(sg_rule_config.port)
rule_dict['ToPort'] = str(sg_rule_config.port)
rule_dict['FromPort'] = sg_rule_config.port
rule_dict['ToPort'] = sg_rule_config.port
else:
rule_dict['FromPort'] = sg_rule_config.from_port
rule_dict['ToPort'] = sg_rule_config.to_port
Expand Down
61 changes: 15 additions & 46 deletions src/paco/cftemplates/segment.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,37 +98,6 @@ def __init__(
#------------------------------------------------------------------------------
Resources:
#------------------------------------------------------------------------------
# NACLs
# Network ACL
NACLAZ3:
Type: AWS::EC2::NetworkAcl
Properties:
VpcId: !Ref VPC
# Tags:
# Inbound NACL: Allow All
NACLAZ3EntryInboundAll:
Type: AWS::EC2::NetworkAclEntry
Properties:
CidrBlock: 0.0.0.0/0
Protocol: '-1'
RuleAction: allow
RuleNumber: '100'
NetworkAclId: !Ref NACLAZ3
# Outbound NACL: Allow All
NACLAZ3EntryOutboundAll:
Type: AWS::EC2::NetworkAclEntry
Properties:
CidrBlock: 0.0.0.0/0
Egress: 'true'
Protocol: '-1'
RuleAction: allow
RuleNumber: '100'
NetworkAclId: !Ref NACLAZ3
#------------------------------------------------------------------------------
# Availability Zone 1
Expand All @@ -147,20 +116,20 @@ def __init__(
Type: AWS::EC2::NetworkAclEntry
Properties:
CidrBlock: 0.0.0.0/0
Protocol: '-1'
Protocol: -1
RuleAction: allow
RuleNumber: '100'
RuleNumber: 100
NetworkAclId: !Ref NACLAZ1
# Outbound NACL: Allow All
NACLAZ1EntryOutboundAll:
Type: AWS::EC2::NetworkAclEntry
Properties:
CidrBlock: 0.0.0.0/0
Egress: 'true'
Protocol: '-1'
Egress: true
Protocol: -1
RuleAction: allow
RuleNumber: '100'
RuleNumber: 100
NetworkAclId: !Ref NACLAZ1
# ---------------------------
Expand Down Expand Up @@ -224,9 +193,9 @@ def __init__(
Condition: AZ2Enabled
Properties:
CidrBlock: 0.0.0.0/0
Protocol: '-1'
Protocol: -1
RuleAction: allow
RuleNumber: '100'
RuleNumber: 100
NetworkAclId: !Ref NACLAZ2
# Outbound NACL: Allow All
Expand All @@ -235,10 +204,10 @@ def __init__(
Condition: AZ2Enabled
Properties:
CidrBlock: 0.0.0.0/0
Egress: 'true'
Protocol: '-1'
Egress: true
Protocol: -1
RuleAction: allow
RuleNumber: '100'
RuleNumber: 100
NetworkAclId: !Ref NACLAZ2
# ---------------------------
Expand Down Expand Up @@ -308,9 +277,9 @@ def __init__(
Condition: AZ3Enabled
Properties:
CidrBlock: 0.0.0.0/0
Protocol: '-1'
Protocol: -1
RuleAction: allow
RuleNumber: '100'
RuleNumber: 100
NetworkAclId: !Ref NACLAZ3
# Outbound NACL: Allow All
Expand All @@ -319,10 +288,10 @@ def __init__(
Condition: AZ3Enabled
Properties:
CidrBlock: 0.0.0.0/0
Egress: 'true'
Protocol: '-1'
Egress: true
Protocol: -1
RuleAction: allow
RuleNumber: '100'
RuleNumber: 100
NetworkAclId: !Ref NACLAZ3
# ---------------------------
Expand Down
2 changes: 2 additions & 0 deletions src/paco/commands/cmd_delete.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def delete_command(
disable_validation,
quiet_changes_only,
hooks_only,
cfn_lint,
config_scope,
home='.'
):
Expand All @@ -38,6 +39,7 @@ def delete_command(
disable_validation,
quiet_changes_only,
hooks_only,
cfn_lint,
config_scope,
home
)
Expand Down
2 changes: 2 additions & 0 deletions src/paco/commands/cmd_lambda.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ def lambda_deploy(
disable_validation,
quiet_changes_only,
hooks_only,
cfn_lint,
config_scope,
home='.',
):
Expand All @@ -51,6 +52,7 @@ def lambda_deploy(
disable_validation,
quiet_changes_only,
hooks_only,
cfn_lint,
config_scope,
home
)
Expand Down
2 changes: 2 additions & 0 deletions src/paco/commands/cmd_provision.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def provision_command(
disable_validation,
quiet_changes_only,
hooks_only,
cfn_lint,
config_scope,
home='.',
auto_publish_code=False,
Expand All @@ -43,6 +44,7 @@ def provision_command(
disable_validation,
quiet_changes_only,
hooks_only,
cfn_lint,
config_scope,
home
)
Expand Down
2 changes: 2 additions & 0 deletions src/paco/commands/cmd_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def set_command(
disable_validation,
quiet_changes_only,
hooks_only,
cfn_lint,
config_scope,
home='.',
):
Expand All @@ -38,6 +39,7 @@ def set_command(
disable_validation,
quiet_changes_only,
hooks_only,
cfn_lint,
config_scope,
home
)
Expand Down
2 changes: 2 additions & 0 deletions src/paco/commands/cmd_validate.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def validate_command(
disable_validation,
quiet_changes_only,
hooks_only,
cfn_lint,
config_scope,
home='.'
):
Expand All @@ -37,6 +38,7 @@ def validate_command(
disable_validation,
quiet_changes_only,
hooks_only,
cfn_lint,
config_scope,
home
)
Expand Down
8 changes: 8 additions & 0 deletions src/paco/commands/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ def init_cloud_command(
disable_validation,
quiet_changes_only,
hooks_only,
cfn_lint,
config_scope,
home
):
Expand All @@ -76,6 +77,7 @@ def init_cloud_command(
paco_ctx.disable_validation = disable_validation
paco_ctx.quiet_changes_only = quiet_changes_only
paco_ctx.hooks_only = hooks_only
paco_ctx.cfn_lint = cfn_lint
paco_ctx.command = command_name
paco_ctx.config_scope = config_scope
init_paco_home_option(paco_ctx, home)
Expand Down Expand Up @@ -288,6 +290,12 @@ def cloud_options(func):
default=False,
help='When updating a stack, only run the hooks and skip the stack update.'
)(func)
func = click.option(
'-l', '--cfn-lint',
is_flag=True,
default=False,
help='Call cfn-lint on CloudFormation templates.'
)(func)
return func

def cloud_args(func):
Expand Down
2 changes: 2 additions & 0 deletions src/paco/config/paco_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,8 @@ def __init__(self, home=None):
self.warn = False
self.quiet_changes_only = False
self.hooks_only = False
self.cfn_lint = False

self.paco_path = os.getcwd()
self.aws_name = "Paco"
self.controllers = {}
Expand Down
82 changes: 53 additions & 29 deletions src/paco/stack/stack.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from paco.models.locations import get_parent_by_interface
from paco.stack.interfaces import IStack, ICloudFormationStack
from paco.utils import md5sum, dict_of_dicts_merge, list_to_comma_string, write_to_file
from pprint import pprint
from shutil import copyfile
from deepdiff import DeepDiff
from zope.interface import implementer
Expand All @@ -18,6 +19,7 @@
import pathlib
import re
import ruamel.yaml
import subprocess
import sys


Expand Down Expand Up @@ -386,6 +388,7 @@ def __init__(
self.support_resource_ref_ext = support_resource_ref_ext
self.dependency_stack = None
self.dependency_group = False
self.template_synced = False
if hooks == None:
self.hooks = StackHooks(self)
else:
Expand Down Expand Up @@ -978,6 +981,8 @@ def generate_template(self):
print("WARNING: Template is reaching size limit of 1 MB: Current size: {} bytes ".format(yaml_path.stat().st_size))
print("template: {}".format(yaml_path))

return yaml_path

def set_parameter(
self,
param_key,
Expand Down Expand Up @@ -1319,23 +1324,28 @@ def sync_template_to_s3bucket(self):
Creates or updates the CloudFormation template body to a Paco Bucket
Returns a template URL to object in the S3 Bucket
"""
template_region = self.aws_region
if self.paco_ctx.project.shared_state != None:
if self.paco_ctx.project.shared_state.cloudformation_region != None:
template_region = self.paco_ctx.project.shared_state.cloudformation_region
s3_key = f"Paco/CloudFormationTemplates/{self.get_name()}.yaml"
bucket_name = self.paco_ctx.paco_buckets.upload_fileobj(
file_contents=self.template.body,
s3_key=s3_key,
account_ctx=self.account_ctx,
region=template_region
)
# https://paco-waterbear-networks-tools-usw2-wbpaco88.s3-us-west-2.amazonaws.com/Paco/CloudFormationTemplates/NE-anet-dev-Secrets-SecretsManager.yaml
if self.aws_region == 'us-east-1':
# us-east-1 is a 'special' S3 region that does not include the region in the URL
return f"https://{bucket_name}.s3.amazonaws.com/{s3_key}"
else:
return f"https://{bucket_name}.s3-{template_region}.amazonaws.com/{s3_key}"
if self.template_synced == False:
template_region = self.aws_region
if self.paco_ctx.project.shared_state != None:
if self.paco_ctx.project.shared_state.cloudformation_region != None:
template_region = self.paco_ctx.project.shared_state.cloudformation_region
s3_key = f"Paco/CloudFormationTemplates/{self.get_name()}.yaml"
bucket_name = self.paco_ctx.paco_buckets.upload_fileobj(
file_contents=self.template.body,
s3_key=s3_key,
account_ctx=self.account_ctx,
region=template_region
)
# https://paco-waterbear-networks-tools-usw2-wbpaco88.s3-us-west-2.amazonaws.com/Paco/CloudFormationTemplates/NE-anet-dev-Secrets-SecretsManager.yaml
if self.aws_region == 'us-east-1':
# us-east-1 is a 'special' S3 region that does not include the region in the URL
self.template_sync_bucket = f"https://{bucket_name}.s3.amazonaws.com/{s3_key}"
else:
self.template_sync_bucket = f"https://{bucket_name}.s3-{template_region}.amazonaws.com/{s3_key}"

self.template_synced = True

return self.template_sync_bucket

def create_stack(self):
"Create an AWS CloudFormation stack"
Expand Down Expand Up @@ -1568,22 +1578,36 @@ def validate(self):
if self.paco_ctx.quiet_changes_only == False:
self.paco_ctx.log_action_col("Validate", "Protected", self.account_ctx.get_name() + '.' + self.aws_region, short_yaml_path, col_2_size=col_2_size)
return
self.generate_template()
yaml_path = self.generate_template()

new_str = ''
if applied_file_path.exists() == False:
new_str = ':new'
self.paco_ctx.log_action_col("Validate", "Template"+new_str, self.account_ctx.get_name() + '.' + self.aws_region, short_yaml_path, col_2_size=col_2_size)
try:
template_url = self.sync_template_to_s3bucket()
self.cfn_client.validate_template(TemplateURL=template_url)
except ClientError as e:
if e.response['Error']['Code'] == 'ValidationError':
message = "Validation Error: {}\nStack: {}\nTemplate: {}\n".format(
e.response['Error']['Message'],
self.get_name(),
self.get_yaml_path()
)
raise StackException(PacoErrorCode.TemplateValidationError, message=message)

# Locally lint CloudFormation - (Extra checks but slows Validate down)
if self.paco_ctx.cfn_lint == True:
args = ("cfn-lint", "-i", "W", "-t", yaml_path)
popen = subprocess.Popen(args, stdout=subprocess.PIPE)
link_ret = popen.wait()
cfn_lint_output = popen.stdout.read()
if link_ret != 0:
message = f"CFN-LINT: Template: {yaml_path}\n{cfn_lint_output}"
pprint(message)
raise StackException(PacoErrorCode.TemplateValidationError, "cfn-lint")
else:
try:
template_url = self.sync_template_to_s3bucket()
self.cfn_client.validate_template(TemplateURL=template_url)
except ClientError as e:
if e.response['Error']['Code'] == 'ValidationError':
message = "Validation Error: {}\nStack: {}\nTemplate: {}\n".format(
e.response['Error']['Message'],
self.get_name(),
self.get_yaml_path()
)
raise StackException(PacoErrorCode.TemplateValidationError, message=message)

self.validate_template_changes()

def delete(self):
Expand Down

0 comments on commit 27e5b76

Please sign in to comment.