instance_accountant 0.0.1 → 0.0.2
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 +4 -4
- data/README.md +14 -18
- data/instance_accountant.gemspec +1 -1
- data/lib/instance_accountant/cli.rb +7 -5
- data/lib/instance_accountant/filer.rb +8 -6
- data/lib/instance_accountant.rb +1 -1
- data/spec/instance_accountant/filer_spec.rb +49 -11
- metadata +74 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 19a81626ec5302f9c0ae2bdd455c7aa70c2384f3
|
4
|
+
data.tar.gz: 611a5db14d5b5284b16d5935e72df9df4148381d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 948d6d0a669a3fa5ed8e6543cb93063e3ced2e46e875ab06c85169c034cfe196be66598cbe28cc0504d436951923299091cb380c6810f03d8708b8c3312690e5
|
7
|
+
data.tar.gz: ff0797c01fb181fe887300fd8740a29ac0196882c51fc7f3c6a51cc96118585c11782afb742151cb97141eb60b476773473448ac72b688b7a26eb941a4917d06
|
data/README.md
CHANGED
@@ -10,13 +10,12 @@ Gemfile:
|
|
10
10
|
|
11
11
|
The gem provides an executable that can be invoked two ways:
|
12
12
|
|
13
|
-
|
13
|
+
1) you want to account for the hourly cost of instances:
|
14
|
+
|
15
|
+
#!/bin/bash
|
14
16
|
|
15
17
|
instance_accountant account \
|
16
|
-
--description 'instance usage for: %s' \
|
17
|
-
--reference 'http://test.com/journal_entry' \
|
18
18
|
--cost 0.1 \
|
19
|
-
--cost_description 'cost for: %s' \
|
20
19
|
--cost_reference 'http://test.com/cost' \
|
21
20
|
--expense_acct subledger_account_id \
|
22
21
|
--payable_acct subledger_account_id \
|
@@ -24,30 +23,24 @@ If you want to account for the hourly cost of instances, use this form:
|
|
24
23
|
--secret subledger_secret \
|
25
24
|
--org_id subledger_org_id \
|
26
25
|
--book_id subledger_book_id \
|
27
|
-
--daemon
|
26
|
+
--daemon 2>&1 >> instance_accountant.log
|
27
|
+
|
28
|
+
2) you want to account for both the hourly cost and income:
|
28
29
|
|
29
|
-
|
30
|
+
#!/bin/bash
|
30
31
|
|
31
32
|
instance_accountant account \
|
32
|
-
--description 'instance usage for: %s' \
|
33
|
-
--reference 'http://test.com/journal_entry' \
|
34
33
|
--cost 0.1 \
|
35
|
-
--cost_description 'cost for: %s' \
|
36
|
-
--cost_reference 'http://test.com/cost' \
|
37
34
|
--expense_acct subledger_account_id \
|
38
35
|
--payable_acct subledger_account_id \
|
39
36
|
--price 0.2 \
|
40
|
-
--price_description 'price for: %s' \
|
41
|
-
--price_reference 'http://test.com/price' \
|
42
37
|
--receivable_acct subledger_account_id \
|
43
38
|
--income_acct subledger_account_id \
|
44
39
|
--key_id subledger_key_id \
|
45
40
|
--secret subledger_secret \
|
46
41
|
--org_id subledger_org_id \
|
47
42
|
--book_id subledger_book_id \
|
48
|
-
--daemon
|
49
|
-
|
50
|
-
Note: %s in descriptions will be replaced by the ISO 8601 of the hour in UTC
|
43
|
+
--daemon 2>&1 >> instance_accountant.log
|
51
44
|
|
52
45
|
Here's a complete set of options:
|
53
46
|
|
@@ -55,17 +48,17 @@ Here's a complete set of options:
|
|
55
48
|
f, [--filepath=FILEPATH]
|
56
49
|
# Default: ~/.instance_accountant
|
57
50
|
d, --description=DESCRIPTION
|
58
|
-
# Default: instance usage for
|
51
|
+
# Default: instance usage for: %
|
59
52
|
[--reference=REFERENCE]
|
60
53
|
c, --cost=COST
|
61
54
|
[--cost-description=COST_DESCRIPTION]
|
62
|
-
# Default: cost for
|
55
|
+
# Default: instance cost for: %
|
63
56
|
[--cost-reference=COST_REFERENCE]
|
64
57
|
e, --expense-acct=EXPENSE_ACCT
|
65
58
|
p, --payable-acct=PAYABLE_ACCT
|
66
59
|
p, [--price=PRICE]
|
67
60
|
[--price-description=PRICE_DESCRIPTION]
|
68
|
-
# Default: price for
|
61
|
+
# Default: instance price for %
|
69
62
|
[--price-reference=PRICE_REFERENCE]
|
70
63
|
i, [--income-acct=INCOME_ACCT]
|
71
64
|
r, [--receivable-acct=RECEIVABLE_ACCT]
|
@@ -74,3 +67,6 @@ Here's a complete set of options:
|
|
74
67
|
o, --org-id=ORG_ID
|
75
68
|
b, --book-id=BOOK_ID
|
76
69
|
[--daemon], [--no-daemon]
|
70
|
+
|
71
|
+
Note: %s in descriptions will be replaced by the ISO 8601 of the hour in UTC
|
72
|
+
Note: instance_accountant captures errors and does its best to keep running
|
data/instance_accountant.gemspec
CHANGED
@@ -17,7 +17,7 @@ Gem::Specification.new do |gem|
|
|
17
17
|
gem.test_files = Dir.glob( 'spec/**/*.rb' )
|
18
18
|
|
19
19
|
gem.name = 'instance_accountant'
|
20
|
-
gem.description =
|
20
|
+
gem.description = File.read 'README.md'
|
21
21
|
gem.summary = 'account for hourly instance usage using Subledger'
|
22
22
|
gem.version = InstanceAccountant::VERSION
|
23
23
|
gem.email = 'admin@subledger.com'
|
@@ -14,7 +14,7 @@ module InstanceAccountant
|
|
14
14
|
method_option :description,
|
15
15
|
aliases: :d,
|
16
16
|
required: true,
|
17
|
-
default: 'instance usage for'
|
17
|
+
default: 'instance usage for: %'
|
18
18
|
|
19
19
|
method_option :reference
|
20
20
|
|
@@ -22,7 +22,7 @@ module InstanceAccountant
|
|
22
22
|
aliases: :c,
|
23
23
|
required: true
|
24
24
|
method_option :cost_description,
|
25
|
-
default: 'cost for'
|
25
|
+
default: 'instance cost for: %'
|
26
26
|
|
27
27
|
method_option :cost_reference
|
28
28
|
|
@@ -38,7 +38,7 @@ module InstanceAccountant
|
|
38
38
|
aliases: :p
|
39
39
|
|
40
40
|
method_option :price_description,
|
41
|
-
default: 'price for'
|
41
|
+
default: 'instnace price for: %'
|
42
42
|
|
43
43
|
method_option :price_reference
|
44
44
|
|
@@ -68,7 +68,7 @@ module InstanceAccountant
|
|
68
68
|
|
69
69
|
SIGNALS = []
|
70
70
|
|
71
|
-
|
71
|
+
SECONDS_BETWEEN_ATTEMPTS = 10
|
72
72
|
|
73
73
|
%w(ABRT ALRM HUP INT STOP TERM QUIT).each do |signal|
|
74
74
|
Signal.trap signal do
|
@@ -96,10 +96,12 @@ module InstanceAccountant
|
|
96
96
|
|
97
97
|
def consider_posting i, options
|
98
98
|
Poster.new(options).post(Hour.new, Time.now) if posting_required? i
|
99
|
+
rescue Exception => e
|
100
|
+
STDERR.puts e
|
99
101
|
end
|
100
102
|
|
101
103
|
def posting_required? i
|
102
|
-
(i %
|
104
|
+
(i % SECONDS_BETWEEN_ATTEMPTS).zero? or signal?
|
103
105
|
end
|
104
106
|
|
105
107
|
def consider_exiting
|
@@ -10,24 +10,26 @@ module InstanceAccountant
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def read
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
hour_string = nil
|
14
|
+
|
15
|
+
@file_klass.open( @filepath, 'r' ) do |file|
|
16
16
|
file.flock File::LOCK_EX
|
17
|
-
file.read
|
17
|
+
hour_string = file.read
|
18
18
|
end
|
19
|
+
|
20
|
+
@time_klass.parse hour_string
|
19
21
|
rescue
|
20
22
|
nil
|
21
23
|
end
|
22
24
|
|
23
25
|
def write hour
|
24
|
-
hour_string = hour.
|
26
|
+
hour_string = hour.hour_string
|
25
27
|
|
26
28
|
@file_klass.open( @filepath,
|
27
29
|
File::RDWR | File::CREAT,
|
28
30
|
0644 ) do |file|
|
29
31
|
file.flock File::LOCK_EX
|
30
|
-
file.
|
32
|
+
file.truncate 0
|
31
33
|
file.write hour_string
|
32
34
|
end
|
33
35
|
|
data/lib/instance_accountant.rb
CHANGED
@@ -4,15 +4,15 @@ require 'helpers'
|
|
4
4
|
require 'instance_accountant/filer'
|
5
5
|
|
6
6
|
module InstanceAccountant
|
7
|
-
Class
|
7
|
+
Class Filer do
|
8
8
|
Instance do
|
9
9
|
subject { Filer.new options }
|
10
10
|
|
11
11
|
let(:options) do
|
12
12
|
{
|
13
|
-
filepath: filepath,
|
14
13
|
file_klass: file_klass,
|
15
|
-
time_klass: time_klass
|
14
|
+
time_klass: time_klass,
|
15
|
+
filepath: filepath
|
16
16
|
}
|
17
17
|
end
|
18
18
|
|
@@ -22,10 +22,28 @@ module InstanceAccountant
|
|
22
22
|
let(:time_klass) { double 'time_klass' }
|
23
23
|
let(:time_inst) { double 'time_inst' }
|
24
24
|
|
25
|
-
let(:
|
25
|
+
let(:hour_string) { double 'hour_string' }
|
26
26
|
let(:hour) { double 'hour' }
|
27
27
|
|
28
|
+
let(:file) { double 'file' }
|
29
|
+
|
28
30
|
RespondsTo :read do
|
31
|
+
When 'it has not been written before' do
|
32
|
+
ByReturning nil do
|
33
|
+
expect(file_klass)
|
34
|
+
.to receive(:expand_path)
|
35
|
+
.with(filepath)
|
36
|
+
.and_return(expanded_filepath)
|
37
|
+
|
38
|
+
expect(file_klass)
|
39
|
+
.to receive(:open)
|
40
|
+
.with(expanded_filepath, 'r')
|
41
|
+
.and_raise(Errno::ENOENT)
|
42
|
+
|
43
|
+
subject.read.must_be_nil
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
29
47
|
When 'it has been written before' do
|
30
48
|
ByReturning 'a Time' do
|
31
49
|
expect(file_klass)
|
@@ -35,12 +53,20 @@ module InstanceAccountant
|
|
35
53
|
|
36
54
|
expect(file_klass)
|
37
55
|
.to receive(:open)
|
38
|
-
.with(expanded_filepath,
|
39
|
-
.
|
56
|
+
.with(expanded_filepath, 'r')
|
57
|
+
.and_yield(file)
|
58
|
+
|
59
|
+
expect(file)
|
60
|
+
.to receive(:flock)
|
61
|
+
.with(File::LOCK_EX)
|
62
|
+
|
63
|
+
expect(file)
|
64
|
+
.to receive(:read)
|
65
|
+
.and_return(hour_string)
|
40
66
|
|
41
67
|
expect(time_klass)
|
42
68
|
.to receive(:parse)
|
43
|
-
.with(
|
69
|
+
.with(hour_string)
|
44
70
|
.and_return(time_inst)
|
45
71
|
|
46
72
|
subject.read.must_be_same_as time_inst
|
@@ -56,15 +82,27 @@ module InstanceAccountant
|
|
56
82
|
.and_return(expanded_filepath)
|
57
83
|
|
58
84
|
expect(hour)
|
59
|
-
.to receive(:
|
60
|
-
.and_return(
|
85
|
+
.to receive(:hour_string)
|
86
|
+
.and_return(hour_string)
|
61
87
|
|
62
88
|
expect(file_klass)
|
63
89
|
.to receive(:open)
|
64
90
|
.with(expanded_filepath, File::RDWR | File::CREAT, 0644)
|
65
|
-
.
|
91
|
+
.and_yield(file)
|
92
|
+
|
93
|
+
expect(file)
|
94
|
+
.to receive(:flock)
|
95
|
+
.with(File::LOCK_EX)
|
96
|
+
|
97
|
+
expect(file)
|
98
|
+
.to receive(:truncate)
|
99
|
+
.with(0)
|
100
|
+
|
101
|
+
expect(file)
|
102
|
+
.to receive(:write)
|
103
|
+
.with(hour_string)
|
66
104
|
|
67
|
-
subject.write(hour).must_be_same_as
|
105
|
+
subject.write(hour).must_be_same_as hour_string
|
68
106
|
end
|
69
107
|
end
|
70
108
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: instance_accountant
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tom Mornini
|
@@ -165,7 +165,79 @@ dependencies:
|
|
165
165
|
- - "~>"
|
166
166
|
- !ruby/object:Gem::Version
|
167
167
|
version: '0.27'
|
168
|
-
description:
|
168
|
+
description: |
|
169
|
+
Subledger instance accountant Ruby gem
|
170
|
+
|
171
|
+
Installation:
|
172
|
+
|
173
|
+
gem install instance_accountant
|
174
|
+
|
175
|
+
Gemfile:
|
176
|
+
|
177
|
+
gem 'instance_accountant'
|
178
|
+
|
179
|
+
The gem provides an executable that can be invoked two ways:
|
180
|
+
|
181
|
+
1) you want to account for the hourly cost of instances:
|
182
|
+
|
183
|
+
#!/bin/bash
|
184
|
+
|
185
|
+
instance_accountant account \
|
186
|
+
--cost 0.1 \
|
187
|
+
--cost_reference 'http://test.com/cost' \
|
188
|
+
--expense_acct subledger_account_id \
|
189
|
+
--payable_acct subledger_account_id \
|
190
|
+
--key_id subledger_key_id \
|
191
|
+
--secret subledger_secret \
|
192
|
+
--org_id subledger_org_id \
|
193
|
+
--book_id subledger_book_id \
|
194
|
+
--daemon 2>&1 >> instance_accountant.log
|
195
|
+
|
196
|
+
2) you want to account for both the hourly cost and income:
|
197
|
+
|
198
|
+
#!/bin/bash
|
199
|
+
|
200
|
+
instance_accountant account \
|
201
|
+
--cost 0.1 \
|
202
|
+
--expense_acct subledger_account_id \
|
203
|
+
--payable_acct subledger_account_id \
|
204
|
+
--price 0.2 \
|
205
|
+
--receivable_acct subledger_account_id \
|
206
|
+
--income_acct subledger_account_id \
|
207
|
+
--key_id subledger_key_id \
|
208
|
+
--secret subledger_secret \
|
209
|
+
--org_id subledger_org_id \
|
210
|
+
--book_id subledger_book_id \
|
211
|
+
--daemon 2>&1 >> instance_accountant.log
|
212
|
+
|
213
|
+
Here's a complete set of options:
|
214
|
+
|
215
|
+
Options:
|
216
|
+
f, [--filepath=FILEPATH]
|
217
|
+
# Default: ~/.instance_accountant
|
218
|
+
d, --description=DESCRIPTION
|
219
|
+
# Default: instance usage for: %
|
220
|
+
[--reference=REFERENCE]
|
221
|
+
c, --cost=COST
|
222
|
+
[--cost-description=COST_DESCRIPTION]
|
223
|
+
# Default: instance cost for: %
|
224
|
+
[--cost-reference=COST_REFERENCE]
|
225
|
+
e, --expense-acct=EXPENSE_ACCT
|
226
|
+
p, --payable-acct=PAYABLE_ACCT
|
227
|
+
p, [--price=PRICE]
|
228
|
+
[--price-description=PRICE_DESCRIPTION]
|
229
|
+
# Default: instance price for %
|
230
|
+
[--price-reference=PRICE_REFERENCE]
|
231
|
+
i, [--income-acct=INCOME_ACCT]
|
232
|
+
r, [--receivable-acct=RECEIVABLE_ACCT]
|
233
|
+
k, --key-id=KEY_ID
|
234
|
+
s, --secret=SECRET
|
235
|
+
o, --org-id=ORG_ID
|
236
|
+
b, --book-id=BOOK_ID
|
237
|
+
[--daemon], [--no-daemon]
|
238
|
+
|
239
|
+
Note: %s in descriptions will be replaced by the ISO 8601 of the hour in UTC
|
240
|
+
Note: instance_accountant captures errors and does its best to keep running
|
169
241
|
email: admin@subledger.com
|
170
242
|
executables:
|
171
243
|
- instance_accountant
|