Skip to main content
Version: Omada Identity Cloud Private

Installation Script mode

This page describes the Installation Script deployment mode for Omada Identity Cloud Private – the recommended and fully supported path for first-time and standard deployments. For an overview of deployment modes and shared prerequisites, see the Deployment guide.

Overview​

A single installation script (install.sh) orchestrates the entire deployment end-to-end:

  • Preflight validation: OS, disk space, network connectivity checks.
  • Toolchain bootstrap: Installs Terraform, Helm, kubectl, kubelogin, skopeo, jq, ODBC Driver 18, Python, and Ansible automatically, and Azure CLI if it is missing. You still need Azure CLI before you run the installer, to log in (see Step 3).
  • Infrastructure provisioning: Terraform backend, shared global infrastructure, and workspace-specific resources.
  • Artifact publishing: Container images to ACR and release artifacts to blob storage.
  • Configuration validation: Key Vault certificate and secret checks before compute provisioning.
  • Node setup: Ansible playbooks for AKS configuration and application deployment.
  • Health check: Automated post-deployment readiness check.

Before starting, make sure the Installation Script prerequisites and Networking prerequisites are in place.

Step 1: Extract the installation package​

Omada provides the Omada Identity Cloud Private installation package via SharePoint. When you download it, it will be a .zip file named oicp_install_<version>.zip, where <version> is the release version you are installing.

tip

If unzip isn't already installed (common on minimal VM images), install it first: sudo apt update && sudo apt install -y unzip.

Extract it and navigate to the installation directory:

Tool: Bash shell

unzip oicp_install_<version>.zip
cd scripts/install

If ./install.sh fails with Permission denied, the scripts lost their execute permission when the package was extracted. This can happen with packages for the July 2026 and August 2026 releases, or when you extract the package on Windows and copy the files to the VM. To fix it, run the following command from the directory where you extracted the package, and then run the installer again.

find scripts -type f -name '*.sh' -exec chmod +x {} +
tip

Before installing the product, you can confirm that the downloaded release packages actually came from Omada and have not been altered in transit. See Release package signing.

Step 2: Configure deployment-config.json​

The deployment-config.json file in the installation directory is the single configuration input for the entire deployment. Edit it with your environment-specific values before running the script.

info

You can create multiple named copies of this file (for example, for different environments) and pass the desired one via the optional --config parameter, described later.

Use an absolute path, or a file name with no directory component, placed directly in scripts/install. A relative path with subdirectories (for example, --config ./configs/dev.json) is not honored as given: only the file name is used, resolved against scripts/install, so the file must be stored there under that name.

Key parameters to configure:

