Skip to content

Conversation

@shwstppr
Copy link
Contributor

@shwstppr shwstppr commented Sep 1, 2025

Description

Adds parameter - 'cleanupexternaldetails' for updateHost and updateServiceOffering API to allow cleaning up external details.

Types of changes

  • Breaking change (fix or feature that would cause existing functionality to change)
  • New feature (non-breaking change which adds functionality)
  • Bug fix (non-breaking change which fixes an issue)
  • Enhancement (improves an existing feature and functionality)
  • Cleanup (Code refactoring and cleanup, that may add test cases)
  • build/CI
  • test (unit or integration test code)

Feature/Enhancement Scale or Bug Severity

Feature/Enhancement Scale

  • Major
  • Minor

Bug Severity

  • BLOCKER
  • Critical
  • Major
  • Minor
  • Trivial

Screenshots (if appropriate):

How Has This Been Tested?

(localcloud) 🐱 > list serviceofferings  id=df5aa731-7ae9-4507-a53c-982b5ef2f0f3 (Test)
{
  "count": 1,
  "serviceoffering": [
    {
      "cacheMode": "none",
      "created": "2025-10-01T10:35:07+0530",
      "defaultuse": false,
      "diskofferingdisplaytext": "Test",
      "diskofferingid": "3a41e1f3-08ab-4302-801e-87acd131cbbc",
      "diskofferingname": "Test",
      "diskofferingstrictness": false,
      "displaytext": "Test",
      "dynamicscalingenabled": true,
      "encryptroot": false,
      "gpudisplay": false,
      "hasannotations": false,
      "id": "df5aa731-7ae9-4507-a53c-982b5ef2f0f3",
      "iscustomized": true,
      "issystem": false,
      "isvolatile": false,
      "limitcpuuse": false,
      "name": "Test",
      "offerha": false,
      "provisioningtype": "thin",
      "rootdisksize": 0,
      "serviceofferingdetails": {
        "External:abc": "123"
      },
      "state": "Active",
      "storagetype": "shared"
    }
  ]
}
(localcloud) 🐱 > update serviceoffering id=df5aa731-7ae9-4507-a53c-982b5ef2f0f3 (Test) cleanupexternaldetails=true 
{
  "serviceoffering": {
    "cacheMode": "none",
    "created": "2025-10-01T10:35:07+0530",
    "defaultuse": false,
    "diskofferingdisplaytext": "Test",
    "diskofferingid": "3a41e1f3-08ab-4302-801e-87acd131cbbc",
    "diskofferingname": "Test",
    "diskofferingstrictness": false,
    "displaytext": "Test",
    "dynamicscalingenabled": true,
    "encryptroot": false,
    "gpudisplay": false,
    "hasannotations": false,
    "id": "df5aa731-7ae9-4507-a53c-982b5ef2f0f3",
    "iscustomized": true,
    "issystem": false,
    "isvolatile": false,
    "limitcpuuse": false,
    "name": "Test",
    "offerha": false,
    "provisioningtype": "thin",
    "rootdisksize": 0,
    "state": "Active",
    "storagetype": "shared"
  }
}
(localcloud) 🐱 > list hosts  id=9e6c04f3-9110-4844-84e8-4e8604b5270a (TestHost)
{
  "count": 1,
  "host": [
    {
      "arch": "x86_64",
      "capabilities": "hvm",
      "clusterid": "89834e7e-ad73-4c32-9a95-c97141e1c5e3",
      "clustername": "Test",
      "clustertype": "CloudManaged",
      "cpuallocated": "0.00%",
      "cpuallocatedpercentage": "0.00%",
      "cpuallocatedvalue": 0,
      "cpuallocatedwithoverprovisioning": "0.00%",
      "cpunumber": 0,
      "cpuspeed": 0,
      "cpuwithoverprovisioning": "0",
      "created": "2025-10-01T12:24:40+0530",
      "details": {
        "External:abc": "123",
        "External:some": "value",
        "com.cloud.network.Networks.RouterPrivateIpStrategy": "HostLocal",
        "cpuOvercommitRatio": "1.0",
        "guid": "External:e26e2c80-9d27-367b-a10e-5c498dc83222",
        "memoryOvercommitRatio": "1.0"
      },
      "encryptionsupported": false,
      "events": "ManagementServerDown; ShutdownRequested; AgentDisconnected; HostDown; PingTimeout; AgentConnected; Remove; Ping; StartAgentRebalance",
      "extensionid": "54244774-9821-42c3-bf59-129da838b4c3",
      "extensionname": "Test",
      "hahost": false,
      "hasannotations": false,
      "hostha": {
        "haenable": false,
        "hastate": "Disabled"
      },
      "hypervisor": "External",
      "id": "9e6c04f3-9110-4844-84e8-4e8604b5270a",
      "ipaddress": "External",
      "islocalstorageactive": false,
      "lastpinged": "1970-01-21T02:44:28+0530",
      "managementserverid": "5ea450a0-21ae-4f71-859b-ca611b4d73a6",
      "managementservername": "shwstppr-zbook",
      "memoryallocated": 0,
      "memoryallocatedbytes": 0,
      "memoryallocatedpercentage": "0.00%",
      "memorytotal": 0,
      "memorywithoverprovisioning": "0",
      "name": "TestHost",
      "outofbandmanagement": {
        "enabled": false,
        "powerstate": "Disabled"
      },
      "podid": "cc5b0da8-1c29-4b49-84bc-4de296292c62",
      "podname": "Z1P1",
      "resourcestate": "Enabled",
      "state": "Up",
      "type": "Routing",
      "ueficapability": false,
      "version": "4.22.0.0-SNAPSHOT",
      "zoneid": "d9ce3849-74f0-41dd-9fc4-66b1183df419",
      "zonename": "zim1"
    }
  ]
}
(localcloud) 🐱 > update host id=9e6c04f3-9110-4844-84e8-4e8604b5270a (TestHost) cleanupexternaldetails=true
{
  "host": {
    "arch": "x86_64",
    "capabilities": "hvm",
    "clusterid": "89834e7e-ad73-4c32-9a95-c97141e1c5e3",
    "clustername": "Test",
    "clustertype": "CloudManaged",
    "cpuallocated": "0.00%",
    "cpuallocatedpercentage": "0.00%",
    "cpuallocatedvalue": 0,
    "cpuallocatedwithoverprovisioning": "0.00%",
    "cpunumber": 0,
    "cpuspeed": 0,
    "cpuwithoverprovisioning": "0",
    "created": "2025-10-01T12:24:40+0530",
    "details": {
      "com.cloud.network.Networks.RouterPrivateIpStrategy": "HostLocal",
      "cpuOvercommitRatio": "1.0",
      "guid": "External:e26e2c80-9d27-367b-a10e-5c498dc83222",
      "memoryOvercommitRatio": "1.0"
    },
    "encryptionsupported": false,
    "events": "ManagementServerDown; ShutdownRequested; AgentDisconnected; HostDown; PingTimeout; AgentConnected; Remove; Ping; StartAgentRebalance",
    "hahost": false,
    "hasannotations": false,
    "hostha": {
      "haenable": false,
      "hastate": "Disabled"
    },
    "hypervisor": "External",
    "id": "9e6c04f3-9110-4844-84e8-4e8604b5270a",
    "ipaddress": "External",
    "islocalstorageactive": false,
    "lastpinged": "1970-01-21T02:44:28+0530",
    "managementserverid": "5ea450a0-21ae-4f71-859b-ca611b4d73a6",
    "managementservername": "shwstppr-zbook",
    "memoryallocated": 0,
    "memoryallocatedbytes": 0,
    "memoryallocatedpercentage": "0.00%",
    "memorytotal": 0,
    "memorywithoverprovisioning": "0",
    "name": "TestHost",
    "outofbandmanagement": {
      "enabled": false,
      "powerstate": "Disabled"
    },
    "podid": "cc5b0da8-1c29-4b49-84bc-4de296292c62",
    "podname": "Z1P1",
    "resourcestate": "Enabled",
    "state": "Up",
    "type": "Routing",
    "ueficapability": false,
    "version": "4.22.0.0-SNAPSHOT",
    "zoneid": "d9ce3849-74f0-41dd-9fc4-66b1183df419",
    "zonename": "zim1"
  }
}

