From 5a3fdc04854752a624b257305ee9b693e29d6973 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Thu, 16 Apr 2026 13:52:34 +0200 Subject: [PATCH] api/server: apply suggestions --- .../engine/orchestration/NetworkOrchestrator.java | 11 +++++++++-- .../extensions/network/NetworkExtensionElement.java | 6 +++--- .../main/java/com/cloud/api/ApiResponseHelper.java | 6 ++++-- .../main/java/com/cloud/network/NetworkModelImpl.java | 6 +++++- .../cloud/network/firewall/FirewallManagerImpl.java | 8 ++++++-- .../network/lb/LoadBalancingRulesManagerImpl.java | 4 +++- .../com/cloud/network/vpc/NetworkACLManagerImpl.java | 5 ++++- .../java/com/cloud/network/vpc/VpcManagerImpl.java | 6 +++++- ui/public/locales/en.json | 2 +- ui/src/views/infra/network/ServiceProvidersTab.vue | 2 +- ui/src/views/offering/AddNetworkOffering.vue | 8 ++++---- ui/src/views/offering/AddVpcOffering.vue | 2 +- 12 files changed, 46 insertions(+), 20 deletions(-) diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index 1b4a57c3194..18d9d0786fe 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -4500,7 +4500,11 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra if (provider == null) { provider = _networkModel.getDefaultUniqueProviderForService(service).getName(); } else { - provider = _networkModel.resolveProvider(provider).getName(); + final Provider resolvedProvider = _networkModel.resolveProvider(provider); + if (resolvedProvider == null) { + throw new InvalidParameterValueException("Invalid provider " + provider + " configured for service " + service); + } + provider = resolvedProvider.getName(); } // check that provider is supported @@ -4526,7 +4530,10 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra final List providerNames = _ntwkSrvcDao.getDistinctProviders(networkId); final List providers = new ArrayList<>(); for (final String providerName : providerNames) { - providers.add(_networkModel.resolveProvider(providerName)); + final Provider provider = _networkModel.resolveProvider(providerName); + if (provider != null) { + providers.add(provider); + } } return providers; diff --git a/framework/extensions/src/main/java/org/apache/cloudstack/framework/extensions/network/NetworkExtensionElement.java b/framework/extensions/src/main/java/org/apache/cloudstack/framework/extensions/network/NetworkExtensionElement.java index aa7e253dfb1..ead27b0450f 100644 --- a/framework/extensions/src/main/java/org/apache/cloudstack/framework/extensions/network/NetworkExtensionElement.java +++ b/framework/extensions/src/main/java/org/apache/cloudstack/framework/extensions/network/NetworkExtensionElement.java @@ -196,7 +196,7 @@ import java.util.stream.Collectors; *
{"host":"192.168.1.10","namespace":"cs-net-42"}
* *

Network capabilities

