Skip to content
This repository has been archived by the owner on Nov 16, 2023. It is now read-only.

New easy-customisable Showback engine #44

Merged
merged 87 commits into from
Jan 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
f364294
snapshots record class
slntopp Dec 2, 2020
c49cc17
deprecated
slntopp Dec 2, 2020
52adc82
deprecated
slntopp Dec 2, 2020
6ac689a
deprecated
slntopp Dec 2, 2020
de57dcf
deprecated
slntopp Dec 2, 2020
e44616b
deprecated
slntopp Dec 2, 2020
fbd628c
Records Source Base
slntopp Dec 2, 2020
4559081
timeline filter method
slntopp Dec 2, 2020
c137166
different snapshot records scheme
slntopp Dec 2, 2020
69b0174
correct key management
slntopp Dec 4, 2020
629854f
sortable method
slntopp Dec 4, 2020
0ecb008
sorter method
slntopp Dec 4, 2020
760d6c3
Timeline base class
slntopp Dec 4, 2020
d2c3f5b
sync
slntopp Dec 4, 2020
2340168
vm instead of vm.id and personal sources
slntopp Dec 4, 2020
36e9ff3
docs and deprecated var
slntopp Dec 4, 2020
2ff5230
Biller base class
slntopp Dec 4, 2020
f69a28b
moving billing to Billing class
slntopp Dec 4, 2020
9c3e302
comm
slntopp Dec 4, 2020
6c20a40
including showback
slntopp Dec 4, 2020
ca0e457
capacity biller base
slntopp Dec 4, 2020
50d90b6
comm
slntopp Dec 4, 2020
11bed43
comm
slntopp Dec 4, 2020
1f9977c
DiskBiller base
slntopp Dec 4, 2020
5249789
source init_state method
slntopp Dec 4, 2020
b56dd2d
rudimentaar
slntopp Dec 4, 2020
b1821f0
kiss find method
slntopp Dec 4, 2020
8aa7015
SnapshotRecordsSource init_state
slntopp Dec 4, 2020
20493f5
init method for collecting initial vm state
slntopp Dec 4, 2020
d7616c4
initiate timeline on billing
slntopp Dec 4, 2020
b20ab42
sorter alias
slntopp Dec 4, 2020
a032551
Using new showback engine
slntopp Dec 15, 2020
a10c2a9
store capacity cost on check
slntopp Dec 15, 2020
6923200
bill method for Biller
slntopp Dec 15, 2020
7082932
modify state method for Records
slntopp Dec 15, 2020
2eb94f1
corr attr
slntopp Dec 15, 2020
4e750b2
make_bill method
slntopp Dec 15, 2020
a8426d0
recept method
slntopp Dec 15, 2020
82cab2f
bill total method
slntopp Dec 15, 2020
550a6b6
bill reader
slntopp Dec 15, 2020
a3b833c
edge records
slntopp Dec 15, 2020
5f09022
showback test env base
slntopp Dec 15, 2020
fde6b2a
disk biller v0
slntopp Dec 15, 2020
1b1a673
disk biller fin
slntopp Dec 15, 2020
8ae50bd
ptch
slntopp Dec 15, 2020
059fae5
int -> float
slntopp Dec 17, 2020
88cfdac
traffic base
slntopp Dec 17, 2020
94c420d
snapshots biller beta
slntopp Dec 17, 2020
7e965be
traffic_records table
slntopp Dec 23, 2020
21ce3fa
traffic recorder cron script
slntopp Dec 23, 2020
5c52809
traffic recorder script logs
slntopp Dec 23, 2020
7b0c8bf
traffic recorder conf
slntopp Dec 23, 2020
60fdc83
traffic recorder table alter
slntopp Dec 23, 2020
dcdd283
move records and detach traffic records and recordssource
slntopp Dec 25, 2020
96a0945
defuq
slntopp Dec 25, 2020
c1026a3
use records
slntopp Dec 25, 2020
ccc56d0
following updates in traffic records schema
slntopp Dec 25, 2020
a3efc28
sync traffic records from monitoring on initialize
slntopp Dec 28, 2020
8f2bde0
calculate showback method test
slntopp Dec 28, 2020
d7cd70f
wrong key fix
slntopp Dec 28, 2020
42576ad
bill if state on or not PAYG
slntopp Dec 28, 2020
2e3b81b
billing_period method for Biller
slntopp Dec 28, 2020
aea387c
IONe Showback notes
slntopp Dec 28, 2020
4fcf627
h8 brckts
slntopp Dec 28, 2020
9420de5
billing period PRE PAID
slntopp Dec 28, 2020
bb2c64b
ah?
slntopp Jan 4, 2021
2c96453
new model and zero record hook
slntopp Jan 4, 2021
10d3d93
new traffic records synchroniser method
slntopp Jan 4, 2021
ef7577f
sorter and modificator
slntopp Jan 4, 2021
210019e
TrafficRecords source find method
slntopp Jan 5, 2021
516c8f5
traffic init_state
slntopp Jan 5, 2021
6ba612f
ints are better, right?
slntopp Jan 5, 2021
0ad3d96
TRAFFIC_COST to settings table
slntopp Jan 5, 2021
76c36b3
i didn't mean it
slntopp Jan 5, 2021
09f8dcb
hyper important alias
slntopp Jan 5, 2021
0237165
ints are always better
slntopp Jan 5, 2021
6457011
quite new params form for bill method
slntopp Jan 5, 2021
4a1d47f
check_biller with teaser
slntopp Jan 5, 2021
9cf830b
TrafficBiller bill method
slntopp Jan 5, 2021
9ee62d6
Using new bill method params
slntopp Jan 5, 2021
545b6ee
Using TrafficBiller in Billing class
slntopp Jan 5, 2021
19a7833
we have floats here
slntopp Jan 5, 2021
6cb5537
VM drives method
slntopp Jan 5, 2021
ad084a1
correct drives billing
slntopp Jan 5, 2021
4913d74
Traffic cost with description in default settings
slntopp Jan 5, 2021
7abc18a
Snapshot cost in default settings
slntopp Jan 5, 2021
9057d42
costs descriptions
slntopp Jan 5, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions docs/Showback.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Notes about configuring VM Showback

