bearclaws 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/bin/bearclaws +47 -0
- data/lib/bearclaws.rb +35 -0
- data/lib/bearclaws/charge.rb +17 -0
- data/lib/bearclaws/group.rb +37 -0
- data/lib/bearclaws/mapping.rb +36 -0
- data/lib/bearclaws/version.rb +3 -0
- metadata +152 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: fc85649f90c991b4233aa6c09992693339c55fc9
|
4
|
+
data.tar.gz: 1977a2eb8e0985d759b6683f3266424b8b71c5a6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5bcc74bdeaaeaa87f36ee0428697ddd2e42778dabfd40fb54ab476e5e4b6792cba195adc0c5dace1210b4ac10969679943c175540b9047af781b42f23e434a09
|
7
|
+
data.tar.gz: 10b350d20dcfba74a6cfb831fd97fc2284679d5629ae533eef69203fbb6d8579d51bf2dbd7b54e18fc9636d66445c4c771651ffafb31d6d0dde643ce12d212b0
|
data/bin/bearclaws
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bearclaws'
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
options = {}
|
7
|
+
|
8
|
+
opt_parser = OptionParser.new do |opt|
|
9
|
+
opt.banner = "Bearclaws"
|
10
|
+
opt.separator "Analyze the output of you AWS cost allocation report. Group your costs by an arbitrary tag"
|
11
|
+
opt.separator ""
|
12
|
+
opt.separator "bearclaws [CSV_FILE] [TAG_COLUMN] [OPTIONS]"
|
13
|
+
opt.separator ""
|
14
|
+
opt.separator "[CSV_FILE] --- Path to an AWS cost allocation report (e.g. 93795-aws-cost-allocation-2013-09.csv)"
|
15
|
+
opt.separator "[TAG_COLUMN] --- The (zero-indexed) column in the report that holds your tag"
|
16
|
+
opt.separator ""
|
17
|
+
opt.separator "Options"
|
18
|
+
|
19
|
+
opt.on("-o","--output OUTPUT","where do you want the results to be written?") do |o|
|
20
|
+
options[:output] = o
|
21
|
+
end
|
22
|
+
|
23
|
+
opt.on("-h","--help","help")
|
24
|
+
end
|
25
|
+
|
26
|
+
opt_parser.parse!
|
27
|
+
|
28
|
+
case ARGV[0]
|
29
|
+
|
30
|
+
when "help", nil
|
31
|
+
puts opt_parser
|
32
|
+
else
|
33
|
+
output = "bearclaws.csv"
|
34
|
+
output = options[:output] unless options[:output].nil?
|
35
|
+
groups = Bearclaws.analyze File.open(ARGV[0]), ARGV[1].to_i
|
36
|
+
|
37
|
+
CSV.open(output.to_s, "wb") do |csv|
|
38
|
+
groups.each do |group|
|
39
|
+
csv << [group.name, nil]
|
40
|
+
group.subtotals.each do |key, subtotal|
|
41
|
+
csv << [key, ('%.2f' % subtotal)]
|
42
|
+
end
|
43
|
+
csv << ['Total', ('%.2f' % group.total)]
|
44
|
+
csv << [nil, nil]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/bearclaws.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'csv'
|
2
|
+
require 'bearclaws/group'
|
3
|
+
require 'bearclaws/charge'
|
4
|
+
|
5
|
+
module Bearclaws
|
6
|
+
|
7
|
+
# Analyze the output of you AWS cost allocation report. Group your costs by an arbitrary tag, like 'client'
|
8
|
+
#
|
9
|
+
# http://aws.amazon.com/about-aws/whats-new/2012/08/21/aws-billing-enables-cost-allocation-reports/
|
10
|
+
#
|
11
|
+
# @param file [File] a CSV of allocated AWS charges (i.e., 937951391671-aws-cost-allocation-2013-09.csv)
|
12
|
+
# @param tag_column [Integer] The zero-indexed column number in the CSV that holds the tag you want to group by
|
13
|
+
# @return [Array] A set of Bearclaws::Group objects grouped by tag
|
14
|
+
def self.analyze(file = nil, tag_column = nil)
|
15
|
+
|
16
|
+
raise "No file supplied!" unless file
|
17
|
+
raise "No CSV group column supplied!" unless tag_column
|
18
|
+
raise "Group column must be an integer!" unless tag_column.is_a? Integer
|
19
|
+
|
20
|
+
groups = { default: Bearclaws::Group.new(:default) }
|
21
|
+
|
22
|
+
rows = CSV.parse file.read
|
23
|
+
|
24
|
+
rows.shift(2) # remove instructions, column labels
|
25
|
+
rows.pop(3) # remove subtotal, total, footer
|
26
|
+
|
27
|
+
rows.each do |row|
|
28
|
+
name = (row[tag_column].nil?) ? :default : row[tag_column]
|
29
|
+
groups[name] ||= Bearclaws::Group.new(name.to_sym)
|
30
|
+
groups[name].charges << Bearclaws::Charge.new(row)
|
31
|
+
end
|
32
|
+
|
33
|
+
return groups.collect { |k, v| v }
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'bearclaws/mapping'
|
2
|
+
|
3
|
+
module Bearclaws
|
4
|
+
|
5
|
+
# A representation of a charge
|
6
|
+
class Charge
|
7
|
+
|
8
|
+
Bearclaws::AWSMAP.each { |k, v| attr_accessor k }
|
9
|
+
|
10
|
+
# @param charge [Array] a CSV row from an AWS cost allocation report
|
11
|
+
def initialize(charge = [])
|
12
|
+
Bearclaws::AWSMAP.each { |k, v|
|
13
|
+
send "#{k}=", charge[v]
|
14
|
+
}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Bearclaws
|
2
|
+
|
3
|
+
# A grouped representation of AWS charges
|
4
|
+
#
|
5
|
+
# @attr name [String] The tag by which the charges are grouped
|
6
|
+
# @attr charges [Array] An array of Bearclaws::Charge objects
|
7
|
+
class Group
|
8
|
+
attr_accessor :name
|
9
|
+
attr_accessor :charges
|
10
|
+
|
11
|
+
# @param name [String] The tag by which the charges are grouped
|
12
|
+
# @param charges [Array] An array of Bearclaws::Charge objects
|
13
|
+
def initialize(name, charges = [])
|
14
|
+
self.name = name.to_sym
|
15
|
+
self.charges = charges
|
16
|
+
end
|
17
|
+
|
18
|
+
# The total cost of all the charges with group's tag
|
19
|
+
#
|
20
|
+
# @return [Float]
|
21
|
+
def total
|
22
|
+
charges.map { |x| x.total_cost.to_f }.inject(:+)
|
23
|
+
end
|
24
|
+
|
25
|
+
# The total costs for the tag broken out by :product_code
|
26
|
+
#
|
27
|
+
# @return [Float]
|
28
|
+
def subtotals
|
29
|
+
x = {}
|
30
|
+
charges.each do |r|
|
31
|
+
x[r.product_code] ||= 0.to_f
|
32
|
+
x[r.product_code] += r.total_cost.to_f
|
33
|
+
end
|
34
|
+
return x
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Bearclaws
|
2
|
+
|
3
|
+
# The mappings for a nomal AWS cost allocation report
|
4
|
+
AWSMAP = {
|
5
|
+
:invoice_id => 0,
|
6
|
+
:payer_account_id => 1,
|
7
|
+
:linked_account_id => 2,
|
8
|
+
:charge_type => 3,
|
9
|
+
:charge_id => 4,
|
10
|
+
:billing_period_start_date => 5,
|
11
|
+
:billing_period_end_date => 6,
|
12
|
+
:invoice_date => 7,
|
13
|
+
:payer_account_name => 8,
|
14
|
+
:linked_account_name => 9,
|
15
|
+
:taxation_address => 10,
|
16
|
+
:payer_po_number => 11,
|
17
|
+
:product_code => 12,
|
18
|
+
:product_name => 13,
|
19
|
+
:seller_of_charge => 14,
|
20
|
+
:usage_type => 15,
|
21
|
+
:operation => 16,
|
22
|
+
:availability_zone => 17,
|
23
|
+
:rate_id => 18,
|
24
|
+
:item_description => 19,
|
25
|
+
:usage_start_date => 20,
|
26
|
+
:usage_end_date => 21,
|
27
|
+
:usage_quantity => 22,
|
28
|
+
:blended_rate => 23,
|
29
|
+
:currency_code => 24,
|
30
|
+
:cost_before_tax => 25,
|
31
|
+
:credits => 26,
|
32
|
+
:tax_amount => 27,
|
33
|
+
:tax_type => 28,
|
34
|
+
:total_cost => 29
|
35
|
+
}
|
36
|
+
end
|
metadata
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bearclaws
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kyle Truscott
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-12-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: guard-rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rb-fsevent
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rb-inotify
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: yard
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: redcarpet
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rake
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description: Analyze the output of you AWS cost allocation report. Group your costs
|
112
|
+
by an arbitrary tag, like `client`
|
113
|
+
email:
|
114
|
+
- keighl@keighl.com
|
115
|
+
executables:
|
116
|
+
- bearclaws
|
117
|
+
extensions: []
|
118
|
+
extra_rdoc_files: []
|
119
|
+
files:
|
120
|
+
- lib/bearclaws.rb
|
121
|
+
- lib/bearclaws/version.rb
|
122
|
+
- lib/bearclaws/charge.rb
|
123
|
+
- lib/bearclaws/group.rb
|
124
|
+
- lib/bearclaws/mapping.rb
|
125
|
+
- bin/bearclaws
|
126
|
+
homepage: https://github.com/keighl/bearclaws
|
127
|
+
licenses:
|
128
|
+
- MIT
|
129
|
+
metadata: {}
|
130
|
+
post_install_message:
|
131
|
+
rdoc_options: []
|
132
|
+
require_paths:
|
133
|
+
- lib
|
134
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - '>='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
140
|
+
requirements:
|
141
|
+
- - '>='
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '0'
|
144
|
+
requirements: []
|
145
|
+
rubyforge_project:
|
146
|
+
rubygems_version: 2.0.2
|
147
|
+
signing_key:
|
148
|
+
specification_version: 4
|
149
|
+
summary: Analyze the output of you AWS cost allocation report. Group your costs by
|
150
|
+
an arbitrary tag, like `client`
|
151
|
+
test_files: []
|
152
|
+
has_rdoc:
|