拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Moto AWS Config 查询支持全解析:在单元测试中模拟资源发现与配置获取

Mock测试【免费下载链接】motoA library that allows you to easily mock out tests based on AWS infrastructure.项目地址https://gitcode.com/gh_mirrors/mo/moto点击查看免费下载导读AWS Config 是 AWS 提供的资源治理服务能够描述账户内的 AWS 资源类型并追踪其变更历史。Moto 在moto/config中提供了一套实验性的 AWS Config 查询能力它不模拟配置历史而是通过查询 Moto 各后端中已创建资源的实时状态以 AWS Config 的返回格式list_discovered_resources、batch_get_resource_config等向外输出。本文基于仓库根目录的 CONFIG_README.md 展开结合moto/config/models.py、moto/s3/config.py、moto/iam/config.py与moto/core/common_models.py的源码实现完整讲解该功能的原理、当前支持范围、端到端用法以及为新增资源类型实现 Config 查询能力的完整开发者指南。一、功能定位为什么需要模拟 AWS Config真实环境中的自动化系统如合规扫描、资源盘点、基于 AWS Config 的巡检脚本通常依赖 AWS Config API 来发现资源并拉取资源配置。这类代码在单元测试阶段如果直接对接真实 AWS会引入账号依赖、费用与网络不确定性。Moto 的 AWS Config 查询支持就是为这个场景设计的它让开发者在测试中通过boto3.client(config)调用 AWS Config 的查询接口并返回与生产环境一致的结构化数据从而用测试代码模拟生产中的自动化逻辑。需要强调的是这是一个实验性特性——并非所有 AWS 资源类型都已接入许多类型需要社区逐步补充。从源码结构看该功能完全基于内存后端实现资源在 Moto 中创建后即存在于对应服务的 backend 中AWS Config 查询模块只是读取这些后端状态并格式化成 Config 返回结构并不维护独立的历史快照。二、工作原理从后端状态生成 Config 格式数据按 CONFIG_README.md 的说明该功能的实现思路是检查在 Moto 内创建的资源状态将状态数据以 AWS Config 的返回格式输出但不含历史记录查询时会遍历给定资源类型对应的所有 Moto 后端region仅对已启用该能力的资源类型生效。在代码层面这一流程的枢纽是moto/config/models.py中的RESOURCE_MAPmoto/config/models.py它把 AWS Config 资源类型字符串映射到各自的ConfigQueryModel实例RESOURCE_MAP: dict[str, ConfigQueryModel[Any]] { AWS::S3::Bucket: s3_config_query, AWS::S3::AccountPublicAccessBlock: s3_account_public_access_block_query, AWS::IAM::Role: role_config_query, AWS::IAM::Policy: policy_config_query, AWS::SNS::Topic: sns_config_query, }前端 API 入口moto/config/responses.py收到list_discovered_resources、list_aggregate_discovered_resources、batch_get_resource_config、batch_aggregate_get_resource_config等请求后转发给ConfigBackend中的同名方法后端方法再根据RESOURCE_MAP找到对应的查询实例最终调用该实例的list_config_service_resources/get_config_resource完成查询。当前支持范围以源码为准原文档列出 S3全部与 IAMRole、Policy两类而从RESOURCE_MAP可以看到仓库当前实际启用了 5 个资源类型映射AWS Config 资源类型查询实例实现文件AWS::S3::Buckets3_config_querymoto/s3/config.pyAWS::S3::AccountPublicAccessBlocks3_account_public_access_block_querymoto/s3control/config.pyAWS::IAM::Rolerole_config_querymoto/iam/config.pyAWS::IAM::Policypolicy_config_querymoto/iam/config.pyAWS::SNS::Topicsns_config_querymoto/sns/config.py其余资源类型在RESOURCE_MAP中无映射相关查询调用会直接跳过返回空结果。三、端到端使用四个核心 API 的测试写法按原文档的测试建议端到端测试应覆盖以下四个 boto 客户端方法boto3.client(config).list_discovered_resources()boto3.client(config).list_aggregate_discovered_resources()boto3.client(config).batch_get_resource_config()boto3.client(config).batch_aggregate_get_resource_config()以 IAM Policy 为例仓库测试 tests/test_iam/test_iam.py 中的test_policy_config_client演示了完整的端到端链路先用mock_aws装饰器挂起 Moto通过 boto3 创建 IAM Policy再通过config客户端查询。一个典型的查询形如import boto3 from moto import mock_aws mock_aws def test_list_discovered_resources(): iam boto3.client(iam, region_nameus-east-1) iam.create_policy( PolicyNamemy-policy, PolicyDocument{Version:2012-10-17, Statement:[{Effect:Allow,Action:ec2:*,Resource:*}]}, ) config boto3.client(config, region_nameus-east-1) resp config.list_discovered_resources(resourceTypeAWS::IAM::Policy) assert len(resp[resourceIdentifiers]) 1 assert resp[resourceIdentifiers][0][resourceType] AWS::IAM::Policy需要注意的一点原文档特别提醒聚合类方法Aggregate的参数名首字母大写如Limit而非聚合类方法参数名首字母小写如limit。这是由 AWS API 本身决定的写测试时容易踩坑。聚合查询需要预先创建 Config Aggregator聚合查询list_aggregate_discovered_resources、batch_aggregate_get_resource_config与普通查询的差异从 moto/config/models.py 的list_aggregate_discovered_resources可以看出它要求先用put_configuration_aggregator创建好 Config Aggregator否则抛出NoSuchConfigurationAggregatorException。之后聚合查询可以按Filters中的Region、ResourceId、ResourceName过滤资源。四、开发者指南为资源类型接入 Config 查询原文档将新增能力的开发拆成两大部分——Listing列出资源与Describing描述资源二者共享同一套前置组件。下面按源码逐一展开。4.1 四个基础组件Base Components每个启用该能力的资源类型至少需要满足一个config.py文件负责导入资源类型的后端从该服务的__init__.py导入xxx_backends在该config.py中实现ConfigQueryModel子类内含该资源类型特有的查询逻辑实例化该ConfigQueryModel在 moto/config/models.py 中导入该实例并更新RESOURCE_MAP建立 AWS Config 资源类型 → 实例 的映射。原文档以 S3 为例指出可参照 moto/s3/config.py 与 moto/config/models.py。从 S3 的实现看完整链路是# moto/s3/config.py from moto.core.common_models import ConfigQueryModel from moto.s3 import s3_backends from moto.s3.models import S3Backend class S3ConfigQuery(ConfigQueryModel[S3Backend]): def list_config_service_resources(self, ...): ... def get_config_resource(self, ...): ... s3_config_query S3ConfigQuery(s3_backends)基类ConfigQueryModel定义在 moto/core/common_models.py是泛型类__init__接收该资源类型的BackendDict即每个 region 各一个后端的集合并声明了两个必须实现的方法list_config_service_resources(...)列出资源支持聚合与非聚合两种模式get_config_resource(...)获取单个资源的 Config 格式配置不存在时返回None。4.2 Listing实现资源列表查询返回值契约list_config_service_resources的返回值是(list[dict], next_token)二元组其中列表元素的格式固定为[ { type: AWS::The AWS Config data type, name: The name of the resource, id: The ID of the resource, region: The region of the resource, # 全局资源可返回聚合器所在区域或 us-east-1 }, ... ]后续的 Config 服务层会基于这个结构分别格式化出聚合与非聚合调用的响应。聚合与非聚合的差异原文档给出两条通用实现要点基类 docstringmoto/core/common_models.py对其做了更精确的补充场景backend_regionresource_region说明非聚合 Listing设置为 API 请求到达的 region置None只列出该 region 后端内的资源聚合 Listing置None可选来自Filters的 region 参数遍历所有region 后端收集资源再按 region 过滤分页建议聚合查询的分页应能跨 region 翻页因此 token 建议采用region 资源名拼接的形式sharded byregion-item-name。S3 之所以没有这样做是因为 S3 桶名全局唯一直接用桶名做 token 即可。S3 实现示例S3 的list_config_service_resourcesmoto/s3/config.py展示了完整逻辑若同时传入resource_ids与resource_name则要求resource_name必须属于resource_ids否则返回空列表无过滤条件时取后端全部桶有过滤条件时按桶名匹配region 过滤region_filter backend_region or resource_region只有桶的region_name等于过滤值才保留分页桶名排序后next_token即下一个桶名若 token 非法则抛InvalidNextTokenException当本页数据未取完时返回下一页起始桶名作为新 token。IAM 实现的特殊性全局资源与聚合复制IAM 角色与策略是全局资源在 Moto 中注册于global分区后端。但真实 AWS 的行为是聚合器会在其覆盖的每个 region 中重复返回这些全局资源。因此 moto/iam/config.py 的聚合分支会从聚合器源account_aggregation_sources或organization_aggregation_source中取出 region 列表若设置了all_aws_regions则用boto3.Session().get_available_regions(config)获取全部可用 region为每个 region 复制一份角色/策略条目并以{resource_id}{region}作为内部排序键_id仅用于排序不对外返回非聚合查询则简单得多每条资源的region直接标注为global。另外Policy 的 Listing 实现moto/iam/config.py还专门过滤掉了 AWS 托管策略ARN 匹配:iam::aws前缀以免把 AWS 预置策略混入用户资源结果。过滤与校验规则moto/config/models.py的list_discovered_resources在调用查询实例之前还做了若干前置校验limit缺省为DEFAULT_PAGE_SIZE 100超过 100 抛InvalidLimitException不能同时传resource_ids和resource_name抛InvalidResourceParametersresource_ids最多 20 个抛TooManyResourceIds。4.3 Describing获取单个资源配置get_config_resource的契约moto/core/common_models.py是资源不存在时返回None存在时返回一个与 AWS Config 返回格式一致的 dict。聚合查询batch_aggregate_get_resource_config与非聚合查询batch_get_resource_config都会按 N 次调用该函数来批量获取 N 个对象。后端方法batch_get_resource_configmoto/config/models.py的关键逻辑每次请求最多 100 个资源键超出抛TooManyResourceKeys资源类型不在RESOURCE_MAP中、或对应后端 region 未实现时直接跳过若查询结果为空则跳过成功则补上accountId字段返回值固定包含baseConfigurationItems与unprocessedResourceKeysMoto 目前不产生未处理项恒为空列表对全局资源类型如 IAM会把查询区域切换到对应 partition 后再查找。Config dict 的生成to_config_dict资源对象本身需要提供to_config_dict()方法把自身状态序列化为 AWS Config 的配置项结构。以 IAM Policy 为例moto/iam/models.py返回的结构包含顶层字段version、configurationItemCaptureTime、configurationItemStatus、configurationStateId、arn、resourceType、resourceId、resourceName、awsRegion全局资源为global、availabilityZoneNot Applicable、resourceCreationTime、tags、configuration、supplementaryConfigurationconfiguration内部policyName、policyId、arn、path、defaultVersionId、attachmentCount、isAttachable、description、createDate、updateDate、tags、policyVersionList含 URL 编码的 policy 文档与版本信息。S3 桶的to_config_dictmoto/s3/models.py则复杂得多——这正是原文档所说S3 非常复杂桶的配置方式决定了 Config 返回什么顶层标识configurationItemStatus为ResourceDiscoveredavailabilityZone为Regionalarn指向桶 ARNsupplementaryConfiguration中按需携带AccessControlList双重 JSON 包装、PublicAccessBlockConfiguration、BucketTaggingConfiguration、BucketAccelerateConfiguration当前为 TODO返回{status: None}、BucketLifecycleConfiguration、BucketLoggingConfiguration、BucketPolicy、IsRequesterPaysEnabled、BucketNotificationConfiguration等。moto/config.py中的查询实例如 S3 的get_config_resource在拿到to_config_dict()结果后还会做两步收尾把configuration字段整体json.dumps成 JSON 字符串AWS Config API 的configuration字段本身就是字符串遍历supplementaryConfiguration把非字符串的值也转成 JSON 字符串。这两步是所有已实现资源类型共用的模式S3、IAM Role/Policy 均如此可视为新增实现的标准样板。五、测试要求三层测试覆盖原文档为每个资源类型指定了三个层次的测试均在仓库测试中能找到对应实现以 IAM Policy 为例见 tests/test_iam/test_iam.py后端查询测试如test_policy_list_config_discovered_resources直接调用查询实例的list_config_service_resources验证资源能被发现。关键约束不得用 boto 创建资源必须用后端模型方法如policy_config_query.backends[DEFAULT_ACCOUNT_ID][global].create_policy(...)直接供给资源以保证测试兼容 Moto Server 模式。测试覆盖 listing 与 object fetching 两件事。Config dict 测试如test_policy_config_dict同样不用 boto 创建资源而是为每种会产生不同 config dict 的有意义的配置分别构造资源再调用get_config_resource断言各 dict 内容符合预期。例如 tests/test_s3/test_s3_config.py 中就有test_s3_config_dict、test_s3_lifecycle_config_dict、test_s3_notification_config_dict、test_s3_acl_to_config_dict、test_s3_public_access_block_to_config_dict等针对 S3 不同配置面的用例。端到端客户端测试如test_policy_config_client用 boto 客户端完整走一遍list_discovered_resources、list_aggregate_discovered_resources、batch_get_resource_config、batch_aggregate_get_resource_config验证前后端逻辑串通、返回正确资源。该测试不必过于详尽核心是前后端协同正确。其中后端直连测试之所以存在第一、二层正是原文档强调的此类测试不依赖 boto 网络栈可在 Moto Server 模式下正常运行。六、限制与注意事项实验性特性仅覆盖RESOURCE_MAP中的资源类型其余类型的查询将返回空结果社区可依本文第四、五节流程逐步扩充。无配置历史Moto 不模拟 AWS Config 的配置变更历史Configuration History只返回当前内存后端的资源状态。聚合语义简化Moto 的聚合查询假定同一账号下的所有 region 资源均已聚合不模拟真实 AWS 的聚合授权、跨账号等复杂约束IAM 全局资源在聚合中按聚合器覆盖的 region 复制返回这也是对真实行为的简化近似。单账号假设聚合查询会忽略请求中的账号维度见batch_get_aggregate_resource_config的实现注释。尚未实现的细节如 S3 的BucketAccelerateConfiguration在to_config_dict中标注为 TODO。七、结语Moto 的 AWS Config 查询支持为依赖 Config API 的自动化代码提供了低成本、可重复的单元测试方案。理解ConfigQueryModel基类契约、RESOURCE_MAP注册机制以及 Listing/Describing 两种查询模式的聚合差异是向该特性贡献新资源类型的基础。开发者既可以按本文第三节直接使用既有能力也可以按第四、五节的指南为社区补齐更多资源类型——从 moto/s3/config.py 与 moto/iam/config.py 两个参考实现出发是最快的上手路径。赞分享Mock测试【免费下载链接】motoA library that allows you to easily mock out tests based on AWS infrastructure.项目地址https://gitcode.com/gh_mirrors/mo/moto点击查看免费下载相关推荐moto 中的 AWS DMS 模拟实现已支持的 API、资源状态机与测试实战指南moto 中的 AWS DMS 模拟实现已支持的 API、资源状态机与测试实战指南 本文基于 moto 仓库中的 DMS 服务覆盖文档 https://linMock测试moto 中的 AWS CodeDeploy 模拟已实现 API 清单、源码实现解析与 boto3 测试实战moto 中的 AWS CodeDeploy 模拟已实现 API 清单、源码实现解析与 boto3 测试实战 本文以 moto 官方服务文档 codedeplMock测试moto 中 AWS Config 服务的实现全解已支持 API、Recorder/Aggregator 机制与源码级剖析moto 中 AWS Config 服务的实现全解已支持 API、Recorder/Aggregator 机制与源码级剖析 本文以 docs/docs/serMock测试上一篇从网络调试新手到高手LightProxy终极指南下一篇MYDB轻量级数据库从环境搭建到性能调优指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门