Deployment Update — DAP / NativeEdge
Runtime Mode
You are running in IDE mode with shell access.
Use the bpa CLI for BPA operations.
Do not use the function interface unless explicitly instructed by the host.
Ground-truth reference for the deployment update API and workflow, sourced directly from the orchestrator and gateway source code.
Source files:
mgmtworker/nativeedge_system_workflows/deployment_update/workflow.pymgmtworker/nativeedge_system_workflows/deployment_update/step_extractor.pymgmtworker/nativeedge_system_workflows/deployment_update/update_instances.pyrest-service/manager_rest/rest/resources_v3_1/deployment_updates.pyhzp-api-gateway-svc/server/api/openapi/config/deployment_updates/
For full details see the reference docs in the resources/ directory alongside this file.
Overview
A deployment update applies changes to a running deployment — new blueprint version, changed inputs, added/removed nodes, changed relationships, updated operations/plugins — without a full teardown and reinstall.
CLI Usage (bpa)
All deployment update operations use the bpa CLI. Always use bpa for these commands — never call the REST API directly from scripts.
Important distinction:
bpa orchestrator deployments updateis a simple PATCH to update a deployment's inputs field directly. It is NOT a deployment update workflow. Usebpa orchestrator deployment-updates initiatefor the full deployment update workflow.
Initiate a deployment update
bpa orchestrator deployment-updates initiate <deployment_id> --body <body.json>
The --body flag accepts a JSON file containing the request body. All 18 parameters are specified in the JSON file.
Example: inputs-only update (no node changes)
# body.json
{
"inputs": { "image_size": "large" },
"skip_reinstall": true
}
bpa orchestrator deployment-updates initiate my-deployment --body body.json
Example: blueprint version bump
# body.json
{
"blueprint_id": "my-bp",
"blueprint_version": "v2.1.0"
}
bpa orchestrator deployment-updates initiate my-deployment --body body.json
Example: preview / dry-run
# body.json
{
"blueprint_version": "v2.1.0",
"preview": true
}
bpa orchestrator deployment-updates initiate my-deployment --body body.json
Example: partial update — force-reinstall specific instances only
# body.json
{
"blueprint_version": "v2.1.0",
"skip_reinstall": true,
"reinstall_list": ["app_server_abc123", "app_server_def456"]
}
bpa orchestrator deployment-updates initiate my-deployment --body body.json
Example: force re-update after failure
# body.json
{ "force": true }
bpa orchestrator deployment-updates initiate my-deployment --body body.json
The command returns the DeploymentUpdate object immediately (state updating). The update workflow runs asynchronously — use bpa orchestrator executions get <execution_id> to monitor progress.
List deployment updates
# All updates across all deployments
bpa orchestrator deployment-updates list
# Updates for a specific deployment
bpa orchestrator deployment-updates list <deployment_id>
Get a specific deployment update
bpa orchestrator deployment-updates get <update_id>
Monitor the update execution
After initiating, the response includes an execution_id. Track progress with:
bpa orchestrator executions get <execution_id> --fields id status error finished_operations total_operations
bpa orchestrator events get <execution_id>
Complete workflow example
# 1. Upload the new blueprint revision
bpa orchestrator blueprints upload --file blueprint.yaml --id my-bp --revision v2.1.0
bpa orchestrator blueprints get my-bp --fields id state revisions
# Wait until state: uploaded
# 2. Initiate the deployment update
cat > update-body.json << 'EOF'
{
"blueprint_id": "my-bp",
"blueprint_version": "v2.1.0",
"skip_reinstall": true
}
EOF
bpa orchestrator deployment-updates initiate my-deployment --body update-body.json
# 3. Monitor progress
bpa orchestrator executions get <execution_id> --fields id status error
bpa orchestrator events get <execution_id>
Request Body Parameters
The deployment update workflow is triggered via:
POST /api/v3.1/deployment-updates/<deployment_id>/update/initiate
| Parameter | Type | Default | Description |
|---|---|---|---|
blueprint_id |
string | current | New blueprint ID (for blueprint version bump) |
blueprint_version |
string | current | New blueprint revision |
inputs |
object | {} |
Input overrides — merged with existing inputs |
reinstall_list |
string[] | [] |
Node instance IDs to force-reinstall even if topology unchanged |
skip_install |
bool | false |
Skip install operations on added nodes |
skip_uninstall |
bool | false |
Skip uninstall operations on removed nodes |
skip_reinstall |
bool | false |
Skip reinstall on modified nodes (use with caution) |
force_reinstall |
bool | false |
Reinstall all nodes regardless of changes |
force |
bool | false |
Force re-update after a failed update |
skip_drift_check |
bool | false |
Skip runtime property drift comparison |
preview |
bool | false |
Dry-run: compute and return the update plan without executing |
runtime_only_evaluation |
bool | false |
Evaluate intrinsic functions at runtime rather than deploy-time |
update_plugins |
bool | true |
Update plugins to latest matching versions |
workflow_id |
string | — | Custom update workflow (receives update context) |
Drift Detection
When skip_drift_check is false (default), the system compares current runtime properties against the blueprint's expected state before applying changes. Nodes with drifted properties are flagged for reinstall.
Preview Mode
Set preview: true to see what would change without executing. The response includes which nodes would be added, removed, modified, or reinstalled; the ordered execution steps; and any drift detected.
Common Patterns
Inputs-only update (no node changes)
{ "inputs": { "image_size": "large" }, "skip_reinstall": true }
skip_reinstall=true prevents nodes from being reinstalled just because an input changed.
Blueprint version bump
{ "blueprint_id": "my-bp", "blueprint_version": "v2.1.0" }
Partial update — touch only specific instances
{
"blueprint_version": "v2.1.0",
"skip_reinstall": true,
"reinstall_list": ["app_server_abc123", "app_server_def456"]
}
skip_reinstall=true suppresses automatic reinstall of every changed node; reinstall_list opts specific IDs back in.
Preview / dry-run
{ "blueprint_version": "v2.1.0", "preview": true }
Returns the update object with steps populated and state: "preview". No lifecycle ops run.
Force re-update after failure
{ "force": true }
Custom workflow
{ "blueprint_version": "v2.1.0", "workflow_id": "my_custom_update_workflow" }
The custom workflow receives: update_id, modified_entity_ids, added_instance_ids, added_target_instances_ids, removed_instance_ids, remove_target_instance_ids, extended_instance_ids, extend_target_instance_ids, reduced_instance_ids, reduce_target_instance_ids, skip_install, skip_uninstall, ignore_failure, install_first, node_instances_to_reinstall, central_plugins_to_install, central_plugins_to_uninstall, update_plugins.
Critical Gotchas
- Unsupported changes abort the entire update (before any lifecycle ops): changing a node's type, changing its
contained_inhost, or modifying relationship properties. skip_reinstall=truedoes NOT mean "run update ops only" — it means skip the node entirely (no update, no reinstall).skip_uninstall=trueleaves ghost instances in the DB; they must be cleaned up manually later.update_pluginsdefaults totrue, notfalse— plugins are updated by default.check_driftruns inpreviewmode and must be read-only from the script's side. The only "side-effect" is the orchestrator itself writing the script's returned payload intosystem_properties["configuration_drift"]after the task completes — do not mutateruntime_propertiesorsystem_propertiesfrom inside acheck_driftscript.- Schedules are never deleted by an update — only created or updated.
bpa orchestrator deployments updateis NOT this — that command is a PATCH to/rest/v1/deployments/{id}that only patches theinputsfield directly (no workflow, no lifecycle ops). Usebpa orchestrator deployment-updates initiatefor the full update workflow.
Authoring update support — required checklist
When the user asks to add / support update, Day-2, or drift on a node (new blueprint or modifying an existing one), you MUST:
- Emit
check_driftin the node's lifecycle first — beforepreupdate,update,postupdate. A blueprint that declaresupdatewithoutcheck_driftis incomplete and non-compliant (see ND-009 inblueprint-rules.md). - Implement
check_driftas a read-only Python script that reports its result viactx.returns(<payload>). A plain Pythonreturnis ignored by the orchestrator. Do not mutateruntime_propertiesorsystem_propertiesfromcheck_drift. - Implement
updateidempotently (ND-004) — retrying must not cause a second state change. - Implement
postupdatefor post-change verification or notification (read-only). - Before presenting the YAML to the user, verify the emitted lifecycle contains
check_drift,update, andpostupdatetogether. If any is missing, fix the output before showing it.
Canonical runnable reference: packages/blueprint-tools/knowledge/blueprints/script/drift-example-blueprint.yaml and its scripts/check_drift.py, scripts/update.py, scripts/postupdate.py.
Node-Level Implementation (ND-009)
When the platform runs a deployment update, it invokes these lifecycle operations on each affected node instance in order:
check_drift— Compare live state to desired state. Must be read-only (no mutations) because it runs duringpreviewmode.preupdate— Pre-change hook (optional).update— Apply the actual change (resize VM, update config, etc.). Must be idempotent (ND-004).postupdate— Post-change validation, notification, or cache invalidation.
Additional optional operations: update_config, update_apply, update_postapply, preheal, heal, postheal.
YAML Example
node_templates:
vm:
type: dell.nodes.vsphere.Server
properties:
# ...
interfaces:
dell.interfaces.lifecycle:
create:
# ... (install workflow)
delete:
# ... (uninstall workflow)
# ND-009: Update workflow operations
check_drift:
implementation: scripts/check_drift.py
inputs:
expected_cpus: { get_input: vm_cpus }
expected_memory: { get_input: vm_memory_mb }
update:
implementation: scripts/update_vm.py
inputs:
cpus: { get_input: vm_cpus }
memory: { get_input: vm_memory_mb }
postupdate:
implementation: scripts/verify_vm.py
Key implementation notes:
- Required operations (emit in this order):
check_drift,update,postupdate. Optional:preupdate, thehealfamily (preheal/heal/postheal), andupdate_config/update_apply/update_postapply. check_driftreturns its result viactx.returns(<payload>)— the script-plugin's sanctioned return channel. A plain Pythonreturnis ignored by the orchestrator. Do not mutateruntime_propertiesfromcheck_drift(it runs in preview mode; it must be read-only).updateapplies the change and should be idempotent — retrying must not cause a second state change. This is whereruntime_propertiesmay be written.postupdateis for validation or notification — it should not mutate infrastructure.
check_drift return payload
The orchestrator takes whatever the script returns via ctx.returns(...) and stores it at system_properties["configuration_drift"] on the node instance. The shape of that payload drives how drift is surfaced in the UI and in the update workflow's decision logic.
Recommended shape (enables the "View actual drift" UI):
# scripts/check_drift.py
from datetime import datetime
import difflib
import yaml
from dell import ctx
def _diff_lines(expected, actual):
exp = yaml.dump(expected, default_flow_style=False).splitlines()
act = yaml.dump(actual, default_flow_style=False).splitlines()
diff = list(difflib.unified_diff(exp, act, n=max(len(exp), len(act)), lineterm=''))
return "\n".join(diff) if diff else None, sum(
1 for tag, *_ in difflib.SequenceMatcher(None, exp, act).get_opcodes() if tag != 'equal'
)
expected = {'cpus': ctx.node.properties['expected_cpus'],
'memory': ctx.node.properties['expected_memory']}
actual = fetch_live_vm_config() # implement against your target system; must be read-only
diff, diff_count = _diff_lines(expected, actual)
if diff_count == 0:
ctx.returns(None) # None → no drift
else:
ctx.returns({
'resource_id': ctx.instance.id,
'diff_count': diff_count,
'diff': diff,
'state_drift': None, # or {'expected': 'started', 'actual': 'stopped'}
'time': datetime.now().isoformat(timespec='microseconds'),
})
Minimum acceptable (boolean-only — "View actual drift" UI will be empty):
ctx.returns({'drift': expected != actual})
Never:
return drift_detected— the orchestrator does not read the Python return value of a script.ctx.instance.runtime_properties['drifted'] = True— violates the read-only rule forcheck_driftand is not read by the update workflow.
See references/blueprint-examples.md → "Update Workflow Lifecycle" and the canonical runnable example at blueprints/script/drift-example-blueprint.yaml (in the blueprint knowledge base).
Full Reference
See resources/api-and-workflow-reference.md for:
- All REST endpoints (including internal ones)
- Full workflow phase diagram
- Node graph diff algorithm detail
update_or_reinstall_instancesdecision logic- Behaviour matrix for all skip/force flag combinations
Retrieval
Search for deployment update topics:
bpa knowledge docs search "deployment update"
bpa knowledge docs search "skip reinstall"