cloud-governance 1.1.402__tar.gz → 1.1.404__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cloud_governance-1.1.402/cloud_governance.egg-info → cloud_governance-1.1.404}/PKG-INFO +2 -2
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/main/environment_variables.py +6 -2
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/main/main.py +1 -1
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/aws/monthly_report.py +11 -2
- cloud_governance-1.1.404/cloud_governance/policy/aws/yearly_savings_report.py +490 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/aws/zombie_non_cluster/run_zombie_non_cluster_policies.py +1 -1
- {cloud_governance-1.1.402 → cloud_governance-1.1.404/cloud_governance.egg-info}/PKG-INFO +2 -2
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance.egg-info/SOURCES.txt +1 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/setup.py +2 -2
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/LICENSE +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/MANIFEST.in +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/README.md +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/clouds/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/clouds/aws/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/clouds/aws/ec2/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/clouds/aws/ec2/aws_monitor_tickets.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/clouds/aws/ec2/aws_tagging_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/clouds/aws/ec2/collect_cro_reports.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/clouds/aws/ec2/cost_over_usage.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/clouds/aws/ec2/monitor_cro_instances.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/clouds/aws/ec2/run_cro.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/clouds/aws/ec2/tag_cro_instances.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/clouds/azure/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/clouds/azure/resource_groups/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/clouds/azure/resource_groups/abstract_resource.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/clouds/azure/resource_groups/azure_monitor_tickets.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/clouds/azure/resource_groups/azure_tagging_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/clouds/azure/resource_groups/collect_cro_reports.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/clouds/azure/resource_groups/cost_over_usage.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/clouds/azure/resource_groups/monitor_cro_resources.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/clouds/azure/resource_groups/tag_cro_resources.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/clouds/common/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/clouds/common/abstract_collect_cro_reports.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/clouds/common/abstract_cost_over_usage.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/clouds/common/abstract_tagging_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/common/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/common/abstract_monitor_tickets.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/common/cro_object.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/common/run_cro.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/monitor/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/monitor/cloud_monitor.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/utils/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/utils/common_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/utils/constant_variables.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/cloud_resource_orchestration/utils/elastic_search_queries.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/athena/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/athena/abstract_athena_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/athena/boto3_client_athena_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/athena/pyathena_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/cloudtrail/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/cloudtrail/cloudtrail_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/cloudwatch/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/cloudwatch/cloudwatch_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/cost_explorer/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/cost_explorer/cost_explorer_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/dynamodb/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/dynamodb/dynamodb_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/ec2/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/ec2/ec2_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/iam/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/iam/iam_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/price/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/price/price.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/price/resources_pricing.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/rds/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/rds/rds_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/resource_explorer/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/resource_explorer/resource_explorer_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/resource_tagging_api/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/resource_tagging_api/resource_tag_api_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/s3/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/s3/s3_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/savingsplan/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/savingsplan/savings_plans_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/sts/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/sts/sts_oprations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/support/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/support/support_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/utils/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/utils/common_methods.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/aws/utils/utils.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/azure/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/azure/common/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/azure/common/common_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/azure/compute/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/azure/compute/compute_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/azure/compute/network_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/azure/compute/resource_group_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/azure/cost_management/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/azure/cost_management/cost_management_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/azure/monitor/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/azure/monitor/monitor_management_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/azure/subscriptions/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/azure/subscriptions/azure_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/cloudability/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/cloudability/cloudability_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/cloudability/templates/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/cloudability/templates/cloudability_dimensions.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/gcp/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/gcp/google_account.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/ibm/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/ibm/account/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/ibm/account/ibm_account.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/ibm/account/ibm_authenticator.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/ibm/classic/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/ibm/classic/classic_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/ibm/developer_tools/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/ibm/developer_tools/schematic_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/ibm/platform_services/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/ibm/platform_services/platform_service_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/ibm/tagging/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/ibm/tagging/global_tagging_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/ibm/vpc/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/clouds/ibm/vpc/vpc_infra_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/elasticsearch/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/elasticsearch/elastic_upload.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/elasticsearch/elasticsearch_exceptions.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/elasticsearch/elasticsearch_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/elasticsearch/modals/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/elasticsearch/modals/cost_usage_reports_data.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/elasticsearch/modals/policy_es_data.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/google_drive/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/google_drive/gcp_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/google_drive/google_drive_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/google_drive/upload_to_gsheet.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/jira/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/jira/jira.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/jira/jira_exceptions.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/jira/jira_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/ldap/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/ldap/ldap_search.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/logger/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/logger/init_logger.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/logger/logger_time_stamp.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/mails/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/mails/gmail.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/mails/mail_message.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/mails/postfix.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/mails/templates/cro_monitor_budget_remain_alert.j2 +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/mails/templates/cro_monitor_budget_remain_high_alert.j2 +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/mails/templates/cro_request_for_manager_approval.j2 +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/mails/templates/policy_alert_agg_message.j2 +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/pandas/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/pandas/pandas_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/tool/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/tool/tool.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/utils/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/utils/api_requests.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/utils/configs.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/utils/json_datetime_encoder.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/common/utils/utils.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/main/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/main/environment_variables_exceptions.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/main/es_uploader.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/main/main_common_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/main/main_oerations/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/main/main_oerations/main_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/main/run_cloud_resource_orchestration.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/aws/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/aws/cleanup/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/aws/cleanup/database_idle.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/aws/cleanup/instance_idle.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/aws/cleanup/instance_run.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/aws/cleanup/unattached_volume.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/aws/cleanup/unused_nat_gateway.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/aws/cost_billing_reports.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/aws/cost_explorer.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/aws/cost_explorer_payer_billings.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/aws/cost_over_usage.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/aws/ebs_in_use.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/aws/ec2_stop.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/aws/empty_roles.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/aws/ip_unattached.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/aws/monitor/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/aws/monitor/cluster_run.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/aws/optimize_resources_report.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/aws/s3_inactive.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/aws/skipped_resources.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/aws/spot_savings_analysis.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/aws/unused_access_key.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/aws/zombie_cluster_resource.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/aws/zombie_snapshots.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/azure/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/azure/cleanup/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/azure/cleanup/instance_idle.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/azure/cleanup/instance_run.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/azure/cleanup/ip_unattached.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/azure/cleanup/unattached_volume.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/azure/cleanup/unused_nat_gateway.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/azure/cost_billing_reports.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/azure/tag_azure_resource_group.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/common_policies/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/common_policies/cloudability_cost_reports.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/common_policies/send_aggregated_alerts.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/gcp/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/gcp/cost_billing_reports.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/helpers/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/helpers/abstract_policy_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/helpers/aws/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/helpers/aws/aws_policy_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/helpers/azure/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/helpers/azure/azure_policy_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/helpers/cloudability_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/ibm/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/ibm/cost_billing_reports.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/ibm/cost_usage_reports.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/ibm/ibm_cost_over_usage.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/ibm/ibm_cost_report.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/ibm/tag_baremetal.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/ibm/tag_resources.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/ibm/tag_vm.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/aws/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/aws/cost_expenditure/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/aws/cost_expenditure/cost_report_policies.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/aws/dynamodb_upload_data/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/aws/dynamodb_upload_data/cloudtrail_to_dynamodb.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/aws/dynamodb_upload_data/upload_data_to_dynamodb.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/aws/tag_cluster/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/aws/tag_cluster/remove_cluster_tags.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/aws/tag_cluster/run_tag_cluster_resouces.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/aws/tag_cluster/tag_cluster_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/aws/tag_cluster/tag_cluster_resouces.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/aws/tag_non_cluster/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/aws/tag_non_cluster/non_cluster_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/aws/tag_non_cluster/remove_non_cluster_tags.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/aws/tag_non_cluster/run_tag_non_cluster_resources.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/aws/tag_non_cluster/tag_non_cluster_resources.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/aws/tag_non_cluster/update_na_tag_resources.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/aws/tag_user/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/aws/tag_user/iam_user_tags.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/aws/tag_user/remove_user_tags.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/aws/tag_user/run_tag_iam_user.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/aws/tag_user/tag_iam_user.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/aws/zombie_cluster/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/aws/zombie_cluster/delete_ec2_resources.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/aws/zombie_cluster/delete_iam_resources.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/aws/zombie_cluster/delete_s3_resources.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/aws/zombie_cluster/run_zombie_cluster_resources.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/aws/zombie_cluster/validate_zombies.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/aws/zombie_cluster/zombie_cluster_common_methods.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/aws/zombie_non_cluster/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/aws/zombie_non_cluster/zombie_non_cluster_polices.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/azure/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/azure/azure_policy_runner.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/gcp/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/gcp/gcp_policy_runner.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/gitleaks/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/gitleaks/gitleaks.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/ibm/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/ibm/ibm_operations/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/ibm/ibm_operations/ibm_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/ibm/ibm_operations/ibm_policy_runner.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/ibm/tagging/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_operations/ibm/tagging/tagging_operations.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_runners/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_runners/aws/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_runners/aws/policy_runner.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_runners/aws/upload_s3.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_runners/azure/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_runners/azure/policy_runner.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_runners/common/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_runners/common/abstract_policy_runner.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_runners/common/abstract_upload.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_runners/common_policy_runner.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_runners/elasticsearch/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_runners/elasticsearch/upload_elastic_search.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_runners/ibm/__init__.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/policy_runners/ibm/policy_runner.py +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance.egg-info/dependency_links.txt +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance.egg-info/not-zip-safe +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance.egg-info/requires.txt +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance.egg-info/top_level.txt +0 -0
- {cloud_governance-1.1.402 → cloud_governance-1.1.404}/setup.cfg +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cloud-governance
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.404
|
|
4
4
|
Summary: Cloud Governance Tool
|
|
5
5
|
Home-page: https://github.com/redhat-performance/cloud-governance
|
|
6
6
|
Author: Red Hat
|
|
7
|
-
Author-email: ebattat@redhat.com,
|
|
7
|
+
Author-email: ebattat@redhat.com, pragchau@redhat.com
|
|
8
8
|
License: Apache License 2.0
|
|
9
9
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
{cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/main/environment_variables.py
RENAMED
|
@@ -105,7 +105,8 @@ class EnvironmentVariables:
|
|
|
105
105
|
self._environment_variables_dict['cluster_policies'] = ['zombie_cluster_resource']
|
|
106
106
|
es_index = 'cloud-governance-policy-es-index'
|
|
107
107
|
self._environment_variables_dict['cost_policies'] = ['cost_explorer', 'cost_over_usage', 'cost_billing_reports',
|
|
108
|
-
'cost_explorer_payer_billings', 'spot_savings_analysis'
|
|
108
|
+
'cost_explorer_payer_billings', 'spot_savings_analysis',
|
|
109
|
+
'yearly_savings_report']
|
|
109
110
|
self._environment_variables_dict['ibm_policies'] = ['tag_baremetal', 'tag_vm', 'ibm_cost_report',
|
|
110
111
|
'ibm_cost_over_usage']
|
|
111
112
|
self._environment_variables_dict['azure_policies'] = ['tag_azure_resource_group']
|
|
@@ -147,6 +148,9 @@ class EnvironmentVariables:
|
|
|
147
148
|
# ['User', 'Budget', 'Project', 'Manager']
|
|
148
149
|
self._environment_variables_dict['cost_explorer_tags'] = EnvironmentVariables.get_env('cost_explorer_tags',
|
|
149
150
|
'{}')
|
|
151
|
+
self._environment_variables_dict['yearly_savings_start_date'] = EnvironmentVariables.get_env('yearly_savings_start_date', '')
|
|
152
|
+
self._environment_variables_dict['yearly_savings_end_date'] = EnvironmentVariables.get_env('yearly_savings_end_date', '')
|
|
153
|
+
self._environment_variables_dict['yearly_savings_es_index'] = EnvironmentVariables.get_env('yearly_savings_es_index', 'cloud-governance-yearly-saving')
|
|
150
154
|
# AZURE Credentials
|
|
151
155
|
self._environment_variables_dict['AZURE_ACCOUNT_ID'] = EnvironmentVariables.get_env('AZURE_ACCOUNT_ID', '')
|
|
152
156
|
self._environment_variables_dict['AZURE_CLIENT_ID'] = EnvironmentVariables.get_env('AZURE_CLIENT_ID', '')
|
|
@@ -279,7 +283,7 @@ class EnvironmentVariables:
|
|
|
279
283
|
self._environment_variables_dict['POLICY_ACTIONS_DAYS'] = literal_eval(
|
|
280
284
|
EnvironmentVariables.get_env('POLICY_ACTIONS_DAYS', '[]'))
|
|
281
285
|
self._environment_variables_dict['DEFAULT_ADMINS'] = literal_eval(
|
|
282
|
-
EnvironmentVariables.get_env('DEFAULT_ADMINS', '["yinsong@redhat.com", "ebattat@redhat.com"]'))
|
|
286
|
+
EnvironmentVariables.get_env('DEFAULT_ADMINS', '["yinsong@redhat.com", "ebattat@redhat.com", "pragchau@redhat.com"]'))
|
|
283
287
|
self._environment_variables_dict['KERBEROS_USERS'] = literal_eval(
|
|
284
288
|
EnvironmentVariables.get_env('KERBEROS_USERS', '[]'))
|
|
285
289
|
self._environment_variables_dict['POLICIES_TO_ALERT'] = literal_eval(
|
|
@@ -244,7 +244,7 @@ def main():
|
|
|
244
244
|
ibm_classic_infrastructure_policy_runner = IBMPolicyRunner()
|
|
245
245
|
|
|
246
246
|
is_cost_explorer_policies_runner = ''
|
|
247
|
-
if environment_variables_dict.get('PUBLIC_CLOUD_NAME').upper() == 'AWS':
|
|
247
|
+
if environment_variables_dict.get('PUBLIC_CLOUD_NAME') and environment_variables_dict.get('PUBLIC_CLOUD_NAME').upper() == 'AWS':
|
|
248
248
|
cost_explorer_policies_runner = None
|
|
249
249
|
is_cost_explorer_policies_runner = policy in environment_variables_dict.get('cost_policies')
|
|
250
250
|
if is_cost_explorer_policies_runner:
|
{cloud_governance-1.1.402 → cloud_governance-1.1.404}/cloud_governance/policy/aws/monthly_report.py
RENAMED
|
@@ -17,8 +17,17 @@ class MonthlyReport:
|
|
|
17
17
|
self._es_index = 'cloud-governance-mail-messages'
|
|
18
18
|
self._es_host = self.__environment_variables_dict.get('es_host', '')
|
|
19
19
|
self._es_port = self.__environment_variables_dict.get('es_port', '')
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
to_mail_str = self.__environment_variables_dict.get('to_mail', '').strip()
|
|
21
|
+
if to_mail_str in ('[]', ''):
|
|
22
|
+
self._to_mail = []
|
|
23
|
+
else:
|
|
24
|
+
self._to_mail = [x.strip() for x in to_mail_str.split(',') if x.strip()]
|
|
25
|
+
|
|
26
|
+
cc_mail_str = self.__environment_variables_dict.get('cc_mail', '').strip()
|
|
27
|
+
if cc_mail_str in ('[]', ''):
|
|
28
|
+
self._to_cc = []
|
|
29
|
+
else:
|
|
30
|
+
self._to_cc = [x.strip() for x in cc_mail_str.split(',') if cc_mail_str.strip()]
|
|
22
31
|
if self._es_host:
|
|
23
32
|
self._elastic_operations = ElasticSearchOperations(es_host=self._es_host, es_port=self._es_port)
|
|
24
33
|
self._postfix_mail = Postfix()
|
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
from datetime import datetime, timezone, date, timedelta
|
|
2
|
+
import time
|
|
3
|
+
|
|
4
|
+
from cloud_governance.common.elasticsearch.elasticsearch_operations import ElasticSearchOperations
|
|
5
|
+
from cloud_governance.common.elasticsearch.elastic_upload import ElasticUpload
|
|
6
|
+
from cloud_governance.common.logger.init_logger import logger
|
|
7
|
+
from cloud_governance.common.logger.logger_time_stamp import logger_time_stamp
|
|
8
|
+
from cloud_governance.main.environment_variables import environment_variables
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class YearlySavingsReport:
|
|
12
|
+
"""
|
|
13
|
+
This class aggregates yearly savings and per-month savings for the current year
|
|
14
|
+
from policy execution data and uploads to a dedicated ES index
|
|
15
|
+
Uses month-by-month queries and deduplication to avoid counting resources multiple times
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
NAT_GATEWAY_HOURLY_COST = 0.045
|
|
19
|
+
ELASTIC_IP_HOURLY_COST = 0.005
|
|
20
|
+
|
|
21
|
+
def __init__(self):
|
|
22
|
+
self.__environment_variables_dict = environment_variables.environment_variables_dict
|
|
23
|
+
self.__es_host = self.__environment_variables_dict.get('es_host', '')
|
|
24
|
+
self.__es_port = self.__environment_variables_dict.get('es_port', '')
|
|
25
|
+
self.__elastic_operations = ElasticSearchOperations(es_host=self.__es_host, es_port=self.__es_port) if self.__es_host else None
|
|
26
|
+
self.__elastic_upload = ElasticUpload()
|
|
27
|
+
self.__policy_es_index = self.__environment_variables_dict.get('es_index', 'cloud-governance-policy-es-index')
|
|
28
|
+
self.__yearly_savings_es_index = self.__environment_variables_dict.get('yearly_savings_es_index')
|
|
29
|
+
account = self.__environment_variables_dict.get('account', 'PERF-DEPT')
|
|
30
|
+
self.__account = account.upper().replace('OPENSHIFT-', '').replace('OPENSHIFT', '').strip()
|
|
31
|
+
# Check for custom date range from environment variables. This won't upload to ES.
|
|
32
|
+
self.__custom_start_date = self.__environment_variables_dict.get('yearly_savings_start_date', '')
|
|
33
|
+
self.__custom_end_date = self.__environment_variables_dict.get('yearly_savings_end_date', '')
|
|
34
|
+
|
|
35
|
+
def __get_last_day_of_month(self, year: int, month: int):
|
|
36
|
+
"""
|
|
37
|
+
Get the last day of a month, handling leap years
|
|
38
|
+
@param year: Year
|
|
39
|
+
@param month: Month (1-12)
|
|
40
|
+
@return: Last day of month
|
|
41
|
+
"""
|
|
42
|
+
if month == 2:
|
|
43
|
+
# Handle February (leap year)
|
|
44
|
+
if year % 4 == 0 and (year % 100 != 0 or year % 400 == 0):
|
|
45
|
+
return 29
|
|
46
|
+
else:
|
|
47
|
+
return 28
|
|
48
|
+
elif month in [4, 6, 9, 11]:
|
|
49
|
+
return 30
|
|
50
|
+
else:
|
|
51
|
+
return 31
|
|
52
|
+
|
|
53
|
+
def __get_savings_value(self, captured_date: date, policy_name: str):
|
|
54
|
+
"""
|
|
55
|
+
@param captured_date: date object
|
|
56
|
+
@param policy_name: policy name
|
|
57
|
+
@return: calculated savings value
|
|
58
|
+
"""
|
|
59
|
+
savings = 0
|
|
60
|
+
end_of_year = date(captured_date.year, 12, 31)
|
|
61
|
+
remaining_days = (end_of_year - captured_date).days
|
|
62
|
+
|
|
63
|
+
if policy_name == 'unused_nat_gateway':
|
|
64
|
+
savings = remaining_days * 24 * self.NAT_GATEWAY_HOURLY_COST
|
|
65
|
+
elif policy_name == 'ip_unattached':
|
|
66
|
+
savings = remaining_days * 24 * self.ELASTIC_IP_HOURLY_COST
|
|
67
|
+
|
|
68
|
+
return savings
|
|
69
|
+
|
|
70
|
+
def __process_monthly_query(self, month_start: str, month_end: str):
|
|
71
|
+
"""
|
|
72
|
+
Process a single monthly query and return resource-level results
|
|
73
|
+
@param month_start: Start date string (YYYY-MM-DD)
|
|
74
|
+
@param month_end: End date string (YYYY-MM-DD)
|
|
75
|
+
@return: Dictionary of {resource_id: {captured_date, policy_name, savings}}
|
|
76
|
+
"""
|
|
77
|
+
if not self.__elastic_operations:
|
|
78
|
+
return {}
|
|
79
|
+
|
|
80
|
+
query = {
|
|
81
|
+
"size": 0,
|
|
82
|
+
"query": {
|
|
83
|
+
"bool": {
|
|
84
|
+
"must": [
|
|
85
|
+
{
|
|
86
|
+
"term": {
|
|
87
|
+
"PublicCloud.keyword": {
|
|
88
|
+
"value": "AWS"
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"term": {
|
|
94
|
+
"account.keyword": {
|
|
95
|
+
"value": self.__account
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
],
|
|
100
|
+
"must_not": [
|
|
101
|
+
{
|
|
102
|
+
"terms": {
|
|
103
|
+
"policy.keyword": [
|
|
104
|
+
"zombie_cluster_resource", "instance_run", "ebs_in_use",
|
|
105
|
+
"s3_inactive", "optimize_resources_report", "instance_idle",
|
|
106
|
+
"cluster_run", "skipped_resources", "ec2_idle", "empty_roles",
|
|
107
|
+
"unused_access_key"
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
],
|
|
112
|
+
"filter": [{
|
|
113
|
+
"range": {
|
|
114
|
+
"timestamp": {
|
|
115
|
+
"gte": month_start,
|
|
116
|
+
"lte": month_end,
|
|
117
|
+
"format": "yyyy-MM-dd"
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}]
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
"aggs": {
|
|
124
|
+
"PolicyName": {
|
|
125
|
+
"terms": {
|
|
126
|
+
"field": "policy.keyword",
|
|
127
|
+
"size": 20,
|
|
128
|
+
"order": {"_key": "desc"}
|
|
129
|
+
},
|
|
130
|
+
"aggs": {
|
|
131
|
+
"CapturedDate": {
|
|
132
|
+
"terms": {
|
|
133
|
+
"field": "timestamp",
|
|
134
|
+
"size": 10000
|
|
135
|
+
},
|
|
136
|
+
"aggs": {
|
|
137
|
+
"ResourceId": {
|
|
138
|
+
"terms": {
|
|
139
|
+
"field": "ResourceId.keyword",
|
|
140
|
+
"size": 10000,
|
|
141
|
+
"order": {"_key": "desc"}
|
|
142
|
+
},
|
|
143
|
+
"aggs": {
|
|
144
|
+
"Savings": {
|
|
145
|
+
"max": {
|
|
146
|
+
"field": "TotalYearlySavings",
|
|
147
|
+
"missing": 0
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
try:
|
|
160
|
+
response = self.__elastic_operations.post_query(
|
|
161
|
+
query=query,
|
|
162
|
+
es_index=self.__policy_es_index,
|
|
163
|
+
result_agg=True
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
if not response or 'PolicyName' not in response:
|
|
167
|
+
logger.warning(f'No response or unexpected structure for {month_start} to {month_end}')
|
|
168
|
+
return {}
|
|
169
|
+
|
|
170
|
+
monthly_resources = {}
|
|
171
|
+
policy_buckets = response.get('PolicyName', {}).get('buckets', [])
|
|
172
|
+
|
|
173
|
+
logger.debug(f'DEBUG: Found {len(policy_buckets)} policies in query results')
|
|
174
|
+
for policy in policy_buckets:
|
|
175
|
+
logger.debug(f'DEBUG: Policy found: {policy.get("key")} with {len(policy.get("CapturedDate", {}).get("buckets", []))} captured dates')
|
|
176
|
+
|
|
177
|
+
for policy in policy_buckets:
|
|
178
|
+
policy_name = policy.get('key')
|
|
179
|
+
|
|
180
|
+
for es_capture_date_values in policy.get('CapturedDate', {}).get('buckets', []):
|
|
181
|
+
captured_date_str = es_capture_date_values.get('key_as_string', '')
|
|
182
|
+
|
|
183
|
+
if captured_date_str:
|
|
184
|
+
captured_date = datetime.strptime(captured_date_str[:10], "%Y-%m-%d").date()
|
|
185
|
+
else:
|
|
186
|
+
captured_date = datetime.now(timezone.utc).date()
|
|
187
|
+
|
|
188
|
+
for resource in es_capture_date_values.get('ResourceId', {}).get('buckets', []):
|
|
189
|
+
resource_id = resource.get('key')
|
|
190
|
+
savings = resource.get('Savings', {}).get('value', 0)
|
|
191
|
+
|
|
192
|
+
if resource_id in monthly_resources:
|
|
193
|
+
if monthly_resources[resource_id]['captured_date'] > captured_date:
|
|
194
|
+
monthly_resources[resource_id]['captured_date'] = captured_date
|
|
195
|
+
if savings == 0:
|
|
196
|
+
savings = self.__get_savings_value(captured_date, policy_name)
|
|
197
|
+
if monthly_resources[resource_id]['savings'] > savings:
|
|
198
|
+
monthly_resources[resource_id]['savings'] = savings
|
|
199
|
+
else:
|
|
200
|
+
if savings == 0:
|
|
201
|
+
savings = self.__get_savings_value(captured_date, policy_name)
|
|
202
|
+
monthly_resources[resource_id] = {
|
|
203
|
+
'captured_date': captured_date,
|
|
204
|
+
'policy_name': policy_name,
|
|
205
|
+
'savings': savings
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
policy_summary = {}
|
|
209
|
+
for resource_id, resource_data in monthly_resources.items():
|
|
210
|
+
policy_name = resource_data.get('policy_name')
|
|
211
|
+
savings = resource_data.get('savings', 0)
|
|
212
|
+
policy_summary[policy_name] = policy_summary.get(policy_name, 0) + savings
|
|
213
|
+
|
|
214
|
+
logger.info(f'Monthly resources summary by policy: {policy_summary}')
|
|
215
|
+
logger.info(f"Found {len(monthly_resources)} resources for {month_start} to {month_end}")
|
|
216
|
+
return monthly_resources
|
|
217
|
+
|
|
218
|
+
except Exception as err:
|
|
219
|
+
logger.error(f'Error processing month {month_start} to {month_end}: {err}')
|
|
220
|
+
return {}
|
|
221
|
+
|
|
222
|
+
def __calculate_month_savings(self, year: int, month: int, start_day: int, end_day: int):
|
|
223
|
+
"""
|
|
224
|
+
Calculate savings for a specific month
|
|
225
|
+
@param year: Year
|
|
226
|
+
@param month: Month (1-12)
|
|
227
|
+
@param start_day: Start day of month
|
|
228
|
+
@param end_day: End day of month
|
|
229
|
+
@return: Dictionary of {policy_name: savings_value}
|
|
230
|
+
"""
|
|
231
|
+
month_start = date(year, month, start_day).strftime("%Y-%m-%d")
|
|
232
|
+
month_end = date(year, month, end_day).strftime("%Y-%m-%d")
|
|
233
|
+
|
|
234
|
+
logger.info(f'Calculating savings for {month_start} to {month_end}')
|
|
235
|
+
|
|
236
|
+
return self.__get_yearly_savings(start_date=month_start, end_date=month_end)
|
|
237
|
+
|
|
238
|
+
def __get_yearly_savings(self, start_date: str = None, end_date: str = None):
|
|
239
|
+
"""
|
|
240
|
+
This method returns the yearly savings of the policies.
|
|
241
|
+
Queries month-by-month to avoid Elasticsearch overload.
|
|
242
|
+
@param start_date: Start date string (YYYY-MM-DD). If None, defaults to Jan 1 of current year.
|
|
243
|
+
@param end_date: End date string (YYYY-MM-DD). If None, defaults to Dec 31 of current year.
|
|
244
|
+
@return: Dictionary of {policy_name: total_savings}
|
|
245
|
+
"""
|
|
246
|
+
if not start_date:
|
|
247
|
+
start_date = datetime.now(timezone.utc).date().replace(day=1, month=1).strftime("%Y-%m-%d")
|
|
248
|
+
if not end_date:
|
|
249
|
+
end_date = datetime.now(timezone.utc).date().replace(day=31, month=12).strftime("%Y-%m-%d")
|
|
250
|
+
|
|
251
|
+
logger.info(f"Getting yearly savings from {start_date} to {end_date}")
|
|
252
|
+
|
|
253
|
+
monthly_ranges = self.__split_date_range_by_month(start_date, end_date)
|
|
254
|
+
logger.debug(f"Split into {len(monthly_ranges)} monthly queries")
|
|
255
|
+
|
|
256
|
+
all_resources = {}
|
|
257
|
+
|
|
258
|
+
for i, (month_start, month_end) in enumerate(monthly_ranges, 1):
|
|
259
|
+
logger.info(f"Processing month {i}/{len(monthly_ranges)}: {month_start} to {month_end}")
|
|
260
|
+
monthly_resources = self.__process_monthly_query(month_start, month_end)
|
|
261
|
+
|
|
262
|
+
for resource_id, resource_data in monthly_resources.items():
|
|
263
|
+
if resource_id in all_resources:
|
|
264
|
+
if all_resources[resource_id]['captured_date'] > resource_data['captured_date']:
|
|
265
|
+
all_resources[resource_id]['captured_date'] = resource_data['captured_date']
|
|
266
|
+
if all_resources[resource_id]['savings'] > resource_data['savings']:
|
|
267
|
+
all_resources[resource_id]['savings'] = resource_data['savings']
|
|
268
|
+
else:
|
|
269
|
+
all_resources[resource_id] = resource_data
|
|
270
|
+
|
|
271
|
+
if i < len(monthly_ranges):
|
|
272
|
+
time.sleep(0.5)
|
|
273
|
+
|
|
274
|
+
result = self.__get_total_policy_sum(all_resources)
|
|
275
|
+
return result
|
|
276
|
+
|
|
277
|
+
def __split_date_range_by_month(self, start_date: str, end_date: str):
|
|
278
|
+
"""
|
|
279
|
+
Split date range into monthly chunks
|
|
280
|
+
@param start_date: Start date string (YYYY-MM-DD)
|
|
281
|
+
@param end_date: End date string (YYYY-MM-DD)
|
|
282
|
+
@return: List of (month_start, month_end) tuples as strings
|
|
283
|
+
"""
|
|
284
|
+
if not start_date or not end_date:
|
|
285
|
+
raise ValueError(f"Both start_date and end_date must be provided. Got: start_date={start_date}, end_date={end_date}")
|
|
286
|
+
|
|
287
|
+
start = datetime.strptime(start_date, "%Y-%m-%d").date()
|
|
288
|
+
end = datetime.strptime(end_date, "%Y-%m-%d").date()
|
|
289
|
+
|
|
290
|
+
if start > end:
|
|
291
|
+
raise ValueError(f"start_date ({start_date}) must be <= end_date ({end_date})")
|
|
292
|
+
|
|
293
|
+
monthly_ranges = []
|
|
294
|
+
current_start = start
|
|
295
|
+
|
|
296
|
+
while current_start <= end:
|
|
297
|
+
if current_start.month == 12:
|
|
298
|
+
current_end = date(current_start.year + 1, 1, 1) - timedelta(days=1)
|
|
299
|
+
else:
|
|
300
|
+
current_end = date(current_start.year, current_start.month + 1, 1) - timedelta(days=1)
|
|
301
|
+
if current_end > end:
|
|
302
|
+
current_end = end
|
|
303
|
+
monthly_ranges.append((
|
|
304
|
+
current_start.strftime("%Y-%m-%d"),
|
|
305
|
+
current_end.strftime("%Y-%m-%d")
|
|
306
|
+
))
|
|
307
|
+
if current_end.month == 12:
|
|
308
|
+
current_start = date(current_end.year + 1, 1, 1)
|
|
309
|
+
else:
|
|
310
|
+
current_start = date(current_end.year, current_end.month + 1, 1)
|
|
311
|
+
|
|
312
|
+
return monthly_ranges
|
|
313
|
+
|
|
314
|
+
def __get_total_policy_sum(self, all_resources: dict):
|
|
315
|
+
"""
|
|
316
|
+
Calculate total savings by policy
|
|
317
|
+
@param all_resources: dict of {resource_id: {savings, policy_name, captured_date}}
|
|
318
|
+
@return: dict of {policy_name: total_savings}
|
|
319
|
+
"""
|
|
320
|
+
savings_result = {}
|
|
321
|
+
|
|
322
|
+
for resource_id, values in all_resources.items():
|
|
323
|
+
policy_name = values.get('policy_name')
|
|
324
|
+
savings = values.get('savings', 0)
|
|
325
|
+
savings_result[policy_name] = round(savings_result.get(policy_name, 0) + savings, 3)
|
|
326
|
+
|
|
327
|
+
return savings_result
|
|
328
|
+
|
|
329
|
+
def __update_yearly_savings(self, year: int, all_months_data: dict, total_annual_saving: float):
|
|
330
|
+
"""
|
|
331
|
+
Update yearly savings in Elasticsearch with all months data.
|
|
332
|
+
Creates a new document if year doesn't exist, or updates existing one.
|
|
333
|
+
@param year: Year (e.g., 2026)
|
|
334
|
+
@param all_months_data: Dictionary of {month_number: savings_value} for all months
|
|
335
|
+
@param total_annual_saving: Total cumulative savings for the year
|
|
336
|
+
@return: True if successful
|
|
337
|
+
"""
|
|
338
|
+
try:
|
|
339
|
+
current_date = datetime.now(timezone.utc).date()
|
|
340
|
+
year_id = f"{year}-{self.__account}"
|
|
341
|
+
|
|
342
|
+
data = {
|
|
343
|
+
'year': year,
|
|
344
|
+
'total_saving': round(total_annual_saving, 3),
|
|
345
|
+
'last_updated': current_date.isoformat(),
|
|
346
|
+
'timestamp': datetime.now(timezone.utc),
|
|
347
|
+
'policy': 'yearly_savings_report',
|
|
348
|
+
'index_id': year_id,
|
|
349
|
+
'account': self.__account
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
for month_num in range(1, 13):
|
|
353
|
+
data[f'month_{month_num}'] = round(all_months_data.get(month_num, 0), 3)
|
|
354
|
+
|
|
355
|
+
try:
|
|
356
|
+
if self.__elastic_operations.verify_elastic_index_doc_id(index=self.__yearly_savings_es_index, doc_id=year_id):
|
|
357
|
+
self.__elastic_operations.update_elasticsearch_index(
|
|
358
|
+
index=self.__yearly_savings_es_index,
|
|
359
|
+
id=year_id,
|
|
360
|
+
metadata=data
|
|
361
|
+
)
|
|
362
|
+
logger.info(f"Updated yearly savings for year {year}")
|
|
363
|
+
else:
|
|
364
|
+
self.__elastic_operations.upload_to_elasticsearch(
|
|
365
|
+
index=self.__yearly_savings_es_index,
|
|
366
|
+
data=data,
|
|
367
|
+
id=year_id
|
|
368
|
+
)
|
|
369
|
+
logger.info(f"Created yearly savings document for year {year}")
|
|
370
|
+
except Exception as e:
|
|
371
|
+
logger.warning(f"Update check failed, trying create: {e}")
|
|
372
|
+
try:
|
|
373
|
+
self.__elastic_operations.upload_to_elasticsearch(
|
|
374
|
+
index=self.__yearly_savings_es_index,
|
|
375
|
+
data=data,
|
|
376
|
+
id=year_id
|
|
377
|
+
)
|
|
378
|
+
logger.info(f"Created yearly savings document for year {year}")
|
|
379
|
+
except Exception as create_err:
|
|
380
|
+
logger.error(f"Failed to create document: {create_err}")
|
|
381
|
+
raise create_err
|
|
382
|
+
|
|
383
|
+
return True
|
|
384
|
+
|
|
385
|
+
except Exception as err:
|
|
386
|
+
logger.error(f"Error updating yearly savings: {err}")
|
|
387
|
+
raise err
|
|
388
|
+
|
|
389
|
+
@logger_time_stamp
|
|
390
|
+
def run(self, start_date: str = None, end_date: str = None):
|
|
391
|
+
"""
|
|
392
|
+
Main method to run the yearly savings report
|
|
393
|
+
|
|
394
|
+
@param start_date: Optional start date string (YYYY-MM-DD). If None, checks environment variable, then defaults to Jan 1 of current year.
|
|
395
|
+
@param end_date: Optional end date string (YYYY-MM-DD). If None, checks environment variable, then defaults to today.
|
|
396
|
+
@return: dict with summary
|
|
397
|
+
"""
|
|
398
|
+
if not start_date:
|
|
399
|
+
start_date = self.__custom_start_date
|
|
400
|
+
if not end_date:
|
|
401
|
+
end_date = self.__custom_end_date
|
|
402
|
+
|
|
403
|
+
if start_date and end_date:
|
|
404
|
+
try:
|
|
405
|
+
logger.info(f'Using custom date range: {start_date} to {end_date}')
|
|
406
|
+
|
|
407
|
+
month_savings = self.__get_yearly_savings(start_date=start_date, end_date=end_date)
|
|
408
|
+
total_savings = sum(month_savings.values()) if month_savings else 0.0
|
|
409
|
+
|
|
410
|
+
logger.info(f'Custom date range - Policy savings: {month_savings}')
|
|
411
|
+
logger.info(f'Custom date range - Total savings: ${total_savings:,.2f}')
|
|
412
|
+
|
|
413
|
+
return {
|
|
414
|
+
'status': 'success',
|
|
415
|
+
'custom_date_range': True,
|
|
416
|
+
'start_date': start_date,
|
|
417
|
+
'end_date': end_date,
|
|
418
|
+
'policy_savings': month_savings,
|
|
419
|
+
'total_yearly_savings': total_savings
|
|
420
|
+
}
|
|
421
|
+
except ValueError as e:
|
|
422
|
+
logger.error(f'Invalid date format: {e}. Expected YYYY-MM-DD')
|
|
423
|
+
return {'status': 'error', 'message': f'Invalid date format: {e}'}
|
|
424
|
+
|
|
425
|
+
current_date = datetime.now(timezone.utc)
|
|
426
|
+
current_year = current_date.year
|
|
427
|
+
current_month = current_date.month
|
|
428
|
+
today = current_date.date()
|
|
429
|
+
|
|
430
|
+
logger.info(f'Using default date range: current year {current_year}')
|
|
431
|
+
|
|
432
|
+
all_months_data = {}
|
|
433
|
+
|
|
434
|
+
for month in range(1, 13):
|
|
435
|
+
try:
|
|
436
|
+
if month < current_month:
|
|
437
|
+
end_day = self.__get_last_day_of_month(current_year, month)
|
|
438
|
+
month_savings = self.__calculate_month_savings(
|
|
439
|
+
year=current_year,
|
|
440
|
+
month=month,
|
|
441
|
+
start_day=1,
|
|
442
|
+
end_day=end_day
|
|
443
|
+
)
|
|
444
|
+
all_months_data[month] = sum(month_savings.values()) if month_savings else 0.0
|
|
445
|
+
|
|
446
|
+
elif month == current_month:
|
|
447
|
+
month_savings = self.__calculate_month_savings(
|
|
448
|
+
year=current_year,
|
|
449
|
+
month=month,
|
|
450
|
+
start_day=1,
|
|
451
|
+
end_day=today.day
|
|
452
|
+
)
|
|
453
|
+
all_months_data[month] = sum(month_savings.values()) if month_savings else 0.0
|
|
454
|
+
|
|
455
|
+
else:
|
|
456
|
+
all_months_data[month] = 0.0
|
|
457
|
+
|
|
458
|
+
if month < 12:
|
|
459
|
+
time.sleep(0.2)
|
|
460
|
+
|
|
461
|
+
except Exception as e:
|
|
462
|
+
logger.warning(f"Error calculating savings for month {month}: {e}, setting to 0")
|
|
463
|
+
all_months_data[month] = 0.0
|
|
464
|
+
|
|
465
|
+
total_annual_saving = sum(all_months_data.values())
|
|
466
|
+
|
|
467
|
+
logger.info(f'Monthly savings: {all_months_data}')
|
|
468
|
+
logger.info(f'Total annual savings: ${total_annual_saving:,.2f}')
|
|
469
|
+
|
|
470
|
+
if self.__elastic_operations:
|
|
471
|
+
try:
|
|
472
|
+
self.__update_yearly_savings(
|
|
473
|
+
year=current_year,
|
|
474
|
+
all_months_data=all_months_data,
|
|
475
|
+
total_annual_saving=total_annual_saving
|
|
476
|
+
)
|
|
477
|
+
logger.info(f'Successfully uploaded yearly savings to {self.__yearly_savings_es_index}')
|
|
478
|
+
return {
|
|
479
|
+
'status': 'success',
|
|
480
|
+
'records_uploaded': 1,
|
|
481
|
+
'year': current_year,
|
|
482
|
+
'total_yearly_savings': total_annual_saving,
|
|
483
|
+
'monthly_savings': all_months_data
|
|
484
|
+
}
|
|
485
|
+
except Exception as err:
|
|
486
|
+
logger.error(f'Error uploading to ES: {err}')
|
|
487
|
+
return {'status': 'error', 'message': str(err)}
|
|
488
|
+
else:
|
|
489
|
+
logger.warning('ES not configured')
|
|
490
|
+
return {'status': 'no_upload', 'message': 'ES not configured'}
|
|
@@ -54,7 +54,7 @@ class NonClusterZombiePolicy:
|
|
|
54
54
|
self.__email_alert = self.__environment_variables_dict.get(
|
|
55
55
|
'EMAIL_ALERT') if self.__environment_variables_dict.get('EMAIL_ALERT') else False
|
|
56
56
|
self.__manager_email_alert = self.__environment_variables_dict.get('MANAGER_EMAIL_ALERT')
|
|
57
|
-
self._admins = ['yinsong@redhat.com', 'ebattat@redhat.com']
|
|
57
|
+
self._admins = ['yinsong@redhat.com', 'ebattat@redhat.com', 'pragchau@redhat.com']
|
|
58
58
|
self._es_upload = ElasticUpload()
|
|
59
59
|
self.resource_pricing = ResourcesPricing()
|
|
60
60
|
self._es_operations = ElasticSearchOperations()
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cloud-governance
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.404
|
|
4
4
|
Summary: Cloud Governance Tool
|
|
5
5
|
Home-page: https://github.com/redhat-performance/cloud-governance
|
|
6
6
|
Author: Red Hat
|
|
7
|
-
Author-email: ebattat@redhat.com,
|
|
7
|
+
Author-email: ebattat@redhat.com, pragchau@redhat.com
|
|
8
8
|
License: Apache License 2.0
|
|
9
9
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -178,6 +178,7 @@ cloud_governance/policy/aws/s3_inactive.py
|
|
|
178
178
|
cloud_governance/policy/aws/skipped_resources.py
|
|
179
179
|
cloud_governance/policy/aws/spot_savings_analysis.py
|
|
180
180
|
cloud_governance/policy/aws/unused_access_key.py
|
|
181
|
+
cloud_governance/policy/aws/yearly_savings_report.py
|
|
181
182
|
cloud_governance/policy/aws/zombie_cluster_resource.py
|
|
182
183
|
cloud_governance/policy/aws/zombie_snapshots.py
|
|
183
184
|
cloud_governance/policy/aws/cleanup/__init__.py
|
|
@@ -2,7 +2,7 @@ from codecs import open
|
|
|
2
2
|
from os import path
|
|
3
3
|
from setuptools import setup, find_packages
|
|
4
4
|
|
|
5
|
-
__version__ = '1.1.
|
|
5
|
+
__version__ = '1.1.404'
|
|
6
6
|
|
|
7
7
|
here = path.abspath(path.dirname(__file__))
|
|
8
8
|
|
|
@@ -19,7 +19,7 @@ setup(
|
|
|
19
19
|
long_description=long_description,
|
|
20
20
|
long_description_content_type='text/markdown',
|
|
21
21
|
author='Red Hat',
|
|
22
|
-
author_email='ebattat@redhat.com,
|
|
22
|
+
author_email='ebattat@redhat.com, pragchau@redhat.com',
|
|
23
23
|
url='https://github.com/redhat-performance/cloud-governance',
|
|
24
24
|
license="Apache License 2.0",
|
|
25
25
|
classifiers=[
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|