Skip to content
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
163 lines (144 sloc) 5.21 KB
name "Azure Reserved Instances Utilization"
rs_pt_ver 20180301
type "policy"
short_description "A policy that sends email notifications when utilization falls below a threshold. See the [README]( and []( to learn more."
long_description "Version: 1.0"
severity "medium"
category "Cost"
# Need to read the Azure EA key from credentials
permission "perm_read_creds" do
actions "rs_cm.show_sensitive","rs_cm.index_sensitive"
resources "rs_cm.credentials"
# Could maybe get this from the EA key, but for now just ask for it
parameter "param_enrollment" do
type "string"
label "Azure Enrollment ID"
parameter "param_utilization" do
category "RI"
label "Show RI's with utilization below this value"
type "number"
parameter "param_email" do
type "list"
label "Email addresses of the recipients you wish to notify"
auth "azure_ea_auth", type: "api_key" do
location "header"
field "Authorization"
type "Bearer"
key cred("AZURE_EA_KEY")
pagination "azure_pagination" do
get_page_marker do
body_path "nextLink"
set_page_marker do
uri true
# Build the API request object dynamically because we need to
# calculate the startdate and enddate based on today
# This is our API:
script "azure_ri_request", type: "javascript" do
parameters "enrollment"
result "request"
code <<-EOS
// Azure API allows you to specify which dates to retrieve utilization for. In order to keep with
// parity on how Optima does this for AWS RIs, and after consultation with COS team, the decision
// was made to use the last week's worth of data. We start from today-2 for a couple of reasons:
// 1 - that's what it is in Optima for AWS
// 2 - it's not clear how up-to-date the Azure data is, so specifying "today" might not work great
var date = new Date();
date.setDate(date.getDate() - 2);
var enddate = date.toISOString().slice(0,10);
date.setDate(date.getDate() - 7);
var startdate = date.toISOString().slice(0,10);
var request = {
auth: "azure_ea_auth",
pagination: "azure_pagination",
host: "",
path: "/v2/enrollments/" + enrollment + "/reservationsummaries",
query_params: {
"grain": "daily",
"startdate": startdate,
"enddate": enddate
headers: {
"User-Agent": "RS Policies"
# Use the request object above to make the API call and get the data
datasource "scripted" do
request do
run_script $azure_ri_request, $param_enrollment
result do
encoding "json"
collect jmes_path(response, "[*]") do
field "reservationId", jmes_path(col_item,"reservationId")
field "skuName", jmes_path(col_item,"skuName")
field "minUtilizationPercentage", jmes_path(col_item,"minUtilizationPercentage")
field "avgUtilizationPercentage", jmes_path(col_item,"avgUtilizationPercentage")
field "maxUtilizationPercentage", jmes_path(col_item,"maxUtilizationPercentage")
field "reservedHours", jmes_path(col_item,"reservedHours")
field "usedHours", jmes_path(col_item,"usedHours")
# The Azure API returns a record per RI per day. This datasource uses the script
# to group the data to be per-RI only, and average/sum the numbers across the
# individual records
datasource "grouped_utilizations" do
run_script $group_results,$scripted
# See note above - this groups the data from the Azure API into a per-RI
# record instead of per-RI per-day
script "group_results", type: "javascript" do
parameters "result"
result "groupings"
code <<-EOS
var groupings =, 'reservationId'), function(v, k){
// Average the "average" utilization
avgUtil = _.reduce(v, function(memo, num) {
return memo + num.avgUtilizationPercentage;
}, 0) / (v.length === 0 ? 1 : v.length);
// Sum the reserved hours
sumReserved = _.reduce(v, function(memo, num) {
return memo + num.reservedHours;
}, 0);
// Sum the used hours
sumUsed = _.reduce(v, function(memo, num) {
return memo + num.usedHours;
}, 0);
return {
id: k,
sku: v[0].skuName,
util: avgUtil,
reserved: sumReserved,
used: sumUsed
policy "azure_superseded_instances_policy" do
validate_each $grouped_utilizations do
summary_template "(Enrollment ID: {{parameters.param_enrollment}}): {{ len data }} Underutilized Azure Reserved Instances"
detail_template <<-EOS
# Azure RIs that are under-utilized
| RI ID | SKU Name | Reserved Hours | Used Hours | Avg Util Pct |
| ------------- | ------------- | ------ | --- | --- |
{{ range data -}}
| {{.id}} | {{.sku}} | {{.reserved}} | {{.used}} | {{.util}} |
{{ end -}}
escalate $email
check gt(to_n(val(item,"util")),$param_utilization)
escalation "email" do
email $param_email
You can’t perform that action at this time.