The following is a partial list of the default billing methods supplied with Flexiant Cloud Orchestrator. This should serve as a useful starting point for writing your own billing methods.
-- This will be the default billing supplied by the Extility code --[[ Please read the following instructions carefully. The Lua FDL code below is meant to run within Jade. Executing this script separately will not work. If you want to log data please use the "logger(String)" function; this will write your log data into the standard Jade log. If you use the default Lua "print", this will write the log data into the Jade .sysout log. The entry point to the Lua script will be the register() function. This returns a list of exported entry points, each of which is associated with an API. All the examples in this file are for the billing API. Each entry point is first called with no parameters, which gives the entry point the chance to describe itself. This works as follows: local confvalues = { -- List of configured values { key = "key_for_configured_value", name = "name for configured value" description = "long description of configured value", measureType = "UNIT", validator = {validatorType = "NUMERIC_DOUBLE"} } } return { -- Unique reference ref = "_serverAllocatedCPUBilling", -- billingFuncName: name of an alternate method to call or nil (or omit) to use this function billingFuncName = nil -- Description of billing method description = "Long description of billing method", -- List of permitted PCTs permittedPCT = {"PCT-SERVER-CPU"}, -- Configured Values configuredValues = confvalues, -- API type api="BILLING", -- API version version = 1 } ]] -- ///////////////////////////////// Global Helper Functions ///////////////////////////////////////d function getRepeatUnits(billingcomp) local val = billingcomp:getBillingValue("repeat_units") if (val) then local units_str = val:getValue() if (units_str) then return tonumber(units_str) end end return nil end function getInitialUnits(billingcomp) local val = billingcomp:getBillingValue("initial_units") if (val) then local units_str = val:getValue() if (units_str) then return tonumber(units_str) end end return nil end -- This will return the allocated size and the type it is measured with function getConfiguredMeasureTypeValue(billingComp, key) local val = billingComp:getProductValue(key) if (val) then local size = val:getValue() local mtype = (val:getMeasureType()):toString() return mtype, size end return nil, nil end function getRepeatUnitsDefinitionTable() return { key = "repeat_units", name = "Repeat Units", description = "Number of units that will be charged or allocate on each subsequent billing cycle after the purchase", measureType = "UNIT", validator = {validatorType = "NUMERIC_DOUBLE"} } end function getInitialUnitsDefinitionTable() return { key = "initial_units", name = "Initial Units", measureType = "UNIT", validator = {validatorType = "NUMERIC_DOUBLE"}, description = "Number of units that will be charged or allocated on the first billing cycle after the purchase" } end function getChargeMeasureTypeDefinition_table(addInitialUnits, addRepeatUnits) local confValues = { { key = "charge_measurement_type", name = "Measurement Type", description = "Measurement type corresponding to the charge; the charge will be applied per byte, kilobyte, megabyte, gigabyte or terabyte according to this setting", validator = {validatorType = "ENUM", validateString = "B,KB,MB,GB,TB"}, measureType = "NUMERIC" } } if (addInitialUnits) then table.insert(confValues, getInitialUnitsDefinitionTable()) end if (addRepeatUnits) then table.insert(confValues, getRepeatUnitsDefinitionTable()) end return confValues end function getChargeMeasureTypeRepeatUnits(billingComp) local measureType = (billingComp:getBillingValue("charge_measurement_type")):getValue() local repeatUnits = getRepeatUnits(billingComp); return measureType, repeatUnits end function getChargeMeasureTypeInitialUnits(billingComp) local measureType = (billingComp:getBillingValue("charge_measurement_type")):getValue() local initalUnits = getInitialUnits(billingComp); return measureType, initalUnits end function getMeasureTypeMeasuredValue(measuredComp, key) local val = measuredComp:getMeasuredValue(key) if (val) then local mtype = (val:getMeasureType()):toString() local mval = val:getValue() return mtype, mval end return nil, nil end -- //////////////////////////////// End of global Helper Function //////////////////////////////////////// -- ************************************ FIXED MODE BILLING ***************************** -- This is the most simplistic billing function this charge a fixed amount each time -- invoked, this can be used with any PCT function fixedResourceBilling(p) if (p == nil) then -- define the which is needs to be configurable params local confvalues = {getInitialUnitsDefinitionTable(), getRepeatUnitsDefinitionTable()} return { ref = "_fixedResourceBilling", name = "Fixed billing for resources", description = "Charge the same number of units in each billing period", permittedPCT = nil, configuredValues = confvalues, api = "BILLING", version = 1 } end --print ("Last Billing Time is : " .. p.lastBillingTime .. " Current Billing Time ".. p.currentBillingTime .." Billing Factor is "..p.billingFactor) if (p.lastBillingTime == p.currentBillingTime) then cunits = getInitialUnits(p.billingComp) if (cunits > 0.0) then --print("Initial charge -"..cunits); return {{units = cunits * -1, description="Initial charge"}} end else cunits = getRepeatUnits(p.billingComp) if (cunits > 0.0) then return {{units = cunits * -1 * p.billingFactor , description = "Charge for period" }} end end return nil end -- ************************************* END OF FIXED MODE BILLING *************************************** -- ************************************ ALLOCATION BASED BILLING ***************************************** function serverBilling(p) local measureType, chargeUnits = getChargeMeasureTypeRepeatUnits(p.billingComp) local only_when_running = (p.billingComp:getBillingValue("only_when_running")):getValue() local chargeUnits = getRepeatUnits(p.billingComp) local doCharge = true -- If the only_when_running billing parameter is set we will only be charging if the server was running at the give time if (only_when_running == "TRUE") then -- print ("Looking for maximum running value between ".. p.lastBillingTime .. " and " .. p.currentBillingTime) local measuredHash = p.measureComp:getMAXMeasureBetween(p.lastBillingTime, p.currentBillingTime, "running") local uptime = measuredHash:get("running") if ((uptime == nil) or (uptime:getMeasurement() <= 0)) then doCharge = false end end if (doCharge) then if ((chargeUnits ~= nil) and (chargeUnits > 0.0)) then if (measureType == "CPU_CORE") then local val = p.billingComp:getProductValue("cpu") if (val) then local cores = tonumber(val:getValue()) return {{ units = (cores * chargeUnits * -1 * p.billingFactor), description = "Charge for " .. cores .." CPU cores" }} end else local configMtype, configSize = getConfiguredMeasureTypeValue(p.billingComp, "ram") if (configSize) then return {{ units = p.billingFactor * -1 * chargeUnits * tonumber(configSize) * (convert_mtype(configMtype, measureType)), description = "Charge for " .. configSize .. configMtype }} end end end end return nil end -- This function will be billing, based on the allocated size of CPU function serverAllocatedCPUBilling(p) local confvalues = { { key = "charge_measurement_type", name = "Per CPU billing", description = "Per CPU billing", value = "CPU_CORE", validator = {validatorType = "ENUM", validateString = "CPU_CORE"}, measureType = "NUMERIC" }, getRepeatUnitsDefinitionTable (), { key = "only_when_running", name = "Bill only when running", description = "If this value is set to TRUE, charging will only be done when server is running", validator = {validatorType = "ENUM", validateString = "TRUE,FALSE"}, measureType = "STRING" } } return { ref = "_serverAllocatedCPUBilling", executionFunction = "serverBilling", name = "Server billing for allocated CPUs", description = "Bill a fixed amount per allocated CPU", permittedPCT = {"PCT_SERVER_CPU"}, configuredValues = confvalues, api = "BILLING", version = 1 } end function serverAllocatedRAMBilling(p) local confvalues = getChargeMeasureTypeDefinition_table (false, true) table.insert (confvalues, { key = "only_when_running", name = "Bill only when running", description = "If this value is set to TRUE, charging will only be done when server is running", validator = {validatorType = "ENUM", validateString = "TRUE,FALSE"}, measureType = "STRING" } ) return { ref = "_serverAllocatedRAMBilling", executionFunction = "serverBilling", name = "Server billing for allocated RAM", description = "Bill a fixed amount depending on allocated RAM", permittedPCT = {"PCT_SERVER_RAM"}, configuredValues = confvalues, api = "BILLING", version = 1 } end -- This billing will be done depending on the allocated size of disk snapshot -- This can only be used with PCT-DISK-ALLOC function sizeAllocatedBilling(p) if (p == nil) then local confvalues = getChargeMeasureTypeDefinition_table(false, true) return { ref = "_sizeAllocatedBilling", name = "Billing based on storage size allocated", description = "Bill a fixed amount depending on the allocated amount of storage", permittedPCT = {"PCT_DISK_ALLOC","PCT_SNAPSHOT","PCT_IMAGE"}, configuredValues = confvalues, api = "BILLING", version = 1 } end local measureType, chargeUnits = getChargeMeasureTypeRepeatUnits (p.billingComp) local configMType, configSize = getConfiguredMeasureTypeValue (p.billingComp, "size") if ((chargeUnits ~= nil) and (chargeUnits > 0.0) and (configSize ~= nil) and (tonumber(configSize) > 0 )) then return {{ units = (chargeUnits * tonumber(configSize) * (convert_mtype(configMType,measureType)) * -1 * p.billingFactor), description = "Charge for " .. configSize .. configMType .. " allocated space" }} end return nil end -- ************************************ END OF ALLOCATION BASED BILLING ***************************************** -- ************************************ USAGE BASED BILLING ***************************************************** function diskIOUsageBilling(p) if (p == nil) then local confvalues = getChargeMeasureTypeDefinition_table(false, true) return { ref = "_diskIOUsageBilling", name = "Disk I/O charging", description = "Bill a variable amount depending on disk I/O in the period", permittedPCT = {"PCT_DISK_IO"}, configuredValues = confvalues, api = "BILLING", version = 1 } end if (p.currentBillingTime == 0 ) then return nil end -- print ("Current bill time is "..p.currentBillingTime) -- No previous measure value: charge the initial units if (p.lastBillingTime == 0) then local iniMtype, chargeUnits = getChargeMeasureTypeInitialUnits(p.billingComp) if ((chargeUnits == nil) or (chargeUnits <= 0.0)) then return nil end return {{ units = (chargeUnits * -1), description="Initial charge" }} end -- Lets bill for the usage local recMtype, chargeUnits = getChargeMeasureTypeRepeatUnits(p.billingComp) if ((recMtype == nil) or (chargeUnits == nil) or (chargeUnits <= 0.0)) then -- print ("Current Condition failing here while getting billing config") return nil end local previousHash = p.measureComp:getMeasureAt(p.lastBillingTime, "disk_read,disk_write") if ((not previousHash) or (previousHash:size() == 0 )) then previousHash = p.measureComp:getMINMeasureBetween(p.lastBillingTime, p.currentBillingTime, "disk_read,disk_write") end local currHash = p.measureComp:getMeasureAt(p.currentBillingTime, "disk_read,disk_write") local currentRead = currHash:get("disk_read") local currentWrite = currHash:get("disk_write") local curReadM = 0 local curWriteM = 0 local currM = "MB" if (currentRead) then curReadM = currentRead:getMeasurement() currM = currentRead:getMeasurementType() end if (currentWrite) then curWriteM = currentWrite:getMeasurement() end local preReadM = 0 local preWriteM = 0 local preM = "MB" local preRead = previousHash:get("disk_read") local preWrite = previousHash:get("disk_write") if (preRead) then preReadM = preRead:getMeasurement() preM = preRead:getMeasurementType() end if (preWrite) then preWriteM = preWrite:getMeasurement() end local usage = ((curReadM * convert_mtype(currM,recMtype)) - (preReadM * convert_mtype(preM,recMtype))) + ((curWriteM * convert_mtype(currM,recMtype)) - (preWriteM * convert_mtype(preM,recMtype))) if (usage > 0) then return {{ units = (usage * chargeUnits * -1), description = "Charge for " .. usage .. recMtype .. " disk I/O" }} end return nil end function networkIOUsageBilling(p) if (p == nil) then local confValues = getChargeMeasureTypeDefinition_table(false, false) table.insert(confValues,{ key = "repeat_units_tx", name = "Repeat Units (TX data)", description = "Number of units that will be charged on given billing cycle for transmitted data", measureType = "UNIT", validator = {validatorType = "NUMERIC_DOUBLE"} } ) table.insert(confValues,{ key = "repeat_units_rx", name = "Repeat Units (RX data)", description = "Number of units that will be charged on given billing cycle for received data", measureType = "UNIT", validator = {validatorType = "NUMERIC_DOUBLE"} } ) return { ref = "_networkIOUsageBilling", name = "Network usage charging", description = "Bill a variable amount depending on network usage during the period", permittedPCT = {"PCT_NETWORK_TRANSFER"}, configuredValues = confValues, api = "BILLING", version = 1 } end local cRxVal = 0 local cTxVal = 0 local cM = "MB" local pRxVal = 0 local pTxVal = 0 local pM = "MB" local preHash = p.measureComp:getMeasureAt(p.lastBillingTime, "traffic_in, traffic_out") -- As we are truncating the measured values tables in slow system we might not get the value for the last billing -- in such cases lets default to the minimum value if ((not preHash) or (preHash:size() == 0 )) then preHash = p.measureComp:getMINMeasureBetween(p.lastBillingTime, p.currentBillingTime, "traffic_in, traffic_out") end local curHash = p.measureComp:getMeasureAt(p.currentBillingTime, "traffic_in, traffic_out") local pRx = preHash:get("traffic_in") local pTx = preHash:get("traffic_out") local cRx = curHash:get("traffic_in") local cTx = curHash:get("traffic_out") if (pRx) then pRxVal = pRx:getMeasurement() pM = pRx:getMeasurementType() end if (pTx) then pTxVal = pTx:getMeasurement() end if (cRx) then cRxVal = cRx:getMeasurement() cM = cRx:getMeasurementType() end if (cTx) then cTxVal = cTx:getMeasurement() end local recMtype = (p.billingComp:getBillingValue("charge_measurement_type")):getValue() -- print ("Measurement Type set " .. recMtype) local txCharge = (p.billingComp:getBillingValue("repeat_units_tx")):getValue() -- print ("Tx charge set " .. txCharge) local rxCharge = (p.billingComp:getBillingValue("repeat_units_rx")):getValue() -- print ("Rx charge set " .. rxCharge) if (recMtype == nil) then return nil end local out = {} if (txCharge ~= nil) then local usage = (cTxVal * (convert_mtype(cM, recMtype))) - (pTxVal * (convert_mtype(pM, recMtype))) -- print ("Charging for TX usage "..usage) if (usage > 0 ) then table.insert(out,{ units = (usage * tonumber(txCharge) * -1 ), description = "Charge for " .. usage .. recMtype .. " network transmitted data" }) end end if (rxCharge ~= nil) then local usage = (cRxVal * (convert_mtype(cM, recMtype))) - (pRxVal * (convert_mtype(pM, recMtype))) -- print ("Charging for RX usage "..usage) if (usage > 0) then table.insert(out,{ units = (usage * tonumber(rxCharge) * -1), description = "Charge for " .. usage .. recMtype .. " network received data" }) end end return out end function fetchResourceBilling(p) if (p == nil ) then local confVals = getChargeMeasureTypeDefinition_table(true, false) return { ref = "_fetchResourceBilling", name = "Resource fetch charging", description = "Bill when a resource is fetched", permittedPCT = {"PCT_FETCH"}, configuredValues = confVals, api = "BILLING", version = 1 } end if (p.currentBillingTime > 0 ) then local mType, mVal = getConfiguredMeasureTypeValue(p.billingComp, "fetchSize") if ((mType == nil) or (mVal == nil)) then return nil end local cType, cVal = getChargeMeasureTypeInitialUnits(p.billingComp) if ((cType == nil) or (cVal == nil)) then return nil end return {{ units = (-1 * cVal * (convert_mtype(mType, cType)) * mVal), description = "Charge for fetching ".. mVal .. " " .. mType .. " of data" }} end return nil end -- ************************************ END OF USAGE BASED BILLING ********************************************** -- ************************************ AUTO TOP UP BILLING ***************************************************** function unitTopUpBilling(p) if (p == nil) then local confValues = {} -- The unit balance threshold before the top up will be started table.insert(confValues, { key = "balance_threshold", name = "Balance threshold", measureType = "UNIT", validator = {validatorType = "NUMERIC_DOUBLE"}, description = "An auto topup will run each time the customer goes below the balance threshold" }) return { ref = "_unitTopUpBilling", name = "Auto top up billing", description = "Billing for purchasing units", permittedPCT = {"PCT_UNIT_TRANSACTION"}, configuredValues = confValues, api = "BILLING", version = 1 } end local curr_bal = p.customer:getCarryOverBalance() -- logger ("Current customer carryover balance for customer [".. p.customer:getResourceUUID() .. "] is " .. curr_bal) local thresholdVal = p.billingComp:getBillingValue("balance_threshold") local threshold = 0 if ( thresholdVal and thresholdVal:getValue()) then threshold = tonumber(thresholdVal:getValue()); end -- logger ("The top up triggering billing threshold is set to "..threshold) if (curr_bal <= threshold or p.billingFactor == 0) then -- Issue the units and ask it to do the charge local charge = tonumber((p.billingComp:getProductValue("transactionCharge")):getValue()) local unitsToAdd = tonumber((p.billingComp:getProductValue("transactionAmount")):getValue()) -- logger("A charge of ["..charge.."] need to be taken and ["..unitsToAdd.."] will be added to the customer account [") return {{ units = unitsToAdd, description = unitsToAdd .. " units", charge = charge }} end return nil; end function arbitraryUnitBilling(p) if (p == nil) then return { ref = "_arbitraryUnitBilling", name = "Arbitrary Unit Billing", description = "This permits unit transactions of arbitrary size and will bill the Transaction Charge for each unit that is purchased.", permittedPCT = {"PCT_UNIT_TRANSACTION"}, configuredValues = confValues, api = "BILLING", version = 1 } end local charge = tonumber((p.billingComp:getProductValue("transactionCharge")):getValue()) local unitsToAdd = tonumber((p.billingComp:getProductValue("transactionAmount")):getValue()) if (charge >= 0 and unitsToAdd > 0) then return {{ units = unitsToAdd, description = unitsToAdd .. " units", charge = charge * unitsToAdd }} end return nil end function fixedUnitBilling(p) if (p == nil) then return { ref = "_fixedUnitBilling", name = "Fixed Unit Billing", description = "This will charge the customer amount specified by the Transaction charge.", permittedPCT = {"PCT_UNIT_TRANSACTION"}, configuredValues = confValues, api = "BILLING", version = 1 } end local charge = tonumber((p.billingComp:getProductValue("transactionCharge")):getValue()) local unitsToAdd = tonumber((p.billingComp:getProductValue("transactionAmount")):getValue()) if (charge >= 0 and unitsToAdd > 0) then return {{ units = unitsToAdd, description = unitsToAdd .. " units", charge = charge }} end return nil end -- ************************************ END OF AUTO TOP UP BILLING ********************************************** -- ************************************ BILLING FOR SUBNET ***************************************************** function subnetBillingIpV4(p) if (p == nil) then local confValues = {} table.insert(confValues,{ key = "units_per_address", name = "Units per IPv4 Address", description = "The number of units to be charged per IPv4 address in subnet", measureType = "UNIT", validator = {validatorType = "NUMERIC_DOUBLE"} }) return { ref = "_subnetBillingIpV4", name = "Bill per IPv4 Address", description = "Billing for each Ip address in a IPv4 subnet", permittedPCT = { "PCT_SUBNET" }, configuredValues = confValues, api = "BILLING", version = 1 } end local chargeVal = p.billingComp:getBillingValue("units_per_address") local unit_charge = 0 if (chargeVal) then unit_charge = tonumber(chargeVal:getValue()) end if (unit_charge > 0 and p.billingResource) then -- Resource is subnet here if (p.billingResource:getSubnetType():getDBValue() == 1 ) then local numIps = math.pow(2,(32 - p.billingResource:getMask())) return {{ units = (p.billingFactor * unit_charge * -1 * numIps) , description = "Charge for " .. numIps .. " of IPv4 addresses" }} end end return nil end -- ************************************* END OF BILLING FOR SUBNETS ********************************************* -- ************************************ BILLING FOR CUSTOMER ASSETS ******************************************** function customerResourceAssetBilling(p) if (p == nil) then local confValues = {} table.insert(confValues,{ key = "standard_units", name = "Base unit charge", description = "The number of units to be charged as standard, regardless of the assets used", measureType = "UNIT", validator = {validatorType = "NUMERIC_DOUBLE"} }) table.insert(confValues,{ key = "free_assets", name = "Asset allowance", description = "The number assets given to the customer as an allowance, without an extra charge ", measureType = "NUMERIC", validator = {validatorType = "NUMERIC_DOUBLE"} }) table.insert(confValues,{ key = "per_extra_asset_units", name = "Units per excess asset", description = "The number of units to be charged for each asset that exceeds the allowance", measureType = "UNIT", validator = {validatorType = "NUMERIC_DOUBLE"} }) return { ref = "_customerResourceAssetBilling", name = "Customer Asset Billing", description = "Bill for customer assets", permittedPCT = { "PCT_CUST_ASSET_USER", "PCT_CUST_ASSET_IMAGE", "PCT_CUST_ASSET_SNAPSHOT", "PCT_CUST_ASSET_STORAGEGB", "PCT_CUST_ASSET_DISK", "PCT_CUST_ASSET_SERVER", "PCT_CUST_ASSET_CPU", "PCT_CUST_ASSET_RAM", "PCT_CUST_ASSET_SUBNET", "PCT_CUST_ASSET_NETWORK", "PCT_CUST_ASSET_VDC", "PCT_CUST_ASSET_IPv4", "PCT_CUST_ASSET_IPv6" }, configuredValues = confValues, api = "BILLING", version = 1 } end local val = p.billingComp:getProductValue("asset_type") -- If the asset type is not defined we do not know what to bill for if (val ~= nil) then local asset = val:getValue() if (asset ~= nil) then local freeAsset = 0 local standardUnits = 0 local extraUnits = 0 local sval = p.billingComp:getBillingValue("standard_units") if (sval ~= nil) then local val = sval:getValue() if (val ~= nil) then standardUnits = tonumber(val) end end local fval = p.billingComp:getBillingValue("free_assets") if (fval ~= nil) then local val = fval:getValue() if (val ~= nil) then freeAsset = tonumber(val) end end local eval = p.billingComp:getBillingValue("per_extra_asset_units") if (eval ~= nil) then local val = eval:getValue() if (val ~= nil) then extraUnits = tonumber(val) end end local usedFql = "used." .. asset local currAsset = 0 local currentUsed = p.measureComp:getMAXMeasureBetween(p.lastBillingTime, p.currentBillingTime, usedFql) if ((currentUsed ~= nil) and (currentUsed:size() > 0)) then currAsset = (currentUsed:get(usedFql)):getMeasurement() end local ret = {} if (standardUnits > 0) then table.insert(ret, { units = standardUnits * -1 * p.billingFactor, description = "Standard Charge for Asset Type " .. asset }) end local billAsset = currAsset - freeAsset if (billAsset > 0 and extraUnits > 0) then table.insert(ret, { units = billAsset * extraUnits * -1 * p.billingFactor, description = "Charge for Using " .. billAsset .. " " .. asset .. "(s) over allowance" }) end return ret; end end return nil end -- ************************************ END OF CUSTOMER ASSET BILLING ****************************************** -- ************************************ CUSTOMER ASSET NETWORK/IO BILLING **************************************** function customerNetIOBilling (p) if (p == nil) then local confValues = getChargeMeasureTypeDefinition_table(false, false) table.insert(confValues,1,{ key = "standard_units", name = "Base unit charge", description = "The number of units to be charged as standard, regardless of the usage", measureType = "UNIT", validator = {validatorType = "NUMERIC_DOUBLE"} }) table.insert(confValues,{ key = "free_assets_tx", name = "TX data allowance", description = "The allowance for transmitted data, without an extra charge ", measureType = "NUMERIC", validator = {validatorType = "NUMERIC_DOUBLE"} }) table.insert(confValues,{ key = "repeat_units_tx", name = "Per excess TX data", description = "Number of units that will be charged on given billing cycle for transmitted data which exceed the transfer allowance", measureType = "UNIT", validator = {validatorType = "NUMERIC_DOUBLE"} } ) table.insert(confValues,{ key = "free_assets_rx", name = "RX data allowance", description = "The allowance for recived data, without an extra charge ", measureType = "NUMERIC", validator = {validatorType = "NUMERIC_DOUBLE"} }) table.insert(confValues,{ key = "repeat_units_rx", name = "Per excess RX data", description = "Number of units that will be charged on given billing cycle for received data which exceed the transfer allowance", measureType = "UNIT", validator = {validatorType = "NUMERIC_DOUBLE"} } ) return { ref = "_customerNetIOBilling", name = "Network IO Billing on customer ", description = "Bill network IO usage on a customer account", permittedPCT = {"PCT_CUST_ASSET_INTERWORK_NET", "PCT_CUST_ASSET_EXTERNAL_NET", "PCT_CUST_ASSET_NETWORK_IP_NET", "PCT_CUST_ASSET_NETWORK_PRIVATE_NET", "PCT_CUST_ASSET_NETWORK_PUBLIC_NET", "PCT_CUST_ASSET_NETWORK_ALL_NET"}, configuredValues = confValues, api = "BILLING", version = 1 } end if (p.currentBillingTime > 0) then -- print ("Current time is "..p.currentBillingTime) local val = p.billingComp:getProductValue("asset_type") if (val ~= nil) then -- print ("Asset Type found") local asset = val:getValue() if (asset ~= nil) then -- print ("Asset is "..asset) local in_measure = "used."..asset.."_IN" local out_measure = "used."..asset.."_OUT" local req = in_measure..", "..out_measure local recMtype = (p.billingComp:getBillingValue("charge_measurement_type")):getValue() -- print ("Measurement Type set " .. recMtype) local txCharge = (p.billingComp:getBillingValue("repeat_units_tx")):getValue() -- print ("Tx charge set " .. txCharge) local rxCharge = (p.billingComp:getBillingValue("repeat_units_rx")):getValue() -- print ("Rx charge set " .. rxCharge) local standardUnits = 0 local freeAssetTX = 0 local freeAssetRX = 0 local sval = p.billingComp:getBillingValue("standard_units") if (sval ~= nil) then local v = sval:getValue() if (v ~= nil) then standardUnits = tonumber(v) end end local ftxval = p.billingComp:getBillingValue("free_assets_tx") if (ftxval ~= nil) then local v = ftxval:getValue() if (v ~= nil) then freeAssetTX = tonumber(v) end end local frxval = p.billingComp:getBillingValue("free_assets_rx") if (frxval ~= nil) then local v = frxval:getValue() if (v ~= nil) then freeAssetRX = tonumber(v) end end local cRxVal = 0 local cTxVal = 0 local cM = "MB" local pRxVal = 0 local pTxVal = 0 local pM = "MB" local preHash = p.measureComp:getMeasureAt(p.lastBillingTime, req) -- As we are truncating the measured values tables in slow system we might not get the value for the last billing -- in such cases lets default to the minimum value if ((not preHash) or (preHash:size() == 0 )) then preHash = p.measureComp:getMINMeasureBetween(p.lastBillingTime, p.currentBillingTime, req) end local curHash = p.measureComp:getMeasureAt(p.currentBillingTime, req) local pRx = preHash:get(in_measure) local pTx = preHash:get(out_measure) local cRx = curHash:get(in_measure) local cTx = curHash:get(out_measure) if (pRx) then pRxVal = pRx:getMeasurement() pM = pRx:getMeasurementType() end if (pTx) then pTxVal = pTx:getMeasurement() end if (cRx) then cRxVal = cRx:getMeasurement() cM = cRx:getMeasurementType() end if (cTx) then cTxVal = cTx:getMeasurement() end if (recMtype == nil) then return nil end local out = {} if (standardUnits > 0) then table.insert(out, { units = standardUnits * -1 * p.billingFactor, description = "Standard Charge for " .. asset }) end if (txCharge ~= nil) then local usage = (cTxVal * (convert_mtype(cM, recMtype))) - (pTxVal * (convert_mtype(pM, recMtype))) -- print ("Charging for TX usage "..usage) usage = (usage - (freeAssetTX * p.billingFactor)) if (usage > 0 ) then table.insert(out,{ units = (usage * tonumber(txCharge) * -1 ), description = "Charge for " .. usage .. recMtype .. " network transmitted data over allowance" }) end end if (rxCharge ~= nil) then local usage = (cRxVal * (convert_mtype(cM, recMtype))) - (pRxVal * (convert_mtype(pM, recMtype))) -- print ("Charging for RX usage "..usage) usage = (usage - (freeAssetRX * p.billingFactor)) if (usage > 0) then table.insert(out,{ units = (usage * tonumber(rxCharge) * -1), description = "Charge for " .. usage .. recMtype .. " network received data over allowance" }) end end return out end end end return nil end function customerDiskIOUsageBilling (p) if (p == nil ) then local confValues = getChargeMeasureTypeDefinition_table(false, false) table.insert(confValues,1,{ key = "standard_units", name = "Base unit charge", description = "The number of units to be charged as standard, regardless of the usage", measureType = "UNIT", validator = {validatorType = "NUMERIC_DOUBLE"} }) table.insert(confValues,{ key = "free_assets_io", name = "Disk IO allowance", description = "The allowance for disk IO, without an extra charge ", measureType = "NUMERIC", validator = {validatorType = "NUMERIC_DOUBLE"} }) table.insert(confValues,{ key = "repeat_units", name = "Units per excess", description = "Number of units that will be charged on given billing cycle for disk io which exceed the allowance", measureType = "UNIT", validator = {validatorType = "NUMERIC_DOUBLE"} } ) return { ref = "_customerDiskIOUsageBilling", name = "Disk I/O charging for customer", description = "Bill a variable amount depending on disk I/O in the period", permittedPCT = {"PCT_CUST_ASSET_DISK_IO"}, configuredValues = confValues, api = "BILLING", version = 1 } end if (p.currentBillingTime == 0 ) then return nil end local val = p.billingComp:getProductValue("asset_type") if (val == nil) then return nil end local asset = val:getValue() if (asset == nil) then return nil end -- Lets bill for the usage local recMtype, chargeUnits = getChargeMeasureTypeRepeatUnits(p.billingComp) local standardUnits = 0 local freeAssetIO = 0 local sval = p.billingComp:getBillingValue("standard_units") if (sval ~= nil) then local v = sval:getValue() if (v ~= nil) then standardUnits = tonumber(v) end end local ftxval = p.billingComp:getBillingValue("free_assets_io") if (ftxval ~= nil) then local v = ftxval:getValue() if (v ~= nil) then freeAssetIO = tonumber(v) end end local out = {} if (standardUnits > 0) then table.insert(out, { units = standardUnits * -1 * p.billingFactor, description = "Standard Charge for disk IO" }) end if ((recMtype == nil) or (chargeUnits == nil) or (chargeUnits <= 0.0)) then -- print ("Current Condition failing here while getting billing config") return out end local read_measure = "used."..asset.."_READ" local write_measure = "used."..asset.."_WRITE" local req = read_measure..", "..write_measure local previousHash = p.measureComp:getMeasureAt(p.lastBillingTime, req) if ((not previousHash) or (previousHash:size() == 0 )) then previousHash = p.measureComp:getMINMeasureBetween(p.lastBillingTime, p.currentBillingTime, req) end local currHash = p.measureComp:getMeasureAt(p.currentBillingTime, req) local currentRead = currHash:get(read_measure) local currentWrite = currHash:get(write_measure) local curReadM = 0 local curWriteM = 0 local currM = "MB" if (currentRead) then curReadM = currentRead:getMeasurement() currM = currentRead:getMeasurementType() end if (currentWrite) then curWriteM = currentWrite:getMeasurement() end local preReadM = 0 local preWriteM = 0 local preM = "MB" local preRead = previousHash:get(read_measure) local preWrite = previousHash:get(write_measure) if (preRead) then preReadM = preRead:getMeasurement() preM = preRead:getMeasurementType() end if (preWrite) then preWriteM = preWrite:getMeasurement() end local usage = ((curReadM * convert_mtype(currM,recMtype)) - (preReadM * convert_mtype(preM,recMtype))) + ((curWriteM * convert_mtype(currM,recMtype)) - (preWriteM * convert_mtype(preM,recMtype))) usage = (usage - (freeAssetIO * p.billingFactor)) if (usage > 0) then table.insert(out, { units = (usage * chargeUnits * -1), description = "Charge for " .. usage .. recMtype .. " disk I/O over allowance" }) end return out end -- ************************************ CUSTOMER ASSET IO END BILLING ************************************* -- ************************************ IMAGE INSTANCE BILLING *************************************************** function imageInstanceBillingRAMCPU (p) if (p == nil) then local confvalues = { { key = "per_cpu_core_units", name = "Per CPU Units", description = "Units to be charged per CPU allocated to the server using the image", measureType = "UNIT", validator = {validatorType = "NUMERIC_DOUBLE"} },{ key = "per_ram_mb_units", name = "Per MB of RAM Units", description = "Units to be charged per MB of RAM allocated to the serve using the image", measureType = "UNIT", validator = {validatorType = "NUMERIC_DOUBLE"} },{ key = "only_when_running", name = "Bill only when server running", description = "If this value is set to TRUE, charging will only take place when the server is running", validator = {validatorType = "ENUM", validateString = "TRUE,FALSE"}, measureType = "STRING" }} return { ref = "_imageInstanceBillingRAMCPU", name = "Image usage billing on server RAM/CPU", description = "Bill for usage of an image based on the configured server RAM and CPU", permittedPCT = {"PCT_IMAGE_INSTANCE"}, configuredValues = confvalues, api = "BILLING", version = 1 } end local only_when_running = (p.billingComp:getBillingValue("only_when_running")):getValue() local doCharge = true -- If the only_when_running billing parameter is set we will only be charging if the server was running at the give time if (only_when_running == "TRUE") then -- print ("Looking for maximum running value between ".. p.lastBillingTime .. " and " .. p.currentBillingTime) local measuredHash = p.measureComp:getMAXMeasureBetween(p.lastBillingTime, p.currentBillingTime, "running") local uptime = measuredHash:get("running") if ((uptime == nil) or (uptime:getMeasurement() <= 0)) then doCharge = false end end if (doCharge) then local ret = {} local per_cpu_charge_val = p.billingComp:getBillingValue("per_cpu_core_units") local per_ram_charge_val = p.billingComp:getBillingValue("per_ram_mb_units") local usageHash = p.measureComp:getMAXMeasureBetween(p.lastBillingTime, p.currentBillingTime, "cpu, ram") if (usageHash and usageHash:size() > 0) then if (per_cpu_charge_val) then local cpuM = usageHash:get("cpu") if (cpuM) then local cval = tonumber(per_cpu_charge_val:getValue()) if (cval > 0 ) then local u = cpuM:getMeasurement() * cval * -1 table.insert(ret, {units = u , description = "Charge for Image CPU "..cpuM:getMeasurement() }) end end end if (per_ram_charge_val) then local ramM = usageHash:get("ram") if (ramM) then local cval = tonumber(per_ram_charge_val:getValue()) if (cval > 0 ) then local u = ramM:getMeasurement() * cval * -1 table.insert(ret, {units = u , description = "Charge for Image RAM "..ramM:getMeasurement().." MB" }) end end end end return ret end return nil end function imageInstanceBillingStandard (p) if (p == nil) then local confvalues = { getRepeatUnitsDefinitionTable(),{ key = "only_when_running", name = "Bill only when server running", description = "If this value is set to TRUE, charging will only take place when the server is running", validator = {validatorType = "ENUM", validateString = "TRUE,FALSE"}, measureType = "STRING" }} return { ref = "_imageInstanceBillingStandard", name = "Image usage billing on a fixed rate", description = "Bill a fixed amount for the image usage ", permittedPCT = {"PCT_IMAGE_INSTANCE"}, configuredValues = confvalues, api = "BILLING", version = 1 } end local only_when_running = (p.billingComp:getBillingValue("only_when_running")):getValue() local doCharge = true local chargeUnits = getRepeatUnits(p.billingComp) -- If the only_when_running billing parameter is set we will only be charging if the server was running at the give time if (only_when_running == "TRUE") then -- print ("Looking for maximum running value between ".. p.lastBillingTime .. " and " .. p.currentBillingTime) local measuredHash = p.measureComp:getMAXMeasureBetween(p.lastBillingTime, p.currentBillingTime, "running") local uptime = measuredHash:get("running") if ((uptime == nil) or (uptime:getMeasurement() <= 0)) then doCharge = false end end if (doCharge and (chargeUnits~=nil) and (chargeUnits > 0 )) then return {{units=(chargeUnits * -1), description = "Charge for Image usage on server "}} end end -- ************************************ END OF IMAGE INSTANCE BILLING ******************************************** -- ************************************ SUBSCRIPTION BILLING ******************************************** function getChargeAmount(p) local chargeAmount = p.billingComp:getBillingValue("charge_amount") if(chargeAmount ~= nil) then local chargeValue = chargeAmount:getValue() if(chargeValue ~= nil) then return tonumber(chargeValue) end end return nil end function advanceSubscriptionBilling(p) if (p == nil) then return { ref = "_advance_subscription_billing", name = "Advance Subscription Billing", description = "Subscription billing which will charge a set amount at the start of each billing period. If the subscription is cancelled you will be refunded the outstanding amount.", permittedPCT = {"PCT_CUST_CREDIT"}, configuredValues = { { key = "charge_amount", name = "Charge amount", description = "The amount that will be charged at the start of each billing period", validator = {validatorType = "NUMERIC_DOUBLE"}, measureType = "NUMERIC" }, }, api = "BILLING", version = 1 } end if(p.lastBillingRun) then local amount = getChargeAmount(p) local refundAmount = amount - (amount * p.billingFactor) if(refundAmount >= 0.01) then return {{charge = refundAmount * -1 , description = "Subscription Refund" }} end else local amount = getChargeAmount(p) if (amount >= 0.01) then return {{charge = amount , description = "Subscription Charge" }} end end return nil end -- ************************************ END OF SUBSCRIPTION BILLING ******************************************** -- Registers all the billing functions function register () -- print ("Loading default billing methods") return { "fixedResourceBilling", "serverAllocatedCPUBilling", "serverAllocatedRAMBilling", "sizeAllocatedBilling", "diskIOUsageBilling", "networkIOUsageBilling", "unitTopUpBilling", "fetchResourceBilling", "customerResourceAssetBilling", "subnetBillingIpV4", "imageInstanceBillingStandard", "imageInstanceBillingRAMCPU", "customerNetIOBilling", "customerDiskIOUsageBilling", "arbitraryUnitBilling", "fixedUnitBilling", "advanceSubscriptionBilling" } end