Add workaround for AWS S3 API, verify md5 hash, exit non-zero on validate failure
This commit is contained in:
parent
f6e3df67bb
commit
7a66cf3ec5
@ -1,5 +1,10 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.9.9
|
||||||
|
- Add workaround for inconsistent AWS API S3 GetBucketLocation
|
||||||
|
- validate now exits with non-zero exit code if valiation of any template failed
|
||||||
|
- the embedded md5 hash in templates are now verified reading the template
|
||||||
|
|
||||||
## 0.9.8
|
## 0.9.8
|
||||||
- Remove support for FortyTwo legacy mode as AWS now behaves as it should
|
- Remove support for FortyTwo legacy mode as AWS now behaves as it should
|
||||||
- Add support for embedded custom output yaml format and removed hardcoded kubezero output template
|
- Add support for embedded custom output yaml format and removed hardcoded kubezero output template
|
||||||
|
@ -2,7 +2,7 @@ import logging
|
|||||||
|
|
||||||
__author__ = "Stefan Reimer"
|
__author__ = "Stefan Reimer"
|
||||||
__email__ = "stefan@zero-downtimet.net"
|
__email__ = "stefan@zero-downtimet.net"
|
||||||
__version__ = "0.9.8"
|
__version__ = "0.9.9"
|
||||||
|
|
||||||
|
|
||||||
# Set up logging to ``/dev/null`` like a library is supposed to.
|
# Set up logging to ``/dev/null`` like a library is supposed to.
|
||||||
|
@ -78,7 +78,9 @@ def validate(cb, stack_names, multi):
|
|||||||
stacks = _find_stacks(cb, stack_names, multi)
|
stacks = _find_stacks(cb, stack_names, multi)
|
||||||
|
|
||||||
for s in stacks:
|
for s in stacks:
|
||||||
s.validate()
|
ret = s.validate()
|
||||||
|
if ret:
|
||||||
|
sys.exit(ret)
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
|
@ -12,3 +12,7 @@ class InvalidProjectDir(Exception):
|
|||||||
|
|
||||||
class InvalidHook(Exception):
|
class InvalidHook(Exception):
|
||||||
"""My documentation"""
|
"""My documentation"""
|
||||||
|
|
||||||
|
|
||||||
|
class ChecksumError(Exception):
|
||||||
|
"""My documentation"""
|
||||||
|
@ -15,7 +15,7 @@ from .utils import dict_merge, search_refs, ensure_dir, get_s3_url
|
|||||||
from .connection import BotoConnection
|
from .connection import BotoConnection
|
||||||
from .jinja import JinjaEnv, read_config_file
|
from .jinja import JinjaEnv, read_config_file
|
||||||
from . import __version__
|
from . import __version__
|
||||||
from .exceptions import ParameterNotFound, ParameterIllegalValue
|
from .exceptions import ParameterNotFound, ParameterIllegalValue, ChecksumError
|
||||||
from .hooks import exec_hooks
|
from .hooks import exec_hooks
|
||||||
|
|
||||||
import cfnlint.core
|
import cfnlint.core
|
||||||
@ -207,6 +207,20 @@ class Stack(object):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# Get checksum
|
||||||
|
if not self.md5:
|
||||||
|
try:
|
||||||
|
self.md5 = self.cfn_data['Metadata']['Template']['Hash']
|
||||||
|
|
||||||
|
# Verify embedded md5 hash
|
||||||
|
source_cfn = re.sub('Hash: [0-9a-f]{32}', 'Hash: __HASH__', self.cfn_template)
|
||||||
|
our_md5 = hashlib.md5(source_cfn.encode('utf-8')).hexdigest()
|
||||||
|
if (our_md5 != self.md5):
|
||||||
|
raise ChecksumError("Template hash checksum mismatch! Expected: {} Got: {}".format(self.md5, our_md5)) from None
|
||||||
|
|
||||||
|
except KeyError:
|
||||||
|
raise ChecksumError("Template missing Hash checksum!") from None
|
||||||
|
|
||||||
# Add CloudBender dependencies
|
# Add CloudBender dependencies
|
||||||
include = []
|
include = []
|
||||||
search_refs(self.cfn_data, include, self.mode)
|
search_refs(self.cfn_data, include, self.mode)
|
||||||
@ -315,6 +329,7 @@ class Stack(object):
|
|||||||
|
|
||||||
self.cfn_data = yaml.load(self.cfn_template, Loader=SafeLoaderIgnoreUnknown)
|
self.cfn_data = yaml.load(self.cfn_template, Loader=SafeLoaderIgnoreUnknown)
|
||||||
self._parse_metadata()
|
self._parse_metadata()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.debug('Using cached cfn template %s.', self.stackname)
|
logger.debug('Using cached cfn template %s.', self.stackname)
|
||||||
|
|
||||||
@ -356,8 +371,10 @@ class Stack(object):
|
|||||||
if len(matches):
|
if len(matches):
|
||||||
for match in matches:
|
for match in matches:
|
||||||
logger.error(formatter._format(match))
|
logger.error(formatter._format(match))
|
||||||
|
return 1
|
||||||
else:
|
else:
|
||||||
logger.info("Passed.")
|
logger.info("Passed.")
|
||||||
|
return 0
|
||||||
|
|
||||||
def get_outputs(self, include='.*', values=False):
|
def get_outputs(self, include='.*', values=False):
|
||||||
""" gets outputs of the stack """
|
""" gets outputs of the stack """
|
||||||
@ -766,6 +783,10 @@ class Stack(object):
|
|||||||
# so we need the region, AWS as usual
|
# so we need the region, AWS as usual
|
||||||
(bucket, path) = get_s3_url(self.template_bucket_url, self.rel_path, self.stackname + ".yaml")
|
(bucket, path) = get_s3_url(self.template_bucket_url, self.rel_path, self.stackname + ".yaml")
|
||||||
bucket_region = self.connection_manager.call('s3', 'get_bucket_location', {'Bucket': bucket}, profile=self.profile, region=self.region)['LocationConstraint']
|
bucket_region = self.connection_manager.call('s3', 'get_bucket_location', {'Bucket': bucket}, profile=self.profile, region=self.region)['LocationConstraint']
|
||||||
|
# If bucket is in us-east-1 AWS returns 'none' cause reasons grrr
|
||||||
|
if not bucket_region:
|
||||||
|
bucket_region = 'us-east-1'
|
||||||
|
|
||||||
kwargs['TemplateURL'] = 'https://{}.s3.{}.amazonaws.com/{}'.format(bucket, bucket_region, path)
|
kwargs['TemplateURL'] = 'https://{}.s3.{}.amazonaws.com/{}'.format(bucket, bucket_region, path)
|
||||||
else:
|
else:
|
||||||
kwargs['TemplateBody'] = self.cfn_template
|
kwargs['TemplateBody'] = self.cfn_template
|
||||||
|
Loading…
Reference in New Issue
Block a user