feat: add asterisk pjsip integration
- infrastructure/docker/asterisk.Dockerfile: Asterisk 22.10.1 LTS compilado do fonte oficial (Debian trixie nao distribui mais o pacote asterisk), com PJSIP, AMI, ARI, res_odbc/res_config_odbc, cdr_adaptive_odbc, cel_odbc, app_queue - infrastructure/asterisk/config: templates renderizados no entrypoint (secrets via envsubst, nunca versionados) + sorcery.conf/extconfig.conf para PJSIP realtime, dialplan de teste (extensao 600) - infrastructure/postgres/init/002-asterisk-realtime.sql: tabelas ps_endpoints/ps_auths/ps_aors/ps_contacts/ps_endpoint_id_ips/ ps_registrations/cdr/cel no schema 'asterisk' - infrastructure/nftables: protege AMI/ARI/SIP contra acesso pela LAN (interface ens18), trazido da Fase 9 do TODO para ja, sem afetar SSH nem a rede interna do Docker - docker-compose.yml: servico asterisk em network_mode: host (RTP); Postgres publicado em 127.0.0.1:5432 (nao 0.0.0.0) para o Asterisk alcanca-lo, ja que host network nao enxerga a rede Docker interna Testado: AMI login, ARI com auth (401 sem auth), pjsip realtime consultando Postgres sem erro, dialplan originate -> CDR e CEL gravados corretamente, healthcheck do compose passando.
This commit is contained in:
17
.dockerignore
Normal file
17
.dockerignore
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
.git
|
||||||
|
.claude
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
node_modules
|
||||||
|
**/node_modules
|
||||||
|
dist
|
||||||
|
**/dist
|
||||||
|
.next
|
||||||
|
**/.next
|
||||||
|
build
|
||||||
|
**/build
|
||||||
|
coverage
|
||||||
|
**/coverage
|
||||||
|
*.log
|
||||||
|
docs
|
||||||
@@ -27,6 +27,11 @@ DATABASE_URL=postgresql://b2bcall:CHANGE_ME_STRONG_PASSWORD@postgres:5432/b2bcal
|
|||||||
# Schema separado usado pelo Asterisk Realtime (res_odbc)
|
# Schema separado usado pelo Asterisk Realtime (res_odbc)
|
||||||
ASTERISK_DB_SCHEMA=asterisk
|
ASTERISK_DB_SCHEMA=asterisk
|
||||||
|
|
||||||
|
# Host que o container do Asterisk (network_mode: host) usa para alcançar o
|
||||||
|
# Postgres — via loopback do host, já que ele não enxerga a rede Docker
|
||||||
|
# interna por nome (ver docker-compose.yml e docs/ARCHITECTURE.md).
|
||||||
|
ASTERISK_DB_HOST=127.0.0.1
|
||||||
|
|
||||||
# --- Redis -----------------------------------------------------------------
|
# --- Redis -----------------------------------------------------------------
|
||||||
REDIS_HOST=redis
|
REDIS_HOST=redis
|
||||||
REDIS_PORT=6379
|
REDIS_PORT=6379
|
||||||
|
|||||||
40
TODO.md
40
TODO.md
@@ -22,13 +22,39 @@ mestre original (`agente.md`, seções 90-93).
|
|||||||
- [ ] packages/database: schema inicial + migrations tool
|
- [ ] packages/database: schema inicial + migrations tool
|
||||||
|
|
||||||
## Fase 2 — Asterisk
|
## Fase 2 — Asterisk
|
||||||
- [ ] Dockerfile Asterisk 22 LTS (host network)
|
- [x] Dockerfile Asterisk 22.10.1 LTS compilado do fonte (host network) —
|
||||||
- [ ] PJSIP (transports, sem chan_sip)
|
Debian trixie não tem mais o pacote `asterisk` nos repos oficiais
|
||||||
- [ ] AMI habilitado (bind local/rede interna apenas)
|
- [x] PJSIP (transport UDP:5060; chan_sip nem existe mais a partir do Ast 21)
|
||||||
- [ ] ARI habilitado (idem)
|
- [x] AMI habilitado — testado login via 127.0.0.1:5038, bloqueado na LAN via nftables
|
||||||
- [ ] Realtime ODBC -> Postgres (schema asterisk)
|
- [x] ARI habilitado — testado GET /ari/asterisk/info via 127.0.0.1:8088, 401 sem auth
|
||||||
- [ ] CDR, CEL, queue_log habilitados
|
- [x] Realtime ODBC -> Postgres schema `asterisk` (sorcery.conf + extconfig.conf
|
||||||
- [ ] Dialplan inicial de teste
|
+ res_odbc.conf) — `pjsip show endpoints` consulta o Postgres sem erro
|
||||||
|
- [x] CDR via cdr_adaptive_odbc — testado, grava em asterisk.cdr (ANSWERED,
|
||||||
|
duration/billsec corretos). Nota: coluna `end` renomeada para
|
||||||
|
`end_time` (palavra reservada no Postgres, cdr_adaptive_odbc não
|
||||||
|
quota identificadores)
|
||||||
|
- [x] CEL via cel_odbc — testado, grava em asterisk.cel (CHAN_START/ANSWER/
|
||||||
|
HANGUP/CHAN_END)
|
||||||
|
- [x] queue_log habilitado (padrão do app_queue, arquivo em /var/log/asterisk)
|
||||||
|
- [x] Dialplan inicial de teste (contexto `b2bcall-healthcheck`, exten 600,
|
||||||
|
Answer/Playback/Echo) — testado via `channel originate ... extension`
|
||||||
|
- [x] nftables protegendo AMI/ARI/SIP na interface da LAN (ens18), trazido da
|
||||||
|
Fase 9 para já — não testado a partir de outra máquina na LAN (só
|
||||||
|
localmente, onde tráfego para o próprio IP vai por `lo` e não
|
||||||
|
exercita a regra; revisar quando OpenSIPS/outro host estiver disponível)
|
||||||
|
|
||||||
|
### Pendências conhecidas da Fase 2 (não bloqueiam, revisitar depois)
|
||||||
|
- [ ] `res_pjsip_outbound_registration` recusa carregar no boot (mensagem
|
||||||
|
"no existing documentation" para o tipo 'registration' do sorcery) —
|
||||||
|
carregamento manual via `module load` funciona mas é desfeito por uma
|
||||||
|
flag interna de "declined at boot". Só afeta troncos com registration
|
||||||
|
outbound; endpoints/aors funcionam normalmente. Investigar na Fase 4
|
||||||
|
ao implementar cadastro de troncos com registration.
|
||||||
|
- [ ] `res_config_ldap` gera ERROR de log no boot (sem LDAP configurado,
|
||||||
|
não usamos). Cosmético — considerar `noload` em modules.conf.
|
||||||
|
- [ ] `cdr_pgsql`/`cel_pgsql` não compilaram (falta libpq-dev na imagem);
|
||||||
|
usamos `cdr_adaptive_odbc`/`cel_odbc` como alternativa funcional via
|
||||||
|
ODBC — decisão adequada, não precisa dos módulos pgsql nativos.
|
||||||
|
|
||||||
## Fase 3 — Backend base
|
## Fase 3 — Backend base
|
||||||
- [ ] apps/api (NestJS + Fastify) bootstrap
|
- [ ] apps/api (NestJS + Fastify) bootstrap
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ networks:
|
|||||||
volumes:
|
volumes:
|
||||||
postgres-data:
|
postgres-data:
|
||||||
redis-data:
|
redis-data:
|
||||||
|
asterisk-lib:
|
||||||
|
asterisk-log:
|
||||||
|
asterisk-spool:
|
||||||
|
|
||||||
services:
|
services:
|
||||||
postgres:
|
postgres:
|
||||||
@@ -22,7 +25,12 @@ services:
|
|||||||
- ./infrastructure/postgres/init:/docker-entrypoint-initdb.d:ro
|
- ./infrastructure/postgres/init:/docker-entrypoint-initdb.d:ro
|
||||||
networks:
|
networks:
|
||||||
- b2bcall-net
|
- b2bcall-net
|
||||||
# Sem "ports": Postgres não deve ficar acessível fora da rede Docker interna.
|
ports:
|
||||||
|
# Publicado SOMENTE em loopback do host: o container do Asterisk usa
|
||||||
|
# network_mode: host (necessário para RTP) e por isso não enxerga a
|
||||||
|
# rede Docker interna por nome — precisa alcançar o Postgres via
|
||||||
|
# 127.0.0.1. Isso nunca fica acessível pela LAN/Internet (não é 0.0.0.0).
|
||||||
|
- "127.0.0.1:${POSTGRES_PORT:-5432}:5432"
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-b2bcall} -d ${POSTGRES_DB:-b2bcall}"]
|
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-b2bcall} -d ${POSTGRES_DB:-b2bcall}"]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
@@ -71,3 +79,45 @@ services:
|
|||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
memory: 160M
|
memory: 160M
|
||||||
|
|
||||||
|
asterisk:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: infrastructure/docker/asterisk.Dockerfile
|
||||||
|
image: b2bcall-asterisk:22.10.1
|
||||||
|
container_name: b2bcall-asterisk
|
||||||
|
restart: unless-stopped
|
||||||
|
network_mode: host
|
||||||
|
# RTP exige uma faixa larga de portas UDP — inviável de mapear uma a uma
|
||||||
|
# em bridge network, por isso host mode (ver docs/ARCHITECTURE.md 3.1).
|
||||||
|
# AMI (5038), ARI (8088) e SIP (5060) ficam protegidos pelo nftables
|
||||||
|
# (infrastructure/nftables/b2bcall.nft), que bloqueia acesso pela LAN.
|
||||||
|
depends_on:
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
environment:
|
||||||
|
# O Asterisk (host network) alcança o Postgres via loopback do host,
|
||||||
|
# não pelo nome do container (ver publicação de porta do serviço postgres).
|
||||||
|
ASTERISK_DB_HOST: ${ASTERISK_DB_HOST:-127.0.0.1}
|
||||||
|
volumes:
|
||||||
|
- ./infrastructure/asterisk/config:/etc/asterisk-templates:ro
|
||||||
|
- asterisk-lib:/var/lib/asterisk
|
||||||
|
- asterisk-log:/var/log/asterisk
|
||||||
|
- asterisk-spool:/var/spool/asterisk
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "asterisk -rx 'core show uptime' | grep -q 'System uptime'"]
|
||||||
|
interval: 15s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
start_period: 20s
|
||||||
|
logging:
|
||||||
|
driver: json-file
|
||||||
|
options:
|
||||||
|
max-size: "10m"
|
||||||
|
max-file: "3"
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 400M
|
||||||
|
|||||||
@@ -84,6 +84,20 @@ O Asterisk nunca terá IP público. OpenSIPS e troncos são acessados via IP pri
|
|||||||
AMI/ARI nunca expostos além do host local (bind em 127.0.0.1 ou rede interna Docker
|
AMI/ARI nunca expostos além do host local (bind em 127.0.0.1 ou rede interna Docker
|
||||||
quando possível).
|
quando possível).
|
||||||
|
|
||||||
|
### 3.2.1 Asterisk (host network) ↔ Postgres/Redis (rede Docker interna)
|
||||||
|
|
||||||
|
Como o Asterisk usa `network_mode: host`, ele não enxerga a rede Docker
|
||||||
|
interna (`b2bcall-net`) por nome — DNS de containers só funciona para quem
|
||||||
|
está anexado à mesma rede definida pelo usuário. Solução adotada: o Postgres
|
||||||
|
publica a porta 5432 **somente em `127.0.0.1` do host**
|
||||||
|
(`127.0.0.1:5432:5432`, nunca `0.0.0.0`), e o Asterisk se conecta via
|
||||||
|
`ASTERISK_DB_HOST=127.0.0.1` (variável própria, distinta de
|
||||||
|
`POSTGRES_HOST=postgres` usada pelos demais serviços na rede interna). Isso
|
||||||
|
mantém o Postgres inacessível pela LAN/Internet, alcançável apenas por
|
||||||
|
processos no próprio host — incluindo um container em host network. Redis
|
||||||
|
não precisa disso: só a aplicação (bridge network) fala com Redis, nunca o
|
||||||
|
Asterisk diretamente.
|
||||||
|
|
||||||
### 3.3 Asterisk Realtime
|
### 3.3 Asterisk Realtime
|
||||||
|
|
||||||
- PJSIP objects (`ps_endpoints`, `ps_auths`, `ps_aors`, `ps_contacts`,
|
- PJSIP objects (`ps_endpoints`, `ps_auths`, `ps_aors`, `ps_contacts`,
|
||||||
|
|||||||
13
infrastructure/asterisk/config/ari.conf.tpl
Normal file
13
infrastructure/asterisk/config/ari.conf.tpl
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
; ARI (Asterisk REST Interface). Usado apenas quando controle fino de
|
||||||
|
; canais/bridges exigir (ver packages/telephony/AsteriskTelephonyProvider).
|
||||||
|
; Protegido pelo nftables da mesma forma que o AMI (porta 8088 bloqueada na
|
||||||
|
; interface da LAN, liberada apenas em loopback/rede interna Docker).
|
||||||
|
[general]
|
||||||
|
enabled = yes
|
||||||
|
pretty = yes
|
||||||
|
allowed_origins =
|
||||||
|
|
||||||
|
[${ARI_USERNAME}]
|
||||||
|
type = user
|
||||||
|
read_only = no
|
||||||
|
password = ${ARI_SECRET}
|
||||||
6
infrastructure/asterisk/config/cdr.conf
Normal file
6
infrastructure/asterisk/config/cdr.conf
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
[general]
|
||||||
|
enable = yes
|
||||||
|
unanswered = yes
|
||||||
|
congestion = yes
|
||||||
|
endbeforehexten = no
|
||||||
|
initiatedseconds = no
|
||||||
7
infrastructure/asterisk/config/cdr_adaptive_odbc.conf
Normal file
7
infrastructure/asterisk/config/cdr_adaptive_odbc.conf
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
; CDR via Adaptive ODBC: introspecciona as colunas reais da tabela
|
||||||
|
; asterisk.cdr (start/answer/end/uniqueid/linkedid/...) em vez de usar o
|
||||||
|
; esquema legado fixo do cdr_odbc (que exige colunas antigas como
|
||||||
|
; "calldate" e não suporta uniqueid/linkedid).
|
||||||
|
[asterisk]
|
||||||
|
connection = asterisk
|
||||||
|
table = cdr
|
||||||
4
infrastructure/asterisk/config/cel.conf
Normal file
4
infrastructure/asterisk/config/cel.conf
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
[general]
|
||||||
|
enable = yes
|
||||||
|
apps = Dial,Queue,Bridge,Park,ParkedCall,AGI,VoiceMail
|
||||||
|
events = CHAN_START,CHAN_END,ANSWER,HANGUP,APP_START,APP_END,BRIDGE_ENTER,BRIDGE_EXIT,PARK_START,PARK_END,BLINDTRANSFER,ATTENDEDTRANSFER
|
||||||
4
infrastructure/asterisk/config/cel_odbc.conf
Normal file
4
infrastructure/asterisk/config/cel_odbc.conf
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
; CEL gravado via ODBC, mesma conexão "asterisk" (ver cdr_odbc.conf).
|
||||||
|
[global]
|
||||||
|
connection = asterisk
|
||||||
|
table = cel
|
||||||
10
infrastructure/asterisk/config/extconfig.conf
Normal file
10
infrastructure/asterisk/config/extconfig.conf
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
; Mapeia as famílias de configuração realtime para a conexão ODBC "asterisk"
|
||||||
|
; (definida em res_odbc.conf) e a respectiva tabela no schema "asterisk" do
|
||||||
|
; Postgres. Usado pelos objetos PJSIP referenciados em sorcery.conf.
|
||||||
|
[settings]
|
||||||
|
ps_endpoints => odbc,asterisk,ps_endpoints
|
||||||
|
ps_auths => odbc,asterisk,ps_auths
|
||||||
|
ps_aors => odbc,asterisk,ps_aors
|
||||||
|
ps_contacts => odbc,asterisk,ps_contacts
|
||||||
|
ps_endpoint_id_ips => odbc,asterisk,ps_endpoint_id_ips
|
||||||
|
ps_registrations => odbc,asterisk,ps_registrations
|
||||||
21
infrastructure/asterisk/config/extensions.conf
Normal file
21
infrastructure/asterisk/config/extensions.conf
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
; Dialplan mínimo de validação da Fase 2 (infraestrutura). O editor
|
||||||
|
; estruturado + versionamento (dialplan_versions) chega na Fase 4 —
|
||||||
|
; Telefonia, e substituirá este arquivo estático por dialplan gerado pela
|
||||||
|
; aplicação (AEL/realtime), com backup/validação/rollback antes de ativar.
|
||||||
|
[general]
|
||||||
|
static = yes
|
||||||
|
writeprotect = no
|
||||||
|
|
||||||
|
[globals]
|
||||||
|
|
||||||
|
; Contexto de teste: confirma que o core do dialplan está funcionando.
|
||||||
|
[b2bcall-healthcheck]
|
||||||
|
exten => 600,1,Answer()
|
||||||
|
same => n,Playback(demo-echotest)
|
||||||
|
same => n,Echo()
|
||||||
|
same => n,Hangup()
|
||||||
|
|
||||||
|
; Placeholder para o contexto de discagem outbound (Fase 6 — Campanhas).
|
||||||
|
[outbound]
|
||||||
|
exten => _X.,1,NoOp(B2BCall outbound placeholder - ${EXTEN})
|
||||||
|
same => n,Hangup()
|
||||||
10
infrastructure/asterisk/config/http.conf
Normal file
10
infrastructure/asterisk/config/http.conf
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
; Servidor HTTP embutido do Asterisk — necessário para ARI (res_ari) e para o
|
||||||
|
; WebSocket usado por ARI. Mesma política de exposição do AMI/ARI: bind em
|
||||||
|
; 0.0.0.0 pois o container roda em network_mode: host, mas o nftables bloqueia
|
||||||
|
; acesso pela interface da LAN (ver infrastructure/nftables/b2bcall.nft).
|
||||||
|
[general]
|
||||||
|
enabled = yes
|
||||||
|
bindaddr = 0.0.0.0
|
||||||
|
bindport = 8088
|
||||||
|
prefix =
|
||||||
|
enablestatic = no
|
||||||
7
infrastructure/asterisk/config/logger.conf
Normal file
7
infrastructure/asterisk/config/logger.conf
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
[general]
|
||||||
|
dateformat = %F %T
|
||||||
|
|
||||||
|
[logfiles]
|
||||||
|
console => notice,warning,error
|
||||||
|
messages => notice,warning,error
|
||||||
|
queue_log => queue_log
|
||||||
19
infrastructure/asterisk/config/manager.conf.tpl
Normal file
19
infrastructure/asterisk/config/manager.conf.tpl
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
; AMI (Asterisk Manager Interface).
|
||||||
|
; NUNCA exposto à LAN/Internet: bind em 0.0.0.0 apenas porque o container usa
|
||||||
|
; network_mode: host, mas o acesso externo é bloqueado pelo nftables
|
||||||
|
; (infrastructure/nftables/b2bcall.nft) — só loopback e a rede interna dos
|
||||||
|
; containers Docker (172.16.0.0/12) alcançam a porta 5038.
|
||||||
|
[general]
|
||||||
|
enabled = yes
|
||||||
|
port = 5038
|
||||||
|
bindaddr = 0.0.0.0
|
||||||
|
displayconnects = no
|
||||||
|
webenabled = no
|
||||||
|
|
||||||
|
[${AMI_USERNAME}]
|
||||||
|
secret = ${AMI_SECRET}
|
||||||
|
deny = 0.0.0.0/0.0.0.0
|
||||||
|
permit = 127.0.0.1/255.255.255.255
|
||||||
|
permit = 172.16.0.0/255.240.0.0
|
||||||
|
read = system,call,agent,user,config,command,dtmf,reporting,cdr,dialplan,originate
|
||||||
|
write = system,call,agent,user,config,command,dtmf,reporting,originate
|
||||||
12
infrastructure/asterisk/config/odbc.ini.tpl
Normal file
12
infrastructure/asterisk/config/odbc.ini.tpl
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
; DSN do sistema usado por res_odbc (conexão nomeada "asterisk" em
|
||||||
|
; res_odbc.conf). "ConnSettings" ajusta o search_path para o schema dedicado
|
||||||
|
; "asterisk" sem misturar com o schema de domínio da aplicação ("public").
|
||||||
|
[asterisk]
|
||||||
|
Description = B2BCall Asterisk Realtime (PostgreSQL)
|
||||||
|
Driver = PostgreSQL Unicode
|
||||||
|
Servername = ${ASTERISK_DB_HOST}
|
||||||
|
Port = ${POSTGRES_PORT}
|
||||||
|
Database = ${POSTGRES_DB}
|
||||||
|
Username = ${POSTGRES_USER}
|
||||||
|
Password = ${POSTGRES_PASSWORD}
|
||||||
|
ConnSettings = SET search_path TO asterisk, public;
|
||||||
13
infrastructure/asterisk/config/pjsip.conf
Normal file
13
infrastructure/asterisk/config/pjsip.conf
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
; Transporte PJSIP estático (transportes não são gerenciados via realtime).
|
||||||
|
; Endpoints/auths/aors/contacts SÃO realtime (ver sorcery.conf +
|
||||||
|
; extconfig.conf) — cadastrados pela aplicação (Fase 4 — Telefonia).
|
||||||
|
;
|
||||||
|
; O Asterisk não possui IP público: este transporte escuta na rede interna/
|
||||||
|
; privada. SIP só deve ser alcançável a partir do OpenSIPS e de troncos
|
||||||
|
; explicitamente autorizados (ver infrastructure/nftables/b2bcall.nft —
|
||||||
|
; atualmente bloqueado por padrão na interface da LAN até essas origens
|
||||||
|
; serem conhecidas).
|
||||||
|
[transport-udp]
|
||||||
|
type = transport
|
||||||
|
protocol = udp
|
||||||
|
bind = 0.0.0.0:5060
|
||||||
8
infrastructure/asterisk/config/queues.conf
Normal file
8
infrastructure/asterisk/config/queues.conf
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
; Configuração global de filas. As filas em si (Fase 5 — Call Center) serão
|
||||||
|
; gerenciadas pela aplicação. queue_log é usado por app_queue por padrão
|
||||||
|
; (grava em /var/log/asterisk/queue_log) e será consumido pelo
|
||||||
|
; apps/asterisk-events para reconciliação (ver docs/ARCHITECTURE.md).
|
||||||
|
[general]
|
||||||
|
persistentmembers = yes
|
||||||
|
autofill = yes
|
||||||
|
shared_lastcall = yes
|
||||||
9
infrastructure/asterisk/config/res_odbc.conf
Normal file
9
infrastructure/asterisk/config/res_odbc.conf
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
; Conexão ODBC nomeada "asterisk", usada pelo Realtime (PJSIP, CDR, CEL) via
|
||||||
|
; res_config_odbc. As credenciais reais ficam no DSN do sistema (/etc/odbc.ini,
|
||||||
|
; renderizado a partir de infrastructure/asterisk/config/odbc.ini.tpl) — este
|
||||||
|
; arquivo não contém segredos.
|
||||||
|
[asterisk]
|
||||||
|
enabled => yes
|
||||||
|
dsn => asterisk
|
||||||
|
pre-connect => yes
|
||||||
|
sanitysql => select 1
|
||||||
11
infrastructure/asterisk/config/sorcery.conf
Normal file
11
infrastructure/asterisk/config/sorcery.conf
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
; Mapeia os objetos PJSIP (sorcery) para o backend realtime/ODBC. As tabelas
|
||||||
|
; físicas (ps_endpoints, ps_auths, ...) vivem no schema "asterisk" do Postgres
|
||||||
|
; (ver infrastructure/postgres/init/002-asterisk-realtime.sql) e o mapeamento
|
||||||
|
; nome-lógico -> conexão ODBC/tabela está em extconfig.conf.
|
||||||
|
[res_pjsip]
|
||||||
|
endpoint = realtime,ps_endpoints
|
||||||
|
auth = realtime,ps_auths
|
||||||
|
aor = realtime,ps_aors
|
||||||
|
contact = realtime,ps_contacts
|
||||||
|
endpoint_id_ip = realtime,ps_endpoint_id_ips
|
||||||
|
registration = realtime,ps_registrations
|
||||||
33
infrastructure/docker/asterisk-entrypoint.sh
Normal file
33
infrastructure/docker/asterisk-entrypoint.sh
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Renderiza os templates de configuração (que contêm variáveis ${VAR}) usando
|
||||||
|
# as variáveis de ambiente do container, para nunca versionar segredos em
|
||||||
|
# texto puro nos arquivos .conf. /etc/asterisk já vem populado pelo `make
|
||||||
|
# samples` no build da imagem — aqui só sobrepomos/adicionamos os arquivos
|
||||||
|
# específicos do B2BCall (o restante dos samples permanece intacto).
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
CONFIG_SRC=/etc/asterisk-templates
|
||||||
|
CONFIG_DST=/etc/asterisk
|
||||||
|
|
||||||
|
mkdir -p "$CONFIG_DST"
|
||||||
|
|
||||||
|
# odbc.ini é configuração do sistema (unixODBC), não do Asterisk.
|
||||||
|
if [ -e "$CONFIG_SRC/odbc.ini.tpl" ]; then
|
||||||
|
envsubst < "$CONFIG_SRC/odbc.ini.tpl" > /etc/odbc.ini
|
||||||
|
fi
|
||||||
|
|
||||||
|
for tpl in "$CONFIG_SRC"/*.conf.tpl; do
|
||||||
|
[ -e "$tpl" ] || continue
|
||||||
|
name="$(basename "$tpl" .tpl)"
|
||||||
|
envsubst < "$tpl" > "$CONFIG_DST/$name"
|
||||||
|
done
|
||||||
|
|
||||||
|
for f in "$CONFIG_SRC"/*.conf; do
|
||||||
|
[ -e "$f" ] || continue
|
||||||
|
name="$(basename "$f")"
|
||||||
|
cp "$f" "$CONFIG_DST/$name"
|
||||||
|
done
|
||||||
|
|
||||||
|
chown -R asterisk:asterisk "$CONFIG_DST" /var/lib/asterisk /var/log/asterisk /var/spool/asterisk /var/run/asterisk
|
||||||
|
|
||||||
|
exec "$@"
|
||||||
70
infrastructure/docker/asterisk.Dockerfile
Normal file
70
infrastructure/docker/asterisk.Dockerfile
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
# Asterisk 22 LTS compilado a partir do fonte oficial.
|
||||||
|
# Debian não distribui mais o pacote `asterisk` em seus repositórios, então
|
||||||
|
# compilamos aqui com controle total dos módulos: PJSIP (chan_sip não existe
|
||||||
|
# mais a partir do Asterisk 21), AMI, ARI, Realtime ODBC (Postgres), CDR, CEL.
|
||||||
|
FROM debian:trixie-slim
|
||||||
|
|
||||||
|
ARG ASTERISK_VERSION=22.10.1
|
||||||
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
build-essential wget ca-certificates git subversion patch \
|
||||||
|
pkg-config autoconf automake libtool \
|
||||||
|
libxml2-dev libsqlite3-dev uuid-dev libjansson-dev libedit-dev \
|
||||||
|
unixodbc unixodbc-dev odbc-postgresql \
|
||||||
|
libsrtp2-dev libssl-dev libncurses-dev libnewt-dev \
|
||||||
|
libspeex-dev libspeexdsp-dev libogg-dev libvorbis-dev \
|
||||||
|
libcurl4-openssl-dev libsystemd-dev gettext-base \
|
||||||
|
odbc-postgresql \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
WORKDIR /usr/src
|
||||||
|
RUN wget -q "https://downloads.asterisk.org/pub/telephony/asterisk/asterisk-${ASTERISK_VERSION}.tar.gz" \
|
||||||
|
&& tar xzf asterisk-${ASTERISK_VERSION}.tar.gz \
|
||||||
|
&& rm asterisk-${ASTERISK_VERSION}.tar.gz \
|
||||||
|
&& mv asterisk-${ASTERISK_VERSION} asterisk
|
||||||
|
|
||||||
|
WORKDIR /usr/src/asterisk
|
||||||
|
|
||||||
|
# Instala dependências adicionais específicas da distro (detectadas pelo
|
||||||
|
# próprio script oficial do Asterisk) sem prompts interativos.
|
||||||
|
RUN contrib/scripts/install_prereq install --yes || true
|
||||||
|
|
||||||
|
RUN ./configure --with-jansson-bundled --with-pjproject-bundled --with-crypto --with-ssl=ssl
|
||||||
|
|
||||||
|
RUN make menuselect.makeopts \
|
||||||
|
&& menuselect/menuselect \
|
||||||
|
--enable res_odbc \
|
||||||
|
--enable res_config_odbc \
|
||||||
|
--enable cdr_odbc \
|
||||||
|
--enable cdr_pgsql \
|
||||||
|
--enable cel_odbc \
|
||||||
|
--enable cel_pgsql \
|
||||||
|
--enable app_queue \
|
||||||
|
--enable res_pjsip \
|
||||||
|
--enable res_pjsip_session \
|
||||||
|
--enable res_ari \
|
||||||
|
--enable res_ari_applications \
|
||||||
|
--enable res_ari_channels \
|
||||||
|
--enable res_ari_bridges \
|
||||||
|
--enable CORE-SOUNDS-EN-WAV \
|
||||||
|
--enable MOH-OPSOUND-WAV \
|
||||||
|
menuselect.makeopts
|
||||||
|
|
||||||
|
RUN make -j"$(nproc)"
|
||||||
|
RUN make install
|
||||||
|
RUN make samples
|
||||||
|
RUN ldconfig
|
||||||
|
|
||||||
|
RUN groupadd -r asterisk && useradd -r -g asterisk -d /var/lib/asterisk asterisk \
|
||||||
|
&& mkdir -p /etc/asterisk /var/lib/asterisk /var/log/asterisk /var/spool/asterisk /var/run/asterisk \
|
||||||
|
&& chown -R asterisk:asterisk /etc/asterisk /var/lib/asterisk /var/log/asterisk /var/spool/asterisk /var/run/asterisk /usr/lib/asterisk
|
||||||
|
|
||||||
|
EXPOSE 5060/udp 5060/tcp 5061/tcp 8088/tcp 8089/tcp 5038/tcp
|
||||||
|
EXPOSE 10000-20000/udp
|
||||||
|
|
||||||
|
COPY infrastructure/docker/asterisk-entrypoint.sh /usr/local/bin/asterisk-entrypoint.sh
|
||||||
|
RUN chmod +x /usr/local/bin/asterisk-entrypoint.sh
|
||||||
|
|
||||||
|
ENTRYPOINT ["/usr/local/bin/asterisk-entrypoint.sh"]
|
||||||
|
CMD ["asterisk", "-f", "-vvv", "-U", "asterisk", "-G", "asterisk"]
|
||||||
15
infrastructure/nftables/b2bcall-nftables.service
Normal file
15
infrastructure/nftables/b2bcall-nftables.service
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=B2BCall custom nftables rules (protects Asterisk admin ports)
|
||||||
|
After=docker.service network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
PartOf=docker.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
RemainAfterExit=yes
|
||||||
|
ExecStartPre=-/usr/sbin/nft delete table inet b2bcall_fw
|
||||||
|
ExecStart=/usr/sbin/nft -f /opt/b2bcall/infrastructure/nftables/b2bcall.nft
|
||||||
|
ExecStop=/usr/sbin/nft delete table inet b2bcall_fw
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
47
infrastructure/nftables/b2bcall.nft
Normal file
47
infrastructure/nftables/b2bcall.nft
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
#!/usr/sbin/nft -f
|
||||||
|
# Regras de firewall do B2BCall.
|
||||||
|
#
|
||||||
|
# IMPORTANTE: este arquivo NUNCA usa "flush ruleset" — o Docker gerencia suas
|
||||||
|
# próprias tabelas iptables-nft (visíveis como "table ip nat" / "table ip
|
||||||
|
# filter" com o aviso "managed by iptables-nft, do not touch"). Uma tabela
|
||||||
|
# separada (`inet b2bcall_fw`) convive com elas sem conflito: cada tabela
|
||||||
|
# anexada ao hook "input" é avaliada em ordem de prioridade; um veredito de
|
||||||
|
# "drop" nesta tabela encerra o processamento do pacote antes mesmo de ele
|
||||||
|
# chegar às regras do Docker, sem jamais apagar as regras do Docker.
|
||||||
|
#
|
||||||
|
# SSH (porta 22) é sempre permitido — nunca deve ficar bloqueado.
|
||||||
|
#
|
||||||
|
# Instalado/atualizado via systemd unit b2bcall-nftables.service (ver
|
||||||
|
# infrastructure/nftables/b2bcall-nftables.service), que roda:
|
||||||
|
# nft delete table inet b2bcall_fw (ignora erro se não existir)
|
||||||
|
# nft -f este arquivo
|
||||||
|
# após o docker.service subir.
|
||||||
|
|
||||||
|
table inet b2bcall_fw {
|
||||||
|
chain input_admin_protect {
|
||||||
|
type filter hook input priority filter - 1; policy accept;
|
||||||
|
|
||||||
|
# Loopback sempre liberado
|
||||||
|
iifname "lo" accept
|
||||||
|
|
||||||
|
# Conexões já estabelecidas / relacionadas sempre liberadas
|
||||||
|
ct state established,related accept
|
||||||
|
|
||||||
|
# Redes internas dos bridges Docker (comunicação entre containers e
|
||||||
|
# entre containers <-> serviços do Asterisk em host network)
|
||||||
|
ip saddr 172.16.0.0/12 accept
|
||||||
|
|
||||||
|
# SSH nunca é bloqueado
|
||||||
|
tcp dport 22 accept
|
||||||
|
|
||||||
|
# --- Serviços administrativos/telefônicos sensíveis do Asterisk ---
|
||||||
|
# Nunca devem ser alcançáveis pela LAN (interface ens18). Habilitar
|
||||||
|
# exceções pontuais aqui somente quando o IP do OpenSIPS/tronco for
|
||||||
|
# conhecido e explicitamente autorizado (ver docs/OPENSIPS.md, a
|
||||||
|
# ser criado na Fase 2 de telefonia).
|
||||||
|
iifname "ens18" tcp dport { 5038, 8088, 8089 } counter drop
|
||||||
|
iifname "ens18" tcp dport { 5060, 5061 } counter drop
|
||||||
|
iifname "ens18" udp dport 5060 counter drop
|
||||||
|
iifname "ens18" udp dport 10000-20000 counter drop
|
||||||
|
}
|
||||||
|
}
|
||||||
236
infrastructure/postgres/init/002-asterisk-realtime.sql
Normal file
236
infrastructure/postgres/init/002-asterisk-realtime.sql
Normal file
@@ -0,0 +1,236 @@
|
|||||||
|
-- Tabelas de Realtime do Asterisk (PJSIP via res_config_odbc) + CDR/CEL
|
||||||
|
-- (cdr_pgsql / cel_pgsql), todas no schema "asterisk" (nunca em "public",
|
||||||
|
-- que é reservado ao domínio da aplicação — ver docs/ARCHITECTURE.md).
|
||||||
|
--
|
||||||
|
-- Colunas seguem o schema oficial documentado pelo Asterisk 22 para
|
||||||
|
-- res_pjsip realtime (sorcery.conf + extconfig.conf apontam para estas
|
||||||
|
-- tabelas). Caso uma coluna adicional seja necessária futuramente
|
||||||
|
-- (ex.: campo específico de um módulo PJSIP menos comum), ela deve ser
|
||||||
|
-- adicionada via migration, nunca editada manualmente em produção.
|
||||||
|
|
||||||
|
SET search_path TO asterisk, public;
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
-- ps_endpoints
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
CREATE TABLE IF NOT EXISTS asterisk.ps_endpoints (
|
||||||
|
id VARCHAR(255) PRIMARY KEY,
|
||||||
|
transport VARCHAR(255),
|
||||||
|
aors VARCHAR(255),
|
||||||
|
auth VARCHAR(255),
|
||||||
|
context VARCHAR(255) DEFAULT 'default',
|
||||||
|
disallow VARCHAR(255) DEFAULT 'all',
|
||||||
|
allow VARCHAR(255),
|
||||||
|
direct_media VARCHAR(3) DEFAULT 'yes',
|
||||||
|
connected_line_method VARCHAR(255),
|
||||||
|
direct_media_method VARCHAR(255),
|
||||||
|
direct_media_glare_mitigation VARCHAR(255),
|
||||||
|
disable_direct_media_on_nat VARCHAR(3),
|
||||||
|
dtmf_mode VARCHAR(255) DEFAULT 'rfc4733',
|
||||||
|
external_media_address VARCHAR(255),
|
||||||
|
force_rport VARCHAR(3) DEFAULT 'yes',
|
||||||
|
ice_support VARCHAR(3) DEFAULT 'no',
|
||||||
|
identify_by VARCHAR(255) DEFAULT 'username,ip',
|
||||||
|
mailboxes VARCHAR(255),
|
||||||
|
moh_suggest VARCHAR(255) DEFAULT 'default',
|
||||||
|
outbound_auth VARCHAR(255),
|
||||||
|
outbound_proxy VARCHAR(255),
|
||||||
|
rewrite_contact VARCHAR(3) DEFAULT 'yes',
|
||||||
|
rtp_symmetric VARCHAR(3) DEFAULT 'yes',
|
||||||
|
send_diversion VARCHAR(3),
|
||||||
|
send_pai VARCHAR(3),
|
||||||
|
send_rpid VARCHAR(3),
|
||||||
|
timers VARCHAR(255) DEFAULT 'yes',
|
||||||
|
timers_min_se INTEGER DEFAULT 90,
|
||||||
|
timers_sess_expires INTEGER DEFAULT 1800,
|
||||||
|
trust_id_inbound VARCHAR(3) DEFAULT 'no',
|
||||||
|
trust_id_outbound VARCHAR(3) DEFAULT 'no',
|
||||||
|
type VARCHAR(255) DEFAULT 'endpoint',
|
||||||
|
use_avpf VARCHAR(3) DEFAULT 'no',
|
||||||
|
use_ptime VARCHAR(3) DEFAULT 'no',
|
||||||
|
callerid VARCHAR(255),
|
||||||
|
callerid_privacy VARCHAR(255),
|
||||||
|
callerid_tag VARCHAR(255),
|
||||||
|
device_state_busy_at INTEGER DEFAULT 0,
|
||||||
|
language VARCHAR(255) DEFAULT 'en',
|
||||||
|
max_audio_streams INTEGER DEFAULT 1,
|
||||||
|
max_video_streams INTEGER DEFAULT 1,
|
||||||
|
media_encryption VARCHAR(255) DEFAULT 'no',
|
||||||
|
media_use_received_transport VARCHAR(3) DEFAULT 'no',
|
||||||
|
one_touch_recording VARCHAR(3) DEFAULT 'no',
|
||||||
|
record_off_feature VARCHAR(255),
|
||||||
|
record_on_feature VARCHAR(255),
|
||||||
|
rtp_engine VARCHAR(255) DEFAULT 'asterisk',
|
||||||
|
rtp_ipv6 VARCHAR(3) DEFAULT 'no',
|
||||||
|
rtp_keepalive INTEGER,
|
||||||
|
rtp_timeout INTEGER,
|
||||||
|
rtp_timeout_hold INTEGER,
|
||||||
|
sdp_owner VARCHAR(255),
|
||||||
|
sdp_session VARCHAR(255),
|
||||||
|
set_var TEXT,
|
||||||
|
srtp_tag_32 VARCHAR(3) DEFAULT 'no',
|
||||||
|
tone_zone VARCHAR(255),
|
||||||
|
tos_audio VARCHAR(255),
|
||||||
|
tos_video VARCHAR(255),
|
||||||
|
cos_audio INTEGER,
|
||||||
|
cos_video INTEGER,
|
||||||
|
allow_transfer VARCHAR(3) DEFAULT 'yes',
|
||||||
|
user_eq_phone VARCHAR(3) DEFAULT 'no',
|
||||||
|
moh_passthrough VARCHAR(3) DEFAULT 'no',
|
||||||
|
account_code VARCHAR(255),
|
||||||
|
notify_early_inuse_ringing VARCHAR(3),
|
||||||
|
max_contacts INTEGER DEFAULT 1,
|
||||||
|
remove_existing VARCHAR(3) DEFAULT 'yes',
|
||||||
|
voicemail_extension VARCHAR(255)
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_ps_endpoints_id ON asterisk.ps_endpoints (id);
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
-- ps_auths
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
CREATE TABLE IF NOT EXISTS asterisk.ps_auths (
|
||||||
|
id VARCHAR(255) PRIMARY KEY,
|
||||||
|
auth_type VARCHAR(255) DEFAULT 'userpass',
|
||||||
|
nonce_lifetime INTEGER DEFAULT 32,
|
||||||
|
md5_cred VARCHAR(255),
|
||||||
|
password VARCHAR(255),
|
||||||
|
realm VARCHAR(255),
|
||||||
|
username VARCHAR(255)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
-- ps_aors
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
CREATE TABLE IF NOT EXISTS asterisk.ps_aors (
|
||||||
|
id VARCHAR(255) PRIMARY KEY,
|
||||||
|
contact VARCHAR(255),
|
||||||
|
default_expiration INTEGER DEFAULT 3600,
|
||||||
|
mailboxes VARCHAR(255),
|
||||||
|
max_contacts INTEGER DEFAULT 1,
|
||||||
|
minimum_expiration INTEGER DEFAULT 60,
|
||||||
|
remove_existing VARCHAR(3) DEFAULT 'yes',
|
||||||
|
qualify_frequency INTEGER DEFAULT 0,
|
||||||
|
authenticate_qualify VARCHAR(3) DEFAULT 'no',
|
||||||
|
max_expiration INTEGER DEFAULT 7200,
|
||||||
|
outbound_proxy VARCHAR(255),
|
||||||
|
support_path VARCHAR(3) DEFAULT 'no',
|
||||||
|
qualify_timeout NUMERIC(5,3) DEFAULT 3.0,
|
||||||
|
voicemail_extension VARCHAR(255),
|
||||||
|
remove_unavailable VARCHAR(3) DEFAULT 'no'
|
||||||
|
);
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
-- ps_contacts (populada dinamicamente pelo registro dos ramais)
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
CREATE TABLE IF NOT EXISTS asterisk.ps_contacts (
|
||||||
|
id VARCHAR(255) PRIMARY KEY,
|
||||||
|
uri VARCHAR(511),
|
||||||
|
expiration_time BIGINT,
|
||||||
|
qualify_frequency INTEGER DEFAULT 0,
|
||||||
|
outbound_proxy VARCHAR(255),
|
||||||
|
path TEXT,
|
||||||
|
user_agent VARCHAR(255),
|
||||||
|
qualify_timeout NUMERIC(5,3) DEFAULT 3.0,
|
||||||
|
reg_server VARCHAR(255),
|
||||||
|
authenticate_qualify VARCHAR(3) DEFAULT 'no',
|
||||||
|
via_addr VARCHAR(255),
|
||||||
|
via_port INTEGER,
|
||||||
|
call_id VARCHAR(255),
|
||||||
|
endpoint VARCHAR(255),
|
||||||
|
prune_on_boot VARCHAR(3) DEFAULT 'no'
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_ps_contacts_endpoint ON asterisk.ps_contacts (endpoint);
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
-- ps_endpoint_id_ips (identificação de troncos por IP)
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
CREATE TABLE IF NOT EXISTS asterisk.ps_endpoint_id_ips (
|
||||||
|
id VARCHAR(255) PRIMARY KEY,
|
||||||
|
endpoint VARCHAR(255),
|
||||||
|
match VARCHAR(80),
|
||||||
|
srv_lookups VARCHAR(3) DEFAULT 'yes',
|
||||||
|
match_header VARCHAR(255)
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_ps_endpoint_id_ips_endpoint ON asterisk.ps_endpoint_id_ips (endpoint);
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
-- ps_registrations (troncos com registration outbound)
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
CREATE TABLE IF NOT EXISTS asterisk.ps_registrations (
|
||||||
|
id VARCHAR(255) PRIMARY KEY,
|
||||||
|
auth_rejection_permanent VARCHAR(3) DEFAULT 'yes',
|
||||||
|
client_uri VARCHAR(255),
|
||||||
|
contact_user VARCHAR(255),
|
||||||
|
expiration INTEGER DEFAULT 3600,
|
||||||
|
max_retries INTEGER DEFAULT 10,
|
||||||
|
outbound_auth VARCHAR(255),
|
||||||
|
outbound_proxy VARCHAR(255),
|
||||||
|
retry_interval INTEGER DEFAULT 60,
|
||||||
|
forbidden_retry_interval INTEGER DEFAULT 0,
|
||||||
|
server_uri VARCHAR(255),
|
||||||
|
transport VARCHAR(255),
|
||||||
|
support_path VARCHAR(3) DEFAULT 'no',
|
||||||
|
fatal_retry_interval INTEGER DEFAULT 0,
|
||||||
|
line VARCHAR(3) DEFAULT 'no',
|
||||||
|
endpoint VARCHAR(255)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
-- CDR (cdr_pgsql) — colunas padrão do CDR nativo do Asterisk
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
CREATE TABLE IF NOT EXISTS asterisk.cdr (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
accountcode VARCHAR(20),
|
||||||
|
src VARCHAR(80),
|
||||||
|
dst VARCHAR(80),
|
||||||
|
dcontext VARCHAR(80),
|
||||||
|
clid VARCHAR(80),
|
||||||
|
channel VARCHAR(80),
|
||||||
|
dstchannel VARCHAR(80),
|
||||||
|
lastapp VARCHAR(80),
|
||||||
|
lastdata VARCHAR(80),
|
||||||
|
start TIMESTAMP,
|
||||||
|
answer TIMESTAMP,
|
||||||
|
end_time TIMESTAMP,
|
||||||
|
duration INTEGER,
|
||||||
|
billsec INTEGER,
|
||||||
|
disposition VARCHAR(45),
|
||||||
|
amaflags VARCHAR(45),
|
||||||
|
uniqueid VARCHAR(150),
|
||||||
|
userfield VARCHAR(255),
|
||||||
|
linkedid VARCHAR(150),
|
||||||
|
peeraccount VARCHAR(20),
|
||||||
|
sequence INTEGER
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_asterisk_cdr_uniqueid ON asterisk.cdr (uniqueid);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_asterisk_cdr_linkedid ON asterisk.cdr (linkedid);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_asterisk_cdr_start ON asterisk.cdr (start);
|
||||||
|
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
-- CEL (cel_pgsql)
|
||||||
|
-- ---------------------------------------------------------------------
|
||||||
|
CREATE TABLE IF NOT EXISTS asterisk.cel (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
eventtype VARCHAR(30),
|
||||||
|
eventtime TIMESTAMP,
|
||||||
|
userdeftype VARCHAR(255),
|
||||||
|
cid_name VARCHAR(80),
|
||||||
|
cid_num VARCHAR(80),
|
||||||
|
cid_ani VARCHAR(80),
|
||||||
|
cid_rdnis VARCHAR(80),
|
||||||
|
cid_dnid VARCHAR(80),
|
||||||
|
exten VARCHAR(80),
|
||||||
|
context VARCHAR(80),
|
||||||
|
channame VARCHAR(80),
|
||||||
|
appname VARCHAR(80),
|
||||||
|
appdata VARCHAR(512),
|
||||||
|
accountcode VARCHAR(20),
|
||||||
|
uniqueid VARCHAR(150),
|
||||||
|
linkedid VARCHAR(150),
|
||||||
|
peer VARCHAR(80),
|
||||||
|
userfield VARCHAR(255),
|
||||||
|
extra TEXT
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_asterisk_cel_uniqueid ON asterisk.cel (uniqueid);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_asterisk_cel_linkedid ON asterisk.cel (linkedid);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_asterisk_cel_eventtime ON asterisk.cel (eventtime);
|
||||||
Reference in New Issue
Block a user