Best Python code snippet using localstack_python
template_deployer.py
Source:template_deployer.py  
...56}57class NoStackUpdates(Exception):58    """Exception indicating that no actions are to be performed in a stack update (which is not allowed)"""59    pass60def lambda_get_params():61    return lambda params, **kwargs: params62# maps resource types to functions and parameters for creation63RESOURCE_TO_FUNCTION = {}64# ----------------65# UTILITY METHODS66# ----------------67def get_secret_arn(secret_name, account_id=None):68    # TODO: create logic to create static without lookup table!69    from localstack.services.secretsmanager import secretsmanager_starter70    storage = secretsmanager_starter.SECRET_ARN_STORAGE71    key = "%s_%s" % (aws_stack.get_region(), secret_name)72    return storage.get(key) or storage.get(secret_name)73def find_stack(stack_name):74    from localstack.services.cloudformation.cloudformation_api import find_stack as api_find_stack75    return api_find_stack(stack_name)76# ---------------------77# CF TEMPLATE HANDLING78# ---------------------79def get_deployment_config(res_type):80    result = RESOURCE_TO_FUNCTION.get(res_type)81    if result is not None:82        return result83    canonical_type = canonical_resource_type(res_type)84    resource_class = RESOURCE_MODELS.get(canonical_type)85    if resource_class:86        return resource_class.get_deploy_templates()87def get_resource_type(resource):88    res_type = resource.get("ResourceType") or resource.get("Type") or ""89    parts = res_type.split("::", 1)90    if len(parts) == 1:91        return parts[0]92    return parts[1]93def get_service_name(resource):94    res_type = resource.get("Type", resource.get("ResourceType", ""))95    parts = res_type.split("::")96    if len(parts) == 1:97        return None98    if res_type.endswith("Cognito::UserPool"):99        return "cognito-idp"100    if parts[-2] == "Cognito":101        return "cognito-idp"102    if parts[-2] == "Elasticsearch":103        return "es"104    if parts[-2] == "KinesisFirehose":105        return "firehose"106    if parts[-2] == "ResourceGroups":107        return "resource-groups"108    if parts[-2] == "CertificateManager":109        return "acm"110    return parts[1].lower()111def get_resource_name(resource):112    properties = resource.get("Properties") or {}113    name = properties.get("Name")114    if name:115        return name116    # try to extract name via resource class117    res_type = canonical_resource_type(get_resource_type(resource))118    model_class = RESOURCE_MODELS.get(res_type)119    if model_class:120        instance = model_class(resource)121        name = instance.get_resource_name()122    if not name:123        LOG.debug('Unable to extract name for resource type "%s"' % res_type)124    return name125def get_client(resource, func_config):126    resource_type = get_resource_type(resource)127    service = get_service_name(resource)128    resource_config = get_deployment_config(resource_type)129    if resource_config is None:130        raise Exception(131            "CloudFormation deployment for resource type %s not yet implemented" % resource_type132        )133    try:134        if func_config.get("boto_client") == "resource":135            return aws_stack.connect_to_resource(service)136        return aws_stack.connect_to_service(service)137    except Exception as e:138        LOG.warning('Unable to get client for "%s" API, skipping deployment: %s' % (service, e))139        return None140def describe_stack_resource(stack_name, logical_resource_id):141    client = aws_stack.connect_to_service("cloudformation")142    try:143        result = client.describe_stack_resource(144            StackName=stack_name, LogicalResourceId=logical_resource_id145        )146        return result["StackResourceDetail"]147    except Exception as e:148        LOG.warning(149            'Unable to get details for resource "%s" in CloudFormation stack "%s": %s'150            % (logical_resource_id, stack_name, e)151        )152def retrieve_resource_details(resource_id, resource_status, resources, stack_name):153    resource = resources.get(resource_id)154    resource_id = resource_status.get("PhysicalResourceId") or resource_id155    if not resource:156        resource = {}157    resource_type = get_resource_type(resource)158    resource_props = resource.get("Properties")159    if resource_props is None:160        raise Exception(161            'Unable to find properties for resource "%s": %s %s'162            % (resource_id, resource, resources)163        )164    try:165        # convert resource props to resource entity166        instance = get_resource_model_instance(resource_id, resources)167        if instance:168            state = instance.fetch_and_update_state(stack_name=stack_name, resources=resources)169            return state170        # special case for stack parameters171        if resource_type == "Parameter":172            return resource_props173        # fallback: try accessing stack.moto_resource_statuses174        stack = find_stack(stack_name)175        moto_resource = stack.moto_resource_statuses.get(resource_id)176        if moto_resource:177            return moto_resource178        # if is_deployable_resource(resource):179        LOG.warning(180            "Unexpected resource type %s when resolving references of resource %s: %s"181            % (resource_type, resource_id, resource)182        )183    except DependencyNotYetSatisfied:184        return185    except Exception as e:186        check_not_found_exception(e, resource_type, resource, resource_status)187    return None188def check_not_found_exception(e, resource_type, resource, resource_status=None):189    # we expect this to be a "not found" exception190    markers = [191        "NoSuchBucket",192        "ResourceNotFound",193        "NoSuchEntity",194        "NotFoundException",195        "404",196        "not found",197        "not exist",198    ]199    if not list(filter(lambda marker, e=e: marker in str(e), markers)):200        LOG.warning(201            "Unexpected error retrieving details for resource type %s: Exception: %s - %s - status: %s"202            % (resource_type, e, resource, resource_status)203        )204        return False205    return True206def extract_resource_attribute(207    resource_type,208    resource_state,209    attribute,210    resource_id=None,211    resource=None,212    resources=None,213    stack_name=None,214):215    LOG.debug("Extract resource attribute: %s %s" % (resource_type, attribute))216    is_ref_attribute = attribute in ["PhysicalResourceId", "Ref"]217    is_ref_attr_or_arn = is_ref_attribute or attribute == "Arn"218    resource = resource or {}219    if not resource and resources:220        resource = resources[resource_id]221    if not resource_state:222        resource_state = retrieve_resource_details(resource_id, {}, resources, stack_name)223        if not resource_state:224            raise DependencyNotYetSatisfied(225                resource_ids=resource_id,226                message='Unable to fetch details for resource "%s" (attribute "%s")'227                % (resource_id, attribute),228            )229    if isinstance(resource_state, MotoCloudFormationModel):230        if is_ref_attribute:231            res_phys_id = getattr(resource_state, "physical_resource_id", None)232            get_res_phys_id = getattr(resource_state, "get_physical_resource_id", None)233            if not res_phys_id and get_res_phys_id:234                res_phys_id = get_res_phys_id(attribute)235            if res_phys_id:236                return res_phys_id237        if hasattr(resource_state, "get_cfn_attribute"):238            try:239                return resource_state.get_cfn_attribute(attribute)240            except Exception:241                pass242        raise Exception(243            'Unable to extract attribute "%s" from "%s" model class %s'244            % (attribute, resource_type, type(resource_state))245        )246    # extract resource specific attributes247    # TODO: remove the code below - move into resource model classes!248    resource_props = resource.get("Properties", {})249    if resource_type == "Parameter":250        result = None251        param_value = resource_props.get(252            "Value",253            resource.get("Value", resource_props.get("Properties", {}).get("Value")),254        )255        if is_ref_attr_or_arn:256            result = param_value257        elif isinstance(param_value, dict):258            result = param_value.get(attribute)259        if result is not None:260            return result261        return ""262    elif resource_type == "Lambda::Function":263        func_configs = resource_state.get("Configuration") or {}264        if is_ref_attr_or_arn:265            func_arn = func_configs.get("FunctionArn")266            if func_arn:267                return resolve_refs_recursively(stack_name, func_arn, resources)268            func_name = resolve_refs_recursively(269                stack_name, func_configs.get("FunctionName"), resources270            )271            return aws_stack.lambda_function_arn(func_name)272        else:273            return func_configs.get(attribute)274    elif resource_type == "Lambda::Version":275        if resource_state.get("Version"):276            return "%s:%s" % (277                resource_state.get("FunctionArn"),278                resource_state.get("Version").split(":")[-1],279            )280    elif resource_type == "DynamoDB::Table":281        actual_attribute = "LatestStreamArn" if attribute == "StreamArn" else attribute282        value = resource_state.get("Table", {}).get(actual_attribute)283        if value:284            return value285    elif resource_type == "ApiGateway::RestApi":286        if is_ref_attribute:287            result = resource_state.get("id")288            if result:289                return result290        if attribute == "RootResourceId":291            api_id = resource_state["id"]292            resources = aws_stack.connect_to_service("apigateway").get_resources(restApiId=api_id)[293                "items"294            ]295            for res in resources:296                if res["path"] == "/" and not res.get("parentId"):297                    return res["id"]298    elif resource_type == "ApiGateway::Resource":299        if is_ref_attribute:300            return resource_state.get("id")301    elif resource_type == "ApiGateway::Deployment":302        if is_ref_attribute:303            return resource_state.get("id")304    elif resource_type == "S3::Bucket":305        if attribute == "WebsiteURL":306            bucket_name = resource_props.get("BucketName")307            return f"http://{bucket_name}.{S3_STATIC_WEBSITE_HOSTNAME}"308        if is_ref_attr_or_arn:309            bucket_name = resource_props.get("BucketName")310            bucket_name = resolve_refs_recursively(stack_name, bucket_name, resources)311            if attribute == "Arn":312                return aws_stack.s3_bucket_arn(bucket_name)313            return bucket_name314    elif resource_type == "Elasticsearch::Domain":315        if attribute == "DomainEndpoint":316            domain_status = resource_state.get("DomainStatus", {})317            result = domain_status.get("Endpoint")318            if result:319                return result320        if attribute in ["Arn", "DomainArn"]:321            domain_name = resource_props.get("DomainName") or resource_state.get("DomainName")322            return aws_stack.es_domain_arn(domain_name)323    elif resource_type == "StepFunctions::StateMachine":324        if is_ref_attr_or_arn:325            return resource_state["stateMachineArn"]326    elif resource_type == "SNS::Topic":327        if is_ref_attribute and resource_state.get("TopicArn"):328            topic_arn = resource_state.get("TopicArn")329            return resolve_refs_recursively(stack_name, topic_arn, resources)330    elif resource_type == "SQS::Queue":331        if is_ref_attr_or_arn:332            if attribute == "Arn" and resource_state.get("QueueArn"):333                return resolve_refs_recursively(334                    stack_name, resource_state.get("QueueArn"), resources335                )336            return aws_stack.get_sqs_queue_url(resource_props.get("QueueName"))337    attribute_lower = common.first_char_to_lower(attribute)338    result = resource_state.get(attribute) or resource_state.get(attribute_lower)339    if result is None and isinstance(resource, dict):340        result = resource_props.get(attribute) or resource_props.get(attribute_lower)341        if result is None:342            result = get_attr_from_model_instance(343                resource,344                attribute,345                resource_type=resource_type,346                resource_id=resource_id,347            )348    if is_ref_attribute:349        for attr in ["Id", "PhysicalResourceId", "Ref"]:350            if result is None:351                for obj in [resource_state, resource]:352                    result = result or obj.get(attr)353    return result354def canonical_resource_type(resource_type):355    if "::" in resource_type and not resource_type.startswith("AWS::"):356        resource_type = "AWS::%s" % resource_type357    return resource_type358def get_attr_from_model_instance(resource, attribute, resource_type, resource_id=None):359    resource_type = canonical_resource_type(resource_type)360    model_class = RESOURCE_MODELS.get(resource_type)361    if not model_class:362        if resource_type not in ["AWS::Parameter", "Parameter"]:363            LOG.debug('Unable to find model class for resource type "%s"' % resource_type)364        return365    try:366        inst = model_class(resource_name=resource_id, resource_json=resource)367        return inst.get_cfn_attribute(attribute)368    except Exception:369        pass370def resolve_ref(stack_name, ref, resources, attribute):371    if ref == "AWS::Region":372        return aws_stack.get_region()373    if ref == "AWS::Partition":374        return "aws"375    if ref == "AWS::StackName":376        return stack_name377    if ref == "AWS::StackId":378        # TODO return proper stack id!379        return stack_name380    if ref == "AWS::AccountId":381        return TEST_AWS_ACCOUNT_ID382    if ref == "AWS::NoValue":383        return PLACEHOLDER_AWS_NO_VALUE384    if ref == "AWS::NotificationARNs":385        # TODO!386        return {}387    if ref == "AWS::URLSuffix":388        return AWS_URL_SUFFIX389    is_ref_attribute = attribute in ["Ref", "PhysicalResourceId", "Arn"]390    if is_ref_attribute:391        # extract the Properties here, as we only want to recurse over the resource props...392        resource_props = resources.get(ref, {}).get("Properties")393        resolve_refs_recursively(stack_name, resource_props, resources)394        return determine_resource_physical_id(395            resource_id=ref,396            resources=resources,397            attribute=attribute,398            stack_name=stack_name,399        )400    if resources.get(ref):401        if isinstance(resources[ref].get(attribute), (str, int, float, bool, dict)):402            return resources[ref][attribute]403    # fetch resource details404    resource_new = retrieve_resource_details(ref, {}, resources, stack_name)405    if not resource_new:406        raise DependencyNotYetSatisfied(407            resource_ids=ref,408            message='Unable to fetch details for resource "%s" (resolving attribute "%s")'409            % (ref, attribute),410        )411    resource = resources.get(ref)412    resource_type = get_resource_type(resource)413    result = extract_resource_attribute(414        resource_type,415        resource_new,416        attribute,417        resource_id=ref,418        resource=resource,419        resources=resources,420        stack_name=stack_name,421    )422    if result is None:423        LOG.warning(424            'Unable to extract reference attribute "%s" from resource: %s %s'425            % (attribute, resource_new, resource)426        )427    return result428# Using a @prevent_stack_overflow decorator here to avoid infinite recursion429# in case we load stack exports that have circular dependencies (see issue 3438)430# TODO: Potentially think about a better approach in the future431@prevent_stack_overflow(match_parameters=True)432def resolve_refs_recursively(stack_name, value, resources):433    if isinstance(value, dict):434        keys_list = list(value.keys())435        stripped_fn_lower = keys_list[0].lower().split("::")[-1] if len(keys_list) == 1 else None436        # process special operators437        if keys_list == ["Ref"]:438            ref = resolve_ref(stack_name, value["Ref"], resources, attribute="Ref")439            if ref is None:440                msg = 'Unable to resolve Ref for resource "%s" (yet)' % value["Ref"]441                LOG.debug("%s - %s" % (msg, resources.get(value["Ref"]) or set(resources.keys())))442                raise DependencyNotYetSatisfied(resource_ids=value["Ref"], message=msg)443            ref = resolve_refs_recursively(stack_name, ref, resources)444            return ref445        if stripped_fn_lower == "getatt":446            attr_ref = value[keys_list[0]]447            attr_ref = attr_ref.split(".") if isinstance(attr_ref, str) else attr_ref448            return resolve_ref(stack_name, attr_ref[0], resources, attribute=attr_ref[1])449        if stripped_fn_lower == "join":450            join_values = value[keys_list[0]][1]451            join_values = [resolve_refs_recursively(stack_name, v, resources) for v in join_values]452            none_values = [v for v in join_values if v is None]453            if none_values:454                raise Exception(455                    "Cannot resolve CF fn::Join %s due to null values: %s" % (value, join_values)456                )457            return value[keys_list[0]][0].join([str(v) for v in join_values])458        if stripped_fn_lower == "sub":459            item_to_sub = value[keys_list[0]]460            attr_refs = dict([(r, {"Ref": r}) for r in STATIC_REFS])461            if not isinstance(item_to_sub, list):462                item_to_sub = [item_to_sub, {}]463            result = item_to_sub[0]464            item_to_sub[1].update(attr_refs)465            for key, val in item_to_sub[1].items():466                val = resolve_refs_recursively(stack_name, val, resources)467                result = result.replace("${%s}" % key, val)468            # resolve placeholders469            result = resolve_placeholders_in_string(470                result, stack_name=stack_name, resources=resources471            )472            return result473        if stripped_fn_lower == "findinmap":474            attr = resolve_refs_recursively(stack_name, value[keys_list[0]][1], resources)475            result = resolve_ref(stack_name, value[keys_list[0]][0], resources, attribute=attr)476            if not result:477                raise Exception(478                    "Cannot resolve fn::FindInMap: %s %s"479                    % (value[keys_list[0]], list(resources.keys()))480                )481            key = value[keys_list[0]][2]482            if not isinstance(key, str):483                key = resolve_refs_recursively(stack_name, key, resources)484            return result.get(key)485        if stripped_fn_lower == "importvalue":486            import_value_key = resolve_refs_recursively(stack_name, value[keys_list[0]], resources)487            stack = find_stack(stack_name)488            stack_export = stack.exports_map.get(import_value_key) or {}489            if not stack_export.get("Value"):490                LOG.info(491                    'Unable to find export "%s" in stack "%s", existing export names: %s'492                    % (import_value_key, stack_name, list(stack.exports_map.keys()))493                )494                return None495            return stack_export["Value"]496        if stripped_fn_lower == "if":497            condition, option1, option2 = value[keys_list[0]]498            condition = evaluate_condition(stack_name, condition, resources)499            return resolve_refs_recursively(500                stack_name, option1 if condition else option2, resources501            )502        if stripped_fn_lower == "condition":503            result = evaluate_condition(stack_name, value[keys_list[0]], resources)504            return result505        if stripped_fn_lower == "not":506            condition = value[keys_list[0]][0]507            condition = resolve_refs_recursively(stack_name, condition, resources)508            return not condition509        if stripped_fn_lower in ["and", "or"]:510            conditions = value[keys_list[0]]511            results = [resolve_refs_recursively(stack_name, cond, resources) for cond in conditions]512            result = all(results) if stripped_fn_lower == "and" else any(results)513            return result514        if stripped_fn_lower == "equals":515            operand1, operand2 = value[keys_list[0]]516            operand1 = resolve_refs_recursively(stack_name, operand1, resources)517            operand2 = resolve_refs_recursively(stack_name, operand2, resources)518            return str(operand1) == str(operand2)519        if stripped_fn_lower == "select":520            index, values = value[keys_list[0]]521            index = resolve_refs_recursively(stack_name, index, resources)522            values = resolve_refs_recursively(stack_name, values, resources)523            return values[index]524        if stripped_fn_lower == "split":525            delimiter, string = value[keys_list[0]]526            delimiter = resolve_refs_recursively(stack_name, delimiter, resources)527            string = resolve_refs_recursively(stack_name, string, resources)528            return string.split(delimiter)529        if stripped_fn_lower == "getazs":530            region = (531                resolve_refs_recursively(stack_name, value["Fn::GetAZs"], resources)532                or aws_stack.get_region()533            )534            azs = []535            for az in ("a", "b", "c", "d"):536                azs.append("%s%s" % (region, az))537            return azs538        if stripped_fn_lower == "base64":539            value_to_encode = value[keys_list[0]]540            value_to_encode = resolve_refs_recursively(stack_name, value_to_encode, resources)541            return to_str(base64.b64encode(to_bytes(value_to_encode)))542        for key, val in dict(value).items():543            value[key] = resolve_refs_recursively(stack_name, val, resources)544    if isinstance(value, list):545        for i in range(len(value)):546            value[i] = resolve_refs_recursively(stack_name, value[i], resources)547    return value548def resolve_placeholders_in_string(result, stack_name=None, resources=None):549    def _replace(match):550        parts = match.group(1).split(".")551        if len(parts) >= 2:552            resource_name, _, attr_name = match.group(1).partition(".")553            resolved = resolve_ref(554                stack_name, resource_name.strip(), resources, attribute=attr_name.strip()555            )556            if resolved is None:557                raise DependencyNotYetSatisfied(558                    resource_ids=resource_name,559                    message="Unable to resolve attribute ref %s" % match.group(1),560                )561            return resolved562        if len(parts) == 1 and parts[0] in resources:563            resource_json = resources[parts[0]]564            resource_type = get_resource_type(resource_json)565            result = extract_resource_attribute(566                resource_type,567                {},568                "Ref",569                resources=resources,570                resource_id=parts[0],571                stack_name=stack_name,572            )573            if result is None:574                raise DependencyNotYetSatisfied(575                    resource_ids=parts[0],576                    message="Unable to resolve attribute ref %s" % match.group(1),577                )578            return result579        # TODO raise exception here?580        return match.group(0)581    regex = r"\$\{([^\}]+)\}"582    result = re.sub(regex, _replace, result)583    return result584def evaluate_condition(stack_name, condition, resources):585    condition = resolve_refs_recursively(stack_name, condition, resources)586    condition = resolve_ref(stack_name, condition, resources, attribute="Ref")587    condition = resolve_refs_recursively(stack_name, condition, resources)588    return condition589def evaluate_resource_condition(resource, stack_name, resources):590    condition = resource.get("Condition")591    if condition:592        condition = evaluate_condition(stack_name, condition, resources)593        if condition is False or condition in FALSE_STRINGS or is_none_or_empty_value(condition):594            return False595    return True596def get_stack_parameter(stack_name, parameter):597    try:598        client = aws_stack.connect_to_service("cloudformation")599        stack = client.describe_stacks(StackName=stack_name)["Stacks"]600    except Exception:601        return None602    stack = stack and stack[0]603    if not stack:604        return None605    result = [p["ParameterValue"] for p in stack["Parameters"] if p["ParameterKey"] == parameter]606    return (result or [None])[0]607def update_resource(resource_id, resources, stack_name):608    resource = resources[resource_id]609    resource_type = get_resource_type(resource)610    if resource_type not in UPDATEABLE_RESOURCES:611        LOG.warning('Unable to update resource type "%s", id "%s"' % (resource_type, resource_id))612        return613    LOG.info("Updating resource %s of type %s" % (resource_id, resource_type))614    instance = get_resource_model_instance(resource_id, resources)615    if instance:616        result = instance.update_resource(resource, stack_name=stack_name, resources=resources)617        instance.fetch_and_update_state(stack_name=stack_name, resources=resources)618        return result619def get_resource_model_instance(resource_id: str, resources) -> Optional[GenericBaseModel]:620    """Obtain a typed resource entity instance representing the given stack resource."""621    resource = resources[resource_id]622    resource_type = get_resource_type(resource)623    canonical_type = canonical_resource_type(resource_type)624    resource_class = RESOURCE_MODELS.get(canonical_type)625    if not resource_class:626        return None627    instance = resource_class(resource)628    return instance629def fix_account_id_in_arns(params):630    def fix_ids(o, **kwargs):631        if isinstance(o, dict):632            for k, v in o.items():633                if common.is_string(v, exclude_binary=True):634                    o[k] = aws_stack.fix_account_id_in_arns(v)635        elif common.is_string(o, exclude_binary=True):636            o = aws_stack.fix_account_id_in_arns(o)637        return o638    result = common.recurse_object(params, fix_ids)639    return result640def convert_data_types(func_details, params):641    """Convert data types in the "params" object, with the type defs642    specified in the 'types' attribute of "func_details"."""643    types = func_details.get("types") or {}644    attr_names = types.keys() or []645    def cast(_obj, _type):646        if _type == bool:647            return _obj in ["True", "true", True]648        if _type == str:649            if isinstance(_obj, bool):650                return str(_obj).lower()651            return str(_obj)652        if _type == int:653            return int(_obj)654        return _obj655    def fix_types(o, **kwargs):656        if isinstance(o, dict):657            for k, v in o.items():658                if k in attr_names:659                    o[k] = cast(v, types[k])660        return o661    result = common.recurse_object(params, fix_types)662    return result663# TODO remove this method664def prepare_template_body(req_data):665    return template_preparer.prepare_template_body(req_data)666def deploy_resource(resource_id, resources, stack_name):667    result = execute_resource_action(resource_id, resources, stack_name, ACTION_CREATE)668    return result669def delete_resource(resource_id, resources, stack_name):670    return execute_resource_action(resource_id, resources, stack_name, ACTION_DELETE)671def execute_resource_action_fallback(672    action_name, resource_id, resources, stack_name, resource, resource_type673):674    # using moto as fallback for now - TODO remove in the future!675    msg = 'Action "%s" for resource type %s not yet implemented' % (676        action_name,677        resource_type,678    )679    long_type = canonical_resource_type(resource_type)680    clazz = parsing.MODEL_MAP.get(long_type)681    if not clazz:682        LOG.warning(msg)683        return684    LOG.info("%s - using fallback mechanism" % msg)685    if action_name == ACTION_CREATE:686        resource_name = get_resource_name(resource) or resource_id687        result = clazz.create_from_cloudformation_json(688            resource_name, resource, aws_stack.get_region()689        )690        return result691def execute_resource_action(resource_id, resources, stack_name, action_name):692    resource = resources[resource_id]693    resource_type = get_resource_type(resource)694    func_details = get_deployment_config(resource_type)695    if not func_details or action_name not in func_details:696        if resource_type in ["Parameter"]:697            return698        return execute_resource_action_fallback(699            action_name, resource_id, resources, stack_name, resource, resource_type700        )701    LOG.debug(702        'Running action "%s" for resource type "%s" id "%s"'703        % (action_name, resource_type, resource_id)704    )705    func_details = func_details[action_name]706    func_details = func_details if isinstance(func_details, list) else [func_details]707    results = []708    for func in func_details:709        if callable(func["function"]):710            result = func["function"](resource_id, resources, resource_type, func, stack_name)711            results.append(result)712            continue713        client = get_client(resource, func)714        if client:715            result = configure_resource_via_sdk(716                resource_id, resources, resource_type, func, stack_name, action_name717            )718            results.append(result)719    return (results or [None])[0]720def configure_resource_via_sdk(721    resource_id, resources, resource_type, func_details, stack_name, action_name722):723    resource = resources[resource_id]724    if resource_type == "EC2::Instance":725        if action_name == "create":726            func_details["boto_client"] = "resource"727    client = get_client(resource, func_details)728    function = getattr(client, func_details["function"])729    params = func_details.get("parameters") or lambda_get_params()730    defaults = func_details.get("defaults", {})731    resource_props = resource["Properties"] = resource.get("Properties", {})732    resource_props = dict(resource_props)733    resource_state = resource.get(KEY_RESOURCE_STATE, {})734    if callable(params):735        params = params(736            resource_props,737            stack_name=stack_name,738            resources=resources,739            resource_id=resource_id,740        )741    else:742        # it could be a list like ['param1', 'param2', {'apiCallParamName': 'cfResourcePropName'}]743        if isinstance(params, list):...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!!
