Table of Contents

Migrate from Legacy AWS (XMPro v4.4) to EKS (XMPro v5.0)

If you're currently running XMPro v4.4 on AWS using the legacy Elastic Beanstalk deployment and planning to move to v5.0 on EKS, this guide walks through a side-by-side migration: deploy the new EKS environment, restore your databases into it, let the schema migration Jobs upgrade them, reconcile them to the new environment, validate, then cut DNS over.

Both environments live in AWS, so the databases move with RDS native backup and restore through S3 (or an RDS snapshot), and you can run both environments in the same account during the transition.

Note

Infrastructure provisioning is your responsibility. This guide uses the example Terraform module's migration4.4 stages, which are templates: community-supported examples of how XMPro provisions this infrastructure, not an officially supported product. As with the EKS deployment guide, you can use them as-is, adapt them, or provision the equivalent resources your own way; you are responsible for infrastructure configuration, maintenance, and support. See the Deployment Responsibility Matrix.

Legacy AWS (v4.4) v5.0 EKS
Compute Elastic Beanstalk environments (EC2, Windows) per product EKS cluster with containers per product - dedicated to one environment, or optionally shared across sites
Products SM, AD, DS SM + IS (identity split out), AD, DS, optional AI
Database Amazon RDS SQL Server Amazon RDS SQL Server (new instance, same or newer engine version)
Caching ElastiCache Redis Optional ElastiCache Redis, only for multi-replica products (enable_autoscale)
TLS ACM certificates on ALB Let's Encrypt via cert-manager at Envoy Gateway
Ingress ALB per Beanstalk environment One NLB on static EIPs → Envoy Gateway → HTTPRoutes
Secrets Systems Manager Parameter Store Secrets Manager (one aggregate bundle) + External Secrets Operator
Storage / persistence EC2 instance filesystem PV/PVCs - RWX shared mounts (EFS) for multi-replica, e.g. the Data Protection key ring
Deployment ZIP packages uploaded to Beanstalk Terraform (layered) + Helm
Multi-environment One stack per environment One cluster, many isolated sites
Important

Your data survives the migration. The databases carry everything that matters:

  • All users, roles, companies, and product registrations (SM database)
  • All applications and pages (AD database)
  • All data streams, collections, and stream host registrations (DS database)
  • AI content, if your environment runs AI and you choose to carry its database over (AI database)

The v5.0 database migration Jobs upgrade the schema from 4.4 to 5.0 automatically on first deploy against the restored databases.

Caution

The side-by-side approach means your legacy environment keeps running untouched until you've validated the new one. Do not decommission anything until the post-migration validation passes.


Required Information from Your Existing Installation

Document these values from your legacy deployment before starting.

1. AWS Resource Information

Configuration Item Where to Find Example
AWS Region Beanstalk console us-west-2
RDS Instance Identifier RDS console xmpro-production-db
RDS Endpoint + Engine Version RDS console → Connectivity / Configuration xmpro-prod.xxxx.rds.amazonaws.com, sqlserver-se 15.00
DB Admin Username/Password Parameter Store (/<app>/xmpro/data/connectionString) or secure storage xmadmin / (your password)
SM / AD / DS Database Names SQL Server (SELECT name FROM sys.databases) SM, AD, DS
AI Database Name (only if your environment runs AI) SQL Server (SELECT name FROM sys.databases) AI
Per-database SQL users (if used) Your DBA / connection strings smdbuser, addbuser, dsdbuser
Current Product URLs Beanstalk environment URLs / Route53 records https://sm.xmpro.yourco.com
Route53 Hosted Zone Route53 console xmpro.yourco.com

2. Application Configuration

Configuration Item Where to Find Example
AD encryption key Parameter Store (/<app>/xmpro/appDesigner/encryptionKey) base64 / string
Company Names SM → Companies YourCo
Stream Host Collection IDs/Secrets DS → Collections GUIDs
SMTP Configuration Beanstalk environment variables / Parameter Store Server, port, credentials
Custom Environment Variables Beanstalk → Configuration → Software Any xm__-prefixed settings