SectionParameterDescription
azuresubscription_idAzure subscription GUID.
azuretenant_idAzure AD (Microsoft Entra ID) tenant GUID.
azurelocationAzure region (for example, swedencentral).
deploymentworkspace_prefixWorkspace identifier – 2 lowercase letters + 4 digits (for example, ab0001).
deploymentproject_nameProject name for resource naming (for example, oicp). Keep it short – see the naming note below for a hard length limit.
deploymentomada_license_stringOmada license key – provided by Omada.
deploymentupdate_private_dns_recordsWhether to update private DNS records automatically. Defaults to true.
backendstorage_account_nameStorage account for Terraform state.
backendcontainer_nameBlob container name for state files.
backendkeyTerraform state file name. Defaults to terraform.tfstate; the shared-infrastructure state is stored as <key>.shared.
releasepackage_urlSecure URL to the Cloud Private release package – provided by Omada. This is a signed, credential-bearing URL – treat it like a password. Don't paste it into chat, tickets, or slides; it expires on its own, but anyone with it can download the package until then. Must contain a /releases/<version>/ path segment, as in the SAS URLs Omada sends – the installer extracts <version> from this segment to name the local deployment directory (Deployment_OICP_<version>) and exits immediately, before any other check runs, if the pattern isn't found.
releasechecksum_urlOptional URL to the release package SHA-256 checksum. If omitted (and no local release-package.sha256 exists), checksum verification is skipped with a warning.
securityentra_admin_group.login / object_idExisting Entra ID admin group. Leave both empty to have the script create the group for you (it will prompt, unless you pass --auto-create-groups).
securitysql_admin_group.login / object_idExisting Entra ID SQL admin group. Same create-or-provide behavior as entra_admin_group, with one difference: if you supply an object_id for an existing group, the identity running the installer must already be a member of that group or the azure phase fails. Terraform makes this group the SQL Server's Entra admin, and the caller needs membership for the Ansible SQL-login step. When the script creates the group itself, it adds the caller automatically.
shareddns_zone_namePublic DNS zone for Cloud Private custom domains (for example, mycompany.example.com). Required – it names the zone whether the zone is referenced or created (see create_dns_zone). With create_dns_zone set to false, the zone must already exist in Azure – the installer validates this and fails if not found.
sharedcreate_dns_zoneWhether the installer creates the DNS zone. Defaults to false, meaning the zone named in dns_zone_name must already exist. Set to true to have the installer create it.
shareddns_zone_resource_groupResource group of the existing DNS zone.
sharedcertificate_secret_nameName of the Azure Key Vault certificate. If certificate_file (below) is set, the installer imports it automatically with no prompt. If it's empty and the certificate isn't already in Key Vault, the script doesn't fail immediately – it presents an interactive menu to retry, import a certificate file on the spot, or quit (see the confirmations note under Step 4). For --non-interactive runs, where that menu cannot be answered and the phase fails instead, set certificate_file. See Key Vault certificate and secrets.
sharedcertificate_fileOptional path to a certificate file (.pfx or .pem) on the machine running the installer. When set and the Key Vault certificate is missing, the installer imports it. The certificate password is read from the OMADA_CERT_PASSWORD environment variable, never from the config file.
infrastructureaks_system_node_sizeVM SKU for the AKS system node pool (Linux; current automation default: Standard_D2s_v5). See AKS node pools for how the cluster's node pools are split.
infrastructureaks_app_node_sizeVM SKU for the AKS application node pool (Windows; current automation default: Standard_D8s_v5).
infrastructureaks_linux_node_sizeVM SKU for the AKS general-purpose Linux node pool (default: Standard_D4s_v5). This node pool is shared with Linux CAG workloads.
infrastructureallowed_ip_addressesPublic IP allowlist applied to network rules on Key Vault, Storage, the SQL Server firewall, Service Bus, Event Hub, and NSGs. Defaults to []. The machine running the installer (or the pipeline agent) must be included in this list, or it will be locked out of these resources mid-install. The installer auto-adds its own detected public IP only when the list is empty; if you pre-populate it with other IPs (for example, office or VPN egress ranges), you must add the installer's IP yourself. On Service Bus and Event Hub the allowlist is only enforced when enable_private_endpoints is true; otherwise those two allow all traffic by default.
infrastructureenable_private_endpointsWhether to provision Azure Private Link endpoints for Key Vault, Storage, SQL Server, Event Hub, Service Bus, SignalR, and App Services. Defaults to false. Enabling it also moves Event Hub and all four Service Bus namespaces from the Standard to the Premium tier, which changes their cost.
infrastructureenable_public_accessControls public network access for App Services and SignalR only. Defaults to true. It does not affect the Key Vault, SQL Server, Event Hub, or Service Bus – those four always remain reachable over the public network by default, protected only by the allowed_ip_addresses firewall rules. Setting this to false does not, by itself, produce a fully private deployment.
infrastructurelogging_levelWhich AKS diagnostic log categories are collected: minimal (default) collects controller, scheduler, and CSI logs; full adds admin audit, autoscaler, cloud-controller, and guard logs. Any other value fails Terraform validation. See Logging level.
infrastructureapplication_insights_sampling_percentageTelemetry sampling rate for Application Insights, from 0–100. Defaults to 100 (all telemetry captured).
secretsaks-extCertBase64, aks-extKeyBase64, aks-pfxCertificate, aks-pfxPasswordOptional. Base64-encoded certificates and keys can be supplied here to pre-populate Key Vault; otherwise add them to Key Vault when the installer reaches the secrets_validate phase. See Key Vault certificate and secrets. The aks-containerRegistryDockerConfigJson secret is also required by validation but is generated automatically from the container registry credentials if not supplied.

