From 5c2e3b7c9656f6009095802f105604a30cd56b36 Mon Sep 17 00:00:00 2001 From: Gean Jair Silva Date: Wed, 9 Sep 2026 17:23:00 -0300 Subject: [PATCH 1/2] Addition of instance snapshots limits to the resource tab --- .../com/cloud/configuration/Resource.java | 3 +- .../com/cloud/user/ResourceLimitService.java | 7 +++ .../apache/cloudstack/api/ApiConstants.java | 46 ++++++++++++++++++- .../UpdateHypervisorCapabilitiesCmd.java | 2 +- .../user/resource/ListResourceLimitsCmd.java | 28 +---------- .../user/resource/UpdateResourceCountCmd.java | 14 +----- .../user/resource/UpdateResourceLimitCmd.java | 5 +- .../api/response/AccountResponse.java | 27 +++++++++++ .../api/response/DomainResponse.java | 27 +++++++++++ .../HypervisorCapabilitiesResponse.java | 2 +- .../api/response/ProjectResponse.java | 27 +++++++++++ .../ResourceLimitAndCountResponse.java | 6 +++ .../META-INF/db/views/cloud.account_view.sql | 8 ++++ .../META-INF/db/views/cloud.domain_view.sql | 8 ++++ .../api/query/dao/AccountJoinDaoImpl.java | 8 ++++ .../api/query/dao/DomainJoinDaoImpl.java | 8 ++++ .../com/cloud/api/query/vo/AccountJoinVO.java | 14 ++++++ .../com/cloud/api/query/vo/DomainJoinVO.java | 14 ++++++ .../ResourceLimitManagerImpl.java | 22 +++++++-- .../vm/snapshot/VMSnapshotManagerImpl.java | 22 +++++++-- .../vm/snapshot/VMSnapshotManagerTest.java | 7 +++ ui/public/locales/en.json | 2 + ui/public/locales/pt_BR.json | 3 +- ui/src/components/view/ResourceCountUsage.vue | 2 +- 24 files changed, 258 insertions(+), 54 deletions(-) diff --git a/api/src/main/java/com/cloud/configuration/Resource.java b/api/src/main/java/com/cloud/configuration/Resource.java index 97be7f9d64c5..5c446ef54630 100644 --- a/api/src/main/java/com/cloud/configuration/Resource.java +++ b/api/src/main/java/com/cloud/configuration/Resource.java @@ -38,7 +38,8 @@ enum ResourceType { // All storage type resources are allocated_storage and not backup_storage("backup_storage", 13), bucket("bucket", 14), object_storage("object_storage", 15), - gpu("gpu", 16); + gpu("gpu", 16), + instance_snapshot("instance_snapshot", 17); private String name; private int ordinal; diff --git a/api/src/main/java/com/cloud/user/ResourceLimitService.java b/api/src/main/java/com/cloud/user/ResourceLimitService.java index 89128f87829e..d0d1221bd3be 100644 --- a/api/src/main/java/com/cloud/user/ResourceLimitService.java +++ b/api/src/main/java/com/cloud/user/ResourceLimitService.java @@ -57,6 +57,13 @@ public interface ResourceLimitService { "The default maximum number of GPU devices that can be used for a domain", false); static final ConfigKey DefaultMaxProjectGpus = new ConfigKey<>("Project Defaults",Long.class,"max.project.gpus","20", "The default maximum number of GPU devices that can be used for a project", false); + static final ConfigKey MaxDomainInstanceSnapshot = new ConfigKey<>("Domain Defaults", Long.class, "max.domain.instance.snapshots", "40", + "The default maximum VM snapshots that can be used for a domain", false); + static final ConfigKey MaxAccountInstanceSnapshot = new ConfigKey<>("Account Defaults", Long.class, "max.account.instance.snapshots", "20", + "The default maximum VM snapshots that can be used for a account", false); + static final ConfigKey MaxProjectInstanceSnapshot = new ConfigKey<>("Project Defaults", Long.class, "max.project.instance.snapshots", "20", + "The default maximum VM snapshots that can be used for a project", false); + static final List HostTagsSupportingTypes = List.of(ResourceType.user_vm, ResourceType.cpu, ResourceType.memory, ResourceType.gpu); static final List StorageTagsSupportingTypes = List.of(ResourceType.volume, ResourceType.primary_storage); 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 f74c46161180..dad2e68e1824 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -528,6 +528,47 @@ public class ApiConstants { public static final String RESOURCE_NAME = "resourcename"; public static final String RESOURCE_TYPE = "resourcetype"; public static final String RESOURCE_TYPE_NAME = "resourcetypename"; + + public static final String RESOURCE_TYPE_DESCRIPTION = "Accepted values are 0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 and 17.\n" + + "0 - Instance. Number of Instances a user can create.\n" + + "1 - IP. Number of public IP addresses an account can own.\n" + + "2 - Volume. Number of disk volumes an account can own.\n" + + "3 - Snapshot. Number of Snapshots an account can own.\n" + + "4 - Template. Number of Templates an account can register/create.\n" + + "5 - Project. Number of projects an account can own.\n" + + "6 - Network. Number of networks an account can own.\n" + + "7 - VPC. Number of VPC an account can own.\n" + + "8 - CPU. Number of CPU an account can allocate for their resources.\n" + + "9 - Memory. Amount of RAM an account can allocate for their resources.\n" + + "10 - PrimaryStorage. Total primary storage space (in GiB) a user can use.\n" + + "11 - SecondaryStorage. Total secondary storage space (in GiB) a user can use. \n" + + "12 - Backup. Number of backups an account can own.\n" + + "13 - BackupStorage. Total backup storage space (in GiB) a user can use.\n" + + "14 - Bucket. Number of buckets an account can own\n" + + "15 - ObjectStorage. Total object storage space (in GiB) a user can use.\n" + + "16 - GPU. Number of GPUs an account can allocate for their resources.\n" + + "17 - InstanceSnapshot. Number of instance snapshots an account can own"; + + public static final String RESOURCE_TYPE_NAME_DESCRIPTION = "Type of resource (wins over resourceType if both are provided). Values are:\n" + + "user_vm - Instance. Number of Instances a user can create.\n" + + "public_ip - IP. Number of public IP addresses an account can own.\n" + + "volume - Volume. Number of disk volumes an account can own.\n" + + "snapshot - Snapshot. Number of Snapshots an account can own.\n" + + "template - Template. Number of Templates an account can register/create.\n" + + "project - Project. Number of projects an account can own.\n" + + "network - Network. Number of networks an account can own.\n" + + "vpc - VPC. Number of VPC an account can own.\n" + + "cpu - CPU. Number of CPU an account can allocate for their resources.\n" + + "memory - Memory. Amount of RAM an account can allocate for their resources.\n" + + "primary_storage - PrimaryStorage. Total primary storage space (in GiB) a user can use.\n" + + "secondary_storage - SecondaryStorage. Total secondary storage space (in GiB) a user can use\n" + + "backup - Backup. Number of backups an account can own.\n" + + "backup_storage - BackupStorage. Total backup storage space (in GiB) a user can use\n" + + "bucket - Bucket. Number of buckets an account can own.\n" + + "object_storage - ObjectStorage. Total object storage space (in GiB) a user can use.\n" + + "gpu - GPU. Number of GPUs an account can allocate for their resources.\n" + + "instance_snapshot - InstanceSnapshot. Number of instance snapshots an account can own"; + public static final String RESPONSE = "response"; public static final String RETRIEVE_ONLY_RESOURCE_COUNT = "retrieveonlyresourcecount"; public static final String REVERTABLE = "revertable"; @@ -915,7 +956,10 @@ public class ApiConstants { public static final String MIGRATE_TO = "migrateto"; public static final String AUTO_MIGRATE = "automigrate"; public static final String GUID = "guid"; - public static final String VM_SNAPSHOT_ENABELD = "vmsnapshotenabled"; + public static final String VM_SNAPSHOT_ENABLED = "vmsnapshotenabled"; + public static final String INSTANCE_SNAPSHOT_LIMIT = "instancesnapshotlimit"; + public static final String INSTANCE_SNAPSHOT_TOTAL = "instancesnapshottotal"; + public static final String INSTANCE_SNAPSHOT_AVAILABLE = "instancesnapshotavailable"; public static final String VSWITCH_TYPE_GUEST_TRAFFIC = "guestvswitchtype"; public static final String VSWITCH_TYPE_PUBLIC_TRAFFIC = "publicvswitchtype"; public static final String VSWITCH_NAME_GUEST_TRAFFIC = "guestvswitchname"; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/config/UpdateHypervisorCapabilitiesCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/config/UpdateHypervisorCapabilitiesCmd.java index d7342654ec40..0f0fcc28d3ad 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/config/UpdateHypervisorCapabilitiesCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/config/UpdateHypervisorCapabilitiesCmd.java @@ -64,7 +64,7 @@ public class UpdateHypervisorCapabilitiesCmd extends BaseCmd { @Parameter(name = ApiConstants.MAX_HOSTS_PER_CLUSTER, type = CommandType.INTEGER, description = "The maximum number of the hypervisor hosts per cluster ", since = "4.16.0") private Integer maxHostsPerClusterLimit; - @Parameter(name = ApiConstants.VM_SNAPSHOT_ENABELD, type = CommandType.BOOLEAN, description = "Set true to enable Instance Snapshots for this hypervisor", since = "4.16.0") + @Parameter(name = ApiConstants.VM_SNAPSHOT_ENABLED, type = CommandType.BOOLEAN, description = "Set true to enable Instance Snapshots for this hypervisor", since = "4.16.0") private Boolean vmSnapshotEnabled; ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/resource/ListResourceLimitsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/resource/ListResourceLimitsCmd.java index 4bda23617092..2f2ddbdd1c56 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/resource/ListResourceLimitsCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/resource/ListResourceLimitsCmd.java @@ -42,34 +42,10 @@ public class ListResourceLimitsCmd extends BaseListProjectAndAccountResourcesCmd @Parameter(name = ApiConstants.ID, type = CommandType.LONG, description = "Lists resource limits by ID.") private Long id; - @Parameter(name = ApiConstants.RESOURCE_TYPE, type = CommandType.INTEGER, description = "Type of resource. Values are 0, 1, 2, 3, 4, 6, 7, 8, 9, 10 and 11. " - + "0 - Instance. Number of Instances a user can create. " - + "1 - IP. Number of public IP addresses an account can own. " - + "2 - Volume. Number of disk volumes an account can own. " - + "3 - Snapshot. Number of Snapshots an account can own. " - + "4 - Template. Number of Templates an account can register/create. " - + "5 - Project. Number of projects an account can own. " - + "6 - Network. Number of networks an account can own. " - + "7 - VPC. Number of VPC an account can own. " - + "8 - CPU. Number of CPU an account can allocate for their resources. " - + "9 - Memory. Amount of RAM an account can allocate for their resources. " - + "10 - PrimaryStorage. Total primary storage space (in GiB) a user can use. " - + "11 - SecondaryStorage. Total secondary storage space (in GiB) a user can use. ") + @Parameter(name = ApiConstants.RESOURCE_TYPE, type = CommandType.INTEGER, description = "Type of resource. " + ApiConstants.RESOURCE_TYPE_DESCRIPTION) private Integer resourceType; - @Parameter(name = ApiConstants.RESOURCE_TYPE_NAME, type = CommandType.STRING, description = "Type of resource (wins over resourceType if both are provided). Values are: " - + "user_vm - Instance. Number of Instances a user can create. " - + "public_ip - IP. Number of public IP addresses an account can own. " - + "volume - Volume. Number of disk volumes an account can own. " - + "snapshot - Snapshot. Number of Snapshots an account can own. " - + "template - Template. Number of Templates an account can register/create. " - + "project - Project. Number of projects an account can own. " - + "network - Network. Number of networks an account can own. " - + "vpc - VPC. Number of VPC an account can own. " - + "cpu - CPU. Number of CPU an account can allocate for their resources. " - + "memory - Memory. Amount of RAM an account can allocate for their resources. " - + "primary_storage - PrimaryStorage. Total primary storage space (in GiB) a user can use. " - + "secondary_storage - SecondaryStorage. Total secondary storage space (in GiB) a user can use. ") + @Parameter(name = ApiConstants.RESOURCE_TYPE_NAME, type = CommandType.STRING, description = ApiConstants.RESOURCE_TYPE_NAME_DESCRIPTION) private String resourceTypeName; @Parameter(name = ApiConstants.TAG, type = CommandType.STRING, description = "Tag for the resource type", since = "4.20.0") diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/resource/UpdateResourceCountCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/resource/UpdateResourceCountCmd.java index d43bb29e9d27..96c3d775b5c8 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/resource/UpdateResourceCountCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/resource/UpdateResourceCountCmd.java @@ -60,19 +60,7 @@ public class UpdateResourceCountCmd extends BaseCmd { @Parameter(name = ApiConstants.RESOURCE_TYPE, type = CommandType.INTEGER, - description = "Type of resource to update. If specifies valid values are 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 and 11. If not specified will update all resource counts" - + "0 - Instance. Number of Instances a user can create. " - + "1 - IP. Number of public IP addresses a user can own. " - + "2 - Volume. Number of disk volumes a user can create. " - + "3 - Snapshot. Number of Snapshots a user can create. " - + "4 - Template. Number of Templates that a user can register/create. " - + "5 - Project. Number of projects that a user can create. " - + "6 - Network. Number of guest network a user can create. " - + "7 - VPC. Number of VPC a user can create. " - + "8 - CPU. Total number of CPU cores a user can use. " - + "9 - Memory. Total Memory (in MB) a user can use. " - + "10 - PrimaryStorage. Total primary storage space (in GiB) a user can use. " - + "11 - SecondaryStorage. Total secondary storage space (in GiB) a user can use. ") + description = "Type of resource to update, if not specified will update all resource counts. " + ApiConstants.RESOURCE_TYPE_DESCRIPTION) private Integer resourceType; @Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, entityType = ProjectResponse.class, description = "Update resource limits for project") diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/resource/UpdateResourceLimitCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/resource/UpdateResourceLimitCmd.java index f88ef9678e31..5ab599baa7c4 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/resource/UpdateResourceLimitCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/resource/UpdateResourceLimitCmd.java @@ -56,7 +56,7 @@ public class UpdateResourceLimitCmd extends BaseCmd { @Parameter(name = ApiConstants.RESOURCE_TYPE, type = CommandType.INTEGER, required = true, - description = "Type of resource to update. Values are 0, 1, 2, 3, 4, 6, 7, 8, 9, 10 and 11. " + description = "Type of resource to update. Values are 0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11 and 12. " + "0 - Instance. Number of Instances a user can create. " + "1 - IP. Number of public IP addresses a user can own. " + "2 - Volume. Number of disk volumes a user can create. " @@ -68,7 +68,8 @@ public class UpdateResourceLimitCmd extends BaseCmd { + "8 - CPU. Total number of CPU cores a user can use. " + "9 - Memory. Total Memory (in MB) a user can use. " + "10 - PrimaryStorage. Total primary storage space (in GiB) a user can use. " - + "11 - SecondaryStorage. Total secondary storage space (in GiB) a user can use. ") + + "11 - SecondaryStorage. Total secondary storage space (in GiB) a user can use. " + + "12 - InstanceSnapshot. Number of instance snapshots an account can own.") private Integer resourceType; @Parameter(name = ApiConstants.TAG, type = CommandType.STRING, description = "Tag for the resource type", since = "4.20.0") diff --git a/api/src/main/java/org/apache/cloudstack/api/response/AccountResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/AccountResponse.java index 93529b8a8887..e01a03dfb2d8 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/AccountResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/AccountResponse.java @@ -151,6 +151,18 @@ public class AccountResponse extends BaseResponse implements ResourceLimitAndCou @Param(description = "the total backup storage space (in GiB) available to the account", since = "4.21.0") private String backupStorageAvailable; + @SerializedName(ApiConstants.INSTANCE_SNAPSHOT_LIMIT) + @Param(description = "The total number of Instance Snapshots that this Account can own") + private String instanceSnapshotLimit; + + @SerializedName(ApiConstants.INSTANCE_SNAPSHOT_TOTAL) + @Param(description = "The number of Instance Snapshots owned by this Account") + private Long instanceSnapshotTotal; + + @SerializedName(ApiConstants.INSTANCE_SNAPSHOT_AVAILABLE) + @Param(description = "The number of Instance Snapshots available for this Account") + private String instanceSnapshotAvailable; + @SerializedName("templatelimit") @Param(description = "The total number of Templates which can be created by this Account") private String templateLimit; @@ -476,6 +488,21 @@ public void setBackupStorageAvailable(String backupStorageAvailable) { this.backupStorageAvailable = backupStorageAvailable; } + @Override + public void setInstanceSnapshotLimit(String instanceSnapshotLimit) { + this.instanceSnapshotLimit = instanceSnapshotLimit; + } + + @Override + public void setInstanceSnapshotTotal(Long instanceSnapshotTotal) { + this.instanceSnapshotTotal = instanceSnapshotTotal; + } + + @Override + public void setInstanceSnapshotAvailable(String instanceSnapshotAvailable) { + this.instanceSnapshotAvailable = instanceSnapshotAvailable; + } + @Override public void setTemplateLimit(String templateLimit) { this.templateLimit = templateLimit; diff --git a/api/src/main/java/org/apache/cloudstack/api/response/DomainResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/DomainResponse.java index 8a8f8b543115..5b895a610e67 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/DomainResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/DomainResponse.java @@ -129,6 +129,18 @@ public class DomainResponse extends BaseResponseWithTagInformation implements Re @Param(description = "the total backup storage space (in GiB) available to the domain", since = "4.21.0") private String backupStorageAvailable; + @SerializedName(ApiConstants.INSTANCE_SNAPSHOT_LIMIT) + @Param(description = "The number of Instance snapshots that can be stored by this domain") + private String instanceSnapshotLimit; + + @SerializedName(ApiConstants.INSTANCE_SNAPSHOT_TOTAL) + @Param(description = "The number of Instance snapshots stored by this domain") + private Long instanceSnapshotTotal; + + @SerializedName(ApiConstants.INSTANCE_SNAPSHOT_AVAILABLE) + @Param(description = "The number of Instance snapshots available for this domain") + private String instanceSnapshotAvailable; + @SerializedName("templatelimit") @Param(description = "The total number of Templates which can be created by this domain") private String templateLimit; @@ -400,6 +412,21 @@ public void setBackupStorageAvailable(String backupStorageAvailable) { this.backupStorageAvailable = backupStorageAvailable; } + @Override + public void setInstanceSnapshotLimit(String instanceSnapshotLimit) { + this.instanceSnapshotLimit = instanceSnapshotLimit; + } + + @Override + public void setInstanceSnapshotTotal(Long instanceSnapshotTotal) { + this.instanceSnapshotTotal = instanceSnapshotTotal; + } + + @Override + public void setInstanceSnapshotAvailable(String instanceSnapshotAvailable) { + this.instanceSnapshotAvailable = instanceSnapshotAvailable; + } + @Override public void setTemplateLimit(String templateLimit) { this.templateLimit = templateLimit; diff --git a/api/src/main/java/org/apache/cloudstack/api/response/HypervisorCapabilitiesResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/HypervisorCapabilitiesResponse.java index a835b2376272..5dbb0c5bd3c2 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/HypervisorCapabilitiesResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/HypervisorCapabilitiesResponse.java @@ -58,7 +58,7 @@ public class HypervisorCapabilitiesResponse extends BaseResponse { @Param(description = "True if storage motion is supported") private boolean isStorageMotionSupported; - @SerializedName(ApiConstants.VM_SNAPSHOT_ENABELD) + @SerializedName(ApiConstants.VM_SNAPSHOT_ENABLED) @Param(description = "True if Instance Snapshots are enabled for this hypervisor") private boolean isVmSnapshotEnabled; diff --git a/api/src/main/java/org/apache/cloudstack/api/response/ProjectResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/ProjectResponse.java index 40f9405d0fc5..1c5e3b6140ee 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/ProjectResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/ProjectResponse.java @@ -248,6 +248,18 @@ public class ProjectResponse extends BaseResponse implements ResourceLimitAndCou @Param(description = "the total backup storage space (in GiB) available to the project", since = "4.21.0") private String backupStorageAvailable; + @SerializedName(ApiConstants.INSTANCE_SNAPSHOT_LIMIT) + @Param(description = "The number of Instance Snapshots that can be stored by this project") + private String instanceSnapshotLimit; + + @SerializedName(ApiConstants.INSTANCE_SNAPSHOT_TOTAL) + @Param(description = "The number of instance snapshots stored by this project") + private Long instanceSnapshotTotal; + + @SerializedName(ApiConstants.INSTANCE_SNAPSHOT_AVAILABLE) + @Param(description = "The number of Instance snapshots available for this project") + private String instanceSnapshotAvailable; + @SerializedName("templatelimit") @Param(description = "The total number of Templates which can be created by this project", since = "4.2.0") private String templateLimit; @@ -410,6 +422,21 @@ public void setBackupStorageAvailable(String backupStorageAvailable) { this.backupStorageAvailable = backupStorageAvailable; } + @Override + public void setInstanceSnapshotLimit(String instanceSnapshotLimit) { + this.instanceSnapshotLimit = instanceSnapshotLimit; + } + + @Override + public void setInstanceSnapshotTotal(Long instanceSnapshotTotal) { + this.instanceSnapshotTotal = instanceSnapshotTotal; + } + + @Override + public void setInstanceSnapshotAvailable(String instanceSnapshotAvailable) { + this.instanceSnapshotAvailable = instanceSnapshotAvailable; + } + @Override public void setTemplateLimit(String templateLimit) { this.templateLimit = templateLimit; diff --git a/api/src/main/java/org/apache/cloudstack/api/response/ResourceLimitAndCountResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/ResourceLimitAndCountResponse.java index 66de71dd7634..6153b269e469 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/ResourceLimitAndCountResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/ResourceLimitAndCountResponse.java @@ -114,6 +114,12 @@ public interface ResourceLimitAndCountResponse { void setObjectStorageAvailable(String objectStorageAvailable); + public void setInstanceSnapshotLimit(String instanceSnapshotLimit); + + public void setInstanceSnapshotTotal(Long instanceSnapshotTotal); + + public void setInstanceSnapshotAvailable(String instanceSnapshotAvailable); + public void setTemplateLimit(String templateLimit); public void setTemplateTotal(Long templateTotal); diff --git a/engine/schema/src/main/resources/META-INF/db/views/cloud.account_view.sql b/engine/schema/src/main/resources/META-INF/db/views/cloud.account_view.sql index edc164c40cbd..aa53fc3bc3ea 100644 --- a/engine/schema/src/main/resources/META-INF/db/views/cloud.account_view.sql +++ b/engine/schema/src/main/resources/META-INF/db/views/cloud.account_view.sql @@ -52,6 +52,8 @@ select `volumecount`.`count` AS `volumeTotal`, `snapshotlimit`.`max` AS `snapshotLimit`, `snapshotcount`.`count` AS `snapshotTotal`, + `instancesnapshotlimit`.`max` AS `instanceSnapshotLimit`, + `instancesnapshotcount`.`count` AS `instanceSnapshotTotal`, `templatelimit`.`max` AS `templateLimit`, `templatecount`.`count` AS `templateTotal`, `vpclimit`.`max` AS `vpcLimit`, @@ -122,6 +124,12 @@ from `cloud`.`resource_count` snapshotcount ON account.id = snapshotcount.account_id and snapshotcount.type = 'snapshot' left join + `cloud`.`resource_limit` instancesnapshotlimit ON account.id = instancesnapshotlimit.account_id + and instancesnapshotlimit.type = 'instance_snapshot' + left join + `cloud`.`resource_count` instancesnapshotcount ON account.id = instancesnapshotcount.account_id + and instancesnapshotcount.type = 'instance_snapshot' + left join `cloud`.`resource_limit` templatelimit ON account.id = templatelimit.account_id and templatelimit.type = 'template' left join diff --git a/engine/schema/src/main/resources/META-INF/db/views/cloud.domain_view.sql b/engine/schema/src/main/resources/META-INF/db/views/cloud.domain_view.sql index 14fd87536aa1..dc29f43588ce 100644 --- a/engine/schema/src/main/resources/META-INF/db/views/cloud.domain_view.sql +++ b/engine/schema/src/main/resources/META-INF/db/views/cloud.domain_view.sql @@ -43,6 +43,8 @@ select `volumecount`.`count` AS `volumeTotal`, `snapshotlimit`.`max` AS `snapshotLimit`, `snapshotcount`.`count` AS `snapshotTotal`, + `instancesnapshotlimit`.`max` AS `instanceSnapshotLimit`, + `instancesnapshotcount`.`count` AS `instanceSnapshotTotal`, `templatelimit`.`max` AS `templateLimit`, `templatecount`.`count` AS `templateTotal`, `vpclimit`.`max` AS `vpcLimit`, @@ -96,6 +98,12 @@ from `cloud`.`resource_count` snapshotcount ON domain.id = snapshotcount.domain_id and snapshotcount.type = 'snapshot' left join + `cloud`.`resource_limit` instancesnapshotlimit ON domain.id = instancesnapshotlimit.domain_id + and instancesnapshotlimit.type = 'instance_snapshot' + left join + `cloud`.`resource_count` instancesnapshotcount ON domain.id = instancesnapshotcount.domain_id + and instancesnapshotcount.type = 'instance_snapshot' + left join `cloud`.`resource_limit` templatelimit ON domain.id = templatelimit.domain_id and templatelimit.type = 'template' left join diff --git a/server/src/main/java/com/cloud/api/query/dao/AccountJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/AccountJoinDaoImpl.java index de66b80ca555..643515e38f2e 100644 --- a/server/src/main/java/com/cloud/api/query/dao/AccountJoinDaoImpl.java +++ b/server/src/main/java/com/cloud/api/query/dao/AccountJoinDaoImpl.java @@ -171,6 +171,14 @@ public void setResourceLimits(AccountJoinVO account, boolean fullView, ResourceL response.setSnapshotTotal(snapshotTotal); response.setSnapshotAvailable(snapshotAvail); + Long instanceSnapshotLimit = ApiDBUtils.findCorrectResourceLimit(account.getInstanceSnapshotLimit(), account.getId(), ResourceType.instance_snapshot); + String instanceSnapshotLimitDisplay = (fullView || instanceSnapshotLimit == -1) ? Resource.UNLIMITED : String.valueOf(instanceSnapshotLimit); + Long instanceSnapshotTotal = (account.getInstanceSnapshotTotal() == null) ? 0 : account.getInstanceSnapshotTotal(); + String instanceSnapshotAvailable = (fullView || instanceSnapshotLimit == -1) ? Resource.UNLIMITED : String.valueOf(instanceSnapshotLimit - instanceSnapshotTotal); + response.setInstanceSnapshotLimit(instanceSnapshotLimitDisplay); + response.setInstanceSnapshotTotal(instanceSnapshotTotal); + response.setInstanceSnapshotAvailable(instanceSnapshotAvailable); + Long templateLimit = ApiDBUtils.findCorrectResourceLimit(account.getTemplateLimit(), account.getId(), ResourceType.template); String templateLimitDisplay = (fullView || templateLimit == -1) ? Resource.UNLIMITED : String.valueOf(templateLimit); Long templateTotal = (account.getTemplateTotal() == null) ? 0 : account.getTemplateTotal(); diff --git a/server/src/main/java/com/cloud/api/query/dao/DomainJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/DomainJoinDaoImpl.java index b6a3370e6bcf..83d1467a4375 100644 --- a/server/src/main/java/com/cloud/api/query/dao/DomainJoinDaoImpl.java +++ b/server/src/main/java/com/cloud/api/query/dao/DomainJoinDaoImpl.java @@ -150,6 +150,14 @@ public void setResourceLimits(DomainJoinVO domain, boolean fullView, ResourceLim response.setSnapshotTotal(snapshotTotal); response.setSnapshotAvailable(snapshotAvail); + Long instanceSnapshotLimit = ApiDBUtils.findCorrectResourceLimitForDomain(domain.getInstanceSnapshotLimit(), ResourceType.instance_snapshot, domain.getId()); + String instanceSnapshotLimitDisplay = (fullView || instanceSnapshotLimit == -1) ? Resource.UNLIMITED : String.valueOf(instanceSnapshotLimit); + Long instanceSnapshotTotal = (domain.getInstanceSnapshotTotal() == null) ? 0 : domain.getInstanceSnapshotTotal(); + String instanceSnapshotAvailable = (fullView || instanceSnapshotLimit == -1) ? Resource.UNLIMITED : String.valueOf(instanceSnapshotLimit - instanceSnapshotTotal); + response.setInstanceSnapshotLimit(instanceSnapshotLimitDisplay); + response.setInstanceSnapshotTotal(instanceSnapshotTotal); + response.setInstanceSnapshotAvailable(instanceSnapshotAvailable); + Long templateLimit = ApiDBUtils.findCorrectResourceLimitForDomain(domain.getTemplateLimit(), ResourceType.template, domain.getId()); String templateLimitDisplay = (fullView || templateLimit == -1) ? Resource.UNLIMITED : String.valueOf(templateLimit); Long templateTotal = (domain.getTemplateTotal() == null) ? 0 : domain.getTemplateTotal(); diff --git a/server/src/main/java/com/cloud/api/query/vo/AccountJoinVO.java b/server/src/main/java/com/cloud/api/query/vo/AccountJoinVO.java index 91abd235ae84..7565e9de3037 100644 --- a/server/src/main/java/com/cloud/api/query/vo/AccountJoinVO.java +++ b/server/src/main/java/com/cloud/api/query/vo/AccountJoinVO.java @@ -135,6 +135,12 @@ public class AccountJoinVO extends BaseViewVO implements InternalIdentity, Ident @Column(name = "backupStorageTotal") private Long backupStorageTotal; + @Column(name = "instanceSnapshotLimit") + private Long instanceSnapshotLimit; + + @Column(name = "instanceSnapshotTotal") + private Long instanceSnapshotTotal; + @Column(name = "templateLimit") private Long templateLimit; @@ -331,6 +337,10 @@ public Long getBackupStorageTotal() { return backupStorageTotal; } + public Long getInstanceSnapshotLimit() { + return instanceSnapshotLimit; + } + public Long getTemplateTotal() { return templateTotal; } @@ -407,6 +417,10 @@ public Long getBackupStorageLimit() { return backupStorageLimit; } + public Long getInstanceSnapshotTotal() { + return instanceSnapshotTotal; + } + public Long getTemplateLimit() { return templateLimit; } diff --git a/server/src/main/java/com/cloud/api/query/vo/DomainJoinVO.java b/server/src/main/java/com/cloud/api/query/vo/DomainJoinVO.java index 83461d470d81..c9eb75b962c3 100644 --- a/server/src/main/java/com/cloud/api/query/vo/DomainJoinVO.java +++ b/server/src/main/java/com/cloud/api/query/vo/DomainJoinVO.java @@ -112,6 +112,12 @@ public class DomainJoinVO extends BaseViewVO implements InternalIdentity, Identi @Column(name="backupTotal") private Long backupTotal; + @Column(name = "instanceSnapshotLimit") + private Long instanceSnapshotLimit; + + @Column(name = "instanceSnapshotTotal") + private Long instanceSnapshotTotal; + @Column(name="templateLimit") private Long templateLimit; @@ -348,6 +354,10 @@ public Long getBackupStorageTotal() { return backupStorageTotal; } + public Long getInstanceSnapshotTotal() { + return instanceSnapshotTotal; + } + public Long getTemplateTotal() { return templateTotal; } @@ -498,6 +508,10 @@ public void setBackupStorageLimit(Long backupStorageLimit) { this.backupStorageLimit = backupStorageLimit; } + public Long getInstanceSnapshotLimit() { + return instanceSnapshotLimit; + } + public Long getTemplateLimit() { return templateLimit; } diff --git a/server/src/main/java/com/cloud/resourcelimit/ResourceLimitManagerImpl.java b/server/src/main/java/com/cloud/resourcelimit/ResourceLimitManagerImpl.java index 93080f8433ce..678eb7f2c87e 100644 --- a/server/src/main/java/com/cloud/resourcelimit/ResourceLimitManagerImpl.java +++ b/server/src/main/java/com/cloud/resourcelimit/ResourceLimitManagerImpl.java @@ -37,6 +37,9 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.network.dao.NetworkDomainDao; +import com.cloud.utils.Ternary; +import com.cloud.vm.snapshot.dao.VMSnapshotDao; import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.response.AccountResponse; @@ -93,7 +96,6 @@ import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.IPAddressVO; import com.cloud.network.dao.NetworkDao; -import com.cloud.network.dao.NetworkDomainDao; import com.cloud.network.vpc.dao.VpcDao; import com.cloud.offering.DiskOffering; import com.cloud.offering.ServiceOffering; @@ -120,7 +122,6 @@ import com.cloud.user.ResourceLimitService; import com.cloud.user.dao.AccountDao; import com.cloud.utils.Pair; -import com.cloud.utils.Ternary; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.DB; @@ -201,6 +202,8 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim @Inject private VlanDao _vlanDao; @Inject + private VMSnapshotDao vmSnapshotDao; + @Inject private ManagementServerHostDao managementServerHostDao; @Inject ServiceOfferingDao serviceOfferingDao; @@ -310,6 +313,7 @@ public boolean configure(final String name, final Map params) th projectResourceLimitMap.put(Resource.ResourceType.backup_storage.name(), Long.parseLong(_configDao.getValue(BackupManager.DefaultMaxProjectBackupStorage.key()))); projectResourceLimitMap.put(Resource.ResourceType.bucket.name(), Long.parseLong(_configDao.getValue(BucketApiService.DefaultMaxProjectBuckets.key()))); projectResourceLimitMap.put(Resource.ResourceType.object_storage.name(), Long.parseLong(_configDao.getValue(BucketApiService.DefaultMaxProjectObjectStorage.key()))); + projectResourceLimitMap.put(Resource.ResourceType.instance_snapshot.name(), MaxProjectInstanceSnapshot.value()); accountResourceLimitMap.put(Resource.ResourceType.public_ip.name(), Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountPublicIPs.key()))); accountResourceLimitMap.put(Resource.ResourceType.snapshot.name(), Long.parseLong(_configDao.getValue(Config.DefaultMaxAccountSnapshots.key()))); @@ -328,6 +332,7 @@ public boolean configure(final String name, final Map params) th accountResourceLimitMap.put(Resource.ResourceType.backup_storage.name(), Long.parseLong(_configDao.getValue(BackupManager.DefaultMaxAccountBackupStorage.key()))); accountResourceLimitMap.put(Resource.ResourceType.bucket.name(), Long.parseLong(_configDao.getValue(BucketApiService.DefaultMaxAccountBuckets.key()))); accountResourceLimitMap.put(Resource.ResourceType.object_storage.name(), Long.parseLong(_configDao.getValue(BucketApiService.DefaultMaxAccountObjectStorage.key()))); + accountResourceLimitMap.put(Resource.ResourceType.instance_snapshot.name(), MaxAccountInstanceSnapshot.value()); domainResourceLimitMap.put(Resource.ResourceType.public_ip.name(), Long.parseLong(_configDao.getValue(Config.DefaultMaxDomainPublicIPs.key()))); domainResourceLimitMap.put(Resource.ResourceType.snapshot.name(), Long.parseLong(_configDao.getValue(Config.DefaultMaxDomainSnapshots.key()))); @@ -346,6 +351,7 @@ public boolean configure(final String name, final Map params) th domainResourceLimitMap.put(Resource.ResourceType.backup_storage.name(), Long.parseLong(_configDao.getValue(BackupManager.DefaultMaxDomainBackupStorage.key()))); domainResourceLimitMap.put(Resource.ResourceType.bucket.name(), Long.parseLong(_configDao.getValue(BucketApiService.DefaultMaxDomainBuckets.key()))); domainResourceLimitMap.put(Resource.ResourceType.object_storage.name(), Long.parseLong(_configDao.getValue(BucketApiService.DefaultMaxDomainObjectStorage.key()))); + domainResourceLimitMap.put(Resource.ResourceType.instance_snapshot.name(), MaxDomainInstanceSnapshot.value()); } catch (NumberFormatException e) { logger.error("NumberFormatException during configuration", e); throw new ConfigurationException("Configuration failed due to NumberFormatException, see log for the stacktrace"); @@ -1332,6 +1338,8 @@ protected long recalculateAccountResourceCount(final long accountId, final Resou newCount = bucketDao.countBucketsForAccount(accountId); } else if (type == ResourceType.object_storage) { newCount = bucketDao.calculateObjectStorageAllocationForAccount(accountId); + } else if (type == Resource.ResourceType.instance_snapshot) { + newCount = (long) getAmountOfInstanceSnapshotsForAccount(accountId); } else { throw new InvalidParameterValueException("Unsupported resource type " + type); } @@ -1358,6 +1366,10 @@ protected long recalculateAccountResourceCount(final long accountId, final Resou return (newCount == null) ? 0 : newCount; } + private int getAmountOfInstanceSnapshotsForAccount(long accountId) { + return CollectionUtils.size(vmSnapshotDao.listByAccountId(accountId)); + } + protected List getVmsWithAccountAndTag(long accountId, String tag) { List states = new ArrayList<>(Arrays.asList(State.Destroyed, State.Error, State.Expunging)); if (VirtualMachineManager.ResourceCountRunningVMsonly.value()) { @@ -2259,7 +2271,11 @@ public ConfigKey[] getConfigKeys() { DefaultMaxDomainProjects, DefaultMaxAccountGpus, DefaultMaxDomainGpus, - DefaultMaxProjectGpus + DefaultMaxProjectGpus, + DefaultMaxDomainProjects, + MaxAccountInstanceSnapshot, + MaxDomainInstanceSnapshot, + MaxProjectInstanceSnapshot }; } 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 e232b980b333..300b763602ab 100644 --- a/server/src/main/java/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java @@ -28,6 +28,9 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.configuration.Resource; +import com.cloud.user.ResourceLimitService; +import com.cloud.utils.fsm.NoTransitionException; import org.apache.cloudstack.annotation.AnnotationService; import org.apache.cloudstack.annotation.dao.AnnotationDao; import org.apache.cloudstack.api.ApiConstants; @@ -112,7 +115,6 @@ import com.cloud.utils.db.TransactionCallbackWithExceptionNoReturn; import com.cloud.utils.db.TransactionStatus; import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.utils.fsm.NoTransitionException; import com.cloud.vm.VMInstanceDetailVO; import com.cloud.vm.UserVmManager; import com.cloud.vm.UserVmVO; @@ -175,6 +177,8 @@ public class VMSnapshotManagerImpl extends MutualExclusiveIdsManagerBase impleme PrimaryDataStoreDao _storagePoolDao; @Inject private AnnotationDao annotationDao; + @Inject + ResourceLimitService resourceLimitMgr; VmWorkJobHandlerProxy _jobHandlerProxy = new VmWorkJobHandlerProxy(this); @@ -339,6 +343,7 @@ public VMSnapshot allocVMSnapshot(Long vmId, String vsDisplayName, String vsDesc throw new InvalidParameterValueException("VM snapshot operation is not allowed for hypervisor type External"); } + Account owner = _accountMgr.getAccount(userVmVo.getAccountId()); // VM snapshot with memory is not supported for VGPU Vms if (snapshotMemory && _serviceOfferingDetailsDao.findDetail(userVmVo.getServiceOfferingId(), GPU.Keys.vgpuType.toString()) != null) { throw new InvalidParameterValueException("Instance Snapshot with MEMORY is not supported for vGPU enabled Instances."); @@ -435,6 +440,8 @@ public VMSnapshot allocVMSnapshot(Long vmId, String vsDisplayName, String vsDesc } } + resourceLimitMgr.checkResourceLimit(owner, Resource.ResourceType.instance_snapshot); + // check if there are other active VM snapshot tasks if (hasActiveVMSnapshotTasks(vmId)) { throw new CloudRuntimeException("There are other active Instance Snapshot tasks on the Instance, please try again later"); @@ -455,8 +462,10 @@ public VMSnapshot allocVMSnapshot(Long vmId, String vsDisplayName, String vsDesc } try { + resourceLimitMgr.incrementResourceCount(caller.getAccountId(), Resource.ResourceType.instance_snapshot); return createAndPersistVMSnapshot(userVmVo, vsDescription, vmSnapshotName, vsDisplayName, vmSnapshotType); } catch (Exception e) { + resourceLimitMgr.decrementResourceCount(caller.getAccountId(), Resource.ResourceType.instance_snapshot); String msg = e.getMessage(); logger.error("Create Instance Snapshot record failed for Instance: " + userVmVo + " due to: " + msg); } @@ -643,6 +652,8 @@ public boolean hasActiveVMSnapshotTasks(Long vmId) { @Override @ActionEvent(eventType = EventTypes.EVENT_VM_SNAPSHOT_DELETE, eventDescription = "Delete Instance Snapshots", async = true) public boolean deleteVMSnapshot(Long vmSnapshotId) { + boolean success = false; + Account caller = getCaller(); VMSnapshotVO vmSnapshot = _vmSnapshotDao.findById(vmSnapshotId); @@ -673,7 +684,7 @@ public boolean deleteVMSnapshot(Long vmSnapshotId) { VmWorkJobVO placeHolder = null; placeHolder = createPlaceHolderWork(vmSnapshot.getVmId()); try { - return orchestrateDeleteVMSnapshot(vmSnapshotId); + success = orchestrateDeleteVMSnapshot(vmSnapshotId); } finally { _workJobDao.expunge(placeHolder.getId()); } @@ -700,10 +711,13 @@ else if (jobResult instanceof Throwable) } if (jobResult instanceof Boolean) - return ((Boolean)jobResult).booleanValue(); + success = ((Boolean)jobResult).booleanValue(); + } - return false; + if (success) { + resourceLimitMgr.decrementResourceCount(caller.getAccountId(), Resource.ResourceType.instance_snapshot); } + return success; } private boolean orchestrateDeleteVMSnapshot(Long vmSnapshotId) { diff --git a/server/src/test/java/com/cloud/vm/snapshot/VMSnapshotManagerTest.java b/server/src/test/java/com/cloud/vm/snapshot/VMSnapshotManagerTest.java index 0ef131faa95b..1a3492a305c0 100644 --- a/server/src/test/java/com/cloud/vm/snapshot/VMSnapshotManagerTest.java +++ b/server/src/test/java/com/cloud/vm/snapshot/VMSnapshotManagerTest.java @@ -17,6 +17,7 @@ package com.cloud.vm.snapshot; import com.cloud.agent.AgentManager; +import com.cloud.configuration.Resource; import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InvalidParameterValueException; @@ -42,6 +43,7 @@ import com.cloud.user.Account; import com.cloud.user.AccountManager; import com.cloud.user.AccountVO; +import com.cloud.user.ResourceLimitService; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.UserDao; import com.cloud.uservm.UserVm; @@ -70,6 +72,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.mockito.Spy; @@ -144,6 +147,8 @@ public class VMSnapshotManagerTest { UserVmManager _userVmManager; @Mock private AccountVO accountVOMock; + @Mock + ResourceLimitService resourceLimitService; private static final long TEST_VM_ID = 3L; private static final long SERVICE_OFFERING_ID = 1L; @@ -198,6 +203,7 @@ public void setup() { _vmSnapshotMgr._guestOSDao = _guestOSDao; _vmSnapshotMgr._hypervisorCapabilitiesDao = _hypervisorCapabilitiesDao; _vmSnapshotMgr._serviceOfferingDetailsDao = _serviceOfferingDetailsDao; + _vmSnapshotMgr.resourceLimitMgr = resourceLimitService; doNothing().when(_accountMgr).checkAccess(any(Account.class), any(AccessType.class), any(Boolean.class), any(ControlledEntity.class)); @@ -326,6 +332,7 @@ public void testCreateVMSnapshot() throws AgentUnavailableException, OperationTi when(userVm.getAccountId()).thenReturn(accountId); when(_accountMgr.getAccount(accountId)).thenReturn(accountVOMock); when(vmMock.getState()).thenReturn(State.Running); + doNothing().when(resourceLimitService).checkResourceLimit(Mockito.eq(admin), Mockito.eq(Resource.ResourceType.instance_snapshot)); _vmSnapshotMgr.allocVMSnapshot(TEST_VM_ID, "", "", true); } diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index 19034d4c4dba..2757127ff1b3 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -1390,6 +1390,7 @@ "label.instanceport": "Instance port", "label.instances": "Instances", "label.leasedinstances": "Leased Instances", +"label.instancesnapshotlimit": "Instance snapshot limits", "label.interface.route.table": "Interface Route Table", "label.interface.router.table": "Interface Router Table", "label.intermediate.certificate": "Intermediate certificate", @@ -1676,6 +1677,7 @@ "label.maxhostspercluster": "Max hosts per Cluster", "label.maximum": "Maximum", "label.maxinstance": "Max Instances", +"label.maxinstancesnapshot": "Max. Instance snapshot", "label.maxiops": "Max IOPS", "label.maxmembers": "Max members", "label.maxmemory": "Max. memory (MiB)", diff --git a/ui/public/locales/pt_BR.json b/ui/public/locales/pt_BR.json index 8fba779b1d12..9823ac102706 100644 --- a/ui/public/locales/pt_BR.json +++ b/ui/public/locales/pt_BR.json @@ -1208,6 +1208,7 @@ "label.instancename": "Nome interno", "label.instanceport": "Instanciar porta", "label.instances": "Inst\u00e2ncias", +"label.instancesnapshotlimit": "Limite de snapshots de inst\u00e2ncias", "label.intermediate.certificate": "Certificado intermedi\u00e1rio", "label.internal.dns.1": "DNS 1 interno", "label.internal.dns.2": "DNS 2 interno", @@ -1461,6 +1462,7 @@ "label.maxhostspercluster": "N\u00famero m\u00e1ximo de hosts por cluster", "label.maximum": "M\u00e1ximo", "label.maxinstance": "Inst\u00e2ncias m\u00e1x", +"label.maxinstancesnapshot": "Max. Snapshots de inst\u00e2ncias", "label.maxiops": "M\u00e1x IOPS", "label.maxmemory": "M\u00e1ximo de mem\u00f3ria (MiB)", "label.maxnetwork": "M\u00e1x. de redes", @@ -2571,7 +2573,6 @@ "label.vmname": "Nome da VM", "label.vms": "VMs", "label.vmscheduleactions": "A\u00e7\u00f5es", -"label.vmsnapshotlimit": "Limite de snapshots de VM", "label.vmstate": "Estado da VM", "label.vmtotal": "VMs totais", "label.vmware": "VMware", diff --git a/ui/src/components/view/ResourceCountUsage.vue b/ui/src/components/view/ResourceCountUsage.vue index c74391f3a9bc..aeb13eb22700 100644 --- a/ui/src/components/view/ResourceCountUsage.vue +++ b/ui/src/components/view/ResourceCountUsage.vue @@ -92,7 +92,7 @@ export default { return { usageList: [ 'vm', 'cpu', 'memory', 'gpu', 'primarystorage', 'volume', 'ip', 'network', - 'vpc', 'secondarystorage', 'snapshot', 'template', 'project', 'backup', 'backupstorage', 'bucket', 'objectstorage' + 'vpc', 'secondarystorage', 'snapshot', 'instancesnapshot', 'template', 'project', 'backup', 'backupstorage', 'bucket', 'objectstorage' ], taggedUsage: {}, tagData: {}, From 096a4db66d80e48f76eab0bf2109efd55e381521 Mon Sep 17 00:00:00 2001 From: Gean Jair Silva Date: Thu, 10 Sep 2026 14:16:10 -0300 Subject: [PATCH 2/2] change updateResourceLimit resourcetype description --- .../user/resource/UpdateResourceLimitCmd.java | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/resource/UpdateResourceLimitCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/resource/UpdateResourceLimitCmd.java index 5ab599baa7c4..175d44ab3757 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/resource/UpdateResourceLimitCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/resource/UpdateResourceLimitCmd.java @@ -56,20 +56,7 @@ public class UpdateResourceLimitCmd extends BaseCmd { @Parameter(name = ApiConstants.RESOURCE_TYPE, type = CommandType.INTEGER, required = true, - description = "Type of resource to update. Values are 0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11 and 12. " - + "0 - Instance. Number of Instances a user can create. " - + "1 - IP. Number of public IP addresses a user can own. " - + "2 - Volume. Number of disk volumes a user can create. " - + "3 - Snapshot. Number of Snapshots a user can create. " - + "4 - Template. Number of Templates that a user can register/create. " - + "5 - Project. Number of Projects a user can create. " - + "6 - Network. Number of guest Network a user can create. " - + "7 - VPC. Number of VPC a user can create. " - + "8 - CPU. Total number of CPU cores a user can use. " - + "9 - Memory. Total Memory (in MB) a user can use. " - + "10 - PrimaryStorage. Total primary storage space (in GiB) a user can use. " - + "11 - SecondaryStorage. Total secondary storage space (in GiB) a user can use. " - + "12 - InstanceSnapshot. Number of instance snapshots an account can own.") + description = "Type of resource to update. " + ApiConstants.RESOURCE_TYPE_DESCRIPTION) private Integer resourceType; @Parameter(name = ApiConstants.TAG, type = CommandType.STRING, description = "Tag for the resource type", since = "4.20.0")