How did you try to break this feature and the system with this change?

offering

Adds parameter - 'cleanupexternaldetails' for updateHost and
updateServiceOffering API to allow cleaning up external details.

Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
@codecov
Copy link

codecov bot commented Sep 1, 2025

Codecov Report

❌ Patch coverage is 20.51282% with 31 lines in your changes missing coverage. Please review.
✅ Project coverage is 17.50%. Comparing base (d60f455) to head (a258cf0).
⚠️ Report is 52 commits behind head on main.

Files with missing lines Patch % Lines
...in/java/com/cloud/host/dao/HostDetailsDaoImpl.java 28.57% 10 Missing ⚠️
...n/java/com/cloud/resource/ResourceManagerImpl.java 0.00% 9 Missing ⚠️
.../cloud/configuration/ConfigurationManagerImpl.java 40.00% 6 Missing ⚠️
...oudstack/api/command/admin/host/UpdateHostCmd.java 0.00% 3 Missing ⚠️
...mmand/admin/offering/UpdateServiceOfferingCmd.java 0.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff            @@
##               main   #11548   +/-   ##
=========================================
  Coverage     17.50%   17.50%           
- Complexity    15427    15431    +4     
=========================================
  Files          5894     5894           
  Lines        526847   526879   +32     
  Branches      64335    64342    +7     
=========================================
+ Hits          92234    92246   +12     
- Misses       424236   424256   +20     
  Partials      10377    10377           
Flag Coverage Δ
uitests 3.61% <ø> (-0.01%) ⬇️
unittests 18.56% <20.51%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@shwstppr
Copy link
Contributor Author

shwstppr commented Sep 1, 2025

@blueorangutan package

@blueorangutan
Copy link

@shwstppr a [SL] Jenkins job has been kicked to build packages. It will be bundled with KVM, XenServer and VMware SystemVM templates. I'll keep you posted as I make progress.

