vault_client 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.
- data/lib/billable_events_client.rb +47 -0
- data/lib/dto/usage_report.rb +32 -0
- data/lib/models/billable_unit.rb +32 -0
- data/lib/models/line_item.rb +21 -0
- data/lib/models/unit_group.rb +60 -0
- data/lib/models/usage_report.rb +21 -0
- data/lib/presenters/base_presenter.rb +22 -0
- data/lib/presenters/line_item_presenter.rb +68 -0
- data/lib/presenters/report_presenter.rb +17 -0
- data/lib/presenters/unit_group_presenter.rb +78 -0
- data/lib/presenters/unit_presenter.rb +34 -0
- data/lib/resource_ownership_client.rb +55 -0
- data/lib/services/line_item_builder.rb +17 -0
- data/lib/services/report_builder.rb +15 -0
- data/lib/usage_reports_client.rb +28 -0
- data/lib/vault_client.rb +88 -0
- data/lib/vault_helper.rb +15 -0
- data/readme.md +68 -0
- data/test/fixtures.rb +29 -0
- data/test/models/usage_report_test.rb +38 -0
- data/test/presenters/report_presenter_test.rb +16 -0
- data/test/resource_ownership_client_test.rb +42 -0
- data/test/services/line_item_builder_test.rb +26 -0
- data/test/test_helper.rb +21 -0
- metadata +94 -0
@@ -0,0 +1,47 @@
|
|
1
|
+
module BillableEventsClient
|
2
|
+
extend self
|
3
|
+
extend VaultHelper
|
4
|
+
|
5
|
+
Open = "open"
|
6
|
+
Close = "close"
|
7
|
+
|
8
|
+
def make_request(action, args)
|
9
|
+
case action
|
10
|
+
when :open
|
11
|
+
open(args)
|
12
|
+
when :close
|
13
|
+
close(args)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def open(args)
|
18
|
+
assert_args!(args, :hid, :event_id, :qty, :time, :rate_code)
|
19
|
+
res = resource(args[:hid], args[:event_id])
|
20
|
+
res.put(
|
21
|
+
:qty => args[:qty],
|
22
|
+
:time => encode_time(args[:time]),
|
23
|
+
:state => Open,
|
24
|
+
:rate_code => args[:rate_code],
|
25
|
+
:product_name => args[:product_name]
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
def close(args)
|
30
|
+
assert_args!(args, :hid, :event_id, :time, :rate_code)
|
31
|
+
res = resource(args[:hid], args[:event_id])
|
32
|
+
res.put(
|
33
|
+
:time => encode_time(args[:time]),
|
34
|
+
:state => Close,
|
35
|
+
:rate_code => args[:rate_code]
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
def resource(hid, event_id)
|
40
|
+
url = VaultClient.url.dup
|
41
|
+
url << "/resources/#{hid}/billable_events/#{event_id}"
|
42
|
+
@resource ||= begin
|
43
|
+
RestClient::Resource.new(url, :headers => {:accept => "application/json"})
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module VaultClient
|
2
|
+
module DataTransferObject
|
3
|
+
module UsageReport
|
4
|
+
extend VaultHelper
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def make_request(action, args)
|
8
|
+
case action
|
9
|
+
when :query
|
10
|
+
query(args)
|
11
|
+
else
|
12
|
+
raise "Unkown Action"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def query(args)
|
17
|
+
assert_args!(args, :account_id, :from, :to)
|
18
|
+
res = resource(args[:account_id])
|
19
|
+
JSON.parse res.get(:params => {:from => encode_time(args[:from]), :to => encode_time(args[:to])})
|
20
|
+
end
|
21
|
+
|
22
|
+
def resource(account_id)
|
23
|
+
url = VaultClient.url.dup
|
24
|
+
url << "/accounts/#{account_id}/usage_reports"
|
25
|
+
@resource ||= begin
|
26
|
+
RestClient::Resource.new(url, :headers => {:accept => "application/json"})
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module VaultClient
|
2
|
+
class BillableUnit
|
3
|
+
attr_accessor(
|
4
|
+
:hid,
|
5
|
+
:from,
|
6
|
+
:to,
|
7
|
+
:qty,
|
8
|
+
:total,
|
9
|
+
:rate,
|
10
|
+
:rate_period,
|
11
|
+
:product_group,
|
12
|
+
:product_name
|
13
|
+
)
|
14
|
+
|
15
|
+
def initialize(args_hash)
|
16
|
+
@hid = args_hash["hid"]
|
17
|
+
@from = args_hash["from"]
|
18
|
+
@to = args_hash["to"]
|
19
|
+
@qty = args_hash["qty"]
|
20
|
+
@rate = args_hash["rate"]
|
21
|
+
@rate_period = args_hash["rate_period"]
|
22
|
+
@product_name = args_hash["product_name"]
|
23
|
+
@product_group = args_hash["product_group"]
|
24
|
+
end
|
25
|
+
|
26
|
+
def id
|
27
|
+
#TODO remove stub
|
28
|
+
Time.now.to_i
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module VaultClient
|
2
|
+
class LineItem
|
3
|
+
|
4
|
+
attr_reader :unit_groups
|
5
|
+
|
6
|
+
def initialize(unit_groups)
|
7
|
+
@unit_groups = unit_groups
|
8
|
+
end
|
9
|
+
|
10
|
+
def app_name
|
11
|
+
@unit_groups.first.hid
|
12
|
+
end
|
13
|
+
|
14
|
+
def total
|
15
|
+
@unit_groups.inject(0) {|memo, unit_group| unit_group.total}
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module VaultClient
|
2
|
+
class UnitGroup
|
3
|
+
InvalidUnitGroup = Class.new(Exception)
|
4
|
+
|
5
|
+
attr_reader :units
|
6
|
+
|
7
|
+
def initialize(units)
|
8
|
+
@units = units
|
9
|
+
check_rates
|
10
|
+
end
|
11
|
+
|
12
|
+
def check_rates
|
13
|
+
if @units.map(&:rate).uniq.length > 1
|
14
|
+
raise(InvalidUnitGroup, "Rates must be homogenius.")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def name
|
19
|
+
@name ||= units.first.product_name
|
20
|
+
end
|
21
|
+
|
22
|
+
def hid
|
23
|
+
units.first.hid
|
24
|
+
end
|
25
|
+
|
26
|
+
def total
|
27
|
+
units.inject(0) {|memo, unit| unit.rate * unit.qty}
|
28
|
+
end
|
29
|
+
|
30
|
+
def dyno_type?
|
31
|
+
sample_unit.product_group == "dyno"
|
32
|
+
end
|
33
|
+
|
34
|
+
def add_on_type?
|
35
|
+
sample_unit.product_group == "addon"
|
36
|
+
end
|
37
|
+
|
38
|
+
def run_type?
|
39
|
+
return false
|
40
|
+
sample_unit.product_name == "run"
|
41
|
+
end
|
42
|
+
|
43
|
+
def description
|
44
|
+
sample_unit.product_name
|
45
|
+
end
|
46
|
+
|
47
|
+
def qty
|
48
|
+
@units.inject(0) {|memo, unit| unit.qty}
|
49
|
+
end
|
50
|
+
|
51
|
+
def rate
|
52
|
+
sample_unit.rate
|
53
|
+
end
|
54
|
+
|
55
|
+
def sample_unit
|
56
|
+
@sample_unit ||= @units.first
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module VaultClient
|
2
|
+
class UsageReport
|
3
|
+
|
4
|
+
attr_accessor(
|
5
|
+
:account_id,
|
6
|
+
:from,
|
7
|
+
:to,
|
8
|
+
:billable_units,
|
9
|
+
:total
|
10
|
+
)
|
11
|
+
|
12
|
+
def initialize(account_id, from, to, billable_units, total)
|
13
|
+
@account_id = from
|
14
|
+
@from = from
|
15
|
+
@to = to
|
16
|
+
@billable_units = billable_units
|
17
|
+
@total = total
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module VaultClient
|
2
|
+
class BasePresenter
|
3
|
+
|
4
|
+
def money(cents)
|
5
|
+
return if cents.nil?
|
6
|
+
pennies_to_dollar(cents.to_i)
|
7
|
+
end
|
8
|
+
|
9
|
+
def pennies_to_dollar(qty)
|
10
|
+
sprintf("%.2f", qty / 100.0)
|
11
|
+
end
|
12
|
+
|
13
|
+
def trunc_hours(hrs)
|
14
|
+
sprintf("%.3f", hrs)
|
15
|
+
end
|
16
|
+
|
17
|
+
def date_range(s, f)
|
18
|
+
s.strftime('%d %b %H:%M ') + " - " + f.strftime('%d %b %H:%M ')
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module VaultClient
|
2
|
+
class LineItemPresenter < BasePresenter
|
3
|
+
|
4
|
+
def initialize(line_item)
|
5
|
+
@line_item = line_item
|
6
|
+
end
|
7
|
+
|
8
|
+
def add_on_unit_group_total
|
9
|
+
result = add_on_unit_group_presenters.map do |ugp|
|
10
|
+
ugp.unit_group
|
11
|
+
end.inject(0) do |memo, ug|
|
12
|
+
ug.total
|
13
|
+
end
|
14
|
+
money(result)
|
15
|
+
end
|
16
|
+
|
17
|
+
def dyno_unit_group_total
|
18
|
+
result = dyno_unit_group_presenters.map do |ugp|
|
19
|
+
ugp.unit_group
|
20
|
+
end.inject(0) do |memo, ug|
|
21
|
+
ug.total
|
22
|
+
end
|
23
|
+
money(result)
|
24
|
+
end
|
25
|
+
|
26
|
+
def dyno_unit_group_rate
|
27
|
+
0.05
|
28
|
+
end
|
29
|
+
|
30
|
+
def dyno_unit_group_qty
|
31
|
+
dyno_unit_group_presenters.map do |upg|
|
32
|
+
upg.unit_group
|
33
|
+
end.inject(0) do |memo, ug|
|
34
|
+
ug.qty
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def dyno_unit_group_presenters
|
39
|
+
unit_group_presenters.select {|ugp| ugp.unit_group.dyno_type?}
|
40
|
+
end
|
41
|
+
|
42
|
+
def add_on_unit_group_presenters
|
43
|
+
unit_group_presenters.select {|ugp| ugp.unit_group.add_on_type?}
|
44
|
+
end
|
45
|
+
|
46
|
+
def unit_group_presenters
|
47
|
+
if defined?(@unit_group_presenters)
|
48
|
+
@unit_group_presenters
|
49
|
+
else
|
50
|
+
@unit_group_presenters = unit_groups.map {|ug| UnitGroupPresenter.new(ug)}
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def total
|
55
|
+
money(@line_item.total)
|
56
|
+
end
|
57
|
+
|
58
|
+
def name
|
59
|
+
@line_item.app_name
|
60
|
+
end
|
61
|
+
|
62
|
+
def unit_groups
|
63
|
+
@unit_groups ||= @line_item.unit_groups
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module VaultClient
|
2
|
+
class ReportPresenter < BasePresenter
|
3
|
+
|
4
|
+
def initialize(units)
|
5
|
+
@units = units
|
6
|
+
end
|
7
|
+
|
8
|
+
def line_item_presenters
|
9
|
+
@line_item_presenters ||= begin
|
10
|
+
LineItemBuilder.build(@units).map do |li|
|
11
|
+
LineItemPresenter.new(li)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module VaultClient
|
2
|
+
class UnitGroupPresenter < BasePresenter
|
3
|
+
|
4
|
+
attr_reader :unit_group
|
5
|
+
|
6
|
+
def initialize(unit_group)
|
7
|
+
@unit_group = unit_group
|
8
|
+
end
|
9
|
+
|
10
|
+
def id
|
11
|
+
[:hid, :name].map {|m| unit_group.send(m)}.join("_").gsub("-", "_")
|
12
|
+
end
|
13
|
+
|
14
|
+
def unit_presenters
|
15
|
+
if defined?(@unit_presenters)
|
16
|
+
@unit_presenters
|
17
|
+
else
|
18
|
+
@unit_presenters = @unit_group.units.map {|u| UnitPresenter.new(u)}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def template
|
23
|
+
if @unit_group.dyno_type?
|
24
|
+
"line_item_types/dyno"
|
25
|
+
elsif @unit_group.add_on_type?
|
26
|
+
"line_item_types/add_on"
|
27
|
+
elsif @unit_group.additional_type?
|
28
|
+
"line_item_types/additional"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def detail_template
|
33
|
+
if @unit_group.run_type?
|
34
|
+
"unit_group_types/flat"
|
35
|
+
elsif @unit_group.dyno_type?
|
36
|
+
"unit_group_types/metered"
|
37
|
+
else
|
38
|
+
"unit_group_types/brief"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def daily_report_url
|
43
|
+
#TODO remove stub
|
44
|
+
#payments_uri("/billable_units/daily")
|
45
|
+
"/billable_units/daily"
|
46
|
+
end
|
47
|
+
|
48
|
+
def compacted_reports
|
49
|
+
#TODO remove stub
|
50
|
+
#BillableUnitReporter.compacted(@unit_group.units)
|
51
|
+
[]
|
52
|
+
end
|
53
|
+
|
54
|
+
def name
|
55
|
+
@unit_group.name
|
56
|
+
end
|
57
|
+
|
58
|
+
def description
|
59
|
+
@unit_group.description
|
60
|
+
end
|
61
|
+
|
62
|
+
def qty
|
63
|
+
trunc_hours(@unit_group.qty)
|
64
|
+
end
|
65
|
+
|
66
|
+
def rate
|
67
|
+
end
|
68
|
+
|
69
|
+
def unit_of_measure
|
70
|
+
end
|
71
|
+
|
72
|
+
def total
|
73
|
+
money(@unit_group.total)
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module VaultClient
|
2
|
+
class UnitPresenter < BasePresenter
|
3
|
+
|
4
|
+
def initialize(unit)
|
5
|
+
@unit = unit
|
6
|
+
end
|
7
|
+
|
8
|
+
def total
|
9
|
+
money(@unit.rate * @unit.qty)
|
10
|
+
end
|
11
|
+
|
12
|
+
def rate
|
13
|
+
[money(@unit.rate), @unit.rate_period].join("/")
|
14
|
+
end
|
15
|
+
|
16
|
+
def qty
|
17
|
+
trunc_hours(@unit.qty)
|
18
|
+
end
|
19
|
+
|
20
|
+
def start
|
21
|
+
@unit.from
|
22
|
+
end
|
23
|
+
|
24
|
+
def end
|
25
|
+
@unit.to
|
26
|
+
end
|
27
|
+
|
28
|
+
def description
|
29
|
+
@unit.subresource
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module ResourceOwnershipClient
|
2
|
+
extend self
|
3
|
+
extend VaultHelper
|
4
|
+
|
5
|
+
def make_request(action, args)
|
6
|
+
case action
|
7
|
+
when :activate
|
8
|
+
activate(args)
|
9
|
+
when :transfer
|
10
|
+
transfer(args)
|
11
|
+
when :deactivate
|
12
|
+
deactivate(args)
|
13
|
+
when :query
|
14
|
+
query(args)
|
15
|
+
else
|
16
|
+
raise(ArgumentError, "Resource Ownership API does not respond to #{action}")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def activate(args)
|
21
|
+
assert_args!(args, :account_id, :event_id, :hid, :time)
|
22
|
+
res = resource(args[:account_id], args[:event_id])
|
23
|
+
res.post(:hid => args[:hid], :time => encode_time(args[:time]))
|
24
|
+
end
|
25
|
+
|
26
|
+
def transfer(args)
|
27
|
+
assert_args!(args, :account_id, :prev_account_id, :event_id, :prev_event_id, :hid, :time)
|
28
|
+
res = resource(args[:prev_account_id], args[:prev_event_id])
|
29
|
+
res.put(:account_id => args[:account_id], :event_id => args[:event_id], :hid => args[:hid], :time => encode_time(args[:time]))
|
30
|
+
end
|
31
|
+
|
32
|
+
def deactivate(args)
|
33
|
+
assert_args!(args, :account_id, :event_id, :hid, :time)
|
34
|
+
res = resource(args[:account_id])["#{args[:event_id]}?hid=#{args[:hid]}&time=#{encode_time(args[:time])}"]
|
35
|
+
res.delete
|
36
|
+
end
|
37
|
+
|
38
|
+
def query(args)
|
39
|
+
assert_args!(args, :account_id)
|
40
|
+
res = resource(args[:account_id])
|
41
|
+
res.get
|
42
|
+
end
|
43
|
+
|
44
|
+
def resource(account_id, event_id=nil)
|
45
|
+
url = VaultClient.url.dup
|
46
|
+
url << "/accounts/#{account_id}/resource_ownerships"
|
47
|
+
if event_id
|
48
|
+
url << "/#{event_id}"
|
49
|
+
end
|
50
|
+
@resource ||= begin
|
51
|
+
RestClient::Resource.new(url, :headers => {:accept => "application/json"})
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module VaultClient
|
2
|
+
module LineItemBuilder
|
3
|
+
extend self
|
4
|
+
|
5
|
+
# Give build() a collection of units and it will return a
|
6
|
+
# collection of line_items. Each line_item will have a collection
|
7
|
+
# of unit_groups wich will hold a collection of units
|
8
|
+
|
9
|
+
def build(units)
|
10
|
+
units.group_by(&:hid).map do |hid, units_by_hid|
|
11
|
+
units_by_hid.group_by(&:product_name).map do |product_name, units_by_name|
|
12
|
+
UnitGroup.new(units_by_name)
|
13
|
+
end
|
14
|
+
end.map {|unit_groups| LineItem.new(unit_groups)}.flatten
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module VaultClient
|
2
|
+
module ReportBuilder
|
3
|
+
extend self
|
4
|
+
|
5
|
+
def usage_report(account_id, from, to)
|
6
|
+
dto = DataTransferObject::UsageReport.query(:account_id => account_id, :from => from, :to => to)
|
7
|
+
billable_units = dto["billable_units"].map{|bu| BillableUnit.new(bu)}
|
8
|
+
from = Time.parse(dto["from"])
|
9
|
+
to = Time.parse(dto["to"])
|
10
|
+
total = dto["total"].to_i
|
11
|
+
UsageReport.new(account_id, from, to, billable_units, total)
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module UsageReportsClient
|
2
|
+
extend VaultHelper
|
3
|
+
extend self
|
4
|
+
|
5
|
+
def make_request(action, args)
|
6
|
+
case action
|
7
|
+
when :query
|
8
|
+
query(args)
|
9
|
+
else
|
10
|
+
raise "Unkown Action"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def query(args)
|
15
|
+
assert_args!(args, :account_id, :from, :to)
|
16
|
+
res = resource(args[:account_id])
|
17
|
+
res.get(:from => encode_time(args[:from]), :to => encode_time(args[:to]))
|
18
|
+
end
|
19
|
+
|
20
|
+
def resource(account_id)
|
21
|
+
url = VaultClient.url.dup
|
22
|
+
url << "/accounts/#{account_id}/usage_reports"
|
23
|
+
@resource ||= begin
|
24
|
+
RestClient::Resource.new(url, :headers => {:accept => "application/json"})
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
data/lib/vault_client.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'rest-client'
|
2
|
+
require 'json'
|
3
|
+
require 'vault_helper'
|
4
|
+
require 'resource_ownership_client'
|
5
|
+
require 'billable_events_client'
|
6
|
+
require 'usage_reports_client'
|
7
|
+
|
8
|
+
module VaultClient
|
9
|
+
|
10
|
+
AuthenticationError = Class.new(Exception)
|
11
|
+
AuthorizationError = Class.new(Exception)
|
12
|
+
ServiceDownError = Class.new(Exception)
|
13
|
+
UnexpectedError = Class.new(Exception)
|
14
|
+
SymanticError = Class.new(Exception)
|
15
|
+
|
16
|
+
attr_accessor :url
|
17
|
+
|
18
|
+
extend self
|
19
|
+
|
20
|
+
def resource_ownerships(action, args={})
|
21
|
+
if ENV["VAULT_CLIENT_UNSAFE"] == "true"
|
22
|
+
make_unsafe_request! {ResourceOwnershipClient.make_request(action, args)}
|
23
|
+
else
|
24
|
+
make_http_request {ResourceOwnershipClient.make_request(action, args)}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def billable_events(action, args={})
|
29
|
+
if ENV["VAULT_CLIENT_UNSAFE"] == "true"
|
30
|
+
make_unsafe_request! {BillableEventsClient.make_request(action, args)}
|
31
|
+
else
|
32
|
+
make_http_request {BillableEventsClient.make_request(action, args)}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def make_unsafe_request!
|
37
|
+
begin
|
38
|
+
resp = yield
|
39
|
+
JSON.parse(resp.body)
|
40
|
+
rescue RestClient => e
|
41
|
+
return e.inspect
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def make_http_request(&block)
|
46
|
+
block.call() do |resp, req, res|
|
47
|
+
response_body = JSON.parse(resp.body)
|
48
|
+
case resp.code
|
49
|
+
when 200, 201
|
50
|
+
response_body
|
51
|
+
when 400, 401,
|
52
|
+
raise(AuthenticationError, response_body)
|
53
|
+
when 403
|
54
|
+
raise(AuthorizationError, response_body)
|
55
|
+
when 404
|
56
|
+
raise(NotFound, response_body)
|
57
|
+
when 422
|
58
|
+
raise(SymanticError, response_body)
|
59
|
+
when 500
|
60
|
+
raise(UnexpectedError)
|
61
|
+
when 503
|
62
|
+
raise(ServiceDownError)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def url
|
68
|
+
@url || ENV["VAULT_URL"]
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
$:.unshift("lib")
|
74
|
+
|
75
|
+
require 'models/usage_report'
|
76
|
+
require 'models/billable_unit'
|
77
|
+
require 'models/unit_group'
|
78
|
+
require 'models/line_item'
|
79
|
+
|
80
|
+
require 'services/line_item_builder'
|
81
|
+
require 'services/report_builder'
|
82
|
+
|
83
|
+
require 'dto/usage_report'
|
84
|
+
|
85
|
+
require 'presenters/base_presenter'
|
86
|
+
require 'presenters/report_presenter'
|
87
|
+
require 'presenters/line_item_presenter'
|
88
|
+
require 'presenters/unit_group_presenter'
|
data/lib/vault_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
|
3
|
+
module VaultHelper
|
4
|
+
|
5
|
+
def encode_time(time)
|
6
|
+
CGI.escape(time.to_s)
|
7
|
+
end
|
8
|
+
|
9
|
+
def assert_args!(args, *list_of_things_that_should_be)
|
10
|
+
unless list_of_things_that_should_be.all? {|key| args.include?(key)}
|
11
|
+
raise(ArgumentError, "Arguments should include: [#{list_of_things_that_should_be}]. You passed: [#{args}]")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
data/readme.md
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# The Vault Client
|
2
|
+
|
3
|
+
## Purpose
|
4
|
+
|
5
|
+
This gem wraps the APIs defined [here](https://github.com/heroku/shushu/tree/master/doc).
|
6
|
+
|
7
|
+
## Usage
|
8
|
+
|
9
|
+
### Setup
|
10
|
+
|
11
|
+
```bash
|
12
|
+
$ gem install vault_client
|
13
|
+
```
|
14
|
+
|
15
|
+
### Configure
|
16
|
+
|
17
|
+
```bash
|
18
|
+
# Optional. When set, vault_client will ignore bad responses from The Vault's API.
|
19
|
+
# Default: false
|
20
|
+
$VAULT_CLIENT_UNSAFE=true
|
21
|
+
|
22
|
+
# Required
|
23
|
+
# Default: nil
|
24
|
+
$VAULT_URL=https://vault-stg.heroku.com
|
25
|
+
```
|
26
|
+
|
27
|
+
**Ruby configuration will take precedence over environment variables.**
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
VaultClient.url = "https://core:secret@vault-stg.heroku.com"
|
31
|
+
```
|
32
|
+
|
33
|
+
### Resource Ownership
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
# When a new app is created, activate a new resource_ownership record.
|
37
|
+
VaultClient.resource_ownerships(:activate, hid, vault_account_id, time, event_id)
|
38
|
+
#=> {"hid"=>"123", "account_id"=>"1", "event_id"=>"event123"}
|
39
|
+
|
40
|
+
|
41
|
+
# When an app is transfered to another vault account, transfer the resource_ownership record.
|
42
|
+
VaultClient.resource_ownerships(:transfer, hid, prev_vault_account_id, new_vault_account_id, time, prev_event_id, event_id)
|
43
|
+
#=> {"hid"=>"123", "account_id"=>"1", "event_id"=>"event123"}
|
44
|
+
|
45
|
+
# When an app is destroyed, deactivate the resource_ownership record.
|
46
|
+
VaultClient.resource_ownerships(:deactivate, hid, new_vault_account_id, time, event_id)
|
47
|
+
#=> {"hid"=>"123", "account_id"=>"1", "event_id"=>"event123"}
|
48
|
+
```
|
49
|
+
|
50
|
+
## Hacking
|
51
|
+
|
52
|
+
### Supporting a vault endpoint
|
53
|
+
|
54
|
+
Define a method in the VaultClient module that looks like the name of the http
|
55
|
+
resource. Have this method dispatch the call to another modle that implements
|
56
|
+
the detail of the api. The aforementioned API client module should only return
|
57
|
+
the data that is needed by rest-client to submit the request.
|
58
|
+
|
59
|
+
### Running the tests
|
60
|
+
|
61
|
+
We only test that our API client modules return the http parameters and the body
|
62
|
+
for the http request. We trust that when rest-client is used correctly it will
|
63
|
+
work.
|
64
|
+
|
65
|
+
```bash
|
66
|
+
$ bundle
|
67
|
+
$ bundle turn test/
|
68
|
+
```
|
data/test/fixtures.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
module Fixtures
|
2
|
+
extend self
|
3
|
+
|
4
|
+
def billable_units
|
5
|
+
[
|
6
|
+
{
|
7
|
+
:hid => 123,
|
8
|
+
:from => Time.mktime(2000,1),
|
9
|
+
:to => Time.mktime(2000,2),
|
10
|
+
:qty => 744,
|
11
|
+
:rate => 5,
|
12
|
+
:rate_period => "hour",
|
13
|
+
:product_group => "dyno",
|
14
|
+
:product_name => "web"
|
15
|
+
},
|
16
|
+
{
|
17
|
+
:hid => 123,
|
18
|
+
:from => Time.mktime(2000,1),
|
19
|
+
:to => Time.mktime(2000,2),
|
20
|
+
:qty => 744,
|
21
|
+
:rate => 5,
|
22
|
+
:rate_period => "hour",
|
23
|
+
:product_group => "dyno",
|
24
|
+
:product_name => "worker"
|
25
|
+
}
|
26
|
+
]
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require File.expand_path('../../test_helper', __FILE__)
|
2
|
+
|
3
|
+
class UsageReportTest < MiniTest::Unit::TestCase
|
4
|
+
|
5
|
+
def test_init_report
|
6
|
+
usage_report = VaultClient::UsageReport.new(account_id, from, to, Fixtures.billable_units)
|
7
|
+
assert(!usage_report.nil?, "Expected a usage report. Got nil")
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_report_returns_from
|
11
|
+
usage_report = VaultClient::UsageReport.new(account_id, from, to, Fixtures.billable_units)
|
12
|
+
assert(!usage_report.from.nil?, "Expected #from to return a Time. Got nil")
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_report_returns_to
|
16
|
+
usage_report = VaultClient::UsageReport.new(account_id, from, to, Fixtures.billable_units)
|
17
|
+
assert(!usage_report.to.nil?, "Expected #to to return a Time. Got nil")
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_report_returns_billable_units
|
21
|
+
usage_report = VaultClient::UsageReport.new(account_id, from, to, Fixtures.billable_units)
|
22
|
+
assert(!usage_report.billable_units.nil?, "Expected #billable_units to return a collection of billable_units. Got nil")
|
23
|
+
assert_equal(VaultClient::BillableUnit, usage_report.billable_units.first.class)
|
24
|
+
end
|
25
|
+
|
26
|
+
def account_id
|
27
|
+
1
|
28
|
+
end
|
29
|
+
|
30
|
+
def from
|
31
|
+
Time.mktime(2000,1)
|
32
|
+
end
|
33
|
+
|
34
|
+
def to
|
35
|
+
Time.mktime(2000,2)
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require File.expand_path('../../test_helper', __FILE__)
|
2
|
+
|
3
|
+
class ReportPresenterTest < VaultClientTest
|
4
|
+
|
5
|
+
def test_init
|
6
|
+
presenter = VaultClient::ReportPresenter.new(units)
|
7
|
+
assert(!presenter.nil?)
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_returns_line_item_presenters
|
11
|
+
presenter = VaultClient::ReportPresenter.new(units)
|
12
|
+
lip = presenter.line_item_presenters
|
13
|
+
assert_equal(VaultClient::LineItemPresenter, lip.first.class)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require File.expand_path('../test_helper', __FILE__)
|
2
|
+
|
3
|
+
class ResourceOwnershipClientTest < MiniTest::Unit::TestCase
|
4
|
+
|
5
|
+
def test_activate
|
6
|
+
verb, uri, body = ResourceOwnershipClient.build_request(:activate, [123, 456])
|
7
|
+
assert_equal(:post, verb)
|
8
|
+
assert_equal("/resource_ownerships", uri)
|
9
|
+
assert_equal({:hid => 123, :account_id => 456}, body)
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_deactivate
|
13
|
+
verb, uri, body = ResourceOwnershipClient.build_request(:deactivate, [123, 456])
|
14
|
+
assert_equal(:put, verb)
|
15
|
+
assert_equal("/resource_ownerships", uri)
|
16
|
+
assert_equal({:hid => 123, :prev_account_id => 456}, body)
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_transfer
|
20
|
+
verb, uri, body = ResourceOwnershipClient.build_request(:transfer, [123, 456, 789])
|
21
|
+
assert_equal(:put, verb)
|
22
|
+
assert_equal("/resource_ownerships", uri)
|
23
|
+
assert_equal({:hid => 123,:prev_account_id => 456, :account_id => 789}, body)
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_query_with_account_id
|
27
|
+
verb, uri = ResourceOwnershipClient.build_request(:query, :account_id => 1)
|
28
|
+
assert_equal(:get, verb)
|
29
|
+
assert_equal("/resource_ownerships?account_id=1", uri)
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_query_with_hid
|
33
|
+
verb, uri = ResourceOwnershipClient.build_request(:query, :hid => 1)
|
34
|
+
assert_equal(:get, verb)
|
35
|
+
assert_equal("/resource_ownerships?hid=1", uri)
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_query_with_account_id_and_hid
|
39
|
+
assert_raises(ArgumentError) {ResourceOwnershipClient.build_request(:query, :hid => 1, :account_id => 2)}
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.expand_path('../../test_helper', __FILE__)
|
2
|
+
|
3
|
+
class LineItemBuilderTest < VaultClientTest
|
4
|
+
|
5
|
+
def test_build
|
6
|
+
line_items = VaultClient::LineItemBuilder.build(units)
|
7
|
+
assert(!line_items.nil?)
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_build_creates_line_item_by_hid
|
11
|
+
line_items = VaultClient::LineItemBuilder.build(units)
|
12
|
+
assert_equal(1, line_items.length)
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_build_creates_one_unit_group_for_line_item
|
16
|
+
line_item = VaultClient::LineItemBuilder.build(units).pop
|
17
|
+
assert_equal(1, line_item.unit_groups.length)
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_build_puts_both_units_on_unit_group
|
21
|
+
line_item = VaultClient::LineItemBuilder.build(units).pop
|
22
|
+
unit_group = line_item.unit_groups.pop
|
23
|
+
assert_equal(2, unit_group.units.length)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
$:.unshift("lib")
|
2
|
+
$:.unshift("test")
|
3
|
+
|
4
|
+
ENV["RACK_ENV"] = "test"
|
5
|
+
|
6
|
+
require "rubygems"
|
7
|
+
require "bundler"
|
8
|
+
Bundler.require(:default, :test)
|
9
|
+
|
10
|
+
require "minitest/autorun"
|
11
|
+
require "webmock/minitest"
|
12
|
+
require "vault_client"
|
13
|
+
require "fixtures"
|
14
|
+
|
15
|
+
class VaultClientTest < MiniTest::Unit::TestCase
|
16
|
+
|
17
|
+
def units
|
18
|
+
Fixtures.billable_units.map{|h| VaultClient::BillableUnit.new(h)}
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: vault_client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ryan Smith
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-12-16 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rest-client
|
16
|
+
requirement: &8576100 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.6.7
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *8576100
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: json
|
27
|
+
requirement: &8572460 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.6.1
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *8572460
|
36
|
+
description: A ruby wrapper around The Vault's HTTP API.
|
37
|
+
email: ryan@heroku.com
|
38
|
+
executables: []
|
39
|
+
extensions: []
|
40
|
+
extra_rdoc_files: []
|
41
|
+
files:
|
42
|
+
- readme.md
|
43
|
+
- lib/dto/usage_report.rb
|
44
|
+
- lib/presenters/base_presenter.rb
|
45
|
+
- lib/presenters/unit_presenter.rb
|
46
|
+
- lib/presenters/unit_group_presenter.rb
|
47
|
+
- lib/presenters/report_presenter.rb
|
48
|
+
- lib/presenters/line_item_presenter.rb
|
49
|
+
- lib/usage_reports_client.rb
|
50
|
+
- lib/vault_client.rb
|
51
|
+
- lib/models/unit_group.rb
|
52
|
+
- lib/models/line_item.rb
|
53
|
+
- lib/models/usage_report.rb
|
54
|
+
- lib/models/billable_unit.rb
|
55
|
+
- lib/billable_events_client.rb
|
56
|
+
- lib/vault_helper.rb
|
57
|
+
- lib/services/line_item_builder.rb
|
58
|
+
- lib/services/report_builder.rb
|
59
|
+
- lib/resource_ownership_client.rb
|
60
|
+
- test/presenters/report_presenter_test.rb
|
61
|
+
- test/fixtures.rb
|
62
|
+
- test/models/usage_report_test.rb
|
63
|
+
- test/resource_ownership_client_test.rb
|
64
|
+
- test/services/line_item_builder_test.rb
|
65
|
+
- test/test_helper.rb
|
66
|
+
homepage: http://github.com/heroku/vault_client
|
67
|
+
licenses: []
|
68
|
+
post_install_message:
|
69
|
+
rdoc_options: []
|
70
|
+
require_paths:
|
71
|
+
- lib
|
72
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
none: false
|
80
|
+
requirements:
|
81
|
+
- - ! '>='
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
requirements: []
|
85
|
+
rubyforge_project:
|
86
|
+
rubygems_version: 1.8.10
|
87
|
+
signing_key:
|
88
|
+
specification_version: 3
|
89
|
+
summary: The Vault
|
90
|
+
test_files:
|
91
|
+
- test/presenters/report_presenter_test.rb
|
92
|
+
- test/models/usage_report_test.rb
|
93
|
+
- test/resource_ownership_client_test.rb
|
94
|
+
- test/services/line_item_builder_test.rb
|