Skip to content

Commit 6ff95ad

Browse files
committed
Tagging Azure resources
1 parent a975107 commit 6ff95ad

7 files changed

Lines changed: 181 additions & 2 deletions

File tree

cloud_governance/common/clouds/azure/subscriptions/azure_operations.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ def __init__(self):
2424
self.billing_client = BillingManagementClient(credential=self.__default_creds,
2525
subscription_id=self.subscription_id)
2626
self.__account_id = self.__environment_variables_dict.get('AZURE_ACCOUNT_ID')
27+
self.global_tags = self.__environment_variables_dict.get('GLOBAL_TAGS')
2728
self.cloud_name = 'AZURE'
2829
self.scope = f'subscriptions/{self.subscription_id}'
2930

cloud_governance/main/environment_variables.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ def __init__(self):
7070
self._environment_variables_dict['account'] = EnvironmentVariables.get_env('account', '').upper().strip()
7171
self._environment_variables_dict['AWS_DEFAULT_REGION'] = EnvironmentVariables.get_env('AWS_DEFAULT_REGION', '')
7272
self._environment_variables_dict['log_level'] = EnvironmentVariables.get_env('log_level', 'INFO')
73+
self._environment_variables_dict['GLOBAL_TAGS'] = literal_eval(EnvironmentVariables.get_env('GLOBAL_TAGS', "{}"))
7374

7475
self._environment_variables_dict['DAYS_TO_TAKE_ACTION'] = int(
7576
EnvironmentVariables.get_env('DAYS_TO_TAKE_ACTION', "7"))

cloud_governance/main/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ def main():
254254
if environment_variables_dict.get('PUBLIC_CLOUD_NAME') and environment_variables_dict.get(
255255
'PUBLIC_CLOUD_NAME').upper() == 'AZURE':
256256
azure_cost_policy_runner = None
257-
is_azure_policy_runner = policy in environment_variables_dict.get('cost_policies')
257+
is_azure_policy_runner = policy in environment_variables_dict.get('cost_policies') or environment_variables_dict.get('azure_policies')
258258
if is_azure_policy_runner:
259259
azure_cost_policy_runner = AzurePolicyRunner()
260260

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
from azure.mgmt.resource import ResourceManagementClient
2+
from cloud_governance.common.logger.init_logger import logger
3+
from cloud_governance.common.clouds.azure.subscriptions.azure_operations import AzureOperations
4+
5+
6+
class TagAzureResourceGroup:
7+
def __init__(self):
8+
"""
9+
Initialize Azure clients and set the tags to apply.
10+
11+
:param tags_to_add: Dictionary of tags to add to resource groups and their resources.
12+
"""
13+
self.azure_operations = AzureOperations()
14+
self.subscription_id = self.azure_operations.subscription_id
15+
self.credential = self.azure_operations._AzureOperations__default_creds # reuse credentials
16+
self.resource_client = ResourceManagementClient(self.credential, self.subscription_id)
17+
self.tags_to_add = self.azure_operations.global_tags
18+
19+
def tag_all(self):
20+
"""
21+
Tag all resource groups and their contained resources with the specified tags.
22+
"""
23+
resource_groups = self.resource_client.resource_groups.list()
24+
25+
for rg in resource_groups:
26+
logger.info(f"Processing resource group: {rg.name}")
27+
28+
# Tag the resource group
29+
try:
30+
self.resource_client.resource_groups.update(
31+
resource_group_name=rg.name,
32+
parameters={"tags": self.tags_to_add}
33+
)
34+
logger.info(f"Tagged resource group: {rg.name}")
35+
except Exception as e:
36+
logger.error(f"Failed to tag resource group {rg.name}: {e}")
37+
continue
38+
39+
# Tag all resources in the resource group
40+
for resource in self.resource_client.resources.list_by_resource_group(rg.name):
41+
logger.info(f" Tagging resource: {resource.name} ({resource.type})")
42+
43+
existing_tags = resource.tags or {}
44+
updated_tags = {**existing_tags, **self.tags_to_add}
45+
46+
try:
47+
provider_ns, resource_type_str = resource.type.split('/')
48+
provider = self.resource_client.providers.get(provider_ns)
49+
resource_type_info = next(
50+
rt for rt in provider.resource_types if rt.resource_type.lower() == resource_type_str.lower()
51+
)
52+
api_version = next(
53+
(v for v in resource_type_info.api_versions if 'preview' not in v.lower()),
54+
resource_type_info.api_versions[0]
55+
)
56+
57+
poller = self.resource_client.resources.begin_update_by_id(
58+
resource_id=resource.id,
59+
api_version=api_version,
60+
parameters={
61+
'location': resource.location,
62+
'tags': updated_tags
63+
}
64+
)
65+
poller.result()
66+
logger.info(f" Tagged resource: {resource.name}")
67+
except Exception as e:
68+
logger.error(f" Failed to tag resource {resource.name}: {e}")
69+
70+
def run(self):
71+
"""
72+
This method tags all Azure resources.
73+
"""
74+
self.tag_all()

jenkins/clouds/azure/daily/policies/run_policies.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def get_policies(file_type: str = '.py', exclude_policies: list = None):
3737
return custodian_policies
3838

3939

40-
GLOBAL_COST_POLICIES = ['cost_billing_reports']
40+
GLOBAL_COST_POLICIES = ['cost_billing_reports', 'tag_azure_resource_group']
4141
available_policies = get_policies(exclude_policies=GLOBAL_COST_POLICIES)
4242