## BILLING_PERIOD

Each and every VM should have BILLING_PERIOD defined in template.
Possible values are:
- PAYG - VM will be billed per second
- PRE_<% n_days %> - Pre-Paid per N days, e.g. `PRE_30`, then full Capacity and Disk cost will be charged on deploy, and then every 30 days.
43 changes: 43 additions & 0 deletions hooks/insert_zero_traffic_record.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env ruby
# -------------------------------------------------------------------------- #
# Copyright 2020, IONe Cloud Project, Support.by #
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
# not use this file except in compliance with the License. You may obtain #
# a copy of the License at #
# #
# http://www.apache.org/licenses/LICENSE-2.0 #
# #
# Unless required by applicable law or agreed to in writing, software #
# distributed under the License is distributed on an "AS IS" BASIS, #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
# See the License for the specific language governing permissions and #
# limitations under the License. #
# -------------------------------------------------------------------------- #

require 'base64'
require 'nokogiri'

xml = Nokogiri::XML(Base64::decode64(ARGV.first))
unless xml.xpath("/CALL_INFO/RESULT").text.to_i == 1 then
puts "VM wasn't allocated, skipping"
exit 0
end

vmid = xml.xpath('//EXTRA/VM')

require 'yaml'
require 'json'
require 'sequel'

$ione_conf = YAML.load_file("/etc/one/ione.conf") # IONe configuration constants

require $ione_conf['DB']['adapter']
$db = Sequel.connect({
adapter: $ione_conf['DB']['adapter'].to_sym,
user: $ione_conf['DB']['user'], password: $ione_conf['DB']['pass'],
database: $ione_conf['DB']['database'], host: $ione_conf['DB']['host'] })

$db[:traffic_records].insert(
vm: vmid, rx: "0", tx: "0", rx_last: "0", tx_last: "0", stime: Time.now.to_i
)
2 changes: 2 additions & 0 deletions ione_server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ class Settings < Sequel::Model(:settings); end
puts 'Including on_helper funcs'
require "#{ROOT}/service/on_helper.rb"
include ONeHelper
puts 'Including showback'
require "#{ROOT}/service/showback.rb"
puts 'Including Deferable module'
require "#{ROOT}/service/defer.rb"

Expand Down
10 changes: 6 additions & 4 deletions models/SettingsDriver.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@

