Skip to main content

OCI Forgotten Resource Detective: Sniff Out Orphaned OCI Resources Like a FinOps Bloodhound

Hunt down forgotten, wasteful OCI resources in your tenancy with this Python-powered detective—no apron needed.

IntermediateCleanup10-15 minutes per tenancyOCI

Standardized doc shell (hero + metadata + quick path). Custom content below remains page-specific.

Download Tool Files

Spread the FinOps flavor!

Blaze
Blaze says:Sort the CSV output by cost estimate descending -- the top 10 resources usually account for 80% of your recoverable waste. Focus there first for maximum bang-for-buck cleanup.

Standard run path

Structured quick-reference sections for prerequisites, installation, usage, and troubleshooting.

Prerequisites

  • Python 3.6+ and OCI SDK/CLI configured
  • Read-only OCI access across the compartments you want to scan
  • Valid OCI profile and key material in your local OCI config
  • Writable local paths for CSV and HTML report output

CLI Parameters

ParameterDescriptionDefaultExample
--profileOCI CLI profile name to useDEFAULT--profile production
--old-shape-patternRegex to flag old-gen compute shapesVM\.Standard1.*--old-shape-pattern "VM\.(Standard1|Standard2).*"
--suspicious-name-regexRegex for suspicious resource names\b(test|temp|demo|old|backup|poc)\b--suspicious-name-regex "\b(dev|qa|test|temp)\b"
--output-csvPath to write CSV reportforgotten_resources_report.csv--output-csv "/reports/oci_waste_2025_06.csv"
--output-htmlPath to write HTML reportforgotten_resources_report.html--output-html "/reports/oci_waste_2025_06.html"

Copied from the page’s advanced usage parameter table.

Usage

  1. 1Start with the default profile in a single tenancy to validate access and output.
  2. 2Sort the CSV by estimated cost to prioritize the biggest waste candidates first.
  3. 3Confirm findings with owners before cleanup, especially for DR or intermittently used resources.
bash
python oci_forgotten_resources.py
bash
python oci_forgotten_resources.py --profile production --output-csv "/reports/oci_waste.csv" --output-html "/reports/oci_waste.html"

Sample Output

OCI cost hygiene review (illustrative visual)

Representative OCI cost-control visual used as a companion reference while reviewing the script-generated reports.

OCI cost control visual

Illustrative OCI cost-control visual. Actual script output is the generated HTML and CSV reports.

Top findings (report excerpt)

ResourceTypeCompartment/ScopeRiskEst. Monthly Cost
orphaned-volume-001Block Volumeprod-shared-servicesHigh$48.00
public-ip-unused-07Reserved Public IPnetworkingMedium$3.60
empty-nsg-dev-legacyNetwork Security Groupdev-legacyLow$0 (complexity)
  • Use the HTML report for richer context and remediation notes.
  • Validate suspicious naming matches with application owners before cleanup.

Troubleshooting

IssueLikely CauseFix
Authentication errorInvalid or expired OCI configVerify OCI config and key pair, then rerun with the correct profile
Permission deniedInsufficient read accessGrant/confirm read access to scanned compartments and resource types
Missing module errorOCI SDK not installedRun `pip install oci` and confirm the active Python environment

Overview

The OCI Forgotten Resource Detective is a Python script that sniffs out those dusty, unused resources lurking in your OCI kitchen and quietly padding your bill. It’s your FinOps bloodhound—pointing out the wasteful ingredients you can toss to slim down costs and keep your cloud pantry lean.

Forget just scratching the surface—this script dives deep into your OCI pantry to sniff out the real leftovers: orphaned block volumes, floating public IPs, empty NSGs, and more. It then whips up both a detailed CSV “shopping list” and a colorful HTML report (complete with cost estimates) so you know exactly which waste to toss first.

Download the Script

Grab the OCI Forgotten Resource Detective script and start trimming your cloud pantry of waste today.

Download Script

Key Features

Comprehensive Scanning