@blueorangutan
Copy link

Packaging result [SF]: ✔️ el8 ✔️ el9 ✔️ debian ✔️ suse15. SL-JID 14804

@harikrishna-patnala
Copy link
Contributor

@shwstppr is it better to handle this using externalDetails param itself somehow ? may be we need to tweak some code while handling empty map!

@shwstppr
Copy link
Contributor Author

shwstppr commented Sep 1, 2025

@shwstppr is it better to handle this using externalDetails param itself somehow ? may be we need to tweak some code while handling empty map!

@harikrishna-patnala no, I don't think so. With a map parameter, it is not possible to ascertain if an empty map is because the user wanted to clean up the existing details or wants them to be unchanged.

@shwstppr
Copy link
Contributor Author

shwstppr commented Sep 8, 2025

@blueorangutan package

@blueorangutan
Copy link

@shwstppr a [SL] Jenkins job has been kicked to build packages. It will be bundled with KVM, XenServer and VMware SystemVM templates. I'll keep you posted as I make progress.

@blueorangutan
Copy link

Packaging result [SF]: ✔️ el8 ✔️ el9 ✔️ el10 ✔️ debian ✔️ suse15. SL-JID 14889

@shwstppr shwstppr closed this Sep 8, 2025
@github-project-automation github-project-automation bot moved this from In Progress to Done in Apache CloudStack 4.22.0 Sep 8, 2025
@shwstppr shwstppr reopened this Sep 8, 2025
@harikrishna-patnala harikrishna-patnala moved this from Done to In Progress in Apache CloudStack 4.22.0 Sep 8, 2025
Copy link
Contributor

@harikrishna-patnala harikrishna-patnala left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

code LGTM

@shwstppr shwstppr marked this pull request as ready for review October 1, 2025 06:55
@shwstppr
Copy link
Contributor Author

shwstppr commented Oct 1, 2025

@blueorangutan package

@blueorangutan
Copy link

@shwstppr a [SL] Jenkins job has been kicked to build packages. It will be bundled with KVM, XenServer and VMware SystemVM templates. I'll keep you posted as I make progress.

@blueorangutan
Copy link

Packaging result [SF]: ✔️ el8 ✔️ el9 ✔️ el10 ✔️ debian ✔️ suse15. SL-JID 15247

@RosiKyu RosiKyu self-assigned this Oct 13, 2025
Copy link
Collaborator

@RosiKyu RosiKyu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

External details functionality was thoroughly verified for Hosts and Service Offerings.

  • Add external details: Successfully added and reflected in API and UI with the External: prefix.
  • Cleanup: cleanupexternaldetails=true consistently removes all external details without impacting other fields.
  • Re-add after cleanup: Works as expected.
  • Precedence test: When both externaldetails and cleanupexternaldetails are passed, cleanup correctly takes precedence.
  • Idempotency: Running cleanup on already clean entities causes no errors or side effects.
  • Persistence: No data persisted in DB for either entity type (in-memory only), which matches current implementation scope.
  • UI behavior: Reflects API state correctly before and after cleanup.

Detailed Test Results

Host External Details Cleanup Testing Results

Step 1: Add external details

  • Added 2 external details (abc, testKey) using externaldetails param.

Expected Result: External details should be stored with External: prefix.
Actual Result: External details successfully added to the host. Non-external fields unaffected.

(localcloud) 🐱 > update host id=a2eac7e2-4b45-4fe3-b52c-d6fd22ecd4fc externaldetails[0].abc=123 externaldetails[0].testKey=testValue
{
  "host": {
    "arch": "x86_64",
    "capabilities": "hvm,snapshot",
    "clusterid": "e4780f28-dc1a-49bc-90dc-1b67f5bee503",
    "clustername": "p1-c1",
    "clustertype": "CloudManaged",
    "cpuallocated": "0.00%",
    "cpuallocatedpercentage": "0.00%",
    "cpuallocatedvalue": 0,
    "cpuallocatedwithoverprovisioning": "0.00%",
    "cpuloadaverage": 0,
    "cpunumber": 3,
    "cpusockets": 3,
    "cpuspeed": 2100,
    "cpuused": "0.62%",
    "cpuwithoverprovisioning": "12600",
    "created": "2025-10-13T12:05:27+0000",
    "details": {
      "External:abc": "123",
      "External:testKey": "testValue",
      "Host.OS": "Red Hat Enterprise Linux",
      "Host.OS.Kernel.Version": "5.4.17-2136.309.5.1.el8uek.x86_64",
      "Host.OS.Version": "8.6",
      "com.cloud.network.Networks.RouterPrivateIpStrategy": "HostLocal",
      "host.uefi.enable": "true",
      "secured": "true"
    },
    "encryptionsupported": true,
    "events": "AgentDisconnected; HostDown; ManagementServerDown; StartAgentRebalance; PingTimeout; AgentConnected; Remove; Ping; ShutdownRequested",
    "hahost": false,
    "hasannotations": false,
    "hostha": {
      "haenable": false,
      "hastate": "Disabled"
    },
    "hypervisor": "KVM",
    "id": "a2eac7e2-4b45-4fe3-b52c-d6fd22ecd4fc",
    "instanceconversionsupported": false,
    "ipaddress": "10.0.34.96",
    "islocalstorageactive": false,
    "lastpinged": "1970-01-20T21:31:38+0000",
    "managementserverid": "c8acac1d-29c4-4dbf-a306-18a6cd277db3",
    "managementservername": "ref-trl-9667-k-mol8-rositsa-kyuchukova-mgmt1.sofia.shapeblue.com",
    "memoryallocated": 0,
    "memoryallocatedbytes": 0,
    "memoryallocatedpercentage": "0.00%",
    "memorytotal": 7259144192,
    "memoryused": 647360512,
    "memorywithoverprovisioning": "7259144192",
    "name": "ref-trl-9667-k-Mol8-rositsa-kyuchukova-kvm1",
    "networkkbsread": 6531,
    "networkkbswrite": 0,
    "outofbandmanagement": {
      "enabled": false,
      "powerstate": "Disabled"
    },
    "podid": "8c8d6db8-572b-4cb4-9407-b71942c757ac",
    "podname": "Pod1",
    "resourcestate": "Enabled",
    "state": "Up",
    "type": "Routing",
    "ueficapability": true,
    "version": "4.22.0.0-SNAPSHOT",
    "zoneid": "f3b9301a-d74e-4794-a887-98e0eb756ce1",
    "zonename": "ref-trl-9667-k-Mol8-rositsa-kyuchukova"
  }
}
(localcloud) 🐱 >  

