ec2spec 0.1.2 → 0.1.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f654ed96111dcd1d53c9518fbf643b443d3ff727
4
- data.tar.gz: 21342c52833a9f060f19de8318ad1f6cd5a35d2c
3
+ metadata.gz: 60150ecbe0bd1b6478aa68c3cd15b31e105ecd6c
4
+ data.tar.gz: 3456da709faf5d462df6944cb3a9de7428b4d0bb
5
5
  SHA512:
6
- metadata.gz: 56b4f3e02cd6b46d652cafdc9ea549bb82bc6d265ac339fd65c6d6d115e877f1510c2b0eda5a31becd75f727c29953e70e3f02c2de0fd07cbbfc5f549c8959c1
7
- data.tar.gz: 04fde02c25dbebf9faa24036bb02fe14a9cce4d94f0b0e7de66f6590981ea5f49261811364afd6aeda4944a8a620d8c94c51ca818bb002f17347ba2815344554
6
+ metadata.gz: f4209d90cdf962bf9ab747c07d2737faafc7375396af3df633a482c308163ca1780f3a32e0ebeba15a4eefddd0498a3c6e62464e41c3090b031e736ee2e6c693
7
+ data.tar.gz: 4c3770534df422645520e5c4504698dd95063eb4579e5a429f77dbc976e033590dfcc61ec075efac9e4706ae6777e2ad84fd20efeedd88dea38bd03f10f4505c
@@ -1,5 +1,15 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.1.3
4
+
5
+ ### Added
6
+ * Add logo
7
+ * Support currency unit price output by API/Manual
8
+ * Support markdown/slack format
9
+
10
+ ### Changed
11
+ * Output error messages when connecting host error was raised
12
+
3
13
  ## 0.1.2
4
14
 
5
15
  ### Added
@@ -1,8 +1,10 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ec2spec (0.1.2)
4
+ ec2spec (0.1.3)
5
5
  faraday
6
+ money
7
+ money-open-exchange-rates
6
8
  specinfra
7
9
  terminal-table
8
10
  thor
@@ -11,10 +13,17 @@ GEM
11
13
  remote: https://rubygems.org/
12
14
  specs:
13
15
  ast (2.4.0)
16
+ concurrent-ruby (1.0.5)
14
17
  diff-lcs (1.3)
15
18
  faraday (0.15.2)
16
19
  multipart-post (>= 1.2, < 3)
20
+ i18n (1.0.1)
21
+ concurrent-ruby (~> 1.0)
17
22
  jaro_winkler (1.5.1)
23
+ money (6.12.0)
24
+ i18n (>= 0.6.4, < 1.1)
25
+ money-open-exchange-rates (1.2.2)
26
+ money (~> 6.6)
18
27
  multipart-post (2.0.0)
19
28
  net-scp (1.2.1)
