Getting Started
Core Concepts
Deploy installation files and firmware based on target systems and versions
Software and firmware files are used across many environments, including servers, branch systems, production equipment, and edge devices.
Software and firmware deployment prepares installation packages, build artifacts, and firmware files, then configures deployment tasks based on the target systems and versions to apply.
You can configure deployment flows suited to the operating environment, such as deploying one file to multiple systems or applying different files and versions to different system groups.
Deployment Configuration
Deployment Files
│
▼
Configure Version Criteria
│
▼
Select Target Systems
│
├────────→ Server Group
├────────→ Branch Systems
└────────→ Edge Devices
│
▼
Check Results
This process lets you manage deployment files, target systems, and application criteria as a single flow.

Deployment Flow
Continue from file preparation through application to target systems and result confirmation
A deployment task starts by preparing the installation file or firmware and configuring the systems and versions to which it will be applied.
When the deployment task runs according to the specified conditions, files are transferred to each target system and you can review progress and file application results by system.
① Prepare Deployment File
↓
② Configure Target Systems
↓
③ Set Version and Execution Criteria
↓
④ Deploy Files by Target
↓
⑤ Check Application Results
When needed, you can rerun deployment for a specific system or system group.
Deployment Benefits
Manage file deployment and version control across multiple systems as a single flow
Software and firmware deployment across multiple systems requires managing the deployment file, targets, version, and execution results together.
Software and firmware deployment lets you organize system-level deployment tasks into a single management flow and identify which files were deployed to which targets.
| Category | Individual System Management | Deployment Flow |
|---|---|---|
| Deployment Targets | Check targets by system | Manage by system and group |
| Deployment Files | Check application targets by file | Configure together with the deployment task |
| Version Application | Check application status by system | Deploy according to version criteria |
| Execution Results | Review each system individually | Review results for all targets together |
| Redeployment | Select required systems again | Rerun by target or group |
This lets you manage the entire operational flow from software and firmware deployment through target-specific result confirmation.
IT Engineers
Deployment Files
Prepare installation packages and firmware files according to deployment criteria
First, prepare the installation packages, build artifacts, or firmware files to use for deployment.
A file can be used for multiple targets within one deployment task, and different files can also be assigned by system group according to the operating environment.
For example, the following file types can be configured as deployment targets.
| File Type | Example Use |
|---|---|
| Installation Package | Application installation file |
| Build Artifact | Latest build file and deployment package |
| Firmware | Firmware for systems and edge devices |
| Update File | Update file to apply to an existing environment |
After preparing the deployment files, configure the systems and groups to which they will be applied in the next step.

Target Configuration
Configure servers, branches, and edge devices by deployment group and individual system
Deployment targets can be configured as individual systems or grouped into a single target group.
For example, configure targets according to operational criteria as headquarters servers, nationwide branch systems, specific production equipment, or edge device groups.
Deployment Targets
│
┌───────────┼───────────┐
▼ ▼ ▼
Server Group Branch Group Edge Group
│ │ │
System A System D System G
System B System E System H
System C System F System I
This lets you select multiple systems in one deployment task or define the deployment scope for a specific group only.

Deployment Criteria
Set file versions and execution conditions by system
After configuring the targets, define which files should be deployed and according to which criteria.
Connect the deployment file version to the target systems and configure execution conditions to run immediately, on a schedule, or after another task completes.
Criteria to Configure
| Configuration Item | Configuration |
|---|---|
| Deployment File | Specify the installation package or firmware |
| Applied Version | Specify the file version to deploy to target systems |
| Target Scope | Select all systems, a group, or individual systems |
| Execution Conditions | Run immediately, on a schedule, or after another task completes |
| File Path | Set the storage or application location on the target system |
For example, you can deploy the latest firmware to a specific system group after it is prepared, or deploy build results to a designated server after the build task completes.

Multi-Target Deployment
Transfer files to multiple target systems with a single deployment task
After setting deployment criteria, configure a multi-target deployment flow that transfers one file to multiple target systems.
Connect one deployment source to multiple target systems in the Flow Canvas to deploy the same file to servers, branches, edge devices, and other environments.
Deployment File
│
▼
Deployment Task
┌─────────┼─────────┐
▼ ▼ ▼
Server Branch Edge
│ │ │
▼ ▼ ▼
Confirm Completion Confirm Completion Confirm Completion
Target systems can be processed together or selected by group and individual system according to operational criteria.