Step 2: Cleanup external details

  • Removed all external details using cleanupexternaldetails=true.

Expected Result: Only External: keys removed, others remain.
Actual Result: All external keys were removed while internal details remained intact.

(localcloud) 🐱 > update host id=a2eac7e2-4b45-4fe3-b52c-d6fd22ecd4fc cleanupexternaldetails=true
{
  "host": {
    "arch": "x86_64",
    "capabilities": "hvm,snapshot",
    "clusterid": "e4780f28-dc1a-49bc-90dc-1b67f5bee503",
    "clustername": "p1-c1",
    "clustertype": "CloudManaged",
    "cpuallocated": "0.00%",
    "cpuallocatedpercentage": "0.00%",
    "cpuallocatedvalue": 0,
    "cpuallocatedwithoverprovisioning": "0.00%",
    "cpuloadaverage": 0,
    "cpunumber": 3,
    "cpusockets": 3,
    "cpuspeed": 2100,
    "cpuused": "0.62%",
    "cpuwithoverprovisioning": "12600",
    "created": "2025-10-13T12:05:27+0000",
    "details": {
      "Host.OS": "Red Hat Enterprise Linux",
      "Host.OS.Kernel.Version": "5.4.17-2136.309.5.1.el8uek.x86_64",
      "Host.OS.Version": "8.6",
      "com.cloud.network.Networks.RouterPrivateIpStrategy": "HostLocal",
      "host.uefi.enable": "true",
      "secured": "true"
    },
    "encryptionsupported": true,
    "events": "AgentDisconnected; HostDown; ManagementServerDown; StartAgentRebalance; PingTimeout; AgentConnected; Remove; Ping; ShutdownRequested",
    "hahost": false,
    "hasannotations": false,
    "hostha": {
      "haenable": false,
      "hastate": "Disabled"
    },
    "hypervisor": "KVM",
    "id": "a2eac7e2-4b45-4fe3-b52c-d6fd22ecd4fc",
    "instanceconversionsupported": false,
    "ipaddress": "10.0.34.96",
    "islocalstorageactive": false,
    "lastpinged": "1970-01-20T21:31:38+0000",
    "managementserverid": "c8acac1d-29c4-4dbf-a306-18a6cd277db3",
    "managementservername": "ref-trl-9667-k-mol8-rositsa-kyuchukova-mgmt1.sofia.shapeblue.com",
    "memoryallocated": 0,
    "memoryallocatedbytes": 0,
    "memoryallocatedpercentage": "0.00%",
    "memorytotal": 7259144192,
    "memoryused": 647360512,
    "memorywithoverprovisioning": "7259144192",
    "name": "ref-trl-9667-k-Mol8-rositsa-kyuchukova-kvm1",
    "networkkbsread": 6531,
    "networkkbswrite": 0,
    "outofbandmanagement": {
      "enabled": false,
      "powerstate": "Disabled"
    },
    "podid": "8c8d6db8-572b-4cb4-9407-b71942c757ac",
    "podname": "Pod1",
    "resourcestate": "Enabled",
    "state": "Up",
    "type": "Routing",
    "ueficapability": true,
    "version": "4.22.0.0-SNAPSHOT",
    "zoneid": "f3b9301a-d74e-4794-a887-98e0eb756ce1",
    "zonename": "ref-trl-9667-k-Mol8-rositsa-kyuchukova"
  }
}

Step 3: Re-add external details

  • Re-added abc and testKey to confirm re-adding works after cleanup.

