Toolset to render and manage AWS CloudFormation ( https://pypi.org/project/cloudbender )
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
132 lines
4.0 KiB
132 lines
4.0 KiB
import logging |
|
import pprint |
|
|
|
from .utils import dict_merge |
|
from .jinja import read_config_file |
|
from .stack import Stack |
|
|
|
logger = logging.getLogger(__name__) |
|
|
|
|
|
class StackGroup(object): |
|
def __init__(self, path, ctx): |
|
self.name = None |
|
self.ctx = ctx |
|
self.path = path |
|
self.rel_path = path.relative_to(ctx["config_path"]) |
|
self.config = {} |
|
self.sgs = [] |
|
self.stacks = [] |
|
|
|
if self.rel_path == ".": |
|
self.rel_path = "" |
|
|
|
def dump_config(self): |
|
for sg in self.sgs: |
|
sg.dump_config() |
|
|
|
logger.debug( |
|
"StackGroup {}: {}".format(self.rel_path, pprint.pformat(self.config)) |
|
) |
|
|
|
for s in self.stacks: |
|
s.dump_config() |
|
|
|
def read_config(self, parent_config={}): |
|
if not self.path.is_dir(): |
|
return None |
|
|
|
# First read config.yaml if present |
|
_config = read_config_file( |
|
self.path.joinpath("config.yaml"), parent_config.get("variables", {}) |
|
) |
|
|
|
# Stack Group name if not explicit via config is derived from subfolder, or in case of root object the parent folder |
|
if "stackgroupname" in _config: |
|
self.name = _config["stackgroupname"] |
|
elif not self.name: |
|
self.name = self.path.stem |
|
|
|
# Merge config with parent config |
|
self.config = dict_merge(parent_config, _config) |
|
stackname_prefix = self.config.get("stacknameprefix", "") |
|
|
|
logger.debug("StackGroup {} added.".format(self.name)) |
|
|
|
# Add stacks |
|
stacks = [s for s in self.path.glob("*.yaml") if not s.name == "config.yaml"] |
|
for stack_path in stacks: |
|
stackname = stack_path.name.split(".")[0] |
|
template = stackname |
|
if stackname_prefix: |
|
stackname = stackname_prefix + stackname |
|
|
|
new_stack = Stack( |
|
name=stackname, |
|
template=template, |
|
path=stack_path, |
|
rel_path=str(self.rel_path), |
|
ctx=self.ctx, |
|
) |
|
new_stack.read_config(self.config) |
|
self.stacks.append(new_stack) |
|
|
|
# Create StackGroups recursively |
|
for sub_group in [s for s in self.path.iterdir() if s.is_dir()]: |
|
sg = StackGroup(sub_group, self.ctx) |
|
sg.read_config(self.config) |
|
|
|
self.sgs.append(sg) |
|
|
|
def get_stacks(self, name=None, recursive=True, match_by="name"): |
|
"""Returns [stack] matching stack_name or [all]""" |
|
stacks = [] |
|
if name: |
|
logger.debug("Looking for stack {} in group {}".format(name, self.name)) |
|
|
|
for s in self.stacks: |
|
if name: |
|
if match_by == "name" and s.stackname != name: |
|
continue |
|
|
|
if match_by == "path" and not s.path.match(name): |
|
continue |
|
|
|
if self.rel_path: |
|
logger.debug( |
|
"Found stack {} in group {}".format(s.stackname, self.rel_path) |
|
) |
|
else: |
|
logger.debug("Found stack {}".format(s.stackname)) |
|
stacks.append(s) |
|
|
|
if recursive: |
|
for sg in self.sgs: |
|
s = sg.get_stacks(name, recursive, match_by) |
|
if s: |
|
stacks = stacks + s |
|
|
|
return stacks |
|
|
|
def get_stackgroup(self, name=None, recursive=True, match_by="name"): |
|
"""Returns stack group matching stackgroup_name or all if None""" |
|
if ( |
|
not name |
|
or (self.name == name and match_by == "name") |
|
or (self.path.match(name) and match_by == "path") |
|
): |
|
logger.debug("Found stack_group {}".format(self.name)) |
|
return self |
|
|
|
if name and self.name != "config": |
|
logger.debug( |
|
"Looking for stack_group {} in group {}".format(name, self.name) |
|
) |
|
|
|
if recursive: |
|
for sg in self.sgs: |
|
s = sg.get_stackgroup(name, recursive, match_by) |
|
if s: |
|
return s |
|
|
|
return None
|
|
|