Skip to content

Commit

Permalink
Cluster graviton savings to non-graviton instances (#852)
Browse files Browse the repository at this point in the history
* Define rosa cluster and graviton type

* Added the graviton cost
  • Loading branch information
athiruma authored Oct 10, 2024
1 parent 21c5e34 commit dbb2801
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 2 deletions.
32 changes: 32 additions & 0 deletions cloud_governance/common/utils/configs.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,35 @@
EC2_NAMESPACE = 'AWS/EC2'
CLOUDWATCH_METRICS_AVAILABLE_DAYS = 14
AWS_DEFAULT_GLOBAL_REGION = 'us-east-1'

# X86 to Graviton
GRAVITON_MAPPINGS = {
'c6a': 'c6g',
'c6i': 'c6g',
'c6in': 'c6gn',
'c7': 'c7g',
'c7i': 'c7g',
'c7a': 'c7g',
'c7i-flex': 'c7g',
'g5': 'g5g',
'hpc7a': 'hpc7g',
'i4i': 'i4g',
'm5': 'm6g',
'm5a': 'm6g',
'm5n': 'm6g',
'm5zn': 'm6g',
'm6i': 'm6g',
'm6in': 'm6g',
'm6a': 'm6g',
'm7i': 'm7g',
'm7a': 'm7g',
'm7i-flex': 'm7g',
'r7i': 'r8g',
'r7a': 'r7g',
'r5': 'r7g',
'r6i': 'r6g',
't3': 't4g',
't2': 'a1'
}

DEFAULT_GRAVITON_INSTANCE = 'm6g'
44 changes: 43 additions & 1 deletion cloud_governance/policy/aws/monitor/cluster_run.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import datetime
import re

from math import ceil

from cloud_governance.cloud_resource_orchestration.utils.common_operations import string_equal_ignore_case
from cloud_governance.common.utils.configs import GRAVITON_MAPPINGS, DEFAULT_ROUND_DIGITS, DEFAULT_GRAVITON_INSTANCE
from cloud_governance.policy.helpers.aws.aws_policy_operations import AWSPolicyOperations


Expand Down Expand Up @@ -40,7 +43,8 @@ def run_policy_operations(self):
name_tag = self.get_tag_name_from_tags(tags=tags, tag_name='Name')
launch_time = instance.get('LaunchTime')
running_instances = stopped_instances = 0
running_days = self.calculate_days(instance.get('LaunchTime'))
running_days = self.calculate_days(launch_time)
running_hours = ceil(self.calculate_hours(launch_time))
stopped_date_time = ''
if string_equal_ignore_case(instance_state, 'stopped'):
stopped_instances = 1
Expand All @@ -54,6 +58,12 @@ def run_policy_operations(self):
else:
running_instances = 1
creation_date = ''
rosa_cluster = True if self.get_tag_name_from_tags(tags=tags, tag_name='red-hat-managed') else False
instance_type = instance.get('InstanceType')
using_graviton = False
for graviton_instance_family in GRAVITON_MAPPINGS.values():
if graviton_instance_family in instance_type:
using_graviton = True
if 'master' in name_tag.lower():
creation_date = self.__get_creation_date(instance.get('BlockDeviceMappings', []))
instance_data = f"{instance.get('InstanceId')}, {self.get_tag_name_from_tags(tags=tags, tag_name='Name')}, {instance.get('InstanceType')}, {instance_state}, {running_days}, {launch_time}"
Expand All @@ -63,6 +73,7 @@ def run_policy_operations(self):
cluster_data[cluster_tag]['ClusterState'] = instance_state
cluster_data[cluster_tag]['StoppedDate'] = stopped_date_time
cluster_data[cluster_tag]['Instances'].append(instance_data)
cluster_data[cluster_tag]['InstanceTypes'].append(instance.get('InstanceType'))
cluster_data[cluster_tag]['InstanceCount'] = len(cluster_data[cluster_tag]['Instances'])
cluster_data[cluster_tag]['Stopped'] = int(cluster_data[cluster_tag]['Stopped']) + stopped_instances
cluster_data[cluster_tag]['Running'] = int(cluster_data[cluster_tag]['Running']) + running_instances
Expand All @@ -72,19 +83,50 @@ def run_policy_operations(self):
'ClusterName2': cluster_tag.split('/')[-1].lower(),
'ResourceId': cluster_tag,
'ClusterTag': cluster_tag,
'InstanceTypes': [instance.get('InstanceType')],
'User': self.get_tag_name_from_tags(tags=tags, tag_name='User'),
'RunningDays': running_days,
'RunningHours': running_hours,
'RegionName': self._region,
'PublicCloud': self._cloud_name,
'Instances': [instance_data],
'LaunchTime': launch_time.date(),
'InstanceCount': 1,
'Stopped': stopped_instances,
'Running': running_instances,
'Graviton': using_graviton,
'RosaCluster': rosa_cluster,
'index-id': f'{datetime.datetime.now(datetime.timezone.utc).date()}-{self._cloud_name.lower()}-{self.account.lower()}-{self._region.lower()}-{cluster_tag}',
}
if creation_date:
cluster_data[cluster_tag]['creation_date'] = creation_date
cluster_data[cluster_tag]['ClusterState'] = instance_state
cluster_data[cluster_tag]['StoppedDate'] = stopped_date_time
for cluster in cluster_data.values():
instance_types = cluster['InstanceTypes']
total_cost = 0
graviton_instance_cost = 0
cluster['GravitonInstanceTypes'] = []
running_hours = 1 if cluster['RunningHours'] == 0 else cluster['RunningHours']
for instance_type in set(instance_types):
instance_types_count = instance_types.count(instance_type)
unit_price = self._resource_pricing.get_ec2_price(region_name=self._region,
instance_type=instance_type)
total_cost += (unit_price * running_hours * instance_types_count)
if not cluster['Graviton']:
instance_family, instance_size = instance_type.split('.')
graviton_instance = f'{DEFAULT_GRAVITON_INSTANCE}.{instance_size}'
if instance_family in GRAVITON_MAPPINGS:
graviton_instance = f'{GRAVITON_MAPPINGS[instance_family]}.{instance_size}'
graviton_unit_price = self._resource_pricing.get_ec2_price(region_name=self._region,
instance_type=graviton_instance)
graviton_instance_cost += (graviton_unit_price * running_hours * instance_types_count)
cluster['GravitonInstanceTypes'].append(f"{graviton_instance}: {instance_types_count}")