Expected Result: External details reappear.
Actual Result: External details successfully re-added after cleanup..

(localcloud) 🐱 > update host id=a2eac7e2-4b45-4fe3-b52c-d6fd22ecd4fc externaldetails[0].abc=123 externaldetails[0].testKey=testValue
{
  "host": {
    "arch": "x86_64",
    "capabilities": "hvm,snapshot",
    "clusterid": "e4780f28-dc1a-49bc-90dc-1b67f5bee503",
    "clustername": "p1-c1",
    "clustertype": "CloudManaged",
    "cpuallocated": "0.00%",
    "cpuallocatedpercentage": "0.00%",
    "cpuallocatedvalue": 0,
    "cpuallocatedwithoverprovisioning": "0.00%",
    "cpuloadaverage": 0,
    "cpunumber": 3,
    "cpusockets": 3,
    "cpuspeed": 2100,
    "cpuused": "0.59%",
    "cpuwithoverprovisioning": "12600",
    "created": "2025-10-13T12:05:27+0000",
    "details": {
      "External:abc": "123",
      "External:testKey": "testValue",
      "Host.OS": "Red Hat Enterprise Linux",
      "Host.OS.Kernel.Version": "5.4.17-2136.309.5.1.el8uek.x86_64",
      "Host.OS.Version": "8.6",
      "com.cloud.network.Networks.RouterPrivateIpStrategy": "HostLocal",
      "host.uefi.enable": "true",
      "secured": "true"
    },
    "encryptionsupported": true,
    "events": "AgentDisconnected; HostDown; ManagementServerDown; StartAgentRebalance; PingTimeout; AgentConnected; Remove; Ping; ShutdownRequested",
    "hahost": false,
    "hasannotations": false,
    "hostha": {
      "haenable": false,
      "hastate": "Disabled"
    },
    "hypervisor": "KVM",
    "id": "a2eac7e2-4b45-4fe3-b52c-d6fd22ecd4fc",
    "instanceconversionsupported": false,
    "ipaddress": "10.0.34.96",
    "islocalstorageactive": false,
    "lastpinged": "1970-01-20T21:31:38+0000",
    "managementserverid": "c8acac1d-29c4-4dbf-a306-18a6cd277db3",
    "managementservername": "ref-trl-9667-k-mol8-rositsa-kyuchukova-mgmt1.sofia.shapeblue.com",
    "memoryallocated": 0,
    "memoryallocatedbytes": 0,
    "memoryallocatedpercentage": "0.00%",
    "memorytotal": 7259144192,
    "memoryused": 649945088,
    "memorywithoverprovisioning": "7259144192",
    "name": "ref-trl-9667-k-Mol8-rositsa-kyuchukova-kvm1",
    "networkkbsread": 6643,
    "networkkbswrite": 0,
    "outofbandmanagement": {
      "enabled": false,
      "powerstate": "Disabled"
    },
    "podid": "8c8d6db8-572b-4cb4-9407-b71942c757ac",
    "podname": "Pod1",
    "resourcestate": "Enabled",
    "state": "Up",
    "type": "Routing",
    "ueficapability": true,
    "version": "4.22.0.0-SNAPSHOT",
    "zoneid": "f3b9301a-d74e-4794-a887-98e0eb756ce1",
    "zonename": "ref-trl-9667-k-Mol8-rositsa-kyuchukova"
  }
}
(localcloud) 🐱 >  

Step 4: Cleanup precedence (externaldetails + cleanup)

  • Passed both externaldetails and cleanupexternaldetails in the same request.

Expected Result: Cleanup should win, leaving no External: keys.
Actual Result: Cleanup takes precedence - no external keys remain, proving correct API behavior.

