diff --git a/VERSION b/VERSION
index 6001980bf9..f7ee150716 100755
--- a/VERSION
+++ b/VERSION
@@ -1,3 +1,3 @@
MAJOR=4
MINOR=10
-UPDATE=16
+UPDATE=20
diff --git a/build/pom.xml b/build/pom.xml
index 2ca7311468..bcea34d5d1 100755
--- a/build/pom.xml
+++ b/build/pom.xml
@@ -292,11 +292,6 @@
cloudformation
${project.version}
-
- org.zstack
- hybrid
- ${project.version}
-
org.zstack
zwatch
@@ -317,21 +312,11 @@
sharedblock
${project.version}
-
- org.zstack
- ministorage
- ${project.version}
-
org.zstack
storage-device
${project.version}
-
- org.zstack
- mini
- ${project.version}
-
org.zstack
autoscaling
@@ -357,11 +342,6 @@
xdragon
${project.version}
-
- org.zstack
- aliyun-storage
- ${project.version}
-
org.zstack
block-primary-storage
@@ -402,21 +382,6 @@
baremetal
${project.version}
-
- org.zstack
- baremetal2
- ${project.version}
-
-
- org.zstack
- external-api-adapter
- ${project.version}
-
-
- org.zstack
- aliyun-proxy
- ${project.version}
-
org.zstack
upgrade-hack
@@ -468,11 +433,6 @@
vpcFirewall
${project.version}
-
- org.zstack
- sns-aliyun-sms
- ${project.version}
-
org.zstack
guesttools
@@ -578,6 +538,11 @@
hostNetworkInterface
${project.version}
+
+ org.zstack
+ managements
+ ${project.version}
+
diff --git a/compute/src/main/java/org/zstack/compute/allocator/HostOsVersionAllocatorFlow.java b/compute/src/main/java/org/zstack/compute/allocator/HostOsVersionAllocatorFlow.java
index 2fa09f72ff..0598be3f25 100755
--- a/compute/src/main/java/org/zstack/compute/allocator/HostOsVersionAllocatorFlow.java
+++ b/compute/src/main/java/org/zstack/compute/allocator/HostOsVersionAllocatorFlow.java
@@ -4,7 +4,6 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.zstack.compute.host.HostManager;
-import org.zstack.core.Platform;
import org.zstack.core.db.Q;
import org.zstack.header.allocator.AbstractHostAllocatorFlow;
import org.zstack.header.allocator.HostCandidate;
@@ -72,7 +71,8 @@ public void allocate() {
private Map generateHostUuidOsMap(List hostList) {
final Map hostHypervisorTypeMap = hostList.stream()
- .collect(Collectors.toMap(ResourceVO::getUuid, HostAO::getHypervisorType));
+ .collect(Collectors.toMap(ResourceVO::getUuid, HostAO::getHypervisorType,
+ (existing, replacement) -> replacement));
final Set hypervisorTypeSet = new HashSet<>(hostHypervisorTypeMap.values());
final Map results = new HashMap<>(hostList.size());
diff --git a/compute/src/main/java/org/zstack/compute/host/HostApiInterceptor.java b/compute/src/main/java/org/zstack/compute/host/HostApiInterceptor.java
index ca555af24e..bd4b13b6ff 100755
--- a/compute/src/main/java/org/zstack/compute/host/HostApiInterceptor.java
+++ b/compute/src/main/java/org/zstack/compute/host/HostApiInterceptor.java
@@ -1,6 +1,7 @@
package org.zstack.compute.host;
import org.springframework.beans.factory.annotation.Autowired;
+import org.zstack.compute.vm.VmHostnameUtils;
import org.zstack.core.CoreGlobalProperty;
import org.zstack.core.componentloader.PluginRegistry;
import org.zstack.core.upgrade.UpgradeGlobalConfig;
@@ -17,6 +18,7 @@
import org.zstack.header.apimediator.ApiMessageInterceptor;
import org.zstack.header.apimediator.StopRoutingException;
import org.zstack.header.host.*;
+import org.zstack.header.image.ImagePlatform;
import org.zstack.header.message.APIMessage;
import org.zstack.utils.ShellResult;
import org.zstack.utils.ShellUtils;
@@ -73,6 +75,8 @@ public APIMessage intercept(APIMessage msg) throws ApiMessageInterceptionExcepti
validate((APIGetPhysicalMachineBlockDevicesMsg) msg);
} else if (msg instanceof APIMountBlockDeviceMsg) {
validate((APIMountBlockDeviceMsg) msg);
+ } else if (msg instanceof APIUpdateHostnameMsg) {
+ validate((APIUpdateHostnameMsg) msg);
}
return msg;
@@ -169,6 +173,10 @@ private void validate(APIMountBlockDeviceMsg msg) {
validateMountPoint(msg.getMountPoint());
}
+ private void validate(APIUpdateHostnameMsg msg) {
+ VmHostnameUtils.validateHostname(msg.getHostname(), false);
+ }
+
private void validatePath(String path) {
if (path == null || path.isEmpty()) {
throw new ApiMessageInterceptionException(operr("path cannot be empty"));
diff --git a/compute/src/main/java/org/zstack/compute/host/HostBase.java b/compute/src/main/java/org/zstack/compute/host/HostBase.java
index 6c90ce3451..1c42cbaaeb 100755
--- a/compute/src/main/java/org/zstack/compute/host/HostBase.java
+++ b/compute/src/main/java/org/zstack/compute/host/HostBase.java
@@ -186,11 +186,34 @@ protected void handleApiMessage(APIMessage msg) {
handle((APIGetHostPowerStatusMsg) msg);
} else if (msg instanceof APIUpdateHostNqnMsg) {
handle((APIUpdateHostNqnMsg) msg);
+ } else if (msg instanceof APIUpdateHostnameMsg) {
+ handle((APIUpdateHostnameMsg) msg);
} else {
bus.dealWithUnknownMessage(msg);
}
}
+ private void handle(APIUpdateHostnameMsg msg) {
+ APIUpdateHostnameEvent event = new APIUpdateHostnameEvent(msg.getId());
+ UpdateHostnameMsg umsg = new UpdateHostnameMsg();
+ umsg.setUuid(msg.getUuid());
+ umsg.setHostname(msg.getHostname());
+ bus.makeTargetServiceIdByResourceUuid(umsg, HostConstant.SERVICE_ID, msg.getHostUuid());
+ bus.send(umsg, new CloudBusCallBack(msg) {
+ @Override
+ public void run(MessageReply reply) {
+ UpdateHostnameReply r = reply.castReply();
+ if (!r.isSuccess()) {
+ event.setSuccess(false);
+ event.setError(r.getError());
+ } else {
+ event.setInventory(r.getInventory());
+ }
+ bus.publish(event);
+ }
+ });
+ }
+
private void handle(APIUpdateHostNqnMsg msg) {
APIUpdateHostNqnEvent event = new APIUpdateHostNqnEvent(msg.getId());
UpdateHostNqnMsg umsg = new UpdateHostNqnMsg();
diff --git a/compute/src/main/java/org/zstack/compute/vm/ApplianceVmAllocatePrimaryStorageFlow.java b/compute/src/main/java/org/zstack/compute/vm/ApplianceVmAllocatePrimaryStorageFlow.java
index eab79d8e1d..3b5ff77d37 100644
--- a/compute/src/main/java/org/zstack/compute/vm/ApplianceVmAllocatePrimaryStorageFlow.java
+++ b/compute/src/main/java/org/zstack/compute/vm/ApplianceVmAllocatePrimaryStorageFlow.java
@@ -34,6 +34,8 @@
import java.util.*;
+import static org.zstack.utils.CollectionUtils.isEmpty;
+
@Configurable(preConstruction = true, autowire = Autowire.BY_TYPE)
public class ApplianceVmAllocatePrimaryStorageFlow implements Flow {
protected static final CLogger logger = Utils.getLogger(ApplianceVmAllocatePrimaryStorageFlow.class);
@@ -64,7 +66,7 @@ public void run(final FlowTrigger trigger, final Map data) {
List primaryStorageTypes = hostAllocatorMgr.getBackupStoragePrimaryStorageMetrics().get(bsType);
DebugUtils.Assert(primaryStorageTypes != null, "why primaryStorageTypes is null");
- DebugUtils.Assert(spec.getDataDiskOfferings().size() == 0, "create appliance vm can not with data volume");
+ DebugUtils.Assert(isEmpty(spec.getDeprecatedDisksSpecs()), "create appliance vm can not with data volume");
for (PrimaryStorageAllocatorStrategyExtensionPoint ext : pluginRgty.getExtensionList(PrimaryStorageAllocatorStrategyExtensionPoint.class)) {
String allocatorStrategyType = ext.getAllocatorStrategy(destHost);
diff --git a/compute/src/main/java/org/zstack/compute/vm/InstantiateVmFromNewCreatedStruct.java b/compute/src/main/java/org/zstack/compute/vm/InstantiateVmFromNewCreatedStruct.java
index ae3b56ad48..485d78a1b7 100644
--- a/compute/src/main/java/org/zstack/compute/vm/InstantiateVmFromNewCreatedStruct.java
+++ b/compute/src/main/java/org/zstack/compute/vm/InstantiateVmFromNewCreatedStruct.java
@@ -1,11 +1,8 @@
package org.zstack.compute.vm;
+import org.zstack.header.configuration.VmCustomSpecificationStruct;
import org.zstack.header.host.CpuArchitecture;
-import org.zstack.header.vm.CreateVmInstanceMsg;
-import org.zstack.header.vm.DiskAO;
-import org.zstack.header.vm.InstantiateNewCreatedVmInstanceMsg;
-import org.zstack.header.vm.VmCreationStrategy;
-import org.zstack.header.vm.VmNicSpec;
+import org.zstack.header.vm.*;
import java.util.ArrayList;
import java.util.List;
@@ -16,7 +13,6 @@
* Created by xing5 on 2016/9/13.
*/
public class InstantiateVmFromNewCreatedStruct {
- private List dataDiskOfferingUuids;
private List dataVolumeTemplateUuids;
private Map> dataVolumeFromTemplateSystemTags;
private List l3NetworkUuids;
@@ -28,12 +24,14 @@ public class InstantiateVmFromNewCreatedStruct {
private String requiredHostUuid;
private List softAvoidHostUuids;
private List avoidHostUuids;
- private Map> dataVolumeSystemTagsOnIndex;
private List disableL3Networks;
private List sshKeyPairUuids;
private final List candidatePrimaryStorageUuidsForRootVolume = new ArrayList<>();
private final List candidatePrimaryStorageUuidsForDataVolume = new ArrayList<>();
- private List diskAOs;
+ private DiskAO rootDisk;
+ private List dataDisks;
+ private List deprecatedDataVolumeSpecs = new ArrayList<>();
+ private VmCustomSpecificationStruct vmCustomSpecification;
public List getCandidatePrimaryStorageUuidsForRootVolume() {
return candidatePrimaryStorageUuidsForRootVolume;
@@ -57,13 +55,36 @@ public void setCandidatePrimaryStorageUuidsForDataVolume(List candidateP
}
}
+ public DiskAO getRootDisk() {
+ return rootDisk;
+ }
+
+ public void setRootDisk(DiskAO rootDisk) {
+ this.rootDisk = rootDisk;
+ }
+
+ public List getDataDisks() {
+ return dataDisks;
+ }
+
+ public void setDataDisks(List dataDisks) {
+ this.dataDisks = dataDisks;
+ }
+
+ public List getDeprecatedDataVolumeSpecs() {
+ return deprecatedDataVolumeSpecs;
+ }
- public List getDiskAOs() {
- return diskAOs;
+ public void setDeprecatedDataVolumeSpecs(List deprecatedDataVolumeSpecs) {
+ this.deprecatedDataVolumeSpecs = deprecatedDataVolumeSpecs;
}
- public void setDiskAOs(List diskAOs) {
- this.diskAOs = diskAOs;
+ public VmCustomSpecificationStruct getVmCustomSpecification() {
+ return vmCustomSpecification;
+ }
+
+ public void setVmCustomSpecification(VmCustomSpecificationStruct vmCustomSpecification) {
+ this.vmCustomSpecification = vmCustomSpecification;
}
public List getRootVolumeSystemTags() {
@@ -86,14 +107,6 @@ public static String makeLabelKey(String vmUuid) {
return String.format("not-start-vm-%s", vmUuid);
}
- public List getDataDiskOfferingUuids() {
- return dataDiskOfferingUuids;
- }
-
- public void setDataDiskOfferingUuids(List dataDiskOfferingUuids) {
- this.dataDiskOfferingUuids = dataDiskOfferingUuids;
- }
-
public List getDataVolumeTemplateUuids() {
return dataVolumeTemplateUuids;
}
@@ -136,7 +149,6 @@ public CpuArchitecture getArchitecture() {
public static InstantiateVmFromNewCreatedStruct fromMessage(InstantiateNewCreatedVmInstanceMsg msg) {
InstantiateVmFromNewCreatedStruct struct = new InstantiateVmFromNewCreatedStruct();
- struct.setDataDiskOfferingUuids(msg.getDataDiskOfferingUuids());
struct.setDataVolumeTemplateUuids(msg.getDataVolumeTemplateUuids());
struct.setDataVolumeFromTemplateSystemTags(msg.getDataVolumeFromTemplateSystemTags());
struct.setL3NetworkUuids(msg.getL3NetworkUuids());
@@ -150,15 +162,16 @@ public static InstantiateVmFromNewCreatedStruct fromMessage(InstantiateNewCreate
struct.setRequiredHostUuid(msg.getHostUuid());
struct.setSoftAvoidHostUuids(msg.getSoftAvoidHostUuids());
struct.setAvoidHostUuids(msg.getAvoidHostUuids());
- struct.setDataVolumeSystemTagsOnIndex(msg.getDataVolumeSystemTagsOnIndex());
struct.setDisableL3Networks(msg.getDisableL3Networks());
- struct.setDiskAOs(msg.getDiskAOs());
+ struct.setRootDisk(msg.getRootDisk());
+ struct.setDataDisks(msg.getDataDisks());
+ struct.setDeprecatedDataVolumeSpecs(msg.getDeprecatedDataVolumeSpecs());
+ struct.setVmCustomSpecification(msg.getVmCustomSpecification());
return struct;
}
public static InstantiateVmFromNewCreatedStruct fromMessage(CreateVmInstanceMsg msg) {
InstantiateVmFromNewCreatedStruct struct = new InstantiateVmFromNewCreatedStruct();
- struct.setDataDiskOfferingUuids(msg.getDataDiskOfferingUuids());
struct.setDataVolumeTemplateUuids(msg.getDataVolumeTemplateUuids());
struct.setDataVolumeFromTemplateSystemTags(msg.getDataVolumeFromTemplateSystemTags());
struct.setL3NetworkUuids(msg.getL3NetworkSpecs());
@@ -169,9 +182,11 @@ public static InstantiateVmFromNewCreatedStruct fromMessage(CreateVmInstanceMsg
struct.setRootVolumeSystemTags(msg.getRootVolumeSystemTags());
struct.setDataVolumeSystemTags(msg.getDataVolumeSystemTags());
struct.setRequiredHostUuid(msg.getHostUuid());
- struct.setDataVolumeSystemTagsOnIndex(msg.getDataVolumeSystemTagsOnIndex());
struct.setDisableL3Networks(msg.getDisableL3Networks());
- struct.setDiskAOs(msg.getDiskAOs());
+ struct.setRootDisk(msg.getRootDisk());
+ struct.setDataDisks(msg.getDataDisks());
+ struct.setDeprecatedDataVolumeSpecs(msg.getDeprecatedDataVolumeSpecs());
+ struct.setVmCustomSpecification(msg.getVmCustomSpecification());
return struct;
}
@@ -231,12 +246,29 @@ public void setDataVolumeFromTemplateSystemTags(Map> dataVo
this.dataVolumeFromTemplateSystemTags = dataVolumeFromTemplateSystemTags;
}
- public Map> getDataVolumeSystemTagsOnIndex() {
- return dataVolumeSystemTagsOnIndex;
- }
-
+ @Deprecated
public void setDataVolumeSystemTagsOnIndex(Map> dataVolumeSystemTagsOnIndex) {
- this.dataVolumeSystemTagsOnIndex = dataVolumeSystemTagsOnIndex;
+ if (dataVolumeSystemTagsOnIndex == null) {
+ return;
+ }
+
+ int maxIndex = dataVolumeSystemTagsOnIndex.keySet().stream().mapToInt(Integer::parseInt).max().orElse(-1);
+ for (int i = deprecatedDataVolumeSpecs.size(); i <= maxIndex; i++) {
+ deprecatedDataVolumeSpecs.add(DiskAO.nonRootDisk());
+ }
+
+ for (int i = 0; i <= maxIndex; i++) {
+ String key = i + "";
+ if (!dataVolumeSystemTagsOnIndex.containsKey(key)) {
+ continue;
+ }
+
+ final DiskAO diskAO = deprecatedDataVolumeSpecs.get(i);
+ if (diskAO.getSystemTags() == null) {
+ diskAO.setSystemTags(new ArrayList<>());
+ }
+ diskAO.getSystemTags().addAll(dataVolumeSystemTagsOnIndex.get(key));
+ }
}
public List getDisableL3Networks() {
diff --git a/compute/src/main/java/org/zstack/compute/vm/VmAllocateHostAndPrimaryStorageFlow.java b/compute/src/main/java/org/zstack/compute/vm/VmAllocateHostAndPrimaryStorageFlow.java
index b5c67052f8..b44398379e 100644
--- a/compute/src/main/java/org/zstack/compute/vm/VmAllocateHostAndPrimaryStorageFlow.java
+++ b/compute/src/main/java/org/zstack/compute/vm/VmAllocateHostAndPrimaryStorageFlow.java
@@ -385,7 +385,7 @@ private boolean dataVolumePsUnique(VmInstanceSpec spec) {
}
private boolean needCreateDataVolume(VmInstanceSpec spec) {
- return !CollectionUtils.isEmpty(spec.getDataDiskOfferings());
+ return !CollectionUtils.isEmpty(spec.getDeprecatedDisksSpecs());
}
private FlowChain buildAllocateHostAndPrimaryStorageFlowChain(final FlowTrigger trigger, VmInstanceSpec spec) {
@@ -451,8 +451,7 @@ private List> getPrimaryStorageCombinationFromSpec(VmInstanceSpec s
autoAllocateDataVolumePs = true;
dataPs.addAll(availPsForDataVolume);
}
- String dataVolumeStrategy = spec.getDataDiskOfferings().get(0).getAllocatorStrategy();
- sortPrimaryStorages(dataPs, dataVolumeStrategy, null);
+ sortPrimaryStorages(dataPs, PrimaryStorageConstant.DEFAULT_PRIMARY_STORAGE_ALLOCATION_STRATEGY_TYPE, null);
} else {
dataPs.add(null);
}
diff --git a/compute/src/main/java/org/zstack/compute/vm/VmAllocateHostFlow.java b/compute/src/main/java/org/zstack/compute/vm/VmAllocateHostFlow.java
index 825a1a203a..9d71ad1458 100755
--- a/compute/src/main/java/org/zstack/compute/vm/VmAllocateHostFlow.java
+++ b/compute/src/main/java/org/zstack/compute/vm/VmAllocateHostFlow.java
@@ -21,6 +21,7 @@
import org.zstack.header.image.ImageInventory;
import org.zstack.header.message.MessageReply;
import org.zstack.header.network.l3.L3NetworkInventory;
+import org.zstack.header.storage.primary.PrimaryStorageConstant;
import org.zstack.header.vm.*;
import org.zstack.header.vm.VmInstanceConstant.VmOperation;
import org.zstack.utils.CollectionUtils;
@@ -47,8 +48,8 @@ public class VmAllocateHostFlow implements Flow {
private long getTotalDataDiskSize(VmInstanceSpec spec) {
long size = 0;
- for (DiskOfferingInventory dinv : spec.getDataDiskOfferings()) {
- size += dinv.getDiskSize();
+ for (DiskAO dinv : spec.getDeprecatedDisksSpecs()) {
+ size += dinv.getSize();
}
return size;
}
@@ -67,7 +68,16 @@ protected AllocateHostMsg prepareMsg(VmInstanceSpec spec) {
diskSize = image.getSize();
}
diskSize += getTotalDataDiskSize(spec);
- diskOfferings.addAll(spec.getDataDiskOfferings());
+
+ for (DiskAO diskAO : spec.getDeprecatedDisksSpecs()) {
+ DiskOfferingInventory dinv = new DiskOfferingInventory();
+ dinv.setUuid(diskAO.getDiskOfferingUuid());
+ dinv.setDiskSize(diskAO.getSize());
+ dinv.setAllocatorStrategy(PrimaryStorageConstant.DEFAULT_PRIMARY_STORAGE_ALLOCATION_STRATEGY_TYPE);
+ dinv.setName("from-DiskAO");
+ diskOfferings.add(dinv);
+ }
+
msg.getLocationSpecs().addAll(spec.getLocationSpecs().stream()
.filter(s -> HostVO.class.getSimpleName().equals(s.getResourceType()))
.collect(Collectors.toList()));
@@ -113,9 +123,15 @@ protected AllocateHostMsg prepareMsg(VmInstanceSpec spec) {
}
msg.setAllowNoL3Networks(true);
- if (!CollectionUtils.isEmpty(spec.getDiskAOs())) {
- msg.getRequiredPrimaryStorageUuids().addAll(spec.getDiskAOs().stream()
- .map(DiskAO::getPrimaryStorageUuid).filter(Objects::nonNull).collect(Collectors.toList()));
+ if (spec.getRootDisk() != null && spec.getRootDisk().getPrimaryStorageUuid() != null) {
+ msg.getRequiredPrimaryStorageUuids().add(spec.getRootDisk().getPrimaryStorageUuid());
+ }
+
+ if (!CollectionUtils.isEmpty(spec.getDataDisks())) {
+ msg.getRequiredPrimaryStorageUuids().addAll(spec.getDataDisks().stream()
+ .map(DiskAO::getPrimaryStorageUuid)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList()));
}
setImageRequiredPrimaryStorageUuidFromDiskAO(msg, spec);
@@ -123,15 +139,14 @@ protected AllocateHostMsg prepareMsg(VmInstanceSpec spec) {
}
private void setImageRequiredPrimaryStorageUuidFromDiskAO(DesignatedAllocateHostMsg msg, VmInstanceSpec spec) {
- if (CollectionUtils.isEmpty(spec.getDiskAOs())) {
+ final DiskAO rootDisk = spec.getRootDisk();
+ if (rootDisk == null) {
return;
}
- spec.getDiskAOs().stream().filter(DiskAO::isBoot).findFirst().ifPresent(rootDiskAO -> {
- if (rootDiskAO.getPrimaryStorageUuid() != null) {
- msg.setImageRequiredPrimaryStorageUuid(rootDiskAO.getPrimaryStorageUuid());
- }
- });
+ if (rootDisk.getPrimaryStorageUuid() != null) {
+ msg.setImageRequiredPrimaryStorageUuid(rootDisk.getPrimaryStorageUuid());
+ }
}
@Override
diff --git a/compute/src/main/java/org/zstack/compute/vm/VmAllocatePrimaryStorageFlow.java b/compute/src/main/java/org/zstack/compute/vm/VmAllocatePrimaryStorageFlow.java
index b3404facb1..4bca73cdbc 100755
--- a/compute/src/main/java/org/zstack/compute/vm/VmAllocatePrimaryStorageFlow.java
+++ b/compute/src/main/java/org/zstack/compute/vm/VmAllocatePrimaryStorageFlow.java
@@ -4,21 +4,19 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.zstack.compute.allocator.HostAllocatorManager;
-import org.zstack.core.Platform;
-import org.zstack.core.asyncbatch.AsyncLoop;
+import org.zstack.core.asyncbatch.While;
import org.zstack.core.cloudbus.CloudBus;
import org.zstack.core.cloudbus.CloudBusCallBack;
import org.zstack.core.db.DatabaseFacade;
import org.zstack.core.db.Q;
import org.zstack.core.errorcode.ErrorFacade;
-import org.zstack.header.configuration.DiskOfferingInventory;
-import org.zstack.header.core.Completion;
+import org.zstack.header.core.WhileDoneCompletion;
import org.zstack.header.core.workflow.Flow;
import org.zstack.header.core.workflow.FlowRollback;
import org.zstack.header.core.workflow.FlowTrigger;
-import org.zstack.header.errorcode.ErrorCode;
+import org.zstack.header.errorcode.ErrorCodeList;
+import org.zstack.header.errorcode.OperationFailureException;
import org.zstack.header.host.HostInventory;
-import org.zstack.header.image.ImageInventory;
import org.zstack.header.message.MessageReply;
import org.zstack.header.storage.backup.BackupStorageVO;
import org.zstack.header.storage.backup.BackupStorageVO_;
@@ -27,6 +25,7 @@
import org.zstack.header.storage.primary.PrimaryStorageAllocationPurpose;
import org.zstack.header.storage.primary.PrimaryStorageConstant;
import org.zstack.header.storage.primary.ReleasePrimaryStorageSpaceMsg;
+import org.zstack.header.vm.DiskAO;
import org.zstack.header.vm.VmInstanceConstant;
import org.zstack.header.vm.VmInstanceSpec;
import org.zstack.header.vm.VmInstanceSpec.VolumeSpec;
@@ -36,12 +35,17 @@
import org.zstack.utils.logging.CLogger;
import java.util.ArrayList;
-import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.Set;
+import static org.zstack.core.Platform.err;
import static org.zstack.header.image.ImageConstant.SNAPSHOT_REUSE_IMAGE_SCHEMA;
+import static org.zstack.header.vm.VmErrors.WRONG_SPECIFIC_PS_ERROR;
+import static org.zstack.utils.CollectionUtils.isEmpty;
@Configurable(preConstruction = true, autowire = Autowire.BY_TYPE)
public class VmAllocatePrimaryStorageFlow implements Flow {
@@ -61,9 +65,55 @@ public void run(final FlowTrigger trigger, final Map data) {
final VmInstanceSpec spec = (VmInstanceSpec) data.get(VmInstanceConstant.Params.VmInstanceSpec.toString());
HostInventory destHost = spec.getDestHost();
- // allocate ps for root volume
+ msgs.add(buildMessageForRootVolume(spec, destHost));
+ msgs.addAll(buildMessageForDataVolumes(spec, destHost));
+
+ new While<>(msgs).each((msg, whileCompletion) -> {
+ bus.send(msg, new CloudBusCallBack(whileCompletion) {
+ @Override
+ public void run(MessageReply reply) {
+ if (!reply.isSuccess()) {
+ whileCompletion.addError(reply.getError());
+ whileCompletion.allDone();
+ return;
+ }
+
+ VolumeSpec volumeSpec = new VolumeSpec();
+ AllocatePrimaryStorageSpaceReply ar = (AllocatePrimaryStorageSpaceReply) reply;
+ volumeSpec.setAllocatedInstallUrl(ar.getAllocatedInstallUrl());
+ volumeSpec.setPrimaryStorageInventory(ar.getPrimaryStorageInventory());
+ volumeSpec.setSize(ar.getSize());
+ volumeSpec.setType(PrimaryStorageAllocationPurpose.CreateNewVm.toString().equals(msg.getPurpose()) ?
+ VolumeType.Root.toString() : VolumeType.Data.toString());
+ volumeSpec.setDiskOfferingUuid(msg.getDiskOfferingUuid());
+ volumeSpec.setTags(msg.getSystemTags());
+ if (VolumeType.Root.toString().equals(volumeSpec.getType())) {
+ spec.getRootDisk().setPrimaryStorageUuid(ar.getPrimaryStorageInventory().getUuid());
+ } else {
+ spec.setAllocatedPrimaryStorageUuidForDataVolume(ar.getPrimaryStorageInventory().getUuid());
+ }
+
+ spec.getVolumeSpecs().add(volumeSpec);
+ whileCompletion.done();
+ }
+ });
+ }).run(new WhileDoneCompletion(trigger) {
+ @Override
+ public void done(ErrorCodeList errorCodeList) {
+ if (errorCodeList.getCauses().isEmpty()) {
+ trigger.next();
+ } else {
+ trigger.fail(errorCodeList.getCauses().get(0));
+ }
+ }
+ });
+ }
+
+ private AllocatePrimaryStorageSpaceMsg buildMessageForRootVolume(final VmInstanceSpec spec, HostInventory destHost) {
AllocatePrimaryStorageSpaceMsg rmsg = new AllocatePrimaryStorageSpaceMsg();
- rmsg.setCandidatePrimaryStorageUuids(spec.getCandidatePrimaryStorageUuidsForRootVolume());
+
+ DiskAO disk = spec.getRootDisk();
+
rmsg.setVmInstanceUuid(spec.getVmInventory().getUuid());
if (spec.getImageSpec() != null) {
if (spec.getImageSpec().getInventory() != null) {
@@ -75,7 +125,7 @@ public void run(final FlowTrigger trigger, final Map data) {
Optional.ofNullable(spec.getImageSpec().getSelectedBackupStorage())
.ifPresent(it -> rmsg.setBackupStorageUuid(it.getBackupStorageUuid()));
}
- rmsg.setSize(spec.getRootDiskAllocateSize());
+ rmsg.setSize(disk != null && disk.getSize() > 0 ? disk.getSize() : spec.getRootDiskAllocateSize());
if (spec.getRootDiskOffering() != null) {
rmsg.setDiskOfferingUuid(spec.getRootDiskOffering().getUuid());
rmsg.setAllocationStrategy(spec.getRootDiskOffering().getAllocatorStrategy());
@@ -83,75 +133,68 @@ public void run(final FlowTrigger trigger, final Map data) {
rmsg.setRequiredHostUuid(destHost.getUuid());
rmsg.setPurpose(PrimaryStorageAllocationPurpose.CreateNewVm.toString());
- rmsg.setPossiblePrimaryStorageTypes(selectPsTypesFromSpec(spec));
- rmsg.setSystemTags(spec.getRootVolumeSystemTags());
+
+ final List candidatePs = spec.getCandidatePrimaryStorageUuidsForRootVolume();
+ if (disk != null && disk.getPrimaryStorageUuid() != null) {
+ if (!isEmpty(candidatePs) && !candidatePs.contains(disk.getPrimaryStorageUuid())) {
+ throw new OperationFailureException(err(WRONG_SPECIFIC_PS_ERROR,
+ "failed to allocate root volume to the primary storage[%s]", disk.getPrimaryStorageUuid())
+ .withOpaque("required.primary.storage.uuid", disk.getPrimaryStorageUuid())
+ .withOpaque("candidate.primary.storage.uuid.list", candidatePs));
+ }
+ rmsg.setRequiredPrimaryStorageUuid(disk.getPrimaryStorageUuid());
+ } else {
+ rmsg.setCandidatePrimaryStorageUuids(candidatePs);
+ rmsg.setPossiblePrimaryStorageTypes(selectPsTypesFromSpec(spec));
+ }
+
+ Set tags = new HashSet<>();
+ if (disk != null && disk.getSystemTags() != null) {
+ tags.addAll(disk.getSystemTags());
+ }
+ if (spec.getRootVolumeSystemTags() != null) {
+ tags.addAll(spec.getRootVolumeSystemTags());
+ }
+
+ rmsg.setSystemTags(new ArrayList<>(tags));
bus.makeLocalServiceId(rmsg, PrimaryStorageConstant.SERVICE_ID);
- msgs.add(rmsg);
+ return rmsg;
+ }
+
+ private List buildMessageForDataVolumes(final VmInstanceSpec spec, HostInventory destHost) {
+ int dataVolumeCount = isEmpty(spec.getDeprecatedDisksSpecs()) ? 0 : spec.getDeprecatedDisksSpecs().size();
+ if (dataVolumeCount == 0) {
+ return Collections.emptyList();
+ }
+
+ List msgs = new ArrayList<>();
+ for (int i = 0; i < dataVolumeCount; i++) {
+ DiskAO deprecatedDisk = isEmpty(spec.getDeprecatedDisksSpecs()) || i >= spec.getDeprecatedDisksSpecs().size() ?
+ null : spec.getDeprecatedDisksSpecs().get(i);
- // allocate ps for data volumes
- for (DiskOfferingInventory dinv : spec.getDataDiskOfferings()) {
AllocatePrimaryStorageSpaceMsg amsg = new AllocatePrimaryStorageSpaceMsg();
amsg.setCandidatePrimaryStorageUuids(spec.getCandidatePrimaryStorageUuidsForDataVolume());
- amsg.setSize(dinv.getDiskSize());
+ amsg.setSize(deprecatedDisk != null && deprecatedDisk.getSize() > 0 ? deprecatedDisk.getSize() : 0);
amsg.setRequiredHostUuid(destHost.getUuid());
- amsg.setAllocationStrategy(dinv.getAllocatorStrategy());
+ amsg.setAllocationStrategy(PrimaryStorageConstant.DEFAULT_PRIMARY_STORAGE_ALLOCATION_STRATEGY_TYPE);
amsg.setPurpose(PrimaryStorageAllocationPurpose.CreateDataVolume.toString());
- amsg.setDiskOfferingUuid(dinv.getUuid());
- amsg.setSystemTags(spec.getDataVolumeSystemTags());
- bus.makeLocalServiceId(amsg, PrimaryStorageConstant.SERVICE_ID);
- msgs.add(amsg);
- }
+ amsg.setDiskOfferingUuid(deprecatedDisk != null ? deprecatedDisk.getDiskOfferingUuid() : null);
- new AsyncLoop(trigger) {
- @Override
- protected Collection collectionForLoop() {
- return msgs;
+ Set tags = new HashSet<>();
+ if (spec.getDataVolumeSystemTags() != null) {
+ tags.addAll(spec.getDataVolumeSystemTags());
}
-
- @Override
- protected void run(AllocatePrimaryStorageSpaceMsg msg, Completion completion) {
- bus.send(msg, new CloudBusCallBack(completion) {
- @Override
- public void run(MessageReply reply) {
- if (!reply.isSuccess()) {
- completion.fail(reply.getError());
- return;
- }
-
- VolumeSpec volumeSpec = new VolumeSpec();
- AllocatePrimaryStorageSpaceReply ar = (AllocatePrimaryStorageSpaceReply) reply;
- volumeSpec.setAllocatedInstallUrl(ar.getAllocatedInstallUrl());
- volumeSpec.setPrimaryStorageInventory(ar.getPrimaryStorageInventory());
- volumeSpec.setSize(ar.getSize());
- volumeSpec.setType(PrimaryStorageAllocationPurpose.CreateNewVm.toString().equals(msg.getPurpose()) ?
- VolumeType.Root.toString() : VolumeType.Data.toString());
- volumeSpec.setDiskOfferingUuid(msg.getDiskOfferingUuid());
- if (VolumeType.Root.toString().equals(volumeSpec.getType())) {
- spec.setAllocatedPrimaryStorageUuidForRootVolume(ar.getPrimaryStorageInventory().getUuid());
- volumeSpec.setTags(spec.getRootVolumeSystemTags());
- } else {
- spec.setAllocatedPrimaryStorageUuidForDataVolume(ar.getPrimaryStorageInventory().getUuid());
- volumeSpec.setTags(spec.getDataVolumeSystemTags());
- }
-
- spec.getVolumeSpecs().add(volumeSpec);
-
- completion.success();
- }
- });
+ if (deprecatedDisk != null && !isEmpty(deprecatedDisk.getSystemTags())) {
+ tags.addAll(deprecatedDisk.getSystemTags());
}
- @Override
- protected void done() {
- trigger.next();
- }
+ amsg.setSystemTags(new ArrayList<>(tags));
+ bus.makeLocalServiceId(amsg, PrimaryStorageConstant.SERVICE_ID);
+ msgs.add(amsg);
+ }
- @Override
- protected void error(ErrorCode errorCode) {
- trigger.fail(errorCode);
- }
- }.start();
+ return msgs;
}
@Override
diff --git a/compute/src/main/java/org/zstack/compute/vm/VmAllocateVolumeFlow.java b/compute/src/main/java/org/zstack/compute/vm/VmAllocateVolumeFlow.java
index 07a9ada4be..b0efbc07bb 100755
--- a/compute/src/main/java/org/zstack/compute/vm/VmAllocateVolumeFlow.java
+++ b/compute/src/main/java/org/zstack/compute/vm/VmAllocateVolumeFlow.java
@@ -1,6 +1,5 @@
package org.zstack.compute.vm;
-import org.apache.commons.collections.MapUtils;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
@@ -21,6 +20,7 @@
import org.zstack.header.errorcode.ErrorCodeList;
import org.zstack.header.exception.CloudRuntimeException;
import org.zstack.header.message.MessageReply;
+import org.zstack.header.vm.DiskAO;
import org.zstack.header.vm.VmInstanceConstant;
import org.zstack.header.vm.VmInstanceSpec;
import org.zstack.header.vm.VmInstanceSpec.VolumeSpec;
@@ -34,10 +34,10 @@
import java.util.*;
import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
import static org.zstack.core.progress.ProgressReportService.taskProgress;
+import static org.zstack.utils.CollectionUtils.filter;
+import static org.zstack.utils.CollectionUtils.isEmpty;
import static org.zstack.utils.CollectionUtils.transformAndRemoveNull;
@Configurable(preConstruction = true, autowire = Autowire.BY_TYPE)
@@ -63,40 +63,47 @@ protected List prepareMsg(Map ctx) {
throw new CloudRuntimeException(String.format("accountUuid for vm[uuid:%s] is null", spec.getVmInventory().getUuid()));
}
- if (!MapUtils.isEmpty(spec.getDataVolumeSystemTagsOnIndex()) && !CollectionUtils.isEmpty(spec.getDataDiskOfferings())) {
- List dataVolumeSpecs = spec.getVolumeSpecs().stream()
- .filter(s -> s.getType().equals(VolumeType.Data.toString())).collect(Collectors.toList());
+ if (!CollectionUtils.isEmpty(spec.getDeprecatedDisksSpecs())) {
+ List dataVolumeSpecs = filter(spec.getVolumeSpecs(), s -> s.getType().equals(VolumeType.Data.toString()));
+ int minLen = Math.min(spec.getDeprecatedDisksSpecs().size(), dataVolumeSpecs.size());
- IntStream.range(0, dataVolumeSpecs.size()).forEach(index -> {
- List systemTags = spec.getDataVolumeSystemTagsOnIndex().get(String.valueOf(index));
- if (!CollectionUtils.isEmpty(systemTags)) {
- dataVolumeSpecs.get(index).setTags(systemTags);
+ for (int i = 0; i < minLen; i++) {
+ DiskAO disk = spec.getDeprecatedDisksSpecs().get(i);
+ if (!CollectionUtils.isEmpty(disk.getSystemTags())) {
+ dataVolumeSpecs.get(i).setTags(disk.getSystemTags());
}
- });
+ }
}
List volumeSpecs = spec.getVolumeSpecs();
List msgs = new ArrayList<>(volumeSpecs.size());
+ int dataVolumeIndex = 0;
+
for (VolumeSpec vspec : volumeSpecs) {
CreateVolumeMsg msg = new CreateVolumeMsg();
Set tags = new HashSet<>();
- if (vspec != null) {
- if (vspec.getTags() != null) {
- tags.addAll(vspec.getTags());
- }
- } else {
+ if (vspec == null) {
continue;
}
+ if (vspec.getTags() != null) {
+ tags.addAll(vspec.getTags());
+ }
+
DebugUtils.Assert(vspec.getType() != null, "VolumeType can not be null!");
- if (VolumeType.Root.toString().equals(vspec.getType())) {
+ if (vspec.isRoot()) {
+ DiskAO disk = spec.getRootDisk();
msg.setResourceUuid((String) ctx.get("uuid"));
- msg.setName("ROOT-for-" + spec.getVmInventory().getName());
- msg.setDescription(String.format("Root volume for VM[uuid:%s]", spec.getVmInventory().getUuid()));
+ String name = disk == null ? null : disk.getName();
+ msg.setName(name == null ? "ROOT-for-" + spec.getVmInventory().getName() : name);
+
+ msg.setDescription(String.format("Root volume for VM[uuid:%s]", spec.getVmInventory().getUuid()));
if (spec.getImageSpec().relayOnImage()) {
msg.setRootImageUuid(spec.getImageSpec().getInventory().getUuid());
+ } else if (disk != null && disk.getTemplateUuid() != null) {
+ msg.setRootImageUuid(disk.getTemplateUuid());
}
msg.setFormat(spec.getVolumeFormatFromImage());
@@ -104,13 +111,33 @@ protected List prepareMsg(Map ctx) {
if (spec.getRootVolumeSystemTags() != null) {
tags.addAll(spec.getRootVolumeSystemTags());
}
- } else if (VolumeType.Data.toString().equals(vspec.getType())) {
- msg.setName(String.format("DATA-for-%s", spec.getVmInventory().getName()));
+
+ if (disk != null && !isEmpty(disk.getSystemTags())) {
+ tags.addAll(disk.getSystemTags());
+ }
+ } else if (vspec.isData()) {
+ DiskAO disk = isEmpty(spec.getDataDisks()) ? null :
+ spec.getDataDisks().size() > dataVolumeIndex ? spec.getDataDisks().get(dataVolumeIndex) : null;
+ DiskAO deprecatedDisk = isEmpty(spec.getDeprecatedDisksSpecs()) ? null :
+ spec.getDeprecatedDisksSpecs().size() > dataVolumeIndex ? spec.getDeprecatedDisksSpecs().get(dataVolumeIndex) : null;
+
+ String name = disk == null ? null : disk.getName();
+ msg.setName(name == null ? "DATA-for-" + spec.getVmInventory().getName() : name);
+
msg.setDescription(String.format("DataVolume-%s", spec.getVmInventory().getUuid()));
msg.setFormat(VolumeFormat.getVolumeFormatByMasterHypervisorType(spec.getDestHost().getHypervisorType()).toString());
+
if (spec.getDataVolumeSystemTags() != null) {
tags.addAll(spec.getDataVolumeSystemTags());
}
+ if (deprecatedDisk != null && !isEmpty(deprecatedDisk.getSystemTags())) {
+ tags.addAll(deprecatedDisk.getSystemTags());
+ }
+ if (disk != null && !isEmpty(disk.getSystemTags())) {
+ tags.addAll(disk.getSystemTags());
+ }
+
+ dataVolumeIndex++;
} else {
continue;
}
diff --git a/compute/src/main/java/org/zstack/compute/vm/VmCascadeExtension.java b/compute/src/main/java/org/zstack/compute/vm/VmCascadeExtension.java
index 130de99322..05810e8bf5 100755
--- a/compute/src/main/java/org/zstack/compute/vm/VmCascadeExtension.java
+++ b/compute/src/main/java/org/zstack/compute/vm/VmCascadeExtension.java
@@ -314,7 +314,7 @@ protected List handleDeletionForIpRange(List WINDOWS_RESERVED_NAMES = new HashSet<>(Arrays.asList(
+ "CON", "PRN", "AUX", "NUL",
+ "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
+ "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"
+ ));
+
+ private static final int MAX_WINDOWS_NETBIOS_LENGTH = 15;
+
+ public static String safeSubstringForHostname(String hostname) {
+ if (hostname == null) {
+ return null;
+ }
+ int length = hostname.codePointCount(0, hostname.length());
+ if (length <= VmHostnameUtils.MAX_WINDOWS_NETBIOS_LENGTH) {
+ return hostname;
+ }
+ int endIndex = hostname.offsetByCodePoints(0, VmHostnameUtils.MAX_WINDOWS_NETBIOS_LENGTH);
+ return hostname.substring(0, endIndex);
+ }
+
+ public static void validateHostname(String hostname, boolean isWindows) {
+ if (hostname == null) {
+ return;
+ } else if (hostname.isEmpty()) {
+ throw new ApiMessageInterceptionException(argerr("hostname is empty"));
+ }
+
+ if (isWindows) {
+ String netBiosName = safeSubstringForHostname(hostname);
+ if (!WINDOWS_NETBIOS_PATTERN.matcher(netBiosName).matches()) {
+ throw new ApiMessageInterceptionException(
+ argerr("%s is not a valid Windows NetBIOS hostname", netBiosName)
+ );
+ }
+ if (WINDOWS_RESERVED_NAMES.contains(netBiosName.toUpperCase())) {
+ throw new ApiMessageInterceptionException(
+ argerr("%s is a reserved Windows NetBIOS hostname", netBiosName)
+ );
+ }
+
+ if (!WINDOWS_HOSTNAME_PATTERN.matcher(hostname).matches()) {
+ throw new ApiMessageInterceptionException(
+ argerr("%s is not a valid Windows hostname", hostname)
+ );
+ }
+ } else {
+ if (!HOSTNAME_PATTERN.matcher(hostname).matches()) {
+ throw new ApiMessageInterceptionException(
+ argerr("%s is not a valid hostname", hostname)
+ );
+ }
+ }
+ }
+
+ public static void validateDomain(String domain) {
+ if (StringUtils.isEmpty(domain)) {
+ return;
+ }
+
+ if (domain.length() > 255) {
+ throw new ApiMessageInterceptionException(
+ argerr("%s exceeds max length 255", domain)
+ );
+ }
+
+ String[] labels = domain.split("\\.");
+ for (String label : labels) {
+ if (!WINDOWS_DOMAIN_LABEL_PATTERN.matcher(label).matches()) {
+ throw new ApiMessageInterceptionException(
+ argerr("%s is not a valid domain label in %s", label, domain)
+ );
+ }
+
+ if (WINDOWS_RESERVED_NAMES.contains(label.toUpperCase(Locale.ROOT))) {
+ throw new ApiMessageInterceptionException(
+ argerr("%s is a reserved Windows label", label)
+ );
+ }
+ }
+ }
+}
diff --git a/compute/src/main/java/org/zstack/compute/vm/VmInstanceApiInterceptor.java b/compute/src/main/java/org/zstack/compute/vm/VmInstanceApiInterceptor.java
index 892c3b73bc..30f4559868 100755
--- a/compute/src/main/java/org/zstack/compute/vm/VmInstanceApiInterceptor.java
+++ b/compute/src/main/java/org/zstack/compute/vm/VmInstanceApiInterceptor.java
@@ -50,6 +50,7 @@
import static org.zstack.core.Platform.argerr;
import static org.zstack.core.Platform.operr;
import static org.zstack.utils.CollectionDSL.*;
+import static org.zstack.utils.CollectionUtils.findOneOrNull;
import static org.zstack.utils.CollectionUtils.isEmpty;
/**
@@ -578,7 +579,6 @@ private void validate(APISetVmStaticIpMsg msg) {
info.ipv6Gateway = msg.getIpv6Gateway();
ipOperator.validateStaticIp(info, l3NetworkVO, new ArrayList<>());
- msg.setIp(info.ipv4Address);
msg.setNetmask(info.ipv4Netmask);
msg.setGateway(info.ipv4Gateway);
msg.setIp6(info.ipv6Address);
@@ -1051,10 +1051,10 @@ private void validate(APICreateVmInstanceMsg msg) {
boolean virtIOTagExists = (isEmpty(msg.getSystemTags())) ? false :
msg.getSystemTags().contains(VmSystemTags.VIRTIO.getTagFormat());
String platform = msg.getPlatform(), guestOsType = msg.getGuestOsType(), architecture = msg.getArchitecture();
+ long rootDiskSize = msg.getRootDiskSize() != null ? msg.getRootDiskSize() : 0L;
if (CollectionUtils.isNotEmpty(msg.getDiskAOs())) {
- DiskAO rootDiskAO = msg.getDiskAOs().stream()
- .filter(DiskAO::isBoot).findFirst().orElse(null);
+ DiskAO rootDiskAO = isEmpty(msg.getDiskAOs()) ? null : findOneOrNull(msg.getDiskAOs(), DiskAO::isBoot);
if (rootDiskAO == null) {
throw new ApiMessageInterceptionException(argerr("missing root disk"));
}
@@ -1062,9 +1062,17 @@ private void validate(APICreateVmInstanceMsg msg) {
platform = platform == null ? rootDiskAO.getPlatform() : platform;
guestOsType = guestOsType == null ? rootDiskAO.getGuestOsType() : guestOsType;
architecture = architecture == null ? rootDiskAO.getArchitecture() : architecture;
+ rootDiskSize = rootDiskSize == 0L ? rootDiskAO.getSize() : rootDiskSize;
+ msg.setRootDiskSize(rootDiskSize);
+
if (!virtIOTagExists && CollectionUtils.isNotEmpty(rootDiskAO.getSystemTags())) {
- virtIOTagExists = rootDiskAO.getSystemTags().contains(VmSystemTags.VIRTIO.getTagFormat());
+ // "driver::virtio" is tag for VmInstanceVO (not for VolumeVO)
+ virtIOTagExists = rootDiskAO.getSystemTags().remove(VmSystemTags.VIRTIO.getTagFormat());
}
+
+ // root disk must be the first
+ msg.getDiskAOs().remove(rootDiskAO);
+ msg.getDiskAOs().add(0, rootDiskAO);
}
if (virtIOTagExists && msg.getVirtio() == Boolean.FALSE) {
@@ -1088,7 +1096,7 @@ private void validate(APICreateVmInstanceMsg msg) {
errorList.add(Platform.missingVariables("architecture"));
}
- if (msg.getRootDiskOfferingUuid() == null && msg.getRootDiskSize() == null) {
+ if (msg.getRootDiskOfferingUuid() == null && rootDiskSize <= 0) {
errorList.add("rootDiskOfferingUuid or rootDiskSize cannot be all null");
}
diff --git a/compute/src/main/java/org/zstack/compute/vm/VmInstanceBase.java b/compute/src/main/java/org/zstack/compute/vm/VmInstanceBase.java
index 664bd86b83..e6c814743a 100755
--- a/compute/src/main/java/org/zstack/compute/vm/VmInstanceBase.java
+++ b/compute/src/main/java/org/zstack/compute/vm/VmInstanceBase.java
@@ -86,6 +86,7 @@
import org.zstack.utils.network.NetworkUtils;
import javax.persistence.PersistenceException;
+import javax.persistence.Tuple;
import javax.persistence.TypedQuery;
import java.sql.Timestamp;
import java.time.LocalDateTime;
@@ -97,6 +98,7 @@
import static org.zstack.core.progress.ProgressReportService.*;
import static org.zstack.header.vm.VmErrors.ATTACH_VOLUME_ERROR;
import static org.zstack.utils.CollectionDSL.*;
+import static org.zstack.utils.CollectionUtils.isEmpty;
import static org.zstack.utils.CollectionUtils.transformAndRemoveNull;
public class VmInstanceBase extends AbstractVmInstance {
@@ -5139,7 +5141,11 @@ private List getAttachableL3Network(String accountUuid) {
q.setParameter("uuid", self.getUuid());
List attachedL3Uuids = Q.New(VmNicVO.class).select(VmNicVO_.l3NetworkUuid).eq(VmNicVO_.vmInstanceUuid, self.getUuid()).listValues();
List l3s = q.getResultList();
- l3s = l3s.stream().filter(l3 -> !IpRangeHelper.getNormalIpRanges(l3).isEmpty() || (!l3.enableIpAllocation() && !attachedL3Uuids.contains(l3.getUuid()))).collect(Collectors.toList());
+ l3s = l3s.stream()
+ .filter(l3 -> !IpRangeHelper.getNormalIpRanges(l3).isEmpty() ||
+ (!l3.getEnableIPAM() &&
+ (!attachedL3Uuids.contains(l3.getUuid()) || VmGlobalConfig.MULTI_VNIC_SUPPORT.value(Boolean.class))))
+ .collect(Collectors.toList());
return L3NetworkInventory.valueOf(l3s);
}
@@ -5196,13 +5202,13 @@ protected List scripts() {
return new ArrayList<>();
}
//filter l3 that already attached
- if (!self.getVmNics().isEmpty()) {
+ if (!self.getVmNics().isEmpty() && !VmGlobalConfig.MULTI_VNIC_SUPPORT.value(Boolean.class)) {
List vmL3Uuids = self.getVmNics().stream().flatMap(nic -> VmNicHelper.getL3Uuids(VmNicInventory.valueOf(nic)).stream())
.distinct().collect(Collectors.toList());
l3s = l3s.stream().filter(l3 -> !vmL3Uuids.contains(l3.getUuid())).collect(Collectors.toList());
}
- l3s = l3s.stream().filter(l3 -> !IpRangeHelper.getNormalIpRanges(l3).isEmpty() || !l3.enableIpAllocation()).collect(Collectors.toList());
+ l3s = l3s.stream().filter(l3 -> !IpRangeHelper.getNormalIpRanges(l3).isEmpty() || !l3.getEnableIPAM()).collect(Collectors.toList());
return L3NetworkInventory.valueOf(l3s);
}
@@ -6706,7 +6712,7 @@ public void rollback(FlowRollback trigger, Map data) {
});
flowChain.then(new NoRollbackFlow() {
- String __name__ = "update-nic-ip-for-disable-ipam";
+ String __name__ = "update-nic-ip-for-ip-allocation-disabled";
@Override
public boolean skip(Map data) {
@@ -7628,7 +7634,6 @@ private VmInstanceSpec buildVmInstanceSpecFromStruct(InstantiateVmFromNewCreated
spec.setDataVolumeSystemTags(struct.getDataVolumeSystemTags());
spec.setRootVolumeSystemTags(struct.getRootVolumeSystemTags());
spec.setRequiredHostUuid(struct.getRequiredHostUuid());
- spec.setDataVolumeSystemTagsOnIndex(struct.getDataVolumeSystemTagsOnIndex());
spec.setDisableL3Networks(struct.getDisableL3Networks());
spec.setStrategy(struct.getStrategy());
@@ -7644,12 +7649,7 @@ private VmInstanceSpec buildVmInstanceSpecFromStruct(InstantiateVmFromNewCreated
for (VmNicSpec nicSpec : struct.getL3NetworkUuids()) {
List l3s = new ArrayList<>();
for (L3NetworkInventory inv : nicSpec.getL3Invs()) {
- L3NetworkInventory l3 = CollectionUtils.find(nws, new Function() {
- @Override
- public L3NetworkInventory call(L3NetworkInventory arg) {
- return arg.getUuid().equals(inv.getUuid()) ? arg : null;
- }
- });
+ L3NetworkInventory l3 = CollectionUtils.findOneOrNull(nws, arg -> arg.getUuid().equals(inv.getUuid()));
if (l3 == null) {
throw new OperationFailureException(operr(
@@ -7673,30 +7673,27 @@ public L3NetworkInventory call(L3NetworkInventory arg) {
spec.setDataVolumeTemplateUuids(struct.getDataVolumeTemplateUuids());
spec.setDataVolumeFromTemplateSystemTags(struct.getDataVolumeFromTemplateSystemTags());
- if (struct.getDataDiskOfferingUuids() != null && !struct.getDataDiskOfferingUuids().isEmpty()) {
- SimpleQuery dquery = dbf.createQuery(DiskOfferingVO.class);
- dquery.add(DiskOfferingVO_.uuid, SimpleQuery.Op.IN, struct.getDataDiskOfferingUuids());
- List vos = dquery.list();
-
- // allow create multiple data volume from the same disk offering
- List disks = new ArrayList<>();
- for (final String duuid : struct.getDataDiskOfferingUuids()) {
- DiskOfferingVO dvo = CollectionUtils.find(vos, new Function() {
- @Override
- public DiskOfferingVO call(DiskOfferingVO arg) {
- if (duuid.equals(arg.getUuid())) {
- return arg;
+ if (!isEmpty(struct.getDeprecatedDataVolumeSpecs())) {
+ List uuidList = struct.getDeprecatedDataVolumeSpecs().stream()
+ .map(DiskAO::getDiskOfferingUuid)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ if (!uuidList.isEmpty()) {
+ List tuples = Q.New(DiskOfferingVO.class)
+ .in(DiskOfferingVO_.uuid, uuidList)
+ .select(DiskOfferingVO_.uuid, DiskOfferingVO_.diskSize)
+ .listTuple();
+
+ for (Tuple tuple : tuples) {
+ String uuid = tuple.get(0, String.class);
+ Long diskSize = tuple.get(1, Long.class);
+ for (DiskAO diskAO : struct.getDeprecatedDataVolumeSpecs()) {
+ if (uuid.equals(diskAO.getDiskOfferingUuid())) {
+ diskAO.setSize(diskSize);
}
- return null;
}
- });
- if (dvo != null) {
- disks.add(DiskOfferingInventory.valueOf(dvo));
}
}
- spec.setDataDiskOfferings(disks);
- } else {
- spec.setDataDiskOfferings(new ArrayList<>());
}
if (struct.getRootDiskOfferingUuid() != null) {
@@ -7704,7 +7701,10 @@ public DiskOfferingVO call(DiskOfferingVO arg) {
spec.setRootDiskOffering(DiskOfferingInventory.valueOf(rootDisk));
}
- spec.setDiskAOs(struct.getDiskAOs());
+ spec.setRootDisk(struct.getRootDisk());
+ spec.setDataDisks(struct.getDataDisks());
+ spec.setDeprecatedDisksSpecs(struct.getDeprecatedDataVolumeSpecs());
+ spec.setVmCustomSpecification(struct.getVmCustomSpecification());
List cdRomSpecs = buildVmCdRomSpecsForNewCreated(spec);
spec.setCdRomSpecs(cdRomSpecs);
diff --git a/compute/src/main/java/org/zstack/compute/vm/VmInstanceManagerImpl.java b/compute/src/main/java/org/zstack/compute/vm/VmInstanceManagerImpl.java
index 7c0a709bbe..a91b947507 100755
--- a/compute/src/main/java/org/zstack/compute/vm/VmInstanceManagerImpl.java
+++ b/compute/src/main/java/org/zstack/compute/vm/VmInstanceManagerImpl.java
@@ -2,7 +2,6 @@
import com.google.common.collect.Maps;
import org.apache.commons.lang.StringUtils;
-import org.apache.commons.validator.routines.DomainValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.zstack.compute.allocator.HostAllocatorManager;
@@ -1204,9 +1203,8 @@ protected VmInstanceVO scripts() {
@Override
public void setup() {
- if (!CollectionUtils.isEmpty(msg.getDiskAOs())) {
- otherDisks = msg.getDiskAOs().stream().filter(diskAO -> !diskAO.isBoot()).collect(Collectors.toList());
- setDiskAOsName(otherDisks);
+ if (!CollectionUtils.isEmpty(msg.getDataDisks())) {
+ setDiskAOsName(otherDisks = msg.getDataDisks());
attachOtherDisks = !otherDisks.isEmpty();
}
@@ -1311,13 +1309,11 @@ public void run(FlowTrigger trigger, Map data) {
InstantiateNewCreatedVmInstanceMsg smsg = new InstantiateNewCreatedVmInstanceMsg();
smsg.setDisableL3Networks(msg.getDisableL3Networks());
smsg.setHostUuid(msg.getHostUuid());
- List temporaryDiskOfferingUuids = createDiskOfferingUuidsFromDataDiskSizes(msg, finalVo.getUuid());
- smsg.setDataDiskOfferingUuids(merge(msg.getDataDiskOfferingUuids(), temporaryDiskOfferingUuids));
smsg.setDataVolumeTemplateUuids(msg.getDataVolumeTemplateUuids());
smsg.setDataVolumeFromTemplateSystemTags(msg.getDataVolumeFromTemplateSystemTags());
smsg.setL3NetworkUuids(msg.getL3NetworkSpecs());
- final DiskAO rootDisk = msg.findBootDisk();
+ final DiskAO rootDisk = msg.getRootDisk();
DiskOfferingVO dvo = null;
if (rootDisk != null) {
if (rootDisk.getDiskOfferingUuid() != null) {
@@ -1357,8 +1353,10 @@ public void run(FlowTrigger trigger, Map data) {
smsg.setTimeout(msg.getTimeout());
smsg.setRootVolumeSystemTags(msg.getRootVolumeSystemTags());
smsg.setDataVolumeSystemTags(msg.getDataVolumeSystemTags());
- smsg.setDataVolumeSystemTagsOnIndex(msg.getDataVolumeSystemTagsOnIndex());
- smsg.setDiskAOs(msg.getDiskAOs());
+ smsg.setRootDisk(msg.getRootDisk());
+ smsg.setDataDisks(msg.getDataDisks());
+ smsg.setDeprecatedDataVolumeSpecs(msg.getDeprecatedDataVolumeSpecs());
+ smsg.setVmCustomSpecification(msg.getVmCustomSpecification());
bus.makeTargetServiceIdByResourceUuid(smsg, VmInstanceConstant.SERVICE_ID, finalVo.getUuid());
bus.send(smsg, new CloudBusCallBack(smsg) {
@Override
@@ -1367,10 +1365,6 @@ public void run(MessageReply reply) {
dbf.removeByPrimaryKey(newCreateDiskOfferingUuid, DiskOfferingVO.class);
}
- if (!temporaryDiskOfferingUuids.isEmpty()) {
- dbf.removeByPrimaryKeys(temporaryDiskOfferingUuids, DiskOfferingVO.class);
- }
-
if (reply.isSuccess()) {
InstantiateNewCreatedVmInstanceReply r = (InstantiateNewCreatedVmInstanceReply) reply;
instantiateVm = r.getVmInventory();
@@ -1461,31 +1455,6 @@ private void setDiskAOsName(List diskAOs) {
}).start();
}
- private List createDiskOfferingUuidsFromDataDiskSizes(final CreateVmInstanceMsg msg, String vmUuid) {
- if (CollectionUtils.isEmpty(msg.getDataDiskSizes())){
- return new ArrayList();
- }
- List diskOfferingUuids = new ArrayList<>();
- List diskOfferingVos = new ArrayList<>();
- List volumeSizes = msg.getDataDiskSizes().stream().distinct().collect(Collectors.toList());
- Map sizeDiskOfferingMap = new HashMap<>();
- for (Long size : volumeSizes) {
- DiskOfferingVO dvo = new DiskOfferingVO();
- dvo.setUuid(Platform.getUuid());
- dvo.setAccountUuid(msg.getAccountUuid());
- dvo.setDiskSize(size);
- dvo.setName(String.format("create-data-volume-for-vm-%s", vmUuid));
- dvo.setType("TemporaryDiskOfferingType");
- dvo.setState(DiskOfferingState.Enabled);
- dvo.setAllocatorStrategy(PrimaryStorageConstant.DEFAULT_PRIMARY_STORAGE_ALLOCATION_STRATEGY_TYPE);
- diskOfferingVos.add(dvo);
- sizeDiskOfferingMap.put(size, dvo.getUuid());
- }
- msg.getDataDiskSizes().forEach(size -> diskOfferingUuids.add(sizeDiskOfferingMap.get(size)));
- dbf.persistCollection(diskOfferingVos);
- return diskOfferingUuids;
- }
-
private void createVmButNotStart(CreateVmInstanceMsg msg, VmInstanceInventory inv) {
InstantiateVmFromNewCreatedStruct struct = InstantiateVmFromNewCreatedStruct.fromMessage(msg);
new JsonLabel().create(InstantiateVmFromNewCreatedStruct.makeLabelKey(inv.getUuid()), struct, inv.getUuid());
@@ -1780,13 +1749,6 @@ public void updateResourceConfig(ResourceConfig config, String resourceUuid, Str
private void installHostnameValidator() {
class HostNameValidator implements SystemTagCreateMessageValidator, SystemTagValidator {
- private void validateHostname(String tag, String hostname) {
- DomainValidator domainValidator = DomainValidator.getInstance(true);
- if (!domainValidator.isValid(hostname)) {
- throw new ApiMessageInterceptionException(argerr("hostname[%s] specified in system tag[%s] is not a valid domain name", hostname, tag));
- }
- }
-
@Override
public void validateSystemTagInCreateMessage(APICreateMessage cmsg) {
final NewVmInstanceMessage msg = (NewVmInstanceMessage) cmsg;
@@ -1799,8 +1761,7 @@ public void validateSystemTagInCreateMessage(APICreateMessage cmsg) {
}
String hostname = VmSystemTags.HOSTNAME.getTokenByTag(sysTag, VmSystemTags.HOSTNAME_TOKEN);
-
- validateHostname(sysTag, hostname);
+ VmHostnameUtils.validateHostname(hostname, ImagePlatform.Windows.toString().equals(msg.getPlatform()));
}
}
}
@@ -1834,12 +1795,11 @@ private void validateHostNameOnDefaultL3Network(String tag, String hostname, Str
public void validateSystemTag(String resourceUuid, Class resourceType, String systemTag) {
if (VmSystemTags.HOSTNAME.isMatch(systemTag)) {
String hostname = VmSystemTags.HOSTNAME.getTokenByTag(systemTag, VmSystemTags.HOSTNAME_TOKEN);
- validateHostname(systemTag, hostname);
-
- SimpleQuery q = dbf.createQuery(VmInstanceVO.class);
- q.select(VmInstanceVO_.defaultL3NetworkUuid);
- q.add(VmInstanceVO_.uuid, Op.EQ, resourceUuid);
- String defaultL3Uuid = q.findValue();
+ boolean isWindows = Q.New(VmInstanceVO.class)
+ .eq(VmInstanceVO_.uuid, resourceUuid)
+ .eq(VmInstanceVO_.platform, ImagePlatform.Windows.toString())
+ .isExists();
+ VmHostnameUtils.validateHostname(hostname, isWindows);
} else if (VmSystemTags.BOOT_ORDER.isMatch(systemTag)) {
validateBootOrder(systemTag);
}
diff --git a/compute/src/main/java/org/zstack/compute/vm/VmInstanceUtils.java b/compute/src/main/java/org/zstack/compute/vm/VmInstanceUtils.java
index 3d253e2237..33afa04327 100644
--- a/compute/src/main/java/org/zstack/compute/vm/VmInstanceUtils.java
+++ b/compute/src/main/java/org/zstack/compute/vm/VmInstanceUtils.java
@@ -13,10 +13,15 @@
import org.zstack.header.vm.VmInstanceVO;
import org.zstack.tag.SystemTagUtils;
+import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import static java.util.Objects.requireNonNull;
+import static org.zstack.compute.vm.VmSystemTags.PRIMARY_STORAGE_UUID_FOR_DATA_VOLUME;
+import static org.zstack.compute.vm.VmSystemTags.PRIMARY_STORAGE_UUID_FOR_DATA_VOLUME_TOKEN;
import static org.zstack.utils.CollectionDSL.list;
import static org.zstack.utils.CollectionUtils.findOneOrNull;
import static org.zstack.utils.CollectionUtils.isEmpty;
@@ -31,12 +36,9 @@ public static CreateVmInstanceMsg fromAPICreateVmInstanceMsg(APICreateVmInstance
if (msg.getAllocatorStrategy() != null) {
cmsg.setAllocatorStrategy(msg.getAllocatorStrategy());
}
- cmsg.setDataDiskSizes(msg.getDataDiskSizes());
- cmsg.setDataDiskOfferingUuids(msg.getDataDiskOfferingUuids());
cmsg.setRootVolumeSystemTags(msg.getRootVolumeSystemTags());
cmsg.setDataVolumeSystemTags(msg.getDataVolumeSystemTags());
cmsg.setPrimaryStorageUuidForRootVolume(msg.getPrimaryStorageUuidForRootVolume());
- cmsg.setDataVolumeSystemTagsOnIndex(msg.getDataVolumeSystemTagsOnIndex());
cmsg.setSshKeyPairUuids(msg.getSshKeyPairUuids());
cmsg.setPlatform(msg.getPlatform());
cmsg.setGuestOsType(msg.getGuestOsType());
@@ -50,9 +52,15 @@ public static CreateVmInstanceMsg fromAPICreateVmInstanceMsg(APICreateVmInstance
} else {
cmsg.setVirtio(msg.getVirtio());
}
- cmsg.setDiskAOs(msg.getDiskAOs());
- if (isEmpty(cmsg.getDiskAOs())) {
+ if (!isEmpty(msg.getDiskAOs())) {
+ DiskAO rootDisk = findOneOrNull(msg.getDiskAOs(), DiskAO::isBoot);
+ cmsg.setRootDisk(rootDisk);
+ cmsg.setDataDisks(new ArrayList<>(msg.getDiskAOs()));
+ cmsg.getDataDisks().remove(rootDisk);
+ }
+
+ if (cmsg.getRootDisk() == null) {
DiskAO bootDisk = DiskAO.rootDisk();
if (msg.getRootDiskOfferingUuid() != null) {
@@ -63,9 +71,9 @@ public static CreateVmInstanceMsg fromAPICreateVmInstanceMsg(APICreateVmInstance
bootDisk.setPlatform(msg.getPlatform());
bootDisk.setGuestOsType(msg.getGuestOsType());
bootDisk.setArchitecture(msg.getArchitecture());
- cmsg.setDiskAOs(list(bootDisk));
+ cmsg.setRootDisk(bootDisk);
} else {
- DiskAO bootDisk = findOneOrNull(cmsg.getDiskAOs(), DiskAO::isBoot);
+ DiskAO bootDisk = cmsg.getRootDisk();
if (msg.getRootDiskOfferingUuid() != null) {
bootDisk.setDiskOfferingUuid(msg.getRootDiskOfferingUuid());
} else if (msg.getRootDiskSize() != null) {
@@ -76,6 +84,64 @@ public static CreateVmInstanceMsg fromAPICreateVmInstanceMsg(APICreateVmInstance
bootDisk.setArchitecture(msg.getArchitecture());
}
+ // dataDiskOfferingUuids + dataDiskSizes -> deprecatedDataVolumeSpecs
+ int expectDataVolumeCount =
+ (msg.getDataDiskOfferingUuids() == null ? 0 : msg.getDataDiskOfferingUuids().size()) +
+ (msg.getDataDiskSizes() == null ? 0 : msg.getDataDiskSizes().size());
+ List deprecatedDataVolumeSpecs = new ArrayList<>();
+ for (int i = 0; i < expectDataVolumeCount; i++) {
+ deprecatedDataVolumeSpecs.add(DiskAO.nonRootDisk());
+ }
+
+ int index = 0;
+ if (!isEmpty(msg.getDataDiskOfferingUuids())) {
+ for (String dataDiskOfferingUuid : msg.getDataDiskOfferingUuids()) {
+ deprecatedDataVolumeSpecs.get(index).setDiskOfferingUuid(dataDiskOfferingUuid);
+ index++;
+ }
+ }
+ if (!isEmpty(msg.getDataDiskSizes())) {
+ for (Long dataDiskSize : msg.getDataDiskSizes()) {
+ deprecatedDataVolumeSpecs.get(index).setSize(dataDiskSize);
+ index++;
+ }
+ }
+
+ // dataVolumeSystemTagsOnIndex -> deprecatedDataVolumeSpecs
+ if (msg.getDataVolumeSystemTagsOnIndex() != null) {
+ final Map> dataVolumeSystemTagsOnIndex = msg.getDataVolumeSystemTagsOnIndex();
+ for (int i = 0; i <= expectDataVolumeCount; i++) {
+ String key = i + "";
+ if (!dataVolumeSystemTagsOnIndex.containsKey(key)) {
+ continue;
+ }
+
+ final DiskAO diskAO = deprecatedDataVolumeSpecs.get(i);
+ if (diskAO.getSystemTags() == null) {
+ diskAO.setSystemTags(new ArrayList<>());
+ }
+ diskAO.getSystemTags().addAll(dataVolumeSystemTagsOnIndex.get(key));
+ }
+ }
+ cmsg.setDeprecatedDataVolumeSpecs(deprecatedDataVolumeSpecs);
+
+ if (!isEmpty(msg.getSystemTags())) {
+ for (Iterator it = msg.getSystemTags().iterator(); it.hasNext();) {
+ String tag = it.next();
+ // systemTags: primaryStorageUuidForDataVolume::{uuid} -> candidatePrimaryStorageUuidsForDataVolume
+ if (PRIMARY_STORAGE_UUID_FOR_DATA_VOLUME.isMatch(tag)) {
+ String psUuid = PRIMARY_STORAGE_UUID_FOR_DATA_VOLUME.getTokenByTag(tag, PRIMARY_STORAGE_UUID_FOR_DATA_VOLUME_TOKEN);
+ cmsg.setCandidatePrimaryStorageUuidsForDataVolume(list(psUuid));
+
+ if (cmsg.getDataDisks() != null) {
+ cmsg.getDataDisks().forEach(diskAO -> diskAO.setPrimaryStorageUuid(psUuid));
+ }
+ cmsg.getDeprecatedDataVolumeSpecs().forEach(diskAO -> diskAO.setPrimaryStorageUuid(psUuid));
+ it.remove();
+ }
+ }
+ }
+
return cmsg;
}
@@ -84,7 +150,7 @@ private static String getPSUuidForDataVolume(List systemTags){
return null;
}
- return SystemTagUtils.findTagValue(systemTags, VmSystemTags.PRIMARY_STORAGE_UUID_FOR_DATA_VOLUME, VmSystemTags.PRIMARY_STORAGE_UUID_FOR_DATA_VOLUME_TOKEN);
+ return SystemTagUtils.findTagValue(systemTags, PRIMARY_STORAGE_UUID_FOR_DATA_VOLUME, PRIMARY_STORAGE_UUID_FOR_DATA_VOLUME_TOKEN);
}
public static UpdateVmInstanceSpec convertToSpec(UpdateVmInstanceMsg message, VmInstanceVO vm) {
diff --git a/compute/src/main/java/org/zstack/compute/vm/VmInstantiateOtherDiskFlow.java b/compute/src/main/java/org/zstack/compute/vm/VmInstantiateOtherDiskFlow.java
index 068c8bf96f..69537bd55f 100644
--- a/compute/src/main/java/org/zstack/compute/vm/VmInstantiateOtherDiskFlow.java
+++ b/compute/src/main/java/org/zstack/compute/vm/VmInstantiateOtherDiskFlow.java
@@ -129,6 +129,7 @@ public void run(final FlowTrigger innerTrigger, Map data) {
amsg.setDiskOfferingUuid(diskAO.getDiskOfferingUuid());
amsg.setRequiredPrimaryStorageUuid(diskAO.getPrimaryStorageUuid());
amsg.setPurpose(PrimaryStorageAllocationPurpose.CreateDataVolume.toString());
+ amsg.setTags(diskAO.getSystemTags());
bus.makeLocalServiceId(amsg, PrimaryStorageConstant.SERVICE_ID);
bus.send(amsg, new CloudBusCallBack(innerTrigger) {
@Override
diff --git a/compute/src/main/java/org/zstack/compute/vm/VmSystemTags.java b/compute/src/main/java/org/zstack/compute/vm/VmSystemTags.java
index 76bedcc65d..52aa2282c8 100755
--- a/compute/src/main/java/org/zstack/compute/vm/VmSystemTags.java
+++ b/compute/src/main/java/org/zstack/compute/vm/VmSystemTags.java
@@ -122,7 +122,12 @@ public class VmSystemTags {
public static String VM_INJECT_QEMUGA_TOKEN = "qemuga";
public static PatternedSystemTag VM_INJECT_QEMUGA = new PatternedSystemTag(String.format("%s", VM_INJECT_QEMUGA_TOKEN), VmInstanceVO.class);
+ @Deprecated
public static String PRIMARY_STORAGE_UUID_FOR_DATA_VOLUME_TOKEN = "primaryStorageUuidForDataVolume";
+ /**
+ * use {@link org.zstack.header.vm.DiskAO#setPrimaryStorageUuid(String)}
+ */
+ @Deprecated
public static PatternedSystemTag PRIMARY_STORAGE_UUID_FOR_DATA_VOLUME = new PatternedSystemTag(String.format("primaryStorageUuidForDataVolume::{%s}", PRIMARY_STORAGE_UUID_FOR_DATA_VOLUME_TOKEN), VmInstanceVO.class);
public static final String VM_SYSTEM_SERIAL_NUMBER_TOKEN = "vmSystemSerialNumber";
diff --git a/conf/db/upgrade/V4.10.18__schema.sql b/conf/db/upgrade/V4.10.18__schema.sql
new file mode 100644
index 0000000000..f8ea123edc
--- /dev/null
+++ b/conf/db/upgrade/V4.10.18__schema.sql
@@ -0,0 +1,21 @@
+CREATE TABLE IF NOT EXISTS `zstack`.`VmCustomSpecificationVO` (
+ `uuid` varchar(32) NOT NULL UNIQUE,
+ `vmInstanceUuid` varchar(32) DEFAULT NULL,
+ `name` varchar(255) NOT NULL,
+ `description` varchar(2048) DEFAULT NULL,
+ `platform` varchar(32) NOT NULL,
+ `hostname` varchar(255) DEFAULT NULL,
+ `rootPassword` varchar(255) DEFAULT NULL,
+ `generateSID` boolean DEFAULT FALSE,
+ `domainMode` varchar(32) DEFAULT 'WorkGroup',
+ `domainName` varchar(255) DEFAULT NULL,
+ `domainUsername` varchar(255) DEFAULT NULL,
+ `domainPassword` varchar(255) DEFAULT NULL,
+ `organization` varchar(255) DEFAULT NULL,
+ `lastOpDate` timestamp ON UPDATE CURRENT_TIMESTAMP,
+ `createDate` timestamp,
+ PRIMARY KEY (`uuid`),
+ CONSTRAINT `fkVmCustomSpecificationVOVmInstanceEO` FOREIGN KEY (`vmInstanceUuid`) REFERENCES `VmInstanceEO` (`uuid`) ON DELETE SET NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+DELETE FROM `zstack`.`ResourceConfigVO` WHERE category='sharedblock' AND name='qcow2.allocation' AND value='metadata';
diff --git a/conf/db/upgrade/V4.10.20__schema.sql b/conf/db/upgrade/V4.10.20__schema.sql
new file mode 100644
index 0000000000..2885624613
--- /dev/null
+++ b/conf/db/upgrade/V4.10.20__schema.sql
@@ -0,0 +1,22 @@
+CREATE TABLE IF NOT EXISTS `zstack`.`SoftwarePackageVO` (
+ `uuid` char(32) NOT NULL UNIQUE,
+ `name` varchar(255) NOT NULL,
+ `hostUuid` char(32),
+ `managementNodeUuid` char(32),
+ `installPath` varchar(2048),
+ `unzipInstallPath` varchar(2048),
+ `type` varchar(1024),
+ `md5sum` char(32),
+ `status` char(32),
+ `size` bigint unsigned,
+ `lastOpDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ `createDate` timestamp,
+ PRIMARY KEY (`uuid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+
+CALL INSERT_COLUMN('HostEO', 'hostname', 'varchar(256)', 1, NULL, 'nqn');
+DROP VIEW IF EXISTS `zstack`.`HostVO`;
+CREATE VIEW `zstack`.`HostVO` AS SELECT uuid, zoneUuid, clusterUuid, name, description, managementIp, hypervisorType,
+state, status, architecture, nqn, hostname, createDate, lastOpDate FROM `zstack`.`HostEO` WHERE deleted IS NULL;
+
diff --git a/conf/errorCodes/SoftwarePackagePlugin.xml b/conf/errorCodes/SoftwarePackagePlugin.xml
new file mode 100644
index 0000000000..012c252d14
--- /dev/null
+++ b/conf/errorCodes/SoftwarePackagePlugin.xml
@@ -0,0 +1,8 @@
+
+ SoftwarePackage
+
+
+ 2000
+ Failed to upload software package
+
+
diff --git a/conf/errorCodes/lun.xml b/conf/errorCodes/lun.xml
new file mode 100644
index 0000000000..a4ad64cecc
--- /dev/null
+++ b/conf/errorCodes/lun.xml
@@ -0,0 +1,18 @@
+
+ LUN
+
+
+ 1000
+ General error
+
+
+
+ 1001
+ Lun has been created
+
+
+
+ 1002
+ Lun cannot be found
+
+
\ No newline at end of file
diff --git a/conf/errorCodes/managements.xml b/conf/errorCodes/managements.xml
new file mode 100644
index 0000000000..49151a0f91
--- /dev/null
+++ b/conf/errorCodes/managements.xml
@@ -0,0 +1,34 @@
+
+ MANAGEMENTS
+
+
+ 1000
+ General error
+
+
+
+ 2000
+ ZSphere (ZStack) HA2 related error
+
+
+
+ 2001
+ Missing ZSphere HA2 tools
+
+
+
+ 2101
+ Failed to get ZSphere HA2 status
+
+
+
+ 2102
+ Failed to parse ZSphere HA2 status
+
+
+
+ 2103
+ HA environment not installed
+
+
+
diff --git a/conf/errorCodes/vm.xml b/conf/errorCodes/vm.xml
index bcf8ce5fc3..89b18111c6 100755
--- a/conf/errorCodes/vm.xml
+++ b/conf/errorCodes/vm.xml
@@ -86,5 +86,20 @@
1017
Cannot get vnc setting.
+
+
+ 1200
+ VM allocation error
+
+
+
+ 1201
+ Wrong specific host error
+
+
+
+ 1202
+ Wrong specific primary storage error
+
diff --git a/conf/errorCodes/vops/vops.xml b/conf/errorCodes/vops/vops.xml
new file mode 100644
index 0000000000..3436bc2ad9
--- /dev/null
+++ b/conf/errorCodes/vops/vops.xml
@@ -0,0 +1,18 @@
+
+ VOPS
+
+
+ 1000
+ VOps Generic Errors
+
+
+
+ 1312
+ Http Timed Out
+
+
+
+ 1315
+ Errors on Remote Vops Agent
+
+
diff --git a/conf/globalConfig/cluster.xml b/conf/globalConfig/cluster.xml
index 73a310ccc4..88926fe516 100755
--- a/conf/globalConfig/cluster.xml
+++ b/conf/globalConfig/cluster.xml
@@ -4,7 +4,7 @@
cluster
update.os.parallelismDegree
The maximum count of cluster that can update operating system at the same time
- 2
+ 10
java.lang.Integer
diff --git a/conf/globalConfig/host.xml b/conf/globalConfig/host.xml
index c84a5dbdd6..795d853586 100755
--- a/conf/globalConfig/host.xml
+++ b/conf/globalConfig/host.xml
@@ -81,7 +81,7 @@
host
update.os.parallelismDegree
The maximum count of host that can update operating system at the same time
- 2
+ 10
java.lang.Integer
diff --git a/conf/guestOs/guestOsCategory.xml b/conf/guestOs/guestOsCategory.xml
index 366f101899..89b190371b 100644
--- a/conf/guestOs/guestOsCategory.xml
+++ b/conf/guestOs/guestOsCategory.xml
@@ -331,6 +331,12 @@
2022
WindowsServer 2022
+
+ Windows
+ Windows
+ 2025
+ WindowsServer 2025
+
Windows
Windows
diff --git a/conf/guestOs/guestOsCharacter.xml b/conf/guestOs/guestOsCharacter.xml
index 9753d8dbed..6431e26c35 100644
--- a/conf/guestOs/guestOsCharacter.xml
+++ b/conf/guestOs/guestOsCharacter.xml
@@ -297,6 +297,12 @@
WindowsServer 2022
false
+
+ x86_64
+ Windows
+ WindowsServer 2025
+ false
+
x86_64
Windows
diff --git a/conf/persistence.xml b/conf/persistence.xml
index 6ed53018d9..aa295bcb36 100755
--- a/conf/persistence.xml
+++ b/conf/persistence.xml
@@ -210,5 +210,6 @@
org.zstack.header.resourceattribute.entity.ResourceAttributeValueVO
org.zstack.header.resourceattribute.entity.ResourceAttributeKeyResourceTypeVO
org.zstack.header.resourceattribute.entity.ResourceAttributeConstraintVO
+ org.zstack.softwarePackage.header.SoftwarePackageVO
diff --git a/conf/serviceConfig/host.xml b/conf/serviceConfig/host.xml
index ce78b04a12..b7aafef93c 100755
--- a/conf/serviceConfig/host.xml
+++ b/conf/serviceConfig/host.xml
@@ -80,4 +80,8 @@
org.zstack.header.host.APIUpdateHostNqnMsg
+
+
+ org.zstack.header.host.APIUpdateHostnameMsg
+
diff --git a/conf/springConfigXml/ExternalPrimaryStorage.xml b/conf/springConfigXml/ExternalPrimaryStorage.xml
index 6b76464906..b1055dc4f1 100644
--- a/conf/springConfigXml/ExternalPrimaryStorage.xml
+++ b/conf/springConfigXml/ExternalPrimaryStorage.xml
@@ -28,6 +28,7 @@
+
diff --git a/conf/springConfigXml/VmInstanceManager.xml b/conf/springConfigXml/VmInstanceManager.xml
index 13c0ece52e..20e094378a 100755
--- a/conf/springConfigXml/VmInstanceManager.xml
+++ b/conf/springConfigXml/VmInstanceManager.xml
@@ -34,7 +34,7 @@
org.zstack.compute.vm.VmImageSelectBackupStorageFlow
org.zstack.compute.vm.VmAllocateHostAndPrimaryStorageFlow
- org.zstack.compute.vm.VmAllocateVolumeFlow
+ org.zstack.compute.vm.VmAllocateVolumeFlow
org.zstack.compute.vm.VmAllocateNicFlow
org.zstack.compute.vm.VmAllocateNicIpFlow
org.zstack.compute.vm.VmAllocateCdRomFlow
@@ -87,8 +87,8 @@
org.zstack.compute.vm.VmDestroyOnHypervisorFlow
org.zstack.compute.vm.VmReturnHostFlow
org.zstack.compute.vm.VmReleaseResourceFlow
- org.zstack.compute.vm.VmReturnReleaseNicFlow
- org.zstack.compute.vm.VmPostReleaseNicFlow
+ org.zstack.compute.vm.VmReturnReleaseNicFlow
+ org.zstack.compute.vm.VmPostReleaseNicFlow
org.zstack.compute.vm.VmDeleteVolumeFlow
@@ -188,7 +188,7 @@
-
+
diff --git a/core/src/main/java/org/zstack/core/ansible/CallBackNetworkChecker.java b/core/src/main/java/org/zstack/core/ansible/CallBackNetworkChecker.java
index e178265f4a..5e833f973e 100644
--- a/core/src/main/java/org/zstack/core/ansible/CallBackNetworkChecker.java
+++ b/core/src/main/java/org/zstack/core/ansible/CallBackNetworkChecker.java
@@ -47,7 +47,7 @@ public void deleteDestFile() {
* if failed, use nmap to try again.
*/
private ErrorCode useNcatAndNmapToTestConnection(Ssh ssh) {
- String srcScript = script.format(password, callBackPort, callbackIp);
+ String srcScript = script.format(Ssh.shellQuote(password), callBackPort, callbackIp);
SshResult ret = ssh.setExecTimeout(60).shell(srcScript).setTimeout(60).runAndClose();
ret.raiseExceptionIfFailed();
diff --git a/core/src/main/java/org/zstack/core/ansible/SshChronyConfigChecker.java b/core/src/main/java/org/zstack/core/ansible/SshChronyConfigChecker.java
index 37fad948ab..e9afbb1ee0 100644
--- a/core/src/main/java/org/zstack/core/ansible/SshChronyConfigChecker.java
+++ b/core/src/main/java/org/zstack/core/ansible/SshChronyConfigChecker.java
@@ -29,11 +29,13 @@ public boolean needDeploy() {
.setPassword(password).setPort(sshPort)
.setHostname(targetIp);
try {
- ssh.command("awk '/^\\s*server/{print $2}' /etc/chrony.conf");
+ ssh.sudoCommand("awk '/^\\s*server/{print $2}' /etc/chrony.conf");
SshResult ret = ssh.run();
int returnCode = ret.getReturnCode();
ssh.reset();
if (returnCode != 0) {
+ logger.warn(String.format("exec ssh command failed, return code: %d, stdout: %s, stderr: %s",
+ ret.getReturnCode(), ret.getStdout(), ret.getStderr()));
return true;
}
diff --git a/core/src/main/java/org/zstack/core/ansible/SshFileExistChecker.java b/core/src/main/java/org/zstack/core/ansible/SshFileExistChecker.java
index b09a5441d2..726e1a1e9a 100755
--- a/core/src/main/java/org/zstack/core/ansible/SshFileExistChecker.java
+++ b/core/src/main/java/org/zstack/core/ansible/SshFileExistChecker.java
@@ -23,7 +23,7 @@ public boolean needDeploy() {
.setHostname(targetIp)
.setTimeout(5);
try {
- ssh.command(String.format("echo %s | sudo -S stat %s 2>/dev/null", password, filePath));
+ ssh.sudoCommand(String.format("stat %s", filePath));
SshResult ret = ssh.run();
if (ret.getReturnCode() != 0) {
logger.debug(String.format("file not exist, file: %s", filePath));
diff --git a/core/src/main/java/org/zstack/core/ansible/SshFileMd5Checker.java b/core/src/main/java/org/zstack/core/ansible/SshFileMd5Checker.java
index e39856677a..338a8a2252 100755
--- a/core/src/main/java/org/zstack/core/ansible/SshFileMd5Checker.java
+++ b/core/src/main/java/org/zstack/core/ansible/SshFileMd5Checker.java
@@ -1,5 +1,6 @@
package org.zstack.core.ansible;
+import org.zstack.core.CoreGlobalProperty;
import org.zstack.utils.ShellResult;
import org.zstack.utils.ShellUtils;
import org.zstack.utils.Utils;
@@ -11,8 +12,6 @@
import java.util.ArrayList;
import java.util.List;
-/**
- */
public class SshFileMd5Checker implements AnsibleChecker {
private static final CLogger logger = Utils.getLogger(SshFileMd5Checker.class);
@@ -33,7 +32,9 @@ private SrcDestPair(String srcPath, String destPath) {
String destPath;
}
- public static final String ZSTACKLIB_SRC_PATH = PathUtil.findFileOnClassPath(String.format("ansible/zstacklib/%s", AnsibleGlobalProperty.ZSTACKLIB_PACKAGE_NAME), true).getAbsolutePath();
+ public static final String ZSTACKLIB_SRC_PATH = CoreGlobalProperty.UNIT_TEST_ON ? "/tmp" :
+ PathUtil.findFileOnClassPath(String.format("ansible/zstacklib/%s",
+ AnsibleGlobalProperty.ZSTACKLIB_PACKAGE_NAME), true).getAbsolutePath();
@Override
public boolean needDeploy() {
@@ -47,11 +48,11 @@ public boolean needDeploy() {
String sourceFilePath = b.srcPath;
String destFilePath = b.destPath;
- ssh.command(String.format("echo %s | sudo -S md5sum %s 2>/dev/null",
- ShellUtils.escapeShellText(password),
- destFilePath));
+ ssh.sudoCommand(String.format("md5sum %s", destFilePath));
SshResult ret = ssh.run();
if (ret.getReturnCode() != 0) {
+ logger.warn(String.format("exec ssh command failed, return code: %d, stdout: %s, stderr: %s",
+ ret.getReturnCode(), ret.getStdout(), ret.getStderr()));
return true;
}
ssh.reset();
@@ -61,7 +62,7 @@ public boolean needDeploy() {
sret.raiseExceptionIfFail();
String srcMd5 = sret.getStdout().split(" ")[0];
if (!destMd5.equals(srcMd5)) {
- logger.debug(String.format("file MD5 changed, src[%s, md5:%s] dest[%s, md5, %s]", sourceFilePath,
+ logger.debug(String.format("file MD5 changed, src[%s, md5:%s] dest[%s, md5: %s]", sourceFilePath,
srcMd5, destFilePath, destMd5));
return true;
}
@@ -77,10 +78,15 @@ public boolean needDeploy() {
public void deleteDestFile() {
for (SrcDestPair b : srcDestPairs) {
String destFilePath = b.destPath;
+ if (!destFilePath.contains("zstack")) {
+ logger.debug(String.format("skip delete dest file[%s] which is not zstack file", destFilePath));
+ continue;
+ }
+
Ssh ssh = new Ssh();
ssh.setUsername(username).setPrivateKey(privateKey)
.setPassword(password).setPort(sshPort)
- .setHostname(targetIp).command(String.format("rm -f %s", destFilePath)).runAndClose();
+ .setHostname(targetIp).sudoCommand(String.format("rm -f %s", destFilePath)).runAndClose();
logger.debug(String.format("delete dest file[%s]", destFilePath));
}
}
diff --git a/core/src/main/java/org/zstack/core/ansible/SshFilesMd5Checker.java b/core/src/main/java/org/zstack/core/ansible/SshFilesMd5Checker.java
index 8f66b2af41..71d9cab88b 100644
--- a/core/src/main/java/org/zstack/core/ansible/SshFilesMd5Checker.java
+++ b/core/src/main/java/org/zstack/core/ansible/SshFilesMd5Checker.java
@@ -29,12 +29,11 @@ public boolean needDeploy() {
.setHostname(ip)
.setTimeout(5);
try {
- ssh.command(String.format("echo %s | sudo -S md5sum %s 2>/dev/null",
- ShellUtils.escapeShellText(password),
- filePath));
+ ssh.sudoCommand(String.format("md5sum %s", filePath));
SshResult ret = ssh.run();
if (ret.getReturnCode() != 0) {
- logger.warn(String.format("Failed to get MD5 for file %s: %s", filePath, ret.getStderr()));
+ logger.warn(String.format("exec ssh command failed, return code: %d, stdout: %s, stderr: %s",
+ ret.getReturnCode(), ret.getStdout(), ret.getStderr()));
return true;
}
ssh.reset();
@@ -52,10 +51,15 @@ public boolean needDeploy() {
@Override
public void deleteDestFile() {
+ if (!filePath.contains("zstack")) {
+ logger.debug(String.format("skip delete dest file[%s] which is not zstack file", filePath));
+ return;
+ }
+
Ssh ssh = new Ssh();
ssh.setUsername(username).setPrivateKey(privateKey)
.setPassword(password).setPort(sshPort)
- .setHostname(ip).command(String.format("rm -f %s", filePath)).runAndClose();
+ .setHostname(ip).sudoCommand(String.format("rm -f %s", filePath)).runAndClose();
logger.debug(String.format("delete dest file[%s]", filePath));
}
diff --git a/core/src/main/java/org/zstack/core/ansible/SshFolderMd5Checker.java b/core/src/main/java/org/zstack/core/ansible/SshFolderMd5Checker.java
index ed6b0e4a1d..e86126756f 100755
--- a/core/src/main/java/org/zstack/core/ansible/SshFolderMd5Checker.java
+++ b/core/src/main/java/org/zstack/core/ansible/SshFolderMd5Checker.java
@@ -11,6 +11,7 @@
import org.zstack.utils.StringDSL.StringWrapper;
import org.zstack.utils.Utils;
import org.zstack.utils.logging.CLogger;
+import org.zstack.utils.ssh.Ssh;
import org.zstack.utils.ssh.SshResult;
import org.zstack.utils.ssh.SshShell;
@@ -107,7 +108,7 @@ public boolean needDeploy() {
srcRes.getStdout(), srcRes.getStderr()));
}
- String dstScript = script.format(dstFolder, password);
+ String dstScript = script.format(dstFolder, Ssh.shellQuote(password));
SshShell ssh = new SshShell();
ssh.setHostname(hostname);
ssh.setUsername(username);
diff --git a/core/src/main/java/org/zstack/core/ansible/SshYamlChecker.java b/core/src/main/java/org/zstack/core/ansible/SshYamlChecker.java
index 80f48782f6..32e6ca5ae0 100644
--- a/core/src/main/java/org/zstack/core/ansible/SshYamlChecker.java
+++ b/core/src/main/java/org/zstack/core/ansible/SshYamlChecker.java
@@ -36,9 +36,11 @@ public boolean needDeploy() {
.setHostname(targetIp);
try {
- ssh.command(String.format("grep -o '%s' %s | uniq | wc -l", getGrepArgs(), yamlFilePath));
+ ssh.sudoCommand(String.format("grep -o '%s' %s | uniq | wc -l", getGrepArgs(), yamlFilePath));
SshResult ret = ssh.run();
if (ret.getReturnCode() != 0) {
+ logger.warn(String.format("exec ssh command failed, return code: %d, stdout: %s, stderr: %s",
+ ret.getReturnCode(), ret.getStdout(), ret.getStderr()));
return true;
}
diff --git a/core/src/main/java/org/zstack/core/ansible/SshYumRepoChecker.java b/core/src/main/java/org/zstack/core/ansible/SshYumRepoChecker.java
index 8732f2067e..8438fce4ea 100644
--- a/core/src/main/java/org/zstack/core/ansible/SshYumRepoChecker.java
+++ b/core/src/main/java/org/zstack/core/ansible/SshYumRepoChecker.java
@@ -36,12 +36,13 @@ public boolean needDeploy() {
.setPassword(password).setPort(sshPort)
.setHostname(targetIp);
try {
- ssh.command(String.format(
- "echo %s | sudo -S sed -i '/baseurl/s/\\([0-9]\\{1,3\\}\\.\\)\\{3\\}[0-9]\\{1,3\\}:\\([0-9]\\+\\)/%s/g' /etc/yum.repos.d/{zstack,qemu-kvm-ev}-mn.repo",
- password, restf.getHostName() + ":" + restf.getPort()
+ ssh.sudoCommand(String.format("sed -i '/baseurl/s/\\([0-9]\\{1,3\\}\\.\\)\\{3\\}[0-9]\\{1,3\\}:\\([0-9]\\+\\)/%s/g' /etc/yum.repos.d/{zstack,qemu-kvm-ev}-mn.repo",
+ restf.getHostName() + ":" + restf.getPort()
));
SshResult ret = ssh.setTimeout(60).runAndClose();
if (ret.getReturnCode() != 0) {
+ logger.warn(String.format("exec ssh command failed, return code: %d, stdout: %s, stderr: %s",
+ ret.getReturnCode(), ret.getStdout(), ret.getStderr()));
return true;
}
diff --git a/core/src/main/java/org/zstack/core/db/QueryMore.java b/core/src/main/java/org/zstack/core/db/QueryMore.java
index 9b56f29a1e..21d1441c67 100644
--- a/core/src/main/java/org/zstack/core/db/QueryMore.java
+++ b/core/src/main/java/org/zstack/core/db/QueryMore.java
@@ -242,7 +242,7 @@ public QueryMore notIn(SingularAttribute, ?> attr, QueryMore subQuery) {
}
public QueryMore notIn(SingularAttribute, ?> attr, Q subQuery) {
- return in(attr, subQuery.toQueryMore());
+ return notIn(attr, subQuery.toQueryMore());
}
public QueryMore isNull(SingularAttribute, ?> attr) {
diff --git a/core/src/main/java/org/zstack/core/rest/AsyncResponseFetcher.java b/core/src/main/java/org/zstack/core/rest/AsyncResponseFetcher.java
new file mode 100644
index 0000000000..cc611e4b73
--- /dev/null
+++ b/core/src/main/java/org/zstack/core/rest/AsyncResponseFetcher.java
@@ -0,0 +1,122 @@
+package org.zstack.core.rest;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.zstack.core.thread.PeriodicTask;
+import org.zstack.core.thread.ThreadFacade;
+import org.zstack.core.timeout.TimeHelper;
+import org.zstack.header.core.ReturnValueCompletion;
+import org.zstack.header.errorcode.ErrorCode;
+import org.zstack.header.errorcode.ErrorableValue;
+import org.zstack.header.errorcode.SysErrors;
+import org.zstack.header.rest.AbstractAsyncResponseFetcher;
+import org.zstack.utils.Utils;
+import org.zstack.utils.logging.CLogger;
+
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+import static org.zstack.core.Platform.err;
+
+public class AsyncResponseFetcher extends AbstractAsyncResponseFetcher {
+ private static final CLogger logger = Utils.getLogger(AsyncResponseFetcher.class);
+ private Future cancelHandler;
+
+ protected long runUtil;
+
+ @Autowired
+ protected ThreadFacade threadFacade;
+ @Autowired
+ protected TimeHelper timeHelper;
+
+ protected AsyncResponseFetcher(Class returnType) {
+ super(returnType);
+ }
+
+ @Override
+ public void fetch(ReturnValueCompletion completion) {
+ runUtil = timeHelper.getCurrentTimeMillis() + allAttemptsTimeoutInMillis;
+
+ ReturnValueCompletion completionOnlyIfFinished = new ReturnValueCompletion(completion) {
+ @Override
+ public void success(T returnValue) {
+ onFinished();
+ completion.success(returnValue);
+ }
+
+ @Override
+ public void fail(ErrorCode errorCode) {
+ onFinished();
+ completion.fail(errorCode);
+ }
+ };
+
+ cancelHandler = threadFacade.submitPeriodicTask(new PeriodicTask() {
+ @Override
+ public TimeUnit getTimeUnit() {
+ return TimeUnit.MILLISECONDS;
+ }
+
+ @Override
+ public long getInterval() {
+ return eachAttemptIntervalInMillis;
+ }
+
+ @Override
+ public String getName() {
+ return "wait-for-api-response";
+ }
+
+ @Override
+ public void run() {
+ if (cancelHandler == null || cancelHandler.isCancelled()) {
+ return;
+ }
+
+ boolean finished = AsyncResponseFetcher.this.run(completionOnlyIfFinished);
+ if (finished) {
+ return;
+ }
+
+ if (timeHelper.getCurrentTimeMillis() > runUtil) {
+ completionOnlyIfFinished.fail(timeoutError());
+ }
+ }
+ });
+ }
+
+ private void onFinished() {
+ try {
+ cancelHandler.cancel(true);
+ cancelHandler = null;
+ } catch (Exception e) {
+ logger.trace("cancel periodic task failed", e);
+ }
+ }
+
+ private ErrorCode timeoutError() {
+ return err(SysErrors.HTTP_ERROR, "http timeout")
+ .withOpaque("timeout.millis", allAttemptsTimeoutInMillis)
+ .withOpaque("expect.response.type", returnType.getSimpleName());
+ }
+
+ /**
+ * invoke completionOnlyIfFinished.success/fail ONLY when task finished !!!
+ * @return finished
+ */
+ protected boolean run(ReturnValueCompletion completionOnlyIfFinished) {
+ ErrorableValue value = eachAttempt();
+
+ if (value.isSuccess()) {
+ completionOnlyIfFinished.success(value.result);
+ return true;
+ }
+
+ final ErrorCode error = value.error;
+ if (error == NOT_FINISHED_YET) {
+ return false;
+ }
+
+ completionOnlyIfFinished.fail(error);
+ return true;
+ }
+}
diff --git a/externalservice/src/main/java/org/zstack/externalservice/vops/VOpsAgent.java b/externalservice/src/main/java/org/zstack/externalservice/vops/VOpsAgent.java
new file mode 100644
index 0000000000..ee59449397
--- /dev/null
+++ b/externalservice/src/main/java/org/zstack/externalservice/vops/VOpsAgent.java
@@ -0,0 +1,63 @@
+package org.zstack.externalservice.vops;
+
+import org.zstack.core.Platform;
+import org.zstack.core.externalservice.AbstractLocalExternalService;
+import org.zstack.core.externalservice.ExternalServiceCapabilitiesBuilder;
+import org.zstack.header.core.external.service.ExternalServiceCapabilities;
+import org.zstack.utils.Bash;
+
+/**
+ * Note: VOps is a handler by systemctl.
+ * It is always running after MN installed.
+ *
+ * So it is why we don't need to write "VOpsFactory" class
+ */
+public class VOpsAgent extends AbstractLocalExternalService {
+ @Override
+ protected String[] getCommandLineKeywords() {
+ return new String[]{"/usr/bin/python3", "/usr/local/vops/vops-agent/setup.py"};
+ }
+
+ ExternalServiceCapabilities capabilities = ExternalServiceCapabilitiesBuilder
+ .build()
+ .reloadConfig(false);
+
+ @Override
+ public String getName() {
+ return "vops-agent";
+ }
+
+ @Override
+ public void start() {
+ if (isAlive()) {
+ return;
+ }
+
+ new Bash() {
+ @Override
+ protected void scripts() {
+ setE();
+ sudoRun("systemctl start vops");
+ }
+ }.execute();
+ }
+
+ @Override
+ public boolean isAlive() {
+ return getPID() != null;
+ }
+
+ @Override
+ public ExternalServiceCapabilities getExternalServiceCapabilities() {
+ return capabilities;
+ }
+
+ @Override
+ public void reload() {
+ // do nothing
+ }
+
+ public VOpsClient createClient() {
+ return Platform.New(VOpsClient::new);
+ }
+}
diff --git a/externalservice/src/main/java/org/zstack/externalservice/vops/VOpsClient.java b/externalservice/src/main/java/org/zstack/externalservice/vops/VOpsClient.java
new file mode 100644
index 0000000000..e4095a5782
--- /dev/null
+++ b/externalservice/src/main/java/org/zstack/externalservice/vops/VOpsClient.java
@@ -0,0 +1,58 @@
+package org.zstack.externalservice.vops;
+
+import org.springframework.beans.factory.annotation.Autowire;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Configurable;
+import org.zstack.core.timeout.TimeHelper;
+import org.zstack.header.rest.RESTFacade;
+import org.zstack.header.rest.RestHttp;
+
+@Configurable(preConstruction = true, autowire = Autowire.BY_TYPE)
+public class VOpsClient {
+ String hostname = "127.0.0.1";
+ int port = VOpsConstant.SERVER_PORT;
+ String sessionUuid;
+
+ @Autowired
+ protected RESTFacade restFacade;
+
+ @Autowired
+ protected TimeHelper timeHelper;
+
+ public VOpsClient withHostname(String hostname) {
+ this.hostname = hostname;
+ return this;
+ }
+
+ public VOpsClient withPort(int port) {
+ this.port = port;
+ return this;
+ }
+
+ public VOpsClient withSession(String sessionUuid) {
+ this.sessionUuid = sessionUuid;
+ return this;
+ }
+
+ long getCurrentTimeMillis() {
+ return timeHelper.getCurrentTimeMillis();
+ }
+
+ protected RestHttp http(Class returnClass) {
+ return restFacade.http(returnClass);
+ }
+
+ public VOpsClientRestHttp createHttp(String path) {
+ if (path.startsWith("/")) {
+ path = path.substring(1);
+ }
+
+ VOpsClientRestHttp http = new VOpsClientRestHttp(this)
+ // "http://{self.hostname}:{self.port}/{path}"
+ .withPath(String.format("http://%s:%s/%s", hostname, port, path));
+ if (sessionUuid != null) {
+ http.withSession(sessionUuid);
+ }
+ return http;
+ }
+}
diff --git a/externalservice/src/main/java/org/zstack/externalservice/vops/VOpsClientRestHttp.java b/externalservice/src/main/java/org/zstack/externalservice/vops/VOpsClientRestHttp.java
new file mode 100644
index 0000000000..d819f1d633
--- /dev/null
+++ b/externalservice/src/main/java/org/zstack/externalservice/vops/VOpsClientRestHttp.java
@@ -0,0 +1,136 @@
+package org.zstack.externalservice.vops;
+
+import org.springframework.http.HttpMethod;
+import org.zstack.header.errorcode.ErrorableValue;
+import org.zstack.header.rest.RestHttp;
+import org.zstack.utils.gson.JSONObjectUtil;
+import com.google.gson.JsonObject;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.zstack.core.Platform.err;
+import static org.zstack.externalservice.vops.VOpsErrors.*;
+
+public class VOpsClientRestHttp {
+ public final VOpsClient client;
+ private String path;
+ private long timeoutInMillis = 10000L;
+ protected String body;
+ protected Map headers = new HashMap<>();
+
+ public VOpsClientRestHttp(VOpsClient client) {
+ this.client = client;
+ }
+
+ public VOpsClientRestHttp withPath(String path) {
+ this.path = path;
+ return this;
+ }
+
+ public VOpsClientRestHttp withTimeoutInMillis(long timeoutInMillis) {
+ this.timeoutInMillis = timeoutInMillis;
+ return this;
+ }
+
+ public VOpsClientRestHttp withBody(String body) {
+ this.body = body;
+ return this;
+ }
+
+ public VOpsClientRestHttp withBodyJson(Object body) {
+ this.body = JSONObjectUtil.toJsonString(body);
+ return this;
+ }
+
+ public VOpsClientRestHttp withHeader(String key, String value) {
+ this.headers.put(key, value);
+ return this;
+ }
+
+ public VOpsClientRestHttp withSession(String sessionUuid) {
+ return withHeader("Authorization", "OAuth " + sessionUuid);
+ }
+
+ public ErrorableValue getWithErrorCode() {
+ return callWithErrorCode(HttpMethod.GET);
+ }
+
+ public ErrorableValue postWithErrorCode() {
+ return callWithErrorCode(HttpMethod.POST);
+ }
+
+ public ErrorableValue putWithErrorCode() {
+ return callWithErrorCode(HttpMethod.PUT);
+ }
+
+ public ErrorableValue callWithErrorCode(HttpMethod method) {
+ long expectEndTime = this.client.getCurrentTimeMillis() + this.timeoutInMillis;
+ final RestHttp http = client.http(JsonObject.class)
+ .withPath(path)
+ .withTimeoutInMillis(timeoutInMillis)
+ .withoutRetry();
+ if (this.headers != null) {
+ for (Map.Entry entry : this.headers.entrySet()) {
+ http.withHeader(entry.getKey(), entry.getValue());
+ }
+ }
+ if (this.body != null) {
+ http.withBody(this.body);
+ }
+ ErrorableValue firstResult = http.callWithErrorCode(method);
+ if (!firstResult.isSuccess()) {
+ return firstResult;
+ }
+
+ if (!firstResult.result.has("api_id")) {
+ return firstResult;
+ }
+ String apiId = firstResult.result.get("api_id").getAsString();
+
+ RestHttp nextHttp = client.http(JsonObject.class)
+ .withPath(String.format("http://%s:%s/api/%s", client.hostname, client.port, apiId))
+ .withTimeoutInMillis(2000L)
+ .withoutRetry();
+ if (this.headers != null) {
+ for (Map.Entry entry : this.headers.entrySet()) {
+ http.withHeader(entry.getKey(), entry.getValue());
+ }
+ }
+ int waitingCount = 0;
+ while (this.client.getCurrentTimeMillis() < expectEndTime) {
+ ErrorableValue nextResult = nextHttp.getWithErrorCode();
+ if (!nextResult.isSuccess()) {
+ return nextResult;
+ }
+
+ if (!nextResult.result.has("finished")) {
+ return nextResult;
+ }
+
+ ++waitingCount;
+ if (nextResult.result.get("finished").getAsBoolean()) {
+ if (!nextResult.result.has("success") || !nextResult.result.get("success").getAsBoolean()) {
+ return ErrorableValue.ofErrorCode(err(REMOTE_AGENT_ERROR, "error on remote node")
+ .withCause(wrapErrorFromVOpsClient(nextResult.result.getAsJsonObject("error"))
+ .withOpaque("response.by", "vops")
+ .withOpaque("path", path)
+ .withOpaque("api.id", apiId)));
+ }
+
+ return ErrorableValue.of(nextResult.result.getAsJsonObject("results"));
+ }
+
+ try {
+ Thread.sleep(waitingCount < 10 ? 500 : 1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ return ErrorableValue.ofErrorCode(err(HTTP_TIMED_OUT, "client http timeout")
+ .withOpaque("response.by", "vops")
+ .withOpaque("path", path)
+ .withOpaque("api.id", apiId));
+ }
+}
diff --git a/externalservice/src/main/java/org/zstack/externalservice/vops/VOpsCommands.java b/externalservice/src/main/java/org/zstack/externalservice/vops/VOpsCommands.java
new file mode 100644
index 0000000000..76ae617277
--- /dev/null
+++ b/externalservice/src/main/java/org/zstack/externalservice/vops/VOpsCommands.java
@@ -0,0 +1,8 @@
+package org.zstack.externalservice.vops;
+
+public class VOpsCommands {
+ public static final String ZSHA2_DEMOTE_PATH = "/zsha2/demote";
+ public static class ZSha2DemoteCmd {
+ public Object params = new Object(); // empty object now
+ }
+}
\ No newline at end of file
diff --git a/externalservice/src/main/java/org/zstack/externalservice/vops/VOpsConstant.java b/externalservice/src/main/java/org/zstack/externalservice/vops/VOpsConstant.java
new file mode 100644
index 0000000000..30a19efcac
--- /dev/null
+++ b/externalservice/src/main/java/org/zstack/externalservice/vops/VOpsConstant.java
@@ -0,0 +1,5 @@
+package org.zstack.externalservice.vops;
+
+public class VOpsConstant {
+ public static final int SERVER_PORT = 8078;
+}
diff --git a/externalservice/src/main/java/org/zstack/externalservice/vops/VOpsErrors.java b/externalservice/src/main/java/org/zstack/externalservice/vops/VOpsErrors.java
new file mode 100644
index 0000000000..b62acfcc63
--- /dev/null
+++ b/externalservice/src/main/java/org/zstack/externalservice/vops/VOpsErrors.java
@@ -0,0 +1,31 @@
+package org.zstack.externalservice.vops;
+
+import org.zstack.header.errorcode.ErrorCode;
+import org.zstack.utils.gson.JSONObjectUtil;
+import com.google.gson.JsonElement;
+
+public enum VOpsErrors {
+ GENERAL_ERROR(1000),
+ HTTP_TIMED_OUT(1312),
+ REMOTE_AGENT_ERROR(1315),
+ ;
+
+ private String code;
+
+ private VOpsErrors(int id) {
+ code = String.format("VOPS.%s", id);
+ }
+
+ @Override
+ public String toString() {
+ return code;
+ }
+
+ public static ErrorCode wrapErrorFromVOpsClient(JsonElement json) {
+ try {
+ return JSONObjectUtil.rehashObject(json, ErrorCode.class);
+ } catch (Exception e) {
+ return new ErrorCode(VOpsErrors.GENERAL_ERROR.toString(), json.toString());
+ }
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/candidate/CandidateDecision.java b/header/src/main/java/org/zstack/header/candidate/CandidateDecision.java
new file mode 100644
index 0000000000..5b951619df
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/candidate/CandidateDecision.java
@@ -0,0 +1,8 @@
+package org.zstack.header.candidate;
+
+public enum CandidateDecision {
+ ACCEPTED,
+ REJECTED,
+ RECOMMENDED,
+ NOT_RECOMMENDED,
+}
diff --git a/header/src/main/java/org/zstack/header/candidate/CandidateDecisionEntry.java b/header/src/main/java/org/zstack/header/candidate/CandidateDecisionEntry.java
new file mode 100644
index 0000000000..59dba7a016
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/candidate/CandidateDecisionEntry.java
@@ -0,0 +1,33 @@
+package org.zstack.header.candidate;
+
+import java.io.Serializable;
+
+public class CandidateDecisionEntry implements Serializable {
+ private CandidateDecision decision;
+ private String decisionMaker;
+ private String reason;
+
+ public CandidateDecision getDecision() {
+ return decision;
+ }
+
+ public void setDecision(CandidateDecision decision) {
+ this.decision = decision;
+ }
+
+ public String getDecisionMaker() {
+ return decisionMaker;
+ }
+
+ public void setDecisionMaker(String decisionMaker) {
+ this.decisionMaker = decisionMaker;
+ }
+
+ public String getReason() {
+ return reason;
+ }
+
+ public void setReason(String reason) {
+ this.reason = reason;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/candidate/CandidateResult.java b/header/src/main/java/org/zstack/header/candidate/CandidateResult.java
new file mode 100644
index 0000000000..5d96b76739
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/candidate/CandidateResult.java
@@ -0,0 +1,63 @@
+package org.zstack.header.candidate;
+
+import org.zstack.header.rest.SDK;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@SDK
+public class CandidateResult implements Serializable {
+ private T candidate;
+ private CandidateDecision finalDecision = CandidateDecision.ACCEPTED;
+ private List decisions = new ArrayList<>();
+
+ public CandidateResult(T candidate) {
+ this.candidate = candidate;
+ }
+
+ public T getCandidate() {
+ return candidate;
+ }
+
+ public void setCandidate(T candidate) {
+ this.candidate = candidate;
+ }
+
+ public CandidateDecision getFinalDecision() {
+ return finalDecision;
+ }
+
+ public void setFinalDecision(CandidateDecision finalDecision) {
+ this.finalDecision = finalDecision;
+ }
+
+ public List getDecisions() {
+ return decisions;
+ }
+
+ public void setDecisions(List decisions) {
+ this.decisions = decisions;
+ }
+
+ public void addFinalDecision(CandidateDecisionEntry entry) {
+ if (this.decisions == null) {
+ this.decisions = new ArrayList<>();
+ }
+ if (entry == null) {
+ return;
+ }
+ this.decisions.add(entry);
+ this.finalDecision = entry.getDecision();
+ }
+
+ public static List> getNotRejectedCandidates(List> candidates) {
+ if (candidates == null) {
+ return new ArrayList<>();
+ }
+ return candidates.stream()
+ .filter(c -> c.getFinalDecision() != CandidateDecision.REJECTED)
+ .collect(Collectors.toList());
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/configuration/VmCustomSpecificationDomainMode.java b/header/src/main/java/org/zstack/header/configuration/VmCustomSpecificationDomainMode.java
new file mode 100644
index 0000000000..c68e8e4289
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/configuration/VmCustomSpecificationDomainMode.java
@@ -0,0 +1,6 @@
+package org.zstack.header.configuration;
+
+public enum VmCustomSpecificationDomainMode {
+ WorkGroup,
+ Domain
+}
diff --git a/header/src/main/java/org/zstack/header/configuration/VmCustomSpecificationDomainModeDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/configuration/VmCustomSpecificationDomainModeDoc_zh_cn.groovy
new file mode 100644
index 0000000000..ab53319568
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/configuration/VmCustomSpecificationDomainModeDoc_zh_cn.groovy
@@ -0,0 +1,21 @@
+package org.zstack.header.configuration
+
+
+
+doc {
+
+ title "加域模式"
+
+ field {
+ name "WorkGroup"
+ desc "工作组"
+ type "VmCustomSpecificationDomainMode"
+ since "4.10.18"
+ }
+ field {
+ name "Domain"
+ desc "域"
+ type "VmCustomSpecificationDomainMode"
+ since "4.10.18"
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/configuration/VmCustomSpecificationStruct.java b/header/src/main/java/org/zstack/header/configuration/VmCustomSpecificationStruct.java
new file mode 100644
index 0000000000..47be1c1e3d
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/configuration/VmCustomSpecificationStruct.java
@@ -0,0 +1,103 @@
+package org.zstack.header.configuration;
+
+import org.zstack.header.log.NoLogging;
+import org.zstack.header.rest.SDK;
+
+import java.io.Serializable;
+
+@PythonClassInventory
+@SDK(sdkClassName = "VmCustomSpecificationStruct")
+public class VmCustomSpecificationStruct implements Serializable {
+ private String uuid;
+ private String platform;
+ private String hostname;
+ @NoLogging
+ private String rootPassword;
+ private Boolean generateSID;
+ private VmCustomSpecificationDomainMode domainMode;
+ private String domainName;
+ private String domainUsername;
+ @NoLogging
+ private String domainPassword;
+ private String organization;
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ public void setUuid(String uuid) {
+ this.uuid = uuid;
+ }
+
+ public String getPlatform() {
+ return platform;
+ }
+
+ public void setPlatform(String platform) {
+ this.platform = platform;
+ }
+
+ public String getHostname() {
+ return hostname;
+ }
+
+ public void setHostname(String hostname) {
+ this.hostname = hostname;
+ }
+
+ public String getRootPassword() {
+ return rootPassword;
+ }
+
+ public void setRootPassword(String rootPassword) {
+ this.rootPassword = rootPassword;
+ }
+
+ public Boolean getGenerateSID() {
+ return generateSID;
+ }
+
+ public void setGenerateSID(Boolean generateSID) {
+ this.generateSID = generateSID;
+ }
+
+ public VmCustomSpecificationDomainMode getDomainMode() {
+ return domainMode;
+ }
+
+ public void setDomainMode(VmCustomSpecificationDomainMode domainMode) {
+ this.domainMode = domainMode;
+ }
+
+ public String getDomainName() {
+ return domainName;
+ }
+
+ public void setDomainName(String domainName) {
+ this.domainName = domainName;
+ }
+
+ public String getDomainUsername() {
+ return domainUsername;
+ }
+
+ public void setDomainUsername(String domainUsername) {
+ this.domainUsername = domainUsername;
+ }
+
+ public String getDomainPassword() {
+ return domainPassword;
+ }
+
+ public void setDomainPassword(String domainPassword) {
+ this.domainPassword = domainPassword;
+ }
+
+ public String getOrganization() {
+ return organization;
+ }
+
+ public void setOrganization(String organization) {
+ this.organization = organization;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/errorcode/ErrorableValue.java b/header/src/main/java/org/zstack/header/errorcode/ErrorableValue.java
index 96728a2673..d02f9c2563 100644
--- a/header/src/main/java/org/zstack/header/errorcode/ErrorableValue.java
+++ b/header/src/main/java/org/zstack/header/errorcode/ErrorableValue.java
@@ -1,5 +1,7 @@
package org.zstack.header.errorcode;
+import org.zstack.header.exception.CloudRuntimeException;
+
import java.util.Objects;
/**
@@ -18,6 +20,18 @@ public static ErrorableValue ofErrorCode(ErrorCode error) {
Objects.requireNonNull(error, "errorCode in ErrorableValue can not be null"));
}
+ /**
+ * Make sure this ErrorableValue is not success
+ */
+ @SuppressWarnings("unchecked")
+ public ErrorableValue cast() {
+ if (isSuccess()) {
+ throw new CloudRuntimeException("Can not cast ErrorableValue");
+ } else {
+ return (ErrorableValue) this;
+ }
+ }
+
protected ErrorableValue(T result, ErrorCode error) {
this.result = result;
this.error = error;
diff --git a/header/src/main/java/org/zstack/header/host/APIUpdateHostnameEvent.java b/header/src/main/java/org/zstack/header/host/APIUpdateHostnameEvent.java
new file mode 100644
index 0000000000..efa889158b
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/host/APIUpdateHostnameEvent.java
@@ -0,0 +1,45 @@
+package org.zstack.header.host;
+
+import org.zstack.header.message.APIEvent;
+import org.zstack.header.rest.RestResponse;
+
+@RestResponse(fieldsTo = {"all"})
+public class APIUpdateHostnameEvent extends APIEvent {
+ private HostInventory inventory;
+
+ public APIUpdateHostnameEvent() { super(null); }
+
+ public APIUpdateHostnameEvent(String apiId) {
+ super(apiId);
+ }
+
+ public HostInventory getInventory() {
+ return inventory;
+ }
+
+ public void setInventory(HostInventory inventory) {
+ this.inventory = inventory;
+ }
+
+ public static APIUpdateHostnameEvent __example__() {
+ APIUpdateHostnameEvent event = new APIUpdateHostnameEvent();
+ HostInventory host = new HostInventory();
+ host.setAvailableCpuCapacity(2L);
+ host.setAvailableMemoryCapacity(4L);
+ host.setManagementIp("192.168.0.1");
+ host.setName("example");
+ host.setState(HostState.Enabled.toString());
+ host.setStatus(HostStatus.Connected.toString());
+ host.setClusterUuid(uuid());
+ host.setZoneUuid(uuid());
+ host.setUuid(uuid());
+ host.setTotalCpuCapacity(4L);
+ host.setTotalMemoryCapacity(4L);
+ host.setHypervisorType("KVM");
+ host.setDescription("example");
+ host.setNqn("nqn.2014-08.org.nvmexpress:uuid:748d0363-8366-44db-803b-146effb96988");
+ host.setHostname("hostname");
+ event.setInventory(host);
+ return event;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/host/APIUpdateHostnameEventDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/host/APIUpdateHostnameEventDoc_zh_cn.groovy
new file mode 100644
index 0000000000..17c8754f87
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/host/APIUpdateHostnameEventDoc_zh_cn.groovy
@@ -0,0 +1,31 @@
+package org.zstack.header.host
+
+import org.zstack.header.errorcode.ErrorCode
+
+doc {
+
+ title "更新主机hostname返回"
+
+ ref {
+ name "inventory"
+ path "org.zstack.header.host.APIUpdateHostnameEvent.inventory"
+ desc "null"
+ type "HostInventory"
+ since "4.10.20"
+ clz HostInventory.class
+ }
+ field {
+ name "success"
+ desc ""
+ type "boolean"
+ since "4.10.20"
+ }
+ ref {
+ name "error"
+ path "org.zstack.header.host.APIUpdateHostnameEvent.error"
+ desc "错误码,若不为null,则表示操作失败, 操作成功时该字段为null",false
+ type "ErrorCode"
+ since "4.10.20"
+ clz ErrorCode.class
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/host/APIUpdateHostnameMsg.java b/header/src/main/java/org/zstack/header/host/APIUpdateHostnameMsg.java
new file mode 100644
index 0000000000..6ebef33152
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/host/APIUpdateHostnameMsg.java
@@ -0,0 +1,47 @@
+package org.zstack.header.host;
+
+import org.springframework.http.HttpMethod;
+import org.zstack.header.message.APIMessage;
+import org.zstack.header.message.APIParam;
+import org.zstack.header.rest.RestRequest;
+
+@RestRequest(
+ path = "/hosts/hostname/{uuid}/actions",
+ method = HttpMethod.PUT,
+ responseClass = APIUpdateHostnameEvent.class,
+ isAction = true
+)
+public class APIUpdateHostnameMsg extends APIMessage implements HostMessage {
+ @APIParam(resourceType = HostVO.class)
+ private String uuid;
+ @APIParam(nonempty = true, emptyString = false)
+ private String hostname;
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ public void setUuid(String uuid) {
+ this.uuid = uuid;
+ }
+
+ @Override
+ public String getHostUuid() {
+ return uuid;
+ }
+
+ public String getHostname() {
+ return hostname;
+ }
+
+ public void setHostname(String hostname) {
+ this.hostname = hostname;
+ }
+
+ public static APIUpdateHostnameMsg __example__() {
+ APIUpdateHostnameMsg msg = new APIUpdateHostnameMsg();
+ msg.setUuid(uuid());
+ msg.setHostname("user");
+ return msg;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/host/APIUpdateHostnameMsgDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/host/APIUpdateHostnameMsgDoc_zh_cn.groovy
new file mode 100644
index 0000000000..4821f2cae0
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/host/APIUpdateHostnameMsgDoc_zh_cn.groovy
@@ -0,0 +1,67 @@
+package org.zstack.header.host
+
+import org.zstack.header.host.APIUpdateHostnameEvent
+
+doc {
+ title "UpdateHostname"
+
+ category "host"
+
+ desc """更新主机hostname"""
+
+ rest {
+ request {
+ url "PUT /v1/hosts/hostname/{uuid}/actions"
+
+ header (Authorization: 'OAuth the-session-uuid')
+
+ clz APIUpdateHostnameMsg.class
+
+ desc """更新主机hostname"""
+
+ params {
+
+ column {
+ name "uuid"
+ enclosedIn "updateHostname"
+ desc "主机UUID"
+ location "url"
+ type "String"
+ optional false
+ since "4.10.20"
+ }
+ column {
+ name "hostname"
+ enclosedIn "updateHostname"
+ desc "主机hostname"
+ location "body"
+ type "String"
+ optional false
+ since "4.10.20"
+ }
+ column {
+ name "systemTags"
+ enclosedIn ""
+ desc "系统标签"
+ location "body"
+ type "List"
+ optional true
+ since "4.10.20"
+ }
+ column {
+ name "userTags"
+ enclosedIn ""
+ desc "用户标签"
+ location "body"
+ type "List"
+ optional true
+ since "4.10.20"
+ }
+ }
+ }
+
+ response {
+ clz APIUpdateHostnameEvent.class
+ }
+ }
+}
\ No newline at end of file
diff --git a/header/src/main/java/org/zstack/header/host/GetFileDownloadProgressMsg.java b/header/src/main/java/org/zstack/header/host/GetFileDownloadProgressMsg.java
new file mode 100644
index 0000000000..e818f60a3f
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/host/GetFileDownloadProgressMsg.java
@@ -0,0 +1,25 @@
+package org.zstack.header.host;
+
+import org.zstack.header.message.CancelMessage;
+
+public class GetFileDownloadProgressMsg extends CancelMessage implements HostMessage {
+ private String hostUuid;
+ private String taskUuid;
+
+ @Override
+ public String getHostUuid() {
+ return hostUuid;
+ }
+
+ public void setHostUuid(String hostUuid) {
+ this.hostUuid = hostUuid;
+ }
+
+ public String getTaskUuid() {
+ return taskUuid;
+ }
+
+ public void setTaskUuid(String taskUuid) {
+ this.taskUuid = taskUuid;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/host/GetFileDownloadProgressReply.java b/header/src/main/java/org/zstack/header/host/GetFileDownloadProgressReply.java
new file mode 100644
index 0000000000..512e1c4236
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/host/GetFileDownloadProgressReply.java
@@ -0,0 +1,88 @@
+package org.zstack.header.host;
+
+import org.zstack.header.message.MessageReply;
+
+public class GetFileDownloadProgressReply extends MessageReply {
+ private boolean completed;
+ private int progress;
+
+ private long size;
+ private long actualSize;
+ private long downloadSize;
+ private String installPath;
+ private long lastOpTime;
+ private boolean supportSuspend;
+ private String md5sum;
+
+ public boolean isCompleted() {
+ return completed;
+ }
+
+ public void setCompleted(boolean completed) {
+ this.completed = completed;
+ }
+
+ public int getProgress() {
+ return progress;
+ }
+
+ public void setProgress(int progress) {
+ this.progress = progress;
+ }
+
+ public long getSize() {
+ return size;
+ }
+
+ public void setSize(long size) {
+ this.size = size;
+ }
+
+ public long getActualSize() {
+ return actualSize;
+ }
+
+ public void setActualSize(long actualSize) {
+ this.actualSize = actualSize;
+ }
+
+ public String getInstallPath() {
+ return installPath;
+ }
+
+ public void setInstallPath(String installPath) {
+ this.installPath = installPath;
+ }
+
+ public long getLastOpTime() {
+ return lastOpTime;
+ }
+
+ public void setLastOpTime(long lastOpTime) {
+ this.lastOpTime = lastOpTime;
+ }
+
+ public long getDownloadSize() {
+ return downloadSize;
+ }
+
+ public void setDownloadSize(long downloadSize) {
+ this.downloadSize = downloadSize;
+ }
+
+ public boolean isSupportSuspend() {
+ return supportSuspend;
+ }
+
+ public void setSupportSuspend(boolean supportSuspend) {
+ this.supportSuspend = supportSuspend;
+ }
+
+ public String getMd5sum() {
+ return md5sum;
+ }
+
+ public void setMd5sum(String md5sum) {
+ this.md5sum = md5sum;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/host/HostAO.java b/header/src/main/java/org/zstack/header/host/HostAO.java
index 761be50827..c75827fabc 100755
--- a/header/src/main/java/org/zstack/header/host/HostAO.java
+++ b/header/src/main/java/org/zstack/header/host/HostAO.java
@@ -40,6 +40,9 @@ public class HostAO extends ResourceVO {
@Column
private String nqn;
+ @Column
+ private String hostname;
+
@Column
@Enumerated(EnumType.STRING)
private HostState state;
@@ -157,4 +160,12 @@ public String getNqn() {
public void setNqn(String nqn) {
this.nqn = nqn;
}
+
+ public String getHostname() {
+ return hostname;
+ }
+
+ public void setHostname(String hostname) {
+ this.hostname = hostname;
+ }
}
diff --git a/header/src/main/java/org/zstack/header/host/HostAO_.java b/header/src/main/java/org/zstack/header/host/HostAO_.java
index 2e34beac2f..660c60defa 100755
--- a/header/src/main/java/org/zstack/header/host/HostAO_.java
+++ b/header/src/main/java/org/zstack/header/host/HostAO_.java
@@ -22,4 +22,5 @@ public class HostAO_ extends ResourceVO_ {
public static volatile SingularAttribute lastOpDate;
public static volatile SingularAttribute architecture;
public static volatile SingularAttribute nqn;
+ public static volatile SingularAttribute hostname;
}
diff --git a/header/src/main/java/org/zstack/header/host/HostInventory.java b/header/src/main/java/org/zstack/header/host/HostInventory.java
index b2f9ceb6c5..2afbf35234 100755
--- a/header/src/main/java/org/zstack/header/host/HostInventory.java
+++ b/header/src/main/java/org/zstack/header/host/HostInventory.java
@@ -187,6 +187,8 @@ public class HostInventory implements Serializable {
private String nqn;
+ private String hostname;
+
/**
* @desc the time this resource gets created
*/
@@ -210,6 +212,7 @@ protected HostInventory(HostVO vo) {
this.setClusterUuid(vo.getClusterUuid());
this.setArchitecture(vo.getArchitecture());
this.setNqn(vo.getNqn());
+ this.setHostname(vo.getHostname());
if (vo.getCapacity() != null) {
this.setTotalCpuCapacity(vo.getCapacity().getTotalCpu());
this.setAvailableCpuCapacity(vo.getCapacity().getAvailableCpu());
@@ -509,4 +512,12 @@ public HwMonitorStatus getTemperatureStatus() {
public void setTemperatureStatus(HwMonitorStatus temperatureStatus) {
this.temperatureStatus = temperatureStatus;
}
+
+ public String getHostname() {
+ return hostname;
+ }
+
+ public void setHostname(String hostname) {
+ this.hostname = hostname;
+ }
}
diff --git a/header/src/main/java/org/zstack/header/host/HostInventoryDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/host/HostInventoryDoc_zh_cn.groovy
index 3fda8f546b..ec4a235837 100644
--- a/header/src/main/java/org/zstack/header/host/HostInventoryDoc_zh_cn.groovy
+++ b/header/src/main/java/org/zstack/header/host/HostInventoryDoc_zh_cn.groovy
@@ -207,6 +207,12 @@ doc {
type "String"
since "zsv 4.10.6"
}
+ field {
+ name "hostname"
+ desc "主机名"
+ type "String"
+ since "4.10.20"
+ }
field {
name "createDate"
desc "创建时间"
diff --git a/header/src/main/java/org/zstack/header/host/HostResizeVolumeExtensionPoint.java b/header/src/main/java/org/zstack/header/host/HostResizeVolumeExtensionPoint.java
new file mode 100644
index 0000000000..d1a1418818
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/host/HostResizeVolumeExtensionPoint.java
@@ -0,0 +1,10 @@
+package org.zstack.header.host;
+
+import org.zstack.header.volume.VolumeInventory;
+
+/**
+ * Created by kayo on 2018/4/2.
+ */
+public interface HostResizeVolumeExtensionPoint {
+ HostResizeVolumeStruct beforeKvmHostResizeVolume(HostResizeVolumeStruct struct, VolumeInventory vol, String hostUuid);
+}
diff --git a/header/src/main/java/org/zstack/header/host/HostResizeVolumeStruct.java b/header/src/main/java/org/zstack/header/host/HostResizeVolumeStruct.java
new file mode 100644
index 0000000000..2f6774c6e1
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/host/HostResizeVolumeStruct.java
@@ -0,0 +1,35 @@
+package org.zstack.header.host;
+
+/**
+ * @author Xingwei Yu
+ * @date 2025/8/12 14:20
+ */
+public class HostResizeVolumeStruct {
+ private String deviceType;
+ String installPath;
+ long size;
+
+ public String getDeviceType() {
+ return deviceType;
+ }
+
+ public void setDeviceType(String deviceType) {
+ this.deviceType = deviceType;
+ }
+
+ public String getInstallPath() {
+ return installPath;
+ }
+
+ public void setInstallPath(String installPath) {
+ this.installPath = installPath;
+ }
+
+ public long getSize() {
+ return size;
+ }
+
+ public void setSize(long size) {
+ this.size = size;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/host/UpdateHostnameMsg.java b/header/src/main/java/org/zstack/header/host/UpdateHostnameMsg.java
new file mode 100644
index 0000000000..0f31cd978c
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/host/UpdateHostnameMsg.java
@@ -0,0 +1,29 @@
+package org.zstack.header.host;
+
+import org.zstack.header.message.NeedReplyMessage;
+
+public class UpdateHostnameMsg extends NeedReplyMessage implements HostMessage {
+ private String uuid;
+ private String hostname;
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ public void setUuid(String uuid) {
+ this.uuid = uuid;
+ }
+
+ public String getHostname() {
+ return hostname;
+ }
+
+ public void setHostname(String hostname) {
+ this.hostname = hostname;
+ }
+
+ @Override
+ public String getHostUuid() {
+ return uuid;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/host/UpdateHostnameReply.java b/header/src/main/java/org/zstack/header/host/UpdateHostnameReply.java
new file mode 100644
index 0000000000..f997927a4f
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/host/UpdateHostnameReply.java
@@ -0,0 +1,15 @@
+package org.zstack.header.host;
+
+import org.zstack.header.message.MessageReply;
+
+public class UpdateHostnameReply extends MessageReply {
+ HostInventory inventory;
+
+ public HostInventory getInventory() {
+ return inventory;
+ }
+
+ public void setInventory(HostInventory inventory) {
+ this.inventory = inventory;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/host/UploadFileToHostMsg.java b/header/src/main/java/org/zstack/header/host/UploadFileToHostMsg.java
new file mode 100644
index 0000000000..68fd5190c9
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/host/UploadFileToHostMsg.java
@@ -0,0 +1,45 @@
+package org.zstack.header.host;
+
+import org.zstack.header.log.NoLogging;
+import org.zstack.header.message.NeedReplyMessage;
+
+public class UploadFileToHostMsg extends NeedReplyMessage implements HostMessage {
+ private String hostUuid;
+ private String taskUuid;
+ @NoLogging(type = NoLogging.Type.Uri)
+ private String url;
+ private String installPath;
+
+ @Override
+ public String getHostUuid() {
+ return hostUuid;
+ }
+
+ public void setHostUuid(String hostUuid) {
+ this.hostUuid = hostUuid;
+ }
+
+ public String getTaskUuid() {
+ return taskUuid;
+ }
+
+ public void setTaskUuid(String taskUuid) {
+ this.taskUuid = taskUuid;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public String getInstallPath() {
+ return installPath;
+ }
+
+ public void setInstallPath(String installPath) {
+ this.installPath = installPath;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/host/UploadFileToHostReply.java b/header/src/main/java/org/zstack/header/host/UploadFileToHostReply.java
new file mode 100644
index 0000000000..4e1106a1d1
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/host/UploadFileToHostReply.java
@@ -0,0 +1,35 @@
+package org.zstack.header.host;
+
+import org.zstack.header.log.NoLogging;
+import org.zstack.header.message.MessageReply;
+
+public class UploadFileToHostReply extends MessageReply {
+ private String md5sum;
+ private long size;
+ @NoLogging(type = NoLogging.Type.Uri)
+ private String directUploadUrl;
+
+ public String getMd5sum() {
+ return md5sum;
+ }
+
+ public void setMd5sum(String md5sum) {
+ this.md5sum = md5sum;
+ }
+
+ public long getSize() {
+ return size;
+ }
+
+ public void setSize(long size) {
+ this.size = size;
+ }
+
+ public String getDirectUploadUrl() {
+ return directUploadUrl;
+ }
+
+ public void setDirectUploadUrl(String directUploadUrl) {
+ this.directUploadUrl = directUploadUrl;
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/network/l3/L3NetworkInventory.java b/header/src/main/java/org/zstack/header/network/l3/L3NetworkInventory.java
index fa95bc3817..d351ebd769 100755
--- a/header/src/main/java/org/zstack/header/network/l3/L3NetworkInventory.java
+++ b/header/src/main/java/org/zstack/header/network/l3/L3NetworkInventory.java
@@ -72,6 +72,8 @@
foreignKey = "uuid", expandedInventoryKey = "l3NetworkUuid", hidden = true),
@ExpandedQuery(expandedField = "usedIp", inventoryClass = UsedIpInventory.class,
foreignKey = "uuid", expandedInventoryKey = "l3NetworkUuid"),
+ @ExpandedQuery(expandedField = "ipRange", inventoryClass = IpRangeInventory.class,
+ foreignKey = "uuid", expandedInventoryKey = "l3NetworkUuid"),
})
@ExpandedQueryAliases({
@ExpandedQueryAlias(alias = "serviceProvider", expandedField = "serviceProviderRef.serviceProvider")
diff --git a/header/src/main/java/org/zstack/header/network/l3/UsedIpInventory.java b/header/src/main/java/org/zstack/header/network/l3/UsedIpInventory.java
index f5aa381cfe..1a21b629a6 100755
--- a/header/src/main/java/org/zstack/header/network/l3/UsedIpInventory.java
+++ b/header/src/main/java/org/zstack/header/network/l3/UsedIpInventory.java
@@ -35,6 +35,7 @@ public class UsedIpInventory implements Serializable {
@APINoSee
private String metaData;
private Long ipInLong;
+ @APINoSee
private byte[] ipInBinary;
private String vmNicUuid;
private Timestamp createDate;
@@ -48,6 +49,7 @@ public UsedIpInventory(UsedIpVO vo) {
this.setIpVersion(vo.getIpVersion());
this.setIp(vo.getIp());
this.setIpInLong(vo.getIpInLong());
+ this.setIpInBinary(vo.getIpInBinary());
this.setIpRangeUuid(vo.getIpRangeUuid());
this.setL3NetworkUuid(vo.getL3NetworkUuid());
this.setGateway(vo.getGateway());
@@ -60,22 +62,7 @@ public UsedIpInventory(UsedIpVO vo) {
}
public static UsedIpInventory valueOf(UsedIpVO vo) {
- UsedIpInventory inv = new UsedIpInventory();
- inv.setCreateDate(vo.getCreateDate());
- inv.setUuid(vo.getUuid());
- inv.setIpVersion(vo.getIpVersion());
- inv.setIp(vo.getIp());
- inv.setIpInLong(vo.getIpInLong());
- inv.setIpInBinary(vo.getIpInBinary());
- inv.setIpRangeUuid(vo.getIpRangeUuid());
- inv.setL3NetworkUuid(vo.getL3NetworkUuid());
- inv.setGateway(vo.getGateway());
- inv.setNetmask(vo.getNetmask());
- inv.setUsedFor(vo.getUsedFor());
- inv.setVmNicUuid(vo.getVmNicUuid());
- inv.setMetaData(vo.getMetaData());
- inv.setLastOpDate(vo.getLastOpDate());
- return inv;
+ return new UsedIpInventory(vo);
}
public static List valueOf(Collection vos) {
diff --git a/header/src/main/java/org/zstack/header/network/l3/UsedIpInventoryDoc_zh_cn.groovy b/header/src/main/java/org/zstack/header/network/l3/UsedIpInventoryDoc_zh_cn.groovy
index ce0c456047..a7d5567966 100644
--- a/header/src/main/java/org/zstack/header/network/l3/UsedIpInventoryDoc_zh_cn.groovy
+++ b/header/src/main/java/org/zstack/header/network/l3/UsedIpInventoryDoc_zh_cn.groovy
@@ -61,12 +61,6 @@ doc {
type "long"
since "4.10.0"
}
- field {
- name "ipInBinary"
- desc "二进制存储的IP地址(字节数组,IPv4长度4,IPv6长度16,网络序)"
- type "byte[]"
- since "4.10.16"
- }
field {
name "vmNicUuid"
desc "云主机网卡UUID"
diff --git a/header/src/main/java/org/zstack/header/network/l3/UsedIpTO.java b/header/src/main/java/org/zstack/header/network/l3/UsedIpTO.java
index c42af8f2b0..a222f7da6b 100644
--- a/header/src/main/java/org/zstack/header/network/l3/UsedIpTO.java
+++ b/header/src/main/java/org/zstack/header/network/l3/UsedIpTO.java
@@ -4,10 +4,14 @@
@PythonClass
public class UsedIpTO {
+ public static final String ACTION_CODE_ADD = "add";
+ public static final String ACTION_CODE_REMOVE = "remove";
+
private int ipVersion;
private String ip;
private String netmask;
private String gateway;
+ private String actionCode;
public int getIpVersion() {
return ipVersion;
@@ -41,23 +45,24 @@ public void setGateway(String gateway) {
this.gateway = gateway;
}
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append(String.format("ipVersion: %s,", this.ipVersion));
- sb.append(String.format("ip: %s,", this.ip));
- sb.append(String.format("netmask: %s,", this.netmask));
- sb.append(String.format("gateway: %s,", this.gateway));
+ public String getActionCode() {
+ return actionCode;
+ }
- return sb.toString();
+ public void setActionCode(String actionCode) {
+ this.actionCode = actionCode;
}
- public String toFullString() {
+ @Override
+ public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(String.format("ipVersion: %s,", this.ipVersion));
sb.append(String.format("ip: %s,", this.ip));
sb.append(String.format("netmask: %s,", this.netmask));
sb.append(String.format("gateway: %s,", this.gateway));
+ if (this.actionCode != null) {
+ sb.append(String.format("action: %s,", this.actionCode));
+ }
return sb.toString();
}
diff --git a/header/src/main/java/org/zstack/header/network/l3/UsedIpVO_.java b/header/src/main/java/org/zstack/header/network/l3/UsedIpVO_.java
index 4186a4a6d5..d319037e9b 100755
--- a/header/src/main/java/org/zstack/header/network/l3/UsedIpVO_.java
+++ b/header/src/main/java/org/zstack/header/network/l3/UsedIpVO_.java
@@ -11,6 +11,7 @@ public class UsedIpVO_ {
public static volatile SingularAttribute l3NetworkUuid;
public static volatile SingularAttribute ipVersion;
public static volatile SingularAttribute ip;
+ public static volatile SingularAttribute netmask;
public static volatile SingularAttribute usedFor;
public static volatile SingularAttribute metaData;
public static volatile SingularAttribute ipInLong;
diff --git a/header/src/main/java/org/zstack/header/rest/AbstractAsyncResponseFetcher.java b/header/src/main/java/org/zstack/header/rest/AbstractAsyncResponseFetcher.java
new file mode 100644
index 0000000000..32381dfc12
--- /dev/null
+++ b/header/src/main/java/org/zstack/header/rest/AbstractAsyncResponseFetcher.java
@@ -0,0 +1,106 @@
+package org.zstack.header.rest;
+
+import org.springframework.beans.factory.annotation.Autowire;
+import org.springframework.beans.factory.annotation.Configurable;
+import org.zstack.header.core.ReturnValueCompletion;
+import org.zstack.header.errorcode.ErrorCode;
+import org.zstack.header.errorcode.ErrorableValue;
+import org.zstack.utils.gson.JSONObjectUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+@Configurable(preConstruction = true, autowire = Autowire.BY_TYPE)
+public abstract class AbstractAsyncResponseFetcher {
+ public final Class returnType;
+ protected Supplier> restHttpFactory;
+ protected List>> restHttpDecorators = new ArrayList<>();
+
+ protected Function resultsBuilder;
+ protected Predicate donePredicate;
+
+ protected long eachAttemptTimeoutInMillis = 3000L;
+ protected long eachAttemptIntervalInMillis = 1000L;
+ protected long allAttemptsTimeoutInMillis = 60000L;
+
+ {
+ restHttpDecorators.add(http -> http.withTimeoutInMillis(eachAttemptTimeoutInMillis));
+ }
+
+ protected static final ErrorCode NOT_FINISHED_YET;
+
+ static {
+ NOT_FINISHED_YET = new ErrorCode();
+ NOT_FINISHED_YET.setCode("AsyncResponseFetcher.NOT_FINISHED_YET");
+ NOT_FINISHED_YET.setDetails("Not finished yet");
+ }
+
+ protected AbstractAsyncResponseFetcher(Class returnType) {
+ this.returnType = returnType;
+ this.resultsBuilder = v -> JSONObjectUtil.toObject(v, this.returnType);
+ }
+
+ public AbstractAsyncResponseFetcher withRestHttpFactory(Supplier> restHttpFactory) {
+ this.restHttpFactory = restHttpFactory;
+ return this;
+ }
+
+ public AbstractAsyncResponseFetcher withRestHttpDecorator(Consumer> restHttpDecorator) {
+ this.restHttpDecorators.add(restHttpDecorator);
+ return this;
+ }
+
+ public AbstractAsyncResponseFetcher withResultsBuilder(Function resultsBuilder) {
+ this.resultsBuilder = resultsBuilder;
+ return this;
+ }
+
+ public AbstractAsyncResponseFetcher withDonePredicate(Predicate donePredicate) {
+ this.donePredicate = donePredicate;
+ return this;
+ }
+
+ public AbstractAsyncResponseFetcher withEachAttemptTimeoutInMillis(long eachAttemptTimeoutInMillis) {
+ this.eachAttemptTimeoutInMillis = eachAttemptTimeoutInMillis;
+ return this;
+ }
+
+ public AbstractAsyncResponseFetcher withEachAttemptIntervalInMillis(long eachAttemptIntervalInMillis) {
+ this.eachAttemptIntervalInMillis = eachAttemptIntervalInMillis;
+ return this;
+ }
+
+ public AbstractAsyncResponseFetcher withAllAttemptsTimeoutInMillis(long allAttemptsTimeoutInMillis) {
+ this.allAttemptsTimeoutInMillis = allAttemptsTimeoutInMillis;
+ return this;
+ }
+
+ protected RestHttp http() {
+ return restHttpFactory.get();
+ }
+
+ public abstract void fetch(ReturnValueCompletion completion);
+
+ protected ErrorableValue eachAttempt() {
+ final RestHttp http = http();
+ for (Consumer> restHttpDecorator : restHttpDecorators) {
+ restHttpDecorator.accept(http);
+ }
+
+ ErrorableValue value = http.getWithErrorCode();
+ if (!value.isSuccess()) {
+ return value.cast();
+ }
+
+ T result = resultsBuilder.apply(value.result);
+ if (donePredicate != null && !donePredicate.test(result)) {
+ return ErrorableValue.ofErrorCode(NOT_FINISHED_YET);
+ }
+
+ return ErrorableValue.of(result);
+ }
+}
diff --git a/header/src/main/java/org/zstack/header/rest/AsyncHttpCallHandler.java b/header/src/main/java/org/zstack/header/rest/AsyncHttpCallHandler.java
deleted file mode 100755
index b755cbbb9e..0000000000
--- a/header/src/main/java/org/zstack/header/rest/AsyncHttpCallHandler.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package org.zstack.header.rest;
-
-import org.zstack.header.core.ReturnValueCompletion;
-
-/**
- * Created by frank on 11/1/2015.
- */
-public interface AsyncHttpCallHandler extends HttpCallHandler {
- void handleAsyncHttpCall(T object, ReturnValueCompletion completion);
-}
diff --git a/header/src/main/java/org/zstack/header/storage/addon/primary/PrimaryStorageControllerSvc.java b/header/src/main/java/org/zstack/header/storage/addon/primary/PrimaryStorageControllerSvc.java
index 14d7d47eb1..5d6896960c 100644
--- a/header/src/main/java/org/zstack/header/storage/addon/primary/PrimaryStorageControllerSvc.java
+++ b/header/src/main/java/org/zstack/header/storage/addon/primary/PrimaryStorageControllerSvc.java
@@ -52,4 +52,6 @@ public interface PrimaryStorageControllerSvc {
void setTrashExpireTime(int timeInSeconds, Completion completion);
void onFirstAdditionConfigure(Completion completion);
+
+ long alignSize(long size);
}
diff --git a/header/src/main/java/org/zstack/header/storage/primary/AfterCreateImageCacheExtensionPoint.java b/header/src/main/java/org/zstack/header/storage/primary/AfterCreateImageCacheExtensionPoint.java
index 0e0d36615c..516be2ac0d 100644
--- a/header/src/main/java/org/zstack/header/storage/primary/AfterCreateImageCacheExtensionPoint.java
+++ b/header/src/main/java/org/zstack/header/storage/primary/AfterCreateImageCacheExtensionPoint.java
@@ -8,7 +8,7 @@
* @Date: 2021/11/16
*/
public interface AfterCreateImageCacheExtensionPoint {
- void saveEncryptAfterCreateImageCache(String hostUuid, ImageCacheInventory inventory);
+ void saveEncryptAfterCreateImageCache(String hostUuid, ImageCacheInventory inventory, Completion completion);
void checkEncryptImageCache(String hostUuid, ImageCacheInventory inventory, Completion completion);
}
diff --git a/header/src/main/java/org/zstack/header/storage/primary/AllocatePrimaryStorageMsg.java b/header/src/main/java/org/zstack/header/storage/primary/AllocatePrimaryStorageMsg.java
index 5126ffa288..e4c3b3e559 100755
--- a/header/src/main/java/org/zstack/header/storage/primary/AllocatePrimaryStorageMsg.java
+++ b/header/src/main/java/org/zstack/header/storage/primary/AllocatePrimaryStorageMsg.java
@@ -3,6 +3,7 @@
import org.zstack.header.message.NeedReplyMessage;
import org.zstack.utils.CollectionDSL;
+import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -30,6 +31,7 @@ public class AllocatePrimaryStorageMsg extends NeedReplyMessage {
private List tags;
private String allocationStrategy;
private String vmInstanceUuid;
+ @Nullable
private String diskOfferingUuid;
private List excludePrimaryStorageUuids;
private List excludeAllocatorStrategies;
diff --git a/header/src/main/java/org/zstack/header/tag/TagConstant.java b/header/src/main/java/org/zstack/header/tag/TagConstant.java
index 6aa7ded2a5..4d79ab91da 100755
--- a/header/src/main/java/org/zstack/header/tag/TagConstant.java
+++ b/header/src/main/java/org/zstack/header/tag/TagConstant.java
@@ -13,8 +13,4 @@ public interface TagConstant {
String RESOURCE_CONFIG_CATEGORY_TOKEN = "category";
String RESOURCE_CONFIG_NAME_TOKEN = "name";
String RESOURCE_CONFIG_VALUE_TOKEN = "value";
-
- static boolean isEphemeralTag(String tag) {
- return tag.startsWith(String.format("%s::", EPHEMERAL_TAG_PREFIX));
- }
}
diff --git a/header/src/main/java/org/zstack/header/vm/CreateVmInstanceMessage.java b/header/src/main/java/org/zstack/header/vm/CreateVmInstanceMessage.java
index 7983863494..ac59948d8b 100644
--- a/header/src/main/java/org/zstack/header/vm/CreateVmInstanceMessage.java
+++ b/header/src/main/java/org/zstack/header/vm/CreateVmInstanceMessage.java
@@ -30,17 +30,15 @@ public interface CreateVmInstanceMessage {
String getType();
default String getRootDiskOfferingUuid() {
- final DiskAO bootDisk = findBootDisk();
+ final DiskAO bootDisk = getRootDisk();
return bootDisk == null ? null : bootDisk.getDiskOfferingUuid();
}
default long getRootDiskSize() {
- final DiskAO bootDisk = findBootDisk();
+ final DiskAO bootDisk = getRootDisk();
return bootDisk == null ? 0 : bootDisk.getSize();
}
- List getDataDiskOfferingUuids();
-
String getZoneUuid();
String getClusterUuid();
@@ -57,9 +55,7 @@ default long getRootDiskSize() {
String getStrategy(); // VmCreationStrategy
- List getDiskAOs();
+ DiskAO getRootDisk();
- default DiskAO findBootDisk() {
- return isEmpty(getDiskAOs()) ? null : findOneOrNull(getDiskAOs(),DiskAO::isBoot);
- }
+ List getDataDisks();
}
diff --git a/header/src/main/java/org/zstack/header/vm/CreateVmInstanceMsg.java b/header/src/main/java/org/zstack/header/vm/CreateVmInstanceMsg.java
index 08640f5131..037d9f8b32 100755
--- a/header/src/main/java/org/zstack/header/vm/CreateVmInstanceMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/CreateVmInstanceMsg.java
@@ -1,5 +1,6 @@
package org.zstack.header.vm;
+import org.zstack.header.configuration.VmCustomSpecificationStruct;
import org.zstack.header.message.NeedReplyMessage;
import java.util.ArrayList;
@@ -20,8 +21,6 @@ public class CreateVmInstanceMsg extends NeedReplyMessage implements CreateVmIns
private long reservedMemorySize;
private List l3NetworkSpecs;
private String type;
- private List dataDiskSizes;
- private List dataDiskOfferingUuids;
private List dataVolumeTemplateUuids;
private Map> dataVolumeFromTemplateSystemTags;
private String zoneUuid;
@@ -38,12 +37,14 @@ public class CreateVmInstanceMsg extends NeedReplyMessage implements CreateVmIns
private Boolean virtio;
private List rootVolumeSystemTags;
private List dataVolumeSystemTags;
- private Map> dataVolumeSystemTagsOnIndex;
private List disableL3Networks;
private List sshKeyPairUuids;
private final List candidatePrimaryStorageUuidsForRootVolume = new ArrayList<>();
private final List candidatePrimaryStorageUuidsForDataVolume = new ArrayList<>();
- private List diskAOs;
+ private DiskAO rootDisk = DiskAO.rootDisk();
+ private List dataDisks;
+ private List deprecatedDataVolumeSpecs = new ArrayList<>();
+ private VmCustomSpecificationStruct vmCustomSpecification;
public List getCandidatePrimaryStorageUuidsForRootVolume() {
return candidatePrimaryStorageUuidsForRootVolume;
@@ -75,12 +76,28 @@ public void setGuestOsType(String guestOsType) {
this.guestOsType = guestOsType;
}
- public List getDiskAOs() {
- return diskAOs;
+ public DiskAO getRootDisk() {
+ return rootDisk;
}
- public void setDiskAOs(List diskAOs) {
- this.diskAOs = diskAOs;
+ public void setRootDisk(DiskAO rootDisk) {
+ this.rootDisk = rootDisk;
+ }
+
+ public List getDataDisks() {
+ return dataDisks;
+ }
+
+ public void setDataDisks(List dataDisks) {
+ this.dataDisks = dataDisks;
+ }
+
+ public List getDeprecatedDataVolumeSpecs() {
+ return deprecatedDataVolumeSpecs;
+ }
+
+ public void setDeprecatedDataVolumeSpecs(List deprecatedDataVolumeSpecs) {
+ this.deprecatedDataVolumeSpecs = deprecatedDataVolumeSpecs;
}
public List getRootVolumeSystemTags() {
@@ -161,23 +178,6 @@ public void setZoneUuid(String zoneUuid) {
this.zoneUuid = zoneUuid;
}
- @Override
- public List getDataDiskOfferingUuids() {
- return dataDiskOfferingUuids;
- }
-
- public void setDataDiskOfferingUuids(List dataDiskOfferingUuids) {
- this.dataDiskOfferingUuids = dataDiskOfferingUuids;
- }
-
- public List getDataDiskSizes() {
- return dataDiskSizes;
- }
-
- public void setDataDiskSizes(List dataDiskSizes) {
- this.dataDiskSizes = dataDiskSizes;
- }
-
@Override
public String getType() {
return type;
@@ -316,14 +316,6 @@ public void setDataVolumeFromTemplateSystemTags(Map> dataVo
this.dataVolumeFromTemplateSystemTags = dataVolumeFromTemplateSystemTags;
}
- public Map> getDataVolumeSystemTagsOnIndex() {
- return dataVolumeSystemTagsOnIndex;
- }
-
- public void setDataVolumeSystemTagsOnIndex(Map> dataVolumeSystemTagsOnIndex) {
- this.dataVolumeSystemTagsOnIndex = dataVolumeSystemTagsOnIndex;
- }
-
public List getDisableL3Networks() {
return disableL3Networks;
}
@@ -363,4 +355,12 @@ public Boolean getVirtio() {
public void setVirtio(Boolean virtio) {
this.virtio = virtio;
}
+
+ public VmCustomSpecificationStruct getVmCustomSpecification() {
+ return vmCustomSpecification;
+ }
+
+ public void setVmCustomSpecification(VmCustomSpecificationStruct vmCustomSpecification) {
+ this.vmCustomSpecification = vmCustomSpecification;
+ }
}
diff --git a/header/src/main/java/org/zstack/header/vm/InstantiateNewCreatedVmInstanceMsg.java b/header/src/main/java/org/zstack/header/vm/InstantiateNewCreatedVmInstanceMsg.java
index ee5bdd701b..55a5747400 100755
--- a/header/src/main/java/org/zstack/header/vm/InstantiateNewCreatedVmInstanceMsg.java
+++ b/header/src/main/java/org/zstack/header/vm/InstantiateNewCreatedVmInstanceMsg.java
@@ -1,5 +1,6 @@
package org.zstack.header.vm;
+import org.zstack.header.configuration.VmCustomSpecificationStruct;
import org.zstack.header.host.CpuArchitecture;
import org.zstack.header.message.NeedReplyMessage;
@@ -10,7 +11,6 @@
public class InstantiateNewCreatedVmInstanceMsg extends NeedReplyMessage implements VmInstanceMessage {
private VmInstanceInventory vmInstanceInventory;
private List l3NetworkUuids;
- private List dataDiskOfferingUuids;
private List dataVolumeTemplateUuids;
private Map> dataVolumeFromTemplateSystemTags;
private String rootDiskOfferingUuid;
@@ -21,10 +21,18 @@ public class InstantiateNewCreatedVmInstanceMsg extends NeedReplyMessage impleme
private List dataVolumeSystemTags;
private List softAvoidHostUuids;
private List avoidHostUuids;
- private Map> dataVolumeSystemTagsOnIndex;
private List disableL3Networks;
private final List candidatePrimaryStorageUuidsForRootVolume = new ArrayList<>();
private final List candidatePrimaryStorageUuidsForDataVolume = new ArrayList<>();
+ private VmCustomSpecificationStruct vmCustomSpecification;
+
+ public VmCustomSpecificationStruct getVmCustomSpecification() {
+ return vmCustomSpecification;
+ }
+
+ public void setVmCustomSpecification(VmCustomSpecificationStruct vmCustomSpecification) {
+ this.vmCustomSpecification = vmCustomSpecification;
+ }
public List getCandidatePrimaryStorageUuidsForRootVolume() {
return candidatePrimaryStorageUuidsForRootVolume;
@@ -48,14 +56,32 @@ public void setCandidatePrimaryStorageUuidsForDataVolume(List candidateP
}
}
- private List diskAOs;
+ private DiskAO rootDisk;
+ private List dataDisks;
+ private List deprecatedDataVolumeSpecs;
+
+ public DiskAO getRootDisk() {
+ return rootDisk;
+ }
+
+ public void setRootDisk(DiskAO rootDisk) {
+ this.rootDisk = rootDisk;
+ }
+
+ public List getDataDisks() {
+ return dataDisks;
+ }
+
+ public void setDataDisks(List dataDisks) {
+ this.dataDisks = dataDisks;
+ }
- public List getDiskAOs() {
- return diskAOs;
+ public List getDeprecatedDataVolumeSpecs() {
+ return deprecatedDataVolumeSpecs;
}
- public void setDiskAOs(List diskAOs) {
- this.diskAOs = diskAOs;
+ public void setDeprecatedDataVolumeSpecs(List deprecatedDataVolumeSpecs) {
+ this.deprecatedDataVolumeSpecs = deprecatedDataVolumeSpecs;
}
public List getSoftAvoidHostUuids() {
@@ -82,14 +108,6 @@ public void setL3NetworkUuids(List l3NetworkUuids) {
this.l3NetworkUuids = l3NetworkUuids;
}
- public List getDataDiskOfferingUuids() {
- return dataDiskOfferingUuids;
- }
-
- public void setDataDiskOfferingUuids(List dataDiskOfferingUuids) {
- this.dataDiskOfferingUuids = dataDiskOfferingUuids;
- }
-
public List getDataVolumeTemplateUuids() {
return dataVolumeTemplateUuids;
}
@@ -191,14 +209,6 @@ public void setDataVolumeFromTemplateSystemTags(Map> dataVo
this.dataVolumeFromTemplateSystemTags = dataVolumeFromTemplateSystemTags;
}
- public Map> getDataVolumeSystemTagsOnIndex() {
- return dataVolumeSystemTagsOnIndex;
- }
-
- public void setDataVolumeSystemTagsOnIndex(Map> dataVolumeSystemTagsOnIndex) {
- this.dataVolumeSystemTagsOnIndex = dataVolumeSystemTagsOnIndex;
- }
-
public List getDisableL3Networks() {
return disableL3Networks;
}
diff --git a/header/src/main/java/org/zstack/header/vm/VmErrors.java b/header/src/main/java/org/zstack/header/vm/VmErrors.java
index 5881e524b3..2cbe362a9a 100755
--- a/header/src/main/java/org/zstack/header/vm/VmErrors.java
+++ b/header/src/main/java/org/zstack/header/vm/VmErrors.java
@@ -20,8 +20,13 @@ public enum VmErrors {
RE_IMAGE_VM_NOT_IN_STOPPED_STATE(1014),
RE_IMAGE_IMAGE_MEDIA_TYPE_SHOULD_NOT_BE_ISO(1015),
RE_IMAGE_CANNOT_FIND_IMAGE_CACHE(1016),
- VNC_SETTING_ERROR(1017);
+ VNC_SETTING_ERROR(1017),
+ // Errors in VM allocation
+ VM_ALLOCATION_ERROR(1200),
+ WRONG_SPECIFIC_HOST_ERROR(1201),
+ WRONG_SPECIFIC_PS_ERROR(1202),
+ ;
private String code;
diff --git a/header/src/main/java/org/zstack/header/vm/VmInstanceConstant.java b/header/src/main/java/org/zstack/header/vm/VmInstanceConstant.java
index 94276d073c..9d0efdd77f 100755
--- a/header/src/main/java/org/zstack/header/vm/VmInstanceConstant.java
+++ b/header/src/main/java/org/zstack/header/vm/VmInstanceConstant.java
@@ -80,7 +80,7 @@ enum VmOperation {
SetVmQga
}
- String USER_VM_REGEX_PASSWORD = "[\\da-zA-Z-`=\\\\\\[\\];',./~!@#$%^&*()_+|{}:\"<>?]{1,}";
+ String USER_VM_REGEX_PASSWORD = "[\\da-zA-Z-`=\\\\\\[\\];',./~!@#$%^&*()_+|{}:\"<>?]{0,}";
enum Capability {
LiveMigration,
diff --git a/header/src/main/java/org/zstack/header/vm/VmInstanceSpec.java b/header/src/main/java/org/zstack/header/vm/VmInstanceSpec.java
index 24588eb4ed..4732fb36d4 100755
--- a/header/src/main/java/org/zstack/header/vm/VmInstanceSpec.java
+++ b/header/src/main/java/org/zstack/header/vm/VmInstanceSpec.java
@@ -4,6 +4,7 @@
import org.zstack.header.allocator.AllocationScene;
import org.zstack.header.cluster.ClusterVO;
import org.zstack.header.configuration.DiskOfferingInventory;
+import org.zstack.header.configuration.VmCustomSpecificationStruct;
import org.zstack.header.host.CpuArchitecture;
import org.zstack.header.host.HostInventory;
import org.zstack.header.host.HostVO;
@@ -124,6 +125,10 @@ public void setTags(List tags) {
public boolean isRoot() {
return VolumeType.Root.toString().equals(type);
}
+
+ public boolean isData() {
+ return VolumeType.Data.toString().equals(type);
+ }
}
public static class ImageSpec implements Serializable {
@@ -318,7 +323,6 @@ public void setHostname(String hostname) {
private VmInstanceInventory vmInventory;
private List l3Networks = new ArrayList<>();
- private List dataDiskOfferings;
private List dataVolumeTemplateUuids;
private Map> dataVolumeFromTemplateSystemTags = new HashMap<>();
private DiskOfferingInventory rootDiskOffering;
@@ -332,7 +336,6 @@ public void setHostname(String hostname) {
private String requiredClusterUuid;
private String requiredHostUuid;
private String memorySnapshotUuid;
- private String allocatedPrimaryStorageUuidForRootVolume;
private String allocatedPrimaryStorageUuidForDataVolume;
private final List candidatePrimaryStorageUuidsForRootVolume = new ArrayList<>();
private final List candidatePrimaryStorageUuidsForDataVolume = new ArrayList<>();
@@ -370,7 +373,6 @@ public void setHostname(String hostname) {
private List rootVolumeSystemTags;
private List dataVolumeSystemTags;
- private Map> dataVolumeSystemTagsOnIndex;
private boolean skipIpAllocation = false;
private VmCreationStrategy strategy;
@@ -397,14 +399,41 @@ public void setCandidatePrimaryStorageUuidsForDataVolume(List candidateP
}
private List disableL3Networks;
- private List diskAOs;
+ private DiskAO rootDisk = DiskAO.rootDisk();
+ private List dataDisks;
+ private List deprecatedDisksSpecs = new ArrayList<>();
+ private VmCustomSpecificationStruct vmCustomSpecification;
+
+ public DiskAO getRootDisk() {
+ return rootDisk;
+ }
+
+ public void setRootDisk(DiskAO rootDisk) {
+ this.rootDisk = rootDisk;
+ }
+
+ public List getDataDisks() {
+ return dataDisks;
+ }
- public List getDiskAOs() {
- return diskAOs;
+ public void setDataDisks(List dataDisks) {
+ this.dataDisks = dataDisks;
}
- public void setDiskAOs(List diskAOs) {
- this.diskAOs = diskAOs;
+ public List getDeprecatedDisksSpecs() {
+ return deprecatedDisksSpecs;
+ }
+
+ public void setDeprecatedDisksSpecs(List deprecatedDisksSpecs) {
+ this.deprecatedDisksSpecs = deprecatedDisksSpecs;
+ }
+
+ public VmCustomSpecificationStruct getVmCustomSpecification() {
+ return vmCustomSpecification;
+ }
+
+ public void setVmCustomSpecification(VmCustomSpecificationStruct vmCustomSpecification) {
+ this.vmCustomSpecification = vmCustomSpecification;
}
public boolean isSkipIpAllocation() {
@@ -609,17 +638,6 @@ public void setL3Networks(List l3Networks) {
this.l3Networks = l3Networks;
}
- public List getDataDiskOfferings() {
- if (dataDiskOfferings == null) {
- dataDiskOfferings = new ArrayList<>(0);
- }
- return dataDiskOfferings;
- }
-
- public void setDataDiskOfferings(List dataDiskOfferings) {
- this.dataDiskOfferings = dataDiskOfferings;
- }
-
public DiskOfferingInventory getRootDiskOffering() {
return rootDiskOffering;
}
@@ -757,11 +775,6 @@ public List getRequiredNetworkServiceTypes() {
return nsTypes;
}
- @Deprecated
- public String getRequiredPrimaryStorageUuidForRootVolume() {
- return this.candidatePrimaryStorageUuidsForRootVolume.isEmpty() ? null : this.candidatePrimaryStorageUuidsForRootVolume.get(0);
- }
-
public void setRequiredPrimaryStorageUuidForRootVolume(String primaryStorageUuidForRootVolume) {
this.candidatePrimaryStorageUuidsForRootVolume.clear();
if (primaryStorageUuidForRootVolume != null) {
@@ -813,14 +826,6 @@ public void setDataVolumeSystemTags(List dataVolumeSystemTags) {
this.dataVolumeSystemTags = dataVolumeSystemTags;
}
- public Map