cluster['TotalGravitonInstanceCost'] = round(graviton_instance_cost, DEFAULT_ROUND_DIGITS)
cluster['TotalCost'] = round(total_cost, DEFAULT_ROUND_DIGITS)

cluster['GravitonSavings'] = round(total_cost - graviton_instance_cost,
DEFAULT_ROUND_DIGITS) if graviton_instance_cost != 0 else 0
cluster['InstanceTypes'] = [f"{x}: {instance_types.count(x)}" for x in set(instance_types)]
return list(cluster_data.values())
19 changes: 18 additions & 1 deletion cloud_governance/policy/helpers/abstract_policy_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@


class AbstractPolicyOperations(ABC):

DAYS_TO_NOTIFY_ADMINS = 2
DAYS_TO_TRIGGER_RESOURCE_MAIL = 4
DAILY_HOURS = 24
Expand Down Expand Up @@ -46,6 +45,24 @@ def calculate_days(self, create_date: Union[datetime, str], start_date: Union[da
days = start_date - create_date.date()
return days.days

def calculate_hours(self, create_date: Union[datetime, str],
start_date: Union[datetime, str] = datetime.now(timezone.utc)):
"""
This method returns the hours
:param start_date:
:type start_date:
:param create_date:
:type create_date:
:return:
:rtype:
"""
if isinstance(create_date, str):
create_date = datetime.strptime(create_date, "%Y-%M-%d %H:%M:%S").replace(tzinfo=timezone.utc)
if isinstance(start_date, str):
start_date = datetime.strptime(start_date, "%Y-%m-%d %H:%M:%S").replace(tzinfo=timezone.utc)
days = start_date - create_date
return days.seconds / 3600

def get_clean_up_days_count(self, tags: Union[list, dict]):
"""
This method returns the cleanup days count
Expand Down

0 comments on commit dbb2801

Please sign in to comment.