Move 150+ scripts from root and scripts/ into client/project directories: - clients/dataforth/scripts/ (110 files: AD2, sync, SSH, DB, DOS scripts) - clients/bg-builders/scripts/ (14 files: Lesley mgmt, Exchange, termination) - clients/internal-infrastructure/scripts/ (10 files: GDAP, Gitea, backups) - projects/msp-tools/scripts/ (9 files: CIPP, MSP onboarding, Datto) - projects/gururmm-agent/scripts/ (3 files: API test, JWT, record counts) - clients/glaztech/scripts/ (1 file: CentraStage removal) Also reorganized: - VPN scripts → infrastructure/vpn-configs/ - Retrieved API/JS files → api/ - Forum posts → projects/community-forum/forum-posts/ - SSH docs → clients/internal-infrastructure/docs/ - NWTOC/CTONW docs → projects/wrightstown-smarthome/docs/ - ACG website files → projects/internal/acg-website-2025/ - Dataforth docs → clients/dataforth/docs/ - schema-retrieved.sql → docs/database/ Deleted 24 tmp_*.ps1 one-off debug scripts (preserved in git history). Root reduced from 220+ files to 62 items (docs + directories only). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
143 lines
4.1 KiB
Markdown
143 lines
4.1 KiB
Markdown
# Fix: FreePBX 17 "Undefined array key trunk_name" on fwconsole reload
|
|
|
|
## Environment
|
|
- FreePBX 17 (Sangoma FreePBX Distro)
|
|
- OS: Debian 12 (bookworm)
|
|
- Asterisk: PJSIP driver
|
|
- Trunk: Single PJSIP trunk (FirstDigital)
|
|
|
|
## Problem
|
|
|
|
`fwconsole reload` fails with:
|
|
|
|
```
|
|
In PJSip.class.php line 504:
|
|
Undefined array key "trunk_name"
|
|
```
|
|
|
|
This prevents any configuration changes made in the FreePBX GUI from being applied to Asterisk. DIDs, transfers, and other call routing changes silently fail to take effect.
|
|
|
|
## Diagnosis
|
|
|
|
### The Bug
|
|
|
|
The `getAllTrunks()` method in `PJSip.class.php` (line ~1606) uses this SQL query:
|
|
|
|
```sql
|
|
SELECT id, keyword, data FROM pjsip as tech
|
|
LEFT OUTER JOIN trunks ON (tech.id = trunks.trunkid) OR (tech.id = trunks.trunkid)
|
|
WHERE trunks.disabled = 'off' OR trunks.disabled IS NULL
|
|
```
|
|
|
|
The `trunks.disabled IS NULL` condition catches rows from the `pjsip` table that have **no matching entry in the `trunks` table** — which includes all **extension** data (extensions 201, 202, 235, etc. are stored in the same `pjsip` table). Extensions don't have a `trunk_name` field, so line 504 crashes:
|
|
|
|
```php
|
|
$tn = $trunk['trunk_name']; // line 504 - crashes for extensions
|
|
```
|
|
|
|
### Additional Issue: Orphaned Trunk Data
|
|
|
|
We also found an orphaned trunk in the `pjsip` table:
|
|
|
|
```sql
|
|
SELECT id, keyword, data FROM pjsip WHERE keyword='trunk_name';
|
|
-- Returns:
|
|
-- id=1, trunk_name=FirstDigital (valid - exists in trunks table)
|
|
-- id=2, trunk_name=FirstDigital_SIP (orphan - NO matching entry in trunks table)
|
|
```
|
|
|
|
This orphan was likely created by a partially-deleted trunk configuration.
|
|
|
|
### Side Effect: Broken Logging
|
|
|
|
We also discovered that `/var/log/asterisk/full` was empty — the logger had no file output configured. This masked the problem since no call errors were being recorded.
|
|
|
|
## Fix
|
|
|
|
### Step 1: Patch PJSip.class.php
|
|
|
|
File location:
|
|
```
|
|
/var/www/html/admin/modules/core/functions.inc/drivers/PJSip.class.php
|
|
```
|
|
|
|
Backup first:
|
|
```bash
|
|
cp /var/www/html/admin/modules/core/functions.inc/drivers/PJSip.class.php \
|
|
/var/www/html/admin/modules/core/functions.inc/drivers/PJSip.class.php.bak
|
|
```
|
|
|
|
Replace line 504:
|
|
```php
|
|
// BEFORE (line 504):
|
|
$tn = $trunk['trunk_name'];
|
|
|
|
// AFTER:
|
|
$tn = $trunk['trunk_name'] ?? null; if ($tn === null) { continue; }
|
|
```
|
|
|
|
Using sed:
|
|
```bash
|
|
sed -i "504s/.*/\t\t\t\$tn = \$trunk['trunk_name'] ?? null; if (\$tn === null) { continue; }/" \
|
|
/var/www/html/admin/modules/core/functions.inc/drivers/PJSip.class.php
|
|
```
|
|
|
|
### Step 2: Clean Up Orphaned Trunk Data (if present)
|
|
|
|
Check for orphans:
|
|
```sql
|
|
-- Run in mysql:
|
|
SELECT p.id, p.data FROM pjsip p
|
|
WHERE p.keyword='trunk_name'
|
|
AND p.id NOT IN (SELECT trunkid FROM trunks);
|
|
```
|
|
|
|
Remove any orphans found:
|
|
```sql
|
|
-- Replace '2' with the orphaned ID from the query above
|
|
DELETE FROM pjsip WHERE id='2';
|
|
```
|
|
|
|
### Step 3: Restore Asterisk Logging
|
|
|
|
If `/var/log/asterisk/full` is empty and `logger show channels` shows no file output:
|
|
|
|
```bash
|
|
echo 'full => notice,warning,error,verbose,dtmf,fax' > /etc/asterisk/logger_logfiles_custom.conf
|
|
```
|
|
|
|
### Step 4: Reload
|
|
|
|
```bash
|
|
fwconsole reload
|
|
# Should output: Reload Complete (no errors)
|
|
```
|
|
|
|
Verify logging:
|
|
```bash
|
|
asterisk -rx "logger show channels"
|
|
# Should show: /var/log/asterisk/full File default Enabled
|
|
```
|
|
|
|
## Verification
|
|
|
|
```bash
|
|
# Reload should succeed cleanly
|
|
fwconsole reload
|
|
# Output: Reload Started / Reload Complete
|
|
|
|
# Asterisk should be logging
|
|
wc -l /var/log/asterisk/full
|
|
# Should be non-zero and growing
|
|
|
|
# Trunk should be connected
|
|
asterisk -rx "pjsip show endpoint <trunk_name>"
|
|
# Contact status should show "Avail"
|
|
```
|
|
|
|
## Important Notes
|
|
|
|
- **This patch will be overwritten on FreePBX module updates.** After running `fwconsole ma updateall` or updating the Core module, check if the fix is still in place.
|
|
- The root cause is a bug in FreePBX's `getAllTrunks()` SQL query that doesn't properly filter extensions from trunk data. An upstream fix would modify the query to use `INNER JOIN` or add a `WHERE` clause filtering on `pjsip.keyword = 'trunk_name'`.
|
|
- The orphaned trunk data suggests a trunk was deleted through the GUI but the `pjsip` table wasn't fully cleaned up — a separate FreePBX bug.
|