Dives into every nook and cranny—root compartment and all—so no orphaned resource escapes your FinOps inspection.

Cost Estimation

Serves up monthly cost estimates for each resource so you know which leftovers to toss first.

Risk Assessment

Sorts findings into High, Medium, and Low risk tiers—so you can tackle the spiciest budget burners first.

Dual Reporting

Whips up a CSV “shopping list” and a stylish HTML menu for easy review and sharing with your FinOps crew.

Resource Types Detected

  • Orphaned Block Volumes: Volumes with no attachments that continue to incur storage costs
  • Unattached Public IPs: Reserved public IP addresses not attached to any resource
  • Empty Network Security Groups: NSGs with no VNICs attached, creating unnecessary complexity
  • Load Balancers with No Backends: Load balancers with backend sets but no actual backends
  • Old-Generation Compute Instances: Instances using outdated shapes that could be migrated to more efficient options
  • Untagged Resources: Resources with no tags, making cost allocation and tracking difficult
  • Suspiciously Named Resources: Resources with names suggesting temporary or test usage (test, temp, demo, etc.)
Cost Optimization Potential

By tossing out those forgotten leftovers in your OCI pantry, you’ll carve off juicy savings from your monthly cloud bill—like trimming the fat for a leaner, tastier outcome.

How It Works

This FinOps bloodhound uses the OCI Python SDK to patrol your tenancy, inspecting resources and their settings to sniff out potential waste. Here’s how the recipe unfolds:

  1. Authentication: Connects to OCI using your configured profile credentials
  2. Compartment Discovery: Identifies all active compartments in your tenancy, including the root compartment
  3. Resource Scanning: For each compartment, scans for various resource types (block volumes, public IPs, NSGs, load balancers, compute instances)
  4. Waste Analysis: Applies specific criteria to identify potentially wasteful resources:
    • Block volumes with no attachments
    • Reserved public IPs not attached to any VNIC
    • Network security groups with no VNICs
    • Load balancers with no backends
    • Compute instances with shapes matching the old-generation pattern
    • Resources with no tags
    • Resources with names matching suspicious patterns
  5. Cost Estimation: Calculates approximate monthly cost impact for identified resources
  6. Reporting: Generates both CSV and HTML reports with the findings

Key Detection Logic

Here’s how we taste-test resources to spot the stale, wasteful ones in your OCI pantry:

Orphaned Block Volumes:
# Find any attachments for this volume
attachments = compute_client.list_volume_attachments(
 compartment_id=comp_id,
 volume_id=vol.id
).data

# If no attachments found → it's orphaned
if len(attachments) == 0:
 # Add to findings
Untagged Resources:
def has_no_tags(resource):
 ff = getattr(resource,"freeform_tags", None)
 df = getattr(resource,"defined_tags", None)
 if (not ff or len(ff) == 0) and (not df or len(df) == 0):
 return True
 return False
Read-Only Operation

This detective only sniffs around—never stirs the pot—performing read-only checks so it’s totally safe to run in your production kitchen.

Prerequisites

Before firing up the OCI Forgotten Resource Detective, make sure your kitchen is stocked with:

  • Python 3.6 or higher - The script is compatible with Python 3.6+
  • OCI Python SDK - The script requires the OCI Python SDK to interact with Oracle Cloud
  • OCI CLI Configuration - A properly configured OCI CLI profile with the necessary permissions
  • Required Permissions - The user or service principal used must have read access to the resources being scanned

Installing Required Packages

Install the OCI Python SDK using pip:

pip install oci

Required OCI Permissions

The user or service principal running the script needs the following permissions:

  • Identity: inspect on compartments
  • Compute: inspect on instances and volume-attachments
  • Block Storage: inspect on volumes
  • Virtual Network: inspect on public-ips and network-security-groups
  • Load Balancer: inspect on load-balancers
Permission Requirements

If the user or service principal doesn't have access to certain compartments or resource types, the script will still run but may not detect all wasteful resources. For best results, use a user with read access across your entire tenancy.

