This is an automated email from the ASF dual-hosted git repository.
rohit pushed a commit to branch 4.20
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/4.20 by this push:
new c5afee21018 UI improvements (#9773)
c5afee21018 is described below
commit c5afee210181db2335f059267c7a2b74f91002d4
Author: Abhisar Sinha <[email protected]>
AuthorDate: Thu Feb 6 11:18:40 2025 +0530
UI improvements (#9773)
* Show Usage Server configuration in a separate pane
* UI: Option to attach volume to an instance during create volume
* Show service ip in management server details tab
* change Schedule Snapshots to Recurring Snapshots
* Change the hypervisor order so that kvm, vmware, xenserver show up first
* Remove extra space in hypervisor names in config.java
* Fix `updateTemplatePermission` when the UI is set to a language other
than English (#9766)
* Fix updateTemplatePermission UI in non-english language
* Improve fix
---------
Co-authored-by: Lucas Martins <[email protected]>
* Autofill vcenter details in add cluster form
* UI: condition to display create vm-vol-snapshots to same as create
vol-snapshots
* Fix alignment on wrapping in global settings tabs
* rename Autofill vCenter credentials to Autofill vCenter credentials from
Zone
* Rename Service Ip to Ip Address in management server response
* Change description of kvm.snapshot.enabled to say that it applies to
volume snapshots
* Return error when kvm vm snapshot is taken withoutsnapshot memory
* Minor naming changes and grammar
* Fix tooltip for attach volume to instance button
* Show Usage Server configuration in a separate pane
* UI: Option to attach volume to an instance during create volume
* Show service ip in management server details tab
* change Schedule Snapshots to Recurring Snapshots
* Change the hypervisor order so that kvm, vmware, xenserver show up first
* Remove extra space in hypervisor names in config.java
* Autofill vcenter details in add cluster form
* UI: condition to display create vm-vol-snapshots to same as create
vol-snapshots
* Fix alignment on wrapping in global settings tabs
* rename Autofill vCenter credentials to Autofill vCenter credentials from
Zone
* Rename Service Ip to Ip Address in management server response
* Change description of kvm.snapshot.enabled to say that it applies to
volume snapshots
* Return error when kvm vm snapshot is taken withoutsnapshot memory
* Minor naming changes and grammar
* Fix tooltip for attach volume to instance button
* Show Usage Server configuration in a separate pane
* UI: Option to attach volume to an instance during create volume
* Show service ip in management server details tab
* change Schedule Snapshots to Recurring Snapshots
* Change the hypervisor order so that kvm, vmware, xenserver show up first
* Remove extra space in hypervisor names in config.java
* Autofill vcenter details in add cluster form
* UI: condition to display create vm-vol-snapshots to same as create
vol-snapshots
* Fix alignment on wrapping in global settings tabs
* rename Autofill vCenter credentials to Autofill vCenter credentials from
Zone
* Rename Service Ip to Ip Address in management server response
* Change description of kvm.snapshot.enabled to say that it applies to
volume snapshots
* Return error when kvm vm snapshot is taken withoutsnapshot memory
* Minor naming changes and grammar
* Fix tooltip for attach volume to instance button
* UI: Option to attach volume to an instance during create volume
* UI: condition to display create vm-vol-snapshots to same as create
vol-snapshots
* moved db changes from 41900to42000 to 42000to42010
* Update group_id in already present usage configuration settings
* remove "schedule" from message in create Recurring Snapshots form
* Update
server/src/main/java/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java
---------
Co-authored-by: Daan Hoogland <[email protected]>
Co-authored-by: Lucas Martins
<[email protected]>
Co-authored-by: Lucas Martins <[email protected]>
Co-authored-by: Boris Stoyanov - a.k.a Bobby <[email protected]>
Co-authored-by: Andrija Panic
<[email protected]>
---
.../org/apache/cloudstack/api/ApiConstants.java | 1 -
.../api/response/ManagementServerResponse.java | 12 +--
.../resources/META-INF/db/schema-42000to42010.sql | 8 ++
.../java/com/cloud/api/query/QueryManagerImpl.java | 2 +-
.../main/java/com/cloud/configuration/Config.java | 6 +-
.../cloud/network/vpn/Site2SiteVpnManagerImpl.java | 4 +-
.../cloud/vm/snapshot/VMSnapshotManagerImpl.java | 10 ++-
ui/public/locales/de_DE.json | 1 -
ui/public/locales/el_GR.json | 1 -
ui/public/locales/en.json | 6 +-
ui/public/locales/ja_JP.json | 1 -
ui/public/locales/ko_KR.json | 1 -
ui/public/locales/pt_BR.json | 1 -
ui/public/locales/zh_CN.json | 1 -
ui/src/config/section/compute.js | 7 +-
ui/src/config/section/infra/managementServers.js | 4 +-
ui/src/config/section/storage.js | 14 +--
ui/src/views/infra/ClusterAdd.vue | 100 +++++++++++++--------
ui/src/views/setting/ConfigurationHierarchy.vue | 9 +-
ui/src/views/storage/CreateVolume.vue | 100 ++++++++++++++++++++-
ui/src/views/storage/RecurringSnapshotVolume.vue | 2 +-
21 files changed, 213 insertions(+), 78 deletions(-)
diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
index cf03f1d2699..efbf9d9d78e 100644
--- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
@@ -447,7 +447,6 @@ public class ApiConstants {
public static final String SENT = "sent";
public static final String SENT_BYTES = "sentbytes";
public static final String SERIAL = "serial";
- public static final String SERVICE_IP = "serviceip";
public static final String SERVICE_OFFERING_ID = "serviceofferingid";
public static final String SESSIONKEY = "sessionkey";
public static final String SHOW_CAPACITIES = "showcapacities";
diff --git
a/api/src/main/java/org/apache/cloudstack/api/response/ManagementServerResponse.java
b/api/src/main/java/org/apache/cloudstack/api/response/ManagementServerResponse.java
index fc7d3b722ab..4165ea25778 100644
---
a/api/src/main/java/org/apache/cloudstack/api/response/ManagementServerResponse.java
+++
b/api/src/main/java/org/apache/cloudstack/api/response/ManagementServerResponse.java
@@ -74,9 +74,9 @@ public class ManagementServerResponse extends BaseResponse {
@Param(description = "the running OS kernel version for this Management
Server")
private String kernelVersion;
- @SerializedName(ApiConstants.SERVICE_IP)
+ @SerializedName(ApiConstants.IP_ADDRESS)
@Param(description = "the IP Address for this Management Server")
- private String serviceIp;
+ private String ipAddress;
@SerializedName(ApiConstants.PEERS)
@Param(description = "the Management Server Peers")
@@ -122,8 +122,8 @@ public class ManagementServerResponse extends BaseResponse {
return lastBoot;
}
- public String getServiceIp() {
- return serviceIp;
+ public String getIpAddress() {
+ return ipAddress;
}
public void setId(String id) {
@@ -170,8 +170,8 @@ public class ManagementServerResponse extends BaseResponse {
this.kernelVersion = kernelVersion;
}
- public void setServiceIp(String serviceIp) {
- this.serviceIp = serviceIp;
+ public void setIpAddress(String ipAddress) {
+ this.ipAddress = ipAddress;
}
public String getKernelVersion() {
diff --git
a/engine/schema/src/main/resources/META-INF/db/schema-42000to42010.sql
b/engine/schema/src/main/resources/META-INF/db/schema-42000to42010.sql
index 92e0dbb5b2a..bf13e5eee1a 100644
--- a/engine/schema/src/main/resources/META-INF/db/schema-42000to42010.sql
+++ b/engine/schema/src/main/resources/META-INF/db/schema-42000to42010.sql
@@ -24,6 +24,14 @@ CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.user',
'api_key_access', 'boolean DE
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.account', 'api_key_access',
'boolean DEFAULT NULL COMMENT "is api key access allowed for the account" ');
CALL `cloud_usage`.`IDEMPOTENT_ADD_COLUMN`('cloud_usage.account',
'api_key_access', 'boolean DEFAULT NULL COMMENT "is api key access allowed for
the account" ');
+-- Create a new group for Usage Server related configurations
+INSERT INTO `cloud`.`configuration_group` (`name`, `description`,
`precedence`) VALUES ('Usage Server', 'Usage Server related configuration', 9);
+UPDATE `cloud`.`configuration_subgroup` set `group_id` = (SELECT `id` FROM
`cloud`.`configuration_group` WHERE `name` = 'Usage Server'), `precedence` = 1
WHERE `name`='Usage';
+UPDATE `cloud`.`configuration` SET `group_id` = (SELECT `id` FROM
`cloud`.`configuration_group` WHERE `name` = 'Usage Server') where
`subgroup_id` = (SELECT `id` FROM `cloud`.`configuration_subgroup` WHERE `name`
= 'Usage');
+
+-- Update the description to indicate this setting applies only to volume
snapshots on running instances
+UPDATE `cloud`.`configuration` SET `description`='whether volume snapshot is
enabled on running instances on KVM hosts' WHERE `name`='kvm.snapshot.enabled';
+
-- Modify index for mshost_peer
DELETE FROM `cloud`.`mshost_peer`;
CALL
`cloud`.`IDEMPOTENT_DROP_FOREIGN_KEY`('cloud.mshost_peer','fk_mshost_peer__owner_mshost');
diff --git a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java
b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java
index 94a87a0b31c..40249dda17a 100644
--- a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java
+++ b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java
@@ -5413,13 +5413,13 @@ public class QueryManagerImpl extends
MutualExclusiveIdsManagerBase implements Q
mgmtResponse.setLastServerStart(mgmt.getLastJvmStart());
mgmtResponse.setLastServerStop(mgmt.getLastJvmStop());
mgmtResponse.setLastBoot(mgmt.getLastSystemBoot());
- mgmtResponse.setServiceIp(mgmt.getServiceIP());
if (listPeers) {
List<ManagementServerHostPeerJoinVO> peers =
mshostPeerJoinDao.listByOwnerMshostId(mgmt.getId());
for (ManagementServerHostPeerJoinVO peer: peers) {
mgmtResponse.addPeer(createPeerManagementServerNodeResponse(peer));
}
}
+ mgmtResponse.setIpAddress(mgmt.getServiceIP());
mgmtResponse.setObjectName("managementserver");
return mgmtResponse;
}
diff --git a/server/src/main/java/com/cloud/configuration/Config.java
b/server/src/main/java/com/cloud/configuration/Config.java
index b9de906ba46..8093af6afc1 100644
--- a/server/src/main/java/com/cloud/configuration/Config.java
+++ b/server/src/main/java/com/cloud/configuration/Config.java
@@ -506,7 +506,7 @@ public enum Config {
"The time interval in seconds when the management server polls for
snapshots to be scheduled.",
null),
SnapshotDeltaMax("Snapshots", SnapshotManager.class, Integer.class,
"snapshot.delta.max", "16", "max delta snapshots between two full snapshots.",
null),
- KVMSnapshotEnabled("Hidden", SnapshotManager.class, Boolean.class,
"kvm.snapshot.enabled", "false", "whether snapshot is enabled for KVM hosts",
null),
+ KVMSnapshotEnabled("Hidden", SnapshotManager.class, Boolean.class,
"kvm.snapshot.enabled", "false", "Whether volume snapshot is enabled on running
instances on a KVM host", null),
// Advanced
EventPurgeInterval(
@@ -665,8 +665,8 @@ public enum Config {
ManagementServer.class,
String.class,
"hypervisor.list",
- HypervisorType.Hyperv + "," + HypervisorType.KVM + "," +
HypervisorType.XenServer + "," + HypervisorType.VMware + "," +
HypervisorType.BareMetal + "," +
- HypervisorType.Ovm + "," + HypervisorType.LXC + "," +
HypervisorType.Ovm3,
+ HypervisorType.KVM + "," + HypervisorType.VMware + "," +
HypervisorType.XenServer + "," + HypervisorType.Hyperv + "," +
+ HypervisorType.BareMetal + "," + HypervisorType.Ovm + ","
+ HypervisorType.LXC + "," + HypervisorType.Ovm3,
"The list of hypervisors that this deployment will use.",
"hypervisorList",
ConfigKey.Kind.CSV,
diff --git
a/server/src/main/java/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java
b/server/src/main/java/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java
index ed83e396abf..8be97644bf5 100644
--- a/server/src/main/java/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java
@@ -343,7 +343,7 @@ public class Site2SiteVpnManagerImpl extends ManagerBase
implements Site2SiteVpn
private void validatePrerequisiteVpnGateway(Site2SiteVpnGateway
vpnGateway) {
// check if gateway has been defined on the VPC
if (_vpnGatewayDao.findByVpcId(vpnGateway.getVpcId()) == null) {
- throw new InvalidParameterValueException("we can not create a VPN
connection for a VPC that does not have a VPN gateway defined");
+ throw new InvalidParameterValueException("We can not create a VPN
connection for a VPC that does not have a VPN gateway defined");
}
}
@@ -590,7 +590,7 @@ public class Site2SiteVpnManagerImpl extends ManagerBase
implements Site2SiteVpn
private void stopVpnConnection(Long id) throws
ResourceUnavailableException {
Site2SiteVpnConnectionVO conn =
_vpnConnectionDao.acquireInLockTable(id);
if (conn == null) {
- throw new CloudRuntimeException("Unable to acquire lock for
stopping of VPN connection with ID " + id);
+ throw new CloudRuntimeException("Unable to acquire lock for
stopping VPN connection with ID " + id);
}
try {
if (conn.getState() == State.Pending) {
diff --git
a/server/src/main/java/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java
b/server/src/main/java/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java
index 8d43875190f..907182edc2a 100644
--- a/server/src/main/java/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java
+++ b/server/src/main/java/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java
@@ -27,6 +27,7 @@ import java.util.Map;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
+import com.cloud.storage.snapshot.SnapshotManager;
import org.apache.cloudstack.annotation.AnnotationService;
import org.apache.cloudstack.annotation.dao.AnnotationDao;
import org.apache.cloudstack.api.ApiConstants;
@@ -377,9 +378,14 @@ public class VMSnapshotManagerImpl extends
MutualExclusiveIdsManagerBase impleme
//StorageVMSnapshotStrategy - allows volume snapshots without
memory; VM has to be in Running state; No limitation of the image format if the
storage plugin supports volume snapshots; "kvm.vmstoragesnapshot.enabled" has
to be enabled
//Other Storage volume plugins could integrate this with their own
functionality for group snapshots
VMSnapshotStrategy snapshotStrategy =
storageStrategyFactory.getVmSnapshotStrategy(userVmVo.getId(),
rootVolumePool.getId(), snapshotMemory);
-
if (snapshotStrategy == null) {
- String message = "KVM does not support the type of snapshot
requested";
+ String message;
+ if (!SnapshotManager.VmStorageSnapshotKvm.value() &&
!snapshotMemory) {
+ message = "Creating a snapshot of a running KVM instance
without memory is not supported";
+ } else {
+ message = "KVM does not support the type of snapshot
requested";
+ }
+
logger.debug(message);
throw new CloudRuntimeException(message);
}
diff --git a/ui/public/locales/de_DE.json b/ui/public/locales/de_DE.json
index d9adc43469e..abf471ae17d 100644
--- a/ui/public/locales/de_DE.json
+++ b/ui/public/locales/de_DE.json
@@ -1265,7 +1265,6 @@
"label.save.new.rule": "Neue Regel Speichern",
"label.schedule": "Zeitplan",
"label.scheduled.backups": "geplante Backups",
-"label.scheduled.snapshots": "geplante Schnappschüsse",
"label.scope": "Geltungsbereich",
"label.search": "Suche",
"label.secondary.isolated.vlan.type.isolated": "Isoliert",
diff --git a/ui/public/locales/el_GR.json b/ui/public/locales/el_GR.json
index 754cde89542..7b7f4b29e12 100644
--- a/ui/public/locales/el_GR.json
+++ b/ui/public/locales/el_GR.json
@@ -1517,7 +1517,6 @@
"label.scale.vm": "Κλίμακα εικονικής μηχανής",
"label.schedule": "Πρόγραμμα",
"label.scheduled.backups": "Προγραμματισμένα αντίγραφα ασφαλείας",
-"label.scheduled.snapshots": "Προγραμματισμένα στιγμιότυπα",
"label.scope": "Πεδίο εφαρμογής",
"label.search": "Αναζήτηση",
"label.secondary.isolated.vlan.type.isolated": "Απομονωμένες",
diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json
index a2d82d477aa..29c917b5174 100644
--- a/ui/public/locales/en.json
+++ b/ui/public/locales/en.json
@@ -54,6 +54,7 @@
"label.action": "Action",
"label.action.attach.disk": "Attach disk",
"label.action.attach.iso": "Attach ISO",
+"label.action.attach.to.instance": "Attach to Instance",
"label.action.bulk.delete.egress.firewall.rules": "Bulk delete egress firewall
rules",
"label.action.bulk.delete.firewall.rules": "Bulk delete firewall rules",
"label.action.bulk.delete.ip.v6.firewall.rules": "Bulk remove IPv6 firewall
rules",
@@ -399,9 +400,11 @@
"label.associatednetworkid": "Associated Network ID",
"label.associatednetworkname": "Network name",
"label.asyncbackup": "Async backup",
+"label.attach.vol.to.instance": "Attach the created Volume to an existing
Instance",
"label.attaching": "Attaching",
"label.authentication.method": "Authentication Method",
"label.authentication.sshkey": "System SSH Key",
+"label.use.existing.vcenter.credentials.from.zone": "Use existing vCenter
credentials from the Zone",
"label.autoscale": "AutoScale",
"label.autoscalevmgroupname": "AutoScaling Group",
"label.author.email": "Author e-mail",
@@ -1073,7 +1076,7 @@
"label.hastate": "HA state",
"label.headers": "Headers",
"label.header.backup.schedule": "You can set up recurring backup schedules by
selecting from the available options below and applying your policy
preference.",
-"label.header.volume.snapshot": "You can set up recurring Snapshot schedules
by selecting from the available options below and applying your policy
preference.",
+"label.header.volume.snapshot": "You can set up recurring Snapshots by
selecting from the available options below and applying your policy
preference.",
"label.header.volume.take.snapshot": "Please confirm that you want to take a
Snapshot of this volume.",
"label.health.check": "Health check",
"label.heapmemoryused": "Heap-memory used",
@@ -1999,7 +2002,6 @@
"label.schedule": "Schedule",
"label.schedule.add": "Add schedule",
"label.scheduled.backups": "Scheduled backups",
-"label.scheduled.snapshots": "Scheduled Snapshots",
"label.schedules": "Schedules",
"label.scope": "Scope",
"label.scope.tooltip": "Primary Storage Pool Scope",
diff --git a/ui/public/locales/ja_JP.json b/ui/public/locales/ja_JP.json
index f1518286f80..53009781500 100644
--- a/ui/public/locales/ja_JP.json
+++ b/ui/public/locales/ja_JP.json
@@ -1969,7 +1969,6 @@
"label.scaleup.policy": "スケールアップポリシー",
"label.schedule": "スケジュール",
"label.scheduled.backups": "スケジュールされたバックアップ",
- "label.scheduled.snapshots": "スケジュールされたスナップショット",
"label.scope": "スコープ",
"label.search": "検索",
"label.secondary.isolated.vlan.type.isolated": "隔離",
diff --git a/ui/public/locales/ko_KR.json b/ui/public/locales/ko_KR.json
index a34cdea767f..153bfd64cef 100644
--- a/ui/public/locales/ko_KR.json
+++ b/ui/public/locales/ko_KR.json
@@ -1322,7 +1322,6 @@
"label.scale.vm": "VM \ud655\uc7a5",
"label.schedule": "\uc2a4\ucf00\uc904",
"label.scheduled.backups": "\uc608\uc57d\ub41c \ubc31\uc5c5",
-"label.scheduled.snapshots": "\uc608\uc57d\ub41c \uc2a4\ub0c5\uc0f7",
"label.scope": "\ubc94\uc704",
"label.search": "\uac80\uc0c9",
"label.secondary.isolated.vlan.type.isolated": "isolated",
diff --git a/ui/public/locales/pt_BR.json b/ui/public/locales/pt_BR.json
index a9c67baa32d..af4d5209017 100644
--- a/ui/public/locales/pt_BR.json
+++ b/ui/public/locales/pt_BR.json
@@ -1428,7 +1428,6 @@
"label.scale.vm": "Escalar VM",
"label.schedule": "Programar",
"label.scheduled.backups": "Backups programados",
-"label.scheduled.snapshots": "Snapshots programados",
"label.scope": "Escopo",
"label.search": "Pesquisar",
"label.secondary.isolated.vlan.type.isolated": "Isolada",
diff --git a/ui/public/locales/zh_CN.json b/ui/public/locales/zh_CN.json
index 91353d2f81a..5337829b53d 100644
--- a/ui/public/locales/zh_CN.json
+++ b/ui/public/locales/zh_CN.json
@@ -2248,7 +2248,6 @@
"label.schedule": "\u65E5\u7A0B",
"label.scheduled.backups": "\u5B9A\u65F6\u5907\u4EFD",
- "label.scheduled.snapshots": "\u8BA1\u5212\u5FEB\u7167",
"label.scope": "\u8303\u56F4",
"label.search": "\u641C\u7D22",
diff --git a/ui/src/config/section/compute.js b/ui/src/config/section/compute.js
index 5737126d463..5de6d78d263 100644
--- a/ui/src/config/section/compute.js
+++ b/ui/src/config/section/compute.js
@@ -207,9 +207,10 @@ export default {
docHelp:
'adminguide/virtual_machines.html#virtual-machine-snapshots',
dataView: true,
popup: true,
- show: (record) => {
- return ((['Running'].includes(record.state) && record.hypervisor
!== 'LXC') ||
- (['Stopped'].includes(record.state) && !['KVM',
'LXC'].includes(record.hypervisor)))
+ show: (record, store) => {
+ return (record.hypervisor !== 'KVM') ||
+ ['Stopped', 'Destroyed'].includes(record.state) ||
+ store.features.kvmsnapshotenabled
},
disabled: (record) => { return record.hostcontrolstate === 'Offline'
&& record.hypervisor === 'KVM' },
component: shallowRef(defineAsyncComponent(() =>
import('@/views/compute/CreateSnapshotWizard.vue')))
diff --git a/ui/src/config/section/infra/managementServers.js
b/ui/src/config/section/infra/managementServers.js
index a8bf1be1a01..bc7b42d9cf0 100644
--- a/ui/src/config/section/infra/managementServers.js
+++ b/ui/src/config/section/infra/managementServers.js
@@ -26,14 +26,14 @@ export default {
permission: ['listManagementServersMetrics'],
resourceType: 'ManagementServer',
columns: () => {
- const fields = ['name', 'state', 'serviceip', 'version', 'osdistribution',
'agentcount']
+ const fields = ['name', 'state', 'ipaddress', 'version', 'osdistribution',
'agentcount']
const metricsFields = ['collectiontime', 'availableprocessors', 'cpuload',
'heapmemoryused']
if (store.getters.metrics) {
fields.push(...metricsFields)
}
return fields
},
- details: ['collectiontime', 'usageislocal', 'dbislocal', 'lastserverstart',
'lastserverstop', 'lastboottime', 'version', 'loginfo', 'systemtotalcpucycles',
'systemloadaverages', 'systemcycleusage', 'systemmemorytotal',
'systemmemoryfree', 'systemmemoryvirtualsize', 'availableprocessors',
'javadistribution', 'javaversion', 'osdistribution', 'kernelversion',
'agentcount', 'sessions', 'heapmemoryused', 'heapmemorytotal',
'threadsblockedcount', 'threadsdeamoncount', 'threadsnewcount', 'thr [...]
+ details: ['ipaddress', 'collectiontime', 'usageislocal', 'dbislocal',
'lastserverstart', 'lastserverstop', 'lastboottime', 'version', 'loginfo',
'systemtotalcpucycles', 'systemloadaverages', 'systemcycleusage',
'systemmemorytotal', 'systemmemoryfree', 'systemmemoryvirtualsize',
'availableprocessors', 'javadistribution', 'javaversion', 'osdistribution',
'kernelversion', 'agentcount', 'sessions', 'heapmemoryused', 'heapmemorytotal',
'threadsblockedcount', 'threadsdeamoncount', 'threadsne [...]
tabs: [
{
name: 'details',
diff --git a/ui/src/config/section/storage.js b/ui/src/config/section/storage.js
index e0fa72dff8a..3ab890d530a 100644
--- a/ui/src/config/section/storage.js
+++ b/ui/src/config/section/storage.js
@@ -165,9 +165,10 @@ export default {
label: 'label.action.take.snapshot',
dataView: true,
show: (record, store) => {
- return record.state === 'Ready' && (record.hypervisor !== 'KVM' ||
- record.hypervisor === 'KVM' && record.vmstate === 'Running' &&
store.features.kvmsnapshotenabled ||
- record.hypervisor === 'KVM' && record.vmstate !== 'Running')
+ return record.state === 'Ready' &&
+ (record.hypervisor !== 'KVM' ||
+ ['Stopped', 'Destroyed'].includes(record.vmstate) ||
+ store.features.kvmsnapshotenabled)
},
popup: true,
component: shallowRef(defineAsyncComponent(() =>
import('@/views/storage/TakeSnapshot.vue')))
@@ -179,9 +180,10 @@ export default {
label: 'label.action.recurring.snapshot',
dataView: true,
show: (record, store) => {
- return record.state === 'Ready' && (record.hypervisor !== 'KVM' ||
- record.hypervisor === 'KVM' && record.vmstate === 'Running' &&
store.features.kvmsnapshotenabled ||
- record.hypervisor === 'KVM' && record.vmstate !== 'Running')
+ return record.state === 'Ready' &&
+ (record.hypervisor !== 'KVM' ||
+ (['Stopped', 'Destroyed'].includes(record.vmstate)) ||
+ (store.features.kvmsnapshotenabled))
},
popup: true,
component: shallowRef(defineAsyncComponent(() =>
import('@/views/storage/RecurringSnapshotVolume.vue'))),
diff --git a/ui/src/views/infra/ClusterAdd.vue
b/ui/src/views/infra/ClusterAdd.vue
index 924722d59bb..e4f5d67a3aa 100644
--- a/ui/src/views/infra/ClusterAdd.vue
+++ b/ui/src/views/infra/ClusterAdd.vue
@@ -47,7 +47,7 @@
<div class="form__label">{{ $t('label.hypervisor') }}</div>
<a-select
v-model:value="hypervisor"
- @change="resetAllFields"
+ @change="hypervisor => onChangeHypervisor(hypervisor)"
showSearch
optionFilterProp="value"
:filterOption="(input, option) => {
@@ -109,19 +109,28 @@
</div>
<div class="form__item">
- <div class="form__label">{{ $t('label.vcenterusername') }}</div>
- <a-input v-model:value="username"></a-input>
+ <div class="form__label">{{ $t('label.vcenterdatacenter') }}</div>
+ <a-input v-model:value="dataCenter"></a-input>
</div>
- <div class="form__item">
- <div class="form__label">{{ $t('label.vcenterpassword') }}</div>
- <a-input type="password" v-model:value="password"></a-input>
+ <div class="form__item" name="useDefaultVMwareCred">
+ <div class="form__label">{{
$t('label.use.existing.vcenter.credentials.from.zone') }}</div>
+ <a-switch v-model="useDefaultVMwareCred"
:checked="useDefaultVMwareCred" @change="onChangeUseDefaultVMwareCred()" />
</div>
- <div class="form__item">
- <div class="form__label">{{ $t('label.vcenterdatacenter') }}</div>
- <a-input v-model:value="dataCenter"></a-input>
- </div>
+ <template v-if="useDefaultVMwareCred === false">
+ <div class="form__item">
+ <div class="form__label"><span class="required">* </span>{{
$t('label.vcenterusername') }}</div>
+ <span class="required required-label" ref="requiredUsername">{{
$t('label.required') }}</span>
+ <a-input v-model:value="username"></a-input>
+ </div>
+
+ <div class="form__item">
+ <div class="form__label"><span class="required">* </span>{{
$t('label.vcenterpassword') }}</div>
+ <span class="required required-label" ref="requiredPassword">{{
$t('label.required') }}</span>
+ <a-input type="password" v-model:value="password"></a-input>
+ </div>
+ </template>
</template>
<div class="form__item">
@@ -176,6 +185,7 @@ export default {
username: null,
password: null,
url: null,
+ useDefaultVMwareCred: true,
host: null,
dataCenter: null,
ovm3pool: null,
@@ -257,6 +267,27 @@ export default {
this.loading = false
})
},
+ fetchVMwareCred () {
+ this.loading = true
+ this.clustertype = 'ExternalManaged'
+ api('listVmwareDcs', {
+ zoneid: this.zoneId
+ }).then(response => {
+ var vmwaredcs = response.listvmwaredcsresponse.VMwareDC
+ if (vmwaredcs !== null) {
+ this.host = vmwaredcs[0].vcenter
+ this.dataCenter = vmwaredcs[0].name
+ }
+ }).catch(error => {
+ this.$notification.error({
+ message: `${this.$t('label.error')} ${error.response.status}`,
+ description: error.response.data.listvmwaredcsresponse.errortext,
+ duration: 0
+ })
+ }).finally(() => {
+ this.loading = false
+ })
+ },
toggleDedicated () {
this.dedicatedDomainId = null
this.dedicatedAccount = null
@@ -270,35 +301,24 @@ export default {
}
this.$refs.requiredCluster.classList.remove('required-label--visible')
+ if (this.hypervisor === 'VMware' && this.useDefaultVMwareCred === false)
{
+ if (!this.username) {
+ this.$refs.requiredUsername.classList.add('required-label--visible')
+ return
+ }
+ if (!this.password) {
+ this.$refs.requiredPassword.classList.add('required-label--visible')
+ return
+ }
+ this.$refs.requiredUsername.classList.remove('required-label--visible')
+ this.$refs.requiredPassword.classList.remove('required-label--visible')
+ }
+
if (this.hypervisor === 'Ovm3') {
this.ovm3pool = 'on'
this.ovm3cluster = 'undefined'
this.ovm3vip = ''
}
-
- if (this.hypervisor === 'VMware') {
- this.clustertype = 'ExternalManaged'
- if ((this.host === null || this.host.length === 0) &&
- (this.dataCenter === null || this.dataCenter.length === 0)) {
- api('listVmwareDcs', {
- zoneid: this.zoneId
- }).then(response => {
- var vmwaredcs = response.listvmwaredcsresponse.VMwareDC
- if (vmwaredcs !== null) {
- this.host = vmwaredcs[0].vcenter
- this.dataCenter = vmwaredcs[0].name
- }
- this.addCluster()
- }).catch(error => {
- this.$notification.error({
- message: `${this.$t('label.error')} ${error.response.status}`,
- description: error.response.data.listvmwaredcsresponse.errortext,
- duration: 0
- })
- })
- return
- }
- }
this.addCluster()
},
addCluster () {
@@ -387,7 +407,7 @@ export default {
this.loading = false
})
},
- resetAllFields () {
+ onChangeHypervisor (hypervisor) {
this.clustertype = 'CloudManaged'
this.username = null
this.password = null
@@ -397,6 +417,16 @@ export default {
this.ovm3pool = null
this.ovm3cluster = null
this.ovm3vip = null
+ if (hypervisor === 'VMware') {
+ this.fetchVMwareCred()
+ }
+ },
+ onChangeUseDefaultVMwareCred () {
+ this.useDefaultVMwareCred = !this.useDefaultVMwareCred
+ if (this.useDefaultVMwareCred) {
+ this.username = null
+ this.password = null
+ }
},
returnPlaceholder (field) {
this.params.find(i => {
diff --git a/ui/src/views/setting/ConfigurationHierarchy.vue
b/ui/src/views/setting/ConfigurationHierarchy.vue
index 45060efa594..80b464e657c 100644
--- a/ui/src/views/setting/ConfigurationHierarchy.vue
+++ b/ui/src/views/setting/ConfigurationHierarchy.vue
@@ -28,11 +28,10 @@
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'name'">
- <span :style="hierarchyExists ? 'padding-left: 0px;' : 'padding-left:
25px;'">
- <b><span v-if="record.parent">└─ </span>{{record.displaytext }}
</b> {{ ' (' + record.name + ')' }}
- </span>
- <br/>
- <span :style="record.parent ? 'padding-left: 50px; display:block' :
'padding-left: 25px; display:block'">{{ record.description }}</span>
+ <a-row :style="hierarchyExists ? 'padding-left: 0px;' : 'padding-left:
25px;'">
+ <b><span v-if="record.parent">└─ </span>{{record.displaytext
}} </b> {{ '(' + record.name + ')' }}
+ </a-row>
+ <span :style="record.parent ? 'padding-left: 50px; display:block' :
'padding-left: 25px; display:block'">{{ record.description }}</span>
</template>
<template v-if="column.key === 'value'">
<ConfigurationValue :configrecord="record" />
diff --git a/ui/src/views/storage/CreateVolume.vue
b/ui/src/views/storage/CreateVolume.vue
index 0b667a1f51f..82fcce5c974 100644
--- a/ui/src/views/storage/CreateVolume.vue
+++ b/ui/src/views/storage/CreateVolume.vue
@@ -116,6 +116,48 @@
:placeholder="apiParams.maxiops.description"/>
</a-form-item>
</span>
+ <a-form-item name="attachVolume" ref="attachVolume"
v-if="!createVolumeFromVM">
+ <template #label>
+ <tooltip-label :title="$t('label.action.attach.to.instance')"
:tooltip="$t('label.attach.vol.to.instance')" />
+ </template>
+ <a-switch v-model:checked="form.attachVolume" :checked="attachVolume"
@change="zone => onChangeAttachToVM(zone.id)" />
+ </a-form-item>
+ <span v-if="attachVolume">
+ <a-form-item :label="$t('label.virtualmachineid')"
name="virtualmachineid" ref="virtualmachineid">
+ <a-select
+ v-focus="true"
+ v-model:value="form.virtualmachineid"
+ :placeholder="attachVolumeApiParams.virtualmachineid.description"
+ showSearch
+ optionFilterProp="label"
+ :filterOption="(input, option) => {
+ return option.label.toLowerCase().indexOf(input.toLowerCase())
>= 0
+ }" >
+ <a-select-option v-for="vm in virtualmachines" :key="vm.id"
:label="vm.name || vm.displayname">
+ {{ vm.name || vm.displayname }}
+ </a-select-option>
+ </a-select>
+ </a-form-item >
+ <a-form-item :label="$t('label.deviceid')">
+ <div style="margin-bottom: 10px">
+ <a-collapse>
+ <a-collapse-panel header="More information about deviceID">
+ <a-alert type="warning">
+ <template #message>
+ <span v-html="attachVolumeApiParams.deviceid.description"
/>
+ </template>
+ </a-alert>
+ </a-collapse-panel>
+ </a-collapse>
+ </div>
+ <a-input-number
+ v-model:value="form.deviceid"
+ style="width: 100%;"
+ :min="0"
+ :placeholder="$t('label.deviceid')"
+ />
+ </a-form-item>
+ </span>
<div :span="24" class="action-button">
<a-button @click="closeModal">{{ $t('label.cancel') }}</a-button>
<a-button type="primary" ref="submit" @click="handleSubmit">{{
$t('label.ok') }}</a-button>
@@ -159,7 +201,10 @@ export default {
offerings: [],
customDiskOffering: false,
loading: false,
- isCustomizedDiskIOps: false
+ isCustomizedDiskIOps: false,
+ virtualmachines: [],
+ attachVolume: false,
+ vmidtoattach: null
}
},
computed: {
@@ -204,6 +249,10 @@ export default {
}
}]
})
+ if (this.attachVolume) {
+ this.rules.virtualmachineid = [{ required: true, message:
this.$t('message.error.select') }]
+ this.rules.deviceid = [{ required: true, message:
this.$t('message.error.select') }]
+ }
if (!this.createVolumeFromSnapshot) {
this.rules.name = [{ required: true, message:
this.$t('message.error.volume.name') }]
this.rules.diskofferingid = [{ required: true, message:
this.$t('message.error.select') }]
@@ -248,6 +297,9 @@ export default {
this.zones = json.listzonesresponse.zone || []
this.form.zoneid = this.zones[0].id || ''
this.fetchDiskOfferings(this.form.zoneid)
+ if (this.attachVolume) {
+ this.fetchVirtualMachines(this.form.zoneid)
+ }
}).finally(() => {
this.loading = false
})
@@ -301,6 +353,31 @@ export default {
this.loading = false
})
},
+ fetchVirtualMachines (zoneId) {
+ var params = {
+ zoneid: zoneId,
+ details: 'min'
+ }
+ if (this.owner.projectid) {
+ params.projectid = this.owner.projectid
+ } else {
+ params.account = this.owner.account
+ params.domainid = this.owner.domainid
+ }
+
+ this.loading = true
+ var vmStates = ['Running', 'Stopped']
+ vmStates.forEach((state) => {
+ params.state = state
+ api('listVirtualMachines', params).then(response => {
+ this.virtualmachines =
this.virtualmachines.concat(response.listvirtualmachinesresponse.virtualmachine
|| [])
+ }).catch(error => {
+ this.$notifyError(error)
+ }).finally(() => {
+ this.loading = false
+ })
+ })
+ },
handleSubmit (e) {
if (this.loading) return
this.formRef.value.validate().then(() => {
@@ -315,6 +392,10 @@ export default {
if (this.createVolumeFromSnapshot) {
values.snapshotid = this.resource.id
}
+ if (this.attachVolume) {
+ this.vmidtoattach = values.virtualmachineid
+ values.virtualmachineid = null
+ }
values.domainid = this.owner.domainid
if (this.owner.projectid) {
values.projectid = this.owner.projectid
@@ -330,10 +411,15 @@ export default {
successMessage: this.$t('message.success.create.volume'),
successMethod: (result) => {
this.closeModal()
- if (this.createVolumeFromVM) {
+ if (this.createVolumeFromVM || this.attachVolume) {
const params = {}
params.id = result.jobresult.volume.id
- params.virtualmachineid = this.resource.id
+ if (this.createVolumeFromVM) {
+ params.virtualmachineid = this.resource.id
+ } else {
+ params.virtualmachineid = this.vmidtoattach
+ params.deviceid = values.deviceid
+ }
api('attachVolume', params).then(response => {
this.$pollJob({
jobId: response.attachvolumeresponse.jobid,
@@ -368,6 +454,14 @@ export default {
const offering = this.offerings.filter(x => x.id === id)
this.customDiskOffering = offering[0]?.iscustomized || false
this.isCustomizedDiskIOps = offering[0]?.iscustomizediops || false
+ },
+ onChangeAttachToVM (zone) {
+ this.attachVolume = !this.attachVolume
+ this.virtualmachines = []
+ if (this.attachVolume) {
+ this.attachVolumeApiParams = this.$getApiParams('attachVolume')
+ this.fetchVirtualMachines(this.form.zoneid)
+ }
}
}
}
diff --git a/ui/src/views/storage/RecurringSnapshotVolume.vue
b/ui/src/views/storage/RecurringSnapshotVolume.vue
index ce929848de4..dc2e83a91c4 100644
--- a/ui/src/views/storage/RecurringSnapshotVolume.vue
+++ b/ui/src/views/storage/RecurringSnapshotVolume.vue
@@ -27,7 +27,7 @@
@close-action="closeAction"
@refresh="handleRefresh"/>
</a-tab-pane>
- <a-tab-pane :tab="$t('label.scheduled.snapshots')" key="2">
+ <a-tab-pane :tab="$t('label.action.recurring.snapshot')" key="2">
<ScheduledSnapshots
:loading="loading"
:resource="resource"