Fixing issue with aliases after the first deployment. Make sure role and policy…
… names have the environment name in them.
Showing
6 changed files
with
57 additions
and
47 deletions
... | @@ -13,7 +13,6 @@ | ... | @@ -13,7 +13,6 @@ |
13 | # limitations under the License. | 13 | # limitations under the License. |
14 | 14 | ||
15 | import logging | 15 | import logging |
16 | -import os | ||
17 | 16 | ||
18 | import jmespath | 17 | import jmespath |
19 | import boto3 | 18 | import boto3 |
... | @@ -44,9 +43,11 @@ class AWSClient(object): | ... | @@ -44,9 +43,11 @@ class AWSClient(object): |
44 | return self._profile_name | 43 | return self._profile_name |
45 | 44 | ||
46 | def _create_client(self): | 45 | def _create_client(self): |
46 | + global recording_path | ||
47 | session = boto3.session.Session( | 47 | session = boto3.session.Session( |
48 | region_name=self._region_name, profile_name=self._profile_name) | 48 | region_name=self._region_name, profile_name=self._profile_name) |
49 | - placebo.attach(session) | 49 | + if recording_path: |
50 | + placebo.attach(session) | ||
50 | client = session.client(self._service_name) | 51 | client = session.client(self._service_name) |
51 | return client | 52 | return client |
52 | 53 | ||
... | @@ -94,12 +95,7 @@ class AWSClient(object): | ... | @@ -94,12 +95,7 @@ class AWSClient(object): |
94 | 95 | ||
95 | _client_cache = {} | 96 | _client_cache = {} |
96 | 97 | ||
97 | - | 98 | +recording_path = None |
98 | -def save_recordings(recording_path): | ||
99 | - for key in _client_cache: | ||
100 | - client = _client_cache[key] | ||
101 | - full_path = os.path.join(recording_path, '{}.json'.format(key)) | ||
102 | - client.client.meta.placebo.save(full_path) | ||
103 | 99 | ||
104 | 100 | ||
105 | def create_client(service_name, context): | 101 | def create_client(service_name, context): |
... | @@ -109,16 +105,5 @@ def create_client(service_name, context): | ... | @@ -109,16 +105,5 @@ def create_client(service_name, context): |
109 | if client_key not in _client_cache: | 105 | if client_key not in _client_cache: |
110 | client = AWSClient(service_name, context.region, | 106 | client = AWSClient(service_name, context.region, |
111 | context.profile) | 107 | context.profile) |
112 | - if 'placebo' in context.config: | ||
113 | - placebo_cfg = context.config['placebo'] | ||
114 | - if placebo_cfg.get('mode') == 'play': | ||
115 | - full_path = os.path.join( | ||
116 | - placebo_cfg['recording_path'], | ||
117 | - '{}.json'.format(client_key)) | ||
118 | - if os.path.exists(full_path): | ||
119 | - client.client.meta.placebo.load(full_path) | ||
120 | - client.client.meta.placebo.start() | ||
121 | - elif placebo_cfg['mode'] == 'record': | ||
122 | - client.client.meta.placebo.record() | ||
123 | _client_cache[client_key] = client | 108 | _client_cache[client_key] = client |
124 | return _client_cache[client_key] | 109 | return _client_cache[client_key] | ... | ... |
... | @@ -18,12 +18,11 @@ import time | ... | @@ -18,12 +18,11 @@ import time |
18 | import os | 18 | import os |
19 | import shutil | 19 | import shutil |
20 | 20 | ||
21 | -from botocore.exceptions import ClientError | ||
22 | - | ||
23 | import kappa.function | 21 | import kappa.function |
24 | import kappa.event_source | 22 | import kappa.event_source |
25 | import kappa.policy | 23 | import kappa.policy |
26 | import kappa.role | 24 | import kappa.role |
25 | +import kappa.awsclient | ||
27 | 26 | ||
28 | LOG = logging.getLogger(__name__) | 27 | LOG = logging.getLogger(__name__) |
29 | 28 | ||
... | @@ -34,15 +33,15 @@ InfoFmtString = '...%(message)s' | ... | @@ -34,15 +33,15 @@ InfoFmtString = '...%(message)s' |
34 | class Context(object): | 33 | class Context(object): |
35 | 34 | ||
36 | def __init__(self, config_file, environment=None, | 35 | def __init__(self, config_file, environment=None, |
37 | - debug=False, force=False): | 36 | + debug=False, recording_path=None): |
38 | if debug: | 37 | if debug: |
39 | self.set_logger('kappa', logging.DEBUG) | 38 | self.set_logger('kappa', logging.DEBUG) |
40 | else: | 39 | else: |
41 | self.set_logger('kappa', logging.INFO) | 40 | self.set_logger('kappa', logging.INFO) |
41 | + kappa.awsclient.recording_path = recording_path | ||
42 | self._load_cache() | 42 | self._load_cache() |
43 | self.config = yaml.load(config_file) | 43 | self.config = yaml.load(config_file) |
44 | self.environment = environment | 44 | self.environment = environment |
45 | - self.force = force | ||
46 | self.policy = kappa.policy.Policy( | 45 | self.policy = kappa.policy.Policy( |
47 | self, self.config['environments'][self.environment]) | 46 | self, self.config['environments'][self.environment]) |
48 | self.role = kappa.role.Role( | 47 | self.role = kappa.role.Role( |
... | @@ -104,9 +103,13 @@ class Context(object): | ... | @@ -104,9 +103,13 @@ class Context(object): |
104 | return self.config.get('tests', '_tests') | 103 | return self.config.get('tests', '_tests') |
105 | 104 | ||
106 | @property | 105 | @property |
106 | + def source_dir(self): | ||
107 | + return self.config.get('source', '_src') | ||
108 | + | ||
109 | + @property | ||
107 | def unit_test_runner(self): | 110 | def unit_test_runner(self): |
108 | return self.config.get('unit_test_runner', | 111 | return self.config.get('unit_test_runner', |
109 | - 'nosetests . ../_tests/unit/') | 112 | + 'nosetests . ../{}/unit/'.format(self.test_dir)) |
110 | 113 | ||
111 | @property | 114 | @property |
112 | def exec_role_arn(self): | 115 | def exec_role_arn(self): | ... | ... |
... | @@ -66,10 +66,6 @@ class Function(object): | ... | @@ -66,10 +66,6 @@ class Function(object): |
66 | return '{}.zip'.format(self._context.name) | 66 | return '{}.zip'.format(self._context.name) |
67 | 67 | ||
68 | @property | 68 | @property |
69 | - def path(self): | ||
70 | - return self._config.get('path', '_src') | ||
71 | - | ||
72 | - @property | ||
73 | def tests(self): | 69 | def tests(self): |
74 | return self._config.get('tests', '_tests') | 70 | return self._config.get('tests', '_tests') |
75 | 71 | ||
... | @@ -137,7 +133,7 @@ class Function(object): | ... | @@ -137,7 +133,7 @@ class Function(object): |
137 | # changed and needs to be updated so return True. | 133 | # changed and needs to be updated so return True. |
138 | changed = True | 134 | changed = True |
139 | self._copy_config_file() | 135 | self._copy_config_file() |
140 | - self.zip_lambda_function(self.zipfile_name, self.path) | 136 | + self.zip_lambda_function(self.zipfile_name, self._context.source_dir) |
141 | m = hashlib.md5() | 137 | m = hashlib.md5() |
142 | with open(self.zipfile_name, 'rb') as fp: | 138 | with open(self.zipfile_name, 'rb') as fp: |
143 | m.update(fp.read()) | 139 | m.update(fp.read()) |
... | @@ -175,9 +171,9 @@ class Function(object): | ... | @@ -175,9 +171,9 @@ class Function(object): |
175 | 171 | ||
176 | def _copy_config_file(self): | 172 | def _copy_config_file(self): |
177 | config_name = '{}_config.json'.format(self._context.environment) | 173 | config_name = '{}_config.json'.format(self._context.environment) |
178 | - config_path = os.path.join(self.path, config_name) | 174 | + config_path = os.path.join(self._context.source_dir, config_name) |
179 | if os.path.exists(config_path): | 175 | if os.path.exists(config_path): |
180 | - dest_path = os.path.join(self.path, 'config.json') | 176 | + dest_path = os.path.join(self._context.source_dir, 'config.json') |
181 | LOG.debug('copy %s to %s', config_path, dest_path) | 177 | LOG.debug('copy %s to %s', config_path, dest_path) |
182 | shutil.copy2(config_path, dest_path) | 178 | shutil.copy2(config_path, dest_path) |
183 | 179 | ||
... | @@ -228,20 +224,24 @@ class Function(object): | ... | @@ -228,20 +224,24 @@ class Function(object): |
228 | LOG.exception('Unable to list aliases') | 224 | LOG.exception('Unable to list aliases') |
229 | return response['Versions'] | 225 | return response['Versions'] |
230 | 226 | ||
231 | - def create_alias(self, name, description, version=None): | 227 | + def find_latest_version(self): |
232 | # Find the current (latest) version by version number | 228 | # Find the current (latest) version by version number |
233 | # First find the SHA256 of $LATEST | 229 | # First find the SHA256 of $LATEST |
234 | - if not version: | 230 | + versions = self.list_versions() |
235 | - versions = self.list_versions() | 231 | + for v in versions: |
236 | - for v in versions: | 232 | + if v['Version'] == '$LATEST': |
237 | - if v['Version'] == '$LATEST': | 233 | + latest_sha256 = v['CodeSha256'] |
238 | - latest_sha256 = v['CodeSha256'] | 234 | + break |
235 | + for v in versions: | ||
236 | + if v['Version'] != '$LATEST': | ||
237 | + if v['CodeSha256'] == latest_sha256: | ||
238 | + version = v['Version'] | ||
239 | break | 239 | break |
240 | - for v in versions: | 240 | + return version |
241 | - if v['Version'] != '$LATEST': | 241 | + |
242 | - if v['CodeSha256'] == latest_sha256: | 242 | + def create_alias(self, name, description, version=None): |
243 | - version = v['Version'] | 243 | + if not version: |
244 | - break | 244 | + version = self.find_latest_version() |
245 | try: | 245 | try: |
246 | LOG.debug('creating alias %s=%s', name, version) | 246 | LOG.debug('creating alias %s=%s', name, version) |
247 | response = self._lambda_client.call( | 247 | response = self._lambda_client.call( |
... | @@ -254,6 +254,23 @@ class Function(object): | ... | @@ -254,6 +254,23 @@ class Function(object): |
254 | except Exception: | 254 | except Exception: |
255 | LOG.exception('Unable to create alias') | 255 | LOG.exception('Unable to create alias') |
256 | 256 | ||
257 | + def update_alias(self, name, description, version=None): | ||
258 | + # Find the current (latest) version by version number | ||
259 | + # First find the SHA256 of $LATEST | ||
260 | + if not version: | ||
261 | + version = self.find_latest_version() | ||
262 | + try: | ||
263 | + LOG.debug('updating alias %s=%s', name, version) | ||
264 | + response = self._lambda_client.call( | ||
265 | + 'update_alias', | ||
266 | + FunctionName=self.name, | ||
267 | + Description=description, | ||
268 | + FunctionVersion=version, | ||
269 | + Name=name) | ||
270 | + LOG.debug(response) | ||
271 | + except Exception: | ||
272 | + LOG.exception('Unable to update alias') | ||
273 | + | ||
257 | def add_permissions(self): | 274 | def add_permissions(self): |
258 | if self.permissions: | 275 | if self.permissions: |
259 | time.sleep(5) | 276 | time.sleep(5) |
... | @@ -329,7 +346,7 @@ class Function(object): | ... | @@ -329,7 +346,7 @@ class Function(object): |
329 | ZipFile=zipdata, | 346 | ZipFile=zipdata, |
330 | Publish=True) | 347 | Publish=True) |
331 | LOG.debug(response) | 348 | LOG.debug(response) |
332 | - self.create_alias( | 349 | + self.update_alias( |
333 | self._context.environment, | 350 | self._context.environment, |
334 | 'For the {} stage'.format(self._context.environment)) | 351 | 'For the {} stage'.format(self._context.environment)) |
335 | except Exception: | 352 | except Exception: | ... | ... |
... | @@ -35,7 +35,7 @@ class Policy(object): | ... | @@ -35,7 +35,7 @@ class Policy(object): |
35 | 35 | ||
36 | @property | 36 | @property |
37 | def name(self): | 37 | def name(self): |
38 | - return self._context.name | 38 | + return '{}_{}'.format(self._context.name, self.environment) |
39 | 39 | ||
40 | @property | 40 | @property |
41 | def description(self): | 41 | def description(self): | ... | ... |
... | @@ -45,7 +45,7 @@ class Role(object): | ... | @@ -45,7 +45,7 @@ class Role(object): |
45 | 45 | ||
46 | @property | 46 | @property |
47 | def name(self): | 47 | def name(self): |
48 | - return self._context.name | 48 | + return '{}_{}'.format(self._context.name, self._context.environment) |
49 | 49 | ||
50 | @property | 50 | @property |
51 | def arn(self): | 51 | def arn(self): | ... | ... |
... | @@ -40,9 +40,14 @@ pass_ctx = click.make_pass_decorator(Context) | ... | @@ -40,9 +40,14 @@ pass_ctx = click.make_pass_decorator(Context) |
40 | default='dev', | 40 | default='dev', |
41 | help='Specify which environment to work with (default dev)' | 41 | help='Specify which environment to work with (default dev)' |
42 | ) | 42 | ) |
43 | +@click.option( | ||
44 | + '--record-path', | ||
45 | + type=click.Path(exists=True, file_okay=False, writable=True), | ||
46 | + help='Uses placebo to record AWS responses to this path' | ||
47 | +) | ||
43 | @click.pass_context | 48 | @click.pass_context |
44 | -def cli(ctx, config=None, debug=False, env=None): | 49 | +def cli(ctx, config=None, debug=False, env=None, record_path=None): |
45 | - ctx.obj = Context(config, env, debug) | 50 | + ctx.obj = Context(config, env, debug, record_path) |
46 | 51 | ||
47 | 52 | ||
48 | @cli.command() | 53 | @cli.command() | ... | ... |
-
Please register or login to post a comment