Installation

Installing this detective is as easy as preheating the oven—just grab the script, install dependencies, and you’re ready to cook.

  1. Download the script - Save the oci_forgotten_resources.py file to your preferred location
  2. Make it executable (Linux/macOS) - Run chmod +x oci_forgotten_resources.py
  3. Install dependencies - Ensure the OCI Python SDK is installed

OCI CLI Configuration

The script uses the OCI CLI configuration file located at ~/.oci/config. If you haven't configured the OCI CLI yet, follow these steps:

  1. Install the OCI CLI following the official documentation
  2. Run oci setup config and follow the prompts
  3. Verify your configuration with oci iam region list
Multiple OCI Profiles

If you have multiple OCI profiles configured, you can specify which one to use with the --profile parameter when running the script. This is useful if you need to scan multiple tenancies or use different credentials.

Usage

Basic Usage

Want the no-frills option? Just run the script as-is (no flags needed), and it will:

  • Use your DEFAULT OCI CLI profile
  • Flag VM.Standard1.* shapes as old-generation
  • Flag resources with names containing test, temp, demo, old, backup, or poc
  • Save the CSV report as"forgotten_resources_report.csv" in the current directory
  • Save the HTML report as"forgotten_resources_report.html" in the current directory
python oci_forgotten_resources.py

Advanced Usage

The script supports several parameters for more customized analysis:

ParameterDescriptionDefaultExample
--profileOCI CLI profile name to useDEFAULT--profile production
--old-shape-patternRegex to flag old-gen compute shapesVM\\.Standard1.*--old-shape-pattern"VM\\.(Standard1|Standard2).*"
--suspicious-name-regexRegex for suspicious resource names\b(test|temp|demo|old|backup|poc)\b--suspicious-name-regex"\b(dev|qa|test|temp)\b"
--output-csvPath to write CSV reportforgotten_resources_report.csv--output-csv"/reports/oci_waste_2025_06.csv"
--output-htmlPath to write HTML reportforgotten_resources_report.html--output-html"/reports/oci_waste_2025_06.html"

Example Commands

Example 1: Use a specific OCI profile

python oci_forgotten_resources.py --profile production

Example 2: Customize the old shape pattern to include more shapes

python oci_forgotten_resources.py --old-shape-pattern"VM\\.(Standard1|Standard.E2).*"

Example 3: Comprehensive custom analysis

python oci_forgotten_resources.py \
  --profile production \
  --old-shape-pattern"VM\\.(Standard1|Standard2|Standard.E2).*" \
  --suspicious-name-regex"\b(dev|test|temp|demo|old|backup|poc)\b" \
  --output-csv"/reports/oci_waste_$(date +%Y-%m-%d).csv" \
  --output-html"/reports/oci_waste_$(date +%Y-%m-%d).html"
Runtime Considerations

Just like baking a multi-layer cake takes time, this script needs a few minutes to sift through every OCI compartment and resource. For big tenancies, let it simmer—waiting a bit ensures you get the full flavor of comprehensive results.

Understanding the Report

This detective serves up results three ways—console output, a CloudCostChefs-styled HTML report, and a handy CSV “shopping list.

Console Output

The console output provides immediate insights and includes:

  • Compartment Scanning Progress - Shows which compartments are being scanned
  • Summary Statistics - Total number of issues found
  • Report Locations - Paths to the generated CSV and HTML reports
Fetching all active compartments under tenancy ocid1.tenancy.oc1..example …
 Found 12 compartments (including root).

Scanning compartment ocid1.compartment.oc1..example1 …
Scanning compartment ocid1.compartment.oc1..example2 …
Scanning compartment ocid1.compartment.oc1..example3 …
...

Found 24 forgotten/suspicious resources in total.
CSV report saved to: forgotten_resources_report.csv
HTML report saved to: forgotten_resources_report.html

HTML Report

The HTML report dishes out a beautiful, easy-to-share feast of your findings—perfect for serving to the whole FinOps team.

