2018-04-16 01:25:36 +00:00
|
|
|
import decimal
|
2017-09-24 18:32:36 +00:00
|
|
|
import logging
|
2018-08-21 22:12:14 +00:00
|
|
|
import subprocess
|
2018-09-05 22:18:04 +00:00
|
|
|
|
2017-09-24 18:32:36 +00:00
|
|
|
from oca.pool import WrongIdError
|
2017-08-31 16:35:19 +00:00
|
|
|
|
2018-04-15 11:31:55 +00:00
|
|
|
from datacenterlight.models import VMPricing
|
2019-11-15 06:28:15 +00:00
|
|
|
from hosting.models import UserHostingKey, VMDetail, VATRates
|
2017-09-24 18:32:36 +00:00
|
|
|
from opennebula_api.serializers import VirtualMachineSerializer
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
2017-08-31 16:35:19 +00:00
|
|
|
|
|
|
|
|
|
|
|
def get_all_public_keys(customer):
|
|
|
|
"""
|
|
|
|
Returns all the public keys of the user
|
|
|
|
:param customer: The customer whose public keys are needed
|
|
|
|
:return: A list of public keys
|
|
|
|
"""
|
2017-09-04 21:59:12 +00:00
|
|
|
return UserHostingKey.objects.filter(user_id=customer.id).values_list(
|
2019-08-26 10:32:08 +00:00
|
|
|
"public_key", flat=True).distinct()
|
2017-09-22 21:46:18 +00:00
|
|
|
|
|
|
|
|
2017-09-24 18:32:36 +00:00
|
|
|
def get_or_create_vm_detail(user, manager, vm_id):
|
|
|
|
"""
|
|
|
|
Returns VMDetail object related to given vm_id. Creates the object
|
|
|
|
if it does not exist
|
|
|
|
|
|
|
|
:param vm_id: The ID of the VM which should be greater than 0.
|
|
|
|
:param user: The CustomUser object that owns this VM
|
|
|
|
:param manager: The OpenNebulaManager object
|
|
|
|
:return: The VMDetail object. None if vm_id is less than or equal to 0.
|
|
|
|
Also, for the cases where the VMDetail does not exist and we can not
|
|
|
|
fetch data about the VM from OpenNebula, the function returns None
|
|
|
|
"""
|
|
|
|
if vm_id <= 0:
|
|
|
|
return None
|
|
|
|
try:
|
|
|
|
vm_detail_obj = VMDetail.objects.get(vm_id=vm_id)
|
|
|
|
except VMDetail.DoesNotExist:
|
|
|
|
try:
|
|
|
|
vm_obj = manager.get_vm(vm_id)
|
|
|
|
except (WrongIdError, ConnectionRefusedError) as e:
|
|
|
|
logger.error(str(e))
|
|
|
|
return None
|
|
|
|
vm = VirtualMachineSerializer(vm_obj).data
|
|
|
|
vm_detail_obj = VMDetail.objects.create(
|
|
|
|
user=user, vm_id=vm_id, disk_size=vm['disk_size'],
|
|
|
|
cores=vm['cores'], memory=vm['memory'],
|
2019-04-10 23:58:51 +00:00
|
|
|
configuration=vm['configuration'], ipv4=vm['ipv4'],
|
2017-09-24 18:32:36 +00:00
|
|
|
ipv6=vm['ipv6']
|
|
|
|
)
|
|
|
|
return vm_detail_obj
|
2017-09-27 20:05:09 +00:00
|
|
|
|
|
|
|
|
2018-04-15 11:31:55 +00:00
|
|
|
def get_vm_price(cpu, memory, disk_size, hdd_size=0, pricing_name='default'):
|
2017-09-22 21:46:18 +00:00
|
|
|
"""
|
|
|
|
A helper function that computes price of a VM from given cpu, ram and
|
|
|
|
ssd parameters
|
|
|
|
|
|
|
|
:param cpu: Number of cores of the VM
|
|
|
|
:param memory: RAM of the VM
|
2018-04-15 11:31:55 +00:00
|
|
|
:param disk_size: Disk space of the VM (SSD)
|
|
|
|
:param hdd_size: The HDD size
|
|
|
|
:param pricing_name: The pricing name to be used
|
2017-09-22 21:46:18 +00:00
|
|
|
:return: The price of the VM
|
|
|
|
"""
|
2018-04-15 11:31:55 +00:00
|
|
|
try:
|
|
|
|
pricing = VMPricing.objects.get(name=pricing_name)
|
|
|
|
except Exception as ex:
|
|
|
|
logger.error(
|
|
|
|
"Error getting VMPricing object for {pricing_name}."
|
|
|
|
"Details: {details}".format(
|
|
|
|
pricing_name=pricing_name, details=str(ex)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
return None
|
2018-04-16 01:25:36 +00:00
|
|
|
price = ((decimal.Decimal(cpu) * pricing.cores_unit_price) +
|
2018-04-17 18:50:41 +00:00
|
|
|
(decimal.Decimal(memory) * pricing.ram_unit_price) +
|
|
|
|
(decimal.Decimal(disk_size) * pricing.ssd_unit_price) +
|
|
|
|
(decimal.Decimal(hdd_size) * pricing.hdd_unit_price))
|
2018-04-16 01:25:36 +00:00
|
|
|
cents = decimal.Decimal('.01')
|
|
|
|
price = price.quantize(cents, decimal.ROUND_HALF_UP)
|
2018-09-05 22:18:04 +00:00
|
|
|
return round(float(price), 2)
|
2018-04-15 18:59:31 +00:00
|
|
|
|
|
|
|
|
2019-12-07 13:56:21 +00:00
|
|
|
def get_vm_price_for_given_vat(cpu, memory, ssd_size, hdd_size=0,
|
|
|
|
pricing_name='default', vat_rate=0):
|
|
|
|
try:
|
|
|
|
pricing = VMPricing.objects.get(name=pricing_name)
|
|
|
|
except Exception as ex:
|
|
|
|
logger.error(
|
|
|
|
"Error getting VMPricing object for {pricing_name}."
|
|
|
|
"Details: {details}".format(
|
|
|
|
pricing_name=pricing_name, details=str(ex)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
return None
|
|
|
|
|
|
|
|
price = (
|
|
|
|
(decimal.Decimal(cpu) * pricing.cores_unit_price) +
|
|
|
|
(decimal.Decimal(memory) * pricing.ram_unit_price) +
|
|
|
|
(decimal.Decimal(ssd_size) * pricing.ssd_unit_price) +
|
|
|
|
(decimal.Decimal(hdd_size) * pricing.hdd_unit_price)
|
|
|
|
)
|
|
|
|
|
2020-01-24 09:30:16 +00:00
|
|
|
discount_name = pricing.discount_name
|
|
|
|
discount_amount = round(float(pricing.discount_amount), 2)
|
|
|
|
vat = (price - discount_amount) * decimal.Decimal(vat_rate) * decimal.Decimal(0.01)
|
2019-12-07 14:08:33 +00:00
|
|
|
vat_percent = vat_rate
|
2019-12-07 13:56:21 +00:00
|
|
|
|
|
|
|
cents = decimal.Decimal('.01')
|
|
|
|
price = price.quantize(cents, decimal.ROUND_HALF_UP)
|
|
|
|
vat = vat.quantize(cents, decimal.ROUND_HALF_UP)
|
|
|
|
discount = {
|
2020-01-24 09:30:16 +00:00
|
|
|
'name': discount_name,
|
|
|
|
'amount': discount_amount
|
2019-12-07 13:56:21 +00:00
|
|
|
}
|
|
|
|
return (round(float(price), 2), round(float(vat), 2),
|
|
|
|
round(float(vat_percent), 2), discount)
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-04-16 01:25:36 +00:00
|
|
|
def get_vm_price_with_vat(cpu, memory, ssd_size, hdd_size=0,
|
2018-04-15 18:59:31 +00:00
|
|
|
pricing_name='default'):
|
|
|
|
"""
|
|
|
|
A helper function that computes price of a VM from given cpu, ram and
|
|
|
|
ssd, hdd and the pricing parameters
|
|
|
|
|
|
|
|
:param cpu: Number of cores of the VM
|
|
|
|
:param memory: RAM of the VM
|
2018-04-16 01:25:36 +00:00
|
|
|
:param ssd_size: Disk space of the VM (SSD)
|
2018-04-15 18:59:31 +00:00
|
|
|
:param hdd_size: The HDD size
|
|
|
|
:param pricing_name: The pricing name to be used
|
2018-04-17 19:36:08 +00:00
|
|
|
:return: The a tuple containing the price of the VM, the VAT and the
|
|
|
|
VAT percentage
|
2018-04-15 18:59:31 +00:00
|
|
|
"""
|
|
|
|
try:
|
|
|
|
pricing = VMPricing.objects.get(name=pricing_name)
|
|
|
|
except Exception as ex:
|
|
|
|
logger.error(
|
|
|
|
"Error getting VMPricing object for {pricing_name}."
|
|
|
|
"Details: {details}".format(
|
|
|
|
pricing_name=pricing_name, details=str(ex)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
return None
|
|
|
|
|
2018-05-06 23:37:58 +00:00
|
|
|
price = (
|
|
|
|
(decimal.Decimal(cpu) * pricing.cores_unit_price) +
|
|
|
|
(decimal.Decimal(memory) * pricing.ram_unit_price) +
|
|
|
|
(decimal.Decimal(ssd_size) * pricing.ssd_unit_price) +
|
2018-05-07 00:41:44 +00:00
|
|
|
(decimal.Decimal(hdd_size) * pricing.hdd_unit_price)
|
2018-05-06 23:37:58 +00:00
|
|
|
)
|
2018-04-15 18:59:31 +00:00
|
|
|
if pricing.vat_inclusive:
|
2018-04-16 01:25:36 +00:00
|
|
|
vat = decimal.Decimal(0)
|
2018-04-17 19:36:08 +00:00
|
|
|
vat_percent = decimal.Decimal(0)
|
2018-04-15 18:59:31 +00:00
|
|
|
else:
|
2018-04-16 01:25:36 +00:00
|
|
|
vat = price * pricing.vat_percentage * decimal.Decimal(0.01)
|
2018-04-17 19:36:08 +00:00
|
|
|
vat_percent = pricing.vat_percentage
|
2018-04-16 01:25:36 +00:00
|
|
|
|
|
|
|
cents = decimal.Decimal('.01')
|
|
|
|
price = price.quantize(cents, decimal.ROUND_HALF_UP)
|
|
|
|
vat = vat.quantize(cents, decimal.ROUND_HALF_UP)
|
2018-05-07 00:55:50 +00:00
|
|
|
discount = {
|
|
|
|
'name': pricing.discount_name,
|
2018-09-07 20:46:18 +00:00
|
|
|
'amount': round(float(pricing.discount_amount), 2)
|
2018-05-07 00:55:50 +00:00
|
|
|
}
|
2018-09-05 22:18:04 +00:00
|
|
|
return (round(float(price), 2), round(float(vat), 2),
|
2018-10-17 05:27:28 +00:00
|
|
|
round(float(vat_percent), 2), discount)
|
2017-10-29 12:14:29 +00:00
|
|
|
|
|
|
|
|
2018-08-21 22:12:14 +00:00
|
|
|
def ping_ok(host_ipv6):
|
|
|
|
"""
|
|
|
|
A utility method to check if a host responds to ping requests. Note: the
|
|
|
|
function relies on `ping6` utility of debian to check.
|
|
|
|
|
|
|
|
:param host_ipv6 str type parameter that represets the ipv6 of the host to
|
|
|
|
checked
|
|
|
|
:return True if the host responds to ping else returns False
|
|
|
|
"""
|
|
|
|
try:
|
2018-08-22 18:27:19 +00:00
|
|
|
subprocess.check_output("ping6 -c 1 " + host_ipv6, shell=True)
|
2018-08-21 22:12:14 +00:00
|
|
|
except Exception as ex:
|
|
|
|
logger.debug(host_ipv6 + " not reachable via ping. Error = " + str(ex))
|
|
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
2019-11-15 06:28:15 +00:00
|
|
|
def get_vat_rate_for_country(country):
|
2019-11-15 06:54:39 +00:00
|
|
|
vat_rate = None
|
|
|
|
try:
|
|
|
|
vat_rate = VATRates.objects.get(
|
2019-11-15 08:02:49 +00:00
|
|
|
territory_codes=country, start_date__isnull=False, stop_date=None
|
2019-11-15 06:54:39 +00:00
|
|
|
)
|
2019-11-15 06:28:15 +00:00
|
|
|
logger.debug("VAT rate for %s is %s" % (country, vat_rate.rate))
|
|
|
|
return vat_rate.rate
|
2019-11-15 06:54:39 +00:00
|
|
|
except VATRates.DoesNotExist as dne:
|
|
|
|
logger.debug(str(dne))
|
2019-11-15 06:28:15 +00:00
|
|
|
logger.debug("Did not find VAT rate for %s, returning 0" % country)
|
|
|
|
return 0
|
|
|
|
|
|
|
|
|
2020-01-20 06:37:32 +00:00
|
|
|
def get_ip_addresses(vm_id):
|
|
|
|
try:
|
|
|
|
vm_detail = VMDetail.objects.get(vm_id=vm_id)
|
|
|
|
return "%s <br/>%s" % (vm_detail.ipv6, vm_detail.ipv4)
|
|
|
|
except VMDetail.DoesNotExist as dne:
|
|
|
|
logger.error(str(dne))
|
|
|
|
logger.error("VMDetail for %s does not exist" % vm_id)
|
|
|
|
return "--"
|
|
|
|
|
2020-01-20 06:39:49 +00:00
|
|
|
|
2017-10-29 12:14:29 +00:00
|
|
|
class HostingUtils:
|
|
|
|
@staticmethod
|
|
|
|
def clear_items_from_list(from_list, items_list):
|
|
|
|
"""
|
|
|
|
A utility function to clear items from a given list.
|
|
|
|
Useful when deleting items in bulk from session.
|
|
|
|
e.g.:
|
|
|
|
HostingUtils.clear_items_from_list(
|
|
|
|
request.session,
|
|
|
|
['token', 'billing_address_data', 'card_id',]
|
|
|
|
)
|
|
|
|
:param from_list:
|
|
|
|
:param items_list:
|
|
|
|
:return:
|
|
|
|
"""
|
|
|
|
for var in items_list:
|
|
|
|
if var in from_list:
|
|
|
|
del from_list[var]
|