Finding values from the AWS CLI (snapshot the AD environment's settings: that's where the application configuration lives):

# RDS instances (note EngineVersion - the new instance must be >= this)
aws rds describe-db-instances \
  --query 'DBInstances[*].[DBInstanceIdentifier,Endpoint.Address,Engine,EngineVersion]' --output table

# Beanstalk environments
aws elasticbeanstalk describe-environments \
  --query 'Environments[*].[EnvironmentName,CNAME,Status]' --output table

# Parameter Store entries (legacy secrets, incl. DB creds + encryption keys)
aws ssm describe-parameters \
  --query 'Parameters[?contains(Name, `xmpro`)].Name' --output table
Note

Dedicated per-database SQL users: if your 4.4 products connect with dedicated users per database (e.g. smdbuser, addbuser, dsdbuser), those database-scoped users are restored with the databases. The v5.0 application layer currently connects to all product databases with the single RDS master login you supply in the app stage: the restored per-database users remain in place but are not used by the products.

Important

Carry over the AD encryption key. XMPro encrypts certain stored values (e.g. data-source connection strings in AD) with the App Designer encryption key. If the v5.0 deployment generates a different key than the legacy environment that wrote the data, those values can't be decrypted after migration. Capture the v4.4 App Designer encryption key (above) and supply it to the v5.0 application layer rather than letting it generate a fresh one. On a legacy AWS deployment it is the Parameter Store entry /<app>/xmpro/appDesigner/encryptionKey. The DS encryption key lives in its own database and carries over automatically, so the AD key is the only one supplied here. If you are also carrying an AI database over, see the AI caveat in step 3.


Backup Before Migrating

Caution

Always back up before migrating. The migration restores copies of your databases (the originals are never modified) but backups are still your recovery path.

You have two ways to move the databases. Native .bak backup/restore (below) is the documented, portable path and fits the layered Terraform flow (a fresh Terraform-managed RDS that you restore into). RDS snapshot-restore is a simpler same-account/region alternative - see Alternative: RDS snapshot-restore.

Important

Engine version: a SQL Server .bak (and an RDS snapshot) can only be restored into the same or a newer engine version, never older. Check your source EngineVersion and set the new instance's db_engine_version to match or exceed it (e.g. a SQL Server 2022 / 16.00 source needs db_engine_version = "16.00" on the target; the example's sqlserver-ex 15.00 default would reject it). The example _infra module derives the parameter-group family and option-group major version from db_engine/db_engine_version, so setting these is enough.

SQL Server target compatibility checklist

Confirm these against your source databases (SELECT name, collation_name, compatibility_level, is_encrypted FROM sys.databases) before restoring:

Property Rule
Engine version Target ≥ source major version (restore can't downgrade).
Edition Restore Standard/Enterprise sources into sqlserver-se/-ee, not Express - Express has a 10 GB/DB cap and rejects SE/EE-only features (partitioning, In-Memory OLTP, some compression).
Compatibility level Restored DBs keep their source compatibility_level; a newer server runs them fine. Optionally bump to the new level after migration.
Collation Match the target RDS server collation to the source to avoid Cannot resolve collation conflict on tempdb/cross-DB operations. The RDS default SQL_Latin1_General_CP1_CI_AS matches a standard XMPro source.
TDE If the source uses Transparent Data Encryption (is_encrypted = 1), replicate the certificate/key on the target (RDS TDE option group + KMS) or the encrypted .bak won't restore. Standard XMPro deployments don't use TDE.
Logins SQL logins are server-level and are not in a .bak - only DB users are. XMPro authenticates application users from inside the SM database and connects as the RDS master, so app users carry over; any SQL-login-based access would need remapping.

1. Set up native backup on the source RDS instance

RDS SQL Server uses an option group for native .bak backup/restore to S3. If your source instance doesn't already have it:

# Create an S3 bucket for the backup transfer
aws s3 mb s3://yourco-xmpro-migration --region us-west-2

# Create the IAM role RDS assumes to read/write the bucket
aws iam create-role --role-name rds-s3-backup-role \
  --assume-role-policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"rds.amazonaws.com"},"Action":"sts:AssumeRole"}]}'