- * When creating the extension, set detail {@code network.capabilities} to a + * When creating the extension, set detail {@code network.service.capabilities} to a * JSON object describing the services and their capabilities: *
  * {
@@ -333,7 +333,7 @@ public class NetworkExtensionElement extends AdapterBase implements
     public Map> getCapabilities() {
         try {
             // If this element is scoped to a provider name, prefer capabilities stored
-            // in the extension's "network.capabilities" detail.  The ExtensionHelper
+            // in the extension's "network.service.capabilities" detail.  The ExtensionHelper
             // exposes a helper that loads the Service→Capability map from the DB.
             if (providerName != null && !providerName.isBlank()) {
                 Map> caps = extensionHelper.getNetworkCapabilitiesForProvider(null, providerName);
@@ -342,7 +342,7 @@ public class NetworkExtensionElement extends AdapterBase implements
                 }
             }
         } catch (Exception e) {
-            logger.warn("Failed to load network capabilities from extension details for provider '{}': {}", providerName, e.getMessage());
+            logger.warn("Failed to load network service capabilities from extension details for provider '{}': {}", providerName, e.getMessage());
         }
 
         return DEFAULT_CAPABILITIES;
diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java
index 7854a141bdf..aec75340c5c 100644
--- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java
+++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java
@@ -3310,8 +3310,10 @@ public class ApiResponseHelper implements ResponseGenerator, ResourceIdSupport {
         response.setServices(services);
 
         Provider serviceProvider = networkModel.resolveProvider(result.getProviderName());
-        boolean canEnableIndividualServices = ApiDBUtils.canElementEnableIndividualServices(serviceProvider);
-        response.setCanEnableIndividualServices(canEnableIndividualServices);
+        if (serviceProvider != null) {
+            boolean canEnableIndividualServices = ApiDBUtils.canElementEnableIndividualServices(serviceProvider);
+            response.setCanEnableIndividualServices(canEnableIndividualServices);
+        }
 
         response.setObjectName("networkserviceprovider");
         return response;
diff --git a/server/src/main/java/com/cloud/network/NetworkModelImpl.java b/server/src/main/java/com/cloud/network/NetworkModelImpl.java
index 35c11ec7002..f9f5f10ad5d 100644
--- a/server/src/main/java/com/cloud/network/NetworkModelImpl.java
+++ b/server/src/main/java/com/cloud/network/NetworkModelImpl.java
@@ -1266,7 +1266,11 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi
             if (providers == null) {
                 providers = new HashSet();
             }
-            providers.add(resolveProvider(instance.getProvider()));
+
+            final Provider provider = resolveProvider(instance.getProvider());
+            if (provider != null) {
+                providers.add(provider);
+            }
             serviceProviderMap.put(Service.getService(service), providers);
         }
 
diff --git a/server/src/main/java/com/cloud/network/firewall/FirewallManagerImpl.java b/server/src/main/java/com/cloud/network/firewall/FirewallManagerImpl.java
index e996bfab273..faf49654486 100644
--- a/server/src/main/java/com/cloud/network/firewall/FirewallManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/firewall/FirewallManagerImpl.java
@@ -723,7 +723,9 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService,
                 String fwProviderName = networkServiceMapDao.getProviderForServiceInNetwork(network.getId(), Service.Firewall);
                 if (fwProviderName != null) {
                     NetworkElement element = _networkModel.getElementImplementingProvider(fwProviderName);
-                    handled = ((FirewallServiceProvider) element).applyFWRules(network, rules);
+                    if (element instanceof FirewallServiceProvider) {
+                        handled = ((FirewallServiceProvider) element).applyFWRules(network, rules);
+                    }
                 }
             }
             break;
@@ -743,7 +745,9 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService,
                 String pfProviderName = networkServiceMapDao.getProviderForServiceInNetwork(network.getId(), Service.PortForwarding);
                 if (pfProviderName != null) {
                     NetworkElement element = _networkModel.getElementImplementingProvider(pfProviderName);
-                    handled = ((PortForwardingServiceProvider) element).applyPFRules(network, (List) rules);
+                    if (element instanceof PortForwardingServiceProvider) {
+                        handled = ((PortForwardingServiceProvider) element).applyPFRules(network, (List) rules);
+                    }
                 }
             }
             break;
diff --git a/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java b/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java
index eba71c57640..1d99c4aa578 100644
--- a/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java
@@ -2055,7 +2055,9 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements
             String lbProviderName = _ntwkSrvcDao.getProviderForServiceInNetwork(network.getId(), Service.Lb);
             if (lbProviderName != null) {
                 NetworkElement element = _networkModel.getElementImplementingProvider(lbProviderName);
-                handled = ((LoadBalancingServiceProvider) element).applyLBRules(network, rules);
+                if (element instanceof LoadBalancingServiceProvider) {
+                    handled = ((LoadBalancingServiceProvider) element).applyLBRules(network, rules);
+                }
             }
         }
         return handled;
