From 6ce6d3dfde8c8bc0f3218bf6cdd195d3f6e88202 Mon Sep 17 00:00:00 2001 From: Pearl Dsilva Date: Tue, 6 Jan 2026 13:59:47 -0500 Subject: [PATCH] fix capability list and mapping of params --- .../ConfigurationManagerImpl.java | 156 ++++++++++++------ 1 file changed, 102 insertions(+), 54 deletions(-) diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index 055244a6a3c..e8f4c668cbd 100644 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -8311,6 +8311,34 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati return createNetworkOffering(cmd); } + /** + * Converts service provider map from internal format to API parameter format. + * + * Internal format: Map> where key=serviceName, value=list of provider names + * API parameter format: Map where each value is a HashMap with "service" and "provider" keys + * + * Example: {"Lb": ["VirtualRouter"]} becomes {0: {"service": "Lb", "provider": "VirtualRouter"}} + */ + private Map> convertToApiParameterFormat(Map> serviceProviderMap) { + Map> apiFormatMap = new HashMap<>(); + int index = 0; + + for (Map.Entry> entry : serviceProviderMap.entrySet()) { + String serviceName = entry.getKey(); + List providers = entry.getValue(); + + for (String provider : providers) { + Map serviceProviderEntry = new HashMap<>(); + serviceProviderEntry.put("service", serviceName); + serviceProviderEntry.put("provider", provider); + apiFormatMap.put(String.valueOf(index), serviceProviderEntry); + index++; + } + } + + return apiFormatMap; + } + private void applySourceOfferingValuesToCloneCmd(CloneNetworkOfferingCmd cmd, NetworkOfferingVO sourceOffering) { Long sourceOfferingId = sourceOffering.getId(); @@ -8320,10 +8348,10 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati // Build final services list with add/drop support List finalServices = resolveFinalServicesList(cmd, sourceServiceProviderMap); - Map finalServiceProviderMap = resolveServiceProviderMap(cmd, sourceServiceProviderMap, finalServices); + Map> finalServiceProviderMap = resolveServiceProviderMap(cmd, sourceServiceProviderMap, finalServices); // Reconstruct service capability list from source offering - Map sourceServiceCapabilityList = reconstructNetworkServiceCapabilityList(sourceOffering); + Map> sourceServiceCapabilityList = reconstructNetworkServiceCapabilityList(sourceOffering); Map sourceDetailsMap = getSourceOfferingDetails(sourceOfferingId); @@ -8356,7 +8384,11 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati List finalServices = new ArrayList<>(); for (Network.Service service : sourceServiceProviderMap.keySet()) { - finalServices.add(service.getName()); + // Gateway service is automatically added by createNetworkOffering if SourceNat is present + // It should not be explicitly included in supportedServices list + if (service != Network.Service.Gateway) { + finalServices.add(service.getName()); + } } if (dropServices != null && !dropServices.isEmpty()) { @@ -8399,7 +8431,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } private void applyResolvedValuesToCommand(CloneNetworkOfferingCmd cmd, NetworkOfferingVO sourceOffering, - List finalServices, Map finalServiceProviderMap, Map sourceServiceCapabilityList, + List finalServices, Map> finalServiceProviderMap, Map> sourceServiceCapabilityList, Map sourceDetailsMap, List sourceDomainIds, List sourceZoneIds) { try { @@ -8409,7 +8441,9 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati setField(cmd, "supportedServices", finalServices); } if (cmd.getServiceProviders() == null || cmd.getServiceProviders().isEmpty()) { - setField(cmd, "serviceProviderList", finalServiceProviderMap); + // Convert to API parameter format: Map with HashMap values containing "service" and "provider" keys + Map> apiFormatMap = convertToApiParameterFormat(finalServiceProviderMap); + setField(cmd, "serviceProviderList", apiFormatMap); } // Apply service capability list if not provided via request parameters @@ -8418,13 +8452,13 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati .anyMatch(key -> key.startsWith(ApiConstants.SERVICE_CAPABILITY_LIST)); if (!hasCapabilityParams && sourceServiceCapabilityList != null && !sourceServiceCapabilityList.isEmpty()) { - setField(cmd, "serviceCapabilitystList", sourceServiceCapabilityList); + setField(cmd, "serviceCapabilitiesList", sourceServiceCapabilityList); } applyIfNotProvided(cmd, requestParams, "displayText", ApiConstants.DISPLAY_TEXT, cmd.getDisplayText(), sourceOffering.getDisplayText()); applyIfNotProvided(cmd, requestParams, "traffictype", ApiConstants.TRAFFIC_TYPE, cmd.getTraffictype(), sourceOffering.getTrafficType().toString()); applyIfNotProvided(cmd, requestParams, "tags", ApiConstants.TAGS, cmd.getTags(), sourceOffering.getTags()); - applyIfNotProvided(cmd, requestParams, "availability", ApiConstants.AVAILABILITY, cmd.getAvailability(), sourceOffering.getAvailability().toString()); + applyIfNotProvided(cmd, requestParams, "availability", ApiConstants.AVAILABILITY, cmd.getAvailability(), Availability.Optional.toString()); applyIfNotProvided(cmd, requestParams, "networkRate", ApiConstants.NETWORKRATE, cmd.getNetworkRate(), sourceOffering.getRateMbps()); applyIfNotProvided(cmd, requestParams, "serviceOfferingId", ApiConstants.SERVICE_OFFERING_ID, cmd.getServiceOfferingId(), sourceOffering.getServiceOfferingId()); applyIfNotProvided(cmd, requestParams, "guestIptype", ApiConstants.GUEST_IP_TYPE, cmd.getGuestIpType(), sourceOffering.getGuestType().toString()); @@ -8482,79 +8516,93 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati * These capabilities were originally passed during creation and stored as boolean flags in the offering. * * Returns a Map in the format expected by CreateNetworkOfferingCmd.serviceCapabilitystList: - * Map with keys like "0.service", "0.capabilitytype", "0.capabilityvalue" + * Map where each value is a HashMap with keys: "service", "capabilitytype", "capabilityvalue" */ - private Map reconstructNetworkServiceCapabilityList(NetworkOfferingVO sourceOffering) { - Map capabilityList = new HashMap<>(); + private Map> reconstructNetworkServiceCapabilityList(NetworkOfferingVO sourceOffering) { + Map> capabilityList = new HashMap<>(); int index = 0; // LB service capabilities if (sourceOffering.isDedicatedLB()) { - capabilityList.put(index + ".service", Network.Service.Lb.getName()); - capabilityList.put(index + ".capabilitytype", Network.Capability.SupportedLBIsolation.getName()); - capabilityList.put(index + ".capabilityvalue", "dedicated"); - index++; + Map cap = new HashMap<>(); + cap.put("service", Network.Service.Lb.getName()); + cap.put("capabilitytype", Network.Capability.SupportedLBIsolation.getName()); + cap.put("capabilityvalue", "dedicated"); + capabilityList.put(String.valueOf(index++), cap); } if (sourceOffering.isElasticLb()) { - capabilityList.put(index + ".service", Network.Service.Lb.getName()); - capabilityList.put(index + ".capabilitytype", Network.Capability.ElasticLb.getName()); - capabilityList.put(index + ".capabilityvalue", "true"); - index++; + Map cap = new HashMap<>(); + cap.put("service", Network.Service.Lb.getName()); + cap.put("capabilitytype", Network.Capability.ElasticLb.getName()); + cap.put("capabilityvalue", "true"); + capabilityList.put(String.valueOf(index++), cap); } if (sourceOffering.isInline()) { - capabilityList.put(index + ".service", Network.Service.Lb.getName()); - capabilityList.put(index + ".capabilitytype", Network.Capability.InlineMode.getName()); - capabilityList.put(index + ".capabilityvalue", "true"); - index++; + Map cap = new HashMap<>(); + cap.put("service", Network.Service.Lb.getName()); + cap.put("capabilitytype", Network.Capability.InlineMode.getName()); + cap.put("capabilityvalue", "true"); + capabilityList.put(String.valueOf(index++), cap); } if (sourceOffering.isPublicLb() || sourceOffering.isInternalLb()) { List schemes = new ArrayList<>(); if (sourceOffering.isPublicLb()) schemes.add("public"); if (sourceOffering.isInternalLb()) schemes.add("internal"); - capabilityList.put(index + ".service", Network.Service.Lb.getName()); - capabilityList.put(index + ".capabilitytype", Network.Capability.LbSchemes.getName()); - capabilityList.put(index + ".capabilityvalue", String.join(",", schemes)); - index++; + Map cap = new HashMap<>(); + cap.put("service", Network.Service.Lb.getName()); + cap.put("capabilitytype", Network.Capability.LbSchemes.getName()); + cap.put("capabilityvalue", String.join(",", schemes)); + capabilityList.put(String.valueOf(index++), cap); } if (sourceOffering.isSupportsVmAutoScaling()) { - capabilityList.put(index + ".service", Network.Service.Lb.getName()); - capabilityList.put(index + ".capabilitytype", Network.Capability.VmAutoScaling.getName()); - capabilityList.put(index + ".capabilityvalue", "true"); - index++; + Map cap = new HashMap<>(); + cap.put("service", Network.Service.Lb.getName()); + cap.put("capabilitytype", Network.Capability.VmAutoScaling.getName()); + cap.put("capabilityvalue", "true"); + capabilityList.put(String.valueOf(index++), cap); } // SourceNat service capabilities - if (sourceOffering.isSharedSourceNat() || sourceOffering.isRedundantRouter()) { - capabilityList.put(index + ".service", Network.Service.SourceNat.getName()); - capabilityList.put(index + ".capabilitytype", Network.Capability.SupportedSourceNatTypes.getName()); - capabilityList.put(index + ".capabilityvalue", sourceOffering.isSharedSourceNat() ? "perzone" : "peraccount"); - index++; + // Only add SupportedSourceNatTypes if explicitly set to perzone (sharedSourceNat=true) + if (sourceOffering.isSharedSourceNat()) { + Map cap = new HashMap<>(); + cap.put("service", Network.Service.SourceNat.getName()); + cap.put("capabilitytype", Network.Capability.SupportedSourceNatTypes.getName()); + cap.put("capabilityvalue", "perzone"); + capabilityList.put(String.valueOf(index++), cap); } - if (sourceOffering.isRedundantRouter()) { - capabilityList.put(index + ".service", Network.Service.SourceNat.getName()); - capabilityList.put(index + ".capabilitytype", Network.Capability.RedundantRouter.getName()); - capabilityList.put(index + ".capabilityvalue", "true"); - index++; - // Also add to Gateway service - capabilityList.put(index + ".service", Network.Service.Gateway.getName()); - capabilityList.put(index + ".capabilitytype", Network.Capability.RedundantRouter.getName()); - capabilityList.put(index + ".capabilityvalue", "true"); - index++; + // Only add RedundantRouter capability when it's true + if (sourceOffering.isRedundantRouter()) { + Map cap1 = new HashMap<>(); + cap1.put("service", Network.Service.SourceNat.getName()); + cap1.put("capabilitytype", Network.Capability.RedundantRouter.getName()); + cap1.put("capabilityvalue", "true"); + capabilityList.put(String.valueOf(index++), cap1); + + // Also add to Gateway service only when redundantRouter is true + Map cap2 = new HashMap<>(); + cap2.put("service", Network.Service.Gateway.getName()); + cap2.put("capabilitytype", Network.Capability.RedundantRouter.getName()); + cap2.put("capabilityvalue", "true"); + capabilityList.put(String.valueOf(index++), cap2); } // StaticNat service capabilities if (sourceOffering.isElasticIp()) { - capabilityList.put(index + ".service", Network.Service.StaticNat.getName()); - capabilityList.put(index + ".capabilitytype", Network.Capability.ElasticIp.getName()); - capabilityList.put(index + ".capabilityvalue", "true"); - index++; + Map cap = new HashMap<>(); + cap.put("service", Network.Service.StaticNat.getName()); + cap.put("capabilitytype", Network.Capability.ElasticIp.getName()); + cap.put("capabilityvalue", "true"); + capabilityList.put(String.valueOf(index++), cap); } - if (sourceOffering.isAssociatePublicIP()) { - capabilityList.put(index + ".service", Network.Service.StaticNat.getName()); - capabilityList.put(index + ".capabilitytype", Network.Capability.AssociatePublicIP.getName()); - capabilityList.put(index + ".capabilityvalue", "true"); - index++; + // AssociatePublicIP can only be set when ElasticIp is true + if (sourceOffering.isElasticIp() && sourceOffering.isAssociatePublicIP()) { + Map cap = new HashMap<>(); + cap.put("service", Network.Service.StaticNat.getName()); + cap.put("capabilitytype", Network.Capability.AssociatePublicIP.getName()); + cap.put("capabilityvalue", "true"); + capabilityList.put(String.valueOf(index++), cap); } return capabilityList;