Clone
2
Reference MIGRATION_README
Patrick Gniza edited this page 2026-08-17 10:48:39 +02:00

Deutsch | English

Romexis Migration Service

This Container is a migration helper service that will be used to migrate an existing Windows-based Planmeca Romexis installation into the Docker-based Romexis Server stack.

  • Flask Web UI / REST API for migration management, status, validation and restore orchestration
  • SFTP upload endpoint for large files and directory trees
  • Manifest-based migration jobs to describe what was transferred
  • Restore hooks for SQL Server database restore and final data placement

The service starts, exposes a web UI, creates migration jobs, provides per-job upload credentials, accepts uploads through SFTP and shows migration state.


Intended Migration Flow

Existing Windows Romexis Installation
    |
    | 1. Create SQL Server .bak backup
    | 2. Collect Romexis data directories
    | 3. Generate manifest.json
    | 4. Upload via SFTP/rclone/WinSCP
    v
Romexis Migration Service
    |
    | 5. Validate uploaded files
    | 6. Stop Romexis container
    | 7. Restore SQL backup
    | 8. Move data directories into target volumes
    | 9. Start Romexis container
    v
Docker-based Romexis Server

Why SFTP Instead of Flask Uploads?

Romexis image archives can become very large. A Flask-only upload approach would require special handling for:

  • upload timeouts
  • interrupted transfers
  • resume support
  • progress tracking
  • large numbers of files
  • large single .bak files

SFTP is better suited for this job because it is supported by many mature tools:

  • rclone (favorite tool)
  • WinSCP
  • FileZilla
  • OpenSSH sftp
  • PowerShell/OpenSSH
  • automation scripts

The web application remains responsible for orchestration, status and restore actions.


Project Structure

.
├── migration-service/
│   ├── Dockerfile
│   ├── requirements.txt
│   ├── entrypoint.sh
│   ├── app/
│   │   ├── app.py
│   │   ├── core/
│   │   │   ├── config.py
│   │   │   ├── migrations.py
│   │   │   └── sftp_users.py
│   │   ├── templates/
│   │   │   ├── base.html
│   │   │   ├── index.html
│   │   │   ├── migration.html
│   │   │   └── new_migration.html
│   │   └── static/
│   │       └── style.css
│   ├── scripts/
│   │   ├── restore-migration.sh
│   │   └── validate-migration.sh
│   └── ssh/
│       └── sshd_config
│
├── migration-client/
│   └── romexis_migration_client.py
│
└── docs/
    ├── examples/
    │   └── manifest.example.json
    ├── MIGRATION_WORKFLOW.md
    └── SECURITY.md

Quick Start

Build and start the migration service:

docker compose -f docker-compose.migration.yml up -d --build

Open the web UI:

http://localhost:8080

SFTP endpoint:

localhost:2222

Create a migration in the web UI. The service will generate:

  • migration ID
  • SFTP username
  • SFTP password
  • upload path

Then upload files into the migration directory.


Expected Upload Layout

Each migration gets its own incoming directory:

/incoming/<migration-id>/
├── manifest.json
├── database/
│   └── Romexis_db.bak
├── romexis_images/
│   └── ...
├── romexis_ergodata/
│   └── ...
└── romexis_cache/
    └── ...     # optional

The cache directory is optional and can usually be skipped.


Manifest

The manifest.json describes the transferred data.

Example:

{
  "source": {
    "hostname": "old-romexis-server",
    "romexis_version": "6.5.3",
    "database_name": "Romexis_db"
  },
  "backup": {
    "file": "database/Romexis_db.bak"
  },
  "data": {
    "images": "romexis_images",
    "ergodata": "romexis_ergodata",
    "cache": null
  }
}

A full example is included in:

examples/manifest.example.json

Current State

Implemented:

  • Flask web UI
  • REST API
  • migration job creation
  • migration state stored as JSON files
  • generated per-migration credentials
  • SFTP server in the same container
  • upload directory preparation
  • validation hook
  • SQL Server restore
  • Python client

Not yet fully implemented:

  • coordinated Romexis restart through a shared state file
  • checksum validation
  • progress aggregation
  • authentication for the web UI
  • production-grade user isolation

These pieces are intentionally separated so they can be implemented and tested step by step.



Current Implementation Update

The migration service now supports both client-driven and manual browser-based migrations.

Implemented workflow:

  1. Create migration job.
  2. Upload database backup through the Web UI or client workflow.
  3. Generate manifest.json on the server.
  4. Restore the database backup.
  5. Upload romexis_images, romexis_ergodata and optionally romexis_cache through SFTP.
  6. Confirm upload completion.
  7. Validate upload.
  8. Run restore workflow.
  9. Request Romexis restart using the shared state file.
  10. Complete migration and remove temporary SFTP access.

Additional supported operation:

  • cancel a migration and remove the temporary SFTP user

Final states such as completed, cancelled and failed do not recreate SFTP users after a service restart.


Server-Side Manifest Generation

The server owns the manifest format. Clients and the Web UI should submit parameters only.

The restore script expects:

{
  "backup": {
    "file": "database/Romexis_db.bak"
  }
}

For manual uploads, the manifest is generated automatically after the database backup was uploaded through the Web UI.


Romexis Restart Coordination

After a successful database restore, the migration service can request a Romexis restart through:

/data/romexis_images/.romexis_restart_state

The Romexis entrypoint monitors this state file, restarts the Romexis process and writes the result back. The migration service reads the result, logs it and removes the state file.

Development Notes

The current implementation is designed as a practical foundation. It keeps the large-file transport path independent from the web application and makes it possible to test migration workflows incrementally.

Next steps:

  • Add checksum generation and validation.
  • Add authentication to the web UI.
  • Add migration logs per job.
  • Add a dry-run restore mode.