Pendahuluan
Orthanc adalah server DICOM open-source yang sangat populer untuk mengelola medical imaging. Secara default, Orthanc menggunakan SQLite sebagai database, namun untuk deployment yang lebih besar atau untuk kebutuhan performa yang lebih tinggi, MySQL sering menjadi pilihan yang lebih baik.
Persiapan Awal
Persyaratan Sistem
- Server lama dengan Orthanc SQLite yang berjalan
- Server baru dengan MySQL/MariaDB terinstal
- Orthanc dengan plugin MySQL terinstal
- Python 3 dengan library
requests - Akses network antara kedua server
Instalasi Plugin MySQL
Pastikan plugin MySQL untuk Orthanc sudah terinstal di server baru:
sudo apt-get install orthanc-mysql
sudo yum install orthanc-mysql
Konfigurasi Database MySQL
Buat database dan user untuk Orthanc:
CREATE DATABASE orthanc_db;
CREATE USER 'orthanc_user'@'localhost' IDENTIFIED BY 'password_anda';
GRANT ALL PRIVILEGES ON orthanc_db.* TO 'orthanc_user'@'localhost';
FLUSH PRIVILEGES;
Konfigurasi Orthanc untuk MySQL
Edit file konfigurasi Orthanc (/etc/orthanc/orthanc.json):
{
"MySQL": {
"EnableIndex": true,
"EnableStorage": false,
"Host": "localhost",
"Port": 3306,
"Database": "orthanc_db",
"Username": "orthanc_user",
"Password": "password_anda",
"UnixSocket": "",
"EnableSsl": false,
"MaximumConnectionRetries": 10,
"ConnectionTimeout": 5
}
}
Metode Migrasi
Metode 1: Menggunakan Script Python Custom
Metode ini menggunakan REST API Orthanc untuk mengunduh dan mengupload semua DICOM instances.
#!/usr/bin/env python3
"""
Script untuk migrasi data DICOM dari Orthanc SQLite ke MySQL
"""
import requests
import json
import sys
from datetime import datetime
# Konfigurasi Orthanc lama dan baru
OLD_ORTHANC_URL = 'http://192.168.1.89:8042'
NEW_ORTHANC_URL = 'http://192.168.3.14:8042'
AUTH = ('orthanc', 'orthanc') # Username dan password Orthanc
def log_message(message):
"""Fungsi untuk logging dengan timestamp"""
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
print(f"[{timestamp}] {message}")
def check_orthanc_connection(url, name):
"""Cek koneksi ke Orthanc server"""
try:
response = requests.get(f"{url}/system", auth=AUTH, timeout=10)
if response.status_code == 200:
log_message(f"✓ Koneksi ke {name} berhasil")
return True
else:
log_message(f"✗ Koneksi ke {name} gagal: HTTP {response.status_code}")
return False
except requests.exceptions.RequestException as e:
log_message(f"✗ Koneksi ke {name} gagal: {e}")
return False
def get_all_instances():
"""Ambil semua instance DICOM dari Orthanc lama"""
try:
response = requests.get(f"{OLD_ORTHANC_URL}/instances", auth=AUTH)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
log_message(f"Error getting instances: {e}")
return []
def get_instance_dicom(instance_id):
"""Download DICOM file dari instance"""
try:
response = requests.get(f"{OLD_ORTHANC_URL}/instances/{instance_id}/file", auth=AUTH)
response.raise_for_status()
return response.content
except requests.exceptions.RequestException as e:
log_message(f"Error downloading instance {instance_id}: {e}")
return None
def upload_dicom_to_new_orthanc(dicom_data):
"""Upload DICOM file ke Orthanc baru"""
try:
headers = {'Content-Type': 'application/dicom'}
response = requests.post(f"{NEW_ORTHANC_URL}/instances",
data=dicom_data,
headers=headers,
auth=AUTH)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
log_message(f"Error uploading DICOM: {e}")
return None
def migrate_all_instances():
"""Migrasi semua instance DICOM"""
log_message("=== Memulai Migrasi Orthanc ===")
# Cek koneksi
if not check_orthanc_connection(OLD_ORTHANC_URL, "Orthanc Lama"):
return False
if not check_orthanc_connection(NEW_ORTHANC_URL, "Orthanc Baru"):
return False
# Ambil semua instance
log_message("Mengambil daftar semua instance...")
instances = get_all_instances()
if not instances:
log_message("Tidak ada instance yang ditemukan")
return False
log_message(f"Total instance yang akan dimigrasi: {len(instances)}")
# Migrasi setiap instance
success_count = 0
error_count = 0
for i, instance_id in enumerate(instances, 1):
log_message(f"Processing instance {i}/{len(instances)}: {instance_id}")
# Download DICOM
dicom_data = get_instance_dicom(instance_id)
if dicom_data is None:
error_count += 1
continue
# Upload ke Orthanc baru
result = upload_dicom_to_new_orthanc(dicom_data)
if result:
success_count += 1
log_message(f"✓ Berhasil upload instance {i}/{len(instances)}")
else:
error_count += 1
log_message(f"✗ Gagal upload instance {i}/{len(instances)}")
# Statistik akhir
log_message("=== Migrasi Selesai ===")
log_message(f"Berhasil: {success_count}")
log_message(f"Gagal: {error_count}")
return success_count > 0
if __name__ == "__main__":
migrate_all_instances()
Metode 2: Menggunakan ImportDicomFiles.py (Recommended)
Metode ini menggunakan script bawaan Orthanc yang lebih stabil dan teruji.
- Script resmi dari Orthanc
- Lebih stabil dan teruji
- Handling error yang lebih baik
- Cocok untuk dataset besar
Langkah-langkah Metode 2:
Export Data dari Server Lama
Buat script untuk export semua DICOM files:
#!/usr/bin/env python3
import requests
import os
from datetime import datetime
OLD_ORTHANC_URL = 'http://192.168.1.89:8042'
AUTH = ('orthanc', 'orthanc')
EXPORT_DIR = '/tmp/dicom_export'
# Buat direktori export
os.makedirs(EXPORT_DIR, exist_ok=True)
def log_message(message):
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
print(f"[{timestamp}] {message}")
try:
# Ambil semua instances
response = requests.get(f'{OLD_ORTHANC_URL}/instances', auth=AUTH)
response.raise_for_status()
instances = response.json()
log_message(f'Total instances: {len(instances)}')
for i, instance_id in enumerate(instances, 1):
if i % 100 == 0:
log_message(f'Progress: {i}/{len(instances)}')
# Download DICOM file
response = requests.get(f'{OLD_ORTHANC_URL}/instances/{instance_id}/file', auth=AUTH)
response.raise_for_status()
# Simpan ke file
with open(f'{EXPORT_DIR}/{instance_id}.dcm', 'wb') as f:
f.write(response.content)
log_message('Export selesai!')
except Exception as e:
log_message(f'Error: {e}')
Transfer ke Server Baru
# Compress dan transfer
tar -czf dicom_files.tar.gz /tmp/dicom_export/
scp dicom_files.tar.gz user@new-server:/tmp/
# Di server baru
cd /tmp
tar -xzf dicom_files.tar.gz
Import ke MySQL Orthanc
Jalankan ImportDicomFiles.py di server baru:
# Pastikan server MySQL Orthanc sudah berjalan
sudo systemctl start orthanc
# Import menggunakan script Orthanc
python3 /usr/share/doc/orthanc/Samples/ImportDicomFiles/ImportDicomFiles.py \
192.168.3.14 8042 /tmp/dicom_export/ orthanc orthanc
Script Otomatis Lengkap
Untuk mempermudah proses, berikut adalah script bash yang mengotomatisasi seluruh proses:
#!/bin/bash
# Script lengkap untuk migrasi Orthanc SQLite ke MySQL
set -e
# Konfigurasi
OLD_ORTHANC_HOST="192.168.1.89"
NEW_ORTHANC_HOST="192.168.3.14"
ORTHANC_PORT="8042"
ORTHANC_USER="orthanc"
ORTHANC_PASSWORD="orthanc"
EXPORT_DIR="/tmp/dicom_export"
LOG_FILE="/var/log/orthanc_migration.log"
# Fungsi logging
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
# Fungsi untuk export dari server lama
export_from_old_server() {
log "=== Memulai Export dari Server Lama ==="
mkdir -p "$EXPORT_DIR"
python3 << EOF
import requests
import os
from datetime import datetime
OLD_ORTHANC_URL = 'http://${OLD_ORTHANC_HOST}:${ORTHANC_PORT}'
AUTH = ('${ORTHANC_USER}', '${ORTHANC_PASSWORD}')
EXPORT_DIR = '${EXPORT_DIR}'
def log_message(message):
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
print(f"[{timestamp}] {message}")
try:
# Cek koneksi
response = requests.get(f'{OLD_ORTHANC_URL}/system', auth=AUTH, timeout=10)
if response.status_code != 200:
log_message(f"ERROR: Tidak dapat terhubung ke Orthanc lama")
exit(1)
log_message("✓ Terhubung ke Orthanc lama")
# Ambil semua instances
response = requests.get(f'{OLD_ORTHANC_URL}/instances', auth=AUTH)
instances = response.json()
log_message(f"Total instances: {len(instances)}")
for i, instance_id in enumerate(instances, 1):
if i % 100 == 0:
log_message(f"Progress: {i}/{len(instances)}")
try:
response = requests.get(f'{OLD_ORTHANC_URL}/instances/{instance_id}/file', auth=AUTH)
response.raise_for_status()
with open(f'{EXPORT_DIR}/{instance_id}.dcm', 'wb') as f:
f.write(response.content)
except Exception as e:
log_message(f"ERROR: {e}")
log_message("Export selesai!")
except Exception as e:
log_message(f"ERROR: {e}")
exit(1)
EOF
tar -czf "${EXPORT_DIR}.tar.gz" -C "$(dirname "$EXPORT_DIR")" "$(basename "$EXPORT_DIR")"
log "Export selesai: ${EXPORT_DIR}.tar.gz"
}
# Fungsi untuk import ke server baru
import_to_new_server() {
log "=== Memulai Import ke Server Baru ==="
if [ ! -f "${EXPORT_DIR}.tar.gz" ]; then
log "ERROR: Archive tidak ditemukan"
exit 1
fi
tar -xzf "${EXPORT_DIR}.tar.gz" -C "$(dirname "$EXPORT_DIR")"
IMPORT_SCRIPT="/usr/share/doc/orthanc/Samples/ImportDicomFiles/ImportDicomFiles.py"
if [ ! -f "$IMPORT_SCRIPT" ]; then
log "ERROR: ImportDicomFiles.py tidak ditemukan"
exit 1
fi
log "Memulai import..."
python3 "$IMPORT_SCRIPT" "$NEW_ORTHANC_HOST" "$ORTHANC_PORT" "$EXPORT_DIR" "$ORTHANC_USER" "$ORTHANC_PASSWORD"
log "Import selesai"
}
# Menu utama
case "${1:-}" in
"export")
export_from_old_server
;;
"import")
import_to_new_server
;;
*)
echo "Usage: $0 {export|import}"
exit 1
;;
esac
Cara Penggunaan
Opsi 1: Script Python Custom
# Simpan script dan jalankan
python3 migration_script.py
Opsi 2: ImportDicomFiles.py (Recommended)
# 1. Export data
./complete_migration.sh export
# 2. Transfer ke server baru
scp /tmp/dicom_export.tar.gz user@new-server:/tmp/
# 3. Import data
./complete_migration.sh import
Opsi 3: Manual One-liner
python3 -c "
import requests
import os
os.makedirs('/tmp/dicom_export', exist_ok=True)
instances = requests.get('http://192.168.1.89:8042/instances', auth=('orthanc', 'orthanc')).json()
for i, instance_id in enumerate(instances):
print(f'Exporting {i+1}/{len(instances)}: {instance_id}')
data = requests.get(f'http://192.168.1.89:8042/instances/{instance_id}/file', auth=('orthanc', 'orthanc')).content
with open(f'/tmp/dicom_export/{instance_id}.dcm', 'wb') as f:
f.write(data)
"
python3 /usr/share/doc/orthanc/Samples/ImportDicomFiles/ImportDicomFiles.py \
192.168.3.14 8042 /tmp/dicom_export/ orthanc orthanc
Verifikasi Hasil Migrasi
Setelah migrasi selesai, lakukan verifikasi dengan perintah berikut:
# Cek statistik database
curl -u orthanc:orthanc http://192.168.3.14:8042/statistics
# Cek database backend
curl -u orthanc:orthanc http://192.168.3.14:8042/system
# Cek jumlah data
curl -u orthanc:orthanc http://192.168.3.14:8042/patients | jq length
curl -u orthanc:orthanc http://192.168.3.14:8042/studies | jq length
curl -u orthanc:orthanc http://192.168.3.14:8042/instances | jq length
Tips dan Troubleshooting
Untuk Dataset Besar
- Gunakan
ImportDicomFiles.pyuntuk stabilitas yang lebih baik - Monitor penggunaan disk space selama proses
- Pertimbangkan untuk melakukan migrasi secara bertahap per patient atau study
- Gunakan compression untuk transfer file yang lebih cepat
Optimasi Performa
- Sesuaikan konfigurasi MySQL untuk dataset DICOM yang besar
- Gunakan SSD untuk storage yang lebih cepat
- Tingkatkan
innodb_buffer_pool_sizedi MySQL - Disable MySQL binary logging selama import untuk performa lebih baik
Common Issues
- Connection refused: Pastikan firewall tidak memblokir port 8042 dan 3306
- MySQL connection error: Cek konfigurasi database dan credential
- Out of disk space: Monitor space disk selama proses export/import
- Timeout errors: Tingkatkan timeout value di konfigurasi
Kesimpulan
Migrasi Orthanc dari SQLite ke MySQL dapat dilakukan dengan beberapa metode. Metode menggunakan ImportDicomFiles.py adalah yang paling direkomendasikan karena:
- Merupakan bagian resmi dari Orthanc
- Sudah teruji untuk berbagai skenario
- Memiliki error handling yang baik
- Cocok untuk dataset besar
Pastikan untuk selalu melakukan backup data sebelum memulai proses migrasi dan verifikasi hasil migrasi dengan teliti sebelum menggunakan sistem di production.