Novo Ambiente | Atualização 1
|
|
@ -7,6 +7,17 @@ MYSQL_PASSWORD=wNTDu1k79z{(
|
||||||
MYSQL_DB=itguys
|
MYSQL_DB=itguys
|
||||||
SMTP_USERNAME=contato.site@itguys.com.br
|
SMTP_USERNAME=contato.site@itguys.com.br
|
||||||
SMTP_PASSWORD=j5j@QaSB\Z4<)W]M|hOYbC\605zfGcv:
|
SMTP_PASSWORD=j5j@QaSB\Z4<)W]M|hOYbC\605zfGcv:
|
||||||
SMTP_HOST=172.16.150.150
|
SMTP_HOST=mail.itguys.com.br
|
||||||
SMTP_PORT=465
|
SMTP_PORT=465
|
||||||
SMTP_RECIPIENT=comercial@itguys.com.br
|
SMTP_RECIPIENT=comercial@itguys.com.br
|
||||||
|
# Configurações LDAP (Windows AD)
|
||||||
|
LDAP_SERVER=10.10.253.199/itguys.com.br
|
||||||
|
LDAP_DOMAIN=itguys.com.br
|
||||||
|
LDAP_BASE_DN=dc=itguys,dc=com,dc=br
|
||||||
|
LDAP_USER=itguys\teste.dev
|
||||||
|
LDAP_PASSWORD=123Mudar
|
||||||
|
|
||||||
|
ZAMMAD_API=http://10.10.253.59/api/v1/
|
||||||
|
ZAMMAD_USERNAME=teste.dev@itguys.com.br
|
||||||
|
ZAMMAD_PASSWORD=123Mudar
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 90 KiB |
|
|
@ -0,0 +1,43 @@
|
||||||
|
from flask import Flask, send_from_directory
|
||||||
|
from flask_mysqldb import MySQL
|
||||||
|
from .config import Config
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Importa os blueprints
|
||||||
|
from .routes.auth import auth
|
||||||
|
from .routes.perfil import perfil
|
||||||
|
from .routes.montagem import montagem
|
||||||
|
from .routes.zabbix import zabbix
|
||||||
|
from .routes.zammad import zammad
|
||||||
|
# Inicializa o MySQL
|
||||||
|
mysql = MySQL()
|
||||||
|
|
||||||
|
# Inicializa a aplicação Flask e outras extensões
|
||||||
|
def create_app():
|
||||||
|
app = Flask(__name__)
|
||||||
|
app.config.from_object(Config)
|
||||||
|
|
||||||
|
# Caminho para o diretório onde estão as imagens
|
||||||
|
app.config['IMAGE_FOLDER'] = '/var/www/Backend/itguys/ambiente_python/repositorio_img'
|
||||||
|
|
||||||
|
# Registra o endpoint para servir as imagens
|
||||||
|
@app.route('/repositorio_img/<path:filename>')
|
||||||
|
def serve_image(filename):
|
||||||
|
return send_from_directory(app.config['IMAGE_FOLDER'], filename)
|
||||||
|
|
||||||
|
# Inicializa o MySQL
|
||||||
|
mysql.init_app(app)
|
||||||
|
|
||||||
|
# Registra os blueprints
|
||||||
|
app.register_blueprint(auth)
|
||||||
|
app.register_blueprint(perfil)
|
||||||
|
app.register_blueprint(montagem)
|
||||||
|
app.register_blueprint(zabbix)
|
||||||
|
app.register_blueprint(zammad)
|
||||||
|
|
||||||
|
@app.route('/')
|
||||||
|
def home():
|
||||||
|
return "Aplicação Flask funcionando!"
|
||||||
|
|
||||||
|
return app
|
||||||
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Carrega as variáveis de ambiente do arquivo .env, se existir
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
# Configurações Gerais
|
||||||
|
SECRET_KEY = os.getenv('SECRET_KEY', 'd702717e2361ba1a31ce3b98d28ee3e24e2e6a9be8e2afd8e004f842563bacbd')
|
||||||
|
DEBUG = os.getenv('DEBUG', 'True') == 'True'
|
||||||
|
JSON_SORT_KEYS = False
|
||||||
|
|
||||||
|
# Configurações do MySQL
|
||||||
|
MYSQL_HOST = os.getenv('MYSQL_HOST', '10.10.253.56')
|
||||||
|
MYSQL_USER = os.getenv('MYSQL_USER', 'remote')
|
||||||
|
MYSQL_PASSWORD = os.getenv('MYSQL_PASSWORD', 'wNTDu1k79z{(')
|
||||||
|
MYSQL_DB = os.getenv('MYSQL_DB', 'itguys')
|
||||||
|
MYSQL_CURSORCLASS = 'DictCursor'
|
||||||
|
|
||||||
|
# Configurações do LDAP (Windows AD)
|
||||||
|
LDAP_SERVER = os.getenv('LDAP_SERVER', 'ldap://itguys.com.br') # IP/Hostname do servidor LDAP
|
||||||
|
LDAP_DOMAIN = os.getenv('LDAP_DOMAIN', 'itguys.com.br') # Domínio do AD (FQDN)
|
||||||
|
LDAP_BASE_DN = os.getenv('LDAP_BASE_DN', 'dc=itguys,dc=com,dc=br') # Distinguished Name (DN)
|
||||||
|
LDAP_USER = os.getenv('LDAP_USER', 'itguys\\teste.dev') # Usuário de serviço LDAP (formato DOMINIO\\Usuario)
|
||||||
|
LDAP_PASSWORD = os.getenv('LDAP_PASSWORD', '123Mudar') # Senha do usuário LDAP
|
||||||
|
|
||||||
|
#Api Zammad
|
||||||
|
zammad_api_url = 'http://10.10.253.59/api/v1'
|
||||||
|
zammad_token = 'L081vJ19kood2uDlTSSt59LWBaewT9-a-MH_VKno8RY'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
from .auth import auth
|
||||||
|
|
||||||
|
|
@ -0,0 +1,156 @@
|
||||||
|
from flask import Blueprint, request, jsonify, current_app
|
||||||
|
import jwt
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
import re
|
||||||
|
import ldap3
|
||||||
|
from ldap3.core.exceptions import LDAPSocketOpenError, LDAPException
|
||||||
|
from functools import wraps
|
||||||
|
from flask_mysqldb import MySQL
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# Configuração de logging para depuração
|
||||||
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
|
|
||||||
|
auth = Blueprint('auth', __name__)
|
||||||
|
mysql = MySQL()
|
||||||
|
|
||||||
|
|
||||||
|
# Decorador para validar o token JWT
|
||||||
|
def token_required(f):
|
||||||
|
@wraps(f)
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
token = request.headers.get('x-access-token')
|
||||||
|
if not token:
|
||||||
|
return jsonify({'msg': 'Token é necessário!'}), 401
|
||||||
|
|
||||||
|
try:
|
||||||
|
data = jwt.decode(token, current_app.config['SECRET_KEY'], algorithms=["HS256"])
|
||||||
|
except jwt.ExpiredSignatureError:
|
||||||
|
# Caso o token esteja expirado, gere um novo token
|
||||||
|
try:
|
||||||
|
# Obter o payload original para criar um novo token
|
||||||
|
payload = jwt.decode(token, current_app.config['SECRET_KEY'], algorithms=["HS256"], options={"verify_exp": False})
|
||||||
|
|
||||||
|
# Gere um novo token com nova validade
|
||||||
|
new_token = jwt.encode({
|
||||||
|
'user_id': payload['user_id'],
|
||||||
|
'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=1)
|
||||||
|
}, current_app.config['SECRET_KEY'], algorithm="HS256")
|
||||||
|
|
||||||
|
response = jsonify({'msg': 'Token expirado! Novo token gerado.', 'new_token': new_token})
|
||||||
|
response.status_code = 401
|
||||||
|
return response
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({'msg': 'Erro ao processar o token expirado.', 'error': str(e)}), 401
|
||||||
|
except jwt.InvalidTokenError:
|
||||||
|
return jsonify({'msg': 'Token inválido!'}), 401
|
||||||
|
|
||||||
|
return f(data, *args, **kwargs)
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
# Validação de SQL Injection
|
||||||
|
def is_valid_input(input_str):
|
||||||
|
sql_injection_pattern = r"(--|\b(SELECT|UNION|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER)\b|;|'|\")"
|
||||||
|
return not re.search(sql_injection_pattern, input_str, re.IGNORECASE)
|
||||||
|
|
||||||
|
|
||||||
|
# Validação de e-mail
|
||||||
|
def is_valid_email(email):
|
||||||
|
return re.match(r"[^@]+@[^@]+\.[^@]+", email)
|
||||||
|
|
||||||
|
|
||||||
|
# Rota de login
|
||||||
|
@auth.route('/login', methods=['POST'])
|
||||||
|
def login():
|
||||||
|
data = request.get_json()
|
||||||
|
|
||||||
|
username_full = data.get('username')
|
||||||
|
password = data.get('password')
|
||||||
|
|
||||||
|
if not username_full or not password:
|
||||||
|
return jsonify({'msg': 'Usuário e senha são obrigatórios.'}), 400
|
||||||
|
|
||||||
|
if not is_valid_input(username_full) or not is_valid_input(password):
|
||||||
|
return jsonify({'msg': 'Solicitação rejeitada devido a padrões maliciosos.'}), 422
|
||||||
|
|
||||||
|
if not is_valid_email(username_full):
|
||||||
|
return jsonify({'msg': 'Formato de e-mail inválido'}), 400
|
||||||
|
|
||||||
|
# Separar nome de usuário e domínio
|
||||||
|
try:
|
||||||
|
username, domain = username_full.split('@')
|
||||||
|
print(f" Domínio extraído: {domain}") # <-- Adiciona este print
|
||||||
|
except ValueError:
|
||||||
|
return jsonify({'msg': 'Formato de usuário inválido. Use "usuario@dominio.com".'}), 400
|
||||||
|
|
||||||
|
# Buscar informações de domínio no banco de dados
|
||||||
|
try:
|
||||||
|
with mysql.connection.cursor() as cur:
|
||||||
|
cur.execute("SELECT idempresa, ip_dominio FROM empresa WHERE dominio = %s", (domain,))
|
||||||
|
empresa_result = cur.fetchone()
|
||||||
|
|
||||||
|
|
||||||
|
if not empresa_result:
|
||||||
|
return jsonify({'msg': 'Domínio não encontrado no banco de dados'}), 404
|
||||||
|
|
||||||
|
id_empresa, ip_dominio = empresa_result
|
||||||
|
|
||||||
|
|
||||||
|
# Verificar se o usuário está associado à empresa no MySQL
|
||||||
|
with mysql.connection.cursor() as cur:
|
||||||
|
cur.execute("SELECT empresa_id, dominio FROM view_usuario_empresa WHERE usuario = %s AND dominio = %s", (username, domain))
|
||||||
|
result = cur.fetchone()
|
||||||
|
|
||||||
|
if not result:
|
||||||
|
return jsonify({'msg': 'Usuário não associado à empresa'}), 404
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Erro no banco de dados: {str(e)}")
|
||||||
|
return jsonify({'msg': 'Erro no banco de dados'}), 500
|
||||||
|
|
||||||
|
# Conexão LDAP com autenticação
|
||||||
|
ldap_server = f'ldap://{"itguys.com.br:389"}' # Altere para 'ldaps://{ip_dominio}:636' se LDAPS for usado
|
||||||
|
ldap_user = f'{domain}\\{username}' # Formato DOMAIN\username
|
||||||
|
|
||||||
|
try:
|
||||||
|
server = ldap3.Server(ldap_server, get_info=ldap3.ALL)
|
||||||
|
conn = ldap3.Connection(
|
||||||
|
server,
|
||||||
|
user=username_full,
|
||||||
|
password=password,
|
||||||
|
authentication=ldap3.SIMPLE
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if conn.bind():
|
||||||
|
token = jwt.encode({
|
||||||
|
'user': username_full,
|
||||||
|
'exp': datetime.utcnow() + timedelta(hours=1)
|
||||||
|
}, current_app.config['SECRET_KEY'], algorithm="HS256")
|
||||||
|
|
||||||
|
conn.unbind()
|
||||||
|
logging.info(f"Login bem-sucedido para usuário: {username_full}")
|
||||||
|
return jsonify({'msg': 'Login bem-sucedido', 'token': token}), 200
|
||||||
|
else:
|
||||||
|
conn.unbind()
|
||||||
|
logging.warning(f"Falha na autenticação LDAP para o usuário: {username_full}")
|
||||||
|
return jsonify({'msg': 'Falha na autenticação LDAP. Verifique credenciais.'}), 401
|
||||||
|
|
||||||
|
except LDAPSocketOpenError:
|
||||||
|
logging.error("Erro de conexão com o servidor LDAP.")
|
||||||
|
return jsonify({'msg': 'Não foi possível conectar ao servidor LDAP. Verifique o IP e a porta.'}), 503
|
||||||
|
except LDAPException as e:
|
||||||
|
logging.error(f"Erro LDAP: {str(e)}")
|
||||||
|
return jsonify({'msg': 'Erro durante a autenticação no servidor LDAP.'}), 500
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Erro inesperado: {str(e)}")
|
||||||
|
return jsonify({'msg': 'Erro inesperado durante a autenticação.'}), 500
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
import os
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
# Carrega as variáveis de ambiente do arquivo .env, se existir
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
# Configurações Gerais
|
||||||
|
SECRET_KEY = os.getenv('SECRET_KEY', 'd702717e2361ba1a31ce3b98d28ee3e24e2e6a9be8e2afd8e004f842563bacbd')
|
||||||
|
DEBUG = os.getenv('DEBUG', 'True') == 'True'
|
||||||
|
JSON_SORT_KEYS = False
|
||||||
|
|
||||||
|
# Configurações do MySQL
|
||||||
|
MYSQL_HOST = os.getenv('MYSQL_HOST', '10.10.253.56')
|
||||||
|
MYSQL_USER = os.getenv('MYSQL_USER', 'remote')
|
||||||
|
MYSQL_PASSWORD = os.getenv('MYSQL_PASSWORD', 'wNTDu1k79z{(')
|
||||||
|
MYSQL_DB = os.getenv('MYSQL_DB', 'itguys')
|
||||||
|
MYSQL_CURSORCLASS = 'DictCursor'
|
||||||
|
|
||||||
|
# Configurações do LDAP (Windows AD)
|
||||||
|
LDAP_SERVER = os.getenv('LDAP_SERVER', 'ldap://itguys.com.br') # IP/Hostname do servidor LDAP
|
||||||
|
LDAP_DOMAIN = os.getenv('LDAP_DOMAIN', 'itguys.com.br') # Domínio do AD (FQDN)
|
||||||
|
LDAP_BASE_DN = os.getenv('LDAP_BASE_DN', 'dc=itguys,dc=com,dc=br') # Distinguished Name (DN)
|
||||||
|
LDAP_USER = os.getenv('LDAP_USER', 'itguys\\teste.dev') # Usuário de serviço LDAP (formato DOMINIO\\Usuario)
|
||||||
|
LDAP_PASSWORD = os.getenv('LDAP_PASSWORD', '123Mudar') # Senha do usuário LDAP
|
||||||
|
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
from flask import Blueprint, request, jsonify, current_app
|
||||||
|
from flask_mysqldb import MySQL
|
||||||
|
import jwt
|
||||||
|
from .auth import token_required # Importa o token_required de auth.py
|
||||||
|
|
||||||
|
montagem = Blueprint('montagem', __name__, static_folder='repositorio_img')
|
||||||
|
mysql = MySQL()
|
||||||
|
|
||||||
|
@montagem.route('/mounting', methods=['GET'])
|
||||||
|
@token_required # Verificação de token para autenticação
|
||||||
|
def mounting(data):
|
||||||
|
username_full = data['user']
|
||||||
|
|
||||||
|
# Verifica se o usuário está autenticado
|
||||||
|
if not username_full:
|
||||||
|
return jsonify({'msg': 'Token inválido!'}), 401
|
||||||
|
|
||||||
|
# Extrair o nome de usuário e o domínio do email do usuário autenticado
|
||||||
|
username = username_full.split('@')[0]
|
||||||
|
domain = username_full.split('@')[1]
|
||||||
|
|
||||||
|
# Consultar o banco de dados para obter as informações do usuário (nome, img_perfil, img_fundo)
|
||||||
|
cur = mysql.connection.cursor()
|
||||||
|
cur.execute("SELECT nome, img_perfil, img_fundo FROM usuarios WHERE usuario = %s", (username,))
|
||||||
|
usuario_result = cur.fetchone()
|
||||||
|
|
||||||
|
if usuario_result is None:
|
||||||
|
cur.close()
|
||||||
|
return jsonify({'msg': 'Usuário não encontrado no banco de dados'}), 404
|
||||||
|
|
||||||
|
nome_usuario, img_perfil_path, img_fundo_path = usuario_result
|
||||||
|
|
||||||
|
perfil_MP = usuario_result['img_perfil']
|
||||||
|
fundo_MP = usuario_result['img_fundo']
|
||||||
|
|
||||||
|
# Consultar o banco de dados para obter o nome e o logo da empresa com base no domínio
|
||||||
|
cur.execute("SELECT nome, logo FROM empresa WHERE dominio = %s", (domain,))
|
||||||
|
empresa_result = cur.fetchone()
|
||||||
|
cur.close()
|
||||||
|
|
||||||
|
if empresa_result is None:
|
||||||
|
return jsonify({'msg': 'Empresa não encontrada no banco de dados para o domínio fornecido'}), 404
|
||||||
|
|
||||||
|
nome_empresa, logo_empresa_path = empresa_result
|
||||||
|
logo_MP = empresa_result['logo']
|
||||||
|
|
||||||
|
# Montar a resposta JSON com os caminhos relativos das imagens e outras informações
|
||||||
|
response_data = {
|
||||||
|
'usuario': {
|
||||||
|
'nome': username,
|
||||||
|
'img_perfil': f"/repositorio_img/{perfil_MP}", # Caminho relativo para a imagem de perfil
|
||||||
|
'img_fundo': f"/repositorio_img/{fundo_MP}" # Caminho relativo para a imagem de fundo
|
||||||
|
},
|
||||||
|
'empresa': {
|
||||||
|
'nome': domain,
|
||||||
|
'logo': f"/repositorio_img/{logo_MP}" # Caminho relativo para o logo da empresa
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return jsonify(response_data), 200
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
import os
|
||||||
|
import mimetypes
|
||||||
|
from flask import Blueprint, jsonify, send_file
|
||||||
|
from .auth import token_required
|
||||||
|
|
||||||
|
perfil = Blueprint('perfil', __name__)
|
||||||
|
|
||||||
|
def get_protected_image_path(filename):
|
||||||
|
# Definindo o caminho base UNC corretamente, sem modificá-lo
|
||||||
|
base_directory = r"\\10.10.253.56\\Backend\\itguys\\ambiente_python\\repositorio_img"
|
||||||
|
|
||||||
|
# Concatene o caminho do arquivo com base_directory
|
||||||
|
file_path = os.path.join(base_directory, filename)
|
||||||
|
print(f"Caminho gerado para a imagem: {file_path}")
|
||||||
|
|
||||||
|
# Verifique se o caminho de file_path está dentro do diretório base_directory
|
||||||
|
if os.path.commonpath([base_directory, file_path]) == base_directory:
|
||||||
|
return file_path
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@perfil.route('/repositorio_img/<path:filename>', methods=['GET'])
|
||||||
|
@token_required
|
||||||
|
def get_profile_picture(data, filename):
|
||||||
|
file_path = get_protected_image_path(filename)
|
||||||
|
|
||||||
|
if file_path and os.path.isfile(file_path):
|
||||||
|
mimetype, _ = mimetypes.guess_type(file_path)
|
||||||
|
if not mimetype:
|
||||||
|
mimetype = 'application/octet-stream'
|
||||||
|
return send_file(file_path, mimetype=mimetype)
|
||||||
|
else:
|
||||||
|
return jsonify({'msg': 'Imagem não encontrada ou acesso não permitido'}), 404
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,189 @@
|
||||||
|
from flask import Blueprint, jsonify, request
|
||||||
|
from flask_mysqldb import MySQL
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
from MySQLdb.cursors import DictCursor
|
||||||
|
|
||||||
|
zabbix = Blueprint('zabbix', __name__)
|
||||||
|
mysql = MySQL()
|
||||||
|
|
||||||
|
# Função para buscar as configurações dos servidores Zabbix do banco de dados
|
||||||
|
def get_zabbix_configs():
|
||||||
|
cursor = mysql.connection.cursor(DictCursor) # Usando DictCursor para retornar dicionários
|
||||||
|
query = "SELECT * FROM connections_zabbix"
|
||||||
|
cursor.execute(query)
|
||||||
|
configs = cursor.fetchall()
|
||||||
|
cursor.close()
|
||||||
|
return configs
|
||||||
|
|
||||||
|
# Função para autenticar no Zabbix via API JSON-RPC
|
||||||
|
def zabbix_login(url, username, password):
|
||||||
|
headers = {'Content-Type': 'application/json-rpc'}
|
||||||
|
payload = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": "user.login",
|
||||||
|
"params": {
|
||||||
|
"username": username,
|
||||||
|
"password": password
|
||||||
|
},
|
||||||
|
"id": 1,
|
||||||
|
"auth": None
|
||||||
|
}
|
||||||
|
response = requests.post(url, headers=headers, data=json.dumps(payload))
|
||||||
|
result = response.json()
|
||||||
|
if 'result' in result:
|
||||||
|
return result['result'] # Retorna o token de autenticação
|
||||||
|
else:
|
||||||
|
raise Exception(f"Erro na autenticação: {result}")
|
||||||
|
|
||||||
|
# Funções auxiliares para buscar dados no Zabbix
|
||||||
|
def get_zabbix_host_groups(auth_token, url):
|
||||||
|
headers = {'Content-Type': 'application/json-rpc'}
|
||||||
|
payload = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": "hostgroup.get",
|
||||||
|
"params": {
|
||||||
|
"output": ["groupid", "name"],
|
||||||
|
"real_hosts": True
|
||||||
|
},
|
||||||
|
"auth": auth_token,
|
||||||
|
"id": 1
|
||||||
|
}
|
||||||
|
response = requests.post(url, headers=headers, data=json.dumps(payload))
|
||||||
|
return response.json().get("result", [])
|
||||||
|
|
||||||
|
def get_zabbix_hosts(auth_token, url, group_id):
|
||||||
|
headers = {'Content-Type': 'application/json-rpc'}
|
||||||
|
payload = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": "host.get",
|
||||||
|
"params": {
|
||||||
|
"groupids": group_id,
|
||||||
|
"output": ["hostid", "name"]
|
||||||
|
},
|
||||||
|
"auth": auth_token,
|
||||||
|
"id": 2
|
||||||
|
}
|
||||||
|
response = requests.post(url, headers=headers, data=json.dumps(payload))
|
||||||
|
return response.json().get("result", [])
|
||||||
|
|
||||||
|
def get_zabbix_items(auth_token, url, host_id):
|
||||||
|
headers = {'Content-Type': 'application/json-rpc'}
|
||||||
|
payload = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": "item.get",
|
||||||
|
"params": {
|
||||||
|
"hostids": host_id,
|
||||||
|
"output": ["itemid", "name", "key_"]
|
||||||
|
},
|
||||||
|
"auth": auth_token,
|
||||||
|
"id": 3
|
||||||
|
}
|
||||||
|
response = requests.post(url, headers=headers, data=json.dumps(payload))
|
||||||
|
return response.json().get("result", [])
|
||||||
|
|
||||||
|
def get_item_data(auth_token, url, item_id):
|
||||||
|
headers = {'Content-Type': 'application/json-rpc'}
|
||||||
|
payload = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": "history.get",
|
||||||
|
"params": {
|
||||||
|
"output": "extend",
|
||||||
|
"history": 0,
|
||||||
|
"itemids": item_id,
|
||||||
|
"sortfield": "clock",
|
||||||
|
"sortorder": "DESC",
|
||||||
|
"limit": 10
|
||||||
|
},
|
||||||
|
"auth": auth_token,
|
||||||
|
"id": 4
|
||||||
|
}
|
||||||
|
response = requests.post(url, headers=headers, data=json.dumps(payload))
|
||||||
|
return response.json().get("result", [])
|
||||||
|
|
||||||
|
# Rota para listar as configurações dos servidores Zabbix
|
||||||
|
@zabbix.route('/servers', methods=['GET'])
|
||||||
|
def get_zabbix_servers(data):
|
||||||
|
try:
|
||||||
|
zabbix_configs = get_zabbix_configs()
|
||||||
|
if not zabbix_configs:
|
||||||
|
return jsonify({"message": "Nenhum servidor Zabbix encontrado"}), 404
|
||||||
|
|
||||||
|
servers = [{"name": config['name'], "type": config['type'], "url": config['url']} for config in zabbix_configs]
|
||||||
|
return jsonify(servers)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({"error": str(e)}), 500
|
||||||
|
|
||||||
|
# Rota para listar os grupos de um servidor específico
|
||||||
|
@zabbix.route('/<server_name>/groups', methods=['GET'])
|
||||||
|
def get_host_groups_route(data, server_name):
|
||||||
|
try:
|
||||||
|
zabbix_configs = get_zabbix_configs()
|
||||||
|
config = next((conf for conf in zabbix_configs if conf['name'] == server_name), None)
|
||||||
|
|
||||||
|
if config is None:
|
||||||
|
return jsonify({"error": "Servidor Zabbix não encontrado"}), 404
|
||||||
|
|
||||||
|
auth_token = zabbix_login(config['url'], config['username'], config['password'])
|
||||||
|
groups = get_zabbix_host_groups(auth_token, config['url'])
|
||||||
|
|
||||||
|
return jsonify(groups)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({"error": str(e)}), 500
|
||||||
|
|
||||||
|
# Rota para listar os hosts de um grupo específico
|
||||||
|
@zabbix.route('/<server_name>/groups/<group_id>/hosts', methods=['GET'])
|
||||||
|
|
||||||
|
def get_hosts_by_group(data, server_name, group_id):
|
||||||
|
try:
|
||||||
|
zabbix_configs = get_zabbix_configs()
|
||||||
|
config = next((conf for conf in zabbix_configs if conf['name'] == server_name), None)
|
||||||
|
|
||||||
|
if config is None:
|
||||||
|
return jsonify({"error": "Servidor Zabbix não encontrado"}), 404
|
||||||
|
|
||||||
|
auth_token = zabbix_login(config['url'], config['username'], config['password'])
|
||||||
|
hosts = get_zabbix_hosts(auth_token, config['url'], group_id)
|
||||||
|
|
||||||
|
return jsonify(hosts)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({"error": str(e)}), 500
|
||||||
|
|
||||||
|
# Rota para listar os itens de um host específico
|
||||||
|
@zabbix.route('/<server_name>/hosts/<host_id>/items', methods=['GET'])
|
||||||
|
def get_items_by_host(data, server_name, host_id):
|
||||||
|
try:
|
||||||
|
zabbix_configs = get_zabbix_configs()
|
||||||
|
config = next((conf for conf in zabbix_configs if conf['name'] == server_name), None)
|
||||||
|
|
||||||
|
if config is None:
|
||||||
|
return jsonify({"error": "Servidor Zabbix não encontrado"}), 404
|
||||||
|
|
||||||
|
auth_token = zabbix_login(config['url'], config['username'], config['password'])
|
||||||
|
items = get_zabbix_items(auth_token, config['url'], host_id)
|
||||||
|
|
||||||
|
return jsonify(items)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({"error": str(e)}), 500
|
||||||
|
|
||||||
|
# Rota para retornar os dados de um item específico
|
||||||
|
@zabbix.route('/<server_name>/items/<item_id>/data', methods=['GET'])
|
||||||
|
def get_item_history_route(data, server_name, item_id):
|
||||||
|
try:
|
||||||
|
zabbix_configs = get_zabbix_configs()
|
||||||
|
config = next((conf for conf in zabbix_configs if conf['name'] == server_name), None)
|
||||||
|
|
||||||
|
if config is None:
|
||||||
|
return jsonify({"error": "Servidor Zabbix não encontrado"}), 404
|
||||||
|
|
||||||
|
auth_token = zabbix_login(config['url'], config['username'], config['password'])
|
||||||
|
item_data = get_item_data(auth_token, config['url'], item_id)
|
||||||
|
|
||||||
|
return jsonify(item_data)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({"error": str(e)}), 500
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
from flask import Blueprint, jsonify, request
|
||||||
|
import requests
|
||||||
|
|
||||||
|
# Blueprint para rotas relacionadas ao Zammad
|
||||||
|
zammad = Blueprint('zammad', __name__)
|
||||||
|
|
||||||
|
# Configurações da API do Zammad
|
||||||
|
base_url = "http://10.10.253.59/api/v1" # URL base da API Zammad
|
||||||
|
zammad_token = "kT0IXO8aVhPoTLcMRNL290rqd9jbRhhM0zf8MgBo3n00NLChToSU6rOGnMgWA0M2" # Token da API Zammad
|
||||||
|
|
||||||
|
# Rota para listar tickets
|
||||||
|
@zammad.route('/tickets', methods=['GET'])
|
||||||
|
def listar_tickets():
|
||||||
|
try:
|
||||||
|
# Cabeçalho de autenticação para a API Zammad
|
||||||
|
headers = {
|
||||||
|
"Authorization": f"Token token={zammad_token}",
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Faz a requisição para a API Zammad
|
||||||
|
url = f"{base_url}/tickets"
|
||||||
|
response = requests.get(url, headers=headers, timeout=10) # Timeout adicionado para evitar requisições travadas
|
||||||
|
|
||||||
|
# Processa a resposta
|
||||||
|
if response.status_code == 200:
|
||||||
|
tickets = response.json()
|
||||||
|
return jsonify(tickets), 200
|
||||||
|
else:
|
||||||
|
return jsonify({
|
||||||
|
"error": f"Erro ao buscar tickets: {response.status_code}",
|
||||||
|
"details": response.text
|
||||||
|
}), response.status_code
|
||||||
|
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
# Captura problemas de conexão ou requisição
|
||||||
|
return jsonify({"error": "Erro na requisição à API", "details": str(e)}), 500
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
# Captura quaisquer outros erros inesperados
|
||||||
|
return jsonify({"error": "Erro interno ao processar a solicitação", "details": str(e)}), 500
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDojCCAyegAwIBAgISAxzDNNJ+D1PrnQBdJr/XblhmMAoGCCqGSM49BAMDMDIx
|
||||||
|
CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQDEwJF
|
||||||
|
NTAeFw0yNDA3MTgxOTE1MzlaFw0yNDEwMTYxOTE1MzhaMBwxGjAYBgNVBAMTEWRl
|
||||||
|
di5pdGd1eXMuY29tLmJyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE+OCuDmslFa26
|
||||||
|
pscnWiCESN+KsGgeEZSxAzDFMmJ0ck6wAZS2xdcFz7JJD3vHXnLSSbcJs65RotpW
|
||||||
|
Nu5MfiHyrkQe5cWYn0viyMZnnVl+ojKcDkDN24/hcsQcevr7Qm11o4ICFDCCAhAw
|
||||||
|
DgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAM
|
||||||
|
BgNVHRMBAf8EAjAAMB0GA1UdDgQWBBSCqHCjFtevuQn0TV9XYV+xrAlogjAfBgNV
|
||||||
|
HSMEGDAWgBSfK1/PPCFPnQS37SssxMZwi9LXDTBVBggrBgEFBQcBAQRJMEcwIQYI
|
||||||
|
KwYBBQUHMAGGFWh0dHA6Ly9lNS5vLmxlbmNyLm9yZzAiBggrBgEFBQcwAoYWaHR0
|
||||||
|
cDovL2U1LmkubGVuY3Iub3JnLzAcBgNVHREEFTATghFkZXYuaXRndXlzLmNvbS5i
|
||||||
|
cjATBgNVHSAEDDAKMAgGBmeBDAECATCCAQUGCisGAQQB1nkCBAIEgfYEgfMA8QB2
|
||||||
|
AN/hVuuqBa+1nA+GcY2owDJOrlbZbqf1pWoB0cE7vlJcAAABkMd8ctUAAAQDAEcw
|
||||||
|
RQIhAJaDpgmOCf/Z4lLL3gZfo1SMIEoSD6JjVBogpQexgEH5AiB8SHzgLDF9z4rk
|
||||||
|
DcUZVpukXMF+OtcuValcNEpfkZffpQB3AEiw42vapkc0D+VqAvqdMOscUgHLVt0s
|
||||||
|
gdm7v6s52IRzAAABkMd8cg0AAAQDAEgwRgIhAIvVuiNpWs0HSrUj1RHt/76L00kB
|
||||||
|
+E+MbdQF/5uMaOlEAiEApu3u5t3vrZRdt2UpTiu7Uzzl1mDWd4fC7Pmbf1HPIqgw
|
||||||
|
CgYIKoZIzj0EAwMDaQAwZgIxAMom8JO8+pOT2PpHj+cUNC3UnrbYMfrKq40gjdxH
|
||||||
|
qLA28Fo2sBBo6WSPAXSHJ23oZwIxAK60hbs1MVqUSXR8vxLEni48kc6gJ4Al4s8l
|
||||||
|
Ncumyp1du4+bi8j5oNZ7btZg8cDuig==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEVzCCAj+gAwIBAgIRAIOPbGPOsTmMYgZigxXJ/d4wDQYJKoZIhvcNAQELBQAw
|
||||||
|
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
|
||||||
|
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjQwMzEzMDAwMDAw
|
||||||
|
WhcNMjcwMzEyMjM1OTU5WjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg
|
||||||
|
RW5jcnlwdDELMAkGA1UEAxMCRTUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNCzqK
|
||||||
|
a2GOtu/cX1jnxkJFVKtj9mZhSAouWXW0gQI3ULc/FnncmOyhKJdyIBwsz9V8UiBO
|
||||||
|
VHhbhBRrwJCuhezAUUE8Wod/Bk3U/mDR+mwt4X2VEIiiCFQPmRpM5uoKrNijgfgw
|
||||||
|
gfUwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD
|
||||||
|
ATASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBSfK1/PPCFPnQS37SssxMZw
|
||||||
|
i9LXDTAfBgNVHSMEGDAWgBR5tFnme7bl5AFzgAiIyBpY9umbbjAyBggrBgEFBQcB
|
||||||
|
AQQmMCQwIgYIKwYBBQUHMAKGFmh0dHA6Ly94MS5pLmxlbmNyLm9yZy8wEwYDVR0g
|
||||||
|
BAwwCjAIBgZngQwBAgEwJwYDVR0fBCAwHjAcoBqgGIYWaHR0cDovL3gxLmMubGVu
|
||||||
|
Y3Iub3JnLzANBgkqhkiG9w0BAQsFAAOCAgEAH3KdNEVCQdqk0LKyuNImTKdRJY1C
|
||||||
|
2uw2SJajuhqkyGPY8C+zzsufZ+mgnhnq1A2KVQOSykOEnUbx1cy637rBAihx97r+
|
||||||
|
bcwbZM6sTDIaEriR/PLk6LKs9Be0uoVxgOKDcpG9svD33J+G9Lcfv1K9luDmSTgG
|
||||||
|
6XNFIN5vfI5gs/lMPyojEMdIzK9blcl2/1vKxO8WGCcjvsQ1nJ/Pwt8LQZBfOFyV
|
||||||
|
XP8ubAp/au3dc4EKWG9MO5zcx1qT9+NXRGdVWxGvmBFRAajciMfXME1ZuGmk3/GO
|
||||||
|
koAM7ZkjZmleyokP1LGzmfJcUd9s7eeu1/9/eg5XlXd/55GtYjAM+C4DG5i7eaNq
|
||||||
|
cm2F+yxYIPt6cbbtYVNJCGfHWqHEQ4FYStUyFnv8sjyqU8ypgZaNJ9aVcWSICLOI
|
||||||
|
E1/Qv/7oKsnZCWJ926wU6RqG1OYPGOi1zuABhLw61cuPVDT28nQS/e6z95cJXq0e
|
||||||
|
K1BcaJ6fJZsmbjRgD5p3mvEf5vdQM7MCEvU0tHbsx2I5mHHJoABHb8KVBgWp/lcX
|
||||||
|
GWiWaeOyB7RP+OfDtvi2OsapxXiV7vNVs7fMlrRjY1joKaqmmycnBvAq14AEbtyL
|
||||||
|
sVfOS66B8apkeFX2NY4XPEYV4ZSCe8VHPrdrERk2wILG3T/EGmSIkCYVUMSnjmJd
|
||||||
|
VQD9F6Na/+zmXCc=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDCLn1GV8AI0K5D46tNo
|
||||||
|
AlfOmKAIUjcEN4lSQ8/zb7fr2xJlb1kEV4CqgqS/pEqClXShZANiAAT44K4OayUV
|
||||||
|
rbqmxydaIIRI34qwaB4RlLEDMMUyYnRyTrABlLbF1wXPskkPe8dectJJtwmzrlGi
|
||||||
|
2lY27kx+IfKuRB7lxZifS+LIxmedWX6iMpwOQM3bj+FyxBx6+vtCbXU=
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
|
|
@ -8,4 +8,3 @@ 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
|
Flask-Talisman==0.8.1 # Para melhorar a segurança da aplicação
|
||||||
influxdb-client==1.35.0 # Cliente para InfluxDB
|
influxdb-client==1.35.0 # Cliente para InfluxDB
|
||||||
gunicorn==20.1.0 # Servidor WSGI (opcional, caso deseje usar em produção)
|
gunicorn==20.1.0 # Servidor WSGI (opcional, caso deseje usar em produção)
|
||||||
requests==2.26.0
|
|
||||||
716
python/server.py
|
|
@ -1,716 +0,0 @@
|
||||||
from flask import Flask, request, jsonify, send_from_directory,url_for,send_file
|
|
||||||
from flask_mysqldb import MySQL
|
|
||||||
from MySQLdb.cursors import DictCursor
|
|
||||||
import ldap3
|
|
||||||
import re
|
|
||||||
import requests
|
|
||||||
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
|
|
||||||
from ldap3.core.exceptions import LDAPSocketOpenError, LDAPException # Importa as exceções específicas de ldap3
|
|
||||||
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
|
|
||||||
import ldap3
|
|
||||||
|
|
||||||
# Carregar variáveis de ambiente do arquivo .env
|
|
||||||
load_dotenv()
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
|
||||||
|
|
||||||
# Configuração de cookies seguros
|
|
||||||
app.config['SESSION_COOKIE_SECURE'] = True # Cookies serão enviados apenas em conexões HTTPS
|
|
||||||
app.config['SESSION_COOKIE_HTTPONLY'] = True # Cookies não estarão acessíveis via JavaScript
|
|
||||||
|
|
||||||
Talisman(app)
|
|
||||||
# Configuração da chave secreta necessária para CSRF e JWT
|
|
||||||
app.config['SECRET_KEY'] = os.getenv('JWT_SECRET') or 'sua_chave_secreta' # Defina uma chave secreta segura
|
|
||||||
# Inicializa a proteção CSRF
|
|
||||||
csrf = CSRFProtect(app)
|
|
||||||
|
|
||||||
# Permitir apenas uma origem específica
|
|
||||||
CORS(app, resources={r"/*": {"origins": "https://dev.itguys.com.br"}})
|
|
||||||
|
|
||||||
# Configuração do MySQL usando variáveis de ambiente
|
|
||||||
app.config['MYSQL_HOST'] = os.getenv('MYSQL_HOST')
|
|
||||||
app.config['MYSQL_USER'] = os.getenv('MYSQL_USER')
|
|
||||||
app.config['MYSQL_PASSWORD'] = os.getenv('MYSQL_PASSWORD')
|
|
||||||
app.config['MYSQL_DB'] = os.getenv('MYSQL_DB')
|
|
||||||
|
|
||||||
#Configuração do SMTP usando variáveis de ambiente
|
|
||||||
app.config['SMTP_USERNAME'] = os.getenv('SMTP_USERNAME')
|
|
||||||
app.config['SMTP_HOST'] = os.getenv('SMTP_HOST')
|
|
||||||
app.config['SMTP_PASSWORD'] = os.getenv('SMTP_PASSWORD')
|
|
||||||
app.config['SMTP_PORT'] = os.getenv('SMTP_PORT')
|
|
||||||
app.config['SMTP_RECIPIENT'] = os.getenv('SMTP_RECIPIENT')
|
|
||||||
|
|
||||||
# Diretório onde as imagens sigilosas estão armazenadas
|
|
||||||
PROTECTED_FOLDER = '/var/www/ambiente_python/Respositorio_img/'
|
|
||||||
mysql = MySQL(app)
|
|
||||||
|
|
||||||
# Função auxiliar para obter o caminho completo da imagem
|
|
||||||
def get_protected_image_path(filename):
|
|
||||||
file_path = os.path.join(PROTECTED_FOLDER, filename)
|
|
||||||
# Verifica se o arquivo existe no diretório seguro
|
|
||||||
if os.path.isfile(file_path):
|
|
||||||
return file_path
|
|
||||||
return None
|
|
||||||
|
|
||||||
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('/login', methods=['POST'])
|
|
||||||
@csrf.exempt # Endpoints de autenticação como este podem ser excluídos da proteção CSRF, remova se quiser aplicar.
|
|
||||||
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.
|
|
||||||
|
|
||||||
# Verificação básica para detecção de padrões de SQL Injection
|
|
||||||
sql_injection_pattern = r"(--|\b(SELECT|UNION|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER)\b|;|'|\")"
|
|
||||||
|
|
||||||
# Checar se o username_full ou o password contêm padrões suspeitos
|
|
||||||
if re.search(sql_injection_pattern, username_full, re.IGNORECASE) or re.search(sql_injection_pattern, password, re.IGNORECASE):
|
|
||||||
return jsonify({'msg': 'A solicitação foi bem formada, mas não pôde ser atendida devido a erros semânticos.'}), 422 # Retorna o status 422
|
|
||||||
|
|
||||||
# Validação do formato do e-mail
|
|
||||||
if not re.match(r"[^@]+@[^@]+\.[^@]+", username_full):
|
|
||||||
return jsonify({'msg': 'Formato de e-mail inválido'}), 400
|
|
||||||
|
|
||||||
# Extrair o nome de usuário (parte antes do @)
|
|
||||||
username = username_full.split('@')[0]
|
|
||||||
# Separar o domínio
|
|
||||||
domain = username_full.split('@')[1]
|
|
||||||
|
|
||||||
# Verificar se o domínio existe na tabela empresa
|
|
||||||
cur = mysql.connection.cursor()
|
|
||||||
cur.execute("SELECT idempresa, ip_dominio FROM empresa WHERE dominio = %s", (domain,))
|
|
||||||
empresa_result = cur.fetchone()
|
|
||||||
|
|
||||||
if empresa_result is None: # Verifica se o domínio não existe na tabela empresa.
|
|
||||||
cur.close()
|
|
||||||
return jsonify({'msg': 'Domínio não encontrado no banco de dados'}), 404
|
|
||||||
|
|
||||||
id_empresa, ip_dominio = empresa_result # Armazena o ID da empresa e o IP do domínio encontrados no banco de dados.
|
|
||||||
|
|
||||||
# Verificar se o usuário está associado à empresa no MySQL usando a view
|
|
||||||
cur.execute("SELECT empresa_id, dominio FROM view_usuario_empresa WHERE usuario = %s AND dominio = %s", (username, domain))
|
|
||||||
result = cur.fetchone()
|
|
||||||
cur.close()
|
|
||||||
|
|
||||||
if result is None: # Verifica se o usuário não está associado à empresa.
|
|
||||||
return jsonify({'msg': 'Usuário não associado à empresa'}), 404
|
|
||||||
|
|
||||||
empresa_id, dominio_empresa = result
|
|
||||||
|
|
||||||
# Conectar ao servidor LDAP correspondente e autenticar o usuário
|
|
||||||
ldap_server = f'ldap://{ip_dominio}:389'
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Configurar o servidor LDAP
|
|
||||||
server = ldap3.Server(ldap_server)
|
|
||||||
# Tentar criar a conexão
|
|
||||||
conn = ldap3.Connection(server, user=username_full, password=password)
|
|
||||||
|
|
||||||
# Tentar autenticar o usuário
|
|
||||||
if conn.bind():
|
|
||||||
# Gerar o token JWT após autenticação bem-sucedida
|
|
||||||
token = jwt.encode({
|
|
||||||
'user': username_full,
|
|
||||||
'exp': datetime.utcnow() + timedelta(hours=1) # Token expira em 1 hora
|
|
||||||
}, app.config['SECRET_KEY'], algorithm="HS256")
|
|
||||||
|
|
||||||
return jsonify({'msg': 'Login bem-sucedido', 'token': token}), 200
|
|
||||||
else:
|
|
||||||
return jsonify({'msg': 'Falha na autenticação LDAP'}), 401
|
|
||||||
except LDAPSocketOpenError:
|
|
||||||
# Erro específico para problemas de conexão com o servidor LDAP
|
|
||||||
return jsonify({'msg': 'Não foi possível conectar ao servidor LDAP. Verifique a conexão de rede e as configurações do servidor.'}), 503
|
|
||||||
except LDAPException as e:
|
|
||||||
# Captura qualquer outra exceção LDAP genérica
|
|
||||||
return jsonify({'Erro 500': f'Erro LDAP: {str(e)}'}), 500
|
|
||||||
|
|
||||||
@app.route('/get_profile_picture/<path:filename>', methods=['GET'])
|
|
||||||
@token_required # Garante que apenas usuários autenticados possam acessar
|
|
||||||
def get_profile_picture(filename):
|
|
||||||
# O 'filename' já pode incluir subpastas, por exemplo: "usuarios/perfil/joao_perfil.jpg"
|
|
||||||
file_path = get_protected_image_path(filename)
|
|
||||||
|
|
||||||
if file_path and os.path.isfile(file_path):
|
|
||||||
return send_file(file_path, mimetype='image/jpg') # Ajuste o mimetype conforme o tipo da imagem
|
|
||||||
else:
|
|
||||||
return jsonify({'msg': 'Imagem não encontrada ou acesso não permitido'}), 404
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/mounting', methods=['GET'])
|
|
||||||
@token_required # Verificação de token para autenticação
|
|
||||||
def mounting():
|
|
||||||
# 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']
|
|
||||||
|
|
||||||
# Verifica se o usuário está autenticado
|
|
||||||
if not username_full:
|
|
||||||
return jsonify({'msg': 'Token inválido!'}), 401
|
|
||||||
|
|
||||||
# Extrair o nome de usuário e o domínio do email do usuário autenticado
|
|
||||||
username = username_full.split('@')[0]
|
|
||||||
domain = username_full.split('@')[1]
|
|
||||||
|
|
||||||
# Consultar o banco de dados para obter as informações do usuário (nome, img_perfil, img_fundo)
|
|
||||||
cur = mysql.connection.cursor()
|
|
||||||
cur.execute("SELECT nome, img_perfil, img_fundo FROM usuarios WHERE usuario = %s", (username,))
|
|
||||||
usuario_result = cur.fetchone()
|
|
||||||
|
|
||||||
if usuario_result is None:
|
|
||||||
cur.close()
|
|
||||||
return jsonify({'msg': 'Usuário não encontrado no banco de dados'}), 404
|
|
||||||
|
|
||||||
nome_usuario, img_perfil_path, img_fundo_path = usuario_result
|
|
||||||
|
|
||||||
# Consultar o banco de dados para obter o nome e o logo da empresa com base no domínio
|
|
||||||
cur.execute("SELECT nome, logo FROM empresa WHERE dominio = %s", (domain,))
|
|
||||||
empresa_result = cur.fetchone()
|
|
||||||
cur.close()
|
|
||||||
|
|
||||||
if empresa_result is None:
|
|
||||||
return jsonify({'msg': 'Empresa não encontrada no banco de dados para o domínio fornecido'}), 404
|
|
||||||
|
|
||||||
nome_empresa, logo_empresa_path = empresa_result
|
|
||||||
|
|
||||||
# Montar a resposta JSON com os caminhos relativos das imagens e outras informações
|
|
||||||
response_data = {
|
|
||||||
'usuario': {
|
|
||||||
'nome': nome_usuario,
|
|
||||||
'img_perfil': f"/get_profile_picture/{img_perfil_path}", # Caminho relativo para a imagem de perfil
|
|
||||||
'img_fundo': f"/get_profile_picture/{img_fundo_path}" # Caminho relativo para a imagem de fundo
|
|
||||||
},
|
|
||||||
'empresa': {
|
|
||||||
'nome': nome_empresa,
|
|
||||||
'logo': f"/get_profile_picture/{logo_empresa_path}" # Caminho relativo para o logo da empresa
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return jsonify(response_data), 200
|
|
||||||
|
|
||||||
@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()
|
|
||||||
|
|
||||||
# Função para buscar as configurações dos servidores Zabbix do banco de dados
|
|
||||||
# Ajustar o cursor para usar DictCursor
|
|
||||||
def get_zabbix_configs():
|
|
||||||
cursor = mysql.connection.cursor(DictCursor) # Usando DictCursor para retornar dicionários
|
|
||||||
query = "SELECT * FROM connections_zabbix"
|
|
||||||
cursor.execute(query)
|
|
||||||
configs = cursor.fetchall() # Agora retorna uma lista de dicionários
|
|
||||||
cursor.close()
|
|
||||||
return configs
|
|
||||||
|
|
||||||
# Função para autenticar no Zabbix via API JSON-RPC
|
|
||||||
def zabbix_login(url, username, password):
|
|
||||||
headers = {'Content-Type': 'application/json-rpc'}
|
|
||||||
payload = {
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"method": "user.login",
|
|
||||||
"params": {
|
|
||||||
"username": username, # Certifique-se de que é 'username' e não 'user'
|
|
||||||
"password": password
|
|
||||||
},
|
|
||||||
"id": 1,
|
|
||||||
"auth": None
|
|
||||||
}
|
|
||||||
|
|
||||||
response = requests.post(url, headers=headers, data=json.dumps(payload))
|
|
||||||
result = response.json()
|
|
||||||
|
|
||||||
if 'result' in result:
|
|
||||||
return result['result'] # Retorna o token de autenticação
|
|
||||||
else:
|
|
||||||
raise Exception(f"Erro na autenticação: {result}")
|
|
||||||
|
|
||||||
def get_zabbix_host_groups(auth_token, url):
|
|
||||||
headers = {'Content-Type': 'application/json-rpc'}
|
|
||||||
payload = {
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"method": "hostgroup.get",
|
|
||||||
"params": {
|
|
||||||
"output": ["groupid", "name"], # Retorna o ID e o nome dos grupos
|
|
||||||
"real_hosts": True # Apenas grupos com hosts reais, excluindo templates
|
|
||||||
},
|
|
||||||
"auth": auth_token,
|
|
||||||
"id": 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# Faz a requisição para a API do Zabbix
|
|
||||||
response = requests.post(url, headers=headers, data=json.dumps(payload))
|
|
||||||
|
|
||||||
# Captura e retorna o resultado da resposta
|
|
||||||
return response.json().get("result", [])
|
|
||||||
|
|
||||||
# Função para buscar os hosts de um grupo no Zabbix
|
|
||||||
def get_zabbix_hosts(auth_token, url, group_id):
|
|
||||||
headers = {'Content-Type': 'application/json-rpc'}
|
|
||||||
payload = {
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"method": "host.get",
|
|
||||||
"params": {
|
|
||||||
"groupids": group_id,
|
|
||||||
"output": ["hostid", "name"] # Retorna o ID e o nome dos hosts
|
|
||||||
},
|
|
||||||
"auth": auth_token,
|
|
||||||
"id": 2
|
|
||||||
}
|
|
||||||
|
|
||||||
response = requests.post(url, headers=headers, data=json.dumps(payload))
|
|
||||||
return response.json().get("result", [])
|
|
||||||
|
|
||||||
# Função para buscar os itens de um host no Zabbix
|
|
||||||
def get_zabbix_items(auth_token, url, host_id):
|
|
||||||
headers = {'Content-Type': 'application/json-rpc'}
|
|
||||||
payload = {
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"method": "item.get",
|
|
||||||
"params": {
|
|
||||||
"hostids": host_id,
|
|
||||||
"output": ["itemid", "name", "key_"] # Retorna o ID, nome e chave dos itens
|
|
||||||
},
|
|
||||||
"auth": auth_token,
|
|
||||||
"id": 3
|
|
||||||
}
|
|
||||||
|
|
||||||
response = requests.post(url, headers=headers, data=json.dumps(payload))
|
|
||||||
return response.json().get("result", [])
|
|
||||||
|
|
||||||
# Função para buscar o valor de um item específico no Zabbix
|
|
||||||
def get_item_data(auth_token, url, item_id):
|
|
||||||
headers = {'Content-Type': 'application/json-rpc'}
|
|
||||||
payload = {
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"method": "history.get",
|
|
||||||
"params": {
|
|
||||||
"output": "extend",
|
|
||||||
"history": 0, # Tipo 0 para dados numéricos
|
|
||||||
"itemids": item_id,
|
|
||||||
"sortfield": "clock", # Ordena pelos mais recentes
|
|
||||||
"sortorder": "DESC",
|
|
||||||
"limit": 10 # Limite de 10 resultados
|
|
||||||
},
|
|
||||||
"auth": auth_token,
|
|
||||||
"id": 4
|
|
||||||
}
|
|
||||||
|
|
||||||
response = requests.post(url, headers=headers, data=json.dumps(payload))
|
|
||||||
return response.json().get("result", [])
|
|
||||||
|
|
||||||
@app.route('/zabbix/servers', methods=['GET'])
|
|
||||||
@token_required
|
|
||||||
def get_zabbix_servers():
|
|
||||||
try:
|
|
||||||
# Busca as configurações do banco de dados
|
|
||||||
zabbix_configs = get_zabbix_configs() # Certifique-se de que essa função está retornando dados válidos
|
|
||||||
|
|
||||||
# Verifique se não há servidores Zabbix
|
|
||||||
if not zabbix_configs:
|
|
||||||
return jsonify({"message": "Nenhum servidor Zabbix encontrado"}), 404
|
|
||||||
|
|
||||||
# Formata os servidores para o frontend
|
|
||||||
servers = []
|
|
||||||
for config in zabbix_configs:
|
|
||||||
servers.append({
|
|
||||||
"name": config['name'], # Acessa a coluna 'name'
|
|
||||||
"type": config['type'], # Acessa a coluna 'type'
|
|
||||||
"url": config['url'] # Acessa a coluna 'url'
|
|
||||||
})
|
|
||||||
|
|
||||||
return jsonify(servers)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
# Mostra o erro exato que está ocorrendo para facilitar o debug
|
|
||||||
return jsonify({"error": str(e)}), 500
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/zabbix/<server_name>/groups', methods=['GET'])
|
|
||||||
@token_required
|
|
||||||
def get_host_groups(server_name):
|
|
||||||
try:
|
|
||||||
# Busca as configurações do banco de dados para o servidor Zabbix com o nome "server_name"
|
|
||||||
zabbix_configs = get_zabbix_configs()
|
|
||||||
config = next((conf for conf in zabbix_configs if conf['name'] == server_name), None)
|
|
||||||
|
|
||||||
if config is None:
|
|
||||||
return jsonify({"error": "Servidor Zabbix não encontrado"}), 404
|
|
||||||
|
|
||||||
# Autentica no servidor Zabbix
|
|
||||||
auth_token = zabbix_login(config['url'], config['username'], config['password'])
|
|
||||||
|
|
||||||
# Busca os grupos de hosts reais, excluindo os templates
|
|
||||||
groups = get_zabbix_host_groups(auth_token, config['url'])
|
|
||||||
|
|
||||||
return jsonify(groups)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
return jsonify({"error": str(e)}), 500
|
|
||||||
|
|
||||||
|
|
||||||
# Rota para listar os hosts de um grupo específico
|
|
||||||
@app.route('/zabbix/<server_name>/groups/<group_id>/hosts', methods=['GET'])
|
|
||||||
@token_required
|
|
||||||
def get_hosts_by_group(server_name, group_id):
|
|
||||||
try:
|
|
||||||
# Busca as configurações do servidor Zabbix no banco de dados
|
|
||||||
zabbix_configs = get_zabbix_configs()
|
|
||||||
config = next((conf for conf in zabbix_configs if conf['name'] == server_name), None)
|
|
||||||
|
|
||||||
if config is None:
|
|
||||||
return jsonify({"error": "Servidor Zabbix não encontrado"}), 404
|
|
||||||
|
|
||||||
# Autentica no servidor Zabbix
|
|
||||||
auth_token = zabbix_login(config['url'], config['username'], config['password'])
|
|
||||||
|
|
||||||
# Busca os hosts do grupo
|
|
||||||
hosts = get_zabbix_hosts(auth_token, config['url'], group_id)
|
|
||||||
|
|
||||||
return jsonify(hosts)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
return jsonify({"error": str(e)}), 500
|
|
||||||
|
|
||||||
# Rota para listar os itens de um host específico
|
|
||||||
@app.route('/zabbix/<server_name>/hosts/<host_id>/items', methods=['GET'])
|
|
||||||
@token_required
|
|
||||||
def get_items_by_host(server_name, host_id):
|
|
||||||
try:
|
|
||||||
# Busca as configurações do servidor Zabbix no banco de dados
|
|
||||||
zabbix_configs = get_zabbix_configs()
|
|
||||||
config = next((conf for conf in zabbix_configs if conf['name'] == server_name), None)
|
|
||||||
|
|
||||||
if config is None:
|
|
||||||
return jsonify({"error": "Servidor Zabbix não encontrado"}), 404
|
|
||||||
|
|
||||||
# Autentica no servidor Zabbix
|
|
||||||
auth_token = zabbix_login(config['url'], config['username'], config['password'])
|
|
||||||
|
|
||||||
# Busca os itens do host
|
|
||||||
items = get_zabbix_items(auth_token, config['url'], host_id)
|
|
||||||
|
|
||||||
return jsonify(items)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
return jsonify({"error": str(e)}), 500
|
|
||||||
|
|
||||||
# Rota para retornar os dados de um item específico
|
|
||||||
@app.route('/zabbix/<server_name>/items/<item_id>/data', methods=['GET'])
|
|
||||||
@token_required
|
|
||||||
def get_item_history(server_name, item_id):
|
|
||||||
try:
|
|
||||||
# Busca as configurações do servidor Zabbix no banco de dados
|
|
||||||
zabbix_configs = get_zabbix_configs()
|
|
||||||
config = next((conf for conf in zabbix_configs if conf['name'] == server_name), None)
|
|
||||||
|
|
||||||
if config is None:
|
|
||||||
return jsonify({"error": "Servidor Zabbix não encontrado"}), 404
|
|
||||||
|
|
||||||
# Autentica no servidor Zabbix
|
|
||||||
auth_token = zabbix_login(config['url'], config['username'], config['password'])
|
|
||||||
|
|
||||||
# Busca os dados do item
|
|
||||||
item_data = get_item_data(auth_token, config['url'], item_id)
|
|
||||||
|
|
||||||
return jsonify(item_data)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
return jsonify({"error": str(e)}), 500
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
app.run(host="0.0.0.0", port=5000, ssl_context=('./fullchain1.pem', './privkey1.pem'))
|
|
||||||
|
After Width: | Height: | Size: 124 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 90 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 590 KiB |
|
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 90 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
|
@ -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)
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
import sys
|
||||||
|
sys.path.append
|
||||||
|
from app import create_app
|
||||||
|
|
||||||
|
# Cria a aplicação usando a função de fábrica do __init__.py
|
||||||
|
app = create_app()
|
||||||
|
|
||||||
|
# Inicia a aplicação
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app.run(host="0.0.0.0", port=5000, ssl_context=('./fullchain1.pem', './privkey1.pem'))
|
||||||