diff --git a/server/src/main/java/com/cloud/network/vpc/NetworkACLManagerImpl.java b/server/src/main/java/com/cloud/network/vpc/NetworkACLManagerImpl.java
index 6b499bbd1fe..77501c5151c 100644
--- a/server/src/main/java/com/cloud/network/vpc/NetworkACLManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/vpc/NetworkACLManagerImpl.java
@@ -455,7 +455,10 @@ public class NetworkACLManagerImpl extends ManagerBase implements NetworkACLMana
             if (aclProviderName != null) {
                 foundProvider = true;
                 NetworkElement element = _networkModel.getElementImplementingProvider(aclProviderName);
-                handled = ((NetworkACLServiceProvider) element).applyNetworkACLs(network, rules);
+                if (element instanceof NetworkACLServiceProvider) {
+                    logger.debug("Applying NetworkACL for network: {} with Network ACL service provider: {}", network, aclProviderName);
+                    handled = ((NetworkACLServiceProvider) element).applyNetworkACLs(network, rules);
+                }
             }
         }
         if (handled) {
diff --git a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
index 4acd5b0f8d5..e2083fac7ff 100644
--- a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
@@ -1857,7 +1857,11 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
                 // Default to VPCVirtualRouter
                 provider = Provider.VPCVirtualRouter.getName();
             } else {
-                provider = _ntwkModel.resolveProvider(provider).getName();
+                final Provider resolvedProvider = _ntwkModel.resolveProvider(provider);
+                if (resolvedProvider == null) {
+                    throw new InvalidParameterValueException("Invalid provider " + provider + " configured for service " + service);
+                }
+                provider = resolvedProvider.getName();
             }
 
             if (!_ntwkModel.isProviderEnabledInZone(zoneId, provider)) {
diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json
index 5ffb410b25b..598fdef6e9e 100644
--- a/ui/public/locales/en.json
+++ b/ui/public/locales/en.json
@@ -4256,6 +4256,6 @@
 "label.external.network.service": "External Network Service",
 "message.confirm.disable.external.network.provider": "Are you sure you want to disable the External Network provider?",
 "message.no.network.orchestrator.extensions": "No NetworkOrchestrator extensions found. Please create one first via createExtension API.",
-"message.extension.services.from.capabilities": "Services are derived automatically from the extension's network.capabilities detail.",
+"message.extension.services.from.capabilities": "Services are derived automatically from the extension's network.service.capabilities detail.",
 "message.select.extension": "Please select an extension."
 }
diff --git a/ui/src/views/infra/network/ServiceProvidersTab.vue b/ui/src/views/infra/network/ServiceProvidersTab.vue
index dd5941f01e6..aec12f3b2a3 100644
--- a/ui/src/views/infra/network/ServiceProvidersTab.vue
+++ b/ui/src/views/infra/network/ServiceProvidersTab.vue
@@ -1258,7 +1258,7 @@ export default {
 
       this.extensionProviderLoading = true
       try {
-        // registerExtension auto-creates the NSP (Enabled) with services from network.capabilities
+        // registerExtension auto-creates the NSP (Enabled) with services from network.service.capabilities
         await postAPI('registerExtension', {
           extensionid: extensionId,
           resourceid: this.resource.id,
diff --git a/ui/src/views/offering/AddNetworkOffering.vue b/ui/src/views/offering/AddNetworkOffering.vue
index e87780e4992..366d4639f60 100644
--- a/ui/src/views/offering/AddNetworkOffering.vue
+++ b/ui/src/views/offering/AddNetworkOffering.vue
@@ -1079,7 +1079,7 @@ export default {
           ...(!this.forVpc && { Firewall: this.Netris })
         }
       } else if (this.isExternalNetworkProvider) {
-        // Extension-backed provider: services come from the extension's network.capabilities.
+        // Extension-backed provider: services come from the extension's network.service.capabilities.
         // this.provider is the extension name (= NSP name)
         const extProviderObj = {
           name: this.provider,
@@ -1087,7 +1087,7 @@ export default {
           enabled: true
         }
         const svcMap = { Dhcp: this.VR, Dns: this.VR, UserData: this.VR }
-        // Infer services from the selected extension's network.capabilities detail
+        // Infer services from the selected extension's network.service.capabilities detail
         const extDef = this.availableExtensionProviders.find(e => e.name === this.provider)
         const services = this._getExtensionServices(extDef)
         if (services.length > 0) {
@@ -1110,9 +1110,9 @@ export default {
       this.fetchSupportedServiceData()
     },
     _getExtensionServices (extDef) {
-      if (!extDef || !extDef.details || !extDef.details['network.capabilities']) return []
+      if (!extDef || !extDef.details || !extDef.details['network.service.capabilities']) return []
       try {
-        const caps = JSON.parse(extDef.details['network.capabilities'])
+        const caps = JSON.parse(extDef.details['network.service.capabilities'])
         return (caps && caps.services) ? caps.services : []
       } catch (e) {
         return []
diff --git a/ui/src/views/offering/AddVpcOffering.vue b/ui/src/views/offering/AddVpcOffering.vue
index 7c91961c055..ef8235412ec 100644
--- a/ui/src/views/offering/AddVpcOffering.vue
+++ b/ui/src/views/offering/AddVpcOffering.vue
@@ -686,7 +686,7 @@ export default {
         return []
       }
 
-      const capsJson = extDef.details['network.capabilities']
+      const capsJson = extDef.details['network.service.capabilities']
       if (capsJson) {
         try {
           const caps = JSON.parse(capsJson)