diff --git a/README.md b/README.md index 9b7a15fc..36f03c17 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,7 @@ determining that location is as follows: | budget\_display\_name | The display name of the budget. If not set defaults to `Budget For ` | `string` | `null` | no | | budget\_labels | A single label and value pair specifying that usage from only this set of labeled resources should be included in the budget. | `map(string)` | `{}` | no | | budget\_monitoring\_notification\_channels | A list of monitoring notification channels in the form `[projects/{project_id}/notificationChannels/{channel_id}]`. A maximum of 5 channels are allowed. | `list(string)` | `[]` | no | -| consumer\_quotas | The quotas configuration you want to override for the project. |
list(object({
service = string,
metric = string,
limit = string,
value = string,
}))
| `[]` | no | +| consumer\_quotas | The quotas configuration you want to override for the project. |
list(object({
service = string,
metric = string,
dimensions = map(string),
limit = string,
value = string,
}))
| `[]` | no | | create\_project\_sa | Whether the default service account for the project shall be created | `bool` | `true` | no | | default\_network\_tier | Default Network Service Tier for resources created in this project. If unset, the value will not be modified. See https://cloud.google.com/network-tiers/docs/using-network-service-tiers and https://cloud.google.com/network-tiers. | `string` | `""` | no | | default\_service\_account | Project default service account setting: can be one of `delete`, `deprivilege`, `disable`, or `keep`. | `string` | `"disable"` | no | diff --git a/build/int.cloudbuild.yaml b/build/int.cloudbuild.yaml index 181d74cf..179c3f8b 100644 --- a/build/int.cloudbuild.yaml +++ b/build/int.cloudbuild.yaml @@ -138,6 +138,28 @@ steps: - verify vpc-sc-project-local name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS' args: ['/bin/bash', '-c', 'source /usr/local/bin/task_helper_functions.sh && export TF_VAR_policy_id=$(gcloud access-context-manager policies list --organization="${TF_VAR_org_id:?}" --format="value(name)") && kitchen_do destroy vpc-sc-project-local'] + +- id: init-quota-project-example + waitFor: + - prepare + name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS' + args: ['/bin/bash', '-c', 'cft test run TestQuotaProject --stage init --verbose'] +- id: apply-quota-project-example + waitFor: + - init-quota-project-example + name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS' + args: ['/bin/bash', '-c', 'cft test run TestQuotaProject --stage apply --verbose'] +- id: verify-quota-project-example + waitFor: + - apply-quota-project-example + name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS' + args: ['/bin/bash', '-c', 'cft test run TestQuotaProject --stage verify --verbose'] +- id: destroy-quota-project-example + waitFor: + - verify-quota-project-example + name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS' + args: ['/bin/bash', '-c', 'cft test run TestQuotaProject --stage destroy --verbose'] + tags: - 'ci' - 'integration' diff --git a/examples/quota_project/README.md b/examples/quota_project/README.md index 83eb00ce..e62990c8 100644 --- a/examples/quota_project/README.md +++ b/examples/quota_project/README.md @@ -1,4 +1,4 @@ -# Budget Project +# Quota Project This example illustrates how to use quota_manager submodule to override customer quotas. @@ -7,12 +7,14 @@ This example illustrates how to use quota_manager submodule to override customer | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| project\_id | The GCP project you want to override the consumer quotas. | `string` | n/a | yes | +| billing\_account | The ID of the billing account to associate this project with | `string` | n/a | yes | +| folder\_id | The ID of a folder to host this project. | `string` | `""` | no | +| org\_id | The organization ID. | `string` | n/a | yes | ## Outputs | Name | Description | |------|-------------| -| quota\_overrides | The server-generated names of the quota override in the provided project. | +| project\_id | The project ID in which to override quota | diff --git a/examples/quota_project/main.tf b/examples/quota_project/main.tf index b40cc644..896dc390 100644 --- a/examples/quota_project/main.tf +++ b/examples/quota_project/main.tf @@ -17,21 +17,43 @@ /****************************************** Consumer Quota *****************************************/ -module "project_quota_manager" { - source = "../../modules/quota_manager" - project_id = var.project_id +resource "random_string" "suffix" { + length = 4 + special = false + upper = false +} + +module "quota-project" { + source = "../../" + name = "pf-ci-test-quota-${random_string.suffix.result}" + random_project_id = true + org_id = var.org_id + folder_id = var.folder_id + billing_account = var.billing_account + + activate_apis = [ + "serviceusage.googleapis.com", + "compute.googleapis.com", + "servicemanagement.googleapis.com" + ] + consumer_quotas = [ { service = "compute.googleapis.com" - metric = "SimulateMaintenanceEventGroup" - limit = "%2F100s%2Fproject" - value = "19" - }, { - service = "servicemanagement.googleapis.com" - metric = "servicemanagement.googleapis.com%2Fdefault_requests" - limit = "%2Fmin%2Fproject" - value = "95" + metric = urlencode("compute.googleapis.com/n2_cpus") + limit = urlencode("/project/region") + dimensions = { + region = "us-central1" + } + value = "10" + }, + { + service = "servicemanagement.googleapis.com" + metric = urlencode("servicemanagement.googleapis.com/default_requests") + limit = urlencode("/min/project") + dimensions = {} + value = "95" } ] } diff --git a/examples/quota_project/outputs.tf b/examples/quota_project/outputs.tf index 03546e69..861d71f6 100644 --- a/examples/quota_project/outputs.tf +++ b/examples/quota_project/outputs.tf @@ -14,7 +14,7 @@ * limitations under the License. */ -output "quota_overrides" { - description = "The server-generated names of the quota override in the provided project." - value = module.project_quota_manager.quota_overrides +output "project_id" { + description = "The project ID in which to override quota" + value = module.quota-project.project_id } diff --git a/examples/quota_project/variables.tf b/examples/quota_project/variables.tf index 0e4bae63..98014911 100644 --- a/examples/quota_project/variables.tf +++ b/examples/quota_project/variables.tf @@ -14,7 +14,18 @@ * limitations under the License. */ -variable "project_id" { - description = "The GCP project you want to override the consumer quotas." +variable "org_id" { + description = "The organization ID." + type = string +} + +variable "folder_id" { + description = "The ID of a folder to host this project." + type = string + default = "" +} + +variable "billing_account" { + description = "The ID of the billing account to associate this project with" type = string } diff --git a/modules/gsuite_enabled/README.md b/modules/gsuite_enabled/README.md index 3c897f6e..a7d5114a 100644 --- a/modules/gsuite_enabled/README.md +++ b/modules/gsuite_enabled/README.md @@ -69,7 +69,7 @@ The roles granted are specifically: | budget\_alert\_spent\_percents | A list of percentages of the budget to alert on when threshold is exceeded | `list(number)` |
[
0.5,
0.7,
1
]
| no | | budget\_amount | The amount to use for a budget alert | `number` | `null` | no | | budget\_monitoring\_notification\_channels | A list of monitoring notification channels in the form `[projects/{project_id}/notificationChannels/{channel_id}]`. A maximum of 5 channels are allowed. | `list(string)` | `[]` | no | -| consumer\_quotas | The quotas configuration you want to override for the project. |
list(object({
service = string,
metric = string,
limit = string,
value = string,
}))
| `[]` | no | +| consumer\_quotas | The quotas configuration you want to override for the project. |
list(object({
service = string,
metric = string,
dimensions = any,
limit = string,
value = string,
}))
| `[]` | no | | create\_group | Whether to create the group or not | `bool` | `false` | no | | create\_project\_sa | Whether the default service account for the project shall be created | `bool` | `true` | no | | default\_network\_tier | Default Network Service Tier for resources created in this project. If unset, the value will not be modified. See https://cloud.google.com/network-tiers/docs/using-network-service-tiers and https://cloud.google.com/network-tiers. | `string` | `""` | no | diff --git a/modules/gsuite_enabled/variables.tf b/modules/gsuite_enabled/variables.tf index 6ae8adcb..d81e3736 100644 --- a/modules/gsuite_enabled/variables.tf +++ b/modules/gsuite_enabled/variables.tf @@ -213,10 +213,11 @@ variable "budget_alert_spent_percents" { variable "consumer_quotas" { description = "The quotas configuration you want to override for the project." type = list(object({ - service = string, - metric = string, - limit = string, - value = string, + service = string, + metric = string, + dimensions = any, + limit = string, + value = string, })) default = [] } diff --git a/modules/quota_manager/README.md b/modules/quota_manager/README.md index 642ce573..3054caa3 100644 --- a/modules/quota_manager/README.md +++ b/modules/quota_manager/README.md @@ -14,11 +14,13 @@ module "project_quota_manager" { { service = "compute.googleapis.com" metric = "SimulateMaintenanceEventGroup" + dimensions = { region = "us-central1" } limit = "%2F100s%2Fproject" value = "19" },{ service = "servicemanagement.googleapis.com" metric = "servicemanagement.googleapis.com%2Fdefault_requests" + dimensions = {} limit = "%2Fmin%2Fproject" value = "95" } @@ -31,7 +33,7 @@ module "project_quota_manager" { | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| consumer\_quotas | The quotas configuration you want to override for the project. |
list(object({
service = string,
metric = string,
limit = string,
value = string,
}))
| n/a | yes | +| consumer\_quotas | The quotas configuration you want to override for the project. |
list(object({
service = string,
metric = string,
dimensions = map(string),
limit = string,
value = string,
}))
| n/a | yes | | project\_id | The GCP project where you want to manage the consumer quotas | `string` | n/a | yes | ## Outputs diff --git a/modules/quota_manager/main.tf b/modules/quota_manager/main.tf index 7c79efde..eeb9975b 100644 --- a/modules/quota_manager/main.tf +++ b/modules/quota_manager/main.tf @@ -26,6 +26,7 @@ resource "google_service_usage_consumer_quota_override" "override" { service = each.value.service metric = each.value.metric limit = each.value.limit + dimensions = each.value.dimensions override_value = each.value.value force = true } diff --git a/modules/quota_manager/variables.tf b/modules/quota_manager/variables.tf index 836239f8..fad0bad5 100644 --- a/modules/quota_manager/variables.tf +++ b/modules/quota_manager/variables.tf @@ -22,9 +22,10 @@ variable "project_id" { variable "consumer_quotas" { description = "The quotas configuration you want to override for the project." type = list(object({ - service = string, - metric = string, - limit = string, - value = string, + service = string, + metric = string, + dimensions = map(string), + limit = string, + value = string, })) } diff --git a/modules/quota_manager/versions.tf b/modules/quota_manager/versions.tf index bf5e2a86..3a458391 100644 --- a/modules/quota_manager/versions.tf +++ b/modules/quota_manager/versions.tf @@ -20,7 +20,7 @@ terraform { required_providers { google-beta = { source = "hashicorp/google-beta" - version = ">= 3.1, < 5.0" + version = "~> 4.11" } } } diff --git a/test/integration/go.mod b/test/integration/go.mod index 6475650a..641b4b87 100644 --- a/test/integration/go.mod +++ b/test/integration/go.mod @@ -3,11 +3,13 @@ module github.com/terraform-google-modules/terraform-google-project-factory/test go 1.17 require ( - github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test v0.0.0-20220204062018-068713996f36 + github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test v0.0.0-20220401205256-9f9a444009fd github.com/stretchr/testify v1.7.0 + golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d ) require ( + cloud.google.com/go v0.51.0 // indirect github.com/PuerkitoBio/purell v1.1.1 // indirect github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/agext/levenshtein v1.2.1 // indirect @@ -18,6 +20,7 @@ require ( github.com/go-openapi/jsonpointer v0.19.3 // indirect github.com/go-openapi/jsonreference v0.19.3 // indirect github.com/go-openapi/swag v0.19.5 // indirect + github.com/golang/protobuf v1.4.2 // indirect github.com/gruntwork-io/terratest v0.35.6 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.0 // indirect @@ -28,14 +31,17 @@ require ( github.com/mitchellh/go-testing-interface v1.14.2-0.20210217184823-a52172cd2f64 // indirect github.com/mitchellh/go-wordwrap v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/tidwall/gjson v1.10.2 // indirect + github.com/tidwall/gjson v1.12.1 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect + github.com/tidwall/sjson v1.2.4 // indirect github.com/zclconf/go-cty v1.2.1 // indirect golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 // indirect golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420 // indirect golang.org/x/sys v0.0.0-20210603125802-9665404d3644 // indirect golang.org/x/text v0.3.6 // indirect + google.golang.org/appengine v1.6.5 // indirect + google.golang.org/protobuf v1.24.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e // indirect diff --git a/test/integration/go.sum b/test/integration/go.sum index 0e6120e9..d5763d8e 100644 --- a/test/integration/go.sum +++ b/test/integration/go.sum @@ -5,6 +5,7 @@ cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6A cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.51.0 h1:PvKAVQWCtlGUSlZkGW3QLelKaWq7KYv/MW1EboG8bfM= cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= @@ -49,9 +50,12 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test v0.0.0-20220204062018-068713996f36 h1:Ltv5FXAgDfewg5Ol3dsMgJdzVr5sn88sGzaqbA3L2RE= github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test v0.0.0-20220204062018-068713996f36/go.mod h1:tWoaVHXM9sZyzxgX2+UHtzdJkav+uTnTJiz42N8FONc= +github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test v0.0.0-20220401205256-9f9a444009fd h1:2CAwT6SraFFMo5m7vISiP4fXXRcua6BpN0aYB7gv46E= +github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test v0.0.0-20220401205256-9f9a444009fd/go.mod h1:ZA21UTC1O82Y8uUfWFDe9rll4pZD/1kpPCC1HSpL2T0= github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/list-setters v0.1.0/go.mod h1:ju1d4EAij/igLgN+0er7tPc1nTKn/PTjY00buPEsx0Q= github.com/GoogleContainerTools/kpt-functions-sdk/go v0.0.0-20210810181223-632b30549de6/go.mod h1:k86q33ABlA9TnUqRmHH9dnKY2Edh8YbxjRyPfjlM8jE= +github.com/GoogleContainerTools/kpt-functions-sdk/go v0.0.0-20220301220754-6964a09d6cd2/go.mod h1:lJYiqfBOl6AOiefK9kmkhinbffIysu+nnclOBwKEPlQ= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -243,6 +247,7 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -480,11 +485,15 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/tidwall/gjson v1.10.2 h1:APbLGOM0rrEkd8WBw9C24nllro4ajFuJu0Sc9hRz8Bo= github.com/tidwall/gjson v1.10.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.12.1 h1:ikuZsLdhr8Ws0IdROXUS1Gi4v9Z4pGqpX/CvJkxvfpo= +github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/sjson v1.2.4 h1:cuiLzLnaMeBhRmEv00Lpk3tkYrcxpmbU81tAY4Dw0tc= +github.com/tidwall/sjson v1.2.4/go.mod h1:098SZ494YoMWPmMO6ct4dcFnqxwj9r/gF0Etp19pSNM= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= @@ -601,6 +610,7 @@ golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAG golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -695,6 +705,7 @@ golang.org/x/tools v0.0.0-20201110201400-7099162a900a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= @@ -710,6 +721,7 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= @@ -739,6 +751,7 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/test/integration/quota_project/quota_project_test.go b/test/integration/quota_project/quota_project_test.go new file mode 100644 index 00000000..a88e9a99 --- /dev/null +++ b/test/integration/quota_project/quota_project_test.go @@ -0,0 +1,79 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package quota_project + +import ( + "context" + "fmt" + "io" + "net/url" + "testing" + + "github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test/pkg/gcloud" + "github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test/pkg/tft" + "github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test/pkg/utils" + "github.com/stretchr/testify/assert" + "golang.org/x/oauth2/google" +) + +func TestQuotaProject(t *testing.T) { + quotaProjectT := tft.NewTFBlueprintTest(t) + + quotaProjectT.DefineVerify(func(assert *assert.Assertions) { + quotaProjectT.DefaultVerify(assert) + + projectID := quotaProjectT.GetStringOutput("project_id") + + apis := gcloud.Runf(t, "services list --project %s", projectID) + assert.Equal("ENABLED", apis.Get("#(config.name==\"serviceusage.googleapis.com\").state").String(), "Service Usage API is enabled") + assert.Equal("ENABLED", apis.Get("#(config.name==\"compute.googleapis.com\").state").String(), "Compute Engine API is enabled") + assert.Equal("ENABLED", apis.Get("#(config.name==\"servicemanagement.googleapis.com\").state").String(), "Service Management API is enabled") + + // Use Service Usage API to get display consumer quota information + httpClient, err := google.DefaultClient(context.Background(), "https://www.googleapis.com/auth/cloud-platform") + assert.NoError(err) + serviceUsageEndpoint := fmt.Sprintf( + "https://serviceusage.googleapis.com/v1beta1/projects/%s/services/%s/consumerQuotaMetrics/%s/limits/%s/consumerOverrides", + projectID, + "compute.googleapis.com", + url.QueryEscape("compute.googleapis.com/n2_cpus"), + url.QueryEscape("/project/region")) + resp, err := httpClient.Get(serviceUsageEndpoint) + assert.NoError(err) + + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + assert.NoError(err) + result := utils.ParseJSONResult(t, string(body)) + assert.Equal("10", result.Get("overrides.0.overrideValue").String(), "has correct consumer quota override value") + assert.Equal("us-central1", result.Get("overrides.0.dimensions.region").String(), "has correct consumer quota override dimensions") + + serviceUsageEndpoint = fmt.Sprintf( + "https://serviceusage.googleapis.com/v1beta1/projects/%s/services/%s/consumerQuotaMetrics/%s/limits/%s/consumerOverrides", + projectID, + "servicemanagement.googleapis.com", + url.QueryEscape("servicemanagement.googleapis.com/default_requests"), + url.QueryEscape("/min/project")) + resp, err = httpClient.Get(serviceUsageEndpoint) + assert.NoError(err) + body, err = io.ReadAll(resp.Body) + assert.NoError(err) + result = utils.ParseJSONResult(t, string(body)) + assert.Equal("95", result.Get("overrides.0.overrideValue").String(), "has correct consumer quota override value") + assert.False(result.Get("overrides.0.dimensions").Exists(), "has empty dimensions") + }) + quotaProjectT.Test() +} diff --git a/test/setup/main.tf b/test/setup/main.tf index 5df3cbeb..1f703391 100644 --- a/test/setup/main.tf +++ b/test/setup/main.tf @@ -46,7 +46,8 @@ module "pfactory_project" { "billingbudgets.googleapis.com", "pubsub.googleapis.com", "accesscontextmanager.googleapis.com", - "essentialcontacts.googleapis.com" + "essentialcontacts.googleapis.com", + "serviceconsumermanagement.googleapis.com" ] } diff --git a/test/setup/versions.tf b/test/setup/versions.tf index e28094a1..ead51540 100644 --- a/test/setup/versions.tf +++ b/test/setup/versions.tf @@ -19,11 +19,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = "~> 3.8" + version = "~> 4.5" } google-beta = { source = "hashicorp/google-beta" - version = "~> 3.8" + version = "~> 4.5" } null = { source = "hashicorp/null" diff --git a/variables.tf b/variables.tf index 8e420e12..c3414566 100644 --- a/variables.tf +++ b/variables.tf @@ -284,10 +284,11 @@ variable "grant_network_role" { variable "consumer_quotas" { description = "The quotas configuration you want to override for the project." type = list(object({ - service = string, - metric = string, - limit = string, - value = string, + service = string, + metric = string, + dimensions = map(string), + limit = string, + value = string, })) default = [] }