4343

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
def accounts_list = ['perfscale']
2+
pipeline {
3+
agent {
4+
docker {
5+
label 'cloud-governance-worker'
6+
image 'quay.io/cloud-governance/centos-stream8-podman:latest'
7+
args '-u root -v /etc/postfix/main.cf:/etc/postfix/main.cf --privileged'
8+
}
9+
}
10+
environment {
11+
QUAY_CLOUD_GOVERNANCE_REPOSITORY = credentials('QUAY_CLOUD_GOVERNANCE_REPOSITORY')
12+
POLICIES_IN_ACTION = '[]'
13+
AZURE_CLIENT_SECRET = credentials('cloud-governance-azure-client-secret')
14+
AZURE_TENANT_ID = credentials('cloud-governance-azure-tenant-id')
15+
AZURE_ACCOUNT_ID = credentials('cloud-governance-azure-account-id')
16+
AZURE_CLIENT_ID = credentials('cloud-governance-azure-client-id')
17+
ES_HOST = credentials('cloud-governance-es-host')
18+
ES_PORT = credentials('cloud-governance-es-port')
19+
LDAP_HOST_NAME = credentials('cloud-governance-ldap-host-name')
20+
GLOBAL_TAGS = credentials('GLOBAL_TAGS')
21+
contact2 = "yinsong@redhat.com"
22+
}
23+
stages {
24+
stage('Checkout') { // Checkout (git clone ...) the projects repository
25+
steps {
26+
checkout scm
27+
}
28+
}
29+
stage('Initial Cleanup') {
30+
steps {
31+
sh '''if [[ "$(podman images -q ${QUAY_CLOUD_GOVERNANCE_REPOSITORY} 2> /dev/null)" != "" ]]; then podman rmi -f $(podman images -q ${QUAY_CLOUD_GOVERNANCE_REPOSITORY} 2> /dev/null); fi'''
32+
}
33+
}
34+
stage('Run Azure Policies') {
35+
steps {
36+
script {
37+
for (account in accounts_list ) {
38+
echo "Running for account ${account.toUpperCase()}"
39+
withCredentials([string(credentialsId: "${account}-azure-client-secret", variable: 'client_secret'),
40+
string(credentialsId: "${account}-azure-client-id", variable: 'client_id'),
41+
string(credentialsId: "${account}-azure-tenant-id", variable: 'tenant_id'),
42+
string(credentialsId: "${account}-azure-subscription-id", variable: 'subscription_id'),
43+
string(credentialsId: "${account}-azure-account-id", variable: 'account_id')]) {
44+
env.account_name = "Azure-${account}"
45+
sh 'python3 jenkins/clouds/azure/daily/policies/run_policies.py'
46+
}
47+
}
48+
}
49+
}
50+
}
51+
stage('Finalize Cleanup') {
52+
steps {
53+
sh '''if [[ "$(podman images -q ${QUAY_CLOUD_GOVERNANCE_REPOSITORY} 2> /dev/null)" != "" ]]; then podman rmi -f $(podman images -q ${QUAY_CLOUD_GOVERNANCE_REPOSITORY} 2> /dev/null); fi'''
54+
deleteDir()
55+
}
56+
}
57+
}
58+
post {
59+
always {
60+
deleteDir()
61+
}
62+
failure {
63+
script {
64+
msg = "Build error for ${env.JOB_NAME} ${env.BUILD_NUMBER} (${env.BUILD_URL})"
65+
emailext body: """\
66+
Jenkins job: ${env.BUILD_URL}\nSee the console output for more details: ${env.BUILD_URL}consoleFull\n\n
67+
""",
68+
subject: msg,
69+
to: "${contact2}"
70+
}
71+
}
72+
}
73+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import os
2+
3+
# Read environment variables
4+
AZURE_CLIENT_SECRET = os.environ['AZURE_CLIENT_SECRET']
5+
AZURE_TENANT_ID = os.environ['AZURE_TENANT_ID']
6+
AZURE_CLIENT_ID = os.environ['AZURE_CLIENT_ID']
7+
AZURE_ACCOUNT_ID = os.environ['AZURE_ACCOUNT_ID']
8+
GLOBAL_TAGS = os.environ['GLOBAL_TAGS']
9+
QUAY_CLOUD_GOVERNANCE_REPOSITORY = os.environ.get(
10+
'QUAY_CLOUD_GOVERNANCE_REPOSITORY',
11+
'quay.io/cloud-governance/cloud-governance:latest'
12+
)
13+
14+
print('Running the Azure tagging')
15+
16+
# Setup container environment variables
17+
input_vars_to_container = [{
18+
'account': 'perf-scale-azure',
19+
'AZURE_CLIENT_ID': AZURE_CLIENT_ID,
20+
'AZURE_TENANT_ID': AZURE_TENANT_ID,
21+
'AZURE_CLIENT_SECRET': AZURE_CLIENT_SECRET,
22+
'AZURE_ACCOUNT_ID': AZURE_ACCOUNT_ID,
23+
'GLOBAL_TAGS': GLOBAL_TAGS
24+
}]
25+
26+
for input_vars in input_vars_to_container:
27+
envs = [f"{k}={v}" for k, v in input_vars.items()]
28+
env_flags = ' '.join([f'-e {env}' for env in envs])
29+
cmd = f"podman run --rm --name cloud-governance {env_flags} -e policy=tag_azure_resource_group {QUAY_CLOUD_GOVERNANCE_REPOSITORY}"
30+
os.system(cmd)

0 commit comments

Comments
 (0)