Result Management
Review application status by target and rerun deployment for required systems
When a deployment task runs, use Runs and task details to review the overall deployment status and results by target.
During review, you can check each system's progress status, processed files, execution time, and other details together.
Deployment Result Flow
Run Deployment
│
▼
Check Overall Task Status
│
├── Completed
│ │
│ └── Check Application Result by Target
│
├── Running
│ │
│ └── Check Progress and Processing Status
│
└── Review Required
│
▼
Review Detailed Result
│
▼
Select Target System
│
▼
Rerun Deployment Task

| Review Item | Details |
|---|---|
| Target System | Servers and systems where files were deployed |
| Progress Status | Current processing status of the deployment task |
| File Result | File application result by target system |
| Execution Time | Deployment start and completion time |
| Redeployment Target | System or group to rerun |
When you need to review the deployment result for a specific system again, rerun the required task based on that target or system group.
Developers
Deploy one artifact to multiple systems and aggregate application results by system
Integration Preparation
Prepare shared request code and status values
import os
import requests
BASE_URL = os.getenv("INNORIX_BASE_URL", "https://app.innorix.com").rstrip("/")
TOKEN = os.environ["INNORIX_ACCESS_TOKEN"]
WORKSPACE_ID = os.getenv("INNORIX_WORKSPACE_ID") # optional; falls back to the current workspace
STATUS_COMPLETE = 2
TERMINAL = {2, 4, 5, 9, 99} # complete / error / cancelled / partial / failed
NOT_SUCCEEDED = {4, 5, 9, 99}
def api(method, path, body=None, params=None):
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {TOKEN}",
}
if WORKSPACE_ID:
headers["x-workspace-id"] = WORKSPACE_ID
response = requests.request(
method, BASE_URL + path,
headers=headers, json=body, params=params, timeout=30,
)
payload = response.json() if response.content else {}
if not response.ok:
raise RuntimeError(payload.get("message") or f"HTTP {response.status_code}")
return payload.get("data")
def is_terminal(detail):
return detail.get("isTerminal", detail.get("status") in TERMINAL)Determine the transfer status using the values below. There are five terminal states, and the successful state is Complete (2).
| Status Value | Meaning | Terminal |
|---|---|---|
| 2 | Complete | Yes |
| 4 | Error | Yes |
| 5 | Cancelled | Yes |
| 9 | Partially Complete | Yes |
| 99 | Failed | Yes |
| 1 · 6 · 12 · 13 | Started · Transferring · Synchronizing · Receiving | No |
Configure Deployment Targets
Define device groups as a list and confirm their identifiers
Manage deployment targets as a list. When working with system names, convert them to identifiers first.
def resolve_device(name):
result = api("GET", "/api/devices/resolve", params={"name": name}) or {}
devices = result.get("devices") or []
count = result.get("matchCount", len(devices))
if count != 1 or not devices:
raise RuntimeError(f"{name}: {count} matches")
return devices[0]["deviceId"]
GROUPS = {
"server": ["srv-01", "srv-02", "srv-03"],
"branch": ["branch-seoul", "branch-busan"],
"edge": ["edge-line-01", "edge-line-02"],
}
RESOLVED = {
group: [resolve_device(name) for name in names]
for group, names in GROUPS.items()
}You can also filter the full system list using conditions.
result = api("GET", "/api/devices", params={"page": 1, "size": 200}) or {}
edge_devices = [d["deviceId"] for d in result.get("devices") or []
if d["name"].startswith("edge-")]The device list is returned in the data.devices array.
Design Version Paths
Make the deployment file version visible in the path
Record which version was applied where in the path.
def package_path(product, version):
return f"/release/{product}/{version}"
def target_path(product, version):
return f"/opt/{product}/{version}"
PRODUCT, VERSION = "app", "2.14.0"Keeping a separate folder for each version leaves previous versions available, making rollback easier when problems occur. If everything is overwritten in a single path, there is no version to roll back to.
Multi-Target Deployment
Send one file to multiple systems
A single transfer handles one target system. Create a transfer for each target and store the returned monitorId by system to track progress and results.
def deploy(source, targets, product, version, target_paths=None):
src = package_path(product, version)
# pass a list when targets need different paths; the order must match
paths = target_paths or [target_path(product, version)] * len(targets)
return {
device: api("POST", "/api/transfers/manual", {
"sourceDevice": source,
"targetDevice": device,
"targetPath": path,
"sourcePaths": [src],
"sendAllFolder": True,
"checkIntegrity": True,
"transferOptions": {"target-action": "overwrite"},
})["monitorId"]
for device, path in zip(targets, paths)
}
transfers = deploy("device-build-01", RESOLVED["edge"], PRODUCT, VERSION)Within a version folder, the same file is usually sent again, so use overwrite. With numbering, copies accumulate every time you redeploy.
Enable integrity verification. If firmware is applied in a corrupted state, the system may fail to boot.
If the environment shares field network links, apply a rate limit so other operations are not affected.
"transferOptions": {
"target-action": "overwrite",
"limitRate": 20480
}
The unit for limitRate is KB/s.
Aggregate Results
Collect application status by system and review it together
def wait(monitor_id, timeout=3600, interval=3):
deadline = time.time() + timeout
while time.time() < deadline:
detail = api("GET", f"/api/transfers/{monitor_id}")
if is_terminal(detail):
return detail
time.sleep(interval)
raise TimeoutError(monitor_id)
def failed_files(monitor_id):
result = api("GET", f"/api/transfers/{monitor_id}/files", params={
"state": "any", "size": 500,
}) or {}
return [r for r in (result.get("children") or [])
if r.get("status") in NOT_SUCCEEDED]
def retry_failed(monitor_id):
rows = failed_files(monitor_id)
if not rows:
return 0
api("POST", f"/api/transfers/{monitor_id}/retry", {
"filesRetry": [
{"filePath": r["sourceFilePath"], "isDir": bool(r.get("isFolder"))}
for r in rows
]
})
return len(rows)Even if one system fails, continue checking the others so you know how far deployment has progressed.
def deploy_report(transfers, timeout=3600):
results = {}
for device, monitor_id in transfers.items():
try:
results[device] = wait(monitor_id, timeout=timeout)
except TimeoutError:
results[device] = {"status": None}
succeeded = [d for d, r in results.items()
if r.get("status") == STATUS_COMPLETE]
failed = [d for d in results if d not in succeeded]
return succeeded, failed, results
succeeded, failed, results = deploy_report(transfers)
print(f"{len(succeeded)} succeeded / {len(failed)} failed")
for device in failed:
detail = results[device]
print(f" {device:20} {detail.get('statusName') or detail.get('status')}")| Review Item | Details |
|---|---|
status | Transfer status by system |
percent | Progress |
fileCount · totalSize | Applied file count and size |
endDate | Completion time |
Redeploy Failed Systems
Skip successful systems and redeploy only failed targets
Rerunning everything transfers files again even to systems where deployment already succeeded. Select only the failed targets and rerun them.
for device in failed:
monitor_id = transfers[device]
rows = failed_files(monitor_id)
if rows:
# reached the device, but some files failed
print(f"{device}: retried {retry_failed(monitor_id)} files")
else:
# no per file record means the transfer never started
state = api("GET", f"/api/devices/{device}/connectivity") or {}
print(f"{device}: transfer never started - connected {state.get('isConnected')}"
f" ({state.get('stateLabel')})")If there is no file-level failure record, check the system connection first. Rerun deployment after the connection is restored.
if still_offline:
retry_transfers = deploy("device-build-01", recovered, PRODUCT, VERSION)
_, still_failed, _ = deploy_report(retry_transfers)Review Deployment History
Check which version was applied to which system and when
from datetime import datetime, timedelta, timezone
def paginate(path, params=None, limit=200, max_pages=50):
query = dict(params or {})
query["limit"] = limit
cursor = None
for _ in range(max_pages):
if cursor:
query["cursor"] = cursor
result = api("GET", path, params=query) or {}
for record in result.get("data") or []:
yield record
pagination = result.get("pagination") or {}
if not pagination.get("hasMore"):
return
cursor = pagination.get("nextCursor")
if not cursor:
return
end = datetime.now(timezone.utc)
fmt = "%Y-%m-%dT%H:%M:%SZ"
for row in paginate(f"/api/devices/{device_id}/transfer-history", params={
"startDate": (end - timedelta(days=30)).strftime(fmt),
"endDate": end.strftime(fmt),
}):
print(row.get("startDate"), row.get("statusName"), row.get("monitorId"))Recording the deployment identifier and version together in the application connects the history with the version.
db.insert("deployments", {
"product": PRODUCT,
"version": VERSION,
"device": device,
"monitorId": transfers[device],
"result": "done" if device in succeeded else "failed",
})| Review Item | Details |
|---|---|
| Deployment File | Transferred package and version |
| Targets | Systems and groups |
| Result | Success and failure by system |
| Redeployment | Targets and results rerun |
| History | Recent deployment history by system |