Header Section

  • Report title with CloudCostChefs branding
  • Generation timestamp
  • Total issues found

Results Table

  • Risk level (color-coded)
  • Resource name and type
  • Compartment ID
  • Issue description
  • Cost estimate
  • Additional information
  • Tags (if any)

Color Coding

The HTML report uses color coding to highlight risk levels:

  • High Risk (Light Red): Resources with significant cost impact or security concerns
  • Medium Risk (Light Orange): Resources with moderate cost impact or potential issues
  • Low Risk (Light Green): Resources with minimal cost impact but still worth reviewing

CSV Report

The CSV report offers a full, spreadsheet-ready spread of your findings—perfect for spreadsheets or data analysis tools hungry for details:

CSV Columns

  • ResourceName: Name of the identified resource
  • ResourceType: Type of resource (BlockVolume, PublicIP, etc.)
  • CompartmentId: OCID of the compartment containing the resource
  • Issue: Description of the identified issue
  • RiskLevel: High, Medium, or Low
  • CostEstimate: Estimated monthly cost impact
  • AdditionalInfo: Extra details about the resource
  • FreeformTags: Any freeform tags on the resource
  • DefinedTags: Any defined tags on the resource
Report Analysis

The CSV report is particularly useful for further analysis and filtering. You can import it into Excel or Google Sheets to:

  • Sort by cost estimate to prioritize high-impact cleanup
  • Filter by resource type to focus on specific areas
  • Group by compartment to assign cleanup tasks to teams
  • Create pivot tables to analyze patterns in your cloud waste

Customization Options

Feel free to tweak the detective’s recipe—adjust the shape regex or suspicious-name regex so it fits your OCI kitchen’s unique flavor:

Customizing Old-Generation Shape Detection

You can adjust the regex pattern used to identify old-generation compute shapes:

# Default pattern (flags VM.Standard1.* shapes)
--old-shape-pattern"VM\.Standard1.*"

# More aggressive pattern (flags VM.Standard1.*, VM.Standard2.*, and VM.Standard.E2.*)
--old-shape-pattern"VM\.(Standard1|Standard2|Standard\.E2).*"

# Include AMD shapes
--old-shape-pattern"VM\.(Standard1|Standard\.E2|Standard\.A1).*"

Modifying the HTML Template

You can modify the HTML template in the script to change the report's appearance or add additional information:

# Find the HTML template section (starts with html_content = f"""<!DOCTYPE html>)
# Modify the CSS styles or HTML structure as needed
# For example, to change the background color:

body { 
 font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; 
 background: #f0f0f0; /* Changed color */
 margin: 20px; 
}

Adding New Detection Rules

Advanced users can modify the script to add new detection rules. For example, to detect compute instances that have been stopped for a long time:

# Add to the scan_compartment function
# Check for long-stopped instances
for inst in instances:
 if inst.lifecycle_state =="STOPPED":
 # Get the instance's lifecycle history
 history = compute_client.list_instance_actions(
 instance_id=inst.id
 ).data
 
 # Look for the most recent stop action
 stop_actions = [a for a in history if a.action =="STOP"]
 if stop_actions and len(stop_actions) > 0:
 latest_stop = max(stop_actions, key=lambda x: x.time_created)
 stop_time = latest_stop.time_created
 
 # Calculate days since stopped
 days_stopped = (datetime.now(timezone.utc) - stop_time).days
 
 if days_stopped > 30: # Stopped for more than 30 days
 findings.append({
"ResourceName": inst.display_name,
"ResourceType":"ComputeInstance",
"CompartmentId": comp_id,
"Issue": f"Stopped for {days_stopped} days",
"RiskLevel":"Medium",
"CostEstimate":"Storage only",
"AdditionalInfo": f"Shape: {inst.shape}, Stopped since: {stop_time.strftime('%Y-%m-%d')}",
"FreeformTags": inst.freeform_tags or {},
"DefinedTags": inst.defined_tags or {},
 })
Maintaining Script Functionality

