Add the ability to generate the config files based on the environment specified.
Showing
4 changed files
with
92 additions
and
47 deletions
... | @@ -25,12 +25,13 @@ import kappa.role | ... | @@ -25,12 +25,13 @@ import kappa.role |
25 | LOG = logging.getLogger(__name__) | 25 | LOG = logging.getLogger(__name__) |
26 | 26 | ||
27 | DebugFmtString = '%(asctime)s - %(name)s - %(levelname)s - %(message)s' | 27 | DebugFmtString = '%(asctime)s - %(name)s - %(levelname)s - %(message)s' |
28 | -InfoFmtString = '\t%(message)s' | 28 | +InfoFmtString = '...%(message)s' |
29 | 29 | ||
30 | 30 | ||
31 | class Context(object): | 31 | class Context(object): |
32 | 32 | ||
33 | - def __init__(self, config_file, environment=None, debug=False): | 33 | + def __init__(self, config_file, environment=None, |
34 | + debug=False, force=False): | ||
34 | if debug: | 35 | if debug: |
35 | self.set_logger('kappa', logging.DEBUG) | 36 | self.set_logger('kappa', logging.DEBUG) |
36 | else: | 37 | else: |
... | @@ -38,6 +39,7 @@ class Context(object): | ... | @@ -38,6 +39,7 @@ class Context(object): |
38 | self._load_cache() | 39 | self._load_cache() |
39 | self.config = yaml.load(config_file) | 40 | self.config = yaml.load(config_file) |
40 | self.environment = environment | 41 | self.environment = environment |
42 | + self.force = force | ||
41 | self.policy = kappa.policy.Policy( | 43 | self.policy = kappa.policy.Policy( |
42 | self, self.config['environments'][self.environment]) | 44 | self, self.config['environments'][self.environment]) |
43 | self.role = kappa.role.Role( | 45 | self.role = kappa.role.Role( |
... | @@ -173,6 +175,9 @@ class Context(object): | ... | @@ -173,6 +175,9 @@ class Context(object): |
173 | def invoke(self): | 175 | def invoke(self): |
174 | return self.function.invoke() | 176 | return self.function.invoke() |
175 | 177 | ||
178 | + def test(self): | ||
179 | + return self.function.invoke() | ||
180 | + | ||
176 | def dryrun(self): | 181 | def dryrun(self): |
177 | return self.function.dryrun() | 182 | return self.function.dryrun() |
178 | 183 | ... | ... |
... | @@ -16,6 +16,7 @@ import logging | ... | @@ -16,6 +16,7 @@ import logging |
16 | import os | 16 | import os |
17 | import zipfile | 17 | import zipfile |
18 | import time | 18 | import time |
19 | +import shutil | ||
19 | 20 | ||
20 | from botocore.exceptions import ClientError | 21 | from botocore.exceptions import ClientError |
21 | 22 | ||
... | @@ -122,7 +123,7 @@ class Function(object): | ... | @@ -122,7 +123,7 @@ class Function(object): |
122 | return self._log | 123 | return self._log |
123 | 124 | ||
124 | def tail(self): | 125 | def tail(self): |
125 | - LOG.debug('tailing function: %s', self.name) | 126 | + LOG.info('tailing function: %s', self.name) |
126 | return self.log.tail() | 127 | return self.log.tail() |
127 | 128 | ||
128 | def _zip_lambda_dir(self, zipfile_name, lambda_dir): | 129 | def _zip_lambda_dir(self, zipfile_name, lambda_dir): |
... | @@ -175,8 +176,17 @@ class Function(object): | ... | @@ -175,8 +176,17 @@ class Function(object): |
175 | except Exception: | 176 | except Exception: |
176 | LOG.exception('Unable to add permission') | 177 | LOG.exception('Unable to add permission') |
177 | 178 | ||
179 | + def _copy_config_file(self): | ||
180 | + config_name = '{}_config.json'.format(self._context.environment) | ||
181 | + config_path = os.path.join(self.path, config_name) | ||
182 | + if os.path.exists(config_path): | ||
183 | + dest_path = os.path.join(self.path, 'config.json') | ||
184 | + LOG.info('copy {} to {}'.format(config_path, dest_path)) | ||
185 | + shutil.copyfile(config_path, dest_path) | ||
186 | + | ||
178 | def create(self): | 187 | def create(self): |
179 | - LOG.debug('creating %s', self.zipfile_name) | 188 | + LOG.info('creating function %s', self.name) |
189 | + self._copy_config_file() | ||
180 | self.zip_lambda_function(self.zipfile_name, self.path) | 190 | self.zip_lambda_function(self.zipfile_name, self.path) |
181 | with open(self.zipfile_name, 'rb') as fp: | 191 | with open(self.zipfile_name, 'rb') as fp: |
182 | exec_role = self._context.exec_role_arn | 192 | exec_role = self._context.exec_role_arn |
... | @@ -198,15 +208,26 @@ class Function(object): | ... | @@ -198,15 +208,26 @@ class Function(object): |
198 | LOG.exception('Unable to upload zip file') | 208 | LOG.exception('Unable to upload zip file') |
199 | self.add_permissions() | 209 | self.add_permissions() |
200 | 210 | ||
201 | - def update(self): | 211 | + def _do_update(self): |
202 | - LOG.debug('updating %s', self.zipfile_name) | 212 | + do_update = False |
203 | - self.zip_lambda_function(self.zipfile_name, self.path) | 213 | + if self._context.force: |
214 | + do_update = True | ||
215 | + else: | ||
204 | stats = os.stat(self.zipfile_name) | 216 | stats = os.stat(self.zipfile_name) |
205 | if self._context.cache.get('zipfile_size') != stats.st_size: | 217 | if self._context.cache.get('zipfile_size') != stats.st_size: |
206 | self._context.cache['zipfile_size'] = stats.st_size | 218 | self._context.cache['zipfile_size'] = stats.st_size |
219 | + do_update = True | ||
220 | + return do_update | ||
221 | + | ||
222 | + def update(self): | ||
223 | + LOG.info('updating %s', self.name) | ||
224 | + self._copy_config_file() | ||
225 | + if self._do_update(): | ||
207 | self._context.save_cache() | 226 | self._context.save_cache() |
208 | with open(self.zipfile_name, 'rb') as fp: | 227 | with open(self.zipfile_name, 'rb') as fp: |
209 | try: | 228 | try: |
229 | + LOG.info('uploading new function zipfile %s', | ||
230 | + self.zipfile_name) | ||
210 | zipdata = fp.read() | 231 | zipdata = fp.read() |
211 | response = self._lambda_client.call( | 232 | response = self._lambda_client.call( |
212 | 'update_function_code', | 233 | 'update_function_code', |
... | @@ -214,9 +235,9 @@ class Function(object): | ... | @@ -214,9 +235,9 @@ class Function(object): |
214 | ZipFile=zipdata) | 235 | ZipFile=zipdata) |
215 | LOG.debug(response) | 236 | LOG.debug(response) |
216 | except Exception: | 237 | except Exception: |
217 | - LOG.exception('Unable to update zip file') | 238 | + LOG.exception('unable to update zip file') |
218 | else: | 239 | else: |
219 | - LOG.info('Code has not changed') | 240 | + LOG.info('function has not changed') |
220 | 241 | ||
221 | def deploy(self): | 242 | def deploy(self): |
222 | if self.exists(): | 243 | if self.exists(): |
... | @@ -224,7 +245,7 @@ class Function(object): | ... | @@ -224,7 +245,7 @@ class Function(object): |
224 | return self.create() | 245 | return self.create() |
225 | 246 | ||
226 | def publish_version(self, description): | 247 | def publish_version(self, description): |
227 | - LOG.debug('publishing version of %s', self.name) | 248 | + LOG.info('publishing version of %s', self.name) |
228 | try: | 249 | try: |
229 | response = self._lambda_client.call( | 250 | response = self._lambda_client.call( |
230 | 'publish_version', | 251 | 'publish_version', |
... | @@ -237,7 +258,7 @@ class Function(object): | ... | @@ -237,7 +258,7 @@ class Function(object): |
237 | return response['Version'] | 258 | return response['Version'] |
238 | 259 | ||
239 | def list_versions(self): | 260 | def list_versions(self): |
240 | - LOG.debug('listing versions of %s', self.name) | 261 | + LOG.info('listing versions of %s', self.name) |
241 | try: | 262 | try: |
242 | response = self._lambda_client.call( | 263 | response = self._lambda_client.call( |
243 | 'list_versions_by_function', | 264 | 'list_versions_by_function', |
... | @@ -248,7 +269,7 @@ class Function(object): | ... | @@ -248,7 +269,7 @@ class Function(object): |
248 | return response['Versions'] | 269 | return response['Versions'] |
249 | 270 | ||
250 | def create_alias(self, name, description, version=None): | 271 | def create_alias(self, name, description, version=None): |
251 | - LOG.debug('creating alias of %s', self.name) | 272 | + LOG.info('creating alias of %s', self.name) |
252 | if version is None: | 273 | if version is None: |
253 | version = self.version | 274 | version = self.version |
254 | try: | 275 | try: |
... | @@ -263,7 +284,7 @@ class Function(object): | ... | @@ -263,7 +284,7 @@ class Function(object): |
263 | LOG.exception('Unable to create alias') | 284 | LOG.exception('Unable to create alias') |
264 | 285 | ||
265 | def list_aliases(self): | 286 | def list_aliases(self): |
266 | - LOG.debug('listing aliases of %s', self.name) | 287 | + LOG.info('listing aliases of %s', self.name) |
267 | try: | 288 | try: |
268 | response = self._lambda_client.call( | 289 | response = self._lambda_client.call( |
269 | 'list_aliases', | 290 | 'list_aliases', |
... | @@ -279,7 +300,7 @@ class Function(object): | ... | @@ -279,7 +300,7 @@ class Function(object): |
279 | self.create_alias(name, description, version) | 300 | self.create_alias(name, description, version) |
280 | 301 | ||
281 | def delete(self): | 302 | def delete(self): |
282 | - LOG.debug('deleting function %s', self.name) | 303 | + LOG.info('deleting function %s', self.name) |
283 | response = None | 304 | response = None |
284 | try: | 305 | try: |
285 | response = self._lambda_client.call( | 306 | response = self._lambda_client.call( |
... | @@ -291,7 +312,6 @@ class Function(object): | ... | @@ -291,7 +312,6 @@ class Function(object): |
291 | return response | 312 | return response |
292 | 313 | ||
293 | def status(self): | 314 | def status(self): |
294 | - LOG.debug('getting status for function %s', self.name) | ||
295 | try: | 315 | try: |
296 | response = self._lambda_client.call( | 316 | response = self._lambda_client.call( |
297 | 'get_function', | 317 | 'get_function', | ... | ... |
... | @@ -121,10 +121,10 @@ class Policy(object): | ... | @@ -121,10 +121,10 @@ class Policy(object): |
121 | LOG.exception('Error creating new Policy version') | 121 | LOG.exception('Error creating new Policy version') |
122 | 122 | ||
123 | def deploy(self): | 123 | def deploy(self): |
124 | - LOG.debug('deploying policy %s', self.name) | 124 | + LOG.info('deploying policy %s', self.name) |
125 | document = self.document() | 125 | document = self.document() |
126 | if not document: | 126 | if not document: |
127 | - LOG.debug('not a custom policy, no need to create it') | 127 | + LOG.info('not a custom policy, no need to create it') |
128 | return | 128 | return |
129 | policy = self.exists() | 129 | policy = self.exists() |
130 | if policy: | 130 | if policy: |
... | @@ -138,7 +138,7 @@ class Policy(object): | ... | @@ -138,7 +138,7 @@ class Policy(object): |
138 | self._context.save_cache() | 138 | self._context.save_cache() |
139 | self._add_policy_version() | 139 | self._add_policy_version() |
140 | else: | 140 | else: |
141 | - LOG.info('Policy unchanged') | 141 | + LOG.info('policy unchanged') |
142 | else: | 142 | else: |
143 | # create a new policy | 143 | # create a new policy |
144 | try: | 144 | try: |
... | @@ -157,7 +157,7 @@ class Policy(object): | ... | @@ -157,7 +157,7 @@ class Policy(object): |
157 | # This indicates that it was a custom policy created by kappa. | 157 | # This indicates that it was a custom policy created by kappa. |
158 | document = self.document() | 158 | document = self.document() |
159 | if self.arn and document: | 159 | if self.arn and document: |
160 | - LOG.debug('deleting policy %s', self.name) | 160 | + LOG.info('deleting policy %s', self.name) |
161 | response = self._iam_client.call( | 161 | response = self._iam_client.call( |
162 | 'delete_policy', PolicyArn=self.arn) | 162 | 'delete_policy', PolicyArn=self.arn) |
163 | LOG.debug(response) | 163 | LOG.debug(response) | ... | ... |
... | @@ -35,12 +35,18 @@ from kappa.context import Context | ... | @@ -35,12 +35,18 @@ from kappa.context import Context |
35 | '--environment', | 35 | '--environment', |
36 | help='Specify which environment to work with' | 36 | help='Specify which environment to work with' |
37 | ) | 37 | ) |
38 | +@click.option( | ||
39 | + '--force/--no-force', | ||
40 | + default=False, | ||
41 | + help='Force an update of the Lambda function' | ||
42 | +) | ||
38 | @click.pass_context | 43 | @click.pass_context |
39 | -def cli(ctx, config=None, debug=False, environment=None): | 44 | +def cli(ctx, config=None, debug=False, environment=None, force=None): |
40 | config = config | 45 | config = config |
41 | ctx.obj['debug'] = debug | 46 | ctx.obj['debug'] = debug |
42 | ctx.obj['config'] = config | 47 | ctx.obj['config'] = config |
43 | ctx.obj['environment'] = environment | 48 | ctx.obj['environment'] = environment |
49 | + ctx.obj['force'] = force | ||
44 | 50 | ||
45 | 51 | ||
46 | @cli.command() | 52 | @cli.command() |
... | @@ -48,10 +54,10 @@ def cli(ctx, config=None, debug=False, environment=None): | ... | @@ -48,10 +54,10 @@ def cli(ctx, config=None, debug=False, environment=None): |
48 | def deploy(ctx): | 54 | def deploy(ctx): |
49 | """Deploy the Lambda function and any policies and roles required""" | 55 | """Deploy the Lambda function and any policies and roles required""" |
50 | context = Context(ctx.obj['config'], ctx.obj['environment'], | 56 | context = Context(ctx.obj['config'], ctx.obj['environment'], |
51 | - ctx.obj['debug']) | 57 | + ctx.obj['debug'], ctx.obj['force']) |
52 | - click.echo('deploying...') | 58 | + click.echo('deploying') |
53 | context.deploy() | 59 | context.deploy() |
54 | - click.echo('...done') | 60 | + click.echo('done') |
55 | 61 | ||
56 | 62 | ||
57 | @cli.command() | 63 | @cli.command() |
... | @@ -59,10 +65,10 @@ def deploy(ctx): | ... | @@ -59,10 +65,10 @@ def deploy(ctx): |
59 | def tag(ctx): | 65 | def tag(ctx): |
60 | """Deploy the Lambda function and any policies and roles required""" | 66 | """Deploy the Lambda function and any policies and roles required""" |
61 | context = Context(ctx.obj['config'], ctx.obj['environment'], | 67 | context = Context(ctx.obj['config'], ctx.obj['environment'], |
62 | - ctx.obj['debug']) | 68 | + ctx.obj['debug'], ctx.obj['force']) |
63 | - click.echo('deploying...') | 69 | + click.echo('tagging') |
64 | context.deploy() | 70 | context.deploy() |
65 | - click.echo('...done') | 71 | + click.echo('done') |
66 | 72 | ||
67 | 73 | ||
68 | @cli.command() | 74 | @cli.command() |
... | @@ -70,13 +76,27 @@ def tag(ctx): | ... | @@ -70,13 +76,27 @@ def tag(ctx): |
70 | def invoke(ctx): | 76 | def invoke(ctx): |
71 | """Invoke the command synchronously""" | 77 | """Invoke the command synchronously""" |
72 | context = Context(ctx.obj['config'], ctx.obj['environment'], | 78 | context = Context(ctx.obj['config'], ctx.obj['environment'], |
73 | - ctx.obj['debug']) | 79 | + ctx.obj['debug'], ctx.obj['force']) |
74 | - click.echo('invoking...') | 80 | + click.echo('invoking') |
75 | response = context.invoke() | 81 | response = context.invoke() |
76 | log_data = base64.b64decode(response['LogResult']) | 82 | log_data = base64.b64decode(response['LogResult']) |
77 | click.echo(log_data) | 83 | click.echo(log_data) |
78 | click.echo(response['Payload'].read()) | 84 | click.echo(response['Payload'].read()) |
79 | - click.echo('...done') | 85 | + click.echo('done') |
86 | + | ||
87 | + | ||
88 | +@cli.command() | ||
89 | +@click.pass_context | ||
90 | +def test(ctx): | ||
91 | + """Test the command synchronously""" | ||
92 | + context = Context(ctx.obj['config'], ctx.obj['environment'], | ||
93 | + ctx.obj['debug'], ctx.obj['force']) | ||
94 | + click.echo('testing') | ||
95 | + response = context.test() | ||
96 | + log_data = base64.b64decode(response['LogResult']) | ||
97 | + click.echo(log_data) | ||
98 | + click.echo(response['Payload'].read()) | ||
99 | + click.echo('done') | ||
80 | 100 | ||
81 | 101 | ||
82 | @cli.command() | 102 | @cli.command() |
... | @@ -84,11 +104,11 @@ def invoke(ctx): | ... | @@ -84,11 +104,11 @@ def invoke(ctx): |
84 | def dryrun(ctx): | 104 | def dryrun(ctx): |
85 | """Show you what would happen but don't actually do anything""" | 105 | """Show you what would happen but don't actually do anything""" |
86 | context = Context(ctx.obj['config'], ctx.obj['environment'], | 106 | context = Context(ctx.obj['config'], ctx.obj['environment'], |
87 | - ctx.obj['debug']) | 107 | + ctx.obj['debug'], ctx.obj['force']) |
88 | - click.echo('invoking dryrun...') | 108 | + click.echo('invoking dryrun') |
89 | response = context.dryrun() | 109 | response = context.dryrun() |
90 | click.echo(response) | 110 | click.echo(response) |
91 | - click.echo('...done') | 111 | + click.echo('done') |
92 | 112 | ||
93 | 113 | ||
94 | @cli.command() | 114 | @cli.command() |
... | @@ -96,11 +116,11 @@ def dryrun(ctx): | ... | @@ -96,11 +116,11 @@ def dryrun(ctx): |
96 | def invoke_async(ctx): | 116 | def invoke_async(ctx): |
97 | """Invoke the Lambda function asynchronously""" | 117 | """Invoke the Lambda function asynchronously""" |
98 | context = Context(ctx.obj['config'], ctx.obj['environment'], | 118 | context = Context(ctx.obj['config'], ctx.obj['environment'], |
99 | - ctx.obj['debug']) | 119 | + ctx.obj['debug'], ctx.obj['force']) |
100 | - click.echo('invoking async...') | 120 | + click.echo('invoking async') |
101 | response = context.invoke_async() | 121 | response = context.invoke_async() |
102 | click.echo(response) | 122 | click.echo(response) |
103 | - click.echo('...done') | 123 | + click.echo('done') |
104 | 124 | ||
105 | 125 | ||
106 | @cli.command() | 126 | @cli.command() |
... | @@ -108,12 +128,12 @@ def invoke_async(ctx): | ... | @@ -108,12 +128,12 @@ def invoke_async(ctx): |
108 | def tail(ctx): | 128 | def tail(ctx): |
109 | """Show the last 10 lines of the log file""" | 129 | """Show the last 10 lines of the log file""" |
110 | context = Context(ctx.obj['config'], ctx.obj['environment'], | 130 | context = Context(ctx.obj['config'], ctx.obj['environment'], |
111 | - ctx.obj['debug']) | 131 | + ctx.obj['debug'], ctx.obj['force']) |
112 | - click.echo('tailing logs...') | 132 | + click.echo('tailing logs') |
113 | for e in context.tail()[-10:]: | 133 | for e in context.tail()[-10:]: |
114 | ts = datetime.utcfromtimestamp(e['timestamp']//1000).isoformat() | 134 | ts = datetime.utcfromtimestamp(e['timestamp']//1000).isoformat() |
115 | click.echo("{}: {}".format(ts, e['message'])) | 135 | click.echo("{}: {}".format(ts, e['message'])) |
116 | - click.echo('...done') | 136 | + click.echo('done') |
117 | 137 | ||
118 | 138 | ||
119 | @cli.command() | 139 | @cli.command() |
... | @@ -159,10 +179,10 @@ def status(ctx): | ... | @@ -159,10 +179,10 @@ def status(ctx): |
159 | def delete(ctx): | 179 | def delete(ctx): |
160 | """Delete the Lambda function and related policies and roles""" | 180 | """Delete the Lambda function and related policies and roles""" |
161 | context = Context(ctx.obj['config'], ctx.obj['environment'], | 181 | context = Context(ctx.obj['config'], ctx.obj['environment'], |
162 | - ctx.obj['debug']) | 182 | + ctx.obj['debug'], ctx.obj['force']) |
163 | - click.echo('deleting...') | 183 | + click.echo('deleting') |
164 | context.delete() | 184 | context.delete() |
165 | - click.echo('...done') | 185 | + click.echo('done') |
166 | 186 | ||
167 | 187 | ||
168 | @cli.command() | 188 | @cli.command() |
... | @@ -170,10 +190,10 @@ def delete(ctx): | ... | @@ -170,10 +190,10 @@ def delete(ctx): |
170 | def add_event_sources(ctx): | 190 | def add_event_sources(ctx): |
171 | """Add any event sources specified in the config file""" | 191 | """Add any event sources specified in the config file""" |
172 | context = Context(ctx.obj['config'], ctx.obj['environment'], | 192 | context = Context(ctx.obj['config'], ctx.obj['environment'], |
173 | - ctx.obj['debug']) | 193 | + ctx.obj['debug'], ctx.obj['force']) |
174 | - click.echo('adding event sources...') | 194 | + click.echo('adding event sources') |
175 | context.add_event_sources() | 195 | context.add_event_sources() |
176 | - click.echo('...done') | 196 | + click.echo('done') |
177 | 197 | ||
178 | 198 | ||
179 | @cli.command() | 199 | @cli.command() |
... | @@ -181,10 +201,10 @@ def add_event_sources(ctx): | ... | @@ -181,10 +201,10 @@ def add_event_sources(ctx): |
181 | def update_event_sources(ctx): | 201 | def update_event_sources(ctx): |
182 | """Update event sources specified in the config file""" | 202 | """Update event sources specified in the config file""" |
183 | context = Context(ctx.obj['config'], ctx.obj['environment'], | 203 | context = Context(ctx.obj['config'], ctx.obj['environment'], |
184 | - ctx.obj['debug']) | 204 | + ctx.obj['debug'], ctx.obj['force']) |
185 | - click.echo('updating event sources...') | 205 | + click.echo('updating event sources') |
186 | context.update_event_sources() | 206 | context.update_event_sources() |
187 | - click.echo('...done') | 207 | + click.echo('done') |
188 | 208 | ||
189 | 209 | ||
190 | cli(obj={}) | 210 | cli(obj={}) | ... | ... |
-
Please register or login to post a comment