diff --git a/modules/account-quotas/README.md b/modules/account-quotas/README.md index 92db56f36..f17dd7aec 100644 --- a/modules/account-quotas/README.md +++ b/modules/account-quotas/README.md @@ -38,9 +38,21 @@ aws --region us-east-1 service-quotas list-service-quotas --service-code ec2 If you make a request to raise a quota, the output will show the requested value as `value` while the request is pending. +### Special usage Notes + Even though the Terraform will submit the support request, you may need to follow up with AWS support to get the request approved, via the AWS console or email. +#### Resources are destroyed on change + +Because the AWS API often returns default values rather than configured or applicable values for a given quota, we have +to ignore the value returned by the API or else face perpetual drift. To allow us to change the value in the future, +even though we are ignoring it, we encode the value in the resource key, so that a change of value will result in a new +resource being created and the old one being destroyed. Destroying the old resource has no actual effect (it does not +even close an open request), so it is safe to do. + +### Example + Here's an example snippet for how to use this component. ```yaml @@ -128,5 +140,10 @@ components: - AWS CLI [command to list service codes](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/service-quotas/list-services.html): `aws service-quotas list-services` +- AWS CLI + [command to list service quotas](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/service-quotas/list-service-quotas.html) + `aws service-quotas list-service-quotas`. Note where it says "For some quotas, only the default values are available." +- [Medium article](https://medium.com/@jsonk/the-limit-does-not-exist-hidden-visibility-of-aws-service-limits-4b786f846bc0) + explaining how many AWS service limits are not available. [](https://cpco.io/component) diff --git a/modules/account-quotas/main.tf b/modules/account-quotas/main.tf index 0305efe81..1e40992c8 100644 --- a/modules/account-quotas/main.tf +++ b/modules/account-quotas/main.tf @@ -21,6 +21,26 @@ locals { quota_code = quota.quota_code != null ? quota.quota_code : data.aws_servicequotas_service_quota.by_name[k].quota_code value = quota.value } } + + # Because the API often returns default values rather than configured or applicable values, + # we have to ignore the value returned by the API or else face perpetual drift. + # To allow us to change the value in the future, even though we are ignoring it, + # we encode the value in the resource key, so that a change of value will + # result in a new resource being created and the old one being destroyed. + # Destroying the old resource has no actual effect, it does not even close + # an open request, so it is safe to do. + + quota_requests = { for k, quota in local.quotas_coded_map : + format("%v/%v/%v", quota.service_code, quota.quota_code, quota.value) => merge( + quota, { input_map_key = k } + ) + } + + quota_results = { for k, v in local.quota_requests : v.input_map_key => merge( + { for k, v in aws_servicequotas_service_quota.this[k] : k => v if k != "value" }, + { "value reported (may be inaccurate)" = aws_servicequotas_service_quota.this[k].value }, + { "value requested" = v.value } + ) } } data "aws_servicequotas_service" "by_name" { @@ -37,9 +57,15 @@ data "aws_servicequotas_service_quota" "by_name" { } resource "aws_servicequotas_service_quota" "this" { - for_each = local.quotas_coded_map + for_each = local.quota_requests quota_code = each.value.quota_code service_code = each.value.service_code value = each.value.value + + lifecycle { + # Literally about 50% of the time, the actual value set is not available, + # so the default value is reported instead, resulting in permanent drift. + ignore_changes = [value] + } } diff --git a/modules/account-quotas/outputs.tf b/modules/account-quotas/outputs.tf index 6258c97f3..48cd0feda 100644 --- a/modules/account-quotas/outputs.tf +++ b/modules/account-quotas/outputs.tf @@ -1,4 +1,4 @@ output "quotas" { - value = aws_servicequotas_service_quota.this + value = local.quota_results description = "Full report on all service quotas managed by this component." }