From 2a6822ae0b22644e991fc464a4ff7b83345d8f04 Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Wed, 3 Apr 2019 00:01:32 +0300 Subject: [PATCH] Add documentation and refactoring for file permissions --- .gitignore | 1 - README.md | 2 +- agent/downloader.py | 0 agent/monitoring_agent.py | 0 agent/netflow/netflow_handler.py | 0 agent/netflow/start_netflow.sh | 0 .../expect_scripts/dlink_DGS1100_reboot.exp | 0 devapp/expect_scripts/f601.py | 0 dhcp_lever.py | 0 dialing.py | 210 ------------ djing/local_settings.py.example | 31 +- docs/ats.md | 0 docs/install_debian.md | 310 ++++++++++++++++++ docs/{install.md => install_fedora.md} | 74 ++--- install/djing.ini | 13 + install/install_debian.sh | 37 ++- install/nginx_server.conf | 42 +++ install/robots.txt | 4 + manage.py | 0 periodic.py | 0 requirements.txt | 6 +- 21 files changed, 441 insertions(+), 289 deletions(-) mode change 100755 => 100644 agent/downloader.py mode change 100755 => 100644 agent/monitoring_agent.py mode change 100755 => 100644 agent/netflow/netflow_handler.py mode change 100755 => 100644 agent/netflow/start_netflow.sh mode change 100755 => 100644 devapp/expect_scripts/dlink_DGS1100_reboot.exp mode change 100755 => 100644 devapp/expect_scripts/f601.py mode change 100755 => 100644 dhcp_lever.py delete mode 100755 dialing.py delete mode 100644 docs/ats.md create mode 100644 docs/install_debian.md rename docs/{install.md => install_fedora.md} (83%) create mode 100644 install/djing.ini create mode 100644 install/nginx_server.conf create mode 100644 install/robots.txt mode change 100755 => 100644 manage.py mode change 100755 => 100644 periodic.py diff --git a/.gitignore b/.gitignore index 21e4a48..c759697 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ *.pyc *.db -*.txt media/* media/min/* ~*/migrations/00*.py diff --git a/README.md b/README.md index 42266be..6b9874f 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Использовано python 3, django 2, bootstrap 3, и другое в файле requirements.txt ## Содержание -* [Установка](./docs/install.md) +* [Установка](./docs/install_debian.md) * [Сервисы и API](./docs/services.md) * [Менеджеры устройств](./docs/dev.md) * [Сбор информации трафика по netflow](./docs/netflow.md) diff --git a/agent/downloader.py b/agent/downloader.py old mode 100755 new mode 100644 diff --git a/agent/monitoring_agent.py b/agent/monitoring_agent.py old mode 100755 new mode 100644 diff --git a/agent/netflow/netflow_handler.py b/agent/netflow/netflow_handler.py old mode 100755 new mode 100644 diff --git a/agent/netflow/start_netflow.sh b/agent/netflow/start_netflow.sh old mode 100755 new mode 100644 diff --git a/devapp/expect_scripts/dlink_DGS1100_reboot.exp b/devapp/expect_scripts/dlink_DGS1100_reboot.exp old mode 100755 new mode 100644 diff --git a/devapp/expect_scripts/f601.py b/devapp/expect_scripts/f601.py old mode 100755 new mode 100644 diff --git a/dhcp_lever.py b/dhcp_lever.py old mode 100755 new mode 100644 diff --git a/dialing.py b/dialing.py deleted file mode 100755 index b9042e6..0000000 --- a/dialing.py +++ /dev/null @@ -1,210 +0,0 @@ -#!/usr/bin/env python3 -from typing import Dict, Optional, AnyStr -import re -import signal -from time import sleep -from urllib.parse import urlencode -from urllib.request import urlopen -from urllib.error import HTTPError -from hashlib import sha256 - -from pid.decorator import pidfile -from djing.lib.messaging.sms import SmsSubmit, SmsDeliver -from asterisk import manager as ast_mngr - - -ASTERISK_MANAGER_AUTH = { - 'username': 'admin', - 'password': 'password', - 'host': '127.0.0.1' -} - -API_AUTH_SECRET = 'your api secret' -SERVER_DOMAIN = 'http://localhost:8000' - -outbox_messages = False - - -def calc_hash(data): - if type(data) is str: - result_data = data.encode('utf-8') - else: - result_data = bytes(data) - return sha256(result_data).hexdigest() - - -def secure_request(data: Dict) -> Optional[AnyStr]: - vars_to_hash = [str(v) for v in data.values()] - vars_to_hash.sort() - vars_to_hash.append(API_AUTH_SECRET) - sign = calc_hash('_'.join(vars_to_hash)) - data.update({'sign': sign}) - try: - with urlopen("%s/dialing/api/sms/?%s" % (SERVER_DOMAIN, urlencode(data))) as r: - return r.read() - except ConnectionRefusedError: - print('ERROR: connection refused') - except HTTPError as e: - print('ERROR:', e) - - -class SMS(object): - def __init__(self, text, who, dev): - self.text = text - self.who = who - self.dev = dev - - def __add__(self, other): - if not isinstance(other, SMS): - raise TypeError - if self.who == other.who and self.dev == other.dev: - self.text += other.text - return self - - def __str__(self): - return "%s: %s" % (self.who, self.text) - - -class ChunkedMsg(object): - def __init__(self, sms_count, ref, sms): - self.sms_count = sms_count - self.ref = ref - self.sms = sms - - -class MyAstManager(ast_mngr.Manager): - sms_chunks = list() - - def new_chunked_sms(self, count, ref, sms): - msg = ChunkedMsg(count, ref, sms) - self.sms_chunks.append(msg) - - @staticmethod - def save_sms(sms): - print('Inbox %s:' % sms.who, sms.text) - if not isinstance(sms, SMS): - raise TypeError - response = secure_request({ - 'who': sms.who, - 'dev': sms.dev, - 'text': sms.text, - 'cmd': 'save_sms' - }) - if response is not None: - print(response) - - def send_sms(self, dev, recipient, utext): - if not validate_tel(recipient): - print("Tel %s is not valid" % recipient) - return - sms = SmsSubmit(recipient, utext) - for pdu in sms.to_pdu(): - response = self.command('dongle pdu %s %s' % (dev, pdu.pdu)) - print(response.data) - - def push_text(self, sms, ref, cnt): - if not isinstance(sms, SMS): - raise TypeError - chunk = [c for c in self.sms_chunks if c.ref == ref] - chunk_len = len(chunk) - if chunk_len == 1: - chunk = chunk[0] - chunk.sms += sms - if chunk.sms_count == cnt: - self.save_sms(chunk.sms) - self.sms_chunks.remove(chunk) - - elif chunk_len == 0: - self.new_chunked_sms(cnt, ref, sms) - - def send_from_outbox(self): - messages = secure_request({'cmd': 'get_new'}) - for msg in messages: - if self.send_sms(dev='sim_8318999', recipient=msg.dst, utext=msg.text): - msg_status = 'st' - else: - msg_status = 'fd' - result = secure_request({ - 'cmd': 'update_status', - 'mid': msg.pk, - 'status': msg_status - }) - if result is not None: - print(result) - - -manager = MyAstManager() - - -def validate_tel(tel, reg=re.compile(r'^\+7978\d{7}$')): - return bool(re.match(reg, tel)) - - -def handle_shutdown(event, mngr): - print("Received shutdown event") - mngr.close() - # we could analyze the event and reconnect here - - -def signal_handler(signum, frame): - if signum != 10: - return - global outbox_messages - outbox_messages = True - - -def handle_inbox_long_sms_message(event, mngr): - if event.has_header('Message'): - pdu = event.get_header('Message') - pdu = re.sub(r'^\+CMGR:\s\d,,\d{1,3}\\r\\n', '', pdu) - sd = SmsDeliver(pdu) - data = sd.data - chunks_count = data.get('cnt') - sms = SMS( - text=data.get('text'), - who=data.get('number'), - dev=event.get_header('Device') - ) - if chunks_count is not None: - # more than 1 message - mngr.push_text(sms=sms, ref=data.get('ref'), cnt=chunks_count) - else: - # one message - mngr.save_sms(sms) - - -@pidfile(pidname='dialing.py.pid', piddir='/run') -def main(): - global outbox_messages - try: - manager.connect(ASTERISK_MANAGER_AUTH['host']) - manager.login(ASTERISK_MANAGER_AUTH['username'], ASTERISK_MANAGER_AUTH['password']) - - # register some callbacks - manager.register_event('Shutdown', handle_shutdown) - manager.register_event('DongleNewCMGR', handle_inbox_long_sms_message) # PDU Here - - # get a status report - response = manager.status() - print(response) - - signal.signal(signal.SIGUSR1, handler=signal_handler) - - while True: - if outbox_messages: - outbox_messages = False - manager.send_from_outbox() - sleep(5) - - except ast_mngr.ManagerSocketException as e: - print("Error connecting to the manager: ", e) - except ast_mngr.ManagerAuthException as e: - print("Error logging in to the manager: ", e) - except ast_mngr.ManagerException as e: - print("Error: ", e) - finally: - manager.logoff() - - -if __name__ == '__main__': - main() diff --git a/djing/local_settings.py.example b/djing/local_settings.py.example index 0f1e69e..3fc5255 100644 --- a/djing/local_settings.py.example +++ b/djing/local_settings.py.example @@ -1,6 +1,7 @@ """ Custom settings for each system """ +import os DEBUG = True @@ -13,23 +14,23 @@ PAGINATION_ITEMS_PER_PAGE = 20 # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = '!!!!!!!!!!!!!!!!!!!!!!!!YOUR SECRET KEY!!!!!!!!!!!!!!!!!!!!!!!!' +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + DATABASES = { 'default': { - #'OPTIONS': { - # 'init_command': "SET sql_mode='STRICT_TRANS_TABLES', default_storage_engine=INNODB", - # 'isolation_level': 'read uncommitted' - #}, - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), - #'ENGINE': 'django.db.backends.mysql', - #'NAME': 'djing_db', - #'USER': 'DJING_MYSQL_USERNAME', # You can change the user name - #'PASSWORD': 'DJING_MYSQL_PASSWORD', # You can change the password - #'HOST': 'localhost', - #'TEST': { - # 'CHARSET': 'utf8', - # 'COLLATION': 'utf8_general_ci' - #} + 'OPTIONS': { + 'init_command': "SET sql_mode='STRICT_TRANS_TABLES', default_storage_engine=INNODB", + 'isolation_level': 'read uncommitted' + }, + 'ENGINE': 'django.db.backends.mysql', + 'NAME': 'djing_db', + 'USER': 'djinguser', # You can change the user name + 'PASSWORD': 'password', # You can change the password + 'HOST': 'localhost', + 'TEST': { + 'CHARSET': 'utf8', + 'COLLATION': 'utf8_general_ci' + } } } diff --git a/docs/ats.md b/docs/ats.md deleted file mode 100644 index e69de29..0000000 diff --git a/docs/install_debian.md b/docs/install_debian.md new file mode 100644 index 0000000..6b66dac --- /dev/null +++ b/docs/install_debian.md @@ -0,0 +1,310 @@ +## Установка: +Работа предполагается на python3. +Я предпочитаю запускать wsgi сервер на связке uWSGI + Nginx, так что ставить будем соответствующие пакеты. + +##### Подготовка системы +Установка происходит в debian версии 9.5. + +Для начала подготовим систему, очистим и обновим пакеты. Процесс обновления долгий, так что можно пойти заварить себе чай :) +``` +# dnf clean all +# dnf -y update +``` + +Затем установим зависимости, в Fedora 25 пакеты называются так: +``` +# dnf -y install python3 python3-devel python3-pip python3-pillow mariadb mariadb-devel uwsgi nginx uwsgi-plugin-python3 net-snmp net-snmp-libs net-snmp-utils net-snmp-devel net-snmp-python git redhat-rpm-config curl-devel expect +``` + +Для Debian 9 это выглядит так: +``` +# apt install mariadb-server libmariadb-dev mariadb-client python3-dev python3-pip python3-pil uwsgi nginx uwsgi-plugin-python3 libsnmp-dev git gettext libcurl4-openssl-dev libssl-dev expect +``` + +Условимся что путь к папке с проектом находится по адресу: */var/www/djing*. +Дальше создадим каталок для web, затем создаём virtualenv, обновляем pip и ставим проект через pip: +```bash +# mkdir /var/www +# cd /var/www +# git clone --depth=1 https://github.com/nerosketch/djing.git +# python3 -m venv venv +# cd djing +# source ./venv/bin/activate +# pip3 install --upgrade pip +# export PYCURL_SSL_LIBRARY=openssl +# pip3 install -r djing/requirements.txt +# chown -R www-data:www-data /var/www/djing +# deactivate +``` + +Или, вместо этих комманд выполните инстальник из *install/install_debian.sh* если у вас *debian*, +или по аналогии для других дистрибутивов. + +Теперь давайте перейдём в баш от имени пользователя www-data, так у нас будет хватать прав на все +директории и файлы +```bash +sudo -u www-data -g www-data bash && cd / +``` + +Скопируем конфиг из примера в реальный: +```bash +$ cd /var/www/djing +$ cp djing/local_settings.py.example djing/settings.py +``` + +Затем отредактируйте конфиг для своих нужд. + +В Debian использую пользователя www-data, остаётся только назначить владельца на папки: +```bash +# chown -R www-data:www-data /var/www/djing +``` + + +### Настройка WEB Сервера +Конфиг Nginx в папке *sites-available* на моём рабочем сервере выглядит примерно так как указано +ниже, не забудьте указать в нужных местах ваш домен. +```nginx +upstream djing{ + server unix:///run/uwsgi/app/djing/socket; +} + +# Для обращений в web серверу на localhost из скриптов +server { + listen 80; + server_name localhost 127.0.0.1; + location / { + uwsgi_pass djing; + include uwsgi_params; + } + access_log /dev/null; + error_log /dev/null; +} + +# Это редирект с http на https, если у вас есть ssl сертификат +server{ + listen 80; + server_name your-domain.com; + return 301 https://your-domain.com$request_uri; +} + +# обработка http запросов. +server { + listen 80 default_server; + server_name <ваш домен>; + root /var/www/djing/; + charset utf-8; + + location = /favicon.ico { alias /var/www/djing/static/img/favicon_m.ico; } + location = /robots.txt { alias /var/www/djing/robots.txt; } + + location /media { + alias /var/www/djing/media; + expires 7d; + } + + location /static { + alias /var/www/djing/static; + expires 1d; + } + + location / { + uwsgi_pass djing; + include uwsgi_params; + } +} + +# Обработка https запросов +server { + listen 443 ssl; + ssl on; + server_name <ваш домен> www.<ваш домен>; + + ssl_certificate "/путь/к/вашему/сертификату.crt"; + ssl_certificate_key "/путь/к/вашему/сертификату.key"; + ssl_session_cache shared:SSL:1m; + ssl_session_timeout 5m; + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_prefer_server_ciphers on; + + location = /favicon.ico { alias /var/www/djing/static/img/favicon_m.ico; } + location = /robots.txt { alias /var/www/djing/robots.txt; } + + location /media { + alias /var/www/djing/media; + expires 7d; + } + + location /static { + alias /var/www/djing/static; + expires 1d; + } + + location / { + uwsgi_pass djing; + include uwsgi_params; + } +} +``` + +Это минимальный конфиг Nginx для работы. Проверте файл /run/uwsgi/djing.sock на доступность пользователю www-data для чтения. + +Далее настраиваем uWSGI. Мой конфиг для uWSGI в debian: +> /etc/uwsgi/apps-available/djing.ini +```ini +[uwsgi] +chdir=/var/www/djing +module=djing.wsgi +master=True +processes=8 +socket=/run/uwsgi/app/djing/socket +;http-socket=:8000 +chmod-socket=644 +;pidfile=/run/uwsgi/django-master.pid +vacuum=True +plugin=python3 +;disable-logging=True +venv=/var/www/djing/venv +``` + +А теперь попробуем запустить биллинг в полной связке Python - Uwsgi - Nginx. +Перейдём в папку биллинга, если вы вышли куда-то ещё, зайдём в баш из под пользователя www-data. +```bash +sudo -u www-data -g www-data bash +cd /var/www/djing +source ./venv/bin/activate +``` + +И скомпилируем переводы: +> \$ ./manage.py compilemessages -l ru + + +Попробуем запустить *uwsgi* и *djing* без *Nginx*, на порт 8000: +Раскомментируйте строку *http-socket=:8000* в файле *djing.ini*, и закомментируйте +*socket=/run/uwsgi/app/djing/socket* и *chmod-socket=644*, теперь можно попробовать запустить +> \# uwsgi --gid www-data --uid www-data /etc/uwsgi/apps-available/djing.ini + +пробуем зайти в биллинг с браузера на <адрес сервера>:8000. Вам должен показаться диалог входа в систему: +![Login screenshot](./img/login.png) + +Теперь, если всё прошло успешно, поменяйте в конфиге */etc/uwsgi.d/djing.ini* сокет с http-socket на unix socket: +Раскомментируйте это: +> socket=/run/uwsgi/app/djing/socket + +И закомментируйте эту строку: +> http-socket=:8000 + +Строка *http-socket=:8000* была для теста, чтоб посмотреть работает-ли uwsgi сам по себе. + +Теперь можно попробовать запустить *nginx* и *uwsgi*. Ставим в **djing/settings.py** опцию **DEBUG = False**, +и пробуем запустить нужные юниты: + +> \# systemctl start uwsgi\ +> \# systemctl start nginx + + +### Настраиваем биллинг +Все настройки биллинга находятся в файле *djing/settings.py*. Большинство опций вы можете найти в документации +[Django settings](https://docs.djangoproject.com/en/2.1/ref/settings). +Те опции, которые были добавлены мной в рамках проекта *djing*, описаны ниже в этом разделе документации по установке. + +#### djing/settings.py +**USE_TZ** — Это опция *Django*, но если вы не работаете в разных часовых диапазонах то я не рекомендую включать +эту опцию чтоб небыло путаницы со временем. Это связано с тем что я ещё не тестировал поведение работы со временем при +включённой опции *USE_TZ*. + +**ALLOWED_HOSTS** — Тоже опция *Django*, но важная для безопасности, укажите в списке возможные имена вашего сервера. +Подробнее в документации [Django settings](https://docs.djangoproject.com/en/2.1/ref/settings/#allowed-hosts). + +**DEFAULT_PICTURE** — Это путь к изображению по умолчанию, оно используется когда нужное изображение не найдено. + +**PAGINATION_ITEMS_PER_PAGE** — Количество выводимых элементов списка на странце с таблицей. Например, если поставить 30, +то на странице абонентов на одной странице будет выведено 30 строк абонентов. + +**DEFAULT_SNMP_PASSWORD** — Пароль snmp по умолчанию для устройств, чтоб при создании устройства он был заполнен в нужном поле. +Если нет такого пароля то оставьте пустым или None. + +**TELEPHONE_REGEXP** — Регулярное выражение для валидации номера телефона. + +**API_AUTH_SECRET** — Секретное слово для безопасной передачи комманд от скриптов. +Содержимое данных можно увидеть, но нельзя изменить. Это нельзя применять для передачи паролей, +секретных номеров, но вполне подходит для защищённого управления. Безопасность гарантируется хеш суммой +__sha256__. Секретное слово должен знать биллинг в конфиге, и доверенный скрипт на примере *agent/monitoring_agent.py* +Позаботьтесь о том чтоб скрипт нельзя было просто так прочитать, или вынесите секретное слово куда-то. Если кто-то лишний узнает +его то ваша система будет под угрозой. + +**API_AUTH_SUBNET** — Так же применяется для авторизации скриптов, но проверяет подсеть с которой была отправлена +комманда. Даже если скрипт будет знать секретное слово, но не будет находится в одной из доверенных +подсетей то в доступе будет отказано. Может быть строковым представлением подсети, например '127.0.0.1/8', или списком +подсетей в строковом представлении. Можно даже передать объект который на выходе при преобразовании в строку +даст подсеть. + +**COMPANY_NAME** — Название вашей компании, будет отображаться в шапке сайта в административной части +и в личном кабинете абонента. + +**TELEGRAM_BOT_TOKEN** — Когда вы включите оповещение через телеграм то вам сюда. + + +#### Создание БД +Подразумевается что сервер баз данных у вас уже есть, или вы его можете установить сами. +В конфиге настроить БД можно по инструкции [Django databases](https://docs.djangoproject.com/en/2.1/ref/settings/#databases). + +Убедитесть что вы в папке с проектом, комманда **pwd** должна выдать */var/www/djing*. +Чтоб создать бд, как описано в документации [Django admin \& migrate](https://docs.djangoproject.com/en/2.1/ref/django-admin/#migrate), +нужно запустить **./manage.py migrate** чтоб создать структуру БД. Вывод будет примерно таким: +``` +$ ./manage.py migrate +Operations to perform: + Apply all migrations: mapapp, contenttypes, msg_app, taskapp, accounts_app, devapp, statistics, tariff_app, admin, sessions, chatbot, auth, abonapp +Running migrations: + Rendering model states... DONE + Applying mapapp.0001_initial... OK + Applying devapp.0001_initial... OK + Applying devapp.0002_auto_20160909_1018... OK + Applying devapp.0003_device_map_dot... OK + Applying contenttypes.0001_initial... OK +... + Applying taskapp.0012_auto_20170407_0124... OK + Applying taskapp.0013_auto_20170413_1944... OK + Applying taskapp.0014_auto_20170416_1029... OK + Applying taskapp.0015_auto_20170816_1109... OK +``` + +После этого вам стоит создать супер пользователя чтоб зайти в систему. +``` +$ ./manage.py createsuperuser +``` +В интерактивном режиме ответьте на вопросы. +``` +$ ./manage.py createsuperuser +Username: username +Telephone: +12223334455 +Password: +Password (again): +Superuser created successfully. +``` +Обратите внимание на то что номер телефона это обязательное поле для заполнения. +Если у вас не выходит указать номер телефона, то проверте чтоб ваш телефон соответствовал регулярному выражению **^(\+[7,8,9,3]\d{10,11})?$**. +Если регулярное выражение вам не подхожит, то вы можете изенить его в настройках, см. опции в настройках выше. +После изменения настроек они не сразу вступят в силу, нужно перезагрузить код django, для этого перезапустите **uwsgi**: +> \# systemctl restart uwsgi + +Теперь произведите тестовый запуск: +> \$ ./manage.py runserver 192.168.0.100:8000 + +Если не подтягивается статика то проверте чтоб опция **DEBUG** в настройках была **True**. + +При условии что адрес вашего сервера *192.168.0.100*, вы сможете открыть биллинг по адресу **http://192.168.0.100:8000/**. +Введите логин и пароль супер пользователя которого вы создали по инструкции выше. + +Если вы успешно зашли то можно пробовать запускать биллинг в рабочую обстановку. +В настройках смените переменную **DEBUG** на **False** и перезапустите *uwsgi*. + +### Настраиваем демоны +Если ваша система работает с поддержкой [**systemd**](https://www.freedesktop.org/wiki/Software/systemd/) то в каталоге *systemd_units* проекта вы найдёте юниты для systemd. +Скопируйте их в каталог юнитов systemd, у меня это путь */etc/systemd/system*. +__Настоятельно рекомендую заглянуть внутрь этих юнитов__. Проверте пути исполняемых файлов, права и прочее. + +Для запуска сервиса **djing_rotate.service** вам нужно сначала настроить сбор статистики по [netflow](./netflow.md). + +Перед включением юнита *djing_telebot.service* создайте Telegram бота и впишите в файл *djing/settings.py* в переменную *TELEGRAM_BOT_TOKEN* токен вашего бота. +С помощью этого бота вы будете получать различные сообщения из биллинга. Подробнее в инструкции к [модулю оповещений](./bot.md). diff --git a/docs/install.md b/docs/install_fedora.md similarity index 83% rename from docs/install.md rename to docs/install_fedora.md index 08af960..dc7643e 100644 --- a/docs/install.md +++ b/docs/install_fedora.md @@ -2,7 +2,7 @@ Работа предполагается на python3. Я предпочитаю запускать wsgi сервер на связке uWSGI + Nginx, так что ставить будем соответствующие пакеты. -##### Подготовка системы +##### На Fedora25 нужные пакеты можно установить так: Для начала подготовим систему, очистим и обновим пакеты. Процесс обновления долгий, так что можно пойти заварить себе чай :) ``` @@ -10,41 +10,38 @@ # dnf -y update ``` -Затем установим зависимости, в Fedora 25 пакеты называются так: +Затем установим зависимости ``` -# dnf -y install python3 python3-devel python3-pip python3-pillow mariadb mariadb-devel uwsgi nginx uwsgi-plugin-python3 net-snmp net-snmp-libs net-snmp-utils net-snmp-devel net-snmp-python git redhat-rpm-config curl-devel expect +# dnf -y install python3 python3-devel python3-pip python3-pillow \ + mariadb mariadb-devel uwsgi nginx uwsgi-plugin-python3 net-snmp \ + net-snmp-libs net-snmp-utils net-snmp-devel net-snmp-python \ + git redhat-rpm-config ``` -Для Debian 9 это выглядит так: +Лучше чтоб версия python по умолчанию была третья: ``` -# apt install mariadb-server libmariadb-dev mariadb-client python3-dev python3-pip python3-pil uwsgi nginx uwsgi-plugin-python3 libsnmp-dev git gettext libcurl4-openssl-dev libssl-dev expect +# ln -sf python3 /usr/bin/python ``` Условимся что путь к папке с проектом находится по адресу: */var/www/djing*. -Дальше создадим каталок для web, затем создаём virtualenv, обновляем pip и ставим проект через pip: +Дальше создадим каталок для web, затем обновляем pip и ставим проект через pip: ``` # mkdir /var/www # cd /var/www -# git clone --depth=1 https://github.com/nerosketch/djing.git -# chown -R http:http djing -# python3 -m venv venv -# sudo -u http -g http bash -$ cd djing -$ source ./venv/bin/activate -$ pip3 install --upgrade pip -$ export PYCURL_SSL_LIBRARY=openssl -$ pip3 install -r djing/requirements.txt +# pip3 install --upgrade pip +# git clone https://github.com/nerosketch/djing.git +# pip3 install -r djing/requirements.txt ``` -Скопируем конфиг из примера в реальные: +Скопируем конфиги из примеров в реальные: ``` $ cd /var/www/djing -$ cp djing/local_settings.py.example djing/settings.py +# cp djing/settings_example.py djing/settings.py ``` -Затем отредактируйте конфиг для своих нужд. +Затем отредактируйте конфиги для своих нужд. -Для удобства в Fedora я создаю пользователя и группу http:http, и всё что связано с web-сервером запускаю от имени http. +Для удобства я создаю пользователя и группу http:http, и всё что связано с web-сервером запускаю от имени http. ``` # groupadd -r http # useradd -l -M -r -d /dev/null -g http -s /sbin/nologin http @@ -54,15 +51,6 @@ $ cp djing/local_settings.py.example djing/settings.py # chown -R http:http /run/uwsgi/ ``` -В Debian использую пользователя www-data, остаётся только назначить владельца на папки: -``` -# chown -R http:http /var/www -# chown -R http:http /etc/nginx -# chown -R http:http /etc/uwsgi.* -# chown -R http:http /run/uwsgi/ -``` - - ### Настройка WEB Сервера Конфиг Nginx на моём рабочем сервере выглядит так: ```nginx @@ -212,21 +200,13 @@ plugin=python3 **PAGINATION_ITEMS_PER_PAGE** — Количество выводимых элементов списка на странце с таблицей. Например, если поставить 30, то на странице абонентов на одной странице будет выведено 30 строк абонентов. -**PAY_SERV_ID** — Эта опция, так же как и **PAY_SECRET** опции для платёжной системы *AllTime24*, если вы используете любую -другую платёжную систему то можете удалить эти опции. - -**DIALING_MEDIA** — Путь, где биллинг сможет найти файлы записей asterisk чтоб вывести статистику звонков. -Подробнее читайте в описании работы с [АТС](./ats.ms). - **DEFAULT_SNMP_PASSWORD** — Пароль snmp по умолчанию для устройств, чтоб при создании устройства он был заполнен в нужном поле. Если нет такого пароля то оставьте пустым или None. **TELEPHONE_REGEXP** — Регулярное выражение для валидации номера телефона. -**ASTERISK_MANAGER_AUTH** — Данные для управления АТС [Asterisk](https://www.asterisk.org/), пример заполнения есть в *djing/settings_example.py*. - **API_AUTH_SECRET** — Секретное слово для безопасной передачи комманд от скриптов. -Содержимое данных можно увидеть, но нельзя изменить. Это нельзя применять лоя передачи паролей, +Содержимое данных можно увидеть, но нельзя изменить. Это нельзя применять для передачи паролей, секретных номеров, но вполне подходит для защищённого управления. Безопасность гарантируется хеш суммой __sha256__. то секретное слово должен знать биллинг в конфиге, и доверенный скрипт на примере *agent/monitoring_agent.py.py* Позаботьтесь о том чтоб скрипт нельзя было просто так прочитать, или вынесите секретное слово куда-то. Если кто-то лишний узнает @@ -288,10 +268,12 @@ Superuser created successfully. После изменения настроек они не сразу вступят в силу, нужно перезагрузить код django, для этого перезапустите **uwsgi**: > \# systemctl restart uwsgi -Теперь произведите тестовый запуск: +Теперь произведите тестовый запуск, например: > \# ./manage.py runserver 192.168.0.100:8000 -Если не подтягивается статика то проверте чтоб опция **DEBUG** в настройках была **True**. +Если не подтягивается статика то проверте чтоб опция **DEBUG** в настройках была **True**, +но в реальном окружении лучше Debug отключить, подробнее об этом тут: +[docs.djangoproject.com/en/2.1/ref/settings](https://docs.djangoproject.com/en/2.1/ref/settings/#std:setting-DEBUG) При условии что адрес вашего сервера *192.168.0.100*, вы сможете открыть биллинг по адресу **http://192.168.0.100:8000/**. Введите логин и пароль супер пользователя которого вы создали по инструкции выше. @@ -300,7 +282,8 @@ Superuser created successfully. В настройках смените переменную **DEBUG** на **False** и перезапустите *uwsgi*. ### Настраиваем демоны -Если ваша система работает с поддержкой [**systemd**](https://www.freedesktop.org/wiki/Software/systemd/) то в каталоге *systemd_units* проекта вы найдёте юниты для systemd. +Если ваша система работает с поддержкой [**systemd**](https://www.freedesktop.org/wiki/Software/systemd/) +то в каталоге *systemd_units* проекта вы найдёте юниты для systemd. Скопируйте их в каталог юнитов systemd, у меня это путь */etc/systemd/system*. __Настоятельно рекомендую заглянуть внутрь этих юнитов__. Проверте пути исполняемых файлов, права и прочее. @@ -308,14 +291,3 @@ __Настоятельно рекомендую заглянуть внутрь Перед включением юнита *djing_telebot.service* создайте Telegram бота и впишите в файл *djing/settings.py* в переменную *TELEGRAM_BOT_TOKEN* токен вашего бота. С помощью этого бота вы будете получать различные сообщения из биллинга. Подробнее в инструкции к [модулю оповещений](./bot.md). - -А теперь включим и запустим нужные демоны -```shell -# systemctl daemon-reload -# systemctl enable djing_queue.service -# systemctl start djing_queue.service -# systemctl enable djing_rotate.timer -# systemctl start djing_rotate.timer -# systemctl enable djing_telebot.service -# systemctl start djing_telebot.service -``` diff --git a/install/djing.ini b/install/djing.ini new file mode 100644 index 0000000..f0843ef --- /dev/null +++ b/install/djing.ini @@ -0,0 +1,13 @@ +[uwsgi] +chdir=/var/www/djing +module=djing.wsgi +master=True +processes=8 +socket=/run/uwsgi/app/djing/socket +;http-socket=:8000 +chmod-socket=644 +;pidfile=/run/uwsgi/django-master.pid +vacuum=True +plugin=python3 +;disable-logging=True +venv=/var/www/djing/venv \ No newline at end of file diff --git a/install/install_debian.sh b/install/install_debian.sh index a16cf74..2e135ba 100644 --- a/install/install_debian.sh +++ b/install/install_debian.sh @@ -2,19 +2,25 @@ PATH=/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin -apt-get -y update +apt -y update +apt -y upgrade sleep 1 -apt-get -y upgrade - -sleep 1 -apt-get -y install mariadb-server libmariadb-dev mariadb-client python3-dev python3-pip python3-pil python3-venv uwsgi nginx uwsgi-plugin-python3 libsnmp-dev git gettext libcurl4-openssl-dev libssl-dev expect +apt -y install mariadb-server libmariadb-dev libmariadbclient-dev \ + mariadb-client python3-dev python3-pip python3-pil python3-venv uwsgi \ + nginx uwsgi-plugin-python3 libsnmp-dev git gettext libcurl4-openssl-dev \ + libssl-dev expect sleep 3 mkdir -p /var/www cd /var/www +mysql -u root -e "create database djing_db charset utf8 collate utf8_general_ci;" +mysql -u root -e "create user 'djinguser'@'localhost' identified by 'password';" +mysql -u root -e "grant all privileges on djing_db.* to 'djinguser'@'localhost';" +mysql -u root -e "flush privileges;" + git clone https://github.com/nerosketch/djing.git -b devel djing cd djing python3 -m venv venv @@ -22,7 +28,24 @@ source ./venv/bin/activate pip3 install --upgrade pip export PYCURL_SSL_LIBRARY=openssl pip3 install -r requirements.txt -cp djing/local_settings.py.example djing/settings.py +cp djing/local_settings.py.example djing/local_settings.py +./manage.py migrate +./manage.py compilemessages -l ru deactivate -chown -R www-data:www-data /var/www +cp install/robots.txt robots.txt +cp install/djing.ini /etc/uwsgi/apps-available/djing.ini +ln -s /etc/uwsgi/apps-available/djing.ini /etc/uwsgi/apps-enabled/djing.ini +cp install/nginx_server.conf /etc/nginx/sites-available/djing.conf +ln -s /etc/nginx/sites-available/djing.conf /etc/nginx/sites-enabled/djing.conf + +chown -R www-data:www-data /var/www/djing + +# dirs +find . -type d \( -path ./venv -o -path ./src -o -path ./.git \) -prune -o -type d -exec chmod 750 {} \; +# files +find . -type d \( -path ./venv -o -path ./src -o -path ./.git \) -prune -o -type f -exec chmod 640 {} \; +# exec scripts +chmod 750 dhcp_lever.py manage.py periodic.py devapp/expect_scripts/dlink_DGS1100_reboot.exp +chmod 400 djing/settings.py + diff --git a/install/nginx_server.conf b/install/nginx_server.conf new file mode 100644 index 0000000..254135d --- /dev/null +++ b/install/nginx_server.conf @@ -0,0 +1,42 @@ +upstream djing{ + server unix:///run/uwsgi/app/djing/socket; +} + +# Для обращений в web серверу на localhost из скриптов +server { + listen 80; + server_name localhost 127.0.0.1; + location / { + uwsgi_pass djing; + include uwsgi_params; + } + access_log /dev/null; + error_log /dev/null; +} + + +# обработка http запросов. +server { + listen 80 default_server; + server_name _; + root /var/www/djing/; + charset utf-8; + + location = /favicon.ico { alias /var/www/djing/static/img/favicon_m.ico; } + location = /robots.txt { alias /var/www/djing/robots.txt; } + + location /media { + alias /var/www/djing/media; + expires 7d; + } + + location /static { + alias /var/www/djing/static; + expires 1d; + } + + location / { + uwsgi_pass djing; + include uwsgi_params; + } +} diff --git a/install/robots.txt b/install/robots.txt new file mode 100644 index 0000000..1a2a056 --- /dev/null +++ b/install/robots.txt @@ -0,0 +1,4 @@ +User-agent: * +Allow: /$ +Allow: /accounts/login/ +Disallow: / \ No newline at end of file diff --git a/manage.py b/manage.py old mode 100755 new mode 100644 diff --git a/periodic.py b/periodic.py old mode 100755 new mode 100644 diff --git a/requirements.txt b/requirements.txt index 2a218a6..a064861 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,8 +9,8 @@ netaddr #xmltodict dicttoxml -# db client for Postgres -psycopg2-binary +# db client for Mariadb +mysqlclient easysnmp pid @@ -23,9 +23,7 @@ django-bootstrap3 requests webdavclient -pyst2 transliterate -asterisk django-encrypted-model-fields # django-xmlview for pay system allpay