(localcloud) 🐱 > update host id=a2eac7e2-4b45-4fe3-b52c-d6fd22ecd4fc externaldetails[0].xyz=SHOULD_BE_REMOVED cleanupexternaldetails=true
{
  "host": {
    "arch": "x86_64",
    "capabilities": "hvm,snapshot",
    "clusterid": "e4780f28-dc1a-49bc-90dc-1b67f5bee503",
    "clustername": "p1-c1",
    "clustertype": "CloudManaged",
    "cpuallocated": "0.00%",
    "cpuallocatedpercentage": "0.00%",
    "cpuallocatedvalue": 0,
    "cpuallocatedwithoverprovisioning": "0.00%",
    "cpuloadaverage": 0,
    "cpunumber": 3,
    "cpusockets": 3,
    "cpuspeed": 2100,
    "cpuused": "0.59%",
    "cpuwithoverprovisioning": "12600",
    "created": "2025-10-13T12:05:27+0000",
    "details": {
      "Host.OS": "Red Hat Enterprise Linux",
      "Host.OS.Kernel.Version": "5.4.17-2136.309.5.1.el8uek.x86_64",
      "Host.OS.Version": "8.6",
      "com.cloud.network.Networks.RouterPrivateIpStrategy": "HostLocal",
      "host.uefi.enable": "true",
      "secured": "true"
    },
    "encryptionsupported": true,
    "events": "AgentDisconnected; HostDown; ManagementServerDown; StartAgentRebalance; PingTimeout; AgentConnected; Remove; Ping; ShutdownRequested",
    "hahost": false,
    "hasannotations": false,
    "hostha": {
      "haenable": false,
      "hastate": "Disabled"
    },
    "hypervisor": "KVM",
    "id": "a2eac7e2-4b45-4fe3-b52c-d6fd22ecd4fc",
    "instanceconversionsupported": false,
    "ipaddress": "10.0.34.96",
    "islocalstorageactive": false,
    "lastpinged": "1970-01-20T21:31:38+0000",
    "managementserverid": "c8acac1d-29c4-4dbf-a306-18a6cd277db3",
    "managementservername": "ref-trl-9667-k-mol8-rositsa-kyuchukova-mgmt1.sofia.shapeblue.com",
    "memoryallocated": 0,
    "memoryallocatedbytes": 0,
    "memoryallocatedpercentage": "0.00%",
    "memorytotal": 7259144192,
    "memoryused": 649945088,
    "memorywithoverprovisioning": "7259144192",
    "name": "ref-trl-9667-k-Mol8-rositsa-kyuchukova-kvm1",
    "networkkbsread": 6643,
    "networkkbswrite": 0,
    "outofbandmanagement": {
      "enabled": false,
      "powerstate": "Disabled"
    },
    "podid": "8c8d6db8-572b-4cb4-9407-b71942c757ac",
    "podname": "Pod1",
    "resourcestate": "Enabled",
    "state": "Up",
    "type": "Routing",
    "ueficapability": true,
    "version": "4.22.0.0-SNAPSHOT",
    "zoneid": "f3b9301a-d74e-4794-a887-98e0eb756ce1",
    "zonename": "ref-trl-9667-k-Mol8-rositsa-kyuchukova"
  }
}
(localcloud) 🐱 >  

Step 5: Cleanup on an already clean host

  • Run cleanup again when there are no External: details.

Expected Result:

  • No changes in output.
  • No errors.
  • Internal details remain intact.

Actual Result: As expected - the response contained only non-external fields (e.g. Host.OS, host.uefi.enable, secured), proving cleanup is idempotent.

(localcloud) 🐱 > update host id=a2eac7e2-4b45-4fe3-b52c-d6fd22ecd4fc cleanupexternaldetails=true
{
  "host": {
    "arch": "x86_64",
    "capabilities": "hvm,snapshot",
    "clusterid": "e4780f28-dc1a-49bc-90dc-1b67f5bee503",
    "clustername": "p1-c1",
    "clustertype": "CloudManaged",
    "cpuallocated": "0.00%",
    "cpuallocatedpercentage": "0.00%",
    "cpuallocatedvalue": 0,
    "cpuallocatedwithoverprovisioning": "0.00%",
    "cpuloadaverage": 0,
    "cpunumber": 3,
    "cpusockets": 3,
    "cpuspeed": 2100,
    "cpuused": "0.63%",
    "cpuwithoverprovisioning": "12600",
    "created": "2025-10-13T12:05:27+0000",
    "details": {
      "Host.OS": "Red Hat Enterprise Linux",
      "Host.OS.Kernel.Version": "5.4.17-2136.309.5.1.el8uek.x86_64",
      "Host.OS.Version": "8.6",
      "com.cloud.network.Networks.RouterPrivateIpStrategy": "HostLocal",
      "host.uefi.enable": "true",
      "secured": "true"
    },
    "encryptionsupported": true,
    "events": "AgentDisconnected; HostDown; ManagementServerDown; StartAgentRebalance; PingTimeout; AgentConnected; Remove; Ping; ShutdownRequested",
    "hahost": false,
    "hasannotations": false,
    "hostha": {
      "haenable": false,
      "hastate": "Disabled"
    },
    "hypervisor": "KVM",
    "id": "a2eac7e2-4b45-4fe3-b52c-d6fd22ecd4fc",
    "instanceconversionsupported": false,
    "ipaddress": "10.0.34.96",
    "islocalstorageactive": false,
    "lastpinged": "1970-01-20T21:31:38+0000",
    "managementserverid": "c8acac1d-29c4-4dbf-a306-18a6cd277db3",
    "managementservername": "ref-trl-9667-k-mol8-rositsa-kyuchukova-mgmt1.sofia.shapeblue.com",
    "memoryallocated": 0,
    "memoryallocatedbytes": 0,
    "memoryallocatedpercentage": "0.00%",
    "memorytotal": 7259144192,
    "memoryused": 654086144,
    "memorywithoverprovisioning": "7259144192",
    "name": "ref-trl-9667-k-Mol8-rositsa-kyuchukova-kvm1",
    "networkkbsread": 8148,
    "networkkbswrite": 0,
    "outofbandmanagement": {
      "enabled": false,
      "powerstate": "Disabled"
    },
    "podid": "8c8d6db8-572b-4cb4-9407-b71942c757ac",
    "podname": "Pod1",
    "resourcestate": "Enabled",
    "state": "Up",
    "type": "Routing",
    "ueficapability": true,
    "version": "4.22.0.0-SNAPSHOT",
    "zoneid": "f3b9301a-d74e-4794-a887-98e0eb756ce1",
    "zonename": "ref-trl-9667-k-Mol8-rositsa-kyuchukova"
  }
}