aws iam put-role-policy --role-name rds-s3-backup-role --policy-name s3-migration-access \
  --policy-document '{"Version":"2012-10-17","Statement":[
    {"Effect":"Allow","Action":["s3:ListBucket","s3:GetBucketLocation"],"Resource":"arn:aws:s3:::yourco-xmpro-migration"},
    {"Effect":"Allow","Action":["s3:GetObject","s3:PutObject","s3:ListMultipartUploadParts","s3:AbortMultipartUpload"],"Resource":"arn:aws:s3:::yourco-xmpro-migration/*"}]}'

# Create an option group with SQLSERVER_BACKUP_RESTORE (match your SOURCE engine major version)
aws rds create-option-group \
  --option-group-name xmpro-backup-restore-src \
  --engine-name sqlserver-se --major-engine-version 15.00 \
  --option-group-description "Native backup/restore for migration (source VPC)"

aws rds add-option-to-option-group \
  --option-group-name xmpro-backup-restore-src \
  --options "OptionName=SQLSERVER_BACKUP_RESTORE,OptionSettings=[{Name=IAM_ROLE_ARN,Value=arn:aws:iam::<account>:role/rds-s3-backup-role}]" \
  --apply-immediately

aws rds modify-db-instance \
  --db-instance-identifier xmpro-production-db \
  --option-group-name xmpro-backup-restore-src --apply-immediately
Note

An RDS option group binds to the VPC of the first instance it's attached to. The -src suffix is deliberate: you'll create a second option group for the new RDS's VPC in the restore step. The rds-s3-backup-role can be reused for both.

2. Back up each database to S3

Connect to the source RDS instance with sqlcmd (or SSMS) and run:

-- Repeat for SM, AD, DS (and AI, if your environment runs it)
exec msdb.dbo.rds_backup_database
  @source_db_name = 'SM',
  @s3_arn_to_backup_to = 'arn:aws:s3:::yourco-xmpro-migration/SM_PreMigration_v44.bak';

exec msdb.dbo.rds_task_status @db_name = 'SM';   -- watch for SUCCESS

Wait for each task to report SUCCESS before continuing.

3. Snapshot Beanstalk configuration

# Repeat for each Beanstalk environment (SM, AD, DS)
aws elasticbeanstalk describe-configuration-settings \
  --application-name <app> --environment-name <env-yourco-ad> \
  > env-yourco-ad-settings-backup-$(date +%Y%m%d).json

Registry Access

Before you start, confirm you can pull the 5.0 images. A migrating installation is more likely to trip on this than a fresh one: your existing 4.4 deployment pulled anonymously from xmpro.azurecr.io and has no pull secret anywhere, so nothing carries over.

read -rs GHE_PAT            # prompts, so the token never lands in shell history
printf '%s' "$GHE_PAT" | docker login containers.xmpro.ghe.com -u YOUR-GHE-USERNAME --password-stdin
docker manifest inspect {{ACR_URL}}/ad:{{VERSION}}

If either command fails, see Registry authentication in the deployment guide. Set registry_username and registry_password in the app stage's tfvars, then pass the resulting secret name to the migration stage:

image_pull_secret = "xmpro-registry"   # app stage's image_pull_secret_name output

Running the Migration

These steps use the migration4.4 example in the EKS Terraform module. It mirrors the standard layered deployment, layer 1 cluster (infra-k8s), layer 2 site infrastructure (infra), layer 3 application (app), and adds one extra migration stage that runs after the application layer to reconcile the references your restored databases carried over from the source environment. You supply a few clearly-labelled inputs and run one apply per stage: there is no SQL to write.

