diff --git a/main.tf b/main.tf index 1acbe9f6..c55a3dab 100755 --- a/main.tf +++ b/main.tf @@ -35,6 +35,7 @@ module "project-factory" { random_project_id = "${var.random_project_id}" org_id = "${var.org_id}" name = "${var.name}" + project_id = "${var.project_id}" shared_vpc = "${var.shared_vpc}" billing_account = "${var.billing_account}" folder_id = "${var.folder_id}" diff --git a/modules/core_project_factory/main.tf b/modules/core_project_factory/main.tf index 041832bd..c4862b32 100644 --- a/modules/core_project_factory/main.tf +++ b/modules/core_project_factory/main.tf @@ -26,18 +26,17 @@ resource "random_id" "random_project_id_suffix" { *****************************************/ locals { group_id = "${var.manage_group ? format("group:%s", var.group_email) : ""}" - project_id = "${google_project.main.project_id}" - project_number = "${google_project.main.number}" + base_project_id = "${var.project_id == "" ? var.name : var.project_id}" project_org_id = "${var.folder_id != "" ? "" : var.org_id}" project_folder_id = "${var.folder_id != "" ? var.folder_id : ""}" - temp_project_id = "${var.random_project_id ? format("%s-%s",var.name,random_id.random_project_id_suffix.hex) : var.name}" + temp_project_id = "${var.random_project_id ? format("%s-%s",local.base_project_id,random_id.random_project_id_suffix.hex) : local.base_project_id}" s_account_fmt = "${format("serviceAccount:%s", google_service_account.default_service_account.email)}" - api_s_account = "${format("%s@cloudservices.gserviceaccount.com", local.project_number)}" + api_s_account = "${format("%s@cloudservices.gserviceaccount.com", google_project.main.number)}" api_s_account_fmt = "${format("serviceAccount:%s", local.api_s_account)}" gke_shared_vpc_enabled = "${var.shared_vpc != "" && contains(var.activate_apis, "container.googleapis.com") ? "true" : "false"}" - gke_s_account = "${format("service-%s@container-engine-robot.iam.gserviceaccount.com", local.project_number)}" + gke_s_account = "${format("service-%s@container-engine-robot.iam.gserviceaccount.com", google_project.main.number)}" gke_s_account_fmt = "${local.gke_shared_vpc_enabled ? format("serviceAccount:%s", local.gke_s_account) : ""}" - project_bucket_name = "${var.bucket_name != "" ? var.bucket_name : format("%s-state", var.name)}" + project_bucket_name = "${var.bucket_name != "" ? var.bucket_name : format("%s-state", local.temp_project_id)}" create_bucket = "${var.bucket_project != "" ? "true" : "false"}" shared_vpc_users = "${compact(list(local.group_id, local.s_account_fmt, local.api_s_account_fmt, local.gke_s_account_fmt))}" @@ -104,7 +103,7 @@ resource "google_resource_manager_lien" "lien" { resource "google_project_service" "project_services" { count = "${length(var.activate_apis)}" - project = "${local.project_id}" + project = "${google_project.main.project_id}" service = "${element(var.activate_apis, count.index)}" disable_on_destroy = "${var.disable_services_on_destroy}" @@ -119,7 +118,7 @@ resource "google_compute_shared_vpc_service_project" "shared_vpc_attachment" { count = "${var.shared_vpc != "" ? 1 : 0}" host_project = "${var.shared_vpc}" - service_project = "${local.project_id}" + service_project = "${google_project.main.project_id}" depends_on = ["google_project_service.project_services"] } @@ -138,7 +137,7 @@ data "null_data_source" "default_service_account" { *****************************************/ resource "null_resource" "delete_default_compute_service_account" { provisioner "local-exec" { - command = "${path.module}/scripts/delete-service-account.sh ${local.project_id} ${data.null_data_source.default_service_account.outputs["email"]} ${var.credentials_path}" + command = "${path.module}/scripts/delete-service-account.sh ${google_project.main.project_id} ${data.null_data_source.default_service_account.outputs["email"]} ${var.credentials_path}" } triggers { @@ -155,7 +154,7 @@ resource "null_resource" "delete_default_compute_service_account" { resource "google_service_account" "default_service_account" { account_id = "project-service-account" display_name = "${var.name} Project Service Account" - project = "${local.project_id}" + project = "${google_project.main.project_id}" } /************************************************** @@ -163,7 +162,7 @@ resource "google_service_account" "default_service_account" { *************************************************/ resource "google_project_iam_member" "default_service_account_membership" { count = "${var.sa_role != "" ? 1 : 0}" - project = "${local.project_id}" + project = "${google_project.main.project_id}" role = "${var.sa_role}" member = "${local.s_account_fmt}" @@ -176,7 +175,7 @@ resource "google_project_iam_member" "gsuite_group_role" { count = "${var.manage_group ? 1 : 0}" member = "${local.group_id}" - project = "${local.project_id}" + project = "${google_project.main.project_id}" role = "${var.group_role}" } @@ -189,7 +188,7 @@ resource "google_service_account_iam_member" "service_account_grant_to_group" { member = "${local.group_id}" role = "roles/iam.serviceAccountUser" - service_account_id = "projects/${local.project_id}/serviceAccounts/${ + service_account_id = "projects/${google_project.main.project_id}/serviceAccounts/${ google_service_account.default_service_account.email }" } @@ -261,9 +260,9 @@ resource "google_compute_subnetwork_iam_member" "apis_service_account_role_to_vp resource "google_project_usage_export_bucket" "usage_report_export" { count = "${var.usage_bucket_name != "" ? 1 : 0}" - project = "${local.project_id}" + project = "${google_project.main.project_id}" bucket_name = "${var.usage_bucket_name}" - prefix = "${var.usage_bucket_prefix != "" ? var.usage_bucket_prefix : "usage-${local.project_id}"}" + prefix = "${var.usage_bucket_prefix != "" ? var.usage_bucket_prefix : "usage-${google_project.main.project_id}"}" depends_on = ["google_project_service.project_services"] } diff --git a/modules/core_project_factory/outputs.tf b/modules/core_project_factory/outputs.tf index d1d05e18..8c55a02a 100644 --- a/modules/core_project_factory/outputs.tf +++ b/modules/core_project_factory/outputs.tf @@ -14,12 +14,16 @@ * limitations under the License. */ +output "project_name" { + value = "${google_project.main.name}" +} + output "project_id" { - value = "${local.project_id}" + value = "${google_project.main.project_id}" } output "project_number" { - value = "${local.project_number}" + value = "${google_project.main.number}" } output "service_account_id" { diff --git a/modules/core_project_factory/variables.tf b/modules/core_project_factory/variables.tf index 2fd90d86..d8013106 100644 --- a/modules/core_project_factory/variables.tf +++ b/modules/core_project_factory/variables.tf @@ -34,8 +34,13 @@ variable "manage_group" { default = "false" } +variable "project_id" { + description = "If provided, the project uses the given project ID. Mutually exclusive with random_project_id being true." + default = "" +} + variable "random_project_id" { - description = "Enables project random id generation" + description = "Enables project random id generation. Mutually exclusive with project_id being non-empty." default = "false" } diff --git a/modules/gsuite_enabled/main.tf b/modules/gsuite_enabled/main.tf index f207e51b..b5118a67 100644 --- a/modules/gsuite_enabled/main.tf +++ b/modules/gsuite_enabled/main.tf @@ -72,6 +72,7 @@ module "project-factory" { random_project_id = "${var.random_project_id}" org_id = "${var.org_id}" name = "${var.name}" + project_id = "${var.project_id}" shared_vpc = "${var.shared_vpc}" billing_account = "${var.billing_account}" folder_id = "${var.folder_id}" diff --git a/modules/gsuite_enabled/outputs.tf b/modules/gsuite_enabled/outputs.tf index 0a78849e..70d38293 100644 --- a/modules/gsuite_enabled/outputs.tf +++ b/modules/gsuite_enabled/outputs.tf @@ -14,6 +14,10 @@ * limitations under the License. */ +output "project_name" { + value = "${module.project-factory.project_name}" +} + output "project_id" { value = "${module.project-factory.project_id}" } diff --git a/modules/gsuite_enabled/variables.tf b/modules/gsuite_enabled/variables.tf index a2749086..731c9f46 100644 --- a/modules/gsuite_enabled/variables.tf +++ b/modules/gsuite_enabled/variables.tf @@ -21,7 +21,7 @@ variable "lien" { } variable "random_project_id" { - description = "Enables project random id generation" + description = "Enables project random id generation. Mutually exclusive with project_id being non-empty." default = "false" } @@ -38,6 +38,11 @@ variable "name" { description = "The name for the project" } +variable "project_id" { + description = "If provided, the project uses the given project ID. Mutually exclusive with random_project_id being true." + default = "" +} + variable "shared_vpc" { description = "The ID of the host project which hosts the shared VPC" default = "" diff --git a/outputs.tf b/outputs.tf index 3e814458..245375d1 100755 --- a/outputs.tf +++ b/outputs.tf @@ -14,6 +14,10 @@ * limitations under the License. */ +output "project_name" { + value = "${module.project-factory.project_name}" +} + output "project_id" { value = "${module.project-factory.project_id}" } diff --git a/test/fixtures/full/main.tf b/test/fixtures/full/main.tf index 6400cf99..33383d69 100644 --- a/test/fixtures/full/main.tf +++ b/test/fixtures/full/main.tf @@ -76,8 +76,9 @@ module "vpc" { module "project-factory" { source = "../../../modules/gsuite_enabled" - name = "pf-ci-test-full-${random_string.suffix.result}" - random_project_id = "true" + name = "pf-ci-test-full-name-${random_string.suffix.result}" + random_project_id = "false" + project_id = "pf-ci-test-full-id-${random_string.suffix.result}" domain = "${var.domain}" org_id = "${var.org_id}" diff --git a/test/fixtures/shared/outputs.tf b/test/fixtures/shared/outputs.tf index 4cd3fe35..c1b5116f 100644 --- a/test/fixtures/shared/outputs.tf +++ b/test/fixtures/shared/outputs.tf @@ -14,6 +14,10 @@ * limitations under the License. */ +output "project_name" { + value = "${module.project-factory.project_name}" +} + output "project_id" { value = "${module.project-factory.project_id}" } diff --git a/test/integration/full/controls/project-factory.rb b/test/integration/full/controls/project-factory.rb index 3b6109dc..e51e287a 100644 --- a/test/integration/full/controls/project-factory.rb +++ b/test/integration/full/controls/project-factory.rb @@ -13,6 +13,7 @@ # limitations under the License. extra_service_account_email = attribute('extra_service_account_email') +project_name = attribute('project_name') project_id = attribute('project_id') sa_role = attribute('sa_role') service_account_email = attribute('service_account_email') @@ -26,9 +27,20 @@ control 'project-factory' do title 'Project Factory' - describe command("gcloud projects describe #{project_id}") do + describe command("gcloud projects describe #{project_id} --format=json") do its('exit_status') { should be 0 } its('stderr') { should eq '' } + + let(:metadata) do + if subject.exit_status == 0 + JSON.parse(subject.stdout, symbolize_names: true) + else + {} + end + end + + it { expect(metadata).to include(name: project_name) } + it { expect(metadata).to include(projectId: project_id) } end describe command("gcloud services list --project #{project_id}") do diff --git a/test/integration/full/inspec.yml b/test/integration/full/inspec.yml index f9df4ccd..0efbdb24 100644 --- a/test/integration/full/inspec.yml +++ b/test/integration/full/inspec.yml @@ -1,5 +1,9 @@ name: full attributes: + - name: project_name + required: true + type: string + - name: project_id required: true type: string diff --git a/test/integration/minimal/controls/minimal.rb b/test/integration/minimal/controls/minimal.rb index 3191bb58..1fd20c4d 100644 --- a/test/integration/minimal/controls/minimal.rb +++ b/test/integration/minimal/controls/minimal.rb @@ -18,9 +18,20 @@ control 'project-factory-minimal' do title 'Project Factory minimal configuration' - describe command("gcloud projects describe #{project_id}") do + describe command("gcloud projects describe #{project_id} --format=json") do its('exit_status') { should be 0 } its('stderr') { should eq '' } + + let(:metadata) do + if subject.exit_status == 0 + JSON.parse(subject.stdout, symbolize_names: true) + else + {} + end + end + + it { expect(metadata).to include(name: project_id[0...-5]) } + it { expect(metadata).to include(projectId: project_id) } end describe command("gcloud services list --project #{project_id}") do diff --git a/variables.tf b/variables.tf index b35ca2bd..ab55c80c 100755 --- a/variables.tf +++ b/variables.tf @@ -15,7 +15,7 @@ */ variable "random_project_id" { - description = "Enables project random id generation" + description = "Enables project random id generation. Mutually exclusive with project_id being non-empty." default = "false" } @@ -32,6 +32,11 @@ variable "name" { description = "The name for the project" } +variable "project_id" { + description = "If provided, the project uses the given project ID. Mutually exclusive with random_project_id being true." + default = "" +} + variable "shared_vpc" { description = "The ID of the host project which hosts the shared VPC" default = ""