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_migration
|
||||
smoke/test_multipleips_per_nic
|
||||
smoke/test_nested_virtualization",
|
||||
smoke/test_nested_virtualization
|
||||
smoke/test_set_sourcenat",
|
||||
"smoke/test_network
|
||||
smoke/test_network_acl
|
||||
smoke/test_network_ipv6
|
||||
|
||||
@ -256,7 +256,7 @@ public interface Network extends ControlledEntity, StateObject<Network.State>, I
|
||||
|
||||
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 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.ListPrivateGatewaysCmd;
|
||||
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.UpdateVPCCmd;
|
||||
|
||||
import com.cloud.exception.ConcurrentOperationException;
|
||||
import com.cloud.exception.InsufficientAddressCapacityException;
|
||||
@ -37,7 +39,6 @@ import com.cloud.utils.Pair;
|
||||
|
||||
public interface VpcService {
|
||||
|
||||
public Vpc createVpc(CreateVPCCmd cmd) throws ResourceAllocationException;
|
||||
/**
|
||||
* Persists VPC record in the database
|
||||
*
|
||||
@ -48,14 +49,25 @@ public interface VpcService {
|
||||
* @param displayText
|
||||
* @param cidr
|
||||
* @param networkDomain TODO
|
||||
* @param ip4Dns1
|
||||
* @param ip4Dns2
|
||||
* @param displayVpc TODO
|
||||
* @return
|
||||
* @throws ResourceAllocationException TODO
|
||||
*/
|
||||
public 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)
|
||||
Vpc createVpc(long zoneId, long vpcOffId, long vpcOwnerId, String vpcName, String displayText, String cidr, String networkDomain,
|
||||
String ip4Dns1, String ip4Dns2, String ip6Dns1, String ip6Dns2, Boolean displayVpc, Integer publicMtu)
|
||||
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
|
||||
*
|
||||
@ -65,48 +77,48 @@ public interface VpcService {
|
||||
* @throws ResourceUnavailableException
|
||||
* @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
|
||||
*
|
||||
* @param vpcId
|
||||
* @param vpcName
|
||||
* @param displayText
|
||||
* @param customId TODO
|
||||
* @param displayVpc TODO
|
||||
* @param mtu
|
||||
* @return
|
||||
* @param vpcId the ID of the Vpc to update
|
||||
* @param vpcName The new name to give the vpc
|
||||
* @param displayText the new display text to use for describing the VPC
|
||||
* @param customId A new custom (external) ID to associate this VPC with
|
||||
* @param displayVpc should this VPC be displayed on public lists
|
||||
* @param mtu what maximal transfer unit to us in this VPCs networks
|
||||
* @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
|
||||
*
|
||||
* @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,
|
||||
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);
|
||||
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,
|
||||
Map<String, String> tags, Long projectId, Boolean display);
|
||||
|
||||
/**
|
||||
* Starts VPC which includes starting VPC provider and applying all the networking rules on the backend
|
||||
@ -130,17 +142,17 @@ public interface VpcService {
|
||||
*/
|
||||
boolean shutdownVpc(long vpcId) throws ConcurrentOperationException, ResourceUnavailableException;
|
||||
|
||||
boolean restartVpc(RestartVPCCmd cmd) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException;
|
||||
|
||||
/**
|
||||
* Restarts the VPC. VPC gets shutdown and started as a part of it
|
||||
*
|
||||
* @param id
|
||||
* @param cleanUp
|
||||
* @param makeredundant
|
||||
* @return
|
||||
* @throws InsufficientCapacityException
|
||||
* @param networkId the network to restart
|
||||
* @param cleanup throw away the existing VR and rebuild a new one?
|
||||
* @param makeRedundant create two VRs for this network
|
||||
* @return success or not
|
||||
* @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;
|
||||
|
||||
/**
|
||||
@ -154,23 +166,12 @@ public interface VpcService {
|
||||
/**
|
||||
* Persists VPC private gateway in the Database.
|
||||
*
|
||||
*
|
||||
* @param vpcId TODO
|
||||
* @param physicalNetworkId
|
||||
* @param vlan
|
||||
* @param ipAddress
|
||||
* @param gateway
|
||||
* @param netmask
|
||||
* @param gatewayOwnerId
|
||||
* @param networkOfferingId
|
||||
* @param isSourceNat
|
||||
* @param aclId
|
||||
* @return
|
||||
* @return data object describing the private gateway
|
||||
* @throws InsufficientCapacityException
|
||||
* @throws ConcurrentOperationException
|
||||
* @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
|
||||
@ -181,12 +182,12 @@ public interface VpcService {
|
||||
* @throws ResourceUnavailableException
|
||||
* @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
|
||||
*
|
||||
* @param id
|
||||
* @param gatewayId
|
||||
* @return
|
||||
* @throws ResourceUnavailableException
|
||||
* @throws ConcurrentOperationException
|
||||
@ -199,7 +200,7 @@ public interface VpcService {
|
||||
* @param listPrivateGatewaysCmd
|
||||
* @return
|
||||
*/
|
||||
public Pair<List<PrivateGateway>, Integer> listPrivateGateway(ListPrivateGatewaysCmd listPrivateGatewaysCmd);
|
||||
Pair<List<PrivateGateway>, Integer> listPrivateGateway(ListPrivateGatewaysCmd listPrivateGatewaysCmd);
|
||||
|
||||
/**
|
||||
* Returns Static Route found by Id
|
||||
@ -216,7 +217,7 @@ public interface VpcService {
|
||||
* @return
|
||||
* @throws ResourceUnavailableException
|
||||
*/
|
||||
public boolean applyStaticRoutesForVpc(long vpcId) throws ResourceUnavailableException;
|
||||
boolean applyStaticRoutesForVpc(long vpcId) throws ResourceUnavailableException;
|
||||
|
||||
/**
|
||||
* Deletes static route from the backend and the database
|
||||
@ -225,7 +226,7 @@ public interface VpcService {
|
||||
* @return TODO
|
||||
* @throws ResourceUnavailableException
|
||||
*/
|
||||
public boolean revokeStaticRoute(long routeId) throws ResourceUnavailableException;
|
||||
boolean revokeStaticRoute(long routeId) throws ResourceUnavailableException;
|
||||
|
||||
/**
|
||||
* Persists static route entry in the Database
|
||||
@ -234,15 +235,15 @@ public interface VpcService {
|
||||
* @param cidr
|
||||
* @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
|
||||
*
|
||||
* @param listStaticRoutesCmd
|
||||
* @param cmd Command object with parameters for { @see ListStaticRoutesCmd }
|
||||
* @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
|
||||
@ -262,6 +263,5 @@ public interface VpcService {
|
||||
* @param routeId
|
||||
* @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 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.
|
||||
* 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
|
||||
public void execute() {
|
||||
Pair<List<? extends IpAddress>, Integer> result = _mgr.searchForIPAddresses(this);
|
||||
ListResponse<IPAddressResponse> response = new ListResponse<IPAddressResponse>();
|
||||
List<IPAddressResponse> ipAddrResponses = new ArrayList<IPAddressResponse>();
|
||||
ListResponse<IPAddressResponse> response = new ListResponse<>();
|
||||
List<IPAddressResponse> ipAddrResponses = new ArrayList<>();
|
||||
for (IpAddress ipAddress : result.first()) {
|
||||
IPAddressResponse ipResponse = _responseGenerator.createIPAddressResponse(getResponseView(), ipAddress);
|
||||
ipResponse.setObjectName("publicipaddress");
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
// under the License.
|
||||
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.cloudstack.acl.RoleType;
|
||||
@ -43,10 +43,10 @@ import com.cloud.exception.InsufficientCapacityException;
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.exception.ResourceAllocationException;
|
||||
import com.cloud.network.Network;
|
||||
import com.cloud.network.NetworkService;
|
||||
import com.cloud.network.Network.GuestType;
|
||||
import com.cloud.offering.NetworkOffering;
|
||||
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},
|
||||
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")
|
||||
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 ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
@ -266,6 +274,10 @@ public class CreateNetworkCmd extends BaseCmd implements UserCmd {
|
||||
return tungstenVirtualRouterUuid;
|
||||
}
|
||||
|
||||
public String getSourceNatIP() {
|
||||
return sourceNatIP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDisplay() {
|
||||
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")
|
||||
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 ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
@ -181,6 +184,10 @@ public class UpdateNetworkCmd extends BaseAsyncCustomIdCmd implements UserCmd {
|
||||
return ip6Dns2;
|
||||
}
|
||||
|
||||
public String getSourceNatIP() {
|
||||
return sourceNatIP;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@ -16,7 +16,6 @@
|
||||
// under the License.
|
||||
package org.apache.cloudstack.api.command.user.vpc;
|
||||
|
||||
import com.cloud.network.NetworkService;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
@ -41,6 +40,7 @@ import com.cloud.exception.ConcurrentOperationException;
|
||||
import com.cloud.exception.InsufficientCapacityException;
|
||||
import com.cloud.exception.ResourceAllocationException;
|
||||
import com.cloud.exception.ResourceUnavailableException;
|
||||
import com.cloud.network.NetworkService;
|
||||
import com.cloud.network.vpc.Vpc;
|
||||
|
||||
@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")
|
||||
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 ///////////////////////
|
||||
// ///////////////////////////////////////////////////
|
||||
@ -180,6 +186,15 @@ public class CreateVPCCmd extends BaseAsyncCreateCmd implements UserCmd {
|
||||
return display;
|
||||
}
|
||||
|
||||
|
||||
public String getSourceNatIP() {
|
||||
return sourceNatIP;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void create() throws ResourceAllocationException {
|
||||
Vpc vpc = _vpcService.createVpc(this);
|
||||
|
||||
@ -142,9 +142,7 @@ public class ListVPCsCmd extends BaseListTaggedResourcesCmd implements UserCmd {
|
||||
@Override
|
||||
public void execute() {
|
||||
Pair<List<? extends Vpc>, Integer> vpcs =
|
||||
_vpcService.listVpcs(getId(), getVpcName(), getDisplayText(), getSupportedServices(), getCidr(), getVpcOffId(), getState(), getAccountName(), getDomainId(),
|
||||
getKeyword(), getStartIndex(), getPageSizeVal(), getZoneId(), isRecursive(), listAll(), getRestartRequired(), getTags(),
|
||||
getProjectId(), getDisplay());
|
||||
_vpcService.listVpcs(this);
|
||||
ListResponse<VpcResponse> response = new ListResponse<VpcResponse>();
|
||||
List<VpcResponse> vpcResponses = new ArrayList<VpcResponse>();
|
||||
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 com.cloud.event.EventTypes;
|
||||
import com.cloud.exception.InsufficientCapacityException;
|
||||
import com.cloud.exception.ResourceUnavailableException;
|
||||
import com.cloud.network.vpc.Vpc;
|
||||
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")
|
||||
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 ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
@ -87,6 +95,10 @@ public class UpdateVPCCmd extends BaseAsyncCustomIdCmd implements UserCmd {
|
||||
return publicMtu;
|
||||
}
|
||||
|
||||
public String getSourceNatIP() {
|
||||
return sourceNatIP;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
@ -107,13 +119,22 @@ public class UpdateVPCCmd extends BaseAsyncCustomIdCmd implements UserCmd {
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
Vpc result = _vpcService.updateVpc(getId(), getVpcName(), getDisplayText(), getCustomId(), isDisplayVpc(), getPublicMtu());
|
||||
if (result != null) {
|
||||
VpcResponse response = _responseGenerator.createVpcResponse(getResponseView(), result);
|
||||
response.setResponseName(getCommandName());
|
||||
setResponseObject(response);
|
||||
} else {
|
||||
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update VPC");
|
||||
try {
|
||||
Vpc result = _vpcService.updateVpc(this);
|
||||
if (result != null) {
|
||||
VpcResponse response = _responseGenerator.createVpcResponse(getResponseView(), result);
|
||||
response.setResponseName(getCommandName());
|
||||
setResponseObject(response);
|
||||
} else {
|
||||
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update VPC");
|
||||
}
|
||||
} catch (final ResourceUnavailableException ex) {
|
||||
s_logger.warn("Exception: ", ex);
|
||||
throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage());
|
||||
} catch (final InsufficientCapacityException ex) {
|
||||
s_logger.info(ex);
|
||||
s_logger.trace(ex);
|
||||
throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -163,10 +163,9 @@ public class IPAddressResponse extends BaseResponseWithAnnotations implements Co
|
||||
@Param(description="the name of the Network where ip belongs to")
|
||||
private String networkName;
|
||||
|
||||
/*
|
||||
@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")
|
||||
private IdentityProxy jobId = new IdentityProxy("async_job");
|
||||
*/
|
||||
@SerializedName(ApiConstants.HAS_RULES)
|
||||
@Param(description="whether the ip address has Firewall/PortForwarding/LoadBalancing rules defined")
|
||||
private boolean hasRules;
|
||||
|
||||
public void setIpAddress(String ipAddress) {
|
||||
this.ipAddress = ipAddress;
|
||||
@ -313,4 +312,8 @@ public class IPAddressResponse extends BaseResponseWithAnnotations implements Co
|
||||
public void setNetworkName(String 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;
|
||||
|
||||
import com.cloud.exception.InsufficientCapacityException;
|
||||
import com.cloud.exception.ResourceUnavailableException;
|
||||
import com.cloud.network.vpc.Vpc;
|
||||
import com.cloud.network.vpc.VpcService;
|
||||
import junit.framework.TestCase;
|
||||
@ -72,7 +74,7 @@ public class UpdateVPCCmdTest extends TestCase {
|
||||
Assert.assertEquals(cmd.getPublicMtu(), publicMtu);
|
||||
}
|
||||
|
||||
public void testExecute() {
|
||||
public void testExecute() throws ResourceUnavailableException, InsufficientCapacityException {
|
||||
ReflectionTestUtils.setField(cmd, "id", 1L);
|
||||
ReflectionTestUtils.setField(cmd, "vpcName", "updatedVpcName");
|
||||
ReflectionTestUtils.setField(cmd, "displayText", "Updated VPC Name");
|
||||
@ -85,10 +87,10 @@ public class UpdateVPCCmdTest extends TestCase {
|
||||
responseGenerator = Mockito.mock(ResponseGenerator.class);
|
||||
cmd._responseGenerator = responseGenerator;
|
||||
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.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_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);
|
||||
|
||||
/**
|
||||
* 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 countRulesByIpIdAndState(long sourceIpId, FirewallRule.State state);
|
||||
|
||||
@ -75,7 +75,7 @@ public interface IPAddressDao extends GenericDao<IPAddressVO, Long> {
|
||||
|
||||
long countFreeIPsInNetwork(long networkId);
|
||||
|
||||
IPAddressVO findByVmIp(String vmIp);
|
||||
IPAddressVO findByIp(String ipAddress);
|
||||
|
||||
IPAddressVO findByAssociatedVmIdAndVmIp(long vmId, String vmIp);
|
||||
|
||||
|
||||
@ -314,9 +314,9 @@ public class IPAddressDaoImpl extends GenericDaoBase<IPAddressVO, Long> implemen
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPAddressVO findByVmIp(String vmIp) {
|
||||
public IPAddressVO findByIp(String ipAddress) {
|
||||
SearchCriteria<IPAddressVO> sc = AllFieldsSearch.create();
|
||||
sc.setParameters("associatedVmIp", vmIp);
|
||||
sc.setParameters("ipAddress", ipAddress);
|
||||
return findOneBy(sc);
|
||||
}
|
||||
|
||||
|
||||
@ -292,6 +292,7 @@ import com.cloud.network.as.AutoScaleVmProfileVO;
|
||||
import com.cloud.network.as.Condition;
|
||||
import com.cloud.network.as.ConditionVO;
|
||||
import com.cloud.network.as.Counter;
|
||||
import com.cloud.network.dao.FirewallRulesDao;
|
||||
import com.cloud.network.dao.IPAddressDao;
|
||||
import com.cloud.network.dao.IPAddressVO;
|
||||
import com.cloud.network.dao.LoadBalancerVO;
|
||||
@ -456,6 +457,8 @@ public class ApiResponseHelper implements ResponseGenerator {
|
||||
UserVmJoinDao userVmJoinDao;
|
||||
@Inject
|
||||
NetworkServiceMapDao ntwkSrvcDao;
|
||||
@Inject
|
||||
FirewallRulesDao firewallRulesDao;
|
||||
|
||||
@Override
|
||||
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(),
|
||||
_accountMgr.isRootAdmin(CallContext.current().getCallingAccount().getId())));
|
||||
|
||||
ipResponse.setHasRules(firewallRulesDao.countRulesByIpId(ipAddr.getId()) > 0);
|
||||
ipResponse.setObjectName("ipaddress");
|
||||
return ipResponse;
|
||||
}
|
||||
|
||||
@ -295,6 +295,8 @@ import com.googlecode.ipv6.IPv6Network;
|
||||
|
||||
public class ConfigurationManagerImpl extends ManagerBase implements ConfigurationManager, ConfigurationService, Configurable {
|
||||
public static final Logger s_logger = Logger.getLogger(ConfigurationManagerImpl.class);
|
||||
public static final String PERACCOUNT = "peraccount";
|
||||
public static final String PERZONE = "perzone";
|
||||
|
||||
@Inject
|
||||
EntityManager _entityMgr;
|
||||
@ -6235,34 +6237,32 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
||||
}
|
||||
|
||||
void validateSourceNatServiceCapablities(final Map<Capability, String> sourceNatServiceCapabilityMap) {
|
||||
if (sourceNatServiceCapabilityMap != null && !sourceNatServiceCapabilityMap.isEmpty()) {
|
||||
if (sourceNatServiceCapabilityMap.keySet().size() > 2) {
|
||||
throw new InvalidParameterValueException("Only " + Capability.SupportedSourceNatTypes.getName() + " and " + Capability.RedundantRouter
|
||||
+ " capabilities can be sepcified for source nat service");
|
||||
}
|
||||
if (MapUtils.isNotEmpty(sourceNatServiceCapabilityMap) && (sourceNatServiceCapabilityMap.size() > 2 || ! sourceNatCapabilitiesContainValidValues(sourceNatServiceCapabilityMap))) {
|
||||
throw new InvalidParameterValueException("Only " + Capability.SupportedSourceNatTypes.getName()
|
||||
+ ", " + Capability.RedundantRouter
|
||||
+ " capabilities can be specified for source nat service");
|
||||
}
|
||||
}
|
||||
|
||||
for (final Map.Entry<Capability ,String> srcNatPair : sourceNatServiceCapabilityMap.entrySet()) {
|
||||
final Capability capability = srcNatPair.getKey();
|
||||
final String value = srcNatPair.getValue();
|
||||
if (capability == Capability.SupportedSourceNatTypes) {
|
||||
final boolean perAccount = value.contains("peraccount");
|
||||
final boolean perZone = value.contains("perzone");
|
||||
if (perAccount && perZone || !perAccount && !perZone) {
|
||||
throw new InvalidParameterValueException("Either peraccount or perzone source NAT type can be specified for "
|
||||
+ Capability.SupportedSourceNatTypes.getName());
|
||||
}
|
||||
} else if (capability == Capability.RedundantRouter) {
|
||||
final boolean enabled = value.contains("true");
|
||||
final boolean disabled = value.contains("false");
|
||||
if (!enabled && !disabled) {
|
||||
throw new InvalidParameterValueException("Unknown specified value for " + Capability.RedundantRouter.getName());
|
||||
}
|
||||
} else {
|
||||
throw new InvalidParameterValueException("Only " + Capability.SupportedSourceNatTypes.getName() + " and " + Capability.RedundantRouter
|
||||
+ " capabilities can be sepcified for source nat service");
|
||||
boolean sourceNatCapabilitiesContainValidValues(Map<Capability, String> sourceNatServiceCapabilityMap) {
|
||||
for (final Entry<Capability ,String> srcNatPair : sourceNatServiceCapabilityMap.entrySet()) {
|
||||
final Capability capability = srcNatPair.getKey();
|
||||
final String value = srcNatPair.getValue();
|
||||
if (Capability.SupportedSourceNatTypes.equals(capability)) {
|
||||
List<String> snatTypes = Arrays.asList(PERACCOUNT, PERZONE);
|
||||
if (! snatTypes.contains(value) || ( value.contains(PERACCOUNT) && value.contains(PERZONE))) {
|
||||
throw new InvalidParameterValueException("Either peraccount or perzone source NAT type can be specified for "
|
||||
+ Capability.SupportedSourceNatTypes.getName());
|
||||
}
|
||||
} else if (Capability.RedundantRouter.equals(capability)) {
|
||||
if (! Arrays.asList("true", "false").contains(value.toLowerCase())) {
|
||||
throw new InvalidParameterValueException("Unknown specified value for " + capability.getName());
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void validateStaticNatServiceCapablities(final Map<Capability, String> staticNatServiceCapabilityMap) {
|
||||
@ -6439,17 +6439,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
||||
|
||||
final Map<Capability, String> sourceNatServiceCapabilityMap = serviceCapabilityMap.get(Service.SourceNat);
|
||||
if (sourceNatServiceCapabilityMap != null && !sourceNatServiceCapabilityMap.isEmpty()) {
|
||||
final String sourceNatType = sourceNatServiceCapabilityMap.get(Capability.SupportedSourceNatTypes);
|
||||
if (sourceNatType != null) {
|
||||
_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");
|
||||
}
|
||||
sharedSourceNat = isSharedSourceNat(serviceProviderMap, sourceNatServiceCapabilityMap);
|
||||
redundantRouter = isRedundantRouter(serviceProviderMap, sourceNatServiceCapabilityMap);
|
||||
}
|
||||
|
||||
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) {
|
||||
for (final Detail detail : details.keySet()) {
|
||||
|
||||
|
||||
@ -2358,4 +2358,19 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
|
||||
public static ConfigKey<Boolean> getSystemvmpublicipreservationmodestrictness() {
|
||||
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;
|
||||
long copyOfVpcId;
|
||||
try {
|
||||
|
||||
copyOfVpc = _vpcService.createVpc(vpc.getZoneId(), vpcOfferingId, vpc.getAccountId(), vpc.getName(),
|
||||
vpc.getDisplayText(), vpc.getCidr(), vpc.getNetworkDomain(), vpc.getIp4Dns1(), vpc.getIp4Dns2(),
|
||||
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.StringUtils;
|
||||
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.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 MAX_GRE_KEY = 4294967295L; // 2^32 -1
|
||||
private static final long MIN_VXLAN_VNI = 0L;
|
||||
/**
|
||||
// MAX_VXLAN_VNI should be 16777215L (2^24-1), but Linux vxlan interface doesn't accept VNI:2^24-1 now.
|
||||
// It seems a bug.
|
||||
// Is this still valid (per 2023?)
|
||||
*/
|
||||
private static final long MAX_VXLAN_VNI = 16777214L; // 2^24 -2
|
||||
// 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.
|
||||
private static final String NETWORK_OFFERING_ID = "networkOfferingId";
|
||||
|
||||
@Inject
|
||||
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,
|
||||
String netmask, String startIpv6, String endIpv6, String ip6Cidr) {
|
||||
void validateSharedNetworkRouterIPs(String gateway, String startIP, String endIP, String netmask, String routerIPv4, String routerIPv6, String startIPv6, String endIPv6, String ip6Cidr, NetworkOffering ntwkOff) {
|
||||
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 (startIp != null && endIp == null) {
|
||||
endIp = startIp;
|
||||
}
|
||||
if (!NetUtils.isValidIp4(routerIp)) {
|
||||
throw new CloudRuntimeException("Router IPv4 IP provided is of incorrect format");
|
||||
}
|
||||
isIPv4AddressValid(routerIp);
|
||||
if (StringUtils.isNoneBlank(startIp, endIp)) {
|
||||
if (!NetUtils.isIpInRange(routerIp, startIp, endIp)) {
|
||||
throw new CloudRuntimeException("Router IPv4 IP provided is not within the specified range: " + startIp + " - " + endIp);
|
||||
@ -1318,26 +1329,39 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
|
||||
}
|
||||
}
|
||||
}
|
||||
if (StringUtils.isNotBlank(routerIpv6)) {
|
||||
if (startIpv6 != null && endIpv6 == null) {
|
||||
endIpv6 = startIpv6;
|
||||
}
|
||||
|
||||
private void validateSharedNetworkRouterIPv6(String routerIPv6, String startIPv6, String endIPv6, String cidrIPv6) {
|
||||
if (StringUtils.isNotBlank(routerIPv6)) {
|
||||
if (startIPv6 != null && endIPv6 == null) {
|
||||
endIPv6 = startIPv6;
|
||||
}
|
||||
if (!NetUtils.isValidIp6(routerIpv6)) {
|
||||
throw new CloudRuntimeException("Router IPv6 address provided is of incorrect format");
|
||||
}
|
||||
if (StringUtils.isNoneBlank(startIpv6, endIpv6)) {
|
||||
String ipv6Range = startIpv6 + "-" + endIpv6;
|
||||
if (!NetUtils.isIp6InRange(routerIpv6, ipv6Range)) {
|
||||
throw new CloudRuntimeException("Router IPv6 address provided is not within the specified range: " + startIpv6 + " - " + endIpv6);
|
||||
isIPv6AddressValid(routerIPv6);
|
||||
if (StringUtils.isNoneBlank(startIPv6, endIPv6)) {
|
||||
String ipv6Range = startIPv6 + "-" + endIPv6;
|
||||
if (!NetUtils.isIp6InRange(routerIPv6, ipv6Range)) {
|
||||
throw new CloudRuntimeException("Router IPv6 address provided is not within the specified range: " + startIPv6 + " - " + endIPv6);
|
||||
}
|
||||
} else {
|
||||
if (!NetUtils.isIp6InNetwork(routerIpv6, ip6Cidr)) {
|
||||
if (!NetUtils.isIp6InNetwork(routerIPv6, cidrIPv6)) {
|
||||
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
|
||||
@DB
|
||||
@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 netmask = cmd.getNetmask();
|
||||
String networkDomain = cmd.getNetworkDomain();
|
||||
String vlanId = null;
|
||||
boolean bypassVlanOverlapCheck = false;
|
||||
boolean hideIpAddressUsage = false;
|
||||
String routerIp = null;
|
||||
String routerIpv6 = null;
|
||||
if (cmd instanceof CreateNetworkCmdByAdmin) {
|
||||
vlanId = ((CreateNetworkCmdByAdmin)cmd).getVlan();
|
||||
bypassVlanOverlapCheck = ((CreateNetworkCmdByAdmin)cmd).getBypassVlanOverlapCheck();
|
||||
hideIpAddressUsage = ((CreateNetworkCmdByAdmin)cmd).getHideIpAddressUsage();
|
||||
routerIp = ((CreateNetworkCmdByAdmin)cmd).getRouterIp();
|
||||
routerIpv6 = ((CreateNetworkCmdByAdmin)cmd).getRouterIpv6();
|
||||
}
|
||||
|
||||
boolean adminCalledUs = cmd instanceof CreateNetworkCmdByAdmin;
|
||||
String vlanId = adminCalledUs ? ((CreateNetworkCmdByAdmin)cmd).getVlan() : null;
|
||||
boolean bypassVlanOverlapCheck = adminCalledUs && ((CreateNetworkCmdByAdmin)cmd).getBypassVlanOverlapCheck();
|
||||
boolean hideIpAddressUsage = adminCalledUs && ((CreateNetworkCmdByAdmin)cmd).getHideIpAddressUsage();
|
||||
String routerIPv4 = adminCalledUs ? ((CreateNetworkCmdByAdmin)cmd).getRouterIp() : null;
|
||||
String routerIPv6 = adminCalledUs ? ((CreateNetworkCmdByAdmin)cmd).getRouterIpv6() : null;
|
||||
|
||||
String name = cmd.getNetworkName();
|
||||
String displayText = cmd.getDisplayText();
|
||||
Account caller = CallContext.current().getCallingAccount();
|
||||
Long physicalNetworkId = cmd.getPhysicalNetworkId();
|
||||
Long zoneId = cmd.getZoneId();
|
||||
String aclTypeStr = cmd.getAclType();
|
||||
Long domainId = cmd.getDomainId();
|
||||
boolean isDomainSpecific = false;
|
||||
Boolean subdomainAccess = cmd.getSubdomainAccess();
|
||||
Long vpcId = cmd.getVpcId();
|
||||
String startIPv6 = cmd.getStartIpv6();
|
||||
String endIPv6 = cmd.getEndIpv6();
|
||||
String ip6Gateway = cmd.getIp6Gateway();
|
||||
String ip6Cidr = cmd.getIp6Cidr();
|
||||
Boolean displayNetwork = cmd.getDisplayNetwork();
|
||||
boolean displayNetwork = ! Boolean.FALSE.equals(cmd.getDisplayNetwork());
|
||||
Long aclId = cmd.getAclId();
|
||||
String isolatedPvlan = cmd.getIsolatedPvlan();
|
||||
String externalId = cmd.getExternalId();
|
||||
@ -1388,127 +1404,31 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
|
||||
String ip6Dns1 = cmd.getIp6Dns1();
|
||||
String ip6Dns2 = cmd.getIp6Dns2();
|
||||
|
||||
// Validate network offering
|
||||
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(), "networkOfferingId");
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
// Validate network offering id
|
||||
NetworkOffering ntwkOff = getAndValidateNetworkOffering(networkOfferingId);
|
||||
|
||||
Account owner = null;
|
||||
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;
|
||||
}
|
||||
Account owner = getOwningAccount(cmd, caller);
|
||||
|
||||
// validate physical network and zone
|
||||
// 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");
|
||||
}
|
||||
}
|
||||
PhysicalNetwork pNtwk = getAndValidatePhysicalNetwork(physicalNetworkId);
|
||||
|
||||
if (zoneId == null) {
|
||||
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");
|
||||
}
|
||||
DataCenter zone = getAndValidateZone(cmd, pNtwk);
|
||||
|
||||
_accountMgr.checkAccess(owner, ntwkOff, 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;
|
||||
}
|
||||
validateZoneAvailability(caller, zone);
|
||||
|
||||
// Only domain and account ACL types are supported in Acton.
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
ACLType aclType = getAclType(caller, cmd.getAclType(), ntwkOff);
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
// 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() != 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");
|
||||
}
|
||||
boolean isDomainSpecific = isDomainSpecificNetworkRequested(caller, domainId, subdomainAccess, ntwkOff, aclType);
|
||||
|
||||
if (aclType == ACLType.Domain) {
|
||||
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;
|
||||
if (zone.getNetworkType() == NetworkType.Advanced && ntwkOff.getGuestType() == GuestType.Isolated) {
|
||||
ipv6 = _networkOfferingDao.isIpv6Supported(ntwkOff.getId());
|
||||
@ -1682,7 +1603,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
|
||||
if (cidr != null && providersConfiguredForExternalNetworking(ntwkProviders)) {
|
||||
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
|
||||
checkSharedNetworkCidrOverlap(zoneId, pNtwk.getId(), cidr);
|
||||
checkSharedNetworkCidrOverlap(zone.getId(), pNtwk.getId(), cidr);
|
||||
} else {
|
||||
// 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.
|
||||
@ -1707,10 +1628,10 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
|
||||
|
||||
// Can add vlan range only to the network which allows it
|
||||
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);
|
||||
|
||||
Network associatedNetwork = null;
|
||||
@ -1729,9 +1650,12 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
|
||||
|
||||
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,
|
||||
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) {
|
||||
_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;
|
||||
}
|
||||
|
||||
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) {
|
||||
if (vpcId != null && publicMtu != null) {
|
||||
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) {
|
||||
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,
|
||||
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 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 Network associatedNetwork, final String ip4Dns1, final String ip4Dns2, final String ip6Dns1, final String ip6Dns2, Pair<Integer, Integer> vrIfaceMTUs) throws InsufficientCapacityException, ResourceAllocationException {
|
||||
try {
|
||||
@ -2373,7 +2504,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
|
||||
}
|
||||
|
||||
if (networkOfferingId != null) {
|
||||
sc.addAnd("networkOfferingId", SearchCriteria.Op.EQ, networkOfferingId);
|
||||
sc.addAnd(NETWORK_OFFERING_ID, SearchCriteria.Op.EQ, networkOfferingId);
|
||||
}
|
||||
|
||||
if (associatedNetworkId != null) {
|
||||
@ -2796,6 +2927,8 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
|
||||
_accountMgr.checkAccess(callerAccount, AccessType.OperateEntry, true, network);
|
||||
_accountMgr.checkAccess(_accountMgr.getActiveAccountById(network.getAccountId()), offering, _dcDao.findById(network.getDataCenterId()));
|
||||
|
||||
restartNetwork |= checkAndUpdateRouterSourceNatIp(cmd, network);
|
||||
|
||||
if (cmd instanceof UpdateNetworkCmdByAdmin) {
|
||||
final Boolean hideIpAddressUsage = ((UpdateNetworkCmdByAdmin) cmd).getHideIpAddressUsage();
|
||||
if (hideIpAddressUsage != null) {
|
||||
@ -2844,13 +2977,13 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
|
||||
NetworkOfferingVO networkOffering = _networkOfferingDao.findById(networkOfferingId);
|
||||
if (networkOfferingId != null) {
|
||||
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
|
||||
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(),
|
||||
"networkOfferingId");
|
||||
NETWORK_OFFERING_ID);
|
||||
}
|
||||
//can't update from vpc to non-vpc network offering
|
||||
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,
|
||||
ip6Dns1, ip6Dns2)) {
|
||||
restartNetwork = true;
|
||||
}
|
||||
restartNetwork |= checkAndUpdateNetworkDns(network, networkOfferingChanged ? networkOffering : oldNtwkOff, ip4Dns1, ip4Dns2,
|
||||
ip6Dns1, ip6Dns2);
|
||||
|
||||
final Map<String, String> newSvcProviders = networkOfferingChanged
|
||||
? _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()) {
|
||||
_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());
|
||||
}
|
||||
|
||||
@ -3647,7 +3778,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
|
||||
if (newNtwkOff == null || newNtwkOff.isSystemOnly()) {
|
||||
InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find network offering.");
|
||||
if (newNtwkOff != null) {
|
||||
ex.addProxyObject(String.valueOf(newNtwkOff.getId()), "networkOfferingId");
|
||||
ex.addProxyObject(String.valueOf(newNtwkOff.getId()), NETWORK_OFFERING_ID);
|
||||
}
|
||||
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.ListStaticRoutesCmd;
|
||||
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.UpdateVPCCmd;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
|
||||
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.lang3.ObjectUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
|
||||
@ -1017,7 +1020,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
||||
@Override
|
||||
@ActionEvent(eventType = EventTypes.EVENT_VPC_CREATE, eventDescription = "creating vpc", create = true)
|
||||
public Vpc createVpc(final long zoneId, final long vpcOffId, final long vpcOwnerId, final String vpcName, final String displayText, final String cidr, String networkDomain,
|
||||
final String ip4Dns1, final String ip4Dns2, final String ip6Dns1, final String ip6Dns2, final Boolean displayVpc, Integer publicMtu) throws ResourceAllocationException {
|
||||
final String ip4Dns1, final String ip4Dns2, final String ip6Dns1, final String ip6Dns2, final Boolean displayVpc, Integer publicMtu) throws ResourceAllocationException {
|
||||
final Account caller = CallContext.current().getCallingAccount();
|
||||
final Account owner = _accountMgr.getAccount(vpcOwnerId);
|
||||
|
||||
@ -1091,6 +1094,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
||||
final VpcVO vpc = new VpcVO(zoneId, vpcName, displayText, owner.getId(), owner.getDomainId(), vpcOffId, cidr, networkDomain, useDistributedRouter, isRegionLevelVpcOff,
|
||||
vpcOff.isRedundantRouter(), ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2);
|
||||
vpc.setPublicMtu(publicMtu);
|
||||
vpc.setDisplay(Boolean.TRUE.equals(displayVpc));
|
||||
|
||||
return createVpc(displayVpc, vpc);
|
||||
}
|
||||
@ -1098,9 +1102,24 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
||||
@Override
|
||||
@ActionEvent(eventType = EventTypes.EVENT_VPC_CREATE, eventDescription = "creating vpc", create = true)
|
||||
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.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
|
||||
@ -1126,10 +1145,6 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
||||
return Transaction.execute(new TransactionCallback<VpcVO>() {
|
||||
@Override
|
||||
public VpcVO doInTransaction(final TransactionStatus status) {
|
||||
if (displayVpc != null) {
|
||||
vpc.setDisplay(displayVpc);
|
||||
}
|
||||
|
||||
final VpcVO persistedVpc = vpcDao.persist(vpc, finalizeServicesAndProvidersForVpc(vpc.getZoneId(), vpc.getVpcOfferingId()));
|
||||
_resourceLimitMgr.incrementResourceCount(vpc.getAccountId(), ResourceType.vpc);
|
||||
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
|
||||
@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);
|
||||
final Account caller = CallContext.current().getCallingAccount();
|
||||
|
||||
@ -1279,14 +1299,80 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
||||
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);
|
||||
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);
|
||||
} else {
|
||||
s_logger.error(String.format("failed to update vpc %s/%s",vpc.getName(), vpc.getUuid()));
|
||||
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) {
|
||||
Long zoneId = vpcToUpdate.getZoneId();
|
||||
if (mtu == null || NetworkService.AllowUsersToSpecifyVRMtu.valueIn(zoneId)) {
|
||||
@ -1373,6 +1459,13 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
||||
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
|
||||
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,
|
||||
@ -1476,7 +1569,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
||||
final boolean listBySupportedServices = supportedServicesStr != null && !supportedServicesStr.isEmpty() && !vpcs.isEmpty();
|
||||
|
||||
if (listBySupportedServices) {
|
||||
final List<VpcVO> supportedVpcs = new ArrayList<VpcVO>();
|
||||
final List<Vpc> supportedVpcs = new ArrayList<>();
|
||||
Service[] supportedServices = null;
|
||||
|
||||
if (listBySupportedServices) {
|
||||
@ -1501,22 +1594,20 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
||||
|
||||
final List<? extends Vpc> wPagination = StringUtils.applyPagination(supportedVpcs, startIndex, pageSizeVal);
|
||||
if (wPagination != null) {
|
||||
final Pair<List<? extends Vpc>, Integer> listWPagination = new Pair<List<? extends Vpc>, Integer>(wPagination, supportedVpcs.size());
|
||||
return listWPagination;
|
||||
return new Pair<>(wPagination, supportedVpcs.size());
|
||||
}
|
||||
return new Pair<List<? extends Vpc>, Integer>(supportedVpcs, supportedVpcs.size());
|
||||
return new Pair<>(supportedVpcs, supportedVpcs.size());
|
||||
} else {
|
||||
final List<? extends Vpc> wPagination = StringUtils.applyPagination(vpcs, startIndex, pageSizeVal);
|
||||
if (wPagination != null) {
|
||||
final Pair<List<? extends Vpc>, Integer> listWPagination = new Pair<List<? extends Vpc>, Integer>(wPagination, vpcs.size());
|
||||
return listWPagination;
|
||||
return new Pair<>(wPagination, vpcs.size());
|
||||
}
|
||||
return new Pair<List<? extends Vpc>, Integer>(vpcs, vpcs.size());
|
||||
return new Pair<>(vpcs, vpcs.size());
|
||||
}
|
||||
}
|
||||
|
||||
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.Dns);
|
||||
services.add(Network.Service.UserData);
|
||||
|
||||
@ -37,6 +37,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.cloudstack.api.command.admin.network.CreateGuestNetworkIpv6PrefixCmd;
|
||||
@ -547,16 +548,68 @@ public class ConfigurationManagerTest {
|
||||
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
|
||||
public void validateEmptyStaticNatServiceCapablitiesTest() {
|
||||
Map<Capability, String> staticNatServiceCapabilityMap = new HashMap<Capability, String>();
|
||||
Map<Capability, String> staticNatServiceCapabilityMap = new HashMap<>();
|
||||
|
||||
configurationMgr.validateStaticNatServiceCapablities(staticNatServiceCapabilityMap);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateInvalidStaticNatServiceCapablitiesTest() {
|
||||
Map<Capability, String> staticNatServiceCapabilityMap = new HashMap<Capability, String>();
|
||||
Map<Capability, String> staticNatServiceCapabilityMap = new HashMap<>();
|
||||
staticNatServiceCapabilityMap.put(Capability.AssociatePublicIP, "Frue and Talse");
|
||||
|
||||
boolean caught = false;
|
||||
@ -569,9 +622,43 @@ public class ConfigurationManagerTest {
|
||||
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
|
||||
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.ElasticIp, "True");
|
||||
|
||||
@ -580,7 +667,7 @@ public class ConfigurationManagerTest {
|
||||
|
||||
@Test
|
||||
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.ElasticIp, "True");
|
||||
|
||||
@ -589,7 +676,7 @@ public class ConfigurationManagerTest {
|
||||
|
||||
@Test
|
||||
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.ElasticIp, "false");
|
||||
|
||||
@ -608,7 +695,7 @@ public class ConfigurationManagerTest {
|
||||
|
||||
@Test
|
||||
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.ElasticIp, "False");
|
||||
|
||||
|
||||
@ -23,11 +23,13 @@ import static org.mockito.Matchers.anyLong;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
|
||||
import com.cloud.user.Account;
|
||||
import org.junit.Assert;
|
||||
@ -230,4 +232,14 @@ public class IpAddressManagerTest {
|
||||
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;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.nullable;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
import static org.mockito.Mockito.mock;
|
||||
@ -34,6 +36,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.cloud.exception.InsufficientAddressCapacityException;
|
||||
import org.apache.cloudstack.alert.AlertService;
|
||||
import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd;
|
||||
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.user.Account;
|
||||
import com.cloud.user.AccountManager;
|
||||
import com.cloud.user.AccountManagerImpl;
|
||||
import com.cloud.user.AccountService;
|
||||
import com.cloud.user.AccountVO;
|
||||
import com.cloud.user.User;
|
||||
@ -122,8 +124,6 @@ public class NetworkServiceImplTest {
|
||||
@Mock
|
||||
NetworkOfferingServiceMapDao networkOfferingServiceMapDao;
|
||||
@Mock
|
||||
AccountManager accountMgr;
|
||||
@Mock
|
||||
EntityManager entityMgr;
|
||||
@Mock
|
||||
NetworkService networkService;
|
||||
@ -162,8 +162,8 @@ public class NetworkServiceImplTest {
|
||||
@Mock
|
||||
ServiceOfferingVO serviceOfferingVoMock;
|
||||
|
||||
@InjectMocks
|
||||
AccountManagerImpl accountManagerImpl;
|
||||
@Mock
|
||||
IpAddressManager ipAddressManager;
|
||||
@Mock
|
||||
ConfigKey<Integer> privateMtuKey;
|
||||
@Mock
|
||||
@ -223,7 +223,7 @@ public class NetworkServiceImplTest {
|
||||
service._networkOfferingDao = networkOfferingDao;
|
||||
service._physicalNetworkDao = physicalNetworkDao;
|
||||
service._dcDao = dcDao;
|
||||
service._accountMgr = accountMgr;
|
||||
service._accountMgr = accountManager;
|
||||
service._networkMgr = networkManager;
|
||||
service.alertManager = alertManager;
|
||||
service._configMgr = configMgr;
|
||||
@ -236,6 +236,7 @@ public class NetworkServiceImplTest {
|
||||
service.routerDao = routerDao;
|
||||
service.commandSetupHelper = commandSetupHelper;
|
||||
service.networkHelper = networkHelper;
|
||||
service._ipAddrMgr = ipAddressManager;
|
||||
PowerMockito.mockStatic(CallContext.class);
|
||||
CallContext callContextMock = PowerMockito.mock(CallContext.class);
|
||||
PowerMockito.when(CallContext.current()).thenReturn(callContextMock);
|
||||
@ -248,8 +249,8 @@ public class NetworkServiceImplTest {
|
||||
Mockito.when(networkOfferingDao.findById(1L)).thenReturn(offering);
|
||||
Mockito.when(physicalNetworkDao.findById(Mockito.anyLong())).thenReturn(phyNet);
|
||||
Mockito.when(dcDao.findById(Mockito.anyLong())).thenReturn(dc);
|
||||
Mockito.lenient().doNothing().when(accountMgr).checkAccess(accountMock, networkOffering, dc);
|
||||
Mockito.when(accountMgr.isRootAdmin(accountMock.getId())).thenReturn(true);
|
||||
Mockito.lenient().doNothing().when(accountManager).checkAccess(accountMock, networkOffering, dc);
|
||||
Mockito.when(accountManager.isRootAdmin(accountMock.getId())).thenReturn(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -352,6 +353,7 @@ public class NetworkServiceImplTest {
|
||||
ReflectionTestUtils.setField(createNetworkCmd, "privateMtu", privateMtu);
|
||||
ReflectionTestUtils.setField(createNetworkCmd, "physicalNetworkId", null);
|
||||
Mockito.when(offering.isSystemOnly()).thenReturn(false);
|
||||
Mockito.when(dc.getId()).thenReturn(1L);
|
||||
Mockito.when(dc.getAllocationState()).thenReturn(Grouping.AllocationState.Enabled);
|
||||
Map<String, String> networkProvidersMap = new HashMap<String, String>();
|
||||
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, "physicalNetworkId", null);
|
||||
ReflectionTestUtils.setField(createNetworkCmd, "vpcId", 1L);
|
||||
Mockito.when(dc.getId()).thenReturn(1L);
|
||||
Mockito.when(configMgr.isOfferingForVpc(offering)).thenReturn(true);
|
||||
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() {
|
||||
registerCallContext();
|
||||
CreateNetworkCmd cmd = Mockito.mock(CreateNetworkCmd.class);
|
||||
@ -577,7 +580,7 @@ public class NetworkServiceImplTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = InvalidParameterValueException.class)
|
||||
@Test(expected = CloudRuntimeException.class)
|
||||
public void testCreateIp4NetworkIp6DnsFailure() {
|
||||
registerCallContext();
|
||||
CreateNetworkCmd cmd = Mockito.mock(CreateNetworkCmd.class);
|
||||
@ -770,4 +773,143 @@ public class NetworkServiceImplTest {
|
||||
|
||||
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.network.NetworkService;
|
||||
import com.cloud.network.dao.FirewallRulesDao;
|
||||
import org.apache.cloudstack.acl.SecurityChecker;
|
||||
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.engine.orchestration.service.NetworkOrchestrationService;
|
||||
import org.junit.After;
|
||||
@ -149,6 +151,8 @@ public class VpcManagerImplTest {
|
||||
AlertManager alertManager;
|
||||
@Mock
|
||||
NetworkService networkServiceMock;
|
||||
@Mock
|
||||
FirewallRulesDao firewallDao;
|
||||
|
||||
public static final long ACCOUNT_ID = 1;
|
||||
private AccountVO account;
|
||||
@ -200,6 +204,7 @@ public class VpcManagerImplTest {
|
||||
manager._vpcOffDao = vpcOfferingDao;
|
||||
manager._dcDao = dataCenterDao;
|
||||
manager._ntwkSvc = networkServiceMock;
|
||||
manager._firewallDao = firewallDao;
|
||||
CallContext.register(Mockito.mock(User.class), Mockito.mock(Account.class));
|
||||
registerCallContext();
|
||||
}
|
||||
@ -354,9 +359,10 @@ public class VpcManagerImplTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateVpcNetwork() throws ResourceUnavailableException {
|
||||
public void testUpdateVpcNetwork() throws ResourceUnavailableException, InsufficientCapacityException {
|
||||
long vpcId = 1L;
|
||||
Integer publicMtu = 1450;
|
||||
String sourceNatIp = "1.2.3.4";
|
||||
Account accountMock = Mockito.mock(Account.class);
|
||||
VpcVO vpcVO = new VpcVO();
|
||||
|
||||
@ -398,9 +404,31 @@ public class VpcManagerImplTest {
|
||||
Mockito.when(networkDao.update(anyLong(), any())).thenReturn(true);
|
||||
Mockito.when(vpcDao.update(vpcId, vpcVO)).thenReturn(true);
|
||||
|
||||
manager.updateVpc(vpcId, null, null, null, true, publicMtu);
|
||||
Assert.assertEquals(publicMtu, vpcVO.getPublicMtu());
|
||||
UpdateVPCCmd cmd = Mockito.mock(UpdateVPCCmd.class);
|
||||
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
|
||||
|
||||
@ -72,9 +72,6 @@ logger.addHandler(stream_handler)
|
||||
|
||||
class TestPublicIP(cloudstackTestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.apiclient = self.testClient.getApiClient()
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
testClient = super(TestPublicIP, cls).getClsTestClient()
|
||||
@ -85,6 +82,7 @@ class TestPublicIP(cloudstackTestCase):
|
||||
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,
|
||||
@ -92,18 +90,21 @@ class TestPublicIP(cloudstackTestCase):
|
||||
admin=True,
|
||||
domainid=cls.domain.id
|
||||
)
|
||||
cls._cleanup.append(cls.account)
|
||||
|
||||
cls.user = Account.create(
|
||||
cls.apiclient,
|
||||
cls.services["account"],
|
||||
domainid=cls.domain.id
|
||||
)
|
||||
cls._cleanup.append(cls.user)
|
||||
cls.services["network"]["zoneid"] = cls.zone.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')
|
||||
|
||||
@ -114,17 +115,20 @@ class TestPublicIP(cloudstackTestCase):
|
||||
cls.account.name,
|
||||
cls.account.domainid
|
||||
)
|
||||
cls._cleanup.append(cls.account_network)
|
||||
cls.user_network = Network.create(
|
||||
cls.apiclient,
|
||||
cls.services["network"],
|
||||
cls.user.name,
|
||||
cls.user.domainid
|
||||
)
|
||||
cls._cleanup.append(cls.user_network)
|
||||
|
||||
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(
|
||||
@ -146,6 +150,7 @@ class TestPublicIP(cloudstackTestCase):
|
||||
networkids=cls.account_network.id,
|
||||
serviceofferingid=cls.service_offering.id
|
||||
)
|
||||
cls._cleanup.append(cls.account_vm)
|
||||
|
||||
cls.user_vm = VirtualMachine.create(
|
||||
cls.apiclient,
|
||||
@ -156,6 +161,7 @@ class TestPublicIP(cloudstackTestCase):
|
||||
networkids=cls.user_network.id,
|
||||
serviceofferingid=cls.service_offering.id
|
||||
)
|
||||
cls._cleanup.append(cls.user_vm)
|
||||
|
||||
# Create Source NAT IP addresses
|
||||
PublicIPAddress.create(
|
||||
@ -170,25 +176,11 @@ class TestPublicIP(cloudstackTestCase):
|
||||
cls.zone.id,
|
||||
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
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
try:
|
||||
# Cleanup resources used
|
||||
cleanup_resources(cls.apiclient, cls._cleanup)
|
||||
except Exception as e:
|
||||
raise Exception("Warning: Exception during cleanup : %s" % e)
|
||||
return
|
||||
super(TestPublicIP, cls).tearDownClass()
|
||||
|
||||
@attr(tags=["advanced", "advancedns", "smoke", "dvs"], required_hardware="false")
|
||||
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,
|
||||
subdomainaccess=None, zoneid=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"""
|
||||
cmd = createNetwork.createNetworkCmd()
|
||||
cmd.name = services["name"]
|
||||
@ -3567,6 +3568,8 @@ class Network:
|
||||
cmd.publicmtu = publicmtu
|
||||
if privatemtu:
|
||||
cmd.privatemtu = privatemtu
|
||||
if sourcenatipaddress:
|
||||
cmd.sourcenatipaddress = sourcenatipaddress
|
||||
return Network(apiclient.createNetwork(cmd).__dict__)
|
||||
|
||||
def delete(self, apiclient):
|
||||
|
||||
@ -1578,6 +1578,8 @@
|
||||
"label.shared": "Κοινόχρηστο",
|
||||
"label.sharedexecutable": "Κοινόχρηστο",
|
||||
"label.sharedmountpoint": "Κοινόχρηστο μέσο",
|
||||
"label.sharedrouterip": "Διεύθυνση IPv4 του δρομολογητή στο κοινόχρηστο δίκτυο ",
|
||||
"label.sharedrouteripv6": "Διεύθυνση IPv6 του δρομολογητή στο κοινόχρηστο δίκτυο",
|
||||
"label.sharewith": "Κοινή χρήση με",
|
||||
"label.showing": "Προβολή",
|
||||
"label.shrinkok": "Συρρίκνωση OK",
|
||||
|
||||
@ -165,6 +165,7 @@
|
||||
"label.action.router.health.checks": "Get health checks result",
|
||||
"label.action.run.diagnostics": "Run diagnostics",
|
||||
"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.start.instance": "Start instance",
|
||||
"label.action.start.router": "Start router",
|
||||
@ -915,6 +916,7 @@
|
||||
"label.haenable": "HA enabled",
|
||||
"label.haprovider": "HA provider",
|
||||
"label.hardware": "Hardware",
|
||||
"label.hasrules":"FW rules defined",
|
||||
"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.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.checks": "Health checks",
|
||||
"label.routercount": "Total of virtual routers",
|
||||
"label.routerip": "IPv4 address for the VR in this shared network.",
|
||||
"label.routeripv6": "IPv6 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 network.",
|
||||
"label.resourcegroup": "Resource group",
|
||||
"label.routing.policy": "Routing policy",
|
||||
"label.routing.policy.terms": "Routing policy terms",
|
||||
@ -1775,6 +1777,8 @@
|
||||
"label.shared": "Shared",
|
||||
"label.sharedexecutable": "Shared",
|
||||
"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.showing": "Showing",
|
||||
"label.shrinkok": "Shrink OK",
|
||||
@ -1803,6 +1807,7 @@
|
||||
"label.sourceipaddress": "Source IP address",
|
||||
"label.sourceipaddressnetworkid": "Network ID of source IP address",
|
||||
"label.sourcenat": "Source NAT",
|
||||
"label.sourcenatipaddress": "Source NAT IP address",
|
||||
"label.sourcenatsupported": "Source NAT supported",
|
||||
"label.sourcenattype": "Supported source NAT type",
|
||||
"label.sourceport": "Source port",
|
||||
@ -1854,6 +1859,7 @@
|
||||
"label.startport": "Start port",
|
||||
"label.startquota": "Quota value",
|
||||
"label.state": "State",
|
||||
"label.staticnat": "Static NAT",
|
||||
"label.static.routes": "Static routes",
|
||||
"label.status": "Status",
|
||||
"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.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.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.value": "Please specify a tag value.",
|
||||
"message.step.2.continue": "Please select a service offering to continue.",
|
||||
|
||||
@ -2046,6 +2046,8 @@
|
||||
"label.shared": "共有",
|
||||
"label.sharedexecutable": "共有",
|
||||
"label.sharedmountpoint": "SharedMountPoint",
|
||||
"label.sharedrouterip": "共有ネットワークのルーターのIPv4アドレス",
|
||||
"label.sharedrouteripv6": "共有ネットワークのルーターのIPv6アドレス",
|
||||
"label.sharewith": "共有",
|
||||
"label.show.ingress.rule": "受信ルールの表示",
|
||||
"label.showing": "表示中",
|
||||
|
||||
@ -1373,6 +1373,8 @@
|
||||
"label.shared": "shared",
|
||||
"label.sharedexecutable": "\uacf5\uc720",
|
||||
"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.showing": "\ubcf4\uae30",
|
||||
"label.shrinkok": "\ubcc0\uacbd \uc644\ub8cc",
|
||||
|
||||
@ -1468,6 +1468,8 @@
|
||||
"label.shared": "Compatilhado",
|
||||
"label.sharedexecutable": "Compatilhado",
|
||||
"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.showing": "Exibindo",
|
||||
"label.shrinkok": "Encolhimento OK",
|
||||
|
||||
@ -2333,6 +2333,8 @@
|
||||
"label.shared": "\u5DF2\u5171\u4EAB",
|
||||
"label.sharedexecutable": "\u5DF2\u5171\u4EAB",
|
||||
"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.show.ingress.rule": "\u663E\u793A\u5165\u53E3\u89C4\u5219",
|
||||
|
||||
@ -228,7 +228,7 @@ export default {
|
||||
icon: 'edit-outlined',
|
||||
label: 'label.edit',
|
||||
dataView: true,
|
||||
args: ['name', 'displaytext', 'publicmtu']
|
||||
args: ['name', 'displaytext', 'publicmtu', 'sourcenatipaddress']
|
||||
},
|
||||
{
|
||||
api: 'restartVPC',
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
// under the License.
|
||||
|
||||
import {
|
||||
AimOutlined,
|
||||
ApartmentOutlined,
|
||||
ApiOutlined,
|
||||
AppstoreOutlined,
|
||||
@ -170,6 +171,7 @@ import renderIcon from '@/utils/renderIcon'
|
||||
|
||||
export default {
|
||||
install: (app) => {
|
||||
app.component('AimOutlined', AimOutlined)
|
||||
app.component('ApartmentOutlined', ApartmentOutlined)
|
||||
app.component('ApiOutlined', ApiOutlined)
|
||||
app.component('AppstoreOutlined', AppstoreOutlined)
|
||||
|
||||
@ -291,6 +291,36 @@
|
||||
</a-col>
|
||||
</a-row>
|
||||
</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">
|
||||
<a-button
|
||||
:loading="actionLoading"
|
||||
@ -397,6 +427,14 @@ export default {
|
||||
return dnsServices && dnsServices.length === 1
|
||||
}
|
||||
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: {
|
||||
@ -596,7 +634,7 @@ export default {
|
||||
displayText: values.displaytext,
|
||||
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) {
|
||||
if (this.isValidTextValueForKey(values, field)) {
|
||||
params[field] = values[field]
|
||||
|
||||
@ -155,6 +155,14 @@
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</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">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.start')" :tooltip="apiParams.start.description"/>
|
||||
@ -212,6 +220,14 @@ export default {
|
||||
return dnsServices && dnsServices.length === 1
|
||||
}
|
||||
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: {
|
||||
@ -274,6 +290,10 @@ export default {
|
||||
this.selectedVpcOffering = this.vpcOfferings[0] || {}
|
||||
}).finally(() => {
|
||||
this.loadingOffering = false
|
||||
if (this.vpcOfferings.length > 0) {
|
||||
this.form.vpcofferingid = 0
|
||||
this.handleVpcOfferingChange(this.vpcOfferings[0].id)
|
||||
}
|
||||
})
|
||||
},
|
||||
handleVpcOfferingChange (value) {
|
||||
@ -284,6 +304,7 @@ export default {
|
||||
for (var offering of this.vpcOfferings) {
|
||||
if (offering.id === value) {
|
||||
this.selectedVpcOffering = offering
|
||||
this.form.vpcofferingid = offering.id
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,9 +67,29 @@
|
||||
:pagination="false" >
|
||||
<template #bodyCell="{ column, text, record }">
|
||||
<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>
|
||||
<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 v-if="column.key === 'state'">
|
||||
@ -150,6 +170,24 @@
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</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
|
||||
v-if="showConfirmationAction || showGroupActionModal"
|
||||
:showConfirmationAction="showConfirmationAction"
|
||||
@ -167,6 +205,7 @@
|
||||
@close-modal="closeModal" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { api } from '@/api'
|
||||
import Status from '@/components/widgets/Status'
|
||||
@ -242,7 +281,8 @@ export default {
|
||||
showAcquireIp: false,
|
||||
acquireLoading: false,
|
||||
acquireIp: null,
|
||||
listPublicIpAddress: []
|
||||
listPublicIpAddress: [],
|
||||
changeSourceNat: false
|
||||
}
|
||||
},
|
||||
created () {
|
||||
@ -315,6 +355,50 @@ export default {
|
||||
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 () {
|
||||
this.setSelection([])
|
||||
},
|
||||
@ -482,6 +566,13 @@ export default {
|
||||
},
|
||||
closeModal () {
|
||||
this.showConfirmationAction = false
|
||||
},
|
||||
showChangeSourceNat (ipaddress) {
|
||||
this.changeSourceNat = true
|
||||
this.sourceNatIp = ipaddress
|
||||
},
|
||||
cancelChangeSourceNat () {
|
||||
this.changeSourceNat = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,6 +80,24 @@
|
||||
</a-col>
|
||||
</a-row>
|
||||
</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">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.networkofferingid')" :tooltip="apiParams.networkofferingid.description"/>
|
||||
@ -238,7 +256,8 @@ export default {
|
||||
minMTU: 68,
|
||||
errorPrivateMtu: '',
|
||||
errorPublicMtu: '',
|
||||
setMTU: false
|
||||
setMTU: false,
|
||||
sourcenatchange: false
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user