Step 6: Add non-external details (e.g. host tags)

  • Update another field while keeping external details untouched.

Expected Result:

  • External: keys remain unchanged (or none if already cleaned).
  • Only host tags are updated.
  • Confirms cleanup doesn’t interfere with unrelated updates.

Actual Result Host tags were successfully updated (explicithosttags and hosttags now show mytag), and external details remained untouched (none present, as expected). Updating unrelated fields works normally and does not interact with the external details cleanup mechanism.

(localcloud) 🐱 > update host id=a2eac7e2-4b45-4fe3-b52c-d6fd22ecd4fc hosttags=mytag
{
  "host": {
    "arch": "x86_64",
    "capabilities": "hvm,snapshot",
    "clusterid": "e4780f28-dc1a-49bc-90dc-1b67f5bee503",
    "clustername": "p1-c1",
    "clustertype": "CloudManaged",
    "cpuallocated": "0.00%",
    "cpuallocatedpercentage": "0.00%",
    "cpuallocatedvalue": 0,
    "cpuallocatedwithoverprovisioning": "0.00%",
    "cpuloadaverage": 0,
    "cpunumber": 3,
    "cpusockets": 3,
    "cpuspeed": 2100,
    "cpuused": "0.59%",
    "cpuwithoverprovisioning": "12600",
    "created": "2025-10-13T12:05:27+0000",
    "details": {
      "Host.OS": "Red Hat Enterprise Linux",
      "Host.OS.Kernel.Version": "5.4.17-2136.309.5.1.el8uek.x86_64",
      "Host.OS.Version": "8.6",
      "com.cloud.network.Networks.RouterPrivateIpStrategy": "HostLocal",
      "host.uefi.enable": "true",
      "secured": "true"
    },
    "encryptionsupported": true,
    "events": "AgentDisconnected; HostDown; ManagementServerDown; StartAgentRebalance; PingTimeout; AgentConnected; Remove; Ping; ShutdownRequested",
    "explicithosttags": "mytag",
    "hahost": false,
    "hasannotations": false,
    "hostha": {
      "haenable": false,
      "hastate": "Disabled"
    },
    "hosttags": "mytag",
    "hypervisor": "KVM",
    "id": "a2eac7e2-4b45-4fe3-b52c-d6fd22ecd4fc",
    "instanceconversionsupported": false,
    "ipaddress": "10.0.34.96",
    "islocalstorageactive": false,
    "istagarule": false,
    "lastpinged": "1970-01-20T21:31:38+0000",
    "managementserverid": "c8acac1d-29c4-4dbf-a306-18a6cd277db3",
    "managementservername": "ref-trl-9667-k-mol8-rositsa-kyuchukova-mgmt1.sofia.shapeblue.com",
    "memoryallocated": 0,
    "memoryallocatedbytes": 0,
    "memoryallocatedpercentage": "0.00%",
    "memorytotal": 7259144192,
    "memoryused": 655081472,
    "memorywithoverprovisioning": "7259144192",
    "name": "ref-trl-9667-k-Mol8-rositsa-kyuchukova-kvm1",
    "networkkbsread": 8797,
    "networkkbswrite": 0,
    "outofbandmanagement": {
      "enabled": false,
      "powerstate": "Disabled"
    },
    "podid": "8c8d6db8-572b-4cb4-9407-b71942c757ac",
    "podname": "Pod1",
    "resourcestate": "Enabled",
    "state": "Up",
    "type": "Routing",
    "ueficapability": true,
    "version": "4.22.0.0-SNAPSHOT",
    "zoneid": "f3b9301a-d74e-4794-a887-98e0eb756ce1",
    "zonename": "ref-trl-9667-k-Mol8-rositsa-kyuchukova"
  }
}

Step 7: UI Check

  • Update external details -> Check UI -> cleanup external details -> Check UI

Before cleanup

image

After cleanup

image

Service Offering External Details Cleanup Testing Results

Step 1: Add ext details to Service offering

Expected Result External details are added

Actual Result: External details successfully added and returned in the API response and present in the UI

(localcloud) 🐱 > update serviceoffering id=67aee29b-fab5-484c-a2cd-8b66b0383a9f externaldetails[0].abc=123 externaldetails[0].xyz=456
{
  "serviceoffering": {
    "cpunumber": 1,
    "cpuspeed": 500,
    "created": "2025-10-13T11:44:00+0000",
    "defaultuse": false,
    "diskofferingdisplaytext": "Small Instance",
    "diskofferingid": "d0094cbf-673c-4945-8c83-2a3f828cba8b",
    "diskofferingname": "Small Instance",
    "diskofferingstrictness": false,
    "displaytext": "Small Instance",
    "dynamicscalingenabled": true,
    "encryptroot": false,
    "hasannotations": false,
    "id": "67aee29b-fab5-484c-a2cd-8b66b0383a9f",
    "iscustomized": false,
    "issystem": false,
    "isvolatile": false,
    "limitcpuuse": false,
    "memory": 512,
    "name": "Small Instance",
    "offerha": false,
    "provisioningtype": "thin",
    "rootdisksize": 0,
    "serviceofferingdetails": {
      "External:abc": "123",
      "External:xyz": "456"
    },
    "state": "Active",
    "storagetype": "shared"
  }
}

