Fetching Google Consolidated Bills
Google announced support for the GCP equivalent of the AWS consolidated bill this Friday. This feature substantially simplifies the complexity of managing billing across multiple projects, allowing you to consolidate the billing and usage statements from all projects into a single bucket.
Attached is a simple Ruby script to allow you to fetch your consolidated bills from a bucket:
#!/usr/bin/env ruby
require 'rubygems'
require 'google/api_client'
require 'json'
if ARGV.size < 7
puts "gcp_get_bill.rb [project name] [certificate file] [certificate passphrase] [service account] [bucket] [object prefix] [date to fetch]"
puts "e.g. gcp_get_bill.rb lovey-cache-373 ./my-project.p12 notasecret 972767832863-li4ihy7251800fr6v585umelvh6dcht9@developer.gserviceaccount.com my-bucket billing 2014-10-13"
exit
end
project_name = ARGV[0]
certificate_file = ARGV[1]
certificate_passphrase = ARGV[2]
service_account = ARGV[3]
bucket = ARGV[4]
object_prefix = ARGV[5]
fetch_date = Date.parse(ARGV[6])
client = Google::APIClient.new(
:application_name => 'Google Bill Fetcher',
:application_version => '1.0.0'
)
storage = client.discovered_api('storage')
key = Google::APIClient::KeyUtils.load_from_pkcs12(certificate_file, certificate_passphrase)
client.authorization = Signet::OAuth2::Client.new(
:token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
:audience => 'https://accounts.google.com/o/oauth2/token',
:scope => 'https://www.googleapis.com/auth/devstorage.read_only',
:issuer => service_account,
:signing_key => key)
client.authorization.fetch_access_token!
page_token = nil
begin
response = client.execute(:api_method => storage.objects.list, :parameters => {:project=>project_name, :zone=>'us-central1-a', :bucket=>bucket, :prefix=>object_prefix, :maxResults=>1000, :pageToken=>page_token})
body = JSON.parse(response.body)
page_token = body["nextPageToken"]
response.data.items.each do |obj|
next unless obj.name.end_with?(".csv")
# Must parse object name to get date since object updated date can be misleading
updated_at = Date.parse(obj.name.slice(obj.name.size-14, 14))
next if updated_at < fetch_date
puts "Writing #{obj.name} to disk"
open obj.name, 'w' do |io|
obj_response = client.execute(:api_method => storage.objects.get, :parameters => {:project=>project_name, :zone=>'us-central1-a', :bucket=>bucket, :object=>obj.name, :alt=>'media'})
io.write obj_response.body
end
end
end while !page_token.nil?
puts "...complete"