Update invoice handling
This commit is contained in:
parent
72c28d2b57
commit
a1e020ae2d
4 changed files with 200 additions and 76 deletions
9
core/feature/unpaid_invoice_handle/actions.py
Normal file
9
core/feature/unpaid_invoice_handle/actions.py
Normal file
|
@ -0,0 +1,9 @@
|
|||
from enum import Enum
|
||||
|
||||
|
||||
class UnpainInvoiceAction(Enum):
|
||||
SEND_MESSAGE = "send_message"
|
||||
STOP_INSTANCE = "stop_instance"
|
||||
SUSPEND_INSTANCE = "suspend_instance"
|
||||
PAUSE_INSTANCE = "pause_instance"
|
||||
DELETE_INSTANCE = "delete_instance"
|
122
core/feature/unpaid_invoice_handle/command.py
Normal file
122
core/feature/unpaid_invoice_handle/command.py
Normal file
|
@ -0,0 +1,122 @@
|
|||
import logging
|
||||
import traceback
|
||||
|
||||
import openstack
|
||||
from django.utils import timezone
|
||||
from core.feature.unpaid_invoice_handle.actions import UnpainInvoiceAction
|
||||
|
||||
from core.models import Invoice
|
||||
from core.notification import send_notification
|
||||
from core.utils.dynamic_setting import get_dynamic_setting, BILLING_ENABLED
|
||||
from yuyu import settings
|
||||
|
||||
|
||||
LOG = logging.getLogger("yuyu")
|
||||
|
||||
class UnpaidInvoiceHandlerCommand:
|
||||
def handle(self):
|
||||
LOG.info("Processing Unpaid Invoice")
|
||||
|
||||
# Initialize connection
|
||||
if not get_dynamic_setting(BILLING_ENABLED):
|
||||
return
|
||||
|
||||
expired_unpaid_invoices = Invoice.objects.filter(state=Invoice.InvoiceState.UNPAID).all()
|
||||
for invoice in expired_unpaid_invoices:
|
||||
self.run_action_on_config(invoice)
|
||||
|
||||
LOG.info("Processing Unpaid Invoice Done")
|
||||
|
||||
def run_action_on_config(self, invoice):
|
||||
schedule_config = settings.UNPAID_INVOICE_HANDLER_CONFIG
|
||||
date_diff = timezone.now() - invoice.end_date
|
||||
past_day = date_diff.days
|
||||
for config in schedule_config:
|
||||
if config['day'] == past_day:
|
||||
self.run_action(invoice, config['action'], config)
|
||||
|
||||
def run_action(self, invoice, action, config=None):
|
||||
try:
|
||||
if action == UnpainInvoiceAction.SEND_MESSAGE:
|
||||
self._send_message(invoice, config)
|
||||
|
||||
if action == UnpainInvoiceAction.STOP_INSTANCE:
|
||||
self._stop_component(invoice)
|
||||
|
||||
if action == UnpainInvoiceAction.SUSPEND_INSTANCE:
|
||||
self._stop_component(invoice)
|
||||
|
||||
if action == UnpainInvoiceAction.PAUSE_INSTANCE:
|
||||
self._stop_component(invoice)
|
||||
|
||||
if action == UnpainInvoiceAction.DELETE_INSTANCE:
|
||||
self._delete_component(invoice)
|
||||
except Exception:
|
||||
LOG.exception("Failed to process Unpaid Invoice")
|
||||
send_notification(
|
||||
project=None,
|
||||
title='[Error] Error when processing unpaid invoice',
|
||||
short_description=f'There is an error when processing unpaid invoice',
|
||||
content=f'There is an error when handling unpaid invoice \n {traceback.format_exc()}',
|
||||
)
|
||||
|
||||
def _stop_component(self, invoice: Invoice):
|
||||
LOG.info("Stopping Component")
|
||||
conn = openstack.connect(cloud=settings.CLOUD_CONFIG_NAME)
|
||||
|
||||
# Stop Instance
|
||||
for server in conn.compute.servers(project_id=invoice.project.tenant_id):
|
||||
conn.compute.stop_server(server)
|
||||
|
||||
def _suspend_component(self, invoice: Invoice):
|
||||
LOG.info("Suspending Component")
|
||||
conn = openstack.connect(cloud=settings.CLOUD_CONFIG_NAME)
|
||||
|
||||
# Suspend Instance
|
||||
for server in conn.compute.servers(project_id=invoice.project.tenant_id):
|
||||
conn.compute.suspend_server(server)
|
||||
|
||||
def _pause_component(self, invoice: Invoice):
|
||||
LOG.info("Pausing Component")
|
||||
conn = openstack.connect(cloud=settings.CLOUD_CONFIG_NAME)
|
||||
|
||||
# Pause Instance
|
||||
for server in conn.compute.servers(project_id=invoice.project.tenant_id):
|
||||
conn.compute.pause_server(server)
|
||||
|
||||
def _delete_component(self, invoice: Invoice):
|
||||
LOG.info("Deleting Component")
|
||||
conn = openstack.connect(cloud=settings.CLOUD_CONFIG_NAME)
|
||||
|
||||
# Delete Instance
|
||||
for server in conn.compute.servers(project_id=invoice.project.tenant_id):
|
||||
conn.compute.delete_server(server)
|
||||
|
||||
# Delete Image
|
||||
for image in conn.compute.images(project_id=invoice.project.tenant_id):
|
||||
conn.compute.delete_image(image)
|
||||
|
||||
# Delete Floating Ips
|
||||
for ip in conn.network.ips(project_id=invoice.project.tenant_id):
|
||||
conn.network.delete_ip(ip)
|
||||
|
||||
# Delete Router
|
||||
for route in conn.network.routers(project_id=invoice.project.tenant_id):
|
||||
conn.network.delete_router(route)
|
||||
|
||||
# Delete Volume
|
||||
for volume in conn.block_storage.volumes(project_id=invoice.project.tenant_id):
|
||||
conn.block_storage.delete_volume(volume)
|
||||
|
||||
# Delete Snapshot
|
||||
for snapshot in conn.block_storage.snapshots(project_id=invoice.project.tenant_id):
|
||||
conn.block_storage.delete_snapshot(snapshot)
|
||||
|
||||
def _send_message(self, invoice: Invoice, message_config):
|
||||
LOG.info("Sending Message")
|
||||
send_notification(
|
||||
project=invoice.project,
|
||||
title=message_config['message_title'],
|
||||
short_description=message_config['message_short_description'],
|
||||
content=message_config['message_content'],
|
||||
)
|
64
core/feature/unpaid_invoice_handle/event_handler.py
Normal file
64
core/feature/unpaid_invoice_handle/event_handler.py
Normal file
|
@ -0,0 +1,64 @@
|
|||
from datetime import timezone
|
||||
import logging
|
||||
from core.feature.unpaid_invoice_handle.actions import UnpainInvoiceAction
|
||||
from core.feature.unpaid_invoice_handle.command import UnpaidInvoiceHandlerCommand
|
||||
from core.models import Invoice
|
||||
from yuyu import settings
|
||||
|
||||
LOG = logging.getLogger("yuyu")
|
||||
|
||||
class UnpaidInvoiceEventHandler:
|
||||
filter_action = [
|
||||
UnpainInvoiceAction.STOP_INSTANCE,
|
||||
UnpainInvoiceAction.SUSPEND_INSTANCE,
|
||||
UnpainInvoiceAction.PAUSE_INSTANCE,
|
||||
UnpainInvoiceAction.DELETE_INSTANCE,
|
||||
]
|
||||
|
||||
def filter_event_project_id(event_type, raw_payload):
|
||||
if event_type == 'floatingip.create.end':
|
||||
return raw_payload['floatingip']['tenant_id']
|
||||
if event_type == 'image.activate':
|
||||
return raw_payload['owner']
|
||||
if event_type == 'compute.instance.update':
|
||||
return raw_payload['tenant_id']
|
||||
if event_type == 'router.create.end':
|
||||
return raw_payload['router']['tenant_id']
|
||||
if event_type == 'router.update.end':
|
||||
return raw_payload['router']['tenant_id']
|
||||
if event_type == 'snapshot.create.end':
|
||||
return raw_payload['tenant_id']
|
||||
if event_type == 'volume.create.end':
|
||||
return raw_payload['tenant_id']
|
||||
|
||||
return None
|
||||
|
||||
def handle(self, event_type, raw_payload):
|
||||
try:
|
||||
LOG.exception("Processing Unpaid Invoice Event")
|
||||
schedule_config = settings.UNPAID_INVOICE_HANDLER_CONFIG
|
||||
command = UnpaidInvoiceHandlerCommand()
|
||||
project_id = self.filter_event_project_id(event_type, raw_payload)
|
||||
if project_id:
|
||||
# Fetch All Unpaid Invoice
|
||||
unpaid_invoice = Invoice.objects.filter(project__tenant_id=project_id, state=Invoice.InvoiceState.UNPAID).first()
|
||||
used_config = {}
|
||||
used_day = 0
|
||||
|
||||
if unpaid_invoice:
|
||||
# Calculate Days
|
||||
# Find last config that has beed runned in past days
|
||||
date_diff = timezone.now() - unpaid_invoice.end_date
|
||||
past_day = date_diff.days
|
||||
for config in schedule_config:
|
||||
if config['action'] not in self.filter_action:
|
||||
continue
|
||||
|
||||
if config['day'] <= past_day and config['day'] > used_day:
|
||||
used_day = config['day']
|
||||
used_config = config
|
||||
|
||||
if used_config:
|
||||
command.run_action(unpaid_invoice, used_config['action'], config)
|
||||
except Exception:
|
||||
LOG.exception("Failed to process Unpaid Invoice Event")
|
|
@ -4,89 +4,18 @@ import traceback
|
|||
import openstack
|
||||
from django.core.management import BaseCommand
|
||||
from django.utils import timezone
|
||||
from core.feature.unpaid_invoice_handle.command import UnpaidInvoiceHandlerCommand
|
||||
|
||||
from core.models import Invoice
|
||||
from core.notification import send_notification
|
||||
from core.utils.dynamic_setting import get_dynamic_setting, BILLING_ENABLED
|
||||
from yuyu import settings
|
||||
|
||||
LOG = logging.getLogger("yuyu_unpaid_invoice_handler")
|
||||
LOG = logging.getLogger("yuyu")
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Yuyu Unpaid Invoice Handler'
|
||||
|
||||
unpaid_invoice_command = UnpaidInvoiceHandlerCommand()
|
||||
|
||||
def handle(self, *args, **options):
|
||||
print("Processing Unpaid Invoice")
|
||||
# Initialize connection
|
||||
if not get_dynamic_setting(BILLING_ENABLED):
|
||||
return
|
||||
|
||||
schedule_config = settings.UNPAID_INVOICE_HANDLER_CONFIG
|
||||
expired_unpaid_invoices = Invoice.objects.filter(state=Invoice.InvoiceState.UNPAID).all()
|
||||
for invoice in expired_unpaid_invoices:
|
||||
date_diff = timezone.now() - invoice.end_date
|
||||
past_day = date_diff.days
|
||||
for config in schedule_config:
|
||||
if config['day'] == past_day:
|
||||
try:
|
||||
if config['action'] == 'send_message':
|
||||
self._send_message(invoice, config)
|
||||
|
||||
if config['action'] == 'stop_instance':
|
||||
self._stop_component(invoice)
|
||||
|
||||
if config['action'] == 'delete_instance':
|
||||
self._delete_component(invoice)
|
||||
except Exception:
|
||||
send_notification(
|
||||
project=None,
|
||||
title='[Error] Error when processing unpaid invoice',
|
||||
short_description=f'There is an error when processing unpaid invoice',
|
||||
content=f'There is an error when handling unpaid invoice \n {traceback.format_exc()}',
|
||||
)
|
||||
|
||||
print("Processing Done")
|
||||
|
||||
def _stop_component(self, invoice: Invoice):
|
||||
conn = openstack.connect(cloud=settings.CLOUD_CONFIG_NAME)
|
||||
|
||||
# Stop Instance
|
||||
for server in conn.compute.servers(project_id=invoice.project.tenant_id):
|
||||
conn.compute.stop_server(server)
|
||||
|
||||
def _delete_component(self, invoice: Invoice):
|
||||
conn = openstack.connect(cloud=settings.CLOUD_CONFIG_NAME)
|
||||
|
||||
# Delete Instance
|
||||
for server in conn.compute.servers(project_id=invoice.project.tenant_id):
|
||||
conn.compute.delete_server(server)
|
||||
|
||||
# Delete Image
|
||||
for image in conn.compute.images(project_id=invoice.project.tenant_id):
|
||||
conn.compute.delete_image(image)
|
||||
|
||||
# Delete Floating Ips
|
||||
for ip in conn.network.ips(project_id=invoice.project.tenant_id):
|
||||
conn.network.delete_ip(ip)
|
||||
|
||||
# Delete Router
|
||||
for route in conn.network.routers(project_id=invoice.project.tenant_id):
|
||||
conn.network.delete_router(route)
|
||||
|
||||
# Delete Volume
|
||||
for volume in conn.block_storage.volumes(project_id=invoice.project.tenant_id):
|
||||
conn.block_storage.delete_volume(volume)
|
||||
|
||||
# Delete Snapshot
|
||||
for snapshot in conn.block_storage.snapshots(project_id=invoice.project.tenant_id):
|
||||
conn.block_storage.delete_snapshot(snapshot)
|
||||
|
||||
def _send_message(self, invoice: Invoice, message_config):
|
||||
print('Sending Message')
|
||||
send_notification(
|
||||
project=invoice.project,
|
||||
title=message_config['message_title'],
|
||||
short_description=message_config['message_short_description'],
|
||||
content=message_config['message_content'],
|
||||
)
|
||||
self.unpaid_invoice_command.handle()
|
Loading…
Add table
Reference in a new issue