diff --git a/.gitignore b/.gitignore index 873440a..8f9d944 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,8 @@ db.sqlite3 db.sqlite3-journal media +env/* + # If your build process includes running collectstatic, then you probably don't need or want to include staticfiles/ # in your Git repository. Update and uncomment the following line accordingly. # /staticfiles/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..296718b --- /dev/null +++ b/README.md @@ -0,0 +1,175 @@ + +# Rintik + +Rintik provide ability to manage openstack billing by listening to every openstack event. Rintik is a required component to use Rintik Dashboard. There are 3 main component in Rintik: API, Cron, Event Monitor + +## Rintik API +Main component to communicate with Rintik Dashboard. + +## Rintik Cron +Provide invoice calculation and rolling capabilities that needed to run every month. + +## Rintik Event Monitor +Monitor event from openstack to calculate billing spent. + +# System Requirement +- Python 3 +- Openstack +- Virtualenv +- Linux environment with Systemd + +# Pre-Installation + +### Virtualenv +Make sure you installed virtualenv before installing Rintik + +```bash +pip3 install virtualenv +``` + +### Openstack Service Notification +You need to enable notification for this openstack service: +- Nova +- Cinder +- Neutron + +### Nova +Add configuration below on `[oslo_messaging_notifications]` + +``` +driver = messagingv2 +topics = notifications +``` + +Add configuration below on `` + +`` +notify_on_state_change = vm_and_task_state +notification_format = unversioned +`` + +### Cinder & Neutron + +Add configuration below on `[oslo_messaging_notifications]` + +``` +driver = messagingv2 +topics = notifications +``` + +### Kolla Note +If you using Kolla, please add configuration above on all service container. For example on Nova you should put the config on `nova-api`, `nova-scheduler`, etc. + +# Installation + +Clone the latest source code and put it on any directory you want. Here i assume you put it on `/var/rintik/` + +```bash +cd /var/rintik/ +git clone {repository} +cd rintik +``` + +Then create virtualenv and activate it +```bash +virtualenv env --python=python3.8 +source env/bin/activate +pip install -r requirements.txt +``` + +Then create a configuration file, just copy from sample file and modify as your preference. + +```bash +cp core/local_settings.py.sample core/local_settings.py +``` + +Please read [Local Setting Configuration](#local-setting-configuration) to get to know about what configuration you should change. + +Then run the database migration + +```bash +python manage.py migrate +``` + +Then create first superuser + +```bash +python manage.py createsuperuser +``` + +## Local Setting Configuration + +### RINTIK_NOTIFICATION_URL (required) +A Messaging Queue URL that used by Openstack, usually it is a RabbitMQ URL. + +Example: +``` +RINTIK_NOTIFICATION_URL = "rabbit://openstack:password@127.0.0.1:5672/" +``` + +### RINTIK_NOTIFICATION_TOPICS (required) +A list of topic notification topic that is configured on each openstack service + +Example: +``` +RINTIK_NOTIFICATION_TOPICS = ["notifications"] +``` + + +### DATABASE +By default, it will use Sqlite. If you want to change it to other database please refer to Django Setting documentation. + +- https://docs.djangoproject.com/en/3.2/ref/settings/#databases +- https://docs.djangoproject.com/en/3.2/ref/databases/ + +## API Installation + +To install Rintik API, you need to execute this command. + +```bash +./bin/setup_api.sh +``` + +This will install `rintik_api` service + +To start the service use this command +```bash +systemctl enable rintik_api +systemctl start rintik_api +``` + +An API server will be open on port `8182`. + +## Event Monitor Installation + +To install Rintik API, you need to execute this command. + +```bash +./bin/setup_event_montor.sh +``` + + +This will install `rintik_event_monitor` service + +To start the service use this command +```bash +systemctl enable rintik_event_monitor +systemctl start rintik_event_monitor +``` + +## Cron Installation + +There is a cronjob that needed to be run every month on 00:01 AM. This cronjob will finish all in progress invoice and start new invoice for the next month. + +To install it, you can use `crontab -e`. + +Put this expression on the crontab + +``` +1 0 1 * * $rintik_dir/bin/process_invoice.sh +``` + +Replace $rintik_dir with the directory of where rintik is located. Example +``` +1 0 1 * * /etc/rintik/bin/process_invoice.sh +``` \ No newline at end of file diff --git a/bin/process_invoice.sh b/bin/process_invoice.sh new file mode 100755 index 0000000..c3e840e --- /dev/null +++ b/bin/process_invoice.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +cd $SCRIPT_DIR || exit +cd .. +./env/bin/python manage.py process_invoice diff --git a/bin/setup_api.sh b/bin/setup_api.sh new file mode 100755 index 0000000..3a46645 --- /dev/null +++ b/bin/setup_api.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +echo "Installing Rintik API Service" +rintik_dir=`pwd -P` + +echo "Riktik dir is $rintik_dir" + +rintik_dir_sub=${rintik_dir//\//\\\/} +sed "s/{{rintik_dir}}/$rintik_dir_sub/g" "$rintik_dir"/script/rintik_api.service > /etc/systemd/system/rintik_api.service + +echo "Rintik API Service Installed on /etc/systemd/system/rintik_api.service" +echo "Done! you can enable Rintik API with systemctl start rintik_api" \ No newline at end of file diff --git a/bin/setup_event_monitor.sh b/bin/setup_event_monitor.sh new file mode 100755 index 0000000..1fe1f0d --- /dev/null +++ b/bin/setup_event_monitor.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +echo "Installing Rintik API Service" +rintik_dir=`pwd -P` + +echo "Riktik dir is $rintik_dir" + +rintik_dir_sub=${rintik_dir//\//\\\/} +sed "s/{{rintik_dir}}/$rintik_dir_sub/g" "$rintik_dir"/script/rintik_event_monitor.service > /etc/systemd/system/rintik_event_monitor.service + +echo "Rintik API Service Installed on /etc/systemd/system/rintik_event_monitor.service" +echo "Done! you can enable Rintik API with systemctl start rintik_event_monitor" \ No newline at end of file diff --git a/core/management/commands/process_invoice.py b/core/management/commands/process_invoice.py index 339a426..6dc2d7c 100644 --- a/core/management/commands/process_invoice.py +++ b/core/management/commands/process_invoice.py @@ -15,6 +15,7 @@ class Command(BaseCommand): help = 'Rintik New Invoice' def handle(self, *args, **options): + print("Processing Invoice") if not get_dynamic_setting(BILLING_ENABLED): return @@ -24,6 +25,7 @@ class Command(BaseCommand): active_invoices = Invoice.objects.filter(state=Invoice.InvoiceState.IN_PROGRESS).all() for active_invoice in active_invoices: self.close_active_invoice(active_invoice) + print("Processing Done") def close_active_invoice(self, active_invoice: Invoice): active_components_map: Dict[str, Iterable[InvoiceComponentMixin]] = {} diff --git a/requirements.txt b/requirements.txt index f60d8db..b9b2d3d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,4 +7,5 @@ django-money==2.0.1 openstacksdk==0.58.0 djangorestframework==3.12.4 django-filter==2.4.0 -Markdown==3.3.4 \ No newline at end of file +Markdown==3.3.4 +gunicorn==20.1.0 \ No newline at end of file diff --git a/rintik/local_settings.py.sample b/rintik/local_settings.py.sample new file mode 100644 index 0000000..912fbe5 --- /dev/null +++ b/rintik/local_settings.py.sample @@ -0,0 +1,7 @@ +RINTIK_NOTIFICATION_URL = "rabbit://openstack:password@127.0.0.1:5672/" +RINTIK_NOTIFICATION_TOPICS = ["notifications"] + +# Currency Configuration +CURRENCIES = ('IDR', 'USD') +DEFAULT_CURRENCY = "IDR" + diff --git a/rintik/settings.py b/rintik/settings.py index ea87a7a..9a85454 100644 --- a/rintik/settings.py +++ b/rintik/settings.py @@ -144,11 +144,7 @@ LOGGING = { }, } -# Currency Configuration -CURRENCIES = ('IDR', 'USD') -DEFAULT_CURRENCY = "IDR" - -# Notification -RINTIK_NOTIFICATION_URL = "rabbit://openstack:HcmHchx2wbxZYjvbZUFkA5FObioWSkUY74DCpgvB@172.10.10.10:5672/" -RINTIK_NOTIFICATION_TOPICS = ["notifications", "cinder_notifications", "versioned_notifications"] -RINTIK_INVOICE_TAX = 10 \ No newline at end of file +try: + from .local_settings import * +except ImportError: + pass diff --git a/script/rintik_api.service b/script/rintik_api.service new file mode 100644 index 0000000..628794d --- /dev/null +++ b/script/rintik_api.service @@ -0,0 +1,12 @@ +[Unit] +Description=rintik api daemon +After=network.target + +[Service] +User=root +Group=root +WorkingDirectory={{rintik_dir}} +ExecStart={{rintik_dir}}/env/bin/gunicorn rintik.wsgi --workers 2 --bind 127.0.0.1:8000 --log-file=logs/gunicorn.log + +[Install] +WantedBy=multi-user.target diff --git a/script/rintik_event_monitor.service b/script/rintik_event_monitor.service new file mode 100644 index 0000000..9a522a3 --- /dev/null +++ b/script/rintik_event_monitor.service @@ -0,0 +1,12 @@ +[Unit] +Description=rintik event monitor daemon +After=network.target + +[Service] +User=root +Group=root +WorkingDirectory={{rintik_dir}} +ExecStart={{rintik_dir}}/env/bin/python manage.py event_monitor + +[Install] +WantedBy=multi-user.target