integração_influxdb
This commit is contained in:
parent
45e1300b96
commit
b5705dd55b
|
|
@ -1,4 +1,5 @@
|
|||
[
|
||||
{
|
||||
"info_html": [
|
||||
{
|
||||
"imagem_Cab": "",
|
||||
"A_cab": "..",
|
||||
|
|
@ -25,4 +26,32 @@
|
|||
"Menu_Config_text": "Configuracões",
|
||||
"Tela": "./Tela_home/Home_page.html"
|
||||
}
|
||||
]
|
||||
],
|
||||
"config_influxdb": [
|
||||
{
|
||||
"Token": "lLgq7Y2eXZ5Hxc68dkyFULevz5pO1QPjQsk23M0ETe0hWDK8n0Fa2hIfUQxOek8n0IpRcy46U3ioU3C9htr3YA==",
|
||||
"org": "iTGuys",
|
||||
"url": "http://influxdb.itguys.com.br"
|
||||
}
|
||||
],
|
||||
"queries": [
|
||||
{
|
||||
"uid": "b6f3a8d4-01a4-4c53-a2a8-123456789abc",
|
||||
"query_name": "Server CPU",
|
||||
"query": "from(bucket: \"${Bucket}\")\n |> range(start: v.timeRangeStart, stop:v.timeRangeStop)\n |> filter(fn: (r) =>\n r._measurement == \"cpustat\" and\n r._field == \"cpu\"\n )\n |> filter(fn: (r) => r[\"host\"] == \"${server}\")\n |> aggregateWindow(every: v.windowPeriod, fn: mean)",
|
||||
"description": "Consulta para obter o uso médio de CPU no último 1 hora."
|
||||
},
|
||||
{
|
||||
"uid": "a2b9d8e5-77b4-4f9d-a2b8-abcdef123456",
|
||||
"query_name": "Logical Cores",
|
||||
"query": "from(bucket: \"${Bucket}\")\n |> range(start: v.timeRangeStart, stop:v.timeRangeStop)\n |> filter(fn: (r) =>\n r._measurement == \"cpustat\" and\n r._field == \"cpus\"\n )\n |> filter(fn: (r) => r[\"host\"] == \"${server}\")\n |> limit(n:1)",
|
||||
"description": "Consulta para obter o uso médio de memória no último 1 hora."
|
||||
},
|
||||
{
|
||||
"uid": "8e214351-69ca-4160-a72f-17d46e2231ea",
|
||||
"query_name": "Total Memory",
|
||||
"query": "from(bucket: \"${Bucket}\")\n |> range(start: v.timeRangeStart, stop:v.timeRangeStop)\n |> filter(fn: (r) =>\n r._measurement == \"memory\" and\n r._field == \"memtotal\"\n )\n |> filter(fn: (r) => r[\"host\"] == \"${server}\")\n |> limit(n:1)",
|
||||
"description": "Consulta para obter a média de I/O de disco nos últimos 30 minutos."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
Flask==2.3.2 # Framework para criar APIs
|
||||
Flask-MySQLdb==0.2.0 # Integração com MySQL
|
||||
ldap3==2.9 # Biblioteca para autenticação com servidores LDAP
|
||||
python-dotenv==1.0.0 # Carregar variáveis de ambiente de arquivos .env
|
||||
PyJWT==2.6.0 # Para gerar e decodificar tokens JWT
|
||||
Flask-Cors==3.0.10 # Suporte a CORS (Cross-Origin Resource Sharing)
|
||||
Flask-WTF==1.1.1 # Proteção contra CSRF (Cross-Site Request Forgery)
|
||||
Flask-Talisman==0.8.1 # Para melhorar a segurança da aplicação
|
||||
influxdb-client==1.35.0 # Cliente para InfluxDB
|
||||
gunicorn==20.1.0 # Servidor WSGI (opcional, caso deseje usar em produção)
|
||||
359
python/server.py
359
python/server.py
|
|
@ -3,6 +3,9 @@ from flask_mysqldb import MySQL
|
|||
import ldap3
|
||||
import re
|
||||
import os
|
||||
import json
|
||||
from functools import wraps
|
||||
from collections import OrderedDict
|
||||
from dotenv import load_dotenv
|
||||
import jwt # Importa a biblioteca JWT para gerar e validar tokens
|
||||
from datetime import datetime, timedelta
|
||||
|
|
@ -10,6 +13,14 @@ from ldap3.core.exceptions import LDAPSocketOpenError, LDAPException # Importa
|
|||
from flask_cors import CORS
|
||||
from flask_wtf.csrf import CSRFProtect # Importa CSRFProtect para proteção CSRF
|
||||
from flask_talisman import Talisman
|
||||
import influxdb_client, time
|
||||
from influxdb_client import InfluxDBClient, Point, WritePrecision
|
||||
from influxdb_client.client.write_api import SYNCHRONOUS
|
||||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
||||
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
import ldap3
|
||||
|
||||
# Carregar variáveis de ambiente do arquivo .env
|
||||
load_dotenv()
|
||||
|
|
@ -44,6 +55,25 @@ app.config['SMTP_RECIPIENT'] = os.getenv('SMTP_RECIPIENT')
|
|||
|
||||
mysql = MySQL(app)
|
||||
|
||||
# Função para derivar a chave usando PBKDF2
|
||||
def derive_key(password: bytes, salt: bytes):
|
||||
kdf = PBKDF2HMAC(
|
||||
algorithm=hashes.SHA512(),
|
||||
length=32, # O tamanho da chave de AES-256 é 32 bytes
|
||||
salt=salt,
|
||||
iterations=500000,
|
||||
backend=default_backend()
|
||||
)
|
||||
key = kdf.derive(password)
|
||||
return key
|
||||
|
||||
# Função para descriptografar dados
|
||||
def decrypt_aes_cbc(ciphertext, key, iv):
|
||||
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())
|
||||
decryptor = cipher.decryptor()
|
||||
plaintext = decryptor.update(ciphertext) + decryptor.finalize()
|
||||
return plaintext
|
||||
|
||||
def recebe_smtp_variaveis_env():
|
||||
return {
|
||||
'SMTP_USERNAME': app.config['SMTP_USERNAME'],
|
||||
|
|
@ -53,6 +83,60 @@ def recebe_smtp_variaveis_env():
|
|||
'SMTP_RECIPIENT': app.config['SMTP_RECIPIENT']
|
||||
}
|
||||
|
||||
def token_required(f):
|
||||
@wraps(f) # Adiciona wraps aqui para manter o nome da função original
|
||||
def wrapper(*args, **kwargs):
|
||||
token = request.headers.get('x-access-token')
|
||||
if not token:
|
||||
return jsonify({'msg': 'Token é necessário!'}), 401
|
||||
|
||||
try:
|
||||
# Decodifica o token para validar
|
||||
data = jwt.decode(token, app.config['SECRET_KEY'], algorithms=["HS256"])
|
||||
except jwt.ExpiredSignatureError:
|
||||
# O token expirou
|
||||
return jsonify({'msg': 'Token expirado! Por favor, faça login novamente.'}), 401
|
||||
except jwt.InvalidTokenError:
|
||||
# Token inválido por qualquer outro motivo
|
||||
return jsonify({'msg': 'Token inválido!'}), 401
|
||||
|
||||
return f(*args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
def get_influxdb_config(domain, mysql):
|
||||
# Consultar o banco de dados para obter o nome da empresa com base no domínio
|
||||
cur = mysql.connection.cursor()
|
||||
cur.execute("SELECT nome FROM empresa WHERE dominio = %s", (domain,))
|
||||
empresa_result = cur.fetchone()
|
||||
cur.close()
|
||||
|
||||
# Verifica se a empresa foi encontrada
|
||||
if empresa_result is None:
|
||||
raise ValueError('Empresa não encontrada no banco de dados')
|
||||
|
||||
# Obtém o nome da empresa (empresa_result é uma tupla)
|
||||
nome_empresa = empresa_result[0]
|
||||
|
||||
# Definir o caminho do diretório onde os arquivos JSON estão armazenados
|
||||
json_directory = './json/' # Substitua pelo caminho real do diretório
|
||||
|
||||
# Nome do arquivo JSON correspondente ao nome da empresa
|
||||
json_filename = f"{nome_empresa}.json"
|
||||
|
||||
# Caminho completo para o arquivo JSON
|
||||
json_filepath = os.path.join(json_directory, json_filename)
|
||||
|
||||
# Verificar se o arquivo JSON existe
|
||||
if not os.path.isfile(json_filepath):
|
||||
raise FileNotFoundError('Arquivo JSON não encontrado para a empresa fornecida')
|
||||
|
||||
# Carregar o conteúdo do arquivo JSON mantendo a ordem
|
||||
with open(json_filepath, 'r') as json_file:
|
||||
json_data = json.load(json_file, object_pairs_hook=OrderedDict)
|
||||
|
||||
return json_data # Retorna todo o JSON carregado
|
||||
|
||||
|
||||
@app.route('/envio-smtp', methods=['GET'])
|
||||
def envio_smtp():
|
||||
smtp_variaveis_env = recebe_smtp_variaveis_env()
|
||||
|
|
@ -60,12 +144,12 @@ def envio_smtp():
|
|||
|
||||
@app.route('/login', methods=['POST'])
|
||||
@csrf.exempt # Endpoints de autenticação como este podem ser excluídos da proteção CSRF, pois o token CSRF não está disponível antes do login; remova este decorador se quiser aplicar proteção CSRF.
|
||||
|
||||
def login():
|
||||
data = request.get_json()
|
||||
username_full = data.get('username') # Extrai o e-mail completo do usuário dos dados da requisição.
|
||||
password = data.get('password') # Extrai a senha dos dados da requisição.
|
||||
|
||||
password = data.get('criptpassaword') # Extrai a senha dos dados da requisição.
|
||||
print(username_full)
|
||||
print(data.get('criptpassaword'))
|
||||
# Validação do formato do e-mail
|
||||
if not re.match(r"[^@]+@[^@]+\.[^@]+", username_full):
|
||||
return jsonify({'msg': 'Formato de e-mail inválido'}), 400
|
||||
|
|
@ -123,28 +207,9 @@ def login():
|
|||
# Captura qualquer outra exceção LDAP genérica
|
||||
return jsonify({'Erro 500': f'Erro LDAP: {str(e)}'}), 500
|
||||
|
||||
# Decorador para proteger rotas com JWT
|
||||
def token_required(f):
|
||||
def wrapper(*args, **kwargs):
|
||||
token = request.headers.get('x-access-token')
|
||||
if not token:
|
||||
return jsonify({'msg': 'Token é necessário!'}), 401
|
||||
|
||||
try:
|
||||
# Decodifica o token para validar
|
||||
data = jwt.decode(token, app.config['SECRET_KEY'], algorithms=["HS256"])
|
||||
except jwt.ExpiredSignatureError:
|
||||
# O token expirou
|
||||
return jsonify({'msg': 'Token expirado! Por favor, faça login novamente.'}), 401
|
||||
except jwt.InvalidTokenError:
|
||||
# Token inválido por qualquer outro motivo
|
||||
return jsonify({'msg': 'Token inválido!'}), 401
|
||||
|
||||
return f(*args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
@app.route('/mounting', methods=['GET'])
|
||||
@token_required # Garante que o usuário esteja autenticado e o token JWT seja validado
|
||||
@token_required
|
||||
def mounting():
|
||||
# Decodifica o token para obter o e-mail do usuário
|
||||
token = request.headers.get('x-access-token')
|
||||
|
|
@ -154,6 +219,7 @@ def mounting():
|
|||
# Extrair o domínio do email do usuário autenticado
|
||||
domain = username_full.split('@')[1]
|
||||
|
||||
# Verifica se o usuário está autenticado
|
||||
if not username_full:
|
||||
return jsonify({'msg': 'Token inválido!'}), 401
|
||||
|
||||
|
|
@ -163,6 +229,7 @@ def mounting():
|
|||
empresa_result = cur.fetchone()
|
||||
cur.close()
|
||||
|
||||
# Verifica se a empresa foi encontrada
|
||||
if empresa_result is None:
|
||||
return jsonify({'msg': 'Empresa não encontrada no banco de dados para o domínio fornecido'}), 404
|
||||
|
||||
|
|
@ -182,8 +249,248 @@ def mounting():
|
|||
if not os.path.isfile(json_filepath):
|
||||
return jsonify({'msg': 'Arquivo JSON não encontrado para a empresa fornecida'}), 404
|
||||
|
||||
# Retornar o conteúdo do arquivo JSON
|
||||
return send_from_directory(json_directory, json_filename, as_attachment=False)
|
||||
# Carregar o conteúdo do arquivo JSON mantendo a ordem
|
||||
with open(json_filepath, 'r') as json_file:
|
||||
json_data = json.load(json_file, object_pairs_hook=OrderedDict)
|
||||
|
||||
# Extrair apenas o conteúdo de 'info_html'
|
||||
info_html_content = json_data.get('info_html', {})
|
||||
|
||||
# Retornar a resposta JSON com apenas o conteúdo de 'info_html'
|
||||
return jsonify(info_html_content)
|
||||
|
||||
@app.route('/api/options', methods=['GET'])
|
||||
@token_required
|
||||
@csrf.exempt
|
||||
def get_options():
|
||||
client = None
|
||||
try:
|
||||
# Decodifica o token para obter o e-mail do usuário
|
||||
token = request.headers.get('x-access-token')
|
||||
data = jwt.decode(token, app.config['SECRET_KEY'], algorithms=["HS256"])
|
||||
username_full = data['user']
|
||||
|
||||
# Extrair o domínio do email do usuário autenticado
|
||||
domain = username_full.split('@')[1]
|
||||
|
||||
# Carregar as configurações do InfluxDB a partir do JSON
|
||||
json_data = get_influxdb_config(domain, mysql)
|
||||
|
||||
# Extrair o token de 'config_influxdb'
|
||||
config_influxdb = json_data.get('config_influxdb', [])
|
||||
|
||||
if not config_influxdb or not isinstance(config_influxdb, list):
|
||||
return jsonify({'msg': 'config_influxdb não encontrado ou inválido'}), 404
|
||||
|
||||
# Acessa o primeiro objeto da lista e obtém os detalhes necessários
|
||||
influxdb_token = config_influxdb[0].get('Token', '')
|
||||
influxdb_org = config_influxdb[0].get('org', '')
|
||||
influxdb_url = config_influxdb[0].get('url', '')
|
||||
|
||||
# Verifica se todos os dados necessários foram encontrados
|
||||
if not influxdb_token:
|
||||
return jsonify({'msg': 'Token não encontrado em config_influxdb'}), 404
|
||||
if not influxdb_org:
|
||||
return jsonify({'msg': 'Org não encontrado em config_influxdb'}), 404
|
||||
if not influxdb_url:
|
||||
return jsonify({'msg': 'URL não encontrado em config_influxdb'}), 404
|
||||
|
||||
# Inicializa o cliente InfluxDB
|
||||
client = influxdb_client.InfluxDBClient(url=influxdb_url, token=influxdb_token, org=influxdb_org)
|
||||
query_api = client.query_api()
|
||||
|
||||
# Consulta para listar os buckets disponíveis
|
||||
buckets_query = '''
|
||||
buckets()
|
||||
'''
|
||||
buckets_result = query_api.query(org=influxdb_org, query=buckets_query)
|
||||
|
||||
# Processa a lista de buckets
|
||||
buckets = []
|
||||
for table in buckets_result:
|
||||
for record in table.records:
|
||||
bucket_name = record.values.get('name') # Acessa diretamente o nome do bucket
|
||||
if bucket_name:
|
||||
buckets.append(bucket_name)
|
||||
|
||||
if len(buckets) == 0:
|
||||
return jsonify({'msg': 'Nenhum bucket encontrado'}), 404
|
||||
|
||||
# Para cada bucket, listar os nodenames diretamente
|
||||
nodenames = {}
|
||||
for bucket in buckets:
|
||||
nodenames_query = f"""
|
||||
from(bucket: \"{bucket}\")
|
||||
|> range(start: -1d)
|
||||
|> keep(columns: [\"nodename\"])
|
||||
|> distinct(column: \"nodename\")
|
||||
"""
|
||||
nodenames_result = query_api.query(org=influxdb_org, query=nodenames_query)
|
||||
|
||||
bucket_nodenames = []
|
||||
for table in nodenames_result:
|
||||
for record in table.records:
|
||||
if record.get_value() is not None: # Ignorar valores nulos
|
||||
bucket_nodenames.append(record.get_value())
|
||||
|
||||
nodenames[bucket] = bucket_nodenames
|
||||
|
||||
# Retorna a lista de buckets e nodenames como resposta JSON
|
||||
return jsonify({
|
||||
"buckets": buckets,
|
||||
"nodenames": nodenames
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({'msg': 'Erro ao recuperar opções', 'error': str(e)}), 500
|
||||
|
||||
finally:
|
||||
if client is not None:
|
||||
client.close()
|
||||
|
||||
@app.route('/api/execute_all_queries', methods=['POST'])
|
||||
@token_required
|
||||
@csrf.exempt
|
||||
def execute_all_queries():
|
||||
client = None
|
||||
try:
|
||||
# Decodifica o token para obter o e-mail do usuário
|
||||
token = request.headers.get('x-access-token')
|
||||
data = jwt.decode(token, app.config['SECRET_KEY'], algorithms=["HS256"])
|
||||
username_full = data['user']
|
||||
domain = username_full.split('@')[1]
|
||||
|
||||
# Carregar as configurações do InfluxDB e queries a partir do JSON
|
||||
json_data = get_influxdb_config(domain, mysql)
|
||||
|
||||
# Extrair as informações da requisição
|
||||
request_data = request.get_json()
|
||||
bucket = request_data.get('bucket')
|
||||
host = request_data.get('host')
|
||||
start_time = request_data.get('startTime')
|
||||
end_time = request_data.get('endTime')
|
||||
window_period = request_data.get('windowPeriod')
|
||||
|
||||
# Inicializa o cliente InfluxDB
|
||||
influxdb_token = json_data['config_influxdb'][0]['Token']
|
||||
influxdb_org = json_data['config_influxdb'][0]['org']
|
||||
influxdb_url = json_data['config_influxdb'][0]['url']
|
||||
client = influxdb_client.InfluxDBClient(url=influxdb_url, token=influxdb_token, org=influxdb_org)
|
||||
query_api = client.query_api()
|
||||
|
||||
# Lista para armazenar os resultados de cada query
|
||||
all_results = []
|
||||
|
||||
# Itera sobre todas as queries no JSON
|
||||
for query_data in json_data['queries']:
|
||||
# Substitui as variáveis na query
|
||||
query_template = query_data['query']
|
||||
query = query_template.replace("${Bucket}", bucket).replace("${server}", host)
|
||||
query = query.replace("v.timeRangeStart", start_time).replace("v.timeRangeStop", end_time)
|
||||
query = query.replace("v.windowPeriod", window_period)
|
||||
|
||||
# Executa a query
|
||||
result = query_api.query(org=influxdb_org, query=query)
|
||||
|
||||
# Processa os resultados da query
|
||||
output = []
|
||||
for table in result:
|
||||
for record in table.records:
|
||||
output.append({
|
||||
"time": record.get_time(),
|
||||
"value": record.get_value(),
|
||||
"measurement": record.get_measurement(),
|
||||
"tags": record.values # Inclui as tags relacionadas ao registro
|
||||
})
|
||||
|
||||
# Adiciona os resultados processados à lista de todas as queries
|
||||
all_results.append({
|
||||
"uid": query_data['uid'],
|
||||
"name": query_data['query_name'],
|
||||
"result": output
|
||||
})
|
||||
|
||||
# Retorna o resultado de todas as queries
|
||||
return jsonify(all_results)
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({'msg': 'Erro ao executar as queries', 'error': str(e)}), 500
|
||||
|
||||
finally:
|
||||
if client:
|
||||
client.close()
|
||||
|
||||
@app.route('/api/execute_query/<uid>', methods=['POST'])
|
||||
@token_required
|
||||
@csrf.exempt
|
||||
def execute_query(uid):
|
||||
client = None
|
||||
try:
|
||||
# Decodifica o token para obter o e-mail do usuário
|
||||
token = request.headers.get('x-access-token')
|
||||
data = jwt.decode(token, app.config['SECRET_KEY'], algorithms=["HS256"])
|
||||
username_full = data['user']
|
||||
domain = username_full.split('@')[1]
|
||||
|
||||
# Carregar as configurações de InfluxDB e queries a partir do JSON
|
||||
json_data = get_influxdb_config(domain, mysql)
|
||||
|
||||
# Extrair as informações da requisição
|
||||
request_data = request.get_json()
|
||||
bucket = request_data.get('bucket')
|
||||
host = request_data.get('host')
|
||||
start_time = request_data.get('startTime')
|
||||
end_time = request_data.get('endTime')
|
||||
window_period = request_data.get('windowPeriod')
|
||||
|
||||
# Encontra a query específica com o UID fornecido
|
||||
query_data = next((q for q in json_data['queries'] if q['uid'] == uid), None)
|
||||
|
||||
if not query_data:
|
||||
return jsonify({'msg': 'Consulta não encontrada'}), 404
|
||||
|
||||
# Substitui as variáveis na query
|
||||
query_template = query_data['query']
|
||||
query = query_template.replace("${Bucket}", bucket).replace("${server}", host)
|
||||
query = query.replace("v.timeRangeStart", start_time).replace("v.timeRangeStop", end_time)
|
||||
query = query.replace("v.windowPeriod", window_period)
|
||||
|
||||
# Inicializa o cliente InfluxDB
|
||||
influxdb_token = json_data['config_influxdb'][0]['Token']
|
||||
influxdb_org = json_data['config_influxdb'][0]['org']
|
||||
influxdb_url = json_data['config_influxdb'][0]['url']
|
||||
client = influxdb_client.InfluxDBClient(url=influxdb_url, token=influxdb_token, org=influxdb_org)
|
||||
query_api = client.query_api()
|
||||
|
||||
# Executa a query
|
||||
result = query_api.query(org=influxdb_org, query=query)
|
||||
|
||||
# Processa os resultados da query
|
||||
output = []
|
||||
for table in result:
|
||||
for record in table.records:
|
||||
output.append({
|
||||
"time": record.get_time(),
|
||||
"value": record.get_value(),
|
||||
"measurement": record.get_measurement(),
|
||||
"tags": record.values # Inclui as tags relacionadas ao registro
|
||||
})
|
||||
|
||||
# Retorna o resultado da consulta específica
|
||||
return jsonify({
|
||||
"uid": query_data['uid'],
|
||||
"name": query_data['query_name'],
|
||||
"result": output
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({'msg': 'Erro ao executar a query', 'error': str(e)}), 500
|
||||
|
||||
finally:
|
||||
if client:
|
||||
client.close()
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(host="0.0.0.0", port=5000, ssl_context=('./fullchain1.pem','./privkey1.pem'))
|
||||
app.run(host="0.0.0.0", port=5000, ssl_context=('./fullchain1.pem', './privkey1.pem'))
|
||||
|
|
|
|||
Loading…
Reference in New Issue