ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Moto 的 AWS Budgets 服务模拟实现:创建、查询与通知管理实战指南

Moto 的 AWS Budgets 服务模拟实现:创建、查询与通知管理实战指南 Mock测试【免费下载链接】motoA library that allows you to easily mock out tests based on AWS infrastructure.项目地址https://gitcode.com/gh_mirrors/mo/moto点击查看免费下载导读AWS Budgets 是云成本治理中常用的预算与告警服务用于为账号设置费用/用量预算并在超出阈值时触发通知。本篇文章以 Moto 仓库中的 budgets 服务文档 为核心骨架结合 moto/budgets 模块的源码与 tests/test_budgets 测试用例系统讲解 Moto 对 AWS Budgets API 的实现范围、数据模型、内存后端工作方式以及如何在本地用 boto3 完成预算创建、查询、删除和通知管理的完整模拟流程。读完本文你将能够用 Moto 在测试中无缝替换真实 AWS Budgets 服务并清楚知道哪些 API 已被模拟、哪些尚未实现。一、服务实现范围总览1.1 已实现与未实现的 API 清单根据 budgets.rst 的实现清单Moto 当前已实现以下 8 个 Budgets APIcreate_budget— 创建预算create_notification— 为预算创建通知delete_budget— 删除预算delete_notification— 删除通知describe_budget— 查询单个预算describe_budgets— 查询账号下所有预算describe_notifications_for_budget— 查询预算下的通知列表中还有[X]标记项请以仓库实际清单为准同时文档明确标注以下 API尚未实现对应[ ]标记create_budget_action/delete_budget_action/describe_budget_action/describe_budget_action_historiesdescribe_budget_actions_for_account/describe_budget_actions_for_budgetdescribe_budget_notifications_for_account/describe_budget_performance_historydescribe_subscribers_for_notification/execute_budget_actionlist_tags_for_resource/tag_resource/untag_resourceupdate_budget/update_budget_action/update_notification/update_subscriber这意味着当前实现聚焦于预算对象本身与通知的增删查而预算动作Actions、标签管理、订阅者查询和更新类操作尚未覆盖。1.2 Pagination 尚未实现文档两处明确标注describe_budgetsPagination is not yet implementeddescribe_notifications_for_budgetPagination has not yet been implemented在 responses.py 中可以看到describe_budgets直接返回全部预算列表并将nextToken置为Nonedescribe_notifications_for_budget同样一次性返回全部通知。这与真实 AWS 的分页行为存在差异如果你的测试逻辑依赖分页游标需要留意这一点。二、源码架构从请求到内存存储的调用链2.1 模块文件构成moto/budgets 目录由 5 个文件组成分工清晰文件职责urls.py注册服务端点budgets.amazonaws.com所有请求统一分发到BudgetsResponse.dispatchresponses.py解析 JSON 请求参数、调用后端、序列化响应application/x-amz-json-1.1models.py定义Budget、Notification数据模型与BudgetsBackend后端逻辑exceptions.py定义服务异常DuplicateRecordException、NotFoundException、BudgetMissingLimitinit.py导出budgets_backends单例注册表2.2 请求分发与参数解析在 urls.py 中所有请求都打在根路径/上通过X-Amz-Target头如AWSBudgetServiceGateway.CreateBudget由 responses.py 的dispatch路由到对应方法。例如create_budget方法会从请求体中取出AccountId、Budget和可选的NotificationsWithSubscribers再转交后端def create_budget(self) - str: account_id self._get_param(AccountId) budget self._get_param(Budget) notifications self._get_param(NotificationsWithSubscribers, []) self.backend.create_budget(account_idaccount_id, budgetbudget, notificationsnotifications) return json.dumps({})从源码结构看响应层只做参数透传 JSON 序列化所有业务逻辑都收敛在后端BudgetsBackend中这也符合 Moto 一贯的responses → models分层设计。2.3 内存数据模型models.py 定义了三个核心类Budget封装预算详情字典与通知列表。构造时校验BudgetLimit或PlannedBudgetLimits必须至少提供一个否则抛出BudgetMissingLimit随后自动补全LastUpdatedTime并在未提供TimePeriod时默认填充当月第一天至今的时间范围End 时间点为3706473600即 2087-06-15。Notification保存通知详情details与订阅者列表subscribers订阅者在当前实现中仅做存储不参与下发逻辑。BudgetsBackend以defaultdict(dict)按account_id → budget_name → Budget的两级字典组织数据所有预算状态均保存在内存中。2.4 序列化时的默认字段补全Budget.to_dict()在返回预算时做了两处关键补全若没有CalculatedSpend自动生成ActualSpend与ForecastedSpend均为{Amount: 0, Unit: USD}若BudgetType COST且未提供CostTypes自动补全一份包含IncludeCredit、IncludeDiscount、IncludeSubscription等 9 个布尔字段默认均为True仅UseAmortized与UseBlended为False的默认 CostTypes。这意味着即使创建预算时只传最小参数describe_budget的返回也会包含完整的CalculatedSpend与CostTypes结构方便下游代码直接读取而不必判空。2.5 异常体系exceptions.py 定义了三个异常全部继承JsonRESTError并以 HTTP 400 返回DuplicateRecordException创建同名预算时抛出消息形如Error creating budget: name - the budget already exists.NotFoundException查询/删除不存在的预算或通知时抛出消息随场景变化如Unable to get budget: name - the budget doesnt exist.BudgetMissingLimit创建预算未提供BudgetLimit与PlannedBudgetLimits时抛出错误码为InvalidParameterException。三、实践用 boto3 在 Moto 中创建与查询预算3.1 最小可运行示例使用mock_aws装饰器即可在测试中启用 Budgets 模拟。以下是最小参数创建预算的完整用例对应 test_budgets.py 中的test_create_and_describe_budget_minimal_paramsimport boto3 from moto import mock_aws from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID mock_aws def test_create_and_describe_budget(): client boto3.client(budgets, region_nameus-east-1) client.create_budget( AccountIdACCOUNT_ID, Budget{ BudgetLimit: {Amount: 10, Unit: USD}, BudgetName: testbudget, TimeUnit: DAILY, BudgetType: COST, }, ) budget client.describe_budget(AccountIdACCOUNT_ID, BudgetNametestbudget)[Budget] assert budget[BudgetLimit] {Amount: 10, Unit: USD} assert budget[TimeUnit] DAILY assert budget[BudgetType] COST # Moto 自动补全的默认字段 assert budget[CalculatedSpend][ActualSpend] {Amount: 0, Unit: USD} assert budget[CostTypes][IncludeTax] is True assert LastUpdatedTime in budget assert TimePeriod in budget3.2 关键参数说明创建预算时的Budget字典核心字段及语义如下字段是否必填说明BudgetName是预算名称同一账号内唯一重名会触发DuplicateRecordExceptionBudgetLimit与PlannedBudgetLimits二选一如{Amount: 10, Unit: USD}两者都不传会触发BudgetMissingLimitPlannedBudgetLimits与BudgetLimit二选一分时间段的计划限额同样满足校验要求BudgetType是取值如COST、USAGE、RI_UTILIZATION等为COST时自动补全CostTypesTimeUnit是如DAILY、MONTHLY、QUARTERLY、ANNUALLYTimePeriod否未提供时自动填充为本月第一天 → 2087-06-153.3 异常场景的行为验证测试代码同样印证了异常路径重复创建同名预算返回错误码DuplicateRecordException消息为Error creating budget: testb - the budget already exists.缺少限额时返回错误码InvalidParameterException消息为Unable to create/update budget - please provide one of the followings: Budget Limit/ Planned Budget Limit/ Auto Adjust Data查询不存在的预算返回NotFoundException消息为Unable to get budget: unknown - the budget doesnt exist.。这些异常消息可以直接作为测试断言依据。四、实践预算列表与删除操作4.1 列出全部预算describe_budgets返回账号下全部预算当前不支持分页一次性返回完整列表nextToken固定为Noneres client.describe_budgets(AccountIdACCOUNT_ID) assert res[Budgets] [] # 尚未创建任何预算创建预算后再调用Budgets列表中即包含该预算的完整序列化结构含自动补全字段。4.2 删除预算delete_budget成功时返回 HTTP 200 与空响应体删除后再次describe_budgets将不再看到该预算client.delete_budget(AccountIdACCOUNT_ID, BudgetNameb1) assert client.describe_budgets(AccountIdACCOUNT_ID)[Budgets] []对不存在的预算调用delete_budget会抛出NotFoundException消息为Unable to delete budget: unknown - the budget doesnt exist. Try creating it first.。4.3 服务端模式验证除mock_aws装饰器外Moto 也支持独立服务进程模式。在 test_server.py 中可以看到通过server.create_backend_app(budgets)构建 Flask 测试客户端后直接向/发送带X-Amz-Target: AWSBudgetServiceGateway.DescribeBudgets头的 POST 请求即可收到{Budgets: [], nextToken: None}的 JSON 响应这也验证了端点在无预算时的返回结构。五、实践通知Notification的创建、查询与删除5.1 随预算一起创建通知通知可以随create_budget通过NotificationsWithSubscribers参数一并创建每个元素由Notification通知规则与Subscribers订阅者列表组成client.create_budget( AccountIdACCOUNT_ID, Budget{ BudgetLimit: {Amount: 10, Unit: USD}, BudgetName: testbudget, TimeUnit: DAILY, BudgetType: COST, }, NotificationsWithSubscribers[ { Notification: { NotificationType: ACTUAL, ComparisonOperator: EQUAL_TO, Threshold: 123.0, ThresholdType: ABSOLUTE_VALUE, NotificationState: ALARM, }, Subscribers: [ {SubscriptionType: EMAIL, Address: adminmoto.com}, ], } ], )5.2 为已有预算追加通知create_notification允许在已创建的预算上追加通知对应 test_notifications.py 的test_create_notificationclient.create_notification( AccountIdACCOUNT_ID, BudgetNametestbudget, Notification{ NotificationType: ACTUAL, ComparisonOperator: GREATER_THAN, Threshold: 0.0, ThresholdType: ABSOLUTE_VALUE, NotificationState: OK, }, Subscribers[{SubscriptionType: SNS, Address: arn:sns:topic:mytopic}], )追加后describe_notifications_for_budget将返回两条通知。注意当前实现中订阅者仅被存储不会被实际用于发送告警也不会触发任何消息下发逻辑。5.3 查询与删除通知describe_notifications_for_budget一次性返回该预算下的全部通知同样不支持分页res client.describe_notifications_for_budget(AccountIdACCOUNT_ID, BudgetNametestbudget) assert len(res[Notifications]) 1删除通知时delete_notification需要传入与创建时完全一致的Notification字典包含NotificationType、ComparisonOperator、Threshold、ThresholdType、NotificationState后端按字典逐字段比对来过滤删除client.delete_notification( AccountIdACCOUNT_ID, BudgetNametestbudget, Notification{ NotificationType: ACTUAL, ComparisonOperator: EQUAL_TO, Threshold: 123.0, ThresholdType: ABSOLUTE_VALUE, NotificationState: ALARM, }, )5.4 通知相关的异常场景对不存在的预算调用create_notification或delete_notification均抛出NotFoundException消息分别为Unable to create notification - the budget doesnt exist.与Unable to delete notification - the budget doesnt exist.注意NotificationType的可选值包括ACTUAL、FORECASTED等但 Moto 后端不校验其取值合法性仅做存储与比对传入任意字符串都能通过 API 层真正拦截的是预算是否存在。六、实现细节与使用限制小结6.1 自动补全行为汇总场景自动补全内容创建预算LastUpdatedTime当前 Unix 时间戳、TimePeriod本月首日至 2087-06-15查询预算CalculatedSpendActualSpend/ForecastedSpend 均为 0 USDBudgetType COST时补全 11 个字段的默认CostTypes6.2 当前限制清单无分页describe_budgets与describe_notifications_for_budget均一次性返回全部数据nextToken固定为None无更新操作update_budget、update_notification等 4 个更新类 API 未实现无预算动作create_budget_action等 6 个与 Action 相关的 API 未实现无标签管理tag_resource、untag_resource、list_tags_for_resource未实现通知仅存储订阅者EMAIL/SNS不触发真实告警下发数据存于内存所有预算随 mock 上下文生命周期存在测试结束后即清空。6.3 适用场景建议基于上述限制Moto 的 budgets 实现最适合以下场景单元/集成测试中验证预算 CRUD 与通知增删查的调用逻辑与参数组装对依赖describe_budget返回结构中CalculatedSpend、CostTypes等默认字段的下游代码做断言覆盖异常路径重复创建、不存在预算、缺少限额的测试。如果你的测试依赖预算动作、标签、分页或更新语义则需要等待对应 API 的后续实现或自行扩展后端。七、进一步探索想深入理解实现细节可以直接阅读以下仓库文件服务文档与实现清单docs/docs/services/budgets.rst后端数据模型与业务逻辑moto/budgets/models.py请求解析与响应序列化moto/budgets/responses.py服务异常定义moto/budgets/exceptions.py端点注册moto/budgets/urls.py预算 CRUD 测试tests/test_budgets/test_budgets.py通知相关测试tests/test_budgets/test_notifications.py服务端模式测试tests/test_budgets/test_server.py通过对照源码与测试你可以快速掌握 Moto 模拟 AWS Budgets 的边界并在自己的测试项目中安全地使用它。赞分享Mock测试【免费下载链接】motoA library that allows you to easily mock out tests based on AWS infrastructure.项目地址https://gitcode.com/gh_mirrors/mo/moto点击查看免费下载相关推荐aws budgets describe-notifications-for-budget 使用指南查询 AWS 预算通知的完整实战手册aws budgets describe notifications for budget 使用指南查询 AWS 预算通知的完整实战手册 本指南基于 AWS开发工具云原生运维Floci 中 AWS Budgets 服务的本地模拟从预算、通知到 Budget Actions 的完整实现解析Floci 中 AWS Budgets 服务的本地模拟从预算、通知到 Budget Actions 的完整实现解析 导读 本文基于开源项目 FlociAWSAWS CLI budgets describe-budgets 实战指南查询账户全部成本与用量预算AWS CLI budgets describe budgets 实战指南查询账户全部成本与用量预算 describe budgets 是 AWS Budge开发工具云原生运维上一篇推荐VueQuill - Vue 3的富文本编辑器组件下一篇如何为Simplefolio添加Google Analytics数据分析与流量追踪终极指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表