The apply order (matching the example's README.md) is:

infra-k8s  →  infra  →  [restore .bak into RDS]  →  app  →  migration

The migration stage runs after app because its reconcile Job reuses the database password from the in-cluster secret the app layer materializes (there is no separate password to supply) and it needs app's dbmigrate Jobs to have settled the upgraded schema first.

1. Deploy the cluster and site infrastructure

From the migration4.4 example, apply the infra-k8s (cluster) and infra (site infrastructure) stages, following the EKS deployment guide, including its two-phase greenfield apply for infra-k8s. Each stage ships only a terraform.tfvars.example: copy it to terraform.tfvars and fill in the marked values before applying. Two adjustments for a migration:

Use a temporary DNS subzone for validation, and delegate it before layer 3. Deploy with a staging zone (e.g. staging.xmpro.yourco.com) so the new environment is fully testable while production traffic still flows to the legacy environment. Layer 2 creates the Route53 zone, but you must delegate it in the parent zone (add the staging zone's NS records to xmpro.yourco.com, wherever that parent is hosted) before applying layer 3: if the parent zone is a Route53 zone in the same account, layer 2 can do this for you via manage_parent_dns_delegation = true and parent_dns_zone_name (see its terraform.tfvars.example). If the staging hostnames don't resolve, cert-manager's HTTP-01 challenge can't complete, the Let's Encrypt certificate stays pending, and the is/sm pods block waiting on the TLS secret.

Layer 2 creates the RDS instance your databases are restored into. Set db_engine_version to match or exceed your source (see the engine-version note above), and db_engine = "sqlserver-se" if your source is Standard/Enterprise edition. Your production databases are restored in under their original names in the next step, and the app and migration stages are then pointed at those names. This applies to AI as well: leave enable_ai = false in the infra stage even if you plan to carry an AI database over, because the name it would emit would not match your restore. AI is enabled in the app stage instead.

Important

Apply the infra-k8s and infra stages, but stop before the app and migration stages. The databases must be restored before app: otherwise the app stage's dbmigrate Jobs initialize fresh empty databases instead of upgrading yours.

2. Restore your databases into the new RDS instance

The infra stage created the RDS instance (endpoint from terraform output rds_endpoint). Because option groups are VPC-scoped, create a separate SQLSERVER_BACKUP_RESTORE option group for the new instance's VPC (reusing the same rds-s3-backup-role), attach it, then restore. The restores keep their source names (SM, AD, DS in this guide); the app and migration stages are pointed at those names in the next steps:

# Second option group - bound to the NEW cluster VPC (match the TARGET engine major version)
aws rds create-option-group \
  --option-group-name xmpro-backup-restore-tgt \
  --engine-name sqlserver-se --major-engine-version 16.00 \
  --option-group-description "Native backup/restore for migration (target VPC)"

aws rds add-option-to-option-group \
  --option-group-name xmpro-backup-restore-tgt \
  --options "OptionName=SQLSERVER_BACKUP_RESTORE,OptionSettings=[{Name=IAM_ROLE_ARN,Value=arn:aws:iam::<account>:role/rds-s3-backup-role}]" \
  --apply-immediately

aws rds modify-db-instance \
  --db-instance-identifier <new-rds-identifier> \
  --option-group-name xmpro-backup-restore-tgt --apply-immediately
-- Connect to the NEW RDS instance (endpoint from `terraform output rds_endpoint`)
-- Repeat for SM, AD, DS, keeping the source names
exec msdb.dbo.rds_restore_database
  @restore_db_name = 'SM',
  @s3_arn_to_restore_from = 'arn:aws:s3:::yourco-xmpro-migration/SM_PreMigration_v44.bak';

exec msdb.dbo.rds_task_status @db_name = 'SM';

Optional - the AI database. If your v4.4 environment runs the AI product, restore its database the same way, then set the extra AI inputs in the app and migration stages (called out where they apply in the next two steps). Skip this if you don't run AI, which is the common case:

exec msdb.dbo.rds_restore_database
  @restore_db_name = 'AI',
  @s3_arn_to_restore_from = 'arn:aws:s3:::yourco-xmpro-migration/AI_PreMigration_v44.bak';
Note

The restored databases will run under the new instance's master login. Database-scoped users carried over from the source; the dbmigrate Jobs connect with the master credentials from your tfvars.

Verify the restores completed:

exec msdb.dbo.rds_task_status;          -- every task SUCCESS
SELECT name FROM sys.databases;         -- SM, AD, DS (and AI) present

3. Apply the application stage

Note

The AI product is off by default (enable_ai = false) and most migrations leave it that way. There are two exceptions:

  • Your v4.4 environment runs AI and you restored its database in step 2: keep reading, the optional AI inputs are covered below.
  • You want AI as a new capability, with no existing data behind it: leave it off through the migration and enable it afterwards by re-applying the app stage; see Enabling the AI Product Later in the EKS deployment guide. That path provisions a fresh AI database rather than upgrading a restored one.

Apply the app stage next, before the migration stage. On startup, its dbmigrate Jobs detect the existing 4.4 schema in each restored database and upgrade it in place to 5.0, including the SM schema changes for the SM/IS split.

Copy app/terraform.tfvars.example to terraform.tfvars (it marks every migration-specific value with a REPLACE_ placeholder) and set:

# The RESTORED databases from step 2 (source names)
sm_database_name = "SM"
ad_database_name = "AD"
ds_database_name = "DS"

# Product IDs/keys from the source SM database - dbo.Product (IDs) and
# dbo.ProductKey (keys) - so each deployed product matches its registered
# OIDC client. Enter the IDs in lowercase.
sm_product_id  = "<source SM product id, lowercase>"
sm_product_key = "<source SM product key>"
ad_product_id  = "<source AD product id, lowercase>"
ad_product_key = "<source AD product key>"
ds_product_id  = "<source DS product id, lowercase>"
ds_product_key = "<source DS product key>"

# Carry over the AD encryption key so migrated AD can decrypt its existing
# data-source connection strings. AD reads it at startup and never stores it,
# so it must be set before the first apply. (DS/AI keys live in their own
# databases and carry over automatically - only the AD key is supplied here.)
ad_encryption_key = "<your v4.4 xmpro:appDesigner:encryptionKey value>"

Capture the product IDs and keys from the source environment (the IDs must be entered in lowercase: 5.0 validates the OIDC audience case-sensitively). Two ways to get them:

Option A - from the SM UI (no SQL needed). Log in to the source SM as the Site Admin and open Products in the left navigation. Click each product: the detail panel shows a Product ID field with a copy button; the Product Keys toolbar button opens the key list. Capture the ID and key for each product you're migrating.

Note

The products are listed under their full names: XMPro is the Subscription Manager (its ID/key go into sm_product_id/sm_product_key), App Designer → ad_product_id/ad_product_key, Data Stream Designer → ds_product_id/ds_product_key. An AI entry appears only if the source environment runs AI → ai_product_id/ai_product_key.

Option B - query the source SM database:

SELECT
    p.Name AS ProductName,
    LOWER(CONVERT(varchar(36), p.Id)) AS ProductId,
    pk.[Key] AS ProductKey
FROM dbo.Product p
JOIN dbo.ProductKey pk ON pk.ProductId = p.Id
ORDER BY p.Name;

Run it against the source SM database. Save the query above as product-ids.sql, then use sqlcmd:

sqlcmd -S xmpro-prod.xxxx.us-west-2.rds.amazonaws.com -d SM -U xmadmin -P '<password>' -C -i product-ids.sql

-C trusts the server certificate (needed by the encrypt-by-default sqlcmd in ODBC 18 / go-sqlcmd; omit it on older builds). If you'd rather not use the CLI, run the same query in SQL Server Management Studio.

Note

RDS blocks connections from your workstation unless its security group allows them: any direct query in this guide (sqlcmd or SSMS) needs a temporary inbound rule for your public IP on the instance's security group first:

aws ec2 authorize-security-group-ingress --group-id <rds-sg-id> \
  --protocol tcp --port 1433 --cidr <your-public-ip>/32

Remove the rule when you're done (aws ec2 revoke-security-group-ingress with the same arguments). Alternatively run the query from a host inside the VPC.

Expected output: one row per product, GUIDs lowercase (product names as they appear in a 4.4 database; XMPro = the SM product):

ProductName            ProductId                             ProductKey
---------------------  ------------------------------------  ------------------------------------
App Designer           a1b2c3d4-1111-2222-3333-444455556666  f0e1d2c3-aaaa-bbbb-cccc-ddddeeeeffff
Data Stream Designer   b2c3d4e5-2222-3333-4444-555566667777  0f1e2d3c-bbbb-cccc-dddd-eeeeffff0000
XMPro                  c3d4e5f6-3333-4444-5555-666677778888  1a2b3c4d-cccc-dddd-eeee-ffff00001111

Extract the AD encryption key from Parameter Store (this is the /<app>/xmpro/appDesigner/encryptionKey entry on a legacy AWS deployment):

aws ssm get-parameter --name /<app>/xmpro/appDesigner/encryptionKey \
  --with-decryption --query Parameter.Value --output text

Optional - carrying over the AI database. Only if you restored an AI database in step 2. Uncomment the AI block at the end of app/terraform.tfvars.example and set:

enable_ai = true

# The RESTORED AI database (source name), not a name generated by the infra stage
ai_database_name = "AI"

# From the same source SM query as the other products - the row named "AI".
# Enter the ID in lowercase.
ai_product_id  = "<source AI product id, lowercase>"
ai_product_key = "<source AI product key>"

The app stage then runs an ai-dbmigrate Job that upgrades the restored AI database in place, exactly as it does for SM/AD/DS, and the ai. hostname starts routing.

The RAG feature is separate and optional on top of this: setting enable_ai_rag = true also requires ai_timescaledb_connection_string and ai_neo4j_connection_string, and Terraform fails the plan if either is missing. Those services aren't part of the migration path, deploy them first with the infra-ai template as described in Enabling the AI Product Later. Leaving enable_ai_rag = false needs no connection strings.

Important

LLM provider credentials don't survive the AI carry-over. AI encrypts stored LLM provider credentials (API keys, secrets) with an infrastructure key that the app stage generates fresh on every deployment, and there is no input to supply the source environment's key. Everything else in the AI database carries over: re-enter the LLM provider credentials in AI once the new environment is up.

Then apply:

cd examples/migration4.4/app
terraform apply

Watch the dbmigrate Jobs complete. The site's Kubernetes namespace is the name_suffix you set in the app stage, site1 throughout this guide:

kubectl get jobs -n site1
kubectl logs -n site1 job/xmpro-sm-dbmigrate --tail=50
kubectl logs -n site1 job/xmpro-ad-dbmigrate --tail=50
kubectl logs -n site1 job/xmpro-ds-dbmigrate --tail=50
kubectl logs -n site1 job/xmpro-ai-dbmigrate --tail=50   # only when enable_ai = true
Note

Schema migrations are cumulative: the Jobs apply every migration between your source version and 5.0 in sequence. For large databases this takes longer than a fresh install. If a Job hits its backoff limit, check its logs before re-running; contact XMPro support if a specific migration step fails repeatedly.

4. Run the migration stage

With the app deployed, apply the migration stage. It runs a Kubernetes Job that connects to your restored databases and reconciles everything still pointing at the old environment, automatically, with no SQL to write:

  • SM - rewrites each product's Product URL / Log Out URL (App Designer, Data Stream Designer, and AI when its URL is supplied), and aligns the SM ProductKey row with the key this deployment presents (the sm_product_key you set in step 3)
  • AD - rewrites the server URL reference in XMGlobalSetting
  • DS - rewrites the server URL references in ServerVariables

This is what makes OIDC sign-in to the products succeed instead of failing with "Access Denied".

The stage runs after the app stage and reuses the app's in-cluster secret for the database password (and its image pull secret): no passwords are entered here. Copy migration/terraform.tfvars.example to terraform.tfvars and set:

rds_endpoint      = "<new-rds-endpoint>"   # terraform output rds_endpoint (from infra)
rds_port          = 1433
db_admin_username = "xmadmin"

# The RESTORED databases from step 2 (source names)
sm_database_name = "SM"
ad_database_name = "AD"
ds_database_name = "DS"

# Must match the app stage's name_suffix - the Job runs in the app's namespace
namespace = "site1"

ad_url = "https://ad.staging.xmpro.yourco.com"
ds_url = "https://ds.staging.xmpro.yourco.com"

# Optional - uncomment only when the app stage was applied with enable_ai = true.
# Left empty (the default), the Job skips AI entirely.
# ai_url = "https://ai.staging.xmpro.yourco.com"

There is no AI database name here: the reconcile Job only rewrites SM's record of the AI product URL, it doesn't touch the AI database itself.

cd examples/migration4.4/migration
terraform apply
Note

The migration stage operates only on your restored databases (it never touches the source environment) and is safe to re-run if you change hostnames. It rewrites only XMPro's own App Designer / Data Stream Designer URL references, leaving any third-party URLs (e.g. cloud-service endpoints) untouched.

Tip

If OIDC sign-in to App Designer or Data Stream Designer still returns "Access Denied" after the migration stage, the most common cause is a hostname that changed after the migration stage ran. Re-apply the migration stage with the corrected hostnames, then restart the affected pods. As a last-resort manual check you can log in to the new SM with your existing admin credentials → menu (☰) → Products and confirm the Product URL / Product Log Out URL for each product match your new hostnames.

5. Upgrade and reconnect Stream Hosts

v4.4 stream hosts are not compatible with the v5.0 platform. Replace each one with a v5.0 Stream Host, reusing the same Collection ID and Secret as before: these carried over in the DS database, so existing data stream bindings reconnect automatically.

  • In the cluster: deploy through the stream-hosts layer, one Helm release per Collection, with ds_server_url pointing at the new DS hostname.
  • Outside the cluster (Windows services on plant networks, for example): install the v5.0 stream host (download link is surfaced in DS → Stream Hosts), configure the same Collection ID and Secret, and point its server URL at the new DS hostname.

Confirm each host shows online in the new DS.

Important

The default in-cluster stream host needs credentials from your migrated DS. If you set enable_default_stream_host = true in the app tfvars, also set stream_host_collection_id and stream_host_collection_secret to a collection that exists in the migrated DS database (DS → Collections shows each collection's ID and secret). Left empty, the deployment generates fresh credentials that the migrated DS rejects: the stream host crash-loops with Unauthorized, and because the Helm release is atomic, the whole app apply fails with it.

6. Validate, then cut over DNS

Run the full post-migration validation below against the staging hostnames. When everything passes:

  1. Update your production DNS records (sm., ad., ds.) to point at the new gateway EIPs (or re-deploy layers 2-3 with the production dns_zone_name and delegate it)
  2. Lower the record TTLs ahead of cutover (e.g. 300s) so rollback is fast
  3. After cutover, monitor the new environment for an agreed soak period before decommissioning

Alternative: RDS snapshot-restore

For a same-account, same-region move you can skip the .bak/S3/option-group choreography and clone the whole instance with a snapshot. This brings all databases at once (and the source master credentials), so it doesn't fit the "fresh Terraform-managed RDS" flow as cleanly: you point the app layer at the restored instance instead of the one the infra layer would create.

# Snapshot the source (read-only to the source), then restore into the cluster VPC
aws rds create-db-snapshot --db-instance-identifier xmpro-production-db \
  --db-snapshot-identifier xmpro-premigration

aws rds restore-db-instance-from-db-snapshot \
  --db-instance-identifier xmpro-v5 \
  --db-snapshot-identifier xmpro-premigration \
  --db-subnet-group-name <cluster-db-subnet-group> \
  --vpc-security-group-ids <sg-allowing-the-cluster>

Then set the example's rds_endpoint (and DB names) to the restored instance, skip the infra stage's RDS creation, and continue from Apply the application stage. The restored instance keeps the source engine version (no downgrade concern).


Post-Migration Validation

Validate by using the platform: log in and exercise your real applications and streams.

  • Log in at https://sm.<zone> with pre-migration credentials - users carried over in the SM database
  • Companies and roles - spot-check in SM that companies, users, and role assignments match the legacy environment
  • Applications - open your most important applications in AD; verify pages render and data connections work
  • Data streams - open existing streams in DS; verify canvases, agent configurations, and run state
  • Stream hosts - all hosts online, streams executing, data flowing end to end
  • Email - trigger a password reset for a quick SMTP end-to-end check
  • Integrations - confirm any agents using AWS resources (S3, Kinesis, etc.) still have network reachability from the new VPC
  • AI (only if you carried an AI database over) - open AI, confirm your existing content is there, and re-enter the LLM provider credentials

Common Issues

OIDC sign-in to App Designer or Data Stream Designer returns "Access Denied" after migration. → A product hostname changed after the migration stage ran. Re-apply the migration stage with the corrected ad_url/ds_url, then restart the affected pods. (See the migration-stage TIP.)

A dbmigrate Job hits its backoff limit or never completes. → Schema migrations are cumulative and take longer on large databases. Check the Job's logs (kubectl logs -n <name_suffix> job/xmpro-sm-dbmigrate) before re-running; contact XMPro support if a specific step fails repeatedly.

The Let's Encrypt certificate stays pending and the is/sm pods won't start. → The staging hostnames aren't resolving publicly, so cert-manager's HTTP-01 challenge can't complete. Delegate the staging subzone (or add its A records) and confirm dig ad.<zone> +short returns the gateway EIPs before re-applying the app stage.

Login works, but App Designer data sources fail to decrypt or connect. → The AD encryption key wasn't carried over: a freshly generated key can't decrypt values written by the v4.4 environment. Set ad_encryption_key to the source App Designer encryption key (the /<app>/xmpro/appDesigner/encryptionKey value) in the app stage and re-apply; it must be supplied before AD first starts.

AI was carried over, but its LLM provider calls fail with authentication errors. → Expected: the stored provider credentials were encrypted with the source environment's infrastructure key, and the app stage generates a fresh one. Re-enter the LLM provider credentials in AI. (See step 3.)

AD and DS log in fine, but Subscription Manager shows "We could not grant you access to the requested subscription". → The app stage was applied with sm_product_id left at its default instead of the source environment's SM product id, so SM's OIDC client looks for a product entry the restored database stores under a different id (the migration Job also logs SKIP: SM ProductKey (no Product row ...)). Set all product IDs and keys from the source database as described in step 3 and re-apply the app and migration stages.

Rollback (if needed)

The legacy environment was never modified, so rollback is a DNS operation:

  1. Revert the DNS records to the legacy ALB targets
  2. Users are back on the old environment within the record TTL
Caution

Any data created in the new environment after cutover lives only in the new databases. If you must roll back after running in production, plan a reverse data reconciliation before re-cutting over, or accept the gap. This is the strongest argument for a generous validation period before decommissioning the legacy environment.

When you're confident in the new environment, decommission the legacy stack: terminate the Beanstalk environments, snapshot-and-delete the old RDS instance, and remove the old ElastiCache cluster and Parameter Store entries. The new environment lives entirely in its own VPC and resources, so removing the legacy stack cannot touch it.

Tip

Need assistance? Contact XMPro Support or your Implementation Partner for help with migration planning, schema upgrade validation, or rollback procedures.


Last modified: September 28, 2026