When customizing the script, be careful not to modify the core functionality that retrieves and processes the resource data. Focus your changes on the detection patterns, HTML template, or output formatting.

Automation

For regular monitoring of forgotten resources, you can automate the OCI Forgotten Resource Detective using various methods:

Cron Job (Linux/macOS)

Set up a cron job to run the script on a regular basis:

# Edit crontab
crontab -e

# Add a line to run weekly on Sunday at 1 AM
0 1 * * 0 /path/to/python /path/to/oci_forgotten_resources.py --output-csv"/reports/oci_waste_$(date +\%Y-\%m-\%d).csv" --output-html"/reports/oci_waste_$(date +\%Y-\%m-\%d).html"

Task Scheduler (Windows)

Set up a scheduled task to run the script on a regular basis:

  1. Open Task Scheduler and create a new Basic Task
  2. Set it to run weekly
  3. Action: Start a program
  4. Program/script: python.exe
  5. Arguments:"C:\Path\To\oci_forgotten_resources.py" --output-csv"C:\Reports\oci_waste_%date:~10,4%-%date:~4,2%-%date:~7,2%.csv" --output-html"C:\Reports\oci_waste_%date:~10,4%-%date:~4,2%-%date:~7,2%.html"

OCI Functions

For a cloud-native approach, deploy the script as an OCI Function:

  1. Create an OCI Function application
  2. Modify the script to use instance principal authentication instead of config file
  3. Deploy the function to OCI
  4. Set up an OCI Events rule to trigger the function on a schedule
  5. Configure the function to save reports to Object Storage
Email Integration

For automated runs, you can modify the script to email the results to your team:

# Add this at the end of the main function
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication

def send_email_report(csv_path, html_path, recipients):
 msg = MIMEMultipart()
 msg['Subject'] = f'OCI Forgotten Resource Report - {datetime.now().strftime("%Y-%m-%d")}'
 msg['From'] = 'oci-detective@yourcompany.com'
 msg['To'] = ', '.join(recipients)
 
 # Add body
 body = f"The OCI Forgotten Resource Detective found {len(all_findings)} issues. See attached reports."
 msg.attach(MIMEText(body, 'plain'))
 
 # Attach CSV
 with open(csv_path, 'rb') as file:
 attachment = MIMEApplication(file.read(), Name=os.path.basename(csv_path))
 attachment['Content-Disposition'] = f'attachment; filename="{os.path.basename(csv_path)}"'
 msg.attach(attachment)
 
 # Attach HTML
 with open(html_path, 'rb') as file:
 attachment = MIMEApplication(file.read(), Name=os.path.basename(html_path))
 attachment['Content-Disposition'] = f'attachment; filename="{os.path.basename(html_path)}"'
 msg.attach(attachment)
 
 # Send email
 smtp = smtplib.SMTP('smtp.yourcompany.com')
 smtp.send_message(msg)
 smtp.close()
 
 print(f"Email report sent to {', '.join(recipients)}")

# Call the function if findings exist
if all_findings:
 send_email_report(
 args.output_csv,
 args.output_html,
 ['cloud-team@yourcompany.com', 'finance@yourcompany.com']
 )

Troubleshooting

If you encounter issues with the OCI Forgotten Resource Detective, here are some common problems and solutions:

IssuePossible CauseSolution
Authentication ErrorInvalid or expired OCI configVerify your OCI config file is correctly set up and your key is valid
Permission DeniedInsufficient permissions for the userEnsure the user has read access to all resource types being scanned
Missing Module ErrorOCI SDK not installedRun pip install oci to install the OCI Python SDK
Script Runs SlowlyLarge tenancy with many resourcesBe patient; the script needs to scan all resources. Consider running during off-hours
No Issues FoundLimited access or clean tenancyVerify the user has access to all compartments; adjust detection patterns if needed

Debugging Tips