Example deployment-config.json​

The following example shows a fully filled-in deployment-config.json for a development environment.

{
"azure": {
"subscription_id": "00000000-0000-0000-0000-000000000000", // Your Azure subscription GUID
"tenant_id": "00000000-0000-0000-0000-000000000000", // Your Microsoft Entra ID tenant GUID
"location": "swedencentral" // Azure region for all resources
},
"deployment": {
"workspace_prefix": "ab0001", // 2 lowercase letters + 4 digits, e.g. ab0001
"project_name": "oicp", // Used to derive resource names; keep short and lowercase
"omada_license_string": "<provided-by-omada>",
"update_private_dns_records": true // Set to false to manage DNS records manually
},
"backend": {
"storage_account_name": "tfstateoicp", // Storage account for Terraform state; must be globally unique
"container_name": "tfstate", // Blob container name; "tfstate" is a safe default
"key": "terraform.tfstate" // State file name; default is "terraform.tfstate"
},
"release": {
"package_url": "<secure-url-provided-by-omada>",
"checksum_url": "<checksum-url-provided-by-omada>" // Optional; omit to skip checksum verification
},
"security": {
"entra_admin_group": {
"login": "omada-admins", // Display name of the Entra ID admin group
"object_id": "", // Leave empty to have the script create the group
"tenant_id": "" // Leave empty to use the signed-in Azure CLI session's tenant
},
"sql_admin_group": {
"login": "omada-sql-admins", // Display name of the SQL admin group
"object_id": "", // Leave empty to have the script create the group
"tenant_id": "" // Leave empty to use the signed-in Azure CLI session's tenant
}
},
"shared": {
"dns_zone_name": "omada.mycompany.com", // Required; the zone to reference or create
"create_dns_zone": false, // false: zone must already exist; true: installer creates it
"dns_zone_resource_group": "my-dns-rg", // Resource group containing the DNS zone
"certificate_secret_name": "omada-tls-cert", // Name of the certificate in Key Vault
"certificate_file": "" // Optional local .pfx/.pem to import if the certificate is missing
},
"infrastructure": {
"aks_system_node_size": "Standard_D2s_v5", // AKS system node pool VM SKU
"aks_app_node_size": "Standard_D8s_v5", // AKS application node pool VM SKU
"aks_linux_node_size": "Standard_D4s_v5", // AKS general-purpose Linux node pool VM SKU (optional to set; defaults to Standard_D4s_v5 if omitted — the pool itself is always provisioned)
"enable_private_endpoints": false, // Set to true to enable Azure Private Link
"enable_public_access": true, // Controls public access for App Services/SignalR only – see table above
"allowed_ip_addresses": ["203.0.113.10"], // IPs allowed through the resource firewalls; if empty, the installer detects your public IP and writes it back into this file
"logging_level": "minimal", // "minimal" (default) or "full"
"application_insights_sampling_percentage": 100 // Telemetry sampling rate (0–100)
},
"secrets": {
"aks-extCertBase64": "", // Base64-encoded external TLS certificate (.crt)
"aks-extKeyBase64": "", // Base64-encoded external TLS private key (.key)
"aks-pfxCertificate": "", // Base64-encoded PFX certificate
"aks-pfxPassword": "" // PFX certificate password
}
}

How to fill in this file:

You do not need to populate every field before running the script. As a starting point:

  • Fill in first: these specific fields are required, and the script will not start without them – azure.subscription_id, azure.tenant_id, azure.location, deployment.workspace_prefix, deployment.project_name, release.package_url, backend.storage_account_name, and shared.certificate_secret_name. Other fields in the same sections (for example, deployment.omada_license_string, backend.container_name/key, release.checksum_url) have defaults or are validated later, not at startup.

  • Confirm prerequisites exist (shared): the certificate doesn't strictly need to exist beforehand for an interactive run – if it's missing, the script offers to import one on the spot. Set certificate_file to skip that prompt and have it import automatically instead. For --non-interactive runs, certificate_file must be set, since there is no prompt to answer if the certificate is missing. See Key Vault certificate and secrets. Similarly, the DNS zone named in dns_zone_name must already exist in Azure, unless you set create_dns_zone to true to have the installer create it.

  • Choose your approach (security): leave object_id empty to let the script create your Entra ID admin groups automatically, or fill them in to use existing groups.

    note

    If entra_admin_group and sql_admin_group are left without an object_id, the script checks whether a group with the configured (or default) name already exists, and prompts to create it if not. When running with --non-interactive, you must either pre-populate both groups' object_id values or pass --auto-create-groups; otherwise the script will fail at this step rather than prompt.

  • Leave as-is unless you have specific requirements (infrastructure): the defaults work for most standard deployments.

  • Optional shortcut (secrets): supply base64-encoded certificates here to let the script push them to Key Vault automatically. If left empty, add them to Key Vault when the script reaches the secrets_validate phase. See Key Vault certificate and secrets.

