- Alterado Código para que use o node cron e o gerenciamento seja feito pelo pm2 - Bug que não envia uma atualização para o SN quando um chamo é fechado fora do escopo corrigido
207 lines
12 KiB
Markdown
207 lines
12 KiB
Markdown
# Sistema de Sincronização ServiceNow <> GLPI
|
|
|
|
## Visão Geral
|
|
|
|
Esta aplicação Node.js é um middleware projetado para realizar a sincronização bidirecional de tickets entre uma instância do **ServiceNow (SNOW)** e uma do **GLPI**. O objetivo é manter os tickets, seus status e comentários consistentes entre as duas plataformas, automatizando o fluxo de trabalho para as equipes de suporte.
|
|
|
|
A aplicação funciona como um job agendado (por exemplo, via cron) que executa um ciclo completo de sincronização.
|
|
|
|
---
|
|
|
|
## Como Executar a Aplicação
|
|
|
|
Esta seção contém as instruções essenciais para configurar e rodar a aplicação em diferentes ambientes.
|
|
|
|
### 1. Pré-requisitos
|
|
|
|
- **Node.js**: Certifique-se de ter o Node.js (versão 18 ou superior) instalado.
|
|
- **Dependências**: Na raiz do projeto, execute o comando abaixo para instalar todas as dependências necessárias:
|
|
```bash
|
|
npm install
|
|
```
|
|
- **Arquivos de Ambiente**: Crie os arquivos `.env.development` e `.env.production` na raiz do projeto, baseando-se no exemplo `.env.example` (se houver) e preenchendo com as credenciais e URLs corretas para cada ambiente.
|
|
|
|
### 2. Executando com Scripts NPM
|
|
|
|
### 2. Configuração do Ambiente Python
|
|
|
|
A aplicação utiliza um script Python para sincronizar o mapeamento de localidades.
|
|
|
|
#### a) Dependências Python
|
|
|
|
Navegue até a pasta do script e instale as dependências listadas no `requirements.txt`:
|
|
|
|
```bash
|
|
cd src/scripts/python
|
|
pip install -r requirements.txt
|
|
```
|
|
|
|
#### b) Montagem do Compartilhamento de Arquivos (CIFS/Samba)
|
|
|
|
O script Python lê um arquivo `.csv` de um compartilhamento de rede. No servidor de produção, é necessário montar este compartilhamento para que o caminho definido em `LOCATION_MAPPING_CSV_PATH` seja acessível.
|
|
|
|
Adicione a seguinte linha ao seu arquivo `/etc/fstab` para montar o compartilhamento automaticamente durante o boot do sistema. **Ajuste o IP, credenciais e caminhos conforme necessário.**
|
|
|
|
```fstab
|
|
//10.0.121.40/Tecnica/Controle\040CAOA/ENTIDADE\040SERVICE\040NOW /mnt/csv_share cifs username=<seu_usuario>,password=<sua_senha>,uid=1000,gid=1000,iocharset=utf8 0 0
|
|
```
|
|
|
|
Após editar o `/etc/fstab`, execute `sudo mount -a` para montar o compartilhamento imediatamente.
|
|
|
|
Os comandos abaixo utilizam a variável `NODE_ENV` para carregar o arquivo de ambiente (`.env`) correto.
|
|
|
|
#### Ambiente de Desenvolvimento
|
|
Para rodar em modo de desenvolvimento com reinício automático a cada alteração de arquivo (usando `nodemon`):
|
|
```bash
|
|
npm run dev
|
|
```
|
|
|
|
#### Ambiente de Produção
|
|
Para rodar a aplicação em modo de produção (usando `node`):
|
|
```bash
|
|
npm start
|
|
```
|
|
ou o comando explícito:
|
|
```bash
|
|
npm run start:prod
|
|
```
|
|
|
|
### 3. Executando com PM2
|
|
|
|
O PM2 é o gerenciador de processos recomendado para ambientes de produção. Ele garante que a aplicação reinicie automaticamente em caso de falhas e facilita o gerenciamento.
|
|
|
|
- **Para iniciar em modo de produção:**
|
|
```bash
|
|
pm2 start ecosystem.config.js --env production
|
|
```
|
|
- **Para iniciar em modo de desenvolvimento:**
|
|
```bash
|
|
pm2 start ecosystem.config.js --env development
|
|
```
|
|
- **Comandos úteis do PM2:**
|
|
```bash
|
|
pm2 list # Lista todos os processos
|
|
pm2 logs sn-glpi-sync-cron # Exibe os logs em tempo real
|
|
pm2 restart sn-glpi-sync-cron # Reinicia a aplicação
|
|
pm2 stop sn-glpi-sync-cron # Para a aplicação
|
|
```
|
|
|
|
## Fluxo de Execução
|
|
|
|
A aplicação segue uma ordem de execução estrita para garantir a consistência dos dados. O ponto de entrada é o arquivo `src/app.js`, que orquestra a chamada dos seguintes controladores:
|
|
|
|
1. **`processErrorController` - Limpeza de Erros**
|
|
- **Objetivo**: Aumentar a resiliência do sistema.
|
|
- **Ação**: Busca por tickets que falharam em execuções anteriores (marcados com status de `error`). Ele reseta o status desses tickets para um estado anterior válido (ex: `pending_check` ou `synced`), permitindo que eles sejam reprocessados no ciclo atual.
|
|
|
|
2. **`processTicketsController` - Criação de Tickets**
|
|
- **Objetivo**: Trazer novos tickets do ServiceNow para o GLPI.
|
|
- **Ação**:
|
|
- **Busca no SNOW**: Invoca o `processSyncController` para buscar incidentes e requisições novas ou atualizadas no ServiceNow, utilizando uma "marca d'água" (timestamp) para otimização.
|
|
- **Criação no GLPI**: Para cada novo ticket coletado, o `glpiTicketService` é chamado para:
|
|
- Verificar se o ticket já existe no GLPI para evitar duplicatas.
|
|
- Formatar os dados (título, descrição, categoria, etc.).
|
|
- Criar o ticket correspondente no banco de dados do GLPI.
|
|
|
|
3. **`processCommentsController` - Sincronização de Comentários**
|
|
- **Objetivo**: Manter as conversas dos tickets sincronizadas.
|
|
- **Ação**: Para cada ticket ativo, realiza uma sincronização bidirecional de comentários (notas/follow-ups):
|
|
- **SNOW -> GLPI**: Busca novos comentários no ServiceNow, os salva no banco intermediário e os insere como follow-ups no GLPI.
|
|
- **GLPI -> SNOW**: Busca novos follow-ups no GLPI, os sanitiza (remove HTML, trata imagens) e os envia como `work_notes` para o ServiceNow.
|
|
|
|
4. **`processStatusAndClosureController` - Sincronização de Status e Fechamento**
|
|
- **Objetivo**: Manter os status dos tickets alinhados e gerenciar o ciclo de vida (resolução e fechamento).
|
|
- **Ação**: Realiza uma sincronização bidirecional de status, tratando reaberturas, pausas, resoluções e fechamentos em ambas as direções.
|
|
|
|
---
|
|
|
|
## Regras de Negócio Principais
|
|
|
|
A aplicação implementa várias regras de negócio para gerenciar a complexidade da sincronização:
|
|
|
|
### Controle de Fluxo com "Bastão" (`source_last`)
|
|
- Para evitar conflitos de atualização (race conditions), o sistema utiliza um campo `source_last` na tabela `ticket_sync`.
|
|
- Este campo funciona como um "bastão da palavra": o sistema que realiza a última atualização (SNOW ou GLPI) "segura o bastão".
|
|
- O sistema oposto só pode atualizar o ticket se ele estiver com o bastão. Isso garante que as atualizações de status e comentários ocorram de forma ordenada.
|
|
|
|
### Criação e Enriquecimento de Tickets
|
|
- **Mapeamento**: Tickets do ServiceNow são mapeados para o GLPI com base em regras de categoria, prioridade e SLA definidas no `ticketGlpiModel.js`.
|
|
- **Título**: O título do ticket no GLPI é padronizado como `[TIPO] - [ENTIDADE] - [TÍTULO ORIGINAL]`.
|
|
- **Enriquecimento de Descrição**: Se uma requisição do ServiceNow chega com a descrição vazia, o sistema busca automaticamente o conteúdo de variáveis de catálogo (como `justificativa` e `telefone`) e as utiliza para preencher a descrição e os dados do ticket no GLPI.
|
|
|
|
### Sincronização de Comentários
|
|
- **Lógica de 4 Casos (GLPI -> SNOW)**: Para evitar duplicatas, a sincronização de comentários do GLPI para o SNOW verifica 4 cenários:
|
|
1. **Já Sincronizado**: O comentário existe em ambos os locais. Nenhuma ação.
|
|
2. **Existe no SN, Falta no BD Local**: O registro local é criado para corrigir o estado.
|
|
3. **Existe no BD Local, Falta no SN**: O comentário é reenviado para o ServiceNow.
|
|
4. **Novo Comentário**: O comentário é enviado para o SNOW e registrado localmente.
|
|
- **Sanitização**: Comentários do GLPI passam por um processo de limpeza (`commentSanitizer.js`) que remove tags HTML e substitui imagens por um texto placeholder, garantindo que o conteúdo seja legível no ServiceNow.
|
|
|
|
### Sincronização de Status
|
|
- **Fechamento de Ticket em Espera**: Se um ticket é resolvido no GLPI, mas seu correspondente no ServiceNow está com o status "Em Espera" ou "Aguardando Atendimento", o sistema primeiro altera o status no ServiceNow para "Em Atendimento" e só então prossegue com a resolução. Isso automatiza o fluxo e evita falhas.
|
|
- **Regra "Fora do Escopo"**: Se um ticket no GLPI é solucionado com o tipo de solução "Fora do Escopo", o sistema não o resolve no ServiceNow. Em vez disso, ele adiciona uma nota de trabalho (`work_note`) explicando o motivo e fecha o registro de sincronização, tratando-o como um caso especial.
|
|
- **Reabertura**: O sistema permite a reabertura de tickets em ambas as direções, desde que o ticket não esteja permanentemente fechado.
|
|
|
|
### Ambientes (`.env`)
|
|
- A aplicação suporta múltiplos ambientes através de arquivos `.env`.
|
|
- Se a variável de ambiente `NODE_ENV` for definida como `production`, o arquivo `.env.production` será carregado.
|
|
- Caso contrário (ou se `NODE_ENV` for `development`), o arquivo `.env.development` será utilizado.
|
|
|
|
### Atualização do Mapeamento de Localidades (`update_location.py`)
|
|
- A aplicação conta com um script Python (`src/scripts/python/update_location.py`) para manter o mapeamento entre as localidades do ServiceNow e as entidades do GLPI.
|
|
- **Fonte da Verdade**: Um arquivo `.csv` localizado em um servidor de arquivos (`LOCATION_MAPPING_CSV_PATH` no `.env`) é a fonte da verdade para este mapeamento.
|
|
- **Processo**:
|
|
1. Um usuário (`sothis`) atualiza o arquivo `.csv` com as correspondências corretas entre os nomes das localidades (SNOW) e os nomes das entidades (GLPI).
|
|
2. Um `cron job` no servidor executa o script `update_location.py` periodicamente.
|
|
3. O script lê o `.csv`, busca os IDs correspondentes nos bancos de dados de ambos os sistemas e recria a tabela `location_mapping` no banco de dados intermediário (PostgreSQL).
|
|
- **Resultado**: Garante que os tickets criados no GLPI sejam sempre associados à entidade correta, com base em um mapeamento centralizado e de fácil manutenção.
|
|
---
|
|
|
|
## Estrutura do Banco de Dados Intermediário (PostgreSQL)
|
|
|
|
- **`tickets_sn`**: Armazena uma cópia local dos dados dos tickets do ServiceNow para otimizar consultas.
|
|
- **`ticket_sync`**: Tabela central que controla o estado da sincronização de cada ticket, incluindo os IDs de ambos os sistemas e o campo `source_last`.
|
|
- **`ticket_updates`**: Log de todas as atualizações (comentários, etc.), usado para evitar duplicidade e rastrear o histórico.
|
|
- **`location_mapping`**: Tabela de mapeamento entre as localizações do ServiceNow e as entidades do GLPI.
|
|
- **`sync_control`**: Armazena metadados do processo, como a marca d'água (timestamp) da última sincronização bem-sucedida.
|
|
|
|
---
|
|
|
|
## Diagrama de Fluxo (Exemplo)
|
|
|
|
### Sincronização de Resolução: GLPI -> ServiceNow
|
|
|
|
O diagrama abaixo ilustra como o sistema lida com um ticket que foi marcado como "Solucionado" no GLPI.
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant App as app.js
|
|
participant StatusCtrl as processStatusAndClosureController
|
|
participant GlpiModel as TicketGlpiModel
|
|
participant SyncModel as TicketSyncModel
|
|
participant SnowService as servicenowService
|
|
participant ServiceNow as ServiceNow API
|
|
|
|
App->>StatusCtrl: Iniciar ciclo de status
|
|
StatusCtrl->>SyncModel: getTicketsToMonitor()
|
|
SyncModel-->>StatusCtrl: Lista de tickets ativos
|
|
|
|
loop Para cada ticket monitorado
|
|
StatusCtrl->>GlpiModel: getTicketStatus(glpi_id)
|
|
GlpiModel-->>StatusCtrl: Status 'Solucionado' (5)
|
|
|
|
alt Status mudou para 'Solucionado'
|
|
StatusCtrl->>GlpiModel: getTicketSolution(glpi_id)
|
|
GlpiModel-->>StatusCtrl: Detalhes da solução
|
|
|
|
StatusCtrl->>SnowService: closeTicketInServiceNow(sn_id, solucao)
|
|
SnowService->>ServiceNow: PATCH /api/now/table/incident/{sys_id} (state: 'Resolved')
|
|
ServiceNow-->>SnowService: 200 OK
|
|
SnowService-->>StatusCtrl: Sucesso
|
|
|
|
StatusCtrl->>SyncModel: updateStatus(sn_id, 'solved', 'solved')
|
|
SyncModel-->>StatusCtrl: OK
|
|
end
|
|
end
|
|
```
|