required = [
['ALERT', "0.0", "Balance, when user will be alerted", 0, "num"],
['CAPACITY_COST', "{\"CPU_COST\":\"0.0\",\"MEMORY_COST\":\"0.0\"}", "VM Capacity resources costs", 1, "object"],
['CAPACITY_COST', "{\"CPU_COST\":\"0.0\",\"MEMORY_COST\":\"0.0\"}", "VM Capacity resources costs per sec", 1, "object"],
['DISK_TYPES', "HDD,SSD,NVMe", "Comma-separated list of existing disk types", 1, "list"],
['DISK_COSTS', "{\"disk_type\":\"price\"}", "Costs of different disk types", 1, "object"],
['DISK_COSTS', "{\"disk_type\":\"price\"}", "Costs of different disk types GB/sec", 1, "object"],
['IAAS_GROUP_ID', 'iaas_group_id', "IaaS(VDC) Users group ID", 1, "num"],
['NODES_DEFAULT', "{\"hypervisor_name\":\"host_id\"}", "Default nodes for different hypervisors", 1, "object"],
['PUBLIC_IP_COST', "0.0", "Public IP Address cost", 0, "num"],
['PUBLIC_IP_COST', "0.0", "Public IP Address cost per sec", 0, "num"],
['PUBLIC_NETWORK_DEFAULTS', "{\"NETWORK_ID\":\"network_id\"}", "Default Public Network Pool ID", 1, "object"],
['PRIVATE_NETWORK_DEFAULTS', "{\"NETWORK_ID\":\"network_id\"}", "Default Private Network Pool ID", 1, "object"],
['CURRENCY_MAIN', "€", "Currency", 0, "str"]
['CURRENCY_MAIN', "€", "Currency", 0, "str"],
['TRAFFIC_COST', "0.0", "Cost per 1 kByte traffic", 1, "num"],
['SNAPSHOT_COST', "0.0", "Cost 1 Snapshot per sec", 1, "num"]
]
required.each do | record |
$db[:settings].insert(name: record[0], body: record[1], description: record[2], access_level: record[3], type: record[4])
Expand Down
7 changes: 7 additions & 0 deletions rake/set_hooks.rake
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ require 'opennebula'
"COMMAND" => '/usr/lib/one/ione/hooks/set_price.rb',
"ARGUMENTS" => '$API'
},
{
"NAME" => 'insert-zero-traffic-record',
"TYPE" => 'api',
"CALL" => 'one.vm.allocate',
"COMMAND" => '/usr/lib/one/ione/hooks/insert_zero_traffic_record.rb',
"ARGUMENTS" => '$API'
},
{
"NAME" => 'pending',
"ON" => "CUSTOM",
Expand Down
17 changes: 17 additions & 0 deletions rake/tests/Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
task :before_test do
require '/usr/lib/one/ione/ione_server.rb'
end

def passed
puts "--- " + "Passed".green
end
def fail msg
puts msg.red
exit
end
def warn msg
puts msg.yellow
end

load "rake/tests/showback.rake"

68 changes: 68 additions & 0 deletions rake/tests/showback.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
desc "Test Capacity Showback"
task :cap_showback_test => :before_test do
puts "\n####################\n# Testing capacity #\n####################"

$db[:settings].where(name: "CAPACITY_COST").update(body: "{\"CPU_COST\":\"0.5\",\"MEMORY_COST\":\"0.5\"}")
$db[:settings].where(name: "DISK_COSTS").update(body: "{\"HDD\":\"0.0\"}")

r = onblock(:vm, 3).calculate_showback 0, 1200
if r[:TOTAL] == 600 then
passed
else
warn "#{0}, #{1200} => #{r[:TOTAL]}"
end
r = onblock(:vm, 3).calculate_showback 300, 1200
if r[:TOTAL] == 300 then
passed
else
warn "#{300}, #{1200} => #{r[:TOTAL]}"
end
r = onblock(:vm, 3).calculate_showback 300, 500
if r[:TOTAL] == 200 then
passed
else
warn "#{300}, #{500} => #{r[:TOTAL]}"
end
r = onblock(:vm, 3).calculate_showback 300, 1400
if r[:TOTAL] == 500 then
passed
else
warn "#{300}, #{1400} => #{r[:TOTAL]}"
end
end

desc "Test Disk Showback"
task :disk_showback_test => :before_test do
puts "\n################\n# Testing Disk #\n################"

$db[:settings].where(name: "CAPACITY_COST").update(body: "{\"CPU_COST\":\"0.0\",\"MEMORY_COST\":\"0.0\"}")
$db[:settings].where(name: "DISK_COSTS").update(body: "{\"HDD\":\"1\"}")

r = onblock(:vm, 3).calculate_showback 0, 1200
if r[:TOTAL] == 1200 then
passed
else
warn "#{0}, #{1200} => #{r[:TOTAL]}"
end
r = onblock(:vm, 3).calculate_showback 300, 1200
if r[:TOTAL] == 900 then
passed
else
warn "#{300}, #{1200} => #{r[:TOTAL]}"
end
r = onblock(:vm, 3).calculate_showback 300, 500
if r[:TOTAL] == 200 then
passed
else
warn "#{300}, #{500} => #{r[:TOTAL]}"
end
r = onblock(:vm, 3).calculate_showback 300, 1400
if r[:TOTAL] == 1100 then
passed
else
warn "#{300}, #{1400} => #{r[:TOTAL]}"
end
end

desc "Showback Tests"
task :showback_test => [:cap_showback_test, :disk_showback_test] do; end
24 changes: 24 additions & 0 deletions scripts/traffic-recorder/main.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
begin
LOG 'Traffic Recorder has been initialized', 'TrafficRecorder'
loop do
begin
vm_pool = VirtualMachinePool.new($client)
vm_pool.info_all
inserts_total = 0

vm_pool.each do | vm |
inserts = TrafficRecords.new(vm.id, true).sync vm
LOG "VM #{vm.id}: Inserted #{inserts} new traffic records", "TrafficRecorder"
inserts_total += inserts
end

LOG "TrafficRecorder inserted totally #{inserts_total} new traffic records", 'TrafficRecorder'
sleep($ione_conf['TrafficRecorder']['check-period'])
rescue => e
LOG "TrafficRecorder Error, code: #{e.message}\nTrafficRecorder is down now", 'TrafficRecorder'
sleep(30)
end
end
rescue
LOG "TrafficRecorder fatal error, service is crashed", 'TrafficRecorderThread'
end
26 changes: 26 additions & 0 deletions service/biller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
class Biller

def initialize vm
@vm = vm
end

# Costs hash
def costs
SETTINGS_TABLE.as_hash(:name, :body).select {|key| key.include? 'COST' }
end

# Check if this biller should be used in Billing
def check_biller
true
end

def billing_period
@vm['//BILLING_PERIOD']
end

def bill bill:, state:, delta:, record: nil
0
end
end

Dir["#{ROOT}/service/billers/*.rb"].each {|file| require file }
24 changes: 24 additions & 0 deletions service/billers/capacity.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
class CapacityBiller < Biller
# Checking if Capacity costs are given, otherwise there is no point to calculate it
def check_biller
@costs = JSON.parse(costs['CAPACITY_COST'])
return false if @costs.nil?

@cost =
@costs.values.inject(0) do | r, c |
r += c.to_f
rescue
r
end
return @cost > 0
rescue
return false
end

def bill bill:, state:, delta:, record: nil
if state[:state] == 'on' || billing_period != 'PAYG' then
bill[:capacity] = delta * @cost
end
bill
end
end
26 changes: 26 additions & 0 deletions service/billers/disk.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
class DiskBiller < Biller
# Checking if Capacity costs are given, otherwise there is no point to calculate it
def check_biller
@costs = JSON.parse(costs['DISK_COSTS'])
return false if @costs.nil?

r =
@costs.values.inject(0) do | r, c |
r += c.to_f
rescue
r
end
return false if r <= 0

@cost = @costs[@vm['/VM/USER_TEMPLATE/DRIVE']].to_f
@size = vm.drives.inject(0) { | r, d | r += d['SIZE'].to_i } / 1000.0
return @cost > 0
rescue
return false
end

def bill bill:, state:, delta:, record: nil
bill[:disk] = delta * @cost * @size
bill
end
end
16 changes: 16 additions & 0 deletions service/billers/snapshots.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
class SnapshotsBiller < Biller
def check_biller
@cost = JSON.parse(costs['SNAPSHOT_COST'])
return false if @cost.nil?

@cost = @cost.to_f
return @cost > 0
rescue
return false
end

def bill bill:, state:, delta:, record: nil
bill[:snapshots] = delta * @cost * state[:snaps]
bill
end
end
25 changes: 25 additions & 0 deletions service/billers/traffic.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
class TrafficBiller < Biller
def check_biller
@cost = JSON.parse(costs['TRAFFIC_COST'])
return false if @cost.nil?

@cost = @cost.to_f
@costs = { rx: @cost, tx: @cost } # Will Add support for differnt rx and tx prices

return @costs.values.inject(0) do | r, c |
r += c.to_f
rescue
r
end > 0
rescue
return false
end

def bill bill:, state:, delta:, record:
if record.class == TrafficRecord then
bill[:rx] = state[:rx] / 1000.0 * @costs[:rx]
bill[:tx] = state[:tx] / 1000.0 * @costs[:tx]
end
bill
end
end
44 changes: 0 additions & 44 deletions service/handlers/cache_handler.rb

This file was deleted.

Loading