Workflow extensions
Since 7.0
In 7.0 this mechanism replaced the old workflow system from 6.4. It allows the admin to execute custom code or Ansible when significant platform events occur, not just pre- and post-deploy.
A workflow extension binds tasks to events via the onAssetChange section of the definition:
"onAssetChange": [ { "stage": "serverRegistered", "tasks": [ { "label": "on-server-registered", "taskType": "ExtensionTaskAnsible", "options": { "asset": "my-bundle", "playbook": "on-register.yaml" } } ] }]Refer to the Extensions overview for how to register and publish an extension, and to the extension definition reference for the full schema.
Supported workflow stages
Section titled “Supported workflow stages”The following values are accepted as events (stage) that trigger the execution of the attached tasks:
serverRegistered- Executed after a server is registeredserverDecommissioned- Executed after a server is decommissioned or deletedswitchRegistered- Executed after a switch is registeredswitchDecommissioned- Executed after a switch is decommissioned or deletedserverInstanceUpdate- Executed during an instance deploymentserverInstanceGroupUpdateDNS- Executed when DNS entries are created, updated or deleted for server instance groupsserverInstanceUpdateDNS- Executed when DNS entries are created, updated or deleted for server instancesclusterUpdateDNS- Executed when DNS entries are updated for a clusterserverCreateDNS- Executed when DNS entries are created for servers’ BMCsserverDeleteDNS- Executed when DNS entries are deleted for servers’ BMCsswitchCreateDNS- Executed when DNS entries are created for a switch’s management interfaceswitchDeleteDNS- Executed when DNS entries are deleted for a switch’s management interface
Definitions written for earlier 7.x releases may reference the stages
serverInstanceGroupCreateDNS,serverInstanceGroupDeleteDNSorserverInstanceDeleteDNS. These no longer exist — create/update/delete DNS events are consolidated into the*UpdateDNSstages above.
Supported task types
Section titled “Supported task types”The following task types can be attached to a stage:
Stage payloads
Section titled “Stage payloads”Each stage provides a payload describing the object that triggered the event. Ansible tasks receive it as extra-vars (reference the keys directly, e.g. {{ server.model }}); HTTP and SSH tasks can reference the same keys in their Nunjucks templates (requestTemplate / commandTemplate).
serverInstanceUpdate
Section titled “serverInstanceUpdate”The serverInstanceRecordSet object:
{ "serverInstanceRecordSet": { "deployStatus": "ongoing", "deployType": "create", "deploymentId": 5388, "instanceIpv4IpRanges": [], "instanceIpv4Ips": [ { "cidr": "10.0.0.4/24", "gateway": "10.0.0.1", "ip": "10.0.0.4", "logicalNetworkId": 1214, "maskBits": 24, "netmask": "255.255.255.0", "networkAddress": "10.0.0.0", "status": "allocated" } ], "instanceIpv6IpRanges": [], "instanceIpv6Ips": [], "logicalNetworks": [ { "interfaces": [ { "macAddress": "8c:84:74:0e:6c:34", "redundancyIndex": null, "serverInterfaceId": 688, "tagged": false } ], "ipv4Subnets": [ { "gateway": "10.0.0.1", "gatewayPlacement": "default", "id": 237, "networkAddress": "10.0.0.0", "prefixLength": 24, "scope": { "kind": "fabric", "resourceId": 1931 }, "status": "allocated" } ], "logicalNetworkId": 1214, "logicalNetworkLabel": "alex-private-net", "logicalNetworkName": "alex-private-net", "vlans": [ { "id": 314, "scope": { "kind": "fabric", "resourceId": 1931 }, "status": "allocated", "vlanId": 826 } ] } ], "serverId": 204, "serverInstanceId": 4434, "serviceStatus": "ordered", "siteLabel": "dc-eveng-qa02" }}serverRegistered, serverDecommissioned
Section titled “serverRegistered, serverDecommissioned”The server object:
{ "server": { "administrationState": "managed", "bdkDebug": 0, "biosInfo": { "vendor": "Dell Inc.", "version": "1.17.2" }, "bmcMacAddress": "08:92:04:a4:d9:98", "bootLastUpdateTimestamp": "0000-00-00T00:00:00Z", "bootingCustomIsoInProgress": 0, "chassisRackId": null, "customInfo": null, "datacenterName": "sonic-qts", "diskCount": 4, "disks": [], "extensionInfo": null, "gpuCount": 0, "gpuInfo": [], "instanceCustomInfo": null, "interfaces": [], "inventoryId": null, "ipmiCredentialsNeedUpdate": 0, "ipmiVersion": "2", "isBasicCampusEndpoint": 0, "jobInfo": { "jobGroupId": null, "jobId": null }, "links": [], "managementAddress": "172.18.33.189", "mgmtSnmpPasswordEncrypted": "...", "mgmtSnmpPort": 161, "model": "PowerEdge R450", "passwordEncrypted": "...", "powerStatus": "off", "powerStatusLastUpdateTimestamp": "2025-09-16T18:48:50Z", "processorCoreCount": 12, "processorCoreMhz": 4000, "processorCount": 1, "processorCpuMark": null, "processorName": "Intel(R) Xeon(R) Silver 4310 CPU @ 2.10GHz", "processorThreads": 24, "rackName": null, "rackPositionLowerUnit": null, "rackPositionUpperUnit": null, "ramGbytes": 32, "registeredTimestamp": "2025-09-16T18:48:50Z", "requiresManualCleaning": 0, "requiresReRegister": 0, "resourcePoolId": null, "revision": 16, "serialNumber": "6SBT0R3", "serverAllocationTimestamp": null, "serverCapacityMbps": 20000, "serverClass": "bigdata", "serverCleanupPolicyId": null, "serverComments": null, "serverCreatedTimestamp": "2025-09-16T18:13:26Z", "serverDhcpStatus": "deny_requests", "serverDiskCount": 4, "serverDiskWipe": 1, "serverId": 27, "serverIsProduction": 0, "serverMetricsMetadata": { "fans": [], "temperatures": [ { "Label": "temperature.cpu.1", "Name": "CPU1 Temp", "Number": 1, "Oem": null, "PhysicalContext": "CPU", "Units": "Celsius", "UpperThresholdCritical": null, "UpperThresholdFatal": null } ] }, "serverStatus": "deleting", "serverSupportsOobProvisioning": 1, "serverSupportsSol": 1, "serverSupportsVirtualMedia": 1, "serverTypeId": 9, "serverUUID": "44454c4c-5300-1042-8054-b6c04f305233", "siteId": 1, "storageControllers": [ { "description": "RAID Controller in SL 3", "id": 112, "label": "PERC H745 Front", "mode": "RAID", "name": "RAID.SL.3-1", "options": { "controllerModesSupported": [ "RAID", "HBA" ], "raidTypesSupported": [ "RAID0", "RAID1", "RAID5", "RAID6", "RAID10", "RAID50", "RAID60" ] }, "serverId": 27 } ], "submodel": null, "supportsFcProvisioning": 0, "tags": null, "username": "root", "vendor": "Dell", "vendorInfo": { "management": "iDRAC", "version": "iDRAC9" }, "vendorSkuId": "PowerEdge R450", "vncPasswordEncrypted": "...", "vncPort": 5901 }}switchRegistered, switchDecommissioned
Section titled “switchRegistered, switchDecommissioned”The networkDevice object:
{ "networkDevice": { "id": "ND-001", "revision": 2, "status": "active", "siteId": 101, "identifierString": "switch-01", "description": "Core switch in datacenter rack 5", "chassisIdentifier": "CHS-12345", "country": "USA", "city": "San Francisco", "datacenterMeta": "DC-West", "datacenterRoom": "Room A", "datacenterRack": "Rack 5", "rackPositionUpperUnit": 42, "rackPositionLowerUnit": 37, "managementAddress": "192.168.1.10", "managementAddressPrefixLength": 24, "managementAddressGateway": "192.168.1.1", "managementPort": 22, "syslogEnabled": 1, "username": "admin", "managementPassword": "password", "managementMacAddress": "00:1A:2B:3C:4D:5E", "serialNumber": "SN-987654321", "driver": { "name": "sonic_enterprise" }, "position": { "role": "leaf" }, "orderIndex": 1, "tags": ["production", "core", "leaf"], "readyForInitialConfiguration": 1, "bootstrapReadinessCheckInProgress": 0, "subnetOobId": 2001, "subnetOobIndex": 1, "requiresOsInstall": true, "bootstrapSkipInitialConfiguration": 0, "bootstrapExpectedPartnerHostname": "switch-02", "loopbackAddressIpv4": "10.0.0.1", "loopbackAddressIpv6": "fe80::1", "asn": 65001, "vtepAddressIpv4": "10.1.1.1", "vtepAddressIpv6": "fe80::2", "mlagSystemMac": "00:1A:2B:3C:4D:5F", "mlagDomainId": 10, "quarantineVlan": 999, "variablesMaterializedForOSAssets": { "osVersion": "1.2.3" }, "secretsMaterializedForOSAssets": { "apiKey": "secret-key" }, "bootstrapReadinessCheckResult": { "status": "ready" }, "isGateway": false, "extensionInfo": { "lastRun": "2025-09-17T12:00:00Z" }, "links": [ { "rel": "self", "href": "/networkdevices/ND-001" } ] }}serverInstanceGroupUpdateDNS
Section titled “serverInstanceGroupUpdateDNS”The serverInstanceGroupDNSRecordSet object: the site DNS zone, the DNS record sets belonging to the server instance group, and the group’s custom variables. Record names carry a terminating dot.
{ "serverInstanceGroupDNSRecordSet": { "zone": { "zoneName": "dc1.example.com", "soaEmail": "admin.dc1.example.com", "nameServers": [ "ns1.dc1.example.com" ], "ttl": 3600, "isDefault": true }, "records": [ { "id": 10, "status": "active", "siteId": 1, "infrastructureId": 3870, "zoneId": 4, "zoneName": "dc1.example.com", "name": "lambda.dc1.example.com.", "type": "A", "ttl": 3600, "records": [ "10.20.50.36" ], "tags": [ "instance-array:3386" ] } ], "customVariables": {} }}serverInstanceUpdateDNS
Section titled “serverInstanceUpdateDNS”The serverInstanceDNSRecordSet object — the same shape as serverInstanceGroupDNSRecordSet above (zone, records, customVariables), with the records belonging to the individual server instance.
clusterUpdateDNS
Section titled “clusterUpdateDNS”The clusterDNSRecordSet object — the same shape (zone, records), with the records belonging to the cluster (the extension instance).
serverCreateDNS, serverDeleteDNS
Section titled “serverCreateDNS, serverDeleteDNS”The serverDNSRecordSet object:
{ "serverDNSRecordSet": { "zone": { "zoneName": "us08.metalsoft.io", "soaEmail": "admin.us08.metalsoft.io", "nameServers": ["n1.metalsoft.io"], "ttl": 3600, "isDefault": true }, "serverId": 10, "serialNumber": "serial-number", "managementAddress": "192.168.100.100", "hostname": "server-10", "fqdn": "server-10.us08.metalsoft.io", "ip": { "status": "allocated", "ip": "192.168.100.100" }, "operation": "create" }}switchCreateDNS, switchDeleteDNS
Section titled “switchCreateDNS, switchDeleteDNS”The switchDNSRecordSet object:
{ "switchDNSRecordSet": { "zone": { "zoneName": "us08.metalsoft.io", "soaEmail": "admin.us08.metalsoft.io", "nameServers": ["n1.metalsoft.io"], "ttl": 3600, "isDefault": true }, "switchId": 10, "managementAddress": "192.168.100.100", "hostname": "switch-10", "fqdn": "switch-10.us08.metalsoft.io", "ip": { "status": "allocated", "ip": "192.168.100.100" }, "operation": "create" }}Examples
Section titled “Examples”The following examples include everything, including the Ansible bundles: