Merge remote-tracking branch 'origin/4.15'

Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
This commit is contained in:
Rohit Yadav 2021-04-01 14:35:01 +05:30
commit d4635e3442
42 changed files with 1581 additions and 342 deletions

View File

@ -164,6 +164,7 @@ env:
- TESTS="component/test_project_usage
component/test_protocol_number_security_group
component/test_public_ip
component/test_resource_limits"
- TESTS="component/test_regions_accounts

View File

@ -27,6 +27,7 @@ import com.cloud.exception.ResourceUnavailableException;
import com.cloud.network.router.VirtualRouter;
import com.cloud.user.Account;
import com.cloud.utils.Pair;
import com.cloud.vm.Nic;
public interface VirtualNetworkApplianceService {
/**
@ -75,4 +76,6 @@ public interface VirtualNetworkApplianceService {
* @return
*/
Pair<Boolean, String> performRouterHealthChecks(long routerId);
<T extends VirtualRouter> void collectNetworkStatistics(T router, Nic nic);
}

View File

@ -18,8 +18,6 @@ package org.apache.cloudstack.api.response;
import java.util.Date;
import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
import org.apache.cloudstack.api.EntityReference;
@ -28,6 +26,7 @@ import com.cloud.host.Host;
import com.cloud.host.Status;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
@EntityReference(value = Host.class)
public class HostForMigrationResponse extends BaseResponse {
@ -452,6 +451,10 @@ public class HostForMigrationResponse extends BaseResponse {
this.hypervisorVersion = hypervisorVersion;
}
public Boolean getHaHost() {
return haHost;
}
public void setHaHost(Boolean haHost) {
this.haHost = haHost;
}

View File

@ -209,7 +209,7 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co
private Long memoryKBs;
@SerializedName("memoryintfreekbs")
@Param(description = "the internal memory thats free in vm")
@Param(description = "the internal memory that's free in vm or zero if it can not be calculated")
private Long memoryIntFreeKBs;
@SerializedName("memorytargetkbs")

View File

@ -208,5 +208,22 @@ public interface IpAddressManager {
void releasePodIp(Long id) throws CloudRuntimeException;
boolean isUsageHidden(IPAddressVO address);
List<IPAddressVO> listAvailablePublicIps(final long dcId,
final Long podId,
final List<Long> vlanDbIds,
final Account owner,
final VlanType vlanUse,
final Long guestNetworkId,
final boolean sourceNat,
final boolean assign,
final boolean allocate,
final String requestedIp,
final boolean isSystem,
final Long vpcId,
final Boolean displayIp,
final boolean forSystemVms,
final boolean lockOneRow)
throws InsufficientAddressCapacityException;
}

View File

@ -383,6 +383,7 @@ public class DomainRouterDaoImpl extends GenericDaoBase<DomainRouterVO, Long> im
final RouterNetworkVO routerNtwkMap = new RouterNetworkVO(router.getId(), guestNetwork.getId(), guestNetwork.getGuestType());
_routerNetworkDao.persist(routerNtwkMap);
//2) create user stats entry for the network
if (router.getVpcId() == null) {
UserStatisticsVO stats =
_userStatsDao.findBy(router.getAccountId(), router.getDataCenterId(), guestNetwork.getId(), null, router.getId(), router.getType().toString());
if (stats == null) {
@ -390,6 +391,7 @@ public class DomainRouterDaoImpl extends GenericDaoBase<DomainRouterVO, Long> im
new UserStatisticsVO(router.getAccountId(), router.getDataCenterId(), null, router.getId(), router.getType().toString(), guestNetwork.getId());
_userStatsDao.persist(stats);
}
}
txn.commit();
}
}

View File

