Skip to content

Commit 65d4eed

Browse files
committed
Moving handle_hooks to try and make #708 easier to review
1 parent 97d5206 commit 65d4eed

File tree

6 files changed

+83
-76
lines changed

6 files changed

+83
-76
lines changed

stacker/actions/build.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from .base import STACK_POLL_TIME
88

99
from ..providers.base import Template
10-
from .. import util
10+
from stacker.hooks import utils
1111
from ..exceptions import (
1212
MissingParameterException,
1313
StackDidNotChange,
@@ -196,7 +196,7 @@ def handle_hooks(stage, hooks, provider, context, dump, outline):
196196
197197
"""
198198
if not outline and not dump and hooks:
199-
util.handle_hooks(
199+
utils.handle_hooks(
200200
stage=stage,
201201
hooks=hooks,
202202
provider=provider,

stacker/actions/destroy.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from .base import BaseAction, plan, build_walker
77
from .base import STACK_POLL_TIME
88
from ..exceptions import StackDoesNotExist
9-
from .. import util
9+
from stacker.hooks.utils import handle_hooks
1010
from ..status import (
1111
CompleteStatus,
1212
SubmittedStatus,
@@ -82,7 +82,7 @@ def pre_run(self, outline=False, *args, **kwargs):
8282
"""Any steps that need to be taken prior to running the action."""
8383
pre_destroy = self.context.config.pre_destroy
8484
if not outline and pre_destroy:
85-
util.handle_hooks(
85+
handle_hooks(
8686
stage="pre_destroy",
8787
hooks=pre_destroy,
8888
provider=self.provider,
@@ -106,7 +106,7 @@ def post_run(self, outline=False, *args, **kwargs):
106106
"""Any steps that need to be taken after running the action."""
107107
post_destroy = self.context.config.post_destroy
108108
if not outline and post_destroy:
109-
util.handle_hooks(
109+
handle_hooks(
110110
stage="post_destroy",
111111
hooks=post_destroy,
112112
provider=self.provider,

stacker/hooks/utils.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,82 @@
22
from __future__ import division
33
from __future__ import absolute_import
44
import os
5+
import sys
6+
import collections
7+
import logging
8+
9+
from stacker.util import load_object_from_string
10+
11+
logger = logging.getLogger(__name__)
512

613

714
def full_path(path):
815
return os.path.abspath(os.path.expanduser(path))
16+
17+
18+
def handle_hooks(stage, hooks, provider, context):
19+
""" Used to handle pre/post_build hooks.
20+
21+
These are pieces of code that we want to run before/after the builder
22+
builds the stacks.
23+
24+
Args:
25+
stage (string): The current stage (pre_run, post_run, etc).
26+
hooks (list): A list of :class:`stacker.config.Hook` containing the
27+
hooks to execute.
28+
provider (:class:`stacker.provider.base.BaseProvider`): The provider
29+
the current stack is using.
30+
context (:class:`stacker.context.Context`): The current stacker
31+
context.
32+
"""
33+
if not hooks:
34+
logger.debug("No %s hooks defined.", stage)
35+
return
36+
37+
hook_paths = []
38+
for i, h in enumerate(hooks):
39+
try:
40+
hook_paths.append(h.path)
41+
except KeyError:
42+
raise ValueError("%s hook #%d missing path." % (stage, i))
43+
44+
logger.info("Executing %s hooks: %s", stage, ", ".join(hook_paths))
45+
for hook in hooks:
46+
data_key = hook.data_key
47+
required = hook.required
48+
kwargs = hook.args or {}
49+
enabled = hook.enabled
50+
if not enabled:
51+
logger.debug("hook with method %s is disabled, skipping",
52+
hook.path)
53+
continue
54+
try:
55+
method = load_object_from_string(hook.path)
56+
except (AttributeError, ImportError):
57+
logger.exception("Unable to load method at %s:", hook.path)
58+
if required:
59+
raise
60+
continue
61+
try:
62+
result = method(context=context, provider=provider, **kwargs)
63+
except Exception:
64+
logger.exception("Method %s threw an exception:", hook.path)
65+
if required:
66+
raise
67+
continue
68+
if not result:
69+
if required:
70+
logger.error("Required hook %s failed. Return value: %s",
71+
hook.path, result)
72+
sys.exit(1)
73+
logger.warning("Non-required hook %s failed. Return value: %s",
74+
hook.path, result)
75+
else:
76+
if isinstance(result, collections.Mapping):
77+
if data_key:
78+
logger.debug("Adding result for hook %s to context in "
79+
"data_key %s.", hook.path, data_key)
80+
context.set_hook_data(data_key, result)
81+
else:
82+
logger.debug("Hook %s returned result data, but no data "
83+
"key set, so ignoring.", hook.path)

stacker/tests/test_context.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from stacker.context import Context, get_fqn
77
from stacker.config import load, Config
8-
from stacker.util import handle_hooks
8+
from stacker.hooks.utils import handle_hooks
99

1010

1111
class TestContext(unittest.TestCase):

stacker/tests/test_util.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
cf_safe_name,
2020
load_object_from_string,
2121
camel_to_snake,
22-
handle_hooks,
2322
merge_map,
2423
yaml_to_ordered_dict,
2524
get_client_region,
@@ -33,6 +32,8 @@
3332
SourceProcessor
3433
)
3534

35+
from stacker.hooks.utils import handle_hooks
36+
3637
from .factories import (
3738
mock_context,
3839
mock_provider,

stacker/util.py

Lines changed: 0 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
import tempfile
1717
import zipfile
1818

19-
import collections
2019
from collections import OrderedDict
2120

2221
import botocore.client
@@ -337,74 +336,6 @@ def cf_safe_name(name):
337336
return "".join([uppercase_first_letter(part) for part in parts])
338337

339338

340-
def handle_hooks(stage, hooks, provider, context):
341-
""" Used to handle pre/post_build hooks.
342-
343-
These are pieces of code that we want to run before/after the builder
344-
builds the stacks.
345-
346-
Args:
347-
stage (string): The current stage (pre_run, post_run, etc).
348-
hooks (list): A list of :class:`stacker.config.Hook` containing the
349-
hooks to execute.
350-
provider (:class:`stacker.provider.base.BaseProvider`): The provider
351-
the current stack is using.
352-
context (:class:`stacker.context.Context`): The current stacker
353-
context.
354-
"""
355-
if not hooks:
356-
logger.debug("No %s hooks defined.", stage)
357-
return
358-
359-
hook_paths = []
360-
for i, h in enumerate(hooks):
361-
try:
362-
hook_paths.append(h.path)
363-
except KeyError:
364-
raise ValueError("%s hook #%d missing path." % (stage, i))
365-
366-
logger.info("Executing %s hooks: %s", stage, ", ".join(hook_paths))
367-
for hook in hooks:
368-
data_key = hook.data_key
369-
required = hook.required
370-
kwargs = hook.args or {}
371-
enabled = hook.enabled
372-
if not enabled:
373-
logger.debug("hook with method %s is disabled, skipping",
374-
hook.path)
375-
continue
376-
try:
377-
method = load_object_from_string(hook.path)
378-
except (AttributeError, ImportError):
379-
logger.exception("Unable to load method at %s:", hook.path)
380-
if required:
381-
raise
382-
continue
383-
try:
384-
result = method(context=context, provider=provider, **kwargs)
385-
except Exception:
386-
logger.exception("Method %s threw an exception:", hook.path)
387-
if required:
388-
raise
389-
continue
390-
if not result:
391-
if required:
392-
logger.error("Required hook %s failed. Return value: %s",
393-
hook.path, result)
394-
sys.exit(1)
395-
logger.warning("Non-required hook %s failed. Return value: %s",
396-
hook.path, result)
397-
else:
398-
if isinstance(result, collections.Mapping):
399-
if data_key:
400-
logger.debug("Adding result for hook %s to context in "
401-
"data_key %s.", hook.path, data_key)
402-
context.set_hook_data(data_key, result)
403-
else:
404-
logger.debug("Hook %s returned result data, but no data "
405-
"key set, so ignoring.", hook.path)
406-
407-
408339
def get_config_directory():
409340
"""Return the directory the config file is located in.
410341

0 commit comments

Comments
 (0)