CoolFace
Modelpublic

shaikhsalman/devsecops-platform

sourceHugging Faceapache-2.0updated 5mo agoView on Hugging Face
0likes
finops_scanner.py89 linesDownload Raw Back to infrastructure
1#!/usr/bin/env python32"""FinOps Cloud Cost Scanner - Detect Waste & Recommend Savings."""3 4import json, subprocess5from datetime import datetime6from pathlib import Path7from typing import Dict, List8 9class FinOpsScanner:10    def __init__(self, output_dir: str = "./finops-reports"):11        self.output_dir = Path(output_dir)12        self.output_dir.mkdir(parents=True, exist_ok=True)13        self.findings: List[Dict] = []14        self.total_potential_savings = 0.015 16    def _aws_cmd(self, service: str, cmd: str) -> str:17        full_cmd = f"aws {service} {cmd} --output json --region us-east-1"18        try:19            result = subprocess.run(full_cmd, shell=True, capture_output=True, text=True, timeout=60)20            return result.stdout if result.returncode == 0 else "[]"21        except Exception:22            return "[]"23 24    def scan_unused_volumes(self) -> List[Dict]:25        output = self._aws_cmd("ec2", "describe-volumes --filters Name=status,Values=available")26        try:27            volumes = json.loads(output).get("Volumes", [])28            for v in volumes:29                size_gb = v["Size"]30                savings = size_gb * 0.0831                self.findings.append({32                    "id": f"FINOPS-001-{v['VolumeId']}",33                    "type": "unused-ebs",34                    "size_gb": size_gb,35                    "monthly_savings": round(savings, 2),36                    "action": f"Delete or snapshot {v['VolumeId']}",37                })38                self.total_potential_savings += savings39            return self.findings40        except json.JSONDecodeError:41            return []42 43    def scan_idle_eips(self) -> List[Dict]:44        output = self._aws_cmd("ec2", "describe-addresses")45        try:46            for addr in json.loads(output).get("Addresses", []):47                if "AssociationId" not in addr:48                    self.findings.append({49                        "id": f"FINOPS-003-{addr['PublicIp']}",50                        "type": "unattached-eip",51                        "monthly_savings": 3.60,52                        "action": f"Release EIP {addr['PublicIp']}",53                    })54                    self.total_potential_savings += 3.6055            return self.findings56        except json.JSONDecodeError:57            return []58 59    def generate_report(self) -> str:60        report = {61            "timestamp": datetime.utcnow().isoformat() + "Z",62            "total_potential_monthly_savings": round(self.total_potential_savings, 2),63            "findings_count": len(self.findings),64            "findings": self.findings,65            "recommendations": [66                {"priority": 1, "action": "Schedule non-prod off-hours", "savings": "65% non-prod"},67                {"priority": 2, "action": "Purchase RIs for EKS nodes", "savings": "30-40% compute"},68                {"priority": 3, "action": "Enable S3 Intelligent-Tiering", "savings": "40-60% storage"},69                {"priority": 4, "action": "Use SPOT for ML training", "savings": "70-90% GPU"},70                {"priority": 5, "action": "Rightsize K8s workloads", "savings": "30-50% cluster"},71            ],72        }73        report_path = self.output_dir / f"finops-{datetime.now().strftime('%Y%m%d')}.json"74        with open(report_path, "w") as f:75            json.dump(report, f, indent=2, default=str)76        print(f"77{'='*60}")78        print(f"FINOPS SCAN: {len(self.findings)} findings | ${self.total_potential_savings:,.2f}/mo potential savings")79        print(f"{'='*60}")80        return str(report_path)81 82    def run_full_scan(self):83        self.scan_unused_volumes()84        self.scan_idle_eips()85        return self.generate_report()86 87if __name__ == "__main__":88    FinOpsScanner().run_full_scan()89