@ -27,6 +27,8 @@ import java.util.Set;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import com.cloud.vm.NicVO;
import com.cloud.vm.dao.NicDao;
import org.apache.cloudstack.acl.Role;
import org.apache.cloudstack.acl.RoleService;
import org.apache.cloudstack.affinity.AffinityGroup;
@ -459,6 +461,7 @@ public class ApiDBUtils {
static BackupDao s_backupDao;
static BackupScheduleDao s_backupScheduleDao;
static BackupOfferingDao s_backupOfferingDao;
static NicDao s_nicDao;
@Inject
private ManagementServer ms;
@ -703,6 +706,8 @@ public class ApiDBUtils {
private BackupOfferingDao backupOfferingDao;
@Inject
private BackupScheduleDao backupScheduleDao;
@Inject
private NicDao nicDao;
@PostConstruct
void init() {
@ -812,6 +817,7 @@ public class ApiDBUtils {
s_hostDetailsDao = hostDetailsDao;
s_clusterDetailsDao = clusterDetailsDao;
s_vmSnapshotDao = vmSnapshotDao;
s_nicDao = nicDao;
s_nicSecondaryIpDao = nicSecondaryIpDao;
s_vpcProvSvc = vpcProvSvc;
s_affinityGroupDao = affinityGroupDao;
@ -2090,4 +2096,12 @@ public class ApiDBUtils {
public static BackupOfferingResponse newBackupOfferingResponse(BackupOffering policy) {
return s_backupOfferingDao.newBackupOfferingResponse(policy);
}
public static NicVO findByIp4AddressAndNetworkId(String ip4Address, long networkId) {
return s_nicDao.findByIp4AddressAndNetworkId(ip4Address, networkId);
}
public static NicSecondaryIpVO findSecondaryIpByIp4AddressAndNetworkId(String ip4Address, long networkId) {
return s_nicSecondaryIpDao.findByIp4AddressAndNetworkId(ip4Address, networkId);
}
}

View File

@ -921,6 +921,9 @@ public class ApiResponseHelper implements ResponseGenerator {
}
}
// show vm info for shared networks
showVmInfoForSharedNetworks(forVirtualNetworks, ipAddr, ipResponse);
// show this info to full view only
if (view == ResponseView.Full) {
VlanVO vl = ApiDBUtils.findVlanById(ipAddr.getVlanId());
@ -955,6 +958,42 @@ public class ApiResponseHelper implements ResponseGenerator {
return ipResponse;
}
private void showVmInfoForSharedNetworks(boolean forVirtualNetworks, IpAddress ipAddr, IPAddressResponse ipResponse) {
if (!forVirtualNetworks) {
NicVO nic = ApiDBUtils.findByIp4AddressAndNetworkId(ipAddr.getAddress().toString(), ipAddr.getNetworkId());
if (nic == null) { // find in nic_secondary_ips, user vm only
NicSecondaryIpVO secondaryIp =
ApiDBUtils.findSecondaryIpByIp4AddressAndNetworkId(ipAddr.getAddress().toString(), ipAddr.getNetworkId());
if (secondaryIp != null) {
UserVm vm = ApiDBUtils.findUserVmById(secondaryIp.getVmId());
if (vm != null) {
ipResponse.setVirtualMachineId(vm.getUuid());
ipResponse.setVirtualMachineName(vm.getHostName());
if (vm.getDisplayName() != null) {
ipResponse.setVirtualMachineDisplayName(vm.getDisplayName());
} else {
ipResponse.setVirtualMachineDisplayName(vm.getHostName());
}
}
}
} else if (nic.getVmType() == VirtualMachine.Type.User) {
UserVm vm = ApiDBUtils.findUserVmById(nic.getInstanceId());
if (vm != null) {
ipResponse.setVirtualMachineId(vm.getUuid());
ipResponse.setVirtualMachineName(vm.getHostName());
if (vm.getDisplayName() != null) {
ipResponse.setVirtualMachineDisplayName(vm.getDisplayName());
} else {
ipResponse.setVirtualMachineDisplayName(vm.getHostName());
}
}
} else if (nic.getVmType() == VirtualMachine.Type.DomainRouter) {
ipResponse.setIsSystem(true);
}
}
}
@Override
public LoadBalancerResponse createLoadBalancerResponse(LoadBalancer loadBalancer) {
LoadBalancerResponse lbResponse = new LoadBalancerResponse();

View File

@ -26,16 +26,18 @@ import java.util.Set;
import javax.inject.Inject;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import org.apache.cloudstack.api.ApiConstants.HostDetails;
import org.apache.cloudstack.api.response.GpuResponse;
import org.apache.cloudstack.api.response.HostForMigrationResponse;
import org.apache.cloudstack.api.response.HostResponse;
import org.apache.cloudstack.api.response.VgpuResponse;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.ha.HAResource;
import org.apache.cloudstack.ha.dao.HAConfigDao;
import org.apache.cloudstack.outofbandmanagement.dao.OutOfBandManagementDao;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import com.cloud.api.ApiDBUtils;
import com.cloud.api.query.vo.HostJoinVO;
@ -52,9 +54,6 @@ import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import org.apache.cloudstack.ha.HAResource;
import org.apache.cloudstack.ha.dao.HAConfigDao;
@Component
public class HostJoinDaoImpl extends GenericDaoBase<HostJoinVO, Long> implements HostJoinDao {
public static final Logger s_logger = Logger.getLogger(HostJoinDaoImpl.class);
@ -178,17 +177,13 @@ public class HostJoinDaoImpl extends GenericDaoBase<HostJoinVO, Long> implements
hostResponse.setMemoryAllocatedPercentage(memoryAllocatedPercentage);
String hostTags = host.getTag();
hostResponse.setHostTags(host.getTag());
hostResponse.setHostTags(hostTags);
hostResponse.setHaHost(false);
String haTag = ApiDBUtils.getHaTag();
if (haTag != null && !haTag.isEmpty() && hostTags != null && !hostTags.isEmpty()) {
if (haTag.equalsIgnoreCase(hostTags)) {
if (StringUtils.isNotEmpty(haTag) && StringUtils.isNotEmpty(hostTags) &&
haTag.equalsIgnoreCase(hostTags)) {
hostResponse.setHaHost(true);
} else {
hostResponse.setHaHost(false);
}
} else {
hostResponse.setHaHost(false);
}
hostResponse.setHypervisorVersion(host.getHypervisorVersion());
@ -274,12 +269,19 @@ public class HostJoinDaoImpl extends GenericDaoBase<HostJoinVO, Long> implements
@Override
public HostResponse setHostResponse(HostResponse response, HostJoinVO host) {
String tag = host.getTag();
if (tag != null) {
if (response.getHostTags() != null && response.getHostTags().length() > 0) {
if (StringUtils.isNotEmpty(tag)) {
if (StringUtils.isNotEmpty(response.getHostTags())) {
response.setHostTags(response.getHostTags() + "," + tag);
} else {
response.setHostTags(tag);
}
if (Boolean.FALSE.equals(response.getHaHost())) {
String haTag = ApiDBUtils.getHaTag();
if (StringUtils.isNotEmpty(haTag) && haTag.equalsIgnoreCase(tag)) {
response.setHaHost(true);
}
}
}
return response;
}
@ -334,17 +336,13 @@ public class HostJoinDaoImpl extends GenericDaoBase<HostJoinVO, Long> implements
hostResponse.setMemoryAllocatedBytes(mem);
String hostTags = host.getTag();
hostResponse.setHostTags(host.getTag());
hostResponse.setHostTags(hostTags);
hostResponse.setHaHost(false);
String haTag = ApiDBUtils.getHaTag();
if (haTag != null && !haTag.isEmpty() && hostTags != null && !hostTags.isEmpty()) {
if (haTag.equalsIgnoreCase(hostTags)) {
if (StringUtils.isNotEmpty(haTag) && StringUtils.isNotEmpty(hostTags) &&
haTag.equalsIgnoreCase(hostTags)) {
hostResponse.setHaHost(true);
} else {
hostResponse.setHaHost(false);
}
} else {
hostResponse.setHaHost(false);
}
hostResponse.setHypervisorVersion(host.getHypervisorVersion());
@ -419,6 +417,13 @@ public class HostJoinDaoImpl extends GenericDaoBase<HostJoinVO, Long> implements
} else {
response.setHostTags(tag);
}
if (Boolean.FALSE.equals(response.getHaHost())) {
String haTag = ApiDBUtils.getHaTag();
if (StringUtils.isNotEmpty(haTag) && haTag.equalsIgnoreCase(tag)) {
response.setHaHost(true);
}
}
}
return response;
}

View File

@ -222,8 +222,11 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJo
userVmResponse.setDiskKbsWrite((long)vmStats.getDiskWriteKBs());
userVmResponse.setDiskIORead((long)vmStats.getDiskReadIOs());
userVmResponse.setDiskIOWrite((long)vmStats.getDiskWriteIOs());
userVmResponse.setMemoryKBs((long)vmStats.getMemoryKBs());
userVmResponse.setMemoryIntFreeKBs((long)vmStats.getIntFreeMemoryKBs());
long totalMemory = (long)vmStats.getMemoryKBs();
long freeMemory = (long)vmStats.getIntFreeMemoryKBs();
long correctedFreeMemory = freeMemory >= totalMemory ? 0 : freeMemory;
userVmResponse.setMemoryKBs(totalMemory);
userVmResponse.setMemoryIntFreeKBs(correctedFreeMemory);
userVmResponse.setMemoryTargetKBs((long)vmStats.getTargetMemoryKBs());
}

View File

@ -323,31 +323,30 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
}
}
for (final IPAddressVO possibleAddr : addressVOS) {
for (IPAddressVO possibleAddr : addressVOS) {
if (possibleAddr.getState() != State.Free) {
continue;
}
final IPAddressVO addressVO = possibleAddr;
addressVO.setSourceNat(sourceNat);
addressVO.setAllocatedTime(new Date());
addressVO.setAllocatedInDomainId(owner.getDomainId());
addressVO.setAllocatedToAccountId(owner.getId());
addressVO.setSystem(isSystem);
possibleAddr.setSourceNat(sourceNat);
possibleAddr.setAllocatedTime(new Date());
possibleAddr.setAllocatedInDomainId(owner.getDomainId());
possibleAddr.setAllocatedToAccountId(owner.getId());
possibleAddr.setSystem(isSystem);
if (displayIp != null) {
addressVO.setDisplay(displayIp);
possibleAddr.setDisplay(displayIp);
}
if (vlanUse != VlanType.DirectAttached) {
addressVO.setAssociatedWithNetworkId(guestNetworkId);
addressVO.setVpcId(vpcId);
possibleAddr.setAssociatedWithNetworkId(guestNetworkId);
possibleAddr.setVpcId(vpcId);
}
if (_ipAddressDao.lockRow(possibleAddr.getId(), true) != null) {
final IPAddressVO userIp = _ipAddressDao.findById(addressVO.getId());
final IPAddressVO userIp = _ipAddressDao.findById(possibleAddr.getId());
if (userIp.getState() == State.Free) {
addressVO.setState(State.Allocating);
if (_ipAddressDao.update(addressVO.getId(), addressVO)) {
finalAddress = addressVO;
possibleAddr.setState(State.Allocating);
if (_ipAddressDao.update(possibleAddr.getId(), possibleAddr)) {
finalAddress = possibleAddr;
break;
}
}
@ -784,9 +783,22 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
public PublicIp fetchNewPublicIp(final long dcId, final Long podId, final List<Long> vlanDbIds, final Account owner, final VlanType vlanUse, final Long guestNetworkId,
final boolean sourceNat, final boolean assign, final boolean allocate, final String requestedIp, final boolean isSystem, final Long vpcId, final Boolean displayIp, final boolean forSystemVms)
throws InsufficientAddressCapacityException {
IPAddressVO addr = Transaction.execute(new TransactionCallbackWithException<IPAddressVO, InsufficientAddressCapacityException>() {
List<IPAddressVO> addrs = listAvailablePublicIps(dcId, podId, vlanDbIds, owner, vlanUse, guestNetworkId, sourceNat, assign, allocate, requestedIp, isSystem, vpcId, displayIp, forSystemVms, true);
IPAddressVO addr = addrs.get(0);
if (vlanUse == VlanType.VirtualNetwork) {
_firewallMgr.addSystemFirewallRules(addr, owner);
}
return PublicIp.createFromAddrAndVlan(addr, _vlanDao.findById(addr.getVlanId()));
}
@Override
public IPAddressVO doInTransaction(TransactionStatus status) throws InsufficientAddressCapacityException {
public List<IPAddressVO> listAvailablePublicIps(final long dcId, final Long podId, final List<Long> vlanDbIds, final Account owner, final VlanType vlanUse, final Long guestNetworkId,
final boolean sourceNat, final boolean assign, final boolean allocate, final String requestedIp, final boolean isSystem,
final Long vpcId, final Boolean displayIp, final boolean forSystemVms, final boolean lockOneRow) throws InsufficientAddressCapacityException {
return Transaction.execute(new TransactionCallbackWithException<List<IPAddressVO>, InsufficientAddressCapacityException>() {
@Override
public List<IPAddressVO> doInTransaction(TransactionStatus status) throws InsufficientAddressCapacityException {
StringBuilder errorMessage = new StringBuilder("Unable to get ip address in ");
boolean fetchFromDedicatedRange = false;
List<Long> dedicatedVlanDbIds = new ArrayList<Long>();
@ -824,6 +836,8 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
if (vlanDbIds == null || vlanDbIds.contains(nonDedicatedVlan.getId()))
nonDedicatedVlanDbIds.add(nonDedicatedVlan.getId());
}
if (vlanUse == VlanType.VirtualNetwork) {
if (dedicatedVlanDbIds != null && !dedicatedVlanDbIds.isEmpty()) {
fetchFromDedicatedRange = true;
sc.setParameters("vlanId", dedicatedVlanDbIds.toArray());
@ -842,6 +856,7 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
ex.addProxyObject(ApiDBUtils.findZoneById(dcId).getUuid());
throw ex;
}
}
sc.setParameters("dc", dcId);
@ -871,21 +886,31 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
filter.addOrderBy(IPAddressVO.class,"vlanId", true);
List<IPAddressVO> addrs = _ipAddressDao.search(sc, filter, false);
List<IPAddressVO> addrs;
if (lockOneRow) {
addrs = _ipAddressDao.lockRows(sc, filter, true);
} else {
addrs = new ArrayList<>(_ipAddressDao.search(sc, null));
}
// If all the dedicated IPs of the owner are in use fetch an IP from the system pool
if (addrs.size() == 0 && fetchFromDedicatedRange) {
if ((!lockOneRow || (lockOneRow && addrs.size() == 0)) && fetchFromDedicatedRange && vlanUse == VlanType.VirtualNetwork) {
// Verify if account is allowed to acquire IPs from the system
boolean useSystemIps = UseSystemPublicIps.valueIn(owner.getId());
if (useSystemIps && nonDedicatedVlanDbIds != null && !nonDedicatedVlanDbIds.isEmpty()) {
fetchFromDedicatedRange = false;
sc.setParameters("vlanId", nonDedicatedVlanDbIds.toArray());
errorMessage.append(", vlanId id=" + Arrays.toString(nonDedicatedVlanDbIds.toArray()));
addrs = _ipAddressDao.search(sc, filter, false);
if (lockOneRow) {
addrs = _ipAddressDao.lockRows(sc, filter, true);
} else {
addrs.addAll(_ipAddressDao.search(sc, null));
}
}
}
if (addrs.size() == 0) {
if (lockOneRow && addrs.size() == 0) {
if (podId != null) {
InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", Pod.class, podId);
// for now, we hardcode the table names, but we should ideally do a lookup for the tablename from the VO object.
@ -898,23 +923,16 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
throw ex;
}
if (lockOneRow) {
assert (addrs.size() == 1) : "Return size is incorrect: " + addrs.size();
IPAddressVO finalAddr = null;
if (assign) {
finalAddr = assignAndAllocateIpAddressEntry(owner, vlanUse, guestNetworkId, sourceNat, allocate,
isSystem,vpcId, displayIp, fetchFromDedicatedRange, addrs);
} else {
finalAddr = addrs.get(0);
}
return finalAddr;
if (assign) {
assignAndAllocateIpAddressEntry(owner, vlanUse, guestNetworkId, sourceNat, allocate,
isSystem,vpcId, displayIp, fetchFromDedicatedRange, addrs);
}
return addrs;
}
});
if (vlanUse == VlanType.VirtualNetwork) {
_firewallMgr.addSystemFirewallRules(addr, owner);
}
return PublicIp.createFromAddrAndVlan(addr, _vlanDao.findById(addr.getVlanId()));
}
@DB

View File

@ -734,100 +734,7 @@ Configurable, StateListener<VirtualMachine.State, VirtualMachine.Event, VirtualM
s_logger.debug("Found " + routers.size() + " running routers. ");
for (final DomainRouterVO router : routers) {
final String privateIP = router.getPrivateIpAddress();
if (privateIP != null) {
final boolean forVpc = router.getVpcId() != null;
final List<? extends Nic> routerNics = _nicDao.listByVmId(router.getId());
for (final Nic routerNic : routerNics) {
final Network network = _networkModel.getNetwork(routerNic.getNetworkId());
// Send network usage command for public nic in VPC VR
// Send network usage command for isolated guest nic of non) VPC VR
//[TODO] Avoiding the NPE now, but I have to find out what is going on with the network. - Wilder Rodrigues
if (network == null) {
s_logger.error("Could not find a network with ID => " + routerNic.getNetworkId() + ". It might be a problem!");
continue;
}
if (forVpc && network.getTrafficType() == TrafficType.Public || !forVpc && network.getTrafficType() == TrafficType.Guest
&& network.getGuestType() == Network.GuestType.Isolated) {
final NetworkUsageCommand usageCmd = new NetworkUsageCommand(privateIP, router.getHostName(), forVpc, routerNic.getIPv4Address());
final String routerType = router.getType().toString();
final UserStatisticsVO previousStats = _userStatsDao.findBy(router.getAccountId(), router.getDataCenterId(), network.getId(),
forVpc ? routerNic.getIPv4Address() : null, router.getId(), routerType);
NetworkUsageAnswer answer = null;
try {
answer = (NetworkUsageAnswer) _agentMgr.easySend(router.getHostId(), usageCmd);
} catch (final Exception e) {
s_logger.warn("Error while collecting network stats from router: " + router.getInstanceName() + " from host: " + router.getHostId(), e);
continue;
}
if (answer != null) {
if (!answer.getResult()) {
s_logger.warn("Error while collecting network stats from router: " + router.getInstanceName() + " from host: " + router.getHostId()
+ "; details: " + answer.getDetails());
continue;
}
try {
if (answer.getBytesReceived() == 0 && answer.getBytesSent() == 0) {
s_logger.debug("Recieved and Sent bytes are both 0. Not updating user_statistics");
continue;
}
final NetworkUsageAnswer answerFinal = answer;
Transaction.execute(new TransactionCallbackNoReturn() {
@Override
public void doInTransactionWithoutResult(final TransactionStatus status) {
final UserStatisticsVO stats = _userStatsDao.lock(router.getAccountId(), router.getDataCenterId(), network.getId(),
forVpc ? routerNic.getIPv4Address() : null, router.getId(), routerType);
if (stats == null) {
s_logger.warn("unable to find stats for account: " + router.getAccountId());
return;
}
if (previousStats != null
&& (previousStats.getCurrentBytesReceived() != stats.getCurrentBytesReceived() || previousStats.getCurrentBytesSent() != stats
.getCurrentBytesSent())) {
s_logger.debug("Router stats changed from the time NetworkUsageCommand was sent. " + "Ignoring current answer. Router: "
+ answerFinal.getRouterName() + " Rcvd: " + answerFinal.getBytesReceived() + "Sent: " + answerFinal.getBytesSent());
return;
}
if (stats.getCurrentBytesReceived() > answerFinal.getBytesReceived()) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Received # of bytes that's less than the last one. "
+ "Assuming something went wrong and persisting it. Router: " + answerFinal.getRouterName() + " Reported: "
+ toHumanReadableSize(answerFinal.getBytesReceived()) + " Stored: " + toHumanReadableSize(stats.getCurrentBytesReceived()));
}
stats.setNetBytesReceived(stats.getNetBytesReceived() + stats.getCurrentBytesReceived());
}
stats.setCurrentBytesReceived(answerFinal.getBytesReceived());
if (stats.getCurrentBytesSent() > answerFinal.getBytesSent()) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Received # of bytes that's less than the last one. "
+ "Assuming something went wrong and persisting it. Router: " + answerFinal.getRouterName() + " Reported: "
+ toHumanReadableSize(answerFinal.getBytesSent()) + " Stored: " + toHumanReadableSize(stats.getCurrentBytesSent()));
}
stats.setNetBytesSent(stats.getNetBytesSent() + stats.getCurrentBytesSent());
}
stats.setCurrentBytesSent(answerFinal.getBytesSent());
if (!_dailyOrHourly) {
// update agg bytes
stats.setAggBytesSent(stats.getNetBytesSent() + stats.getCurrentBytesSent());
stats.setAggBytesReceived(stats.getNetBytesReceived() + stats.getCurrentBytesReceived());
}
_userStatsDao.update(stats.getId(), stats);
}
});
} catch (final Exception e) {
s_logger.warn("Unable to update user statistics for account: " + router.getAccountId() + " Rx: " + toHumanReadableSize(answer.getBytesReceived()) + "; Tx: "
+ toHumanReadableSize(answer.getBytesSent()));
}
}
}
}
}
collectNetworkStatistics(router, null);
}
} catch (final Exception e) {
s_logger.warn("Error while collecting network stats", e);
@ -3121,6 +3028,11 @@ Configurable, StateListener<VirtualMachine.State, VirtualMachine.Event, VirtualM
// Collect network usage before stopping Vm
final DomainRouterVO router = _routerDao.findById(profile.getVirtualMachine().getId());
collectNetworkStatistics(router, null);
}
@Override
public <T extends VirtualRouter> void collectNetworkStatistics(final T router, final Nic nic) {
if (router == null) {
return;
}
@ -3129,12 +3041,23 @@ Configurable, StateListener<VirtualMachine.State, VirtualMachine.Event, VirtualM
if (privateIP != null) {
final boolean forVpc = router.getVpcId() != null;
final List<? extends Nic> routerNics = _nicDao.listByVmId(router.getId());
List<Nic> routerNics = new ArrayList<Nic>();
if (nic != null) {
routerNics.add(nic);
} else {
routerNics.addAll(_nicDao.listByVmId(router.getId()));
}
for (final Nic routerNic : routerNics) {
final Network network = _networkModel.getNetwork(routerNic.getNetworkId());
// Send network usage command for public nic in VPC VR
// Send network usage command for isolated guest nic of non VPC
// VR
//[TODO] Avoiding the NPE now, but I have to find out what is going on with the network. - Wilder Rodrigues
if (network == null) {
s_logger.error("Could not find a network with ID => " + routerNic.getNetworkId() + ". It might be a problem!");
continue;
}
if (forVpc && network.getTrafficType() == TrafficType.Public || !forVpc && network.getTrafficType() == TrafficType.Guest
&& network.getGuestType() == Network.GuestType.Isolated) {
final NetworkUsageCommand usageCmd = new NetworkUsageCommand(privateIP, router.getHostName(), forVpc, routerNic.getIPv4Address());

View File

@ -40,6 +40,7 @@ import com.cloud.network.NetworkModel;
import com.cloud.network.Networks.BroadcastDomainType;
import com.cloud.network.Networks.IsolationType;
import com.cloud.network.PublicIpAddress;
import com.cloud.network.VpcVirtualNetworkApplianceService;
import com.cloud.network.dao.FirewallRulesDao;
import com.cloud.network.dao.IPAddressDao;
import com.cloud.network.dao.IPAddressVO;
@ -84,6 +85,7 @@ public class NicPlugInOutRules extends RuleApplier {
NetworkModel networkModel = visitor.getVirtualNetworkApplianceFactory().getNetworkModel();
VirtualMachineManager itMgr = visitor.getVirtualNetworkApplianceFactory().getItMgr();
NicDao nicDao = visitor.getVirtualNetworkApplianceFactory().getNicDao();
VpcVirtualNetworkApplianceService routerService = visitor.getVirtualNetworkApplianceFactory().getRouterService();
// de-associate IPs before unplugging nics
if (!nicsToUnplug.isEmpty()) {
@ -107,6 +109,12 @@ public class NicPlugInOutRules extends RuleApplier {
// 1) Unplug the nics
for (Entry<String, PublicIpAddress> entry : nicsToUnplug.entrySet()) {
PublicIpAddress ip = entry.getValue();
NicVO nic = nicDao.findByIp4AddressAndNetworkIdAndInstanceId(ip.getNetworkId(), _router.getId(), ip.getAddress().addr());
if (nic != null) {
s_logger.info("Collect network statistics for nic " + nic + " from router " + _router);
routerService.collectNetworkStatistics(_router, nic);
}
Network publicNtwk = null;
try {
publicNtwk = networkModel.getNetwork(entry.getValue().getNetworkId());

View File

@ -26,6 +26,7 @@ import com.cloud.dc.dao.HostPodDao;
import com.cloud.dc.dao.VlanDao;
import com.cloud.network.IpAddressManager;
import com.cloud.network.NetworkModel;
import com.cloud.network.VpcVirtualNetworkApplianceService;
import com.cloud.network.dao.FirewallRulesDao;
import com.cloud.network.dao.IPAddressDao;
import com.cloud.network.dao.LoadBalancerDao;
@ -98,6 +99,8 @@ public class VirtualNetworkApplianceFactory {
@Inject
private NetworkTopologyContext _networkTopologyContext;
@Inject
private VpcVirtualNetworkApplianceService _routerService;
public NetworkModel getNetworkModel() {
return _networkModel;
@ -190,4 +193,8 @@ public class VirtualNetworkApplianceFactory {
public FirewallRulesDao getFirewallRulesDao() {
return _rulesDao;
}
public VpcVirtualNetworkApplianceService getRouterService() {
return _routerService;
}
}

View File

@ -613,6 +613,7 @@ import com.cloud.event.EventTypes;
import com.cloud.event.EventVO;
import com.cloud.event.dao.EventDao;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientAddressCapacityException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.ManagementServerException;
import com.cloud.exception.OperationTimedoutException;
@ -637,12 +638,20 @@ import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao;
import com.cloud.hypervisor.kvm.dpdk.DpdkHelper;
import com.cloud.info.ConsoleProxyInfo;
import com.cloud.network.IpAddress;
import com.cloud.network.IpAddressManager;
import com.cloud.network.Network;
import com.cloud.network.NetworkModel;
import com.cloud.network.dao.IPAddressDao;
import com.cloud.network.dao.IPAddressVO;
import com.cloud.network.dao.LoadBalancerDao;
import com.cloud.network.dao.LoadBalancerVO;
import com.cloud.network.dao.NetworkAccountDao;
import com.cloud.network.dao.NetworkAccountVO;
import com.cloud.network.dao.NetworkDomainDao;
import com.cloud.network.dao.NetworkDomainVO;
import com.cloud.network.dao.NetworkDao;
import com.cloud.network.dao.NetworkVO;
import com.cloud.network.vpc.dao.VpcDao;
import com.cloud.org.Cluster;
import com.cloud.org.Grouping.AllocationState;
import com.cloud.projects.Project;
@ -858,6 +867,16 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
private VolumeDataStoreDao _volumeStoreDao;
@Inject
private TemplateDataStoreDao _vmTemplateStoreDao;
@Inject
private IpAddressManager _ipAddressMgr;
@Inject
private NetworkAccountDao _networkAccountDao;
@Inject
private NetworkDomainDao _networkDomainDao;
@Inject
private NetworkModel _networkMgr;
@Inject
private VpcDao _vpcDao;
private LockMasterListener _lockMasterListener;
private final ScheduledExecutorService _eventExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("EventChecker"));
@ -2024,29 +2043,90 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
@Override
public Pair<List<? extends IpAddress>, Integer> searchForIPAddresses(final ListPublicIpAddressesCmd cmd) {
final Object keyword = cmd.getKeyword();
final Long physicalNetworkId = cmd.getPhysicalNetworkId();
final Long associatedNetworkId = cmd.getAssociatedNetworkId();
final Long sourceNetworkId = cmd.getNetworkId();
final Long zone = cmd.getZoneId();
final String address = cmd.getIpAddress();
final Long vlan = cmd.getVlanId();
final Boolean forVirtualNetwork = cmd.isForVirtualNetwork();
final Boolean forLoadBalancing = cmd.isForLoadBalancing();
final Long ipId = cmd.getId();
final Boolean sourceNat = cmd.isSourceNat();
final Boolean staticNat = cmd.isStaticNat();
final Long networkId = cmd.getNetworkId();
final Long vpcId = cmd.getVpcId();
final Boolean forDisplay = cmd.getDisplay();
final Map<String, String> tags = cmd.getTags();
final String state = cmd.getState();
Boolean isAllocated = cmd.isAllocatedOnly();
if (isAllocated == null) {
isAllocated = Boolean.TRUE;
if (state != null) {
if (state != null && state.equalsIgnoreCase(IpAddress.State.Free.name())) {
isAllocated = Boolean.FALSE;
} else {
isAllocated = Boolean.TRUE; // default
}
} else {
if (state != null && state.equalsIgnoreCase(IpAddress.State.Free.name())) {
if (isAllocated) {
throw new InvalidParameterValueException("Conflict: allocatedonly is true but state is Free");
}
} else if (state != null && state.equalsIgnoreCase(IpAddress.State.Allocated.name())) {
isAllocated = Boolean.TRUE;
}
}
VlanType vlanType = null;
if (forVirtualNetwork != null) {
vlanType = forVirtualNetwork ? VlanType.VirtualNetwork : VlanType.DirectAttached;
} else {
vlanType = VlanType.VirtualNetwork;
}
final Account caller = getCaller();
List<IPAddressVO> addrs = new ArrayList<>();
if (vlanType == VlanType.DirectAttached && networkId == null && ipId == null) { // only root admin can list public ips in all shared networks
if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN) {
isAllocated = true;
}
} else if (vlanType == VlanType.DirectAttached) {
// list public ip address on shared network
// access control. admin: all Ips, domain admin/user: all Ips in shared network in the domain/sub-domain/user
NetworkVO network = null;
if (networkId == null) {
IPAddressVO ip = _publicIpAddressDao.findById(ipId);
if (ip == null) {
throw new InvalidParameterValueException("Please specify a valid ipaddress id");
}
network = _networkDao.findById(ip.getSourceNetworkId());
} else {
network = _networkDao.findById(networkId);
}
if (network == null || network.getGuestType() != Network.GuestType.Shared) {
throw new InvalidParameterValueException("Please specify a valid network id");
}
if (network.getAclType() == ControlledEntity.ACLType.Account) {
NetworkAccountVO networkMap = _networkAccountDao.getAccountNetworkMapByNetworkId(network.getId());
if (networkMap == null) {
return new Pair<>(addrs, 0);
}
_accountMgr.checkAccess(caller, null, false, _accountDao.findById(networkMap.getAccountId()));
} else { // Domain level
NetworkDomainVO networkMap = _networkDomainDao.getDomainNetworkMapByNetworkId(network.getId());
if (networkMap == null) {
return new Pair<>(addrs, 0);
}
if (caller.getType() == Account.ACCOUNT_TYPE_NORMAL || caller.getType() == Account.ACCOUNT_TYPE_PROJECT) {
if (_networkMgr.isNetworkAvailableInDomain(network.getId(), caller.getDomainId())) {
isAllocated = Boolean.TRUE;
} else {
return new Pair<>(addrs, 0);
}
} else if (caller.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN || caller.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN) {
if (caller.getDomainId() == networkMap.getDomainId() || _domainDao.isChildDomain(caller.getDomainId(), networkMap.getDomainId())) {
s_logger.debug("Caller " + caller.getUuid() + " has permission to access the network : " + network.getUuid());
} else {
if (_networkMgr.isNetworkAvailableInDomain(network.getId(), caller.getDomainId())) {
isAllocated = Boolean.TRUE;
} else {
return new Pair<>(addrs, 0);
}
}
}
}
}
@ -2054,12 +2134,10 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
final SearchBuilder<IPAddressVO> sb = _publicIpAddressDao.createSearchBuilder();
Long domainId = null;
Boolean isRecursive = null;
final List<Long> permittedAccounts = new ArrayList<Long>();
final List<Long> permittedAccounts = new ArrayList<>();
ListProjectResourcesCriteria listProjectResourcesCriteria = null;
if (isAllocated) {
final Account caller = getCaller();
final Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, ListProjectResourcesCriteria>(cmd.getDomainId(), cmd.isRecursive(),
if (isAllocated || (vlanType == VlanType.VirtualNetwork && (caller.getType() != Account.ACCOUNT_TYPE_ADMIN || cmd.getDomainId() != null))) {
final Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<>(cmd.getDomainId(), cmd.isRecursive(),
null);
_accountMgr.buildACLSearchParameters(caller, cmd.getId(), cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false);
domainId = domainIdRecursiveListProject.first();
@ -2068,12 +2146,93 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
_accountMgr.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
}
buildParameters(sb, cmd);
SearchCriteria<IPAddressVO> sc = sb.create();
setParameters(sc, cmd, vlanType);
if (isAllocated || (vlanType == VlanType.VirtualNetwork && (caller.getType() != Account.ACCOUNT_TYPE_ADMIN || cmd.getDomainId() != null))) {
_accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
}
if (associatedNetworkId != null) {
_accountMgr.checkAccess(caller, null, false, _networkDao.findById(associatedNetworkId));
sc.setParameters("associatedNetworkIdEq", associatedNetworkId);
}
if (vpcId != null) {
_accountMgr.checkAccess(caller, null, false, _vpcDao.findById(vpcId));
sc.setParameters("vpcId", vpcId);
}
addrs = _publicIpAddressDao.search(sc, searchFilter); // Allocated
// Free IP addresses in system IP ranges
List<Long> freeAddrIds = new ArrayList<>();
if (!(isAllocated || vlanType == VlanType.DirectAttached)) {
Long zoneId = zone;
Account owner = _accountMgr.finalizeOwner(CallContext.current().getCallingAccount(), cmd.getAccountName(), cmd.getDomainId(), cmd.getProjectId());
if (associatedNetworkId != null) {
NetworkVO guestNetwork = _networkDao.findById(associatedNetworkId);
if (zoneId == null) {
zoneId = guestNetwork.getDataCenterId();
} else if (zoneId != guestNetwork.getDataCenterId()) {
InvalidParameterValueException ex = new InvalidParameterValueException("Please specify a valid associated network id in the specified zone.");
throw ex;
}
owner = _accountDao.findById(guestNetwork.getAccountId());
}
List<DataCenterVO> dcList = new ArrayList<>();
if (zoneId == null){
dcList = ApiDBUtils.listZones();
} else {
dcList.add(ApiDBUtils.findZoneById(zoneId));
}
List<Long> vlanDbIds = null;
if (vlan != null) {
vlanDbIds = new ArrayList<>();
vlanDbIds.add(vlan);
}
List<IPAddressVO> freeAddrs = new ArrayList<>();
for (DataCenterVO dc : dcList) {
long dcId = dc.getId();
try {
freeAddrs.addAll(_ipAddressMgr.listAvailablePublicIps(dcId, null, vlanDbIds, owner, VlanType.VirtualNetwork, associatedNetworkId,
false, false, false, null, false, cmd.getVpcId(), cmd.isDisplay(), false, false)); // Free
} catch (InsufficientAddressCapacityException e) {
s_logger.warn("no free address is found in zone " + dcId);
}
}
for (IPAddressVO addr: freeAddrs) {
freeAddrIds.add(addr.getId());
}
}
if (freeAddrIds.size() > 0) {
final SearchBuilder<IPAddressVO> sb2 = _publicIpAddressDao.createSearchBuilder();
buildParameters(sb2, cmd);
sb2.and("ids", sb2.entity().getId(), SearchCriteria.Op.IN);
SearchCriteria<IPAddressVO> sc2 = sb2.create();
setParameters(sc2, cmd, vlanType);
sc2.setParameters("ids", freeAddrIds.toArray());
addrs.addAll(_publicIpAddressDao.search(sc2, searchFilter)); // Allocated + Free
}
return new Pair<>(addrs, addrs.size());
}
private void buildParameters(final SearchBuilder<IPAddressVO> sb, final ListPublicIpAddressesCmd cmd) {
final Object keyword = cmd.getKeyword();
final String address = cmd.getIpAddress();
final Boolean forLoadBalancing = cmd.isForLoadBalancing();
Boolean isAllocated = cmd.isAllocatedOnly();
final Map<String, String> tags = cmd.getTags();
sb.and("dataCenterId", sb.entity().getDataCenterId(), SearchCriteria.Op.EQ);
sb.and("address", sb.entity().getAddress(), SearchCriteria.Op.EQ);
sb.and("vlanDbId", sb.entity().getVlanId(), SearchCriteria.Op.EQ);
sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ);
sb.and("physicalNetworkId", sb.entity().getPhysicalNetworkId(), SearchCriteria.Op.EQ);
sb.and("associatedNetworkId", sb.entity().getAssociatedWithNetworkId(), SearchCriteria.Op.EQ);
sb.and("associatedNetworkIdEq", sb.entity().getAssociatedWithNetworkId(), SearchCriteria.Op.EQ);
sb.and("sourceNetworkId", sb.entity().getSourceNetworkId(), SearchCriteria.Op.EQ);
sb.and("isSourceNat", sb.entity().isSourceNat(), SearchCriteria.Op.EQ);
sb.and("isStaticNat", sb.entity().isOneToOneNat(), SearchCriteria.Op.EQ);
@ -2109,21 +2268,24 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
vlanSearch.and("removed", vlanSearch.entity().getRemoved(), SearchCriteria.Op.NULL);
sb.join("vlanSearch", vlanSearch, sb.entity().getVlanId(), vlanSearch.entity().getId(), JoinBuilder.JoinType.INNER);
if (isAllocated != null && isAllocated == true) {
if (isAllocated != null && isAllocated) {
sb.and("allocated", sb.entity().getAllocatedTime(), SearchCriteria.Op.NNULL);
}
VlanType vlanType = null;
if (forVirtualNetwork != null) {
vlanType = forVirtualNetwork ? VlanType.VirtualNetwork : VlanType.DirectAttached;
} else {
vlanType = VlanType.VirtualNetwork;
}
final SearchCriteria<IPAddressVO> sc = sb.create();
if (isAllocated) {
_accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
}
private void setParameters(SearchCriteria<IPAddressVO> sc, final ListPublicIpAddressesCmd cmd, VlanType vlanType) {
final Object keyword = cmd.getKeyword();
final Long physicalNetworkId = cmd.getPhysicalNetworkId();
final Long sourceNetworkId = cmd.getNetworkId();
final Long zone = cmd.getZoneId();
final String address = cmd.getIpAddress();
final Long vlan = cmd.getVlanId();
final Long ipId = cmd.getId();
final Boolean sourceNat = cmd.isSourceNat();
final Boolean staticNat = cmd.isStaticNat();
final Boolean forDisplay = cmd.getDisplay();
final String state = cmd.getState();
final Map<String, String> tags = cmd.getTags();
sc.setJoinParameters("vlanSearch", "vlanType", vlanType);
@ -2141,10 +2303,6 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
sc.setParameters("dataCenterId", zone);
}
if (vpcId != null) {
sc.setParameters("vpcId", vpcId);
}
if (ipId != null) {
sc.setParameters("id", ipId);
}
@ -2173,10 +2331,6 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
sc.setParameters("physicalNetworkId", physicalNetworkId);
}
if (associatedNetworkId != null) {
sc.setParameters("associatedNetworkId", associatedNetworkId);
}
if (sourceNetworkId != null) {
sc.setParameters("sourceNetworkId", sourceNetworkId);
}
@ -2190,8 +2344,6 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
}
sc.setParameters( "forsystemvms", false);
final Pair<List<IPAddressVO>, Integer> result = _publicIpAddressDao.searchAndCount(sc, searchFilter);
return new Pair<List<? extends IpAddress>, Integer>(result.first(), result.second());
}
@Override

View File

@ -920,8 +920,6 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
if (template.isCrossZones()) {
// sync template from cache store to region store if it is not there, for cases where we are going to migrate existing NFS to S3.
_tmpltSvr.syncTemplateToRegionStore(templateId, srcSecStore);
s_logger.debug("Template " + templateId + " is cross-zone, don't need to copy");
return template;
}
for (Long destZoneId : destZoneIds) {
DataStore dstSecStore = getImageStore(destZoneId, templateId);

View File

@ -42,6 +42,7 @@ import com.cloud.user.User;
import com.cloud.utils.Pair;
import com.cloud.utils.component.ManagerBase;
import com.cloud.vm.DomainRouterVO;
import com.cloud.vm.Nic;
import com.cloud.vm.VirtualMachineProfile;
@Component
@ -281,4 +282,10 @@ public class MockVpcVirtualNetworkApplianceManager extends ManagerBase implement
// TODO Auto-generated method stub
return false;
}
@Override
public <T extends VirtualRouter> void collectNetworkStatistics(T router, Nic nic) {
// TODO Auto-generated method stub
return;
}
}

View File

@ -11,15 +11,3 @@ size 50M
compress
# RPM packages drop log rotation information into this directory
include /etc/logrotate.d
# no packages own wtmp and btmp -- we'll rotate them here
/var/log/wtmp {
monthly
create 0664 root utmp
rotate 1
}
/var/log/btmp {
missingok
monthly
create 0600 root utmp
rotate 1
}

View File

@ -0,0 +1,7 @@
# no packages own btmp -- we'll rotate it here
/var/log/btmp {
missingok
monthly
create 0660 root utmp
rotate 1
}

View File

@ -6,7 +6,7 @@
notifempty
compress
postrotate
/usr/sbin/invoke-rc.d rsyslog rotate > /dev/null
/usr/lib/rsyslog/rsyslog-rotate
endscript
}
@ -30,6 +30,6 @@
compress
sharedscripts
postrotate
/usr/sbin/invoke-rc.d rsyslog rotate > /dev/null
/usr/lib/rsyslog/rsyslog-rotate
endscript
}

View File

@ -0,0 +1,8 @@
# no packages own wtmp -- we'll rotate it here
/var/log/wtmp {
missingok
monthly
create 0664 root utmp
minsize 1M
rotate 1
}

View File

@ -476,11 +476,6 @@ class CsIP:
"-A PREROUTING -m state --state NEW -i %s -s %s ! -d %s/32 -j ACL_OUTBOUND_%s" %
(self.dev, guestNetworkCidr, self.address['gateway'], self.dev)])
self.fw.append(["", "front", "-A NETWORK_STATS_%s -i %s -d %s" %
("eth1", "eth1", guestNetworkCidr)])
self.fw.append(["", "front", "-A NETWORK_STATS_%s -o %s -s %s" %
("eth1", "eth1", guestNetworkCidr)])
if self.is_private_gateway():
self.fw.append(["filter", "", "-A FORWARD -d %s -o %s -j ACL_INBOUND_%s" %
(self.address['network'], self.dev, self.dev)])
@ -518,6 +513,10 @@ class CsIP:
["mangle", "", "-A VPN_STATS_%s -i %s -m mark --mark 0x524/0xffffffff" % (self.dev, self.dev)])
self.fw.append(
["", "front", "-A FORWARD -j NETWORK_STATS_%s" % self.dev])
self.fw.append(
["", "front", "-A NETWORK_STATS_%s -s %s -o %s" % (self.dev, self.cl.get_vpccidr(), self.dev)])
self.fw.append(
["", "front", "-A NETWORK_STATS_%s -d %s -i %s" % (self.dev, self.cl.get_vpccidr(), self.dev)])
self.fw.append(["", "front", "-A FORWARD -j NETWORK_STATS"])
self.fw.append(["", "front", "-A INPUT -j NETWORK_STATS"])

View File

@ -0,0 +1,870 @@
# 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.
""" Tests for acquiring/listing public ip address
"""
from nose.plugins.attrib import attr
from marvin.cloudstackTestCase import cloudstackTestCase
from marvin.lib.utils import cleanup_resources
from marvin.lib.base import (Account,
Configurations,
Domain,
PublicIpRange,
PublicIPAddress,
Network,
NetworkOffering,
ServiceOffering,
VPC,
VpcOffering,
Zone)
from marvin.lib.common import (get_zone,
get_domain,
get_template,
get_free_vlan
)
import logging
import random
class TestPublicIp(cloudstackTestCase):
@classmethod
def setUpClass(cls):
cls.testClient = super(TestPublicIp, cls).getClsTestClient()
cls.apiclient = cls.testClient.getApiClient()
cls.services = cls.testClient.getParsedTestDataConfig()
# Get Zone, Domain and templates
cls.zone = get_zone(cls.apiclient, cls.testClient.getZoneForTests())
cls.services['mode'] = cls.zone.networktype
cls.logger = logging.getLogger("TestPublicIp")
cls.domain = get_domain(cls.apiclient)
cls.services["virtual_machine"]["zoneid"] = cls.zone.id
cls.template = get_template(
cls.apiclient,
cls.zone.id,
cls.services["ostype"]
)
cls.use_system_ips_config_name = "use.system.public.ips"
cls.use_system_ips_config = Configurations.list(
cls.apiclient,
name=cls.use_system_ips_config_name
)
cls.use_system_ips_config_value = cls.use_system_ips_config[0].value
Configurations.update(
cls.apiclient,
name=cls.use_system_ips_config_name,
value="false"
)
cls._cleanup = []
cls.unsupportedHypervisor = False
cls.hypervisor = cls.testClient.getHypervisorInfo()
if cls.hypervisor.lower() in ['lxc']:
cls.unsupportedHypervisor = True
return
# Create new domain1
cls.domain1 = Domain.create(
cls.apiclient,
services=cls.services["acl"]["domain1"],
parentdomainid=cls.domain.id)
# Create account1
cls.account1 = Account.create(
cls.apiclient,
cls.services["account"],
# cls.services["acl"]["accountD1"],
admin=True,
domainid=cls.domain1.id
)
# Create new sub-domain
cls.sub_domain = Domain.create(
cls.apiclient,
services=cls.services["acl"]["domain11"],
parentdomainid=cls.domain1.id)
# Create account for sub-domain
cls.sub_account = Account.create(
cls.apiclient,
cls.services["acl"]["accountD11"],
domainid=cls.sub_domain.id
)
# Create new domain2
cls.domain2 = Domain.create(
cls.apiclient,
services=cls.services["acl"]["domain2"],
parentdomainid=cls.domain.id)
# Create account2
cls.account2 = Account.create(
cls.apiclient,
cls.services["acl"]["accountD2"],
domainid=cls.domain2.id
)
cls.services["publiciprange"]["zoneid"] = cls.zone.id
cls.services["publiciprange"]["forvirtualnetwork"] = "true"
# Create public ip range 1
cls.services["publiciprange"]["vlan"] = get_free_vlan(
cls.apiclient,
cls.zone.id)[1]
random_subnet_number = random.randrange(10,20)
cls.services["publiciprange"]["gateway"] = "10.100." + \
str(random_subnet_number) + ".254"
cls.services["publiciprange"]["startip"] = "10.100." + \
str(random_subnet_number) + ".1"
cls.services["publiciprange"]["endip"] = "10.100." + \
str(random_subnet_number) + ".10"
cls.services["publiciprange"]["netmask"] = "255.255.255.0"
cls.public_ip_range1 = PublicIpRange.create(
cls.apiclient,
cls.services["publiciprange"],
account=cls.account1.name,
domainid=cls.account1.domainid
)
# dedicate ip range to sub domain
cls.services["publiciprange"]["vlan"] = get_free_vlan(
cls.apiclient,
cls.zone.id)[1]
random_subnet_number = random.randrange(10,20)
cls.services["publiciprange"]["gateway"] = "10.110." + \
str(random_subnet_number) + ".254"
cls.services["publiciprange"]["startip"] = "10.110." + \
str(random_subnet_number) + ".1"
cls.services["publiciprange"]["endip"] = "10.110." + \
str(random_subnet_number) + ".10"
cls.services["publiciprange"]["netmask"] = "255.255.255.0"
cls.public_ip_range2 = PublicIpRange.create(
cls.apiclient,
cls.services["publiciprange"],
account=cls.sub_account.name,
domainid=cls.sub_account.domainid
)
# dedicate ip range to second domain
cls.services["publiciprange"]["vlan"] = get_free_vlan(
cls.apiclient,
cls.zone.id)[1]
random_subnet_number = random.randrange(10,20)
cls.services["publiciprange"]["gateway"] = "10.120." + \
str(random_subnet_number) + ".254"
cls.services["publiciprange"]["startip"] = "10.120." + \
str(random_subnet_number) + ".1"
cls.services["publiciprange"]["endip"] = "10.120." + \
str(random_subnet_number) + ".10"
cls.services["publiciprange"]["netmask"] = "255.255.255.0"
cls.public_ip_range3 = PublicIpRange.create(
cls.apiclient,
cls.services["publiciprange"],
account=cls.account2.name,
domainid=cls.account2.domainid
)
# create vpc offering and VPC
cls.vpc_off = VpcOffering.create(
cls.apiclient,
cls.services["vpc_offering"]
)
cls.vpc_off.update(cls.apiclient, state='Enabled')
# create network offering
cls.isolated_network_offering = NetworkOffering.create(
cls.apiclient,
cls.services["isolated_network_offering"],
conservemode=False
)
NetworkOffering.update(
cls.isolated_network_offering,
cls.apiclient,
id=cls.isolated_network_offering.id,
state="enabled"
)
physical_network, shared_vlan = get_free_vlan(
cls.apiclient, cls.zone.id)
if shared_vlan is None:
cls.fail("Failed to get free vlan id for shared network")
cls.services["shared_network_offering"]["specifyVlan"] = "True"
cls.services["shared_network_offering"]["specifyIpRanges"] = "True"
cls.shared_network_offering = NetworkOffering.create(
cls.apiclient,
cls.services["shared_network_offering"],
conservemode=False
)
NetworkOffering.update(
cls.shared_network_offering,
cls.apiclient,
id=cls.shared_network_offering.id,
state="enabled"
)
# create network using the shared network offering created
cls.services["shared_network"]["acltype"] = "Domain"
cls.services["shared_network"][
"networkofferingid"] = cls.shared_network_offering.id
cls.services["shared_network"][
"physicalnetworkid"] = physical_network.id
cls.services["shared_network"]["vlan"] = shared_vlan
shared_network_subnet_number = random.randrange(1, 254)
cls.services["shared_network"]["netmask"] = "255.255.255.0"
cls.services["shared_network"]["gateway"] = "172.16." + \
str(shared_network_subnet_number) + ".254"
cls.services["shared_network"]["startip"] = "172.16." + \
str(shared_network_subnet_number) + ".1"
cls.services["shared_network"]["endip"] = "172.16." + \
str(shared_network_subnet_number) + ".10"
cls.guest_network = Network.create(
cls.apiclient,
cls.services["shared_network"],
networkofferingid=cls.shared_network_offering.id,
zoneid=cls.zone.id
)
cls._cleanup.append(cls.guest_network)
cls._cleanup.append(cls.shared_network_offering)
cls._cleanup.append(cls.account1)
cls._cleanup.append(cls.account2)
cls._cleanup.append(cls.sub_account)
cls._cleanup.append(cls.sub_domain)
cls._cleanup.append(cls.domain1)
cls._cleanup.append(cls.domain2)
cls._cleanup.append(cls.public_ip_range1)
cls._cleanup.append(cls.public_ip_range2)
cls._cleanup.append(cls.public_ip_range3)
@classmethod
def tearDownClass(cls):
try:
cls.apiclient = super(
TestPublicIp,
cls).getClsTestClient().getApiClient()
Configurations.update(
cls.apiclient,
name=cls.use_system_ips_config_name,
value=cls.use_system_ips_config_value
)
# Cleanup resources used
cleanup_resources(cls.apiclient, cls._cleanup)
except Exception as e:
raise Exception("Warning: Exception during cleanup : %s" % e)
return
def setUp(self):
self.apiclient = self.testClient.getApiClient()
self.cleanup = []
return
def tearDown(self):
try:
# Clean up, terminate the resources created
cleanup_resources(self.apiclient, self.cleanup)
except Exception as e:
raise Exception("Warning: Exception during cleanup : %s" % e)
return
@attr(tags=["advanced", "basic", "sg"], required_hardware="false")
def test_01_list_publicip_root_domain(self):
"""
ROOT domain should be able to list public IP address of all
sub domains
Step 1: List all public ip address
Step 2: Ensure that the count is greater than or equal to 30
Step 3: Display only allocated ip address
Step 4: Ensure that the count is greater than or equal to 0
Step 5: Display ip address from shared networks
Step 6: Ensure that the count is greater than or equal to 30
:return:
"""
# Step 1
ipAddresses = PublicIPAddress.list(
self.apiclient,
allocatedonly=False,
isrecursive=True,
listall=True,
forvirtualnetwork=True)
# Step 2
self.assertGreaterEqual(
len(ipAddresses),
30,
"Unable to display all public ip for ROOT domain"
)
# Step 4
ipAddresses = PublicIPAddress.list(
self.apiclient,
allocatedonly=True,
isrecursive=True,
listall=True,
forvirtualnetwork=True)
self.assertGreaterEqual(
len(ipAddresses),
0,
"Unable to display all public ip for ROOT domain"
)
# Step 5
ipAddresses = PublicIPAddress.list(
self.apiclient,
allocatedonly=False,
isrecursive=True,
listall=True,
forvirtualnetwork=False)
# Step 6
self.assertGreaterEqual(
len(ipAddresses),
10,
"Unable to display all public ip for ROOT domain"
)
@attr(tags=["advanced", "basic", "sg"], required_hardware="false")
def test_02_list_publicip_domain_admin(self):
"""
A domain admin should be able to list public IP address of
his/her domain and all sub domains
Step 1: Create an isolated network in the user domain and sub domain
Step 2: Associate IP in the range, dedicated to domain1
Step 3: Display all public ip address in domain1
Step 4: Ensure that the count is greater than or equal to 10
Step 5: Display only the allocated Ip address in domain1
Step 6: Ensure that the count is 1
Step 7: Try to display public ip address from shared networks
Step 8: It should not return any result
Step 9: Try to display ip address of domain1 from domain2
Step 10: Ensure that it doesnt not return any result
:return:
"""
# Step 1. Create isolated network
self.isolated_network1 = Network.create(
self.apiclient,
self.services["isolated_network"],
accountid=self.account1.name,
domainid=self.account1.domainid,
networkofferingid=self.isolated_network_offering.id,
zoneid=self.zone.id
)
# Step 2. Associate IP in range dedicated to domain1
ip_address_1 = self.get_free_ipaddress(self.public_ip_range1.vlan.id)
ipaddress = PublicIPAddress.create(
self.apiclient,
zoneid=self.zone.id,
networkid=self.isolated_network1.id,
ipaddress=ip_address_1
)
self.assertIsNotNone(
ipaddress,
"Failed to Associate IP Address"
)
# Step 3: Display all public ip address in domain1
user = self.account1.user[0]
user_api_client = self.testClient.getUserApiClient(user.username, self.domain1.name)
ipAddresses = PublicIPAddress.list(
user_api_client,
allocatedonly=False,
isrecursive=True,
listall=True,
forvirtualnetwork=True)
# Step 4: Ensure that the count is equal to 10
self.assertEqual(
len(ipAddresses),
10,
"Failed to display all public ip address is domain %s" % self.domain1.name
)
# Display public ip address using network id
ipAddresses = PublicIPAddress.list(
self.apiclient,
associatednetworkid=self.isolated_network1.id,
account=self.account1.name,
domainid=self.account1.domainid,
allocatedonly=False,
listall=True,
forvirtualnetwork=True)
# Step 4: Ensure that the count is greater than or equal to 10
self.assertEqual(
len(ipAddresses),
10,
"Failed to display all public ip address using network id"
)
# Step 5: Display all allocated public ip address in domain1
ipAddresses = PublicIPAddress.list(
user_api_client,
allocatedonly=True,
isrecursive=True,
listall=True,
forvirtualnetwork=True)
# Step 6: Ensure that the count is greater than or equal to 1
self.assertEqual(
len(ipAddresses),
1,
"Allocated IP address is greater than 1"
)
# Step 7: Display public ip address from shared networks
ipAddresses = PublicIPAddress.list(
user_api_client,
allocatedonly=True,
isrecursive=True,
listall=True,
forvirtualnetwork=False)
# Step 8: Ensure that the result is empty
self.assertIsNone(
ipAddresses,
"Users should not display ip from shared networks"
)
try:
# Step 9
user = self.account2.user[0]
user_api_client = self.testClient.getUserApiClient(user.username, self.domain2.name)
ipAddresses = PublicIPAddress.list(
user_api_client,
allocatedonly=False,
listall=True,
associatednetworkid=self.isolated_network1.id,
forvirtualnetwork=True)
# Step 10
self.fail("Domain should not access public ip of sibling domain")
except Exception as e:
self.info("Got exception as expected since domain2 cant access network of domain1")
@attr(tags=["advanced", "basic", "sg"], required_hardware="false")
def test_03_list_publicip_user_domain(self):
"""
A regular user should be able to display public ip address
only in his domain
Step 1: Create an isolated network in the user domain
Step 2: Display all public ip address in that domain
Step 3: Ensure that the count is 10
Step 4: Associate IP in the range, dedicated to domain2
Step 5: Display only the allocated Ip address in domain2
Step 6: Ensure that the count is 1
Step 7: Try to display public ip address from shared networks
Step 8: It should not return any result
Step 9: Try to display allocated public ip address of child domain using networkid
Step 10: It should display all allocated ip address from child domain
Step 11: Try to display all public ip address from child domain
Step 12: It should display all public ip of child domain
Step 13: Try to display ip of domain2 from a different domain
Step 14: Ensure that we get exception when trying to do so
:return:
"""
user = self.sub_account.user[0]
sub_user_api_client = self.testClient.getUserApiClient(user.username, self.sub_domain.name)
# Step 1: create network in child domain
self.isolated_network2 = Network.create(
self.apiclient,
self.services["isolated_network"],
accountid=self.sub_account.name,
domainid=self.sub_account.domainid,
networkofferingid=self.isolated_network_offering.id,
zoneid=self.zone.id
)
# Step 2: Display all public ip address in sub domain
ipAddresses = PublicIPAddress.list(
sub_user_api_client,
allocatedonly=False,
listall=True,
forvirtualnetwork=True)
# Step 3: Ensure that sub domain can list only the ip address in his domain
self.assertEqual(
len(ipAddresses),
10,
"Allocated IP address is greater than 1"
)
# Step 4: Associate IP in range dedicated to sub domain
ip_address_1 = self.get_free_ipaddress(self.public_ip_range2.vlan.id)
ipaddress = PublicIPAddress.create(
sub_user_api_client,
zoneid=self.zone.id,
networkid=self.isolated_network2.id,
ipaddress=ip_address_1
)
# Step 5: Display all allocated ip address in sub domain
ipAddresses = PublicIPAddress.list(
sub_user_api_client,
allocatedonly=True,
listall=True,
forvirtualnetwork=True)
# Step 6: Ensure that the count is 1
self.assertEqual(
len(ipAddresses),
1,
"Allocated IP address is greater than 1"
)
# Step 7: Display ip address from shared networks
ipAddresses = PublicIPAddress.list(
sub_user_api_client,
allocatedonly=True,
listall=True,
forvirtualnetwork=False)
# Step 8: It should not return any result
self.assertIsNone(
ipAddresses,
"Users should not display ip from shared networks"
)
user = self.account1.user[0]
user_api_client = self.testClient.getUserApiClient(user.username, self.domain1.name)
# Step 9: display ip of child domain using network id
ipAddresses = PublicIPAddress.list(
user_api_client,
allocatedonly=True,
listall=True,
isrecursive=True,
associatednetworkid=self.isolated_network2.id,
forvirtualnetwork=True)
# Step 10: Ensure that the count is 1 as only 1 ip is acquired in test 3
self.assertEqual(
len(ipAddresses),
1,
"Unable to display IP address of child domain using network id"
)
# Step 11: display ip of child domain using network id
ipAddresses = PublicIPAddress.list(
user_api_client,
allocatedonly=False,
listall=True,
isrecursive=True,
associatednetworkid=self.isolated_network2.id,
forvirtualnetwork=True)
# Step 12: Ensure that the count is 1 as only 1 ip is acquired in test 3
self.assertEqual(
len(ipAddresses),
10,
"Unable to display IP address of child domain using network id"
)
try:
# Step 13
user = self.account2.user[0]
user_api_client = self.testClient.getUserApiClient(user.username, self.domain2.name)
PublicIPAddress.list(
user_api_client,
allocatedonly=False,
listall=True,
associatednetworkid=self.isolated_network2.id,
forvirtualnetwork=True)
# Step 14
self.fail("Domain should not access public ip of sibling domain")
except Exception as e:
self.info("Got exception as expected since domain2 cant access network of domain1")
@attr(tags=["advanced", "basic", "sg"], required_hardware="false")
def test_04_list_publicip_all_subdomains(self):
"""
A domain admin should be able to display public ip address
in his domain and also all child domains
Step 1: Display all public ip address in that domain and sub domain
Step 2: Ensure that the count is 11 (all ip from parent domain and allocated from sub domain)
Step 3: Display only the allocated Ip address
Step 4: Ensure that the count is 2
Step 5: Display public ip of child domain using domain/account
Step 6: Ensure that the count is 10
Step 7: Display public ip of child domain using network id
Step 8: Ensure that the count is 1 as only one IP is allocated
:return:
"""
user = self.account1.user[0]
user_api_client = self.testClient.getUserApiClient(user.username, self.domain1.name)
# Step 1: Display all public ip
ipAddresses = PublicIPAddress.list(
user_api_client,
allocatedonly=False,
listall=True,
isrecursive=True,
forvirtualnetwork=True)
# Step 2: Ensure that it can display all ip from current domain and
# only allocated ip from child domains
self.assertEqual(
len(ipAddresses),
11,
"Unable to display all IP address is domain %s" % self.domain1.name
)
# Step 3: display only allocated ip for parent and sub domain
ipAddresses = PublicIPAddress.list(
user_api_client,
allocatedonly=True,
listall=True,
isrecursive=True,
forvirtualnetwork=True)
# Step 4: Ensure that the count is 2
self.assertEqual(
len(ipAddresses),
2,
"Unable to display all allocated IP address is domain %s" % self.domain1.name
)
# Step 5: display ip of child domain using domainid/account
ipAddresses = PublicIPAddress.list(
user_api_client,
allocatedonly=False,
listall=True,
isrecursive=True,
domainid=self.sub_domain.id,
account=self.sub_account.name,
forvirtualnetwork=True)
# Step 6: Ensure that the count is 10
self.assertEqual(
len(ipAddresses),
10,
"Unable to display IP address of child domain"
)
@attr(tags=["advanced", "basic", "sg"], required_hardware="false")
def test_05_list_publicip_user_domain(self):
"""
A domain admin should be able to display public ip address
in his domain and also all child domains
Step 1: Display all public ip address in that domain and sub domain
Step 2: Ensure that the count is 20
Step 3: Display only the allocated Ip address
Step 4: Ensure that the count is 2
Step 5: Try to display public ip of vpc from different domain
Step 6: Ensure that we get exception when trying to do so
:return:
"""
user = self.account2.user[0]
user_api_client = self.testClient.getUserApiClient(user.username, self.domain2.name)
self.services["vpc"]["cidr"] = "10.1.1.1/16"
vpc_1 = VPC.create(
user_api_client,
self.services["vpc"],
vpcofferingid=self.vpc_off.id,
zoneid=self.zone.id,
account=self.account2.name,
domainid=self.account2.domainid
)
self.validate_vpc_network(vpc_1)
ipAddresses = PublicIPAddress.list(
user_api_client,
allocatedonly=False,
listall=True,
forvirtualnetwork=True)
self.assertGreaterEqual(
len(ipAddresses),
10,
"Unable to display all public ip in VPC"
)
# List ip address using vpcid
ipAddresses = PublicIPAddress.list(
self.apiclient,
vpcid=vpc_1.id,
allocatedonly=False,
account=self.account2.name,
domainid=self.domain2.id,
forvirtualnetwork=True)
self.assertGreaterEqual(
len(ipAddresses),
10,
"Unable to display all public ip in VPC"
)
# Acquire public ip address from VPC
ip_address_1 = self.get_free_ipaddress(self.public_ip_range3.vlan.id)
PublicIPAddress.create(
user_api_client,
zoneid=self.zone.id,
vpcid=vpc_1.id,
ipaddress=ip_address_1
)
ipAddresses = PublicIPAddress.list(
user_api_client,
allocatedonly=True,
listall=True,
forvirtualnetwork=True)
self.assertGreaterEqual(
len(ipAddresses),
2,
"Unable to display allocated public ip in VPC"
)
try:
# Step 5
user = self.account1.user[0]
user_api_client = self.testClient.getUserApiClient(user.username, self.domain1.name)
PublicIPAddress.list(
user_api_client,
allocatedonly=False,
listall=True,
vpcid=vpc_1.id,
forvirtualnetwork=True)
# Step 6
self.fail("Domain should not access public ip of sibling domain")
except Exception as e:
self.info("Got exception as expected since domain2 cant access network of domain1")
self.vpc_off.update(self.apiclient, state='Disabled')
self.cleanup.append(vpc_1)
self.cleanup.append(self.vpc_off)
@attr(tags=["advanced", "basic", "sg"], required_hardware="false")
def test_06_list_publicip_user_domain(self):
"""
Display public ip address from shared networks
1. List public ip address of shared network as root admin
2. Ensure that it can display all public ip address
3. List public ip address of shared networks as domain admin
4. It should not return any result
5. Try to display public ip by passing network id
6. Ensure that we get exception when trying to do so
:return:
"""
# Step 1
ipAddresses = PublicIPAddress.list(
self.apiclient,
allocatedonly=False,
listall=True,
networkid=self.guest_network.id,
forvirtualnetwork=False)
# Step 2
self.assertGreaterEqual(
len(ipAddresses),
10,
"Unable to display allocated public ip in VPC"
)
user = self.account1.user[0]
user_api_client = self.testClient.getUserApiClient(user.username, self.domain1.name)
# Step 3
ipAddresses = PublicIPAddress.list(
user_api_client,
allocatedonly=False,
listall=True,
networkid=self.guest_network.id,
forvirtualnetwork=False)
# Step 4
self.assertIsNone(
ipAddresses,
"Unable to display allocated public ip in VPC"
)
try:
# Step 5
PublicIPAddress.list(
user_api_client,
allocatedonly=False,
listall=True,
associatednetworkid=self.guest_network.id,
forvirtualnetwork=True)
# Step 6
self.fail("Domain should not access public ip of sibling domain")
except Exception as e:
self.info("Got exception as expected since domain2 cant access network of domain1")
def get_free_ipaddress(self, vlanId):
ipaddresses = PublicIPAddress.list(
self.apiclient,
vlanid=vlanId,
state='Free'
)
self.assertEqual(
isinstance(ipaddresses, list),
True,
"List ipaddresses should return a valid response for Free ipaddresses"
)
random.shuffle(ipaddresses)
return ipaddresses[0].ipaddress
def validate_vpc_network(self, network, state=None):
"""Validates the VPC network"""
self.debug("Check if the VPC network is created successfully?")
vpc_networks = VPC.list(
self.apiclient,
id=network.id
)
self.assertEqual(
isinstance(vpc_networks, list),
True,
"List VPC network should return a valid list"
)
self.assertEqual(
network.name,
vpc_networks[0].name,
"Name of the VPC network should match with listVPC data"
)
if state:
self.assertEqual(
vpc_networks[0].state,
state,
"VPC state should be '%s'" % state
)
self.debug("VPC network validated - %s" % network.name)
return

View File

@ -227,7 +227,8 @@ class TestPublicIP(cloudstackTestCase):
# 1.listPublicIpAddresses should no more return the released address
list_pub_ip_addr_resp = list_publicIP(
self.apiclient,
id=ip_address.ipaddress.id
id=ip_address.ipaddress.id,
allocatedonly=True
)
if list_pub_ip_addr_resp is None:
return
@ -279,7 +280,8 @@ class TestPublicIP(cloudstackTestCase):
list_pub_ip_addr_resp = list_publicIP(
self.apiclient,
id=ip_address.ipaddress.id
id=ip_address.ipaddress.id,
allocatedonly=True
)
self.assertEqual(
@ -883,7 +885,8 @@ class TestReleaseIP(cloudstackTestCase):
while retriesCount > 0:
listResponse = list_publicIP(
self.apiclient,
id=self.ip_addr.id
id=self.ip_addr.id,
state="Allocated"
)
if listResponse is None:
isIpAddressDisassociated = True

View File

@ -46,5 +46,7 @@
"jp": "label.japanese.keyboard",
"sc": "label.simplified.chinese.keyboard"
},
"plugins": []
"docHelpMappings": {},
"plugins": [],
"basicZoneEnabled": true
}

View File

@ -1817,6 +1817,7 @@
"label.rolename": "Role",
"label.roles": "Roles",
"label.roletype": "Role Type",
"label.rootdisksize": "Root disk size (GB)",
"label.root.certificate": "Root certificate",
"label.root.disk.offering": "Root Disk Offering",
"label.root.disk.size": "Root disk size (GB)",

View File

@ -134,6 +134,9 @@ export default {
methods: {
execAction (action) {
action.resource = this.resource
if (action.docHelp) {
action.docHelp = this.$applyDocHelpMappings(action.docHelp)
}
this.$emit('exec-action', action)
},
handleShowBadge () {

View File

@ -33,6 +33,11 @@
<router-link :to="{ path: '/volume/' + volume.uuid }">{{ volume.type }} - {{ volume.path }}</router-link> ({{ parseFloat(volume.size / (1024.0 * 1024.0 * 1024.0)).toFixed(1) }} GB)
</div>
</div>
<div v-else-if="$route.meta.name === 'computeoffering' && item === 'rootdisksize'">
<div>
{{ parseFloat( resource.rootdisksize / (1024.0 * 1024.0 * 1024.0)).toFixed(1) }} GB
</div>
</div>
<div v-else-if="['name', 'type'].includes(item)">
<span v-if="['USER.LOGIN', 'USER.LOGOUT', 'ROUTER.HEALTH.CHECKS', 'FIREWALL.CLOSE', 'ALERT.SERVICE.DOMAINROUTER'].includes(resource[item])">{{ $t(resource[item].toLowerCase()) }}</span>
<span v-else>{{ resource[item] }}</span>

View File

@ -42,7 +42,7 @@ function generateRouterMap (section) {
name: section.name,
path: '/' + section.name,
hidden: section.hidden,
meta: { title: section.title, icon: section.icon, docHelp: section.docHelp, searchFilters: section.searchFilters },
meta: { title: section.title, icon: section.icon, docHelp: Vue.prototype.$applyDocHelpMappings(section.docHelp), searchFilters: section.searchFilters },
component: RouteView
}
@ -63,7 +63,7 @@ function generateRouterMap (section) {
title: child.title,
name: child.name,
icon: child.icon,
docHelp: child.docHelp,
docHelp: Vue.prototype.$applyDocHelpMappings(child.docHelp),
permission: child.permission,
resourceType: child.resourceType,
filters: child.filters,
@ -85,7 +85,7 @@ function generateRouterMap (section) {
title: child.title,
name: child.name,
icon: child.icon,
docHelp: child.docHelp,
docHelp: Vue.prototype.$applyDocHelpMappings(child.docHelp),
permission: child.permission,
resourceType: child.resourceType,
params: child.params ? child.params : {},
@ -140,7 +140,7 @@ function generateRouterMap (section) {
title: section.title,
name: section.name,
icon: section.icon,
docHelp: section.docHelp,
docHelp: Vue.prototype.$applyDocHelpMappings(section.docHelp),
hidden: section.hidden,
permission: section.permission,
resourceType: section.resourceType,

View File

@ -36,6 +36,10 @@ export default {
store.getters.apis.createServiceOffering.params.filter(x => x.name === 'storagepolicy').length > 0) {
fields.splice(6, 0, 'vspherestoragepolicy')
}
if (store.getters.apis.createServiceOffering &&
store.getters.apis.createServiceOffering.params.filter(x => x.name === 'rootdisksize').length > 0) {
fields.splice(12, 0, 'rootdisksize')
}
return fields
},
related: [{

View File

@ -26,7 +26,7 @@ import './core/lazy_use'
import './core/ext'
import './permission' // permission control
import './utils/filter' // global filter
import { pollJobPlugin, notifierPlugin, toLocaleDatePlugin } from './utils/plugins'
import { pollJobPlugin, notifierPlugin, toLocaleDatePlugin, configUtilPlugin } from './utils/plugins'
import { VueAxios } from './utils/request'
Vue.config.productionTip = false
@ -49,3 +49,5 @@ fetch('config.json').then(response => response.json()).then(config => {
}).$mount('#app')
})
})
Vue.use(configUtilPlugin)

View File

@ -167,3 +167,21 @@ export const toLocaleDatePlugin = {
}
}
}
export const configUtilPlugin = {
install (Vue) {
Vue.prototype.$applyDocHelpMappings = function (docHelp) {
var docHelpMappings = this.$config.docHelpMappings
if (docHelp && docHelpMappings &&
docHelpMappings.constructor === Object && Object.keys(docHelpMappings).length > 0) {
for (var key in docHelpMappings) {
if (docHelp.includes(key)) {
docHelp = docHelp.replace(key, docHelpMappings[key])
break
}
}
}
return docHelp
}
}
}

View File

@ -134,6 +134,10 @@ export default {
this.selectedDomain = this.domains[0].id
this.fetchAccounts()
this.fetchProjects()
}).catch(error => {
this.$notifyError(error)
}).finally(() => {
this.loading = false
})
},
fetchAccounts () {
@ -142,9 +146,12 @@ export default {
response: 'json',
domainId: this.selectedDomain,
state: 'Enabled',
listAll: true
isrecursive: false
}).then(response => {
this.accounts = response.listaccountsresponse.account
}).catch(error => {
this.$notifyError(error)
}).finally(() => {
this.loading = false
})
},
@ -155,9 +162,12 @@ export default {
domainId: this.selectedDomain,
state: 'Active',
details: 'min',
listAll: true
isrecursive: false
}).then(response => {
this.projects = response.listprojectsresponse.project
}).catch(error => {
this.$notifyError(error)
}).finally(() => {
this.loading = false
})
},
@ -172,6 +182,9 @@ export default {
projectid: this.selectedProject
}).then(response => {
this.networks = response.listnetworksresponse.network
}).catch(error => {
this.$notifyError(error)
}).finally(() => {
this.loading = false
})
},

View File

@ -194,11 +194,10 @@ export default {
min-height: 200px;
text-align: center;
vertical-align: center;
padding-top: 16px;
padding-top: 16px;
margin-top: 8px;
max-height: 300px;
overflow-y: auto;
padding: 16px 20px 0;
/deep/.has-error {
.ant-form-explain {

View File

@ -24,19 +24,22 @@
</a-card>
<a-table
bordered
:scroll="{ x: 500 }"
:dataSource="ipRanges"
:columns="columns"
:pagination="false"
style="margin-bottom: 24px;" >
style="margin-bottom: 24px; width: 100%" >
<template slot="actions" slot-scope="text, record">
<a-button type="danger" shape="circle" icon="delete" @click="onDelete(record.key)" />
</template>
<template slot="footer">
<a-form
layout="inline"
:layout="isMobile() ? 'horizontal': 'inline'"
:form="form"
@submit="handleAddRange">
<a-form-item :style="{ display: 'inline-block', width: '14%' }">
<a-row :gutter="12">
<a-col :md="4" :lg="4">
<a-form-item>
<a-input
v-decorator="[ 'gateway', {
rules: [{ required: true, message: $t('message.error.gateway') }]
@ -45,7 +48,9 @@
autoFocus
/>
</a-form-item>
<a-form-item :style="{ display: 'inline-block', width: '14%' }">
</a-col>
<a-col :md="4" :lg="4">
<a-form-item>
<a-input
v-decorator="[ 'netmask', {
rules: [{ required: true, message: $t('message.error.netmask') }]
@ -53,13 +58,17 @@
:placeholder="$t('label.netmask')"
/>
</a-form-item>
<a-form-item :style="{ display: 'inline-block', width: '14%' }">
</a-col>
<a-col :md="4" :lg="4">
<a-form-item>
<a-input
v-decorator="[ 'vlan', { rules: [{ required: false }] }]"
:placeholder="$t('label.vlan')"
/>
</a-form-item>
<a-form-item :style="{ display: 'inline-block', width: '14%' }">
</a-col>
<a-col :md="4" :lg="4">
<a-form-item>
<a-input
v-decorator="[ 'startIp', {
rules: [
@ -77,7 +86,9 @@
:placeholder="$t('label.start.ip')"
/>
</a-form-item>
<a-form-item :style="{ display: 'inline-block', width: '14%' }">
</a-col>
<a-col :md="4" :lg="4">
<a-form-item>
<a-input
v-decorator="[ 'endIp', {
rules: [
@ -94,9 +105,13 @@
:placeholder="$t('label.end.ip')"
/>
</a-form-item>
<a-form-item :style="{ display: 'inline-block', width: '14%' }">
</a-col>
<a-col :md="4" :lg="4">
<a-form-item :style="{ display: 'inline-block', float: 'right' }">
<a-button type="primary" html-type="submit">{{ $t('label.add') }}</a-button>
</a-form-item>
</a-col>
</a-row>
</a-form>
</template>
</a-table>
@ -126,7 +141,10 @@
</div>
</template>
<script>
import { mixinDevice } from '@/utils/mixin.js'
export default {
mixins: [mixinDevice],
props: {
traffic: {
type: String,
@ -183,7 +201,7 @@ export default {
title: '',
dataIndex: 'actions',
scopedSlots: { customRender: 'actions' },
width: 50
width: 70
}
],
showError: false,

View File

@ -251,11 +251,10 @@ export default {
min-height: 200px;
text-align: center;
vertical-align: center;
padding-top: 16px;
padding-top: 16px;
margin-top: 8px;
max-height: 300px;
overflow-y: auto;
padding: 16px 20px 0;
/deep/.has-error {
.ant-form-explain {

View File

@ -18,13 +18,15 @@
<template>
<div class="form">
<a-steps
ref="zoneStep"
labelPlacement="vertical"
size="small"
:current="currentStep">
<a-step
v-for="(item) in steps"
v-for="(item, index) in steps"
:key="item.title"
:title="$t(item.title)">
:title="$t(item.title)"
:ref="`step${index}`">
</a-step>
</a-steps>
<div>
@ -79,6 +81,7 @@
</div>
</template>
<script>
import { mixinDevice } from '@/utils/mixin.js'
import ZoneWizardZoneTypeStep from '@views/infra/zone/ZoneWizardZoneTypeStep'
import ZoneWizardZoneDetailsStep from '@views/infra/zone/ZoneWizardZoneDetailsStep'
import ZoneWizardNetworkSetupStep from '@views/infra/zone/ZoneWizardNetworkSetupStep'
@ -93,6 +96,7 @@ export default {
ZoneWizardAddResources,
ZoneWizardLaunchZone
},
mixins: [mixinDevice],
data () {
return {
currentStep: 0,
@ -138,9 +142,26 @@ export default {
methods: {
nextPressed () {
this.currentStep++
this.scrollToStepActive()
},
backPressed (data) {
this.currentStep--
this.scrollToStepActive()
},
scrollToStepActive () {
if (!this.isMobile()) {
return
}
this.$nextTick(() => {
if (!this.$refs.zoneStep) {
return
}
if (this.currentStep === 0) {
this.$refs.zoneStep.$el.scrollLeft = 0
return
}
this.$refs.zoneStep.$el.scrollLeft = this.$refs['step' + (this.currentStep - 1)][0].$el.offsetLeft
})
},
onFieldsChanged (data) {
if (data.zoneType &&
@ -177,7 +198,8 @@ export default {
<style scoped lang="scss">
.form {
width: 95vw;
width: 100%;
@media (min-width: 1000px) {
width: 800px;
}
@ -197,6 +219,15 @@ export default {
position: absolute;
right: 0;
}
/deep/.ant-steps {
overflow-x: auto;
padding: 10px 0;
}
/deep/.submit-btn {
display: none;
}
}
/deep/.ant-form-text {

View File

@ -17,9 +17,15 @@
<template>
<div style="width: auto;">
<a-steps progressDot :current="currentStep" size="small" style="margin-left: 0; margin-top: 16px;">
<a-steps
ref="resourceStep"
progressDot
:current="currentStep"
size="small"
style="margin-left: 0; margin-top: 16px;">
<a-step
v-for="step in steps"
v-for="(step, index) in steps"
:ref="`resourceStep${index}`"
:key="step.title"
:title="$t(step.title)"></a-step>
</a-steps>
@ -97,13 +103,15 @@
</div>
</template>
<script>
import StaticInputsForm from '@views/infra/zone/StaticInputsForm'
import { api } from '@/api'
import { mixinDevice } from '@/utils/mixin.js'
import StaticInputsForm from '@views/infra/zone/StaticInputsForm'
export default {
components: {
StaticInputsForm
},
mixins: [mixinDevice],
props: {
prefillContent: {
type: Object,
@ -687,14 +695,16 @@ export default {
primaryStorageScopes: [],
primaryStorageProtocols: [],
storageProviders: [],
currentStep: 0,
currentStep: null,
options: ['primaryStorageScope', 'primaryStorageProtocol', 'provider']
}
},
mounted () {
this.currentStep = this.prefillContent.resourceStep ? this.prefillContent.resourceStep : 0
if (this.stepChild && this.stepChild !== '') {
this.currentStep = this.steps.findIndex(item => item.fromKey === this.stepChild)
}
this.scrollToStepActive()
if (this.prefillContent.hypervisor.value === 'BareMetal') {
this.$emit('nextPressed')
} else {
@ -719,14 +729,35 @@ export default {
this.$emit('nextPressed')
} else {
this.currentStep++
this.$emit('fieldsChanged', { resourceStep: this.currentStep })
}
this.scrollToStepActive()
},
handleBack (e) {
if (this.currentStep === 0) {
this.$emit('backPressed')
} else {
this.currentStep--
this.$emit('fieldsChanged', { resourceStep: this.currentStep })
}
this.scrollToStepActive()
},
scrollToStepActive () {
if (!this.isMobile()) {
return
}
this.$nextTick(() => {
if (!this.$refs.resourceStep) {
return
}
if (this.currentStep === 0) {
this.$refs.resourceStep.$el.scrollLeft = 0
return
}
this.$refs.resourceStep.$el.scrollLeft = this.$refs['resourceStep' + (this.currentStep - 1)][0].$el.offsetLeft
})
},
fieldsChanged (changed) {
this.$emit('fieldsChanged', changed)

View File

@ -17,12 +17,18 @@
<template>
<div style="width: auto;">
<a-steps progressDot :current="currentStep" size="small" style="margin-left: 0px; margin-top: 16px;">
<a-steps
ref="zoneNetStep"
progressDot
:current="currentStep"
size="small"
style="margin-left: 0px; margin-top: 16px;">
<a-step
v-for="step in steps"
v-for="(step, index) in steps"
:key="step.title"
:title="$t(step.title)"
:style="stepScales"></a-step>
:style="stepScales"
:ref="`netStep${index}`"></a-step>
</a-steps>
<zone-wizard-physical-network-setup-step
v-if="steps && steps[currentStep].formKey === 'physicalNetwork'"
@ -110,6 +116,7 @@
<script>
import { api } from '@/api'
import { mixinDevice } from '@/utils/mixin.js'
import ZoneWizardPhysicalNetworkSetupStep from '@views/infra/zone/ZoneWizardPhysicalNetworkSetupStep'
import IpAddressRangeForm from '@views/infra/zone/IpAddressRangeForm'
import StaticInputsForm from '@views/infra/zone/StaticInputsForm'
@ -122,6 +129,7 @@ export default {
StaticInputsForm,
AdvancedGuestTrafficForm
},
mixins: [mixinDevice],
props: {
prefillContent: {
type: Object,
@ -187,8 +195,8 @@ export default {
return steps
},
stepScales () {
if (this.allSteps.length > 4) {
return { width: 'calc(100% / ' + this.allSteps.length + ')' }
if (!this.isMobile() && this.steps.length > 4) {
return { width: 'calc(100% / ' + this.steps.length + ')' }
}
return {}
},
@ -368,6 +376,7 @@ export default {
if (this.stepChild && this.stepChild !== '') {
this.currentStep = this.steps.findIndex(item => item.formKey === this.stepChild)
}
this.scrollToStepActive()
if (this.zoneType === 'Basic' ||
(this.zoneType === 'Advanced' && this.sgEnabled)) {
this.skipGuestTrafficStep = false
@ -401,6 +410,7 @@ export default {
} else {
this.currentStep++
this.$emit('fieldsChanged', { networkStep: this.currentStep })
this.scrollToStepActive()
}
},
handleBack (e) {
@ -409,8 +419,24 @@ export default {
} else {
this.currentStep--
this.$emit('fieldsChanged', { networkStep: this.currentStep })
this.scrollToStepActive()
}
},
scrollToStepActive () {
if (!this.isMobile()) {
return
}
this.$nextTick(() => {
if (!this.$refs.zoneNetStep) {
return
}
if (this.currentStep === 0) {
this.$refs.zoneNetStep.$el.scrollLeft = 0
return
}
this.$refs.zoneNetStep.$el.scrollLeft = this.$refs['netStep' + (this.currentStep - 1)][0].$el.offsetLeft
})
},
submitLaunchZone () {
this.$emit('submitLaunchZone')
},

View File

@ -24,10 +24,11 @@
</a-card>
<a-table
bordered
:scroll="{ x: 500 }"
:dataSource="physicalNetworks"
:columns="columns"
:pagination="false"
style="margin-bottom: 24px;">
style="margin-bottom: 24px; width: 100%">
<template slot="name" slot-scope="text, record">
<a-input :value="text" @change="e => onCellChange(record.key, 'name', e.target.value)" autoFocus />
</template>
@ -212,19 +213,20 @@ export default {
columns.push({
title: this.$t('label.network.name'),
dataIndex: 'name',
width: '30%',
width: 175,
scopedSlots: { customRender: 'name' }
})
columns.push({
title: this.$t('label.isolation.method'),
dataIndex: 'isolationMethod',
width: '20%',
width: 150,
scopedSlots: { customRender: 'isolationMethod' }
})
columns.push({
title: this.$t('label.traffic.types'),
key: 'traffics',
dataIndex: 'traffics',
width: 250,
scopedSlots: { customRender: 'traffics' }
})
if (this.isAdvancedZone) {
@ -232,7 +234,7 @@ export default {
title: '',
dataIndex: 'actions',
scopedSlots: { customRender: 'actions' },
width: 50
width: 70
})
}

View File

@ -30,10 +30,18 @@
initialValue: zoneType
}]
}]">
<a-card :gutter="12" class="card-item" v-if="$config.basicZoneEnabled">
<a-col :md="6" :lg="6">
<a-radio class="card-form-item" value="Basic">{{ $t('label.basic') }}</a-radio>
</a-col>
<a-col :md="18" :lg="18">
<a-card class="ant-form-text zone-support">{{ $t(zoneDescription.Basic) }}</a-card>
</a-col>
</a-card>
<a-card :gutter="12" class="card-item">
<a-col :md="6" :lg="6">
<a-radio style="display: none;" class="card-form-item" value="Advanced">{{ $t('label.advanced') }}</a-radio>
<span style="margin-top: 20px" class="card-form-item">
<a-radio class="card-form-item" value="Advanced" v-if="$config.basicZoneEnabled">{{ $t('label.advanced') }}</a-radio>
<span style="margin-top: 20px;" class="card-form-item" v-else>
<a-icon type="setting" style="margin-right: 10px" />
{{ $t('label.advanced') }}
</span>
@ -86,6 +94,7 @@ export default {
wrapperCol: { span: 14 }
},
zoneDescription: {
Basic: 'message.desc.basic.zone',
Advanced: 'message.desc.advanced.zone',
SecurityGroups: 'message.advanced.security.group'
}
@ -108,7 +117,7 @@ export default {
return this.zoneType === 'Advanced'
},
zoneType () {
return this.prefillContent.zoneType ? this.prefillContent.zoneType.value : 'Advanced'
return this.prefillContent.zoneType ? this.prefillContent.zoneType.value : (this.$config.basicZoneEnabled ? 'Basic' : 'Advanced')
},
securityGroupsEnabled () {
return this.isAdvancedZone && (this.prefillContent.securityGroupsEnabled ? this.prefillContent.securityGroupsEnabled.value : false)

View File

@ -21,10 +21,11 @@ import mockRouter from '../mock/mockRouter'
import localVue from '../setup'
import { mount } from '@vue/test-utils'
import { pollJobPlugin, notifierPlugin } from '@/utils/plugins'
import { pollJobPlugin, notifierPlugin, configUtilPlugin } from '@/utils/plugins'
localVue.use(pollJobPlugin)
localVue.use(notifierPlugin)
localVue.use(configUtilPlugin)
function createMockRouter (newRoutes = []) {
let routes = []