I've been retrieving monthly invoice cost information on our SoftLayer accounts for quite some time using the Ruby softlayer gem. However, there is a concern in the team that we may be missing certain costs, such as any overages on network utilization. I'd like to have some piece of mind that what I'm doing is correctly gathering all costs and we are not missing anything. Here is my code/query:
account = SoftLayer::Service.new("SoftLayer_Account",:username => user, :api_key => api_key, :timeout => 999999999)
softlayer_client = SoftLayer::Client.new(:username => user, :api_key => api_key, :timeout => 999999999)
billing_invoice_service = softlayer_client.service_named("Billing_Invoice")
object_filter = SoftLayer::ObjectFilter.new
object_filter.set_criteria_for_key_path('invoices.createDate', 'operation' => 'betweenDate', 'options' => [{'name' => 'startDate', 'value' => ["#{startTime}"]}, {'name' => 'endDate', 'value' => ["#{endTime}"]}])
# Set startDate and endDate around the beginning of the month in search of the "Recurring" invoice that should appear on the 1st.
invoices = account.result_limit(0,10000).object_filter(object_filter).object_mask("mask[id,typeCode,itemCount,invoiceTotalAmount,closedDate,createDate]").getInvoices
invoices.each do | invoice |
if invoice["typeCode"] == "RECURRING"
invoice_reference = billing_invoice_service.object_with_id(invoice["id"])
invoice_object = invoice_reference.object_mask("mask[itemCount]").getObject
billing_items_count = invoice_object["itemCount"]
billing_machines_map = Hash.new
all_billing_items = Array.new
# Search for billing items containing a hostName value.
# The corresponding billing item ID will become the key of a new hash.
# Child costs will be added to the existing costs.
billing_items_retrieval_operation = proc {
for i in 0..(billing_items_count/8000.0).ceil - 1
billing_items = invoice_reference.result_limit(i*8000, 8000).object_mask("mask[id,resourceTableId,billingItemId,parentId,categoryCode,hostName,domainName,hourlyRecurringFee,laborFee,oneTimeFee,recurringFee,recurringTaxAmount,setupFee,setupTaxAmount,location[name]]").getItems()
billing_items.each do | billing_item |
if billing_item["hostName"]
billing_machines_map[billing_item["id"]] = billing_item
end
end
all_billing_items.concat(billing_items)
end
}
# Look for items with parentIds or resourceTableIds.
# Both Ids represent a "parent" of the item.
# Give higher importance to parentId.
billing_items_retrieval_callback = proc {
cost_of_billing_items_without_parent = BigDecimal.new("0.00")
all_billing_items.each do | billing_item |
if billing_item["parentId"] != ""
parent_billing_machine = billing_machines_map[billing_item["parentId"]]
if parent_billing_machine parent_billing_machine["recurringFee"] = (BigDecimal.new(parent_billing_machine["recurringFee"]) + BigDecimal.new(billing_item["recurringFee"])).to_s('F')
parent_billing_machine["setupFee"] = (BigDecimal.new(parent_billing_machine["setupFee"]) + BigDecimal.new(billing_item["setupFee"])).to_s('F')
parent_billing_machine["laborFee"] = (BigDecimal.new(parent_billing_machine["laborFee"]) + BigDecimal.new(billing_item["laborFee"])).to_s('F')
parent_billing_machine["oneTimeFee"] = (BigDecimal.new(parent_billing_machine["oneTimeFee"]) + BigDecimal.new(billing_item["oneTimeFee"])).to_s('F')
end
elsif billing_item["resourceTableId"] != ""
parent_billing_machine = billing_machines_map[billing_item["resourceTableId"]]
if parent_billing_machine
parent_billing_machine["recurringFee"] = (BigDecimal.new(parent_billing_machine["recurringFee"]) + BigDecimal.new(billing_item["recurringFee"])).to_s('F')
parent_billing_machine["setupFee"] = (BigDecimal.new(parent_billing_machine["setupFee"]) + BigDecimal.new(billing_item["setupFee"])).to_s('F')
parent_billing_machine["laborFee"] = (BigDecimal.new(parent_billing_machine["laborFee"]) + BigDecimal.new(billing_item["laborFee"])).to_s('F')
parent_billing_machine["oneTimeFee"] = (BigDecimal.new(parent_billing_machine["oneTimeFee"]) + BigDecimal.new(billing_item["oneTimeFee"])).to_s('F')
end
else
cost_of_billing_items_without_parent = (BigDecimal.new(cost_of_billing_items_without_parent) + BigDecimal.new(billing_item["recurringFee"])).to_s('F')
cost_of_billing_items_without_parent = (BigDecimal.new(cost_of_billing_items_without_parent) + BigDecimal.new(billing_item["setupFee"])).to_s('F')
cost_of_billing_items_without_parent = (BigDecimal.new(cost_of_billing_items_without_parent) + BigDecimal.new(billing_item["laborFee"])).to_s('F')
cost_of_billing_items_without_parent = (BigDecimal.new(cost_of_billing_items_without_parent) + BigDecimal.new(billing_item["oneTimeFee"])).to_s('F')
end
end
pp "INVOICE: Total cost of devices for account without a parent is:"
pp cost_of_billing_items_without_parent
end
end
end
After the above I make calls to getVirtualGuests and getHardware to get some additional meta information for each machine (I tie them together based on billingItem.id. Example:
billingItemId = billing_machine["billingItemId"]
account_service = softlayer_client.service_named("Account")
filter = SoftLayer::ObjectFilter.new {|f| f.accept("virtualGuests.billingItem.id").when_it is(billingItemId)}
virtual_guests_array = account_service.object_filter(filter).object_mask("mask[id, hostname, datacenter[name], billingItem[orderItem[order[userRecord[username]]]], tagReferences[tagId, tag[name]], primaryIpAddress, primaryBackendIpAddress]").getVirtualGuests()
As you can see I don't make any calls to capture bandwith overage charges. I have printed out the various "category" values I get from the above query but I am not seeing anything specific to network utilization (it's possible there are no extra network utilization costs but I am not certain).
Thank you.
Any extra costs such as bandwidth overages will be included in the billing item from the server. So you don't need to make any other call to the api to get it.