Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
c7b0005
UI support for extraconfig in deploy and update instance (#11719)
abh1sar Sep 30, 2025
c822028
CKS: generate a random UUID as password of CKS user in project (#11639)
weizhouapache Oct 1, 2025
1f436b6
server: Consider Instance in Starting state as well for allocation al…
sudo87 Oct 2, 2025
23dbe3c
CKS: fix CKS creation on an existing Shared and Routed network (#11735)
weizhouapache Oct 3, 2025
6da9414
VMware: match nic mac for ip address fetch (#10641)
alexandru-bagu Oct 4, 2025
9e46ee1
server: add user.password.reset.smtp.useStartTLS and enabledSecurityP…
weizhouapache Oct 7, 2025
77247b1
server: do not enable the disabled local storage(s) on host connectio…
sureshanaparti Oct 7, 2025
1fc1a5d
linstor: use sparse/discard qemu-img convert on thin devices (#11787)
rp- Oct 6, 2025
0c61d97
Add support for providing userdata to system VMs (#11654)
vishesh92 Oct 8, 2025
6f74ebf
Storage pool response improvements (#10740)
sureshanaparti Oct 8, 2025
4a9b4a4
refactor: remove use of term entry-point from extensions code base (#…
shwstppr Oct 8, 2025
39ef8f6
Add `Hypervisor default` as cache mode for disk offerings (#10282)
hsato03 Oct 8, 2025
572c520
systemvmtemplate: Bump Debian version to 12.12.0 (#11778)
weizhouapache Oct 8, 2025
9b8d822
UI: Deal with crosssite api call after login (#10533)
DaanHoogland Oct 8, 2025
1b6436d
UI: Fix primary storage for datastore cluster and retain traffic labe…
sudo87 Oct 8, 2025
2392bc8
Sanitize the rbd file cmd parameter logs during qemu-img convert (thr…
sureshanaparti Oct 8, 2025
53370cf
storage: change storage pool to Up state when cancel storage migratio…
weizhouapache Oct 8, 2025
80a3c0b
Initial primary storage pool plugin skeleton
Sep 30, 2025
db371e2
Initial primary storage pool plugin skeleton - added license string
rajiv-jain-netapp Oct 8, 2025
9bb758a
Initial primary storage pool plugin skeleton - added license string +…
rajiv-jain-netapp Oct 8, 2025
25fb255
Initial primary storage pool plugin skeleton - added license string +…
rajiv-jain-netapp Oct 8, 2025
6d933e8
Feignconfiguration and volume feignClient along with desired POJOs
rajiv-jain-netapp Oct 13, 2025
f07a444
Feignconfiguration and volume feignClient along with desired POJOs
rajiv-jain-netapp Oct 13, 2025
43867e6
Revert "Feignconfiguration and volume feignClient along with desired …
rajiv-jain-netapp Oct 13, 2025
4f57cd2
Revert "Feignconfiguration and volume feignClient along with desired …
rajiv-jain-netapp Oct 13, 2025
bd4a23a
Feignconfiguration and volume feignClient along with desired POJOs
rajiv-jain-netapp Oct 13, 2025
1bb907f
Feignconfiguration and volume feignClient along with desired POJOs
rajiv-jain-netapp Oct 13, 2025
3327c15
CSTACKEX-28: added copyright comment in the logger configuration
rajiv-jain-netapp Oct 13, 2025
35ccaab
CSTACKEX-28: added newline in the end of the file
rajiv-jain-netapp Oct 13, 2025
b4c2f30
CSTACKEX-28 - incorporated review comments
rajiv-jain-netapp Oct 14, 2025
8e4efd1
Cluster, SVM and Aggr Feign Client
suryag1201 Oct 16, 2025
d8b98ed
NAS and Job Feign Client
suryag1201 Oct 17, 2025
a20dc4e
# This is a combination of 11 commits. This is a combination of 10 c…
Oct 10, 2025
572a1d5
CSTACKEX-25: Basic class structure
Oct 17, 2025
0be388b
CSTACKEX-25: Added code for job polling and addressed the review comm…
Oct 21, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api/src/main/java/com/cloud/offering/DiskOffering.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ enum State {
State getState();

enum DiskCacheMode {
NONE("none"), WRITEBACK("writeback"), WRITETHROUGH("writethrough");
NONE("none"), WRITEBACK("writeback"), WRITETHROUGH("writethrough"), HYPERVISOR_DEFAULT("hypervisor_default");

private final String _diskCacheMode;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class ApiConstants {
public static final String ACTIVATION_RULE = "activationrule";
public static final String ACTIVITY = "activity";
public static final String ADAPTER_TYPE = "adaptertype";
public static final String ADDITONAL_CONFIG_ENABLED = "additionalconfigenabled";
public static final String ADDRESS = "address";
public static final String ALGORITHM = "algorithm";
public static final String ALIAS = "alias";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ public class CreateDiskOfferingCmd extends BaseCmd {
@Parameter(name = ApiConstants.CACHE_MODE,
type = CommandType.STRING,
required = false,
description = "the cache mode to use for this disk offering. none, writeback or writethrough",
description = "the cache mode to use for this disk offering. none, writeback, writethrough or hypervisor default. If the hypervisor default cache mode is used on other hypervisors than KVM, it will fall back to none cache mode",
since = "4.14")
private String cacheMode;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ public class CreateServiceOfferingCmd extends BaseCmd {
@Parameter(name = ApiConstants.CACHE_MODE,
type = CommandType.STRING,
required = false,
description = "the cache mode to use for this disk offering. none, writeback or writethrough",
description = "the cache mode to use for this disk offering. none, writeback, writethrough or hypervisor default. If the hypervisor default cache mode is used on other hypervisors than KVM, it will fall back to none cache mode",
since = "4.14")
private String cacheMode;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ public void execute() {
response.setInstanceLeaseEnabled((Boolean) capabilities.get(ApiConstants.INSTANCE_LEASE_ENABLED));
response.setExtensionsPath((String)capabilities.get(ApiConstants.EXTENSIONS_PATH));
response.setDynamicScalingEnabled((Boolean) capabilities.get(ApiConstants.DYNAMIC_SCALING_ENABLED));
response.setAdditionalConfigEnabled((Boolean) capabilities.get(ApiConstants.ADDITONAL_CONFIG_ENABLED));
response.setObjectName("capability");
response.setResponseName(getCommandName());
this.setResponseObject(response);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,10 @@ public class CapabilitiesResponse extends BaseResponse {
@Param(description = "true if dynamically scaling for instances is enabled", since = "4.21.0")
private Boolean dynamicScalingEnabled;

@SerializedName(ApiConstants.ADDITONAL_CONFIG_ENABLED)
@Param(description = "true if additional configurations or extraconfig can be passed to Instances", since = "4.20.2")
private Boolean additionalConfigEnabled;

public void setSecurityGroupsEnabled(boolean securityGroupsEnabled) {
this.securityGroupsEnabled = securityGroupsEnabled;
}
Expand Down Expand Up @@ -272,4 +276,8 @@ public void setExtensionsPath(String extensionsPath) {
public void setDynamicScalingEnabled(Boolean dynamicScalingEnabled) {
this.dynamicScalingEnabled = dynamicScalingEnabled;
}

public void setAdditionalConfigEnabled(Boolean additionalConfigEnabled) {
this.additionalConfigEnabled = additionalConfigEnabled;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ public class ServiceOfferingResponse extends BaseResponseWithAnnotations {
private Boolean isCustomized;

@SerializedName("cacheMode")
@Param(description = "the cache mode to use for this disk offering. none, writeback or writethrough", since = "4.14")
@Param(description = "the cache mode to use for this disk offering. none, writeback, writethrough or hypervisor default", since = "4.14")
private String cacheMode;

@SerializedName("vspherestoragepolicy")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,19 +77,24 @@ public class StoragePoolResponse extends BaseResponseWithAnnotations {
@Param(description = "the name of the cluster for the storage pool")
private String clusterName;

@SerializedName(ApiConstants.CAPACITY_BYTES)
@Param(description = "bytes CloudStack can provision from this storage pool", since = "4.22.0")
private Long capacityBytes;

@Deprecated(since = "4.22.0")
@SerializedName("disksizetotal")
@Param(description = "the total disk size of the storage pool")
private Long diskSizeTotal;

@SerializedName("disksizeallocated")
@Param(description = "the host's currently allocated disk size")
@Param(description = "the pool's currently allocated disk size")
private Long diskSizeAllocated;

@SerializedName("disksizeused")
@Param(description = "the host's currently used disk size")
@Param(description = "the pool's currently used disk size")
private Long diskSizeUsed;

@SerializedName("capacityiops")
@SerializedName(ApiConstants.CAPACITY_IOPS)
@Param(description = "IOPS CloudStack can provision from this storage pool")
private Long capacityIops;

Expand Down Expand Up @@ -288,6 +293,14 @@ public void setClusterName(String clusterName) {
this.clusterName = clusterName;
}

public Long getCapacityBytes() {
return capacityBytes;
}

public void setCapacityBytes(Long capacityBytes) {
this.capacityBytes = capacityBytes;
}

public Long getDiskSizeTotal() {
return diskSizeTotal;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,23 @@

import com.cloud.utils.component.Manager;

import java.io.IOException;

public interface UserDataManager extends Manager, Configurable {
String VM_USERDATA_MAX_LENGTH_STRING = "vm.userdata.max.length";
ConfigKey<Integer> VM_USERDATA_MAX_LENGTH = new ConfigKey<>("Advanced", Integer.class, VM_USERDATA_MAX_LENGTH_STRING, "32768",
"Max length of vm userdata after base64 encoding. Default is 32768 and maximum is 1048576", true);

String concatenateUserData(String userdata1, String userdata2, String userdataProvider);
String validateUserData(String userData, BaseCmd.HTTPMethod httpmethod);

/**
* This method validates the user data uuid for system VMs and returns the user data
* after compression and base64 encoding for the system VM to consume.
*
* @param userDataUuid
* @return a String containing the user data after compression and base64 encoding
* @throws IOException
*/
String validateAndGetUserDataForSystemVM(String userDataUuid) throws IOException;
}
5 changes: 5 additions & 0 deletions client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,11 @@
<artifactId>cloud-plugin-storage-volume-adaptive</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-plugin-storage-volume-ontap</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-plugin-storage-volume-solidfire</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,8 @@ public VolumeObjectTO(VolumeInfo volume) {
iopsWriteRate = volume.getIopsWriteRate();
iopsWriteRateMax = volume.getIopsWriteRateMax();
iopsWriteRateMaxLength = volume.getIopsWriteRateMaxLength();
cacheMode = volume.getCacheMode();
hypervisorType = volume.getHypervisorType();
setCacheMode(volume.getCacheMode());
setDeviceId(volume.getDeviceId());
this.migrationOptions = volume.getMigrationOptions();
this.directDownload = volume.isDirectDownload();
Expand Down Expand Up @@ -343,6 +343,10 @@ public void setDeviceId(Long deviceId) {
}

public void setCacheMode(DiskCacheMode cacheMode) {
if (DiskCacheMode.HYPERVISOR_DEFAULT.equals(cacheMode) && !Hypervisor.HypervisorType.KVM.equals(hypervisorType)) {
this.cacheMode = DiskCacheMode.NONE;
return;
}
this.cacheMode = cacheMode;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ public interface VirtualMachineManager extends Manager {
ConfigKey<Boolean> VmSyncPowerStateTransitioning = new ConfigKey<>("Advanced", Boolean.class, "vm.sync.power.state.transitioning", "true",
"Whether to sync power states of the transitioning and stalled VMs while processing VM power reports.", false);

ConfigKey<Boolean> SystemVmEnableUserData = new ConfigKey<>(Boolean.class, "systemvm.userdata.enabled", "Advanced", "false",
"Enable user data for system VMs. When enabled, the CPVM, SSVM, and Router system VMs will use the values from the global settings console.proxy.vm.userdata, secstorage.vm.userdata, and virtual.router.userdata, respectively, to provide cloud-init user data to the VM.",
true, ConfigKey.Scope.Zone, null);

interface Topics {
String VM_POWER_STATE = "vm.powerstate";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
import com.cloud.storage.StoragePool;

public interface PrimaryDataStoreLifeCycle extends DataStoreLifeCycle {
public static final String CAPACITY_BYTES = "capacityBytes";
public static final String CAPACITY_IOPS = "capacityIops";
String CAPACITY_BYTES = "capacityBytes";
String CAPACITY_IOPS = "capacityIops";

void updateStoragePool(StoragePool storagePool, Map<String, String> details);
void enableStoragePool(DataStore store);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,8 @@ static Boolean getFullCloneConfiguration(Long storeId) {

Answer sendToPool(StoragePool pool, long[] hostIdsToTryFirst, Command cmd) throws StorageUnavailableException;

void updateStoragePoolHostVOAndBytes(StoragePool pool, long hostId, ModifyStoragePoolAnswer mspAnswer);

CapacityVO getSecondaryStorageUsedStats(Long hostId, Long zoneId);

CapacityVO getStoragePoolUsedStats(Long poolId, Long clusterId, Long podId, Long zoneId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5244,7 +5244,7 @@ public ConfigKey<?>[] getConfigKeys() {
VmConfigDriveLabel, VmConfigDriveOnPrimaryPool, VmConfigDriveForceHostCacheUse, VmConfigDriveUseHostCacheOnUnsupportedPool,
HaVmRestartHostUp, ResourceCountRunningVMsonly, AllowExposeHypervisorHostname, AllowExposeHypervisorHostnameAccountLevel, SystemVmRootDiskSize,
AllowExposeDomainInMetadata, MetadataCustomCloudName, VmMetadataManufacturer, VmMetadataProductName,
VmSyncPowerStateTransitioning
VmSyncPowerStateTransitioning, SystemVmEnableUserData
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,17 +116,17 @@ public class VMInstanceDaoImpl extends GenericDaoBase<VMInstanceVO, Long> implem

protected Attribute _updateTimeAttr;

private static final String ORDER_CLUSTERS_NUMBER_OF_VMS_FOR_ACCOUNT_PART1 = "SELECT host.cluster_id, SUM(IF(vm.state='Running' AND vm.account_id = ?, 1, 0)) " +
private static final String ORDER_CLUSTERS_NUMBER_OF_VMS_FOR_ACCOUNT_PART1 = "SELECT host.cluster_id, SUM(IF(vm.state IN ('Running', 'Starting') AND vm.account_id = ?, 1, 0)) " +
"FROM `cloud`.`host` host LEFT JOIN `cloud`.`vm_instance` vm ON host.id = vm.host_id WHERE ";
private static final String ORDER_CLUSTERS_NUMBER_OF_VMS_FOR_ACCOUNT_PART2 = " AND host.type = 'Routing' AND host.removed is null GROUP BY host.cluster_id " +
"ORDER BY 2 ASC ";

private static final String ORDER_PODS_NUMBER_OF_VMS_FOR_ACCOUNT = "SELECT pod.id, SUM(IF(vm.state='Running' AND vm.account_id = ?, 1, 0)) FROM `cloud`.`" +
private static final String ORDER_PODS_NUMBER_OF_VMS_FOR_ACCOUNT = "SELECT pod.id, SUM(IF(vm.state IN ('Running', 'Starting') AND vm.account_id = ?, 1, 0)) FROM `cloud`.`" +
"host_pod_ref` pod LEFT JOIN `cloud`.`vm_instance` vm ON pod.id = vm.pod_id WHERE pod.data_center_id = ? AND pod.removed is null "
+ " GROUP BY pod.id ORDER BY 2 ASC ";

private static final String ORDER_HOSTS_NUMBER_OF_VMS_FOR_ACCOUNT =
"SELECT host.id, SUM(IF(vm.state='Running' AND vm.account_id = ?, 1, 0)) FROM `cloud`.`host` host LEFT JOIN `cloud`.`vm_instance` vm ON host.id = vm.host_id " +
"SELECT host.id, SUM(IF(vm.state IN ('Running', 'Starting') AND vm.account_id = ?, 1, 0)) FROM `cloud`.`host` host LEFT JOIN `cloud`.`vm_instance` vm ON host.id = vm.host_id " +
"WHERE host.data_center_id = ? AND host.type = 'Routing' AND host.removed is null ";

private static final String ORDER_HOSTS_NUMBER_OF_VMS_FOR_ACCOUNT_PART2 = " GROUP BY host.id ORDER BY 2 ASC ";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,9 @@ public StoragePoolVO persist(StoragePoolVO pool, Map<String, String> details, Li
pool = super.persist(pool);
if (details != null) {
for (Map.Entry<String, String> detail : details.entrySet()) {
if (detail.getKey().toLowerCase().contains("password") || detail.getKey().toLowerCase().contains("token")) {
displayDetails = false;
}
StoragePoolDetailVO vo = new StoragePoolDetailVO(pool.getId(), detail.getKey(), detail.getValue(), displayDetails);
_detailsDao.persist(vo);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ CALL `cloud`.`IDEMPOTENT_CHANGE_COLUMN`('router_health_check', 'check_result', '
-- Increase length of scripts_version column to 128 due to md5sum to sha512sum change
CALL `cloud`.`IDEMPOTENT_CHANGE_COLUMN`('cloud.domain_router', 'scripts_version', 'scripts_version', 'VARCHAR(128)');

-- Increase the cache_mode column size from cloud.disk_offering table
CALL `cloud`.`IDEMPOTENT_CHANGE_COLUMN`('cloud.disk_offering', 'cache_mode', 'cache_mode', 'varchar(18) DEFAULT "none" COMMENT "The disk cache mode to use for disks created with this offering"');

-- Add uuid column to ldap_configuration table
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.ldap_configuration', 'uuid', 'VARCHAR(40) NOT NULL');

Expand All @@ -34,3 +37,7 @@ UPDATE `cloud`.`ldap_configuration` SET uuid = UUID() WHERE uuid IS NULL OR uuid

-- Add the column cross_zone_instance_creation to cloud.backup_repository. if enabled it means that new Instance can be created on all Zones from Backups on this Repository.
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.backup_repository', 'cross_zone_instance_creation', 'TINYINT(1) DEFAULT NULL COMMENT ''Backup Repository can be used for disaster recovery on another zone''');

-- Updated display to false for password/token detail of the storage pool details
UPDATE `cloud`.`storage_pool_details` SET display = 0 WHERE name LIKE '%password%';
UPDATE `cloud`.`storage_pool_details` SET display = 0 WHERE name LIKE '%token%';
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,7 @@ public class PrimaryDataStoreHelper {
DataStoreProviderManager dataStoreProviderMgr;

public DataStore createPrimaryDataStore(PrimaryDataStoreParameters params) {
if(params == null)
{
if (params == null) {
throw new InvalidParameterValueException("createPrimaryDataStore: Input params is null, please check");
}
StoragePoolVO dataStoreVO = dataStoreDao.findPoolByUUID(params.getUuid());
Expand Down Expand Up @@ -190,7 +189,9 @@ public DataStore attachHost(DataStore store, HostScope scope, StoragePoolInfo ex
pool.setScope(scope.getScopeType());
pool.setUsedBytes(existingInfo.getCapacityBytes() - existingInfo.getAvailableBytes());
pool.setCapacityBytes(existingInfo.getCapacityBytes());
pool.setStatus(StoragePoolStatus.Up);
if (pool.getStatus() != StoragePoolStatus.Disabled) {
pool.setStatus(StoragePoolStatus.Up);
}
this.dataStoreDao.update(pool.getId(), pool);
this.storageMgr.createCapacityEntry(pool, Capacity.CAPACITY_TYPE_LOCAL_STORAGE, pool.getUsedBytes());
return dataStoreMgr.getDataStore(pool.getId(), DataStoreRole.Primary);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,18 @@
// under the License.
package org.apache.cloudstack.userdata;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.cloud.domain.Domain;
import com.cloud.user.User;
import com.cloud.user.UserDataVO;
import com.cloud.user.dao.UserDataDao;
import com.cloud.utils.compression.CompressionUtil;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.commons.codec.binary.Base64;
Expand All @@ -31,7 +37,12 @@
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.exception.CloudRuntimeException;

import javax.inject.Inject;

public class UserDataManagerImpl extends ManagerBase implements UserDataManager {
@Inject
UserDataDao userDataDao;

private static final int MAX_USER_DATA_LENGTH_BYTES = 2048;
private static final int MAX_HTTP_GET_LENGTH = 2 * MAX_USER_DATA_LENGTH_BYTES; // 4KB
private static final int NUM_OF_2K_BLOCKS = 512;
Expand Down Expand Up @@ -118,6 +129,25 @@ public String validateUserData(String userData, BaseCmd.HTTPMethod httpmethod) {
return Base64.encodeBase64String(decodedUserData);
}

@Override
public String validateAndGetUserDataForSystemVM(String userDataUuid) throws IOException {
if (StringUtils.isBlank(userDataUuid)) {
return null;
}
UserDataVO userDataVo = userDataDao.findByUuid(userDataUuid);
if (userDataVo == null) {
return null;
}
if (userDataVo.getDomainId() == Domain.ROOT_DOMAIN && userDataVo.getAccountId() == User.UID_ADMIN) {
// Decode base64 user data, compress it, then re-encode to reduce command line length
String plainTextUserData = new String(java.util.Base64.getDecoder().decode(userDataVo.getUserData()));
CompressionUtil compressionUtil = new CompressionUtil();
byte[] compressedUserData = compressionUtil.compressString(plainTextUserData);
return java.util.Base64.getEncoder().encodeToString(compressedUserData);
}
throw new CloudRuntimeException("User data can only be used by system VMs if it belongs to the ROOT domain and ADMIN account.");
}

private byte[] validateAndDecodeByHTTPMethod(String userData, int maxHTTPLength, BaseCmd.HTTPMethod httpMethod) {
byte[] decodedUserData = Base64.decodeBase64(userData.getBytes());
if (decodedUserData == null || decodedUserData.length < 1) {
Expand Down
Loading
Loading