mirror of https://github.com/apache/cloudstack.git
Merge release branch 4.20 to 4.22
* 4.20: Fix/flasharray delete rename destroy patch conflict (#13049) Fix VPC network offerings listing in isolated network creation form (#12645) Update mysql java connector version to 8.4.0 (matching version for MySQL 8.4) (#12640) adaptive: honor user-provided capacityBytes when provider stats are unavailable (#13059) Flexibilize public IP selection (#11076)
This commit is contained in:
commit
21b2025c50
|
|
@ -282,7 +282,7 @@ jobs:
|
|||
# https://github.com/actions/runner-images/blob/main/images/linux/Ubuntu2004-Readme.md#mysql
|
||||
sudo apt-get install -y mysql-server
|
||||
sudo systemctl start mysql
|
||||
sudo mysql -uroot -proot -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY ''; FLUSH PRIVILEGES;"
|
||||
sudo mysql -uroot -proot -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY ''; FLUSH PRIVILEGES;"
|
||||
sudo systemctl restart mysql
|
||||
sudo mysql -uroot -e "SELECT VERSION();"
|
||||
|
||||
|
|
|
|||
|
|
@ -19,9 +19,21 @@ package com.cloud.network.dao;
|
|||
import com.cloud.network.vo.PublicIpQuarantineVO;
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
public interface PublicIpQuarantineDao extends GenericDao<PublicIpQuarantineVO, Long> {
|
||||
|
||||
PublicIpQuarantineVO findByPublicIpAddressId(long publicIpAddressId);
|
||||
|
||||
PublicIpQuarantineVO findByIpAddress(String publicIpAddress);
|
||||
|
||||
/**
|
||||
* Returns a list of public IP addresses that are actively quarantined at the specified date and the previous owner differs from the specified user.
|
||||
*
|
||||
* @param userId used to check against the IP's previous owner;
|
||||
* @param date used to check if the quarantine is active;
|
||||
* @return a list of PublicIpQuarantineVOs.
|
||||
*/
|
||||
List<PublicIpQuarantineVO> listQuarantinedIpAddressesToUser(Long userId, Date date);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ import org.springframework.stereotype.Component;
|
|||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.inject.Inject;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class PublicIpQuarantineDaoImpl extends GenericDaoBase<PublicIpQuarantineVO, Long> implements PublicIpQuarantineDao {
|
||||
|
|
@ -33,6 +35,8 @@ public class PublicIpQuarantineDaoImpl extends GenericDaoBase<PublicIpQuarantine
|
|||
|
||||
private SearchBuilder<IPAddressVO> ipAddressSearchBuilder;
|
||||
|
||||
private SearchBuilder<PublicIpQuarantineVO> quarantinedIpAddressesSearch;
|
||||
|
||||
@Inject
|
||||
IPAddressDao ipAddressDao;
|
||||
|
||||
|
|
@ -47,8 +51,16 @@ public class PublicIpQuarantineDaoImpl extends GenericDaoBase<PublicIpQuarantine
|
|||
publicIpAddressByIdSearch.join("quarantineJoin", ipAddressSearchBuilder, ipAddressSearchBuilder.entity().getId(),
|
||||
publicIpAddressByIdSearch.entity().getPublicIpAddressId(), JoinBuilder.JoinType.INNER);
|
||||
|
||||
quarantinedIpAddressesSearch = createSearchBuilder();
|
||||
quarantinedIpAddressesSearch.and("previousOwnerId", quarantinedIpAddressesSearch.entity().getPreviousOwnerId(), SearchCriteria.Op.NEQ);
|
||||
quarantinedIpAddressesSearch.and();
|
||||
quarantinedIpAddressesSearch.op("removedIsNull", quarantinedIpAddressesSearch.entity().getRemoved(), SearchCriteria.Op.NULL);
|
||||
quarantinedIpAddressesSearch.and("endDate", quarantinedIpAddressesSearch.entity().getEndDate(), SearchCriteria.Op.GT);
|
||||
quarantinedIpAddressesSearch.cp();
|
||||
|
||||
ipAddressSearchBuilder.done();
|
||||
publicIpAddressByIdSearch.done();
|
||||
quarantinedIpAddressesSearch.done();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -68,4 +80,14 @@ public class PublicIpQuarantineDaoImpl extends GenericDaoBase<PublicIpQuarantine
|
|||
|
||||
return findOneBy(sc, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PublicIpQuarantineVO> listQuarantinedIpAddressesToUser(Long userId, Date date) {
|
||||
SearchCriteria<PublicIpQuarantineVO> sc = quarantinedIpAddressesSearch.create();
|
||||
|
||||
sc.setParameters("previousOwnerId", userId);
|
||||
sc.setParameters("endDate", date);
|
||||
|
||||
return searchIncludingRemoved(sc, null, false, false);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,8 +57,8 @@
|
|||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
|
|
|||
|
|
@ -53,8 +53,8 @@
|
|||
<artifactId>commons-pool2</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.cloudstack</groupId>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
JAVA_OPTS="-Djava.security.properties=/etc/cloudstack/management/java.security.ciphers -Djava.awt.headless=true -Xmx2G -XX:+UseParallelGC -XX:MaxGCPauseMillis=500 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/cloudstack/management/ -XX:ErrorFile=/var/log/cloudstack/management/cloudstack-management.err --add-opens=java.base/java.lang=ALL-UNNAMED --add-exports=java.base/sun.security.x509=ALL-UNNAMED"
|
||||
|
||||
CLASSPATH="/usr/share/cloudstack-management/lib/*:/etc/cloudstack/management:/usr/share/cloudstack-common:/usr/share/cloudstack-management/setup:/usr/share/cloudstack-management:/usr/share/java/mysql-connector-java.jar:/usr/share/cloudstack-mysql-ha/lib/*"
|
||||
CLASSPATH="/usr/share/cloudstack-management/lib/*:/etc/cloudstack/management:/usr/share/cloudstack-common:/usr/share/cloudstack-management/setup:/usr/share/cloudstack-management:/usr/share/cloudstack-mysql-ha/lib/*"
|
||||
|
||||
BOOTSTRAP_CLASS=org.apache.cloudstack.ServerDaemon
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
JAVA_OPTS="-Xms256m -Xmx2048m --add-opens=java.base/java.lang=ALL-UNNAMED"
|
||||
|
||||
CLASSPATH="/usr/share/cloudstack-usage/*:/usr/share/cloudstack-usage/lib/*:/usr/share/cloudstack-mysql-ha/lib/*:/etc/cloudstack/usage:/usr/share/java/mysql-connector-java.jar"
|
||||
CLASSPATH="/usr/share/cloudstack-usage/*:/usr/share/cloudstack-usage/lib/*:/usr/share/cloudstack-mysql-ha/lib/*:/etc/cloudstack/usage"
|
||||
|
||||
JAVA_CLASS=com.cloud.usage.UsageServer
|
||||
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@
|
|||
<artifactId>globodns-client</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
|
|
|||
|
|
@ -41,8 +41,8 @@
|
|||
<artifactId>reload4j</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
|
|
|||
|
|
@ -217,13 +217,14 @@ public class AdaptiveDataStoreLifeCycleImpl extends BasePrimaryDataStoreLifeCycl
|
|||
// validate the provided details are correct/valid for the provider
|
||||
api.validate();
|
||||
|
||||
// if we have user-provided capacity bytes, validate they do not exceed the manaaged storage capacity bytes
|
||||
// User-provided capacityBytes always wins; validate against storage stats only when
|
||||
// the provider could actually report them. If the provider cannot (empty pod with no
|
||||
// footprint, no quota set, transient probe failure), fall through and use what the
|
||||
// user supplied rather than failing the whole registration.
|
||||
ProviderVolumeStorageStats stats = api.getManagedStorageStats();
|
||||
if (capacityBytes != null && capacityBytes != 0 && stats != null) {
|
||||
if (stats.getCapacityInBytes() > 0) {
|
||||
if (stats.getCapacityInBytes() < capacityBytes) {
|
||||
throw new InvalidParameterValueException("Capacity bytes provided exceeds the capacity of the storage endpoint: provided by user: " + capacityBytes + ", storage capacity from storage provider: " + stats.getCapacityInBytes());
|
||||
}
|
||||
if (capacityBytes != null && capacityBytes > 0) {
|
||||
if (stats != null && stats.getCapacityInBytes() > 0 && stats.getCapacityInBytes() < capacityBytes) {
|
||||
throw new InvalidParameterValueException("Provided capacity bytes exceed the capacity of the storage endpoint: provided by user: " + capacityBytes + ", storage capacity from storage provider: " + stats.getCapacityInBytes());
|
||||
}
|
||||
parameters.setCapacityBytes(capacityBytes);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,8 @@ import java.net.URL;
|
|||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
|
@ -88,6 +89,9 @@ public class FlashArrayAdapter implements ProviderAdapter {
|
|||
static final ObjectMapper mapper = new ObjectMapper();
|
||||
public String pod = null;
|
||||
public String hostgroup = null;
|
||||
private static final DateTimeFormatter DELETION_TIMESTAMP_FORMAT =
|
||||
DateTimeFormatter.ofPattern("yyyyMMddHHmmss").withZone(ZoneOffset.UTC);
|
||||
|
||||
private String username;
|
||||
private String password;
|
||||
private String accessToken;
|
||||
|
|
@ -200,28 +204,63 @@ public class FlashArrayAdapter implements ProviderAdapter {
|
|||
|
||||
@Override
|
||||
public void delete(ProviderAdapterContext context, ProviderAdapterDataObject dataObject) {
|
||||
// first make sure we are disconnected
|
||||
removeVlunsAll(context, pod, dataObject.getExternalName());
|
||||
String fullName = normalizeName(pod, dataObject.getExternalName());
|
||||
|
||||
FlashArrayVolume volume = new FlashArrayVolume();
|
||||
// Snapshots live under /volume-snapshots and already use the array's
|
||||
// reserved form <volume>.<suffix>, which legitimately contains ".".
|
||||
// The stricter [A-Za-z0-9_-] naming rule applies to regular volume
|
||||
// names and free-form rename targets, not to these reserved snapshot
|
||||
// names. Since FlashArray snapshot names are system-defined rather
|
||||
// than arbitrary rename targets, we skip the usual timestamped rename
|
||||
// and only mark snapshots destroyed; the array's own ".N" suffix
|
||||
// already disambiguates them in the recycle bin.
|
||||
if (dataObject.getType() == ProviderAdapterDataObject.Type.SNAPSHOT) {
|
||||
try {
|
||||
FlashArrayVolume destroy = new FlashArrayVolume();
|
||||
destroy.setDestroyed(true);
|
||||
PATCH("/volume-snapshots?names=" + fullName, destroy, new TypeReference<FlashArrayList<FlashArrayVolume>>() {
|
||||
});
|
||||
} catch (CloudRuntimeException e) {
|
||||
String msg = e.getMessage();
|
||||
if (msg != null && (msg.contains("No such volume or snapshot")
|
||||
|| msg.contains("Volume does not exist"))) {
|
||||
return;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// rename as we delete so it doesn't conflict if the template or volume is ever recreated
|
||||
// pure keeps the volume(s) around in a Destroyed bucket for a period of time post delete
|
||||
String timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new java.util.Date());
|
||||
volume.setExternalName(fullName + "-" + timestamp);
|
||||
// first make sure we are disconnected
|
||||
removeVlunsAll(context, pod, dataObject.getExternalName());
|
||||
|
||||
// Rename then destroy: FlashArray keeps destroyed volumes in a recycle
|
||||
// bin (default 24h) from which they can be recovered. Renaming with a
|
||||
// deletion timestamp gives operators a forensic trail when browsing the
|
||||
// array - they can see when each destroyed copy was deleted on the
|
||||
// CloudStack side. FlashArray rejects a single PATCH that combines
|
||||
// {name, destroyed}, so the rename and the destroy must be issued as
|
||||
// two separate requests each carrying only its own field.
|
||||
// Use UTC so the rename suffix is stable regardless of the management
|
||||
// server's local timezone or DST changes - operators correlating the
|
||||
// CloudStack delete event with the array's audit log get a consistent
|
||||
// wall-clock value.
|
||||
String timestamp = DELETION_TIMESTAMP_FORMAT.format(java.time.Instant.now());
|
||||
String renamedName = fullName + "-" + timestamp;
|
||||
|
||||
try {
|
||||
PATCH("/volumes?names=" + fullName, volume, new TypeReference<FlashArrayList<FlashArrayVolume>>() {
|
||||
FlashArrayVolume rename = new FlashArrayVolume();
|
||||
rename.setExternalName(renamedName);
|
||||
PATCH("/volumes?names=" + fullName, rename, new TypeReference<FlashArrayList<FlashArrayVolume>>() {
|
||||
});
|
||||
|
||||
// now delete it with new name
|
||||
volume.setDestroyed(true);
|
||||
|
||||
PATCH("/volumes?names=" + fullName + "-" + timestamp, volume, new TypeReference<FlashArrayList<FlashArrayVolume>>() {
|
||||
FlashArrayVolume destroy = new FlashArrayVolume();
|
||||
destroy.setDestroyed(true);
|
||||
PATCH("/volumes?names=" + renamedName, destroy, new TypeReference<FlashArrayList<FlashArrayVolume>>() {
|
||||
});
|
||||
} catch (CloudRuntimeException e) {
|
||||
if (e.toString().contains("Volume does not exist")) {
|
||||
String msg = e.getMessage();
|
||||
if (msg != null && msg.contains("Volume does not exist")) {
|
||||
return;
|
||||
} else {
|
||||
throw e;
|
||||
|
|
|
|||
12
pom.xml
12
pom.xml
|
|
@ -168,7 +168,7 @@
|
|||
<cs.libvirt-java.version>0.5.3</cs.libvirt-java.version>
|
||||
<cs.mail.version>1.5.0-b01</cs.mail.version>
|
||||
<cs.mustache.version>0.9.14</cs.mustache.version>
|
||||
<cs.mysql.version>8.0.33</cs.mysql.version>
|
||||
<cs.mysql.version>8.4.0</cs.mysql.version>
|
||||
<cs.neethi.version>2.0.4</cs.neethi.version>
|
||||
<cs.nitro.version>10.1</cs.nitro.version>
|
||||
<cs.opensaml.version>2.6.6</cs.opensaml.version>
|
||||
|
|
@ -468,8 +468,8 @@
|
|||
<version>${cs.reload4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<version>${cs.mysql.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
|
@ -484,12 +484,6 @@
|
|||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<version>${cs.mysql.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sf.ehcache</groupId>
|
||||
<artifactId>ehcache-core</artifactId>
|
||||
|
|
|
|||
|
|
@ -539,6 +539,9 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
|
|||
AssignIpAddressSearch.and("allocated", AssignIpAddressSearch.entity().getAllocatedTime(), Op.NULL);
|
||||
AssignIpAddressSearch.and("vlanId", AssignIpAddressSearch.entity().getVlanId(), Op.IN);
|
||||
AssignIpAddressSearch.and("forSystemVms", AssignIpAddressSearch.entity().isForSystemVms(), Op.EQ);
|
||||
AssignIpAddressSearch.and("id", AssignIpAddressSearch.entity().getId(), Op.NIN);
|
||||
AssignIpAddressSearch.and("requestedAddress", AssignIpAddressSearch.entity().getAddress(), Op.EQ);
|
||||
AssignIpAddressSearch.and("routerAddress", AssignIpAddressSearch.entity().getAddress(), Op.NEQ);
|
||||
|
||||
SearchBuilder<VlanVO> vlanSearch = _vlanDao.createSearchBuilder();
|
||||
vlanSearch.and("type", vlanSearch.entity().getVlanType(), Op.EQ);
|
||||
|
|
@ -945,10 +948,23 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
|
|||
if (podId != null) {
|
||||
sc = AssignIpAddressFromPodVlanSearch.create();
|
||||
sc.setJoinParameters("podVlanMapSB", "podId", podId);
|
||||
errorMessage.append(" pod id=" + podId);
|
||||
errorMessage.append(" pod id=").append(podId);
|
||||
} else {
|
||||
sc = AssignIpAddressSearch.create();
|
||||
errorMessage.append(" zone id=" + dcId);
|
||||
errorMessage.append(" zone id=").append(dcId);
|
||||
}
|
||||
|
||||
if (lockOneRow) {
|
||||
logger.debug("Listing quarantined public IPs to ignore on search for public IP for system VM. The IPs ignored will be the ones that: were not associated to account [{}]; were not removed yet; and with quarantine end dates after [{}].", owner.getUuid(), new Date());
|
||||
|
||||
List<PublicIpQuarantineVO> quarantinedAddresses = publicIpQuarantineDao.listQuarantinedIpAddressesToUser(owner.getId(), new Date());
|
||||
List<Long> quarantinedAddressesIDs = quarantinedAddresses.stream().map(PublicIpQuarantineVO::getPublicIpAddressId).collect(Collectors.toList());
|
||||
|
||||
logger.debug("Found addresses with the following IDs: [{}] that will be ignored when searching for available public IPs.", quarantinedAddressesIDs);
|
||||
|
||||
if (CollectionUtils.isNotEmpty(quarantinedAddressesIDs)) {
|
||||
sc.setParameters("id", quarantinedAddressesIDs.toArray());
|
||||
}
|
||||
}
|
||||
|
||||
sc.setParameters("dc", dcId);
|
||||
|
|
@ -956,11 +972,11 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
|
|||
// for direct network take ip addresses only from the vlans belonging to the network
|
||||
if (vlanUse == VlanType.DirectAttached) {
|
||||
sc.setJoinParameters("vlan", "networkId", guestNetworkId);
|
||||
errorMessage.append(", network id=" + guestNetworkId);
|
||||
errorMessage.append(", network id=").append(guestNetworkId);
|
||||
}
|
||||
if (requestedGateway != null) {
|
||||
sc.setJoinParameters("vlan", "vlanGateway", requestedGateway);
|
||||
errorMessage.append(", requested gateway=" + requestedGateway);
|
||||
errorMessage.append(", requested gateway=").append(requestedGateway);
|
||||
}
|
||||
sc.setJoinParameters("vlan", "type", vlanUse);
|
||||
|
||||
|
|
@ -970,38 +986,39 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
|
|||
NetworkDetailVO routerIpDetail = _networkDetailsDao.findDetail(network.getId(), ApiConstants.ROUTER_IP);
|
||||
routerIpAddress = routerIpDetail != null ? routerIpDetail.getValue() : null;
|
||||
}
|
||||
|
||||
if (requestedIp != null) {
|
||||
sc.addAnd("address", SearchCriteria.Op.EQ, requestedIp);
|
||||
errorMessage.append(": requested ip " + requestedIp + " is not available");
|
||||
sc.setParameters("requestedAddress", requestedIp);
|
||||
errorMessage.append(": requested ip ").append(requestedIp).append(" is not available");
|
||||
} else if (routerIpAddress != null) {
|
||||
sc.addAnd("address", Op.NEQ, routerIpAddress);
|
||||
sc.setParameters("routerAddress", routerIpAddress);
|
||||
}
|
||||
|
||||
boolean ascOrder = ! forSystemVms;
|
||||
Filter filter = new Filter(IPAddressVO.class, "forSystemVms", ascOrder, 0l, 1l);
|
||||
Filter filter = new Filter(IPAddressVO.class, "forSystemVms", ascOrder, 0L, 1L);
|
||||
|
||||
filter.addOrderBy(IPAddressVO.class,"vlanId", true);
|
||||
|
||||
List<IPAddressVO> addrs = new ArrayList<>();
|
||||
List<IPAddressVO> addresses = new ArrayList<>();
|
||||
|
||||
if (forSystemVms) {
|
||||
// Get Public IPs for system vms in dedicated ranges
|
||||
sc.setParameters("forSystemVms", true);
|
||||
if (lockOneRow) {
|
||||
addrs = _ipAddressDao.lockRows(sc, filter, true);
|
||||
addresses = _ipAddressDao.lockRows(sc, filter, true);
|
||||
} else {
|
||||
addrs = new ArrayList<>(_ipAddressDao.search(sc, null));
|
||||
addresses = new ArrayList<>(_ipAddressDao.search(sc, null));
|
||||
}
|
||||
}
|
||||
if ((!lockOneRow || (lockOneRow && CollectionUtils.isEmpty(addrs))) &&
|
||||
if ((!lockOneRow || (lockOneRow && CollectionUtils.isEmpty(addresses))) &&
|
||||
!(forSystemVms && SystemVmPublicIpReservationModeStrictness.value())) {
|
||||
sc.setParameters("forSystemVms", false);
|
||||
// If owner has dedicated Public IP ranges, fetch IP from the dedicated range
|
||||
// Otherwise fetch IP from the system pool
|
||||
// Checking if network is null in the case of system VM's. At the time of allocation of IP address to systemVm, no network is present.
|
||||
if (network == null || !(network.getGuestType() == GuestType.Shared && zone.getNetworkType() == NetworkType.Advanced)) {
|
||||
List<AccountVlanMapVO> maps = _accountVlanMapDao.listAccountVlanMapsByAccount(owner.getId());
|
||||
for (AccountVlanMapVO map : maps) {
|
||||
List<AccountVlanMapVO> accountVlanMaps = _accountVlanMapDao.listAccountVlanMapsByAccount(owner.getId());
|
||||
for (AccountVlanMapVO map : accountVlanMaps) {
|
||||
if (vlanDbIds == null || vlanDbIds.contains(map.getVlanDbId()))
|
||||
dedicatedVlanDbIds.add(map.getVlanDbId());
|
||||
}
|
||||
|
|
@ -1020,10 +1037,10 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
|
|||
if (!dedicatedVlanDbIds.isEmpty()) {
|
||||
fetchFromDedicatedRange = true;
|
||||
sc.setParameters("vlanId", dedicatedVlanDbIds.toArray());
|
||||
errorMessage.append(", vlanId id=" + Arrays.toString(dedicatedVlanDbIds.toArray()));
|
||||
errorMessage.append(", vlanId id=").append(Arrays.toString(dedicatedVlanDbIds.toArray()));
|
||||
} else if (!nonDedicatedVlanDbIds.isEmpty()) {
|
||||
sc.setParameters("vlanId", nonDedicatedVlanDbIds.toArray());
|
||||
errorMessage.append(", vlanId id=" + Arrays.toString(nonDedicatedVlanDbIds.toArray()));
|
||||
errorMessage.append(", vlanId id=").append(Arrays.toString(nonDedicatedVlanDbIds.toArray()));
|
||||
} else {
|
||||
if (podId != null) {
|
||||
InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", Pod.class, podId);
|
||||
|
|
@ -1037,13 +1054,13 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
|
|||
}
|
||||
}
|
||||
if (lockOneRow) {
|
||||
addrs = _ipAddressDao.lockRows(sc, filter, true);
|
||||
addresses = _ipAddressDao.lockRows(sc, filter, true);
|
||||
} else {
|
||||
addrs = new ArrayList<>(_ipAddressDao.search(sc, null));
|
||||
addresses = 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 ((!lockOneRow || (lockOneRow && addrs.size() == 0)) && fetchFromDedicatedRange && vlanUse == VlanType.VirtualNetwork) {
|
||||
if ((!lockOneRow || (lockOneRow && addresses.isEmpty())) && fetchFromDedicatedRange && vlanUse == VlanType.VirtualNetwork) {
|
||||
// Verify if account is allowed to acquire IPs from the system
|
||||
boolean useSystemIps = UseSystemPublicIps.valueIn(owner.getId());
|
||||
if (useSystemIps && !nonDedicatedVlanDbIds.isEmpty()) {
|
||||
|
|
@ -1051,15 +1068,15 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
|
|||
sc.setParameters("vlanId", nonDedicatedVlanDbIds.toArray());
|
||||
errorMessage.append(", vlanId id=" + Arrays.toString(nonDedicatedVlanDbIds.toArray()));
|
||||
if (lockOneRow) {
|
||||
addrs = _ipAddressDao.lockRows(sc, filter, true);
|
||||
addresses = _ipAddressDao.lockRows(sc, filter, true);
|
||||
} else {
|
||||
addrs.addAll(_ipAddressDao.search(sc, null));
|
||||
addresses.addAll(_ipAddressDao.search(sc, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lockOneRow && addrs.size() == 0) {
|
||||
if (lockOneRow && addresses.isEmpty()) {
|
||||
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.
|
||||
|
|
@ -1073,13 +1090,12 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
|
|||
}
|
||||
|
||||
if (lockOneRow) {
|
||||
assert (addrs.size() == 1) : "Return size is incorrect: " + addrs.size();
|
||||
IpAddress ipAddress = addrs.get(0);
|
||||
boolean ipCanBeAllocated = canPublicIpAddressBeAllocated(ipAddress, owner);
|
||||
IPAddressVO allocatableIp = addresses.get(0);
|
||||
|
||||
if (!ipCanBeAllocated) {
|
||||
throw new InsufficientAddressCapacityException(String.format("Failed to allocate public IP address [%s] as it is in quarantine.", ipAddress.getAddress()),
|
||||
DataCenter.class, dcId);
|
||||
boolean isPublicIpAllocatable = canPublicIpAddressBeAllocated(allocatableIp, owner);
|
||||
|
||||
if (!isPublicIpAllocatable) {
|
||||
throw new InsufficientAddressCapacityException(String.format("Failed to allocate public IP [%s] as it is in quarantine.", allocatableIp.getAddress()), DataCenter.class, dcId);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1088,12 +1104,12 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
|
|||
try {
|
||||
_resourceLimitMgr.checkResourceLimit(owner, ResourceType.public_ip);
|
||||
} catch (ResourceAllocationException ex) {
|
||||
logger.warn("Failed to allocate resource of type " + ex.getResourceType() + " for account " + owner);
|
||||
logger.warn("Failed to allocate resource of type {} for account {}", ex.getResourceType(), owner);
|
||||
throw new AccountLimitException("Maximum number of public IP addresses for account: " + owner.getAccountName() + " has been exceeded.");
|
||||
}
|
||||
}
|
||||
|
||||
return addrs;
|
||||
return addresses;
|
||||
}
|
||||
|
||||
@DB
|
||||
|
|
@ -2546,26 +2562,27 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
|
|||
PublicIpQuarantineVO publicIpQuarantineVO = publicIpQuarantineDao.findByPublicIpAddressId(ip.getId());
|
||||
|
||||
if (publicIpQuarantineVO == null) {
|
||||
logger.debug(String.format("Public IP address [%s] is not in quarantine; therefore, it is allowed to be allocated.", ip));
|
||||
logger.debug("Public IP address [{}] is not in quarantine; therefore, it is allowed to be allocated.", ip);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!isPublicIpAddressStillInQuarantine(publicIpQuarantineVO, new Date())) {
|
||||
logger.debug(String.format("Public IP address [%s] is no longer in quarantine; therefore, it is allowed to be allocated.", ip));
|
||||
logger.debug("Public IP address [{}] is no longer in quarantine; therefore, it is allowed to be allocated.", ip);
|
||||
removePublicIpAddressFromQuarantine(publicIpQuarantineVO.getId(), "IP was removed from quarantine because it was no longer in quarantine.");
|
||||
return true;
|
||||
}
|
||||
|
||||
Account previousOwner = _accountMgr.getAccount(publicIpQuarantineVO.getPreviousOwnerId());
|
||||
|
||||
if (Objects.equals(previousOwner.getUuid(), newOwner.getUuid())) {
|
||||
logger.debug(String.format("Public IP address [%s] is in quarantine; however, the Public IP previous owner [%s] is the same as the new owner [%s]; therefore the IP" +
|
||||
" can be allocated. The public IP address will be removed from quarantine.", ip, previousOwner, newOwner));
|
||||
logger.debug("Public IP address [{}] is in quarantine; however, the Public IP previous owner [{}] is the same as the new owner [{}]; therefore the IP" +
|
||||
" can be allocated. The public IP address will be removed from quarantine.", ip, previousOwner, newOwner);
|
||||
removePublicIpAddressFromQuarantine(publicIpQuarantineVO.getId(), "IP was removed from quarantine because it has been allocated by the previous owner");
|
||||
return true;
|
||||
}
|
||||
|
||||
logger.error(String.format("Public IP address [%s] is in quarantine and the previous owner [%s] is different than the new owner [%s]; therefore, the IP cannot be " +
|
||||
"allocated.", ip, previousOwner, newOwner));
|
||||
logger.error("Public IP address [{}] is in quarantine and the previous owner [{}] is different than the new owner [{}]; therefore, the IP cannot be " +
|
||||
"allocated.", ip, previousOwner, newOwner);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -2616,7 +2633,7 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
|
|||
publicIpQuarantineVO.setRemovalReason(removalReason);
|
||||
publicIpQuarantineVO.setRemoverAccountId(removerAccountId);
|
||||
|
||||
logger.debug(String.format("Removing public IP Address [%s] from quarantine by updating the removed date to [%s].", ipAddress, removedDate));
|
||||
logger.debug("Removing public IP Address [{}] from quarantine by updating the removed date to [{}].", ipAddress, removedDate);
|
||||
publicIpQuarantineDao.persist(publicIpQuarantineVO);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -356,6 +356,7 @@ public class IpAddressManagerTest {
|
|||
Mockito.when(ipAddressMock.getId()).thenReturn(dummyID);
|
||||
Mockito.when(publicIpQuarantineDaoMock.findByPublicIpAddressId(Mockito.anyLong())).thenReturn(publicIpQuarantineVOMock);
|
||||
Mockito.doReturn(false).when(ipAddressManager).isPublicIpAddressStillInQuarantine(Mockito.any(PublicIpQuarantineVO.class), Mockito.any(Date.class));
|
||||
Mockito.doNothing().when(ipAddressManager).removePublicIpAddressFromQuarantine(Mockito.anyLong(), Mockito.anyString());
|
||||
|
||||
boolean result = ipAddressManager.canPublicIpAddressBeAllocated(ipAddressMock, newOwnerMock);
|
||||
|
||||
|
|
|
|||
|
|
@ -104,9 +104,10 @@ CP=./
|
|||
|
||||
CP=${CP}$PATHSEP$CATALINA_HOME/conf
|
||||
|
||||
# Add mysql jar from mysql-connector-java package to CP
|
||||
# Add mysql jar from mysql-connector-j package to CP
|
||||
# for Jenkins
|
||||
CP=${CP}${PATHSEP}/usr/share/java/mysql-connector-java.jar
|
||||
MYSQL_CONNECTOR_VERSION = '8.4.0'
|
||||
CP=${CP}${PATHSEP}/usr/share/java/mysql-connector-j-${MYSQL_CONNECTOR_VERSION}.jar
|
||||
|
||||
for file in $CATALINA_HOME/webapps/client/WEB-INF/lib/*.jar
|
||||
do
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ class TestQuarantineIPs(cloudstackTestCase):
|
|||
self.services["root_admin"]["roletype"])
|
||||
|
||||
"""
|
||||
Set public.ip.address.quarantine.duration to 60 minutes
|
||||
Set public.ip.address.quarantine.duration to 1 minute
|
||||
"""
|
||||
update_configuration_cmd = updateConfiguration.updateConfigurationCmd()
|
||||
update_configuration_cmd.name = "public.ip.address.quarantine.duration"
|
||||
|
|
@ -168,8 +168,7 @@ class TestQuarantineIPs(cloudstackTestCase):
|
|||
zoneid=self.zone.id,
|
||||
vpcid=root_vpc.id,
|
||||
ipaddress=ip_address)
|
||||
self.assertIn(f"Failed to allocate public IP address [{ip_address}] as it is in quarantine.",
|
||||
exception.exception.errorMsg)
|
||||
self.assertIn("errorCode: 533", exception.exception.errorMsg)
|
||||
|
||||
# Owner should be able to allocate its IP in quarantine
|
||||
public_ip = PublicIPAddress.create(self.domain_admin_apiclient,
|
||||
|
|
@ -267,8 +266,7 @@ class TestQuarantineIPs(cloudstackTestCase):
|
|||
zoneid=self.zone.id,
|
||||
networkid=root_network.id,
|
||||
ipaddress=ip_address)
|
||||
self.assertIn(f"Failed to allocate public IP address [{ip_address}] as it is in quarantine.",
|
||||
exception.exception.errorMsg)
|
||||
self.assertIn("errorCode: 533", exception.exception.errorMsg)
|
||||
|
||||
# Owner should be able to allocate its IP in quarantine
|
||||
public_ip = PublicIPAddress.create(self.domain_admin_apiclient,
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ RUN mvn -Pdeveloper -Dsimulator -DskipTests clean install
|
|||
RUN find /var/lib/mysql -type f -exec touch {} \; && \
|
||||
(/usr/bin/mysqld_safe &) && \
|
||||
sleep 5; \
|
||||
mysql -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password by ''" --connect-expired-password; \
|
||||
mysql -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password by ''" --connect-expired-password; \
|
||||
mvn -Pdeveloper -pl developer -Ddeploydb; \
|
||||
mvn -Pdeveloper -pl developer -Ddeploydb-simulator; \
|
||||
MARVIN_FILE=`find /root/tools/marvin/dist/ -name "Marvin*.tar.gz"`; \
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ setup(name="Marvin",
|
|||
"marvin.sandbox.basic"],
|
||||
license="LICENSE.txt",
|
||||
install_requires=[
|
||||
"mysql-connector-python <= 8.0.30",
|
||||
"mysql-connector-python <= 8.4.0",
|
||||
"requests >= 2.2.1",
|
||||
"paramiko >= 1.13.0",
|
||||
"nose >= 1.3.3",
|
||||
|
|
|
|||
|
|
@ -4092,6 +4092,7 @@
|
|||
"message.warn.importing.instance.without.nic": "WARNING: This Instance is being imported without NICs and many Network resources will not be available. Consider creating a NIC via vCenter before importing or as soon as the Instance is imported. For KVM host, allocate a NIC to Instance after import.",
|
||||
"message.warn.select.template": "Please select a Template for Registration.",
|
||||
"message.warn.zone.mtu.update": "Please note that this limit won't affect pre-existing Network's MTU settings",
|
||||
"message.warn.vpc.offerings": "VPC offerings will only be shown if the selected account has at least one VPC.",
|
||||
"message.webhook.deliveries.time.filter": "Webhook deliveries list can be filtered based on date-time. Select 'Custom' for specifying start and end date range.",
|
||||
"message.zone.creation.complete": "Zone creation complete.",
|
||||
"message.zone.detail.description": "Populate Zone details.",
|
||||
|
|
|
|||
|
|
@ -2524,6 +2524,7 @@
|
|||
"message.vr.alert.upon.network.offering.creation.others": "Como nenhum dos servi\u00e7os obrigat\u00f3rios para cria\u00e7\u00e3o do VR (VPN, DHCP, DNS, Firewall, LB, UserData, SourceNat, StaticNat, PortForwarding) foram habilitados, o VR n\u00e3o ser\u00e1 criado e a oferta de computa\u00e7\u00e3o n\u00e3o ser\u00e1 usada.",
|
||||
"message.warn.filetype": "jpg, jpeg, png, bmp e svg s\u00e3o os \u00fanicos formatos de imagem suportados",
|
||||
"message.warn.importing.instance.without.nic": "AVISO: essa inst\u00e2ncia est\u00e1 sendo importada sem NICs e muitos recursos de rede n\u00e3o estar\u00e3o dispon\u00edveis. Considere criar uma NIC antes de importar via VCenter ou assim que a inst\u00e2ncia for importada.",
|
||||
"message.warn.vpc.offerings": "Ofertas de VPC somente ser\u00c3o exibidas caso a conta selecionada possua ao menos uma VPC.",
|
||||
"message.zone.creation.complete": "Cria\u00e7\u00e3o de zona completa",
|
||||
"message.zone.detail.description": "Preencha os detalhes da zona",
|
||||
"message.zone.detail.hint": "Uma zona \u00e9 a maior unidade organizacional no CloudStack, e normalmente corresponde a um \u00fanico datacenter. As zonas proporcionam isolamento f\u00edsico e redund\u00e2ncia. Uma zona consiste em um ou mais pods (cada um contendo hosts e servidores de armazenamento prim\u00e1rio) e um servidor de armazenamento secund\u00e1rio que \u00e9 compartilhado por todos os pods da zona.",
|
||||
|
|
|
|||
|
|
@ -96,6 +96,11 @@
|
|||
{{ opt.displaytext || opt.name || opt.description }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
<a-alert type="warning" v-if="!this.hasVPC">
|
||||
<template #message>
|
||||
<span v-html="$t('message.warn.vpc.offerings')"/>
|
||||
</template>
|
||||
</a-alert>
|
||||
</a-form-item>
|
||||
<a-form-item ref="asnumber" name="asnumber" v-if="isASNumberRequired()">
|
||||
<template #label>
|
||||
|
|
@ -369,7 +374,8 @@ export default {
|
|||
setMTU: false,
|
||||
asNumberLoading: false,
|
||||
selectedAsNumber: 0,
|
||||
asNumbersZone: []
|
||||
asNumbersZone: [],
|
||||
hasVPC: true
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
|
@ -515,13 +521,17 @@ export default {
|
|||
if (this.vpc !== null) { // from VPC section
|
||||
this.fetchNetworkOfferingData(true)
|
||||
} else { // from guest network section
|
||||
var params = {}
|
||||
const params = {
|
||||
account: this.owner.account,
|
||||
projectid: this.owner.projectid,
|
||||
domainid: this.owner.domainid
|
||||
}
|
||||
this.networkOfferingLoading = true
|
||||
if ('listVPCs' in this.$store.getters.apis) {
|
||||
getAPI('listVPCs', params).then(json => {
|
||||
const listVPCs = json.listvpcsresponse.vpc
|
||||
var vpcAvailable = this.arrayHasItems(listVPCs)
|
||||
if (vpcAvailable === false) {
|
||||
this.hasVPC = this.arrayHasItems(listVPCs)
|
||||
if (!this.hasVPC) {
|
||||
this.fetchNetworkOfferingData(false)
|
||||
} else {
|
||||
this.fetchNetworkOfferingData()
|
||||
|
|
@ -534,7 +544,7 @@ export default {
|
|||
},
|
||||
fetchNetworkOfferingData (forVpc) {
|
||||
this.networkOfferingLoading = true
|
||||
var params = {
|
||||
const params = {
|
||||
zoneid: this.selectedZone.id,
|
||||
guestiptype: 'Isolated',
|
||||
state: 'Enabled'
|
||||
|
|
@ -577,7 +587,7 @@ export default {
|
|||
},
|
||||
fetchVpcData () {
|
||||
this.vpcLoading = true
|
||||
var params = {
|
||||
const params = {
|
||||
listAll: true,
|
||||
details: 'min'
|
||||
}
|
||||
|
|
@ -600,14 +610,14 @@ export default {
|
|||
const formRaw = toRaw(this.form)
|
||||
const values = this.handleRemoveFields(formRaw)
|
||||
this.actionLoading = true
|
||||
var params = {
|
||||
const params = {
|
||||
zoneId: this.selectedZone.id,
|
||||
name: values.name,
|
||||
displayText: values.displaytext,
|
||||
networkOfferingId: this.selectedNetworkOffering.id
|
||||
}
|
||||
var usefulFields = ['gateway', 'netmask', 'cidrsize', 'startip', 'startipv4', 'endip', 'endipv4', 'dns1', 'dns2', 'ip6dns1', 'ip6dns2', 'sourcenatipaddress', 'externalid', 'vpcid', 'vlan', 'networkdomain']
|
||||
for (var field of usefulFields) {
|
||||
const usefulFields = ['gateway', 'netmask', 'cidrsize', 'startip', 'startipv4', 'endip', 'endipv4', 'dns1', 'dns2', 'ip6dns1', 'ip6dns2', 'sourcenatipaddress', 'externalid', 'vpcid', 'vlan', 'networkdomain']
|
||||
for (const field of usefulFields) {
|
||||
if (this.isValidTextValueForKey(values, field)) {
|
||||
params[field] = values[field]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -289,7 +289,7 @@ public class UsageSanityChecker {
|
|||
}
|
||||
|
||||
/**
|
||||
* usage something like: /usr/bin/java -Xmx2G -cp /usr/share/cloudstack-usage/*:/usr/share/cloudstack-usage/lib/*:/usr/share/cloudstack-mysql-ha/lib/*:/etc/cloudstack/usage:/usr/share/java/mysql-connector-java.jar:/usr/share/cloudstack-common com.cloud.usage.UsageSanityChecker
|
||||
* usage something like: /usr/bin/java -Xmx2G -cp /usr/share/cloudstack-usage/*:/usr/share/cloudstack-usage/lib/*:/usr/share/cloudstack-mysql-ha/lib/*:/etc/cloudstack/usage:/usr/share/cloudstack-common com.cloud.usage.UsageSanityChecker
|
||||
* @param args none
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue