kakin 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3bdc1d071c18078ed62113fda208987cb1a00acb
4
+ data.tar.gz: 5fef69e865080c33b8ad4c6acf27719e0f8e5057
5
+ SHA512:
6
+ metadata.gz: fe4b4b84a4b7c3b3659af0a700cf2b1eaeb22fcdab2eb6a3b00cc3f4bba91e0c3c46517b66b0992eab56394608aac9806540756754d96e2d06bc998bee6923f4
7
+ data.tar.gz: 81c4ed52991a268bee1079e648c17c1ad49969189f42688d8a124a448873685bdbed1fcdb2c659c59a6151a9a83f4462d967c60edeef889b6e0436c24f708a62
@@ -0,0 +1,28 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+
12
+ ## Documentation cache and generated files:
13
+ /.yardoc/
14
+ /_yardoc/
15
+ /doc/
16
+ /rdoc/
17
+
18
+ ## Environment normalisation:
19
+ /.bundle/
20
+ /vendor/bundle
21
+ /lib/bundler/man/
22
+
23
+ .ruby-version
24
+ .ruby-gemset
25
+ .rvmrc
26
+
27
+ /cost.yaml
28
+ /Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 buty4649
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
@@ -0,0 +1,25 @@
1
+ # kakin
2
+ OpenStackのリソース使用料金按分ツール
3
+
4
+ ## Usage
5
+
6
+ ```
7
+ $ mv cost.yaml.sample cost.yaml
8
+ $ vi cost.yaml
9
+ ```
10
+
11
+ You need to create configuration file located `~/.kakin` for openstack credential like this.
12
+
13
+ ```
14
+ auth_url: "http://your-openstack-host:35357/v2.0/tokens"
15
+ management_url: "http://your-openstack-host:8774/v2"
16
+ username: "username"
17
+ tenant: "your-admin-tenant"
18
+ password: "password"
19
+ ```
20
+
21
+ You can get resource usage with following command.
22
+
23
+ ```
24
+ $ kakin -f cost.yaml
25
+ ```
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "kakin"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,5 @@
1
+ vcpu_per_hour: 1
2
+ memory_mb_per_hour: 0.0009765625
3
+ disk_gb_per_hour: 1
4
+ cost_per_ip: 1
5
+ ip_regexp: ^192.128
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $: << File.expand_path("#{File.dirname __FILE__}/../lib")
4
+ require 'rubygems'
5
+ require 'kakin'
6
+
7
+ Kakin::CLI.start
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'kakin/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "kakin"
8
+ spec.version = Kakin::VERSION
9
+ spec.authors = ["buty4649", "SHIBATA Hiroshi"]
10
+ spec.email = ["", "hsbt@ruby-lang.org"]
11
+
12
+ spec.summary = %q{kakin is resource calcuration tool for OpenStack}
13
+ spec.description = %q{kakin is resource calcuration tool for OpenStack}
14
+ spec.homepage = "https://github.com/yaocloud/kakin"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.bindir = "exe"
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency 'thor'
22
+ spec.add_dependency 'yao', '~> 0.2.13'
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.10"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "minitest"
27
+ end
@@ -0,0 +1,6 @@
1
+ require 'kakin/version'
2
+ require 'kakin/cli'
3
+ require 'kakin/configuration'
4
+
5
+ module Kakin
6
+ end
@@ -0,0 +1,141 @@
1
+ require 'date'
2
+ require 'yaml'
3
+ require 'json'
4
+ require 'net/http'
5
+ require 'yao'
6
+ require 'kakin/yao_ext/tenant'
7
+ require 'kakin/yao_ext/server'
8
+ require 'thor'
9
+
10
+ module Kakin
11
+ class CLI <Thor
12
+ default_command :calc
13
+
14
+ option :f, type: :string, banner: "<file>", desc: "cost define file(yaml)", required: true
15
+ option :s, type: :string, banner: "<start>", desc: "start time", default: (DateTime.now << 1).strftime("%Y-%m-01")
16
+ option :e, type: :string, banner: "<end>", desc: "end time", default: Time.now.strftime("%Y-%m-01")
17
+ option :t, type: :string, banner: "<tenant>", desc: "specify tenant", default: ""
18
+ desc 'calc', 'Calculate the cost'
19
+ def calc
20
+ Kakin::Configuration.setup
21
+
22
+ yaml = YAML.load_file(options[:f])
23
+ start_time = Time.parse(options[:s]).strftime("%FT%T")
24
+ end_time = Time.parse(options[:e]).strftime("%FT%T")
25
+
26
+ STDERR.puts "Start: #{start_time}"
27
+ STDERR.puts "End: #{end_time}"
28
+ url = URI.parse("#{Kakin::Configuration.management_url}/#{Yao::Tenant.get_by_name(Kakin::Configuration.tenant).id}/os-simple-tenant-usage?start=#{start_time}&end=#{end_time}")
29
+ req = Net::HTTP::Get.new(url)
30
+ req["Accept"] = "application/json"
31
+ req["X-Auth-Token"] = Yao::Auth.try_new.token
32
+ res = Net::HTTP.start(url.host, url.port) {|http|
33
+ http.request(req)
34
+ }
35
+
36
+ if res.code != "200"
37
+ raise "usage data fatch is failed"
38
+ else
39
+ result = Hash.new
40
+ tenant_usages = JSON.load(res.body)["tenant_usages"]
41
+ tenants = Yao::Tenant.list
42
+
43
+ unless options[:t].empty?
44
+ tenant = tenants.find { |tenant| tenant.name == options[:t] }
45
+ raise "Not Found tenant #{options[:t]}" unless tenant
46
+
47
+ tenant_usages = tenant_usages.select { |tenant_usage| tenant_usage["tenant_id"] == tenant.id }
48
+ end
49
+
50
+ tenant_usages.each do |usage|
51
+ tenant = tenants.find { |tenant| tenant.id == usage["tenant_id"] }
52
+
53
+ total_vcpus_usage = usage["total_vcpus_usage"]
54
+ total_memory_mb_usage = usage["total_memory_mb_usage"]
55
+ total_local_gb_usage = usage["total_local_gb_usage"]
56
+
57
+ bill_vcpu = total_vcpus_usage * yaml["vcpu_per_hour"]
58
+ bill_memory = total_memory_mb_usage * yaml["memory_mb_per_hour"]
59
+ bill_disk = total_local_gb_usage * yaml["disk_gb_per_hour"]
60
+
61
+ result[tenant.name] = {
62
+ 'bill_total' => bill_vcpu + bill_memory + bill_disk,
63
+ 'bill_vcpu' => bill_vcpu,
64
+ 'bill_memory' => bill_memory,
65
+ 'bill_disk' => bill_disk,
66
+ 'total_hours' => usage["total_hours"],
67
+ 'total_vcpus_usage' => total_vcpus_usage,
68
+ 'total_memory_mb_usage' => total_memory_mb_usage,
69
+ 'total_local_gb_usage' => total_local_gb_usage,
70
+ }
71
+ end
72
+
73
+ puts YAML.dump(result)
74
+ end
75
+ end
76
+
77
+ option :f, type: :string, banner: "<file>", desc: "cost define file(yaml)", required: true
78
+ option :s, type: :string, banner: "<start>", desc: "start time", default: (DateTime.now << 1).strftime("%Y-%m-01")
79
+ option :e, type: :string, banner: "<end>", desc: "end time", default: Time.now.strftime("%Y-%m-01")
80
+ option :t, type: :string, banner: "<tenant>", desc: "specify tenant", default: ""
81
+ desc 'network', 'network resource'
82
+ def network
83
+ Kakin::Configuration.setup
84
+
85
+ yaml = YAML.load_file(options[:f])
86
+ start_time = Time.parse(options[:s])
87
+ end_time = Time.parse(options[:e])
88
+
89
+ STDERR.puts "Start: #{start_time}"
90
+ STDERR.puts "End: #{end_time}"
91
+
92
+ result = Hash.new
93
+ tenants = unless options[:t].empty?
94
+ Yao::Tenant.list(name: options[:t])
95
+ else
96
+ Yao::Tenant.list
97
+ end
98
+ tenants = [tenants] unless tenants.is_a?(Array)
99
+
100
+ tenants.each do |tenant|
101
+ incoming = tenant.network_usage(Regexp.new(yaml["ip_regexp"]), :incoming, start_time.iso8601, end_time.iso8601)
102
+ outgoing = tenant.network_usage(Regexp.new(yaml["ip_regexp"]), :outgoing, start_time.iso8601, end_time.iso8601)
103
+ result[tenant.name] = {
104
+ 'incoming_usage' => incoming,
105
+ 'outgoing_usage' => outgoing,
106
+ 'total_usage' => incoming + outgoing
107
+ }
108
+ end
109
+
110
+ puts YAML.dump(result)
111
+ end
112
+
113
+ option :f, type: :string, banner: "<file>", desc: "cost define file(yaml)", required: true
114
+ option :t, type: :string, banner: "<tenant>", desc: "specify tenant", default: ""
115
+ desc 'ip', 'ip use count'
116
+ def ip
117
+ Kakin::Configuration.setup
118
+
119
+ yaml = YAML.load_file(options[:f])
120
+ ip_regexp = Regexp.new(yaml["ip_regexp"])
121
+
122
+ result = Hash.new
123
+ tenants = unless options[:t].empty?
124
+ Yao::Tenant.list(name: options[:t])
125
+ else
126
+ Yao::Tenant.list
127
+ end
128
+ tenants = [tenants] unless tenants.is_a?(Array)
129
+
130
+ tenants.each do |tenant|
131
+ count = tenant.ports.select {|p| p.fixed_ips[0]["ip_address"] =~ ip_regexp}.count
132
+ result[tenant.name] = {
133
+ 'count' => count,
134
+ 'total_usage' => count * yaml["cost_per_ip"],
135
+ }
136
+ end
137
+
138
+ puts YAML.dump(result)
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,27 @@
1
+ module Kakin
2
+ class Configuration
3
+
4
+ def self.management_url
5
+ @@_management_url
6
+ end
7
+
8
+ def self.tenant
9
+ @@_tenant
10
+ end
11
+
12
+ def self.setup
13
+ yaml = YAML.load_file(File.expand_path('~/.kakin'))
14
+
15
+ @@_management_url = yaml['management_url']
16
+ @@_tenant = yaml['tenant']
17
+
18
+ Yao.configure do
19
+ auth_url yaml['auth_url']
20
+ tenant_name yaml['tenant']
21
+ username yaml['username']
22
+ password yaml['password']
23
+ timeout yaml['timeout'] if yaml['timeout']
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,3 @@
1
+ module Kakin
2
+ VERSION = "0.0.3"
3
+ end
@@ -0,0 +1,10 @@
1
+ require 'yao/resources/server'
2
+
3
+ module Yao::Resources
4
+ class Server < Base
5
+ def mac_address(ip_regexp)
6
+ port = addresses.select{|_, v| v[0]["addr"] =~ ip_regexp}
7
+ port.empty? ? nil : port.values[0][0]["OS-EXT-IPS-MAC:mac_addr"]
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,35 @@
1
+ require 'yao/resources/tenant'
2
+
3
+ module Yao::Resources
4
+ class Tenant < Base
5
+ def network_usage(ip_regexp, type, start_time, end_time)
6
+ servers.inject(0) do |t, server|
7
+ samples = server.old_samples(counter_name: "network.#{type}.bytes", query: {'q.field': 'timestamp', 'q.op': 'gt', 'q.value': start_time})
8
+ if samples.empty?
9
+ t
10
+ else
11
+ wan_samples = samples.select{|s| s.resource_metadata["mac"] == server.mac_address(ip_regexp) }.sort_by(&:timestamp)
12
+ if wan_samples.empty? || (wan_samples.size == 1)
13
+ t
14
+ else
15
+ last_sample_index = wan_samples.find_index{|s| s.timestamp > Time.parse(end_time) }
16
+ last_sample = if last_sample_index
17
+ wan_samples[last_sample_index]
18
+ else
19
+ wan_samples[-1]
20
+ end
21
+ transferred_bits = last_sample.counter_volume - wan_samples[0].counter_volume
22
+ period = (last_sample.timestamp - wan_samples[0].timestamp).to_i
23
+ # ignored negative number or zero period. Thease are unexpected data.
24
+ # We need to investigate why generate these counter.
25
+ if transferred_bits < 0 || period.zero?
26
+ t
27
+ else
28
+ t + transferred_bits / period
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
metadata ADDED
@@ -0,0 +1,132 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kakin
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - buty4649
8
+ - SHIBATA Hiroshi
9
+ autorequire:
10
+ bindir: exe
11
+ cert_chain: []
12
+ date: 2017-01-20 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: thor
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: yao
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: 0.2.13
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: 0.2.13
42
+ - !ruby/object:Gem::Dependency
43
+ name: bundler
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '1.10'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '1.10'
56
+ - !ruby/object:Gem::Dependency
57
+ name: rake
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '10.0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '10.0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: minitest
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ description: kakin is resource calcuration tool for OpenStack
85
+ email:
86
+ - ''
87
+ - hsbt@ruby-lang.org
88
+ executables:
89
+ - kakin
90
+ extensions: []
91
+ extra_rdoc_files: []
92
+ files:
93
+ - ".gitignore"
94
+ - Gemfile
95
+ - LICENSE
96
+ - README.md
97
+ - Rakefile
98
+ - bin/console
99
+ - bin/setup
100
+ - cost.yaml.sample
101
+ - exe/kakin
102
+ - kakin.gemspec
103
+ - lib/kakin.rb
104
+ - lib/kakin/cli.rb
105
+ - lib/kakin/configuration.rb
106
+ - lib/kakin/version.rb
107
+ - lib/kakin/yao_ext/server.rb
108
+ - lib/kakin/yao_ext/tenant.rb
109
+ homepage: https://github.com/yaocloud/kakin
110
+ licenses: []
111
+ metadata: {}
112
+ post_install_message:
113
+ rdoc_options: []
114
+ require_paths:
115
+ - lib
116
+ required_ruby_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - ">="
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ required_rubygems_version: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ requirements: []
127
+ rubyforge_project:
128
+ rubygems_version: 2.6.8
129
+ signing_key:
130
+ specification_version: 4
131
+ summary: kakin is resource calcuration tool for OpenStack
132
+ test_files: []