Source-available bridge that brings Zerto disaster-recovery state into ServiceNow. Business Source License 1.1 — free for non-production use; commercial license required for production. Zerto-first.
Status: v0.1 implemented end-to-end. All seven v0.1 flows shipped; 100 tests passing. Verified against ServiceNow Zurich/Yokohama PDIs and Zerto v10.8 Linux Appliances. SNOW-side install is fully automated as of 0.1.2.
The bridge runs in the customer's network next to the Zerto ZVM and reconciles state into ServiceNow on a polling cadence. From the operator's perspective, SNOW is the only thing they touch.
Every Zerto alert (RPO breach, peer-site loss, FOT-reminder overdue, license expiry...) becomes an em_alert. The bridge transitions alerts cleanly when Zerto resolves them — no duplicates, no manual ack-ack-ack.
A custom CI class u_cmdb_ci_zerto_vpg (extends cmdb_ci) is created on
install. Every VPG is upserted with its full Zerto configuration, then member
VMs are linked to existing cmdb_ci_vm_instance rows. The bridge does NOT
create VM CIs — vCenter is the source of truth for VM identity.
Each VPG record exposes the full Zerto configuration plus 5 action buttons wired to bridge endpoints. Refresh from Zerto pulls fresh detail on demand; the FOT lifecycle buttons drive ServiceNow's Change Management workflow.
Click "Zerto - Request Test Failover" on a VPG → bridge creates a
change_request with the FOT pre-staged. Run it through your existing CM
approval workflow. After approval, click "Run Test Failover" to actually fire
the test in Zerto. Click "Stop FOT - Successful" or "Stop FOT - Failed" to
record the result. The operator never touches the Zerto GUI.
Every Zerto Failover Test, Failover, AND Move task gets a corresponding change_request — whether initiated from SNOW or directly in Zerto. The bridge mirrors task state in real time and closes the change when the task terminates. Type mapping in v0.1:
- Failover Test →
change_request.type = normal - planned Failover / Move →
change_request.type = normal - unplanned Failover (Zerto auto-failover) →
change_request.type = emergency
This is Flow 4 — the audit lane. It runs independently of Flow 5 (the SNOW-initiated FOT button); together they ensure every Zerto operation lands in Change Management regardless of where it was started.
zsnow is a long-running async Python process that runs inside the customer's network next to the Zerto ZVM and reconciles Zerto state into ServiceNow:
| # | Flow | What it does |
|---|---|---|
| 1 | Alerts → em_event | Poll /v1/alerts every 60s, drive SNOW Event Management state via transition-only writes |
| 2 | Bidirectional close | SNOW operator closes em_alert → bridge POSTs /v1/alerts/{id}/dismiss back to Zerto |
| 3 | VPG reconcile → CMDB | Cheap-tick every 5 min + deep-detail sweep every hour + on-demand pull via SNOW UI |
| 4 | Failover / Move tasks → change_request | Mirror Zerto-initiated FOT/FOL/Move as auto-record change_requests, type=emergency for unplanned failovers |
| 5 | Run/Stop FOT from SNOW | Full SNOW-driven Failover Test lifecycle: Request → Approve → Run → Stop Successful/Failed |
| 6 | Deterministic CMDB enrichment | Walk CMDB on each alert to annotate em_event with business service / owner / tier |
| 7 | Audit log | Every write captured in SNOW u_zerto_audit + local SQLite intent log |
The bridge is level-triggered and stateless — restart it, lose its SQLite, redeploy elsewhere, all no-ops. SNOW is the state store. Read the architecture deep-dive for why.
The MID Server is ServiceNow's lightweight Java agent that runs inside the customer's network. It's the standard way SNOW integrates with on-prem systems — Discovery uses it, Orchestration uses it, every ITOM integration uses it. zsnow uses it for the same reason: it makes the integration zero-pinhole at the customer's edge.
What the MID Server gives you, deployed alongside zsnow:
| Without a MID Server | With a MID Server |
|---|---|
| SNOW can't reach the bridge unless you punch an inbound firewall hole | MID Server polls SNOW outbound only — no inbound firewall hole needed |
Refresh from Zerto, Run Test Failover, Stop FOT buttons in SNOW have no path to call the bridge |
Those buttons work via the MID Server's ecc_queue channel |
| Bridge can only push data INTO SNOW; SNOW can't initiate anything against Zerto | Full bidirectional control — SNOW operators drive Failover Tests, dismiss alerts, refresh CMDB on demand |
| Customer security team has to approve an inbound firewall change for every PDI / SaaS region | No change required; uses the same outbound HTTPS path the MID Server already uses for everything else |
For many enterprises this is the difference between "we can deploy zsnow" and "we can't, our security team won't approve the inbound rule." If you already have a MID Server for any other reason (Discovery, Orchestration, Cloud Provisioning) — you can reuse it; nothing zsnow-specific has to be installed on it.
Install path: zsnow does NOT ship a MID Server installer. The download URL is date-stamped (no stable "latest" link), the registration step is interactive, and most enterprises already have an in-house playbook. Follow ServiceNow's docs (search "MID Server install") or use the known-good prompt-answers in snow-app/mid-server/example-install.md.
The MID must be Up + Validated in your PDI before running the bridge install below.
The install is two halves: install + validate a MID Server, then run the bridge against it. Total ~30 minutes including the MID Server registration wait.
The MID Server logs into SNOW as a dedicated service account. Create it BEFORE installing the agent so the installer has somewhere to authenticate.
In SNOW navigate to sys_user.list → New and fill in:
| Field | Value |
|---|---|
| User ID | mid.server.zsnow |
| First name | MID |
| Last name | Server |
| Identity type | Machine (Zurich+; replaces the old "Web service access only" checkbox) |
| Internal Integration User | ✅ checked (keeps this user off the licensed-seat count) |
| Active | ✅ |
Submit. Then click Set Password on the saved record. Then scroll to the
Roles related list at the bottom → Edit → add the role
mid_server → Save.
⚠️ Password charset matters. ServiceNow's "Generate password" button produces values full of special chars ($,!,<,&,{,},;) that break the MID installer'sconfig.xmland shell expansion. Use an alphanumeric-only password —openssl rand -hex 16produces a clean 32-character one.
zsnow doesn't ship a MID Server installer (the download URL is date-stamped and the registration step is interactive). Follow ServiceNow's docs (search "MID Server Linux install") OR the field-by-field walkthrough at snow-app/mid-server/example-install.md.
When the installer prompts, use these exact values (the rest of the install assumes them):
| Prompt | Answer | Why |
|---|---|---|
| ServiceNow Instance URL | https://<your-pdi>.service-now.com |
Your PDI |
| Username for mid user | mid.server.zsnow |
Matches Step 1 |
| Password for mid user | (paste from Step 1) | |
| MID Server Name | Zerto-Prod |
Must match ZSNOW_MID_AGENT= in .env (Step 3) |
| Unique service name | mid_zerto_prod |
Underscores only — installer rejects dashes |
| Long service name | Zerto_Prod_MID_Server |
Cosmetic; shown in systemctl status long output |
| Non-root user | <your-vm-user> (e.g. zerto) |
The agent runs as this user |
| Block all other user access? | yes |
Locks down /opt/servicenow/mid/agent/ so only this user can read config.xml (where the password lives plaintext) |
After install, validate the MID Server in SNOW:
- Open
ecc_agent.listin SNOW - Find the
Zerto-Prodrow - Click into it → click Validate (top-right of the form)
- Status should flip from "Up, Validated: No" to "Up, Validated: Yes"
within ~30 seconds. If it hangs, restart the agent on the VM:
sudo systemctl restart mid_zerto_prod
# 1. Get .env in place — copy template, fill in real values
cp .env.example .env
$EDITOR .envRequired .env values (the script validates these at startup and fails
fast if any are missing or still placeholders):
| Variable | Example | Notes |
|---|---|---|
ZERTO_APPLIANCE_URL |
https://192.0.2.10 |
Your Zerto ZVM (v10+) over HTTPS |
ZERTO_USERNAME / ZERTO_PASSWORD |
admin / <your-pw> |
Keycloak-backed ZVM admin user |
VCENTER_HOST |
192.0.2.20 |
For VPG-member VM CMDB enrichment |
VCENTER_USERNAME / VCENTER_PASSWORD |
administrator@vsphere.local / <your-pw> |
|
SNOW_INSTANCE_URL |
https://<your-pdi>.service-now.com |
|
SNOW_USERNAME / SNOW_PASSWORD |
admin / <your-pw> |
|
ZSNOW_API_TOKEN |
<openssl rand -base64 32> |
Shared secret between bridge and MID Server |
ZSNOW_BRIDGE_LAN_URL |
http://192.0.2.50:8088 |
Where MID Server reaches the bridge |
ZSNOW_MID_AGENT |
Zerto-Prod |
Must match the MID Server Name from Step 2 |
# 2. One command does the rest
./install-bridge.shinstall-bridge.sh pulls the Docker image, starts the container, runs
ensure-cmdb-schema (custom tables + columns), and runs ensure-snow-config
(sys_properties + Script Includes + UI Actions + form layouts). It's
idempotent: re-run it to upgrade or to repair drift.
If you'd rather type out each step (or you're integrating with your own CI/CD):
docker run -d --name zsnow --restart unless-stopped \
--env-file .env -p 8088:8088 \
-v zsnow-data:/home/zsnow/app/var \
ghcr.io/dvermagithub/zsnow:0.1.2
docker exec zsnow python -m zsnow ensure-cmdb-schema
docker exec zsnow python -m zsnow ensure-snow-config
curl http://localhost:8088/healthzFull Docker options (Compose, local builds, healthcheck details): deploy/docker/README.md.
git clone https://github.com/dvermagithub/zsnow.git
cd zsnow
conda create -n zsnow python=3.12 -y
conda activate zsnow
pip install -r requirements.txt
pip install -e .
cp .env.example .env
$EDITOR .env
python -m zsnow ensure-cmdb-schema
python -m zsnow ensure-snow-config
python -m zsnow runpython -m zsnow stop cleanly terminates a running bridge by PID file.
Customer datacenter (private) ServiceNow SaaS
───────────────────────────── ───────────────
Zerto ZVM <your-pdi>.service-now.com
▲ ▲
│ HTTPS │ HTTPS (basic for v0.1, OAuth2 in v1.0)
│ │
│ outbound only
└────── zsnow bridge ───── SNOW Table API ───────┘
│
▼
MID Server ◄────── inbound SNOW UI Actions
│ (no firewall pinholes;
▼ MID Server polls SNOW)
zsnow bridge again, via ecc_queue
The MID Server path exists so SNOW UI Actions ("Refresh from Zerto", "Run Test
Failover", "Stop FOT") can reach the bridge without opening an inbound
firewall port on the customer's edge. The MID Server polls SNOW outbound;
SNOW puts work in ecc_queue; the MID picks it up and calls the bridge over
LAN. See docs/deployment.md for production deployment
options.
| Path | What's there |
|---|---|
| install-bridge.sh | One-command install of the bridge half: pull image, start container, run ensure-cmdb-schema and ensure-snow-config. |
| src/zsnow/ | The Python bridge — pollers, adapters, ServiceNow client, FastAPI surface |
| tests/ | Pytest suite — 100 tests, pure-function reconciler tests + API tests against fake sources |
| docs/architecture.md | Why the bridge is level-triggered, stateless, content-derived correlation keys |
| docs/deployment.md | Production deployment options (MID Server, reverse proxy, mesh VPN) |
| docs/zerto-api-deficiencies.md | Catalog of Zerto API gaps that forced our design |
| docs/snow-links.md | SNOW URL cheat-sheet for the records the bridge touches |
| snow-app/mid-server/ | SNOW Script Includes, UI Actions, install cookbooks (the source of truth for what ensure-snow-config installs) |
| deploy/docker/ | Container deployment guide |
| .env.example | Full reference of every env var the bridge reads |
| CHANGELOG.md | Release notes — 0.1.0 → 0.1.1 → 0.1.2; known issues per version |
Business Source License 1.1 — non-production use is free; any production use requires a commercial license. Each release auto-converts to Apache License, Version 2.0 four years after publication (the 0.1.x line sunsets on 2030-06-08).
For a commercial production license, contact: dverma.wi@gmail.com
External contributions are welcome but require a signed Contributor License Agreement (CLA) before they can be merged. The CLA confirms you have the right to contribute the code and that you grant the project the same rights to your contribution as the LICENSE grants to recipients. See CONTRIBUTING.md.
This is an early open-source release. Bug reports, install feedback, and PRs welcome — open an issue on GitHub. Please don't include real PDI credentials or Zerto API tokens in issue text or screenshots.




