weizhouapache commented on code in PR #13032: URL: https://github.com/apache/cloudstack/pull/13032#discussion_r3342328982
########## framework/extensions/src/main/java/org/apache/cloudstack/framework/extensions/network/NetworkExtensionElement.java: ########## @@ -0,0 +1,2728 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.framework.extensions.network; + +import java.io.File; +import java.net.URI; +import java.net.InetAddress; +import java.nio.ByteBuffer; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.inject.Inject; +import javax.naming.ConfigurationException; + +import com.cloud.agent.api.to.LoadBalancerTO; +import com.cloud.dc.DataCenter; +import com.cloud.dc.Vlan; +import com.cloud.dc.VlanVO; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.dc.dao.VlanDao; +import com.cloud.deploy.DeployDestination; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.host.dao.HostDao; +import com.cloud.hypervisor.Hypervisor; +import com.cloud.network.IpAddressManager; +import com.cloud.network.IpAddress; +import com.cloud.network.Network; +import com.cloud.network.Network.Capability; +import com.cloud.network.Network.Provider; +import com.cloud.network.Network.Service; +import com.cloud.network.NetworkModel; +import com.cloud.network.Networks; +import com.cloud.network.dao.NetworkDetailVO; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.dao.PhysicalNetworkDao; +import com.cloud.network.dao.PhysicalNetworkVO; +import com.cloud.network.PhysicalNetworkServiceProvider; +import com.cloud.network.PublicIpAddress; +import com.cloud.network.addr.PublicIp; +import com.cloud.network.dao.FirewallRulesDao; +import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.dao.NetworkDetailsDao; +import com.cloud.network.dao.NetworkServiceMapDao; +import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.network.element.AggregatedCommandExecutor; +import com.cloud.network.element.DhcpServiceProvider; +import com.cloud.network.element.DnsServiceProvider; +import com.cloud.network.element.FirewallServiceProvider; +import com.cloud.network.element.IpDeployer; +import com.cloud.network.element.LoadBalancingServiceProvider; +import com.cloud.network.element.NetworkACLServiceProvider; +import com.cloud.network.element.NetworkElement; +import com.cloud.network.element.PortForwardingServiceProvider; +import com.cloud.network.element.SourceNatServiceProvider; +import com.cloud.network.element.StaticNatServiceProvider; +import com.cloud.network.element.UserDataServiceProvider; +import com.cloud.network.element.VpcProvider; +import com.cloud.network.vpc.NetworkACLItem; +import com.cloud.network.vpc.PrivateGateway; +import com.cloud.network.vpc.StaticRouteProfile; +import com.cloud.network.vpc.Vpc; +import com.cloud.network.lb.LoadBalancingRule; +import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.FirewallRuleVO; +import com.cloud.network.rules.PortForwardingRule; +import com.cloud.network.rules.StaticNat; +import com.cloud.offerings.NetworkOfferingVO; +import com.cloud.offerings.dao.NetworkOfferingDao; +import com.cloud.service.ServiceOfferingVO; +import com.cloud.service.dao.ServiceOfferingDao; +import com.cloud.storage.dao.GuestOSCategoryDao; +import com.cloud.storage.dao.GuestOSDao; +import com.cloud.user.AccountService; +import com.cloud.uservm.UserVm; +import com.cloud.offering.NetworkOffering; +import com.cloud.user.Account; +import com.cloud.utils.Pair; +import com.cloud.utils.component.AdapterBase; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.Nic; +import com.cloud.vm.NicProfile; +import com.cloud.vm.NicVO; +import com.cloud.vm.ReservationContext; +import com.cloud.vm.UserVmVO; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachineManager; +import com.cloud.vm.VirtualMachineProfile; +import com.cloud.vm.VMInstanceDetailVO; +import com.cloud.vm.VmDetailConstants; +import com.cloud.vm.dao.NicDao; +import com.cloud.vm.dao.UserVmDao; +import com.cloud.vm.dao.VMInstanceDetailsDao; +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; +import org.apache.cloudstack.extension.Extension; +import org.apache.cloudstack.extension.ExtensionHelper; +import org.apache.cloudstack.extension.NetworkCustomActionProvider; +import org.apache.cloudstack.framework.extensions.dao.ExtensionDetailsDao; +import org.apache.cloudstack.resourcedetail.dao.VpcDetailsDao; +import org.apache.commons.lang3.EnumUtils; +import org.apache.commons.lang3.StringUtils; + +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.stream.Collectors; + + +public class NetworkExtensionElement extends AdapterBase implements + NetworkElement, SourceNatServiceProvider, StaticNatServiceProvider, + PortForwardingServiceProvider, IpDeployer, NetworkCustomActionProvider, + DhcpServiceProvider, DnsServiceProvider, FirewallServiceProvider, + UserDataServiceProvider, LoadBalancingServiceProvider, + VpcProvider, NetworkACLServiceProvider, AggregatedCommandExecutor { + + private static final Map<Service, Map<Capability, String>> DEFAULT_CAPABILITIES = new HashMap<>(); + + + /** + * When non-null, restricts all operations to the extension whose name + * matches this provider name. + */ + private String providerName; + + @Inject + private NetworkModel networkModel; + @Inject + private NetworkServiceMapDao ntwkSrvcDao; + @Inject + private ExtensionHelper extensionHelper; + @Inject + private NetworkDetailsDao networkDetailsDao; + @Inject + private IpAddressManager ipAddressManager; + @Inject + private NetworkOrchestrationService networkManager; + @Inject + private AccountService accountService; + @Inject + private PhysicalNetworkDao physicalNetworkDao; + @Inject + private ExtensionDetailsDao extensionDetailsDao; + @Inject + private NetworkDao networkDao; + @Inject + private DataCenterDao dataCenterDao; + @Inject + private VlanDao vlanDao; + @Inject + private GuestOSCategoryDao guestOSCategoryDao; + @Inject + private GuestOSDao guestOSDao; + @Inject + private HostDao hostDao; + @Inject + private VMInstanceDetailsDao vmInstanceDetailsDao; + @Inject + private UserVmDao userVmDao; + @Inject + private NicDao nicDao; + @Inject + private NetworkOfferingDao networkOfferingDao; + @Inject + private ServiceOfferingDao serviceOfferingDao; + @Inject + private FirewallRulesDao firewallRulesDao; + @Inject + private IPAddressDao ipAddressDao; + @Inject + private VpcDao vpcDao; + @Inject + private VpcDetailsDao vpcDetailsDao; + + // ---- Script argument names ---- + + public static final String ARG_PHYSICAL_NETWORK_EXTENSION_DETAILS = "physical-network-extension-details"; + public static final String ARG_NETWORK_EXTENSION_DETAILS = "network-extension-details"; + public static final String ARG_PAYLOAD = "payload"; + public static final String ARG_ACTION_PARAMS = "action-params"; + + public static final int DEFAULT_SCRIPT_TIMEOUT_SECONDS = 60; + + public static final int EXIT_CODE_SUCCESS = 0; + public static final int EXIT_CODE_FAILURE = -1; + + // ---- Script command names ---- + + public static final String CMD_IMPLEMENT_NETWORK = "implement-network"; + public static final String CMD_SHUTDOWN_NETWORK = "shutdown-network"; + public static final String CMD_DESTROY_NETWORK = "destroy-network"; + public static final String CMD_ENSURE_NETWORK_DEVICE = "ensure-network-device"; + public static final String CMD_ASSIGN_IP = "assign-ip"; + public static final String CMD_RELEASE_IP = "release-ip"; + public static final String CMD_ADD_STATIC_NAT = "add-static-nat"; + public static final String CMD_DELETE_STATIC_NAT = "delete-static-nat"; + public static final String CMD_ADD_PORT_FORWARD = "add-port-forward"; + public static final String CMD_DELETE_PORT_FORWARD = "delete-port-forward"; + public static final String CMD_ADD_DHCP_ENTRY = "add-dhcp-entry"; + public static final String CMD_CONFIG_DHCP_SUBNET = "config-dhcp-subnet"; + public static final String CMD_REMOVE_DHCP_SUBNET = "remove-dhcp-subnet"; + public static final String CMD_SET_DHCP_OPTIONS = "set-dhcp-options"; + public static final String CMD_REMOVE_DHCP_ENTRY = "remove-dhcp-entry"; + public static final String CMD_ADD_DNS_ENTRY = "add-dns-entry"; + public static final String CMD_CONFIG_DNS_SUBNET = "config-dns-subnet"; + public static final String CMD_REMOVE_DNS_SUBNET = "remove-dns-subnet"; + public static final String CMD_SAVE_VM_DATA = "save-vm-data"; + public static final String CMD_SAVE_PASSWORD = "save-password"; + public static final String CMD_SAVE_USERDATA = "save-userdata"; + public static final String CMD_SAVE_SSHKEY = "save-sshkey"; + public static final String CMD_SAVE_HYPERVISOR_HOSTNAME = "save-hypervisor-hostname"; + public static final String CMD_APPLY_LB_RULES = "apply-lb-rules"; + public static final String CMD_APPLY_FW_RULES = "apply-fw-rules"; + public static final String CMD_RESTORE_NETWORK = "restore-network"; + public static final String CMD_IMPLEMENT_VPC = "implement-vpc"; + public static final String CMD_SHUTDOWN_VPC = "shutdown-vpc"; + public static final String CMD_UPDATE_VPC_SOURCE_NAT_IP = "update-vpc-source-nat-ip"; + public static final String CMD_APPLY_NETWORK_ACL = "apply-network-acl"; + public static final String CMD_CUSTOM_ACTION = "custom-action"; + + // ---- Network detail key ---- + + /** + * Key used to persist the per-network JSON blob in {@code network_details}. + * The blob is produced by the network-extension.sh's {@code ensure-network-device} + * command and may contain any fields the script needs (e.g. selected host, + * namespace name, VRF ID, …). + */ + public static final String NETWORK_DETAIL_EXTENSION_DETAILS = "extension.details"; + + public String getProviderName() { + return providerName; + } + + /** + * Returns a new {@link NetworkExtensionElement} scoped to {@code providerName}, + * sharing all injected dependencies with this instance. + */ + public NetworkExtensionElement withProviderName(String providerName) { + NetworkExtensionElement copy = new NetworkExtensionElement(); + copy.networkModel = this.networkModel; + copy.ntwkSrvcDao = this.ntwkSrvcDao; + copy.extensionHelper = this.extensionHelper; + copy.networkDetailsDao = this.networkDetailsDao; + copy.ipAddressManager = this.ipAddressManager; + copy.physicalNetworkDao = this.physicalNetworkDao; + copy.extensionDetailsDao = this.extensionDetailsDao; + copy.networkDao = this.networkDao; + copy.dataCenterDao = this.dataCenterDao; + copy.vlanDao = this.vlanDao; + copy.guestOSCategoryDao = this.guestOSCategoryDao; + copy.guestOSDao = this.guestOSDao; + copy.hostDao = this.hostDao; + copy.vmInstanceDetailsDao = this.vmInstanceDetailsDao; + copy.userVmDao = this.userVmDao; + copy.nicDao = this.nicDao; + copy.networkManager = this.networkManager; + copy.networkOfferingDao = this.networkOfferingDao; + copy.serviceOfferingDao = this.serviceOfferingDao; + copy.accountService = this.accountService; + copy.firewallRulesDao = this.firewallRulesDao; + copy.ipAddressDao = this.ipAddressDao; + copy.vpcDao = this.vpcDao; + copy.vpcDetailsDao = this.vpcDetailsDao; + copy.providerName = providerName; + + logger.debug("NetworkExtensionElement initialised with provider name '{}'", providerName); + return copy; + } + + // ---- Capabilities ---- + + @Override + public Map<Service, Map<Capability, String>> getCapabilities() { + try { + // If this element is scoped to a provider name, prefer capabilities stored + // 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<Service, Map<Capability, String>> caps = extensionHelper.getNetworkCapabilitiesForProvider(null, providerName); + if (caps != null && !caps.isEmpty()) { + return caps; + } + } + } catch (Exception e) { + logger.warn("Failed to load network service capabilities from extension details for provider '{}': {}", providerName, e.getMessage()); + } + + return DEFAULT_CAPABILITIES; + } + + @Override + public Provider getProvider() { + if (providerName != null) { + return Provider.createTransientProvider(providerName); + } + return Provider.NetworkExtension; + } + + // ---- Extension / provider resolution ---- + + protected Extension resolveExtension(Network network) { + Long physicalNetworkId = network.getPhysicalNetworkId(); + if (physicalNetworkId == null) { + logger.warn("Network {} has no physical network — cannot resolve extension", network.getId()); + return null; + } + if (providerName != null && !providerName.isBlank()) { + Extension ext = extensionHelper.getExtensionForPhysicalNetworkAndProvider(physicalNetworkId, providerName); + if (ext != null) { + return ext; + } + logger.warn("No extension found for scoped provider '{}' on physical network {}", providerName, physicalNetworkId); + } + List<String> providers = ntwkSrvcDao.getDistinctProviders(network.getId()); + if (providers != null) { + for (String p : providers) { + Extension ext = extensionHelper.getExtensionForPhysicalNetworkAndProvider(physicalNetworkId, p); + if (ext != null) { + return ext; + } + } + } + return null; + } + + protected boolean canHandle(Network network, Service service) { + Long physicalNetworkId = network.getPhysicalNetworkId(); + if (physicalNetworkId == null) { + return false; + } + if (providerName != null && !providerName.isBlank()) { Review Comment: removing -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
