Add a safety check on stack ARN when building
Support for specifying a stack_name separate from name was added in https://github.com/remind101/stacker/pull/551 to support stacks with the same name, but in different regions/accounts, however, this introduces the possibility for two nodes in the graph to operate on the same stack.
I think it'd be wise to add an extra layer of safety so that stacker will error out if two nodes in the graph operate on the same stack ARN, as this would almost always be programmer error (e.g. copy/paste but forget to change stack_name).
Yup, agreed. We could also try to solve this during config validation.
We already prevent two stacks from being named the same, we could also prevent two stacks from having the same stack_name where if not defined, we assume stack_name = name and do the validation like normal.
We already prevent two stacks from being named the same, we could also prevent two stacks from having the same stack_name where if not defined, we assume stack_name = name and do the validation like normal.
That won't actually work, since it's entirely valid to have multiple stacks in a stacker config using the same stack_name (e.g. they could be stacks in different regions, or stacks in different accounts, etc). Trying to validate this in the config would be prone to a lot of issues.
What shouldn't be valid, is multiple nodes in the graph operating on the same stack ARN. I think the only way to reasonably do that in stacker right now is at runtime, by keeping a list of visited stack ARNs and error'ing out if a stack ARN has been visited.
I wonder if we made a hash of stack_name (or name if missing) + region + profile and used that to validate uniqueness.
I think I would prefer this because we can validate the graph without having to go on the network to get stack ARNs.
For example, in this class https://github.com/remind101/stacker/blob/master/stacker/stack.py#L46 :
class Stack(object):
def __eq__(self, other):
"""Determine if equal by stack id"""
return self.stack_id == other.stack_id
def __ne__(self, other):
"""Determine if not equal by stack id"""
return (not self.__eq__(other))
def __hash__(self):
return hash(self.stack_id)
def stack_id(self):
return "{}-{}-{}".format(self.profile, self.region, self.fqn)
Then we can simply build up a list of all stacks in the graph and do something like this:
if len(stacks) != len(set(stacks)):
raise Exception("invalid stack config")