On this page
Findings#
A finding is one thing a detector found wrong or wasteful about one resource: a volume attached to nothing, a database nobody connects to, a bucket open to the public. This page says how findings are made, what states they go through and what each detector looks at.
What a finding is#
A detector is one query over the data Hyvop collected. On every detection run, each row the query returns becomes a finding. There is one finding for each resource and kind of waste: if two detectors report the same kind of waste on one resource, they share it.
Detection runs after each collection and every night. An administrator can start it at once from Detection > Installed
(/detection/installed) with "Run detection now".
A finding carries: the resource, the kind of waste, a risk (high, medium or low), the savings options with a monthly amount where one can be worked out, the resource's tags, its owner and team when known, and the step it has reached.
Find them at Detection > Active (/inefficiencies), the page titled Inefficiencies. Filter by source, status, type,
risk, owner and team, or search. "Export Filtered" and the bulk Export write a CSV file of the rows. Opening a finding
shows where it stands, why, and the way on: the plan, the resource, and who owns it.
The states#
Core moves a finding from one state to the next. Nobody changes it by hand on this page.
| State (as shown) | What it means |
|---|---|
| Detected | A detector reported it. Nothing else has happened yet |
| Ownership requested | Nobody had looked at who owns the resource, so Hyvop asked the ownership agents (ownership.md) |
| Owned | A person is confirmed as accountable for the resource. A plan is being written |
| Planned | A plan exists and may still be changed |
| Awaiting approval | The plan waits for the people who must approve it. The reason names them |
| Approved | Every required approver has approved. In the Community Edition the loop stops here: nothing is carried out (remediation.md) |
| Blocked | Nobody can take it further. The reason on the finding says why: no accountable person is confirmed; not enough people are confirmed to approve; or a policy forbids a change to the resource |
| Rejected | The plan was rejected. It stays rejected |
| Resolved | Detection no longer reports it, so it was closed on its own |
| Compliant by policy | A policy says what was found is compliant, not waste. See below |
Compliant by policy#
A policy that exempts a resource from detection turns its finding into "Compliant by policy": it is not listed as waste
on the Active page, it is in no sum of savings, it gets no plan, and the policy that did it is named with its reason.
The list of them is the tab "Compliant by policy" under Governance > Policies (/policy-management). If the policy is
deleted or no longer covers the resource, the finding comes back as Detected at once. See policies.md.
Blocked#
A finding is blocked in three cases.
- No accountable person is confirmed for the resource. The finding shows a link to the ownership review
(Ownership > Unassigned,
/ownership/unassigned). Once somebody is confirmed it moves on by itself. - Fewer people are confirmed than the plan needs as approvers.
- A policy forbids remediation of the resource. The reason starts "Blocked by policy", and the finding links to the policies.
When a finding closes or comes back#
- A detector's finding is closed as Resolved after the detector has read its whole view twice in a row and not reported it again. Only findings still in triage are closed this way. A finding somebody owns, is deciding on, approved or rejected is never closed by detection.
- A run that fails, is cut short, or cannot reach the data changes no finding. A failed read is not a fix.
- A resource that is gone from the cloud leaves the inventory, so its findings stop being reported and close.
Detectors#
Detection > Installed (/detection/installed) lists the detectors your organisation has. Each shows when it last ran
and what it found, or why it failed and when it last worked, or "Not run yet". An administrator can switch one off (its
findings stay and none is closed for it), update it, or uninstall it. Detection > Marketplace (/detection/discover)
is the catalogue: install from it.
Without anyone asking, Hyvop installs the official detectors of the connected cloud before a run, from the catalogue shipped with the release, and does not put back one a person uninstalled.
Detectors come with the release; an update is yours to apply. When the registry publishes a higher version of a detector your organisation has installed, an administrator is offered the update and can apply it, one detector or all of them. Nothing is applied automatically. An install with no internet access loses nothing and is offered no update (../air-gapped.md).
Open a detector (/detection/detector/<id>) to read its description, its Detection logic (the query, in SQL), its
last thirty runs, and to "Run simulation": it runs the query against your data in a sandbox and shows the matching
resources and the estimated savings. A simulation changes nothing.
Detection > Create Detector (/detection/create, administrators) writes a detector from a sentence. It needs a model
(ai.md). The model writes one query; Hyvop checks it, you simulate it, then save it.
The detectors that ship with core#
Core's shipped catalogue holds 42 detectors: 21 for AWS, 11 for Azure and 10 for GCP. Detection > Marketplace shows what the catalogue offers beyond them.
Thresholds#
Eleven of the AWS detectors declare thirteen thresholds (the Azure and GCP ones are further down). The numbers in the table below are their defaults. An administrator changes one on the detector's page (Detection, then the detector, Thresholds). The change applies to the whole install, takes effect at the next run of the detector, and is recorded on the audit trail. A finding names the threshold in force in its condition and its detail. The value must lie within the range shown; Hyvop refuses one outside it.
| Detector | Threshold | Default | Range |
|---|---|---|---|
ec2_overprovisioned |
cpu_below: 95th percentile CPU below, in percent |
20 | 1 to 90 |
ec2_overprovisioned |
network_below_mbps: 95th percentile network below, in Mbps |
10 | 0.1 to 10000 |
ec2_stopped_long |
stopped_days: stopped for more than, in days |
7 | 1 to 365 |
ebs_unattached |
unattached_days: attached to nothing for more than, in days |
7 | 1 to 365 |
ebs_overprovisioned_iops |
used_below_percent: 95th percentile IOPS used below, in percent of provisioned |
50 | 1 to 95 |
ebs_snapshot_old |
older_than_days: older than, in days |
90 | 1 to 3650 |
snapshot_orphaned_old |
older_than_days: older than, in days |
90 | 1 to 3650 |
rds_overprovisioned |
cpu_below: 95th percentile CPU below, in percent |
20 | 1 to 90 |
rds_overprovisioned |
connections_below: 95th percentile connections below |
10 | 1 to 10000 |
s3_versioning_cost |
versions_above: noncurrent versions above |
100 | 1 to 100 |
lambda_overprovisioned_memory |
memory_below: 95th percentile memory used below, in percent |
40 | 1 to 90 |
elb_idle |
requests_below: requests on the busiest of the last 7 days below |
10 | 1 to 1000000 |
dynamodb_overprovisioned |
provisioned_over_times: provisioned capacity more than this many times the 95th percentile consumed |
4 | 1.5 to 100 |
The other ten detectors have no threshold: they judge on a state or on zero (rds_idle, dynamodb_idle,
lambda_unused, elb_no_targets, eip_unassociated, ec2_old_generation, rds_multi_az_dev, rds_public_access,
s3_no_lifecycle, s3_public_access).
What the prices are#
Every rule that states a saving reads only prices in US dollars that have not expired. A price in another currency, or one
whose end date has passed, is not read: the resource is still found, and the finding states no saving. Four rules do not
price what would go but estimate the saving as a share of the current price, and say so in the finding:
ec2_overprovisioned, rds_overprovisioned and dynamodb_overprovisioned take half of it, ec2_old_generation takes
15 percent. The finding ends with "Savings estimate uses proxy pricing" and names the share.
"95th percentile" is the value that the resource stayed under 95 percent of the time over the window. A rule that reads usage waits until the resource has enough days of datapoints, and reports nothing for it until then. Metrics are kept for 30 days in this edition.
| Detector | Service | Severity | What it flags | History it waits for | Saving it states |
|---|---|---|---|---|---|
dynamodb_idle |
DynamoDB | Medium | A table that consumed no read or write capacity. | 7 days | A month of the provisioned capacity price |
dynamodb_overprovisioned |
DynamoDB | Medium | A provisioned table whose read or write capacity is more than 4 times its 95th percentile use. | 7 days | Half a month of the provisioned capacity price |
ebs_overprovisioned_iops |
EBS | Medium | A volume with provisioned IOPS whose 95th percentile use is below half of them. | 7 days | The unused IOPS times the IOPS price |
ebs_snapshot_old |
EBS | Low | A snapshot older than 90 days that no image (AMI) refers to, whose source volume still exists. | - | The bytes the snapshot stores where AWS reports them, otherwise the volume size, times the snapshot price |
ebs_unattached |
EBS | Medium | A volume in the state available (attached to nothing) for more than 7 days. | - | Volume size times the volume price |
ec2_old_generation |
EC2 | Low | A running instance of an old family: m3, m4, c3, c4, r3 or r4. | - | 15 percent of a month of the instance price |
ec2_overprovisioned |
EC2 | Medium | A running instance whose 95th percentile CPU is below 20 percent and network below 10 Mbps over 30 days. | 28 days | Half a month of the instance price |
ec2_stopped_long |
EC2 | Medium | An instance stopped for more than 7 days. | - | The idle addresses the instance holds plus its attached volumes, each at its own type's price (storage only). The saving is realised only when the volumes are deleted |
eip_unassociated |
EC2 | Medium | An Elastic IP address with no association. | - | A month of the address price |
elb_idle |
ELB | Medium | A load balancer that receives fewer than 10 requests a day. | 7 days | A month of the load balancer price |
elb_no_targets |
ELB | High | A load balancer with no healthy target in any target group. | - | A month of the load balancer price |
lambda_overprovisioned_memory |
Lambda | Low | A function whose 95th percentile memory use is below 40 percent of what it is given. | 28 days | The unused memory at the function price, over the seconds the function ran in the last 30 days |
lambda_unused |
Lambda | Low | A function with no invocation in 30 days, created at least 28 days ago. | 28 days | None |
rds_idle |
RDS | High | An available database instance with no connection at all. | 7 days | A month of the instance price |
rds_multi_az_dev |
RDS | Low | A database instance with Multi-AZ on whose env tag is a non-production value. | - | A full month of the Single-AZ instance price |
rds_overprovisioned |
RDS | Medium | A database instance with 95th percentile CPU below 20 percent and fewer than 10 connections over 30 days. | 28 days | Half a month of the instance price |
rds_public_access |
RDS | High | A database instance that is publicly accessible. | - | None |
s3_no_lifecycle |
S3 | Low | A bucket with no lifecycle configuration. | - | None |
s3_public_access |
S3 | High | A bucket that does not have all four Block Public Access settings on. | - | None |
s3_versioning_cost |
S3 | Low | A bucket with versioning on and more than 100 noncurrent versions. | - | None |
snapshot_orphaned_old |
EBS | Low | A snapshot older than 90 days that no image refers to, whose source volume is gone, was never seen or is in another account. | - | The bytes the snapshot stores where AWS reports them, otherwise the volume size, times the snapshot price |
If a detector is not in this table, read its page: the description says what it flags, and Detection logic shows the exact test.
Azure and GCP detectors#
Core's catalogue also holds 11 detectors for Azure and 10 for GCP. They follow the same rules as the AWS ones: a state rule counts from when Hyvop saw the resource enter the state, a usage rule waits for its history, a price in another currency or one that has ended is not read, and a resource with no price is still found and states no saving.
Read this first. The rules run for the clouds an organisation has connected. They have been seen running on demo data; they have not yet been run against a real Azure subscription or GCP project, so what they find in a real account is not yet confirmed.
The first collection of a newly connected cloud reads 30 days of metrics. A rule that needs history reports once that history is there; until then it reports nothing for a resource, and that is not "all is well".
Two new kinds of finding#
- A resource that could be scheduled (kind
schedulable_resource). The start/stop candidate rules find a virtual machine that is running but idle in the same hours of the day on most days. The finding names the hours. - A resource that is exposed (kind
exposed_resource). A blob container or a storage bucket open to the public. It is a risk, not a cost, so it states no saving.
Thresholds#
Some Azure and GCP detectors declare thresholds. The numbers are defaults, changed the way described under Thresholds above.
| Detector | Threshold | Default | Range |
|---|---|---|---|
azure_vm_overprovisioned, gcp_vm_overprovisioned |
cpu_below: 95th percentile CPU below, in percent |
20 | 1 to 90 |
azure_vm_overprovisioned, gcp_vm_overprovisioned |
network_below_mbps: 95th percentile network, in or out, below, in Mbps |
10 | 0.1 to 10000 |
azure_vm_deallocated_long |
deallocated_days: deallocated for more than, in days |
7 | 1 to 365 |
gcp_vm_stopped_long |
stopped_days: stopped for more than, in days |
7 | 1 to 365 |
azure_disk_unattached, gcp_disk_unattached |
unattached_days: attached to nothing for more than, in days |
7 | 1 to 365 |
azure_sql_overprovisioned, gcp_sql_overprovisioned |
cpu_below: 95th percentile CPU below, in percent |
20 | 1 to 90 |
azure_cosmos_overprovisioned |
provisioned_over_times: provisioned throughput more than this many times the 95th percentile consumed |
4 | 1.5 to 100 |
azure_vm_start_stop_candidate, gcp_vm_start_stop_candidate |
cpu_below: an hour is idle when its average CPU was below this on at least 80 percent of the days measured, in percent |
5 | 1 to 50 |
azure_vm_start_stop_candidate, gcp_vm_start_stop_candidate |
idle_hours: idle hours a day, at least |
8 | 1 to 23 |
Azure#
| Detector | Service | Severity | What it flags | History it waits for | Saving it states |
|---|---|---|---|---|---|
azure_vm_overprovisioned |
Virtual Machines | Medium | A running VM whose 95th percentile CPU is below 20 percent and network below 10 Mbps over 30 days. | 28 days | Half a month of the VM size's price (a proxy; the finding says so) |
azure_vm_deallocated_long |
Virtual Machines | Medium | A VM deallocated for more than 7 days. | - | None: a deallocated VM is not billed for compute |
azure_disk_unattached |
Managed Disks | Medium | A managed disk attached to nothing for more than 7 days. | - | A month of the price of the disk's tier |
azure_sql_idle |
SQL Database | High | An online database with no connection in the last 7 days. | 7 days | None: no price in the price list can be matched to the tier of a database |
azure_sql_overprovisioned |
SQL Database | Medium | An online database whose 95th percentile CPU is below 20 percent over 30 days. | 28 days | None, for the same reason |
azure_blob_no_lifecycle |
Blob Storage | Low | A storage account with no lifecycle management policy. | - | None: what it saves depends on the data, which is not measured |
azure_blob_public_access |
Blob Storage | High | A blob container that allows anonymous access, unless its storage account forbids it. | - | None: it is an exposure, not a cost |
azure_pip_unassociated |
Public IP | Medium | A public IP address that no resource holds. | - | A month (730 hours) of the address's hourly price |
azure_cosmos_idle |
Cosmos DB | High | An account that consumed no request units in the last 7 days. | 7 days | None: no price can be matched to the throughput of an account |
azure_cosmos_overprovisioned |
Cosmos DB | Medium | An account with provisioned throughput more than 4 times the 95th percentile it consumed over 30 days. | 7 days | None, for the same reason |
azure_vm_start_stop_candidate |
Virtual Machines | Low | A running VM idle for at least 8 hours of the day, in the same hours, on most days. | The 30-day window | The on-demand price of the idle hours, for every day of the month |
GCP#
| Detector | Service | Severity | What it flags | History it waits for | Saving it states |
|---|---|---|---|---|---|
gcp_vm_overprovisioned |
Compute Engine | Medium | A running instance whose 95th percentile CPU is below 20 percent and network below 10 Mbps over 30 days. | 28 days | Half a month of the machine type's price in its region (a proxy; the finding says so) |
gcp_vm_stopped_long |
Compute Engine | Medium | An instance stopped (TERMINATED) for more than 7 days. | - | None: a stopped instance is not billed for compute |
gcp_disk_unattached |
Persistent Disk | Medium | A persistent disk attached to no instance for more than 7 days. | - | The disk's size times the price per gigabyte-month of its type in its region |
gcp_sql_idle |
Cloud SQL | High | A running instance with no connection in the last 7 days. | 7 days | None: the price list holds no price for the tier of an instance |
gcp_sql_overprovisioned |
Cloud SQL | Medium | A running instance whose 95th percentile CPU is below 20 percent over 30 days. | 28 days | None, for the same reason |
gcp_storage_no_lifecycle |
Cloud Storage | Low | A bucket with no lifecycle configuration. | - | None: what it saves depends on the data, which is not measured |
gcp_storage_public |
Cloud Storage | High | A bucket with a public IAM binding (allUsers or allAuthenticatedUsers). | - | None: it is an exposure, not a cost |
gcp_bigquery_idle_dataset |
BigQuery | Low | A dataset that no query read in the last 30 days. | 28 days | None: the size of a dataset is not measured |
gcp_bigquery_no_expiry |
BigQuery | Low | A dataset with no default table expiration. | - | None, for the same reason |
gcp_vm_start_stop_candidate |
Compute Engine | Low | A running instance idle for at least 8 hours of the day, in the same hours, on most days. | The 30-day window | The on-demand price of the idle hours, for every day of the month |
Resources that are gone, and "since when"#
A detector that says "stopped for more than 7 days" or "unattached for more than 7 days" counts from when Hyvop saw the resource enter that state, not from when it was created. A resource seen for the first time is in its state "since now", so on the first day of an install these rules find nothing, and start finding after that many days.