warning
  • Comments (prefixed //) are included for reference and must be removed from your actual file before use.

  • Workspace naming: The workspace_prefix must follow the format 2 lowercase letters + 4 digits exactly (for example, ab0001).

  • Combined length limit: project_name and workspace_prefix together form the name of the workspace's shared storage account (<project_name><workspace_prefix>sharedsa – dashes are stripped). Azure caps storage account names at 24 characters, and configuration validation fails immediately if the combination exceeds it. Keep project_name short.

    This limit applies to the workspace's shared storage account, not to the Terraform state account named in backend.storage_account_name.

Key Vault certificate and secrets​

The installer creates the Key Vault, <project_name>-shared-kv, in the terraform_iac_shared phase. On a first installation, you cannot upload anything to it in advance. Provide the certificate and secrets in one of these ways:

  • Unattended (--non-interactive) runs: set shared.certificate_file, with the certificate password in the OMADA_CERT_PASSWORD environment variable, and fill in the secrets section of deployment-config.json. The installer imports both during the secrets_validate phase.
  • Interactive runs: if anything is missing at secrets_validate, the installer prints the Key Vault name and a link to it in the Azure portal, then waits. Add the missing items in the Azure portal and choose Re-validate.
  • An unattended run that stopped at secrets_validate: populate the Key Vault named in the error, then rerun the installer with --resume.

You can check the required secrets with validate-secrets.sh --vault-name <project_name>-shared-kv (add --list to see the required secrets without checking their values). It flags any required secrets that are missing or still set to a placeholder. Because it only works once the Key Vault exists, use it after a stopped run or before an upgrade, not before a first installation. It does not validate the TLS certificate named in shared.certificate_secret_name – the installer checks that certificate separately during the secrets_validate phase.

Infrastructure sizing​

The default VM SKUs are configured in deployment-config.json via the aks_system_node_size, aks_app_node_size, and aks_linux_node_size parameters. For sizing profiles, SKU recommendations, and cost optimization guidance, see Azure infrastructure sizing in the Omada Identity Cloud Private overview.

After initial deployment, monitor CPU and memory usage in the Azure portal to determine if scaling is needed.

Logging level​

The logging_level field in the deployment-config.json file controls the verbosity of AKS cluster controller logs.

AKS cluster controller logs record the activity of Kubernetes controllers – the automated systems that manage cluster health and state. This includes pod restarts, node status checks, resource allocation decisions, and other routine cluster maintenance operations.

ValueDescription
minimalDefault. Logs essential cluster events only. Recommended for most deployments.
fullLogs all controller activity, including routine checks and updates. This mode generates high-volume logs and can rapidly fill the Log Analytics workspace.
note

Logging verbosity is separate from telemetry sampling, which is controlled by application_insights_sampling_percentage in the same section.

Step 3: Azure login​

tip

If Azure CLI is not already installed (common on a fresh VM), install it first. The installer installs it only later, in the tools phase, so az login fails with command not found until then.

curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash

This command needs curl, which minimal VM images may also lack. If it is missing, install it first: sudo apt update && sudo apt install -y curl.

Authenticate with Azure CLI and verify you are on the correct subscription:

Tool: Bash shell

az login --tenant <your-tenant-id>
az account set --subscription <your-subscription-id>
az account show

Ensure your account has the Azure roles described in Identity – Contributor (or Owner) and User Access Administrator (or Owner) at subscription scope.

Step 4: Run the installation script​

From the installation directory, run:

Tool: Bash shell

./install.sh --config ./deployment-config.json
note

The ./deployment-config.json is the default value for --config, so this is equivalent to running ./install.sh with no arguments. It is provided here for full reference.

By default, the script logs progress to the following, relative to the installation directory (scripts/install) you're running it from (where <project> is your project_name and <workspace> is your workspace_prefix):

../../Deployment_OICP_<version>/run-<project>-<workspace>/logs/install-<timestamp>.log
note

Set the INSTALL_WORK_DIR environment variable to relocate the entire deployment directory elsewhere – useful if the installation directory's disk does not have enough room. For example:

INSTALL_WORK_DIR=/mnt/bigdisk/oicp-work ./install.sh --config ./deployment-config.json

When set, the deployment directory (and its logs) live at ${INSTALL_WORK_DIR}/Deployment_OICP_<version>/... instead of the default path above – adjust the tail command below accordingly.

Currently, the preflight disk check measures free space on the disk that holds the installation package, not on INSTALL_WORK_DIR. That disk must still have 30 GB free, or 12 GB when resuming after the release package is already staged, even if INSTALL_WORK_DIR points to a larger disk.

If you set INSTALL_WORK_DIR, set it to the same value every time you run --resume. See Resuming an interrupted installation.

Progress is shown live in the terminal in both interactive and non-interactive mode. To follow it from a separate terminal session instead – for example, if the installer is running in the background or over a connection you do not want to keep occupied – execute (from scripts/install – adjust the path if INSTALL_WORK_DIR is set):

Tool: Bash shell

tail -f ../../Deployment_OICP_<version>/run-<project>-<workspace>/logs/install-*.log

Interactive confirmations during installation​

The script pauses for confirmation at several points during a fresh installation, typically:

  • At startup, after configuration is loaded (press Enter to continue).
  • Before creating Terraform backend resources (resource group, storage account, container), if they don't already exist.
  • Before publishing release artifacts to blob storage, and again before publishing container images to the registry.
  • Before each terraform apply (once for shared infrastructure, once for workspace-specific infrastructure).
  • If your detected OS version differs from Ubuntu 24.04.
  • If some of the requested VM sizes are not available in the selected Azure region (continuing may cause the deployment to fail).
  • During certificate validation (secrets_validate phase): if a required certificate is missing or invalid, the script presents a menu to retry, import a certificate file interactively, or quit. Have your certificate files (.pfx or .pem) accessible before running the script.
  • On a re-run where the release package is already staged: whether to reuse it rather than downloading and extracting it again.

For the Yes/No prompts above, answer y to proceed. The certificate-validation menu is a numbered choice, not a Yes/No prompt – see its own bullet above for the options it presents.

danger

There is one prompt where y can be destructive. If a phase fails after workspace infrastructure has been applied, the installer offers a rollback:

Rollback triggered. This will destroy all resources in workspace '<workspace_prefix>'.
Proceed with rollback (terraform destroy)? [y/N]

This prompt defaults to No, and answering y runs terraform destroy against the workspace. Rollback on failure is enabled by default; set ROLLBACK_ON_FAILURE=false in the environment to disable it for a run. Upgrade runs force it off and refuse the rollback outright.

Run the script in a regular interactive terminal session (not piped, backgrounded, or invoked from automation) so these prompts can be answered.

In --non-interactive mode, each prompt resolves to its default instead of pausing:

  • Prompts that default to Yes (the startup pause, Terraform backend resource creation, the two artifact-publish confirmations, and each terraform apply) are accepted automatically. A non-interactive run therefore creates backend resources and applies Terraform changes without pausing for review.
  • Prompts that default to No (the OS-mismatch confirmation and the VM-size availability warning) fail the run immediately. The rollback confirmation also defaults to No, so an unattended run never destroys the workspace.

The certificate validation menu does not block unattended runs – it automatically quits, failing the phase, if a certificate is missing.

Resuming an interrupted installation​

If the installation is interrupted or a phase fails, resume from the last completed phase:

Tool: Bash shell

./install.sh --config ./deployment-config.json --resume

If you set INSTALL_WORK_DIR for the original run, set it to the same value for --resume. Otherwise, the installer does not find the existing checkpoints and starts again from the beginning. For example:

Tool: Bash shell

INSTALL_WORK_DIR=/mnt/bigdisk/oicp-work ./install.sh --config ./deployment-config.json --resume
note

Transient Azure errors, such as a Terraform apply failing with HTTP response was nil; connection may have been reset, are usually resolved by resuming. For details, see Known issue: Terraform apply fails with a connection reset error.

To clear all checkpoints and restart the entire installation:

Tool: Bash shell

./install.sh --config ./deployment-config.json --force
important
  • Each phase records its completion as a <phase_id>.done file containing the UTC timestamp of when it ran, stored in Deployment_OICP_<version>/run-<project>-<workspace>/ (under INSTALL_WORK_DIR, if set). Deleting a phase's .done file will cause that phase to be re-executed the next time --resume is run.

  • --force clears all checkpoints but does not destroy Azure resources. To tear down infrastructure, use Azure portal or terraform destroy.

Automatic rollback on failure​

If the installer fails after workspace-specific infrastructure has already been provisioned (the terraform_iac phase has completed) and --skip-terraform was not used, it prompts to roll back:

Prompt: Proceed with rollback (terraform destroy)? – default: No

  • Confirming runs terraform destroy against the workspace's infrastructure on a best-effort basis.
  • Declining (or a failure earlier than terraform_iac, or a run with --skip-terraform) leaves resources as they are; the log notes that resources may be in a partial state.
  • In --non-interactive mode, this prompt is never shown – it silently resolves to No, so resources are left in place and the run exits with its original error. Follow up with --resume to continue, or tear down manually through the Azure portal or terraform destroy.

There is currently no flag to disable this behavior when it would otherwise apply.

Common options​

FlagDescription
-h, --helpPrint usage information and exit.
--resumeSkip completed phases and continue from the last failure.
--forceClear all checkpoints and re-run all phases.
--verbose, -vEnable debug output.
--dry-runRun the Ansible phases in check mode (Ansible --check). This affects the Ansible phases only; Terraform still plans and applies changes.
--skip-toolsSkip installing the toolchain. A verification step still runs regardless of this flag and requires az, terraform, kubectl, kubelogin, helm, skopeo, python3, jq, and ODBC Driver 18 to already be on PATH – the run fails immediately if any are missing. Use this flag only when the full toolchain is already installed and verified.
--skip-terraformSkip both Terraform phases, along with artifact publishing (blob and container registry), tfvars sync, and Key Vault secret validation — the entire Phase 7 block runs only when Terraform isn't skipped. Use only when a prior run already completed Phase 7 and you're re-running later phases.
--skip-ansibleSkip the Ansible configuration phase.
--tags <tags>Restrict Ansible execution to specific tags (comma-separated), for example --tags dns_records. The value applies to all four Ansible sub-phases, and each sub-phase is still checkpointed as complete when it exits successfully – including the ones where the tag matched no tasks. A later --resume skips those, so use --force or delete the relevant .done files before a full re-run.
--non-interactiveDisable interactive prompts; fail on missing input (CI/CD mode).
--auto-create-groupsCreate Entra ID groups automatically without prompting.
--entra-group-name <name>Override the default Entra admin group name (omada-admins).
--sql-group-name <name>Override the default SQL admin group name (omada-sql-admins).
--update-configWrite newly created Entra/SQL group IDs back into deployment-config.json.
--workspace <prefix>Override deployment.workspace_prefix from the command line.
--no-cacheForce re-download of the release package instead of reusing a cached copy.
--config <path>Path to the deployment configuration file (default: ./deployment-config.json).
--upgradeAcknowledge a forward product-version change against an existing workspace. Required when upgrading – see the Upgrade guide.
--drain-timeout <mins>On any run against an existing environment, how long to wait for an import already in flight to finish (default: 30; 0 fails immediately instead of waiting).
--skip-import-drainStill pause imports, but do not wait for an import already in flight to finish.
-h, --helpPrint the full option list and exit.
Ansible warnings

During Ansible phases, you may see deprecation warnings related to ansible.module_utils._text imports (to_bytes, to_native, to_text). These warnings come from the Azure Ansible collection and do not affect task execution with the current pinned Ansible Core version. For details, see Known issue: Ansible module deprecation warnings.

Stage dependency overview​

The installer runs the following phases in order, with each phase checkpointed on success. When using --resume, the script skips phases whose checkpoint already exists and continues from the first incomplete one – including resuming partway through the Ansible stage, since each Ansible sub-phase has its own checkpoint.

note

Four phases are an exception and always run on every invocation, checkpoint or not:

  • config – to reload configuration values into the current shell
  • terraform_backend – to re-validate, not recreate, the Terraform state backend
  • import_gate – an import can start between runs, so a stale checkpoint must never skip the check
  • pause_imports – a resumed run must re-establish the pause rather than assume an earlier attempt still holds it

None of the four performs destructive or duplicate work when re-run. In upgrade mode, upgrade_snapshot also always runs; a re-run adopts the snapshot the earlier attempt captured rather than taking a new one, so the restore anchor stays fixed at the first attempt.

OrderStagePurpose
1preflightOS, disk, network checks.
2configLoad and validate deployment-config.json.
3toolsInstall toolchain (Terraform, Ansible, kubectl, etc.).
4azureAzure auth, RBAC and quota checks, Entra/SQL group provisioning.
5terraform_backendCreate or validate Terraform state storage.
6releaseDownload and extract Cloud Private release package.
7version_guardCompare the release version against the workspace resource group's ProductVersion tag and block an unacknowledged change.
8import_gateRefuse to continue while an import is active.
9pause_importsPause imports for the rest of the run and wait for any import already in flight to finish. Skipped on a genuine fresh install; released automatically when the run ends, however it ends.
10terraform_iac_sharedProvision shared global infrastructure.
11artifacts_publish_blobPublish release artifacts to blob storage.
12artifacts_publish_acrPublish container images to ACR.
13tfvars_syncSync release-derived values into Terraform variables.
14secrets_validateValidate Key Vault certificates and secrets.
15terraform_iacProvision workspace-specific infrastructure.
16ansible_db_preaksTier 1 – pre-AKS database setup.
17ansible_deploy_aksPhase 1 – deploy AKS cluster, ES pod, Timer pod, the four Cloud Application Gateway worker pods, and DNS records.
18ansible_configure_esTier 2+3 – ES configuration (changeset import, provisioning, connectivity).
19ansible_deploy_aks_phase2Phase 2 – deploy RoPE and CagOps pods.
20health_checkAutomated post-deployment health check. Detailed documentation: Post-deployment health check.
21environment_snapshot_postCapture the environment's post-deployment state as JSON. Runs on fresh installs as well as upgrades, and is attempted best-effort even when an earlier phase fails.

Two further phases run only with --upgrade: upgrade_snapshot, which captures the pre-upgrade state before anything is modified, and upgrade_verify, which checks that the upgrade actually took effect and then marks it complete. See Upgrade verification in the Upgrade guide.

Completed phases are marked with checkpoint files under Deployment_OICP_<version>/run-<project>-<workspace>/.

note

Review the installation log for the health_check phase result and address any reported issues before handing over the environment. For the full validation checklist, see Deployment validation checklist in the Deployment guide.

If the health check reports failures or warnings and you need to troubleshoot further, see Collecting debug logs to gather diagnostic data for analysis or to send to Omada Support.