in critter/stack.py [0:0]
def process_outputs(self):
# Save stack outputs in an easy access dict
self.stack_outputs = self.OUTPUTS_DEFAULTS.copy()
for o in self.stack.outputs:
self.stack_outputs[o["OutputKey"]] = o["OutputValue"]
# Sleep for DelayAfterDeploy immediately after loading stack outputs
self.delay_after_deploy = int(self.stack_outputs[self.OUTPUT_KEYS["DELAY_AFTER_DEPLOY"]])
if self.delay_after_deploy and self.deploy_action_performed:
logger.info(f"Sleeping {self.delay_after_deploy} seconds")
time.sleep(self.delay_after_deploy)
self.config_rule_name = self.stack_outputs[self.OUTPUT_KEYS["CONFIG_RULE_NAME"]].strip()
if self.config_rule_name == self.OUTPUTS_DEFAULTS[self.OUTPUT_KEYS["CONFIG_RULE_NAME"]]:
raise Exception(
f"Error - Missing required output '{self.OUTPUT_KEYS['CONFIG_RULE_NAME']}' "
f"on CloudFormation stack '{self.stack_name}'"
)
try:
self.config_rule = self.config.describe_config_rules(ConfigRuleNames=[self.config_rule_name])[
"ConfigRules"
][0]
except botocore.exceptions.ClientError as e:
if e.response["Error"]["Code"] == "NoSuchConfigRuleException":
raise Exception(f"Error - Config rule '{self.config_rule_name}' not found!")
else:
raise e
self.resources = {}
resource_ids_output_keys = self.EXPECTED_COMPLIANCE_TYPE_LOOKUP.keys()
for output_key in resource_ids_output_keys:
resource_ids_csv = self.stack_outputs[output_key]
if not resource_ids_csv:
# Empty string means cfn stack did not declare the output
continue
for r_id in [i.strip() for i in resource_ids_csv.split(",")]:
expected_compliance_type = self.EXPECTED_COMPLIANCE_TYPE_LOOKUP[output_key]
if expected_compliance_type == "NOT_APPLICABLE":
logger.warning(
"Warning - Testing for NOT_APPLICABLE compliance type is experimental and "
"may yield unexpected results."
)
if r_id in self.resources.keys():
raise Exception(f"Error - Resource id '{r_id}' declared in multiple outputs")
self.resources[r_id] = {
"expected_compliance_type": expected_compliance_type,
"evaluation_result": {},
}
if not self.resources:
raise Exception(
"Error - Did not find any resource ids outputs. Specify one or more of the following "
f"CloudFormation stack outputs: {list(resource_ids_output_keys)}"
)
# TODO: load resource types from test stack output if not provided in rule scope attribute
self.resource_types = self.config_rule["Scope"]["ComplianceResourceTypes"]
self.skip_wait_for_resource_recording = (
self.stack_outputs[self.OUTPUT_KEYS["SKIP_WAIT_FOR_RESOURCE_RECORDING"]].lower() == "true"
)