Estate analysis New in 4.0
A read-only review of what an account already runs on Fabric, with priced findings and the evidence behind each.
Purpose#
Estate analysis reads the resources that an account already has (ports, connections, Cloud Routers, networks, service tokens and Network Edge devices) and reports which of them to resize, convert to a term, consolidate, remove or protect. Each finding carries its evidence and a monthly amount. The analysis makes no change to the account.
The package entered the tree in the week of 2026-11-12, and its API may change before 4.0.0 is published.
Run#
import com.eqixiac.equinix.design.estate.EstateAnalyzer;
import com.eqixiac.equinix.design.estate.EstateFinding;
import com.eqixiac.equinix.design.estate.EstateReport;
import com.eqixiac.equinix.design.estate.EstateScope;
EstateReport report = EstateAnalyzer.builder(fabric)
.networkEdge(networkEdge) // optional: include virtual devices
.scope(EstateScope.projects(projectId))
.window(Duration.ofDays(30)) // utilization window
.progress(System.err::println)
.analyze();
for (EstateFinding finding : report.findings()) {
System.out.println(finding.severity() + " " + finding.category() + ": " + finding.title());
System.out.println(" action: " + finding.action());
System.out.println(" impact: " + finding.impact() + ", confidence " + finding.confidence());
finding.evidence().forEach(e -> System.out.println(" evidence: " + e));
finding.assumptions().forEach(a -> System.out.println(" assumes: " + a));
}
Files.writeString(Path.of("estate-review.md"), report.toMarkdown());
Files.writeString(Path.of("estate-review.json"), report.toJson());eq.design().analyzeEstate() returns the same builder on a session.
Scope#
EstateScope limits the resources that are read. A run without a scope on a large account sends one or more requests per resource, so most runs name a scope.
| Factory | Reads |
|---|---|
EstateScope.projects(...) | Resources in the named projects |
EstateScope.accounts(...) | Resources of the named billing accounts |
EstateScope.resources(...) | The named resource UUIDs |
EstateScope.entireAccount(max) | Everything the credential can see, up to max resources per type |
The collector reads a bounded number of pages per resource type. It records each resource that it could not read in report.coverageGaps(), and report.notAnalysed() lists what the rules did not cover. The rules produce findings only from data that was read.
Utilization#
For each connection the analysis reduces the Fabric bandwidth metrics over the window to the median, the 95th percentile and the peak. A connection with fewer samples than the minimum, 24 by default, has unknown utilization and is not reported as idle.
Rules#
| Category | Finding | Default threshold |
|---|---|---|
RIGHT_SIZE_DOWN | The 95th-percentile use is far below the provisioned bandwidth | Below 30%; the target is the smallest tier at or above the 95th percentile times 1.3 |
RIGHT_SIZE_UP | The 95th-percentile use is close to the provisioned bandwidth | Above 80% |
ON_DEMAND_TO_TERM | An on-demand connection or Cloud Router, older than the minimum age, is cheaper on a contract term | Older than 90 days |
CONSOLIDATE_BEHIND_ROUTER | Several port-to-cloud connections in one metro could share a Cloud Router, or a router carries too little to justify it | At least 3 connections |
IDLE_OR_UNUSED | A resource is held and not used, for example an active port with no connection | |
SINGLE_POINT_OF_FAILURE | A cloud connection has no secondary in its redundancy group | |
CAPACITY_RISK | A port's allocated bandwidth, or a Cloud Router's connection count, is near its limit | |
HYGIENE | Stuck or inconsistent resources, grouped as one finding per issue and resource kind |
thresholds(EstateThresholds) changes the thresholds. addRule(EstateRule) adds a rule and rules(List) replaces the set.
Money#
Each finding carries a FinancialImpact priced through a rate card: the current monthly cost, the cost after the action, and the difference. The report totals the savings for each currency separately in addressableMonthlySaving() and lists the items it could not price in unpriced().
Two findings can address the same resource, for example a right-size and a term conversion on one connection. The savings of the two findings then overlap, and the sum over all findings exceeds the amount that can be saved. actions() returns the findings as an ordered list of actions.
Offline use#
Collection and analysis are separate steps, so an inventory can be collected once, stored, and analysed later without access to the API.
import com.eqixiac.equinix.design.estate.EstateInventory;
EstateInventory inventory = EstateAnalyzer.builder(fabric)
.scope(EstateScope.projects(projectId))
.collect();
EstateReport offline = EstateAnalyzer.fromSnapshot(inventory).analyze();The same rules applied to the same stored inventory give the same findings, which makes a review repeatable.
Limits#
- The analysis takes prices from the rate-card chain. A live Equinix price is the list price for the account's region, and a contract rate is used only when it is supplied through a
CustomRateCard. - Utilization is taken from the Fabric metrics API for the chosen window, so traffic outside the window, such as a batch job that ran before it, does not appear.
- A right-size finding on a cloud connection does not check the provider side. An Azure ExpressRoute circuit, for example, cannot be reduced in place.
- The analysis covers Fabric and, when a Network Edge client is supplied, Network Edge. It does not cover colocation space, power or cross connects.