20
29
  net-ssh (>= 2.6.5)
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # ec2spec
1
+ # [![](https://user-images.githubusercontent.com/3317191/44626545-42a39380-a959-11e8-96a4-de3b0ea3e96f.png)](https://github.com/kyoshidajp/ec2spec)
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/ec2spec.svg)](https://badge.fury.io/rb/ec2spec)
4
4
  [![Build Status](https://travis-ci.org/kyoshidajp/ec2spec.svg?branch=master)](https://travis-ci.org/kyoshidajp/ec2spec)
@@ -32,6 +32,30 @@ $ gem install ec2spec
32
32
  $ ec2spec ssh -h host1 ... [options]
33
33
  ```
34
34
 
35
+ ### Example
36
+
37
+ ```
38
+ $ ec2spec ssh -h host1 host2 host3
39
+ I, [2018-08-12T20:54:25.814752 #64341] INFO -- : Started: host1
40
+ I, [2018-08-12T20:54:25.814835 #64341] INFO -- : Started: host2
41
+ I, [2018-08-12T20:54:25.814867 #64341] INFO -- : Started: host3
42
+ E, [2018-08-12T20:54:25.826113 #64341] ERROR -- : Connection refused: host3
43
+ I, [2018-08-12T20:54:29.385848 #64341] INFO -- : Finished: host1
44
+ I, [2018-08-12T20:54:37.560003 #64341] INFO -- : Finished: host2
45
+ +---------------+-------------+---------------------+-------+
46
+ | | host1 | host2 | host3 |
47
+ +---------------+-------------+---------------------|-------+
48
+ | instance_type | t2.micro | c4.2xlarge | N/A |
49
+ | instance_id | i-xxxxxxxx | i-yyyyyyyy | N/A |
50
+ | vCPU | 1 | 8 | N/A |
51
+ | memory | 1 GiB | 15 GiB | N/A |
52
+ | price (USD/H) | 0.0152 | 0.504 | N/A |
53
+ | price (USD/M) | 11.3088 | 374.976 | N/A |
54
+ +---------------+-------------+---------------------+-------+
55
+ ```
56
+
57
+ The data of `host3` could not be acquired due to a connection refused error.
58
+
35
59
  ### Options
36
60
 
37
61
  ```
@@ -40,39 +64,101 @@ $ ec2spec ssh -h host1 ... [options]
40
64
  --days How many days per one month.
41
65
 
42
66
  --format Output format (default: plain_text).
43
- plain_text, json, hash
67
+ plain_text, json, hash, slack, markdown
44
68
 
45
69
  --region Region of EC2 (default: ap-northeast-1).
46
70
 
71
+ --unit Currency unit.
72
+ with --rate.
73
+
74
+ --rate Dollar exchange rate.
75
+ with --unit.
76
+
77
+ --calc_type Calculate exchange currency rate type.
78
+ api, manual
79
+ with --app_id, --unit (if app)
80
+ --unit, rate (if manual)
81
+
82
+ --app_id App ID of Open Exchange Rates
83
+ https://openexchangerates.org/
84
+ with --calc_type, --unit
85
+
47
86
  --debug Output logs as DEBUG level.
48
87
  ```
49
88
 
50
- ### Example
89
+ #### --format (`plain_text`)
51
90
 
52
91
  ```
53
- $ ec2spec ssh -h host1 host2 host3
92
+ +---------------+-------------+-------------+
93
+ | | host1 | host2 |
94
+ +---------------+-------------+-------------|
95
+ | instance_type | t2.micro | c4.2xlarge |
96
+ | instance_id | i-xxxxxxxx | i-yyyyyyyy |
97
+ | vCPU | 1 | 8 |
98
+ | memory | 1 GiB | 15 GiB |
99
+ | price (USD/H) | 0.0152 | 0.504 |
100
+ | price (USD/M) | 11.3088 | 374.976 |
101
+ +---------------+-------------+-------------+
54
102
  ```
55
103
 
104
+ #### --format (`json` and `hash`)
105
+
56
106
  ```
57
- I, [2018-08-12T20:54:25.814752 #64341] INFO -- : Started: host1
58
- I, [2018-08-12T20:54:25.814835 #64341] INFO -- : Started: host2
59
- I, [2018-08-12T20:54:25.814867 #64341] INFO -- : Started: host3
60
- I, [2018-08-12T20:54:25.826113 #64341] INFO -- : Finished: host3
61
- I, [2018-08-12T20:54:29.385848 #64341] INFO -- : Finished: host1
62
- I, [2018-08-12T20:54:37.560003 #64341] INFO -- : Finished: host2
63
- +---------------+-------------+-------------+-------+
64
- | | host1 | host2 | host3 |
65
- +---------------+-------------+-------------|-------+
66
- | instance_type | t2.micro | c4.2xlarge | N/A |
67
- | instance_id | i-xxxxxxxx | i-yyyyyyyy | N/A |
68
- | vCPU | 1 | 8 | N/A |
69
- | memory | 1 GiB | 15 GiB | N/A |
70
- | price (USD/H) | 0.0152 | 0.504 | N/A |
71
- | price (USD/M) | 11.3088 | 374.976 | N/A |
72
- +---------------+-------------+---------------------+
73
- ```
74
-
75
- The data of `host3` could not be acquired due to some error.
107
+ {"host1":{"instance_type":"t2.micro","instance_id":"i-xxxxxxxx","vCPU":"1","memory":"1 GiB","price (USD/H)":0.0152,"price (USD/M)":11.3088},"host2":{"instance_type":"c4.2xlarge","instance_id":"i-yyyyyyyy","vCPU":"8","memory":"15 GiB","price (USD/H)":0.504,"price (USD/M)":374.976}}
108
+ ```
109
+
110
+ #### --format (`slack`)
111
+
112
+ ````
113
+ ```
114
+ +---------------+-------------+-------------+
115
+ | | host1 | host2 |
116
+ +---------------+-------------+-------------+
117
+ | instance_type | t2.micro | c4.2xlarge |
118
+ | instance_id | i-xxxxxxxx | i-yyyyyyyy |
119
+ | vCPU | 1 | 8 |
120
+ | memory | 1 GiB | 15 GiB |
121
+ | price (USD/H) | 0.0152 | 0.504 |
122
+ | price (USD/M) | 11.3088 | 374.976 |
123
+ +---------------+-------------+-------------+
124
+ ```
125
+ ````
126
+
127
+ #### --format (`markdown`)
128
+
129
+ ```
130
+ | | stg-bastion | worker1 |
131
+ |---------------|-------------|-------------|
132
+ | instance_type | t2.micro | c4.2xlarge |
133
+ | instance_id | i-xxxxxxxx | i-yyyyyyyy |
134
+ | vCPU | 1 | 8 |
135
+ | memory | 1 GiB | 15 GiB |
136
+ | price (USD/H) | 0.0152 | 0.504 |
137
+ | price (USD/M) | 11.3088 | 374.976 |
138
+ ```
139
+
140
+ ### Exchange currency rate
141
+
142
+ #### Manual
143
+
144
+ Output JPY as exchange rate is 1 dollar 111 yen.
145
+
146
+ ```
147
+ $ ec2spec ssh -h host1 host2 --unit JPY --calc_type manual
148
+ ```
149
+
150
+ #### API
151
+
152
+ First, get App ID from
153
+ https://openexchangerates.org/
154
+
155
+ Output JPY with it.
156
+
157
+ ```
158
+ $ ec2spec ssh -h host1 host2 --unit JPY --calc_type api --app_id xxxxxxxx
159
+ ```
160
+
161
+ **Note:** Exchange rate is cached in `~/.ec2spec/oxr.json`. If you want to refresh, you have to delete it.
76
162
 
77
163
  ## As a library
78
164
 
@@ -4,11 +4,12 @@ require 'ec2spec/version'
4
4
  Gem::Specification.new do |spec|
5
5
  spec.name = 'ec2spec'
6
6
  spec.version = Ec2spec::VERSION
7
- spec.authors = %w[Katsuhiko YOSHIDA]
7
+ spec.authors = %w["Katsuhiko YOSHIDA"]
8
8
  spec.email = %w[claddvd@gmail.com]
9
9
 
10
- spec.summary = 'Write a short summary, because RubyGems requires one.'
11
- spec.description = 'Write a longer description or delete this line.'
10
+ spec.description = 'ec2spec is a simple comparison tool '\
11
+ 'for Amazon EC2 Instances you can access.'
12
+ spec.summary = spec.description
12
13
  spec.homepage = 'https://github.com/kyoshidajp/ec2spec'
13
14
  spec.license = 'MIT'
14
15
 
@@ -20,6 +21,8 @@ Gem::Specification.new do |spec|
20
21
  spec.require_paths = ['lib']
21
22
 
22
23
  spec.add_dependency 'faraday'
24
+ spec.add_dependency 'money'
25
+ spec.add_dependency 'money-open-exchange-rates'
23
26
  spec.add_dependency 'specinfra'
24
27
  spec.add_dependency 'terminal-table'
25
28
  spec.add_dependency 'thor'
@@ -5,9 +5,17 @@ require 'terminal-table'
5
5
  require 'ec2spec/cli'
6
6
  require 'ec2spec/client'
7
7
  require 'ec2spec/const'
8
+ require 'ec2spec/formatter'
9
+ require 'ec2spec/initializer'
8
10
  require 'ec2spec/version'
9
11
  require 'ec2spec/host_result'
10
12
  require 'ec2spec/logger'
11
13
  require 'ec2spec/offer_file'
12
14
  require 'ec2spec/offer_index_file'
13
15
  require 'ec2spec/price_calculator'
16
+
17
+ module Ec2spec
18
+ def self.project_dir
19
+ File.join(ENV['HOME'], Const::PROJECT_DIR)
20
+ end
21
+ end
@@ -0,0 +1,34 @@
1
+ require 'money'
2
+ require 'money/bank/open_exchange_rates_bank'
3
+
4
+ module Ec2spec
5
+ module Calculator
6
+ module ApiPriceCalculator
7
+ OXR_CACHE = 'oxr.json'
8
+
9
+ def currency_unit
10
+ @currency_unit
11
+ end
12
+
13
+ def currency_unit_price(dollar_price)
14
+ Money.new(dollar_price * 100, :USD).exchange_to(currency_unit)
15
+ end
16
+
17
+ def cache_file
18
+ File.join(Ec2spec.project_dir, OXR_CACHE)
19
+ end
20
+
21
+ def prepare_exchange_api(app_id)
22
+ prepare_money(app_id)
23
+ end
24
+
25
+ def prepare_money(app_id)
26
+ oxr = Money::Bank::OpenExchangeRatesBank.new
27
+ oxr.app_id = app_id
28
+ oxr.cache = cache_file
29
+ oxr.update_rates
30
+ Money.default_bank = oxr
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,9 @@
1
+ module Ec2spec
2
+ module Calculator
3
+ module ManualPriceCalculator
4
+ def currency_unit_price(dollar_price)
5
+ Money.new(dollar_price.to_f * @dollar_exchange_rate.to_f, :USD)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -5,21 +5,39 @@ module Ec2spec
5
5
  desc 'ssh -h host1 ...', 'Compare the specifications of EC2 instances.'
6
6
  option 'host', aliases: 'h', type: :array, equired: true
7
7
  option 'days', type: :numeric
8
+ option 'rate', type: :numeric
9
+ option 'unit'
8
10
  option 'format'
9
11
  option 'region'
12
+ option 'app_id'
13
+ option 'calc_type'
10
14
  option 'debug', type: :boolean
11
15
 
12
- # rubocop:disable Metrics/AbcSize
16
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
13
17
  def ssh
14
18
  hosts = options['host']
15
19
  days = options['days']
20
+ rate = options['rate']
21
+ unit = options['unit']
22
+ app_id = options['app_id']
23
+ calc_type = options['calc_type']
16
24
  format = options['format'] || :plain_text
17
25
  region = options['region'] || 'ap-northeast-1'
18
26
 
19
27
  Ec2spec.logger.level = Logger::DEBUG if options['debug']
20
28
  client = Ec2spec::Client.new(hosts, days, format, region)
29
+ if exchange_unit?(unit, rate, app_id)
30
+ client.prepare_price_calculator(unit, rate,
31
+ calc_type, app_id)
32
+ end
21
33
  puts client.run
22
34
  end
23
- # rubocop:enable Metrics/AbcSize
35
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
36
+
37
+ private
38
+
39
+ def exchange_unit?(unit, rate, app_id)
40
+ (rate || app_id) && unit
41
+ end
24
42
  end
25
43
  end
@@ -1,6 +1,5 @@
1
- require 'ec2spec/json_formatter'
2
- require 'ec2spec/plain_text_formatter'
3
- require 'ec2spec/hash_formatter'
1
+ require 'ec2spec/formatter'
2
+ require 'ec2spec/price_calculator'
4
3
 
5
4
  module Ec2spec
6
5
  class UndefineFormatterError < StandardError; end
@@ -12,9 +11,17 @@ module Ec2spec
12
11
  DEFAULT_REGION = 'ap-northeast-1'
13
12
 
14
13
  OUTPUT_FORMATTERS = {
15
- plain_text: PlainTextFormatter,
16
- json: JsonFormatter,
17
- hash: HashFormatter,
14
+ plain_text: Formatter::PlainTextFormatter,
15
+ json: Formatter::JsonFormatter,
16
+ hash: Formatter::HashFormatter,
17
+ slack: Formatter::SlackFormatter,
18
+ markdown: Formatter::MarkdownFormatter,
19
+ }
20
+
21
+ CONNECTION_ERROR_WITH_MESSAGES = {
22
+ Errno::ECONNREFUSED => 'Connection refused: %{host}',
23
+ Net::SSH::ConnectionTimeout => 'Connection timeout: %{host}',
24
+ StandardError => 'Unknown error: %{host}',
18
25
  }
19
26
 
20
27
  def initialize(hosts, days, format, region = DEFAULT_REGION)
@@ -23,8 +30,13 @@ module Ec2spec
23
30
  @format = format
24
31
  @region = region
25
32
 
33
+ Initializer.instance.do(region)
34
+
26
35
  extend_formatter
27
- OfferFile.instance.prepare(@region)
36
+ end
37
+
38
+ def prepare_price_calculator(unit, rate, calc_type, app_id = nil)
39
+ PriceCalculator.instance.prepare(unit, rate, calc_type, app_id)
28
40
  end
29
41
 
30
42
  def run
@@ -51,17 +63,19 @@ module Ec2spec
51
63
  extend OUTPUT_FORMATTERS[format_sym]
52
64
  end
53
65
 
66
+ def host_result(host, backend)
67
+ Ec2spec.logger.info("Finished: #{host.host}")
68
+ host.instance_type = instance_type(backend)
69
+ host.instance_id = instance_id(backend)
70
+ rescue *CONNECTION_ERROR_WITH_MESSAGES.keys => e
71
+ message = format(CONNECTION_ERROR_WITH_MESSAGES[e.class], host: host.host)
72
+ Ec2spec.logger.error(message)
73
+ host.na_values
74
+ end
75
+
54
76
  def exec_host_result(host, backend)
55
77
  Ec2spec.logger.info("Started: #{host.host}")
56
-
57
- begin
58
- host.instance_type = instance_type(backend)
59
- host.instance_id = instance_id(backend)
60
- rescue Errno::ECONNREFUSED
61
- host.na_values
62
- end
63
-
64
- Ec2spec.logger.info("Finished: #{host.host}")
78
+ host_result(host, backend)
65
79
  host
66
80
  end
67
81
 
@@ -0,0 +1,5 @@
1
+ require 'ec2spec/formatter/json_formatter'
2
+ require 'ec2spec/formatter/markdown_formatter'
3
+ require 'ec2spec/formatter/plain_text_formatter'
4
+ require 'ec2spec/formatter/hash_formatter'
5
+ require 'ec2spec/formatter/slack_formatter'
@@ -0,0 +1,13 @@
1
+ require 'json'
2
+
3
+ module Ec2spec
4
+ module Formatter
5
+ module HashFormatter
6
+ def output(results, _hosts)
7
+ results.each_with_object({}) do |result, hash|
8
+ hash[result.host] = result.to_hash
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ require 'json'
2
+ require 'ec2spec/formatter/hash_formatter'
3
+
4
+ module Ec2spec
5
+ module Formatter
6
+ module JsonFormatter
7
+ include Ec2spec::Formatter::HashFormatter
8
+
9
+ def output(results, _hosts)
10
+ super.to_json
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,15 @@
1
+ require 'ec2spec/formatter/plain_text_formatter'
2
+
3
+ module Ec2spec
4
+ module Formatter
5
+ module MarkdownFormatter
6
+ include Ec2spec::Formatter::PlainTextFormatter
7
+
8
+ def output(results, _hosts)
9
+ table = super
10
+ table.style = { border_i: '|', border_top: false, border_bottom: false }
11
+ table
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,27 @@
1
+ module Ec2spec
2
+ module Formatter
3
+ module PlainTextFormatter
4
+ def output(results, hosts)
5
+ table = Terminal::Table.new
6
+ table.headings = table_header(results)
7
+ table.rows = table_rows(results)
8
+ column_count = hosts.size + 1
9
+ column_count.times { |i| table.align_column(i, :right) }
10
+ table
11
+ end
12
+
13
+ def table_header(results)
14
+ [''].concat(results.map(&:host))
15
+ end
16
+
17
+ def table_rows(results)
18
+ Ec2spec::HostResult.label_with_methods
19
+ .each_with_object([]) do |(k, v), row|
20
+ unit = PriceCalculator.instance.currency_unit
21
+ label = format(k, unit)
22
+ row << [label].concat(results.map(&v))
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,13 @@
1
+ require 'json'
2
+
3
+ module Ec2spec
4
+ module Formatter
5
+ module SlackFormatter
6
+ include Ec2spec::Formatter::PlainTextFormatter
7
+
8
+ def output(results, _hosts)
9
+ "```\n#{super}\n```"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -2,6 +2,7 @@ module Ec2spec
2
2
  class HostResult
3
3
  MONTH_OF_DAYS = 31
4
4
  NA_VALUE = 'N/A'
5
+ NUMBER_OF_DECIMAL_PLACES = 3
5
6
 
6
7
  LABEL_WITH_METHODS = {
7
8
  'instance_type' => :instance_type,
@@ -12,9 +13,18 @@ module Ec2spec
12
13
  'price (USD/M)' => :price_per_month,
13
14
  }
14
15
 
15
- attr_accessor :host, :backend, :instance_id, :cpu
16
+ attr_accessor :host, :backend, :instance_id
16
17
  attr_reader :instance_type
17
- attr_writer :price_per_unit
18
+ attr_writer :price_per_unit, :vcpu
19
+
20
+ def self.label_with_methods
21
+ label_methods = LABEL_WITH_METHODS
22
+ if PriceCalculator.instance.currency_values?
23
+ label_methods['price (%s/H)'] = :price_per_currency_unit
24
+ label_methods['price (%s/M)'] = :price_per_currency_unit_month
25
+ end
26
+ label_methods
27
+ end
18
28
 
19
29
  def initialize(region, host, days = nil)
20
30
  @region = region
@@ -27,7 +37,7 @@ module Ec2spec
27
37
  @instance_type = NA_VALUE
28
38
  @instance_id = NA_VALUE
29
39
  @memory = NA_VALUE
30
- @cpu = NA_VALUE
40
+ @vcpu = NA_VALUE
31
41
  @price_per_unit = NA_VALUE
32
42
  end
33
43
 
@@ -53,11 +63,26 @@ module Ec2spec
53
63
  Ec2spec::OfferFile.instance.price_per_unit(@instance_type)
54
64
  end
55
65
 
66
+ def price_per_currency_unit
67
+ return @price_per_currency_unit unless @price_per_currency_unit.nil?
68
+
69
+ dollar_price = Ec2spec::OfferFile.instance.price_per_unit(@instance_type)
70
+ @price_per_currency_unit = PriceCalculator
71
+ .instance.currency_unit_price(dollar_price)
72
+ @price_per_currency_unit.fractional.floor(NUMBER_OF_DECIMAL_PLACES).to_f
73
+ end
74
+
56
75
  def price_per_month
57
76
  return NA_VALUE if @price_per_unit == NA_VALUE
58
77
  @price_per_unit * 24 * @days
59
78
  end
60
79
 
80
+ def price_per_currency_unit_month
81
+ return NA_VALUE if @price_per_currency_unit == NA_VALUE
82
+ (@price_per_currency_unit * 24 * @days)
83
+ .fractional.floor(NUMBER_OF_DECIMAL_PLACES).to_f
84
+ end
85
+
61
86
  def to_hash
62
87
  host_values
63
88
  end
@@ -65,8 +90,10 @@ module Ec2spec
65
90
  private
66
91
 
67
92
  def host_values
68
- LABEL_WITH_METHODS.each_with_object({}) do |(k, v), hash|
69
- hash[k] = public_send(v)
93
+ self.class.label_with_methods.each_with_object({}) do |(k, v), hash|
94
+ unit = PriceCalculator.instance.currency_unit
95
+ label = format(k, unit)
96
+ hash[label] = public_send(v)
70
97
  end
71
98
  end
72
99
  end
@@ -0,0 +1,21 @@
1
+ require 'singleton'
2
+
3
+ module Ec2spec
4
+ class Initializer
5
+ include Singleton
6
+
7
+ def do(region)
8
+ mkdir_project_dir
9
+ OfferFile.instance.prepare(region)
10
+ end
11
+
12
+ private
13
+
14
+ def mkdir_project_dir
15
+ return if Dir.exist?(Ec2spec.project_dir)
16
+
17
+ Dir.mkdir(Ec2spec.project_dir)
18
+ Ec2spec.logger.debug("Created project dir: #{Ec2spec.project_dir}")
19
+ end
20
+ end
21
+ end
@@ -7,7 +7,6 @@ module Ec2spec
7
7
  REGION_INDEX_FILE_URL = 'https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/AmazonEC2/current/region_index.json'
8
8
 
9
9
  def offer_file_url(region)
10
- mkdir_project_dir
11
10
  offer_index_file_json
12
11
 
13
12
  file_path = @offer_index_file_json['regions'][region]['currentVersionUrl']
@@ -18,21 +17,13 @@ module Ec2spec
18
17
 
19
18
  private
20
19
 
21
- def project_dir
22
- File.join(ENV['HOME'], Const::PROJECT_DIR)
23
- end
24
-
25
- def mkdir_project_dir
26
- Dir.mkdir(project_dir) unless Dir.exist?(project_dir)
27
- end
28
-
29
20
  def region_index_file_path
30
- File.join(project_dir, REGION_INDEX_FILE_URL)
21
+ File.join(Ec2spec.project_dir, REGION_INDEX_FILE_URL)
31
22
  end
32
23
 
33
24
  def offer_index_file_path
34
25
  file_name = File.basename(REGION_INDEX_FILE_URL)
35
- File.join(project_dir, file_name)
26
+ File.join(Ec2spec.project_dir, file_name)
36
27
  end
37
28
 
38
29
  def offer_index_file_json
@@ -1,9 +1,57 @@
1
+ require 'singleton'
2
+ require 'ec2spec/calculator/api_price_calculator'
3
+ require 'ec2spec/calculator/manual_price_calculator'
4
+
1
5
  module Ec2spec
6
+ class UndefinedCalcError < StandardError; end
7
+ class ApiKeyError < StandardError; end
8
+
2
9
  class PriceCalculator
3
- def initialize(instance_type)
4
- @instance_type = instance_type
10
+ include Singleton
11
+
12
+ attr_accessor :currency_unit, :dollar_exchange_rate
13
+
14
+ PRICE_CALCULATORS = {
15
+ manual: Calculator::ManualPriceCalculator,
16
+ api: Calculator::ApiPriceCalculator,
17
+ }
18
+
19
+ def initialize
20
+ @currency_unit = nil
21
+ @dollar_exchange_rate = nil
22
+ @app_id = nil
5
23
  end
6
24
 
7
- def price_per_unit; end
25
+ def prepare(unit, rate, calc_type = :manual, app_id = nil)
26
+ @currency_unit = unit
27
+ @dollar_exchange_rate = rate
28
+ @app_id = app_id
29
+ @calc_type = calc_type
30
+
31
+ extend_calc
32
+
33
+ Money.infinite_precision = true
34
+ raise ApiKeyError if calc_type_sym == :api && app_id.nil?
35
+ prepare_exchange_api(app_id) if calc_type_sym == :api
36
+ self
37
+ end
38
+
39
+ def currency_values?
40
+ !@currency_unit.nil?
41
+ end
42
+
43
+ private
44
+
45
+ def extend_calc
46
+ raise UndefinedCalcError unless PRICE_CALCULATORS.key?(calc_type_sym)
47
+ extend PRICE_CALCULATORS[calc_type_sym]
48
+ Ec2spec.logger.debug("Calculate price: #{@calc_type}")
49
+ end
50
+
51
+ def calc_type_sym
52
+ @calc_type.to_sym
53
+ rescue NoMethodError
54
+ raise UndefinedCalcError
55
+ end
8
56
  end
9
57
  end
@@ -1,3 +1,3 @@
1
1
  module Ec2spec
2
- VERSION = '0.1.2'
2
+ VERSION = '0.1.3'
3
3
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ec2spec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
- - Katsuhiko
8
- - YOSHIDA
7
+ - "\"Katsuhiko"
8
+ - YOSHIDA"
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2018-08-15 00:00:00.000000000 Z
12
+ date: 2018-08-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: faraday
@@ -25,6 +25,34 @@ dependencies:
25
25
  - - ">="
26
26
  - !ruby/object:Gem::Version
27
27
  version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: money
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: money-open-exchange-rates
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
28
56
  - !ruby/object:Gem::Dependency
29
57
  name: specinfra
30
58
  requirement: !ruby/object:Gem::Requirement
@@ -123,7 +151,8 @@ dependencies:
123
151
  - - ">="
124
152
  - !ruby/object:Gem::Version
125
153
  version: '0'
126
- description: Write a longer description or delete this line.
154
+ description: ec2spec is a simple comparison tool for Amazon EC2 Instances you can
155
+ access.
127
156
  email:
128
157
  - claddvd@gmail.com
129
158
  executables:
@@ -148,16 +177,22 @@ files:
148
177
  - exe/ec2spec
149
178
  - exe/setup
150
179
  - lib/ec2spec.rb
180
+ - lib/ec2spec/calculator/api_price_calculator.rb
181
+ - lib/ec2spec/calculator/manual_price_calculator.rb
151
182
  - lib/ec2spec/cli.rb
152
183
  - lib/ec2spec/client.rb
153
184
  - lib/ec2spec/const.rb
154
- - lib/ec2spec/hash_formatter.rb
185
+ - lib/ec2spec/formatter.rb
186
+ - lib/ec2spec/formatter/hash_formatter.rb
187
+ - lib/ec2spec/formatter/json_formatter.rb
188
+ - lib/ec2spec/formatter/markdown_formatter.rb
189
+ - lib/ec2spec/formatter/plain_text_formatter.rb
190
+ - lib/ec2spec/formatter/slack_formatter.rb
155
191
  - lib/ec2spec/host_result.rb
156
- - lib/ec2spec/json_formatter.rb
192
+ - lib/ec2spec/initializer.rb
157
193
  - lib/ec2spec/logger.rb
158
194
  - lib/ec2spec/offer_file.rb
159
195
  - lib/ec2spec/offer_index_file.rb
160
- - lib/ec2spec/plain_text_formatter.rb
161
196
  - lib/ec2spec/price_calculator.rb
162
197
  - lib/ec2spec/version.rb
163
198
  homepage: https://github.com/kyoshidajp/ec2spec
@@ -183,5 +218,5 @@ rubyforge_project:
183
218
  rubygems_version: 2.6.14.1
184
219
  signing_key:
185
220
  specification_version: 4
186
- summary: Write a short summary, because RubyGems requires one.
221
+ summary: ec2spec is a simple comparison tool for Amazon EC2 Instances you can access.
187
222
  test_files: []
@@ -1,11 +0,0 @@
1
- require 'json'
2
-
3
- module Ec2spec
4
- module HashFormatter
5
- def output(results, _hosts)
6
- results.each_with_object({}) do |result, hash|
7
- hash[result.host] = result.to_hash
8
- end
9
- end
10
- end
11
- end
@@ -1,12 +0,0 @@
1
- require 'json'
2
-
3
- module Ec2spec
4
- module JsonFormatter
5
- def output(results, _hosts)
6
- result_hash = results.each_with_object({}) do |result, hash|
7
- hash[result.host] = result.to_hash
8
- end
9
- result_hash.to_json
10
- end
11
- end
12
- end
@@ -1,23 +0,0 @@
1
- module Ec2spec
2
- module PlainTextFormatter
3
- def output(results, hosts)
4
- table = Terminal::Table.new
5
- table.headings = table_header(results)
6
- table.rows = table_rows(results)
7
- column_count = hosts.size + 1
8
- column_count.times { |i| table.align_column(i, :right) }
9
- table
10
- end
11
-
12
- def table_header(results)
13
- [''].concat(results.map(&:host))
14
- end
15
-
16
- def table_rows(results)
17
- Ec2spec::HostResult::LABEL_WITH_METHODS
18
- .each_with_object([]) do |(k, v), row|
19
- row << [k].concat(results.map(&v))
20
- end
21
- end
22
- end
23
- end