mirror of
				https://github.com/apache/cloudstack.git
				synced 2025-10-26 08:42:29 +01:00 
			
		
		
		
	Possibility to choose the source NAT IP address on a isolated network or VPC (#6442)
Co-authored-by: NuxRo <nux@li.nux.ro> Co-authored-by: Daniel Augusto Veronezi Salvador <38945620+GutoVeronezi@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									41e8ad7487
								
							
						
					
					
						commit
						ae10263b3b
					
				
							
								
								
									
										3
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							| @ -80,7 +80,8 @@ jobs: | |||||||
|                   smoke/test_metrics_api |                   smoke/test_metrics_api | ||||||
|                   smoke/test_migration |                   smoke/test_migration | ||||||
|                   smoke/test_multipleips_per_nic |                   smoke/test_multipleips_per_nic | ||||||
|                   smoke/test_nested_virtualization", |                   smoke/test_nested_virtualization | ||||||
|  |                   smoke/test_set_sourcenat", | ||||||
|                 "smoke/test_network |                 "smoke/test_network | ||||||
|                   smoke/test_network_acl |                   smoke/test_network_acl | ||||||
|                   smoke/test_network_ipv6 |                   smoke/test_network_ipv6 | ||||||
|  | |||||||
| @ -256,7 +256,7 @@ public interface Network extends ControlledEntity, StateObject<Network.State>, I | |||||||
| 
 | 
 | ||||||
|     public static class Capability { |     public static class Capability { | ||||||
| 
 | 
 | ||||||
|         private static List<Capability> supportedCapabilities = new ArrayList<Capability>(); |         private static List<Capability> supportedCapabilities = new ArrayList<>(); | ||||||
| 
 | 
 | ||||||
|         public static final Capability SupportedProtocols = new Capability("SupportedProtocols"); |         public static final Capability SupportedProtocols = new Capability("SupportedProtocols"); | ||||||
|         public static final Capability SupportedLBAlgorithms = new Capability("SupportedLbAlgorithms"); |         public static final Capability SupportedLBAlgorithms = new Capability("SupportedLbAlgorithms"); | ||||||
|  | |||||||
| @ -23,7 +23,9 @@ import org.apache.cloudstack.api.command.user.vpc.CreatePrivateGatewayCmd; | |||||||
| import org.apache.cloudstack.api.command.user.vpc.CreateVPCCmd; | import org.apache.cloudstack.api.command.user.vpc.CreateVPCCmd; | ||||||
| import org.apache.cloudstack.api.command.user.vpc.ListPrivateGatewaysCmd; | import org.apache.cloudstack.api.command.user.vpc.ListPrivateGatewaysCmd; | ||||||
| import org.apache.cloudstack.api.command.user.vpc.ListStaticRoutesCmd; | import org.apache.cloudstack.api.command.user.vpc.ListStaticRoutesCmd; | ||||||
|  | import org.apache.cloudstack.api.command.user.vpc.ListVPCsCmd; | ||||||
| import org.apache.cloudstack.api.command.user.vpc.RestartVPCCmd; | import org.apache.cloudstack.api.command.user.vpc.RestartVPCCmd; | ||||||
|  | import org.apache.cloudstack.api.command.user.vpc.UpdateVPCCmd; | ||||||
| 
 | 
 | ||||||
| import com.cloud.exception.ConcurrentOperationException; | import com.cloud.exception.ConcurrentOperationException; | ||||||
| import com.cloud.exception.InsufficientAddressCapacityException; | import com.cloud.exception.InsufficientAddressCapacityException; | ||||||
| @ -37,7 +39,6 @@ import com.cloud.utils.Pair; | |||||||
| 
 | 
 | ||||||
| public interface VpcService { | public interface VpcService { | ||||||
| 
 | 
 | ||||||
|     public Vpc createVpc(CreateVPCCmd cmd) throws ResourceAllocationException; |  | ||||||
|     /** |     /** | ||||||
|      * Persists VPC record in the database |      * Persists VPC record in the database | ||||||
|      * |      * | ||||||
| @ -48,14 +49,25 @@ public interface VpcService { | |||||||
|      * @param displayText |      * @param displayText | ||||||
|      * @param cidr |      * @param cidr | ||||||
|      * @param networkDomain TODO |      * @param networkDomain TODO | ||||||
|  |      * @param ip4Dns1 | ||||||
|  |      * @param ip4Dns2 | ||||||
|      * @param displayVpc TODO |      * @param displayVpc TODO | ||||||
|      * @return |      * @return | ||||||
|      * @throws ResourceAllocationException TODO |      * @throws ResourceAllocationException TODO | ||||||
|      */ |      */ | ||||||
|     public Vpc createVpc(long zoneId, long vpcOffId, long vpcOwnerId, String vpcName, String displayText, String cidr, String networkDomain, |     Vpc createVpc(long zoneId, long vpcOffId, long vpcOwnerId, String vpcName, String displayText, String cidr, String networkDomain, | ||||||
|                          String dns1, String dns2, String ip6Dns1, String ip6Dns2, Boolean displayVpc, Integer publicMtu) |                   String ip4Dns1, String ip4Dns2, String ip6Dns1, String ip6Dns2, Boolean displayVpc, Integer publicMtu) | ||||||
|             throws ResourceAllocationException; |             throws ResourceAllocationException; | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * Persists VPC record in the database | ||||||
|  |      * | ||||||
|  |      * @param cmd the command with specification data for the new vpc | ||||||
|  |      * @return a data object describing the new vpc | ||||||
|  |      * @throws ResourceAllocationException the resources for this VPC cannot be allocated | ||||||
|  |      */ | ||||||
|  |     Vpc createVpc(CreateVPCCmd cmd) throws ResourceAllocationException; | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * Deletes a VPC |      * Deletes a VPC | ||||||
|      * |      * | ||||||
| @ -65,48 +77,48 @@ public interface VpcService { | |||||||
|      * @throws ResourceUnavailableException |      * @throws ResourceUnavailableException | ||||||
|      * @throws ConcurrentOperationException |      * @throws ConcurrentOperationException | ||||||
|      */ |      */ | ||||||
|     public boolean deleteVpc(long vpcId) throws ConcurrentOperationException, ResourceUnavailableException; |     boolean deleteVpc(long vpcId) throws ConcurrentOperationException, ResourceUnavailableException; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Persists VPC record in the database | ||||||
|  |      * | ||||||
|  |      * @param cmd the command with specification data for updating the vpc | ||||||
|  |      * @return a data object describing the new vpc state | ||||||
|  |      * @throws ResourceUnavailableException if during restart some resources may not be available | ||||||
|  |      * @throws InsufficientCapacityException if for instance no address space, compute or storage is sufficiently available | ||||||
|  |      */ | ||||||
|  |     Vpc updateVpc(UpdateVPCCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Updates VPC with new name/displayText |      * Updates VPC with new name/displayText | ||||||
|      * |      * | ||||||
|      * @param vpcId |      * @param vpcId the ID of the Vpc to update | ||||||
|      * @param vpcName |      * @param vpcName The new name to give the vpc | ||||||
|      * @param displayText |      * @param displayText the new display text to use for describing the VPC | ||||||
|      * @param customId    TODO |      * @param customId A new custom (external) ID to associate this VPC with | ||||||
|      * @param displayVpc  TODO |      * @param displayVpc should this VPC be displayed on public lists | ||||||
|      * @param mtu |      * @param mtu what maximal transfer unit to us in this VPCs networks | ||||||
|      * @return |      * @param sourceNatIp the source NAT address to use for this VPC (must already be associated with the VPC) | ||||||
|  |      * @return an object describing the current state of the VPC | ||||||
|  |      * @throws ResourceUnavailableException if during restart some resources may not be available | ||||||
|  |      * @throws InsufficientCapacityException if for instance no address space, compute or storage is sufficiently available | ||||||
|      */ |      */ | ||||||
|     public Vpc updateVpc(long vpcId, String vpcName, String displayText, String customId, Boolean displayVpc, Integer mtu); |     Vpc updateVpc(long vpcId, String vpcName, String displayText, String customId, Boolean displayVpc, Integer mtu, String sourceNatIp) throws ResourceUnavailableException, InsufficientCapacityException; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Lists VPC(s) based on the parameters passed to the API call | ||||||
|  |      * | ||||||
|  |      * @param cmd object containing the search specs | ||||||
|  |      * @return the List of VPCs | ||||||
|  |      */ | ||||||
|  |     Pair<List<? extends Vpc>, Integer> listVpcs(ListVPCsCmd cmd); | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Lists VPC(s) based on the parameters passed to the method call |      * Lists VPC(s) based on the parameters passed to the method call | ||||||
|      * |  | ||||||
|      * @param id |  | ||||||
|      * @param vpcName |  | ||||||
|      * @param displayText |  | ||||||
|      * @param supportedServicesStr |  | ||||||
|      * @param cidr |  | ||||||
|      * @param state TODO |  | ||||||
|      * @param accountName |  | ||||||
|      * @param domainId |  | ||||||
|      * @param keyword |  | ||||||
|      * @param startIndex |  | ||||||
|      * @param pageSizeVal |  | ||||||
|      * @param zoneId TODO |  | ||||||
|      * @param isRecursive TODO |  | ||||||
|      * @param listAll TODO |  | ||||||
|      * @param restartRequired TODO |  | ||||||
|      * @param tags TODO |  | ||||||
|      * @param projectId TODO |  | ||||||
|      * @param display TODO |  | ||||||
|      * @param vpc |  | ||||||
|      * @return |  | ||||||
|      */ |      */ | ||||||
|     public Pair<List<? extends Vpc>, Integer> listVpcs(Long id, String vpcName, String displayText, List<String> supportedServicesStr, String cidr, Long vpcOffId, String state, |     Pair<List<? extends Vpc>, Integer> listVpcs(Long id, String vpcName, String displayText, List<String> supportedServicesStr, String cidr, Long vpcOffId, String state, | ||||||
|             String accountName, Long domainId, String keyword, Long startIndex, Long pageSizeVal, Long zoneId, Boolean isRecursive, Boolean listAll, Boolean restartRequired, |                                                 String accountName, Long domainId, String keyword, Long startIndex, Long pageSizeVal, Long zoneId, Boolean isRecursive, Boolean listAll, Boolean restartRequired, | ||||||
|             Map<String, String> tags, Long projectId, Boolean display); |                                                 Map<String, String> tags, Long projectId, Boolean display); | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Starts VPC which includes starting VPC provider and applying all the networking rules on the backend |      * Starts VPC which includes starting VPC provider and applying all the networking rules on the backend | ||||||
| @ -130,17 +142,17 @@ public interface VpcService { | |||||||
|      */ |      */ | ||||||
|     boolean shutdownVpc(long vpcId) throws ConcurrentOperationException, ResourceUnavailableException; |     boolean shutdownVpc(long vpcId) throws ConcurrentOperationException, ResourceUnavailableException; | ||||||
| 
 | 
 | ||||||
|  |     boolean restartVpc(RestartVPCCmd cmd) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException; | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * Restarts the VPC. VPC gets shutdown and started as a part of it |      * Restarts the VPC. VPC gets shutdown and started as a part of it | ||||||
|      * |      * | ||||||
|      * @param id |      * @param networkId the network to restart | ||||||
|      * @param cleanUp |      * @param cleanup throw away the existing VR and rebuild a new one? | ||||||
|      * @param makeredundant |      * @param makeRedundant create two VRs for this network | ||||||
|      * @return |      * @return success or not | ||||||
|      * @throws InsufficientCapacityException |      * @throws InsufficientCapacityException when there is no suitable deployment plan possible | ||||||
|      */ |      */ | ||||||
|     boolean restartVpc(RestartVPCCmd cmd) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException; |  | ||||||
| 
 |  | ||||||
|     boolean restartVpc(Long networkId, boolean cleanup, boolean makeRedundant, boolean livePatch, User user) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException; |     boolean restartVpc(Long networkId, boolean cleanup, boolean makeRedundant, boolean livePatch, User user) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -154,23 +166,12 @@ public interface VpcService { | |||||||
|     /** |     /** | ||||||
|      * Persists VPC private gateway in the Database. |      * Persists VPC private gateway in the Database. | ||||||
|      * |      * | ||||||
|      * |      * @return data object describing the private gateway | ||||||
|      * @param vpcId TODO |  | ||||||
|      * @param physicalNetworkId |  | ||||||
|      * @param vlan |  | ||||||
|      * @param ipAddress |  | ||||||
|      * @param gateway |  | ||||||
|      * @param netmask |  | ||||||
|      * @param gatewayOwnerId |  | ||||||
|      * @param networkOfferingId |  | ||||||
|      * @param isSourceNat |  | ||||||
|      * @param aclId |  | ||||||
|      * @return |  | ||||||
|      * @throws InsufficientCapacityException |      * @throws InsufficientCapacityException | ||||||
|      * @throws ConcurrentOperationException |      * @throws ConcurrentOperationException | ||||||
|      * @throws ResourceAllocationException |      * @throws ResourceAllocationException | ||||||
|      */ |      */ | ||||||
|     public PrivateGateway createVpcPrivateGateway(CreatePrivateGatewayCmd command) throws ResourceAllocationException, ConcurrentOperationException, InsufficientCapacityException; |     PrivateGateway createVpcPrivateGateway(CreatePrivateGatewayCmd command) throws ResourceAllocationException, ConcurrentOperationException, InsufficientCapacityException; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Applies VPC private gateway on the backend, so it becomes functional |      * Applies VPC private gateway on the backend, so it becomes functional | ||||||
| @ -181,12 +182,12 @@ public interface VpcService { | |||||||
|      * @throws ResourceUnavailableException |      * @throws ResourceUnavailableException | ||||||
|      * @throws ConcurrentOperationException |      * @throws ConcurrentOperationException | ||||||
|      */ |      */ | ||||||
|     public PrivateGateway applyVpcPrivateGateway(long gatewayId, boolean destroyOnFailure) throws ConcurrentOperationException, ResourceUnavailableException; |     PrivateGateway applyVpcPrivateGateway(long gatewayId, boolean destroyOnFailure) throws ConcurrentOperationException, ResourceUnavailableException; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Deletes VPC private gateway |      * Deletes VPC private gateway | ||||||
|      * |      * | ||||||
|      * @param id |      * @param gatewayId | ||||||
|      * @return |      * @return | ||||||
|      * @throws ResourceUnavailableException |      * @throws ResourceUnavailableException | ||||||
|      * @throws ConcurrentOperationException |      * @throws ConcurrentOperationException | ||||||
| @ -199,7 +200,7 @@ public interface VpcService { | |||||||
|      * @param listPrivateGatewaysCmd |      * @param listPrivateGatewaysCmd | ||||||
|      * @return |      * @return | ||||||
|      */ |      */ | ||||||
|     public Pair<List<PrivateGateway>, Integer> listPrivateGateway(ListPrivateGatewaysCmd listPrivateGatewaysCmd); |     Pair<List<PrivateGateway>, Integer> listPrivateGateway(ListPrivateGatewaysCmd listPrivateGatewaysCmd); | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Returns Static Route found by Id |      * Returns Static Route found by Id | ||||||
| @ -216,7 +217,7 @@ public interface VpcService { | |||||||
|      * @return |      * @return | ||||||
|      * @throws ResourceUnavailableException |      * @throws ResourceUnavailableException | ||||||
|      */ |      */ | ||||||
|     public boolean applyStaticRoutesForVpc(long vpcId) throws ResourceUnavailableException; |     boolean applyStaticRoutesForVpc(long vpcId) throws ResourceUnavailableException; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Deletes static route from the backend and the database |      * Deletes static route from the backend and the database | ||||||
| @ -225,7 +226,7 @@ public interface VpcService { | |||||||
|      * @return TODO |      * @return TODO | ||||||
|      * @throws ResourceUnavailableException |      * @throws ResourceUnavailableException | ||||||
|      */ |      */ | ||||||
|     public boolean revokeStaticRoute(long routeId) throws ResourceUnavailableException; |     boolean revokeStaticRoute(long routeId) throws ResourceUnavailableException; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Persists static route entry in the Database |      * Persists static route entry in the Database | ||||||
| @ -234,15 +235,15 @@ public interface VpcService { | |||||||
|      * @param cidr |      * @param cidr | ||||||
|      * @return |      * @return | ||||||
|      */ |      */ | ||||||
|     public StaticRoute createStaticRoute(long gatewayId, String cidr) throws NetworkRuleConflictException; |     StaticRoute createStaticRoute(long gatewayId, String cidr) throws NetworkRuleConflictException; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Lists static routes based on parameters passed to the call |      * Lists static routes based on parameters passed to the call | ||||||
|      * |      * | ||||||
|      * @param listStaticRoutesCmd |      * @param cmd Command object with parameters for { @see ListStaticRoutesCmd } | ||||||
|      * @return |      * @return | ||||||
|      */ |      */ | ||||||
|     public Pair<List<? extends StaticRoute>, Integer> listStaticRoutes(ListStaticRoutesCmd cmd); |     Pair<List<? extends StaticRoute>, Integer> listStaticRoutes(ListStaticRoutesCmd cmd); | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Associates IP address from the Public network, to the VPC |      * Associates IP address from the Public network, to the VPC | ||||||
| @ -262,6 +263,5 @@ public interface VpcService { | |||||||
|      * @param routeId |      * @param routeId | ||||||
|      * @return |      * @return | ||||||
|      */ |      */ | ||||||
|     public boolean applyStaticRoute(long routeId) throws ResourceUnavailableException; |     boolean applyStaticRoute(long routeId) throws ResourceUnavailableException; | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -1032,6 +1032,10 @@ public class ApiConstants { | |||||||
|     public static final String AUTO_ENABLE_KVM_HOST = "autoenablekvmhost"; |     public static final String AUTO_ENABLE_KVM_HOST = "autoenablekvmhost"; | ||||||
|     public static final String LIST_APIS = "listApis"; |     public static final String LIST_APIS = "listApis"; | ||||||
| 
 | 
 | ||||||
|  |     public static final String SOURCE_NAT_IP = "sourcenatipaddress"; | ||||||
|  |     public static final String SOURCE_NAT_IP_ID = "sourcenatipaddressid"; | ||||||
|  |     public static final String HAS_RULES = "hasrules"; | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * This enum specifies IO Drivers, each option controls specific policies on I/O. |      * This enum specifies IO Drivers, each option controls specific policies on I/O. | ||||||
|      * Qemu guests support "threads" and "native" options Since 0.8.8 ; "io_uring" is supported Since 6.3.0 (QEMU 5.0). |      * Qemu guests support "threads" and "native" options Since 0.8.8 ; "io_uring" is supported Since 6.3.0 (QEMU 5.0). | ||||||
|  | |||||||
| @ -192,8 +192,8 @@ public class ListPublicIpAddressesCmd extends BaseListTaggedResourcesCmd impleme | |||||||
|     @Override |     @Override | ||||||
|     public void execute() { |     public void execute() { | ||||||
|         Pair<List<? extends IpAddress>, Integer> result = _mgr.searchForIPAddresses(this); |         Pair<List<? extends IpAddress>, Integer> result = _mgr.searchForIPAddresses(this); | ||||||
|         ListResponse<IPAddressResponse> response = new ListResponse<IPAddressResponse>(); |         ListResponse<IPAddressResponse> response = new ListResponse<>(); | ||||||
|         List<IPAddressResponse> ipAddrResponses = new ArrayList<IPAddressResponse>(); |         List<IPAddressResponse> ipAddrResponses = new ArrayList<>(); | ||||||
|         for (IpAddress ipAddress : result.first()) { |         for (IpAddress ipAddress : result.first()) { | ||||||
|             IPAddressResponse ipResponse = _responseGenerator.createIPAddressResponse(getResponseView(), ipAddress); |             IPAddressResponse ipResponse = _responseGenerator.createIPAddressResponse(getResponseView(), ipAddress); | ||||||
|             ipResponse.setObjectName("publicipaddress"); |             ipResponse.setObjectName("publicipaddress"); | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
| // under the License. | // under the License. | ||||||
| package org.apache.cloudstack.api.command.user.network; | package org.apache.cloudstack.api.command.user.network; | ||||||
| 
 | 
 | ||||||
| import com.cloud.network.NetworkService; | import org.apache.commons.lang3.StringUtils; | ||||||
| import org.apache.log4j.Logger; | import org.apache.log4j.Logger; | ||||||
| 
 | 
 | ||||||
| import org.apache.cloudstack.acl.RoleType; | import org.apache.cloudstack.acl.RoleType; | ||||||
| @ -43,10 +43,10 @@ import com.cloud.exception.InsufficientCapacityException; | |||||||
| import com.cloud.exception.InvalidParameterValueException; | import com.cloud.exception.InvalidParameterValueException; | ||||||
| import com.cloud.exception.ResourceAllocationException; | import com.cloud.exception.ResourceAllocationException; | ||||||
| import com.cloud.network.Network; | import com.cloud.network.Network; | ||||||
|  | import com.cloud.network.NetworkService; | ||||||
| import com.cloud.network.Network.GuestType; | import com.cloud.network.Network.GuestType; | ||||||
| import com.cloud.offering.NetworkOffering; | import com.cloud.offering.NetworkOffering; | ||||||
| import com.cloud.utils.net.NetUtils; | import com.cloud.utils.net.NetUtils; | ||||||
| import org.apache.commons.lang3.StringUtils; |  | ||||||
| 
 | 
 | ||||||
| @APICommand(name = "createNetwork", description = "Creates a network", responseObject = NetworkResponse.class, responseView = ResponseView.Restricted, entityType = {Network.class}, | @APICommand(name = "createNetwork", description = "Creates a network", responseObject = NetworkResponse.class, responseView = ResponseView.Restricted, entityType = {Network.class}, | ||||||
|         requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) |         requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) | ||||||
| @ -183,6 +183,14 @@ public class CreateNetworkCmd extends BaseCmd implements UserCmd { | |||||||
|     @Parameter(name = ApiConstants.IP6_DNS2, type = CommandType.STRING, description = "the second IPv6 DNS for the network", since = "4.18.0") |     @Parameter(name = ApiConstants.IP6_DNS2, type = CommandType.STRING, description = "the second IPv6 DNS for the network", since = "4.18.0") | ||||||
|     private String ip6Dns2; |     private String ip6Dns2; | ||||||
| 
 | 
 | ||||||
|  |     @Parameter(name = ApiConstants.SOURCE_NAT_IP, | ||||||
|  |             type = CommandType.STRING, | ||||||
|  |             description = "IPV4 address to be assigned to the public interface of the network router. " + | ||||||
|  |                     "This address will be used as source NAT address for the network. " + | ||||||
|  |                     "\nIf an address is given and it cannot be acquired, an error will be returned and the network won´t be implemented,", | ||||||
|  |             since = "4.19") | ||||||
|  |     private String sourceNatIP; | ||||||
|  | 
 | ||||||
|     ///////////////////////////////////////////////////// |     ///////////////////////////////////////////////////// | ||||||
|     /////////////////// Accessors /////////////////////// |     /////////////////// Accessors /////////////////////// | ||||||
|     ///////////////////////////////////////////////////// |     ///////////////////////////////////////////////////// | ||||||
| @ -266,6 +274,10 @@ public class CreateNetworkCmd extends BaseCmd implements UserCmd { | |||||||
|         return tungstenVirtualRouterUuid; |         return tungstenVirtualRouterUuid; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public String getSourceNatIP() { | ||||||
|  |         return sourceNatIP; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     @Override |     @Override | ||||||
|     public boolean isDisplay() { |     public boolean isDisplay() { | ||||||
|         if(displayNetwork == null) |         if(displayNetwork == null) | ||||||
|  | |||||||
| @ -104,6 +104,9 @@ public class UpdateNetworkCmd extends BaseAsyncCustomIdCmd implements UserCmd { | |||||||
|     @Parameter(name = ApiConstants.IP6_DNS2, type = CommandType.STRING, description = "the second IPv6 DNS for the network. Empty string will update the second IPv6 DNS with the value from the zone", since = "4.18.0") |     @Parameter(name = ApiConstants.IP6_DNS2, type = CommandType.STRING, description = "the second IPv6 DNS for the network. Empty string will update the second IPv6 DNS with the value from the zone", since = "4.18.0") | ||||||
|     private String ip6Dns2; |     private String ip6Dns2; | ||||||
| 
 | 
 | ||||||
|  |     @Parameter(name = ApiConstants.SOURCE_NAT_IP, type = CommandType.STRING, description = "IPV4 address to be assigned to the public interface of the network router. This address must already be acquired for this network", since = "4.19") | ||||||
|  |     private String sourceNatIP; | ||||||
|  | 
 | ||||||
|     ///////////////////////////////////////////////////// |     ///////////////////////////////////////////////////// | ||||||
|     /////////////////// Accessors /////////////////////// |     /////////////////// Accessors /////////////////////// | ||||||
|     ///////////////////////////////////////////////////// |     ///////////////////////////////////////////////////// | ||||||
| @ -181,6 +184,10 @@ public class UpdateNetworkCmd extends BaseAsyncCustomIdCmd implements UserCmd { | |||||||
|         return ip6Dns2; |         return ip6Dns2; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public String getSourceNatIP() { | ||||||
|  |         return sourceNatIP; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     ///////////////////////////////////////////////////// |     ///////////////////////////////////////////////////// | ||||||
|     /////////////// API Implementation/////////////////// |     /////////////// API Implementation/////////////////// | ||||||
|     ///////////////////////////////////////////////////// |     ///////////////////////////////////////////////////// | ||||||
|  | |||||||
| @ -16,7 +16,6 @@ | |||||||
| // under the License. | // under the License. | ||||||
| package org.apache.cloudstack.api.command.user.vpc; | package org.apache.cloudstack.api.command.user.vpc; | ||||||
| 
 | 
 | ||||||
| import com.cloud.network.NetworkService; |  | ||||||
| import org.apache.commons.lang3.StringUtils; | import org.apache.commons.lang3.StringUtils; | ||||||
| import org.apache.log4j.Logger; | import org.apache.log4j.Logger; | ||||||
| 
 | 
 | ||||||
| @ -41,6 +40,7 @@ import com.cloud.exception.ConcurrentOperationException; | |||||||
| import com.cloud.exception.InsufficientCapacityException; | import com.cloud.exception.InsufficientCapacityException; | ||||||
| import com.cloud.exception.ResourceAllocationException; | import com.cloud.exception.ResourceAllocationException; | ||||||
| import com.cloud.exception.ResourceUnavailableException; | import com.cloud.exception.ResourceUnavailableException; | ||||||
|  | import com.cloud.network.NetworkService; | ||||||
| import com.cloud.network.vpc.Vpc; | import com.cloud.network.vpc.Vpc; | ||||||
| 
 | 
 | ||||||
| @APICommand(name = "createVPC", description = "Creates a VPC", responseObject = VpcResponse.class, responseView = ResponseView.Restricted, entityType = {Vpc.class}, | @APICommand(name = "createVPC", description = "Creates a VPC", responseObject = VpcResponse.class, responseView = ResponseView.Restricted, entityType = {Vpc.class}, | ||||||
| @ -113,6 +113,12 @@ public class CreateVPCCmd extends BaseAsyncCreateCmd implements UserCmd { | |||||||
|     @Parameter(name = ApiConstants.IP6_DNS2, type = CommandType.STRING, description = "the second IPv6 DNS for the VPC", since = "4.18.0") |     @Parameter(name = ApiConstants.IP6_DNS2, type = CommandType.STRING, description = "the second IPv6 DNS for the VPC", since = "4.18.0") | ||||||
|     private String ip6Dns2; |     private String ip6Dns2; | ||||||
| 
 | 
 | ||||||
|  |     @Parameter(name = ApiConstants.SOURCE_NAT_IP, type = CommandType.STRING, description = "IPV4 address to be assigned to the public interface of the network router." + | ||||||
|  |             "This address will be used as source NAT address for the networks in ths VPC. " + | ||||||
|  |             "\nIf an address is given and it cannot be acquired, an error will be returned and the network won´t be implemented,", | ||||||
|  |             since = "4.19") | ||||||
|  |     private String sourceNatIP; | ||||||
|  | 
 | ||||||
|     // /////////////////////////////////////////////////// |     // /////////////////////////////////////////////////// | ||||||
|     // ///////////////// Accessors /////////////////////// |     // ///////////////// Accessors /////////////////////// | ||||||
|     // /////////////////////////////////////////////////// |     // /////////////////////////////////////////////////// | ||||||
| @ -180,6 +186,15 @@ public class CreateVPCCmd extends BaseAsyncCreateCmd implements UserCmd { | |||||||
|         return display; |         return display; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  |     public String getSourceNatIP() { | ||||||
|  |         return sourceNatIP; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ///////////////////////////////////////////////////// | ||||||
|  |     /////////////// API Implementation/////////////////// | ||||||
|  |     ///////////////////////////////////////////////////// | ||||||
|  | 
 | ||||||
|     @Override |     @Override | ||||||
|     public void create() throws ResourceAllocationException { |     public void create() throws ResourceAllocationException { | ||||||
|         Vpc vpc = _vpcService.createVpc(this); |         Vpc vpc = _vpcService.createVpc(this); | ||||||
|  | |||||||
| @ -142,9 +142,7 @@ public class ListVPCsCmd extends BaseListTaggedResourcesCmd implements UserCmd { | |||||||
|     @Override |     @Override | ||||||
|     public void execute() { |     public void execute() { | ||||||
|         Pair<List<? extends Vpc>, Integer> vpcs = |         Pair<List<? extends Vpc>, Integer> vpcs = | ||||||
|             _vpcService.listVpcs(getId(), getVpcName(), getDisplayText(), getSupportedServices(), getCidr(), getVpcOffId(), getState(), getAccountName(), getDomainId(), |             _vpcService.listVpcs(this); | ||||||
|                 getKeyword(), getStartIndex(), getPageSizeVal(), getZoneId(), isRecursive(), listAll(), getRestartRequired(), getTags(), |  | ||||||
|                 getProjectId(), getDisplay()); |  | ||||||
|         ListResponse<VpcResponse> response = new ListResponse<VpcResponse>(); |         ListResponse<VpcResponse> response = new ListResponse<VpcResponse>(); | ||||||
|         List<VpcResponse> vpcResponses = new ArrayList<VpcResponse>(); |         List<VpcResponse> vpcResponses = new ArrayList<VpcResponse>(); | ||||||
|         for (Vpc vpc : vpcs.first()) { |         for (Vpc vpc : vpcs.first()) { | ||||||
|  | |||||||
| @ -34,6 +34,8 @@ import org.apache.cloudstack.api.command.user.UserCmd; | |||||||
| import org.apache.cloudstack.api.response.VpcResponse; | import org.apache.cloudstack.api.response.VpcResponse; | ||||||
| 
 | 
 | ||||||
| import com.cloud.event.EventTypes; | import com.cloud.event.EventTypes; | ||||||
|  | import com.cloud.exception.InsufficientCapacityException; | ||||||
|  | import com.cloud.exception.ResourceUnavailableException; | ||||||
| import com.cloud.network.vpc.Vpc; | import com.cloud.network.vpc.Vpc; | ||||||
| import com.cloud.user.Account; | import com.cloud.user.Account; | ||||||
| 
 | 
 | ||||||
| @ -63,6 +65,12 @@ public class UpdateVPCCmd extends BaseAsyncCustomIdCmd implements UserCmd { | |||||||
|             description = "MTU to be configured on the network VR's public facing interfaces", since = "4.18.0") |             description = "MTU to be configured on the network VR's public facing interfaces", since = "4.18.0") | ||||||
|     private Integer publicMtu; |     private Integer publicMtu; | ||||||
| 
 | 
 | ||||||
|  |     @Parameter(name = ApiConstants.SOURCE_NAT_IP, | ||||||
|  |             type = CommandType.STRING, | ||||||
|  |             description = "IPV4 address to be assigned to the public interface of the network router. This address must already be acquired for this VPC", | ||||||
|  |             since = "4.19") | ||||||
|  |     private String sourceNatIP; | ||||||
|  | 
 | ||||||
|     ///////////////////////////////////////////////////// |     ///////////////////////////////////////////////////// | ||||||
|     /////////////////// Accessors /////////////////////// |     /////////////////// Accessors /////////////////////// | ||||||
|     ///////////////////////////////////////////////////// |     ///////////////////////////////////////////////////// | ||||||
| @ -87,6 +95,10 @@ public class UpdateVPCCmd extends BaseAsyncCustomIdCmd implements UserCmd { | |||||||
|         return publicMtu; |         return publicMtu; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public String getSourceNatIP() { | ||||||
|  |         return sourceNatIP; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     ///////////////////////////////////////////////////// |     ///////////////////////////////////////////////////// | ||||||
|     /////////////// API Implementation/////////////////// |     /////////////// API Implementation/////////////////// | ||||||
|     ///////////////////////////////////////////////////// |     ///////////////////////////////////////////////////// | ||||||
| @ -107,13 +119,22 @@ public class UpdateVPCCmd extends BaseAsyncCustomIdCmd implements UserCmd { | |||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public void execute() { |     public void execute() { | ||||||
|         Vpc result = _vpcService.updateVpc(getId(), getVpcName(), getDisplayText(), getCustomId(), isDisplayVpc(), getPublicMtu()); |         try { | ||||||
|         if (result != null) { |             Vpc result = _vpcService.updateVpc(this); | ||||||
|             VpcResponse response = _responseGenerator.createVpcResponse(getResponseView(), result); |             if (result != null) { | ||||||
|             response.setResponseName(getCommandName()); |                 VpcResponse response = _responseGenerator.createVpcResponse(getResponseView(), result); | ||||||
|             setResponseObject(response); |                 response.setResponseName(getCommandName()); | ||||||
|         } else { |                 setResponseObject(response); | ||||||
|             throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update VPC"); |             } else { | ||||||
|  |                 throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update VPC"); | ||||||
|  |             } | ||||||
|  |         } catch (final ResourceUnavailableException ex) { | ||||||
|  |             s_logger.warn("Exception: ", ex); | ||||||
|  |             throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage()); | ||||||
|  |         } catch (final InsufficientCapacityException ex) { | ||||||
|  |             s_logger.info(ex); | ||||||
|  |             s_logger.trace(ex); | ||||||
|  |             throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, ex.getMessage()); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -163,10 +163,9 @@ public class IPAddressResponse extends BaseResponseWithAnnotations implements Co | |||||||
|     @Param(description="the name of the Network where ip belongs to") |     @Param(description="the name of the Network where ip belongs to") | ||||||
|     private String networkName; |     private String networkName; | ||||||
| 
 | 
 | ||||||
|     /* |     @SerializedName(ApiConstants.HAS_RULES) | ||||||
|         @SerializedName(ApiConstants.JOB_ID) @Param(description="shows the current pending asynchronous job ID. This tag is not returned if no current pending jobs are acting on the volume") |     @Param(description="whether the ip address has Firewall/PortForwarding/LoadBalancing rules defined") | ||||||
|         private IdentityProxy jobId = new IdentityProxy("async_job"); |     private boolean hasRules; | ||||||
|     */ |  | ||||||
| 
 | 
 | ||||||
|     public void setIpAddress(String ipAddress) { |     public void setIpAddress(String ipAddress) { | ||||||
|         this.ipAddress = ipAddress; |         this.ipAddress = ipAddress; | ||||||
| @ -313,4 +312,8 @@ public class IPAddressResponse extends BaseResponseWithAnnotations implements Co | |||||||
|     public void setNetworkName(String networkName) { |     public void setNetworkName(String networkName) { | ||||||
|         this.networkName = networkName; |         this.networkName = networkName; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     public void setHasRules(final boolean hasRules) { | ||||||
|  |         this.hasRules = hasRules; | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -17,6 +17,8 @@ | |||||||
| 
 | 
 | ||||||
| package org.apache.cloudstack.api.command.user.vpc; | package org.apache.cloudstack.api.command.user.vpc; | ||||||
| 
 | 
 | ||||||
|  | import com.cloud.exception.InsufficientCapacityException; | ||||||
|  | import com.cloud.exception.ResourceUnavailableException; | ||||||
| import com.cloud.network.vpc.Vpc; | import com.cloud.network.vpc.Vpc; | ||||||
| import com.cloud.network.vpc.VpcService; | import com.cloud.network.vpc.VpcService; | ||||||
| import junit.framework.TestCase; | import junit.framework.TestCase; | ||||||
| @ -72,7 +74,7 @@ public class UpdateVPCCmdTest extends TestCase { | |||||||
|         Assert.assertEquals(cmd.getPublicMtu(), publicMtu); |         Assert.assertEquals(cmd.getPublicMtu(), publicMtu); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public void testExecute() { |     public void testExecute() throws ResourceUnavailableException, InsufficientCapacityException { | ||||||
|         ReflectionTestUtils.setField(cmd, "id", 1L); |         ReflectionTestUtils.setField(cmd, "id", 1L); | ||||||
|         ReflectionTestUtils.setField(cmd, "vpcName", "updatedVpcName"); |         ReflectionTestUtils.setField(cmd, "vpcName", "updatedVpcName"); | ||||||
|         ReflectionTestUtils.setField(cmd, "displayText", "Updated VPC Name"); |         ReflectionTestUtils.setField(cmd, "displayText", "Updated VPC Name"); | ||||||
| @ -85,10 +87,10 @@ public class UpdateVPCCmdTest extends TestCase { | |||||||
|         responseGenerator = Mockito.mock(ResponseGenerator.class); |         responseGenerator = Mockito.mock(ResponseGenerator.class); | ||||||
|         cmd._responseGenerator = responseGenerator; |         cmd._responseGenerator = responseGenerator; | ||||||
|         Mockito.when(_vpcService.updateVpc(Mockito.anyLong(), Mockito.anyString(), Mockito.anyString(), |         Mockito.when(_vpcService.updateVpc(Mockito.anyLong(), Mockito.anyString(), Mockito.anyString(), | ||||||
|                 Mockito.anyString(), Mockito.anyBoolean(), Mockito.anyInt())).thenReturn(vpc); |                 Mockito.anyString(), Mockito.anyBoolean(), Mockito.anyInt(), Mockito.anyString())).thenReturn(vpc); | ||||||
|         Mockito.when(responseGenerator.createVpcResponse(ResponseObject.ResponseView.Full, vpc)).thenReturn(response); |         Mockito.when(responseGenerator.createVpcResponse(ResponseObject.ResponseView.Full, vpc)).thenReturn(response); | ||||||
|         Mockito.verify(_vpcService, Mockito.times(0)).updateVpc(Mockito.anyLong(), Mockito.anyString(), Mockito.anyString(), |         Mockito.verify(_vpcService, Mockito.times(0)).updateVpc(Mockito.anyLong(), Mockito.anyString(), Mockito.anyString(), | ||||||
|                 Mockito.anyString(), Mockito.anyBoolean(), Mockito.anyInt()); |                 Mockito.anyString(), Mockito.anyBoolean(), Mockito.anyInt(), Mockito.anyString()); | ||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -233,4 +233,6 @@ public interface IpAddressManager { | |||||||
| 
 | 
 | ||||||
|     public static final String MESSAGE_ASSIGN_IPADDR_EVENT = "Message.AssignIpAddr.Event"; |     public static final String MESSAGE_ASSIGN_IPADDR_EVENT = "Message.AssignIpAddr.Event"; | ||||||
|     public static final String MESSAGE_RELEASE_IPADDR_EVENT = "Message.ReleaseIpAddr.Event"; |     public static final String MESSAGE_RELEASE_IPADDR_EVENT = "Message.ReleaseIpAddr.Event"; | ||||||
|  | 
 | ||||||
|  |     void updateSourceNatIpAddress(IPAddressVO requestedIp, List<IPAddressVO> userIps) throws Exception; | ||||||
| } | } | ||||||
|  | |||||||
| @ -53,6 +53,12 @@ public interface FirewallRulesDao extends GenericDao<FirewallRuleVO, Long> { | |||||||
| 
 | 
 | ||||||
|     List<FirewallRuleVO> listByIpAndNotRevoked(long ipAddressId); |     List<FirewallRuleVO> listByIpAndNotRevoked(long ipAddressId); | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * counts the number of portforwarding rules for an IP address | ||||||
|  |      * | ||||||
|  |      * @param sourceIpId the id of the IP record | ||||||
|  |      * @return the number of portforwarding rules for this IP | ||||||
|  |      */ | ||||||
|     long countRulesByIpId(long sourceIpId); |     long countRulesByIpId(long sourceIpId); | ||||||
| 
 | 
 | ||||||
|     long countRulesByIpIdAndState(long sourceIpId, FirewallRule.State state); |     long countRulesByIpIdAndState(long sourceIpId, FirewallRule.State state); | ||||||
|  | |||||||
| @ -75,7 +75,7 @@ public interface IPAddressDao extends GenericDao<IPAddressVO, Long> { | |||||||
| 
 | 
 | ||||||
|     long countFreeIPsInNetwork(long networkId); |     long countFreeIPsInNetwork(long networkId); | ||||||
| 
 | 
 | ||||||
|     IPAddressVO findByVmIp(String vmIp); |     IPAddressVO findByIp(String ipAddress); | ||||||
| 
 | 
 | ||||||
|     IPAddressVO findByAssociatedVmIdAndVmIp(long vmId, String vmIp); |     IPAddressVO findByAssociatedVmIdAndVmIp(long vmId, String vmIp); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -314,9 +314,9 @@ public class IPAddressDaoImpl extends GenericDaoBase<IPAddressVO, Long> implemen | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public IPAddressVO findByVmIp(String vmIp) { |     public IPAddressVO findByIp(String ipAddress) { | ||||||
|         SearchCriteria<IPAddressVO> sc = AllFieldsSearch.create(); |         SearchCriteria<IPAddressVO> sc = AllFieldsSearch.create(); | ||||||
|         sc.setParameters("associatedVmIp", vmIp); |         sc.setParameters("ipAddress", ipAddress); | ||||||
|         return findOneBy(sc); |         return findOneBy(sc); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -292,6 +292,7 @@ import com.cloud.network.as.AutoScaleVmProfileVO; | |||||||
| import com.cloud.network.as.Condition; | import com.cloud.network.as.Condition; | ||||||
| import com.cloud.network.as.ConditionVO; | import com.cloud.network.as.ConditionVO; | ||||||
| import com.cloud.network.as.Counter; | import com.cloud.network.as.Counter; | ||||||
|  | import com.cloud.network.dao.FirewallRulesDao; | ||||||
| import com.cloud.network.dao.IPAddressDao; | import com.cloud.network.dao.IPAddressDao; | ||||||
| import com.cloud.network.dao.IPAddressVO; | import com.cloud.network.dao.IPAddressVO; | ||||||
| import com.cloud.network.dao.LoadBalancerVO; | import com.cloud.network.dao.LoadBalancerVO; | ||||||
| @ -456,6 +457,8 @@ public class ApiResponseHelper implements ResponseGenerator { | |||||||
|     UserVmJoinDao userVmJoinDao; |     UserVmJoinDao userVmJoinDao; | ||||||
|     @Inject |     @Inject | ||||||
|     NetworkServiceMapDao ntwkSrvcDao; |     NetworkServiceMapDao ntwkSrvcDao; | ||||||
|  |     @Inject | ||||||
|  |     FirewallRulesDao firewallRulesDao; | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public UserResponse createUserResponse(User user) { |     public UserResponse createUserResponse(User user) { | ||||||
| @ -1084,6 +1087,7 @@ public class ApiResponseHelper implements ResponseGenerator { | |||||||
|         ipResponse.setHasAnnotation(annotationDao.hasAnnotations(ipAddr.getUuid(), AnnotationService.EntityType.PUBLIC_IP_ADDRESS.name(), |         ipResponse.setHasAnnotation(annotationDao.hasAnnotations(ipAddr.getUuid(), AnnotationService.EntityType.PUBLIC_IP_ADDRESS.name(), | ||||||
|                 _accountMgr.isRootAdmin(CallContext.current().getCallingAccount().getId()))); |                 _accountMgr.isRootAdmin(CallContext.current().getCallingAccount().getId()))); | ||||||
| 
 | 
 | ||||||
|  |         ipResponse.setHasRules(firewallRulesDao.countRulesByIpId(ipAddr.getId()) > 0); | ||||||
|         ipResponse.setObjectName("ipaddress"); |         ipResponse.setObjectName("ipaddress"); | ||||||
|         return ipResponse; |         return ipResponse; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -295,6 +295,8 @@ import com.googlecode.ipv6.IPv6Network; | |||||||
| 
 | 
 | ||||||
| public class ConfigurationManagerImpl extends ManagerBase implements ConfigurationManager, ConfigurationService, Configurable { | public class ConfigurationManagerImpl extends ManagerBase implements ConfigurationManager, ConfigurationService, Configurable { | ||||||
|     public static final Logger s_logger = Logger.getLogger(ConfigurationManagerImpl.class); |     public static final Logger s_logger = Logger.getLogger(ConfigurationManagerImpl.class); | ||||||
|  |     public static final String PERACCOUNT = "peraccount"; | ||||||
|  |     public static final String PERZONE = "perzone"; | ||||||
| 
 | 
 | ||||||
|     @Inject |     @Inject | ||||||
|     EntityManager _entityMgr; |     EntityManager _entityMgr; | ||||||
| @ -6235,34 +6237,32 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void validateSourceNatServiceCapablities(final Map<Capability, String> sourceNatServiceCapabilityMap) { |     void validateSourceNatServiceCapablities(final Map<Capability, String> sourceNatServiceCapabilityMap) { | ||||||
|         if (sourceNatServiceCapabilityMap != null && !sourceNatServiceCapabilityMap.isEmpty()) { |         if (MapUtils.isNotEmpty(sourceNatServiceCapabilityMap) && (sourceNatServiceCapabilityMap.size() > 2 || ! sourceNatCapabilitiesContainValidValues(sourceNatServiceCapabilityMap))) { | ||||||
|             if (sourceNatServiceCapabilityMap.keySet().size() > 2) { |             throw new InvalidParameterValueException("Only " + Capability.SupportedSourceNatTypes.getName() | ||||||
|                 throw new InvalidParameterValueException("Only " + Capability.SupportedSourceNatTypes.getName() + " and " + Capability.RedundantRouter |                     + ", " + Capability.RedundantRouter | ||||||
|                         + " capabilities can be sepcified for source nat service"); |                     + " capabilities can be specified for source nat service"); | ||||||
|             } |         } | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|             for (final Map.Entry<Capability ,String> srcNatPair : sourceNatServiceCapabilityMap.entrySet()) { |     boolean sourceNatCapabilitiesContainValidValues(Map<Capability, String> sourceNatServiceCapabilityMap) { | ||||||
|                 final Capability capability = srcNatPair.getKey(); |         for (final Entry<Capability ,String> srcNatPair : sourceNatServiceCapabilityMap.entrySet()) { | ||||||
|                 final String value = srcNatPair.getValue(); |             final Capability capability = srcNatPair.getKey(); | ||||||
|                 if (capability == Capability.SupportedSourceNatTypes) { |             final String value = srcNatPair.getValue(); | ||||||
|                     final boolean perAccount = value.contains("peraccount"); |             if (Capability.SupportedSourceNatTypes.equals(capability)) { | ||||||
|                     final boolean perZone = value.contains("perzone"); |                 List<String> snatTypes = Arrays.asList(PERACCOUNT, PERZONE); | ||||||
|                     if (perAccount && perZone || !perAccount && !perZone) { |                 if (! snatTypes.contains(value) || ( value.contains(PERACCOUNT) && value.contains(PERZONE))) { | ||||||
|                         throw new InvalidParameterValueException("Either peraccount or perzone source NAT type can be specified for " |                     throw new InvalidParameterValueException("Either peraccount or perzone source NAT type can be specified for " | ||||||
|                                 + Capability.SupportedSourceNatTypes.getName()); |                             + Capability.SupportedSourceNatTypes.getName()); | ||||||
|                     } |  | ||||||
|                 } else if (capability == Capability.RedundantRouter) { |  | ||||||
|                     final boolean enabled = value.contains("true"); |  | ||||||
|                     final boolean disabled = value.contains("false"); |  | ||||||
|                     if (!enabled && !disabled) { |  | ||||||
|                         throw new InvalidParameterValueException("Unknown specified value for " + Capability.RedundantRouter.getName()); |  | ||||||
|                     } |  | ||||||
|                 } else { |  | ||||||
|                     throw new InvalidParameterValueException("Only " + Capability.SupportedSourceNatTypes.getName() + " and " + Capability.RedundantRouter |  | ||||||
|                             + " capabilities can be sepcified for source nat service"); |  | ||||||
|                 } |                 } | ||||||
|  |             } else if (Capability.RedundantRouter.equals(capability)) { | ||||||
|  |                 if (! Arrays.asList("true", "false").contains(value.toLowerCase())) { | ||||||
|  |                     throw new InvalidParameterValueException("Unknown specified value for " + capability.getName()); | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 return false; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |         return true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void validateStaticNatServiceCapablities(final Map<Capability, String> staticNatServiceCapabilityMap) { |     void validateStaticNatServiceCapablities(final Map<Capability, String> staticNatServiceCapabilityMap) { | ||||||
| @ -6439,17 +6439,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati | |||||||
| 
 | 
 | ||||||
|             final Map<Capability, String> sourceNatServiceCapabilityMap = serviceCapabilityMap.get(Service.SourceNat); |             final Map<Capability, String> sourceNatServiceCapabilityMap = serviceCapabilityMap.get(Service.SourceNat); | ||||||
|             if (sourceNatServiceCapabilityMap != null && !sourceNatServiceCapabilityMap.isEmpty()) { |             if (sourceNatServiceCapabilityMap != null && !sourceNatServiceCapabilityMap.isEmpty()) { | ||||||
|                 final String sourceNatType = sourceNatServiceCapabilityMap.get(Capability.SupportedSourceNatTypes); |                 sharedSourceNat = isSharedSourceNat(serviceProviderMap, sourceNatServiceCapabilityMap); | ||||||
|                 if (sourceNatType != null) { |                 redundantRouter = isRedundantRouter(serviceProviderMap, sourceNatServiceCapabilityMap); | ||||||
|                     _networkModel.checkCapabilityForProvider(serviceProviderMap.get(Service.SourceNat), Service.SourceNat, Capability.SupportedSourceNatTypes, sourceNatType); |  | ||||||
|                     sharedSourceNat = sourceNatType.contains("perzone"); |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 final String param = sourceNatServiceCapabilityMap.get(Capability.RedundantRouter); |  | ||||||
|                 if (param != null) { |  | ||||||
|                     _networkModel.checkCapabilityForProvider(serviceProviderMap.get(Service.SourceNat), Service.SourceNat, Capability.RedundantRouter, param); |  | ||||||
|                     redundantRouter = param.contains("true"); |  | ||||||
|                 } |  | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             final Map<Capability, String> staticNatServiceCapabilityMap = serviceCapabilityMap.get(Service.StaticNat); |             final Map<Capability, String> staticNatServiceCapabilityMap = serviceCapabilityMap.get(Service.StaticNat); | ||||||
| @ -6599,6 +6590,26 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati | |||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     boolean isRedundantRouter(Map<Service, Set<Provider>> serviceProviderMap, Map<Capability, String> sourceNatServiceCapabilityMap) { | ||||||
|  |         boolean redundantRouter = false; | ||||||
|  |         String param = sourceNatServiceCapabilityMap.get(Capability.RedundantRouter); | ||||||
|  |         if (param != null) { | ||||||
|  |             _networkModel.checkCapabilityForProvider(serviceProviderMap.get(Service.SourceNat), Service.SourceNat, Capability.RedundantRouter, param); | ||||||
|  |             redundantRouter = param.contains("true"); | ||||||
|  |         } | ||||||
|  |         return redundantRouter; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     boolean isSharedSourceNat(Map<Service, Set<Provider>> serviceProviderMap, Map<Capability, String> sourceNatServiceCapabilityMap) { | ||||||
|  |         boolean sharedSourceNat = false; | ||||||
|  |         String param = sourceNatServiceCapabilityMap.get(Capability.SupportedSourceNatTypes); | ||||||
|  |         if (param != null) { | ||||||
|  |             _networkModel.checkCapabilityForProvider(serviceProviderMap.get(Service.SourceNat), Service.SourceNat, Capability.SupportedSourceNatTypes, param); | ||||||
|  |             sharedSourceNat = param.contains(PERZONE); | ||||||
|  |         } | ||||||
|  |         return sharedSourceNat; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     protected void validateNtwkOffDetails(final Map<Detail, String> details, final Map<Service, Set<Provider>> serviceProviderMap) { |     protected void validateNtwkOffDetails(final Map<Detail, String> details, final Map<Service, Set<Provider>> serviceProviderMap) { | ||||||
|         for (final Detail detail : details.keySet()) { |         for (final Detail detail : details.keySet()) { | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -2358,4 +2358,19 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage | |||||||
|     public static ConfigKey<Boolean> getSystemvmpublicipreservationmodestrictness() { |     public static ConfigKey<Boolean> getSystemvmpublicipreservationmodestrictness() { | ||||||
|         return SystemVmPublicIpReservationModeStrictness; |         return SystemVmPublicIpReservationModeStrictness; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void updateSourceNatIpAddress(IPAddressVO requestedIp, List<IPAddressVO> userIps) throws Exception{ | ||||||
|  |         Transaction.execute((TransactionCallbackWithException<IpAddress, Exception>) status -> { | ||||||
|  |             // update all other IPs to not be sourcenat, should be at most one | ||||||
|  |             for(IPAddressVO oldIpAddress :userIps) { | ||||||
|  |                 oldIpAddress.setSourceNat(false); | ||||||
|  |                 _ipAddressDao.update(oldIpAddress.getId(), oldIpAddress); | ||||||
|  |             } | ||||||
|  |             requestedIp.setSourceNat(true); | ||||||
|  |             _ipAddressDao.update(requestedIp.getId(),requestedIp); | ||||||
|  |             return requestedIp; | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -297,6 +297,7 @@ public class NetworkMigrationManagerImpl implements NetworkMigrationManager { | |||||||
|         Vpc copyOfVpc; |         Vpc copyOfVpc; | ||||||
|         long copyOfVpcId; |         long copyOfVpcId; | ||||||
|         try { |         try { | ||||||
|  | 
 | ||||||
|             copyOfVpc = _vpcService.createVpc(vpc.getZoneId(), vpcOfferingId, vpc.getAccountId(), vpc.getName(), |             copyOfVpc = _vpcService.createVpc(vpc.getZoneId(), vpcOfferingId, vpc.getAccountId(), vpc.getName(), | ||||||
|                     vpc.getDisplayText(), vpc.getCidr(), vpc.getNetworkDomain(), vpc.getIp4Dns1(), vpc.getIp4Dns2(), |                     vpc.getDisplayText(), vpc.getCidr(), vpc.getNetworkDomain(), vpc.getIp4Dns1(), vpc.getIp4Dns2(), | ||||||
|                     vpc.getIp6Dns1(), vpc.getIp6Dns2(), vpc.isDisplay(), vpc.getPublicMtu()); |                     vpc.getIp6Dns1(), vpc.getIp6Dns2(), vpc.isDisplay(), vpc.getPublicMtu()); | ||||||
|  | |||||||
| @ -80,6 +80,8 @@ import org.apache.commons.lang3.EnumUtils; | |||||||
| import org.apache.commons.lang3.ObjectUtils; | import org.apache.commons.lang3.ObjectUtils; | ||||||
| import org.apache.commons.lang3.StringUtils; | import org.apache.commons.lang3.StringUtils; | ||||||
| import org.apache.log4j.Logger; | import org.apache.log4j.Logger; | ||||||
|  | import org.jetbrains.annotations.NotNull; | ||||||
|  | import org.jetbrains.annotations.Nullable; | ||||||
| import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||||
| import org.springframework.beans.factory.annotation.Qualifier; | import org.springframework.beans.factory.annotation.Qualifier; | ||||||
| 
 | 
 | ||||||
| @ -267,9 +269,13 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C | |||||||
|     private static final long MIN_GRE_KEY = 0L; |     private static final long MIN_GRE_KEY = 0L; | ||||||
|     private static final long MAX_GRE_KEY = 4294967295L; // 2^32 -1 |     private static final long MAX_GRE_KEY = 4294967295L; // 2^32 -1 | ||||||
|     private static final long MIN_VXLAN_VNI = 0L; |     private static final long MIN_VXLAN_VNI = 0L; | ||||||
|  |     /** | ||||||
|  |      // MAX_VXLAN_VNI should be 16777215L (2^24-1), but Linux vxlan interface doesn't accept VNI:2^24-1 now. | ||||||
|  |      // It seems a bug. | ||||||
|  |      // Is this still valid (per 2023?) | ||||||
|  |      */ | ||||||
|     private static final long MAX_VXLAN_VNI = 16777214L; // 2^24 -2 |     private static final long MAX_VXLAN_VNI = 16777214L; // 2^24 -2 | ||||||
|     // MAX_VXLAN_VNI should be 16777215L (2^24-1), but Linux vxlan interface doesn't accept VNI:2^24-1 now. |     private static final String NETWORK_OFFERING_ID = "networkOfferingId"; | ||||||
|     // It seems a bug. |  | ||||||
| 
 | 
 | ||||||
|     @Inject |     @Inject | ||||||
|     DataCenterDao _dcDao = null; |     DataCenterDao _dcDao = null; | ||||||
| @ -1298,15 +1304,20 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void validateRouterIps(String routerIp, String routerIpv6, String startIp, String endIp, String gateway, |     void validateSharedNetworkRouterIPs(String gateway, String startIP, String endIP, String netmask, String routerIPv4, String routerIPv6, String startIPv6, String endIPv6, String ip6Cidr, NetworkOffering ntwkOff) { | ||||||
|                                    String netmask, String startIpv6, String endIpv6, String ip6Cidr) { |         if (ntwkOff.getGuestType() == GuestType.Shared) { | ||||||
|  |             validateSharedNetworkRouterIPv4(routerIPv4, startIP, endIP, gateway, netmask); | ||||||
|  |             validateSharedNetworkRouterIPv6(routerIPv6, startIPv6, endIPv6, ip6Cidr); | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void validateSharedNetworkRouterIPv4(String routerIp, String startIp, String endIp, String gateway, String netmask) { | ||||||
|         if (StringUtils.isNotBlank(routerIp)) { |         if (StringUtils.isNotBlank(routerIp)) { | ||||||
|             if (startIp != null && endIp == null) { |             if (startIp != null && endIp == null) { | ||||||
|                 endIp = startIp; |                 endIp = startIp; | ||||||
|             } |             } | ||||||
|             if (!NetUtils.isValidIp4(routerIp)) { |             isIPv4AddressValid(routerIp); | ||||||
|                 throw new CloudRuntimeException("Router IPv4 IP provided is of incorrect format"); |  | ||||||
|             } |  | ||||||
|             if (StringUtils.isNoneBlank(startIp, endIp)) { |             if (StringUtils.isNoneBlank(startIp, endIp)) { | ||||||
|                 if (!NetUtils.isIpInRange(routerIp, startIp, endIp)) { |                 if (!NetUtils.isIpInRange(routerIp, startIp, endIp)) { | ||||||
|                     throw new CloudRuntimeException("Router IPv4 IP provided is not within the specified range: " + startIp + " - " + endIp); |                     throw new CloudRuntimeException("Router IPv4 IP provided is not within the specified range: " + startIp + " - " + endIp); | ||||||
| @ -1318,26 +1329,39 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         if (StringUtils.isNotBlank(routerIpv6)) { |     } | ||||||
|             if (startIpv6 != null && endIpv6 == null) { | 
 | ||||||
|                 endIpv6 = startIpv6; |     private void validateSharedNetworkRouterIPv6(String routerIPv6, String startIPv6, String endIPv6, String cidrIPv6) { | ||||||
|  |         if (StringUtils.isNotBlank(routerIPv6)) { | ||||||
|  |             if (startIPv6 != null && endIPv6 == null) { | ||||||
|  |                 endIPv6 = startIPv6; | ||||||
|             } |             } | ||||||
|             if (!NetUtils.isValidIp6(routerIpv6)) { |             isIPv6AddressValid(routerIPv6); | ||||||
|                 throw new CloudRuntimeException("Router IPv6 address provided is of incorrect format"); |             if (StringUtils.isNoneBlank(startIPv6, endIPv6)) { | ||||||
|             } |                 String ipv6Range = startIPv6 + "-" + endIPv6; | ||||||
|             if (StringUtils.isNoneBlank(startIpv6, endIpv6)) { |                 if (!NetUtils.isIp6InRange(routerIPv6, ipv6Range)) { | ||||||
|                 String ipv6Range = startIpv6 + "-" + endIpv6; |                     throw new CloudRuntimeException("Router IPv6 address provided is not within the specified range: " + startIPv6 + " - " + endIPv6); | ||||||
|                 if (!NetUtils.isIp6InRange(routerIpv6, ipv6Range)) { |  | ||||||
|                     throw new CloudRuntimeException("Router IPv6 address provided is not within the specified range: " + startIpv6 + " - " + endIpv6); |  | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 if (!NetUtils.isIp6InNetwork(routerIpv6, ip6Cidr)) { |                 if (!NetUtils.isIp6InNetwork(routerIPv6, cidrIPv6)) { | ||||||
|                     throw new CloudRuntimeException("Router IPv6 address provided is not with the network range"); |                     throw new CloudRuntimeException("Router IPv6 address provided is not with the network range"); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     private void isIPv4AddressValid(String routerIp) { | ||||||
|  |         if (!NetUtils.isValidIp4(routerIp)) { | ||||||
|  |             throw new CloudRuntimeException("Router IPv4 IP provided is of incorrect format"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void isIPv6AddressValid(String routerIPv6) { | ||||||
|  |         if (!NetUtils.isValidIp6(routerIPv6)) { | ||||||
|  |             throw new CloudRuntimeException("Router IPv6 address provided is of incorrect format"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     @Override |     @Override | ||||||
|     @DB |     @DB | ||||||
|     @ActionEvent(eventType = EventTypes.EVENT_NETWORK_CREATE, eventDescription = "creating network") |     @ActionEvent(eventType = EventTypes.EVENT_NETWORK_CREATE, eventDescription = "creating network") | ||||||
| @ -1348,34 +1372,26 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C | |||||||
|         String endIP = cmd.getEndIp(); |         String endIP = cmd.getEndIp(); | ||||||
|         String netmask = cmd.getNetmask(); |         String netmask = cmd.getNetmask(); | ||||||
|         String networkDomain = cmd.getNetworkDomain(); |         String networkDomain = cmd.getNetworkDomain(); | ||||||
|         String vlanId = null; | 
 | ||||||
|         boolean bypassVlanOverlapCheck = false; |         boolean adminCalledUs = cmd instanceof CreateNetworkCmdByAdmin; | ||||||
|         boolean hideIpAddressUsage = false; |         String vlanId = adminCalledUs ? ((CreateNetworkCmdByAdmin)cmd).getVlan() : null; | ||||||
|         String routerIp = null; |         boolean bypassVlanOverlapCheck = adminCalledUs && ((CreateNetworkCmdByAdmin)cmd).getBypassVlanOverlapCheck(); | ||||||
|         String routerIpv6 = null; |         boolean hideIpAddressUsage = adminCalledUs && ((CreateNetworkCmdByAdmin)cmd).getHideIpAddressUsage(); | ||||||
|         if (cmd instanceof CreateNetworkCmdByAdmin) { |         String routerIPv4 = adminCalledUs ? ((CreateNetworkCmdByAdmin)cmd).getRouterIp() : null; | ||||||
|             vlanId = ((CreateNetworkCmdByAdmin)cmd).getVlan(); |         String routerIPv6 = adminCalledUs ? ((CreateNetworkCmdByAdmin)cmd).getRouterIpv6() : null; | ||||||
|             bypassVlanOverlapCheck = ((CreateNetworkCmdByAdmin)cmd).getBypassVlanOverlapCheck(); |  | ||||||
|             hideIpAddressUsage = ((CreateNetworkCmdByAdmin)cmd).getHideIpAddressUsage(); |  | ||||||
|             routerIp = ((CreateNetworkCmdByAdmin)cmd).getRouterIp(); |  | ||||||
|             routerIpv6 = ((CreateNetworkCmdByAdmin)cmd).getRouterIpv6(); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         String name = cmd.getNetworkName(); |         String name = cmd.getNetworkName(); | ||||||
|         String displayText = cmd.getDisplayText(); |         String displayText = cmd.getDisplayText(); | ||||||
|         Account caller = CallContext.current().getCallingAccount(); |         Account caller = CallContext.current().getCallingAccount(); | ||||||
|         Long physicalNetworkId = cmd.getPhysicalNetworkId(); |         Long physicalNetworkId = cmd.getPhysicalNetworkId(); | ||||||
|         Long zoneId = cmd.getZoneId(); |  | ||||||
|         String aclTypeStr = cmd.getAclType(); |  | ||||||
|         Long domainId = cmd.getDomainId(); |         Long domainId = cmd.getDomainId(); | ||||||
|         boolean isDomainSpecific = false; |  | ||||||
|         Boolean subdomainAccess = cmd.getSubdomainAccess(); |         Boolean subdomainAccess = cmd.getSubdomainAccess(); | ||||||
|         Long vpcId = cmd.getVpcId(); |         Long vpcId = cmd.getVpcId(); | ||||||
|         String startIPv6 = cmd.getStartIpv6(); |         String startIPv6 = cmd.getStartIpv6(); | ||||||
|         String endIPv6 = cmd.getEndIpv6(); |         String endIPv6 = cmd.getEndIpv6(); | ||||||
|         String ip6Gateway = cmd.getIp6Gateway(); |         String ip6Gateway = cmd.getIp6Gateway(); | ||||||
|         String ip6Cidr = cmd.getIp6Cidr(); |         String ip6Cidr = cmd.getIp6Cidr(); | ||||||
|         Boolean displayNetwork = cmd.getDisplayNetwork(); |         boolean displayNetwork = ! Boolean.FALSE.equals(cmd.getDisplayNetwork()); | ||||||
|         Long aclId = cmd.getAclId(); |         Long aclId = cmd.getAclId(); | ||||||
|         String isolatedPvlan = cmd.getIsolatedPvlan(); |         String isolatedPvlan = cmd.getIsolatedPvlan(); | ||||||
|         String externalId = cmd.getExternalId(); |         String externalId = cmd.getExternalId(); | ||||||
| @ -1388,127 +1404,31 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C | |||||||
|         String ip6Dns1 = cmd.getIp6Dns1(); |         String ip6Dns1 = cmd.getIp6Dns1(); | ||||||
|         String ip6Dns2 = cmd.getIp6Dns2(); |         String ip6Dns2 = cmd.getIp6Dns2(); | ||||||
| 
 | 
 | ||||||
|         // Validate network offering |         // Validate network offering id | ||||||
|         NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId); |         NetworkOffering ntwkOff = getAndValidateNetworkOffering(networkOfferingId); | ||||||
|         if (ntwkOff == null || ntwkOff.isSystemOnly()) { |  | ||||||
|             InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find network offering by specified id"); |  | ||||||
|             if (ntwkOff != null) { |  | ||||||
|                 ex.addProxyObject(ntwkOff.getUuid(), "networkOfferingId"); |  | ||||||
|             } |  | ||||||
|             throw ex; |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         Account owner = null; |         Account owner = getOwningAccount(cmd, caller); | ||||||
|         if ((cmd.getAccountName() != null && domainId != null) || cmd.getProjectId() != null) { |  | ||||||
|             owner = _accountMgr.finalizeOwner(caller, cmd.getAccountName(), domainId, cmd.getProjectId()); |  | ||||||
|         } else { |  | ||||||
|             s_logger.info(String.format("Assigning the network to caller:%s because either projectId or accountname and domainId are not provided", caller.getAccountName())); |  | ||||||
|             owner = caller; |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         // validate physical network and zone |         PhysicalNetwork pNtwk = getAndValidatePhysicalNetwork(physicalNetworkId); | ||||||
|         // Check if physical network exists |  | ||||||
|         PhysicalNetwork pNtwk = null; |  | ||||||
|         if (physicalNetworkId != null) { |  | ||||||
|             pNtwk = _physicalNetworkDao.findById(physicalNetworkId); |  | ||||||
|             if (pNtwk == null) { |  | ||||||
|                 throw new InvalidParameterValueException("Unable to find a physical network having the specified physical network id"); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         if (zoneId == null) { |         DataCenter zone = getAndValidateZone(cmd, pNtwk); | ||||||
|             zoneId = pNtwk.getDataCenterId(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if (displayNetwork == null) { |  | ||||||
|             displayNetwork = true; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         DataCenter zone = _dcDao.findById(zoneId); |  | ||||||
|         if (zone == null) { |  | ||||||
|             throw new InvalidParameterValueException("Specified zone id was not found"); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         _accountMgr.checkAccess(owner, ntwkOff, zone); |         _accountMgr.checkAccess(owner, ntwkOff, zone); | ||||||
| 
 | 
 | ||||||
|         if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getId())) { |         validateZoneAvailability(caller, zone); | ||||||
|             // See DataCenterVO.java |  | ||||||
|             PermissionDeniedException ex = new PermissionDeniedException("Cannot perform this operation since specified Zone is currently disabled"); |  | ||||||
|             ex.addProxyObject(zone.getUuid(), "zoneId"); |  | ||||||
|             throw ex; |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         // Only domain and account ACL types are supported in Acton. |         ACLType aclType = getAclType(caller, cmd.getAclType(), ntwkOff); | ||||||
|         ACLType aclType = null; |  | ||||||
|         if (aclTypeStr != null) { |  | ||||||
|             if (aclTypeStr.equalsIgnoreCase(ACLType.Account.toString())) { |  | ||||||
|                 aclType = ACLType.Account; |  | ||||||
|             } else if (aclTypeStr.equalsIgnoreCase(ACLType.Domain.toString())) { |  | ||||||
|                 aclType = ACLType.Domain; |  | ||||||
|             } else { |  | ||||||
|                 throw new InvalidParameterValueException("Incorrect aclType specified. Check the API documentation for supported types"); |  | ||||||
|             } |  | ||||||
|             // In 3.0 all Shared networks should have aclType == Domain, all Isolated networks aclType==Account |  | ||||||
|             if (ntwkOff.getGuestType() == GuestType.Isolated) { |  | ||||||
|                 if (aclType != ACLType.Account) { |  | ||||||
|                     throw new InvalidParameterValueException("AclType should be " + ACLType.Account + " for network of type " + Network.GuestType.Isolated); |  | ||||||
|                 } |  | ||||||
|             } else if (ntwkOff.getGuestType() == GuestType.Shared) { |  | ||||||
|                 if (!(aclType == ACLType.Domain || aclType == ACLType.Account)) { |  | ||||||
|                     throw new InvalidParameterValueException("AclType should be " + ACLType.Domain + " or " + ACLType.Account + " for network of type " + Network.GuestType.Shared); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } else { |  | ||||||
|             if (ntwkOff.getGuestType() == GuestType.Isolated || ntwkOff.getGuestType() == GuestType.L2) { |  | ||||||
|                 aclType = ACLType.Account; |  | ||||||
|             } else if (ntwkOff.getGuestType() == GuestType.Shared) { |  | ||||||
|                 if (_accountMgr.isRootAdmin(caller.getId())) { |  | ||||||
|                     aclType = ACLType.Domain; |  | ||||||
|                 } else if (_accountMgr.isNormalUser(caller.getId())) { |  | ||||||
|                     aclType = ACLType.Account; |  | ||||||
|                 } else { |  | ||||||
|                     throw new InvalidParameterValueException("AclType must be specified for shared network created by domain admin"); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         if (ntwkOff.getGuestType() != GuestType.Shared && (!StringUtils.isAllBlank(routerIp, routerIpv6))) { |         if (ntwkOff.getGuestType() != GuestType.Shared && (!StringUtils.isAllBlank(routerIPv4, routerIPv6))) { | ||||||
|             throw new InvalidParameterValueException("Router IP can be specified only for Shared networks"); |             throw new InvalidParameterValueException("Router IP can be specified only for Shared networks"); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (ntwkOff.getGuestType() == GuestType.Shared && !_networkModel.isProviderForNetworkOffering(Provider.VirtualRouter, networkOfferingId) |         if (ntwkOff.getGuestType() == GuestType.Shared && !_networkModel.isProviderForNetworkOffering(Provider.VirtualRouter, networkOfferingId) | ||||||
|                 && (!StringUtils.isAllBlank(routerIp, routerIpv6))) { |                 && (!StringUtils.isAllBlank(routerIPv4, routerIPv6))) { | ||||||
|             throw new InvalidParameterValueException("Virtual Router is not a supported provider for the Shared network, hence router ip should not be provided"); |             throw new InvalidParameterValueException("Virtual Router is not a supported provider for the Shared network, hence router ip should not be provided"); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // Check if the network is domain specific |         boolean isDomainSpecific = isDomainSpecificNetworkRequested(caller, domainId, subdomainAccess, ntwkOff, aclType); | ||||||
|         if (aclType == ACLType.Domain) { |  | ||||||
|             // only Admin can create domain with aclType=Domain |  | ||||||
|             if (!_accountMgr.isAdmin(caller.getId())) { |  | ||||||
|                 throw new PermissionDeniedException("Only admin can create networks with aclType=Domain"); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             // only shared networks can be Domain specific |  | ||||||
|             if (ntwkOff.getGuestType() != GuestType.Shared) { |  | ||||||
|                 throw new InvalidParameterValueException("Only " + GuestType.Shared + " networks can have aclType=" + ACLType.Domain); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             if (domainId != null) { |  | ||||||
|                 if (ntwkOff.getTrafficType() != TrafficType.Guest || ntwkOff.getGuestType() != Network.GuestType.Shared) { |  | ||||||
|                     throw new InvalidParameterValueException("Domain level networks are supported just for traffic type " + TrafficType.Guest + " and guest type " + Network.GuestType.Shared); |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 DomainVO domain = _domainDao.findById(domainId); |  | ||||||
|                 if (domain == null) { |  | ||||||
|                     throw new InvalidParameterValueException("Unable to find domain by specified id"); |  | ||||||
|                 } |  | ||||||
|                 _accountMgr.checkAccess(caller, domain); |  | ||||||
|             } |  | ||||||
|             isDomainSpecific = true; |  | ||||||
| 
 |  | ||||||
|         } else if (subdomainAccess != null) { |  | ||||||
|             throw new InvalidParameterValueException("Parameter subDomainAccess can be specified only with aclType=Domain"); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         if (aclType == ACLType.Domain) { |         if (aclType == ACLType.Domain) { | ||||||
|             owner = _accountDao.findById(Account.ACCOUNT_ID_SYSTEM); |             owner = _accountDao.findById(Account.ACCOUNT_ID_SYSTEM); | ||||||
| @ -1610,7 +1530,8 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         validateRouterIps(routerIp, routerIpv6, startIP, endIP, gateway, netmask, startIPv6, endIPv6, ip6Cidr); |         validateSharedNetworkRouterIPs(gateway, startIP, endIP, netmask, routerIPv4, routerIPv6, startIPv6, endIPv6, ip6Cidr, ntwkOff); | ||||||
|  | 
 | ||||||
|         Pair<String, String> ip6GatewayCidr = null; |         Pair<String, String> ip6GatewayCidr = null; | ||||||
|         if (zone.getNetworkType() == NetworkType.Advanced && ntwkOff.getGuestType() == GuestType.Isolated) { |         if (zone.getNetworkType() == NetworkType.Advanced && ntwkOff.getGuestType() == GuestType.Isolated) { | ||||||
|             ipv6 = _networkOfferingDao.isIpv6Supported(ntwkOff.getId()); |             ipv6 = _networkOfferingDao.isIpv6Supported(ntwkOff.getId()); | ||||||
| @ -1682,7 +1603,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C | |||||||
|         if (cidr != null && providersConfiguredForExternalNetworking(ntwkProviders)) { |         if (cidr != null && providersConfiguredForExternalNetworking(ntwkProviders)) { | ||||||
|             if (ntwkOff.getGuestType() == GuestType.Shared && (zone.getNetworkType() == NetworkType.Advanced) && isSharedNetworkOfferingWithServices(networkOfferingId)) { |             if (ntwkOff.getGuestType() == GuestType.Shared && (zone.getNetworkType() == NetworkType.Advanced) && isSharedNetworkOfferingWithServices(networkOfferingId)) { | ||||||
|                 // validate if CIDR specified overlaps with any of the CIDR's allocated for isolated networks and shared networks in the zone |                 // validate if CIDR specified overlaps with any of the CIDR's allocated for isolated networks and shared networks in the zone | ||||||
|                 checkSharedNetworkCidrOverlap(zoneId, pNtwk.getId(), cidr); |                 checkSharedNetworkCidrOverlap(zone.getId(), pNtwk.getId(), cidr); | ||||||
|             } else { |             } else { | ||||||
|                 // if the guest network is for the VPC, if any External Provider are supported in VPC |                 // if the guest network is for the VPC, if any External Provider are supported in VPC | ||||||
|                 // cidr will not be null as it is generated from the super cidr of vpc. |                 // cidr will not be null as it is generated from the super cidr of vpc. | ||||||
| @ -1707,10 +1628,10 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C | |||||||
| 
 | 
 | ||||||
|         // Can add vlan range only to the network which allows it |         // Can add vlan range only to the network which allows it | ||||||
|         if (createVlan && !ntwkOff.isSpecifyIpRanges()) { |         if (createVlan && !ntwkOff.isSpecifyIpRanges()) { | ||||||
|             throwInvalidIdException("Network offering with specified id doesn't support adding multiple ip ranges", ntwkOff.getUuid(), "networkOfferingId"); |             throwInvalidIdException("Network offering with specified id doesn't support adding multiple ip ranges", ntwkOff.getUuid(), NETWORK_OFFERING_ID); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         Pair<Integer, Integer> interfaceMTUs = validateMtuConfig(publicMtu, privateMtu, zoneId); |         Pair<Integer, Integer> interfaceMTUs = validateMtuConfig(publicMtu, privateMtu, zone.getId()); | ||||||
|         mtuCheckForVpcNetwork(vpcId, interfaceMTUs, publicMtu, privateMtu); |         mtuCheckForVpcNetwork(vpcId, interfaceMTUs, publicMtu, privateMtu); | ||||||
| 
 | 
 | ||||||
|         Network associatedNetwork = null; |         Network associatedNetwork = null; | ||||||
| @ -1729,9 +1650,12 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C | |||||||
| 
 | 
 | ||||||
|         checkNetworkDns(ipv6, ntwkOff, vpcId, ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2); |         checkNetworkDns(ipv6, ntwkOff, vpcId, ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2); | ||||||
| 
 | 
 | ||||||
|         Network network = commitNetwork(networkOfferingId, gateway, startIP, endIP, netmask, networkDomain, vlanId, bypassVlanOverlapCheck, name, displayText, caller, physicalNetworkId, zoneId, |         Network network = commitNetwork(networkOfferingId, gateway, startIP, endIP, netmask, networkDomain, vlanId, bypassVlanOverlapCheck, name, displayText, caller, physicalNetworkId, zone.getId(), | ||||||
|                 domainId, isDomainSpecific, subdomainAccess, vpcId, startIPv6, endIPv6, ip6Gateway, ip6Cidr, displayNetwork, aclId, secondaryVlanId, privateVlanType, ntwkOff, pNtwk, aclType, owner, cidr, createVlan, |                 domainId, isDomainSpecific, subdomainAccess, vpcId, startIPv6, endIPv6, ip6Gateway, ip6Cidr, displayNetwork, aclId, secondaryVlanId, privateVlanType, ntwkOff, pNtwk, aclType, owner, cidr, createVlan, | ||||||
|                 externalId, routerIp, routerIpv6, associatedNetwork, ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2, interfaceMTUs); |                 externalId, routerIPv4, routerIPv6, associatedNetwork, ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2, interfaceMTUs); | ||||||
|  | 
 | ||||||
|  |         // retrieve, acquire and associate the correct ip adresses | ||||||
|  |         checkAndSetRouterSourceNatIp(owner, cmd, network); | ||||||
| 
 | 
 | ||||||
|         if (hideIpAddressUsage) { |         if (hideIpAddressUsage) { | ||||||
|             _networkDetailsDao.persist(new NetworkDetailVO(network.getId(), Network.hideIpAddressUsage, String.valueOf(hideIpAddressUsage), false)); |             _networkDetailsDao.persist(new NetworkDetailVO(network.getId(), Network.hideIpAddressUsage, String.valueOf(hideIpAddressUsage), false)); | ||||||
| @ -1748,6 +1672,213 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C | |||||||
|         return network; |         return network; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     void checkAndSetRouterSourceNatIp(Account owner, CreateNetworkCmd cmd, Network network) throws InsufficientAddressCapacityException, ResourceAllocationException { | ||||||
|  |         String sourceNatIp = cmd.getSourceNatIP(); | ||||||
|  |         if (sourceNatIp == null) { | ||||||
|  |             s_logger.debug(String.format("no source nat ip given for create network %s command, using something arbitrary.", cmd.getNetworkName())); | ||||||
|  |             return; // nothing to try | ||||||
|  |         } | ||||||
|  |         IpAddress ip = allocateIP(owner, cmd.getZoneId(), network.getId(), null, sourceNatIp); | ||||||
|  |         try { | ||||||
|  |             associateIPToNetwork(ip.getId(), network.getId()); | ||||||
|  |         } catch (ResourceUnavailableException e) { | ||||||
|  |             String msg = String.format("can´t use %s as sourcenat IP address for network %s/%s as it is un available", sourceNatIp, network.getName(), network.getUuid()); | ||||||
|  |             s_logger.error(msg); | ||||||
|  |             throw new CloudRuntimeException(msg,e); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * @param cmd | ||||||
|  |      * @param network | ||||||
|  |      * @return whether the sourceNat is changed, and consequently restart is needed | ||||||
|  |      * @throws InsufficientAddressCapacityException | ||||||
|  |      * @throws ResourceAllocationException | ||||||
|  |      */ | ||||||
|  |     private boolean checkAndUpdateRouterSourceNatIp(UpdateNetworkCmd cmd, Network network) { | ||||||
|  |         IPAddressVO requestedIp = checkSourceNatIpAddressForUpdate(cmd, network); | ||||||
|  |         if (requestedIp == null) return false; // ip not associated with this network | ||||||
|  | 
 | ||||||
|  |         List<IPAddressVO> userIps = _ipAddressDao.listByAssociatedNetwork(network.getId(), true); | ||||||
|  |         if (! userIps.isEmpty()) { | ||||||
|  |             try { | ||||||
|  |                 _ipAddrMgr.updateSourceNatIpAddress(requestedIp, userIps); | ||||||
|  |             } catch (Exception e) { // pokemon execption from transaction | ||||||
|  |                 String msg = String.format("Update of source NAT ip to %s for network \"%s\"/%s failed due to %s", | ||||||
|  |                         requestedIp.getAddress().addr(), network.getName(), network.getUuid(), e.getLocalizedMessage()); | ||||||
|  |                 s_logger.error(msg); | ||||||
|  |                 throw new CloudRuntimeException(msg, e); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Nullable | ||||||
|  |     private IPAddressVO checkSourceNatIpAddressForUpdate(UpdateNetworkCmd cmd, Network network) { | ||||||
|  |         String sourceNatIp = cmd.getSourceNatIP(); | ||||||
|  |         if (sourceNatIp == null) { | ||||||
|  |             s_logger.trace(String.format("no source NAT ip given to update network %s with.", cmd.getNetworkName())); | ||||||
|  |             return null; | ||||||
|  |         } else { | ||||||
|  |             s_logger.info(String.format("updating network %s to have source NAT ip %s", cmd.getNetworkName(), sourceNatIp)); | ||||||
|  |         } | ||||||
|  |         // check if the address is already aqcuired for this network | ||||||
|  |         IPAddressVO requestedIp = _ipAddressDao.findByIp(sourceNatIp); | ||||||
|  |         if (requestedIp == null || requestedIp.getAssociatedWithNetworkId() == null || ! requestedIp.getAssociatedWithNetworkId().equals(network.getId())) { | ||||||
|  |             s_logger.warn(String.format("Source NAT IP %s is not associated with network %s/%s. It cannot be used as source NAT IP.", | ||||||
|  |                     sourceNatIp, network.getName(), network.getUuid())); | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |         // check if it is the current source NAT address | ||||||
|  |         if (requestedIp.isSourceNat()) { | ||||||
|  |             s_logger.info(String.format("IP address %s is allready the source Nat address. Not updating!", sourceNatIp)); | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |         return requestedIp; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Nullable | ||||||
|  |     private ACLType getAclType(Account caller, String aclTypeStr, NetworkOffering ntwkOff) { | ||||||
|  |         // Only domain and account ACL types are supported in Acton. | ||||||
|  |         ACLType aclType = null; | ||||||
|  |         if (aclTypeStr != null) { | ||||||
|  |             aclType = getAclType(aclTypeStr, ntwkOff); | ||||||
|  |         } else { | ||||||
|  |             aclType = getAclType(caller, ntwkOff, aclType); | ||||||
|  |         } | ||||||
|  |         return aclType; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @NotNull | ||||||
|  |     private static ACLType getAclType(String aclTypeStr, NetworkOffering ntwkOff) { | ||||||
|  |         ACLType aclType; | ||||||
|  |         if (aclTypeStr.equalsIgnoreCase(ACLType.Account.toString())) { | ||||||
|  |             aclType = ACLType.Account; | ||||||
|  |         } else if (aclTypeStr.equalsIgnoreCase(ACLType.Domain.toString())) { | ||||||
|  |             aclType = ACLType.Domain; | ||||||
|  |         } else { | ||||||
|  |             throw new InvalidParameterValueException("Incorrect aclType specified. Check the API documentation for supported types"); | ||||||
|  |         } | ||||||
|  |         // In 3.0 all Shared networks should have aclType == Domain, all Isolated networks aclType==Account | ||||||
|  |         if (ntwkOff.getGuestType() == GuestType.Isolated && aclType != ACLType.Account) { | ||||||
|  |             throw new InvalidParameterValueException("AclType should be " + ACLType.Account + " for network of type " + GuestType.Isolated); | ||||||
|  |         } | ||||||
|  |         return aclType; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private ACLType getAclType(Account caller, NetworkOffering ntwkOff, ACLType aclType) { | ||||||
|  |         if (ntwkOff.getGuestType() == GuestType.Isolated || ntwkOff.getGuestType() == GuestType.L2) { | ||||||
|  |             aclType = ACLType.Account; | ||||||
|  |         } else if (ntwkOff.getGuestType() == GuestType.Shared) { | ||||||
|  |             if (_accountMgr.isRootAdmin(caller.getId())) { | ||||||
|  |                 aclType = ACLType.Domain; | ||||||
|  |             } else if (_accountMgr.isNormalUser(caller.getId())) { | ||||||
|  |                 aclType = ACLType.Account; | ||||||
|  |             } else { | ||||||
|  |                 throw new InvalidParameterValueException("AclType must be specified for shared network created by domain admin"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return aclType; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void validateZoneAvailability(Account caller, DataCenter zone) { | ||||||
|  |         if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getId())) { | ||||||
|  |             // See DataCenterVO.java | ||||||
|  |             PermissionDeniedException ex = new PermissionDeniedException("Cannot perform this operation since specified Zone is currently disabled"); | ||||||
|  |             ex.addProxyObject(zone.getUuid(), "zoneId"); | ||||||
|  |             throw ex; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private boolean isDomainSpecificNetworkRequested(Account caller, Long domainId, Boolean subdomainAccess, NetworkOffering ntwkOff, ACLType aclType) { | ||||||
|  |         boolean isDomainSpecific = false; | ||||||
|  |         // Check if the network is domain specific | ||||||
|  |         if (aclType == ACLType.Domain) { | ||||||
|  |             // only Admin can create domain with aclType=Domain | ||||||
|  |             if (!_accountMgr.isAdmin(caller.getId())) { | ||||||
|  |                 throw new PermissionDeniedException("Only admin can create networks with aclType=Domain"); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // only shared networks can be Domain specific | ||||||
|  |             if (ntwkOff.getGuestType() != GuestType.Shared) { | ||||||
|  |                 throw new InvalidParameterValueException("Only " + GuestType.Shared + " networks can have aclType=" + ACLType.Domain); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (domainId != null) { | ||||||
|  |                 if (ntwkOff.getTrafficType() != TrafficType.Guest || ntwkOff.getGuestType() != GuestType.Shared) { | ||||||
|  |                     throw new InvalidParameterValueException("Domain level networks are supported just for traffic type " + TrafficType.Guest + " and guest type " + GuestType.Shared); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 DomainVO domain = _domainDao.findById(domainId); | ||||||
|  |                 if (domain == null) { | ||||||
|  |                     throw new InvalidParameterValueException("Unable to find domain by specified id"); | ||||||
|  |                 } | ||||||
|  |                 _accountMgr.checkAccess(caller, domain); | ||||||
|  |             } | ||||||
|  |             isDomainSpecific = true; | ||||||
|  | 
 | ||||||
|  |         } else if (subdomainAccess != null) { | ||||||
|  |             throw new InvalidParameterValueException("Parameter subDomainAccess can be specified only with aclType=Domain"); | ||||||
|  |         } | ||||||
|  |         return isDomainSpecific; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @NotNull | ||||||
|  |     private DataCenter getAndValidateZone(CreateNetworkCmd cmd, PhysicalNetwork pNtwk) { | ||||||
|  |         Long zoneId = (cmd.getZoneId() == null) ? pNtwk.getDataCenterId() : cmd.getZoneId(); | ||||||
|  |         DataCenter zone = _dcDao.findById(zoneId); | ||||||
|  |         if (zone == null) { | ||||||
|  |             throw new InvalidParameterValueException("Specified zone id was not found"); | ||||||
|  |         } | ||||||
|  |         return zone; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      // validate physical network and zone | ||||||
|  |      // Check if physical network exists | ||||||
|  |      * | ||||||
|  |      * @param physicalNetworkId the id of the required physical network | ||||||
|  |      * @return the data object for the physical network | ||||||
|  |      */ | ||||||
|  |     @NotNull | ||||||
|  |     private PhysicalNetwork getAndValidatePhysicalNetwork(Long physicalNetworkId) { | ||||||
|  |         PhysicalNetwork pNtwk = null; | ||||||
|  |         if (physicalNetworkId != null) { | ||||||
|  |             pNtwk = getPhysicalNetwork(physicalNetworkId); | ||||||
|  |             if (pNtwk == null) { | ||||||
|  |                 throw new InvalidParameterValueException("Unable to find a physical network having the specified physical network id"); | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             throw new CloudRuntimeException("cannot create Guestnetwork without physical network."); | ||||||
|  |         } | ||||||
|  |         return pNtwk; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private Account getOwningAccount(CreateNetworkCmd cmd, Account caller) { | ||||||
|  |         Account owner = null; | ||||||
|  |         Long domainId = cmd.getDomainId(); | ||||||
|  |         if ((cmd.getAccountName() != null && domainId != null) || cmd.getProjectId() != null) { | ||||||
|  |             owner = _accountMgr.finalizeOwner(caller, cmd.getAccountName(), domainId, cmd.getProjectId()); | ||||||
|  |         } else { | ||||||
|  |             s_logger.info(String.format("Assigning the network to caller:%s because either projectId or accountname and domainId are not provided", caller.getAccountName())); | ||||||
|  |             owner = caller; | ||||||
|  |         } | ||||||
|  |         return owner; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @NotNull | ||||||
|  |     private NetworkOffering getAndValidateNetworkOffering(Long networkOfferingId) { | ||||||
|  |         NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId); | ||||||
|  |         if (ntwkOff == null || ntwkOff.isSystemOnly()) { | ||||||
|  |             InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find network offering by specified id"); | ||||||
|  |             if (ntwkOff != null) { | ||||||
|  |                 ex.addProxyObject(ntwkOff.getUuid(), NETWORK_OFFERING_ID); | ||||||
|  |             } | ||||||
|  |             throw ex; | ||||||
|  |         } | ||||||
|  |         return ntwkOff; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     protected void mtuCheckForVpcNetwork(Long vpcId, Pair<Integer, Integer> interfaceMTUs, Integer publicMtu, Integer privateMtu) { |     protected void mtuCheckForVpcNetwork(Long vpcId, Pair<Integer, Integer> interfaceMTUs, Integer publicMtu, Integer privateMtu) { | ||||||
|         if (vpcId != null && publicMtu != null) { |         if (vpcId != null && publicMtu != null) { | ||||||
|             VpcVO vpc = _vpcDao.findById(vpcId); |             VpcVO vpc = _vpcDao.findById(vpcId); | ||||||
| @ -1862,7 +1993,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void validateNetworkOfferingForNonRootAdminUser(NetworkOfferingVO ntwkOff) { |     private void validateNetworkOfferingForNonRootAdminUser(NetworkOffering ntwkOff) { | ||||||
|         if (ntwkOff.getTrafficType() != TrafficType.Guest) { |         if (ntwkOff.getTrafficType() != TrafficType.Guest) { | ||||||
|             throw new InvalidParameterValueException("This user can only create a Guest network"); |             throw new InvalidParameterValueException("This user can only create a Guest network"); | ||||||
|         } |         } | ||||||
| @ -1924,7 +2055,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C | |||||||
|     private Network commitNetwork(final Long networkOfferingId, final String gateway, final String startIP, final String endIP, final String netmask, final String networkDomain, final String vlanIdFinal, |     private Network commitNetwork(final Long networkOfferingId, final String gateway, final String startIP, final String endIP, final String netmask, final String networkDomain, final String vlanIdFinal, | ||||||
|                                   final Boolean bypassVlanOverlapCheck, final String name, final String displayText, final Account caller, final Long physicalNetworkId, final Long zoneId, final Long domainId, |                                   final Boolean bypassVlanOverlapCheck, final String name, final String displayText, final Account caller, final Long physicalNetworkId, final Long zoneId, final Long domainId, | ||||||
|                                   final boolean isDomainSpecific, final Boolean subdomainAccessFinal, final Long vpcId, final String startIPv6, final String endIPv6, final String ip6Gateway, final String ip6Cidr, |                                   final boolean isDomainSpecific, final Boolean subdomainAccessFinal, final Long vpcId, final String startIPv6, final String endIPv6, final String ip6Gateway, final String ip6Cidr, | ||||||
|                                   final Boolean displayNetwork, final Long aclId, final String isolatedPvlan, final PVlanType isolatedPvlanType, final NetworkOfferingVO ntwkOff, final PhysicalNetwork pNtwk, final ACLType aclType, final Account ownerFinal, |                                   final Boolean displayNetwork, final Long aclId, final String isolatedPvlan, final PVlanType isolatedPvlanType, final NetworkOffering ntwkOff, final PhysicalNetwork pNtwk, final ACLType aclType, final Account ownerFinal, | ||||||
|                                   final String cidr, final boolean createVlan, final String externalId, String routerIp, String routerIpv6, |                                   final String cidr, final boolean createVlan, final String externalId, String routerIp, String routerIpv6, | ||||||
|                                   final Network associatedNetwork, final String ip4Dns1, final String ip4Dns2, final String ip6Dns1, final String ip6Dns2, Pair<Integer, Integer> vrIfaceMTUs) throws InsufficientCapacityException, ResourceAllocationException { |                                   final Network associatedNetwork, final String ip4Dns1, final String ip4Dns2, final String ip6Dns1, final String ip6Dns2, Pair<Integer, Integer> vrIfaceMTUs) throws InsufficientCapacityException, ResourceAllocationException { | ||||||
|         try { |         try { | ||||||
| @ -2373,7 +2504,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (networkOfferingId != null) { |         if (networkOfferingId != null) { | ||||||
|             sc.addAnd("networkOfferingId", SearchCriteria.Op.EQ, networkOfferingId); |             sc.addAnd(NETWORK_OFFERING_ID, SearchCriteria.Op.EQ, networkOfferingId); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (associatedNetworkId != null) { |         if (associatedNetworkId != null) { | ||||||
| @ -2796,6 +2927,8 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C | |||||||
|         _accountMgr.checkAccess(callerAccount, AccessType.OperateEntry, true, network); |         _accountMgr.checkAccess(callerAccount, AccessType.OperateEntry, true, network); | ||||||
|         _accountMgr.checkAccess(_accountMgr.getActiveAccountById(network.getAccountId()), offering, _dcDao.findById(network.getDataCenterId())); |         _accountMgr.checkAccess(_accountMgr.getActiveAccountById(network.getAccountId()), offering, _dcDao.findById(network.getDataCenterId())); | ||||||
| 
 | 
 | ||||||
|  |         restartNetwork |= checkAndUpdateRouterSourceNatIp(cmd, network); | ||||||
|  | 
 | ||||||
|         if (cmd instanceof UpdateNetworkCmdByAdmin) { |         if (cmd instanceof UpdateNetworkCmdByAdmin) { | ||||||
|             final Boolean hideIpAddressUsage = ((UpdateNetworkCmdByAdmin) cmd).getHideIpAddressUsage(); |             final Boolean hideIpAddressUsage = ((UpdateNetworkCmdByAdmin) cmd).getHideIpAddressUsage(); | ||||||
|             if (hideIpAddressUsage != null) { |             if (hideIpAddressUsage != null) { | ||||||
| @ -2844,13 +2977,13 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C | |||||||
|         NetworkOfferingVO networkOffering = _networkOfferingDao.findById(networkOfferingId); |         NetworkOfferingVO networkOffering = _networkOfferingDao.findById(networkOfferingId); | ||||||
|         if (networkOfferingId != null) { |         if (networkOfferingId != null) { | ||||||
|             if (networkOffering == null || networkOffering.isSystemOnly()) { |             if (networkOffering == null || networkOffering.isSystemOnly()) { | ||||||
|                 throwInvalidIdException("Unable to find network offering with specified id", networkOfferingId.toString(), "networkOfferingId"); |                 throwInvalidIdException("Unable to find network offering with specified id", networkOfferingId.toString(), NETWORK_OFFERING_ID); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             // network offering should be in Enabled state |             // network offering should be in Enabled state | ||||||
|             if (networkOffering.getState() != NetworkOffering.State.Enabled) { |             if (networkOffering.getState() != NetworkOffering.State.Enabled) { | ||||||
|                 throwInvalidIdException("Network offering with specified id is not in " + NetworkOffering.State.Enabled + " state, can't upgrade to it", networkOffering.getUuid(), |                 throwInvalidIdException("Network offering with specified id is not in " + NetworkOffering.State.Enabled + " state, can't upgrade to it", networkOffering.getUuid(), | ||||||
|                         "networkOfferingId"); |                         NETWORK_OFFERING_ID); | ||||||
|             } |             } | ||||||
|             //can't update from vpc to non-vpc network offering |             //can't update from vpc to non-vpc network offering | ||||||
|             boolean forVpcNew = _configMgr.isOfferingForVpc(networkOffering); |             boolean forVpcNew = _configMgr.isOfferingForVpc(networkOffering); | ||||||
| @ -2893,10 +3026,8 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (checkAndUpdateNetworkDns(network, networkOfferingChanged ? networkOffering : oldNtwkOff, ip4Dns1, ip4Dns2, |         restartNetwork |= checkAndUpdateNetworkDns(network, networkOfferingChanged ? networkOffering : oldNtwkOff, ip4Dns1, ip4Dns2, | ||||||
|                 ip6Dns1, ip6Dns2)) { |                 ip6Dns1, ip6Dns2); | ||||||
|             restartNetwork = true; |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         final Map<String, String> newSvcProviders = networkOfferingChanged |         final Map<String, String> newSvcProviders = networkOfferingChanged | ||||||
|                 ? _networkMgr.finalizeServicesAndProvidersForNetwork(_entityMgr.findById(NetworkOffering.class, networkOfferingId), network.getPhysicalNetworkId()) |                 ? _networkMgr.finalizeServicesAndProvidersForNetwork(_entityMgr.findById(NetworkOffering.class, networkOfferingId), network.getPhysicalNetworkId()) | ||||||
| @ -3093,7 +3224,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C | |||||||
|             if (servicesNotInNewOffering != null && !servicesNotInNewOffering.isEmpty()) { |             if (servicesNotInNewOffering != null && !servicesNotInNewOffering.isEmpty()) { | ||||||
|                 _networkMgr.cleanupConfigForServicesInNetwork(servicesNotInNewOffering, network); |                 _networkMgr.cleanupConfigForServicesInNetwork(servicesNotInNewOffering, network); | ||||||
|             } |             } | ||||||
|         } catch (Throwable e) { |         } catch (Exception e) { // old pokemon catch that used to catch throwable | ||||||
|             s_logger.debug("failed to cleanup config related to unused services error:" + e.getMessage()); |             s_logger.debug("failed to cleanup config related to unused services error:" + e.getMessage()); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -3647,7 +3778,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C | |||||||
|         if (newNtwkOff == null || newNtwkOff.isSystemOnly()) { |         if (newNtwkOff == null || newNtwkOff.isSystemOnly()) { | ||||||
|             InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find network offering."); |             InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find network offering."); | ||||||
|             if (newNtwkOff != null) { |             if (newNtwkOff != null) { | ||||||
|                 ex.addProxyObject(String.valueOf(newNtwkOff.getId()), "networkOfferingId"); |                 ex.addProxyObject(String.valueOf(newNtwkOff.getId()), NETWORK_OFFERING_ID); | ||||||
|             } |             } | ||||||
|             throw ex; |             throw ex; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -53,7 +53,9 @@ import org.apache.cloudstack.api.command.user.vpc.CreateVPCCmd; | |||||||
| import org.apache.cloudstack.api.command.user.vpc.ListPrivateGatewaysCmd; | import org.apache.cloudstack.api.command.user.vpc.ListPrivateGatewaysCmd; | ||||||
| import org.apache.cloudstack.api.command.user.vpc.ListStaticRoutesCmd; | import org.apache.cloudstack.api.command.user.vpc.ListStaticRoutesCmd; | ||||||
| import org.apache.cloudstack.api.command.user.vpc.ListVPCOfferingsCmd; | import org.apache.cloudstack.api.command.user.vpc.ListVPCOfferingsCmd; | ||||||
|  | import org.apache.cloudstack.api.command.user.vpc.ListVPCsCmd; | ||||||
| import org.apache.cloudstack.api.command.user.vpc.RestartVPCCmd; | import org.apache.cloudstack.api.command.user.vpc.RestartVPCCmd; | ||||||
|  | import org.apache.cloudstack.api.command.user.vpc.UpdateVPCCmd; | ||||||
| import org.apache.cloudstack.context.CallContext; | import org.apache.cloudstack.context.CallContext; | ||||||
| import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; | import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; | ||||||
| import org.apache.cloudstack.framework.config.dao.ConfigurationDao; | import org.apache.cloudstack.framework.config.dao.ConfigurationDao; | ||||||
| @ -62,6 +64,7 @@ import org.apache.cloudstack.query.QueryService; | |||||||
| import org.apache.commons.collections.CollectionUtils; | import org.apache.commons.collections.CollectionUtils; | ||||||
| import org.apache.commons.lang3.ObjectUtils; | import org.apache.commons.lang3.ObjectUtils; | ||||||
| import org.apache.log4j.Logger; | import org.apache.log4j.Logger; | ||||||
|  | import org.jetbrains.annotations.Nullable; | ||||||
| import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||||
| import org.springframework.beans.factory.annotation.Qualifier; | import org.springframework.beans.factory.annotation.Qualifier; | ||||||
| 
 | 
 | ||||||
| @ -1017,7 +1020,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis | |||||||
|     @Override |     @Override | ||||||
|     @ActionEvent(eventType = EventTypes.EVENT_VPC_CREATE, eventDescription = "creating vpc", create = true) |     @ActionEvent(eventType = EventTypes.EVENT_VPC_CREATE, eventDescription = "creating vpc", create = true) | ||||||
|     public Vpc createVpc(final long zoneId, final long vpcOffId, final long vpcOwnerId, final String vpcName, final String displayText, final String cidr, String networkDomain, |     public Vpc createVpc(final long zoneId, final long vpcOffId, final long vpcOwnerId, final String vpcName, final String displayText, final String cidr, String networkDomain, | ||||||
|             final String ip4Dns1, final String ip4Dns2, final String ip6Dns1, final String ip6Dns2, final Boolean displayVpc, Integer publicMtu) throws ResourceAllocationException { |                          final String ip4Dns1, final String ip4Dns2, final String ip6Dns1, final String ip6Dns2, final Boolean displayVpc, Integer publicMtu) throws ResourceAllocationException { | ||||||
|         final Account caller = CallContext.current().getCallingAccount(); |         final Account caller = CallContext.current().getCallingAccount(); | ||||||
|         final Account owner = _accountMgr.getAccount(vpcOwnerId); |         final Account owner = _accountMgr.getAccount(vpcOwnerId); | ||||||
| 
 | 
 | ||||||
| @ -1091,6 +1094,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis | |||||||
|         final VpcVO vpc = new VpcVO(zoneId, vpcName, displayText, owner.getId(), owner.getDomainId(), vpcOffId, cidr, networkDomain, useDistributedRouter, isRegionLevelVpcOff, |         final VpcVO vpc = new VpcVO(zoneId, vpcName, displayText, owner.getId(), owner.getDomainId(), vpcOffId, cidr, networkDomain, useDistributedRouter, isRegionLevelVpcOff, | ||||||
|                 vpcOff.isRedundantRouter(), ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2); |                 vpcOff.isRedundantRouter(), ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2); | ||||||
|             vpc.setPublicMtu(publicMtu); |             vpc.setPublicMtu(publicMtu); | ||||||
|  |             vpc.setDisplay(Boolean.TRUE.equals(displayVpc)); | ||||||
| 
 | 
 | ||||||
|         return createVpc(displayVpc, vpc); |         return createVpc(displayVpc, vpc); | ||||||
|     } |     } | ||||||
| @ -1098,9 +1102,24 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis | |||||||
|     @Override |     @Override | ||||||
|     @ActionEvent(eventType = EventTypes.EVENT_VPC_CREATE, eventDescription = "creating vpc", create = true) |     @ActionEvent(eventType = EventTypes.EVENT_VPC_CREATE, eventDescription = "creating vpc", create = true) | ||||||
|     public Vpc createVpc(CreateVPCCmd cmd) throws ResourceAllocationException { |     public Vpc createVpc(CreateVPCCmd cmd) throws ResourceAllocationException { | ||||||
|         return createVpc(cmd.getZoneId(), cmd.getVpcOffering(), cmd.getEntityOwnerId(), cmd.getVpcName(), cmd.getDisplayText(), |         Vpc vpc = createVpc(cmd.getZoneId(), cmd.getVpcOffering(), cmd.getEntityOwnerId(), cmd.getVpcName(), cmd.getDisplayText(), | ||||||
|             cmd.getCidr(), cmd.getNetworkDomain(), cmd.getIp4Dns1(), cmd.getIp4Dns2(), cmd.getIp6Dns1(), |             cmd.getCidr(), cmd.getNetworkDomain(), cmd.getIp4Dns1(), cmd.getIp4Dns2(), cmd.getIp6Dns1(), | ||||||
|             cmd.getIp6Dns2(), cmd.isDisplay(), cmd.getPublicMtu()); |             cmd.getIp6Dns2(), cmd.isDisplay(), cmd.getPublicMtu()); | ||||||
|  |         // associate cmd.getSourceNatIP() with this vpc | ||||||
|  |         allocateSourceNatIp(vpc, cmd.getSourceNatIP()); | ||||||
|  |         return vpc; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void allocateSourceNatIp(Vpc vpc, String sourceNatIP) { | ||||||
|  |         Account account = _accountMgr.getAccount(vpc.getAccountId()); | ||||||
|  |         DataCenter zone = _dcDao.findById(vpc.getZoneId()); | ||||||
|  |         // reserve this ip and then | ||||||
|  |         try { | ||||||
|  |             IpAddress ip = _ipAddrMgr.allocateIp(account, false, CallContext.current().getCallingAccount(), CallContext.current().getCallingUserId(), zone, null, sourceNatIP); | ||||||
|  |             this.associateIPToVpc(ip.getId(), vpc.getId()); | ||||||
|  |         } catch (ResourceAllocationException | ResourceUnavailableException | InsufficientAddressCapacityException e){ | ||||||
|  |             throw new CloudRuntimeException("new source NAT address cannot be acquired", e); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @DB |     @DB | ||||||
| @ -1126,10 +1145,6 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis | |||||||
|         return Transaction.execute(new TransactionCallback<VpcVO>() { |         return Transaction.execute(new TransactionCallback<VpcVO>() { | ||||||
|             @Override |             @Override | ||||||
|             public VpcVO doInTransaction(final TransactionStatus status) { |             public VpcVO doInTransaction(final TransactionStatus status) { | ||||||
|                 if (displayVpc != null) { |  | ||||||
|                     vpc.setDisplay(displayVpc); |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 final VpcVO persistedVpc = vpcDao.persist(vpc, finalizeServicesAndProvidersForVpc(vpc.getZoneId(), vpc.getVpcOfferingId())); |                 final VpcVO persistedVpc = vpcDao.persist(vpc, finalizeServicesAndProvidersForVpc(vpc.getZoneId(), vpc.getVpcOfferingId())); | ||||||
|                 _resourceLimitMgr.incrementResourceCount(vpc.getAccountId(), ResourceType.vpc); |                 _resourceLimitMgr.incrementResourceCount(vpc.getAccountId(), ResourceType.vpc); | ||||||
|                 s_logger.debug("Created VPC " + persistedVpc); |                 s_logger.debug("Created VPC " + persistedVpc); | ||||||
| @ -1242,9 +1257,14 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @Override | ||||||
|  |     public Vpc updateVpc(UpdateVPCCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException { | ||||||
|  |         return updateVpc(cmd.getId(), cmd.getVpcName(), cmd.getDisplayText(), cmd.getCustomId(), cmd.isDisplayVpc(), cmd.getPublicMtu(), cmd.getSourceNatIP()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     @Override |     @Override | ||||||
|     @ActionEvent(eventType = EventTypes.EVENT_VPC_UPDATE, eventDescription = "updating vpc") |     @ActionEvent(eventType = EventTypes.EVENT_VPC_UPDATE, eventDescription = "updating vpc") | ||||||
|     public Vpc updateVpc(final long vpcId, final String vpcName, final String displayText, final String customId, final Boolean displayVpc, Integer mtu) { |     public Vpc updateVpc(final long vpcId, final String vpcName, final String displayText, final String customId, final Boolean displayVpc, Integer mtu, String sourceNatIp) throws ResourceUnavailableException, InsufficientCapacityException { | ||||||
|         CallContext.current().setEventDetails(" Id: " + vpcId); |         CallContext.current().setEventDetails(" Id: " + vpcId); | ||||||
|         final Account caller = CallContext.current().getCallingAccount(); |         final Account caller = CallContext.current().getCallingAccount(); | ||||||
| 
 | 
 | ||||||
| @ -1279,14 +1299,80 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis | |||||||
|             updateMtuOfVpcNetwork(vpcToUpdate, vpc, mtu); |             updateMtuOfVpcNetwork(vpcToUpdate, vpc, mtu); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (vpcDao.update(vpcId, vpc)) { |         boolean restartRequired = checkAndUpdateRouterSourceNatIp(vpcToUpdate, sourceNatIp); | ||||||
|  | 
 | ||||||
|  |         if (vpcDao.update(vpcId, vpc) || restartRequired) { // Note that the update may fail because nothing has changed, other than the sourcenat ip | ||||||
|             s_logger.debug("Updated VPC id=" + vpcId); |             s_logger.debug("Updated VPC id=" + vpcId); | ||||||
|  |             if (restartRequired) { | ||||||
|  |                 if (s_logger.isDebugEnabled()) { | ||||||
|  |                     s_logger.debug(String.format("restarting vpc %s/%s, due to changing sourcenat in Update VPC call", vpc.getName(), vpc.getUuid())); | ||||||
|  |                 } | ||||||
|  |                 final User callingUser = _accountMgr.getActiveUser(CallContext.current().getCallingUserId()); | ||||||
|  |                 restartVpc(vpcId, true, false, false, callingUser); | ||||||
|  |             } else { | ||||||
|  |                 if (s_logger.isDebugEnabled()) { | ||||||
|  |                     s_logger.debug("no restart needed."); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|             return vpcDao.findById(vpcId); |             return vpcDao.findById(vpcId); | ||||||
|         } else { |         } else { | ||||||
|  |             s_logger.error(String.format("failed to update vpc %s/%s",vpc.getName(), vpc.getUuid())); | ||||||
|             return null; |             return null; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     private boolean checkAndUpdateRouterSourceNatIp(Vpc vpc, String sourceNatIp) { | ||||||
|  |         IPAddressVO requestedIp = validateSourceNatip(vpc, sourceNatIp); | ||||||
|  |         if (requestedIp == null) return false; // ip not associated with this network | ||||||
|  | 
 | ||||||
|  |         List<IPAddressVO> userIps = _ipAddressDao.listByAssociatedVpc(vpc.getId(), true); | ||||||
|  |         if (! userIps.isEmpty()) { | ||||||
|  |             try { | ||||||
|  |                 _ipAddrMgr.updateSourceNatIpAddress(requestedIp, userIps); | ||||||
|  |             } catch (Exception e) { // pokemon exception from transaction | ||||||
|  |                 String msg = String.format("Update of source NAT ip to %s for network \"%s\"/%s failed due to %s", | ||||||
|  |                         requestedIp.getAddress().addr(), vpc.getName(), vpc.getUuid(), e.getLocalizedMessage()); | ||||||
|  |                 s_logger.error(msg); | ||||||
|  |                 throw new CloudRuntimeException(msg, e); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Nullable | ||||||
|  |     protected IPAddressVO validateSourceNatip(Vpc vpc, String sourceNatIp) { | ||||||
|  |         if (sourceNatIp == null) { | ||||||
|  |             s_logger.trace(String.format("no source NAT ip given to update vpc %s with.", vpc.getName())); | ||||||
|  |             return null; | ||||||
|  |         } else { | ||||||
|  |             s_logger.info(String.format("updating VPC %s to have source NAT ip %s", vpc.getName(), sourceNatIp)); | ||||||
|  |         } | ||||||
|  |         IPAddressVO requestedIp = getIpAddressVO(vpc, sourceNatIp); | ||||||
|  |         if (requestedIp == null) return null; | ||||||
|  |         // check if it is the current source NAT address | ||||||
|  |         if (requestedIp.isSourceNat()) { | ||||||
|  |             s_logger.info(String.format("IP address %s is already the source Nat address. Not updating!", sourceNatIp)); | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |         if (_firewallDao.countRulesByIpId(requestedIp.getId()) > 0) { | ||||||
|  |             s_logger.info(String.format("IP address %s has firewall/portforwarding rules. Not updating!", sourceNatIp)); | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |         return requestedIp; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Nullable | ||||||
|  |     private IPAddressVO getIpAddressVO(Vpc vpc, String sourceNatIp) { | ||||||
|  |         // check if the address is already aqcuired for this network | ||||||
|  |         IPAddressVO requestedIp = _ipAddressDao.findByIp(sourceNatIp); | ||||||
|  |         if (requestedIp == null || requestedIp.getVpcId() == null || ! requestedIp.getVpcId().equals(vpc.getId())) { | ||||||
|  |             s_logger.warn(String.format("Source NAT IP %s is not associated with network %s/%s. It cannot be used as source NAT IP.", | ||||||
|  |                     sourceNatIp, vpc.getName(), vpc.getUuid())); | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |         return requestedIp; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     protected Integer validateMtu(VpcVO vpcToUpdate, Integer mtu) { |     protected Integer validateMtu(VpcVO vpcToUpdate, Integer mtu) { | ||||||
|         Long zoneId = vpcToUpdate.getZoneId(); |         Long zoneId = vpcToUpdate.getZoneId(); | ||||||
|         if (mtu == null || NetworkService.AllowUsersToSpecifyVRMtu.valueIn(zoneId)) { |         if (mtu == null || NetworkService.AllowUsersToSpecifyVRMtu.valueIn(zoneId)) { | ||||||
| @ -1373,6 +1459,13 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis | |||||||
|         return success; |         return success; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @Override | ||||||
|  |     public Pair<List<? extends Vpc>, Integer> listVpcs(ListVPCsCmd cmd) { | ||||||
|  |         return listVpcs(cmd.getId(), cmd.getVpcName(), cmd.getDisplayText(), cmd.getSupportedServices(), cmd.getCidr(), cmd.getVpcOffId(), | ||||||
|  |                 cmd.getState(), cmd.getAccountName(), cmd.getDomainId(), cmd.getKeyword(), cmd.getStartIndex(), cmd.getPageSizeVal(), | ||||||
|  |                 cmd.getZoneId(), cmd.isRecursive(), cmd.listAll(), cmd.getRestartRequired(), cmd.getTags(), cmd.getProjectId(), | ||||||
|  |                 cmd.getDisplay()); | ||||||
|  |     } | ||||||
|     @Override |     @Override | ||||||
|     public Pair<List<? extends Vpc>, Integer> listVpcs(final Long id, final String vpcName, final String displayText, final List<String> supportedServicesStr, final String cidr, |     public Pair<List<? extends Vpc>, Integer> listVpcs(final Long id, final String vpcName, final String displayText, final List<String> supportedServicesStr, final String cidr, | ||||||
|                                                        final Long vpcOffId, final String state, final String accountName, Long domainId, final String keyword, final Long startIndex, final Long pageSizeVal, |                                                        final Long vpcOffId, final String state, final String accountName, Long domainId, final String keyword, final Long startIndex, final Long pageSizeVal, | ||||||
| @ -1476,7 +1569,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis | |||||||
|         final boolean listBySupportedServices = supportedServicesStr != null && !supportedServicesStr.isEmpty() && !vpcs.isEmpty(); |         final boolean listBySupportedServices = supportedServicesStr != null && !supportedServicesStr.isEmpty() && !vpcs.isEmpty(); | ||||||
| 
 | 
 | ||||||
|         if (listBySupportedServices) { |         if (listBySupportedServices) { | ||||||
|             final List<VpcVO> supportedVpcs = new ArrayList<VpcVO>(); |             final List<Vpc> supportedVpcs = new ArrayList<>(); | ||||||
|             Service[] supportedServices = null; |             Service[] supportedServices = null; | ||||||
| 
 | 
 | ||||||
|             if (listBySupportedServices) { |             if (listBySupportedServices) { | ||||||
| @ -1501,22 +1594,20 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis | |||||||
| 
 | 
 | ||||||
|             final List<? extends Vpc> wPagination = StringUtils.applyPagination(supportedVpcs, startIndex, pageSizeVal); |             final List<? extends Vpc> wPagination = StringUtils.applyPagination(supportedVpcs, startIndex, pageSizeVal); | ||||||
|             if (wPagination != null) { |             if (wPagination != null) { | ||||||
|                 final Pair<List<? extends Vpc>, Integer> listWPagination = new Pair<List<? extends Vpc>, Integer>(wPagination, supportedVpcs.size()); |                 return new Pair<>(wPagination, supportedVpcs.size()); | ||||||
|                 return listWPagination; |  | ||||||
|             } |             } | ||||||
|             return new Pair<List<? extends Vpc>, Integer>(supportedVpcs, supportedVpcs.size()); |             return new Pair<>(supportedVpcs, supportedVpcs.size()); | ||||||
|         } else { |         } else { | ||||||
|             final List<? extends Vpc> wPagination = StringUtils.applyPagination(vpcs, startIndex, pageSizeVal); |             final List<? extends Vpc> wPagination = StringUtils.applyPagination(vpcs, startIndex, pageSizeVal); | ||||||
|             if (wPagination != null) { |             if (wPagination != null) { | ||||||
|                 final Pair<List<? extends Vpc>, Integer> listWPagination = new Pair<List<? extends Vpc>, Integer>(wPagination, vpcs.size()); |                 return new Pair<>(wPagination, vpcs.size()); | ||||||
|                 return listWPagination; |  | ||||||
|             } |             } | ||||||
|             return new Pair<List<? extends Vpc>, Integer>(vpcs, vpcs.size()); |             return new Pair<>(vpcs, vpcs.size()); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected List<Service> getSupportedServices() { |     protected List<Service> getSupportedServices() { | ||||||
|         final List<Service> services = new ArrayList<Service>(); |         final List<Service> services = new ArrayList<>(); | ||||||
|         services.add(Network.Service.Dhcp); |         services.add(Network.Service.Dhcp); | ||||||
|         services.add(Network.Service.Dns); |         services.add(Network.Service.Dns); | ||||||
|         services.add(Network.Service.UserData); |         services.add(Network.Service.UserData); | ||||||
|  | |||||||
| @ -37,6 +37,7 @@ import java.util.HashMap; | |||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| import java.util.Random; | import java.util.Random; | ||||||
|  | import java.util.Set; | ||||||
| import java.util.UUID; | import java.util.UUID; | ||||||
| 
 | 
 | ||||||
| import org.apache.cloudstack.api.command.admin.network.CreateGuestNetworkIpv6PrefixCmd; | import org.apache.cloudstack.api.command.admin.network.CreateGuestNetworkIpv6PrefixCmd; | ||||||
| @ -547,16 +548,68 @@ public class ConfigurationManagerTest { | |||||||
|         assertThat(configurationMgr.searchForNetworkOfferings(cmd).second(), is(2)); |         assertThat(configurationMgr.searchForNetworkOfferings(cmd).second(), is(2)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @Test | ||||||
|  |     public void validateEmptySourceNatServiceCapablitiesTest() { | ||||||
|  |         Map<Capability, String> sourceNatServiceCapabilityMap = new HashMap<>(); | ||||||
|  | 
 | ||||||
|  |         configurationMgr.validateSourceNatServiceCapablities(sourceNatServiceCapabilityMap); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void validateInvalidSourceNatTypeForSourceNatServiceCapablitiesTest() { | ||||||
|  |         Map<Capability, String> sourceNatServiceCapabilityMap = new HashMap<>(); | ||||||
|  |         sourceNatServiceCapabilityMap.put(Capability.SupportedSourceNatTypes, "perDomain"); | ||||||
|  | 
 | ||||||
|  |         boolean caught = false; | ||||||
|  |         try { | ||||||
|  |             configurationMgr.validateSourceNatServiceCapablities(sourceNatServiceCapabilityMap); | ||||||
|  |         } catch (InvalidParameterValueException e) { | ||||||
|  |             Assert.assertTrue(e.getMessage(), e.getMessage().contains("Either peraccount or perzone source NAT type can be specified for SupportedSourceNatTypes")); | ||||||
|  |             caught = true; | ||||||
|  |         } | ||||||
|  |         Assert.assertTrue("should not be accepted", caught); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void validateInvalidBooleanValueForSourceNatServiceCapablitiesTest() { | ||||||
|  |         Map<Capability, String> sourceNatServiceCapabilityMap = new HashMap<>(); | ||||||
|  |         sourceNatServiceCapabilityMap.put(Capability.RedundantRouter, "maybe"); | ||||||
|  | 
 | ||||||
|  |         boolean caught = false; | ||||||
|  |         try { | ||||||
|  |             configurationMgr.validateSourceNatServiceCapablities(sourceNatServiceCapabilityMap); | ||||||
|  |         } catch (InvalidParameterValueException e) { | ||||||
|  |             Assert.assertTrue(e.getMessage(), e.getMessage().contains("Unknown specified value for RedundantRouter")); | ||||||
|  |             caught = true; | ||||||
|  |         } | ||||||
|  |         Assert.assertTrue("should not be accepted", caught); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void validateInvalidCapabilityForSourceNatServiceCapablitiesTest() { | ||||||
|  |         Map<Capability, String> sourceNatServiceCapabilityMap = new HashMap<>(); | ||||||
|  |         sourceNatServiceCapabilityMap.put(Capability.ElasticIp, "perDomain"); | ||||||
|  | 
 | ||||||
|  |         boolean caught = false; | ||||||
|  |         try { | ||||||
|  |             configurationMgr.validateSourceNatServiceCapablities(sourceNatServiceCapabilityMap); | ||||||
|  |         } catch (InvalidParameterValueException e) { | ||||||
|  |             Assert.assertTrue(e.getMessage(), e.getMessage().contains("Only SupportedSourceNatTypes, Network.Capability[name=RedundantRouter] capabilities can be specified for source nat service")); | ||||||
|  |             caught = true; | ||||||
|  |         } | ||||||
|  |         Assert.assertTrue("should not be accepted", caught); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void validateEmptyStaticNatServiceCapablitiesTest() { |     public void validateEmptyStaticNatServiceCapablitiesTest() { | ||||||
|         Map<Capability, String> staticNatServiceCapabilityMap = new HashMap<Capability, String>(); |         Map<Capability, String> staticNatServiceCapabilityMap = new HashMap<>(); | ||||||
| 
 | 
 | ||||||
|         configurationMgr.validateStaticNatServiceCapablities(staticNatServiceCapabilityMap); |         configurationMgr.validateStaticNatServiceCapablities(staticNatServiceCapabilityMap); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void validateInvalidStaticNatServiceCapablitiesTest() { |     public void validateInvalidStaticNatServiceCapablitiesTest() { | ||||||
|         Map<Capability, String> staticNatServiceCapabilityMap = new HashMap<Capability, String>(); |         Map<Capability, String> staticNatServiceCapabilityMap = new HashMap<>(); | ||||||
|         staticNatServiceCapabilityMap.put(Capability.AssociatePublicIP, "Frue and Talse"); |         staticNatServiceCapabilityMap.put(Capability.AssociatePublicIP, "Frue and Talse"); | ||||||
| 
 | 
 | ||||||
|         boolean caught = false; |         boolean caught = false; | ||||||
| @ -569,9 +622,43 @@ public class ConfigurationManagerTest { | |||||||
|         Assert.assertTrue("should not be accepted", caught); |         Assert.assertTrue("should not be accepted", caught); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @Test | ||||||
|  |     public void isRedundantRouter() { | ||||||
|  |         Map<Network.Service, Set<Network.Provider>> serviceCapabilityMap = new HashMap<>(); | ||||||
|  |         Map<Capability, String> sourceNatServiceCapabilityMap = new HashMap<>(); | ||||||
|  |         sourceNatServiceCapabilityMap.put(Capability.SupportedSourceNatTypes, "peraccount"); | ||||||
|  |         sourceNatServiceCapabilityMap.put(Capability.RedundantRouter, "true"); | ||||||
|  |         Assert.assertTrue(configurationMgr.isRedundantRouter(serviceCapabilityMap, sourceNatServiceCapabilityMap)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void isSharedSourceNat() { | ||||||
|  |         Map<Network.Service, Set<Network.Provider>> serviceCapabilityMap = new HashMap<>(); | ||||||
|  |         Map<Capability, String> sourceNatServiceCapabilityMap = new HashMap<>(); | ||||||
|  |         sourceNatServiceCapabilityMap.put(Capability.SupportedSourceNatTypes, "perzone"); | ||||||
|  |         Assert.assertTrue(configurationMgr.isSharedSourceNat(serviceCapabilityMap, sourceNatServiceCapabilityMap)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void isNotSharedSourceNat() { | ||||||
|  |         Map<Network.Service, Set<Network.Provider>> serviceCapabilityMap = new HashMap<>(); | ||||||
|  |         Map<Capability, String> sourceNatServiceCapabilityMap = new HashMap<>(); | ||||||
|  |         sourceNatServiceCapabilityMap.put(Capability.SupportedSourceNatTypes, "peraccount"); | ||||||
|  |         Assert.assertFalse(configurationMgr.isSharedSourceNat(serviceCapabilityMap, sourceNatServiceCapabilityMap)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void sourceNatCapabilitiesContainValidValues() { | ||||||
|  |         Map<Capability, String> sourceNatServiceCapabilityMap = new HashMap<>(); | ||||||
|  |         sourceNatServiceCapabilityMap.put(Capability.SupportedSourceNatTypes, "peraccount"); | ||||||
|  |         sourceNatServiceCapabilityMap.put(Capability.RedundantRouter, "True"); | ||||||
|  | 
 | ||||||
|  |         Assert.assertTrue(configurationMgr.sourceNatCapabilitiesContainValidValues(sourceNatServiceCapabilityMap)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void validateTTStaticNatServiceCapablitiesTest() { |     public void validateTTStaticNatServiceCapablitiesTest() { | ||||||
|         Map<Capability, String> staticNatServiceCapabilityMap = new HashMap<Capability, String>(); |         Map<Capability, String> staticNatServiceCapabilityMap = new HashMap<>(); | ||||||
|         staticNatServiceCapabilityMap.put(Capability.AssociatePublicIP, "true and Talse"); |         staticNatServiceCapabilityMap.put(Capability.AssociatePublicIP, "true and Talse"); | ||||||
|         staticNatServiceCapabilityMap.put(Capability.ElasticIp, "True"); |         staticNatServiceCapabilityMap.put(Capability.ElasticIp, "True"); | ||||||
| 
 | 
 | ||||||
| @ -580,7 +667,7 @@ public class ConfigurationManagerTest { | |||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void validateFTStaticNatServiceCapablitiesTest() { |     public void validateFTStaticNatServiceCapablitiesTest() { | ||||||
|         Map<Capability, String> staticNatServiceCapabilityMap = new HashMap<Capability, String>(); |         Map<Capability, String> staticNatServiceCapabilityMap = new HashMap<>(); | ||||||
|         staticNatServiceCapabilityMap.put(Capability.AssociatePublicIP, "false"); |         staticNatServiceCapabilityMap.put(Capability.AssociatePublicIP, "false"); | ||||||
|         staticNatServiceCapabilityMap.put(Capability.ElasticIp, "True"); |         staticNatServiceCapabilityMap.put(Capability.ElasticIp, "True"); | ||||||
| 
 | 
 | ||||||
| @ -589,7 +676,7 @@ public class ConfigurationManagerTest { | |||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void validateTFStaticNatServiceCapablitiesTest() { |     public void validateTFStaticNatServiceCapablitiesTest() { | ||||||
|         Map<Capability, String> staticNatServiceCapabilityMap = new HashMap<Capability, String>(); |         Map<Capability, String> staticNatServiceCapabilityMap = new HashMap<>(); | ||||||
|         staticNatServiceCapabilityMap.put(Capability.AssociatePublicIP, "true and Talse"); |         staticNatServiceCapabilityMap.put(Capability.AssociatePublicIP, "true and Talse"); | ||||||
|         staticNatServiceCapabilityMap.put(Capability.ElasticIp, "false"); |         staticNatServiceCapabilityMap.put(Capability.ElasticIp, "false"); | ||||||
| 
 | 
 | ||||||
| @ -608,7 +695,7 @@ public class ConfigurationManagerTest { | |||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void validateFFStaticNatServiceCapablitiesTest() { |     public void validateFFStaticNatServiceCapablitiesTest() { | ||||||
|         Map<Capability, String> staticNatServiceCapabilityMap = new HashMap<Capability, String>(); |         Map<Capability, String> staticNatServiceCapabilityMap = new HashMap<>(); | ||||||
|         staticNatServiceCapabilityMap.put(Capability.AssociatePublicIP, "false"); |         staticNatServiceCapabilityMap.put(Capability.AssociatePublicIP, "false"); | ||||||
|         staticNatServiceCapabilityMap.put(Capability.ElasticIp, "False"); |         staticNatServiceCapabilityMap.put(Capability.ElasticIp, "False"); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -23,11 +23,13 @@ import static org.mockito.Matchers.anyLong; | |||||||
| import static org.mockito.Mockito.doReturn; | import static org.mockito.Mockito.doReturn; | ||||||
| import static org.mockito.Mockito.lenient; | import static org.mockito.Mockito.lenient; | ||||||
| import static org.mockito.Mockito.mock; | import static org.mockito.Mockito.mock; | ||||||
|  | import static org.mockito.Mockito.verify; | ||||||
| import static org.mockito.Mockito.when; | import static org.mockito.Mockito.when; | ||||||
| 
 | 
 | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.Collections; | import java.util.Collections; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  | import java.util.Vector; | ||||||
| 
 | 
 | ||||||
| import com.cloud.user.Account; | import com.cloud.user.Account; | ||||||
| import org.junit.Assert; | import org.junit.Assert; | ||||||
| @ -230,4 +232,14 @@ public class IpAddressManagerTest { | |||||||
|         return network; |         return network; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @Test | ||||||
|  |     public void updateSourceNatIpAddress() throws Exception { | ||||||
|  |         IPAddressVO requestedIp = Mockito.mock(IPAddressVO.class); | ||||||
|  |         IPAddressVO oldIp = Mockito.mock(IPAddressVO.class); | ||||||
|  |         List<IPAddressVO> userIps = new Vector<>(); | ||||||
|  |         userIps.add(oldIp); | ||||||
|  |         ipAddressManager.updateSourceNatIpAddress(requestedIp, userIps); | ||||||
|  |         verify(requestedIp).setSourceNat(true); | ||||||
|  |         verify(oldIp).setSourceNat(false); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -17,8 +17,10 @@ | |||||||
| package com.cloud.network; | package com.cloud.network; | ||||||
| 
 | 
 | ||||||
| import static org.mockito.ArgumentMatchers.any; | import static org.mockito.ArgumentMatchers.any; | ||||||
|  | import static org.mockito.ArgumentMatchers.anyBoolean; | ||||||
| import static org.mockito.ArgumentMatchers.anyLong; | import static org.mockito.ArgumentMatchers.anyLong; | ||||||
| import static org.mockito.ArgumentMatchers.anyString; | import static org.mockito.ArgumentMatchers.anyString; | ||||||
|  | import static org.mockito.ArgumentMatchers.eq; | ||||||
| import static org.mockito.ArgumentMatchers.nullable; | import static org.mockito.ArgumentMatchers.nullable; | ||||||
| import static org.mockito.Mockito.lenient; | import static org.mockito.Mockito.lenient; | ||||||
| import static org.mockito.Mockito.mock; | import static org.mockito.Mockito.mock; | ||||||
| @ -34,6 +36,7 @@ import java.util.List; | |||||||
| import java.util.Map; | import java.util.Map; | ||||||
| import java.util.UUID; | import java.util.UUID; | ||||||
| 
 | 
 | ||||||
|  | import com.cloud.exception.InsufficientAddressCapacityException; | ||||||
| import org.apache.cloudstack.alert.AlertService; | import org.apache.cloudstack.alert.AlertService; | ||||||
| import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd; | import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd; | ||||||
| import org.apache.cloudstack.api.command.user.network.UpdateNetworkCmd; | import org.apache.cloudstack.api.command.user.network.UpdateNetworkCmd; | ||||||
| @ -81,7 +84,6 @@ import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; | |||||||
| import com.cloud.org.Grouping; | import com.cloud.org.Grouping; | ||||||
| import com.cloud.user.Account; | import com.cloud.user.Account; | ||||||
| import com.cloud.user.AccountManager; | import com.cloud.user.AccountManager; | ||||||
| import com.cloud.user.AccountManagerImpl; |  | ||||||
| import com.cloud.user.AccountService; | import com.cloud.user.AccountService; | ||||||
| import com.cloud.user.AccountVO; | import com.cloud.user.AccountVO; | ||||||
| import com.cloud.user.User; | import com.cloud.user.User; | ||||||
| @ -122,8 +124,6 @@ public class NetworkServiceImplTest { | |||||||
|     @Mock |     @Mock | ||||||
|     NetworkOfferingServiceMapDao networkOfferingServiceMapDao; |     NetworkOfferingServiceMapDao networkOfferingServiceMapDao; | ||||||
|     @Mock |     @Mock | ||||||
|     AccountManager accountMgr; |  | ||||||
|     @Mock |  | ||||||
|     EntityManager entityMgr; |     EntityManager entityMgr; | ||||||
|     @Mock |     @Mock | ||||||
|     NetworkService networkService; |     NetworkService networkService; | ||||||
| @ -162,8 +162,8 @@ public class NetworkServiceImplTest { | |||||||
|     @Mock |     @Mock | ||||||
|     ServiceOfferingVO serviceOfferingVoMock; |     ServiceOfferingVO serviceOfferingVoMock; | ||||||
| 
 | 
 | ||||||
|     @InjectMocks |     @Mock | ||||||
|     AccountManagerImpl accountManagerImpl; |     IpAddressManager ipAddressManager; | ||||||
|     @Mock |     @Mock | ||||||
|     ConfigKey<Integer> privateMtuKey; |     ConfigKey<Integer> privateMtuKey; | ||||||
|     @Mock |     @Mock | ||||||
| @ -223,7 +223,7 @@ public class NetworkServiceImplTest { | |||||||
|         service._networkOfferingDao = networkOfferingDao; |         service._networkOfferingDao = networkOfferingDao; | ||||||
|         service._physicalNetworkDao = physicalNetworkDao; |         service._physicalNetworkDao = physicalNetworkDao; | ||||||
|         service._dcDao = dcDao; |         service._dcDao = dcDao; | ||||||
|         service._accountMgr = accountMgr; |         service._accountMgr = accountManager; | ||||||
|         service._networkMgr = networkManager; |         service._networkMgr = networkManager; | ||||||
|         service.alertManager = alertManager; |         service.alertManager = alertManager; | ||||||
|         service._configMgr = configMgr; |         service._configMgr = configMgr; | ||||||
| @ -236,6 +236,7 @@ public class NetworkServiceImplTest { | |||||||
|         service.routerDao = routerDao; |         service.routerDao = routerDao; | ||||||
|         service.commandSetupHelper = commandSetupHelper; |         service.commandSetupHelper = commandSetupHelper; | ||||||
|         service.networkHelper = networkHelper; |         service.networkHelper = networkHelper; | ||||||
|  |         service._ipAddrMgr = ipAddressManager; | ||||||
|         PowerMockito.mockStatic(CallContext.class); |         PowerMockito.mockStatic(CallContext.class); | ||||||
|         CallContext callContextMock = PowerMockito.mock(CallContext.class); |         CallContext callContextMock = PowerMockito.mock(CallContext.class); | ||||||
|         PowerMockito.when(CallContext.current()).thenReturn(callContextMock); |         PowerMockito.when(CallContext.current()).thenReturn(callContextMock); | ||||||
| @ -248,8 +249,8 @@ public class NetworkServiceImplTest { | |||||||
|         Mockito.when(networkOfferingDao.findById(1L)).thenReturn(offering); |         Mockito.when(networkOfferingDao.findById(1L)).thenReturn(offering); | ||||||
|         Mockito.when(physicalNetworkDao.findById(Mockito.anyLong())).thenReturn(phyNet); |         Mockito.when(physicalNetworkDao.findById(Mockito.anyLong())).thenReturn(phyNet); | ||||||
|         Mockito.when(dcDao.findById(Mockito.anyLong())).thenReturn(dc); |         Mockito.when(dcDao.findById(Mockito.anyLong())).thenReturn(dc); | ||||||
|         Mockito.lenient().doNothing().when(accountMgr).checkAccess(accountMock, networkOffering, dc); |         Mockito.lenient().doNothing().when(accountManager).checkAccess(accountMock, networkOffering, dc); | ||||||
|         Mockito.when(accountMgr.isRootAdmin(accountMock.getId())).thenReturn(true); |         Mockito.when(accountManager.isRootAdmin(accountMock.getId())).thenReturn(true); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
| @ -352,6 +353,7 @@ public class NetworkServiceImplTest { | |||||||
|         ReflectionTestUtils.setField(createNetworkCmd, "privateMtu", privateMtu); |         ReflectionTestUtils.setField(createNetworkCmd, "privateMtu", privateMtu); | ||||||
|         ReflectionTestUtils.setField(createNetworkCmd, "physicalNetworkId", null); |         ReflectionTestUtils.setField(createNetworkCmd, "physicalNetworkId", null); | ||||||
|         Mockito.when(offering.isSystemOnly()).thenReturn(false); |         Mockito.when(offering.isSystemOnly()).thenReturn(false); | ||||||
|  |         Mockito.when(dc.getId()).thenReturn(1L); | ||||||
|         Mockito.when(dc.getAllocationState()).thenReturn(Grouping.AllocationState.Enabled); |         Mockito.when(dc.getAllocationState()).thenReturn(Grouping.AllocationState.Enabled); | ||||||
|         Map<String, String> networkProvidersMap = new HashMap<String, String>(); |         Map<String, String> networkProvidersMap = new HashMap<String, String>(); | ||||||
|         Mockito.when(networkManager.finalizeServicesAndProvidersForNetwork(ArgumentMatchers.any(NetworkOffering.class), anyLong())).thenReturn(networkProvidersMap); |         Mockito.when(networkManager.finalizeServicesAndProvidersForNetwork(ArgumentMatchers.any(NetworkOffering.class), anyLong())).thenReturn(networkProvidersMap); | ||||||
| @ -409,6 +411,7 @@ public class NetworkServiceImplTest { | |||||||
|         ReflectionTestUtils.setField(createNetworkCmd, "privateMtu", privateMtu); |         ReflectionTestUtils.setField(createNetworkCmd, "privateMtu", privateMtu); | ||||||
|         ReflectionTestUtils.setField(createNetworkCmd, "physicalNetworkId", null); |         ReflectionTestUtils.setField(createNetworkCmd, "physicalNetworkId", null); | ||||||
|         ReflectionTestUtils.setField(createNetworkCmd, "vpcId", 1L); |         ReflectionTestUtils.setField(createNetworkCmd, "vpcId", 1L); | ||||||
|  |         Mockito.when(dc.getId()).thenReturn(1L); | ||||||
|         Mockito.when(configMgr.isOfferingForVpc(offering)).thenReturn(true); |         Mockito.when(configMgr.isOfferingForVpc(offering)).thenReturn(true); | ||||||
|         Mockito.when(vpcDao.findById(anyLong())).thenReturn(vpc); |         Mockito.when(vpcDao.findById(anyLong())).thenReturn(vpc); | ||||||
| 
 | 
 | ||||||
| @ -562,7 +565,7 @@ public class NetworkServiceImplTest { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Test(expected = InvalidParameterValueException.class) |     @Test(expected = CloudRuntimeException.class) | ||||||
|     public void testCreateNetworkDnsOfferingServiceFailure() { |     public void testCreateNetworkDnsOfferingServiceFailure() { | ||||||
|         registerCallContext(); |         registerCallContext(); | ||||||
|         CreateNetworkCmd cmd = Mockito.mock(CreateNetworkCmd.class); |         CreateNetworkCmd cmd = Mockito.mock(CreateNetworkCmd.class); | ||||||
| @ -577,7 +580,7 @@ public class NetworkServiceImplTest { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Test(expected = InvalidParameterValueException.class) |     @Test(expected = CloudRuntimeException.class) | ||||||
|     public void testCreateIp4NetworkIp6DnsFailure() { |     public void testCreateIp4NetworkIp6DnsFailure() { | ||||||
|         registerCallContext(); |         registerCallContext(); | ||||||
|         CreateNetworkCmd cmd = Mockito.mock(CreateNetworkCmd.class); |         CreateNetworkCmd cmd = Mockito.mock(CreateNetworkCmd.class); | ||||||
| @ -770,4 +773,143 @@ public class NetworkServiceImplTest { | |||||||
| 
 | 
 | ||||||
|         networkServiceImplMock.validateIfServiceOfferingIsActiveAndSystemVmTypeIsDomainRouter(1l); |         networkServiceImplMock.validateIfServiceOfferingIsActiveAndSystemVmTypeIsDomainRouter(1l); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void validateNotSharedNetworkRouterIPv4() { | ||||||
|  |         NetworkOffering ntwkOff = Mockito.mock(NetworkOffering.class); | ||||||
|  |         when(ntwkOff.getGuestType()).thenReturn(Network.GuestType.L2); | ||||||
|  |         service.validateSharedNetworkRouterIPs(null, null, null, null, null, null, null, null, null, ntwkOff); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void validateSharedNetworkRouterIPs() { | ||||||
|  |         String startIP = "10.0.16.2"; | ||||||
|  |         String endIP = "10.0.16.100"; | ||||||
|  |         String routerIPv4 = "10.0.16.100"; | ||||||
|  |         String routerPv6 = "fd17:ac56:1234:2000::fb"; | ||||||
|  |         String startIPv6 = "fd17:ac56:1234:2000::1"; | ||||||
|  |         String endIPv6 = "fd17:ac56:1234:2000::fc"; | ||||||
|  |         NetworkOffering ntwkOff = Mockito.mock(NetworkOffering.class); | ||||||
|  |         when(ntwkOff.getGuestType()).thenReturn(Network.GuestType.Shared); | ||||||
|  |         service.validateSharedNetworkRouterIPs(IP4_GATEWAY, startIP, endIP, IP4_NETMASK, routerIPv4, routerPv6, startIPv6, endIPv6, IP6_CIDR, ntwkOff); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void validateSharedNetworkWrongRouterIPv4() { | ||||||
|  |         String startIP = "10.0.16.2"; | ||||||
|  |         String endIP = "10.0.16.100"; | ||||||
|  |         String routerIPv4 = "10.0.16.101"; | ||||||
|  |         String routerPv6 = "fd17:ac56:1234:2000::fb"; | ||||||
|  |         String startIPv6 = "fd17:ac56:1234:2000::1"; | ||||||
|  |         String endIPv6 = "fd17:ac56:1234:2000::fc"; | ||||||
|  |         NetworkOffering ntwkOff = Mockito.mock(NetworkOffering.class); | ||||||
|  |         when(ntwkOff.getGuestType()).thenReturn(Network.GuestType.Shared); | ||||||
|  |         boolean passing = false; | ||||||
|  |         try { | ||||||
|  |             service.validateSharedNetworkRouterIPs(IP4_GATEWAY, startIP, endIP, IP4_NETMASK, routerIPv4, routerPv6, startIPv6, endIPv6, IP6_CIDR, ntwkOff); | ||||||
|  |         } catch (CloudRuntimeException e) { | ||||||
|  |             Assert.assertTrue(e.getMessage().contains("Router IPv4 IP provided is not within the specified range: ")); | ||||||
|  |             passing = true; | ||||||
|  |         } | ||||||
|  |         Assert.assertTrue(passing); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void validateSharedNetworkNoEndOfIPv6Range() { | ||||||
|  |         String startIP = null; | ||||||
|  |         String endIP = null; | ||||||
|  |         String routerIPv4 = null; | ||||||
|  |         String routerPv6 = "fd17:ac56:1234:2000::1"; | ||||||
|  |         String startIPv6 = "fd17:ac56:1234:2000::1"; | ||||||
|  |         String endIPv6 = null; | ||||||
|  |         NetworkOffering ntwkOff = Mockito.mock(NetworkOffering.class); | ||||||
|  |         when(ntwkOff.getGuestType()).thenReturn(Network.GuestType.Shared); | ||||||
|  |         service.validateSharedNetworkRouterIPs(IP4_GATEWAY, startIP, endIP, IP4_NETMASK, routerIPv4, routerPv6, startIPv6, endIPv6, IP6_CIDR, ntwkOff); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void validateSharedNetworkIPv6RouterNotInRange() { | ||||||
|  |         String routerIPv4 = null; | ||||||
|  |         String routerIPv6 = "fd17:ac56:1234:2001::1"; | ||||||
|  |         NetworkOffering ntwkOff = Mockito.mock(NetworkOffering.class); | ||||||
|  |         when(ntwkOff.getGuestType()).thenReturn(Network.GuestType.Shared); | ||||||
|  |         boolean passing = true; | ||||||
|  |         try { | ||||||
|  |             service.validateSharedNetworkRouterIPs(IP4_GATEWAY, null, null, IP4_NETMASK, routerIPv4, routerIPv6, null, null, IP6_CIDR, ntwkOff); | ||||||
|  |             passing = false; | ||||||
|  |         } catch (CloudRuntimeException e) { | ||||||
|  |             Assert.assertTrue(e.getMessage().contains("Router IPv6 address provided is not with the network range")); | ||||||
|  |         } | ||||||
|  |         Assert.assertTrue(passing); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void invalidateSharedNetworkIPv6RouterAddress() { | ||||||
|  |         String routerIPv6 = "fd17:ac56:1234:2000::fg"; | ||||||
|  |         NetworkOffering ntwkOff = Mockito.mock(NetworkOffering.class); | ||||||
|  |         when(ntwkOff.getGuestType()).thenReturn(Network.GuestType.Shared); | ||||||
|  |         boolean passing = false; | ||||||
|  |         try { | ||||||
|  |             service.validateSharedNetworkRouterIPs(IP4_GATEWAY, null, null, IP4_NETMASK, null, routerIPv6, null, null, IP6_CIDR, ntwkOff); | ||||||
|  |         } catch (CloudRuntimeException e) { | ||||||
|  |             Assert.assertTrue(e.getMessage().contains("Router IPv6 address provided is of incorrect format")); | ||||||
|  |             passing = true; | ||||||
|  |         } | ||||||
|  |         Assert.assertTrue(passing); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void invalidateSharedNetworkIPv4RouterAddress() { | ||||||
|  |         String routerIPv4 = "10.100.1000.1"; | ||||||
|  |         NetworkOffering ntwkOff = Mockito.mock(NetworkOffering.class); | ||||||
|  |         when(ntwkOff.getGuestType()).thenReturn(Network.GuestType.Shared); | ||||||
|  |         boolean passing = false; | ||||||
|  |         try { | ||||||
|  |             service.validateSharedNetworkRouterIPs(IP4_GATEWAY, null, null, IP4_NETMASK, routerIPv4, null, null, null, IP6_CIDR, ntwkOff); | ||||||
|  |         } catch (CloudRuntimeException e) { | ||||||
|  |             Assert.assertTrue(e.getMessage().contains("Router IPv4 IP provided is of incorrect format")); | ||||||
|  |             passing = true; | ||||||
|  |         } | ||||||
|  |         Assert.assertTrue(passing); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void checkAndDontSetSourceNatIp() { | ||||||
|  |         CreateNetworkCmd cmd = new CreateNetworkCmd(); | ||||||
|  |         try { | ||||||
|  |             service.checkAndSetRouterSourceNatIp(account, cmd, null); | ||||||
|  |         } catch (InsufficientAddressCapacityException | ResourceAllocationException e) { | ||||||
|  |             Assert.fail(e.getMessage()); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void checkAndSetSourceNatIp() { | ||||||
|  |         String srcNatIp = "10.100.1000.10000"; | ||||||
|  |         Long networkOfferingId = 2l; | ||||||
|  |         Long zoneId = 3l; | ||||||
|  |         registerCallContext(); | ||||||
|  |         ReflectionTestUtils.setField(createNetworkCmd, "networkOfferingId", networkOfferingId); | ||||||
|  |         ReflectionTestUtils.setField(createNetworkCmd, "sourceNatIP", srcNatIp); | ||||||
|  |         ReflectionTestUtils.setField(createNetworkCmd, "zoneId", zoneId); | ||||||
|  |         ReflectionTestUtils.setField(createNetworkCmd, "physicalNetworkId", null); | ||||||
|  |         NetworkVO networkVO = Mockito.spy(NetworkVO.class); | ||||||
|  |         IpAddress ipAddress = Mockito.mock(IPAddressVO.class); | ||||||
|  |         NetworkOffering ntwkOff = Mockito.mock(NetworkOffering.class); | ||||||
|  |         Long networkId = 7l; | ||||||
|  |         when(networkVO.getId()).thenReturn(networkId); | ||||||
|  |         when(networkVO.getGuestType()).thenReturn(Network.GuestType.Isolated); | ||||||
|  |         when(networkDao.findById(networkId)).thenReturn(networkVO); | ||||||
|  |         when(entityMgr.findById(NetworkOffering.class, networkOfferingId)).thenReturn(ntwkOff); | ||||||
|  |         when(entityMgr.findById(eq(DataCenter.class), anyLong())).thenReturn(dc); | ||||||
|  |         when(ipAddress.getId()).thenReturn(5l); | ||||||
|  |         when(networkVO.getId()).thenReturn(networkId); | ||||||
|  |         when(networkVO.getGuestType()).thenReturn(Network.GuestType.Isolated); | ||||||
|  |         try { | ||||||
|  |             when(ipAddressManager.allocateIp(any(), anyBoolean(), any(), anyLong(), any(), any(), eq(srcNatIp))).thenReturn(ipAddress); | ||||||
|  |             service.checkAndSetRouterSourceNatIp(account, createNetworkCmd, networkVO); | ||||||
|  |         } catch (InsufficientAddressCapacityException | ResourceAllocationException e) { | ||||||
|  |             Assert.fail(e.getMessage()); | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -42,8 +42,10 @@ import java.util.UUID; | |||||||
| 
 | 
 | ||||||
| import com.cloud.alert.AlertManager; | import com.cloud.alert.AlertManager; | ||||||
| import com.cloud.network.NetworkService; | import com.cloud.network.NetworkService; | ||||||
|  | import com.cloud.network.dao.FirewallRulesDao; | ||||||
| import org.apache.cloudstack.acl.SecurityChecker; | import org.apache.cloudstack.acl.SecurityChecker; | ||||||
| import org.apache.cloudstack.alert.AlertService; | import org.apache.cloudstack.alert.AlertService; | ||||||
|  | import org.apache.cloudstack.api.command.user.vpc.UpdateVPCCmd; | ||||||
| import org.apache.cloudstack.context.CallContext; | import org.apache.cloudstack.context.CallContext; | ||||||
| import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; | import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; | ||||||
| import org.junit.After; | import org.junit.After; | ||||||
| @ -149,6 +151,8 @@ public class VpcManagerImplTest { | |||||||
|     AlertManager alertManager; |     AlertManager alertManager; | ||||||
|     @Mock |     @Mock | ||||||
|     NetworkService networkServiceMock; |     NetworkService networkServiceMock; | ||||||
|  |     @Mock | ||||||
|  |     FirewallRulesDao firewallDao; | ||||||
| 
 | 
 | ||||||
|     public static final long ACCOUNT_ID = 1; |     public static final long ACCOUNT_ID = 1; | ||||||
|     private AccountVO account; |     private AccountVO account; | ||||||
| @ -200,6 +204,7 @@ public class VpcManagerImplTest { | |||||||
|         manager._vpcOffDao = vpcOfferingDao; |         manager._vpcOffDao = vpcOfferingDao; | ||||||
|         manager._dcDao = dataCenterDao; |         manager._dcDao = dataCenterDao; | ||||||
|         manager._ntwkSvc = networkServiceMock; |         manager._ntwkSvc = networkServiceMock; | ||||||
|  |         manager._firewallDao = firewallDao; | ||||||
|         CallContext.register(Mockito.mock(User.class), Mockito.mock(Account.class)); |         CallContext.register(Mockito.mock(User.class), Mockito.mock(Account.class)); | ||||||
|         registerCallContext(); |         registerCallContext(); | ||||||
|     } |     } | ||||||
| @ -354,9 +359,10 @@ public class VpcManagerImplTest { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void testUpdateVpcNetwork() throws ResourceUnavailableException { |     public void testUpdateVpcNetwork() throws ResourceUnavailableException, InsufficientCapacityException { | ||||||
|         long vpcId = 1L; |         long vpcId = 1L; | ||||||
|         Integer publicMtu = 1450; |         Integer publicMtu = 1450; | ||||||
|  |         String sourceNatIp = "1.2.3.4"; | ||||||
|         Account accountMock = Mockito.mock(Account.class); |         Account accountMock = Mockito.mock(Account.class); | ||||||
|         VpcVO vpcVO = new VpcVO(); |         VpcVO vpcVO = new VpcVO(); | ||||||
| 
 | 
 | ||||||
| @ -398,9 +404,31 @@ public class VpcManagerImplTest { | |||||||
|         Mockito.when(networkDao.update(anyLong(), any())).thenReturn(true); |         Mockito.when(networkDao.update(anyLong(), any())).thenReturn(true); | ||||||
|         Mockito.when(vpcDao.update(vpcId, vpcVO)).thenReturn(true); |         Mockito.when(vpcDao.update(vpcId, vpcVO)).thenReturn(true); | ||||||
| 
 | 
 | ||||||
|         manager.updateVpc(vpcId, null, null, null, true, publicMtu); |         UpdateVPCCmd cmd = Mockito.mock(UpdateVPCCmd.class); | ||||||
|         Assert.assertEquals(publicMtu, vpcVO.getPublicMtu()); |         Mockito.when(cmd.getId()).thenReturn(vpcId); | ||||||
|  |         Mockito.when(cmd.getVpcName()).thenReturn(null); | ||||||
|  |         Mockito.when(cmd.getDisplayText()).thenReturn(null); | ||||||
|  |         Mockito.when(cmd.getCustomId()).thenReturn(null); | ||||||
|  |         Mockito.when(cmd.isDisplayVpc()).thenReturn(true); | ||||||
|  |         Mockito.when(cmd.getPublicMtu()).thenReturn(publicMtu); | ||||||
|  |         Mockito.when(cmd.getSourceNatIP()).thenReturn(sourceNatIp); | ||||||
| 
 | 
 | ||||||
|  |         manager.updateVpc(cmd); | ||||||
|  |         Assert.assertEquals(publicMtu, vpcVO.getPublicMtu()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void verifySourceNatIp() { | ||||||
|  |         String sourceNatIp = "1.2.3.4"; | ||||||
|  |         VpcVO vpcVO = Mockito.mock(VpcVO.class); //new VpcVO(1l, "vpc", null, 10l, 1l, 1l, "10.1.0.0/16", null, false, false, false, null, null, null, null); | ||||||
|  |         Mockito.when(vpcVO.getId()).thenReturn(1l); | ||||||
|  |         IPAddressVO requestedIp = Mockito.mock(IPAddressVO.class);//new IPAddressVO(new Ip(sourceNatIp), 1l, 1l, 1l, true); | ||||||
|  |         Mockito.when(ipAddressDao.findByIp(sourceNatIp)).thenReturn(requestedIp); | ||||||
|  |         Mockito.when(requestedIp.getVpcId()).thenReturn(1l); | ||||||
|  |         Mockito.when(requestedIp.getVpcId()).thenReturn(1l); | ||||||
|  |         Mockito.when(firewallDao.countRulesByIpId(1l)).thenReturn(0l); | ||||||
|  |         Assert.assertNull(manager.validateSourceNatip(vpcVO, null)); | ||||||
|  |         Assert.assertEquals(requestedIp, manager.validateSourceNatip(vpcVO, sourceNatIp)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|  | |||||||
| @ -72,9 +72,6 @@ logger.addHandler(stream_handler) | |||||||
| 
 | 
 | ||||||
| class TestPublicIP(cloudstackTestCase): | class TestPublicIP(cloudstackTestCase): | ||||||
| 
 | 
 | ||||||
|     def setUp(self): |  | ||||||
|         self.apiclient = self.testClient.getApiClient() |  | ||||||
| 
 |  | ||||||
|     @classmethod |     @classmethod | ||||||
|     def setUpClass(cls): |     def setUpClass(cls): | ||||||
|         testClient = super(TestPublicIP, cls).getClsTestClient() |         testClient = super(TestPublicIP, cls).getClsTestClient() | ||||||
| @ -85,6 +82,7 @@ class TestPublicIP(cloudstackTestCase): | |||||||
|         cls.domain = get_domain(cls.apiclient) |         cls.domain = get_domain(cls.apiclient) | ||||||
|         cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests()) |         cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests()) | ||||||
|         cls.services['mode'] = cls.zone.networktype |         cls.services['mode'] = cls.zone.networktype | ||||||
|  |         cls._cleanup = [] | ||||||
|         # Create Accounts & networks |         # Create Accounts & networks | ||||||
|         cls.account = Account.create( |         cls.account = Account.create( | ||||||
|             cls.apiclient, |             cls.apiclient, | ||||||
| @ -92,18 +90,21 @@ class TestPublicIP(cloudstackTestCase): | |||||||
|             admin=True, |             admin=True, | ||||||
|             domainid=cls.domain.id |             domainid=cls.domain.id | ||||||
|         ) |         ) | ||||||
|  |         cls._cleanup.append(cls.account) | ||||||
| 
 | 
 | ||||||
|         cls.user = Account.create( |         cls.user = Account.create( | ||||||
|             cls.apiclient, |             cls.apiclient, | ||||||
|             cls.services["account"], |             cls.services["account"], | ||||||
|             domainid=cls.domain.id |             domainid=cls.domain.id | ||||||
|         ) |         ) | ||||||
|  |         cls._cleanup.append(cls.user) | ||||||
|         cls.services["network"]["zoneid"] = cls.zone.id |         cls.services["network"]["zoneid"] = cls.zone.id | ||||||
| 
 | 
 | ||||||
|         cls.network_offering = NetworkOffering.create( |         cls.network_offering = NetworkOffering.create( | ||||||
|             cls.apiclient, |             cls.apiclient, | ||||||
|             cls.services["network_offering"], |             cls.services["network_offering"], | ||||||
|         ) |         ) | ||||||
|  |         cls._cleanup.append(cls.network_offering) | ||||||
|         # Enable Network offering |         # Enable Network offering | ||||||
|         cls.network_offering.update(cls.apiclient, state='Enabled') |         cls.network_offering.update(cls.apiclient, state='Enabled') | ||||||
| 
 | 
 | ||||||
| @ -114,17 +115,20 @@ class TestPublicIP(cloudstackTestCase): | |||||||
|             cls.account.name, |             cls.account.name, | ||||||
|             cls.account.domainid |             cls.account.domainid | ||||||
|         ) |         ) | ||||||
|  |         cls._cleanup.append(cls.account_network) | ||||||
|         cls.user_network = Network.create( |         cls.user_network = Network.create( | ||||||
|             cls.apiclient, |             cls.apiclient, | ||||||
|             cls.services["network"], |             cls.services["network"], | ||||||
|             cls.user.name, |             cls.user.name, | ||||||
|             cls.user.domainid |             cls.user.domainid | ||||||
|         ) |         ) | ||||||
|  |         cls._cleanup.append(cls.user_network) | ||||||
| 
 | 
 | ||||||
|         cls.service_offering = ServiceOffering.create( |         cls.service_offering = ServiceOffering.create( | ||||||
|             cls.apiclient, |             cls.apiclient, | ||||||
|             cls.services["service_offerings"]["tiny"], |             cls.services["service_offerings"]["tiny"], | ||||||
|         ) |         ) | ||||||
|  |         cls._cleanup.append(cls.service_offering) | ||||||
| 
 | 
 | ||||||
|         cls.hypervisor = testClient.getHypervisorInfo() |         cls.hypervisor = testClient.getHypervisorInfo() | ||||||
|         cls.template = get_test_template( |         cls.template = get_test_template( | ||||||
| @ -146,6 +150,7 @@ class TestPublicIP(cloudstackTestCase): | |||||||
|             networkids=cls.account_network.id, |             networkids=cls.account_network.id, | ||||||
|             serviceofferingid=cls.service_offering.id |             serviceofferingid=cls.service_offering.id | ||||||
|         ) |         ) | ||||||
|  |         cls._cleanup.append(cls.account_vm) | ||||||
| 
 | 
 | ||||||
|         cls.user_vm = VirtualMachine.create( |         cls.user_vm = VirtualMachine.create( | ||||||
|             cls.apiclient, |             cls.apiclient, | ||||||
| @ -156,6 +161,7 @@ class TestPublicIP(cloudstackTestCase): | |||||||
|             networkids=cls.user_network.id, |             networkids=cls.user_network.id, | ||||||
|             serviceofferingid=cls.service_offering.id |             serviceofferingid=cls.service_offering.id | ||||||
|         ) |         ) | ||||||
|  |         cls._cleanup.append(cls.user_vm) | ||||||
| 
 | 
 | ||||||
|         # Create Source NAT IP addresses |         # Create Source NAT IP addresses | ||||||
|         PublicIPAddress.create( |         PublicIPAddress.create( | ||||||
| @ -170,25 +176,11 @@ class TestPublicIP(cloudstackTestCase): | |||||||
|             cls.zone.id, |             cls.zone.id, | ||||||
|             cls.user.domainid |             cls.user.domainid | ||||||
|         ) |         ) | ||||||
|         cls._cleanup = [ |  | ||||||
|             cls.account_vm, |  | ||||||
|             cls.user_vm, |  | ||||||
|             cls.account_network, |  | ||||||
|             cls.user_network, |  | ||||||
|             cls.account, |  | ||||||
|             cls.user, |  | ||||||
|             cls.network_offering |  | ||||||
|         ] |  | ||||||
|         return |         return | ||||||
| 
 | 
 | ||||||
|     @classmethod |     @classmethod | ||||||
|     def tearDownClass(cls): |     def tearDownClass(cls): | ||||||
|         try: |         super(TestPublicIP, cls).tearDownClass() | ||||||
|             # Cleanup resources used |  | ||||||
|             cleanup_resources(cls.apiclient, cls._cleanup) |  | ||||||
|         except Exception as e: |  | ||||||
|             raise Exception("Warning: Exception during cleanup : %s" % e) |  | ||||||
|         return |  | ||||||
| 
 | 
 | ||||||
|     @attr(tags=["advanced", "advancedns", "smoke", "dvs"], required_hardware="false") |     @attr(tags=["advanced", "advancedns", "smoke", "dvs"], required_hardware="false") | ||||||
|     def test_public_ip_admin_account(self): |     def test_public_ip_admin_account(self): | ||||||
|  | |||||||
							
								
								
									
										274
									
								
								test/integration/smoke/test_set_sourcenat.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										274
									
								
								test/integration/smoke/test_set_sourcenat.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,274 @@ | |||||||
|  | # Licensed to the Apache Software Foundation (ASF) under one | ||||||
|  | # 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. | ||||||
|  | """ BVT tests for Network Life Cycle | ||||||
|  | """ | ||||||
|  | # Import Local Modules | ||||||
|  | from marvin.codes import (FAILED, STATIC_NAT_RULE, LB_RULE, | ||||||
|  |                           NAT_RULE, PASS) | ||||||
|  | from marvin.cloudstackTestCase import cloudstackTestCase | ||||||
|  | from marvin.lib.base import (Account, | ||||||
|  |                              VPC, | ||||||
|  |                              VpcOffering, | ||||||
|  |                              ServiceOffering, | ||||||
|  |                              PublicIPAddress, | ||||||
|  |                              Network, | ||||||
|  |                              NetworkOffering) | ||||||
|  | from marvin.lib.common import (get_domain, | ||||||
|  |                                get_free_vlan, | ||||||
|  |                                get_zone, | ||||||
|  |                                get_template, | ||||||
|  |                                get_test_template, | ||||||
|  |                                list_publicIP) | ||||||
|  | 
 | ||||||
|  | from nose.plugins.attrib import attr | ||||||
|  | # Import System modules | ||||||
|  | import time | ||||||
|  | import logging | ||||||
|  | 
 | ||||||
|  | _multiprocess_shared_ = True | ||||||
|  | 
 | ||||||
|  | logger = logging.getLogger('TestSetSourceNatIp') | ||||||
|  | stream_handler = logging.StreamHandler() | ||||||
|  | logger.setLevel(logging.DEBUG) | ||||||
|  | logger.addHandler(stream_handler) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestSetSourceNatIp(cloudstackTestCase): | ||||||
|  | 
 | ||||||
|  |     @classmethod | ||||||
|  |     def setUpClass(cls): | ||||||
|  |         testClient = super(TestSetSourceNatIp, cls).getClsTestClient() | ||||||
|  |         cls.apiclient = testClient.getApiClient() | ||||||
|  |         cls.services = testClient.getParsedTestDataConfig() | ||||||
|  | 
 | ||||||
|  |         # Get Zone, Domain and templates | ||||||
|  |         cls.domain = get_domain(cls.apiclient) | ||||||
|  |         cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests()) | ||||||
|  |         cls.services['mode'] = cls.zone.networktype | ||||||
|  |         cls._cleanup = [] | ||||||
|  |         # Create Accounts & networks | ||||||
|  |         cls.account = Account.create( | ||||||
|  |             cls.apiclient, | ||||||
|  |             cls.services["account"], | ||||||
|  |             admin=True, | ||||||
|  |             domainid=cls.domain.id | ||||||
|  |         ) | ||||||
|  |         cls._cleanup.append(cls.account) | ||||||
|  | 
 | ||||||
|  |         cls.services["network"]["zoneid"] = cls.zone.id | ||||||
|  | 
 | ||||||
|  |         cls.vpc_offering = VpcOffering.create( | ||||||
|  |             cls.apiclient, | ||||||
|  |             cls.services["vpc_offering"], | ||||||
|  |         ) | ||||||
|  |         cls._cleanup.append(cls.vpc_offering) | ||||||
|  |         cls.vpc_offering.update(cls.apiclient, state='Enabled') | ||||||
|  |         cls.services["vpc"]["vpcoffering"] = cls.vpc_offering.id | ||||||
|  | 
 | ||||||
|  |         cls.network_offering = NetworkOffering.create( | ||||||
|  |             cls.apiclient, | ||||||
|  |             cls.services["network_offering"], | ||||||
|  |         ) | ||||||
|  |         cls._cleanup.append(cls.network_offering) | ||||||
|  |         # Enable Network offering | ||||||
|  |         cls.network_offering.update(cls.apiclient, state='Enabled') | ||||||
|  | 
 | ||||||
|  |         cls.services["network"]["networkoffering"] = cls.network_offering.id | ||||||
|  | 
 | ||||||
|  |         cls.service_offering = ServiceOffering.create( | ||||||
|  |             cls.apiclient, | ||||||
|  |             cls.services["service_offerings"]["tiny"], | ||||||
|  |         ) | ||||||
|  |         cls._cleanup.append(cls.service_offering) | ||||||
|  | 
 | ||||||
|  |         cls.hypervisor = testClient.getHypervisorInfo() | ||||||
|  |         cls.template = get_test_template( | ||||||
|  |             cls.apiclient, | ||||||
|  |             cls.zone.id, | ||||||
|  |             cls.hypervisor | ||||||
|  |         ) | ||||||
|  |         if cls.template == FAILED: | ||||||
|  |             assert False, "get_test_template() failed to return template" | ||||||
|  | 
 | ||||||
|  |         cls.services["virtual_machine"]["zoneid"] = cls.zone.id | ||||||
|  |         network = Network.create( | ||||||
|  |             cls.apiclient, | ||||||
|  |             cls.services["network"], | ||||||
|  |             cls.account.name, | ||||||
|  |             cls.account.domainid | ||||||
|  |         ) | ||||||
|  |         cls._cleanup.append(network) | ||||||
|  |         ip_address = PublicIPAddress.create( | ||||||
|  |             cls.apiclient, | ||||||
|  |             cls.account.name, | ||||||
|  |             cls.zone.id, | ||||||
|  |             cls.account.domainid | ||||||
|  |         ) | ||||||
|  |         cls._cleanup.append(ip_address) | ||||||
|  |         cls.ip_to_want = ip_address.ipaddress.ipaddress | ||||||
|  |         cls.debug(f'==== my local ip: {cls.ip_to_want}') | ||||||
|  |         ip_address.delete(cls.apiclient) | ||||||
|  |         cls._cleanup.remove(ip_address) | ||||||
|  |         network.delete(cls.apiclient) | ||||||
|  |         cls._cleanup.remove(network) | ||||||
|  |         return | ||||||
|  | 
 | ||||||
|  |     @classmethod | ||||||
|  |     def tearDownClass(cls): | ||||||
|  |         super(TestSetSourceNatIp, cls).tearDownClass() | ||||||
|  | 
 | ||||||
|  |     def setUp(self): | ||||||
|  |         self.cleanup = [] | ||||||
|  | 
 | ||||||
|  |     def tearDown(self): | ||||||
|  |         super(TestSetSourceNatIp, self).tearDown() | ||||||
|  | 
 | ||||||
|  |     @attr(tags=["advanced", "advancedns", "smoke"], required_hardware="false") | ||||||
|  |     def test_01_create_network_with_specified_source_nat_ip_address(self): | ||||||
|  |         """ | ||||||
|  |         For creation of network witjh a specified address | ||||||
|  |         """ | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         self.services["network"]["networkoffering"] = self.network_offering.id | ||||||
|  |         network = Network.create( | ||||||
|  |             self.apiclient, | ||||||
|  |             self.services["network"], | ||||||
|  |             self.account.name, | ||||||
|  |             self.account.domainid, | ||||||
|  |             sourcenatipaddress = self.ip_to_want | ||||||
|  |         ) | ||||||
|  |         self.cleanup.append(network) | ||||||
|  | 
 | ||||||
|  |         self.validate_source_nat(network=network, ip=self.ip_to_want) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     @attr(tags=["advanced", "advancedns", "smoke"], required_hardware="false") | ||||||
|  |     def test_02_change_source_nat_ip_address_for_network(self): | ||||||
|  |         """ | ||||||
|  |         Test changing a networks source NAT IP address | ||||||
|  |         """ | ||||||
|  |         network = Network.create( | ||||||
|  |             self.apiclient, | ||||||
|  |             self.services["network"], | ||||||
|  |             self.account.name, | ||||||
|  |             self.account.domainid, | ||||||
|  |             sourcenatipaddress = self.ip_to_want | ||||||
|  |         ) | ||||||
|  |         self.cleanup.append(network) | ||||||
|  |         second_ip = PublicIPAddress.create( | ||||||
|  |             self.apiclient, | ||||||
|  |             self.account.name, | ||||||
|  |             self.zone.id, | ||||||
|  |             self.account.domainid, | ||||||
|  |             networkid=network.id | ||||||
|  |         ) | ||||||
|  |         self.cleanup.append(second_ip) | ||||||
|  |         self.debug(f'==== second ip: {second_ip.ipaddress.ipaddress}') | ||||||
|  | 
 | ||||||
|  |         self.validate_source_nat(network=network, ip=self.ip_to_want) | ||||||
|  | 
 | ||||||
|  |         network.update(self.apiclient, sourcenatipaddress=second_ip.ipaddress.ipaddress) | ||||||
|  | 
 | ||||||
|  |         self.validate_source_nat(network=network, ip=second_ip.ipaddress.ipaddress) | ||||||
|  | 
 | ||||||
|  |         return | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     @attr(tags=["advanced", "advancedns", "smoke"], required_hardware="false") | ||||||
|  |     def test_03_create_vpc_with_specified_source_nat_ip_address(self): | ||||||
|  |         """ | ||||||
|  |         Test for creation of a VPC with a specified address | ||||||
|  |         """ | ||||||
|  | 
 | ||||||
|  |         vpc = VPC.create( | ||||||
|  |             self.apiclient, | ||||||
|  |             self.services["vpc"], | ||||||
|  |             self.vpc_offering.id, | ||||||
|  |             self.zone.id, | ||||||
|  |             sourcenatipaddress = self.ip_to_want | ||||||
|  |         ) | ||||||
|  |         self.cleanup.append(vpc) | ||||||
|  | 
 | ||||||
|  |         self.validate_source_nat(vpc=vpc, ip=self.ip_to_want) | ||||||
|  | 
 | ||||||
|  |     @attr(tags=["advanced", "advancedns", "smoke"], required_hardware="false") | ||||||
|  |     def test_04_change_source_nat_ip_address_for_vpc(self): | ||||||
|  |         """ | ||||||
|  |         Test changing a networks source NAT IP address | ||||||
|  |         """ | ||||||
|  |         vpc = VPC.create( | ||||||
|  |             self.apiclient, | ||||||
|  |             self.services["vpc"], | ||||||
|  |             self.vpc_offering.id, | ||||||
|  |             self.zone.id, | ||||||
|  |             account=self.account.name, | ||||||
|  |             domainid = self.account.domainid, | ||||||
|  |             sourcenatipaddress = self.ip_to_want | ||||||
|  |         ) | ||||||
|  |         self.cleanup.append(vpc) | ||||||
|  |         second_ip = PublicIPAddress.create( | ||||||
|  |             self.apiclient, | ||||||
|  |             self.account.name, | ||||||
|  |             self.zone.id, | ||||||
|  |             self.account.domainid, | ||||||
|  |             vpcid=vpc.id | ||||||
|  |         ) | ||||||
|  |         self.debug(f'==== second ip: {second_ip.ipaddress.ipaddress}') | ||||||
|  | 
 | ||||||
|  |         self.validate_source_nat(vpc=vpc, ip=self.ip_to_want) | ||||||
|  | 
 | ||||||
|  |         vpc.update(self.apiclient, sourcenatipaddress=second_ip.ipaddress.ipaddress) | ||||||
|  | 
 | ||||||
|  |         self.validate_source_nat(vpc=vpc, ip=second_ip.ipaddress.ipaddress) | ||||||
|  | 
 | ||||||
|  |         return | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     def validate_source_nat(self, network=None, vpc=None, ip=None): | ||||||
|  |         list_pub_ip_addr_resp = None | ||||||
|  |         if network: | ||||||
|  |             list_pub_ip_addr_resp = list_publicIP( | ||||||
|  |                 self.apiclient, | ||||||
|  |                 associatednetworkid=network.id, | ||||||
|  |                 listall=True, | ||||||
|  |                 issourcenat=True | ||||||
|  |             ) | ||||||
|  |         elif vpc: | ||||||
|  |             list_pub_ip_addr_resp = list_publicIP( | ||||||
|  |                 self.apiclient, | ||||||
|  |                 vpc=vpc.id, | ||||||
|  |                 listall=True, | ||||||
|  |                 issourcenat=True | ||||||
|  |             ) | ||||||
|  |         self.assertEqual( | ||||||
|  |             isinstance(list_pub_ip_addr_resp, list), | ||||||
|  |             True, | ||||||
|  |             "Check list response returns a valid list" | ||||||
|  |         ) | ||||||
|  |         self.assertNotEqual( | ||||||
|  |             len(list_pub_ip_addr_resp), | ||||||
|  |             0, | ||||||
|  |             "Check if new IP Address is associated" | ||||||
|  |         ) | ||||||
|  |         self.debug(f'==== my result {list_pub_ip_addr_resp[0]}') | ||||||
|  |         self.assertEqual( | ||||||
|  |             list_pub_ip_addr_resp[0].ipaddress, | ||||||
|  |             ip, | ||||||
|  |             f"Check Correct IP Address is returned in the List, expected {ip} but got {list_pub_ip_addr_resp[0].ipaddress}" | ||||||
|  |         ) | ||||||
| @ -3485,7 +3485,8 @@ class Network: | |||||||
|                networkofferingid=None, projectid=None, |                networkofferingid=None, projectid=None, | ||||||
|                subdomainaccess=None, zoneid=None, |                subdomainaccess=None, zoneid=None, | ||||||
|                gateway=None, netmask=None, vpcid=None, aclid=None, vlan=None, |                gateway=None, netmask=None, vpcid=None, aclid=None, vlan=None, | ||||||
|                externalid=None, bypassvlanoverlapcheck=None, associatednetworkid=None, publicmtu=None, privatemtu=None): |                externalid=None, bypassvlanoverlapcheck=None, associatednetworkid=None, publicmtu=None, privatemtu=None, | ||||||
|  |                sourcenatipaddress=None): | ||||||
|         """Create Network for account""" |         """Create Network for account""" | ||||||
|         cmd = createNetwork.createNetworkCmd() |         cmd = createNetwork.createNetworkCmd() | ||||||
|         cmd.name = services["name"] |         cmd.name = services["name"] | ||||||
| @ -3567,6 +3568,8 @@ class Network: | |||||||
|             cmd.publicmtu = publicmtu |             cmd.publicmtu = publicmtu | ||||||
|         if privatemtu: |         if privatemtu: | ||||||
|             cmd.privatemtu = privatemtu |             cmd.privatemtu = privatemtu | ||||||
|  |         if sourcenatipaddress: | ||||||
|  |             cmd.sourcenatipaddress = sourcenatipaddress | ||||||
|         return Network(apiclient.createNetwork(cmd).__dict__) |         return Network(apiclient.createNetwork(cmd).__dict__) | ||||||
| 
 | 
 | ||||||
|     def delete(self, apiclient): |     def delete(self, apiclient): | ||||||
|  | |||||||
| @ -1578,6 +1578,8 @@ | |||||||
| "label.shared": "Κοινόχρηστο", | "label.shared": "Κοινόχρηστο", | ||||||
| "label.sharedexecutable": "Κοινόχρηστο", | "label.sharedexecutable": "Κοινόχρηστο", | ||||||
| "label.sharedmountpoint": "Κοινόχρηστο μέσο", | "label.sharedmountpoint": "Κοινόχρηστο μέσο", | ||||||
|  | "label.sharedrouterip": "Διεύθυνση IPv4 του δρομολογητή στο κοινόχρηστο δίκτυο ", | ||||||
|  | "label.sharedrouteripv6": "Διεύθυνση IPv6 του δρομολογητή στο κοινόχρηστο δίκτυο", | ||||||
| "label.sharewith": "Κοινή χρήση με", | "label.sharewith": "Κοινή χρήση με", | ||||||
| "label.showing": "Προβολή", | "label.showing": "Προβολή", | ||||||
| "label.shrinkok": "Συρρίκνωση OK", | "label.shrinkok": "Συρρίκνωση OK", | ||||||
|  | |||||||
| @ -165,6 +165,7 @@ | |||||||
| "label.action.router.health.checks": "Get health checks result", | "label.action.router.health.checks": "Get health checks result", | ||||||
| "label.action.run.diagnostics": "Run diagnostics", | "label.action.run.diagnostics": "Run diagnostics", | ||||||
| "label.action.secure.host": "Provision host security keys", | "label.action.secure.host": "Provision host security keys", | ||||||
|  | "label.action.set.as.source.nat.ip": "make source NAT", | ||||||
| "label.action.setup.2FA.user.auth": "Setup User Two Factor Authentication", | "label.action.setup.2FA.user.auth": "Setup User Two Factor Authentication", | ||||||
| "label.action.start.instance": "Start instance", | "label.action.start.instance": "Start instance", | ||||||
| "label.action.start.router": "Start router", | "label.action.start.router": "Start router", | ||||||
| @ -915,6 +916,7 @@ | |||||||
| "label.haenable": "HA enabled", | "label.haenable": "HA enabled", | ||||||
| "label.haprovider": "HA provider", | "label.haprovider": "HA provider", | ||||||
| "label.hardware": "Hardware", | "label.hardware": "Hardware", | ||||||
|  | "label.hasrules":"FW rules defined", | ||||||
| "label.hastate": "HA state", | "label.hastate": "HA state", | ||||||
| "label.header.backup.schedule": "You can set up recurring backup schedules by selecting from the available options below and applying your policy preference.", | "label.header.backup.schedule": "You can set up recurring backup schedules by selecting from the available options below and applying your policy preference.", | ||||||
| "label.header.volume.snapshot": "You can set up recurring snapshot schedules by selecting from the available options below and applying your policy preference.", | "label.header.volume.snapshot": "You can set up recurring snapshot schedules by selecting from the available options below and applying your policy preference.", | ||||||
| @ -1668,8 +1670,8 @@ | |||||||
| "label.router.health.check.success": "Success", | "label.router.health.check.success": "Success", | ||||||
| "label.router.health.checks": "Health checks", | "label.router.health.checks": "Health checks", | ||||||
| "label.routercount": "Total of virtual routers", | "label.routercount": "Total of virtual routers", | ||||||
| "label.routerip": "IPv4 address for the VR in this shared network.", | "label.routerip": "IPv4 address for the VR in this network.", | ||||||
| "label.routeripv6": "IPv6 address for the VR in this shared network.", | "label.routeripv6": "IPv6 address for the VR in this network.", | ||||||
| "label.resourcegroup": "Resource group", | "label.resourcegroup": "Resource group", | ||||||
| "label.routing.policy": "Routing policy", | "label.routing.policy": "Routing policy", | ||||||
| "label.routing.policy.terms": "Routing policy terms", | "label.routing.policy.terms": "Routing policy terms", | ||||||
| @ -1775,6 +1777,8 @@ | |||||||
| "label.shared": "Shared", | "label.shared": "Shared", | ||||||
| "label.sharedexecutable": "Shared", | "label.sharedexecutable": "Shared", | ||||||
| "label.sharedmountpoint": "SharedMountPoint", | "label.sharedmountpoint": "SharedMountPoint", | ||||||
|  | "label.sharedrouterip": "IPv4 address for the VR in this shared network.", | ||||||
|  | "label.sharedrouteripv6": "IPv6 address for the VR in this shared network.", | ||||||
| "label.sharewith": "Share with", | "label.sharewith": "Share with", | ||||||
| "label.showing": "Showing", | "label.showing": "Showing", | ||||||
| "label.shrinkok": "Shrink OK", | "label.shrinkok": "Shrink OK", | ||||||
| @ -1803,6 +1807,7 @@ | |||||||
| "label.sourceipaddress": "Source IP address", | "label.sourceipaddress": "Source IP address", | ||||||
| "label.sourceipaddressnetworkid": "Network ID of source IP address", | "label.sourceipaddressnetworkid": "Network ID of source IP address", | ||||||
| "label.sourcenat": "Source NAT", | "label.sourcenat": "Source NAT", | ||||||
|  | "label.sourcenatipaddress": "Source NAT IP address", | ||||||
| "label.sourcenatsupported": "Source NAT supported", | "label.sourcenatsupported": "Source NAT supported", | ||||||
| "label.sourcenattype": "Supported source NAT type", | "label.sourcenattype": "Supported source NAT type", | ||||||
| "label.sourceport": "Source port", | "label.sourceport": "Source port", | ||||||
| @ -1854,6 +1859,7 @@ | |||||||
| "label.startport": "Start port", | "label.startport": "Start port", | ||||||
| "label.startquota": "Quota value", | "label.startquota": "Quota value", | ||||||
| "label.state": "State", | "label.state": "State", | ||||||
|  | "label.staticnat": "Static NAT", | ||||||
| "label.static.routes": "Static routes", | "label.static.routes": "Static routes", | ||||||
| "label.status": "Status", | "label.status": "Status", | ||||||
| "label.step.1": "Step 1", | "label.step.1": "Step 1", | ||||||
| @ -2888,6 +2894,8 @@ | |||||||
| "message.setup.physical.network.during.zone.creation.basic": "When adding a basic zone, you can set up one physical network, which corresponds to a NIC on the hypervisor. The network carries several types of traffic.<br/><br/>You may also <strong>add</strong> other traffic types onto the physical network.", | "message.setup.physical.network.during.zone.creation.basic": "When adding a basic zone, you can set up one physical network, which corresponds to a NIC on the hypervisor. The network carries several types of traffic.<br/><br/>You may also <strong>add</strong> other traffic types onto the physical network.", | ||||||
| "message.shared.network.offering.warning": "Domain admins and regular users can only create shared networks from network offering with the setting specifyvlan=false. Please contact an administrator to create a network offering if this list is empty.", | "message.shared.network.offering.warning": "Domain admins and regular users can only create shared networks from network offering with the setting specifyvlan=false. Please contact an administrator to create a network offering if this list is empty.", | ||||||
| "message.shutdown.triggered": "A shutdown has been triggered. CloudStack will not accept new jobs", | "message.shutdown.triggered": "A shutdown has been triggered. CloudStack will not accept new jobs", | ||||||
|  | "message.sourcenatip.change.warning": "WARNING: Changing the sourcenat IP address of the network will cause connectivity downtime for the VMs with NICs in the network.", | ||||||
|  | "message.sourcenatip.change.inhibited": "Changing the sourcenat to this IP of the network to this address is inhibited as firewall rules are defined for it. This can include port forwarding or load balancing rules.\n - If this is an isolated network, please use updateNetwork/click the edit button.\n - If this is a VPC, first clear all other rules for this address.", | ||||||
| "message.specify.tag.key": "Please specify a tag key.", | "message.specify.tag.key": "Please specify a tag key.", | ||||||
| "message.specify.tag.value": "Please specify a tag value.", | "message.specify.tag.value": "Please specify a tag value.", | ||||||
| "message.step.2.continue": "Please select a service offering to continue.", | "message.step.2.continue": "Please select a service offering to continue.", | ||||||
|  | |||||||
| @ -2046,6 +2046,8 @@ | |||||||
|   "label.shared": "共有", |   "label.shared": "共有", | ||||||
|   "label.sharedexecutable": "共有", |   "label.sharedexecutable": "共有", | ||||||
|   "label.sharedmountpoint": "SharedMountPoint", |   "label.sharedmountpoint": "SharedMountPoint", | ||||||
|  |   "label.sharedrouterip": "共有ネットワークのルーターのIPv4アドレス", | ||||||
|  |   "label.sharedrouteripv6": "共有ネットワークのルーターのIPv6アドレス", | ||||||
|   "label.sharewith": "共有", |   "label.sharewith": "共有", | ||||||
|   "label.show.ingress.rule": "受信ルールの表示", |   "label.show.ingress.rule": "受信ルールの表示", | ||||||
|   "label.showing": "表示中", |   "label.showing": "表示中", | ||||||
|  | |||||||
| @ -1373,6 +1373,8 @@ | |||||||
| "label.shared": "shared", | "label.shared": "shared", | ||||||
| "label.sharedexecutable": "\uacf5\uc720", | "label.sharedexecutable": "\uacf5\uc720", | ||||||
| "label.sharedmountpoint": "\uacf5\uc720 \ub9c8\uc6b4\ud2b8 \ud3ec\uc778\ud2b8", | "label.sharedmountpoint": "\uacf5\uc720 \ub9c8\uc6b4\ud2b8 \ud3ec\uc778\ud2b8", | ||||||
|  | "label.sharedrouterip": "\uc11c\ube44\uc2a4\uc6a9 \ub124\ud2b8\uc6cc\ud06c\uc758 \ub77c\uc6b0\ud130\uc5d0 \ub300\ud55c IPv4 \uc8fc\uc18c", | ||||||
|  | "label.sharedrouteripv6": "\uc11c\ube44\uc2a4\uc6a9 \ub124\ud2b8\uc6cc\ud06c\uc758 \ub77c\uc6b0\ud130\uc5d0 \ub300\ud55c IPv6 \uc8fc\uc18c", | ||||||
| "label.sharewith": "\uacf5\uc720", | "label.sharewith": "\uacf5\uc720", | ||||||
| "label.showing": "\ubcf4\uae30", | "label.showing": "\ubcf4\uae30", | ||||||
| "label.shrinkok": "\ubcc0\uacbd \uc644\ub8cc", | "label.shrinkok": "\ubcc0\uacbd \uc644\ub8cc", | ||||||
|  | |||||||
| @ -1468,6 +1468,8 @@ | |||||||
| "label.shared": "Compatilhado", | "label.shared": "Compatilhado", | ||||||
| "label.sharedexecutable": "Compatilhado", | "label.sharedexecutable": "Compatilhado", | ||||||
| "label.sharedmountpoint": "SharedMountPoint", | "label.sharedmountpoint": "SharedMountPoint", | ||||||
|  | "label.sharedrouterip": "Endere\u00e7os IPv4 para o roteador dentro da rede compartilhada", | ||||||
|  | "label.sharedrouteripv6": "Endere\u00e7os IPv6 para o roteador dentro da rede compartilhada", | ||||||
| "label.sharewith": "Compartilhar com", | "label.sharewith": "Compartilhar com", | ||||||
| "label.showing": "Exibindo", | "label.showing": "Exibindo", | ||||||
| "label.shrinkok": "Encolhimento OK", | "label.shrinkok": "Encolhimento OK", | ||||||
|  | |||||||
| @ -2333,6 +2333,8 @@ | |||||||
|   "label.shared": "\u5DF2\u5171\u4EAB", |   "label.shared": "\u5DF2\u5171\u4EAB", | ||||||
|   "label.sharedexecutable": "\u5DF2\u5171\u4EAB", |   "label.sharedexecutable": "\u5DF2\u5171\u4EAB", | ||||||
|   "label.sharedmountpoint": "\u5171\u4EAB\u6302\u8F7D\u70B9", |   "label.sharedmountpoint": "\u5171\u4EAB\u6302\u8F7D\u70B9", | ||||||
|  |   "label.sharedrouterip": "\u5171\u4EAB\u7F51\u7EDC\u4E2D\u8DEF\u7531\u5668\u7684 IPv4 \u5730\u5740", | ||||||
|  |   "label.sharedrouteripv6": "\u5171\u4EAB\u7F51\u7EDC\u4E2D\u8DEF\u7531\u5668\u7684 IPv6 \u5730\u5740", | ||||||
|   "label.sharewith": "\u5206\u4EAB", |   "label.sharewith": "\u5206\u4EAB", | ||||||
| 
 | 
 | ||||||
|   "label.show.ingress.rule": "\u663E\u793A\u5165\u53E3\u89C4\u5219", |   "label.show.ingress.rule": "\u663E\u793A\u5165\u53E3\u89C4\u5219", | ||||||
|  | |||||||
| @ -228,7 +228,7 @@ export default { | |||||||
|           icon: 'edit-outlined', |           icon: 'edit-outlined', | ||||||
|           label: 'label.edit', |           label: 'label.edit', | ||||||
|           dataView: true, |           dataView: true, | ||||||
|           args: ['name', 'displaytext', 'publicmtu'] |           args: ['name', 'displaytext', 'publicmtu', 'sourcenatipaddress'] | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|           api: 'restartVPC', |           api: 'restartVPC', | ||||||
|  | |||||||
| @ -16,6 +16,7 @@ | |||||||
| // under the License.
 | // under the License.
 | ||||||
| 
 | 
 | ||||||
| import { | import { | ||||||
|  |   AimOutlined, | ||||||
|   ApartmentOutlined, |   ApartmentOutlined, | ||||||
|   ApiOutlined, |   ApiOutlined, | ||||||
|   AppstoreOutlined, |   AppstoreOutlined, | ||||||
| @ -170,6 +171,7 @@ import renderIcon from '@/utils/renderIcon' | |||||||
| 
 | 
 | ||||||
| export default { | export default { | ||||||
|   install: (app) => { |   install: (app) => { | ||||||
|  |     app.component('AimOutlined', AimOutlined) | ||||||
|     app.component('ApartmentOutlined', ApartmentOutlined) |     app.component('ApartmentOutlined', ApartmentOutlined) | ||||||
|     app.component('ApiOutlined', ApiOutlined) |     app.component('ApiOutlined', ApiOutlined) | ||||||
|     app.component('AppstoreOutlined', AppstoreOutlined) |     app.component('AppstoreOutlined', AppstoreOutlined) | ||||||
|  | |||||||
| @ -291,6 +291,36 @@ | |||||||
|               </a-col> |               </a-col> | ||||||
|             </a-row> |             </a-row> | ||||||
|           </div> |           </div> | ||||||
|  |           <a-form-item v-if="selectedNetworkOfferingSupportsSourceNat" name="sourcenatipaddress" ref="sourcenatipaddress"> | ||||||
|  |             <template #label> | ||||||
|  |               <tooltip-label :title="$t('label.routerip')" :tooltip="apiParams.sourcenatipaddress.description"/> | ||||||
|  |             </template> | ||||||
|  |             <a-input | ||||||
|  |               v-model:value="form.sourcenatipaddress" | ||||||
|  |               :placeholder="apiParams.sourcenatipaddress.description"/> | ||||||
|  |           </a-form-item> | ||||||
|  |           <a-form-item | ||||||
|  |             ref="networkdomain" | ||||||
|  |             name="networkdomain" | ||||||
|  |             v-if="!isObjectEmpty(selectedNetworkOffering) && !selectedNetworkOffering.forvpc"> | ||||||
|  |             <template #label> | ||||||
|  |               <tooltip-label :title="$t('label.networkdomain')" :tooltip="apiParams.networkdomain.description"/> | ||||||
|  |             </template> | ||||||
|  |             <a-input | ||||||
|  |              v-model:value="form.networkdomain" | ||||||
|  |               :placeholder="apiParams.networkdomain.description"/> | ||||||
|  |           </a-form-item> | ||||||
|  |           <a-form-item | ||||||
|  |             ref="account" | ||||||
|  |             name="account" | ||||||
|  |             v-if="accountVisible"> | ||||||
|  |             <template #label> | ||||||
|  |               <tooltip-label :title="$t('label.account')" :tooltip="apiParams.account.description"/> | ||||||
|  |             </template> | ||||||
|  |             <a-input | ||||||
|  |              v-model:value="form.account" | ||||||
|  |               :placeholder="apiParams.account.description"/> | ||||||
|  |           </a-form-item> | ||||||
|           <div :span="24" class="action-button"> |           <div :span="24" class="action-button"> | ||||||
|             <a-button |             <a-button | ||||||
|               :loading="actionLoading" |               :loading="actionLoading" | ||||||
| @ -397,6 +427,14 @@ export default { | |||||||
|         return dnsServices && dnsServices.length === 1 |         return dnsServices && dnsServices.length === 1 | ||||||
|       } |       } | ||||||
|       return false |       return false | ||||||
|  |     }, | ||||||
|  |     selectedNetworkOfferingSupportsSourceNat () { | ||||||
|  |       if (this.selectedNetworkOffering) { | ||||||
|  |         const services = this.selectedNetworkOffering?.service || [] | ||||||
|  |         const sourcenatService = services.filter(service => service.name === 'SourceNat') | ||||||
|  |         return sourcenatService && sourcenatService.length === 1 | ||||||
|  |       } | ||||||
|  |       return false | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   methods: { |   methods: { | ||||||
| @ -596,7 +634,7 @@ export default { | |||||||
|           displayText: values.displaytext, |           displayText: values.displaytext, | ||||||
|           networkOfferingId: this.selectedNetworkOffering.id |           networkOfferingId: this.selectedNetworkOffering.id | ||||||
|         } |         } | ||||||
|         var usefulFields = ['gateway', 'netmask', 'startip', 'endip', 'dns1', 'dns2', 'ip6dns1', 'ip6dns2', 'externalid', 'vpcid', 'vlan', 'networkdomain'] |         var usefulFields = ['gateway', 'netmask', 'startip', 'startipv4', 'endip', 'endipv4', 'dns1', 'dns2', 'ip6dns1', 'ip6dns2', 'sourcenatipaddress', 'externalid', 'vpcid', 'vlan', 'networkdomain'] | ||||||
|         for (var field of usefulFields) { |         for (var field of usefulFields) { | ||||||
|           if (this.isValidTextValueForKey(values, field)) { |           if (this.isValidTextValueForKey(values, field)) { | ||||||
|             params[field] = values[field] |             params[field] = values[field] | ||||||
|  | |||||||
| @ -155,6 +155,14 @@ | |||||||
|             </a-form-item> |             </a-form-item> | ||||||
|           </a-col> |           </a-col> | ||||||
|         </a-row> |         </a-row> | ||||||
|  |         <a-form-item v-if="selectedNetworkOfferingSupportsSourceNat" name="sourcenatipaddress" ref="sourcenatipaddress"> | ||||||
|  |           <template #label> | ||||||
|  |             <tooltip-label :title="$t('label.routerip')" :tooltip="apiParams.sourcenatipaddress.description"/> | ||||||
|  |           </template> | ||||||
|  |           <a-input | ||||||
|  |             v-model:value="form.sourcenatipaddress" | ||||||
|  |             :placeholder="apiParams.sourcenatipaddress.description"/> | ||||||
|  |         </a-form-item> | ||||||
|         <a-form-item name="start" ref="start"> |         <a-form-item name="start" ref="start"> | ||||||
|           <template #label> |           <template #label> | ||||||
|             <tooltip-label :title="$t('label.start')" :tooltip="apiParams.start.description"/> |             <tooltip-label :title="$t('label.start')" :tooltip="apiParams.start.description"/> | ||||||
| @ -212,6 +220,14 @@ export default { | |||||||
|         return dnsServices && dnsServices.length === 1 |         return dnsServices && dnsServices.length === 1 | ||||||
|       } |       } | ||||||
|       return false |       return false | ||||||
|  |     }, | ||||||
|  |     selectedNetworkOfferingSupportsSourceNat () { | ||||||
|  |       if (this.selectedVpcOffering) { | ||||||
|  |         const services = this.selectedVpcOffering?.service || [] | ||||||
|  |         const sourcenatService = services.filter(service => service.name === 'SourceNat') | ||||||
|  |         return sourcenatService && sourcenatService.length === 1 | ||||||
|  |       } | ||||||
|  |       return false | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   methods: { |   methods: { | ||||||
| @ -274,6 +290,10 @@ export default { | |||||||
|         this.selectedVpcOffering = this.vpcOfferings[0] || {} |         this.selectedVpcOffering = this.vpcOfferings[0] || {} | ||||||
|       }).finally(() => { |       }).finally(() => { | ||||||
|         this.loadingOffering = false |         this.loadingOffering = false | ||||||
|  |         if (this.vpcOfferings.length > 0) { | ||||||
|  |           this.form.vpcofferingid = 0 | ||||||
|  |           this.handleVpcOfferingChange(this.vpcOfferings[0].id) | ||||||
|  |         } | ||||||
|       }) |       }) | ||||||
|     }, |     }, | ||||||
|     handleVpcOfferingChange (value) { |     handleVpcOfferingChange (value) { | ||||||
| @ -284,6 +304,7 @@ export default { | |||||||
|       for (var offering of this.vpcOfferings) { |       for (var offering of this.vpcOfferings) { | ||||||
|         if (offering.id === value) { |         if (offering.id === value) { | ||||||
|           this.selectedVpcOffering = offering |           this.selectedVpcOffering = offering | ||||||
|  |           this.form.vpcofferingid = offering.id | ||||||
|           return |           return | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|  | |||||||
| @ -67,9 +67,29 @@ | |||||||
|         :pagination="false" > |         :pagination="false" > | ||||||
|         <template #bodyCell="{ column, text, record }"> |         <template #bodyCell="{ column, text, record }"> | ||||||
|           <template v-if="column.key === 'ipaddress'"> |           <template v-if="column.key === 'ipaddress'"> | ||||||
|             <router-link v-if="record.forvirtualnetwork === true" :to="{ path: '/publicip/' + record.id }" >{{ text }} </router-link> |             <router-link v-if="record.forvirtualnetwork === true" :to="{ path: '/publicip/' + record.id }" >{{ text }} </router-link> | ||||||
|             <div v-else>{{ text }}</div> |             <div v-else>{{ text }}</div> | ||||||
|             <a-tag v-if="record.issourcenat === true">source-nat</a-tag> |             <template v-if="record.issourcenat === true"> | ||||||
|  |               <a-tag>{{ $t('label.sourcenat') }}</a-tag> | ||||||
|  |             </template> | ||||||
|  |             <template v-else-if="record.isstaticnat === true"> | ||||||
|  |               <a-tag>{{ $t('label.staticnat') }}</a-tag> | ||||||
|  |             </template> | ||||||
|  |             <template v-else-if="record.hasrules === false"> | ||||||
|  |               <tooltip-button | ||||||
|  |                 v-if="record.forvirtualnetwork === true" | ||||||
|  |                 :tooltip="$t('label.action.set.as.source.nat.ip')" | ||||||
|  |                 type="primary" | ||||||
|  |                 :danger="false" | ||||||
|  |                 icon="aim-outlined" | ||||||
|  |                 :disabled="!('updateNetwork' in $store.getters.apis)" | ||||||
|  |                 @onClick="showChangeSourceNat(record)"></tooltip-button> | ||||||
|  |             </template> | ||||||
|  |             <template v-else><!-- -if="record.hasrules === true" --> | ||||||
|  |               <Tooltip placement="topLeft" :title="$t('message.sourcenatip.change.inhibited')" > | ||||||
|  |                 <a-tag>{{ $t('label.hasrules') }}</a-tag> | ||||||
|  |               </Tooltip> | ||||||
|  |             </template> | ||||||
|           </template> |           </template> | ||||||
| 
 | 
 | ||||||
|           <template v-if="column.key === 'state'"> |           <template v-if="column.key === 'state'"> | ||||||
| @ -150,6 +170,24 @@ | |||||||
|         </a-form> |         </a-form> | ||||||
|       </a-spin> |       </a-spin> | ||||||
|     </a-modal> |     </a-modal> | ||||||
|  |     <a-modal | ||||||
|  |       v-if="changeSourceNat" | ||||||
|  |       :title="$t('message.sourcenatip.change.warning')" | ||||||
|  |       :visible="changeSourceNat" | ||||||
|  |       :closable="true" | ||||||
|  |       :footer="null" | ||||||
|  |       @cancel="cancelChangeSourceNat" | ||||||
|  |       centered | ||||||
|  |       :disabled="!('updateNetwork' in $store.getters.apis)" | ||||||
|  |       width="450px"> | ||||||
|  |       <template> | ||||||
|  |         <a-alert :message="$t('message.sourcenatip.change.warning')" type="warning" /> | ||||||
|  |       </template> | ||||||
|  |       <div :span="24" class="action-button"> | ||||||
|  |         <a-button @click="cancelChangeSourceNat">{{ $t('label.cancel') }}</a-button> | ||||||
|  |         <a-button ref="submit" type="primary" @click="setSourceNatIp(record)">{{ $t('label.ok') }}</a-button> | ||||||
|  |       </div> | ||||||
|  |     </a-modal> | ||||||
|     <bulk-action-view |     <bulk-action-view | ||||||
|       v-if="showConfirmationAction || showGroupActionModal" |       v-if="showConfirmationAction || showGroupActionModal" | ||||||
|       :showConfirmationAction="showConfirmationAction" |       :showConfirmationAction="showConfirmationAction" | ||||||
| @ -167,6 +205,7 @@ | |||||||
|       @close-modal="closeModal" /> |       @close-modal="closeModal" /> | ||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
|  | 
 | ||||||
| <script> | <script> | ||||||
| import { api } from '@/api' | import { api } from '@/api' | ||||||
| import Status from '@/components/widgets/Status' | import Status from '@/components/widgets/Status' | ||||||
| @ -242,7 +281,8 @@ export default { | |||||||
|       showAcquireIp: false, |       showAcquireIp: false, | ||||||
|       acquireLoading: false, |       acquireLoading: false, | ||||||
|       acquireIp: null, |       acquireIp: null, | ||||||
|       listPublicIpAddress: [] |       listPublicIpAddress: [], | ||||||
|  |       changeSourceNat: false | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   created () { |   created () { | ||||||
| @ -315,6 +355,50 @@ export default { | |||||||
|         return selection.indexOf(item.id) !== -1 |         return selection.indexOf(item.id) !== -1 | ||||||
|       })) |       })) | ||||||
|     }, |     }, | ||||||
|  |     setSourceNatIp (ipaddress) { | ||||||
|  |       if (this.settingsourcenat) return | ||||||
|  |       if (this.$route.path.startsWith('/vpc')) { | ||||||
|  |         this.updateVpc(ipaddress) | ||||||
|  |       } else { | ||||||
|  |         this.updateNetwork(ipaddress) | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     updateNetwork (ipaddress) { | ||||||
|  |       const params = {} | ||||||
|  |       params.sourcenatipaddress = this.sourceNatIp.ipaddress | ||||||
|  |       params.id = this.resource.id | ||||||
|  |       this.settingsourcenat = true | ||||||
|  |       api('updateNetwork', params).then(response => { | ||||||
|  |         this.fetchData() | ||||||
|  |       }).catch(error => { | ||||||
|  |         this.$notification.error({ | ||||||
|  |           message: `${this.$t('label.error')} ${error.response.status}`, | ||||||
|  |           description: error.response.data.updatenetworkresponse.errortext || error.response.data.errorresponse.errortext, | ||||||
|  |           duration: 0 | ||||||
|  |         }) | ||||||
|  |       }).finally(() => { | ||||||
|  |         this.settingsourcenat = false | ||||||
|  |         this.cancelChangeSourceNat() | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     updateVpc (ipaddress) { | ||||||
|  |       const params = {} | ||||||
|  |       params.sourcenatipaddress = this.sourceNatIp.ipaddress | ||||||
|  |       params.id = this.resource.id | ||||||
|  |       this.settingsourcenat = true | ||||||
|  |       api('updateVPC', params).then(response => { | ||||||
|  |         this.fetchData() | ||||||
|  |       }).catch(error => { | ||||||
|  |         this.$notification.error({ | ||||||
|  |           message: `${this.$t('label.error')} ${error.response.status}`, | ||||||
|  |           description: error.response.data.updatevpcresponse.errortext || error.response.data.errorresponse.errortext, | ||||||
|  |           duration: 0 | ||||||
|  |         }) | ||||||
|  |       }).finally(() => { | ||||||
|  |         this.settingsourcenat = false | ||||||
|  |         this.cancelChangeSourceNat() | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|     resetSelection () { |     resetSelection () { | ||||||
|       this.setSelection([]) |       this.setSelection([]) | ||||||
|     }, |     }, | ||||||
| @ -482,6 +566,13 @@ export default { | |||||||
|     }, |     }, | ||||||
|     closeModal () { |     closeModal () { | ||||||
|       this.showConfirmationAction = false |       this.showConfirmationAction = false | ||||||
|  |     }, | ||||||
|  |     showChangeSourceNat (ipaddress) { | ||||||
|  |       this.changeSourceNat = true | ||||||
|  |       this.sourceNatIp = ipaddress | ||||||
|  |     }, | ||||||
|  |     cancelChangeSourceNat () { | ||||||
|  |       this.changeSourceNat = false | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -80,6 +80,24 @@ | |||||||
|             </a-col> |             </a-col> | ||||||
|           </a-row> |           </a-row> | ||||||
|         </div> |         </div> | ||||||
|  |         <a-form-item name="sourcenatipaddress" ref="sourcenatipaddress"> | ||||||
|  |           <template #label> | ||||||
|  |             <tooltip-label :title="$t('label.sourcenatipaddress')" :tooltip="apiParams.sourcenatipaddress.description"/> | ||||||
|  |           </template> | ||||||
|  |           <span v-if="sourcenatchange"> | ||||||
|  |             <a-alert type="warning"> | ||||||
|  |               <template #message> | ||||||
|  |                 <span v-html="$t('message.sourcenatip.change.warning')" /> | ||||||
|  |               </template> | ||||||
|  |             </a-alert> | ||||||
|  |             <br/> | ||||||
|  |           </span> | ||||||
|  |           <a-input | ||||||
|  |             v-model:value="form.sourcenatipaddress" | ||||||
|  |             :placeholder="apiParams.sourcenatipaddress.description" | ||||||
|  |             v-focus="true" | ||||||
|  |             @change="sourcenatchange = form.sourcenatipaddress.length > 0"/> | ||||||
|  |         </a-form-item> | ||||||
|         <a-form-item name="networkofferingid" ref="networkofferingid" v-if="isUpdatingIsolatedNetwork"> |         <a-form-item name="networkofferingid" ref="networkofferingid" v-if="isUpdatingIsolatedNetwork"> | ||||||
|           <template #label> |           <template #label> | ||||||
|             <tooltip-label :title="$t('label.networkofferingid')" :tooltip="apiParams.networkofferingid.description"/> |             <tooltip-label :title="$t('label.networkofferingid')" :tooltip="apiParams.networkofferingid.description"/> | ||||||
| @ -238,7 +256,8 @@ export default { | |||||||
|       minMTU: 68, |       minMTU: 68, | ||||||
|       errorPrivateMtu: '', |       errorPrivateMtu: '', | ||||||
|       errorPublicMtu: '', |       errorPublicMtu: '', | ||||||
|       setMTU: false |       setMTU: false, | ||||||
|  |       sourcenatchange: false | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   beforeCreate () { |   beforeCreate () { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user