Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RAD Lab Module to create GCP Projects with Billing budgets #58

Merged
merged 3 commits into from
May 17, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Initial Commit for Billing Budget Module
  • Loading branch information
guptamukul-google committed May 13, 2022
commit a1a2cdc1a13818a5922b8ef946d701d1874e6383
Binary file added docs/images/V7_Billing_Budget.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
65 changes: 65 additions & 0 deletions modules/billing_budget/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# RAD Lab Billing Budget Module

This module creates a simple GCP project, enables APIs, adds users to the project and also creates a Billing Budget for the Project.

## GCP Products/Services

* GCP Project
* APIs & Services
* Billing Budget

## Reference Architecture Diagram

Below Architechture Diagram is the base representation of what will be created as a part of [RAD Lab Launcher](../../radlab-launcher/radlab.py).

![](../../docs/images/V7_Billing_Budget.png)

## API Prerequisites

In the RAD Lab Management Project make sure that _Cloud Billing Budget API (`billingbudgets.googleapis.com`)_ is enabled.

## IAM Permissions Prerequisites

Create a Terraform Service Account in RAD Lab Management Project to execute / deploy the RAD Lab module. Ensure that the Service Account has the following IAM permissions, **when creating the project** (`create_project` = true):

- Parent: `roles/resourcemanager.projectCreator`
- Parent: `roles/billing.user`
- Parent: `roles/billing.costsManager`

The User, Group, or Service Account who will be deploying the module should have access to impersonate and grant it the roles, `roles/iam.serviceAccountTokenCreator` on the **Terraform Service Account’s IAM Policy**.

Note: This is not a Project IAM Binding; this is a **Service Account** IAM Binding.

