lita-spendo 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +16 -4
- data/lib/lita/handlers/spendo.rb +72 -41
- data/lita-spendo.gemspec +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bc4b4aeb89372358c7c9cf749bb1100460133b65
|
4
|
+
data.tar.gz: f35e2fc01077fc05be824d154207c8bbe7bb710e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a8f027a73e88ef7a89ae731e79e21c216e384c1c8d4ad51c93b6b63fdc74660afbe8a5f548e203531702392cf3d4d1642acb90f240bb75bb500194392bac5072
|
7
|
+
data.tar.gz: 7079d9d39d5486cf7715a4bf32e0846239259319aa6f8f03745bc56fa7bbf7025af0741e99e34d861e75ed9751074d15b1a10db349a55e27079cbc668c86c5b9
|
data/README.md
CHANGED
@@ -12,17 +12,29 @@ gem "lita-spendo"
|
|
12
12
|
|
13
13
|
## Configuration
|
14
14
|
|
15
|
-
Spendo relies on the aws-sdk gem
|
15
|
+
Spendo relies on the aws-sdk gem so it requires an AWS account. The account requires read access to the DynamoDB table holding your billing history.
|
16
16
|
|
17
17
|
### Required attributes
|
18
18
|
|
19
|
-
* `aws_account_id` (String) - Account number for your AWS account
|
20
19
|
* `base_image_url` (String) - Base url for alert images. Images should be named 'n.jpg' where n is the alert level. We suggest increasingly-scary clown photos.
|
20
|
+
* `accounts` (Array) - Array of hashes containing account information. Each hash should look like this:
|
21
|
+
|
22
|
+
``` ruby
|
23
|
+
{
|
24
|
+
nickname: 'foo',
|
25
|
+
aws_account_id: ENV['AWS_ACCOUNT_ID'],
|
26
|
+
aws_access_key_id: ENV['AWS_ACCESS_KEY_ID'],
|
27
|
+
aws_secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'],
|
28
|
+
aws_region: 'us-east-1',
|
29
|
+
room: 'shell', # or room JID or whatever
|
30
|
+
dynamodb_table: 'BillingHistory'
|
31
|
+
}
|
32
|
+
```
|
21
33
|
|
22
34
|
### Optional attributes
|
23
35
|
|
24
|
-
* `
|
36
|
+
* `time_between_polls` (Integer) - Spendo will wait this many seconds between polls to the BillingHistory table. Defaults to one hour (3600 seconds).
|
25
37
|
|
26
38
|
## Usage
|
27
39
|
|
28
|
-
|
40
|
+
`lita spendo foo` - display current billing alert level for account foo.
|
data/lib/lita/handlers/spendo.rb
CHANGED
@@ -7,12 +7,16 @@ module Lita
|
|
7
7
|
attr_accessor :account, :table_name
|
8
8
|
|
9
9
|
def initialize(params={})
|
10
|
+
@aws_access_key_id = params[:aws_access_key_id]
|
11
|
+
@aws_secret_access_key = params[:aws_secret_access_key]
|
12
|
+
@aws_region = params[:aws_region]
|
10
13
|
@account = params[:aws_account_id]
|
11
14
|
@table_name = params[:dynamodb_table]
|
12
15
|
end
|
13
16
|
|
14
17
|
def latest
|
15
|
-
|
18
|
+
credentials = Aws::Credentials.new(@aws_access_key_id, @aws_secret_access_key)
|
19
|
+
ddb = Aws::DynamoDB::Resource.new(region: @aws_region, credentials: credentials)
|
16
20
|
table = ddb.table(table_name)
|
17
21
|
opts = {
|
18
22
|
key_condition_expression: 'Account = :account',
|
@@ -26,69 +30,89 @@ module Lita
|
|
26
30
|
end
|
27
31
|
|
28
32
|
class Spendo < Handler
|
29
|
-
|
30
33
|
LAST_RECORD_KEY = 'last_record'
|
31
34
|
|
32
|
-
config :
|
33
|
-
config :dynamodb_table, type: String, default: 'BillingHistory'
|
34
|
-
config :base_image_url, type: String
|
35
|
-
config :room, type: String
|
35
|
+
config :base_image_url, type: String
|
36
36
|
config :time_between_polls, type: Integer, default: 60*60
|
37
37
|
|
38
|
-
|
39
|
-
|
38
|
+
# array of hashes, each hash describing a different
|
39
|
+
# account to monitor.
|
40
|
+
# config.accounts = [
|
41
|
+
# {
|
42
|
+
# :aws_account_id = 'foo',
|
43
|
+
# :dynamodb_table = 'BillingHistory',
|
44
|
+
# :room = 'shell',
|
45
|
+
# :aws_access_key_id = 'foo',
|
46
|
+
# :aws_secret_access_key = 'foo',
|
47
|
+
# :nickname = 'foo'
|
48
|
+
# }
|
49
|
+
# ]
|
50
|
+
config :accounts, type: Array
|
51
|
+
|
52
|
+
route(/^spendo\s+(\S+)$/, :show, command: true, help: {
|
53
|
+
"spendo account_name" => "show current billing level for account_name"
|
40
54
|
})
|
41
55
|
|
42
|
-
on(:connected) do
|
43
|
-
|
44
|
-
|
45
|
-
|
56
|
+
on(:connected) do
|
57
|
+
config.accounts.each do |account|
|
58
|
+
setup account
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def setup(account)
|
63
|
+
if account[:room]
|
64
|
+
robot.join account[:room]
|
46
65
|
end
|
47
66
|
|
48
|
-
# set up a timer to poll DynamoDB
|
49
67
|
every(config.time_between_polls) do |timer|
|
50
|
-
check_for_alerts
|
68
|
+
check_for_alerts account
|
51
69
|
end
|
52
70
|
end
|
53
71
|
|
54
72
|
def show(response)
|
55
|
-
|
73
|
+
account_nick = response.match_data[1]
|
74
|
+
account = lookup_account account_nick
|
75
|
+
message, url = create_message account
|
56
76
|
|
57
77
|
response.reply message
|
58
78
|
response.reply url
|
59
79
|
end
|
60
80
|
|
61
|
-
|
81
|
+
def create_client(account)
|
82
|
+
params = {
|
83
|
+
aws_account_id: account[:aws_account_id],
|
84
|
+
aws_region: account[:aws_region],
|
85
|
+
dynamodb_table: account[:dynamodb_table],
|
86
|
+
aws_access_key_id: account[:aws_access_key_id],
|
87
|
+
aws_secret_access_key: account[:aws_secret_access_key]
|
88
|
+
}
|
89
|
+
|
90
|
+
BillingHistory.new(params)
|
91
|
+
end
|
62
92
|
|
63
|
-
def
|
64
|
-
|
65
|
-
params = {
|
66
|
-
aws_account_id: config.aws_account_id,
|
67
|
-
dynamodb_table: config.dynamodb_table
|
68
|
-
}
|
69
|
-
@billing_history = BillingHistory.new(params)
|
70
|
-
end
|
71
|
-
@billing_history
|
93
|
+
def lookup_account(nickname)
|
94
|
+
config.accounts.select {|a| a[:nickname] == nickname }.first
|
72
95
|
end
|
73
96
|
|
74
|
-
def create_message
|
75
|
-
|
97
|
+
def create_message(account)
|
98
|
+
client = create_client account
|
99
|
+
data = client.latest
|
76
100
|
|
77
|
-
|
101
|
+
account_id = data['Account']
|
78
102
|
current_fees = data['TotalFees'].to_f
|
79
103
|
expected_fees = data['ExpectedFees'].to_f
|
80
104
|
alert_level = data['AlertLevel'].to_i
|
81
105
|
categorized_fees = data['FeesByCategory']
|
82
106
|
|
83
107
|
message = "The current fees alert threshold has been reached.\n"
|
84
|
-
message << "\nAccount: #{account}"
|
108
|
+
message << "\nAccount: #{account[:nickname]} #{account_id}"
|
85
109
|
message << "\nCurrent fees: $#{current_fees}"
|
86
110
|
message << "\nExpected monthly fees: $#{expected_fees}" # TODO
|
87
111
|
message << "\nFee level is at #{alert_level * 25}% of expected"
|
88
112
|
message << "\n\n Fee Category Breakdown\n\n"
|
89
113
|
|
90
|
-
categorized_fees.
|
91
|
-
value =
|
114
|
+
categorized_fees.keys.sort.each do |k|
|
115
|
+
value = categorized_fees[k].to_f
|
92
116
|
next if value == 0.0
|
93
117
|
message << "#{k.ljust(20)}: $#{sprintf('%8.2f', value.round(2))}\n"
|
94
118
|
end
|
@@ -98,16 +122,22 @@ module Lita
|
|
98
122
|
return [message, url]
|
99
123
|
end
|
100
124
|
|
125
|
+
def account_key(account)
|
126
|
+
account[:aws_account_id] + '_' + LAST_RECORD_KEY
|
127
|
+
end
|
128
|
+
|
101
129
|
# write current data to redis
|
102
130
|
# BigDecimals get saved as strings which fail to
|
103
131
|
# deserialize as integers (but do deserialize as floats)
|
104
|
-
def save_billing_data(data)
|
105
|
-
|
132
|
+
def save_billing_data(account, data)
|
133
|
+
key = account_key account
|
134
|
+
redis.set key, data.to_json
|
106
135
|
end
|
107
136
|
|
108
137
|
# read previous data from redis
|
109
|
-
def load_billing_data
|
110
|
-
|
138
|
+
def load_billing_data(account)
|
139
|
+
key = account_key account
|
140
|
+
data = redis.get key
|
111
141
|
return nil if data.nil?
|
112
142
|
|
113
143
|
JSON.parse(data)
|
@@ -117,20 +147,21 @@ module Lita
|
|
117
147
|
previous['AlertLevel'].to_f != current['AlertLevel'].to_f
|
118
148
|
end
|
119
149
|
|
120
|
-
def check_for_alerts
|
150
|
+
def check_for_alerts(account)
|
121
151
|
log.debug "checking for alerts"
|
122
|
-
|
123
|
-
|
152
|
+
client = create_client account
|
153
|
+
current_data = client.latest
|
154
|
+
last_data = load_billing_data(account)
|
124
155
|
|
125
156
|
if last_data && alert_level_changed?(last_data, current_data)
|
126
|
-
message, url = create_message
|
127
|
-
target = Source.new(room:
|
157
|
+
message, url = create_message account
|
158
|
+
target = Source.new(room: account[:room])
|
128
159
|
robot.send_messages(target, message, url)
|
129
160
|
else
|
130
161
|
log.debug "alert level unchanged"
|
131
162
|
end
|
132
163
|
|
133
|
-
save_billing_data current_data
|
164
|
+
save_billing_data account, current_data
|
134
165
|
end
|
135
166
|
end
|
136
167
|
|
data/lita-spendo.gemspec
CHANGED