Skip to content

Commit 4403dbe

Browse files
authored
feat: Update project cleaner function to clean up Cloud Endpoints (#38)
1 parent 909d428 commit 4403dbe

File tree

11 files changed

+90
-17
lines changed

11 files changed

+90
-17
lines changed

.kitchen.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
driver:
1717
name: "terraform"
1818
command_timeout: 1800
19+
verify_version: false
1920

2021
provisioner:
2122
name: "terraform"

build/int.cloudbuild.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,4 @@ tags:
3838
- 'integration'
3939
substitutions:
4040
_DOCKER_IMAGE_DEVELOPER_TOOLS: 'cft/developer-tools'
41-
_DOCKER_TAG_VERSION_DEVELOPER_TOOLS: '0.6.0'
41+
_DOCKER_TAG_VERSION_DEVELOPER_TOOLS: '0'

examples/logs-slack-alerts/main.tf

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,13 @@
1515
*/
1616

1717
provider "google-beta" {
18-
version = "~> 2.1"
18+
version = "~> 3.33"
19+
project = var.project_id
20+
region = var.region
21+
}
22+
23+
provider "google" {
24+
version = "~> 3.33"
1925
project = var.project_id
2026
region = var.region
2127
}

examples/pubsub_scheduled/main.tf

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,13 @@ terraform {
1919
}
2020

2121
provider "google-beta" {
22-
version = "~> 2.5"
22+
version = "~> 3.33"
23+
project = var.project_id
24+
region = var.region
25+
}
26+
27+
provider "google" {
28+
version = "~> 3.33"
2329
project = var.project_id
2430
region = var.region
2531
}

examples/pubsub_scheduled_multiple/main.tf

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,13 @@ terraform {
1919
}
2020

2121
provider "google-beta" {
22-
version = "~> 2.5"
22+
version = "~> 3.33"
23+
project = var.project_id
24+
region = var.region
25+
}
26+
27+
provider "google" {
28+
version = "~> 3.33"
2329
project = var.project_id
2430
region = var.region
2531
}

modules/project_cleanup/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ The following services must be enabled on the project housing the cleanup functi
2121

2222
| Name | Description | Type | Default | Required |
2323
|------|-------------|:----:|:-----:|:-----:|
24-
| function\_timeout\_s | The amount of time in seconds allotted for the execution of the function. | number | `"60"` | no |
24+
| function\_timeout\_s | The amount of time in seconds allotted for the execution of the function. | number | `"500"` | no |
2525
| job\_schedule | Cleaner function run frequency, in cron syntax | string | `"*/5 * * * *"` | no |
2626
| max\_project\_age\_in\_hours | The maximum number of hours that a GCP project, selected by `target_tag_name` and `target_tag_value`, can exist | number | `"6"` | no |
2727
| organization\_id | The organization ID whose projects to clean up | string | n/a | yes |

modules/project_cleanup/function_source/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ The following environment variables may be specified to configure the cleanup ut
1616
| Name | Description | Type | Default | Required |
1717
|------|-------------|:----:|:-----:|:-----:|
1818
| `TARGET_EXCLUDED_LABELS` | Labels to match on for identifying projects to avoid deletion | string | n/a | no |
19-
| `TARGET_FOLDER_ID` | Folder ID to delete prjojects under | string | n/a | yes |
19+
| `TARGET_FOLDER_ID` | Folder ID to delete projects under | string | n/a | yes |
2020
| `TARGET_INCLUDED_LABELS` | Labels to match on for identifying projects to delete | string | n/a | no |
21-
| `MAX_PROJECT_AGE_HOURS` | The project age, in hours, at which point deletion should be considered | integer | n/a | no |
21+
| `MAX_PROJECT_AGE_HOURS` | The project age, in hours, at which point deletion should be considered | integer | n/a | yes |
2222

2323
## Required Permissions
2424

modules/project_cleanup/function_source/go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
module github.com/terraform-google-modules/project-cleaner
1+
module github.com/terraform-google-modules/terraform-google-scheduled-function/modules/project_cleanup
22

3-
go 1.11
3+
go 1.13
44

55
require (
66
golang.org/x/net v0.0.0-20190318221613-d196dffd7c2b

modules/project_cleanup/function_source/main.go

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
package project_cleaner
17+
package project_cleanup
1818

1919
import (
2020
"encoding/json"
@@ -26,10 +26,12 @@ import (
2626
"strconv"
2727
"strings"
2828
"time"
29+
2930
"golang.org/x/net/context"
3031
"golang.org/x/oauth2/google"
3132
"google.golang.org/api/cloudresourcemanager/v1"
3233
cloudresourcemanager2 "google.golang.org/api/cloudresourcemanager/v2"
34+
"google.golang.org/api/servicemanagement/v1"
3335
)
3436

3537
const (
@@ -123,6 +125,12 @@ func getLabelsMapFromEnv(envVariableName string) map[string]string {
123125
targetExcludedLabels := os.Getenv(envVariableName)
124126
logger.Println("Try to get labels map")
125127
labels := make(map[string]string)
128+
129+
if targetExcludedLabels == "" {
130+
logger.Printf("No labels provided.")
131+
return nil
132+
}
133+
126134
err := json.Unmarshal([]byte(targetExcludedLabels), &labels)
127135
if err != nil {
128136
logger.Printf("Fail to get labels map from [%s] env variable, error [%s]", envVariableName, err.Error())
@@ -141,6 +149,14 @@ func getCorrectFolderIdOrTerminateExecution() string {
141149
return targetFolderIdString
142150
}
143151

152+
func getServiceManagementServiceOrTerminateExecution(client *http.Client) *servicemanagement.APIService {
153+
service, err := servicemanagement.New(client)
154+
if err != nil {
155+
logger.Fatalf("Failed to get service management API client with error [%s], terminate execution", err.Error())
156+
}
157+
return service
158+
}
159+
144160
func getResourceManagerServiceOrTerminateExecution(client *http.Client) *cloudresourcemanager.Service {
145161
logger.Println("Try to get Cloud Resource Manager")
146162
cloudResourceManagerService, err := cloudresourcemanager.New(client)
@@ -175,6 +191,7 @@ func invoke(ctx context.Context) {
175191
client := initializeGoogleClient(ctx)
176192
cloudResourceManagerService := getResourceManagerServiceOrTerminateExecution(client)
177193
folderService := getFolderServiceOrTerminateExecution(client)
194+
endpointService := getServiceManagementServiceOrTerminateExecution(client)
178195

179196
removeLien := func(name string) {
180197
logger.Printf("Try to remove lien [%s]", name)
@@ -184,12 +201,44 @@ func invoke(ctx context.Context) {
184201
} else {
185202
logger.Printf("Removed lien [%s]", name)
186203
}
204+
}
205+
206+
removeProjectById := func(projectId string) error {
207+
_, err := cloudResourceManagerService.Projects.Delete(projectId).Context(ctx).Do()
208+
return err
209+
}
210+
211+
removeProjectEndpoints := func(projectId string) {
212+
logger.Printf("Try to remove endpoints for [%s]", projectId)
213+
listResponse, err := endpointService.Services.List().ProducerProjectId(projectId).Do()
214+
if err != nil {
215+
logger.Printf("Fail to list services for [%s], error [%s]", projectId, err.Error())
216+
return
217+
}
218+
219+
if len(listResponse.Services) <= 1 {
220+
return
221+
}
187222

223+
for _, service := range listResponse.Services {
224+
logger.Printf("Try to remove service: %s", service.ServiceName)
225+
_, err = endpointService.Services.Delete(service.ServiceName).Do()
226+
if err != nil {
227+
logger.Printf("Fail to delete service [%s] for [%s], error [%s]", service.ServiceName, projectId, err.Error())
228+
}
229+
}
230+
231+
// wait for services to complete deletion
232+
time.Sleep(10 * time.Second)
188233
}
189234

190-
removeProjectById := func(projectId string) {
235+
cleanupProjectById := func(projectId string) {
191236
logger.Printf("Try to remove project [%s]", projectId)
192-
_, err := cloudResourceManagerService.Projects.Delete(projectId).Context(ctx).Do()
237+
err := removeProjectById(projectId)
238+
if err != nil {
239+
removeProjectEndpoints(projectId)
240+
err = removeProjectById(projectId)
241+
}
193242
if err != nil {
194243
logger.Printf("Fail to remove project [%s], error [%s]", projectId, err.Error())
195244
} else {
@@ -206,7 +255,7 @@ func invoke(ctx context.Context) {
206255
for _, lien := range page.Liens {
207256
removeLien(lien.Name)
208257
}
209-
removeProjectById(projectId)
258+
cleanupProjectById(projectId)
210259
return nil
211260
}); err != nil {
212261
logger.Printf("Fail to get all liens for the project [%s], error [%s]", projectId, err.Error())

modules/project_cleanup/main.tf

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,16 @@ resource "google_service_account" "project_cleaner_function" {
2525
}
2626

2727
resource "google_organization_iam_member" "main" {
28-
for_each = toset(["projectDeleter", "folderViewer", "lienModifier"])
28+
for_each = toset([
29+
"roles/resourcemanager.projectDeleter",
30+
"roles/resourcemanager.folderViewer",
31+
"roles/resourcemanager.lienModifier",
32+
"roles/owner"
33+
])
2934

3035
member = "serviceAccount:${google_service_account.project_cleaner_function.email}"
3136
org_id = var.organization_id
32-
role = "roles/resourcemanager.${each.value}"
37+
role = each.value
3338
}
3439

3540
module "scheduled_project_cleaner" {
@@ -44,7 +49,7 @@ module "scheduled_project_cleaner" {
4449
topic_name = var.topic_name
4550
function_available_memory_mb = 128
4651
function_description = "Clean up GCP projects older than ${var.max_project_age_in_hours} hours matching particular tags"
47-
function_runtime = "go111"
52+
function_runtime = "go113"
4853
function_service_account_email = google_service_account.project_cleaner_function.email
4954
function_timeout_s = var.function_timeout_s
5055

0 commit comments

Comments
 (0)