мета-данные страницы
  •  

Различия

Показаны различия между двумя версиями страницы.

Ссылка на это сравнение

Следующая версия
Предыдущая версия
poleznosti:bareos_reports [2024/09/25 06:15] – создано Администраторpoleznosti:bareos_reports [2024/09/25 07:20] (текущий) – [Создаем демона для reports_bareos.py] Администратор
Строка 3: Строка 3:
 И я решил сам сделать такой функционал т.к. смотреть через **bconsole** не очень удобно из-за привязки записанных файлов к заданию **job**\\ И я решил сам сделать такой функционал т.к. смотреть через **bconsole** не очень удобно из-за привязки записанных файлов к заданию **job**\\
 Я изучил структуру базы данных и зависимости таблиц между собой, что бы понять какие данные мне нужно включить в отчетность и что бы ничего лишнего не попало туда. Я изучил структуру базы данных и зависимости таблиц между собой, что бы понять какие данные мне нужно включить в отчетность и что бы ничего лишнего не попало туда.
- 
 ===== Кратко описываю что мне нужно извлечь из базы ===== ===== Кратко описываю что мне нужно извлечь из базы =====
 Есть таблицы **job**, **file**, **media**\\ Есть таблицы **job**, **file**, **media**\\
Строка 66: Строка 65:
 ) TO '/ВАШ ПУТЬ/report.txt' WITH (FORMAT csv, HEADER); ) TO '/ВАШ ПУТЬ/report.txt' WITH (FORMAT csv, HEADER);
 </code> </code>
 +
 +Но это все сырые данные и так мы только убедились что все работает, теперь нужно создать веб интерфейс и прикрутить кнопку в основной веб интерфейс bareos
 +===== Создание веб интерфейса =====
 +Создаем такую структуру
 +<code | download>
 +/var/www/html/
 +└── reports_bareos
 +    ├── reports_bareos.py
 +    ├── static
 +    │   └── style.css
 +    └── templates
 +        ├── index.html
 +        └── report.html
 +</code>
 +==== Содержимое файла index.html ====
 +<code | download>
 +<!DOCTYPE html>
 +<html lang="ru">
 +<head>
 +    <meta charset="UTF-8">
 +    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 +    <title>Форма для отчета</title>
 +    <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
 +</head>
 +<body>
 +    <h1>Форма для отчета</h1>
 +    <form action="/report" method="get">
 +        <label for="volumename">Номер ленты (Пример 000005):</label>
 +        <input type="text" id="volumename" name="volumename">
 +
 +        <label for="start_date">Дата начала:</label>
 +        <input type="date" id="start_date" name="start_date">
 +
 +        <label for="end_date">Дата окончания:</label>
 +        <input type="date" id="end_date" name="end_date">
 +
 +        <input type="submit" value="Сформировать отчет">
 +    </form>
 +</body>
 +</html>
 +</code>
 +==== Содержимое файла report.html ====
 +<code | download>
 +<!DOCTYPE html>
 +<html lang="ru">
 +<head>
 +    <meta charset="UTF-8">
 +    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 +    <title>Отчет</title>
 +    <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
 +</head>
 +<body>
 +    <h1>Отчет</h1>
 +    <table border="1">
 +        <tr>
 +            <th>Volume Name</th>
 +            <th>File Name</th>
 +            <th>Job Name</th>
 +            <th>Job ID</th>
 +            <th>Media Type</th>
 +            <th>Start Time</th>
 +            <th>End Time</th>
 +            <th>Pool ID</th>
 +        </tr>
 +        {% for row in reports %}
 +        <tr>
 +            <td>{{ row[0] }}</td>
 +            <td>{{ row[1] }}</td>
 +               <td>{{ row[2] }}</td>
 +               <td>{{ row[3] }}</td>
 +               <td>{{ row[4] }}</td>
 +               <td>{{ row[5] }}</td>
 +               <td>{{ row[6] }}</td>
 +               <td>{{ row[7] }}</td>
 +           </tr>
 +           {% endfor %}
 +       </table>
 +       <br>
 +       <a href="/">Вернуться назад</a>
 +   </body>
 +   </html>
 +</code>
 +==== Содержимое файла style.css ====
 +<code | download>
 +body {
 +    font-family: Arial, sans-serif;
 +    background-color: #f4f4f4;
 +    margin: 0;
 +    padding: 20px;
 +}
 +
 +h1 {
 +    text-align: center;
 +    color: #333;
 +}
 +
 +form {
 +    max-width: 600px;
 +    margin: auto;
 +    background: #fff;
 +    padding: 20px;
 +    border-radius: 8px;
 +    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
 +}
 +
 +label {
 +    display: block;
 +    margin-bottom: 8px;
 +    color: #555;
 +}
 +
 +input[type="text"],
 +input[type="date"] {
 +    width: 100%;
 +    padding: 10px;
 +    margin-bottom: 15px;
 +    border: 1px solid #ccc;
 +    border-radius: 4px;
 +}
 +
 +input[type="submit"] {
 +    background-color: #5cb85c;
 +    color: white;
 +    border: none;
 +    padding: 10px 15px;
 +    border-radius: 4px;
 +    cursor: pointer;
 +    font-size: 16px;
 +    transition: background-color 0.3s;
 +}
 +
 +input[type="submit"]:hover {
 +    background-color: #4cae4c;
 +}
 +
 +/* Стили для таблицы */
 +table {
 +    width: 100%;
 +    border-collapse: collapse;
 +    margin-top: 20px;
 +}
 +
 +table, th, td {
 +    border: 1px solid #ccc;
 +}
 +
 +th {
 +    background-color: #5cb85c;
 +    color: white;
 +    padding: 10px;
 +}
 +
 +td {
 +    padding: 10px;
 +    text-align: center;
 +}
 +
 +/* Стили для ссылки */
 +a {
 +    display: block;
 +    text-align: center;
 +    margin-top: 20px;
 +    color: #5cb85c;
 +    text-decoration: none;
 +}
 +
 +a:hover {
 +    text-decoration: underline;
 +}
 +</code>
 +===== Создаем логику работы (backend) =====
 +Логику будем описывать с помощью **Python** и фреймворка **Flask**
 +==== Содержимое файла reports_bareos.py ====
 +<code | download>
 +from flask import Flask, request, render_template
 +import psycopg2
 +
 +app = Flask(__name__)
 +
 +def get_db_connection():
 +    conn = psycopg2.connect(dbname='ВАША БАЗА', user='ВАШ ПОЛЬЗОВАТЕЛЬ', password='ВАШ ПАРОЛЬ', host='localhost')
 +    return conn
 +
 +@app.route('/')
 +def index():
 +    return render_template('index.html')
 +
 +@app.route('/report', methods=['GET'])
 +def report():
 +    volumename = request.args.get('volumename')
 +    start_date = request.args.get('start_date')
 +    end_date = request.args.get('end_date')
 +
 +    conn = get_db_connection()
 +    cur = conn.cursor()
 +
 +    query = '''
 +    SELECT
 +        m.volumename AS volumename,
 +        f.name AS file_name,
 +        j.name AS job_name,
 +        j.jobid AS jobid,
 +        m.mediatype AS mediatype,
 +        j.starttime AS starttime,
 +        j.endtime AS endtime,
 +        m.poolid AS poolid
 +    FROM
 +        public.job j
 +    JOIN
 +        public.file f ON j.jobid = f.jobid
 +    JOIN
 +        public.media m ON m.poolid IS NOT NULL
 +    WHERE
 +        j.name = 'BackupOnTape' AND
 +        m.mediatype = 'LTO' AND
 +        m.poolid = 2
 +    '''
 +
 +    if volumename:
 +        query += ' AND m.volumename = %s'
 +        cur.execute(query, (volumename,))
 +    else:
 +        cur.execute(query)
 +
 +    reports = cur.fetchall()
 +
 +    cur.close()
 +    conn.close()
 +
 +    # Фильтруем строки, у которых file_name пустая
 +    reports = [row for row in reports if row[1]]  # row[1] - это file_name
 +
 +    return render_template('report.html', reports=reports)
 +
 +if __name__ == '__main__':
 +    app.run(host='0.0.0.0', port=5000, debug=True)
 +</code>
 +===== Тестируем =====
 +Откройте порт 5000 в вашем firewall если это необходимо\\
 +Далее нужно вручную запустить приложение командой
 +<code>
 +python /var/www/html/reports_bareos.py
 +</code>
 +Теперь идем в браузер
 +<code>http://ВАШ IP:5000</code>
 +И вы увидите вот эту форму\\
 +{{:poleznosti:pasted:20240925-093950.png?nolink}}\\
 +Значит все идет как нужно. Но запускать таким образом приложение не удобно, нужно сделать его отдельным демоном в системе
 +===== Создаем демона для reports_bareos.py =====
 +Открываем
 +<code>
 +nano /etc/systemd/system/reports_bareos.service
 +</code>
 +Содержимое будет примерно такое
 +<code | download>
 +[Unit]
 +Description=Flask Application for Reports Bareos
 +After=network.target
 +
 +[Service]
 +User=bareos
 +Group=bareos
 +WorkingDirectory=/var/www/html/reports_bareos
 +ExecStart=/var/lib/bareos/.local/bin/gunicorn -w 4 -b 0.0.0.0:5000 reports_bareos:app
 +Restart=always
 +RestartSec=10
 +Environment="FLASK_ENV=development"
 +Environment="PATH=/var/lib/bareos/.local/bin:$PATH"
 +StandardOutput=append:/var/log/reports_bareos.log
 +StandardError=append:/var/log/reports_bareos.log
 +
 +[Install]
 +WantedBy=multi-user.target
 +</code>
 +Запускаем демона и проверяем его
 +<code>
 +systemctl daemon-reload
 +systemctl enable reports_bareos.service
 +systemctl start reports_bareos.service
 +</code>
 +<code>
 +systemctl status reports_bareos.service
 +</code>
 +{{:poleznosti:pasted:20240925-094718.png?nolink}}\\
 +Теперь идем в браузер
 +<code>http://ВАШ IP:5000</code>
 +И вы увидите вот эту форму\\
 +{{:poleznosti:pasted:20240925-093950.png?nolink}}\\
 +Значит все получилось.
 +===== Прикручиваем кнопку отчетов в bareos-webui =====
 +Тут уже все индивидуально и куда вам будет удобнее, туда и прикручивайте, я покажу свой пример как сделал я\\
 +Внешний вид интерфейса вот такой по умолчанию\\
 +{{:poleznosti:pasted:20240925-095308.png?nolink}}\\
 +Я решил в пункте **Analytics** сделать кнопку отчетности
 +{{:poleznosti:pasted:20240925-095436.png?nolink}}\\
 +Открываем файл
 +<code>
 +nano /usr/share/bareos-webui/module/Analytics/view/analytics/analytics/index.phtml
 +</code>
 +Ищем в нем где упоминается **Stored Data** как видно на скрине выше это такой раздел\\
 +И туда отдельным пунктом добавляем кнопку перехода в наш созданный интерфейс
 +<code>
 +<li><a href="http://10.0.5.210:5000" class="nav-link">Отчетность</a></li>
 +</code>
 +Визуально выглядит вот так
 +{{:poleznosti:pasted:20240925-100458.png?nolink}}
 +
 +На этом все, мы проделали отличную работу по созданию интерфейса для отчетности.\\
 +Его можно расширять если вам необходимы еще какие-то данные из базы визуализировать