diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 457dd2e1af4..1be892f4577 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -23,6 +23,9 @@ concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
+permissions:
+ contents: read
+
jobs:
build:
runs-on: ubuntu-22.04
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index c0422cd4bd0..c6edc7bdb20 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -23,6 +23,9 @@ concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
+permissions:
+ contents: read
+
jobs:
build:
if: github.repository == 'apache/cloudstack'
@@ -90,6 +93,7 @@ jobs:
smoke/test_nic
smoke/test_nic_adapter_type
smoke/test_non_contigiousvlan
+ smoke/test_object_stores
smoke/test_outofbandmanagement
smoke/test_outofbandmanagement_nestedplugin
smoke/test_over_provisioning
@@ -108,7 +112,8 @@ jobs:
smoke/test_reset_configuration_settings
smoke/test_reset_vm_on_reboot
smoke/test_resource_accounting
- smoke/test_resource_detail",
+ smoke/test_resource_detail
+ smoke/test_global_acls",
"smoke/test_router_dhcphosts
smoke/test_router_dns
smoke/test_router_dnsservice
diff --git a/.github/workflows/rat.yml b/.github/workflows/rat.yml
index d243fa863fe..64fa4c3da0c 100644
--- a/.github/workflows/rat.yml
+++ b/.github/workflows/rat.yml
@@ -23,6 +23,9 @@ concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
+permissions:
+ contents: read
+
jobs:
build:
runs-on: ubuntu-22.04
diff --git a/.github/workflows/ui.yml b/.github/workflows/ui.yml
index 280024b5a91..4d89977adf9 100644
--- a/.github/workflows/ui.yml
+++ b/.github/workflows/ui.yml
@@ -23,6 +23,9 @@ concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
+permissions:
+ contents: read
+
jobs:
build:
runs-on: ubuntu-22.04
diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md
index 7fe648a39fd..8293a22973a 100644
--- a/PULL_REQUEST_TEMPLATE.md
+++ b/PULL_REQUEST_TEMPLATE.md
@@ -10,10 +10,10 @@ This PR...
-
-
+
+
-
+
### Types of changes
diff --git a/agent/conf/agent.properties b/agent/conf/agent.properties
index b88da3621cd..3f07ba16237 100644
--- a/agent/conf/agent.properties
+++ b/agent/conf/agent.properties
@@ -407,3 +407,15 @@ iscsi.session.cleanup.enabled=false
# The path of an executable file/script for host health check for CloudStack to Auto Disable/Enable the host
# depending on the return value of the file/script
# agent.health.check.script.path=
+
+# Time interval (in milliseconds) between KVM heartbeats.
+# kvm.heartbeat.update.frequency=60000
+
+# Number of maximum tries to KVM heartbeats.
+# kvm.heartbeat.update.max.tries=5
+
+# Time amount (in milliseconds) for the KVM heartbeat retry sleep.
+# kvm.heartbeat.update.retry.sleep=10000
+
+# Timeout (in milliseconds) of the KVM heartbeat checker.
+# kvm.heartbeat.checker.timeout=360000
diff --git a/agent/src/main/java/com/cloud/agent/dao/impl/PropertiesStorage.java b/agent/src/main/java/com/cloud/agent/dao/impl/PropertiesStorage.java
index a1db88c86c4..87610c29f34 100644
--- a/agent/src/main/java/com/cloud/agent/dao/impl/PropertiesStorage.java
+++ b/agent/src/main/java/com/cloud/agent/dao/impl/PropertiesStorage.java
@@ -92,11 +92,14 @@ public class PropertiesStorage implements StorageComponent {
file = new File(path);
try {
if (!file.createNewFile()) {
- s_logger.error("Unable to create _file: " + file.getAbsolutePath());
+ s_logger.error(String.format("Unable to create _file: %s", file.getAbsolutePath()));
return false;
}
} catch (IOException e) {
- s_logger.error("Unable to create _file: " + file.getAbsolutePath(), e);
+ s_logger.error(String.format("Unable to create file: %s", file.getAbsolutePath()));
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug(String.format("IOException while trying to create file: %s", file.getAbsolutePath()), e);
+ }
return false;
}
}
diff --git a/agent/src/main/java/com/cloud/agent/properties/AgentProperties.java b/agent/src/main/java/com/cloud/agent/properties/AgentProperties.java
index 610c5be759f..8f51d470f07 100644
--- a/agent/src/main/java/com/cloud/agent/properties/AgentProperties.java
+++ b/agent/src/main/java/com/cloud/agent/properties/AgentProperties.java
@@ -539,10 +539,10 @@ public class AgentProperties{
/**
* Heartbeat update timeout (in ms).
* Depending on the use case, this timeout might need increasing/decreasing.
- * Data type: Integer.
- * Default value: 60000
+ * Data type: Long.
+ * Default value: 60000L
*/
- public static final Property HEARTBEAT_UPDATE_TIMEOUT = new Property<>("heartbeat.update.timeout", 60000);
+ public static final Property HEARTBEAT_UPDATE_TIMEOUT = new Property<>("heartbeat.update.timeout", 60000L);
/**
* The timeout (in seconds) to retrieve the target's domain ID when migrating a VM with KVM.
@@ -740,6 +740,38 @@ public class AgentProperties{
*/
public static final Property CONTROL_CIDR = new Property<>("control.cidr", "169.254.0.0/16");
+ /**
+ * Time interval (in milliseconds) between KVM heartbeats.
+ * This property is for KVM only.
+ * Data type: Long.
+ * Default value: 60000l
+ */
+ public static final Property KVM_HEARTBEAT_UPDATE_FREQUENCY = new Property<>("kvm.heartbeat.update.frequency", 60000L);
+
+ /**
+ * Number of maximum tries to KVM heartbeats.
+ * This property is for KVM only.
+ * Data type: Long.
+ * Default value: 5l
+ */
+ public static final Property KVM_HEARTBEAT_UPDATE_MAX_TRIES = new Property<>("kvm.heartbeat.update.max.tries", 5L);
+
+ /**
+ * Time amount (in milliseconds) for the KVM heartbeat retry sleep.
+ * This property is for KVM only.
+ * Data type: Long.
+ * Default value: 10000l
+ */
+ public static final Property KVM_HEARTBEAT_UPDATE_RETRY_SLEEP = new Property<>("kvm.heartbeat.update.retry.sleep", 10000L);
+
+ /**
+ * Timeout (in milliseconds) of the KVM heartbeat checker.
+ * This property is for KVM only.
+ * Data type: Long.
+ * Default value: 360000l
+ */
+ public static final Property KVM_HEARTBEAT_CHECKER_TIMEOUT = new Property<>("kvm.heartbeat.checker.timeout", 360000L);
+
public static class Property {
private String name;
private T defaultValue;
diff --git a/api/src/main/java/com/cloud/agent/api/StoragePoolInfo.java b/api/src/main/java/com/cloud/agent/api/StoragePoolInfo.java
index d923694a854..eb7e8813ecd 100644
--- a/api/src/main/java/com/cloud/agent/api/StoragePoolInfo.java
+++ b/api/src/main/java/com/cloud/agent/api/StoragePoolInfo.java
@@ -52,6 +52,13 @@ public class StoragePoolInfo {
this.details = details;
}
+ public StoragePoolInfo(String uuid, String host, String hostPath, String localPath, StoragePoolType poolType, long capacityBytes, long availableBytes,
+ Map details, String name) {
+ this(uuid, host, hostPath, localPath, poolType, capacityBytes, availableBytes);
+ this.details = details;
+ this.name = name;
+ }
+
public long getCapacityBytes() {
return capacityBytes;
}
diff --git a/api/src/main/java/com/cloud/event/EventTypes.java b/api/src/main/java/com/cloud/event/EventTypes.java
index 1ac8d79b9d5..5fce169ffed 100644
--- a/api/src/main/java/com/cloud/event/EventTypes.java
+++ b/api/src/main/java/com/cloud/event/EventTypes.java
@@ -29,6 +29,8 @@ import org.apache.cloudstack.api.response.PodResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.cloudstack.config.Configuration;
import org.apache.cloudstack.ha.HAConfig;
+import org.apache.cloudstack.storage.object.Bucket;
+import org.apache.cloudstack.storage.object.ObjectStore;
import org.apache.cloudstack.usage.Usage;
import org.apache.cloudstack.vm.schedule.VMSchedule;
@@ -714,6 +716,16 @@ public class EventTypes {
// SystemVM
public static final String EVENT_LIVE_PATCH_SYSTEMVM = "LIVE.PATCH.SYSTEM.VM";
+ // OBJECT STORE
+ public static final String EVENT_OBJECT_STORE_CREATE = "OBJECT.STORE.CREATE";
+ public static final String EVENT_OBJECT_STORE_DELETE = "OBJECT.STORE.DELETE";
+ public static final String EVENT_OBJECT_STORE_UPDATE = "OBJECT.STORE.UPDATE";
+
+ // BUCKETS
+ public static final String EVENT_BUCKET_CREATE = "BUCKET.CREATE";
+ public static final String EVENT_BUCKET_DELETE = "BUCKET.DELETE";
+ public static final String EVENT_BUCKET_UPDATE = "BUCKET.UPDATE";
+
static {
// TODO: need a way to force author adding event types to declare the entity details as well, with out braking
@@ -1151,6 +1163,16 @@ public class EventTypes {
entityEventDetails.put(EVENT_IMAGE_STORE_DATA_MIGRATE, ImageStore.class);
entityEventDetails.put(EVENT_IMAGE_STORE_OBJECT_DOWNLOAD, ImageStore.class);
entityEventDetails.put(EVENT_LIVE_PATCH_SYSTEMVM, "SystemVMs");
+
+ //Object Store
+ entityEventDetails.put(EVENT_OBJECT_STORE_CREATE, ObjectStore.class);
+ entityEventDetails.put(EVENT_OBJECT_STORE_UPDATE, ObjectStore.class);
+ entityEventDetails.put(EVENT_OBJECT_STORE_DELETE, ObjectStore.class);
+
+ //Buckets
+ entityEventDetails.put(EVENT_BUCKET_CREATE, Bucket.class);
+ entityEventDetails.put(EVENT_BUCKET_UPDATE, Bucket.class);
+ entityEventDetails.put(EVENT_BUCKET_DELETE, Bucket.class);
}
public static String getEntityForEvent(String eventName) {
diff --git a/api/src/main/java/com/cloud/network/NetworkService.java b/api/src/main/java/com/cloud/network/NetworkService.java
index fedde27835e..3efbc315e1a 100644
--- a/api/src/main/java/com/cloud/network/NetworkService.java
+++ b/api/src/main/java/com/cloud/network/NetworkService.java
@@ -25,6 +25,8 @@ import org.apache.cloudstack.api.command.admin.network.DedicateGuestVlanRangeCmd
import org.apache.cloudstack.api.command.admin.network.ListDedicatedGuestVlanRangesCmd;
import org.apache.cloudstack.api.command.admin.network.ListGuestVlansCmd;
import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd;
+import org.apache.cloudstack.api.command.user.address.RemoveQuarantinedIpCmd;
+import org.apache.cloudstack.api.command.user.address.UpdateQuarantinedIpCmd;
import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd;
import org.apache.cloudstack.api.command.user.network.CreateNetworkPermissionsCmd;
import org.apache.cloudstack.api.command.user.network.ListNetworkPermissionsCmd;
@@ -115,6 +117,8 @@ public interface NetworkService {
IpAddress getIp(long id);
+ IpAddress getIp(String ipAddress);
+
Network updateGuestNetwork(final UpdateNetworkCmd cmd);
/**
@@ -249,4 +253,8 @@ public interface NetworkService {
boolean resetNetworkPermissions(ResetNetworkPermissionsCmd resetNetworkPermissionsCmd);
void validateIfServiceOfferingIsActiveAndSystemVmTypeIsDomainRouter(final Long serviceOfferingId) throws InvalidParameterValueException;
+
+ PublicIpQuarantine updatePublicIpAddressInQuarantine(UpdateQuarantinedIpCmd cmd);
+
+ void removePublicIpAddressFromQuarantine(RemoveQuarantinedIpCmd cmd);
}
diff --git a/api/src/main/java/com/cloud/network/PublicIpQuarantine.java b/api/src/main/java/com/cloud/network/PublicIpQuarantine.java
new file mode 100644
index 00000000000..d1ec98afe46
--- /dev/null
+++ b/api/src/main/java/com/cloud/network/PublicIpQuarantine.java
@@ -0,0 +1,36 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.network;
+
+import org.apache.cloudstack.api.Identity;
+import org.apache.cloudstack.api.InternalIdentity;
+
+import java.util.Date;
+
+public interface PublicIpQuarantine extends InternalIdentity, Identity {
+ Long getPublicIpAddressId();
+
+ Long getPreviousOwnerId();
+
+ Date getEndDate();
+
+ String getRemovalReason();
+
+ Date getRemoved();
+
+ Date getCreated();
+}
diff --git a/api/src/main/java/com/cloud/network/VNF.java b/api/src/main/java/com/cloud/network/VNF.java
index ebc11c1f39b..e7a7fb01cb9 100644
--- a/api/src/main/java/com/cloud/network/VNF.java
+++ b/api/src/main/java/com/cloud/network/VNF.java
@@ -68,7 +68,6 @@ public class VNF {
}
public enum VnfDetail {
- ICON,
VERSION,
VENDOR,
MAINTAINER
diff --git a/api/src/main/java/com/cloud/server/ResourceTag.java b/api/src/main/java/com/cloud/server/ResourceTag.java
index 89ec5b905c9..9bbb5d43eae 100644
--- a/api/src/main/java/com/cloud/server/ResourceTag.java
+++ b/api/src/main/java/com/cloud/server/ResourceTag.java
@@ -30,7 +30,7 @@ public interface ResourceTag extends ControlledEntity, Identity, InternalIdentit
public enum ResourceObjectType {
UserVm(true, true, true),
Template(true, true, true),
- VnfTemplate(true, true, true),
+ VnfTemplate(false, false, true),
ISO(true, false, true),
Volume(true, true),
Snapshot(true, false),
@@ -69,7 +69,8 @@ public interface ResourceTag extends ControlledEntity, Identity, InternalIdentit
GuestOs(false, true),
NetworkOffering(false, true),
VpcOffering(true, false),
- Domain(false, false, true);
+ Domain(false, false, true),
+ ObjectStore(false, false, true);
ResourceObjectType(boolean resourceTagsSupport, boolean resourceMetadataSupport) {
diff --git a/api/src/main/java/com/cloud/storage/DataStoreRole.java b/api/src/main/java/com/cloud/storage/DataStoreRole.java
index cc20cc0ce96..185e370159c 100644
--- a/api/src/main/java/com/cloud/storage/DataStoreRole.java
+++ b/api/src/main/java/com/cloud/storage/DataStoreRole.java
@@ -21,7 +21,7 @@ package com.cloud.storage;
import com.cloud.utils.exception.CloudRuntimeException;
public enum DataStoreRole {
- Primary("primary"), Image("image"), ImageCache("imagecache"), Backup("backup");
+ Primary("primary"), Image("image"), ImageCache("imagecache"), Backup("backup"), Object("object");
public boolean isImageStore() {
return (role.equalsIgnoreCase("image") || role.equalsIgnoreCase("imagecache")) ? true : false;
@@ -45,6 +45,8 @@ public enum DataStoreRole {
return ImageCache;
} else if (role.equalsIgnoreCase("backup")) {
return Backup;
+ } else if (role.equalsIgnoreCase("object")) {
+ return Object;
} else {
throw new CloudRuntimeException("can't identify the role");
}
diff --git a/api/src/main/java/com/cloud/storage/StorageService.java b/api/src/main/java/com/cloud/storage/StorageService.java
index bb086ad05cb..c3609cfd8ee 100644
--- a/api/src/main/java/com/cloud/storage/StorageService.java
+++ b/api/src/main/java/com/cloud/storage/StorageService.java
@@ -24,9 +24,11 @@ import org.apache.cloudstack.api.command.admin.storage.CancelPrimaryStorageMaint
import org.apache.cloudstack.api.command.admin.storage.CreateSecondaryStagingStoreCmd;
import org.apache.cloudstack.api.command.admin.storage.CreateStoragePoolCmd;
import org.apache.cloudstack.api.command.admin.storage.DeleteImageStoreCmd;
+import org.apache.cloudstack.api.command.admin.storage.DeleteObjectStoragePoolCmd;
import org.apache.cloudstack.api.command.admin.storage.DeletePoolCmd;
import org.apache.cloudstack.api.command.admin.storage.DeleteSecondaryStagingStoreCmd;
import org.apache.cloudstack.api.command.admin.storage.SyncStoragePoolCmd;
+import org.apache.cloudstack.api.command.admin.storage.UpdateObjectStoragePoolCmd;
import org.apache.cloudstack.api.command.admin.storage.UpdateStoragePoolCmd;
import com.cloud.exception.DiscoveryException;
@@ -34,6 +36,11 @@ import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.ResourceInUseException;
import com.cloud.exception.ResourceUnavailableException;
+import org.apache.cloudstack.api.command.admin.storage.heuristics.CreateSecondaryStorageSelectorCmd;
+import org.apache.cloudstack.api.command.admin.storage.heuristics.RemoveSecondaryStorageSelectorCmd;
+import org.apache.cloudstack.api.command.admin.storage.heuristics.UpdateSecondaryStorageSelectorCmd;
+import org.apache.cloudstack.secstorage.heuristics.Heuristic;
+import org.apache.cloudstack.storage.object.ObjectStore;
public interface StorageService {
/**
@@ -109,4 +116,15 @@ public interface StorageService {
StoragePool syncStoragePool(SyncStoragePoolCmd cmd);
+ Heuristic createSecondaryStorageHeuristic(CreateSecondaryStorageSelectorCmd cmd);
+
+ Heuristic updateSecondaryStorageHeuristic(UpdateSecondaryStorageSelectorCmd cmd);
+
+ void removeSecondaryStorageHeuristic(RemoveSecondaryStorageSelectorCmd cmd);
+
+ ObjectStore discoverObjectStore(String name, String url, String providerName, Map details) throws IllegalArgumentException, DiscoveryException, InvalidParameterValueException;
+
+ boolean deleteObjectStore(DeleteObjectStoragePoolCmd cmd);
+
+ ObjectStore updateObjectStore(Long id, UpdateObjectStoragePoolCmd cmd);
}
diff --git a/api/src/main/java/org/apache/cloudstack/annotation/AnnotationService.java b/api/src/main/java/org/apache/cloudstack/annotation/AnnotationService.java
index 51c6286a9d5..64bd96d9a9b 100644
--- a/api/src/main/java/org/apache/cloudstack/annotation/AnnotationService.java
+++ b/api/src/main/java/org/apache/cloudstack/annotation/AnnotationService.java
@@ -45,7 +45,7 @@ public interface AnnotationService {
SERVICE_OFFERING(false), DISK_OFFERING(false), NETWORK_OFFERING(false),
ZONE(false), POD(false), CLUSTER(false), HOST(false), DOMAIN(false),
PRIMARY_STORAGE(false), SECONDARY_STORAGE(false), VR(false), SYSTEM_VM(false),
- AUTOSCALE_VM_GROUP(true), MANAGEMENT_SERVER(false),;
+ AUTOSCALE_VM_GROUP(true), MANAGEMENT_SERVER(false), OBJECT_STORAGE(false);
private final boolean usersAllowed;
@@ -78,6 +78,7 @@ public interface AnnotationService {
list.add(EntityType.VR);
list.add(EntityType.SYSTEM_VM);
list.add(EntityType.MANAGEMENT_SERVER);
+ list.add(EntityType.OBJECT_STORAGE);
if (roleType != RoleType.DomainAdmin) {
list.add(EntityType.DOMAIN);
list.add(EntityType.SERVICE_OFFERING);
diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiCommandResourceType.java b/api/src/main/java/org/apache/cloudstack/api/ApiCommandResourceType.java
index 9267ca6fa96..affceb4e3f9 100644
--- a/api/src/main/java/org/apache/cloudstack/api/ApiCommandResourceType.java
+++ b/api/src/main/java/org/apache/cloudstack/api/ApiCommandResourceType.java
@@ -78,7 +78,9 @@ public enum ApiCommandResourceType {
VmSnapshot(com.cloud.vm.snapshot.VMSnapshot.class),
Role(org.apache.cloudstack.acl.Role.class),
VpnCustomerGateway(com.cloud.network.Site2SiteCustomerGateway.class),
- ManagementServer(org.apache.cloudstack.management.ManagementServerHost.class);
+ ManagementServer(org.apache.cloudstack.management.ManagementServerHost.class),
+ ObjectStore(org.apache.cloudstack.storage.object.ObjectStore.class),
+ Bucket(org.apache.cloudstack.storage.object.Bucket.class);
private final Class> clazz;
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 ee64caabed0..82273cfdd0c 100644
--- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
@@ -224,6 +224,8 @@ public class ApiConstants {
public static final String INSTANCES_STATS_USER_ONLY = "instancesstatsuseronly";
public static final String PREFIX = "prefix";
public static final String PREVIOUS_ACL_RULE_ID = "previousaclruleid";
+ public static final String PREVIOUS_OWNER_ID = "previousownerid";
+ public static final String PREVIOUS_OWNER_NAME = "previousownername";
public static final String NEXT_ACL_RULE_ID = "nextaclruleid";
public static final String MOVE_ACL_CONSISTENCY_HASH = "aclconsistencyhash";
public static final String IMAGE_PATH = "imagepath";
@@ -404,6 +406,7 @@ public class ApiConstants {
public static final String SHOW_CAPACITIES = "showcapacities";
public static final String SHOW_REMOVED = "showremoved";
public static final String SHOW_RESOURCE_ICON = "showicon";
+ public static final String SHOW_INACTIVE = "showinactive";
public static final String SHOW_UNIQUE = "showunique";
public static final String SIGNATURE = "signature";
public static final String SIGNATURE_VERSION = "signatureversion";
@@ -802,6 +805,7 @@ public class ApiConstants {
public static final String IPSEC_PSK = "ipsecpsk";
public static final String GUEST_IP = "guestip";
public static final String REMOVED = "removed";
+ public static final String REMOVAL_REASON = "removalreason";
public static final String COMPLETED = "completed";
public static final String IKE_VERSION = "ikeversion";
public static final String IKE_POLICY = "ikepolicy";
@@ -1059,11 +1063,20 @@ public class ApiConstants {
public static final String MTU = "mtu";
public static final String AUTO_ENABLE_KVM_HOST = "autoenablekvmhost";
public static final String LIST_APIS = "listApis";
+ public static final String OBJECT_STORAGE_ID = "objectstorageid";
+ public static final String VERSIONING = "versioning";
+ public static final String OBJECT_LOCKING = "objectlocking";
+ public static final String ENCRYPTION = "encryption";
+ public static final String QUOTA = "quota";
+ public static final String ACCESS_KEY = "accesskey";
public static final String SOURCE_NAT_IP = "sourcenatipaddress";
public static final String SOURCE_NAT_IP_ID = "sourcenatipaddressid";
public static final String HAS_RULES = "hasrules";
public static final String NSX_DETAIL_KEY = "forNsx";
+ public static final String OBJECT_STORAGE = "objectstore";
+ public static final String HEURISTIC_RULE = "heuristicrule";
+ public static final String HEURISTIC_TYPE_VALID_OPTIONS = "Valid options are: ISO, SNAPSHOT, TEMPLATE and VOLUME.";
public static final String MANAGEMENT = "management";
public static final String IS_VNF = "isvnf";
public static final String VNF_NICS = "vnfnics";
@@ -1076,6 +1089,10 @@ public class ApiConstants {
public static final String CLIENT_ID = "clientid";
public static final String REDIRECT_URI = "redirecturi";
+ public static final String IS_TAG_A_RULE = "istagarule";
+
+ public static final String PARAMETER_DESCRIPTION_IS_TAG_A_RULE = "Whether the informed tag is a JS interpretable rule or not.";
+
/**
* This enum specifies IO Drivers, each option controls specific policies on I/O.
* Qemu guests support "threads" and "native" options Since 0.8.8 ; "io_uring" is supported Since 6.3.0 (QEMU 5.0).
diff --git a/api/src/main/java/org/apache/cloudstack/api/BaseCmd.java b/api/src/main/java/org/apache/cloudstack/api/BaseCmd.java
index 0b80cfc8229..f32922819b0 100644
--- a/api/src/main/java/org/apache/cloudstack/api/BaseCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/BaseCmd.java
@@ -42,6 +42,7 @@ import org.apache.cloudstack.network.element.InternalLoadBalancerElementService;
import org.apache.cloudstack.network.lb.ApplicationLoadBalancerService;
import org.apache.cloudstack.network.lb.InternalLoadBalancerVMService;
import org.apache.cloudstack.query.QueryService;
+import org.apache.cloudstack.storage.object.BucketApiService;
import org.apache.cloudstack.storage.ImageStoreService;
import org.apache.cloudstack.storage.template.VnfTemplateManager;
import org.apache.cloudstack.usage.UsageService;
@@ -216,6 +217,9 @@ public abstract class BaseCmd {
public Ipv6Service ipv6Service;
@Inject
public VnfTemplateManager vnfTemplateManager;
+ @Inject
+ public BucketApiService _bucketService;
+
public abstract void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException,
ResourceAllocationException, NetworkRuleConflictException;
diff --git a/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java b/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java
index 1a0df486298..0bddf6d2994 100644
--- a/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java
+++ b/api/src/main/java/org/apache/cloudstack/api/ResponseGenerator.java
@@ -22,6 +22,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
+import org.apache.cloudstack.storage.object.Bucket;
import org.apache.cloudstack.affinity.AffinityGroup;
import org.apache.cloudstack.affinity.AffinityGroupResponse;
import org.apache.cloudstack.api.ApiConstants.HostDetails;
@@ -37,6 +38,7 @@ import org.apache.cloudstack.api.response.AutoScaleVmProfileResponse;
import org.apache.cloudstack.api.response.BackupOfferingResponse;
import org.apache.cloudstack.api.response.BackupResponse;
import org.apache.cloudstack.api.response.BackupScheduleResponse;
+import org.apache.cloudstack.api.response.BucketResponse;
import org.apache.cloudstack.api.response.CapacityResponse;
import org.apache.cloudstack.api.response.ClusterResponse;
import org.apache.cloudstack.api.response.ConditionResponse;
@@ -64,6 +66,7 @@ import org.apache.cloudstack.api.response.HostResponse;
import org.apache.cloudstack.api.response.HypervisorCapabilitiesResponse;
import org.apache.cloudstack.api.response.HypervisorGuestOsNamesResponse;
import org.apache.cloudstack.api.response.IPAddressResponse;
+import org.apache.cloudstack.api.response.IpQuarantineResponse;
import org.apache.cloudstack.api.response.ImageStoreResponse;
import org.apache.cloudstack.api.response.InstanceGroupResponse;
import org.apache.cloudstack.api.response.InternalLoadBalancerElementResponse;
@@ -81,6 +84,7 @@ import org.apache.cloudstack.api.response.NetworkPermissionsResponse;
import org.apache.cloudstack.api.response.NetworkResponse;
import org.apache.cloudstack.api.response.NicResponse;
import org.apache.cloudstack.api.response.NicSecondaryIpResponse;
+import org.apache.cloudstack.api.response.ObjectStoreResponse;
import org.apache.cloudstack.api.response.OvsProviderResponse;
import org.apache.cloudstack.api.response.PhysicalNetworkResponse;
import org.apache.cloudstack.api.response.PodResponse;
@@ -100,6 +104,7 @@ import org.apache.cloudstack.api.response.ResourceTagResponse;
import org.apache.cloudstack.api.response.RollingMaintenanceResponse;
import org.apache.cloudstack.api.response.RouterHealthCheckResultResponse;
import org.apache.cloudstack.api.response.SSHKeyPairResponse;
+import org.apache.cloudstack.api.response.SecondaryStorageHeuristicsResponse;
import org.apache.cloudstack.api.response.SecurityGroupResponse;
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
import org.apache.cloudstack.api.response.ServiceResponse;
@@ -144,6 +149,8 @@ import org.apache.cloudstack.network.lb.ApplicationLoadBalancerRule;
import org.apache.cloudstack.region.PortableIp;
import org.apache.cloudstack.region.PortableIpRange;
import org.apache.cloudstack.region.Region;
+import org.apache.cloudstack.secstorage.heuristics.Heuristic;
+import org.apache.cloudstack.storage.object.ObjectStore;
import org.apache.cloudstack.usage.Usage;
import com.cloud.capacity.Capacity;
@@ -169,6 +176,7 @@ import com.cloud.network.OvsProvider;
import com.cloud.network.PhysicalNetwork;
import com.cloud.network.PhysicalNetworkServiceProvider;
import com.cloud.network.PhysicalNetworkTrafficType;
+import com.cloud.network.PublicIpQuarantine;
import com.cloud.network.RemoteAccessVpn;
import com.cloud.network.RouterHealthCheckResult;
import com.cloud.network.Site2SiteCustomerGateway;
@@ -529,4 +537,12 @@ public interface ResponseGenerator {
DirectDownloadCertificateHostStatusResponse createDirectDownloadCertificateProvisionResponse(Long certificateId, Long hostId, Pair result);
FirewallResponse createIpv6FirewallRuleResponse(FirewallRule acl);
+
+ SecondaryStorageHeuristicsResponse createSecondaryStorageSelectorResponse(Heuristic heuristic);
+
+ IpQuarantineResponse createQuarantinedIpsResponse(PublicIpQuarantine publicIp);
+
+ ObjectStoreResponse createObjectStoreResponse(ObjectStore os);
+
+ BucketResponse createBucketResponse(Bucket bucket);
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java
index 75fe339b710..b8668f61ca4 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java
@@ -119,6 +119,10 @@ public class ListHostsCmd extends BaseListCmd {
return id;
}
+ public void setId(Long id) {
+ this.id = id;
+ }
+
public String getHostName() {
return hostName;
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/host/UpdateHostCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/host/UpdateHostCmd.java
index e3ff130e2d4..9cf47a9c4b9 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/host/UpdateHostCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/host/UpdateHostCmd.java
@@ -60,6 +60,9 @@ public class UpdateHostCmd extends BaseCmd {
@Parameter(name = ApiConstants.HOST_TAGS, type = CommandType.LIST, collectionType = CommandType.STRING, description = "list of tags to be added to the host")
private List hostTags;
+ @Parameter(name = ApiConstants.IS_TAG_A_RULE, type = CommandType.BOOLEAN, description = ApiConstants.PARAMETER_DESCRIPTION_IS_TAG_A_RULE)
+ private Boolean isTagARule;
+
@Parameter(name = ApiConstants.URL, type = CommandType.STRING, description = "the new uri for the secondary storage: nfs://host/path")
private String url;
@@ -90,6 +93,10 @@ public class UpdateHostCmd extends BaseCmd {
return hostTags;
}
+ public Boolean getIsTagARule() {
+ return isTagARule;
+ }
+
public String getUrl() {
return url;
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/AddObjectStoragePoolCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/AddObjectStoragePoolCmd.java
new file mode 100644
index 00000000000..a538962e076
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/AddObjectStoragePoolCmd.java
@@ -0,0 +1,132 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.admin.storage;
+
+import org.apache.cloudstack.storage.object.ObjectStore;
+import com.cloud.user.Account;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.ObjectStoreResponse;
+import org.apache.log4j.Logger;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+@APICommand(name = "addObjectStoragePool", description = "Adds a object storage pool", responseObject = ObjectStoreResponse.class, since = "4.19.0",
+ requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
+public class AddObjectStoragePoolCmd extends BaseCmd {
+ public static final Logger s_logger = Logger.getLogger(AddObjectStoragePoolCmd.class.getName());
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+
+ @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "the name for the object store")
+ private String name;
+
+ @Parameter(name = ApiConstants.URL, type = CommandType.STRING, length = 2048, required = true, description = "the URL for the object store")
+ private String url;
+
+ @Parameter(name = ApiConstants.PROVIDER, type = CommandType.STRING, required = true, description = "the object store provider name")
+ private String providerName;
+
+ @Parameter(name = ApiConstants.DETAILS,
+ type = CommandType.MAP,
+ description = "the details for the object store. Example: details[0].key=accesskey&details[0].value=s389ddssaa&details[1].key=secretkey&details[1].value=8dshfsss")
+ private Map details;
+
+ @Parameter(name = ApiConstants.TAGS, type = CommandType.STRING, description = "the tags for the storage pool")
+ private String tags;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ public String getUrl() {
+ return url;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Map getDetails() {
+ Map detailsMap = null;
+ if (details != null && !details.isEmpty()) {
+ detailsMap = new HashMap();
+ Collection> props = details.values();
+ Iterator> iter = props.iterator();
+ while (iter.hasNext()) {
+ HashMap detail = (HashMap)iter.next();
+ String key = detail.get(ApiConstants.KEY);
+ String value = detail.get(ApiConstants.VALUE);
+ detailsMap.put(key, value);
+ }
+ }
+ return detailsMap;
+ }
+
+ public String getProviderName() {
+ return providerName;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public void setProviderName(String providerName) {
+ this.providerName = providerName;
+ }
+
+ public void setDetails(Map details) {
+ this.details = details;
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
+ @Override
+ public long getEntityOwnerId() {
+ return Account.ACCOUNT_ID_SYSTEM;
+ }
+
+ @Override
+ public void execute(){
+ try{
+ ObjectStore result = _storageService.discoverObjectStore(getName(), getUrl(), getProviderName(), getDetails());
+ ObjectStoreResponse storeResponse = null;
+ if (result != null) {
+ storeResponse = _responseGenerator.createObjectStoreResponse(result);
+ storeResponse.setResponseName(getCommandName());
+ storeResponse.setObjectName("objectstore");
+ setResponseObject(storeResponse);
+ } else {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add object storage");
+ }
+ } catch (Exception ex) {
+ s_logger.error("Exception: ", ex);
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage());
+ }
+ }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/CreateStoragePoolCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/CreateStoragePoolCmd.java
index 0eacc5cda6b..477d7570dfa 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/CreateStoragePoolCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/CreateStoragePoolCmd.java
@@ -90,6 +90,9 @@ public class CreateStoragePoolCmd extends BaseCmd {
description = "hypervisor type of the hosts in zone that will be attached to this storage pool. KVM, VMware supported as of now.")
private String hypervisor;
+ @Parameter(name = ApiConstants.IS_TAG_A_RULE, type = CommandType.BOOLEAN, description = ApiConstants.PARAMETER_DESCRIPTION_IS_TAG_A_RULE)
+ private Boolean isTagARule;
+
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@@ -146,6 +149,10 @@ public class CreateStoragePoolCmd extends BaseCmd {
return hypervisor;
}
+ public Boolean isTagARule() {
+ return this.isTagARule;
+ }
+
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/DeleteObjectStoragePoolCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/DeleteObjectStoragePoolCmd.java
new file mode 100644
index 00000000000..ed305d9689d
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/DeleteObjectStoragePoolCmd.java
@@ -0,0 +1,69 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.admin.storage;
+
+import com.cloud.user.Account;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.ObjectStoreResponse;
+import org.apache.cloudstack.api.response.SuccessResponse;
+import org.apache.log4j.Logger;
+
+@APICommand(name = "deleteObjectStoragePool", description = "Deletes an Object Storage Pool", responseObject = SuccessResponse.class, since = "4.19.0",
+ requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
+public class DeleteObjectStoragePoolCmd extends BaseCmd {
+ public static final Logger s_logger = Logger.getLogger(DeleteObjectStoragePoolCmd.class.getName());
+
+ // ///////////////////////////////////////////////////
+ // ////////////// API parameters /////////////////////
+ // ///////////////////////////////////////////////////
+
+ @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = ObjectStoreResponse.class, required = true, description = "The Object Storage ID.")
+ private Long id;
+
+ // ///////////////////////////////////////////////////
+ // ///////////////// Accessors ///////////////////////
+ // ///////////////////////////////////////////////////
+
+ public Long getId() {
+ return id;
+ }
+
+ // ///////////////////////////////////////////////////
+ // ///////////// API Implementation///////////////////
+ // ///////////////////////////////////////////////////
+
+ @Override
+ public long getEntityOwnerId() {
+ return Account.ACCOUNT_ID_SYSTEM;
+ }
+
+ @Override
+ public void execute() {
+ boolean result = _storageService.deleteObjectStore(this);
+ if (result) {
+ SuccessResponse response = new SuccessResponse(getCommandName());
+ this.setResponseObject(response);
+ } else {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete object store");
+ }
+ }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/ListObjectStoragePoolsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/ListObjectStoragePoolsCmd.java
new file mode 100644
index 00000000000..9d8d8eccc3c
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/ListObjectStoragePoolsCmd.java
@@ -0,0 +1,79 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.admin.storage;
+
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseListCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.api.response.ObjectStoreResponse;
+import org.apache.log4j.Logger;
+
+@APICommand(name = "listObjectStoragePools", description = "Lists object storage pools.", responseObject = ObjectStoreResponse.class, since = "4.19.0",
+ requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
+ authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
+public class ListObjectStoragePoolsCmd extends BaseListCmd {
+ public static final Logger s_logger = Logger.getLogger(ListObjectStoragePoolsCmd.class.getName());
+
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+
+ @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "the name of the object store")
+ private String storeName;
+
+ @Parameter(name = ApiConstants.PROVIDER, type = CommandType.STRING, description = "the object store provider")
+ private String provider;
+
+ @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = ObjectStoreResponse.class, description = "the ID of the storage pool")
+ private Long id;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+
+ public String getStoreName() {
+ return storeName;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public String getProvider() {
+ return provider;
+ }
+
+ public void setProvider(String provider) {
+ this.provider = provider;
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
+ @Override
+ public void execute() {
+ ListResponse response = _queryService.searchForObjectStores(this);
+ response.setResponseName(getCommandName());
+ this.setResponseObject(response);
+ }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/ListStoragePoolsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/ListStoragePoolsCmd.java
index 209aaac279c..6923353b3bf 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/ListStoragePoolsCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/ListStoragePoolsCmd.java
@@ -24,6 +24,7 @@ import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseListCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.ClusterResponse;
+import org.apache.cloudstack.api.response.HostResponse;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.PodResponse;
import org.apache.cloudstack.api.response.StoragePoolResponse;
@@ -63,16 +64,25 @@ public class ListStoragePoolsCmd extends BaseListCmd {
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = StoragePoolResponse.class, description = "the ID of the storage pool")
private Long id;
- @Parameter(name = ApiConstants.SCOPE, type = CommandType.STRING, entityType = StoragePoolResponse.class, description = "the ID of the storage pool")
+ @Parameter(name = ApiConstants.SCOPE, type = CommandType.STRING, entityType = StoragePoolResponse.class, description = "the scope of the storage pool")
private String scope;
+
@Parameter(name = ApiConstants.STATUS, type = CommandType.STRING, description = "the status of the storage pool")
private String status;
+ @Parameter(name = ApiConstants.HOST_ID, type = CommandType.UUID, entityType = HostResponse.class, description = "host ID of the storage pools")
+ private Long hostId;
+
+
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
+ public Long getHostId() {
+ return hostId;
+ }
+
public Long getClusterId() {
return clusterId;
}
@@ -81,6 +91,10 @@ public class ListStoragePoolsCmd extends BaseListCmd {
return ipAddress;
}
+ public void setIpAddress(String ipAddress) {
+ this.ipAddress = ipAddress;
+ }
+
public String getStoragePoolName() {
return storagePoolName;
}
@@ -108,6 +122,15 @@ public class ListStoragePoolsCmd extends BaseListCmd {
public void setId(Long id) {
this.id = id;
}
+
+ public String getScope() {
+ return scope;
+ }
+
+ public void setScope(String scope) {
+ this.scope = scope;
+ }
+
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@@ -123,8 +146,4 @@ public class ListStoragePoolsCmd extends BaseListCmd {
response.setResponseName(getCommandName());
this.setResponseObject(response);
}
-
- public String getScope() {
- return scope;
- }
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/UpdateObjectStoragePoolCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/UpdateObjectStoragePoolCmd.java
new file mode 100644
index 00000000000..497179d25ef
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/UpdateObjectStoragePoolCmd.java
@@ -0,0 +1,93 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.cloudstack.api.command.admin.storage;
+
+import org.apache.cloudstack.storage.object.ObjectStore;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.ObjectStoreResponse;
+import org.apache.cloudstack.context.CallContext;
+
+@APICommand(name = UpdateObjectStoragePoolCmd.APINAME, description = "Updates object storage pool", responseObject = ObjectStoreResponse.class, entityType = {ObjectStore.class},
+ requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.19.0")
+public class UpdateObjectStoragePoolCmd extends BaseCmd {
+ public static final String APINAME = "updateObjectStoragePool";
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+ @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = ObjectStoreResponse.class, required = true, description = "Object Store ID")
+ private Long id;
+
+ @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "the name for the object store")
+ private String name;
+
+ @Parameter(name = ApiConstants.URL, type = CommandType.STRING, description = "the url for the object store")
+ private String url;
+
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ public Long getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
+ @Override
+ public void execute() {
+ ObjectStore result = _storageService.updateObjectStore(getId(), this);
+
+ ObjectStoreResponse storeResponse = null;
+ if (result != null) {
+ storeResponse = _responseGenerator.createObjectStoreResponse(result);
+ storeResponse.setResponseName(getCommandName());
+ storeResponse.setObjectName("objectstore");
+ setResponseObject(storeResponse);
+ } else {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update object storage");
+ }
+ }
+
+ @Override
+ public String getCommandName() {
+ return APINAME;
+ }
+
+
+ @Override
+ public long getEntityOwnerId() {
+ return CallContext.current().getCallingAccountId();
+ }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/UpdateStoragePoolCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/UpdateStoragePoolCmd.java
index 9e34684a09d..09ec5394921 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/UpdateStoragePoolCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/UpdateStoragePoolCmd.java
@@ -61,6 +61,9 @@ public class UpdateStoragePoolCmd extends BaseCmd {
" enable it back.")
private Boolean enabled;
+ @Parameter(name = ApiConstants.IS_TAG_A_RULE, type = CommandType.BOOLEAN, description = ApiConstants.PARAMETER_DESCRIPTION_IS_TAG_A_RULE)
+ private Boolean isTagARule;
+
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@@ -89,6 +92,10 @@ public class UpdateStoragePoolCmd extends BaseCmd {
return enabled;
}
+ public Boolean isTagARule() {
+ return isTagARule;
+ }
+
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/heuristics/CreateSecondaryStorageSelectorCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/heuristics/CreateSecondaryStorageSelectorCmd.java
new file mode 100644
index 00000000000..a0e99b55971
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/heuristics/CreateSecondaryStorageSelectorCmd.java
@@ -0,0 +1,93 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.admin.storage.heuristics;
+
+import com.cloud.user.Account;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.response.SecondaryStorageHeuristicsResponse;
+import org.apache.cloudstack.api.response.ZoneResponse;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.secstorage.heuristics.Heuristic;
+
+import static org.apache.cloudstack.api.ApiConstants.HEURISTIC_TYPE_VALID_OPTIONS;
+
+@APICommand(name = "createSecondaryStorageSelector", description = "Creates a secondary storage selector, described by the heuristic rule.", since = "4.19.0", responseObject =
+ SecondaryStorageHeuristicsResponse.class, entityType = {Heuristic.class}, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, authorized = {RoleType.Admin})
+public class CreateSecondaryStorageSelectorCmd extends BaseCmd{
+
+ @Parameter(name = ApiConstants.NAME, required = true, type = CommandType.STRING, description = "The name identifying the heuristic rule.")
+ private String name;
+
+ @Parameter(name = ApiConstants.DESCRIPTION, required = true, type = BaseCmd.CommandType.STRING, description = "The description of the heuristic rule.")
+ private String description;
+
+ @Parameter(name = ApiConstants.ZONE_ID, required = true, entityType = ZoneResponse.class, type = BaseCmd.CommandType.UUID, description = "The zone in which the heuristic " +
+ "rule will be applied.")
+ private Long zoneId;
+
+ @Parameter(name = ApiConstants.TYPE, required = true, type = BaseCmd.CommandType.STRING, description =
+ "The resource type directed to a specific secondary storage by the selector. " + HEURISTIC_TYPE_VALID_OPTIONS)
+ private String type;
+
+ @Parameter(name = ApiConstants.HEURISTIC_RULE, required = true, type = BaseCmd.CommandType.STRING, description = "The heuristic rule, in JavaScript language. It is required " +
+ "that it returns the UUID of a secondary storage pool. An example of a rule is `if (snapshot.hypervisorType === 'KVM') { '7832f261-c602-4e8e-8580-2496ffbbc45d'; " +
+ "}` would allocate all snapshots with the KVM hypervisor to the specified secondary storage UUID.", length = 65535)
+ private String heuristicRule;
+
+ public String getName() {
+ return name;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public Long getZoneId() {
+ return zoneId;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public String getHeuristicRule() {
+ return heuristicRule;
+ }
+
+ @Override
+ public void execute() {
+ Heuristic heuristic = _storageService.createSecondaryStorageHeuristic(this);
+
+ if (heuristic == null) {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create a secondary storage selector.");
+ }
+
+ SecondaryStorageHeuristicsResponse response = _responseGenerator.createSecondaryStorageSelectorResponse(heuristic);
+ response.setResponseName(getCommandName());
+ this.setResponseObject(response);
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return Account.ACCOUNT_ID_SYSTEM;
+ }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/heuristics/ListSecondaryStorageSelectorsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/heuristics/ListSecondaryStorageSelectorsCmd.java
new file mode 100644
index 00000000000..c437cd660e7
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/heuristics/ListSecondaryStorageSelectorsCmd.java
@@ -0,0 +1,63 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.admin.storage.heuristics;
+
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseListCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.api.response.SecondaryStorageHeuristicsResponse;
+import org.apache.cloudstack.api.response.ZoneResponse;
+import org.apache.cloudstack.secstorage.heuristics.Heuristic;
+
+import static org.apache.cloudstack.api.ApiConstants.HEURISTIC_TYPE_VALID_OPTIONS;
+
+@APICommand(name = "listSecondaryStorageSelectors", description = "Lists the secondary storage selectors and their rules.", since = "4.19.0", responseObject =
+ SecondaryStorageHeuristicsResponse.class, requestHasSensitiveInfo = false, entityType = {Heuristic.class}, responseHasSensitiveInfo = false, authorized = {RoleType.Admin})
+public class ListSecondaryStorageSelectorsCmd extends BaseListCmd {
+
+ @Parameter(name = ApiConstants.ZONE_ID, required = true, entityType = ZoneResponse.class, type = CommandType.UUID, description = "The zone ID to be used in the search filter.")
+ private Long zoneId;
+
+ @Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, description =
+ "Whether to filter the selectors by type and, if so, which one. " + HEURISTIC_TYPE_VALID_OPTIONS)
+ private String type;
+
+ @Parameter(name = ApiConstants.SHOW_REMOVED, type = CommandType.BOOLEAN, description = "Show removed heuristics.")
+ private boolean showRemoved = false;
+
+ public Long getZoneId() {
+ return zoneId;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public boolean isShowRemoved() {
+ return showRemoved;
+ }
+
+ @Override
+ public void execute() {
+ ListResponse response = _queryService.listSecondaryStorageSelectors(this);
+ response.setResponseName(getCommandName());
+ this.setResponseObject(response);
+ }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/heuristics/RemoveSecondaryStorageSelectorCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/heuristics/RemoveSecondaryStorageSelectorCmd.java
new file mode 100644
index 00000000000..79554f44782
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/heuristics/RemoveSecondaryStorageSelectorCmd.java
@@ -0,0 +1,54 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.admin.storage.heuristics;
+
+import com.cloud.user.Account;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.response.SecondaryStorageHeuristicsResponse;
+import org.apache.cloudstack.api.response.SuccessResponse;
+import org.apache.cloudstack.secstorage.heuristics.Heuristic;
+
+@APICommand(name = "removeSecondaryStorageSelector", description = "Removes an existing secondary storage selector.", since = "4.19.0", responseObject =
+ SecondaryStorageHeuristicsResponse.class, requestHasSensitiveInfo = false, entityType = {Heuristic.class}, responseHasSensitiveInfo = false, authorized = {RoleType.Admin})
+public class RemoveSecondaryStorageSelectorCmd extends BaseCmd {
+ @Parameter(name = ApiConstants.ID, type = BaseCmd.CommandType.UUID, entityType = SecondaryStorageHeuristicsResponse.class, required = true,
+ description = "The unique identifier of the secondary storage selector to be removed.")
+ private Long id;
+
+ public Long getId() {
+ return id;
+ }
+
+ @Override
+ public void execute() {
+ _storageService.removeSecondaryStorageHeuristic(this);
+ final SuccessResponse response = new SuccessResponse();
+ response.setResponseName(getCommandName());
+ response.setSuccess(true);
+ setResponseObject(response);
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return Account.ACCOUNT_ID_SYSTEM;
+ }
+
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/heuristics/UpdateSecondaryStorageSelectorCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/heuristics/UpdateSecondaryStorageSelectorCmd.java
new file mode 100644
index 00000000000..e63d1cbfa27
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/heuristics/UpdateSecondaryStorageSelectorCmd.java
@@ -0,0 +1,67 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.admin.storage.heuristics;
+
+import com.cloud.user.Account;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.SecondaryStorageHeuristicsResponse;
+import org.apache.cloudstack.secstorage.heuristics.Heuristic;
+
+@APICommand(name = "updateSecondaryStorageSelector", description = "Updates an existing secondary storage selector.", since = "4.19.0", responseObject =
+ SecondaryStorageHeuristicsResponse.class, requestHasSensitiveInfo = false, entityType = {Heuristic.class}, responseHasSensitiveInfo = false, authorized = {RoleType.Admin})
+public class UpdateSecondaryStorageSelectorCmd extends BaseCmd {
+ @Parameter(name = ApiConstants.ID, type = BaseCmd.CommandType.UUID, entityType = SecondaryStorageHeuristicsResponse.class, required = true,
+ description = "The unique identifier of the secondary storage selector.")
+ private Long id;
+
+ @Parameter(name = ApiConstants.HEURISTIC_RULE, required = true, type = BaseCmd.CommandType.STRING, description = "The heuristic rule, in JavaScript language. It is required " +
+ "that it returns the UUID of a secondary storage pool. An example of a rule is `if (snapshot.hypervisorType === 'KVM') { '7832f261-c602-4e8e-8580-2496ffbbc45d'; " +
+ "}` would allocate all snapshots with the KVM hypervisor to the specified secondary storage UUID.", length = 65535)
+ private String heuristicRule;
+
+ public Long getId() {
+ return id;
+ }
+
+ public String getHeuristicRule() {
+ return heuristicRule;
+ }
+
+ @Override
+ public void execute() {
+ Heuristic heuristic = _storageService.updateSecondaryStorageHeuristic(this);
+
+ if (heuristic == null) {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update the secondary storage selector.");
+ }
+
+ SecondaryStorageHeuristicsResponse response = _responseGenerator.createSecondaryStorageSelectorResponse(heuristic);
+ response.setResponseName(getCommandName());
+ this.setResponseObject(response);
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return Account.ACCOUNT_ID_SYSTEM;
+ }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/address/DisassociateIPAddrCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/address/DisassociateIPAddrCmd.java
index b31520e1b88..f9bfcb253b4 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/address/DisassociateIPAddrCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/address/DisassociateIPAddrCmd.java
@@ -46,10 +46,14 @@ public class DisassociateIPAddrCmd extends BaseAsyncCmd {
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
- @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = IPAddressResponse.class, required = true, description = "the ID of the public IP address"
- + " to disassociate")
+ @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = IPAddressResponse.class, description = "the ID of the public IP address"
+ + " to disassociate. Mutually exclusive with the ipaddress parameter")
private Long id;
+ @Parameter(name=ApiConstants.IP_ADDRESS, type=CommandType.STRING, since="4.19.0", description="IP Address to be disassociated."
+ + " Mutually exclusive with the id parameter")
+ private String ipAddress;
+
// unexposed parameter needed for events logging
@Parameter(name = ApiConstants.ACCOUNT_ID, type = CommandType.UUID, entityType = AccountResponse.class, expose = false)
private Long ownerId;
@@ -59,7 +63,18 @@ public class DisassociateIPAddrCmd extends BaseAsyncCmd {
/////////////////////////////////////////////////////
public Long getIpAddressId() {
- return id;
+ if (id != null & ipAddress != null) {
+ throw new InvalidParameterValueException("id parameter is mutually exclusive with ipaddress parameter");
+ }
+
+ if (id != null) {
+ return id;
+ } else if (ipAddress != null) {
+ IpAddress ip = getIpAddressByIp(ipAddress);
+ return ip.getId();
+ }
+
+ throw new InvalidParameterValueException("Please specify either IP address or IP address ID");
}
/////////////////////////////////////////////////////
@@ -68,12 +83,13 @@ public class DisassociateIPAddrCmd extends BaseAsyncCmd {
@Override
public void execute() throws InsufficientAddressCapacityException {
- CallContext.current().setEventDetails("IP ID: " + getIpAddressId());
+ Long ipAddressId = getIpAddressId();
+ CallContext.current().setEventDetails("IP ID: " + ipAddressId);
boolean result = false;
- if (!isPortable(id)) {
- result = _networkService.releaseIpAddress(getIpAddressId());
+ if (!isPortable()) {
+ result = _networkService.releaseIpAddress(ipAddressId);
} else {
- result = _networkService.releasePortableIpAddress(getIpAddressId());
+ result = _networkService.releasePortableIpAddress(ipAddressId);
}
if (result) {
SuccessResponse response = new SuccessResponse(getCommandName());
@@ -85,7 +101,7 @@ public class DisassociateIPAddrCmd extends BaseAsyncCmd {
@Override
public String getEventType() {
- if (!isPortable(id)) {
+ if (!isPortable()) {
return EventTypes.EVENT_NET_IP_RELEASE;
} else {
return EventTypes.EVENT_PORTABLE_IP_RELEASE;
@@ -100,10 +116,7 @@ public class DisassociateIPAddrCmd extends BaseAsyncCmd {
@Override
public long getEntityOwnerId() {
if (ownerId == null) {
- IpAddress ip = getIpAddress(id);
- if (ip == null) {
- throw new InvalidParameterValueException("Unable to find IP address by ID=" + id);
- }
+ IpAddress ip = getIpAddress();
ownerId = ip.getAccountId();
}
@@ -120,11 +133,11 @@ public class DisassociateIPAddrCmd extends BaseAsyncCmd {
@Override
public Long getSyncObjId() {
- IpAddress ip = getIpAddress(id);
+ IpAddress ip = getIpAddress();
return ip.getAssociatedWithNetworkId();
}
- private IpAddress getIpAddress(long id) {
+ private IpAddress getIpAddressById(Long id) {
IpAddress ip = _entityMgr.findById(IpAddress.class, id);
if (ip == null) {
@@ -134,6 +147,29 @@ public class DisassociateIPAddrCmd extends BaseAsyncCmd {
}
}
+ private IpAddress getIpAddressByIp(String ipAddress) {
+ IpAddress ip = _networkService.getIp(ipAddress);
+ if (ip == null) {
+ throw new InvalidParameterValueException("Unable to find IP address by IP address=" + ipAddress);
+ } else {
+ return ip;
+ }
+ }
+
+ private IpAddress getIpAddress() {
+ if (id != null & ipAddress != null) {
+ throw new InvalidParameterValueException("id parameter is mutually exclusive with ipaddress parameter");
+ }
+
+ if (id != null) {
+ return getIpAddressById(id);
+ } else if (ipAddress != null){
+ return getIpAddressByIp(ipAddress);
+ }
+
+ throw new InvalidParameterValueException("Please specify either IP address or IP address ID");
+ }
+
@Override
public ApiCommandResourceType getApiResourceType() {
return ApiCommandResourceType.IpAddress;
@@ -144,8 +180,8 @@ public class DisassociateIPAddrCmd extends BaseAsyncCmd {
return getIpAddressId();
}
- private boolean isPortable(long id) {
- IpAddress ip = getIpAddress(id);
+ private boolean isPortable() {
+ IpAddress ip = getIpAddress();
return ip.isPortable();
}
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/address/ListQuarantinedIpsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/address/ListQuarantinedIpsCmd.java
new file mode 100644
index 00000000000..cc014702c81
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/address/ListQuarantinedIpsCmd.java
@@ -0,0 +1,51 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.user.address;
+
+import com.cloud.network.PublicIpQuarantine;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseListCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.response.IpQuarantineResponse;
+import org.apache.cloudstack.api.response.ListResponse;
+
+@APICommand(name = "listQuarantinedIps", responseObject = IpQuarantineResponse.class, description = "List public IP addresses in quarantine.", since = "4.19",
+ entityType = {PublicIpQuarantine.class}, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, authorized = {RoleType.Admin, RoleType.DomainAdmin})
+public class ListQuarantinedIpsCmd extends BaseListCmd {
+
+ @Parameter(name = ApiConstants.SHOW_REMOVED, type = CommandType.BOOLEAN, description = "Show IPs removed from quarantine.")
+ private boolean showRemoved = false;
+
+ @Parameter(name = ApiConstants.SHOW_INACTIVE, type = CommandType.BOOLEAN, description = "Show IPs that are no longer in quarantine.")
+ private boolean showInactive = false;
+
+ public boolean isShowRemoved() {
+ return showRemoved;
+ }
+ public boolean isShowInactive() {
+ return showInactive;
+ }
+
+ @Override
+ public void execute() {
+ ListResponse response = _queryService.listQuarantinedIps(this);
+ response.setResponseName(getCommandName());
+ this.setResponseObject(response);
+ }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/address/RemoveQuarantinedIpCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/address/RemoveQuarantinedIpCmd.java
new file mode 100644
index 00000000000..82e8373d93a
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/address/RemoveQuarantinedIpCmd.java
@@ -0,0 +1,72 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.user.address;
+
+import com.cloud.network.PublicIpQuarantine;
+import com.cloud.user.Account;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.response.IpQuarantineResponse;
+import org.apache.cloudstack.api.response.SuccessResponse;
+
+@APICommand(name = "removeQuarantinedIp", responseObject = IpQuarantineResponse.class, description = "Removes a public IP address from quarantine. Only IPs in active " +
+ "quarantine can be removed.",
+ since = "4.19", entityType = {PublicIpQuarantine.class}, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
+ authorized = {RoleType.Admin, RoleType.DomainAdmin})
+public class RemoveQuarantinedIpCmd extends BaseCmd {
+
+ @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = IpQuarantineResponse.class, description = "The ID of the public IP address in active quarantine. " +
+ "Either the IP address is informed, or the ID of the IP address in quarantine.")
+ private Long id;
+
+ @Parameter(name = ApiConstants.IP_ADDRESS, type = CommandType.STRING, description = "The public IP address in active quarantine. Either the IP address is informed, or the ID" +
+ " of the IP address in quarantine.")
+ private String ipAddress;
+
+ @Parameter(name = ApiConstants.REMOVAL_REASON, type = CommandType.STRING, required = true, description = "The reason for removing the public IP address from quarantine " +
+ "prematurely.")
+ private String removalReason;
+
+ public Long getId() {
+ return id;
+ }
+
+ public String getIpAddress() {
+ return ipAddress;
+ }
+
+ public String getRemovalReason() {
+ return removalReason;
+ }
+
+ @Override
+ public void execute() {
+ _networkService.removePublicIpAddressFromQuarantine(this);
+ final SuccessResponse response = new SuccessResponse();
+ response.setResponseName(getCommandName());
+ response.setSuccess(true);
+ setResponseObject(response);
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return Account.ACCOUNT_ID_SYSTEM;
+ }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/address/UpdateQuarantinedIpCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/address/UpdateQuarantinedIpCmd.java
new file mode 100644
index 00000000000..b3b71c33781
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/address/UpdateQuarantinedIpCmd.java
@@ -0,0 +1,75 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.user.address;
+
+import com.cloud.network.PublicIpQuarantine;
+import com.cloud.user.Account;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.IpQuarantineResponse;
+
+import java.util.Date;
+
+@APICommand(name = "updateQuarantinedIp", responseObject = IpQuarantineResponse.class, description = "Updates the quarantine end date for the given public IP address.",
+ since = "4.19", entityType = {PublicIpQuarantine.class}, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
+ authorized = {RoleType.Admin, RoleType.DomainAdmin})
+public class UpdateQuarantinedIpCmd extends BaseCmd {
+
+ @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = IpQuarantineResponse.class, description = "The ID of the public IP address in " +
+ "active quarantine.")
+ private Long id;
+
+ @Parameter(name = ApiConstants.IP_ADDRESS, type = CommandType.STRING, description = "The public IP address in active quarantine. Either the IP address is informed, or the ID" +
+ " of the IP address in quarantine.")
+ private String ipAddress;
+
+ @Parameter(name = ApiConstants.END_DATE, type = BaseCmd.CommandType.DATE, required = true, description = "The date when the quarantine will no longer be active.")
+ private Date endDate;
+
+ public Long getId() {
+ return id;
+ }
+
+ public String getIpAddress() {
+ return ipAddress;
+ }
+
+ public Date getEndDate() {
+ return endDate;
+ }
+
+ @Override
+ public void execute() {
+ PublicIpQuarantine publicIpQuarantine = _networkService.updatePublicIpAddressInQuarantine(this);
+ if (publicIpQuarantine == null) {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update public IP quarantine.");
+ }
+ IpQuarantineResponse response = _responseGenerator.createQuarantinedIpsResponse(publicIpQuarantine);
+ response.setResponseName(getCommandName());
+ this.setResponseObject(response);
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ return Account.ACCOUNT_ID_SYSTEM;
+ }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/bucket/CreateBucketCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/bucket/CreateBucketCmd.java
new file mode 100644
index 00000000000..e9a140cf46e
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/bucket/CreateBucketCmd.java
@@ -0,0 +1,202 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.user.bucket;
+
+import com.cloud.event.EventTypes;
+import com.cloud.exception.ResourceAllocationException;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.storage.object.Bucket;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiCommandResourceType;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCreateCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ResponseObject.ResponseView;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.command.user.UserCmd;
+import org.apache.cloudstack.api.response.BucketResponse;
+import org.apache.cloudstack.api.response.DomainResponse;
+import org.apache.cloudstack.api.response.ObjectStoreResponse;
+import org.apache.cloudstack.api.response.ProjectResponse;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.log4j.Logger;
+
+@APICommand(name = "createBucket", responseObject = BucketResponse.class,
+ description = "Creates a bucket in the specified object storage pool. ", responseView = ResponseView.Restricted,
+ entityType = {Bucket.class}, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.19.0",
+ authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
+public class CreateBucketCmd extends BaseAsyncCreateCmd implements UserCmd {
+ public static final Logger s_logger = Logger.getLogger(CreateBucketCmd.class.getName());
+ private static final String s_name = "createbucketresponse";
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+
+ @Parameter(name = ApiConstants.ACCOUNT,
+ type = CommandType.STRING,
+ description = "the account associated with the bucket. Must be used with the domainId parameter.")
+ private String accountName;
+
+ @Parameter(name = ApiConstants.PROJECT_ID,
+ type = CommandType.UUID,
+ entityType = ProjectResponse.class,
+ description = "the project associated with the bucket. Mutually exclusive with account parameter")
+ private Long projectId;
+
+ @Parameter(name = ApiConstants.DOMAIN_ID,
+ type = CommandType.UUID,
+ entityType = DomainResponse.class,
+ description = "the domain ID associated with the bucket. If used with the account parameter"
+ + " returns the bucket associated with the account for the specified domain.")
+ private Long domainId;
+
+ @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true,description = "the name of the bucket")
+ private String bucketName;
+
+ @Parameter(name = ApiConstants.OBJECT_STORAGE_ID, type = CommandType.UUID,
+ entityType = ObjectStoreResponse.class, required = true,
+ description = "Id of the Object Storage Pool where bucket is created")
+ private long objectStoragePoolId;
+
+ @Parameter(name = ApiConstants.QUOTA, type = CommandType.INTEGER,description = "Bucket Quota in GB")
+ private Integer quota;
+
+ @Parameter(name = ApiConstants.ENCRYPTION, type = CommandType.BOOLEAN, description = "Enable bucket encryption")
+ private boolean encryption;
+
+ @Parameter(name = ApiConstants.VERSIONING, type = CommandType.BOOLEAN, description = "Enable bucket versioning")
+ private boolean versioning;
+
+ @Parameter(name = ApiConstants.OBJECT_LOCKING, type = CommandType.BOOLEAN, description = "Enable object locking in bucket")
+ private boolean objectLocking;
+
+ @Parameter(name = ApiConstants.POLICY, type = CommandType.STRING,description = "The Bucket access policy")
+ private String policy;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ public String getAccountName() {
+ return accountName;
+ }
+
+ public Long getDomainId() {
+ return domainId;
+ }
+
+ public String getBucketName() {
+ return bucketName;
+ }
+
+ private Long getProjectId() {
+ return projectId;
+ }
+
+ public long getObjectStoragePoolId() {
+ return objectStoragePoolId;
+ }
+
+ public Integer getQuota() {
+ return quota;
+ }
+
+ public boolean isEncryption() {
+ return encryption;
+ }
+
+ public boolean isVersioning() {
+ return versioning;
+ }
+
+ public boolean isObjectLocking() {
+ return objectLocking;
+ }
+
+ public String getPolicy() {
+ return policy;
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+ @Override
+ public String getCommandName() {
+ return s_name;
+ }
+
+ public static String getResultObjectName() {
+ return "bucket";
+ }
+
+ @Override
+ public ApiCommandResourceType getApiResourceType() {
+ return ApiCommandResourceType.Bucket;
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
+ if (accountId == null) {
+ return CallContext.current().getCallingAccount().getId();
+ }
+
+ return accountId;
+ }
+
+ @Override
+ public String getEventType() {
+ return EventTypes.EVENT_BUCKET_CREATE;
+ }
+
+ @Override
+ public String getEventDescription() {
+ return "creating bucket: " + getBucketName();
+ }
+
+ @Override
+ public void create() throws ResourceAllocationException {
+ Bucket bucket = _bucketService.allocBucket(this);
+ if (bucket != null) {
+ setEntityId(bucket.getId());
+ setEntityUuid(bucket.getUuid());
+ } else {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create bucket");
+ }
+ }
+
+ @Override
+ public void execute() {
+ CallContext.current().setEventDetails("Bucket Id: " + getEntityUuid());
+
+ Bucket bucket;
+ try {
+ bucket = _bucketService.createBucket(this);
+ } catch (Exception e) {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
+ }
+ if (bucket != null) {
+ BucketResponse response = _responseGenerator.createBucketResponse(bucket);
+ response.setResponseName(getCommandName());
+ setResponseObject(response);
+ } else {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create bucket with name: "+getBucketName());
+ }
+ }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/bucket/DeleteBucketCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/bucket/DeleteBucketCmd.java
new file mode 100644
index 00000000000..bf9552b779e
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/bucket/DeleteBucketCmd.java
@@ -0,0 +1,94 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.user.bucket;
+
+import com.cloud.exception.ConcurrentOperationException;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.storage.object.Bucket;
+import com.cloud.user.Account;
+import org.apache.cloudstack.acl.SecurityChecker.AccessType;
+import org.apache.cloudstack.api.ACL;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiCommandResourceType;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.response.BucketResponse;
+import org.apache.cloudstack.api.response.SuccessResponse;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.log4j.Logger;
+
+@APICommand(name = "deleteBucket", description = "Deletes an empty Bucket.", responseObject = SuccessResponse.class, entityType = {Bucket.class},
+ requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.19.0",
+ authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
+public class DeleteBucketCmd extends BaseCmd {
+ public static final Logger s_logger = Logger.getLogger(DeleteBucketCmd.class.getName());
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+
+ @ACL(accessType = AccessType.OperateEntry)
+ @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType=BucketResponse.class,
+ required=true, description="The ID of the Bucket")
+ private Long id;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ public Long getId() {
+ return id;
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
+ public static String getResultObjectName() {
+ return "bucket";
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ Bucket Bucket = _entityMgr.findById(Bucket.class, getId());
+ if (Bucket != null) {
+ return Bucket.getAccountId();
+ }
+
+ return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked
+ }
+
+ @Override
+ public Long getApiResourceId() {
+ return id;
+ }
+
+ @Override
+ public ApiCommandResourceType getApiResourceType() {
+ return ApiCommandResourceType.Bucket;
+ }
+
+ @Override
+ public void execute() throws ConcurrentOperationException {
+ CallContext.current().setEventDetails("Bucket Id: " + this._uuidMgr.getUuid(Bucket.class, getId()));
+ boolean result = _bucketService.deleteBucket(id, CallContext.current().getCallingAccount());
+ SuccessResponse response = new SuccessResponse(getCommandName());
+ response.setSuccess(result);
+ setResponseObject(response);
+ }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/bucket/ListBucketsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/bucket/ListBucketsCmd.java
new file mode 100644
index 00000000000..897b9fc6696
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/bucket/ListBucketsCmd.java
@@ -0,0 +1,100 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.user.bucket;
+
+import org.apache.cloudstack.storage.object.Bucket;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiCommandResourceType;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseListTaggedResourcesCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ResponseObject.ResponseView;
+import org.apache.cloudstack.api.command.user.UserCmd;
+import org.apache.cloudstack.api.response.BucketResponse;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.api.response.StoragePoolResponse;
+import org.apache.log4j.Logger;
+
+import java.util.List;
+
+@APICommand(name = "listBuckets", description = "Lists all Buckets.", responseObject = BucketResponse.class, responseView = ResponseView.Restricted, entityType = {
+ Bucket.class}, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.19.0",
+ authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
+public class ListBucketsCmd extends BaseListTaggedResourcesCmd implements UserCmd {
+ public static final Logger s_logger = Logger.getLogger(ListBucketsCmd.class.getName());
+
+ private static final String s_name = "listbucketsresponse";
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+
+ @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = BucketResponse.class, description = "the ID of the bucket")
+ private Long id;
+
+ @Parameter(name = ApiConstants.IDS, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = BucketResponse.class, description = "the IDs of the Buckets, mutually exclusive with id")
+ private List ids;
+
+ @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "the name of the bucket")
+ private String bucketName;
+
+ @Parameter(name = ApiConstants.OBJECT_STORAGE_ID, type = CommandType.UUID, entityType = StoragePoolResponse.class, description = "the ID of the object storage pool, available to ROOT admin only", authorized = {
+ RoleType.Admin})
+ private Long objectStorageId;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ public Long getId() {
+ return id;
+ }
+
+ public String getBucketName() {
+ return bucketName;
+ }
+
+ public Long getObjectStorageId() {
+ return objectStorageId;
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
+ @Override
+ public String getCommandName() {
+ return s_name;
+ }
+
+ @Override
+ public ApiCommandResourceType getApiResourceType() {
+ return ApiCommandResourceType.Bucket;
+ }
+
+ @Override
+ public void execute() {
+ ListResponse response = _queryService.searchForBuckets(this);
+ response.setResponseName(getCommandName());
+ setResponseObject(response);
+ }
+
+ public List getIds() {
+ return ids;
+ }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/bucket/UpdateBucketCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/bucket/UpdateBucketCmd.java
new file mode 100644
index 00000000000..b3b7e00770d
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/bucket/UpdateBucketCmd.java
@@ -0,0 +1,132 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.user.bucket;
+
+import com.cloud.exception.ConcurrentOperationException;
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.storage.object.Bucket;
+import com.cloud.user.Account;
+import org.apache.cloudstack.acl.SecurityChecker.AccessType;
+import org.apache.cloudstack.api.ACL;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiCommandResourceType;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.BucketResponse;
+import org.apache.cloudstack.api.response.SuccessResponse;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.log4j.Logger;
+
+@APICommand(name = "updateBucket", description = "Updates Bucket properties", responseObject = SuccessResponse.class, entityType = {Bucket.class},
+ requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.19.0",
+ authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
+public class UpdateBucketCmd extends BaseCmd {
+ public static final Logger s_logger = Logger.getLogger(UpdateBucketCmd.class.getName());
+
+ /////////////////////////////////////////////////////
+ //////////////// API parameters /////////////////////
+ /////////////////////////////////////////////////////
+
+ @ACL(accessType = AccessType.OperateEntry)
+ @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType=BucketResponse.class,
+ required=true, description="The ID of the Bucket")
+ private Long id;
+
+ @Parameter(name = ApiConstants.VERSIONING, type = CommandType.BOOLEAN, description = "Enable/Disable Bucket Versioning")
+ private Boolean versioning;
+
+ @Parameter(name = ApiConstants.ENCRYPTION, type = CommandType.BOOLEAN, description = "Enable/Disable Bucket encryption")
+ private Boolean encryption;
+
+ @Parameter(name = ApiConstants.POLICY, type = CommandType.STRING, description = "Bucket Access Policy")
+ private String policy;
+
+ @Parameter(name = ApiConstants.QUOTA, type = CommandType.INTEGER,description = "Bucket Quota in GB")
+ private Integer quota;
+
+ /////////////////////////////////////////////////////
+ /////////////////// Accessors ///////////////////////
+ /////////////////////////////////////////////////////
+
+ public Long getId() {
+ return id;
+ }
+
+ public Boolean getVersioning() {
+ return versioning;
+ }
+
+ public Boolean getEncryption() {
+ return encryption;
+ }
+
+ public String getPolicy() {
+ return policy;
+ }
+
+ public Integer getQuota() {
+ return quota;
+ }
+
+ /////////////////////////////////////////////////////
+ /////////////// API Implementation///////////////////
+ /////////////////////////////////////////////////////
+
+ public static String getResultObjectName() {
+ return "bucket";
+ }
+
+ @Override
+ public long getEntityOwnerId() {
+ Bucket Bucket = _entityMgr.findById(Bucket.class, getId());
+ if (Bucket != null) {
+ return Bucket.getAccountId();
+ }
+
+ return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked
+ }
+
+ @Override
+ public Long getApiResourceId() {
+ return id;
+ }
+
+ @Override
+ public ApiCommandResourceType getApiResourceType() {
+ return ApiCommandResourceType.Bucket;
+ }
+
+ @Override
+ public void execute() throws ConcurrentOperationException {
+ CallContext.current().setEventDetails("Bucket Id: " + this._uuidMgr.getUuid(Bucket.class, getId()));
+ boolean result = false;
+ try {
+ result = _bucketService.updateBucket(this, CallContext.current().getCallingAccount());
+ } catch (Exception e) {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Error while updating bucket. "+e.getMessage());
+ }
+ if(result) {
+ SuccessResponse response = new SuccessResponse(getCommandName());
+ setResponseObject(response);
+ } else {
+ throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update bucket");
+ }
+ }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/iso/GetUploadParamsForIsoCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/iso/GetUploadParamsForIsoCmd.java
index a7a418f5a86..e1759566299 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/iso/GetUploadParamsForIsoCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/iso/GetUploadParamsForIsoCmd.java
@@ -29,6 +29,7 @@ import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.GetUploadParamsResponse;
import org.apache.cloudstack.api.response.GuestOSResponse;
import org.apache.cloudstack.context.CallContext;
+import org.apache.commons.lang3.StringUtils;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
@@ -54,7 +55,6 @@ public class GetUploadParamsForIsoCmd extends AbstractGetUploadParamsCmd {
@Parameter(name = ApiConstants.DISPLAY_TEXT,
type = BaseCmd.CommandType.STRING,
- required = true,
description = "the display text of the ISO. This is usually used for display purposes.",
length = 4096)
private String displayText;
@@ -85,7 +85,7 @@ public class GetUploadParamsForIsoCmd extends AbstractGetUploadParamsCmd {
}
public String getDisplayText() {
- return displayText;
+ return StringUtils.isBlank(displayText) ? getName() : displayText;
}
public Boolean isFeatured() {
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java
index ecab3930e8b..1d750038042 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java
@@ -177,6 +177,9 @@ public class RegisterIsoCmd extends BaseCmd implements UserCmd {
}
public Long getZoneId() {
+ if (zoneId == null || zoneId == -1) {
+ return null;
+ }
return zoneId;
}
@@ -220,6 +223,10 @@ public class RegisterIsoCmd extends BaseCmd implements UserCmd {
return directDownload == null ? false : directDownload;
}
+ public void setDirectDownload(Boolean directDownload) {
+ this.directDownload = directDownload;
+ }
+
public boolean isPasswordEnabled() {
return passwordEnabled == null ? false : passwordEnabled;
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkACLListCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkACLListCmd.java
index 14dbfcafd7b..e5dbcc7b6d1 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkACLListCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkACLListCmd.java
@@ -16,6 +16,7 @@
// under the License.
package org.apache.cloudstack.api.command.user.network;
+import com.cloud.exception.PermissionDeniedException;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiCommandResourceType;
@@ -26,6 +27,7 @@ import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.NetworkACLResponse;
import org.apache.cloudstack.api.response.VpcResponse;
+import org.apache.cloudstack.context.CallContext;
import org.apache.log4j.Logger;
import com.cloud.event.EventTypes;
@@ -35,7 +37,8 @@ import com.cloud.network.vpc.NetworkACL;
import com.cloud.network.vpc.Vpc;
import com.cloud.user.Account;
-@APICommand(name = "createNetworkACLList", description = "Creates a network ACL for the given VPC", responseObject = NetworkACLResponse.class,
+@APICommand(name = "createNetworkACLList", description = "Creates a network ACL. If no VPC is given, then it creates a global ACL that can be used by everyone.",
+ responseObject = NetworkACLResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class CreateNetworkACLListCmd extends BaseAsyncCreateCmd {
public static final Logger s_logger = Logger.getLogger(CreateNetworkACLListCmd.class.getName());
@@ -53,7 +56,6 @@ public class CreateNetworkACLListCmd extends BaseAsyncCreateCmd {
@Parameter(name = ApiConstants.VPC_ID,
type = CommandType.UUID,
- required = true,
entityType = VpcResponse.class,
description = "ID of the VPC associated with this network ACL list")
private Long vpcId;
@@ -77,6 +79,10 @@ public class CreateNetworkACLListCmd extends BaseAsyncCreateCmd {
return vpcId;
}
+ public void setVpcId(Long vpcId) {
+ this.vpcId = vpcId;
+ }
+
@Override
public boolean isDisplay() {
if (display != null) {
@@ -92,6 +98,9 @@ public class CreateNetworkACLListCmd extends BaseAsyncCreateCmd {
@Override
public void create() {
+ if (getVpcId() == null) {
+ setVpcId(0L);
+ }
NetworkACL result = _networkACLService.createNetworkACL(getName(), getDescription(), getVpcId(), isDisplay());
setEntityId(result.getId());
setEntityUuid(result.getUuid());
@@ -111,12 +120,21 @@ public class CreateNetworkACLListCmd extends BaseAsyncCreateCmd {
@Override
public long getEntityOwnerId() {
- Vpc vpc = _entityMgr.findById(Vpc.class, getVpcId());
- if (vpc == null) {
- throw new InvalidParameterValueException("Invalid vpcId is given");
- }
+ Account account;
+ if (isAclAttachedToVpc(this.vpcId)) {
+ Vpc vpc = _entityMgr.findById(Vpc.class, this.vpcId);
+ if (vpc == null) {
+ throw new InvalidParameterValueException(String.format("Invalid VPC ID [%s] provided.", this.vpcId));
+ }
+ account = _accountService.getAccount(vpc.getAccountId());
+ } else {
+ account = CallContext.current().getCallingAccount();
+ if (!Account.Type.ADMIN.equals(account.getType())) {
+ s_logger.warn(String.format("Only Root Admin can create global ACLs. Account [%s] cannot create any global ACL.", account));
+ throw new PermissionDeniedException("Only Root Admin can create global ACLs.");
+ }
- Account account = _accountService.getAccount(vpc.getAccountId());
+ }
return account.getId();
}
@@ -139,4 +157,8 @@ public class CreateNetworkACLListCmd extends BaseAsyncCreateCmd {
public ApiCommandResourceType getApiResourceType() {
return ApiCommandResourceType.NetworkAcl;
}
+
+ public boolean isAclAttachedToVpc(Long aclVpcId) {
+ return aclVpcId != null && aclVpcId != 0;
+ }
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/offering/ListDiskOfferingsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/offering/ListDiskOfferingsCmd.java
index 5fa24ec1630..e7284d515a2 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/offering/ListDiskOfferingsCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/offering/ListDiskOfferingsCmd.java
@@ -16,6 +16,7 @@
// under the License.
package org.apache.cloudstack.api.command.user.offering;
+import org.apache.cloudstack.api.BaseListProjectAndAccountResourcesCmd;
import org.apache.cloudstack.api.response.StoragePoolResponse;
import org.apache.cloudstack.api.response.VolumeResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
@@ -23,14 +24,14 @@ import org.apache.log4j.Logger;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
-import org.apache.cloudstack.api.BaseListDomainResourcesCmd;
import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.BaseCmd.CommandType;
import org.apache.cloudstack.api.response.DiskOfferingResponse;
import org.apache.cloudstack.api.response.ListResponse;
@APICommand(name = "listDiskOfferings", description = "Lists all available disk offerings.", responseObject = DiskOfferingResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
-public class ListDiskOfferingsCmd extends BaseListDomainResourcesCmd {
+public class ListDiskOfferingsCmd extends BaseListProjectAndAccountResourcesCmd {
public static final Logger s_logger = Logger.getLogger(ListDiskOfferingsCmd.class.getName());
@@ -60,6 +61,12 @@ public class ListDiskOfferingsCmd extends BaseListDomainResourcesCmd {
@Parameter(name = ApiConstants.ENCRYPT, type = CommandType.BOOLEAN, description = "listed offerings support disk encryption", since = "4.18")
private Boolean encrypt;
+ @Parameter(name = ApiConstants.STORAGE_TYPE,
+ type = CommandType.STRING,
+ description = "the storage type of the service offering. Values are local and shared.",
+ since = "4.19")
+ private String storageType;
+
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@@ -84,6 +91,10 @@ public class ListDiskOfferingsCmd extends BaseListDomainResourcesCmd {
public Boolean getEncrypt() { return encrypt; }
+ public String getStorageType() {
+ return storageType;
+ }
+
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/offering/ListServiceOfferingsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/offering/ListServiceOfferingsCmd.java
index 3208ef58a4f..a9a699ed3ef 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/offering/ListServiceOfferingsCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/offering/ListServiceOfferingsCmd.java
@@ -16,20 +16,21 @@
// under the License.
package org.apache.cloudstack.api.command.user.offering;
+import org.apache.cloudstack.api.BaseListProjectAndAccountResourcesCmd;
import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.log4j.Logger;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
-import org.apache.cloudstack.api.BaseListDomainResourcesCmd;
import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.BaseCmd.CommandType;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
@APICommand(name = "listServiceOfferings", description = "Lists all available service offerings.", responseObject = ServiceOfferingResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
-public class ListServiceOfferingsCmd extends BaseListDomainResourcesCmd {
+public class ListServiceOfferingsCmd extends BaseListProjectAndAccountResourcesCmd {
public static final Logger s_logger = Logger.getLogger(ListServiceOfferingsCmd.class.getName());
@@ -88,6 +89,12 @@ public class ListServiceOfferingsCmd extends BaseListDomainResourcesCmd {
since = "4.18")
private Boolean encryptRoot;
+ @Parameter(name = ApiConstants.STORAGE_TYPE,
+ type = CommandType.STRING,
+ description = "the storage type of the service offering. Values are local and shared.",
+ since = "4.19")
+ private String storageType;
+
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@@ -130,6 +137,10 @@ public class ListServiceOfferingsCmd extends BaseListDomainResourcesCmd {
public Boolean getEncryptRoot() { return encryptRoot; }
+ public String getStorageType() {
+ return storageType;
+ }
+
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/template/CreateTemplateCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/template/CreateTemplateCmd.java
index 73a6155c8c5..6c39ab6d3c7 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/template/CreateTemplateCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/template/CreateTemplateCmd.java
@@ -21,18 +21,6 @@ import java.util.List;
import java.util.Map;
import org.apache.cloudstack.acl.SecurityChecker;
-import org.apache.cloudstack.api.command.user.UserCmd;
-import org.apache.cloudstack.api.response.GuestOSResponse;
-import org.apache.cloudstack.api.response.SnapshotResponse;
-import org.apache.cloudstack.api.response.TemplateResponse;
-import org.apache.cloudstack.api.response.UserVmResponse;
-import org.apache.cloudstack.api.response.VolumeResponse;
-import org.apache.cloudstack.api.response.ProjectResponse;
-
-import org.apache.cloudstack.api.response.ZoneResponse;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.log4j.Logger;
-
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiCommandResourceType;
import org.apache.cloudstack.api.ApiConstants;
@@ -41,13 +29,23 @@ import org.apache.cloudstack.api.BaseAsyncCreateCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ResponseObject.ResponseView;
import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.command.user.UserCmd;
+import org.apache.cloudstack.api.response.DomainResponse;
+import org.apache.cloudstack.api.response.GuestOSResponse;
+import org.apache.cloudstack.api.response.ProjectResponse;
+import org.apache.cloudstack.api.response.SnapshotResponse;
+import org.apache.cloudstack.api.response.TemplateResponse;
+import org.apache.cloudstack.api.response.UserVmResponse;
+import org.apache.cloudstack.api.response.VolumeResponse;
+import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.cloudstack.context.CallContext;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.log4j.Logger;
import com.cloud.event.EventTypes;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.ResourceAllocationException;
-import com.cloud.projects.Project;
import com.cloud.storage.Snapshot;
import com.cloud.storage.Volume;
import com.cloud.template.VirtualMachineTemplate;
@@ -139,6 +137,19 @@ public class CreateTemplateCmd extends BaseAsyncCreateCmd implements UserCmd {
@Parameter(name = ApiConstants.ZONE_ID, type = CommandType.UUID, entityType = ZoneResponse.class, description = "the zone for the template. Can be specified with snapshot only", since = "4.19.0")
private Long zoneId;
+ @Parameter(name = ApiConstants.DOMAIN_ID,
+ type = CommandType.UUID,
+ entityType = DomainResponse.class,
+ description = "an optional domainId. If the account parameter is used, domainId must also be used.",
+ since = "4.19.0")
+ private Long domainId;
+
+ @Parameter(name = ApiConstants.ACCOUNT,
+ type = CommandType.STRING,
+ description = "an optional accountName. Must be used with domainId.",
+ since = "4.19.0")
+ private String accountName;
+
// ///////////////////////////////////////////////////
// ///////////////// Accessors ///////////////////////
// ///////////////////////////////////////////////////
@@ -217,6 +228,14 @@ public class CreateTemplateCmd extends BaseAsyncCreateCmd implements UserCmd {
return zoneId;
}
+ public Long getDomainId() {
+ return domainId;
+ }
+
+ public String getAccountName() {
+ return accountName;
+ }
+
// ///////////////////////////////////////////////////
// ///////////// API Implementation///////////////////
// ///////////////////////////////////////////////////
@@ -232,47 +251,12 @@ public class CreateTemplateCmd extends BaseAsyncCreateCmd implements UserCmd {
@Override
public long getEntityOwnerId() {
- Long volumeId = getVolumeId();
- Long snapshotId = getSnapshotId();
Account callingAccount = CallContext.current().getCallingAccount();
- if (volumeId != null) {
- Volume volume = _entityMgr.findById(Volume.class, volumeId);
- if (volume != null) {
- _accountService.checkAccess(callingAccount, SecurityChecker.AccessType.UseEntry, false, volume);
- } else {
- throw new InvalidParameterValueException("Unable to find volume by id=" + volumeId);
- }
- } else {
- Snapshot snapshot = _entityMgr.findById(Snapshot.class, snapshotId);
- if (snapshot != null) {
- _accountService.checkAccess(callingAccount, SecurityChecker.AccessType.UseEntry, false, snapshot);
- } else {
- throw new InvalidParameterValueException("Unable to find snapshot by id=" + snapshotId);
- }
- }
-
- if(projectId != null){
- final Project project = _projectService.getProject(projectId);
- if (project != null) {
- if (project.getState() == Project.State.Active) {
- Account projectAccount= _accountService.getAccount(project.getProjectAccountId());
- _accountService.checkAccess(callingAccount, SecurityChecker.AccessType.UseEntry, false, projectAccount);
- return project.getProjectAccountId();
- } else {
- final PermissionDeniedException ex =
- new PermissionDeniedException("Can't add resources to the project with specified projectId in state=" + project.getState() +
- " as it's no longer active");
- ex.addProxyObject(project.getUuid(), "projectId");
- throw ex;
- }
- } else {
- throw new InvalidParameterValueException("Unable to find project by id");
- }
- }
-
- return callingAccount.getId();
+ ensureAccessCheck(callingAccount);
+ return findAccountIdToUse(callingAccount);
}
+
@Override
public String getEventType() {
return EventTypes.EVENT_TEMPLATE_CREATE;
@@ -330,4 +314,47 @@ public class CreateTemplateCmd extends BaseAsyncCreateCmd implements UserCmd {
}
}
+
+ /***
+ * Performs access check on volume and snapshot for given account
+ * @param account
+ */
+ private void ensureAccessCheck(Account account) {
+ if (volumeId != null) {
+ Volume volume = _entityMgr.findById(Volume.class, volumeId);
+ if (volume != null) {
+ _accountService.checkAccess(account, SecurityChecker.AccessType.UseEntry, false, volume);
+ } else {
+ throw new InvalidParameterValueException("Unable to find volume by id=" + volumeId);
+ }
+ } else {
+ Snapshot snapshot = _entityMgr.findById(Snapshot.class, snapshotId);
+ if (snapshot != null) {
+ _accountService.checkAccess(account, SecurityChecker.AccessType.UseEntry, false, snapshot);
+ } else {
+ throw new InvalidParameterValueException("Unable to find snapshot by id=" + snapshotId);
+ }
+ }
+ }
+
+ /***
+ * Find accountId based on accountName and domainId or projectId
+ * if not found, return callingAccountId for further use
+ * @param callingAccount
+ * @return accountId
+ */
+ private Long findAccountIdToUse(Account callingAccount) {
+ Long accountIdToUse = null;
+ try {
+ accountIdToUse = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
+ } catch (InvalidParameterValueException | PermissionDeniedException ex) {
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug(String.format("An exception occurred while finalizing account id with accountName, domainId and projectId" +
+ "using callingAccountId=%s", callingAccount.getUuid()), ex);
+ }
+ s_logger.warn("Unable to find accountId associated with accountName=" + accountName + " and domainId="
+ + domainId + " or projectId=" + projectId + ", using callingAccountId=" + callingAccount.getUuid());
+ }
+ return accountIdToUse != null ? accountIdToUse : callingAccount.getAccountId();
+ }
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/template/GetUploadParamsForTemplateCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/template/GetUploadParamsForTemplateCmd.java
index 3a9e1c8b429..ab872b84edb 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/template/GetUploadParamsForTemplateCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/template/GetUploadParamsForTemplateCmd.java
@@ -33,6 +33,7 @@ import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.GetUploadParamsResponse;
import org.apache.cloudstack.api.response.GuestOSResponse;
import org.apache.cloudstack.context.CallContext;
+import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import com.cloud.exception.ResourceAllocationException;
@@ -46,7 +47,7 @@ public class GetUploadParamsForTemplateCmd extends AbstractGetUploadParamsCmd {
private static final String s_name = "postuploadtemplateresponse";
- @Parameter(name = ApiConstants.DISPLAY_TEXT, type = CommandType.STRING, required = true, description = "the display text of the template. This is usually used for display purposes.", length = 4096)
+ @Parameter(name = ApiConstants.DISPLAY_TEXT, type = CommandType.STRING, description = "the display text of the template. This is usually used for display purposes.", length = 4096)
private String displayText;
@Parameter(name = ApiConstants.HYPERVISOR, type = CommandType.STRING, required = true, description = "the target hypervisor for the template")
@@ -95,7 +96,7 @@ public class GetUploadParamsForTemplateCmd extends AbstractGetUploadParamsCmd {
private Boolean deployAsIs;
public String getDisplayText() {
- return displayText;
+ return StringUtils.isBlank(displayText) ? getName() : displayText;
}
public String getHypervisor() {
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/AddVpnUserCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/AddVpnUserCmd.java
index 9c9f1c0f50f..f3b452008c9 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/AddVpnUserCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/AddVpnUserCmd.java
@@ -125,6 +125,9 @@ public class AddVpnUserCmd extends BaseAsyncCreateCmd {
vpnResponse.setId(vpnUser.getUuid());
vpnResponse.setUserName(vpnUser.getUsername());
vpnResponse.setAccountName(account.getAccountName());
+ // re-retrieve the vpnuser, as the call to `applyVpnUsers` might have changed the state
+ vpnUser = _entityMgr.findById(VpnUser.class, getEntityId());
+ vpnResponse.setState(vpnUser.getState().toString());
Domain domain = _entityMgr.findById(Domain.class, account.getDomainId());
if (domain != null) {
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/AcquireIPAddressResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/AcquireIPAddressResponse.java
index a74c95780d1..7270fa949c8 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/AcquireIPAddressResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/AcquireIPAddressResponse.java
@@ -124,7 +124,7 @@ public class AcquireIPAddressResponse extends BaseResponse implements Controlle
private String networkId;
@SerializedName(ApiConstants.STATE)
- @Param(description = "State of the ip address. Can be: Allocatin, Allocated and Releasing")
+ @Param(description = "State of the ip address. Can be: Allocating, Allocated and Releasing")
private String state;
@SerializedName(ApiConstants.PHYSICAL_NETWORK_ID)
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/BucketResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/BucketResponse.java
new file mode 100644
index 00000000000..b75f3604324
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/response/BucketResponse.java
@@ -0,0 +1,293 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.response;
+
+import com.cloud.serializer.Param;
+import com.google.gson.annotations.SerializedName;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseResponseWithTagInformation;
+import org.apache.cloudstack.api.EntityReference;
+import org.apache.cloudstack.storage.object.Bucket;
+
+import java.util.Date;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+@EntityReference(value = Bucket.class)
+@SuppressWarnings("unused")
+public class BucketResponse extends BaseResponseWithTagInformation implements ControlledViewEntityResponse, ControlledEntityResponse {
+ @SerializedName(ApiConstants.ID)
+ @Param(description = "ID of the Bucket")
+ private String id;
+ @SerializedName(ApiConstants.NAME)
+ @Param(description = "name of the Bucket")
+ private String name;
+ @SerializedName(ApiConstants.CREATED)
+ @Param(description = "the date the Bucket was created")
+ private Date created;
+ @SerializedName(ApiConstants.ACCOUNT)
+ @Param(description = "the account associated with the Bucket")
+ private String accountName;
+ @SerializedName(ApiConstants.PROJECT_ID)
+ @Param(description = "the project id of the bucket")
+ private String projectId;
+ @SerializedName(ApiConstants.PROJECT)
+ @Param(description = "the project name of the bucket")
+ private String projectName;
+ @SerializedName(ApiConstants.DOMAIN_ID)
+ @Param(description = "the ID of the domain associated with the bucket")
+ private String domainId;
+ @SerializedName(ApiConstants.DOMAIN)
+ @Param(description = "the domain associated with the bucket")
+ private String domainName;
+ @SerializedName(ApiConstants.OBJECT_STORAGE_ID)
+ @Param(description = "id of the object storage hosting the Bucket; returned to admin user only")
+ private String objectStoragePoolId;
+
+ @SerializedName(ApiConstants.OBJECT_STORAGE)
+ @Param(description = "Name of the object storage hosting the Bucket; returned to admin user only")
+ private String objectStoragePool;
+
+ @SerializedName(ApiConstants.SIZE)
+ @Param(description = "Total size of objects in Bucket")
+ private Long size;
+
+ @SerializedName(ApiConstants.STATE)
+ @Param(description = "State of the Bucket")
+ private String state;
+
+ @SerializedName(ApiConstants.QUOTA)
+ @Param(description = "Bucket Quota in GB")
+ private Integer quota;
+
+ @SerializedName(ApiConstants.ENCRYPTION)
+ @Param(description = "Bucket Encryption")
+ private Boolean encryption;
+
+ @SerializedName(ApiConstants.VERSIONING)
+ @Param(description = "Bucket Versioning")
+ private Boolean versioning;
+
+ @SerializedName(ApiConstants.OBJECT_LOCKING)
+ @Param(description = "Bucket Object Locking")
+ private Boolean objectLock;
+
+ @SerializedName(ApiConstants.POLICY)
+ @Param(description = "Bucket Access Policy")
+ private String policy;
+
+ @SerializedName(ApiConstants.URL)
+ @Param(description = "Bucket URL")
+ private String bucketURL;
+
+ @SerializedName(ApiConstants.ACCESS_KEY)
+ @Param(description = "Bucket Access Key")
+ private String accessKey;
+
+ @SerializedName(ApiConstants.SECRET_KEY)
+ @Param(description = "Bucket Secret Key")
+ private String secretKey;
+
+ @SerializedName(ApiConstants.PROVIDER)
+ @Param(description = "Object storage provider")
+ private String provider;
+
+ public BucketResponse() {
+ tags = new LinkedHashSet();
+ }
+
+ @Override
+ public String getObjectId() {
+ return this.getId();
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setCreated(Date created) {
+ this.created = created;
+ }
+
+ @Override
+ public void setAccountName(String accountName) {
+ this.accountName = accountName;
+ }
+
+ @Override
+ public void setDomainId(String domainId) {
+ this.domainId = domainId;
+ }
+
+ @Override
+ public void setDomainName(String domainName) {
+ this.domainName = domainName;
+ }
+
+ @Override
+ public void setProjectId(String projectId) {
+ this.projectId = projectId;
+ }
+
+ @Override
+ public void setProjectName(String projectName) {
+ this.projectName = projectName;
+ }
+
+ public void setTags(Set tags) {
+ this.tags = tags;
+ }
+
+ public void setObjectStoragePoolId(String objectStoragePoolId) {
+ this.objectStoragePoolId = objectStoragePoolId;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Date getCreated() {
+ return created;
+ }
+
+ public String getAccountName() {
+ return accountName;
+ }
+
+ public String getProjectId() {
+ return projectId;
+ }
+
+ public String getProjectName() {
+ return projectName;
+ }
+
+ public String getDomainId() {
+ return domainId;
+ }
+
+ public String getDomainName() {
+ return domainName;
+ }
+
+ public String getObjectStoragePoolId() {
+ return objectStoragePoolId;
+ }
+
+ public long getSize() {
+ return size;
+ }
+
+ public void setSize(long size) {
+ this.size = size;
+ }
+ public long getQuota() {
+ return quota;
+ }
+
+ public void setQuota(Integer quota) {
+ this.quota = quota;
+ }
+
+ public boolean isVersioning() {
+ return versioning;
+ }
+
+ public void setVersioning(boolean versioning) {
+ this.versioning = versioning;
+ }
+
+ public boolean isEncryption() {
+ return encryption;
+ }
+
+ public void setEncryption(boolean encryption) {
+ this.encryption = encryption;
+ }
+
+ public boolean isObjectLock() {
+ return objectLock;
+ }
+
+ public void setObjectLock(boolean objectLock) {
+ this.objectLock = objectLock;
+ }
+
+ public String getPolicy() {
+ return policy;
+ }
+
+ public void setPolicy(String policy) {
+ this.policy = policy;
+ }
+
+ public String getBucketURL() {
+ return bucketURL;
+ }
+
+ public void setBucketURL(String bucketURL) {
+ this.bucketURL = bucketURL;
+ }
+
+ public String getAccessKey() {
+ return accessKey;
+ }
+
+ public void setAccessKey(String accessKey) {
+ this.accessKey = accessKey;
+ }
+
+ public String getSecretKey() {
+ return secretKey;
+ }
+
+ public void setSecretKey(String secretKey) {
+ this.secretKey = secretKey;
+ }
+
+ public void setState(Bucket.State state) {
+ this.state = state.toString();
+ }
+
+ public String getState() {
+ return state;
+ }
+
+ public void setObjectStoragePool(String objectStoragePool) {
+ this.objectStoragePool = objectStoragePool;
+ }
+
+ public String getObjectStoragePool() {
+ return objectStoragePool;
+ }
+
+ public String getProvider() {
+ return provider;
+ }
+
+ public void setProvider(String provider) {
+ this.provider = provider;
+ }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/HostResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/HostResponse.java
index e1f1e5ee241..d72d23b99c9 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/HostResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/HostResponse.java
@@ -221,6 +221,10 @@ public class HostResponse extends BaseResponseWithAnnotations {
@Param(description = "comma-separated list of tags for the host")
private String hostTags;
+ @SerializedName(ApiConstants.IS_TAG_A_RULE)
+ @Param(description = ApiConstants.PARAMETER_DESCRIPTION_IS_TAG_A_RULE)
+ private Boolean isTagARule;
+
@SerializedName("hasenoughcapacity")
@Param(description = "true if this host has enough CPU and RAM capacity to migrate a VM to it, false otherwise")
private Boolean hasEnoughCapacity;
@@ -732,4 +736,12 @@ public class HostResponse extends BaseResponseWithAnnotations {
public void setEncryptionSupported(Boolean encryptionSupported) {
this.encryptionSupported = encryptionSupported;
}
+
+ public Boolean getIsTagARule() {
+ return isTagARule;
+ }
+
+ public void setIsTagARule(Boolean tagARule) {
+ isTagARule = tagARule;
+ }
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/IPAddressResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/IPAddressResponse.java
index 2ad997f39d1..8a9bf7789dd 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/IPAddressResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/IPAddressResponse.java
@@ -128,7 +128,7 @@ public class IPAddressResponse extends BaseResponseWithAnnotations implements Co
private String networkId;
@SerializedName(ApiConstants.STATE)
- @Param(description = "State of the ip address. Can be: Allocatin, Allocated and Releasing")
+ @Param(description = "State of the ip address. Can be: Allocating, Allocated, Releasing, Reserved and Free")
private String state;
@SerializedName(ApiConstants.PHYSICAL_NETWORK_ID)
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/IpQuarantineResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/IpQuarantineResponse.java
new file mode 100644
index 00000000000..55720296315
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/response/IpQuarantineResponse.java
@@ -0,0 +1,130 @@
+//Licensed to the Apache Software Foundation (ASF) under one
+//or more contributor license agreements. See the NOTICE file
+//distributed with this work for additional information
+//regarding copyright ownership. The ASF licenses this file
+//to you under the Apache License, Version 2.0 (the
+//"License"); you may not use this file except in compliance
+//with the License. You may obtain a copy of the License at
+//
+//http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing,
+//software distributed under the License is distributed on an
+//"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+//KIND, either express or implied. See the License for the
+//specific language governing permissions and limitations
+//under the License.
+package org.apache.cloudstack.api.response;
+
+import com.cloud.network.PublicIpQuarantine;
+import com.cloud.serializer.Param;
+import com.google.gson.annotations.SerializedName;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseResponse;
+import org.apache.cloudstack.api.EntityReference;
+
+import java.util.Date;
+
+@EntityReference(value = {PublicIpQuarantine.class})
+public class IpQuarantineResponse extends BaseResponse {
+
+ @SerializedName(ApiConstants.ID)
+ @Param(description = "ID of the quarantine process.")
+ private String id;
+
+ @SerializedName(ApiConstants.IP_ADDRESS)
+ @Param(description = "The public IP address in quarantine.")
+ private String publicIpAddress;
+
+ @SerializedName(ApiConstants.PREVIOUS_OWNER_ID)
+ @Param(description = "Account ID of the previous public IP address owner.")
+ private String previousOwnerId;
+
+ @SerializedName(ApiConstants.PREVIOUS_OWNER_NAME)
+ @Param(description = "Account name of the previous public IP address owner.")
+ private String previousOwnerName;
+
+ @SerializedName(ApiConstants.CREATED)
+ @Param(description = "When the quarantine was created.")
+ private Date created;
+
+ @SerializedName(ApiConstants.REMOVED)
+ @Param(description = "When the quarantine was removed.")
+ private Date removed;
+
+ @SerializedName(ApiConstants.END_DATE)
+ @Param(description = "End date for the quarantine.")
+ private Date endDate;
+
+ @SerializedName(ApiConstants.REMOVAL_REASON)
+ @Param(description = "The reason for removing the IP from quarantine prematurely.")
+ private String removalReason;
+
+ public IpQuarantineResponse() {
+ super("quarantinedips");
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getPublicIpAddress() {
+ return publicIpAddress;
+ }
+
+ public void setPublicIpAddress(String publicIpAddress) {
+ this.publicIpAddress = publicIpAddress;
+ }
+
+ public String getPreviousOwnerId() {
+ return previousOwnerId;
+ }
+
+ public void setPreviousOwnerId(String previousOwnerId) {
+ this.previousOwnerId = previousOwnerId;
+ }
+
+ public String getPreviousOwnerName() {
+ return previousOwnerName;
+ }
+
+ public void setPreviousOwnerName(String previousOwnerName) {
+ this.previousOwnerName = previousOwnerName;
+ }
+
+ public Date getCreated() {
+ return created;
+ }
+
+ public void setCreated(Date created) {
+ this.created = created;
+ }
+
+ public Date getRemoved() {
+ return removed;
+ }
+
+ public void setRemoved(Date removed) {
+ this.removed = removed;
+ }
+
+ public Date getEndDate() {
+ return endDate;
+ }
+
+ public void setEndDate(Date endDate) {
+ this.endDate = endDate;
+ }
+
+ public String getRemovalReason() {
+ return removalReason;
+ }
+
+ public void setRemovalReason(String removalReason) {
+ this.removalReason = removalReason;
+ }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/ObjectStoreResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/ObjectStoreResponse.java
new file mode 100644
index 00000000000..e4030799aa7
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/response/ObjectStoreResponse.java
@@ -0,0 +1,106 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.response;
+
+import com.cloud.serializer.Param;
+import org.apache.cloudstack.storage.object.ObjectStore;
+import com.google.gson.annotations.SerializedName;
+import org.apache.cloudstack.api.BaseResponseWithAnnotations;
+import org.apache.cloudstack.api.EntityReference;
+
+@EntityReference(value = ObjectStore.class)
+public class ObjectStoreResponse extends BaseResponseWithAnnotations {
+ @SerializedName("id")
+ @Param(description = "the ID of the object store")
+ private String id;
+
+ @SerializedName("name")
+ @Param(description = "the name of the object store")
+ private String name;
+
+ @SerializedName("url")
+ @Param(description = "the url of the object store")
+ private String url;
+
+ @SerializedName("providername")
+ @Param(description = "the provider name of the object store")
+ private String providerName;
+
+ @SerializedName("storagetotal")
+ @Param(description = "the total size of the object store")
+ private Long storageTotal;
+
+ @SerializedName("storageused")
+ @Param(description = "the object store currently used size")
+ private Long storageUsed;
+
+ public ObjectStoreResponse() {
+ }
+
+ @Override
+ public String getObjectId() {
+ return this.getId();
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public String getProviderName() {
+ return providerName;
+ }
+
+ public void setProviderName(String providerName) {
+ this.providerName = providerName;
+ }
+
+ public Long getStorageTotal() {
+ return storageTotal;
+ }
+
+ public void setStorageTotal(Long storageTotal) {
+ this.storageTotal = storageTotal;
+ }
+
+ public Long getStorageUsed() {
+ return storageUsed;
+ }
+
+ public void setStorageUsed(Long storageUsed) {
+ this.storageUsed = storageUsed;
+ }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/PortableIpResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/PortableIpResponse.java
index 73008b01ccd..e477b111561 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/PortableIpResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/PortableIpResponse.java
@@ -68,7 +68,7 @@ public class PortableIpResponse extends BaseResponse {
private Date allocated;
@SerializedName(ApiConstants.STATE)
- @Param(description = "State of the ip address. Can be: Allocatin, Allocated and Releasing")
+ @Param(description = "State of the ip address. Can be: Allocating, Allocated, Releasing and Free")
private String state;
public void setRegionId(Integer regionId) {
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/SecondaryStorageHeuristicsResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/SecondaryStorageHeuristicsResponse.java
new file mode 100644
index 00000000000..25a6b2eca75
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/api/response/SecondaryStorageHeuristicsResponse.java
@@ -0,0 +1,141 @@
+//Licensed to the Apache Software Foundation (ASF) under one
+//or more contributor license agreements. See the NOTICE file
+//distributed with this work for additional information
+//regarding copyright ownership. The ASF licenses this file
+//to you under the Apache License, Version 2.0 (the
+//"License"); you may not use this file except in compliance
+//with the License. You may obtain a copy of the License at
+//
+//http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing,
+//software distributed under the License is distributed on an
+//"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+//KIND, either express or implied. See the License for the
+//specific language governing permissions and limitations
+//under the License.
+package org.apache.cloudstack.api.response;
+
+import com.cloud.serializer.Param;
+import com.google.gson.annotations.SerializedName;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseResponse;
+import org.apache.cloudstack.api.EntityReference;
+import org.apache.cloudstack.secstorage.heuristics.Heuristic;
+
+import java.util.Date;
+
+import static org.apache.cloudstack.api.ApiConstants.HEURISTIC_TYPE_VALID_OPTIONS;
+
+@EntityReference(value = {Heuristic.class})
+public class SecondaryStorageHeuristicsResponse extends BaseResponse {
+
+ @SerializedName(ApiConstants.ID)
+ @Param(description = "ID of the heuristic.")
+ private String id;
+
+ @SerializedName(ApiConstants.NAME)
+ @Param(description = "Name of the heuristic.")
+ private String name;
+
+ @SerializedName(ApiConstants.DESCRIPTION)
+ @Param(description = "Description of the heuristic.")
+ private String description;
+
+ @SerializedName(ApiConstants.ZONE_ID)
+ @Param(description = "The zone which the heuristic is valid upon.")
+ private String zoneId;
+
+ @SerializedName(ApiConstants.TYPE)
+ @Param(description = "The resource type directed to a specific secondary storage by the selector. " + HEURISTIC_TYPE_VALID_OPTIONS)
+ private String type;
+
+ @SerializedName(ApiConstants.HEURISTIC_RULE)
+ @Param(description = "The heuristic rule, in JavaScript language, used to select a secondary storage to be directed.")
+ private String heuristicRule;
+
+ @SerializedName(ApiConstants.CREATED)
+ @Param(description = "When the heuristic was created.")
+ private Date created;
+
+ @SerializedName(ApiConstants.REMOVED)
+ @Param(description = "When the heuristic was removed.")
+ private Date removed;
+
+
+ public SecondaryStorageHeuristicsResponse(String id, String name, String description, String zoneId, String type, String heuristicRule, Date created, Date removed) {
+ super("heuristics");
+ this.id = id;
+ this.name = name;
+ this.description = description;
+ this.zoneId = zoneId;
+ this.type = type;
+ this.heuristicRule = heuristicRule;
+ this.created = created;
+ this.removed = removed;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public String getZoneId() {
+ return zoneId;
+ }
+
+ public void setZoneId(String zoneId) {
+ this.zoneId = zoneId;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getHeuristicRule() {
+ return heuristicRule;
+ }
+
+ public void setHeuristicRule(String heuristicRule) {
+ this.heuristicRule = heuristicRule;
+ }
+
+ public Date getCreated() {
+ return created;
+ }
+
+ public void setCreated(Date created) {
+ this.created = created;
+ }
+
+ public Date getRemoved() {
+ return removed;
+ }
+
+ public void setRemoved(Date removed) {
+ this.removed = removed;
+ }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/StoragePoolResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/StoragePoolResponse.java
index 89256c26473..183290ec9eb 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/StoragePoolResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/StoragePoolResponse.java
@@ -101,6 +101,10 @@ public class StoragePoolResponse extends BaseResponseWithAnnotations {
@Param(description = "the tags for the storage pool")
private String tags;
+ @SerializedName(ApiConstants.IS_TAG_A_RULE)
+ @Param(description = ApiConstants.PARAMETER_DESCRIPTION_IS_TAG_A_RULE)
+ private Boolean isTagARule;
+
@SerializedName(ApiConstants.STATE)
@Param(description = "the state of the storage pool")
private StoragePoolStatus state;
@@ -304,6 +308,14 @@ public class StoragePoolResponse extends BaseResponseWithAnnotations {
this.tags = tags;
}
+ public Boolean getIsTagARule() {
+ return isTagARule;
+ }
+
+ public void setIsTagARule(Boolean tagARule) {
+ isTagARule = tagARule;
+ }
+
public StoragePoolStatus getState() {
return state;
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/response/VpnUsersResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/VpnUsersResponse.java
index 3a0e84285aa..d3e4d941678 100644
--- a/api/src/main/java/org/apache/cloudstack/api/response/VpnUsersResponse.java
+++ b/api/src/main/java/org/apache/cloudstack/api/response/VpnUsersResponse.java
@@ -57,7 +57,7 @@ public class VpnUsersResponse extends BaseResponse implements ControlledEntityRe
private String projectName;
@SerializedName(ApiConstants.STATE)
- @Param(description = "the state of the Vpn User")
+ @Param(description = "the state of the Vpn User, can be 'Add', 'Revoke' or 'Active'.")
private String state;
public void setId(String id) {
diff --git a/api/src/main/java/org/apache/cloudstack/query/QueryService.java b/api/src/main/java/org/apache/cloudstack/query/QueryService.java
index 097a3c3f262..3299e7537a2 100644
--- a/api/src/main/java/org/apache/cloudstack/query/QueryService.java
+++ b/api/src/main/java/org/apache/cloudstack/query/QueryService.java
@@ -28,13 +28,17 @@ import org.apache.cloudstack.api.command.admin.resource.icon.ListResourceIconCmd
import org.apache.cloudstack.api.command.admin.router.GetRouterHealthCheckResultsCmd;
import org.apache.cloudstack.api.command.admin.router.ListRoutersCmd;
import org.apache.cloudstack.api.command.admin.storage.ListImageStoresCmd;
+import org.apache.cloudstack.api.command.admin.storage.ListObjectStoragePoolsCmd;
import org.apache.cloudstack.api.command.admin.storage.ListSecondaryStagingStoresCmd;
import org.apache.cloudstack.api.command.admin.storage.ListStoragePoolsCmd;
import org.apache.cloudstack.api.command.admin.storage.ListStorageTagsCmd;
+import org.apache.cloudstack.api.command.admin.storage.heuristics.ListSecondaryStorageSelectorsCmd;
import org.apache.cloudstack.api.command.admin.user.ListUsersCmd;
import org.apache.cloudstack.api.command.user.account.ListAccountsCmd;
import org.apache.cloudstack.api.command.user.account.ListProjectAccountsCmd;
+import org.apache.cloudstack.api.command.user.address.ListQuarantinedIpsCmd;
import org.apache.cloudstack.api.command.user.affinitygroup.ListAffinityGroupsCmd;
+import org.apache.cloudstack.api.command.user.bucket.ListBucketsCmd;
import org.apache.cloudstack.api.command.user.event.ListEventsCmd;
import org.apache.cloudstack.api.command.user.iso.ListIsosCmd;
import org.apache.cloudstack.api.command.user.job.ListAsyncJobsCmd;
@@ -55,6 +59,7 @@ import org.apache.cloudstack.api.command.user.volume.ListVolumesCmd;
import org.apache.cloudstack.api.command.user.zone.ListZonesCmd;
import org.apache.cloudstack.api.response.AccountResponse;
import org.apache.cloudstack.api.response.AsyncJobResponse;
+import org.apache.cloudstack.api.response.BucketResponse;
import org.apache.cloudstack.api.response.DetailOptionsResponse;
import org.apache.cloudstack.api.response.DiskOfferingResponse;
import org.apache.cloudstack.api.response.DomainResponse;
@@ -64,8 +69,10 @@ import org.apache.cloudstack.api.response.HostResponse;
import org.apache.cloudstack.api.response.HostTagResponse;
import org.apache.cloudstack.api.response.ImageStoreResponse;
import org.apache.cloudstack.api.response.InstanceGroupResponse;
+import org.apache.cloudstack.api.response.IpQuarantineResponse;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.ManagementServerResponse;
+import org.apache.cloudstack.api.response.ObjectStoreResponse;
import org.apache.cloudstack.api.response.ProjectAccountResponse;
import org.apache.cloudstack.api.response.ProjectInvitationResponse;
import org.apache.cloudstack.api.response.ProjectResponse;
@@ -73,6 +80,7 @@ import org.apache.cloudstack.api.response.ResourceDetailResponse;
import org.apache.cloudstack.api.response.ResourceIconResponse;
import org.apache.cloudstack.api.response.ResourceTagResponse;
import org.apache.cloudstack.api.response.RouterHealthCheckResultResponse;
+import org.apache.cloudstack.api.response.SecondaryStorageHeuristicsResponse;
import org.apache.cloudstack.api.response.SecurityGroupResponse;
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
import org.apache.cloudstack.api.response.SnapshotResponse;
@@ -183,7 +191,15 @@ public interface QueryService {
List listRouterHealthChecks(GetRouterHealthCheckResultsCmd cmd);
+ ListResponse listSecondaryStorageSelectors(ListSecondaryStorageSelectorsCmd cmd);
+
+ ListResponse listQuarantinedIps(ListQuarantinedIpsCmd cmd);
+
ListResponse listSnapshots(ListSnapshotsCmd cmd);
SnapshotResponse listSnapshot(CopySnapshotCmd cmd);
+
+ ListResponse searchForObjectStores(ListObjectStoragePoolsCmd listObjectStoragePoolsCmd);
+
+ ListResponse searchForBuckets(ListBucketsCmd listBucketsCmd);
}
diff --git a/api/src/main/java/org/apache/cloudstack/secstorage/heuristics/Heuristic.java b/api/src/main/java/org/apache/cloudstack/secstorage/heuristics/Heuristic.java
new file mode 100644
index 00000000000..2a0b8d6ea24
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/secstorage/heuristics/Heuristic.java
@@ -0,0 +1,40 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.secstorage.heuristics;
+
+import org.apache.cloudstack.api.Identity;
+import org.apache.cloudstack.api.InternalIdentity;
+
+import java.util.Date;
+
+public interface Heuristic extends InternalIdentity, Identity {
+
+ String getName();
+
+ String getDescription();
+
+ Long getZoneId();
+
+ String getType();
+
+ String getHeuristicRule();
+
+ Date getCreated();
+
+ Date getRemoved();
+
+}
diff --git a/api/src/main/java/org/apache/cloudstack/secstorage/heuristics/HeuristicType.java b/api/src/main/java/org/apache/cloudstack/secstorage/heuristics/HeuristicType.java
new file mode 100644
index 00000000000..f23e4b0b633
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/secstorage/heuristics/HeuristicType.java
@@ -0,0 +1,25 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.secstorage.heuristics;
+
+/**
+ * The type of the heuristic used in the allocation process of secondary storage resources.
+ * Valid options are: {@link #ISO}, {@link #SNAPSHOT}, {@link #TEMPLATE} and {@link #VOLUME}
+ */
+public enum HeuristicType {
+ ISO, SNAPSHOT, TEMPLATE, VOLUME
+}
diff --git a/api/src/main/java/org/apache/cloudstack/storage/object/Bucket.java b/api/src/main/java/org/apache/cloudstack/storage/object/Bucket.java
new file mode 100644
index 00000000000..c821dbac589
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/storage/object/Bucket.java
@@ -0,0 +1,64 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.storage.object;
+
+import org.apache.cloudstack.acl.ControlledEntity;
+import org.apache.cloudstack.api.Identity;
+import org.apache.cloudstack.api.InternalIdentity;
+
+import java.util.Date;
+
+public interface Bucket extends ControlledEntity, Identity, InternalIdentity {
+
+ long getObjectStoreId();
+
+ Date getCreated();
+
+ State getState();
+
+ void setName(String name);
+
+ Long getSize();
+
+ Integer getQuota();
+
+ boolean isVersioning();
+
+ boolean isEncryption();
+
+ boolean isObjectLock();
+
+ String getPolicy();
+
+ String getBucketURL();
+
+ String getAccessKey();
+
+ String getSecretKey();
+
+ public enum State {
+ Allocated, Created, Destroyed;
+ @Override
+ public String toString() {
+ return this.name();
+ }
+
+ public boolean equals(String status) {
+ return this.toString().equalsIgnoreCase(status);
+ }
+ }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/storage/object/BucketApiService.java b/api/src/main/java/org/apache/cloudstack/storage/object/BucketApiService.java
new file mode 100644
index 00000000000..7e1361d1e71
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/storage/object/BucketApiService.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cloudstack.storage.object;
+
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.user.Account;
+import org.apache.cloudstack.api.command.user.bucket.CreateBucketCmd;
+import org.apache.cloudstack.api.command.user.bucket.UpdateBucketCmd;
+
+public interface BucketApiService {
+
+
+ /**
+ * Creates the database object for a Bucket based on the given criteria
+ *
+ * @param cmd
+ * the API command wrapping the criteria (account/domainId [admin only], zone, diskOffering, snapshot,
+ * name)
+ * @return the Bucket object
+ */
+ Bucket allocBucket(CreateBucketCmd cmd) throws ResourceAllocationException;
+
+ /**
+ * Creates the Bucket based on the given criteria
+ *
+ * @param cmd
+ * the API command wrapping the criteria (account/domainId [admin only], zone, diskOffering, snapshot,
+ * name)
+ * @return the Bucket object
+ */
+ Bucket createBucket(CreateBucketCmd cmd);
+
+ boolean deleteBucket(long bucketId, Account caller);
+
+ boolean updateBucket(UpdateBucketCmd cmd, Account caller);
+
+ void getBucketUsage();
+}
diff --git a/api/src/main/java/org/apache/cloudstack/storage/object/ObjectStore.java b/api/src/main/java/org/apache/cloudstack/storage/object/ObjectStore.java
new file mode 100644
index 00000000000..47741fc67f4
--- /dev/null
+++ b/api/src/main/java/org/apache/cloudstack/storage/object/ObjectStore.java
@@ -0,0 +1,40 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.storage.object;
+
+import org.apache.cloudstack.api.Identity;
+import org.apache.cloudstack.api.InternalIdentity;
+
+public interface ObjectStore extends Identity, InternalIdentity {
+
+ /**
+ * @return name of the object store.
+ */
+ String getName();
+
+ /**
+ * @return object store provider name
+ */
+ String getProviderName();
+
+ /**
+ *
+ * @return uri
+ */
+ String getUrl();
+
+}
diff --git a/api/src/main/java/org/apache/cloudstack/usage/UsageTypes.java b/api/src/main/java/org/apache/cloudstack/usage/UsageTypes.java
index 48cff3076fd..5e0f03ff583 100644
--- a/api/src/main/java/org/apache/cloudstack/usage/UsageTypes.java
+++ b/api/src/main/java/org/apache/cloudstack/usage/UsageTypes.java
@@ -45,6 +45,7 @@ public class UsageTypes {
public static final int VOLUME_SECONDARY = 26;
public static final int VM_SNAPSHOT_ON_PRIMARY = 27;
public static final int BACKUP = 28;
+ public static final int BUCKET = 29;
public static List listUsageTypes() {
List responseList = new ArrayList();
@@ -70,6 +71,7 @@ public class UsageTypes {
responseList.add(new UsageTypeResponse(VOLUME_SECONDARY, "Volume on secondary storage usage"));
responseList.add(new UsageTypeResponse(VM_SNAPSHOT_ON_PRIMARY, "VM Snapshot on primary storage usage"));
responseList.add(new UsageTypeResponse(BACKUP, "Backup storage usage"));
+ responseList.add(new UsageTypeResponse(BUCKET, "Bucket storage usage"));
return responseList;
}
}
diff --git a/api/src/test/java/org/apache/cloudstack/api/command/admin/storage/AddObjectStoragePoolCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/admin/storage/AddObjectStoragePoolCmdTest.java
new file mode 100644
index 00000000000..f64df167e25
--- /dev/null
+++ b/api/src/test/java/org/apache/cloudstack/api/command/admin/storage/AddObjectStoragePoolCmdTest.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cloudstack.api.command.admin.storage;
+
+import com.cloud.exception.DiscoveryException;
+import com.cloud.storage.StorageService;
+import org.apache.cloudstack.api.ResponseGenerator;
+import org.apache.cloudstack.api.response.ObjectStoreResponse;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.storage.object.ObjectStore;
+import org.apache.log4j.Logger;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.mockito.ArgumentMatchers.anyObject;
+
+@RunWith(MockitoJUnitRunner.class)
+public class AddObjectStoragePoolCmdTest {
+ public static final Logger s_logger = Logger.getLogger(AddObjectStoragePoolCmdTest.class.getName());
+
+ @Mock
+ StorageService storageService;
+
+ @Mock
+ ObjectStore objectStore;
+
+ @Mock
+ ResponseGenerator responseGenerator;
+
+ @Spy
+ AddObjectStoragePoolCmd addObjectStoragePoolCmdSpy;
+
+ String name = "testObjStore";
+
+ String url = "testURL";
+
+ String provider = "Simulator";
+
+ Map details;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ details = new HashMap<>();
+ addObjectStoragePoolCmdSpy = Mockito.spy(new AddObjectStoragePoolCmd());
+ ReflectionTestUtils.setField(addObjectStoragePoolCmdSpy, "name", name);
+ ReflectionTestUtils.setField(addObjectStoragePoolCmdSpy, "url", url);
+ ReflectionTestUtils.setField(addObjectStoragePoolCmdSpy, "providerName", provider);
+ ReflectionTestUtils.setField(addObjectStoragePoolCmdSpy, "details", details);
+ addObjectStoragePoolCmdSpy._storageService = storageService;
+ addObjectStoragePoolCmdSpy._responseGenerator = responseGenerator;
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ CallContext.unregister();
+ }
+
+ @Test
+ public void testAddObjectStore() throws DiscoveryException {
+ Mockito.doReturn(objectStore).when(storageService).discoverObjectStore(Mockito.anyString(),
+ Mockito.anyString(), Mockito.anyString(), anyObject());
+ ObjectStoreResponse objectStoreResponse = new ObjectStoreResponse();
+ Mockito.doReturn(objectStoreResponse).when(responseGenerator).createObjectStoreResponse(anyObject());
+ addObjectStoragePoolCmdSpy.execute();
+
+ Mockito.verify(storageService, Mockito.times(1))
+ .discoverObjectStore(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any());
+ }
+}
diff --git a/api/src/test/java/org/apache/cloudstack/api/command/admin/storage/DeleteObjectStoragePoolCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/admin/storage/DeleteObjectStoragePoolCmdTest.java
new file mode 100644
index 00000000000..35be56d0c75
--- /dev/null
+++ b/api/src/test/java/org/apache/cloudstack/api/command/admin/storage/DeleteObjectStoragePoolCmdTest.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cloudstack.api.command.admin.storage;
+
+import com.cloud.storage.StorageService;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.log4j.Logger;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+
+public class DeleteObjectStoragePoolCmdTest {
+ public static final Logger s_logger = Logger.getLogger(DeleteObjectStoragePoolCmdTest.class.getName());
+ @Mock
+ private StorageService storageService;
+
+ @Spy
+ DeleteObjectStoragePoolCmd deleteObjectStoragePoolCmd;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ deleteObjectStoragePoolCmd = Mockito.spy(new DeleteObjectStoragePoolCmd());
+ deleteObjectStoragePoolCmd._storageService = storageService;
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ CallContext.unregister();
+ }
+
+ @Test
+ public void testDeleteObjectStore() {
+ Mockito.doReturn(true).when(storageService).deleteObjectStore(deleteObjectStoragePoolCmd);
+ deleteObjectStoragePoolCmd.execute();
+ Mockito.verify(storageService, Mockito.times(1))
+ .deleteObjectStore(deleteObjectStoragePoolCmd);
+ }
+}
diff --git a/api/src/test/java/org/apache/cloudstack/api/command/admin/storage/UpdateObjectStoragePoolCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/admin/storage/UpdateObjectStoragePoolCmdTest.java
new file mode 100644
index 00000000000..ef66c2a1a64
--- /dev/null
+++ b/api/src/test/java/org/apache/cloudstack/api/command/admin/storage/UpdateObjectStoragePoolCmdTest.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cloudstack.api.command.admin.storage;
+
+import com.cloud.storage.StorageService;
+import org.apache.cloudstack.api.ResponseGenerator;
+import org.apache.cloudstack.api.response.ObjectStoreResponse;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.storage.object.ObjectStore;
+import org.apache.log4j.Logger;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import static org.mockito.ArgumentMatchers.anyObject;
+
+public class UpdateObjectStoragePoolCmdTest {
+ public static final Logger s_logger = Logger.getLogger(UpdateObjectStoragePoolCmdTest.class.getName());
+
+ @Mock
+ private StorageService storageService;
+
+ @Spy
+ UpdateObjectStoragePoolCmd updateObjectStoragePoolCmd;
+
+ @Mock
+ ObjectStore objectStore;
+
+ @Mock
+ ResponseGenerator responseGenerator;
+
+ private String name = "testObjStore";
+
+ private String url = "testURL";
+
+ private String provider = "Simulator";
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ updateObjectStoragePoolCmd = Mockito.spy(new UpdateObjectStoragePoolCmd());
+ updateObjectStoragePoolCmd._storageService = storageService;
+ updateObjectStoragePoolCmd._responseGenerator = responseGenerator;
+ ReflectionTestUtils.setField(updateObjectStoragePoolCmd, "name", name);
+ ReflectionTestUtils.setField(updateObjectStoragePoolCmd, "url", url);
+ ReflectionTestUtils.setField(updateObjectStoragePoolCmd, "id", 1L);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ CallContext.unregister();
+ }
+
+ @Test
+ public void testUpdateObjectStore() {
+ Mockito.doReturn(objectStore).when(storageService).updateObjectStore(1L, updateObjectStoragePoolCmd);
+ ObjectStoreResponse objectStoreResponse = new ObjectStoreResponse();
+ Mockito.doReturn(objectStoreResponse).when(responseGenerator).createObjectStoreResponse(anyObject());
+ updateObjectStoragePoolCmd.execute();
+ Mockito.verify(storageService, Mockito.times(1))
+ .updateObjectStore(1L, updateObjectStoragePoolCmd);
+ }
+
+}
diff --git a/api/src/test/java/org/apache/cloudstack/api/command/user/template/CreateTemplateCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/user/template/CreateTemplateCmdTest.java
index d8af670a7b2..55e9c8dba1e 100644
--- a/api/src/test/java/org/apache/cloudstack/api/command/user/template/CreateTemplateCmdTest.java
+++ b/api/src/test/java/org/apache/cloudstack/api/command/user/template/CreateTemplateCmdTest.java
@@ -29,4 +29,20 @@ public class CreateTemplateCmdTest {
ReflectionTestUtils.setField(cmd, "zoneId", id);
Assert.assertEquals(id, cmd.getZoneId());
}
+
+ @Test
+ public void testDomainId() {
+ final CreateTemplateCmd cmd = new CreateTemplateCmd();
+ Long id = 2L;
+ ReflectionTestUtils.setField(cmd, "domainId", id);
+ Assert.assertEquals(id, cmd.getDomainId());
+ }
+
+ @Test
+ public void testGetAccountName() {
+ final CreateTemplateCmd cmd = new CreateTemplateCmd();
+ String accountName = "user1";
+ ReflectionTestUtils.setField(cmd, "accountName", accountName);
+ Assert.assertEquals(accountName, cmd.getAccountName());
+ }
}
diff --git a/client/pom.xml b/client/pom.xml
index 05aa7f8b53e..048bddbe549 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -582,6 +582,21 @@
cloud-plugin-shutdown
${project.version}
+
+ org.apache.cloudstack
+ cloud-engine-storage-object
+ ${project.version}
+
+
+ org.apache.cloudstack
+ cloud-plugin-storage-object-minio
+ ${project.version}
+
+
+ org.apache.cloudstack
+ cloud-plugin-storage-object-simulator
+ ${project.version}
+
diff --git a/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/BucketInfo.java b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/BucketInfo.java
new file mode 100644
index 00000000000..366c7c8fb41
--- /dev/null
+++ b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/BucketInfo.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cloudstack.engine.subsystem.api.storage;
+
+import org.apache.cloudstack.storage.object.Bucket;
+
+public interface BucketInfo extends DataObject, Bucket {
+
+ void addPayload(Object data);
+
+ Object getPayload();
+
+ Bucket getBucket();
+}
diff --git a/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreManager.java b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreManager.java
index 3ee5803a91a..de26a09c6e5 100644
--- a/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreManager.java
+++ b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreManager.java
@@ -35,6 +35,8 @@ public interface DataStoreManager {
List getImageStoresByScopeExcludingReadOnly(ZoneScope scope);
+ List getImageStoresByZoneIds(Long ... zoneIds);
+
DataStore getRandomImageStore(long zoneId);
DataStore getRandomUsableImageStore(long zoneId);
@@ -55,5 +57,7 @@ public interface DataStoreManager {
boolean isRegionStore(DataStore store);
+ DataStore getImageStoreByUuid(String uuid);
+
Long getStoreZoneId(long storeId, DataStoreRole role);
}
diff --git a/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreProvider.java b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreProvider.java
index 3e5761ef37f..41c1d940745 100644
--- a/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreProvider.java
+++ b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreProvider.java
@@ -31,7 +31,7 @@ public interface DataStoreProvider {
String DEFAULT_PRIMARY = "DefaultPrimary";
enum DataStoreProviderType {
- PRIMARY, IMAGE, ImageCache
+ PRIMARY, IMAGE, ImageCache, OBJECT
}
DataStoreLifeCycle getDataStoreLifeCycle();
diff --git a/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreProviderManager.java b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreProviderManager.java
index e476d8f3b35..379911a54fb 100644
--- a/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreProviderManager.java
+++ b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreProviderManager.java
@@ -33,4 +33,6 @@ public interface DataStoreProviderManager extends Manager, DataStoreProviderApiS
DataStoreProvider getDefaultCacheDataStoreProvider();
List getProviders();
+
+ DataStoreProvider getDefaultObjectStoreProvider();
}
diff --git a/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/ObjectStorageService.java b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/ObjectStorageService.java
new file mode 100644
index 00000000000..691da7ecc8d
--- /dev/null
+++ b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/ObjectStorageService.java
@@ -0,0 +1,22 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.cloudstack.engine.subsystem.api.storage;
+
+public interface ObjectStorageService {
+
+}
diff --git a/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/ObjectStoreProvider.java b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/ObjectStoreProvider.java
new file mode 100644
index 00000000000..71b3762b441
--- /dev/null
+++ b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/ObjectStoreProvider.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cloudstack.engine.subsystem.api.storage;
+
+public interface ObjectStoreProvider extends DataStoreProvider {
+
+}
diff --git a/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreParameters.java b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreParameters.java
index 1dbff59a891..1b18264df15 100644
--- a/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreParameters.java
+++ b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreParameters.java
@@ -43,6 +43,8 @@ public class PrimaryDataStoreParameters {
private boolean managed;
private Long capacityIops;
+ private Boolean isTagARule;
+
/**
* @return the userInfo
*/
@@ -277,4 +279,12 @@ public class PrimaryDataStoreParameters {
public void setUsedBytes(long usedBytes) {
this.usedBytes = usedBytes;
}
+
+ public Boolean isTagARule() {
+ return isTagARule;
+ }
+
+ public void setIsTagARule(Boolean isTagARule) {
+ this.isTagARule = isTagARule;
+ }
}
diff --git a/engine/api/src/main/java/org/apache/cloudstack/storage/object/ObjectStoreEntity.java b/engine/api/src/main/java/org/apache/cloudstack/storage/object/ObjectStoreEntity.java
new file mode 100644
index 00000000000..9ee94b083cf
--- /dev/null
+++ b/engine/api/src/main/java/org/apache/cloudstack/storage/object/ObjectStoreEntity.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cloudstack.storage.object;
+
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
+
+import java.util.List;
+import java.util.Map;
+
+public interface ObjectStoreEntity extends DataStore, ObjectStore {
+ Bucket createBucket(Bucket bucket, boolean objectLock);
+
+ List listBuckets();
+
+ boolean createUser(long accountId);
+
+ boolean deleteBucket(String name);
+
+ boolean setBucketEncryption(String name);
+
+ boolean deleteBucketEncryption(String name);
+
+ boolean setBucketVersioning(String name);
+
+ boolean deleteBucketVersioning(String name);
+
+ void setBucketPolicy(String name, String policy);
+
+ void setQuota(String name, int quota);
+
+ Map getAllBucketsUsage();
+}
diff --git a/engine/components-api/src/main/java/com/cloud/network/IpAddressManager.java b/engine/components-api/src/main/java/com/cloud/network/IpAddressManager.java
index ab179d302d0..36937460b20 100644
--- a/engine/components-api/src/main/java/com/cloud/network/IpAddressManager.java
+++ b/engine/components-api/src/main/java/com/cloud/network/IpAddressManager.java
@@ -16,6 +16,7 @@
// under the License.
package com.cloud.network;
+import java.util.Date;
import java.util.List;
import org.apache.cloudstack.api.response.AcquirePodIpCmdResponse;
@@ -238,5 +239,52 @@ public interface IpAddressManager {
public static final String MESSAGE_ASSIGN_IPADDR_EVENT = "Message.AssignIpAddr.Event";
public static final String MESSAGE_RELEASE_IPADDR_EVENT = "Message.ReleaseIpAddr.Event";
+
+ /**
+ * Checks if the given public IP address is not in active quarantine.
+ * It returns `true` if:
+ *
+ * - The IP was never in quarantine;
+ * - The IP was in quarantine, but the quarantine expired;
+ * - The IP is still in quarantine; however, the new owner is the same as the previous owner, therefore, the IP can be allocated.
+ *
+ *
+ * It returns `false` if:
+ *
+ * - The IP is in active quarantine and the new owner is different from the previous owner.
+ *
+ *
+ * @param ip used to check if it is in active quarantine.
+ * @param account used to identify the new owner of the public IP.
+ * @return true if the IP can be allocated, and false otherwise.
+ */
+ boolean canPublicIpAddressBeAllocated(IpAddress ip, Account account);
+
+ /**
+ * Adds the given public IP address to quarantine for the duration of the global configuration `public.ip.address.quarantine.duration` value.
+ *
+ * @param publicIpAddress to be quarantined.
+ * @param domainId used to retrieve the quarantine duration.
+ * @return the {@link PublicIpQuarantine} persisted in the database.
+ */
+ PublicIpQuarantine addPublicIpAddressToQuarantine(IpAddress publicIpAddress, Long domainId);
+
+ /**
+ * Prematurely removes a public IP address from quarantine. It is required to provide a reason for removing it.
+ *
+ * @param quarantineProcessId the ID of the active quarantine process.
+ * @param removalReason for prematurely removing the public IP address from quarantine.
+ */
+ void removePublicIpAddressFromQuarantine(Long quarantineProcessId, String removalReason);
+
+ /**
+ * Updates the end date of a public IP address in active quarantine. It can increase and decrease the duration of the quarantine.
+ *
+ * @param quarantineProcessId the ID of the quarantine process.
+ * @param endDate the new end date for the quarantine.
+ * @return the updated quarantine object.
+ */
+ PublicIpQuarantine updatePublicIpAddressInQuarantine(Long quarantineProcessId, Date endDate);
+
void updateSourceNatIpAddress(IPAddressVO requestedIp, List userIps) throws Exception;
}
diff --git a/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java b/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java
index 28e7c89419a..1437457725a 100644
--- a/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java
+++ b/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java
@@ -192,6 +192,9 @@ public interface StorageManager extends StorageService {
ConfigKey.Scope.Global,
null);
+ ConfigKey HEURISTICS_SCRIPT_TIMEOUT = new ConfigKey<>("Advanced", Long.class, "heuristics.script.timeout", "3000",
+ "The maximum runtime, in milliseconds, to execute the heuristic rule; if it is reached, a timeout will happen.", true);
+
/**
* should we execute in sequence not involving any storages?
* @return tru if commands should execute in sequence
diff --git a/engine/components-api/src/main/java/com/cloud/template/TemplateManager.java b/engine/components-api/src/main/java/com/cloud/template/TemplateManager.java
index 2c129dfd6a5..3b3537d5488 100644
--- a/engine/components-api/src/main/java/com/cloud/template/TemplateManager.java
+++ b/engine/components-api/src/main/java/com/cloud/template/TemplateManager.java
@@ -34,6 +34,7 @@ import com.cloud.storage.Storage.TemplateType;
import com.cloud.storage.StoragePool;
import com.cloud.storage.VMTemplateStoragePoolVO;
import com.cloud.storage.VMTemplateVO;
+import com.cloud.storage.VolumeVO;
import com.cloud.utils.Pair;
import com.cloud.vm.VirtualMachineProfile;
@@ -116,7 +117,7 @@ public interface TemplateManager {
Long getTemplateSize(long templateId, long zoneId);
- DataStore getImageStore(String storeUuid, Long zoneId);
+ DataStore getImageStore(String storeUuid, Long zoneId, VolumeVO volume);
String getChecksum(DataStore store, String templatePath, String algorithm);
diff --git a/engine/pom.xml b/engine/pom.xml
index b2f41834403..6ecfb4bebf4 100644
--- a/engine/pom.xml
+++ b/engine/pom.xml
@@ -55,6 +55,7 @@
storage/configdrive
storage/datamotion
storage/image
+ storage/object
storage/snapshot
storage/volume
userdata/cloud-init
diff --git a/engine/schema/src/main/java/com/cloud/host/HostTagVO.java b/engine/schema/src/main/java/com/cloud/host/HostTagVO.java
index 6b8b754849c..cd4ac29738d 100644
--- a/engine/schema/src/main/java/com/cloud/host/HostTagVO.java
+++ b/engine/schema/src/main/java/com/cloud/host/HostTagVO.java
@@ -24,6 +24,7 @@ import javax.persistence.Id;
import javax.persistence.Table;
import org.apache.cloudstack.api.InternalIdentity;
+import org.apache.commons.lang3.BooleanUtils;
@Entity
@Table(name = "host_tags")
@@ -39,12 +40,22 @@ public class HostTagVO implements InternalIdentity {
@Column(name = "tag")
private String tag;
+ @Column(name = "is_tag_a_rule")
+ private boolean isTagARule;
+
protected HostTagVO() {
}
public HostTagVO(long hostId, String tag) {
this.hostId = hostId;
this.tag = tag;
+ this.isTagARule = false;
+ }
+
+ public HostTagVO(long hostId, String tag, Boolean isTagARule) {
+ this.hostId = hostId;
+ this.tag = tag;
+ this.isTagARule = BooleanUtils.toBooleanDefaultIfNull(isTagARule, false);
}
public long getHostId() {
@@ -59,6 +70,11 @@ public class HostTagVO implements InternalIdentity {
this.tag = tag;
}
+ public boolean getIsTagARule() {
+ return isTagARule;
+ }
+
+
@Override
public long getId() {
return id;
diff --git a/engine/schema/src/main/java/com/cloud/host/HostVO.java b/engine/schema/src/main/java/com/cloud/host/HostVO.java
index d6e7ea1fd87..697401ad069 100644
--- a/engine/schema/src/main/java/com/cloud/host/HostVO.java
+++ b/engine/schema/src/main/java/com/cloud/host/HostVO.java
@@ -39,6 +39,7 @@ import javax.persistence.TemporalType;
import javax.persistence.Transient;
import com.cloud.agent.api.VgpuTypesInfo;
+import com.cloud.host.dao.HostTagsDao;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.offering.ServiceOffering;
import com.cloud.resource.ResourceState;
@@ -46,7 +47,10 @@ import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.db.GenericDao;
import java.util.Arrays;
+
+import org.apache.cloudstack.utils.jsinterpreter.TagAsRuleHelper;
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
+import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
@Entity
@@ -159,6 +163,14 @@ public class HostVO implements Host {
@Transient
List hostTags;
+ /**
+ * This is a delayed load value.
+ * If the value is null, then this field has not been loaded yet.
+ * Call host dao to load it.
+ */
+ @Transient
+ Boolean isTagARule;
+
// This value is only for saving and current cannot be loaded.
@Transient
HashMap> groupDetails = new HashMap>();
@@ -322,8 +334,13 @@ public class HostVO implements Host {
return hostTags;
}
- public void setHostTags(List hostTags) {
+ public void setHostTags(List hostTags, Boolean isTagARule) {
this.hostTags = hostTags;
+ this.isTagARule = isTagARule;
+ }
+
+ public Boolean getIsTagARule() {
+ return isTagARule;
}
public HashMap> getGpuGroupDetails() {
@@ -748,6 +765,11 @@ public class HostVO implements Host {
if (serviceOffering == null) {
return false;
}
+
+ if (BooleanUtils.isTrue(this.getIsTagARule())) {
+ return TagAsRuleHelper.interpretTagAsRule(this.getHostTags().get(0), serviceOffering.getHostTag(), HostTagsDao.hostTagRuleExecutionTimeout.value());
+ }
+
if (StringUtils.isEmpty(serviceOffering.getHostTag())) {
return true;
}
diff --git a/engine/schema/src/main/java/com/cloud/host/dao/HostDao.java b/engine/schema/src/main/java/com/cloud/host/dao/HostDao.java
index ca51ad3f428..fe30722feb1 100644
--- a/engine/schema/src/main/java/com/cloud/host/dao/HostDao.java
+++ b/engine/schema/src/main/java/com/cloud/host/dao/HostDao.java
@@ -108,6 +108,8 @@ public interface HostDao extends GenericDao, StateDao listAllHostsByZoneAndHypervisorType(long zoneId, HypervisorType hypervisorType);
+ List listAllHostsThatHaveNoRuleTag(Host.Type type, Long clusterId, Long podId, Long dcId);
+
List listAllHostsByType(Host.Type type);
HostVO findByPublicIp(String publicIp);
@@ -161,4 +163,8 @@ public interface HostDao extends GenericDao, StateDao listOrderedHostsHypervisorVersionsInDatacenter(long datacenterId, HypervisorType hypervisorType);
+
+ List findHostsWithTagRuleThatMatchComputeOferringTags(String computeOfferingTags);
+
+ List findClustersThatMatchHostTagRule(String computeOfferingTags);
}
diff --git a/engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java b/engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java
index 392b623299f..136351527f6 100644
--- a/engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/host/dao/HostDaoImpl.java
@@ -22,9 +22,11 @@ import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
import java.util.TimeZone;
import java.util.stream.Collectors;
@@ -32,6 +34,8 @@ import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.persistence.TableGenerator;
+import org.apache.cloudstack.utils.jsinterpreter.TagAsRuleHelper;
+import org.apache.commons.collections.CollectionUtils;
import org.apache.log4j.Logger;
import com.cloud.agent.api.VgpuTypesInfo;
@@ -80,8 +84,8 @@ public class HostDaoImpl extends GenericDaoBase implements HostDao
private static final Logger state_logger = Logger.getLogger(ResourceState.class);
private static final String LIST_HOST_IDS_BY_COMPUTETAGS = "SELECT filtered.host_id, COUNT(filtered.tag) AS tag_count "
- + "FROM (SELECT host_id, tag FROM host_tags GROUP BY host_id,tag) AS filtered "
- + "WHERE tag IN(%s) "
+ + "FROM (SELECT host_id, tag, is_tag_a_rule FROM host_tags GROUP BY host_id,tag) AS filtered "
+ + "WHERE tag IN(%s) AND is_tag_a_rule = 0 "
+ "GROUP BY host_id "
+ "HAVING tag_count = %s ";
private static final String SEPARATOR = ",";
@@ -148,6 +152,10 @@ public class HostDaoImpl extends GenericDaoBase implements HostDao
protected GenericSearchBuilder AllClustersSearch;
protected SearchBuilder HostsInClusterSearch;
+ protected SearchBuilder searchBuilderFindByIdTypeClusterIdPodIdDcIdAndWithoutRuleTag;
+
+ protected SearchBuilder searchBuilderFindByRuleTag;
+
protected Attribute _statusAttr;
protected Attribute _resourceStateAttr;
protected Attribute _msIdAttr;
@@ -455,6 +463,22 @@ public class HostDaoImpl extends GenericDaoBase implements HostDao
HostIdSearch.and("dataCenterId", HostIdSearch.entity().getDataCenterId(), Op.EQ);
HostIdSearch.done();
+ searchBuilderFindByRuleTag = _hostTagsDao.createSearchBuilder();
+ searchBuilderFindByRuleTag.and("is_tag_a_rule", searchBuilderFindByRuleTag.entity().getIsTagARule(), Op.EQ);
+ searchBuilderFindByRuleTag.or("tagDoesNotExist", searchBuilderFindByRuleTag.entity().getIsTagARule(), Op.NULL);
+
+ searchBuilderFindByIdTypeClusterIdPodIdDcIdAndWithoutRuleTag = createSearchBuilder();
+ searchBuilderFindByIdTypeClusterIdPodIdDcIdAndWithoutRuleTag.and("id", searchBuilderFindByIdTypeClusterIdPodIdDcIdAndWithoutRuleTag.entity().getId(), Op.EQ);
+ searchBuilderFindByIdTypeClusterIdPodIdDcIdAndWithoutRuleTag.and("type", searchBuilderFindByIdTypeClusterIdPodIdDcIdAndWithoutRuleTag.entity().getType(), Op.EQ);
+ searchBuilderFindByIdTypeClusterIdPodIdDcIdAndWithoutRuleTag.and("cluster_id", searchBuilderFindByIdTypeClusterIdPodIdDcIdAndWithoutRuleTag.entity().getClusterId(), Op.EQ);
+ searchBuilderFindByIdTypeClusterIdPodIdDcIdAndWithoutRuleTag.and("pod_id", searchBuilderFindByIdTypeClusterIdPodIdDcIdAndWithoutRuleTag.entity().getPodId(), Op.EQ);
+ searchBuilderFindByIdTypeClusterIdPodIdDcIdAndWithoutRuleTag.and("data_center_id", searchBuilderFindByIdTypeClusterIdPodIdDcIdAndWithoutRuleTag.entity().getDataCenterId(), Op.EQ);
+ searchBuilderFindByIdTypeClusterIdPodIdDcIdAndWithoutRuleTag.join("id", searchBuilderFindByRuleTag, searchBuilderFindByRuleTag.entity().getHostId(),
+ searchBuilderFindByIdTypeClusterIdPodIdDcIdAndWithoutRuleTag.entity().getId(), JoinType.LEFTOUTER);
+
+ searchBuilderFindByRuleTag.done();
+ searchBuilderFindByIdTypeClusterIdPodIdDcIdAndWithoutRuleTag.done();
+
_statusAttr = _allAttributes.get("status");
_msIdAttr = _allAttributes.get("managementServerId");
_pingTimeAttr = _allAttributes.get("lastPinged");
@@ -792,9 +816,12 @@ public class HostDaoImpl extends GenericDaoBase implements HostDao
@Override
public List listAllUpAndEnabledNonHAHosts(Type type, Long clusterId, Long podId, long dcId, String haTag) {
- SearchBuilder hostTagSearch = null;
+ SearchBuilder hostTagSearch = _hostTagsDao.createSearchBuilder();
+ hostTagSearch.and();
+ hostTagSearch.op("isTagARule", hostTagSearch.entity().getIsTagARule(), Op.EQ);
+ hostTagSearch.or("tagDoesNotExist", hostTagSearch.entity().getIsTagARule(), Op.NULL);
+ hostTagSearch.cp();
if (haTag != null && !haTag.isEmpty()) {
- hostTagSearch = _hostTagsDao.createSearchBuilder();
hostTagSearch.and().op("tag", hostTagSearch.entity().getTag(), SearchCriteria.Op.NEQ);
hostTagSearch.or("tagNull", hostTagSearch.entity().getTag(), SearchCriteria.Op.NULL);
hostTagSearch.cp();
@@ -809,12 +836,14 @@ public class HostDaoImpl extends GenericDaoBase implements HostDao
hostSearch.and("status", hostSearch.entity().getStatus(), SearchCriteria.Op.EQ);
hostSearch.and("resourceState", hostSearch.entity().getResourceState(), SearchCriteria.Op.EQ);
- if (haTag != null && !haTag.isEmpty()) {
- hostSearch.join("hostTagSearch", hostTagSearch, hostSearch.entity().getId(), hostTagSearch.entity().getHostId(), JoinBuilder.JoinType.LEFTOUTER);
- }
+
+ hostSearch.join("hostTagSearch", hostTagSearch, hostSearch.entity().getId(), hostTagSearch.entity().getHostId(), JoinBuilder.JoinType.LEFTOUTER);
+
SearchCriteria sc = hostSearch.create();
+ sc.setJoinParameters("hostTagSearch", "isTagARule", false);
+
if (haTag != null && !haTag.isEmpty()) {
sc.setJoinParameters("hostTagSearch", "tag", haTag);
}
@@ -846,8 +875,13 @@ public class HostDaoImpl extends GenericDaoBase implements HostDao
@Override
public void loadHostTags(HostVO host) {
- List hostTags = _hostTagsDao.getHostTags(host.getId());
- host.setHostTags(hostTags);
+ List hostTagVOList = _hostTagsDao.getHostTags(host.getId());
+ if (CollectionUtils.isNotEmpty(hostTagVOList)) {
+ List hostTagList = hostTagVOList.parallelStream().map(HostTagVO::getTag).collect(Collectors.toList());
+ host.setHostTags(hostTagList, hostTagVOList.get(0).getIsTagARule());
+ } else {
+ host.setHostTags(null, null);
+ }
}
@DB
@@ -881,10 +915,10 @@ public class HostDaoImpl extends GenericDaoBase implements HostDao
protected void saveHostTags(HostVO host) {
List hostTags = host.getHostTags();
- if (hostTags == null || (hostTags != null && hostTags.isEmpty())) {
+ if (CollectionUtils.isEmpty(hostTags)) {
return;
}
- _hostTagsDao.persist(host.getId(), hostTags);
+ _hostTagsDao.persist(host.getId(), hostTags, host.getIsTagARule());
}
protected void saveGpuRecords(HostVO host) {
@@ -1244,6 +1278,26 @@ public class HostDaoImpl extends GenericDaoBase implements HostDao
return listBy(sc);
}
+ @Override
+ public List listAllHostsThatHaveNoRuleTag(Type type, Long clusterId, Long podId, Long dcId) {
+ SearchCriteria sc = searchBuilderFindByIdTypeClusterIdPodIdDcIdAndWithoutRuleTag.create();
+ if (type != null) {
+ sc.setParameters("type", type);
+ }
+ if (clusterId != null) {
+ sc.setParameters("cluster_id", clusterId);
+ }
+ if (podId != null) {
+ sc.setParameters("pod_id", podId);
+ }
+ if (dcId != null) {
+ sc.setParameters("data_center_id", dcId);
+ }
+ sc.setJoinParameters("id", "is_tag_a_rule", false);
+
+ return search(sc, null);
+ }
+
@Override
public List listClustersByHostTag(String computeOfferingTags) {
TransactionLegacy txn = TransactionLegacy.currentTxn();
@@ -1266,9 +1320,6 @@ public class HostDaoImpl extends GenericDaoBase implements HostDao
result.add(rs.getLong(1));
}
pstmt.close();
- if(result.isEmpty()){
- throw new CloudRuntimeException("No suitable host found for follow compute offering tags: " + computeOfferingTags);
- }
return result;
} catch (SQLException e) {
throw new CloudRuntimeException("DB Exception on: " + sql, e);
@@ -1293,15 +1344,33 @@ public class HostDaoImpl extends GenericDaoBase implements HostDao
result.add(rs.getLong(1));
}
pstmt.close();
- if(result.isEmpty()){
- throw new CloudRuntimeException("No suitable host found for follow compute offering tags: " + computeOfferingTags);
- }
return result;
} catch (SQLException e) {
throw new CloudRuntimeException("DB Exception on: " + select, e);
}
}
+ public List findHostsWithTagRuleThatMatchComputeOferringTags(String computeOfferingTags) {
+ List hostTagVOList = _hostTagsDao.findHostRuleTags();
+ List result = new ArrayList<>();
+ for (HostTagVO rule: hostTagVOList) {
+ if (TagAsRuleHelper.interpretTagAsRule(rule.getTag(), computeOfferingTags, HostTagsDao.hostTagRuleExecutionTimeout.value())) {
+ result.add(findById(rule.getHostId()));
+ }
+ }
+
+ return result;
+ }
+
+ public List findClustersThatMatchHostTagRule(String computeOfferingTags) {
+ Set result = new HashSet<>();
+ List hosts = findHostsWithTagRuleThatMatchComputeOferringTags(computeOfferingTags);
+ for (HostVO host: hosts) {
+ result.add(host.getClusterId());
+ }
+ return new ArrayList<>(result);
+ }
+
private String getHostIdsByComputeTags(List offeringTags){
List questionMarks = new ArrayList();
offeringTags.forEach((tag) -> { questionMarks.add("?"); });
diff --git a/engine/schema/src/main/java/com/cloud/host/dao/HostTagsDao.java b/engine/schema/src/main/java/com/cloud/host/dao/HostTagsDao.java
index 0fb5370d81a..d134db33403 100644
--- a/engine/schema/src/main/java/com/cloud/host/dao/HostTagsDao.java
+++ b/engine/schema/src/main/java/com/cloud/host/dao/HostTagsDao.java
@@ -20,15 +20,21 @@ import java.util.List;
import com.cloud.host.HostTagVO;
import com.cloud.utils.db.GenericDao;
+import org.apache.cloudstack.framework.config.ConfigKey;
public interface HostTagsDao extends GenericDao {
- void persist(long hostId, List hostTags);
+ ConfigKey hostTagRuleExecutionTimeout = new ConfigKey<>("Advanced", Long.class, "host.tag.rule.execution.timeout", "2000", "The maximum runtime, in milliseconds, " +
+ "to execute a host tag rule; if it is reached, a timeout will happen.", true);
- List getHostTags(long hostId);
+ void persist(long hostId, List hostTags, Boolean isTagARule);
+
+ List getHostTags(long hostId);
List getDistinctImplicitHostTags(List hostIds, String[] implicitHostTags);
void deleteTags(long hostId);
+ List findHostRuleTags();
+
}
diff --git a/engine/schema/src/main/java/com/cloud/host/dao/HostTagsDaoImpl.java b/engine/schema/src/main/java/com/cloud/host/dao/HostTagsDaoImpl.java
index a73899b7b33..65deb1d1c9b 100644
--- a/engine/schema/src/main/java/com/cloud/host/dao/HostTagsDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/host/dao/HostTagsDaoImpl.java
@@ -16,10 +16,10 @@
// under the License.
package com.cloud.host.dao;
-import java.util.ArrayList;
import java.util.List;
-
+import org.apache.cloudstack.framework.config.ConfigKey;
+import org.apache.cloudstack.framework.config.Configurable;
import org.springframework.stereotype.Component;
import com.cloud.host.HostTagVO;
@@ -31,13 +31,14 @@ import com.cloud.utils.db.TransactionLegacy;
import com.cloud.utils.db.SearchCriteria.Func;
@Component
-public class HostTagsDaoImpl extends GenericDaoBase implements HostTagsDao {
+public class HostTagsDaoImpl extends GenericDaoBase implements HostTagsDao, Configurable {
protected final SearchBuilder HostSearch;
protected final GenericSearchBuilder DistinctImplictTagsSearch;
public HostTagsDaoImpl() {
HostSearch = createSearchBuilder();
HostSearch.and("hostId", HostSearch.entity().getHostId(), SearchCriteria.Op.EQ);
+ HostSearch.and("isTagARule", HostSearch.entity().getIsTagARule(), SearchCriteria.Op.EQ);
HostSearch.done();
DistinctImplictTagsSearch = createSearchBuilder(String.class);
@@ -48,17 +49,11 @@ public class HostTagsDaoImpl extends GenericDaoBase implements
}
@Override
- public List getHostTags(long hostId) {
+ public List getHostTags(long hostId) {
SearchCriteria sc = HostSearch.create();
sc.setParameters("hostId", hostId);
- List results = search(sc, null);
- List hostTags = new ArrayList(results.size());
- for (HostTagVO result : results) {
- hostTags.add(result.getTag());
- }
-
- return hostTags;
+ return search(sc, null);
}
@Override
@@ -80,7 +75,15 @@ public class HostTagsDaoImpl extends GenericDaoBase implements
}
@Override
- public void persist(long hostId, List hostTags) {
+ public List findHostRuleTags() {
+ SearchCriteria sc = HostSearch.create();
+ sc.setParameters("isTagARule", true);
+
+ return search(sc, null);
+ }
+
+ @Override
+ public void persist(long hostId, List hostTags, Boolean isTagARule) {
TransactionLegacy txn = TransactionLegacy.currentTxn();
txn.start();
@@ -91,10 +94,20 @@ public class HostTagsDaoImpl extends GenericDaoBase implements
for (String tag : hostTags) {
tag = tag.trim();
if (tag.length() > 0) {
- HostTagVO vo = new HostTagVO(hostId, tag);
+ HostTagVO vo = new HostTagVO(hostId, tag, isTagARule);
persist(vo);
}
}
txn.commit();
}
+
+ @Override
+ public ConfigKey>[] getConfigKeys() {
+ return new ConfigKey>[] {hostTagRuleExecutionTimeout};
+ }
+
+ @Override
+ public String getConfigComponentName() {
+ return HostTagsDaoImpl.class.getSimpleName();
+ }
}
diff --git a/engine/schema/src/main/java/com/cloud/network/dao/IPAddressDao.java b/engine/schema/src/main/java/com/cloud/network/dao/IPAddressDao.java
index bb4822ebb38..f75dc8a6661 100644
--- a/engine/schema/src/main/java/com/cloud/network/dao/IPAddressDao.java
+++ b/engine/schema/src/main/java/com/cloud/network/dao/IPAddressDao.java
@@ -21,6 +21,7 @@ import java.util.List;
import com.cloud.dc.Vlan.VlanType;
import com.cloud.network.IpAddress.State;
import com.cloud.utils.db.GenericDao;
+import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.net.Ip;
public interface IPAddressDao extends GenericDao {
@@ -100,4 +101,6 @@ public interface IPAddressDao extends GenericDao {
List listByDcIdAndAssociatedNetwork(long dcId);
List listByNetworkId(long networkId);
+
+ void buildQuarantineSearchCriteria(SearchCriteria sc);
}
diff --git a/engine/schema/src/main/java/com/cloud/network/dao/IPAddressDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/dao/IPAddressDaoImpl.java
index d82ffbe2af0..9ffc4c9159c 100644
--- a/engine/schema/src/main/java/com/cloud/network/dao/IPAddressDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/network/dao/IPAddressDaoImpl.java
@@ -24,6 +24,7 @@ import java.util.List;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
+import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.resourcedetail.dao.UserIpAddressDetailsDao;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
@@ -32,6 +33,7 @@ import com.cloud.dc.Vlan.VlanType;
import com.cloud.dc.VlanVO;
import com.cloud.dc.dao.VlanDao;
import com.cloud.network.IpAddress.State;
+import com.cloud.network.vo.PublicIpQuarantineVO;
import com.cloud.server.ResourceTag.ResourceObjectType;
import com.cloud.tags.dao.ResourceTagDao;
import com.cloud.utils.db.DB;
@@ -69,6 +71,9 @@ public class IPAddressDaoImpl extends GenericDaoBase implemen
@Inject
UserIpAddressDetailsDao _detailsDao;
+ @Inject
+ PublicIpQuarantineDao publicIpQuarantineDao;
+
// make it public for JUnit test
public IPAddressDaoImpl() {
}
@@ -534,4 +539,19 @@ public class IPAddressDaoImpl extends GenericDaoBase implemen
sc.setParameters("state", State.Allocated);
return listBy(sc);
}
+
+ @Override
+ public void buildQuarantineSearchCriteria(SearchCriteria sc) {
+ long accountId = CallContext.current().getCallingAccount().getAccountId();
+ SearchBuilder listAllIpsInQuarantine = publicIpQuarantineDao.createSearchBuilder();
+ listAllIpsInQuarantine.and("quarantineEndDate", listAllIpsInQuarantine.entity().getEndDate(), SearchCriteria.Op.GT);
+ listAllIpsInQuarantine.and("previousOwnerId", listAllIpsInQuarantine.entity().getPreviousOwnerId(), Op.NEQ);
+
+ SearchCriteria searchCriteria = listAllIpsInQuarantine.create();
+ searchCriteria.setParameters("quarantineEndDate", new Date());
+ searchCriteria.setParameters("previousOwnerId", accountId);
+ Object[] quarantinedIpsIdsAllowedToUser = publicIpQuarantineDao.search(searchCriteria, null).stream().map(PublicIpQuarantineVO::getPublicIpAddressId).toArray();
+
+ sc.setParametersIfNotNull("quarantinedPublicIpsIdsNIN", quarantinedIpsIdsAllowedToUser);
+ }
}
diff --git a/engine/schema/src/main/java/com/cloud/network/dao/IPAddressVO.java b/engine/schema/src/main/java/com/cloud/network/dao/IPAddressVO.java
index 7c4d56bd1ee..4c7569a55b9 100644
--- a/engine/schema/src/main/java/com/cloud/network/dao/IPAddressVO.java
+++ b/engine/schema/src/main/java/com/cloud/network/dao/IPAddressVO.java
@@ -29,7 +29,6 @@ import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
-import javax.persistence.Transient;
import com.cloud.network.IpAddress;
import com.cloud.utils.db.GenericDao;
@@ -97,14 +96,6 @@ public class IPAddressVO implements IpAddress {
@Column(name = "is_system")
private boolean system;
- @Column(name = "account_id")
- @Transient
- private Long accountId = null;
-
- @Transient
- @Column(name = "domain_id")
- private Long domainId = null;
-
@Column(name = "vpc_id")
private Long vpcId;
diff --git a/engine/schema/src/main/java/com/cloud/network/dao/PublicIpQuarantineDao.java b/engine/schema/src/main/java/com/cloud/network/dao/PublicIpQuarantineDao.java
new file mode 100644
index 00000000000..ccba6bb1889
--- /dev/null
+++ b/engine/schema/src/main/java/com/cloud/network/dao/PublicIpQuarantineDao.java
@@ -0,0 +1,27 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.network.dao;
+
+import com.cloud.network.vo.PublicIpQuarantineVO;
+import com.cloud.utils.db.GenericDao;
+
+public interface PublicIpQuarantineDao extends GenericDao {
+
+ PublicIpQuarantineVO findByPublicIpAddressId(long publicIpAddressId);
+
+ PublicIpQuarantineVO findByIpAddress(String publicIpAddress);
+}
diff --git a/engine/schema/src/main/java/com/cloud/network/dao/PublicIpQuarantineDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/dao/PublicIpQuarantineDaoImpl.java
new file mode 100644
index 00000000000..a1b789b8a46
--- /dev/null
+++ b/engine/schema/src/main/java/com/cloud/network/dao/PublicIpQuarantineDaoImpl.java
@@ -0,0 +1,71 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.network.dao;
+
+import com.cloud.network.vo.PublicIpQuarantineVO;
+import com.cloud.utils.db.Filter;
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.JoinBuilder;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+
+@Component
+public class PublicIpQuarantineDaoImpl extends GenericDaoBase implements PublicIpQuarantineDao {
+ private SearchBuilder publicIpAddressByIdSearch;
+
+ private SearchBuilder ipAddressSearchBuilder;
+
+ @Inject
+ IPAddressDao ipAddressDao;
+
+ @PostConstruct
+ public void init() {
+ publicIpAddressByIdSearch = createSearchBuilder();
+ publicIpAddressByIdSearch.and("publicIpAddressId", publicIpAddressByIdSearch.entity().getPublicIpAddressId(), SearchCriteria.Op.EQ);
+
+ ipAddressSearchBuilder = ipAddressDao.createSearchBuilder();
+ ipAddressSearchBuilder.and("ipAddress", ipAddressSearchBuilder.entity().getAddress(), SearchCriteria.Op.EQ);
+ ipAddressSearchBuilder.and("removed", ipAddressSearchBuilder.entity().getRemoved(), SearchCriteria.Op.NULL);
+ publicIpAddressByIdSearch.join("quarantineJoin", ipAddressSearchBuilder, ipAddressSearchBuilder.entity().getId(),
+ publicIpAddressByIdSearch.entity().getPublicIpAddressId(), JoinBuilder.JoinType.INNER);
+
+ ipAddressSearchBuilder.done();
+ publicIpAddressByIdSearch.done();
+ }
+
+ @Override
+ public PublicIpQuarantineVO findByPublicIpAddressId(long publicIpAddressId) {
+ SearchCriteria sc = publicIpAddressByIdSearch.create();
+ sc.setParameters("publicIpAddressId", publicIpAddressId);
+ final Filter filter = new Filter(PublicIpQuarantineVO.class, "created", false);
+
+ return findOneBy(sc, filter);
+ }
+
+ @Override
+ public PublicIpQuarantineVO findByIpAddress(String publicIpAddress) {
+ SearchCriteria sc = publicIpAddressByIdSearch.create();
+ sc.setJoinParameters("quarantineJoin", "ipAddress", publicIpAddress);
+ final Filter filter = new Filter(PublicIpQuarantineVO.class, "created", false);
+
+ return findOneBy(sc, filter);
+ }
+}
diff --git a/engine/schema/src/main/java/com/cloud/network/vo/PublicIpQuarantineVO.java b/engine/schema/src/main/java/com/cloud/network/vo/PublicIpQuarantineVO.java
new file mode 100644
index 00000000000..56d167a0060
--- /dev/null
+++ b/engine/schema/src/main/java/com/cloud/network/vo/PublicIpQuarantineVO.java
@@ -0,0 +1,131 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.network.vo;
+
+import com.cloud.network.PublicIpQuarantine;
+import com.cloud.utils.db.GenericDao;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import java.util.Date;
+import java.util.UUID;
+
+@Entity
+@Table(name = "quarantined_ips")
+public class PublicIpQuarantineVO implements PublicIpQuarantine {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "id", nullable = false)
+ private Long id;
+
+ @Column(name = "uuid", nullable = false)
+ private String uuid = UUID.randomUUID().toString();
+
+ @Column(name = "public_ip_address_id", nullable = false)
+ private Long publicIpAddressId;
+
+ @Column(name = "previous_owner_id", nullable = false)
+ private Long previousOwnerId;
+
+ @Column(name = GenericDao.CREATED_COLUMN, nullable = false)
+ @Temporal(value = TemporalType.TIMESTAMP)
+ private Date created;
+
+ @Column(name = GenericDao.REMOVED_COLUMN)
+ @Temporal(value = TemporalType.TIMESTAMP)
+ private Date removed = null;
+
+ @Column(name = "end_date", nullable = false)
+ @Temporal(value = TemporalType.TIMESTAMP)
+ private Date endDate;
+
+ @Column(name = "removal_reason")
+ private String removalReason = null;
+
+ public PublicIpQuarantineVO() {
+ }
+
+ public PublicIpQuarantineVO(Long publicIpAddressId, Long previousOwnerId, Date created, Date endDate) {
+ this.publicIpAddressId = publicIpAddressId;
+ this.previousOwnerId = previousOwnerId;
+ this.created = created;
+ this.endDate = endDate;
+ }
+
+ @Override
+ public long getId() {
+ return id;
+ }
+
+ @Override
+ public Long getPublicIpAddressId() {
+ return publicIpAddressId;
+ }
+
+ @Override
+ public Long getPreviousOwnerId() {
+ return previousOwnerId;
+ }
+
+ @Override
+ public Date getEndDate() {
+ return endDate;
+ }
+
+ @Override
+ public String getRemovalReason() {
+ return removalReason;
+ }
+
+ @Override
+ public String getUuid() {
+ return uuid;
+ }
+
+ public void setEndDate(Date endDate) {
+ this.endDate = endDate;
+ }
+
+ public void setRemovalReason(String removalReason) {
+ this.removalReason = removalReason;
+ }
+
+ @Override
+ public Date getRemoved() {
+ return removed;
+ }
+
+ public void setRemoved(Date removed) {
+ this.removed = removed;
+ }
+
+ @Override
+ public Date getCreated() {
+ return created;
+ }
+
+ public void setCreated(Date created) {
+ this.created = created;
+ }
+}
diff --git a/engine/schema/src/main/java/com/cloud/network/vpc/NetworkACLVO.java b/engine/schema/src/main/java/com/cloud/network/vpc/NetworkACLVO.java
index 4eaa2b575e0..280d5dfaf4b 100644
--- a/engine/schema/src/main/java/com/cloud/network/vpc/NetworkACLVO.java
+++ b/engine/schema/src/main/java/com/cloud/network/vpc/NetworkACLVO.java
@@ -17,6 +17,8 @@
package com.cloud.network.vpc;
+import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
+
import java.util.UUID;
import javax.persistence.Column;
@@ -85,6 +87,11 @@ public class NetworkACLVO implements NetworkACL {
return name;
}
+ @Override
+ public String toString() {
+ return ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this, "uuid", "name", "vpcId");
+ }
+
public void setUuid(String uuid) {
this.uuid = uuid;
}
diff --git a/engine/schema/src/main/java/com/cloud/storage/BucketVO.java b/engine/schema/src/main/java/com/cloud/storage/BucketVO.java
new file mode 100644
index 00000000000..181b02e5a1b
--- /dev/null
+++ b/engine/schema/src/main/java/com/cloud/storage/BucketVO.java
@@ -0,0 +1,257 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.storage;
+
+import com.cloud.utils.db.GenericDao;
+import com.google.gson.annotations.Expose;
+import org.apache.cloudstack.storage.object.Bucket;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import java.util.Date;
+import java.util.UUID;
+
+@Entity
+@Table(name = "bucket")
+public class BucketVO implements Bucket {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "id")
+ private long id;
+
+ @Column(name = "account_id")
+ long accountId;
+
+ @Column(name = "domain_id")
+ long domainId;
+
+ @Column(name = "object_store_id")
+ long objectStoreId;
+
+ @Expose
+ @Column(name = "name")
+ String name;
+
+ @Expose
+ @Column(name = "state", updatable = true, nullable = false)
+ @Enumerated(value = EnumType.STRING)
+ private State state;
+
+ @Column(name = "size")
+ Long size;
+
+ @Column(name = "quota")
+ Integer quota;
+
+ @Column(name = "versioning")
+ boolean versioning;
+
+ @Column(name = "encryption")
+ boolean encryption;
+
+ @Column(name = "object_lock")
+ boolean objectLock;
+
+ @Column(name = "policy")
+ String policy;
+
+ @Column(name = "bucket_url")
+ String bucketURL;
+
+ @Column(name = "access_key")
+ String accessKey;
+
+ @Column(name = "secret_key")
+ String secretKey;
+
+ @Column(name = GenericDao.CREATED_COLUMN)
+ Date created;
+
+ @Column(name = GenericDao.REMOVED_COLUMN)
+ Date removed;
+
+ @Column(name = "uuid")
+ String uuid;
+
+ public BucketVO() {
+ }
+
+ public BucketVO(long accountId, long domainId, long objectStoreId, String name, Integer quota, boolean versioning,
+ boolean encryption, boolean objectLock, String policy)
+ {
+ this.accountId = accountId;
+ this.domainId = domainId;
+ this.objectStoreId = objectStoreId;
+ this.name = name;
+ state = State.Allocated;
+ uuid = UUID.randomUUID().toString();
+ this.quota = quota;
+ this.versioning = versioning;
+ this.encryption = encryption;
+ this.objectLock = objectLock;
+ this.policy = policy;
+ this.size = 0L;
+ }
+
+ @Override
+ public long getId() {
+ return id;
+ }
+
+ @Override
+ public long getAccountId() {
+ return accountId;
+ }
+
+ @Override
+ public long getDomainId() {
+ return domainId;
+ }
+
+ @Override
+ public long getObjectStoreId() {
+ return objectStoreId;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ public Long getSize() {
+ return size;
+ }
+
+ @Override
+ public Date getCreated() {
+ return created;
+ }
+
+ public Date getRemoved() {
+ return removed;
+ }
+
+ @Override
+ public State getState() {
+ return state;
+ }
+
+ @Override
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setState(State state) {
+ this.state = state;
+ }
+
+ @Override
+ public String getUuid() {
+ return uuid;
+ }
+
+ public void setUuid(String uuid) {
+ this.uuid = uuid;
+ }
+
+ public Integer getQuota() {
+ return quota;
+ }
+
+ public void setQuota(Integer quota) {
+ this.quota = quota;
+ }
+
+ public boolean isVersioning() {
+ return versioning;
+ }
+
+ public void setVersioning(boolean versioning) {
+ this.versioning = versioning;
+ }
+
+ public boolean isEncryption() {
+ return encryption;
+ }
+
+ public void setEncryption(boolean encryption) {
+ this.encryption = encryption;
+ }
+
+ public boolean isObjectLock() {
+ return objectLock;
+ }
+
+ public void setObjectLock(boolean objectLock) {
+ this.objectLock = objectLock;
+ }
+
+ public String getPolicy() {
+ return policy;
+ }
+
+ public void setPolicy(String policy) {
+ this.policy = policy;
+ }
+
+ public String getBucketURL() {
+ return bucketURL;
+ }
+ public void setBucketURL(String bucketURL) {
+ this.bucketURL = bucketURL;
+ }
+
+ public String getAccessKey() {
+ return accessKey;
+ }
+
+ public void setAccessKey(String accessKey) {
+ this.accessKey = accessKey;
+ }
+
+ public String getSecretKey() {
+ return secretKey;
+ }
+
+ public void setSecretKey(String secretKey) {
+ this.secretKey = secretKey;
+ }
+
+ public void setSize(Long size) {
+ this.size = size;
+ }
+
+ @Override
+ public Class> getEntityType() {
+ return Bucket.class;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("Bucket %s", new ToStringBuilder(this, ToStringStyle.JSON_STYLE).append("uuid", getUuid()).append("name", getName())
+ .append("ObjectStoreId", getObjectStoreId()).toString());
+ }
+}
diff --git a/engine/schema/src/main/java/com/cloud/storage/StoragePoolTagVO.java b/engine/schema/src/main/java/com/cloud/storage/StoragePoolTagVO.java
index 18c0dc3c326..2675c36f27f 100755
--- a/engine/schema/src/main/java/com/cloud/storage/StoragePoolTagVO.java
+++ b/engine/schema/src/main/java/com/cloud/storage/StoragePoolTagVO.java
@@ -23,7 +23,9 @@ import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
+import com.cloud.utils.NumbersUtil;
import org.apache.cloudstack.api.InternalIdentity;
+import org.apache.commons.lang3.BooleanUtils;
@Entity
@Table(name = "storage_pool_tags")
@@ -43,9 +45,19 @@ public class StoragePoolTagVO implements InternalIdentity {
@Column(name = "tag")
private String tag;
+ @Column(name = "is_tag_a_rule")
+ private boolean isTagARule;
+
public StoragePoolTagVO(long poolId, String tag) {
this.poolId = poolId;
this.tag = tag;
+ this.isTagARule = false;
+ }
+
+ public StoragePoolTagVO(long poolId, String tag, Boolean isTagARule) {
+ this.poolId = poolId;
+ this.tag = tag;
+ this.isTagARule = BooleanUtils.toBooleanDefaultIfNull(isTagARule, false);
}
@Override
@@ -61,4 +73,20 @@ public class StoragePoolTagVO implements InternalIdentity {
return tag;
}
+ public boolean isTagARule() {
+ return this.isTagARule;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof StoragePoolTagVO) {
+ return this.poolId == ((StoragePoolTagVO)obj).getPoolId();
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return NumbersUtil.hash(id);
+ }
}
diff --git a/engine/schema/src/main/java/com/cloud/storage/dao/BucketDao.java b/engine/schema/src/main/java/com/cloud/storage/dao/BucketDao.java
new file mode 100644
index 00000000000..f45f28b5c2c
--- /dev/null
+++ b/engine/schema/src/main/java/com/cloud/storage/dao/BucketDao.java
@@ -0,0 +1,30 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.storage.dao;
+
+import com.cloud.storage.BucketVO;
+import com.cloud.utils.db.GenericDao;
+
+import java.util.List;
+
+public interface BucketDao extends GenericDao {
+ List listByObjectStoreId(long objectStoreId);
+
+ List listByObjectStoreIdAndAccountId(long objectStoreId, long accountId);
+
+ List searchByIds(Long[] ids);
+}
diff --git a/engine/schema/src/main/java/com/cloud/storage/dao/BucketDaoImpl.java b/engine/schema/src/main/java/com/cloud/storage/dao/BucketDaoImpl.java
new file mode 100644
index 00000000000..83b5f6bdb74
--- /dev/null
+++ b/engine/schema/src/main/java/com/cloud/storage/dao/BucketDaoImpl.java
@@ -0,0 +1,84 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.storage.dao;
+
+import com.cloud.storage.BucketVO;
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Component;
+
+import javax.naming.ConfigurationException;
+import java.util.List;
+import java.util.Map;
+
+@Component
+public class BucketDaoImpl extends GenericDaoBase implements BucketDao {
+ public static final Logger s_logger = Logger.getLogger(BucketDaoImpl.class.getName());
+ private SearchBuilder searchFilteringStoreId;
+
+ private SearchBuilder bucketSearch;
+
+ private static final String STORE_ID = "store_id";
+ private static final String STATE = "state";
+ private static final String ACCOUNT_ID = "account_id";
+
+ protected BucketDaoImpl() {
+
+ }
+
+ @Override
+ public boolean configure(String name, Map params) throws ConfigurationException {
+ super.configure(name, params);
+
+ searchFilteringStoreId = createSearchBuilder();
+ searchFilteringStoreId.and(STORE_ID, searchFilteringStoreId.entity().getObjectStoreId(), SearchCriteria.Op.EQ);
+ searchFilteringStoreId.and(ACCOUNT_ID, searchFilteringStoreId.entity().getAccountId(), SearchCriteria.Op.EQ);
+ searchFilteringStoreId.and(STATE, searchFilteringStoreId.entity().getState(), SearchCriteria.Op.NEQ);
+ searchFilteringStoreId.done();
+
+ bucketSearch = createSearchBuilder();
+ bucketSearch.and("idIN", bucketSearch.entity().getId(), SearchCriteria.Op.IN);
+ bucketSearch.done();
+
+ return true;
+ }
+ @Override
+ public List listByObjectStoreId(long objectStoreId) {
+ SearchCriteria sc = searchFilteringStoreId.create();
+ sc.setParameters(STORE_ID, objectStoreId);
+ sc.setParameters(STATE, BucketVO.State.Destroyed);
+ return listBy(sc);
+ }
+
+ @Override
+ public List listByObjectStoreIdAndAccountId(long objectStoreId, long accountId) {
+ SearchCriteria sc = searchFilteringStoreId.create();
+ sc.setParameters(STORE_ID, objectStoreId);
+ sc.setParameters(ACCOUNT_ID, accountId);
+ sc.setParameters(STATE, BucketVO.State.Destroyed);
+ return listBy(sc);
+ }
+
+ @Override
+ public List searchByIds(Long[] ids) {
+ SearchCriteria sc = bucketSearch.create();
+ sc.setParameters("idIN", ids);
+ return search(sc, null, null, false);
+ }
+}
diff --git a/engine/schema/src/main/java/com/cloud/storage/dao/StoragePoolTagsDao.java b/engine/schema/src/main/java/com/cloud/storage/dao/StoragePoolTagsDao.java
index 946b46b5cfe..9352ee21858 100755
--- a/engine/schema/src/main/java/com/cloud/storage/dao/StoragePoolTagsDao.java
+++ b/engine/schema/src/main/java/com/cloud/storage/dao/StoragePoolTagsDao.java
@@ -25,10 +25,14 @@ import com.cloud.utils.db.GenericDao;
public interface StoragePoolTagsDao extends GenericDao {
- void persist(long poolId, List storagePoolTags);
+ void persist(long poolId, List storagePoolTags, Boolean isTagARule);
+
+ void persist(List storagePoolTags);
List getStoragePoolTags(long poolId);
void deleteTags(long poolId);
List searchByIds(Long... stIds);
StorageTagResponse newStorageTagResponse(StoragePoolTagVO tag);
+ List findStoragePoolTags(long poolId);
+
}
diff --git a/engine/schema/src/main/java/com/cloud/storage/dao/StoragePoolTagsDaoImpl.java b/engine/schema/src/main/java/com/cloud/storage/dao/StoragePoolTagsDaoImpl.java
index f20e0c411de..c01c66763af 100755
--- a/engine/schema/src/main/java/com/cloud/storage/dao/StoragePoolTagsDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/storage/dao/StoragePoolTagsDaoImpl.java
@@ -21,6 +21,9 @@ import java.util.List;
import javax.inject.Inject;
+import com.cloud.utils.db.Transaction;
+import com.cloud.utils.db.TransactionCallbackNoReturn;
+import com.cloud.utils.db.TransactionStatus;
import org.apache.cloudstack.api.response.StorageTagResponse;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
@@ -50,7 +53,7 @@ public class StoragePoolTagsDaoImpl extends GenericDaoBase storagePoolTags) {
+ public void persist(long poolId, List storagePoolTags, Boolean isTagARule) {
TransactionLegacy txn = TransactionLegacy.currentTxn();
txn.start();
@@ -61,13 +64,23 @@ public class StoragePoolTagsDaoImpl extends GenericDaoBase 0) {
- StoragePoolTagVO vo = new StoragePoolTagVO(poolId, tag);
+ StoragePoolTagVO vo = new StoragePoolTagVO(poolId, tag, isTagARule);
persist(vo);
}
}
txn.commit();
}
+ public void persist(List storagePoolTags) {
+ Transaction.execute(TransactionLegacy.CLOUD_DB, new TransactionCallbackNoReturn() {
+ @Override public void doInTransactionWithoutResult(TransactionStatus status) {
+ for (StoragePoolTagVO storagePoolTagVO : storagePoolTags) {
+ persist(storagePoolTagVO);
+ }
+ }
+ });
+ }
+
@Override
public List getStoragePoolTags(long poolId) {
SearchCriteria sc = StoragePoolSearch.create();
@@ -157,4 +170,12 @@ public class StoragePoolTagsDaoImpl extends GenericDaoBase findStoragePoolTags(long poolId) {
+ SearchCriteria sc = StoragePoolSearch.create();
+ sc.setParameters("poolId", poolId);
+
+ return search(sc, null);
+ }
+
}
diff --git a/engine/schema/src/main/java/com/cloud/upgrade/DatabaseUpgradeChecker.java b/engine/schema/src/main/java/com/cloud/upgrade/DatabaseUpgradeChecker.java
index 21331f654e3..697782dc1db 100644
--- a/engine/schema/src/main/java/com/cloud/upgrade/DatabaseUpgradeChecker.java
+++ b/engine/schema/src/main/java/com/cloud/upgrade/DatabaseUpgradeChecker.java
@@ -22,15 +22,18 @@ import static com.google.common.collect.ObjectArrays.concat;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.nio.file.Paths;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Date;
+import java.util.List;
import javax.inject.Inject;
+import com.cloud.utils.FileUtil;
import org.apache.cloudstack.utils.CloudStackVersion;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
@@ -123,6 +126,7 @@ import com.google.common.annotations.VisibleForTesting;
public class DatabaseUpgradeChecker implements SystemIntegrityChecker {
private static final Logger s_logger = Logger.getLogger(DatabaseUpgradeChecker.class);
private final DatabaseVersionHierarchy hierarchy;
+ private static final String VIEWS_DIRECTORY = Paths.get("META-INF", "db", "views").toString();
@Inject
VersionDao _dao;
@@ -363,9 +367,33 @@ public class DatabaseUpgradeChecker implements SystemIntegrityChecker {
txn.close();
}
}
+
+ executeViewScripts();
updateSystemVmTemplates(upgrades);
}
+ protected void executeViewScripts() {
+ s_logger.info(String.format("Executing VIEW scripts that are under resource directory [%s].", VIEWS_DIRECTORY));
+ List filesPathUnderViewsDirectory = FileUtil.getFilesPathsUnderResourceDirectory(VIEWS_DIRECTORY);
+
+ try (TransactionLegacy txn = TransactionLegacy.open("execute-view-scripts")) {
+ Connection conn = txn.getConnection();
+
+ for (String filePath : filesPathUnderViewsDirectory) {
+ s_logger.debug(String.format("Executing VIEW script [%s].", filePath));
+
+ InputStream viewScript = Thread.currentThread().getContextClassLoader().getResourceAsStream(filePath);
+ runScript(conn, viewScript);
+ }
+
+ s_logger.info(String.format("Finished execution of VIEW scripts that are under resource directory [%s].", VIEWS_DIRECTORY));
+ } catch (SQLException e) {
+ String message = String.format("Unable to execute VIEW scripts due to [%s].", e.getMessage());
+ s_logger.error(message, e);
+ throw new CloudRuntimeException(message, e);
+ }
+ }
+
@Override
public void check() {
GlobalLock lock = GlobalLock.getInternLock("DatabaseUpgrade");
diff --git a/engine/schema/src/main/java/com/cloud/usage/BucketStatisticsVO.java b/engine/schema/src/main/java/com/cloud/usage/BucketStatisticsVO.java
new file mode 100644
index 00000000000..ab5fcfc493c
--- /dev/null
+++ b/engine/schema/src/main/java/com/cloud/usage/BucketStatisticsVO.java
@@ -0,0 +1,74 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.usage;
+
+import org.apache.cloudstack.api.InternalIdentity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "bucket_statistics")
+public class BucketStatisticsVO implements InternalIdentity {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "id")
+ private Long id;
+
+ @Column(name = "account_id", updatable = false)
+ private long accountId;
+
+ @Column(name = "bucket_id", updatable = false)
+ private long bucketId;
+
+ @Column(name = "size")
+ private long size;
+
+ protected BucketStatisticsVO() {
+ }
+
+ public BucketStatisticsVO(long accountId, long bucketId) {
+ this.accountId = accountId;
+ this.bucketId = bucketId;
+ }
+
+ public long getAccountId() {
+ return accountId;
+ }
+
+ public long getBucketId() {
+ return bucketId;
+ }
+
+ @Override
+ public long getId() {
+ return id;
+ }
+
+ public long getSize() {
+ return size;
+ }
+
+ public void setSize(long size) {
+ this.size = size;
+ }
+
+}
diff --git a/engine/schema/src/main/java/com/cloud/usage/dao/BucketStatisticsDao.java b/engine/schema/src/main/java/com/cloud/usage/dao/BucketStatisticsDao.java
new file mode 100644
index 00000000000..48388af9446
--- /dev/null
+++ b/engine/schema/src/main/java/com/cloud/usage/dao/BucketStatisticsDao.java
@@ -0,0 +1,30 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.usage.dao;
+
+import com.cloud.usage.BucketStatisticsVO;
+import com.cloud.utils.db.GenericDao;
+
+import java.util.List;
+
+public interface BucketStatisticsDao extends GenericDao {
+ BucketStatisticsVO findBy(long accountId, long bucketId);
+
+ BucketStatisticsVO lock(long accountId, long bucketId);
+
+ List listBy(long accountId);
+}
diff --git a/engine/schema/src/main/java/com/cloud/usage/dao/BucketStatisticsDaoImpl.java b/engine/schema/src/main/java/com/cloud/usage/dao/BucketStatisticsDaoImpl.java
new file mode 100644
index 00000000000..2261389eab6
--- /dev/null
+++ b/engine/schema/src/main/java/com/cloud/usage/dao/BucketStatisticsDaoImpl.java
@@ -0,0 +1,67 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.usage.dao;
+
+import com.cloud.usage.BucketStatisticsVO;
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+@Component
+public class BucketStatisticsDaoImpl extends GenericDaoBase implements BucketStatisticsDao {
+ private static final Logger s_logger = Logger.getLogger(BucketStatisticsDaoImpl.class);
+ private final SearchBuilder AllFieldsSearch;
+ private final SearchBuilder AccountSearch;
+
+ public BucketStatisticsDaoImpl() {
+ AccountSearch = createSearchBuilder();
+ AccountSearch.and("account", AccountSearch.entity().getAccountId(), SearchCriteria.Op.EQ);
+ AccountSearch.done();
+
+ AllFieldsSearch = createSearchBuilder();
+ AllFieldsSearch.and("account", AllFieldsSearch.entity().getAccountId(), SearchCriteria.Op.EQ);
+ AllFieldsSearch.and("bucket", AllFieldsSearch.entity().getBucketId(), SearchCriteria.Op.EQ);
+ AllFieldsSearch.done();
+ }
+
+ @Override
+ public BucketStatisticsVO findBy(long accountId, long bucketId) {
+ SearchCriteria sc = AllFieldsSearch.create();
+ sc.setParameters("account", accountId);
+ sc.setParameters("bucket", bucketId);
+ return findOneBy(sc);
+ }
+
+ @Override
+ public BucketStatisticsVO lock(long accountId, long bucketId) {
+ SearchCriteria sc = AllFieldsSearch.create();
+ sc.setParameters("account", accountId);
+ sc.setParameters("bucket", bucketId);
+ return lockOneRandomRow(sc, true);
+ }
+
+ @Override
+ public List listBy(long accountId) {
+ SearchCriteria sc = AccountSearch.create();
+ sc.setParameters("account", accountId);
+ return search(sc, null);
+ }
+}
diff --git a/engine/schema/src/main/java/com/cloud/usage/dao/UsageDao.java b/engine/schema/src/main/java/com/cloud/usage/dao/UsageDao.java
index 4099b3ada0d..ea490e60f9e 100644
--- a/engine/schema/src/main/java/com/cloud/usage/dao/UsageDao.java
+++ b/engine/schema/src/main/java/com/cloud/usage/dao/UsageDao.java
@@ -16,6 +16,7 @@
// under the License.
package com.cloud.usage.dao;
+import com.cloud.usage.BucketStatisticsVO;
import com.cloud.usage.UsageVO;
import com.cloud.user.AccountVO;
import com.cloud.user.UserStatisticsVO;
@@ -45,6 +46,12 @@ public interface UsageDao extends GenericDao {
Long getLastUserStatsId();
+ Long getLastBucketStatsId();
+
+ void saveBucketStats(List userStats);
+
+ void updateBucketStats(List userStats);
+
List listPublicTemplatesByAccount(long accountId);
Long getLastVmDiskStatsId();
diff --git a/engine/schema/src/main/java/com/cloud/usage/dao/UsageDaoImpl.java b/engine/schema/src/main/java/com/cloud/usage/dao/UsageDaoImpl.java
index 4553ed822b4..0d9e727abe2 100644
--- a/engine/schema/src/main/java/com/cloud/usage/dao/UsageDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/usage/dao/UsageDaoImpl.java
@@ -16,6 +16,7 @@
// under the License.
package com.cloud.usage.dao;
+import com.cloud.usage.BucketStatisticsVO;
import com.cloud.usage.UsageVO;
import com.cloud.user.AccountVO;
import com.cloud.user.UserStatisticsVO;
@@ -82,6 +83,13 @@ public class UsageDaoImpl extends GenericDaoBase implements Usage
+ "WHERE cloud_usage.usage_type = ? AND cloud_usage.account_id = ? AND cloud_usage.start_date >= ? AND cloud_usage.end_date <= ? "
+ "GROUP BY cloud_usage.usage_id ";
+ private static final String GET_LAST_BUCKET_STATS_ID = "SELECT id FROM cloud_usage.bucket_statistics ORDER BY id DESC LIMIT 1";
+
+ private static final String INSERT_BUCKET_STATS = "INSERT INTO cloud_usage.bucket_statistics (id, account_id, bucket_id, size) VALUES (?,?,?,?)";
+
+ private static final String UPDATE_BUCKET_STATS = "UPDATE cloud_usage.bucket_statistics SET size=? WHERE id=?";
+
+
public UsageDaoImpl() {
}
@@ -285,6 +293,69 @@ public class UsageDaoImpl extends GenericDaoBase implements Usage
return null;
}
+ @Override
+ public Long getLastBucketStatsId() {
+ TransactionLegacy txn = TransactionLegacy.currentTxn();
+ PreparedStatement pstmt = null;
+ String sql = GET_LAST_BUCKET_STATS_ID;
+ try {
+ pstmt = txn.prepareAutoCloseStatement(sql);
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next()) {
+ return Long.valueOf(rs.getLong(1));
+ }
+ } catch (Exception ex) {
+ s_logger.error("error getting last bucket stats id", ex);
+ }
+ return null;
+ }
+
+ @Override
+ public void saveBucketStats(List bucketStats) {
+ TransactionLegacy txn = TransactionLegacy.currentTxn();
+ try {
+ txn.start();
+ String sql = INSERT_BUCKET_STATS;
+ PreparedStatement pstmt = null;
+ pstmt = txn.prepareAutoCloseStatement(sql); // in reality I just want CLOUD_USAGE dataSource connection
+ for (BucketStatisticsVO bucketStat : bucketStats) {
+ pstmt.setLong(1, bucketStat.getId());
+ pstmt.setLong(2, bucketStat.getAccountId());
+ pstmt.setLong(3, bucketStat.getBucketId());
+ pstmt.setLong(4, bucketStat.getSize());
+ pstmt.addBatch();
+ }
+ pstmt.executeBatch();
+ txn.commit();
+ } catch (Exception ex) {
+ txn.rollback();
+ s_logger.error("error saving bucket stats to cloud_usage db", ex);
+ throw new CloudRuntimeException(ex.getMessage());
+ }
+ }
+
+ @Override
+ public void updateBucketStats(List bucketStats) {
+ TransactionLegacy txn = TransactionLegacy.currentTxn();
+ try {
+ txn.start();
+ String sql = UPDATE_BUCKET_STATS;
+ PreparedStatement pstmt = null;
+ pstmt = txn.prepareAutoCloseStatement(sql); // in reality I just want CLOUD_USAGE dataSource connection
+ for (BucketStatisticsVO bucketStat : bucketStats) {
+ pstmt.setLong(1, bucketStat.getSize());
+ pstmt.setLong(2, bucketStat.getId());
+ pstmt.addBatch();
+ }
+ pstmt.executeBatch();
+ txn.commit();
+ } catch (Exception ex) {
+ txn.rollback();
+ s_logger.error("error updating bucket stats to cloud_usage db", ex);
+ throw new CloudRuntimeException(ex.getMessage());
+ }
+ }
+
@Override
public List listPublicTemplatesByAccount(long accountId) {
TransactionLegacy txn = TransactionLegacy.currentTxn();
diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/NicDao.java b/engine/schema/src/main/java/com/cloud/vm/dao/NicDao.java
index 22165641f7e..68f57329d77 100644
--- a/engine/schema/src/main/java/com/cloud/vm/dao/NicDao.java
+++ b/engine/schema/src/main/java/com/cloud/vm/dao/NicDao.java
@@ -79,7 +79,9 @@ public interface NicDao extends GenericDao {
List listByNetworkIdTypeAndGatewayAndBroadcastUri(long networkId, VirtualMachine.Type vmType, String gateway, URI broadcastUri);
- int countNicsForStartingVms(long networkId);
+ int countNicsForNonStoppedVms(long networkId);
+
+ int countNicsForNonStoppedRunningVrs(long networkId);
NicVO getControlNicForVM(long vmId);
diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/NicDaoImpl.java b/engine/schema/src/main/java/com/cloud/vm/dao/NicDaoImpl.java
index 211e5480423..59d2417b073 100644
--- a/engine/schema/src/main/java/com/cloud/vm/dao/NicDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/vm/dao/NicDaoImpl.java
@@ -44,7 +44,7 @@ public class NicDaoImpl extends GenericDaoBase implements NicDao {
private GenericSearchBuilder IpSearch;
private SearchBuilder NonReleasedSearch;
private GenericSearchBuilder deviceIdSearch;
- private GenericSearchBuilder CountByForStartingVms;
+ private GenericSearchBuilder CountByForNonStoppedVms;
private SearchBuilder PeerRouterSearch;
@Inject
@@ -91,14 +91,16 @@ public class NicDaoImpl extends GenericDaoBase implements NicDao {
deviceIdSearch.and("instance", deviceIdSearch.entity().getInstanceId(), Op.EQ);
deviceIdSearch.done();
- CountByForStartingVms = createSearchBuilder(Integer.class);
- CountByForStartingVms.select(null, Func.COUNT, CountByForStartingVms.entity().getId());
- CountByForStartingVms.and("networkId", CountByForStartingVms.entity().getNetworkId(), Op.EQ);
- CountByForStartingVms.and("removed", CountByForStartingVms.entity().getRemoved(), Op.NULL);
+ CountByForNonStoppedVms = createSearchBuilder(Integer.class);
+ CountByForNonStoppedVms.select(null, Func.COUNT, CountByForNonStoppedVms.entity().getId());
+ CountByForNonStoppedVms.and("vmType", CountByForNonStoppedVms.entity().getVmType(), Op.EQ);
+ CountByForNonStoppedVms.and("vmTypeNEQ", CountByForNonStoppedVms.entity().getVmType(), Op.NEQ);
+ CountByForNonStoppedVms.and("networkId", CountByForNonStoppedVms.entity().getNetworkId(), Op.EQ);
+ CountByForNonStoppedVms.and("removed", CountByForNonStoppedVms.entity().getRemoved(), Op.NULL);
SearchBuilder join1 = _vmDao.createSearchBuilder();
- join1.and("state", join1.entity().getState(), Op.EQ);
- CountByForStartingVms.join("vm", join1, CountByForStartingVms.entity().getInstanceId(), join1.entity().getId(), JoinBuilder.JoinType.INNER);
- CountByForStartingVms.done();
+ join1.and("state", join1.entity().getState(), Op.IN);
+ CountByForNonStoppedVms.join("vm", join1, CountByForNonStoppedVms.entity().getInstanceId(), join1.entity().getId(), JoinBuilder.JoinType.INNER);
+ CountByForNonStoppedVms.done();
PeerRouterSearch = createSearchBuilder();
PeerRouterSearch.and("instanceId", PeerRouterSearch.entity().getInstanceId(), Op.NEQ);
@@ -346,10 +348,21 @@ public class NicDaoImpl extends GenericDaoBase implements NicDao {
}
@Override
- public int countNicsForStartingVms(long networkId) {
- SearchCriteria sc = CountByForStartingVms.create();
+ public int countNicsForNonStoppedVms(long networkId) {
+ SearchCriteria sc = CountByForNonStoppedVms.create();
sc.setParameters("networkId", networkId);
- sc.setJoinParameters("vm", "state", VirtualMachine.State.Starting);
+ sc.setParameters("vmType", VirtualMachine.Type.User);
+ sc.setJoinParameters("vm", "state", new Object[] {VirtualMachine.State.Starting, VirtualMachine.State.Running, VirtualMachine.State.Stopping, VirtualMachine.State.Migrating});
+ List results = customSearch(sc, null);
+ return results.get(0);
+ }
+
+ @Override
+ public int countNicsForNonStoppedRunningVrs(long networkId) {
+ SearchCriteria sc = CountByForNonStoppedVms.create();
+ sc.setParameters("networkId", networkId);
+ sc.setParameters("vmTypeNEQ", VirtualMachine.Type.User);
+ sc.setJoinParameters("vm", "state", new Object[] {VirtualMachine.State.Starting, VirtualMachine.State.Stopping, VirtualMachine.State.Migrating});
List results = customSearch(sc, null);
return results.get(0);
}
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/secstorage/HeuristicVO.java b/engine/schema/src/main/java/org/apache/cloudstack/secstorage/HeuristicVO.java
new file mode 100644
index 00000000000..b0da0c5e747
--- /dev/null
+++ b/engine/schema/src/main/java/org/apache/cloudstack/secstorage/HeuristicVO.java
@@ -0,0 +1,125 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.secstorage;
+
+import com.cloud.utils.db.GenericDao;
+import org.apache.cloudstack.secstorage.heuristics.Heuristic;
+import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import java.util.Date;
+import java.util.UUID;
+
+@Entity
+@Table(name = "heuristics")
+public class HeuristicVO implements Heuristic {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "id", nullable = false)
+ private Long id;
+
+ @Column(name = "uuid", nullable = false)
+ private String uuid = UUID.randomUUID().toString();
+
+ @Column(name = "name")
+ private String name;
+
+ @Column(name = "description")
+ private String description;
+
+ @Column(name = "zone_id", nullable = false)
+ private Long zoneId;
+
+ @Column(name = "type", nullable = false)
+ private String type;
+
+ @Column(name = "heuristic_rule", nullable = false, length = 65535)
+ private String heuristicRule;
+
+ @Column(name = GenericDao.CREATED_COLUMN, nullable = false)
+ @Temporal(value = TemporalType.TIMESTAMP)
+ private Date created;
+
+ @Column(name = GenericDao.REMOVED_COLUMN)
+ @Temporal(value = TemporalType.TIMESTAMP)
+ private Date removed = null;
+
+ public HeuristicVO() {
+ }
+
+ public HeuristicVO(String name, String description, Long zoneId, String type, String heuristicRule) {
+ this.name = name;
+ this.description = description;
+ this.zoneId = zoneId;
+ this.type = type;
+ this.heuristicRule = heuristicRule;
+ }
+
+ @Override
+ public long getId() {
+ return id;
+ }
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public Long getZoneId() {
+ return zoneId;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public String getHeuristicRule() {
+ return heuristicRule;
+ }
+
+ public Date getCreated() {
+ return created;
+ }
+
+ public Date getRemoved() {
+ return removed;
+ }
+
+ public void setHeuristicRule(String heuristicRule) {
+ this.heuristicRule = heuristicRule;
+ }
+
+ @Override
+ public String toString() {
+ return ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this, "name", "heuristicRule", "type");
+ }
+}
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/secstorage/dao/SecondaryStorageHeuristicDao.java b/engine/schema/src/main/java/org/apache/cloudstack/secstorage/dao/SecondaryStorageHeuristicDao.java
new file mode 100644
index 00000000000..1c4057a7beb
--- /dev/null
+++ b/engine/schema/src/main/java/org/apache/cloudstack/secstorage/dao/SecondaryStorageHeuristicDao.java
@@ -0,0 +1,26 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.secstorage.dao;
+
+import com.cloud.utils.db.GenericDao;
+import org.apache.cloudstack.secstorage.HeuristicVO;
+import org.apache.cloudstack.secstorage.heuristics.HeuristicType;
+
+public interface SecondaryStorageHeuristicDao extends GenericDao {
+
+ HeuristicVO findByZoneIdAndType(long zoneId, HeuristicType type);
+}
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/secstorage/dao/SecondaryStorageHeuristicDaoImpl.java b/engine/schema/src/main/java/org/apache/cloudstack/secstorage/dao/SecondaryStorageHeuristicDaoImpl.java
new file mode 100644
index 00000000000..0b51b2aec6b
--- /dev/null
+++ b/engine/schema/src/main/java/org/apache/cloudstack/secstorage/dao/SecondaryStorageHeuristicDaoImpl.java
@@ -0,0 +1,50 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.secstorage.dao;
+
+import com.cloud.utils.db.Filter;
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import org.apache.cloudstack.secstorage.HeuristicVO;
+import org.apache.cloudstack.secstorage.heuristics.HeuristicType;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+
+@Component
+public class SecondaryStorageHeuristicDaoImpl extends GenericDaoBase implements SecondaryStorageHeuristicDao {
+ private SearchBuilder zoneAndTypeSearch;
+
+ @PostConstruct
+ public void init() {
+ zoneAndTypeSearch = createSearchBuilder();
+ zoneAndTypeSearch.and("zoneId", zoneAndTypeSearch.entity().getZoneId(), SearchCriteria.Op.EQ);
+ zoneAndTypeSearch.and("type", zoneAndTypeSearch.entity().getType(), SearchCriteria.Op.IN);
+ zoneAndTypeSearch.done();
+ }
+
+ @Override
+ public HeuristicVO findByZoneIdAndType(long zoneId, HeuristicType type) {
+ SearchCriteria searchCriteria = zoneAndTypeSearch.create();
+ searchCriteria.setParameters("zoneId", zoneId);
+ searchCriteria.setParameters("type", type.toString());
+ final Filter filter = new Filter(HeuristicVO.class, "created", false);
+
+ return findOneBy(searchCriteria, filter);
+ }
+}
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/ImageStoreDao.java b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/ImageStoreDao.java
index ba9825c3c86..1c31b3e0cc4 100644
--- a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/ImageStoreDao.java
+++ b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/ImageStoreDao.java
@@ -49,4 +49,6 @@ public interface ImageStoreDao extends GenericDao {
List findByProtocol(String protocol);
ImageStoreVO findOneByZoneAndProtocol(long zoneId, String protocol);
+
+ List listImageStoresByZoneIds(Long... zoneIds);
}
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/ImageStoreDaoImpl.java b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/ImageStoreDaoImpl.java
index 3468b6008d9..a4827a1beae 100644
--- a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/ImageStoreDaoImpl.java
+++ b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/ImageStoreDaoImpl.java
@@ -43,6 +43,8 @@ public class ImageStoreDaoImpl extends GenericDaoBase implem
private SearchBuilder protocolSearch;
private SearchBuilder zoneProtocolSearch;
+ private SearchBuilder zonesInSearch;
+
public ImageStoreDaoImpl() {
super();
protocolSearch = createSearchBuilder();
@@ -55,6 +57,11 @@ public class ImageStoreDaoImpl extends GenericDaoBase implem
zoneProtocolSearch.and("protocol", zoneProtocolSearch.entity().getProtocol(), SearchCriteria.Op.EQ);
zoneProtocolSearch.and("role", zoneProtocolSearch.entity().getRole(), SearchCriteria.Op.EQ);
zoneProtocolSearch.done();
+
+ zonesInSearch = createSearchBuilder();
+ zonesInSearch.and("zonesIn", zonesInSearch.entity().getDcId(), SearchCriteria.Op.IN);
+ zonesInSearch.done();
+
}
@Override
public boolean configure(String name, Map params) throws ConfigurationException {
@@ -191,4 +198,12 @@ public class ImageStoreDaoImpl extends GenericDaoBase implem
List results = listBy(sc, filter);
return results.size() == 0 ? null : results.get(0);
}
+
+
+ @Override
+ public List listImageStoresByZoneIds(Long... zoneIds) {
+ SearchCriteria sc = zonesInSearch.create();
+ sc.setParametersIfNotNull("zonesIn", zoneIds);
+ return listBy(sc);
+ }
}
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/ObjectStoreDao.java b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/ObjectStoreDao.java
new file mode 100644
index 00000000000..94f6b5ec372
--- /dev/null
+++ b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/ObjectStoreDao.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cloudstack.storage.datastore.db;
+
+import com.cloud.utils.db.GenericDao;
+import org.apache.cloudstack.api.response.ObjectStoreResponse;
+
+import java.util.List;
+
+public interface ObjectStoreDao extends GenericDao {
+ ObjectStoreVO findByName(String name);
+
+ List findByProvider(String provider);
+
+ ObjectStoreVO findByUrl(String url);
+
+ List listObjectStores();
+
+ List searchByIds(Long[] osIds);
+
+ ObjectStoreResponse newObjectStoreResponse(ObjectStoreVO store);
+
+ ObjectStoreResponse setObjectStoreResponse(ObjectStoreResponse storeData, ObjectStoreVO store);
+
+ Integer countAllObjectStores();
+}
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/ObjectStoreDaoImpl.java b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/ObjectStoreDaoImpl.java
new file mode 100644
index 00000000000..51abde013b6
--- /dev/null
+++ b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/ObjectStoreDaoImpl.java
@@ -0,0 +1,162 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cloudstack.storage.datastore.db;
+
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import org.apache.cloudstack.api.response.ObjectStoreResponse;
+import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
+import org.springframework.stereotype.Component;
+
+import javax.inject.Inject;
+import javax.naming.ConfigurationException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+@Component
+public class ObjectStoreDaoImpl extends GenericDaoBase implements ObjectStoreDao {
+ private SearchBuilder nameSearch;
+ private SearchBuilder providerSearch;
+ @Inject
+ private ConfigurationDao _configDao;
+ private final SearchBuilder osSearch;
+
+ private SearchBuilder urlSearch;
+
+ protected ObjectStoreDaoImpl() {
+ osSearch = createSearchBuilder();
+ osSearch.and("idIN", osSearch.entity().getId(), SearchCriteria.Op.IN);
+ osSearch.done();
+ }
+
+ @Override
+ public boolean configure(String name, Map params) throws ConfigurationException {
+ super.configure(name, params);
+
+ nameSearch = createSearchBuilder();
+ nameSearch.and("name", nameSearch.entity().getName(), SearchCriteria.Op.EQ);
+ nameSearch.done();
+
+ providerSearch = createSearchBuilder();
+ providerSearch.and("providerName", providerSearch.entity().getProviderName(), SearchCriteria.Op.EQ);
+ providerSearch.done();
+
+ urlSearch = createSearchBuilder();
+ urlSearch.and("url", urlSearch.entity().getUrl(), SearchCriteria.Op.EQ);
+ urlSearch.done();
+
+ return true;
+ }
+
+ @Override
+ public ObjectStoreVO findByName(String name) {
+ SearchCriteria sc = nameSearch.create();
+ sc.setParameters("name", name);
+ return findOneBy(sc);
+ }
+
+ @Override
+ public List findByProvider(String provider) {
+ SearchCriteria sc = providerSearch.create();
+ sc.setParameters("providerName", provider);
+ return listBy(sc);
+ }
+
+ @Override
+ public ObjectStoreVO findByUrl(String url) {
+ SearchCriteria sc = urlSearch.create();
+ sc.setParameters("url", url);
+ return findOneBy(sc);
+ }
+
+ @Override
+ public List listObjectStores() {
+ SearchCriteria sc = createSearchCriteria();
+ return listBy(sc);
+ }
+
+ @Override
+ public List searchByIds(Long[] osIds) {
+ // set detail batch query size
+ int DETAILS_BATCH_SIZE = 2000;
+ String batchCfg = _configDao.getValue("detail.batch.query.size");
+ if (batchCfg != null) {
+ DETAILS_BATCH_SIZE = Integer.parseInt(batchCfg);
+ }
+ // query details by batches
+ List osList = new ArrayList<>();
+ // query details by batches
+ int curr_index = 0;
+ if (osIds.length > DETAILS_BATCH_SIZE) {
+ while ((curr_index + DETAILS_BATCH_SIZE) <= osIds.length) {
+ Long[] ids = new Long[DETAILS_BATCH_SIZE];
+ for (int k = 0, j = curr_index; j < curr_index + DETAILS_BATCH_SIZE; j++, k++) {
+ ids[k] = osIds[j];
+ }
+ SearchCriteria sc = osSearch.create();
+ sc.setParameters("idIN", ids);
+ List stores = searchIncludingRemoved(sc, null, null, false);
+ if (stores != null) {
+ osList.addAll(stores);
+ }
+ curr_index += DETAILS_BATCH_SIZE;
+ }
+ }
+ if (curr_index < osIds.length) {
+ int batch_size = (osIds.length - curr_index);
+ // set the ids value
+ Long[] ids = new Long[batch_size];
+ for (int k = 0, j = curr_index; j < curr_index + batch_size; j++, k++) {
+ ids[k] = osIds[j];
+ }
+ SearchCriteria sc = osSearch.create();
+ sc.setParameters("idIN", ids);
+ List stores = searchIncludingRemoved(sc, null, null, false);
+ if (stores != null) {
+ osList.addAll(stores);
+ }
+ }
+ return osList;
+ }
+
+ @Override
+ public ObjectStoreResponse newObjectStoreResponse(ObjectStoreVO store) {
+ ObjectStoreResponse osResponse = new ObjectStoreResponse();
+ osResponse.setId(store.getUuid());
+ osResponse.setName(store.getName());
+ osResponse.setProviderName(store.getProviderName());
+ String url = store.getUrl();
+ osResponse.setUrl(url);
+ osResponse.setObjectName("objectstore");
+ return osResponse;
+ }
+
+ @Override
+ public ObjectStoreResponse setObjectStoreResponse(ObjectStoreResponse storeData, ObjectStoreVO store) {
+ return storeData;
+ }
+
+ @Override
+ public Integer countAllObjectStores() {
+ SearchCriteria sc = createSearchCriteria();
+ return getCount(sc);
+ }
+}
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/ObjectStoreDetailVO.java b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/ObjectStoreDetailVO.java
new file mode 100644
index 00000000000..1f4047f8f90
--- /dev/null
+++ b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/ObjectStoreDetailVO.java
@@ -0,0 +1,77 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.storage.datastore.db;
+
+import org.apache.cloudstack.api.ResourceDetail;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "object_store_details")
+public class ObjectStoreDetailVO implements ResourceDetail {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "id")
+ long id;
+
+ @Column(name = "store_id")
+ long resourceId;
+
+ @Column(name = "name")
+ String name;
+
+ @Column(name = "value")
+ String value;
+
+ public ObjectStoreDetailVO() {
+ }
+ public ObjectStoreDetailVO(long storeId, String name, String value) {
+ this.resourceId = storeId;
+ this.name = name;
+ this.value = value;
+ }
+ @Override
+ public long getId() {
+ return id;
+ }
+
+ @Override
+ public long getResourceId() {
+ return resourceId;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getValue() {
+ return value;
+ }
+
+ @Override
+ public boolean isDisplay() {
+ return true;
+ }
+
+}
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/ObjectStoreDetailsDao.java b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/ObjectStoreDetailsDao.java
new file mode 100644
index 00000000000..170a28af502
--- /dev/null
+++ b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/ObjectStoreDetailsDao.java
@@ -0,0 +1,31 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.storage.datastore.db;
+
+import com.cloud.utils.db.GenericDao;
+import org.apache.cloudstack.resourcedetail.ResourceDetailsDao;
+
+import java.util.Map;
+
+public interface ObjectStoreDetailsDao extends GenericDao, ResourceDetailsDao {
+
+ void update(long storeId, Map details);
+
+ Map getDetails(long storeId);
+
+ void deleteDetails(long storeId);
+}
diff --git a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/ObjectStoreDetailsDaoImpl.java b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/ObjectStoreDetailsDaoImpl.java
new file mode 100644
index 00000000000..e1000e5d045
--- /dev/null
+++ b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/ObjectStoreDetailsDaoImpl.java
@@ -0,0 +1,104 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.storage.datastore.db;
+
+import com.cloud.utils.crypt.DBEncryptionUtil;
+import com.cloud.utils.db.QueryBuilder;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import com.cloud.utils.db.SearchCriteria.Op;
+import com.cloud.utils.db.TransactionLegacy;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Component
+public class ObjectStoreDetailsDaoImpl extends ResourceDetailsDaoBase implements ObjectStoreDetailsDao {
+
+ protected final SearchBuilder storeSearch;
+
+ public ObjectStoreDetailsDaoImpl() {
+ super();
+ storeSearch = createSearchBuilder();
+ storeSearch.and("store", storeSearch.entity().getResourceId(), Op.EQ);
+ storeSearch.done();
+ }
+
+ @Override
+ public void update(long storeId, Map details) {
+ TransactionLegacy txn = TransactionLegacy.currentTxn();
+ SearchCriteria sc = storeSearch.create();
+ sc.setParameters("store", storeId);
+
+ txn.start();
+ expunge(sc);
+ for (Map.Entry entry : details.entrySet()) {
+ ObjectStoreDetailVO detail = new ObjectStoreDetailVO(storeId, entry.getKey(), entry.getValue());
+ persist(detail);
+ }
+ txn.commit();
+ }
+
+ @Override
+ public Map getDetails(long storeId) {
+ SearchCriteria sc = storeSearch.create();
+ sc.setParameters("store", storeId);
+
+ List details = listBy(sc);
+ Map detailsMap = new HashMap();
+ for (ObjectStoreDetailVO detail : details) {
+ String name = detail.getName();
+ String value = detail.getValue();
+ if (name.equals(ApiConstants.KEY)) {
+ value = DBEncryptionUtil.decrypt(value);
+ }
+ detailsMap.put(name, value);
+ }
+
+ return detailsMap;
+ }
+
+ @Override
+ public void deleteDetails(long storeId) {
+ SearchCriteria sc = storeSearch.create();
+ sc.setParameters("store", storeId);
+
+ List results = search(sc, null);
+ for (ObjectStoreDetailVO result : results) {
+ remove(result.getId());
+ }
+ }
+
+ @Override
+ public ObjectStoreDetailVO findDetail(long storeId, String name) {
+ QueryBuilder