If you're experiencing issues, try these debugging approaches:

  1. Verify OCI CLI Access: Run a simple OCI CLI command to confirm your authentication works:
    oci iam region list
  2. Check Python Version: Ensure you're using Python 3.6 or higher:
    python --version
  3. Verify OCI SDK Installation: Confirm the OCI SDK is installed:
    pip list | grep oci
  4. Add Debug Prints: Add print statements to the script to track progress and identify where issues occur
  5. Run with Limited Scope: Modify the script to scan only a specific compartment to isolate issues
Service Limits

The OCI API has service limits that may affect the script's performance. If you're running into rate limiting issues, consider adding retry logic or spreading the scans across multiple runs.

Next Steps

After identifying forgotten resources with this tool, consider these next steps to optimize your OCI costs:

Implement Resource Cleanup

Systematically review and remove identified wasteful resources after verifying they're truly unused.

Learn about safe cleanup procedures →

Establish Tagging Policies

Implement comprehensive tagging policies to prevent untagged resources in the future.

Explore tagging best practices →

Set Up Regular Monitoring

Automate this script to run regularly and track resource waste over time.

Learn about continuous optimization →

Implement Governance Controls

Create policies and procedures to prevent wasteful resources from being created.

Discover governance frameworks →

Extending the Script

Consider these enhancements to the script for more advanced use cases:

  • Resource Cleanup: Add functionality to automatically terminate or delete identified resources (with appropriate safeguards)
  • Additional Resource Types: Extend the script to check for other resource types like Object Storage buckets, Autonomous Databases, or File Storage
  • Integration with Ticketing Systems: Automatically create tickets for resource cleanup in systems like ServiceNow or Jira
  • Historical Tracking: Store results in a database to track waste over time and measure improvement
  • Multi-Tenancy Support: Enhance the script to scan multiple tenancies in a single run
Building a FinOps Practice

The OCI Forgotten Resource Detective is just one tool in your FinOps toolkit. For a comprehensive approach to cloud financial management, explore our complete FinOps implementation guide.

Share This Guide

If this recipe hit the spot, pass it along to your cloud crew and the wider kitchen!

Was this documentation helpful?

Have suggestions for improving this document? Contact us.

What to do next

Pick the path that fits where you are right now.

Trust & run-safety metadata

Key execution details for Cloud Cost Chefs OCI Forgotten Resource Detective so users know what they are downloading or running before they act.

Need verification guidance? See Security & Trust and Responsible Disclosure.

Read-only / reportingDirect downloadExplicit + inferred metadata

Maintainer

CloudCostChefs

Last Updated

June 5, 2025

Last Tested

February 23, 2026

Minimum Access

Read-only OCI access

Execution Type

Python script (reporting + export)

Version

2025-06-05

SHA256 Checksum

a0ec8034ca427230e79ccbbfa2698ccdbacac4fc7c784798fd611ff9243529c2

Verification Notes

Designed for discovery/reporting. SHA256 recorded and Python syntax compiled successfully on February 25, 2026. Validate OCI CLI/profile configuration and output file location before running.

Safe Usage Checklist

  • Run in a non-production subscription/account/tenancy first and capture sample output before broader rollout.
  • Use least-privilege access. Current best hint from docs: Read-only OCI access.
  • Confirm report/export destinations and protect any generated cost or inventory files that may contain sensitive metadata.

Quick start (fast path)

Minimal steps to safely get value from this tool without reading the entire page first.

Estimated time: 10-15 minutes per tenancyDifficulty: IntermediateAccess: Review / read-only
  1. 1. Confirm scope and permissions

    Use least privilege and test in a non-production scope first. Minimum access hint: Read-only OCI access.

  2. 2. Get the tool package / source

    Download Tool Files and review the files before running.

    Download
  3. 3. Check prerequisites

    • ✅ Read-only OCI access
    • ✅ Python 3.6+
  4. 4. Run safely and review output

    Designed for discovery/reporting. SHA256 recorded and Python syntax compiled successfully on February 25, 2026. Validate OCI CLI/profile configuration and output file location before running. Start with a small sample scope, then expand once results look correct.