NOTE: Additional [permissions](../../radlab-launcher/README.md#iam-permissions-prerequisites) are required when deploying the RAD Lab modules via [RAD Lab Launcher](../../radlab-launcher)


<!-- BEGIN TFDOC -->
## Variables

| name | description | type | required | default |
|---|---|:---: |:---:|:---:|
| billing_account_id | Billing Account associated to the GCP Resources | <code title="">string</code> | ✓ | |
| *apis* | The list of GCP apis to enable. | <code title="set&#40;string&#41;">set(string)</code> | | <code title="">["compute.googleapis.com","bigquery.googleapis.com","bigquerystorage.googleapis.com"]</code> |
| *billing_budget_alert_spend_basis* | The type of basis used to determine if spend has passed the threshold | <code title="">string</code> | | <code title="">CURRENT_SPEND</code> |
| *billing_budget_alert_spent_percents* | A list of percentages of the budget to alert on when threshold is exceeded | <code title="list&#40;number&#41;">list(number)</code> | | <code title="">[0.5,0.7,1]</code> |
| *billing_budget_amount* | The amount to use as the budget in USD | <code title="">number</code> | | <code title="">1000</code> |
| *billing_budget_credit_types_treatment* | Specifies how credits should be treated when determining spend for threshold calculations | <code title="">string</code> | | <code title="">INCLUDE_ALL_CREDITS</code> |
| *billing_budget_labels* | A single label and value pair specifying that usage from only this set of labeled resources should be included in the budget. | <code title="map&#40;string&#41;">map(string)</code> | | <code title="&#123;&#125;&#10;validation &#123;&#10;condition &#61; length&#40;var.billing_budget_labels&#41; &#60;&#61; 1&#10;error_message &#61; &#34;Only 0 or 1 labels may be supplied for the budget filter.&#34;&#10;&#125;">...</code> |
| *billing_budget_services* | A list of services ids to be included in the budget. If omitted, all services will be included in the budget. Service ids can be found at https://cloud.google.com/skus/ | <code title="list&#40;string&#41;">list(string)</code> | | <code title="">null</code> |
| *create_project* | Set to true if the module has to create a project. If you want to deploy in an existing project, set this variable to false. | <code title="">bool</code> | | <code title="">true</code> |
| *enable_services* | Enable the necessary APIs on the project. When using an existing project, this can be set to false. | <code title="">bool</code> | | <code title="">true</code> |
| *folder_id* | Folder ID where the project should be created. It can be skipped if already setting organization_id. Leave blank if the project should be created directly underneath the Organization node. | <code title="">string</code> | | <code title=""></code> |
| *organization_id* | Organization ID where GCP Resources need to get spin up. It can be skipped if already setting folder_id | <code title="">string</code> | | <code title=""></code> |
| *project_name* | Project name or ID, if it's an existing project. | <code title="">string</code> | | <code title="">radlab-billing-budget</code> |
| *random_id* | Adds a suffix of 4 random characters to the `project_id` | <code title="">string</code> | | <code title="">null</code> |
| *sa* | Terraform Service Account which will be creating the GCP resources | <code title="">string</code> | | <code title=""></code> |
| *trusted_users* | The list of trusted users who will be assigned Editor role on the project | <code title="set&#40;string&#41;">set(string)</code> | | <code title="">[]</code> |

## Outputs

| name | description | sensitive |
|---|---|:---:|
| billing_budget_budgetId | Resource name of the budget. Values are of the form `billingAccounts/{billingAccountId}/budgets/{budgetId}` | |
| deployment_id | RADLab Module Deployment ID | |
| project-radlab-billing-budget-id | GCP Project ID | |
<!-- END TFDOC -->
120 changes: 120 additions & 0 deletions modules/billing_budget/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/**
* Copyright 2022 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.
*/


provider "google" {
alias = "impersonated"
scopes = [
"https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/userinfo.email"
]
}

data "google_service_account_access_token" "default" {
provider = google.impersonated
scopes = ["userinfo-email", "cloud-platform"]
target_service_account = var.sa
lifetime = "1800s"
}

provider "google" {
access_token = data.google_service_account_access_token.default.access_token
}

provider "google-beta" {
access_token = data.google_service_account_access_token.default.access_token
}


locals {
random_id = var.random_id != null ? var.random_id : random_id.default.hex
project = (var.create_project
? try(module.project_radlab_billing_budget.0, null)
: try(data.google_project.existing_project.0, null)
)

project_services = var.enable_services ? var.apis : []
}

resource "random_id" "default" {
byte_length = 2
}

###############
# GCP PROJECT #
###############

data "google_project" "existing_project" {
count = var.create_project ? 0 : 1
project_id = var.project_name
}

module "project_radlab_billing_budget" {
count = var.create_project ? 1 : 0
source = "terraform-google-modules/project-factory/google"
version = "~> 11.0"

name = format("%s-%s", var.project_name, local.random_id)
random_project_id = false
folder_id = var.folder_id
billing_account = var.billing_account_id
org_id = var.organization_id

activate_apis = []
}


resource "google_project_service" "enabled_services" {
for_each = toset(local.project_services)
project = local.project.project_id
service = each.value
disable_dependent_services = true
disable_on_destroy = true
}

resource "time_sleep" "wait_120_seconds" {
count = var.enable_services ? 1 : 0
create_duration = "120s"

depends_on = [
google_project_service.enabled_services
]
}

module "billing_budget" {
source = "terraform-google-modules/project-factory/google//modules/budget"
display_name = format("RADLab Billing Budget - %s", local.project.project_id)
billing_account = var.billing_account_id
projects = ["${local.project.project_id}"]
amount = var.billing_budget_amount
alert_spend_basis = var.billing_budget_alert_spend_basis
alert_spent_percents = var.billing_budget_alert_spent_percents
credit_types_treatment = var.billing_budget_credit_types_treatment
labels = var.billing_budget_labels
services = var.billing_budget_services

depends_on = [
time_sleep.wait_120_seconds
]

}

resource "google_project_iam_member" "user_role_assignment" {
for_each = var.trusted_users
project = local.project.project_id
member = each.value
role = "roles/editor"
}
30 changes: 30 additions & 0 deletions modules/billing_budget/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* Copyright 2022 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.
*/

output "deployment_id" {
description = "RADLab Module Deployment ID"
value = local.random_id
}

output "project-radlab-billing-budget-id" {
description = "GCP Project ID"
value = local.project.project_id
}

output "billing_budget_budgetId" {
description = "Resource name of the budget. Values are of the form `billingAccounts/{billingAccountId}/budgets/{budgetId}`"
value = module.billing_budget.name
}
114 changes: 114 additions & 0 deletions modules/billing_budget/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/**
* Copyright 2022 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.
*/

variable "apis" {
description = "The list of GCP apis to enable."
type = set(string)
default = ["compute.googleapis.com","bigquery.googleapis.com","bigquerystorage.googleapis.com"]
}

variable "billing_account_id" {
description = "Billing Account associated to the GCP Resources"
type = string
}

variable "billing_budget_alert_spend_basis" {
description = "The type of basis used to determine if spend has passed the threshold"
type = string
default = "CURRENT_SPEND"
}

variable "billing_budget_alert_spent_percents" {
description = "A list of percentages of the budget to alert on when threshold is exceeded"
type = list(number)
default = [0.5,0.7,1]
}

variable "billing_budget_amount" {
description = "The amount to use as the budget in USD"
type = number
default = 1000
}

variable "billing_budget_credit_types_treatment" {
description = "Specifies how credits should be treated when determining spend for threshold calculations"
type = string
default = "INCLUDE_ALL_CREDITS"
}

variable "billing_budget_labels" {
description = "A single label and value pair specifying that usage from only this set of labeled resources should be included in the budget."
type = map(string)
default = {}
validation {
condition = length(var.billing_budget_labels) <= 1
error_message = "Only 0 or 1 labels may be supplied for the budget filter."
}
}

variable "billing_budget_services" {
description = "A list of services ids to be included in the budget. If omitted, all services will be included in the budget. Service ids can be found at https://cloud.google.com/skus/"
type = list(string)
default = null
}

variable "create_project" {
description = "Set to true if the module has to create a project. If you want to deploy in an existing project, set this variable to false."
type = bool
default = true
}

variable "enable_services" {
description = "Enable the necessary APIs on the project. When using an existing project, this can be set to false."
type = bool
default = true
}

variable "folder_id" {
description = "Folder ID where the project should be created. It can be skipped if already setting organization_id. Leave blank if the project should be created directly underneath the Organization node. "
type = string
default = ""
}

variable "organization_id" {
description = "Organization ID where GCP Resources need to get spin up. It can be skipped if already setting folder_id"
type = string
default = ""
}

variable "project_name" {
description = "Project name or ID, if it's an existing project."
type = string
default = "radlab-billing-budget"
}

variable "random_id" {
description = "Adds a suffix of 4 random characters to the `project_id`"
type = string
default = null
}

variable "sa" {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we rename this to something more meaningful? resource_creator_identity or something?

description = "Terraform Service Account which will be creating the GCP resources"
type = string
default = ""
}

variable "trusted_users" {
description = "The list of trusted users who will be assigned Editor role on the project"
type = set(string)
default = []
}
24 changes: 24 additions & 0 deletions modules/billing_budget/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* Copyright 2022 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.
*/

terraform {
required_version = "~> 1.0"

required_providers {
google = ">= 3.87.0"
google-beta = ">= 3.87.0"
}
}