Mitch Garnaat

Fixing issue with aliases after the first deployment. Make sure role and policy…

… names have the environment name in them.
......@@ -13,7 +13,6 @@
# limitations under the License.
import logging
import os
import jmespath
import boto3
......@@ -44,9 +43,11 @@ class AWSClient(object):
return self._profile_name
def _create_client(self):
global recording_path
session = boto3.session.Session(
region_name=self._region_name, profile_name=self._profile_name)
placebo.attach(session)
if recording_path:
placebo.attach(session)
client = session.client(self._service_name)
return client
......@@ -94,12 +95,7 @@ class AWSClient(object):
_client_cache = {}
def save_recordings(recording_path):
for key in _client_cache:
client = _client_cache[key]
full_path = os.path.join(recording_path, '{}.json'.format(key))
client.client.meta.placebo.save(full_path)
recording_path = None
def create_client(service_name, context):
......@@ -109,16 +105,5 @@ def create_client(service_name, context):
if client_key not in _client_cache:
client = AWSClient(service_name, context.region,
context.profile)
if 'placebo' in context.config:
placebo_cfg = context.config['placebo']
if placebo_cfg.get('mode') == 'play':
full_path = os.path.join(
placebo_cfg['recording_path'],
'{}.json'.format(client_key))
if os.path.exists(full_path):
client.client.meta.placebo.load(full_path)
client.client.meta.placebo.start()
elif placebo_cfg['mode'] == 'record':
client.client.meta.placebo.record()
_client_cache[client_key] = client
return _client_cache[client_key]
......
......@@ -18,12 +18,11 @@ import time
import os
import shutil
from botocore.exceptions import ClientError
import kappa.function
import kappa.event_source
import kappa.policy
import kappa.role
import kappa.awsclient
LOG = logging.getLogger(__name__)
......@@ -34,15 +33,15 @@ InfoFmtString = '...%(message)s'
class Context(object):
def __init__(self, config_file, environment=None,
debug=False, force=False):
debug=False, recording_path=None):
if debug:
self.set_logger('kappa', logging.DEBUG)
else:
self.set_logger('kappa', logging.INFO)
kappa.awsclient.recording_path = recording_path
self._load_cache()
self.config = yaml.load(config_file)
self.environment = environment
self.force = force
self.policy = kappa.policy.Policy(
self, self.config['environments'][self.environment])
self.role = kappa.role.Role(
......@@ -104,9 +103,13 @@ class Context(object):
return self.config.get('tests', '_tests')
@property
def source_dir(self):
return self.config.get('source', '_src')
@property
def unit_test_runner(self):
return self.config.get('unit_test_runner',
'nosetests . ../_tests/unit/')
'nosetests . ../{}/unit/'.format(self.test_dir))
@property
def exec_role_arn(self):
......
......@@ -66,10 +66,6 @@ class Function(object):
return '{}.zip'.format(self._context.name)
@property
def path(self):
return self._config.get('path', '_src')
@property
def tests(self):
return self._config.get('tests', '_tests')
......@@ -137,7 +133,7 @@ class Function(object):
# changed and needs to be updated so return True.
changed = True
self._copy_config_file()
self.zip_lambda_function(self.zipfile_name, self.path)
self.zip_lambda_function(self.zipfile_name, self._context.source_dir)
m = hashlib.md5()
with open(self.zipfile_name, 'rb') as fp:
m.update(fp.read())
......@@ -175,9 +171,9 @@ class Function(object):
def _copy_config_file(self):
config_name = '{}_config.json'.format(self._context.environment)
config_path = os.path.join(self.path, config_name)
config_path = os.path.join(self._context.source_dir, config_name)
if os.path.exists(config_path):
dest_path = os.path.join(self.path, 'config.json')
dest_path = os.path.join(self._context.source_dir, 'config.json')
LOG.debug('copy %s to %s', config_path, dest_path)
shutil.copy2(config_path, dest_path)
......@@ -228,20 +224,24 @@ class Function(object):
LOG.exception('Unable to list aliases')
return response['Versions']
def create_alias(self, name, description, version=None):
def find_latest_version(self):
# Find the current (latest) version by version number
# First find the SHA256 of $LATEST
if not version:
versions = self.list_versions()
for v in versions:
if v['Version'] == '$LATEST':
latest_sha256 = v['CodeSha256']
versions = self.list_versions()
for v in versions:
if v['Version'] == '$LATEST':
latest_sha256 = v['CodeSha256']
break
for v in versions:
if v['Version'] != '$LATEST':
if v['CodeSha256'] == latest_sha256:
version = v['Version']
break
for v in versions:
if v['Version'] != '$LATEST':
if v['CodeSha256'] == latest_sha256:
version = v['Version']
break
return version
def create_alias(self, name, description, version=None):
if not version:
version = self.find_latest_version()
try:
LOG.debug('creating alias %s=%s', name, version)
response = self._lambda_client.call(
......@@ -254,6 +254,23 @@ class Function(object):
except Exception:
LOG.exception('Unable to create alias')
def update_alias(self, name, description, version=None):
# Find the current (latest) version by version number
# First find the SHA256 of $LATEST
if not version:
version = self.find_latest_version()
try:
LOG.debug('updating alias %s=%s', name, version)
response = self._lambda_client.call(
'update_alias',
FunctionName=self.name,
Description=description,
FunctionVersion=version,
Name=name)
LOG.debug(response)
except Exception:
LOG.exception('Unable to update alias')
def add_permissions(self):
if self.permissions:
time.sleep(5)
......@@ -329,7 +346,7 @@ class Function(object):
ZipFile=zipdata,
Publish=True)
LOG.debug(response)
self.create_alias(
self.update_alias(
self._context.environment,
'For the {} stage'.format(self._context.environment))
except Exception:
......
......@@ -35,7 +35,7 @@ class Policy(object):
@property
def name(self):
return self._context.name
return '{}_{}'.format(self._context.name, self.environment)
@property
def description(self):
......
......@@ -45,7 +45,7 @@ class Role(object):
@property
def name(self):
return self._context.name
return '{}_{}'.format(self._context.name, self._context.environment)
@property
def arn(self):
......
......@@ -40,9 +40,14 @@ pass_ctx = click.make_pass_decorator(Context)
default='dev',
help='Specify which environment to work with (default dev)'
)
@click.option(
'--record-path',
type=click.Path(exists=True, file_okay=False, writable=True),
help='Uses placebo to record AWS responses to this path'
)
@click.pass_context
def cli(ctx, config=None, debug=False, env=None):
ctx.obj = Context(config, env, debug)
def cli(ctx, config=None, debug=False, env=None, record_path=None):
ctx.obj = Context(config, env, debug, record_path)
@cli.command()
......