Best Python code snippet using localstack_python
template_deployer.py
Source:template_deployer.py  
...1157                "Replacement": "False",1158                "ChangeSetId": change_set_id,1159            },1160        }1161    def resource_config_differs(self, resource_new):1162        """Return whether the given resource properties differ from the existing config (for stack updates)."""1163        resource_id = resource_new["LogicalResourceId"]1164        resource_old = self.resources[resource_id]1165        props_old = resource_old["Properties"]1166        props_new = resource_new["Properties"]1167        ignored_keys = ["LogicalResourceId", "PhysicalResourceId"]1168        old_keys = set(props_old.keys()) - set(ignored_keys)1169        new_keys = set(props_new.keys()) - set(ignored_keys)1170        if old_keys != new_keys:1171            return True1172        for key in old_keys:1173            if props_old[key] != props_new[key]:1174                return True1175        old_status = self.stack.resource_states.get(resource_id) or {}1176        previous_state = (1177            old_status.get("PreviousResourceStatus") or old_status.get("ResourceStatus") or ""1178        )1179        if old_status and "DELETE" in previous_state:1180            return True1181    def merge_properties(self, resource_id, old_stack, new_stack):1182        old_resources = old_stack.template["Resources"]1183        new_resources = new_stack.template["Resources"]1184        new_resource = new_resources[resource_id]1185        old_resource = old_resources[resource_id] = old_resources.get(resource_id) or {}1186        for key, value in new_resource.items():1187            if key == "Properties":1188                continue1189            old_resource[key] = old_resource.get(key, value)1190        old_res_props = old_resource["Properties"] = old_resource.get("Properties", {})1191        for key, value in new_resource["Properties"].items():1192            old_res_props[key] = value1193        # overwrite original template entirely1194        old_stack.template_original["Resources"][resource_id] = new_stack.template_original[1195            "Resources"1196        ][resource_id]1197    def resolve_param(1198        self, logical_id: str, param_type: str, default_value: Optional[str] = None1199    ) -> Optional[str]:1200        if param_type == "AWS::SSM::Parameter::Value<String>":1201            ssm_client = aws_stack.connect_to_service("ssm")1202            param = ssm_client.get_parameter(Name=default_value)1203            return param["Parameter"]["Value"]1204        return None1205    def apply_parameter_changes(self, old_stack, new_stack) -> None:1206        parameters = {1207            p["ParameterKey"]: p1208            for p in old_stack.metadata["Parameters"]  # go through current parameter values1209        }1210        for logical_id, value in new_stack.template["Parameters"].items():1211            default = value.get("Default")1212            provided_param_value = parameters.get(logical_id)1213            param = {1214                "ParameterKey": logical_id,1215                "ParameterValue": provided_param_value if default is None else default,1216            }1217            if default is not None:1218                resolved_value = self.resolve_param(logical_id, value.get("Type"), default)1219                if resolved_value is not None:1220                    param["ResolvedValue"] = resolved_value1221            parameters[logical_id] = param1222        def _update_params(params_list: List[Dict]):1223            for param in params_list:1224                # make sure we preserve parameter values if UsePreviousValue=true1225                if not param.get("UsePreviousValue"):1226                    parameters.update({param["ParameterKey"]: param})1227        _update_params(new_stack.metadata["Parameters"])1228        for change_set in new_stack.change_sets:1229            _update_params(change_set.metadata["Parameters"])1230        # TODO: unclear/undocumented behavior in implicitly updating old_stack parameter here1231        # Note: Indeed it seems that parameters from Change Sets are applied to a stack1232        #   itself, and are preserved even after a change set has been deleted. However,1233        #   a proper implementation would distinguish between (1) Change Sets and (2) Change1234        #   Set Executions - the former are only a template for the changes to be applied,1235        #   whereas the latter actually perform changes (including parameter updates).1236        #   Also, (1) can be deleted, and (2) can only be rolled back (in case of errors).1237        #   Once we have the distinction between (1) and (2) in place, this logic (updating1238        #   the parameters of the stack itself) will become obsolete, then the parameter1239        #   values can be determined by replaying the values of the sequence of (immutable)1240        #   Change Set Executions.1241        old_stack.metadata["Parameters"] = [v for v in parameters.values() if v]1242    # TODO: fix circular import with cloudformation_api.py when importing Stack here1243    def construct_changes(1244        self,1245        existing_stack,1246        new_stack,1247        initialize=False,1248        change_set_id=None,1249        append_to_changeset=False,1250        filter_unchanged_resources=False,1251    ):1252        from localstack.services.cloudformation.provider import StackChangeSet1253        old_resources = existing_stack.template["Resources"]1254        new_resources = new_stack.template["Resources"]1255        deletes = [val for key, val in old_resources.items() if key not in new_resources]1256        adds = [val for key, val in new_resources.items() if initialize or key not in old_resources]1257        modifies = [val for key, val in new_resources.items() if key in old_resources]1258        changes = []1259        for action, items in (("Remove", deletes), ("Add", adds), ("Modify", modifies)):1260            for item in items:1261                item["Properties"] = item.get("Properties", {})1262                if (1263                    not filter_unchanged_resources1264                    or action != "Modify"1265                    or self.resource_config_differs(item)1266                ):1267                    change = self.get_change_config(action, item, change_set_id=change_set_id)1268                    changes.append(change)1269        # append changes to change set1270        if append_to_changeset and isinstance(new_stack, StackChangeSet):1271            new_stack.changes.extend(changes)1272        return changes1273    def apply_changes(1274        self,1275        existing_stack,1276        new_stack,1277        stack_name,1278        change_set_id=None,1279        initialize=False,1280        action=None,1281    ):1282        old_resources = existing_stack.template["Resources"]1283        new_resources = new_stack.template["Resources"]1284        action = action or "CREATE"1285        self.init_resource_status(old_resources, action="UPDATE")1286        # apply parameter changes to existing stack1287        self.apply_parameter_changes(existing_stack, new_stack)1288        # construct changes1289        changes = self.construct_changes(1290            existing_stack,1291            new_stack,1292            initialize=initialize,1293            change_set_id=change_set_id,1294        )1295        # check if we have actual changes in the stack, and prepare properties1296        contains_changes = False1297        for change in changes:1298            res_action = change["ResourceChange"]["Action"]1299            resource = new_resources.get(change["ResourceChange"]["LogicalResourceId"])1300            if res_action != "Modify" or self.resource_config_differs(resource):1301                contains_changes = True1302            if res_action in ["Modify", "Add"]:1303                self.merge_properties(resource["LogicalResourceId"], existing_stack, new_stack)1304        if not contains_changes:1305            raise NoStackUpdates("No updates are to be performed.")1306        # merge stack outputs and conditions1307        existing_stack.outputs.update(new_stack.outputs)1308        existing_stack.conditions.update(new_stack.conditions)1309        # start deployment loop1310        return self.apply_changes_in_loop(1311            changes, existing_stack, stack_name, action=action, new_stack=new_stack1312        )1313    def apply_changes_in_loop(self, changes, stack, stack_name, action=None, new_stack=None):1314        from localstack.services.cloudformation.provider import StackChangeSet...Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
