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,46 +77,46 @@ 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);
|
||||||
|
|
||||||
@ -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,7 +119,8 @@ 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 {
|
||||||
|
Vpc result = _vpcService.updateVpc(this);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
VpcResponse response = _responseGenerator.createVpcResponse(getResponseView(), result);
|
VpcResponse response = _responseGenerator.createVpcResponse(getResponseView(), result);
|
||||||
response.setResponseName(getCommandName());
|
response.setResponseName(getCommandName());
|
||||||
@ -115,6 +128,14 @@ public class UpdateVPCCmd extends BaseAsyncCustomIdCmd implements UserCmd {
|
|||||||
} else {
|
} else {
|
||||||
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update VPC");
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -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) {
|
||||||
|
for (final Entry<Capability ,String> srcNatPair : sourceNatServiceCapabilityMap.entrySet()) {
|
||||||
final Capability capability = srcNatPair.getKey();
|
final Capability capability = srcNatPair.getKey();
|
||||||
final String value = srcNatPair.getValue();
|
final String value = srcNatPair.getValue();
|
||||||
if (capability == Capability.SupportedSourceNatTypes) {
|
if (Capability.SupportedSourceNatTypes.equals(capability)) {
|
||||||
final boolean perAccount = value.contains("peraccount");
|
List<String> snatTypes = Arrays.asList(PERACCOUNT, PERZONE);
|
||||||
final boolean perZone = value.contains("perzone");
|
if (! snatTypes.contains(value) || ( value.contains(PERACCOUNT) && value.contains(PERZONE))) {
|
||||||
if (perAccount && perZone || !perAccount && !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) {
|
} else if (Capability.RedundantRouter.equals(capability)) {
|
||||||
final boolean enabled = value.contains("true");
|
if (! Arrays.asList("true", "false").contains(value.toLowerCase())) {
|
||||||
final boolean disabled = value.contains("false");
|
throw new InvalidParameterValueException("Unknown specified value for " + capability.getName());
|
||||||
if (!enabled && !disabled) {
|
|
||||||
throw new InvalidParameterValueException("Unknown specified value for " + Capability.RedundantRouter.getName());
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new InvalidParameterValueException("Only " + Capability.SupportedSourceNatTypes.getName() + " and " + Capability.RedundantRouter
|
return false;
|
||||||
+ " capabilities can be sepcified for source nat service");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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;
|
||||||
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.
|
// 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.
|
// It seems a bug.
|
||||||
|
// Is this still valid (per 2023?)
|
||||||
|
*/
|
||||||
|
private static final long MAX_VXLAN_VNI = 16777214L; // 2^24 -2
|
||||||
|
private static final String NETWORK_OFFERING_ID = "networkOfferingId";
|
||||||
|
|
||||||
@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;
|
|
||||||
}
|
}
|
||||||
if (!NetUtils.isValidIp6(routerIpv6)) {
|
|
||||||
throw new CloudRuntimeException("Router IPv6 address provided is of incorrect format");
|
private void validateSharedNetworkRouterIPv6(String routerIPv6, String startIPv6, String endIPv6, String cidrIPv6) {
|
||||||
|
if (StringUtils.isNotBlank(routerIPv6)) {
|
||||||
|
if (startIPv6 != null && endIPv6 == null) {
|
||||||
|
endIPv6 = startIPv6;
|
||||||
}
|
}
|
||||||
if (StringUtils.isNoneBlank(startIpv6, endIpv6)) {
|
isIPv6AddressValid(routerIPv6);
|
||||||
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;
|
||||||
|
|
||||||
@ -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