image

Step 2: Update One External Detail (No Cleanup)

Expected Result:

  • External:abc remains unchanged.
  • External:xyz updates to NEWVALUE.

Actual Result Same as expected

image
(localcloud) 🐱 > update serviceoffering id=67aee29b-fab5-484c-a2cd-8b66b0383a9f externaldetails[0].xyz=NEWVALUE
{
  "serviceoffering": {
    "cpunumber": 1,
    "cpuspeed": 500,
    "created": "2025-10-13T11:44:00+0000",
    "defaultuse": false,
    "diskofferingdisplaytext": "Small Instance",
    "diskofferingid": "d0094cbf-673c-4945-8c83-2a3f828cba8b",
    "diskofferingname": "Small Instance",
    "diskofferingstrictness": false,
    "displaytext": "Small Instance",
    "dynamicscalingenabled": true,
    "encryptroot": false,
    "hasannotations": false,
    "id": "67aee29b-fab5-484c-a2cd-8b66b0383a9f",
    "iscustomized": false,
    "issystem": false,
    "isvolatile": false,
    "limitcpuuse": false,
    "memory": 512,
    "name": "Small Instance",
    "offerha": false,
    "provisioningtype": "thin",
    "rootdisksize": 0,
    "serviceofferingdetails": {
      "External:xyz": "NEWVALUE"
    },
    "state": "Active",
    "storagetype": "shared"
  }
}

Step 3: Cleanup External Details

Expected Result:

  • All external keys should be removed from the response.
  • serviceofferingdetails should no longer contain any External: keys.

Actual Restul:

  • cleanupexternaldetails=true removed all previously set external keys from the API response.
  • UI shows only the standard service offering properties (as in your screenshot).
(localcloud) 🐱 > update serviceoffering id=67aee29b-fab5-484c-a2cd-8b66b0383a9f cleanupexternaldetails=true
{
  "serviceoffering": {
    "cpunumber": 1,
    "cpuspeed": 500,
    "created": "2025-10-13T11:44:00+0000",
    "defaultuse": false,
    "diskofferingdisplaytext": "Small Instance",
    "diskofferingid": "d0094cbf-673c-4945-8c83-2a3f828cba8b",
    "diskofferingname": "Small Instance",
    "diskofferingstrictness": false,
    "displaytext": "Small Instance",
    "dynamicscalingenabled": true,
    "encryptroot": false,
    "hasannotations": false,
    "id": "67aee29b-fab5-484c-a2cd-8b66b0383a9f",
    "iscustomized": false,
    "issystem": false,
    "isvolatile": false,
    "limitcpuuse": false,
    "memory": 512,
    "name": "Small Instance",
    "offerha": false,
    "provisioningtype": "thin",
    "rootdisksize": 0,
    "state": "Active",
    "storagetype": "shared"
  }
}

image

Step 4: Precedence Test

Expected Result:

  • Cleanup wins over externaldetails in the same request.
  • serviceofferingdetails should remain empty.
  • UI shows no external details.
(localcloud) 🐱 > update serviceoffering id=67aee29b-fab5-484c-a2cd-8b66b0383a9f externaldetails[0].xyz=SHOULD_BE_REMOVED cleanupexternaldetails=true
{
  "serviceoffering": {
    "cpunumber": 1,
    "cpuspeed": 500,
    "created": "2025-10-13T11:44:00+0000",
    "defaultuse": false,
    "diskofferingdisplaytext": "Small Instance",
    "diskofferingid": "d0094cbf-673c-4945-8c83-2a3f828cba8b",
    "diskofferingname": "Small Instance",
    "diskofferingstrictness": false,
    "displaytext": "Small Instance",
    "dynamicscalingenabled": true,
    "encryptroot": false,
    "hasannotations": false,
    "id": "67aee29b-fab5-484c-a2cd-8b66b0383a9f",
    "iscustomized": false,
    "issystem": false,
    "isvolatile": false,
    "limitcpuuse": false,
    "memory": 512,
    "name": "Small Instance",
    "offerha": false,
    "provisioningtype": "thin",
    "rootdisksize": 0,
    "state": "Active",
    "storagetype": "shared"
  }
}
(localcloud) 🐱 >  

@shwstppr
Copy link
Contributor Author

Thanks alot @rosi-shapeblue for exhaustive tests

@DaanHoogland DaanHoogland merged commit 0ca63f3 into apache:main Oct 13, 2025
28 checks passed
@github-project-automation github-project-automation bot moved this from In Progress to Done in Apache CloudStack 4.22.0 Oct 13, 2025
dhslove pushed a commit to ablecloud-team/ablestack-cloud that referenced this pull request Oct 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

No open projects
Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants