Skip to content

Commit 0af0579

Browse files
Merge pull request #1 from devwithkrishna/feature/resourcelist
Add list of resources gt decmmisioned as a output in console
2 parents 492357a + 4d797ef commit 0af0579

File tree

5 files changed

+129
-5
lines changed

5 files changed

+129
-5
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: create release on azure terraforminator
2+
3+
on:
4+
pull_request:
5+
types:
6+
- closed
7+
branches:
8+
- main
9+
run-name: create release from pr number ${{ github.event.number }}
10+
jobs:
11+
create-release:
12+
runs-on: ubuntu-latest
13+
14+
steps:
15+
16+
- name: Token generator
17+
uses: githubofkrishnadhas/github-access-using-githubapp@v2
18+
id: token-generation
19+
with:
20+
github_app_id: ${{ secrets.TOKEN_GENERATOR_APPID }}
21+
github_app_private_key: ${{ secrets.TOKEN_GENERATOR_PRIVATE_KEY }}
22+
23+
- name: Checkout Repository
24+
uses: actions/checkout@v4
25+
with:
26+
token: ${{ steps.token-generation.outputs.token }}
27+
28+
- name: create-release
29+
uses: devwithkrishna/[email protected]
30+
with:
31+
token: ${{ steps.token-generation.outputs.token }}
32+
pr_number: ${{ github.event.number }}
33+
generate_release_notes: true

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
.idea/**
22
.env
33
poetry.lock
4-
4+
__pycache__/**
55

README.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,54 @@
11
# azure-terraforminator
22
A pipeline to delete unused resources in azure based on a specific tag
3+
4+
[![azure-decommision-unsed-resource-groups-with-temporary-tag-as-true](https://github.com/devwithkrishna/azure-terraforminator/actions/workflows/azure-terraforminator.yaml/badge.svg)](https://github.com/devwithkrishna/azure-terraforminator/actions/workflows/azure-terraforminator.yaml)
5+
6+
# What this does
7+
8+
* Reducing cloud costs and decommissioning unused resources are essential practices for efficient cloud management.
9+
10+
#### Cost Savings
11+
* Pay-as-you-go model: Cloud services charge based on resource usage, so any unused or idle resources still incur costs. Decommissioning these saves money that can be allocated elsewhere.
12+
* Hidden costs: Over-provisioned or forgotten services like unused VMs, storage, or databases can rack up unexpected costs over time.
13+
#### Resource Optimization
14+
* Avoid over-provisioning: Scaling down unused or underutilized resources ensures you're only paying for what you need, preventing waste.
15+
* Better performance: By right-sizing resources, you allocate appropriate computing power to services, improving overall performance.
16+
#### Improved Security
17+
* Minimize attack surface: Decommissioning unused resources reduces potential vulnerabilities that could be exploited by attackers.
18+
* Avoid data leakage: Retiring unnecessary storage or services prevents accidental exposure of sensitive data.
19+
#### Operational Efficiency
20+
* Simplified management: Fewer resources mean less administrative overhead in terms of monitoring, patching, and maintenance.
21+
* Compliance and governance: Removing outdated or unnecessary assets helps maintain compliance with regulatory standards, as only necessary resources are active
22+
23+
24+
### This is defined in a way that it decommisions a resource group based on a specific tag in azure. When the autmation finds `Temporary` tag wth Value as `TRUE` it decommisions.
25+
26+
27+
#### For the automation to work we needd a service principal which has access to the subscription level atleast with contributor permission as deletion of resources are involved.
28+
29+
#### Configure the below environment variables as GitHub secrets
30+
31+
```markdown
32+
AZURE_CLIENT_ID = "value"
33+
AZURE_CLIENT_SECRET = "value"
34+
AZURE_TENANT_ID = "value"
35+
```
36+
37+
* The code is using python with poetry as package management tool
38+
39+
* This job is set to run as a cron every day and as a manual trigger as well if necessary
40+
41+
```markdown
42+
43+
This is a sample of output showing what are the resources deleted
44+
45+
The below resources are decommisioned on <Date : yyyy-mm-dd>
46+
+------------------------+-----------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------+
47+
| Name | Type | ID | Resource Group Name |
48+
+========================+===================================+====================================================================================================================================================+=======================+
49+
| Name of resource | Type | Resource Id | Rg name |
50+
+------------------------+-----------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------+
51+
| mystorageaccountswswwe | Microsoft.Storage/storageAccounts | /subscriptions/es271149ae-05d3-4dcsssf-b946-d71f3f39/resourceGroups/ARCHITECTS-3/providers/Microsoft.Storage/storageAccounts/mystorageaccountswswwe | ARCHITECTS-3 |
52+
+------------------------+-----------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------+
53+
54+
```

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ azure-identity = "^1.18.0"
1313
azure-mgmt-resource = "^23.1.1"
1414
azure-mgmt-resourcegraph = "^8.0.0"
1515
azure-core = "^1.31.0"
16+
tabulate = "^0.9.0"
1617

1718

1819
[build-system]

terraforminator.py

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import os
2-
from datetime import datetime
2+
from datetime import datetime, date
33
import argparse
44
import asyncio
5+
from tabulate import tabulate
56
from dotenv import load_dotenv
67
from azure.identity import DefaultAzureCredential
78
from azure.mgmt.resource.resources.v2022_09_01 import ResourceManagementClient
@@ -26,9 +27,10 @@ async def list_resource_groups_with_temporary_tag(subscription_id: str):
2627
}
2728
rgs_to_deleted.append(rg_dict) # final dictionary of rgs to be deleted with Temporary tag value as TRUE
2829

29-
print(rgs_to_deleted)
30-
30+
# print(rgs_to_deleted)
3131
return rgs_to_deleted
32+
33+
3234
async def delete_resource_groups(subscription_id: str, rgs_to_be_deleted: list[dict]):
3335
"""
3436
Delete the resource groups with Temporary tag value as TRUE
@@ -39,7 +41,7 @@ async def delete_resource_groups(subscription_id: str, rgs_to_be_deleted: list[d
3941

4042
for rg in rgs_to_be_deleted:
4143
try:
42-
print(f"Deleting {rg['name']} from {subscription_id}")
44+
print(f"Deleting {rg['name']} from {subscription_id} subscription")
4345
resource_management_client.resource_groups.begin_delete(resource_group_name=rg['name']).result()
4446
print(f"Successfully deleted {rg['name']}")
4547

@@ -54,6 +56,35 @@ async def delete_resource_groups(subscription_id: str, rgs_to_be_deleted: list[d
5456
await asyncio.sleep(1)
5557

5658

59+
def list_resources_in_rg(subscription_id:str, rgs_to_be_deleted: list[dict]):
60+
"""
61+
get the list of resources inside an RG
62+
:param rgs_to_be_deleted:
63+
:return:
64+
"""
65+
credential = DefaultAzureCredential()
66+
resource_management_client = ResourceManagementClient(subscription_id=subscription_id, credential=credential)
67+
68+
details_to_display = []
69+
for rg in rgs_to_be_deleted:
70+
try:
71+
resource_list = resource_management_client.resources.list_by_resource_group(resource_group_name=rg['name'])
72+
for resources in resource_list:
73+
resource = {
74+
'name' : resources.name,
75+
'resource_id' : resources.id,
76+
'resource_type' : resources.type,
77+
'resource_group' : rg['name']
78+
}
79+
details_to_display.append(resource)
80+
81+
except Exception as e:
82+
83+
print(f"Failed to reteive resources from resource group '{rg['name']}': {e}")
84+
85+
return details_to_display
86+
87+
5788
async def main():
5889
"""To test the code"""
5990
start_time = datetime.utcnow() # Get start time in UTC
@@ -67,7 +98,14 @@ async def main():
6798
subscription_name = args.subscription_name
6899
subscription_id = run_azure_rg_query(subscription_name=subscription_name)
69100
rgs_to_deleted = await list_resource_groups_with_temporary_tag(subscription_id=subscription_id)
101+
details_to_dispaly = list_resources_in_rg(subscription_id=subscription_id, rgs_to_be_deleted=rgs_to_deleted)
70102
await delete_resource_groups(subscription_id=subscription_id, rgs_to_be_deleted=rgs_to_deleted)
103+
print(f"The below resources are decommisioned on {date.today()}")
104+
# Extracting headers and rows
105+
headers = ["Name", "Type", "ID", "Resource Group Name"]
106+
rows = [[item["name"], item["resource_type"], item["resource_id"], item["resource_group"]] for item in details_to_dispaly]
107+
# Printing in tabular format
108+
print(tabulate(rows, headers=headers, tablefmt="grid"))
71109
end_time = datetime.utcnow() # Get end time in UTC
72110
print(f"Process completed at (UTC): {end_time}")
73111
# Calculate and print elapsed time

0 commit comments

Comments
 (0)