ObjectStore Framework with MinIO and Simulator plugins (#7752)

This PR adds Object Storage feature to CloudStack.

FS: https://cwiki.apache.org/confluence/display/CLOUDSTACK/%5BDRAFT%5D+CloudStack+Object+Store
This commit is contained in:
kishankavala 2023-12-01 17:51:00 +05:30 committed by GitHub
parent 37a2350159
commit 5651eab49c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
120 changed files with 8985 additions and 224 deletions

View File

@ -93,6 +93,7 @@ jobs:
smoke/test_nic smoke/test_nic
smoke/test_nic_adapter_type smoke/test_nic_adapter_type
smoke/test_non_contigiousvlan smoke/test_non_contigiousvlan
smoke/test_object_stores
smoke/test_outofbandmanagement smoke/test_outofbandmanagement
smoke/test_outofbandmanagement_nestedplugin smoke/test_outofbandmanagement_nestedplugin
smoke/test_over_provisioning smoke/test_over_provisioning

View File

@ -29,6 +29,8 @@ import org.apache.cloudstack.api.response.PodResponse;
import org.apache.cloudstack.api.response.ZoneResponse; import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.cloudstack.config.Configuration; import org.apache.cloudstack.config.Configuration;
import org.apache.cloudstack.ha.HAConfig; 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.usage.Usage;
import org.apache.cloudstack.vm.schedule.VMSchedule; import org.apache.cloudstack.vm.schedule.VMSchedule;
@ -714,6 +716,16 @@ public class EventTypes {
// SystemVM // SystemVM
public static final String EVENT_LIVE_PATCH_SYSTEMVM = "LIVE.PATCH.SYSTEM.VM"; 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 { static {
// TODO: need a way to force author adding event types to declare the entity details as well, with out braking // 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_DATA_MIGRATE, ImageStore.class);
entityEventDetails.put(EVENT_IMAGE_STORE_OBJECT_DOWNLOAD, ImageStore.class); entityEventDetails.put(EVENT_IMAGE_STORE_OBJECT_DOWNLOAD, ImageStore.class);
entityEventDetails.put(EVENT_LIVE_PATCH_SYSTEMVM, "SystemVMs"); 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) { public static String getEntityForEvent(String eventName) {

View File

@ -69,7 +69,8 @@ public interface ResourceTag extends ControlledEntity, Identity, InternalIdentit
GuestOs(false, true), GuestOs(false, true),
NetworkOffering(false, true), NetworkOffering(false, true),
VpcOffering(true, false), VpcOffering(true, false),
Domain(false, false, true); Domain(false, false, true),
ObjectStore(false, false, true);
ResourceObjectType(boolean resourceTagsSupport, boolean resourceMetadataSupport) { ResourceObjectType(boolean resourceTagsSupport, boolean resourceMetadataSupport) {

View File

@ -21,7 +21,7 @@ package com.cloud.storage;
import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.CloudRuntimeException;
public enum DataStoreRole { public enum DataStoreRole {
Primary("primary"), Image("image"), ImageCache("imagecache"), Backup("backup"); Primary("primary"), Image("image"), ImageCache("imagecache"), Backup("backup"), Object("object");
public boolean isImageStore() { public boolean isImageStore() {
return (role.equalsIgnoreCase("image") || role.equalsIgnoreCase("imagecache")) ? true : false; return (role.equalsIgnoreCase("image") || role.equalsIgnoreCase("imagecache")) ? true : false;
@ -45,6 +45,8 @@ public enum DataStoreRole {
return ImageCache; return ImageCache;
} else if (role.equalsIgnoreCase("backup")) { } else if (role.equalsIgnoreCase("backup")) {
return Backup; return Backup;
} else if (role.equalsIgnoreCase("object")) {
return Object;
} else { } else {
throw new CloudRuntimeException("can't identify the role"); throw new CloudRuntimeException("can't identify the role");
} }

View File

@ -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.CreateSecondaryStagingStoreCmd;
import org.apache.cloudstack.api.command.admin.storage.CreateStoragePoolCmd; 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.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.DeletePoolCmd;
import org.apache.cloudstack.api.command.admin.storage.DeleteSecondaryStagingStoreCmd; 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.SyncStoragePoolCmd;
import org.apache.cloudstack.api.command.admin.storage.UpdateObjectStoragePoolCmd;
import org.apache.cloudstack.api.command.admin.storage.UpdateStoragePoolCmd; import org.apache.cloudstack.api.command.admin.storage.UpdateStoragePoolCmd;
import com.cloud.exception.DiscoveryException; import com.cloud.exception.DiscoveryException;
@ -34,6 +36,7 @@ import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.ResourceInUseException; import com.cloud.exception.ResourceInUseException;
import com.cloud.exception.ResourceUnavailableException; import com.cloud.exception.ResourceUnavailableException;
import org.apache.cloudstack.storage.object.ObjectStore;
public interface StorageService { public interface StorageService {
/** /**
@ -109,4 +112,9 @@ public interface StorageService {
StoragePool syncStoragePool(SyncStoragePoolCmd cmd); StoragePool syncStoragePool(SyncStoragePoolCmd 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);
} }

View File

@ -45,7 +45,7 @@ public interface AnnotationService {
SERVICE_OFFERING(false), DISK_OFFERING(false), NETWORK_OFFERING(false), SERVICE_OFFERING(false), DISK_OFFERING(false), NETWORK_OFFERING(false),
ZONE(false), POD(false), CLUSTER(false), HOST(false), DOMAIN(false), ZONE(false), POD(false), CLUSTER(false), HOST(false), DOMAIN(false),
PRIMARY_STORAGE(false), SECONDARY_STORAGE(false), VR(false), SYSTEM_VM(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; private final boolean usersAllowed;
@ -78,6 +78,7 @@ public interface AnnotationService {
list.add(EntityType.VR); list.add(EntityType.VR);
list.add(EntityType.SYSTEM_VM); list.add(EntityType.SYSTEM_VM);
list.add(EntityType.MANAGEMENT_SERVER); list.add(EntityType.MANAGEMENT_SERVER);
list.add(EntityType.OBJECT_STORAGE);
if (roleType != RoleType.DomainAdmin) { if (roleType != RoleType.DomainAdmin) {
list.add(EntityType.DOMAIN); list.add(EntityType.DOMAIN);
list.add(EntityType.SERVICE_OFFERING); list.add(EntityType.SERVICE_OFFERING);

View File

@ -78,7 +78,9 @@ public enum ApiCommandResourceType {
VmSnapshot(com.cloud.vm.snapshot.VMSnapshot.class), VmSnapshot(com.cloud.vm.snapshot.VMSnapshot.class),
Role(org.apache.cloudstack.acl.Role.class), Role(org.apache.cloudstack.acl.Role.class),
VpnCustomerGateway(com.cloud.network.Site2SiteCustomerGateway.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; private final Class<?> clazz;

View File

@ -1049,10 +1049,17 @@ public class ApiConstants {
public static final String MTU = "mtu"; public static final String MTU = "mtu";
public static final String AUTO_ENABLE_KVM_HOST = "autoenablekvmhost"; public static final String AUTO_ENABLE_KVM_HOST = "autoenablekvmhost";
public static final String LIST_APIS = "listApis"; 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 = "sourcenatipaddress";
public static final String SOURCE_NAT_IP_ID = "sourcenatipaddressid"; public static final String SOURCE_NAT_IP_ID = "sourcenatipaddressid";
public static final String HAS_RULES = "hasrules"; public static final String HAS_RULES = "hasrules";
public static final String OBJECT_STORAGE = "objectstore";
public static final String MANAGEMENT = "management"; public static final String MANAGEMENT = "management";
public static final String IS_VNF = "isvnf"; public static final String IS_VNF = "isvnf";

View File

@ -42,6 +42,7 @@ import org.apache.cloudstack.network.element.InternalLoadBalancerElementService;
import org.apache.cloudstack.network.lb.ApplicationLoadBalancerService; import org.apache.cloudstack.network.lb.ApplicationLoadBalancerService;
import org.apache.cloudstack.network.lb.InternalLoadBalancerVMService; import org.apache.cloudstack.network.lb.InternalLoadBalancerVMService;
import org.apache.cloudstack.query.QueryService; import org.apache.cloudstack.query.QueryService;
import org.apache.cloudstack.storage.object.BucketApiService;
import org.apache.cloudstack.storage.ImageStoreService; import org.apache.cloudstack.storage.ImageStoreService;
import org.apache.cloudstack.storage.template.VnfTemplateManager; import org.apache.cloudstack.storage.template.VnfTemplateManager;
import org.apache.cloudstack.usage.UsageService; import org.apache.cloudstack.usage.UsageService;
@ -216,6 +217,9 @@ public abstract class BaseCmd {
public Ipv6Service ipv6Service; public Ipv6Service ipv6Service;
@Inject @Inject
public VnfTemplateManager vnfTemplateManager; public VnfTemplateManager vnfTemplateManager;
@Inject
public BucketApiService _bucketService;
public abstract void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, public abstract void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException,
ResourceAllocationException, NetworkRuleConflictException; ResourceAllocationException, NetworkRuleConflictException;

View File

@ -22,6 +22,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.apache.cloudstack.storage.object.Bucket;
import org.apache.cloudstack.affinity.AffinityGroup; import org.apache.cloudstack.affinity.AffinityGroup;
import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.affinity.AffinityGroupResponse;
import org.apache.cloudstack.api.ApiConstants.HostDetails; 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.BackupOfferingResponse;
import org.apache.cloudstack.api.response.BackupResponse; import org.apache.cloudstack.api.response.BackupResponse;
import org.apache.cloudstack.api.response.BackupScheduleResponse; 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.CapacityResponse;
import org.apache.cloudstack.api.response.ClusterResponse; import org.apache.cloudstack.api.response.ClusterResponse;
import org.apache.cloudstack.api.response.ConditionResponse; import org.apache.cloudstack.api.response.ConditionResponse;
@ -82,6 +84,7 @@ import org.apache.cloudstack.api.response.NetworkPermissionsResponse;
import org.apache.cloudstack.api.response.NetworkResponse; import org.apache.cloudstack.api.response.NetworkResponse;
import org.apache.cloudstack.api.response.NicResponse; import org.apache.cloudstack.api.response.NicResponse;
import org.apache.cloudstack.api.response.NicSecondaryIpResponse; 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.OvsProviderResponse;
import org.apache.cloudstack.api.response.PhysicalNetworkResponse; import org.apache.cloudstack.api.response.PhysicalNetworkResponse;
import org.apache.cloudstack.api.response.PodResponse; import org.apache.cloudstack.api.response.PodResponse;
@ -145,6 +148,7 @@ import org.apache.cloudstack.network.lb.ApplicationLoadBalancerRule;
import org.apache.cloudstack.region.PortableIp; import org.apache.cloudstack.region.PortableIp;
import org.apache.cloudstack.region.PortableIpRange; import org.apache.cloudstack.region.PortableIpRange;
import org.apache.cloudstack.region.Region; import org.apache.cloudstack.region.Region;
import org.apache.cloudstack.storage.object.ObjectStore;
import org.apache.cloudstack.usage.Usage; import org.apache.cloudstack.usage.Usage;
import com.cloud.capacity.Capacity; import com.cloud.capacity.Capacity;
@ -533,4 +537,8 @@ public interface ResponseGenerator {
FirewallResponse createIpv6FirewallRuleResponse(FirewallRule acl); FirewallResponse createIpv6FirewallRuleResponse(FirewallRule acl);
IpQuarantineResponse createQuarantinedIpsResponse(PublicIpQuarantine publicIp); IpQuarantineResponse createQuarantinedIpsResponse(PublicIpQuarantine publicIp);
ObjectStoreResponse createObjectStoreResponse(ObjectStore os);
BucketResponse createBucketResponse(Bucket bucket);
} }

View File

@ -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<String, String> getDetails() {
Map<String, String> detailsMap = null;
if (details != null && !details.isEmpty()) {
detailsMap = new HashMap<String, String>();
Collection<?> props = details.values();
Iterator<?> iter = props.iterator();
while (iter.hasNext()) {
HashMap<String, String> detail = (HashMap<String, String>)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<String, String> 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());
}
}
}

View File

@ -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");
}
}
}

View File

@ -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<ObjectStoreResponse> response = _queryService.searchForObjectStores(this);
response.setResponseName(getCommandName());
this.setResponseObject(response);
}
}

View File

@ -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();
}
}

View File

@ -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());
}
}
}

View File

@ -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);
}
}

View File

@ -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<Long> 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<BucketResponse> response = _queryService.searchForBuckets(this);
response.setResponseName(getCommandName());
setResponseObject(response);
}
public List<Long> getIds() {
return ids;
}
}

View File

@ -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");
}
}
}

View File

@ -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<ResourceTagResponse>();
}
@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<ResourceTagResponse> 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;
}
}

View File

@ -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;
}
}

View File

@ -28,6 +28,7 @@ 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.GetRouterHealthCheckResultsCmd;
import org.apache.cloudstack.api.command.admin.router.ListRoutersCmd; 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.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.ListSecondaryStagingStoresCmd;
import org.apache.cloudstack.api.command.admin.storage.ListStoragePoolsCmd; 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.ListStorageTagsCmd;
@ -36,6 +37,7 @@ 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.account.ListProjectAccountsCmd;
import org.apache.cloudstack.api.command.user.address.ListQuarantinedIpsCmd; 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.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.event.ListEventsCmd;
import org.apache.cloudstack.api.command.user.iso.ListIsosCmd; import org.apache.cloudstack.api.command.user.iso.ListIsosCmd;
import org.apache.cloudstack.api.command.user.job.ListAsyncJobsCmd; import org.apache.cloudstack.api.command.user.job.ListAsyncJobsCmd;
@ -56,6 +58,7 @@ import org.apache.cloudstack.api.command.user.volume.ListVolumesCmd;
import org.apache.cloudstack.api.command.user.zone.ListZonesCmd; import org.apache.cloudstack.api.command.user.zone.ListZonesCmd;
import org.apache.cloudstack.api.response.AccountResponse; import org.apache.cloudstack.api.response.AccountResponse;
import org.apache.cloudstack.api.response.AsyncJobResponse; 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.DetailOptionsResponse;
import org.apache.cloudstack.api.response.DiskOfferingResponse; import org.apache.cloudstack.api.response.DiskOfferingResponse;
import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.DomainResponse;
@ -68,6 +71,7 @@ import org.apache.cloudstack.api.response.InstanceGroupResponse;
import org.apache.cloudstack.api.response.IpQuarantineResponse; import org.apache.cloudstack.api.response.IpQuarantineResponse;
import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.ManagementServerResponse; 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.ProjectAccountResponse;
import org.apache.cloudstack.api.response.ProjectInvitationResponse; import org.apache.cloudstack.api.response.ProjectInvitationResponse;
import org.apache.cloudstack.api.response.ProjectResponse; import org.apache.cloudstack.api.response.ProjectResponse;
@ -190,4 +194,8 @@ public interface QueryService {
ListResponse<SnapshotResponse> listSnapshots(ListSnapshotsCmd cmd); ListResponse<SnapshotResponse> listSnapshots(ListSnapshotsCmd cmd);
SnapshotResponse listSnapshot(CopySnapshotCmd cmd); SnapshotResponse listSnapshot(CopySnapshotCmd cmd);
ListResponse<ObjectStoreResponse> searchForObjectStores(ListObjectStoragePoolsCmd listObjectStoragePoolsCmd);
ListResponse<BucketResponse> searchForBuckets(ListBucketsCmd listBucketsCmd);
} }

View File

@ -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);
}
}
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -45,6 +45,7 @@ public class UsageTypes {
public static final int VOLUME_SECONDARY = 26; public static final int VOLUME_SECONDARY = 26;
public static final int VM_SNAPSHOT_ON_PRIMARY = 27; public static final int VM_SNAPSHOT_ON_PRIMARY = 27;
public static final int BACKUP = 28; public static final int BACKUP = 28;
public static final int BUCKET = 29;
public static List<UsageTypeResponse> listUsageTypes() { public static List<UsageTypeResponse> listUsageTypes() {
List<UsageTypeResponse> responseList = new ArrayList<UsageTypeResponse>(); List<UsageTypeResponse> responseList = new ArrayList<UsageTypeResponse>();
@ -70,6 +71,7 @@ public class UsageTypes {
responseList.add(new UsageTypeResponse(VOLUME_SECONDARY, "Volume on secondary storage usage")); 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(VM_SNAPSHOT_ON_PRIMARY, "VM Snapshot on primary storage usage"));
responseList.add(new UsageTypeResponse(BACKUP, "Backup storage usage")); responseList.add(new UsageTypeResponse(BACKUP, "Backup storage usage"));
responseList.add(new UsageTypeResponse(BUCKET, "Bucket storage usage"));
return responseList; return responseList;
} }
} }

View File

@ -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<String, String> 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());
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -577,6 +577,21 @@
<artifactId>cloud-plugin-shutdown</artifactId> <artifactId>cloud-plugin-shutdown</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine-storage-object</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-plugin-storage-object-minio</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-plugin-storage-object-simulator</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies> </dependencies>
<build> <build>
<plugins> <plugins>

View File

@ -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();
}

View File

@ -31,7 +31,7 @@ public interface DataStoreProvider {
String DEFAULT_PRIMARY = "DefaultPrimary"; String DEFAULT_PRIMARY = "DefaultPrimary";
enum DataStoreProviderType { enum DataStoreProviderType {
PRIMARY, IMAGE, ImageCache PRIMARY, IMAGE, ImageCache, OBJECT
} }
DataStoreLifeCycle getDataStoreLifeCycle(); DataStoreLifeCycle getDataStoreLifeCycle();

View File

@ -33,4 +33,6 @@ public interface DataStoreProviderManager extends Manager, DataStoreProviderApiS
DataStoreProvider getDefaultCacheDataStoreProvider(); DataStoreProvider getDefaultCacheDataStoreProvider();
List<DataStoreProvider> getProviders(); List<DataStoreProvider> getProviders();
DataStoreProvider getDefaultObjectStoreProvider();
} }

View File

@ -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 {
}

View File

@ -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 {
}

View File

@ -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<Bucket> 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<String, Long> getAllBucketsUsage();
}

View File

@ -55,6 +55,7 @@
<module>storage/configdrive</module> <module>storage/configdrive</module>
<module>storage/datamotion</module> <module>storage/datamotion</module>
<module>storage/image</module> <module>storage/image</module>
<module>storage/object</module>
<module>storage/snapshot</module> <module>storage/snapshot</module>
<module>storage/volume</module> <module>storage/volume</module>
<module>userdata/cloud-init</module> <module>userdata/cloud-init</module>

View File

@ -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());
}
}

View File

@ -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<BucketVO, Long> {
List<BucketVO> listByObjectStoreId(long objectStoreId);
List<BucketVO> listByObjectStoreIdAndAccountId(long objectStoreId, long accountId);
List<BucketVO> searchByIds(Long[] ids);
}

View File

@ -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<BucketVO, Long> implements BucketDao {
public static final Logger s_logger = Logger.getLogger(BucketDaoImpl.class.getName());
private SearchBuilder<BucketVO> searchFilteringStoreId;
private SearchBuilder<BucketVO> 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<String, Object> 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<BucketVO> listByObjectStoreId(long objectStoreId) {
SearchCriteria<BucketVO> sc = searchFilteringStoreId.create();
sc.setParameters(STORE_ID, objectStoreId);
sc.setParameters(STATE, BucketVO.State.Destroyed);
return listBy(sc);
}
@Override
public List<BucketVO> listByObjectStoreIdAndAccountId(long objectStoreId, long accountId) {
SearchCriteria<BucketVO> 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<BucketVO> searchByIds(Long[] ids) {
SearchCriteria<BucketVO> sc = bucketSearch.create();
sc.setParameters("idIN", ids);
return search(sc, null, null, false);
}
}

View File

@ -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;
}
}

View File

@ -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, Long> {
BucketStatisticsVO findBy(long accountId, long bucketId);
BucketStatisticsVO lock(long accountId, long bucketId);
List<BucketStatisticsVO> listBy(long accountId);
}

View File

@ -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<BucketStatisticsVO, Long> implements BucketStatisticsDao {
private static final Logger s_logger = Logger.getLogger(BucketStatisticsDaoImpl.class);
private final SearchBuilder<BucketStatisticsVO> AllFieldsSearch;
private final SearchBuilder<BucketStatisticsVO> 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<BucketStatisticsVO> sc = AllFieldsSearch.create();
sc.setParameters("account", accountId);
sc.setParameters("bucket", bucketId);
return findOneBy(sc);
}
@Override
public BucketStatisticsVO lock(long accountId, long bucketId) {
SearchCriteria<BucketStatisticsVO> sc = AllFieldsSearch.create();
sc.setParameters("account", accountId);
sc.setParameters("bucket", bucketId);
return lockOneRandomRow(sc, true);
}
@Override
public List<BucketStatisticsVO> listBy(long accountId) {
SearchCriteria<BucketStatisticsVO> sc = AccountSearch.create();
sc.setParameters("account", accountId);
return search(sc, null);
}
}

View File

@ -16,6 +16,7 @@
// under the License. // under the License.
package com.cloud.usage.dao; package com.cloud.usage.dao;
import com.cloud.usage.BucketStatisticsVO;
import com.cloud.usage.UsageVO; import com.cloud.usage.UsageVO;
import com.cloud.user.AccountVO; import com.cloud.user.AccountVO;
import com.cloud.user.UserStatisticsVO; import com.cloud.user.UserStatisticsVO;
@ -45,6 +46,12 @@ public interface UsageDao extends GenericDao<UsageVO, Long> {
Long getLastUserStatsId(); Long getLastUserStatsId();
Long getLastBucketStatsId();
void saveBucketStats(List<BucketStatisticsVO> userStats);
void updateBucketStats(List<BucketStatisticsVO> userStats);
List<Long> listPublicTemplatesByAccount(long accountId); List<Long> listPublicTemplatesByAccount(long accountId);
Long getLastVmDiskStatsId(); Long getLastVmDiskStatsId();

View File

@ -16,6 +16,7 @@
// under the License. // under the License.
package com.cloud.usage.dao; package com.cloud.usage.dao;
import com.cloud.usage.BucketStatisticsVO;
import com.cloud.usage.UsageVO; import com.cloud.usage.UsageVO;
import com.cloud.user.AccountVO; import com.cloud.user.AccountVO;
import com.cloud.user.UserStatisticsVO; import com.cloud.user.UserStatisticsVO;
@ -82,6 +83,13 @@ public class UsageDaoImpl extends GenericDaoBase<UsageVO, Long> implements Usage
+ "WHERE cloud_usage.usage_type = ? AND cloud_usage.account_id = ? AND cloud_usage.start_date >= ? AND cloud_usage.end_date <= ? " + "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 "; + "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() { public UsageDaoImpl() {
} }
@ -285,6 +293,69 @@ public class UsageDaoImpl extends GenericDaoBase<UsageVO, Long> implements Usage
return null; 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<BucketStatisticsVO> 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<BucketStatisticsVO> 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 @Override
public List<Long> listPublicTemplatesByAccount(long accountId) { public List<Long> listPublicTemplatesByAccount(long accountId) {
TransactionLegacy txn = TransactionLegacy.currentTxn(); TransactionLegacy txn = TransactionLegacy.currentTxn();

View File

@ -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, Long> {
ObjectStoreVO findByName(String name);
List<ObjectStoreVO> findByProvider(String provider);
ObjectStoreVO findByUrl(String url);
List<ObjectStoreVO> listObjectStores();
List<ObjectStoreVO> searchByIds(Long[] osIds);
ObjectStoreResponse newObjectStoreResponse(ObjectStoreVO store);
ObjectStoreResponse setObjectStoreResponse(ObjectStoreResponse storeData, ObjectStoreVO store);
Integer countAllObjectStores();
}

View File

@ -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<ObjectStoreVO, Long> implements ObjectStoreDao {
private SearchBuilder<ObjectStoreVO> nameSearch;
private SearchBuilder<ObjectStoreVO> providerSearch;
@Inject
private ConfigurationDao _configDao;
private final SearchBuilder<ObjectStoreVO> osSearch;
private SearchBuilder<ObjectStoreVO> urlSearch;
protected ObjectStoreDaoImpl() {
osSearch = createSearchBuilder();
osSearch.and("idIN", osSearch.entity().getId(), SearchCriteria.Op.IN);
osSearch.done();
}
@Override
public boolean configure(String name, Map<String, Object> 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<ObjectStoreVO> sc = nameSearch.create();
sc.setParameters("name", name);
return findOneBy(sc);
}
@Override
public List<ObjectStoreVO> findByProvider(String provider) {
SearchCriteria<ObjectStoreVO> sc = providerSearch.create();
sc.setParameters("providerName", provider);
return listBy(sc);
}
@Override
public ObjectStoreVO findByUrl(String url) {
SearchCriteria<ObjectStoreVO> sc = urlSearch.create();
sc.setParameters("url", url);
return findOneBy(sc);
}
@Override
public List<ObjectStoreVO> listObjectStores() {
SearchCriteria<ObjectStoreVO> sc = createSearchCriteria();
return listBy(sc);
}
@Override
public List<ObjectStoreVO> 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<ObjectStoreVO> 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<ObjectStoreVO> sc = osSearch.create();
sc.setParameters("idIN", ids);
List<ObjectStoreVO> 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<ObjectStoreVO> sc = osSearch.create();
sc.setParameters("idIN", ids);
List<ObjectStoreVO> 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<ObjectStoreVO> sc = createSearchCriteria();
return getCount(sc);
}
}

View File

@ -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;
}
}

View File

@ -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<ObjectStoreDetailVO, Long>, ResourceDetailsDao<ObjectStoreDetailVO> {
void update(long storeId, Map<String, String> details);
Map<String, String> getDetails(long storeId);
void deleteDetails(long storeId);
}

View File

@ -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<ObjectStoreDetailVO> implements ObjectStoreDetailsDao {
protected final SearchBuilder<ObjectStoreDetailVO> storeSearch;
public ObjectStoreDetailsDaoImpl() {
super();
storeSearch = createSearchBuilder();
storeSearch.and("store", storeSearch.entity().getResourceId(), Op.EQ);
storeSearch.done();
}
@Override
public void update(long storeId, Map<String, String> details) {
TransactionLegacy txn = TransactionLegacy.currentTxn();
SearchCriteria<ObjectStoreDetailVO> sc = storeSearch.create();
sc.setParameters("store", storeId);
txn.start();
expunge(sc);
for (Map.Entry<String, String> entry : details.entrySet()) {
ObjectStoreDetailVO detail = new ObjectStoreDetailVO(storeId, entry.getKey(), entry.getValue());
persist(detail);
}
txn.commit();
}
@Override
public Map<String, String> getDetails(long storeId) {
SearchCriteria<ObjectStoreDetailVO> sc = storeSearch.create();
sc.setParameters("store", storeId);
List<ObjectStoreDetailVO> details = listBy(sc);
Map<String, String> detailsMap = new HashMap<String, String>();
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<ObjectStoreDetailVO> sc = storeSearch.create();
sc.setParameters("store", storeId);
List<ObjectStoreDetailVO> results = search(sc, null);
for (ObjectStoreDetailVO result : results) {
remove(result.getId());
}
}
@Override
public ObjectStoreDetailVO findDetail(long storeId, String name) {
QueryBuilder<ObjectStoreDetailVO> sc = QueryBuilder.create(ObjectStoreDetailVO.class);
sc.and(sc.entity().getResourceId(), Op.EQ, storeId);
sc.and(sc.entity().getName(), Op.EQ, name);
return sc.find();
}
@Override
public void addDetail(long resourceId, String key, String value, boolean display) {
// ToDo: Add Display
super.addDetail(new ObjectStoreDetailVO(resourceId, key, value));
}
}

View File

@ -0,0 +1,143 @@
/*
* 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.storage.object.ObjectStore;
import com.cloud.utils.db.GenericDao;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.TableGenerator;
import javax.persistence.Transient;
import java.util.Date;
import java.util.Map;
@Entity
@Table(name = "object_store")
public class ObjectStoreVO implements ObjectStore {
@Id
@TableGenerator(name = "object_store_sq", table = "sequence", pkColumnName = "name", valueColumnName = "value", pkColumnValue = "object_store_seq", allocationSize = 1)
@Column(name = "id", nullable = false)
private long id;
@Column(name = "name", nullable = false)
private String name;
@Column(name = "uuid", nullable = false)
private String uuid;
@Column(name = "url", nullable = false, length = 2048)
private String url;
@Column(name = "object_provider_name", nullable = false)
private String providerName;
@Column(name = GenericDao.CREATED_COLUMN)
private Date created;
@Column(name = GenericDao.REMOVED_COLUMN)
private Date removed;
@Column(name = "total_size")
private Long totalSize;
@Column(name = "used_bytes")
private Long usedBytes;
@Transient
Map<String, String> details;
@Override
public long getId() {
return this.id;
}
@Override
public String getName() {
return this.name;
}
@Override
public String getProviderName() {
return this.providerName;
}
public void setName(String name) {
this.name = name;
}
public void setProviderName(String provider) {
this.providerName = provider;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
@Override
public String getUuid() {
return this.uuid;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
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 Long getTotalSize() {
return totalSize;
}
public void setTotalSize(Long totalSize) {
this.totalSize = totalSize;
}
public Long getUsedBytes() {
return usedBytes;
}
public void setUsedBytes(Long usedBytes) {
this.usedBytes = usedBytes;
}
public void setDetails(Map<String, String> details) {
this.details = details;
}
}

View File

@ -283,4 +283,6 @@
<bean id="vnfTemplateNicDaoImpl" class="com.cloud.storage.dao.VnfTemplateNicDaoImpl" /> <bean id="vnfTemplateNicDaoImpl" class="com.cloud.storage.dao.VnfTemplateNicDaoImpl" />
<bean id="ClusterDrsPlanDaoImpl" class="org.apache.cloudstack.cluster.dao.ClusterDrsPlanDaoImpl" /> <bean id="ClusterDrsPlanDaoImpl" class="org.apache.cloudstack.cluster.dao.ClusterDrsPlanDaoImpl" />
<bean id="ClusterDrsPlanDetailsDaoImpl" class="org.apache.cloudstack.cluster.dao.ClusterDrsPlanMigrationDaoImpl" /> <bean id="ClusterDrsPlanDetailsDaoImpl" class="org.apache.cloudstack.cluster.dao.ClusterDrsPlanMigrationDaoImpl" />
<bean id="objectStoreDetailsDaoImpl" class="org.apache.cloudstack.storage.datastore.db.ObjectStoreDetailsDaoImpl" />
<bean id="bucketStatisticsDaoImpl" class="com.cloud.usage.dao.BucketStatisticsDaoImpl" />
</beans> </beans>

View File

@ -233,3 +233,69 @@ ALTER TABLE `cloud`.`storage_pool_tags` MODIFY tag text NOT NULL;
ALTER TABLE `cloud`.`host_tags` ADD COLUMN is_tag_a_rule int(1) UNSIGNED not null DEFAULT 0; ALTER TABLE `cloud`.`host_tags` ADD COLUMN is_tag_a_rule int(1) UNSIGNED not null DEFAULT 0;
ALTER TABLE `cloud`.`host_tags` MODIFY tag text NOT NULL; ALTER TABLE `cloud`.`host_tags` MODIFY tag text NOT NULL;
DROP TABLE IF EXISTS `cloud`.`object_store`;
CREATE TABLE `cloud`.`object_store` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
`name` varchar(255) NOT NULL COMMENT 'name of object store',
`object_provider_name` varchar(255) NOT NULL COMMENT 'id of object_store_provider',
`url` varchar(255) NOT NULL COMMENT 'url of the object store',
`uuid` varchar(255) COMMENT 'uuid of object store',
`created` datetime COMMENT 'date the object store first signed on',
`removed` datetime COMMENT 'date removed if not null',
`total_size` bigint unsigned COMMENT 'storage total size statistics',
`used_bytes` bigint unsigned COMMENT 'storage available bytes statistics',
PRIMARY KEY(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `cloud`.`object_store_details`;
CREATE TABLE `cloud`.`object_store_details` (
`id` bigint unsigned UNIQUE NOT NULL AUTO_INCREMENT COMMENT 'id',
`store_id` bigint unsigned NOT NULL COMMENT 'store the detail is related to',
`name` varchar(255) NOT NULL COMMENT 'name of the detail',
`value` varchar(255) NOT NULL COMMENT 'value of the detail',
PRIMARY KEY (`id`),
CONSTRAINT `fk_object_store_details__store_id` FOREIGN KEY `fk_object_store__store_id`(`store_id`) REFERENCES `object_store`(`id`) ON DELETE CASCADE,
INDEX `i_object_store__name__value`(`name`(128), `value`(128))
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `cloud`.`bucket`;
CREATE TABLE `cloud`.`bucket` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
`name` varchar(255) NOT NULL COMMENT 'name of bucket',
`object_store_id` varchar(255) NOT NULL COMMENT 'id of object_store',
`state` varchar(255) NOT NULL COMMENT 'state of the bucket',
`uuid` varchar(255) COMMENT 'uuid of bucket',
`domain_id` bigint unsigned NOT NULL COMMENT 'domain the bucket belongs to',
`account_id` bigint unsigned NOT NULL COMMENT 'owner of this bucket',
`size` bigint unsigned COMMENT 'total size of bucket objects',
`quota` bigint unsigned COMMENT 'Allocated bucket quota in GB',
`versioning` boolean COMMENT 'versioning enable/disable',
`encryption` boolean COMMENT 'encryption enable/disbale',
`object_lock` boolean COMMENT 'Lock objects in bucket',
`policy` varchar(255) COMMENT 'Bucket Access Policy',
`access_key` varchar(255) COMMENT 'Bucket Access Key',
`secret_key` varchar(255) COMMENT 'Bucket Secret Key',
`bucket_url` varchar(255) COMMENT 'URL to access bucket',
`created` datetime COMMENT 'date the bucket was created',
`removed` datetime COMMENT 'date removed if not null',
PRIMARY KEY(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `cloud`.`bucket_statistics`;
CREATE TABLE `cloud`.`bucket_statistics` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
`account_id` bigint unsigned NOT NULL COMMENT 'owner of this bucket',
`bucket_id` bigint unsigned NOT NULL COMMENT 'id of this bucket',
`size` bigint unsigned COMMENT 'total size of bucket objects',
PRIMARY KEY(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `cloud_usage`.`bucket_statistics`;
CREATE TABLE `cloud_usage`.`bucket_statistics` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
`account_id` bigint unsigned NOT NULL COMMENT 'owner of this bucket',
`bucket_id` bigint unsigned NOT NULL COMMENT 'id of this bucket',
`size` bigint unsigned COMMENT 'total size of bucket objects',
PRIMARY KEY(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

View File

@ -87,4 +87,8 @@
<bean id="storageStrategyFactoryImpl" class="org.apache.cloudstack.storage.helper.StorageStrategyFactoryImpl" /> <bean id="storageStrategyFactoryImpl" class="org.apache.cloudstack.storage.helper.StorageStrategyFactoryImpl" />
<bean id="vmsnapshotDetailsDao" class="com.cloud.vm.snapshot.dao.VMSnapshotDetailsDaoImpl" /> <bean id="vmsnapshotDetailsDao" class="com.cloud.vm.snapshot.dao.VMSnapshotDetailsDaoImpl" />
<bean id="snapshotManager" class="com.cloud.storage.snapshot.SnapshotManagerImpl" /> <bean id="snapshotManager" class="com.cloud.storage.snapshot.SnapshotManagerImpl" />
<bean id="objectStoreProviderManagerImpl" class="org.apache.cloudstack.storage.object.manager.ObjectStoreProviderManagerImpl" />
<bean id="objectStoreDaoImpl" class="org.apache.cloudstack.storage.datastore.db.ObjectStoreDaoImpl" />
<bean id="objectStoreDetailsDaoImpl" class="org.apache.cloudstack.storage.datastore.db.ObjectStoreDetailsDaoImpl" />
<bean id="objectStoreHelper" class="org.apache.cloudstack.storage.object.datastore.ObjectStoreHelper" />
</beans> </beans>

View File

@ -0,0 +1,37 @@
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-engine-storage-object</artifactId>
<name>Apache CloudStack Engine Storage Object Component</name>
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine</artifactId>
<version>4.19.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine-storage</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,196 @@
// 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.agent.api.Answer;
import com.cloud.agent.api.to.DataObjectType;
import com.cloud.agent.api.to.DataTO;
import org.apache.cloudstack.engine.subsystem.api.storage.BucketInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
import java.util.Date;
public class BucketObject implements BucketInfo {
private String name;
@Override
public long getDomainId() {
return 0;
}
@Override
public long getAccountId() {
return 0;
}
@Override
public Class<?> getEntityType() {
return null;
}
@Override
public String getName() {
return this.name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public void addPayload(Object data) {
}
@Override
public Object getPayload() {
return null;
}
@Override
public Bucket getBucket() {
return null;
}
@Override
public long getId() {
return 0;
}
@Override
public String getUri() {
return null;
}
@Override
public DataTO getTO() {
return null;
}
@Override
public DataStore getDataStore() {
return null;
}
@Override
public Long getSize() {
return null;
}
@Override
public Integer getQuota() {
return null;
}
@Override
public boolean isVersioning() {
return false;
}
@Override
public boolean isEncryption() {
return false;
}
@Override
public boolean isObjectLock() {
return false;
}
@Override
public String getPolicy() {
return null;
}
@Override
public String getBucketURL() {
return null;
}
@Override
public String getAccessKey() {
return null;
}
@Override
public String getSecretKey() {
return null;
}
@Override
public long getPhysicalSize() {
return 0;
}
@Override
public DataObjectType getType() {
return null;
}
@Override
public String getUuid() {
return null;
}
@Override
public boolean delete() {
return false;
}
@Override
public void processEvent(ObjectInDataStoreStateMachine.Event event) {
}
@Override
public void processEvent(ObjectInDataStoreStateMachine.Event event, Answer answer) {
}
@Override
public void incRefCount() {
}
@Override
public void decRefCount() {
}
@Override
public Long getRefCount() {
return null;
}
@Override
public long getObjectStoreId() {
return 0;
}
@Override
public Date getCreated() {
return null;
}
@Override
public State getState() {
return null;
}
}

View File

@ -0,0 +1,28 @@
// 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.ObjectStorageService;
import org.apache.log4j.Logger;
public class ObjectStorageServiceImpl implements ObjectStorageService {
private static final Logger s_logger = Logger.getLogger(ObjectStorageServiceImpl.class);
}

View File

@ -0,0 +1,111 @@
/*
* 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.manager;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectStoreProvider;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreDao;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreVO;
import org.apache.cloudstack.storage.object.ObjectStoreDriver;
import org.apache.cloudstack.storage.object.ObjectStoreEntity;
import org.apache.cloudstack.storage.object.datastore.ObjectStoreProviderManager;
import org.apache.cloudstack.storage.object.store.ObjectStoreImpl;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
public class ObjectStoreProviderManagerImpl implements ObjectStoreProviderManager, Configurable {
private static final Logger s_logger = Logger.getLogger(ObjectStoreProviderManagerImpl.class);
@Inject
ObjectStoreDao objectStoreDao;
@Inject
DataStoreProviderManager providerManager;
Map<String, ObjectStoreDriver> driverMaps;
@PostConstruct
public void config() {
driverMaps = new HashMap<String, ObjectStoreDriver>();
}
@Override
public ObjectStoreEntity getObjectStore(long objectStoreId) {
ObjectStoreVO objectStore = objectStoreDao.findById(objectStoreId);
String providerName = objectStore.getProviderName();
ObjectStoreProvider provider = (ObjectStoreProvider)providerManager.getDataStoreProvider(providerName);
ObjectStoreEntity objStore = ObjectStoreImpl.getDataStore(objectStore, driverMaps.get(provider.getName()), provider);
return objStore;
}
@Override
public boolean registerDriver(String providerName, ObjectStoreDriver driver) {
if (driverMaps.containsKey(providerName)) {
return false;
}
driverMaps.put(providerName, driver);
return true;
}
@Override
public ObjectStoreEntity getObjectStore(String uuid) {
ObjectStoreVO objectStore = objectStoreDao.findByUuid(uuid);
return getObjectStore(objectStore.getId());
}
@Override
public List<DataStore> listObjectStores() {
List<ObjectStoreVO> stores = objectStoreDao.listObjectStores();
List<DataStore> ObjectStores = new ArrayList<DataStore>();
for (ObjectStoreVO store : stores) {
ObjectStores.add(getObjectStore(store.getId()));
}
return ObjectStores;
}
@Override
public List<DataStore> listObjectStoreByProvider(String provider) {
List<ObjectStoreVO> stores = objectStoreDao.findByProvider(provider);
List<DataStore> ObjectStores = new ArrayList<DataStore>();
for (ObjectStoreVO store : stores) {
ObjectStores.add(getObjectStore(store.getId()));
}
return ObjectStores;
}
@Override
public String getConfigComponentName() {
return ObjectStoreProviderManager.class.getSimpleName();
}
@Override
public ConfigKey<?>[] getConfigKeys() {
return new ConfigKey<?>[] { };
}
}

View File

@ -0,0 +1,184 @@
/*
* 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.store;
import com.cloud.agent.api.to.DataStoreTO;
import org.apache.cloudstack.storage.object.Bucket;
import com.cloud.storage.DataStoreRole;
import com.cloud.utils.component.ComponentContext;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectStoreProvider;
import org.apache.cloudstack.engine.subsystem.api.storage.Scope;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreVO;
import org.apache.cloudstack.storage.object.ObjectStoreDriver;
import org.apache.cloudstack.storage.object.ObjectStoreEntity;
import org.apache.log4j.Logger;
import java.util.Date;
import java.util.List;
import java.util.Map;
public class ObjectStoreImpl implements ObjectStoreEntity {
private static final Logger s_logger = Logger.getLogger(ObjectStoreImpl.class);
protected ObjectStoreDriver driver;
protected ObjectStoreVO objectStoreVO;
protected ObjectStoreProvider provider;
public ObjectStoreImpl() {
super();
}
protected void configure(ObjectStoreVO objectStoreVO, ObjectStoreDriver objectStoreDriver, ObjectStoreProvider provider) {
this.driver = objectStoreDriver;
this.objectStoreVO = objectStoreVO;
this.provider = provider;
}
public static ObjectStoreEntity getDataStore(ObjectStoreVO objectStoreVO, ObjectStoreDriver objectStoreDriver, ObjectStoreProvider provider) {
ObjectStoreImpl instance = ComponentContext.inject(ObjectStoreImpl.class);
instance.configure(objectStoreVO, objectStoreDriver, provider);
return instance;
}
@Override
public DataStoreDriver getDriver() {
return this.driver;
}
@Override
public DataStoreRole getRole() {
return null;
}
@Override
public long getId() {
return this.objectStoreVO.getId();
}
@Override
public String getUri() {
return this.objectStoreVO.getUrl();
}
@Override
public Scope getScope() {
return null;
}
@Override
public String getUuid() {
return this.objectStoreVO.getUuid();
}
public Date getCreated() {
return this.objectStoreVO.getCreated();
}
@Override
public String getName() {
return objectStoreVO.getName();
}
@Override
public DataObject create(DataObject obj) {
return null;
}
@Override
public Bucket createBucket(Bucket bucket, boolean objectLock) {
return driver.createBucket(bucket, objectLock);
}
@Override
public boolean deleteBucket(String bucketName) {
return driver.deleteBucket(bucketName, objectStoreVO.getId());
}
@Override
public boolean setBucketEncryption(String bucketName) {
return driver.setBucketEncryption(bucketName, objectStoreVO.getId());
}
@Override
public boolean deleteBucketEncryption(String bucketName) {
return driver.deleteBucketEncryption(bucketName, objectStoreVO.getId());
}
@Override
public boolean setBucketVersioning(String bucketName) {
return driver.setBucketVersioning(bucketName, objectStoreVO.getId());
}
@Override
public boolean deleteBucketVersioning(String bucketName) {
return driver.deleteBucketVersioning(bucketName, objectStoreVO.getId());
}
@Override
public void setBucketPolicy(String bucketName, String policy) {
driver.setBucketPolicy(bucketName, policy, objectStoreVO.getId());
}
@Override
public void setQuota(String bucketName, int quota) {
driver.setBucketQuota(bucketName, objectStoreVO.getId(), quota);
}
@Override
public Map<String, Long> getAllBucketsUsage() {
return driver.getAllBucketsUsage(objectStoreVO.getId());
}
@Override
public List<Bucket> listBuckets() {
return driver.listBuckets(objectStoreVO.getId());
}
/*
Create user if not exists
*/
@Override
public boolean createUser(long accountId) {
return driver.createUser(accountId, objectStoreVO.getId());
}
@Override
public boolean delete(DataObject obj) {
return false;
}
@Override
public DataStoreTO getTO() {
return null;
}
@Override
public String getProviderName() {
return objectStoreVO.getProviderName();
}
@Override
public String getUrl() {
return objectStoreVO.getUrl();
}
}

View File

@ -0,0 +1,24 @@
/*
* 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.store.lifecycle;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreLifeCycle;
public interface ObjectStoreLifeCycle extends DataStoreLifeCycle {
}

View File

@ -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.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
>
<bean id="objectStoreDao" class="org.apache.cloudstack.storage.datastore.db.ObjectStoreDaoImpl" />
<bean id="objectStoreProviderMgr"
class="org.apache.cloudstack.storage.object.manager.ObjectStoreProviderManagerImpl" />
<bean id="objectStoreHelper"
class="org.apache.cloudstack.storage.object.datastore.ObjectStoreHelper" />
<bean id="bucketDao" class="com.cloud.storage.dao.BucketDaoImpl" />
</beans>

View File

@ -0,0 +1,117 @@
/*
* 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.manager;
import junit.framework.TestCase;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectStoreProvider;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreDao;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreVO;
import org.apache.cloudstack.storage.object.ObjectStoreDriver;
import org.apache.cloudstack.storage.object.ObjectStoreEntity;
import org.apache.cloudstack.storage.object.store.ObjectStoreImpl;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class ObjectStoreProviderManagerImplTest extends TestCase{
ObjectStoreProviderManagerImpl objectStoreProviderManagerImplSpy;
@Mock
ObjectStoreDao objectStoreDao;
@Mock
ObjectStoreVO objectStoreVO;
@Mock
DataStoreProviderManager providerManager;
@Mock
ObjectStoreProvider provider;
@Mock
Map<String, ObjectStoreDriver> driverMaps;
@Mock
ObjectStoreDriver objectStoreDriver;
@Mock
ObjectStoreEntity objectStoreEntity;
MockedStatic<ObjectStoreImpl> mockObjectStoreImpl;
@Before
public void setup(){
objectStoreProviderManagerImplSpy = Mockito.spy(new ObjectStoreProviderManagerImpl());
objectStoreProviderManagerImplSpy.objectStoreDao = objectStoreDao;
objectStoreProviderManagerImplSpy.providerManager = providerManager;
objectStoreProviderManagerImplSpy.driverMaps = driverMaps;
mockObjectStoreImpl = mockStatic(ObjectStoreImpl.class);
}
@Test
public void getObjectStoreTest() {
Mockito.doReturn(objectStoreVO).when(objectStoreDao).findById(Mockito.anyLong());
Mockito.doReturn(provider).when(providerManager).getDataStoreProvider(Mockito.anyString());
Mockito.doReturn(objectStoreDriver).when(driverMaps).get(Mockito.anyString());
Mockito.doReturn("Simulator").when(provider).getName();
Mockito.doReturn("Simulator").when(objectStoreVO).getProviderName();
when(ObjectStoreImpl.getDataStore(Mockito.any(ObjectStoreVO.class), Mockito.any(ObjectStoreDriver.class),
Mockito.any(ObjectStoreProvider.class))).thenReturn(objectStoreEntity);
assertNotNull(objectStoreProviderManagerImplSpy.getObjectStore(1L));
}
@Test
public void listObjectStoresTest() {
List<ObjectStoreVO> stores = new ArrayList<>();
stores.add(objectStoreVO);
Mockito.doReturn(objectStoreVO).when(objectStoreDao).findById(Mockito.anyLong());
Mockito.doReturn(provider).when(providerManager).getDataStoreProvider(Mockito.anyString());
Mockito.doReturn(objectStoreDriver).when(driverMaps).get(Mockito.anyString());
Mockito.doReturn("Simulator").when(provider).getName();
Mockito.doReturn("Simulator").when(objectStoreVO).getProviderName();
when(ObjectStoreImpl.getDataStore(Mockito.any(ObjectStoreVO.class), Mockito.any(ObjectStoreDriver.class),
Mockito.any(ObjectStoreProvider.class))).thenReturn(objectStoreEntity);
Mockito.doReturn(stores).when(objectStoreDao).listObjectStores();
assertEquals(1, objectStoreProviderManagerImplSpy.listObjectStores().size());
}
@Override
@After
public void tearDown() throws Exception {
mockObjectStoreImpl.close();
super.tearDown();
}
}

View File

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config />
<context:component-scan base-package="org.apache.cloudstack.storage" />
<context:component-scan
base-package="org.apache.cloudstack.engine.subsystem.api.storage" />
<context:component-scan base-package="com.cloud.utils.db" />
<context:component-scan base-package="com.cloud.utils.component" />
<context:component-scan base-package="com.cloud.host.dao" />
<context:component-scan base-package="com.cloud.dc.dao" />
<context:component-scan base-package="com.cloud.dc.dao" />
<context:component-scan base-package="org.apache.cloudstack.framework" />
<tx:annotation-driven transaction-manager="transactionManager" />
<bean class="org.apache.cloudstack.storage.volume.test.TestConfiguration" />
<aop:config proxy-target-class="true">
<aop:aspect id="dbContextBuilder" ref="transactionContextBuilder">
<aop:pointcut id="captureAnyMethod" expression="@annotation(com.cloud.utils.db.DB)" />
<aop:around pointcut-ref="captureAnyMethod" method="AroundAnyMethod" />
</aop:aspect>
</aop:config>
<bean id="transactionContextBuilder" class="com.cloud.utils.db.TransactionContextBuilder" />
<bean id="onwireRegistry" class="org.apache.cloudstack.framework.serializer.OnwireClassRegistry"
init-method="scan" >
<property name="packages">
<list>
<value>org.apache.cloudstack.framework</value>
</list>
</property>
</bean>
<bean id="messageSerializer" class="org.apache.cloudstack.framework.serializer.JsonMessageSerializer">
<property name="onwireClassRegistry" ref="onwireRegistry" />
</bean>
<bean id="transportProvider" class="org.apache.cloudstack.framework.server.ServerTransportProvider" init-method="initialize">
<property name="workerPoolSize" value="5" />
<property name="nodeId" value="Node1" />
<property name="messageSerializer" ref="messageSerializer" />
</bean>
<bean id="rpcProvider" class="org.apache.cloudstack.framework.rpc.RpcProviderImpl" init-method="initialize">
<constructor-arg ref="transportProvider" />
<property name="messageSerializer" ref="messageSerializer" />
</bean>
<bean id="eventBus" class = "org.apache.cloudstack.framework.eventbus.EventBusBase" />
</beans>

View File

@ -26,6 +26,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
import org.apache.cloudstack.engine.subsystem.api.storage.Scope; import org.apache.cloudstack.engine.subsystem.api.storage.Scope;
import org.apache.cloudstack.storage.object.datastore.ObjectStoreProviderManager;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.apache.cloudstack.storage.image.datastore.ImageStoreProviderManager; import org.apache.cloudstack.storage.image.datastore.ImageStoreProviderManager;
@ -40,6 +41,8 @@ public class DataStoreManagerImpl implements DataStoreManager {
PrimaryDataStoreProviderManager primaryStoreMgr; PrimaryDataStoreProviderManager primaryStoreMgr;
@Inject @Inject
ImageStoreProviderManager imageDataStoreMgr; ImageStoreProviderManager imageDataStoreMgr;
@Inject
ObjectStoreProviderManager objectStoreProviderMgr;
@Override @Override
public DataStore getDataStore(long storeId, DataStoreRole role) { public DataStore getDataStore(long storeId, DataStoreRole role) {
@ -50,6 +53,8 @@ public class DataStoreManagerImpl implements DataStoreManager {
return imageDataStoreMgr.getImageStore(storeId); return imageDataStoreMgr.getImageStore(storeId);
} else if (role == DataStoreRole.ImageCache) { } else if (role == DataStoreRole.ImageCache) {
return imageDataStoreMgr.getImageStore(storeId); return imageDataStoreMgr.getImageStore(storeId);
} else if (role == DataStoreRole.Object) {
return objectStoreProviderMgr.getObjectStore(storeId);
} }
} catch (CloudRuntimeException e) { } catch (CloudRuntimeException e) {
throw e; throw e;
@ -63,6 +68,8 @@ public class DataStoreManagerImpl implements DataStoreManager {
return primaryStoreMgr.getPrimaryDataStore(uuid); return primaryStoreMgr.getPrimaryDataStore(uuid);
} else if (role == DataStoreRole.Image) { } else if (role == DataStoreRole.Image) {
return imageDataStoreMgr.getImageStore(uuid); return imageDataStoreMgr.getImageStore(uuid);
} else if (role == DataStoreRole.Object) {
return objectStoreProviderMgr.getObjectStore(uuid);
} }
throw new CloudRuntimeException("un recognized type" + role); throw new CloudRuntimeException("un recognized type" + role);
} }

View File

@ -30,6 +30,8 @@ import java.util.concurrent.CopyOnWriteArrayList;
import javax.inject.Inject; import javax.inject.Inject;
import javax.naming.ConfigurationException; import javax.naming.ConfigurationException;
import org.apache.cloudstack.storage.object.ObjectStoreDriver;
import org.apache.cloudstack.storage.object.datastore.ObjectStoreProviderManager;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -56,6 +58,8 @@ public class DataStoreProviderManagerImpl extends ManagerBase implements DataSto
PrimaryDataStoreProviderManager primaryDataStoreProviderMgr; PrimaryDataStoreProviderManager primaryDataStoreProviderMgr;
@Inject @Inject
ImageStoreProviderManager imageStoreProviderMgr; ImageStoreProviderManager imageStoreProviderMgr;
@Inject
ObjectStoreProviderManager objectStoreProviderMgr;
@Override @Override
public DataStoreProvider getDataStoreProvider(String name) { public DataStoreProvider getDataStoreProvider(String name) {
@ -144,6 +148,8 @@ public class DataStoreProviderManagerImpl extends ManagerBase implements DataSto
primaryDataStoreProviderMgr.registerHostListener(provider.getName(), provider.getHostListener()); primaryDataStoreProviderMgr.registerHostListener(provider.getName(), provider.getHostListener());
} else if (types.contains(DataStoreProviderType.IMAGE)) { } else if (types.contains(DataStoreProviderType.IMAGE)) {
imageStoreProviderMgr.registerDriver(provider.getName(), (ImageStoreDriver)provider.getDataStoreDriver()); imageStoreProviderMgr.registerDriver(provider.getName(), (ImageStoreDriver)provider.getDataStoreDriver());
} else if (types.contains(DataStoreProviderType.OBJECT)) {
objectStoreProviderMgr.registerDriver(provider.getName(), (ObjectStoreDriver)provider.getDataStoreDriver());
} }
} catch (Exception e) { } catch (Exception e) {
s_logger.debug("configure provider failed", e); s_logger.debug("configure provider failed", e);
@ -169,6 +175,11 @@ public class DataStoreProviderManagerImpl extends ManagerBase implements DataSto
return this.getDataStoreProvider(DataStoreProvider.NFS_IMAGE); return this.getDataStoreProvider(DataStoreProvider.NFS_IMAGE);
} }
@Override
public DataStoreProvider getDefaultObjectStoreProvider() {
return this.getDataStoreProvider(DataStoreProvider.S3_IMAGE);
}
@Override @Override
public List<StorageProviderResponse> getDataStoreProviders(String type) { public List<StorageProviderResponse> getDataStoreProviders(String type) {
if (type == null) { if (type == null) {
@ -180,7 +191,9 @@ public class DataStoreProviderManagerImpl extends ManagerBase implements DataSto
return this.getImageDataStoreProviders(); return this.getImageDataStoreProviders();
} else if (type.equalsIgnoreCase(DataStoreProvider.DataStoreProviderType.ImageCache.toString())) { } else if (type.equalsIgnoreCase(DataStoreProvider.DataStoreProviderType.ImageCache.toString())) {
return this.getCacheDataStoreProviders(); return this.getCacheDataStoreProviders();
} else { } else if (type.equalsIgnoreCase(DataStoreProviderType.OBJECT.toString())) {
return this.getObjectStoreProviders();
}else {
throw new InvalidParameterValueException("Invalid parameter: " + type); throw new InvalidParameterValueException("Invalid parameter: " + type);
} }
} }
@ -223,4 +236,16 @@ public class DataStoreProviderManagerImpl extends ManagerBase implements DataSto
return providers; return providers;
} }
public List<StorageProviderResponse> getObjectStoreProviders() {
List<StorageProviderResponse> providers = new ArrayList<StorageProviderResponse>();
for (DataStoreProvider provider : providerMap.values()) {
if (provider.getTypes().contains(DataStoreProviderType.OBJECT)) {
StorageProviderResponse response = new StorageProviderResponse();
response.setName(provider.getName());
response.setType(DataStoreProviderType.OBJECT.toString());
providers.add(response);
}
}
return providers;
}
} }

View File

@ -0,0 +1,81 @@
/*
* 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.agent.api.to.DataTO;
import com.cloud.host.Host;
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
import org.apache.cloudstack.framework.async.AsyncRpcContext;
import org.apache.cloudstack.storage.command.CommandResult;
import org.apache.log4j.Logger;
import java.util.Map;
public abstract class BaseObjectStoreDriverImpl implements ObjectStoreDriver {
private static final Logger LOGGER = Logger.getLogger(BaseObjectStoreDriverImpl.class);
@Override
public Map<String, String> getCapabilities() {
return null;
}
@Override
public DataTO getTO(DataObject data) {
return null;
}
protected class CreateContext<T> extends AsyncRpcContext<T> {
final DataObject data;
public CreateContext(AsyncCompletionCallback<T> callback, DataObject data) {
super(callback);
this.data = data;
}
}
@Override
public void createAsync(DataStore dataStore, DataObject data, AsyncCompletionCallback<CreateCmdResult> callback) {
}
@Override
public void deleteAsync(DataStore dataStore, DataObject data, AsyncCompletionCallback<CommandResult> callback) {
}
@Override
public void copyAsync(DataObject srcdata, DataObject destData, AsyncCompletionCallback<CopyCommandResult> callback) {
}
@Override
public void copyAsync(DataObject srcData, DataObject destData, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
copyAsync(srcData, destData, callback);
}
@Override
public boolean canCopy(DataObject srcData, DataObject destData) {
return false;
}
@Override
public void resize(DataObject data, AsyncCompletionCallback<CreateCmdResult> callback) {
}
}

View File

@ -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.storage.object;
import com.amazonaws.services.s3.model.AccessControlList;
import com.amazonaws.services.s3.model.BucketPolicy;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver;
import java.util.List;
import java.util.Map;
public interface ObjectStoreDriver extends DataStoreDriver {
Bucket createBucket(Bucket bucket, boolean objectLock);
List<Bucket> listBuckets(long storeId);
boolean deleteBucket(String bucketName, long storeId);
AccessControlList getBucketAcl(String bucketName, long storeId);
void setBucketAcl(String bucketName, AccessControlList acl, long storeId);
void setBucketPolicy(String bucketName, String policyType, long storeId);
BucketPolicy getBucketPolicy(String bucketName, long storeId);
void deleteBucketPolicy(String bucketName, long storeId);
boolean createUser(long accountId, long storeId);
boolean setBucketEncryption(String bucketName, long storeId);
boolean deleteBucketEncryption(String bucketName, long storeId);
boolean setBucketVersioning(String bucketName, long storeId);
boolean deleteBucketVersioning(String bucketName, long storeId);
void setBucketQuota(String bucketName, long storeId, long size);
Map<String, Long> getAllBucketsUsage(long storeId);
}

View File

@ -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.storage.object.datastore;
import com.cloud.utils.exception.CloudRuntimeException;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreDao;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreDetailVO;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreDetailsDao;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreVO;
import org.springframework.stereotype.Component;
import javax.inject.Inject;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;
@Component
public class ObjectStoreHelper {
@Inject
ObjectStoreDao ObjectStoreDao;
@Inject
ObjectStoreDetailsDao ObjectStoreDetailsDao;
public ObjectStoreVO createObjectStore(Map<String, Object> params, Map<String, String> details) {
ObjectStoreVO store = new ObjectStoreVO();
store.setProviderName((String)params.get("providerName"));
store.setUuid(UUID.randomUUID().toString());
store.setUrl((String)params.get("url"));
store.setName((String)params.get("name"));
store = ObjectStoreDao.persist(store);
// persist details
if (details != null) {
Iterator<String> keyIter = details.keySet().iterator();
while (keyIter.hasNext()) {
String key = keyIter.next().toString();
String value = details.get(key);
ObjectStoreDetailVO detail = new ObjectStoreDetailVO(store.getId(), key, value);
ObjectStoreDetailsDao.persist(detail);
}
}
return store;
}
public boolean deleteObjectStore(long id) {
ObjectStoreVO store = ObjectStoreDao.findById(id);
if (store == null) {
throw new CloudRuntimeException("can't find Object store:" + id);
}
ObjectStoreDao.remove(id);
return true;
}
}

View File

@ -0,0 +1,38 @@
/*
* 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.datastore;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.storage.object.ObjectStoreDriver;
import org.apache.cloudstack.storage.object.ObjectStoreEntity;
import java.util.List;
public interface ObjectStoreProviderManager {
ObjectStoreEntity getObjectStore(String uuid);
List<DataStore> listObjectStores();
List<DataStore> listObjectStoreByProvider(String provider);
ObjectStoreEntity getObjectStore(long objectStoreId);
boolean registerDriver(String uuid, ObjectStoreDriver driver);
}

View File

@ -55,6 +55,7 @@ public class QuotaTypes extends UsageTypes {
quotaTypeList.put(VOLUME_SECONDARY, new QuotaTypes(VOLUME_SECONDARY, "VOLUME_SECONDARY", UsageUnitTypes.GB_MONTH.toString(), "Volume secondary storage usage")); quotaTypeList.put(VOLUME_SECONDARY, new QuotaTypes(VOLUME_SECONDARY, "VOLUME_SECONDARY", UsageUnitTypes.GB_MONTH.toString(), "Volume secondary storage usage"));
quotaTypeList.put(VM_SNAPSHOT_ON_PRIMARY, new QuotaTypes(VM_SNAPSHOT_ON_PRIMARY, "VM_SNAPSHOT_ON_PRIMARY", UsageUnitTypes.GB_MONTH.toString(), "VM Snapshot primary storage usage")); quotaTypeList.put(VM_SNAPSHOT_ON_PRIMARY, new QuotaTypes(VM_SNAPSHOT_ON_PRIMARY, "VM_SNAPSHOT_ON_PRIMARY", UsageUnitTypes.GB_MONTH.toString(), "VM Snapshot primary storage usage"));
quotaTypeList.put(BACKUP, new QuotaTypes(BACKUP, "BACKUP", UsageUnitTypes.GB_MONTH.toString(), "Backup storage usage")); quotaTypeList.put(BACKUP, new QuotaTypes(BACKUP, "BACKUP", UsageUnitTypes.GB_MONTH.toString(), "Backup storage usage"));
quotaTypeList.put(BUCKET, new QuotaTypes(BUCKET, "BUCKET", UsageUnitTypes.GB_MONTH.toString(), "Object Store bucket usage"));
quotaTypeMap = Collections.unmodifiableMap(quotaTypeList); quotaTypeMap = Collections.unmodifiableMap(quotaTypeList);
} }

View File

@ -71,6 +71,7 @@ import org.apache.cloudstack.response.VolumeMetricsResponse;
import org.apache.cloudstack.response.VolumeMetricsStatsResponse; import org.apache.cloudstack.response.VolumeMetricsStatsResponse;
import org.apache.cloudstack.response.ZoneMetricsResponse; import org.apache.cloudstack.response.ZoneMetricsResponse;
import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreDao;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.utils.bytescale.ByteScaleUtils; import org.apache.cloudstack.utils.bytescale.ByteScaleUtils;
import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.beanutils.BeanUtils;
@ -176,6 +177,9 @@ public class MetricsServiceImpl extends MutualExclusiveIdsManagerBase implements
@Inject @Inject
private VolumeStatsDao volumeStatsDao; private VolumeStatsDao volumeStatsDao;
@Inject
private ObjectStoreDao objectStoreDao;
private static Gson gson = new Gson(); private static Gson gson = new Gson();
protected MetricsServiceImpl() { protected MetricsServiceImpl() {
@ -557,6 +561,7 @@ public class MetricsServiceImpl extends MutualExclusiveIdsManagerBase implements
response.setHosts(hostDao.countAllByType(Host.Type.Routing)); response.setHosts(hostDao.countAllByType(Host.Type.Routing));
response.setStoragePools(storagePoolDao.countAll()); response.setStoragePools(storagePoolDao.countAll());
response.setImageStores(imageStoreDao.countAllImageStores()); response.setImageStores(imageStoreDao.countAllImageStores());
response.setObjectStores(objectStoreDao.countAllObjectStores());
response.setSystemvms(vmInstanceDao.listByTypes(VirtualMachine.Type.ConsoleProxy, VirtualMachine.Type.SecondaryStorageVm).size()); response.setSystemvms(vmInstanceDao.listByTypes(VirtualMachine.Type.ConsoleProxy, VirtualMachine.Type.SecondaryStorageVm).size());
response.setRouters(domainRouterDao.countAllByRole(VirtualRouter.Role.VIRTUAL_ROUTER)); response.setRouters(domainRouterDao.countAllByRole(VirtualRouter.Role.VIRTUAL_ROUTER));
response.setInternalLbs(domainRouterDao.countAllByRole(VirtualRouter.Role.INTERNAL_LB_VM)); response.setInternalLbs(domainRouterDao.countAllByRole(VirtualRouter.Role.INTERNAL_LB_VM));

View File

@ -47,6 +47,10 @@ public class InfrastructureResponse extends BaseResponse {
@Param(description = "Number of images stores") @Param(description = "Number of images stores")
private Integer imageStores; private Integer imageStores;
@SerializedName("objectstores")
@Param(description = "Number of object stores")
private Integer objectStores;
@SerializedName("systemvms") @SerializedName("systemvms")
@Param(description = "Number of systemvms") @Param(description = "Number of systemvms")
private Integer systemvms; private Integer systemvms;
@ -118,4 +122,8 @@ public class InfrastructureResponse extends BaseResponse {
public void setAlerts(Integer alerts) { this.alerts = alerts; } public void setAlerts(Integer alerts) { this.alerts = alerts; }
public void setInternalLbs(Integer internalLbs) { this.internalLbs = internalLbs; } public void setInternalLbs(Integer internalLbs) { this.internalLbs = internalLbs; }
public void setObjectStores(Integer objectStores) {
this.objectStores = objectStores;
}
} }

View File

@ -133,6 +133,8 @@
<module>storage/volume/scaleio</module> <module>storage/volume/scaleio</module>
<module>storage/volume/linstor</module> <module>storage/volume/linstor</module>
<module>storage/volume/storpool</module> <module>storage/volume/storpool</module>
<module>storage/object/minio</module>
<module>storage/object/simulator</module>
<module>storage-allocators/random</module> <module>storage-allocators/random</module>
@ -187,6 +189,30 @@
<type>test-jar</type> <type>test-jar</type>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine-storage</artifactId>
<version>4.19.0.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.5.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio-admin</artifactId>
<version>8.5.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine-storage-object</artifactId>
<version>4.19.0.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies> </dependencies>
<profiles> <profiles>
<profile> <profile>

View File

@ -18,12 +18,15 @@
package org.apache.cloudstack.shutdown; package org.apache.cloudstack.shutdown;
import org.apache.cloudstack.framework.jobs.AsyncJobManager; import org.apache.cloudstack.framework.jobs.AsyncJobManager;
import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy; import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.MockitoJUnitRunner;
@ -39,6 +42,12 @@ public class ShutdownManagerImplTest {
@Mock @Mock
AsyncJobManager jobManagerMock; AsyncJobManager jobManagerMock;
private AutoCloseable closeable;
@Before
public void setUp() throws Exception {
closeable = MockitoAnnotations.openMocks(this);
}
private long prepareCountPendingJobs() { private long prepareCountPendingJobs() {
long expectedCount = 1L; long expectedCount = 1L;
@ -75,4 +84,9 @@ public class ShutdownManagerImplTest {
spy.cancelShutdown(); spy.cancelShutdown();
Mockito.verify(jobManagerMock).enableAsyncJobs(); Mockito.verify(jobManagerMock).enableAsyncJobs();
} }
@After
public void tearDown() throws Exception {
closeable.close();
}
} }

View File

@ -0,0 +1,57 @@
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-plugin-storage-object-minio</artifactId>
<name>Apache CloudStack Plugin - MinIO object storage provider</name>
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
<version>4.19.0.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine-storage</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine-storage-object</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine-schema</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.5.2</version>
</dependency>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio-admin</artifactId>
<version>8.5.2</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,404 @@
/*
* 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.driver;
import com.amazonaws.services.s3.model.AccessControlList;
import com.amazonaws.services.s3.model.BucketPolicy;
import com.cloud.agent.api.to.DataStoreTO;
import org.apache.cloudstack.storage.object.Bucket;
import com.cloud.storage.BucketVO;
import com.cloud.storage.dao.BucketDao;
import com.cloud.user.Account;
import com.cloud.user.AccountDetailsDao;
import com.cloud.user.dao.AccountDao;
import com.cloud.utils.exception.CloudRuntimeException;
import io.minio.BucketExistsArgs;
import io.minio.DeleteBucketEncryptionArgs;
import io.minio.MakeBucketArgs;
import io.minio.MinioClient;
import io.minio.RemoveBucketArgs;
import io.minio.SetBucketEncryptionArgs;
import io.minio.SetBucketPolicyArgs;
import io.minio.SetBucketVersioningArgs;
import io.minio.admin.MinioAdminClient;
import io.minio.admin.QuotaUnit;
import io.minio.admin.UserInfo;
import io.minio.admin.messages.DataUsageInfo;
import io.minio.messages.SseConfiguration;
import io.minio.messages.VersioningConfiguration;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreDao;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreDetailsDao;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreVO;
import org.apache.cloudstack.storage.object.BaseObjectStoreDriverImpl;
import org.apache.cloudstack.storage.object.BucketObject;
import org.apache.commons.codec.binary.Base64;
import org.apache.log4j.Logger;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.inject.Inject;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MinIOObjectStoreDriverImpl extends BaseObjectStoreDriverImpl {
private static final Logger s_logger = Logger.getLogger(MinIOObjectStoreDriverImpl.class);
@Inject
AccountDao _accountDao;
@Inject
AccountDetailsDao _accountDetailsDao;
@Inject
ObjectStoreDao _storeDao;
@Inject
BucketDao _bucketDao;
@Inject
ObjectStoreDetailsDao _storeDetailsDao;
private static final String ACCESS_KEY = "accesskey";
private static final String SECRET_KEY = "secretkey";
private static final String MINIO_ACCESS_KEY = "minio-accesskey";
private static final String MINIO_SECRET_KEY = "minio-secretkey";
@Override
public DataStoreTO getStoreTO(DataStore store) {
return null;
}
@Override
public Bucket createBucket(Bucket bucket, boolean objectLock) {
//ToDo Client pool mgmt
String bucketName = bucket.getName();
long storeId = bucket.getObjectStoreId();
long accountId = bucket.getAccountId();
MinioClient minioClient = getMinIOClient(storeId);
Account account = _accountDao.findById(accountId);
if ((_accountDetailsDao.findDetail(accountId, MINIO_ACCESS_KEY) == null)
|| (_accountDetailsDao.findDetail(accountId, MINIO_SECRET_KEY) == null)) {
throw new CloudRuntimeException("Bucket access credentials unavailable for account: "+account.getAccountName());
}
try {
if(minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
throw new CloudRuntimeException("Bucket already exists with name "+ bucketName);
}
} catch (Exception e) {
throw new CloudRuntimeException(e);
}
try {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).objectLock(objectLock).build());
} catch (Exception e) {
throw new CloudRuntimeException(e);
}
List<BucketVO> buckets = _bucketDao.listByObjectStoreIdAndAccountId(storeId, accountId);
StringBuilder resources_builder = new StringBuilder();
for(BucketVO exitingBucket : buckets) {
resources_builder.append("\"arn:aws:s3:::"+exitingBucket.getName()+"/*\",\n");
}
resources_builder.append("\"arn:aws:s3:::"+bucketName+"/*\"\n");
String policy = " {\n" +
" \"Statement\": [\n" +
" {\n" +
" \"Action\": \"s3:*\",\n" +
" \"Effect\": \"Allow\",\n" +
" \"Principal\": \"*\",\n" +
" \"Resource\": ["+resources_builder+"]" +
" }\n" +
" ],\n" +
" \"Version\": \"2012-10-17\"\n" +
" }";
MinioAdminClient minioAdminClient = getMinIOAdminClient(storeId);
String policyName = "acs-"+account.getAccountName()+"-policy";
String userName = "acs-"+account.getAccountName();
try {
minioAdminClient.addCannedPolicy(policyName, policy);
minioAdminClient.setPolicy(userName, false, policyName);
} catch (Exception e) {
throw new CloudRuntimeException(e);
}
String accessKey = _accountDetailsDao.findDetail(accountId, MINIO_ACCESS_KEY).getValue();
String secretKey = _accountDetailsDao.findDetail(accountId, MINIO_SECRET_KEY).getValue();
ObjectStoreVO store = _storeDao.findById(storeId);
BucketVO bucketVO = _bucketDao.findById(bucket.getId());
bucketVO.setAccessKey(accessKey);
bucketVO.setSecretKey(secretKey);
bucketVO.setBucketURL(store.getUrl()+"/"+bucketName);
_bucketDao.update(bucket.getId(), bucketVO);
return bucket;
}
@Override
public List<Bucket> listBuckets(long storeId) {
MinioClient minioClient = getMinIOClient(storeId);
List<Bucket> bucketsList = new ArrayList<>();
try {
List<io.minio.messages.Bucket> minIOBuckets = minioClient.listBuckets();
for(io.minio.messages.Bucket minIObucket : minIOBuckets) {
Bucket bucket = new BucketObject();
bucket.setName(minIObucket.name());
bucketsList.add(bucket);
}
} catch (Exception e) {
throw new CloudRuntimeException(e);
}
return bucketsList;
}
@Override
public boolean deleteBucket(String bucketName, long storeId) {
MinioClient minioClient = getMinIOClient(storeId);
try {
if(!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
throw new CloudRuntimeException("Bucket doesn't exist: "+ bucketName);
}
} catch (Exception e) {
throw new CloudRuntimeException(e);
}
//ToDo: check bucket empty
try {
minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
} catch (Exception e) {
throw new CloudRuntimeException(e);
}
return true;
}
@Override
public AccessControlList getBucketAcl(String bucketName, long storeId) {
return null;
}
@Override
public void setBucketAcl(String bucketName, AccessControlList acl, long storeId) {
}
@Override
public void setBucketPolicy(String bucketName, String policy, long storeId) {
String privatePolicy = "{\"Version\":\"2012-10-17\",\"Statement\":[]}";
StringBuilder builder = new StringBuilder();
builder.append("{\n");
builder.append(" \"Statement\": [\n");
builder.append(" {\n");
builder.append(" \"Action\": [\n");
builder.append(" \"s3:GetBucketLocation\",\n");
builder.append(" \"s3:ListBucket\"\n");
builder.append(" ],\n");
builder.append(" \"Effect\": \"Allow\",\n");
builder.append(" \"Principal\": \"*\",\n");
builder.append(" \"Resource\": \"arn:aws:s3:::"+bucketName+"\"\n");
builder.append(" },\n");
builder.append(" {\n");
builder.append(" \"Action\": \"s3:GetObject\",\n");
builder.append(" \"Effect\": \"Allow\",\n");
builder.append(" \"Principal\": \"*\",\n");
builder.append(" \"Resource\": \"arn:aws:s3:::"+bucketName+"/*\"\n");
builder.append(" }\n");
builder.append(" ],\n");
builder.append(" \"Version\": \"2012-10-17\"\n");
builder.append("}\n");
String publicPolicy = builder.toString();
//ToDo Support custom policy
String policyConfig = (policy.equalsIgnoreCase("public"))? publicPolicy : privatePolicy;
MinioClient minioClient = getMinIOClient(storeId);
try {
minioClient.setBucketPolicy(
SetBucketPolicyArgs.builder().bucket(bucketName).config(policyConfig).build());
} catch (Exception e) {
throw new CloudRuntimeException(e);
}
}
@Override
public BucketPolicy getBucketPolicy(String bucketName, long storeId) {
return null;
}
@Override
public void deleteBucketPolicy(String bucketName, long storeId) {
}
@Override
public boolean createUser(long accountId, long storeId) {
Account account = _accountDao.findById(accountId);
MinioAdminClient minioAdminClient = getMinIOAdminClient(storeId);
String accessKey = "acs-"+account.getAccountName();
// Check user exists
try {
UserInfo userInfo = minioAdminClient.getUserInfo(accessKey);
if(userInfo != null) {
s_logger.debug("User already exists in MinIO store: "+accessKey);
return true;
}
} catch (Exception e) {
s_logger.debug("User does not exist. Creating user: "+accessKey);
}
KeyGenerator generator = null;
try {
generator = KeyGenerator.getInstance("HmacSHA1");
} catch (NoSuchAlgorithmException e) {
throw new CloudRuntimeException(e);
}
SecretKey key = generator.generateKey();
String secretKey = Base64.encodeBase64URLSafeString(key.getEncoded());
try {
minioAdminClient.addUser(accessKey, UserInfo.Status.ENABLED, secretKey, "", new ArrayList<String>());
} catch (Exception e) {
throw new CloudRuntimeException(e);
}
// Store user credentials
Map<String, String> details = new HashMap<>();
details.put(MINIO_ACCESS_KEY, accessKey);
details.put(MINIO_SECRET_KEY, secretKey);
_accountDetailsDao.persist(accountId, details);
return true;
}
@Override
public boolean setBucketEncryption(String bucketName, long storeId) {
MinioClient minioClient = getMinIOClient(storeId);
try {
minioClient.setBucketEncryption(SetBucketEncryptionArgs.builder()
.bucket(bucketName)
.config(SseConfiguration.newConfigWithSseS3Rule())
.build()
);
} catch (Exception e) {
throw new CloudRuntimeException(e);
}
return true;
}
@Override
public boolean deleteBucketEncryption(String bucketName, long storeId) {
MinioClient minioClient = getMinIOClient(storeId);
try {
minioClient.deleteBucketEncryption(DeleteBucketEncryptionArgs.builder()
.bucket(bucketName)
.build()
);
} catch (Exception e) {
throw new CloudRuntimeException(e);
}
return true;
}
@Override
public boolean setBucketVersioning(String bucketName, long storeId) {
MinioClient minioClient = getMinIOClient(storeId);
try {
minioClient.setBucketVersioning(SetBucketVersioningArgs.builder()
.bucket(bucketName)
.config(new VersioningConfiguration(VersioningConfiguration.Status.ENABLED, null))
.build()
);
} catch (Exception e) {
throw new CloudRuntimeException(e);
}
return true;
}
@Override
public boolean deleteBucketVersioning(String bucketName, long storeId) {
MinioClient minioClient = getMinIOClient(storeId);
try {
minioClient.setBucketVersioning(SetBucketVersioningArgs.builder()
.bucket(bucketName)
.config(new VersioningConfiguration(VersioningConfiguration.Status.SUSPENDED, null))
.build()
);
} catch (Exception e) {
throw new CloudRuntimeException(e);
}
return true;
}
@Override
public void setBucketQuota(String bucketName, long storeId, long size) {
MinioAdminClient minioAdminClient = getMinIOAdminClient(storeId);
try {
minioAdminClient.setBucketQuota(bucketName, size, QuotaUnit.GB);
} catch (Exception e) {
throw new CloudRuntimeException(e);
}
}
@Override
public Map<String, Long> getAllBucketsUsage(long storeId) {
MinioAdminClient minioAdminClient = getMinIOAdminClient(storeId);
try {
DataUsageInfo dataUsageInfo = minioAdminClient.getDataUsageInfo();
return dataUsageInfo.bucketsSizes();
} catch (Exception e) {
throw new CloudRuntimeException(e);
}
}
protected MinioClient getMinIOClient(long storeId) {
ObjectStoreVO store = _storeDao.findById(storeId);
Map<String, String> storeDetails = _storeDetailsDao.getDetails(storeId);
String url = store.getUrl();
String accessKey = storeDetails.get(ACCESS_KEY);
String secretKey = storeDetails.get(SECRET_KEY);
MinioClient minioClient =
MinioClient.builder()
.endpoint(url)
.credentials(accessKey,secretKey)
.build();
if(minioClient == null){
throw new CloudRuntimeException("Error while creating MinIO client");
}
return minioClient;
}
protected MinioAdminClient getMinIOAdminClient(long storeId) {
ObjectStoreVO store = _storeDao.findById(storeId);
Map<String, String> storeDetails = _storeDetailsDao.getDetails(storeId);
String url = store.getUrl();
String accessKey = storeDetails.get(ACCESS_KEY);
String secretKey = storeDetails.get(SECRET_KEY);
MinioAdminClient minioAdminClient =
MinioAdminClient.builder()
.endpoint(url)
.credentials(accessKey,secretKey)
.build();
if(minioAdminClient == null){
throw new CloudRuntimeException("Error while creating MinIO client");
}
return minioAdminClient;
}
}

View File

@ -0,0 +1,129 @@
// 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.lifecycle;
import com.cloud.agent.api.StoragePoolInfo;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.utils.exception.CloudRuntimeException;
import io.minio.MinioClient;
import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.HostScope;
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreVO;
import org.apache.cloudstack.storage.object.datastore.ObjectStoreHelper;
import org.apache.cloudstack.storage.object.datastore.ObjectStoreProviderManager;
import org.apache.cloudstack.storage.object.store.lifecycle.ObjectStoreLifeCycle;
import org.apache.log4j.Logger;
import javax.inject.Inject;
import java.util.HashMap;
import java.util.Map;
public class MinIOObjectStoreLifeCycleImpl implements ObjectStoreLifeCycle {
private static final Logger s_logger = Logger.getLogger(MinIOObjectStoreLifeCycleImpl.class);
@Inject
ObjectStoreHelper objectStoreHelper;
@Inject
ObjectStoreProviderManager objectStoreMgr;
public MinIOObjectStoreLifeCycleImpl() {
}
@SuppressWarnings("unchecked")
@Override
public DataStore initialize(Map<String, Object> dsInfos) {
String url = (String)dsInfos.get("url");
String name = (String)dsInfos.get("name");
String providerName = (String)dsInfos.get("providerName");
Map<String, String> details = (Map<String, String>)dsInfos.get("details");
if(details == null){
throw new CloudRuntimeException("MinIO credentials are missing");
}
String accessKey = details.get("accesskey");
String secretKey = details.get("secretkey");
Map<String, Object> objectStoreParameters = new HashMap();
objectStoreParameters.put("name", name);
objectStoreParameters.put("url", url);
objectStoreParameters.put("providerName", providerName);
objectStoreParameters.put("accesskey", accessKey);
objectStoreParameters.put("secretkey", secretKey);
//check credentials
MinioClient minioClient =
MinioClient.builder()
.endpoint(url)
.credentials(accessKey,secretKey)
.build();
try {
// Test connection by listing buckets
minioClient.listBuckets();
s_logger.debug("Successfully connected to MinIO EndPoint: "+url);
} catch (Exception e) {
s_logger.debug("Error while initializing MinIO Object Store: "+e.getMessage());
throw new RuntimeException("Error while initializing MinIO Object Store. Invalid credentials or URL");
}
ObjectStoreVO objectStore = objectStoreHelper.createObjectStore(objectStoreParameters, details);
return objectStoreMgr.getObjectStore(objectStore.getId());
}
@Override
public boolean attachCluster(DataStore store, ClusterScope scope) {
return false;
}
@Override
public boolean attachHost(DataStore store, HostScope scope, StoragePoolInfo existingInfo) {
return false;
}
@Override
public boolean attachZone(DataStore dataStore, ZoneScope scope, HypervisorType hypervisorType) {
return false;
}
@Override
public boolean maintain(DataStore store) {
return false;
}
@Override
public boolean cancelMaintain(DataStore store) {
return false;
}
@Override
public boolean deleteDataStore(DataStore store) {
return false;
}
/* (non-Javadoc)
* @see org.apache.cloudstack.engine.subsystem.api.storage.DataStoreLifeCycle#migrateToObjectStore(org.apache.cloudstack.engine.subsystem.api.storage.DataStore)
*/
@Override
public boolean migrateToObjectStore(DataStore store) {
return false;
}
}

View File

@ -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.storage.datastore.provider;
import com.cloud.utils.component.ComponentContext;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreLifeCycle;
import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectStoreProvider;
import org.apache.cloudstack.storage.datastore.driver.MinIOObjectStoreDriverImpl;
import org.apache.cloudstack.storage.datastore.lifecycle.MinIOObjectStoreLifeCycleImpl;
import org.apache.cloudstack.storage.object.ObjectStoreDriver;
import org.apache.cloudstack.storage.object.datastore.ObjectStoreHelper;
import org.apache.cloudstack.storage.object.datastore.ObjectStoreProviderManager;
import org.apache.cloudstack.storage.object.store.lifecycle.ObjectStoreLifeCycle;
import org.springframework.stereotype.Component;
import javax.inject.Inject;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@Component
public class MinIOObjectStoreProviderImpl implements ObjectStoreProvider {
@Inject
ObjectStoreProviderManager storeMgr;
@Inject
ObjectStoreHelper helper;
private final String providerName = "MinIO";
protected ObjectStoreLifeCycle lifeCycle;
protected ObjectStoreDriver driver;
@Override
public DataStoreLifeCycle getDataStoreLifeCycle() {
return lifeCycle;
}
@Override
public String getName() {
return this.providerName;
}
@Override
public boolean configure(Map<String, Object> params) {
lifeCycle = ComponentContext.inject(MinIOObjectStoreLifeCycleImpl.class);
driver = ComponentContext.inject(MinIOObjectStoreDriverImpl.class);
storeMgr.registerDriver(this.getName(), driver);
return true;
}
@Override
public DataStoreDriver getDataStoreDriver() {
return this.driver;
}
@Override
public HypervisorHostListener getHostListener() {
return null;
}
@Override
public Set<DataStoreProviderType> getTypes() {
Set<DataStoreProviderType> types = new HashSet<DataStoreProviderType>();
types.add(DataStoreProviderType.OBJECT);
return types;
}
}

View File

@ -0,0 +1,18 @@
# 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.
name=storage-object-minio
parent=storage

View File

@ -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.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
>
<bean id="minioStoreProviderImpl"
class="org.apache.cloudstack.storage.datastore.provider.MinIOObjectStoreProviderImpl" />
</beans>

View File

@ -0,0 +1,122 @@
// 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.driver;
import com.cloud.storage.BucketVO;
import com.cloud.storage.dao.BucketDao;
import com.cloud.user.AccountDetailVO;
import com.cloud.user.AccountDetailsDao;
import com.cloud.user.AccountVO;
import com.cloud.user.dao.AccountDao;
import io.minio.BucketExistsArgs;
import io.minio.MinioClient;
import io.minio.RemoveBucketArgs;
import io.minio.admin.MinioAdminClient;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreDao;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreDetailsDao;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreVO;
import org.apache.cloudstack.storage.object.Bucket;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.ArrayList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyLong;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class MinIOObjectStoreDriverImplTest {
@Spy
MinIOObjectStoreDriverImpl minioObjectStoreDriverImpl = new MinIOObjectStoreDriverImpl();
@Mock
MinioClient minioClient;
@Mock
MinioAdminClient minioAdminClient;
@Mock
ObjectStoreDao objectStoreDao;
@Mock
ObjectStoreVO objectStoreVO;
@Mock
ObjectStoreDetailsDao objectStoreDetailsDao;
@Mock
AccountDao accountDao;
@Mock
BucketDao bucketDao;
@Mock
AccountVO account;
@Mock
AccountDetailsDao accountDetailsDao;
Bucket bucket;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
minioObjectStoreDriverImpl._storeDao = objectStoreDao;
minioObjectStoreDriverImpl._storeDetailsDao = objectStoreDetailsDao;
minioObjectStoreDriverImpl._accountDao = accountDao;
minioObjectStoreDriverImpl._bucketDao = bucketDao;
minioObjectStoreDriverImpl._accountDetailsDao = accountDetailsDao;
bucket = new BucketVO();
bucket.setName("test-bucket");
when(objectStoreVO.getUrl()).thenReturn("http://localhost:9000");
when(objectStoreDao.findById(any())).thenReturn(objectStoreVO);
}
@Test
public void testCreateBucket() throws Exception {
doReturn(minioClient).when(minioObjectStoreDriverImpl).getMinIOClient(anyLong());
doReturn(minioAdminClient).when(minioObjectStoreDriverImpl).getMinIOAdminClient(anyLong());
when(bucketDao.listByObjectStoreIdAndAccountId(anyLong(), anyLong())).thenReturn(new ArrayList<BucketVO>());
when(account.getAccountName()).thenReturn("admin");
when(accountDao.findById(anyLong())).thenReturn(account);
when(accountDetailsDao.findDetail(anyLong(),anyString())).
thenReturn(new AccountDetailVO(1L, "abc","def"));
when(bucketDao.findById(anyLong())).thenReturn(new BucketVO());
Bucket bucketRet = minioObjectStoreDriverImpl.createBucket(bucket, false);
assertEquals(bucketRet.getName(), bucket.getName());
verify(minioClient, times(1)).bucketExists(any());
verify(minioClient, times(1)).makeBucket(any());
}
@Test
public void testDeleteBucket() throws Exception {
String bucketName = "test-bucket";
doReturn(minioClient).when(minioObjectStoreDriverImpl).getMinIOClient(anyLong());
when(minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())).thenReturn(true);
doNothing().when(minioClient).removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
boolean success = minioObjectStoreDriverImpl.deleteBucket(bucketName, 1L);
assertTrue(success);
verify(minioClient, times(1)).bucketExists(any());
verify(minioClient, times(1)).removeBucket(any());
}
}

View File

@ -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.storage.datastore.provider;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider.DataStoreProviderType;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockitoAnnotations;
import java.util.Set;
import static org.junit.Assert.assertEquals;
public class MinIOObjectStoreProviderImplTest {
private MinIOObjectStoreProviderImpl minioObjectStoreProviderImpl;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
minioObjectStoreProviderImpl = new MinIOObjectStoreProviderImpl();
}
@Test
public void testGetName() {
String name = minioObjectStoreProviderImpl.getName();
assertEquals("MinIO", name);
}
@Test
public void testGetTypes() {
Set<DataStoreProviderType> types = minioObjectStoreProviderImpl.getTypes();
assertEquals(1, types.size());
assertEquals("OBJECT", types.toArray()[0].toString());
}
}

View File

@ -0,0 +1,57 @@
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-plugin-storage-object-simulator</artifactId>
<name>Apache CloudStack Plugin - Simulator object storage provider</name>
<parent>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloudstack-plugins</artifactId>
<version>4.19.0.0-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine-storage</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine-storage-object</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine-schema</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.5.2</version>
</dependency>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio-admin</artifactId>
<version>8.5.2</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,139 @@
/*
* 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.driver;
import com.amazonaws.services.s3.model.AccessControlList;
import com.amazonaws.services.s3.model.BucketPolicy;
import com.cloud.agent.api.to.DataStoreTO;
import org.apache.cloudstack.storage.object.Bucket;
import com.cloud.storage.BucketVO;
import com.cloud.storage.dao.BucketDao;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreDao;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreVO;
import org.apache.cloudstack.storage.object.BaseObjectStoreDriverImpl;
import org.apache.log4j.Logger;
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class SimulatorObjectStoreDriverImpl extends BaseObjectStoreDriverImpl {
private static final Logger s_logger = Logger.getLogger(SimulatorObjectStoreDriverImpl.class);
@Inject
ObjectStoreDao _storeDao;
@Inject
BucketDao _bucketDao;
private static final String ACCESS_KEY = "accesskey";
private static final String SECRET_KEY = "secretkey";
@Override
public DataStoreTO getStoreTO(DataStore store) {
return null;
}
@Override
public Bucket createBucket(Bucket bucket, boolean objectLock) {
String bucketName = bucket.getName();
long storeId = bucket.getObjectStoreId();
ObjectStoreVO store = _storeDao.findById(storeId);
BucketVO bucketVO = _bucketDao.findById(bucket.getId());
bucketVO.setAccessKey(ACCESS_KEY);
bucketVO.setSecretKey(SECRET_KEY);
bucketVO.setBucketURL(store.getUrl()+"/"+bucketName);
_bucketDao.update(bucket.getId(), bucketVO);
return bucket;
}
@Override
public List<Bucket> listBuckets(long storeId) {
List<Bucket> bucketsList = new ArrayList<>();
return bucketsList;
}
@Override
public boolean deleteBucket(String bucketName, long storeId) {
return true;
}
@Override
public AccessControlList getBucketAcl(String bucketName, long storeId) {
return null;
}
@Override
public void setBucketAcl(String bucketName, AccessControlList acl, long storeId) {
}
@Override
public void setBucketPolicy(String bucketName, String policy, long storeId) {
}
@Override
public BucketPolicy getBucketPolicy(String bucketName, long storeId) {
return null;
}
@Override
public void deleteBucketPolicy(String bucketName, long storeId) {
}
@Override
public boolean createUser(long accountId, long storeId) {
return true;
}
@Override
public boolean setBucketEncryption(String bucketName, long storeId) {
return true;
}
@Override
public boolean deleteBucketEncryption(String bucketName, long storeId) {
return true;
}
@Override
public boolean setBucketVersioning(String bucketName, long storeId) {
return true;
}
@Override
public boolean deleteBucketVersioning(String bucketName, long storeId) {
return true;
}
@Override
public void setBucketQuota(String bucketName, long storeId, long size) {
}
@Override
public Map<String, Long> getAllBucketsUsage(long storeId) {
return new HashMap<String, Long>();
}
}

View File

@ -0,0 +1,120 @@
// 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.lifecycle;
import com.cloud.agent.api.StoragePoolInfo;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.resource.Discoverer;
import com.cloud.resource.ResourceManager;
import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.HostScope;
import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreDao;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreVO;
import org.apache.cloudstack.storage.object.datastore.ObjectStoreHelper;
import org.apache.cloudstack.storage.object.datastore.ObjectStoreProviderManager;
import org.apache.cloudstack.storage.object.store.lifecycle.ObjectStoreLifeCycle;
import org.apache.log4j.Logger;
import javax.inject.Inject;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class SimulatorObjectStoreLifeCycleImpl implements ObjectStoreLifeCycle {
private static final Logger s_logger = Logger.getLogger(SimulatorObjectStoreLifeCycleImpl.class);
@Inject
protected ResourceManager _resourceMgr;
@Inject
protected ObjectStoreDao objectStoreDao;
@Inject
ObjectStoreHelper objectStoreHelper;
@Inject
ObjectStoreProviderManager objectStoreMgr;
protected List<? extends Discoverer> _discoverers;
public List<? extends Discoverer> getDiscoverers() {
return _discoverers;
}
public void setDiscoverers(List<? extends Discoverer> discoverers) {
this._discoverers = discoverers;
}
public SimulatorObjectStoreLifeCycleImpl() {
}
@SuppressWarnings("unchecked")
@Override
public DataStore initialize(Map<String, Object> dsInfos) {
String url = (String)dsInfos.get("url");
String name = (String)dsInfos.get("name");
String providerName = (String)dsInfos.get("providerName");
Map<String, String> details = (Map<String, String>)dsInfos.get("details");
Map<String, Object> objectStoreParameters = new HashMap();
objectStoreParameters.put("name", name);
objectStoreParameters.put("url", url);
objectStoreParameters.put("providerName", providerName);
ObjectStoreVO ids = objectStoreHelper.createObjectStore(objectStoreParameters, details);
return objectStoreMgr.getObjectStore(ids.getId());
}
@Override
public boolean attachCluster(DataStore store, ClusterScope scope) {
return false;
}
@Override
public boolean attachHost(DataStore store, HostScope scope, StoragePoolInfo existingInfo) {
return false;
}
@Override
public boolean attachZone(DataStore dataStore, ZoneScope scope, HypervisorType hypervisorType) {
return false;
}
@Override
public boolean maintain(DataStore store) {
return false;
}
@Override
public boolean cancelMaintain(DataStore store) {
return false;
}
@Override
public boolean deleteDataStore(DataStore store) {
return false;
}
/* (non-Javadoc)
* @see org.apache.cloudstack.engine.subsystem.api.storage.DataStoreLifeCycle#migrateToObjectStore(org.apache.cloudstack.engine.subsystem.api.storage.DataStore)
*/
@Override
public boolean migrateToObjectStore(DataStore store) {
return false;
}
}

View File

@ -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.storage.datastore.provider;
import com.cloud.utils.component.ComponentContext;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreLifeCycle;
import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectStoreProvider;
import org.apache.cloudstack.storage.datastore.driver.SimulatorObjectStoreDriverImpl;
import org.apache.cloudstack.storage.datastore.lifecycle.SimulatorObjectStoreLifeCycleImpl;
import org.apache.cloudstack.storage.object.ObjectStoreDriver;
import org.apache.cloudstack.storage.object.datastore.ObjectStoreHelper;
import org.apache.cloudstack.storage.object.datastore.ObjectStoreProviderManager;
import org.apache.cloudstack.storage.object.store.lifecycle.ObjectStoreLifeCycle;
import org.springframework.stereotype.Component;
import javax.inject.Inject;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@Component
public class SimulatorObjectStoreProviderImpl implements ObjectStoreProvider {
@Inject
ObjectStoreProviderManager storeMgr;
@Inject
ObjectStoreHelper helper;
private final String providerName = "Simulator";
protected ObjectStoreLifeCycle lifeCycle;
protected ObjectStoreDriver driver;
@Override
public DataStoreLifeCycle getDataStoreLifeCycle() {
return lifeCycle;
}
@Override
public String getName() {
return this.providerName;
}
@Override
public boolean configure(Map<String, Object> params) {
lifeCycle = ComponentContext.inject(SimulatorObjectStoreLifeCycleImpl.class);
driver = ComponentContext.inject(SimulatorObjectStoreDriverImpl.class);
storeMgr.registerDriver(this.getName(), driver);
return true;
}
@Override
public DataStoreDriver getDataStoreDriver() {
return this.driver;
}
@Override
public HypervisorHostListener getHostListener() {
return null;
}
@Override
public Set<DataStoreProviderType> getTypes() {
Set<DataStoreProviderType> types = new HashSet<DataStoreProviderType>();
types.add(DataStoreProviderType.OBJECT);
return types;
}
}

View File

@ -0,0 +1,18 @@
# 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.
name=storage-object-simulator
parent=storage

View File

@ -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.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
>
<bean id="simulatorObjectStoreProviderImpl"
class="org.apache.cloudstack.storage.datastore.provider.SimulatorObjectStoreProviderImpl" />
</beans>

View File

@ -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.storage.datastore.provider;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockitoAnnotations;
import java.util.Set;
import static org.junit.Assert.assertEquals;
public class SimulatorObjectStoreProviderImplTest {
private SimulatorObjectStoreProviderImpl simulatorObjectStoreProviderImpl;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
simulatorObjectStoreProviderImpl = new SimulatorObjectStoreProviderImpl();
}
@Test
public void testGetName() {
String name = simulatorObjectStoreProviderImpl.getName();
assertEquals("Simulator", name);
}
@Test
public void testGetTypes() {
Set<DataStoreProvider.DataStoreProviderType> types = simulatorObjectStoreProviderImpl.getTypes();
assertEquals(1, types.size());
assertEquals("OBJECT", types.toArray()[0].toString());
}
}

View File

@ -294,6 +294,7 @@ import com.cloud.storage.Volume;
import com.cloud.storage.Volume.Type; import com.cloud.storage.Volume.Type;
import com.cloud.storage.VolumeStats; import com.cloud.storage.VolumeStats;
import com.cloud.storage.VolumeVO; import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.BucketDao;
import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.storage.dao.DiskOfferingDao;
import com.cloud.storage.dao.GuestOSCategoryDao; import com.cloud.storage.dao.GuestOSCategoryDao;
import com.cloud.storage.dao.GuestOSDao; import com.cloud.storage.dao.GuestOSDao;
@ -349,6 +350,10 @@ import com.cloud.vm.dao.VMInstanceDao;
import com.cloud.vm.snapshot.VMSnapshot; import com.cloud.vm.snapshot.VMSnapshot;
import com.cloud.vm.snapshot.dao.VMSnapshotDao; import com.cloud.vm.snapshot.dao.VMSnapshotDao;
import org.apache.cloudstack.api.response.ObjectStoreResponse;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreDao;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreVO;
public class ApiDBUtils { public class ApiDBUtils {
private static ManagementServer s_ms; private static ManagementServer s_ms;
static AsyncJobManager s_asyncMgr; static AsyncJobManager s_asyncMgr;
@ -481,6 +486,9 @@ public class ApiDBUtils {
static NicDao s_nicDao; static NicDao s_nicDao;
static ResourceManagerUtil s_resourceManagerUtil; static ResourceManagerUtil s_resourceManagerUtil;
static SnapshotPolicyDetailsDao s_snapshotPolicyDetailsDao; static SnapshotPolicyDetailsDao s_snapshotPolicyDetailsDao;
static ObjectStoreDao s_objectStoreDao;
static BucketDao s_bucketDao;
@Inject @Inject
private ManagementServer ms; private ManagementServer ms;
@ -740,6 +748,11 @@ public class ApiDBUtils {
@Inject @Inject
SnapshotPolicyDetailsDao snapshotPolicyDetailsDao; SnapshotPolicyDetailsDao snapshotPolicyDetailsDao;
@Inject
private ObjectStoreDao objectStoreDao;
@Inject
private BucketDao bucketDao;
@PostConstruct @PostConstruct
void init() { void init() {
s_ms = ms; s_ms = ms;
@ -871,6 +884,8 @@ public class ApiDBUtils {
s_backupOfferingDao = backupOfferingDao; s_backupOfferingDao = backupOfferingDao;
s_resourceIconDao = resourceIconDao; s_resourceIconDao = resourceIconDao;
s_resourceManagerUtil = resourceManagerUtil; s_resourceManagerUtil = resourceManagerUtil;
s_objectStoreDao = objectStoreDao;
s_bucketDao = bucketDao;
} }
// /////////////////////////////////////////////////////////// // ///////////////////////////////////////////////////////////
@ -2208,4 +2223,12 @@ public class ApiDBUtils {
public static NicSecondaryIpVO findSecondaryIpByIp4AddressAndNetworkId(String ip4Address, long networkId) { public static NicSecondaryIpVO findSecondaryIpByIp4AddressAndNetworkId(String ip4Address, long networkId) {
return s_nicSecondaryIpDao.findByIp4AddressAndNetworkId(ip4Address, networkId); return s_nicSecondaryIpDao.findByIp4AddressAndNetworkId(ip4Address, networkId);
} }
public static ObjectStoreResponse newObjectStoreResponse(ObjectStoreVO store) {
return s_objectStoreDao.newObjectStoreResponse(store);
}
public static ObjectStoreResponse fillObjectStoreDetails(ObjectStoreResponse storeData, ObjectStoreVO store) {
return s_objectStoreDao.setObjectStoreResponse(storeData, store);
}
} }

View File

@ -38,6 +38,8 @@ import java.util.stream.Collectors;
import javax.inject.Inject; import javax.inject.Inject;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.storage.BucketVO;
import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.acl.ControlledEntity.ACLType;
import org.apache.cloudstack.affinity.AffinityGroup; import org.apache.cloudstack.affinity.AffinityGroup;
@ -63,6 +65,7 @@ import org.apache.cloudstack.api.response.AutoScaleVmProfileResponse;
import org.apache.cloudstack.api.response.BackupOfferingResponse; import org.apache.cloudstack.api.response.BackupOfferingResponse;
import org.apache.cloudstack.api.response.BackupResponse; import org.apache.cloudstack.api.response.BackupResponse;
import org.apache.cloudstack.api.response.BackupScheduleResponse; import org.apache.cloudstack.api.response.BackupScheduleResponse;
import org.apache.cloudstack.api.response.BucketResponse;
import org.apache.cloudstack.api.response.CapabilityResponse; import org.apache.cloudstack.api.response.CapabilityResponse;
import org.apache.cloudstack.api.response.CapacityResponse; import org.apache.cloudstack.api.response.CapacityResponse;
import org.apache.cloudstack.api.response.ClusterResponse; import org.apache.cloudstack.api.response.ClusterResponse;
@ -119,6 +122,7 @@ import org.apache.cloudstack.api.response.NetworkResponse;
import org.apache.cloudstack.api.response.NicExtraDhcpOptionResponse; import org.apache.cloudstack.api.response.NicExtraDhcpOptionResponse;
import org.apache.cloudstack.api.response.NicResponse; import org.apache.cloudstack.api.response.NicResponse;
import org.apache.cloudstack.api.response.NicSecondaryIpResponse; 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.OvsProviderResponse;
import org.apache.cloudstack.api.response.PhysicalNetworkResponse; import org.apache.cloudstack.api.response.PhysicalNetworkResponse;
import org.apache.cloudstack.api.response.PodResponse; import org.apache.cloudstack.api.response.PodResponse;
@ -196,10 +200,14 @@ import org.apache.cloudstack.network.lb.ApplicationLoadBalancerRule;
import org.apache.cloudstack.region.PortableIp; import org.apache.cloudstack.region.PortableIp;
import org.apache.cloudstack.region.PortableIpRange; import org.apache.cloudstack.region.PortableIpRange;
import org.apache.cloudstack.region.Region; import org.apache.cloudstack.region.Region;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreDao;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreVO;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.storage.object.Bucket;
import org.apache.cloudstack.storage.object.ObjectStore;
import org.apache.cloudstack.usage.Usage; import org.apache.cloudstack.usage.Usage;
import org.apache.cloudstack.usage.UsageService; import org.apache.cloudstack.usage.UsageService;
import org.apache.cloudstack.usage.UsageTypes; import org.apache.cloudstack.usage.UsageTypes;
@ -263,7 +271,6 @@ import com.cloud.gpu.GPU;
import com.cloud.host.ControlState; import com.cloud.host.ControlState;
import com.cloud.host.Host; import com.cloud.host.Host;
import com.cloud.host.HostVO; import com.cloud.host.HostVO;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.hypervisor.HypervisorCapabilities; import com.cloud.hypervisor.HypervisorCapabilities;
import com.cloud.network.GuestVlan; import com.cloud.network.GuestVlan;
import com.cloud.network.GuestVlanRange; import com.cloud.network.GuestVlanRange;
@ -470,6 +477,9 @@ public class ApiResponseHelper implements ResponseGenerator {
@Inject @Inject
UserDataDao userDataDao; UserDataDao userDataDao;
@Inject
ObjectStoreDao _objectStoreDao;
@Override @Override
public UserResponse createUserResponse(User user) { public UserResponse createUserResponse(User user) {
UserAccountJoinVO vUser = ApiDBUtils.newUserView(user); UserAccountJoinVO vUser = ApiDBUtils.newUserView(user);
@ -4309,6 +4319,10 @@ public class ApiResponseHelper implements ResponseGenerator {
} }
usageRecResponse.setDescription(builder.toString()); usageRecResponse.setDescription(builder.toString());
} }
} else if (usageRecord.getUsageType() == UsageTypes.BUCKET) {
BucketVO bucket = _entityMgr.findByIdIncludingRemoved(BucketVO.class, usageRecord.getUsageId().toString());
usageRecResponse.setUsageId(bucket.getUuid());
usageRecResponse.setResourceName(bucket.getName());
} }
if(resourceTagResponseMap != null && resourceTagResponseMap.get(resourceId + ":" + resourceType) != null) { if(resourceTagResponseMap != null && resourceTagResponseMap.get(resourceId + ":" + resourceType) != null) {
usageRecResponse.setTags(resourceTagResponseMap.get(resourceId + ":" + resourceType)); usageRecResponse.setTags(resourceTagResponseMap.get(resourceId + ":" + resourceType));
@ -5109,4 +5123,40 @@ public class ApiResponseHelper implements ResponseGenerator {
return quarantinedIpsResponse; return quarantinedIpsResponse;
} }
public ObjectStoreResponse createObjectStoreResponse(ObjectStore os) {
ObjectStoreResponse objectStoreResponse = new ObjectStoreResponse();
objectStoreResponse.setId(os.getUuid());
objectStoreResponse.setName(os.getName());
objectStoreResponse.setProviderName(os.getProviderName());
objectStoreResponse.setObjectName("objectstore");
return objectStoreResponse;
}
@Override
public BucketResponse createBucketResponse(Bucket bucket) {
BucketResponse bucketResponse = new BucketResponse();
bucketResponse.setName(bucket.getName());
bucketResponse.setId(bucket.getUuid());
bucketResponse.setCreated(bucket.getCreated());
bucketResponse.setState(bucket.getState());
bucketResponse.setSize(bucket.getSize());
if(bucket.getQuota() != null) {
bucketResponse.setQuota(bucket.getQuota());
}
bucketResponse.setVersioning(bucket.isVersioning());
bucketResponse.setEncryption(bucket.isEncryption());
bucketResponse.setObjectLock(bucket.isObjectLock());
bucketResponse.setPolicy(bucket.getPolicy());
bucketResponse.setBucketURL(bucket.getBucketURL());
bucketResponse.setAccessKey(bucket.getAccessKey());
bucketResponse.setSecretKey(bucket.getSecretKey());
ObjectStoreVO objectStoreVO = _objectStoreDao.findById(bucket.getObjectStoreId());
bucketResponse.setObjectStoragePoolId(objectStoreVO.getUuid());
bucketResponse.setObjectStoragePool(objectStoreVO.getName());
bucketResponse.setObjectName("bucket");
bucketResponse.setProvider(objectStoreVO.getProviderName());
populateAccount(bucketResponse, bucket.getAccountId());
return bucketResponse;
}
} }

View File

@ -83,6 +83,7 @@ import org.apache.cloudstack.api.command.admin.router.GetRouterHealthCheckResult
import org.apache.cloudstack.api.command.admin.router.ListRoutersCmd; import org.apache.cloudstack.api.command.admin.router.ListRoutersCmd;
import org.apache.cloudstack.api.command.admin.snapshot.ListSnapshotsCmdByAdmin; import org.apache.cloudstack.api.command.admin.snapshot.ListSnapshotsCmdByAdmin;
import org.apache.cloudstack.api.command.admin.storage.ListImageStoresCmd; 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.ListSecondaryStagingStoresCmd;
import org.apache.cloudstack.api.command.admin.storage.ListStoragePoolsCmd; 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.ListStorageTagsCmd;
@ -126,6 +127,7 @@ import org.apache.cloudstack.api.response.InstanceGroupResponse;
import org.apache.cloudstack.api.response.IpQuarantineResponse; import org.apache.cloudstack.api.response.IpQuarantineResponse;
import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.ManagementServerResponse; 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.ProjectAccountResponse;
import org.apache.cloudstack.api.response.ProjectInvitationResponse; import org.apache.cloudstack.api.response.ProjectInvitationResponse;
import org.apache.cloudstack.api.response.ProjectResponse; import org.apache.cloudstack.api.response.ProjectResponse;
@ -156,6 +158,8 @@ import org.apache.cloudstack.framework.config.Configurable;
import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO; import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO;
import org.apache.cloudstack.query.QueryService; import org.apache.cloudstack.query.QueryService;
import org.apache.cloudstack.resourcedetail.dao.DiskOfferingDetailsDao; import org.apache.cloudstack.resourcedetail.dao.DiskOfferingDetailsDao;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreDao;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreVO;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
@ -261,6 +265,7 @@ import com.cloud.server.ResourceTag.ResourceObjectType;
import com.cloud.service.ServiceOfferingVO; import com.cloud.service.ServiceOfferingVO;
import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.service.dao.ServiceOfferingDao;
import com.cloud.service.dao.ServiceOfferingDetailsDao; import com.cloud.service.dao.ServiceOfferingDetailsDao;
import com.cloud.storage.BucketVO;
import com.cloud.storage.DataStoreRole; import com.cloud.storage.DataStoreRole;
import com.cloud.storage.DiskOfferingVO; import com.cloud.storage.DiskOfferingVO;
import com.cloud.storage.ScopeType; import com.cloud.storage.ScopeType;
@ -275,6 +280,7 @@ import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.Volume; import com.cloud.storage.Volume;
import com.cloud.storage.VolumeApiServiceImpl; import com.cloud.storage.VolumeApiServiceImpl;
import com.cloud.storage.VolumeVO; import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.BucketDao;
import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.storage.dao.DiskOfferingDao;
import com.cloud.storage.dao.StoragePoolTagsDao; import com.cloud.storage.dao.StoragePoolTagsDao;
import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VMTemplateDao;
@ -310,6 +316,8 @@ import com.cloud.vm.VmDetailConstants;
import com.cloud.vm.dao.DomainRouterDao; import com.cloud.vm.dao.DomainRouterDao;
import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.VMInstanceDao; import com.cloud.vm.dao.VMInstanceDao;
import org.apache.cloudstack.api.command.user.bucket.ListBucketsCmd;
import org.apache.cloudstack.api.response.BucketResponse;
import static com.cloud.vm.VmDetailConstants.SSH_PUBLIC_KEY; import static com.cloud.vm.VmDetailConstants.SSH_PUBLIC_KEY;
@ -543,6 +551,12 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
@Inject @Inject
private SnapshotJoinDao snapshotJoinDao; private SnapshotJoinDao snapshotJoinDao;
@Inject
private ObjectStoreDao objectStoreDao;
@Inject
private BucketDao bucketDao;
@Inject @Inject
EntityManager entityManager; EntityManager entityManager;
@ -5030,6 +5044,158 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
return new Pair<>(snapshots, count); return new Pair<>(snapshots, count);
} }
public ListResponse<ObjectStoreResponse> searchForObjectStores(ListObjectStoragePoolsCmd cmd) {
Pair<List<ObjectStoreVO>, Integer> result = searchForObjectStoresInternal(cmd);
ListResponse<ObjectStoreResponse> response = new ListResponse<ObjectStoreResponse>();
List<ObjectStoreResponse> poolResponses = ViewResponseHelper.createObjectStoreResponse(result.first().toArray(new ObjectStoreVO[result.first().size()]));
response.setResponses(poolResponses, result.second());
return response;
}
private Pair<List<ObjectStoreVO>, Integer> searchForObjectStoresInternal(ListObjectStoragePoolsCmd cmd) {
Object id = cmd.getId();
Object name = cmd.getStoreName();
String provider = cmd.getProvider();
Object keyword = cmd.getKeyword();
Long startIndex = cmd.getStartIndex();
Long pageSize = cmd.getPageSizeVal();
Filter searchFilter = new Filter(ObjectStoreVO.class, "id", Boolean.TRUE, startIndex, pageSize);
SearchBuilder<ObjectStoreVO> sb = objectStoreDao.createSearchBuilder();
sb.select(null, Func.DISTINCT, sb.entity().getId()); // select distinct
// ids
sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ);
sb.and("name", sb.entity().getName(), SearchCriteria.Op.EQ);
sb.and("provider", sb.entity().getProviderName(), SearchCriteria.Op.EQ);
SearchCriteria<ObjectStoreVO> sc = sb.create();
if (keyword != null) {
SearchCriteria<ObjectStoreVO> ssc = objectStoreDao.createSearchCriteria();
ssc.addOr("name", SearchCriteria.Op.LIKE, "%" + keyword + "%");
ssc.addOr("providerName", SearchCriteria.Op.LIKE, "%" + keyword + "%");
sc.addAnd("name", SearchCriteria.Op.SC, ssc);
}
if (id != null) {
sc.setParameters("id", id);
}
if (name != null) {
sc.setParameters("name", name);
}
if (provider != null) {
sc.setParameters("provider", provider);
}
// search Store details by ids
Pair<List<ObjectStoreVO>, Integer> uniqueStorePair = objectStoreDao.searchAndCount(sc, searchFilter);
Integer count = uniqueStorePair.second();
if (count.intValue() == 0) {
// empty result
return uniqueStorePair;
}
List<ObjectStoreVO> uniqueStores = uniqueStorePair.first();
Long[] osIds = new Long[uniqueStores.size()];
int i = 0;
for (ObjectStoreVO v : uniqueStores) {
osIds[i++] = v.getId();
}
List<ObjectStoreVO> objectStores = objectStoreDao.searchByIds(osIds);
return new Pair<>(objectStores, count);
}
@Override
public ListResponse<BucketResponse> searchForBuckets(ListBucketsCmd listBucketsCmd) {
List<BucketVO> buckets = searchForBucketsInternal(listBucketsCmd);
List<BucketResponse> bucketResponses = new ArrayList<>();
for (BucketVO bucket : buckets) {
bucketResponses.add(responseGenerator.createBucketResponse(bucket));
}
ListResponse<BucketResponse> response = new ListResponse<>();
response.setResponses(bucketResponses, bucketResponses.size());
return response;
}
private List<BucketVO> searchForBucketsInternal(ListBucketsCmd cmd) {
Long id = cmd.getId();
String name = cmd.getBucketName();
Long storeId = cmd.getObjectStorageId();
String keyword = cmd.getKeyword();
Long startIndex = cmd.getStartIndex();
Long pageSize = cmd.getPageSizeVal();
Account caller = CallContext.current().getCallingAccount();
List<Long> permittedAccounts = new ArrayList<Long>();
// Verify parameters
if (id != null) {
BucketVO bucket = bucketDao.findById(id);
if (bucket != null) {
accountMgr.checkAccess(CallContext.current().getCallingAccount(), null, true, bucket);
}
}
List<Long> ids = getIdsListFromCmd(cmd.getId(), cmd.getIds());
Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, ListProjectResourcesCriteria>(cmd.getDomainId(),
cmd.isRecursive(), null);
accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false);
Long domainId = domainIdRecursiveListProject.first();
Boolean isRecursive = domainIdRecursiveListProject.second();
ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third();
Filter searchFilter = new Filter(BucketVO.class, "id", Boolean.TRUE, startIndex, pageSize);
SearchBuilder<BucketVO> sb = bucketDao.createSearchBuilder();
accountMgr.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
sb.select(null, Func.DISTINCT, sb.entity().getId()); // select distinct
// ids
sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ);
sb.and("name", sb.entity().getName(), SearchCriteria.Op.EQ);
SearchCriteria<BucketVO> sc = sb.create();
accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
if (keyword != null) {
SearchCriteria<BucketVO> ssc = bucketDao.createSearchCriteria();
ssc.addOr("name", SearchCriteria.Op.LIKE, "%" + keyword + "%");
ssc.addOr("state", SearchCriteria.Op.LIKE, "%" + keyword + "%");
sc.addAnd("name", SearchCriteria.Op.SC, ssc);
}
if (id != null) {
sc.setParameters("id", id);
}
if (name != null) {
sc.setParameters("name", name);
}
setIdsListToSearchCriteria(sc, ids);
// search Volume details by ids
Pair<List<BucketVO>, Integer> uniqueBktPair = bucketDao.searchAndCount(sc, searchFilter);
Integer count = uniqueBktPair.second();
if (count.intValue() == 0) {
// empty result
return uniqueBktPair.first();
}
List<BucketVO> uniqueBkts = uniqueBktPair.first();
Long[] bktIds = new Long[uniqueBkts.size()];
int i = 0;
for (BucketVO b : uniqueBkts) {
bktIds[i++] = b.getId();
}
return bucketDao.searchByIds(bktIds);
}
@Override @Override
public String getConfigComponentName() { public String getConfigComponentName() {
return QueryService.class.getSimpleName(); return QueryService.class.getSimpleName();

View File

@ -21,6 +21,7 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.HashMap; import java.util.HashMap;
import java.util.Hashtable;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -43,6 +44,7 @@ import org.apache.cloudstack.api.response.HostResponse;
import org.apache.cloudstack.api.response.HostTagResponse; import org.apache.cloudstack.api.response.HostTagResponse;
import org.apache.cloudstack.api.response.ImageStoreResponse; import org.apache.cloudstack.api.response.ImageStoreResponse;
import org.apache.cloudstack.api.response.InstanceGroupResponse; import org.apache.cloudstack.api.response.InstanceGroupResponse;
import org.apache.cloudstack.api.response.ObjectStoreResponse;
import org.apache.cloudstack.api.response.ProjectAccountResponse; import org.apache.cloudstack.api.response.ProjectAccountResponse;
import org.apache.cloudstack.api.response.ProjectInvitationResponse; import org.apache.cloudstack.api.response.ProjectInvitationResponse;
import org.apache.cloudstack.api.response.ProjectResponse; import org.apache.cloudstack.api.response.ProjectResponse;
@ -58,6 +60,7 @@ import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.api.response.VolumeResponse; import org.apache.cloudstack.api.response.VolumeResponse;
import org.apache.cloudstack.api.response.ZoneResponse; import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreVO;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import com.cloud.api.ApiDBUtils; import com.cloud.api.ApiDBUtils;
@ -659,4 +662,20 @@ public class ViewResponseHelper {
return new ArrayList<AffinityGroupResponse>(vrDataList.values()); return new ArrayList<AffinityGroupResponse>(vrDataList.values());
} }
public static List<ObjectStoreResponse> createObjectStoreResponse(ObjectStoreVO[] stores) {
Hashtable<Long, ObjectStoreResponse> storeList = new Hashtable<Long, ObjectStoreResponse>();
// Initialise the storeList with the input data
for (ObjectStoreVO store : stores) {
ObjectStoreResponse storeData = storeList.get(store.getId());
if (storeData == null) {
// first time encountering this store
storeData = ApiDBUtils.newObjectStoreResponse(store);
} else {
// update tags
storeData = ApiDBUtils.fillObjectStoreDetails(storeData, store);
}
storeList.put(store.getId(), storeData);
}
return new ArrayList<>(storeList.values());
}
} }

View File

@ -209,14 +209,17 @@ import org.apache.cloudstack.api.command.admin.router.UpgradeRouterTemplateCmd;
import org.apache.cloudstack.api.command.admin.snapshot.ListSnapshotsCmdByAdmin; import org.apache.cloudstack.api.command.admin.snapshot.ListSnapshotsCmdByAdmin;
import org.apache.cloudstack.api.command.admin.storage.AddImageStoreCmd; import org.apache.cloudstack.api.command.admin.storage.AddImageStoreCmd;
import org.apache.cloudstack.api.command.admin.storage.AddImageStoreS3CMD; import org.apache.cloudstack.api.command.admin.storage.AddImageStoreS3CMD;
import org.apache.cloudstack.api.command.admin.storage.AddObjectStoragePoolCmd;
import org.apache.cloudstack.api.command.admin.storage.CancelPrimaryStorageMaintenanceCmd; import org.apache.cloudstack.api.command.admin.storage.CancelPrimaryStorageMaintenanceCmd;
import org.apache.cloudstack.api.command.admin.storage.CreateSecondaryStagingStoreCmd; 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.CreateStoragePoolCmd;
import org.apache.cloudstack.api.command.admin.storage.DeleteImageStoreCmd; 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.DeletePoolCmd;
import org.apache.cloudstack.api.command.admin.storage.DeleteSecondaryStagingStoreCmd; import org.apache.cloudstack.api.command.admin.storage.DeleteSecondaryStagingStoreCmd;
import org.apache.cloudstack.api.command.admin.storage.FindStoragePoolsForMigrationCmd; import org.apache.cloudstack.api.command.admin.storage.FindStoragePoolsForMigrationCmd;
import org.apache.cloudstack.api.command.admin.storage.ListImageStoresCmd; 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.ListSecondaryStagingStoresCmd;
import org.apache.cloudstack.api.command.admin.storage.ListStoragePoolsCmd; import org.apache.cloudstack.api.command.admin.storage.ListStoragePoolsCmd;
import org.apache.cloudstack.api.command.admin.storage.ListStorageProvidersCmd; import org.apache.cloudstack.api.command.admin.storage.ListStorageProvidersCmd;
@ -227,6 +230,7 @@ import org.apache.cloudstack.api.command.admin.storage.PreparePrimaryStorageForM
import org.apache.cloudstack.api.command.admin.storage.SyncStoragePoolCmd; import org.apache.cloudstack.api.command.admin.storage.SyncStoragePoolCmd;
import org.apache.cloudstack.api.command.admin.storage.UpdateCloudToUseObjectStoreCmd; import org.apache.cloudstack.api.command.admin.storage.UpdateCloudToUseObjectStoreCmd;
import org.apache.cloudstack.api.command.admin.storage.UpdateImageStoreCmd; import org.apache.cloudstack.api.command.admin.storage.UpdateImageStoreCmd;
import org.apache.cloudstack.api.command.admin.storage.UpdateObjectStoragePoolCmd;
import org.apache.cloudstack.api.command.admin.storage.UpdateStorageCapabilitiesCmd; import org.apache.cloudstack.api.command.admin.storage.UpdateStorageCapabilitiesCmd;
import org.apache.cloudstack.api.command.admin.storage.UpdateStoragePoolCmd; import org.apache.cloudstack.api.command.admin.storage.UpdateStoragePoolCmd;
import org.apache.cloudstack.api.command.admin.swift.AddSwiftCmd; import org.apache.cloudstack.api.command.admin.swift.AddSwiftCmd;
@ -360,6 +364,10 @@ import org.apache.cloudstack.api.command.user.autoscale.UpdateAutoScalePolicyCmd
import org.apache.cloudstack.api.command.user.autoscale.UpdateAutoScaleVmGroupCmd; import org.apache.cloudstack.api.command.user.autoscale.UpdateAutoScaleVmGroupCmd;
import org.apache.cloudstack.api.command.user.autoscale.UpdateAutoScaleVmProfileCmd; import org.apache.cloudstack.api.command.user.autoscale.UpdateAutoScaleVmProfileCmd;
import org.apache.cloudstack.api.command.user.autoscale.UpdateConditionCmd; import org.apache.cloudstack.api.command.user.autoscale.UpdateConditionCmd;
import org.apache.cloudstack.api.command.user.bucket.CreateBucketCmd;
import org.apache.cloudstack.api.command.user.bucket.DeleteBucketCmd;
import org.apache.cloudstack.api.command.user.bucket.ListBucketsCmd;
import org.apache.cloudstack.api.command.user.bucket.UpdateBucketCmd;
import org.apache.cloudstack.api.command.user.config.ListCapabilitiesCmd; import org.apache.cloudstack.api.command.user.config.ListCapabilitiesCmd;
import org.apache.cloudstack.api.command.user.consoleproxy.CreateConsoleEndpointCmd; import org.apache.cloudstack.api.command.user.consoleproxy.CreateConsoleEndpointCmd;
import org.apache.cloudstack.api.command.user.event.ArchiveEventsCmd; import org.apache.cloudstack.api.command.user.event.ArchiveEventsCmd;
@ -3908,6 +3916,16 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
cmdList.add(DeleteUserDataCmd.class); cmdList.add(DeleteUserDataCmd.class);
cmdList.add(ListUserDataCmd.class); cmdList.add(ListUserDataCmd.class);
cmdList.add(LinkUserDataToTemplateCmd.class); cmdList.add(LinkUserDataToTemplateCmd.class);
//object store APIs
cmdList.add(AddObjectStoragePoolCmd.class);
cmdList.add(ListObjectStoragePoolsCmd.class);
cmdList.add(UpdateObjectStoragePoolCmd.class);
cmdList.add(DeleteObjectStoragePoolCmd.class);
cmdList.add(CreateBucketCmd.class);
cmdList.add(UpdateBucketCmd.class);
cmdList.add(DeleteBucketCmd.class);
cmdList.add(ListBucketsCmd.class);
return cmdList; return cmdList;
} }

View File

@ -54,9 +54,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.CreateSecondaryStagingStoreCmd;
import org.apache.cloudstack.api.command.admin.storage.CreateStoragePoolCmd; 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.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.DeletePoolCmd;
import org.apache.cloudstack.api.command.admin.storage.DeleteSecondaryStagingStoreCmd; 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.SyncStoragePoolCmd;
import org.apache.cloudstack.api.command.admin.storage.UpdateObjectStoragePoolCmd;
import org.apache.cloudstack.api.command.admin.storage.UpdateStoragePoolCmd; import org.apache.cloudstack.api.command.admin.storage.UpdateStoragePoolCmd;
import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope; import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
@ -104,6 +106,9 @@ import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao;
import org.apache.cloudstack.storage.datastore.db.ImageStoreObjectDownloadDao; import org.apache.cloudstack.storage.datastore.db.ImageStoreObjectDownloadDao;
import org.apache.cloudstack.storage.datastore.db.ImageStoreObjectDownloadVO; import org.apache.cloudstack.storage.datastore.db.ImageStoreObjectDownloadVO;
import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreDao;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreDetailsDao;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreVO;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO; import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
@ -115,6 +120,8 @@ import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao; import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreVO; import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreVO;
import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity; import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity;
import org.apache.cloudstack.storage.object.ObjectStore;
import org.apache.cloudstack.storage.object.ObjectStoreEntity;
import org.apache.cloudstack.storage.to.VolumeObjectTO; import org.apache.cloudstack.storage.to.VolumeObjectTO;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.time.DateUtils; import org.apache.commons.lang.time.DateUtils;
@ -192,6 +199,7 @@ import com.cloud.service.dao.ServiceOfferingDetailsDao;
import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.ImageFormat;
import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.storage.Volume.Type; import com.cloud.storage.Volume.Type;
import com.cloud.storage.dao.BucketDao;
import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.storage.dao.DiskOfferingDao;
import com.cloud.storage.dao.SnapshotDao; import com.cloud.storage.dao.SnapshotDao;
import com.cloud.storage.dao.StoragePoolHostDao; import com.cloud.storage.dao.StoragePoolHostDao;
@ -353,6 +361,14 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
@Inject @Inject
protected UserVmManager userVmManager; protected UserVmManager userVmManager;
@Inject
protected ObjectStoreDao _objectStoreDao;
@Inject
protected ObjectStoreDetailsDao _objectStoreDetailsDao;
@Inject
protected BucketDao _bucketDao;
protected List<StoragePoolDiscoverer> _discoverers; protected List<StoragePoolDiscoverer> _discoverers;
public List<StoragePoolDiscoverer> getDiscoverers() { public List<StoragePoolDiscoverer> getDiscoverers() {
@ -3633,4 +3649,124 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
volumeTO.setIopsWriteRate(getDiskIopsWriteRate(offering, diskOffering)); volumeTO.setIopsWriteRate(getDiskIopsWriteRate(offering, diskOffering));
} }
@Override
@ActionEvent(eventType = EventTypes.EVENT_OBJECT_STORE_CREATE, eventDescription = "creating object storage")
public ObjectStore discoverObjectStore(String name, String url, String providerName, Map details)
throws IllegalArgumentException, InvalidParameterValueException {
DataStoreProvider storeProvider = _dataStoreProviderMgr.getDataStoreProvider(providerName);
if (storeProvider == null) {
throw new InvalidParameterValueException("can't find object store provider: " + providerName);
}
// Check Unique object store name
ObjectStoreVO objectStore = _objectStoreDao.findByName(name);
if (objectStore != null) {
throw new InvalidParameterValueException("The object store with name " + name + " already exists, try creating with another name");
}
try {
// Check URL
UriUtils.validateUrl(url);
} catch (final Exception e) {
throw new InvalidParameterValueException(url + " is not a valid URL");
}
// Check Unique object store url
ObjectStoreVO objectStoreUrl = _objectStoreDao.findByUrl(url);
if (objectStoreUrl != null) {
throw new InvalidParameterValueException("The object store with url " + url + " already exists");
}
Map<String, Object> params = new HashMap<>();
params.put("url", url);
params.put("name", name);
params.put("providerName", storeProvider.getName());
params.put("role", DataStoreRole.Object);
params.put("details", details);
DataStoreLifeCycle lifeCycle = storeProvider.getDataStoreLifeCycle();
DataStore store;
try {
store = lifeCycle.initialize(params);
} catch (Exception e) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Failed to add object store: " + e.getMessage(), e);
}
throw new CloudRuntimeException("Failed to add object store: " + e.getMessage(), e);
}
return (ObjectStore)_dataStoreMgr.getDataStore(store.getId(), DataStoreRole.Object);
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_OBJECT_STORE_DELETE, eventDescription = "deleting object storage")
public boolean deleteObjectStore(DeleteObjectStoragePoolCmd cmd) {
final long storeId = cmd.getId();
// Verify that object store exists
ObjectStoreVO store = _objectStoreDao.findById(storeId);
if (store == null) {
throw new InvalidParameterValueException("Object store with id " + storeId + " doesn't exist");
}
// Verify that there are no buckets in the store
List<BucketVO> buckets = _bucketDao.listByObjectStoreId(storeId);
if(buckets != null && buckets.size() > 0) {
throw new InvalidParameterValueException("Cannot delete object store with buckets");
}
// ready to delete
Transaction.execute(new TransactionCallbackNoReturn() {
@Override
public void doInTransactionWithoutResult(TransactionStatus status) {
_objectStoreDetailsDao.deleteDetails(storeId);
_objectStoreDao.remove(storeId);
}
});
s_logger.debug("Successfully deleted object store with Id: "+storeId);
return true;
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_OBJECT_STORE_UPDATE, eventDescription = "update object storage")
public ObjectStore updateObjectStore(Long id, UpdateObjectStoragePoolCmd cmd) {
// Input validation
ObjectStoreVO objectStoreVO = _objectStoreDao.findById(id);
if (objectStoreVO == null) {
throw new IllegalArgumentException("Unable to find object store with ID: " + id);
}
if(cmd.getUrl() != null ) {
String url = cmd.getUrl();
try {
// Check URL
UriUtils.validateUrl(url);
} catch (final Exception e) {
throw new InvalidParameterValueException(url + " is not a valid URL");
}
ObjectStoreEntity objectStore = (ObjectStoreEntity)_dataStoreMgr.getDataStore(objectStoreVO.getId(), DataStoreRole.Object);
String oldUrl = objectStoreVO.getUrl();
objectStoreVO.setUrl(url);
_objectStoreDao.update(id, objectStoreVO);
//Update URL and check access
try {
objectStore.listBuckets();
} catch (Exception e) {
//Revert to old URL on failure
objectStoreVO.setUrl(oldUrl);
_objectStoreDao.update(id, objectStoreVO);
throw new IllegalArgumentException("Unable to access Object Storage with URL: " + cmd.getUrl());
}
}
if(cmd.getName() != null ) {
objectStoreVO.setName(cmd.getName());
}
_objectStoreDao.update(id, objectStoreVO);
s_logger.debug("Successfully updated object store with Id: "+id);
return objectStoreVO;
}
} }

View File

@ -197,6 +197,7 @@ public final class AnnotationManagerImpl extends ManagerBase implements Annotati
s_typeMap.put(EntityType.SYSTEM_VM, ApiCommandResourceType.SystemVm); s_typeMap.put(EntityType.SYSTEM_VM, ApiCommandResourceType.SystemVm);
s_typeMap.put(EntityType.AUTOSCALE_VM_GROUP, ApiCommandResourceType.AutoScaleVmGroup); s_typeMap.put(EntityType.AUTOSCALE_VM_GROUP, ApiCommandResourceType.AutoScaleVmGroup);
s_typeMap.put(EntityType.MANAGEMENT_SERVER, ApiCommandResourceType.Host); s_typeMap.put(EntityType.MANAGEMENT_SERVER, ApiCommandResourceType.Host);
s_typeMap.put(EntityType.OBJECT_STORAGE, ApiCommandResourceType.ObjectStore);
} }
public List<KubernetesClusterHelper> getKubernetesClusterHelpers() { public List<KubernetesClusterHelper> getKubernetesClusterHelpers() {

View File

@ -0,0 +1,304 @@
// 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.amazonaws.services.s3.internal.BucketNameUtils;
import com.amazonaws.services.s3.model.IllegalBucketNameException;
import com.cloud.event.ActionEvent;
import com.cloud.event.EventTypes;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.storage.BucketVO;
import com.cloud.storage.DataStoreRole;
import com.cloud.storage.dao.BucketDao;
import com.cloud.usage.BucketStatisticsVO;
import com.cloud.usage.dao.BucketStatisticsDao;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.concurrency.NamedThreadFactory;
import com.cloud.utils.db.GlobalLock;
import com.cloud.utils.exception.CloudRuntimeException;
import org.apache.cloudstack.api.command.user.bucket.CreateBucketCmd;
import org.apache.cloudstack.api.command.user.bucket.UpdateBucketCmd;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable;
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreDao;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreVO;
import org.apache.log4j.Logger;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class BucketApiServiceImpl extends ManagerBase implements BucketApiService, Configurable {
private final static Logger s_logger = Logger.getLogger(BucketApiServiceImpl.class);
@Inject
private ObjectStoreDao _objectStoreDao;
@Inject
DataStoreManager _dataStoreMgr;
@Inject
private BucketDao _bucketDao;
@Inject
private AccountManager _accountMgr;
@Inject
private BucketStatisticsDao _bucketStatisticsDao;
private ScheduledExecutorService _executor = null;
private static final int ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION = 3;
protected BucketApiServiceImpl() {
}
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
_executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("Bucket-Usage"));
return true;
}
@Override
public boolean start() {
_executor.scheduleWithFixedDelay(new BucketUsageTask(), 60L, 3600L, TimeUnit.SECONDS);
return true;
}
@Override
public boolean stop() {
_executor.shutdown();
return true;
}
@Override
public String getConfigComponentName() {
return BucketApiService.class.getSimpleName();
}
@Override
public ConfigKey<?>[] getConfigKeys() {
return new ConfigKey<?>[] {
};
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_BUCKET_CREATE, eventDescription = "creating bucket", create = true)
public Bucket allocBucket(CreateBucketCmd cmd) {
try {
BucketNameUtils.validateBucketName(cmd.getBucketName());
} catch (IllegalBucketNameException e) {
s_logger.error("Invalid Bucket Name: " +cmd.getBucketName(), e);
throw new InvalidParameterValueException("Invalid Bucket Name: "+e.getMessage());
}
//ToDo check bucket exists
long ownerId = cmd.getEntityOwnerId();
Account owner = _accountMgr.getActiveAccountById(ownerId);
ObjectStoreVO objectStoreVO = _objectStoreDao.findById(cmd.getObjectStoragePoolId());
ObjectStoreEntity objectStore = (ObjectStoreEntity)_dataStoreMgr.getDataStore(objectStoreVO.getId(), DataStoreRole.Object);
try {
if(!objectStore.createUser(ownerId)) {
s_logger.error("Failed to create user in objectstore "+ objectStore.getName());
return null;
}
} catch (CloudRuntimeException e) {
s_logger.error("Error while checking object store user.", e);
return null;
}
BucketVO bucket = new BucketVO(ownerId, owner.getDomainId(), cmd.getObjectStoragePoolId(), cmd.getBucketName(), cmd.getQuota(),
cmd.isVersioning(), cmd.isEncryption(), cmd.isObjectLocking(), cmd.getPolicy());
_bucketDao.persist(bucket);
return bucket;
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_BUCKET_CREATE, eventDescription = "creating bucket", async = true)
public Bucket createBucket(CreateBucketCmd cmd) {
ObjectStoreVO objectStoreVO = _objectStoreDao.findById(cmd.getObjectStoragePoolId());
ObjectStoreEntity objectStore = (ObjectStoreEntity)_dataStoreMgr.getDataStore(objectStoreVO.getId(), DataStoreRole.Object);
BucketVO bucket = _bucketDao.findById(cmd.getEntityId());
boolean objectLock = false;
boolean bucketCreated = false;
if(cmd.isObjectLocking()) {
objectLock = true;
}
try {
objectStore.createBucket(bucket, objectLock);
bucketCreated = true;
if (cmd.isVersioning()) {
objectStore.setBucketVersioning(bucket.getName());
}
if (cmd.isEncryption()) {
objectStore.setBucketEncryption(bucket.getName());
}
if (cmd.getQuota() != null) {
objectStore.setQuota(bucket.getName(), cmd.getQuota());
}
if (cmd.getPolicy() != null) {
objectStore.setBucketPolicy(bucket.getName(), cmd.getPolicy());
}
bucket.setState(Bucket.State.Created);
_bucketDao.update(bucket.getId(), bucket);
} catch (Exception e) {
s_logger.debug("Failed to create bucket with name: "+bucket.getName(), e);
if(bucketCreated) {
objectStore.deleteBucket(bucket.getName());
}
_bucketDao.remove(bucket.getId());
throw new CloudRuntimeException("Failed to create bucket with name: "+bucket.getName()+". "+e.getMessage());
}
return bucket;
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_BUCKET_DELETE, eventDescription = "deleting bucket")
public boolean deleteBucket(long bucketId, Account caller) {
Bucket bucket = _bucketDao.findById(bucketId);
if (bucket == null) {
throw new InvalidParameterValueException("Unable to find bucket with ID: " + bucketId);
}
_accountMgr.checkAccess(caller, null, true, bucket);
ObjectStoreVO objectStoreVO = _objectStoreDao.findById(bucket.getObjectStoreId());
ObjectStoreEntity objectStore = (ObjectStoreEntity)_dataStoreMgr.getDataStore(objectStoreVO.getId(), DataStoreRole.Object);
if (objectStore.deleteBucket(bucket.getName())) {
return _bucketDao.remove(bucketId);
}
return false;
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_BUCKET_UPDATE, eventDescription = "updating bucket")
public boolean updateBucket(UpdateBucketCmd cmd, Account caller) {
BucketVO bucket = _bucketDao.findById(cmd.getId());
if (bucket == null) {
throw new InvalidParameterValueException("Unable to find bucket with ID: " + cmd.getId());
}
_accountMgr.checkAccess(caller, null, true, bucket);
ObjectStoreVO objectStoreVO = _objectStoreDao.findById(bucket.getObjectStoreId());
ObjectStoreEntity objectStore = (ObjectStoreEntity)_dataStoreMgr.getDataStore(objectStoreVO.getId(), DataStoreRole.Object);
try {
if (cmd.getEncryption() != null) {
if (cmd.getEncryption()) {
objectStore.setBucketEncryption(bucket.getName());
} else {
objectStore.deleteBucketEncryption(bucket.getName());
}
bucket.setEncryption(cmd.getEncryption());
}
if (cmd.getVersioning() != null) {
if (cmd.getVersioning()) {
objectStore.setBucketVersioning(bucket.getName());
} else {
objectStore.deleteBucketVersioning(bucket.getName());
}
bucket.setVersioning(cmd.getVersioning());
}
if (cmd.getPolicy() != null) {
objectStore.setBucketPolicy(bucket.getName(), cmd.getPolicy());
bucket.setPolicy(cmd.getPolicy());
}
if (cmd.getQuota() != null) {
objectStore.setQuota(bucket.getName(), cmd.getQuota());
bucket.setQuota(cmd.getQuota());
}
_bucketDao.update(bucket.getId(), bucket);
} catch (Exception e) {
throw new CloudRuntimeException("Error while updating bucket: " +bucket.getName() +". "+e.getMessage());
}
return true;
}
public void getBucketUsage() {
//ToDo track usage one last time when object store or bucket is removed
List<ObjectStoreVO> objectStores = _objectStoreDao.listObjectStores();
for(ObjectStoreVO objectStoreVO: objectStores) {
ObjectStoreEntity objectStore = (ObjectStoreEntity)_dataStoreMgr.getDataStore(objectStoreVO.getId(), DataStoreRole.Object);
Map<String, Long> bucketSizes = objectStore.getAllBucketsUsage();
List<BucketVO> buckets = _bucketDao.listByObjectStoreId(objectStoreVO.getId());
for(BucketVO bucket : buckets) {
Long size = bucketSizes.get(bucket.getName());
if( size != null){
bucket.setSize(size);
_bucketDao.update(bucket.getId(), bucket);
}
}
}
}
private class BucketUsageTask extends ManagedContextRunnable {
public BucketUsageTask() {
}
@Override
protected void runInContext() {
GlobalLock scanLock = GlobalLock.getInternLock("BucketUsage");
try {
if (scanLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION)) {
try {
List<ObjectStoreVO> objectStores = _objectStoreDao.listObjectStores();
for(ObjectStoreVO objectStoreVO: objectStores) {
ObjectStoreEntity objectStore = (ObjectStoreEntity)_dataStoreMgr.getDataStore(objectStoreVO.getId(), DataStoreRole.Object);
Map<String, Long> bucketSizes = objectStore.getAllBucketsUsage();
List<BucketVO> buckets = _bucketDao.listByObjectStoreId(objectStoreVO.getId());
for(BucketVO bucket : buckets) {
Long size = bucketSizes.get(bucket.getName());
if( size != null){
bucket.setSize(size);
_bucketDao.update(bucket.getId(), bucket);
//Update Bucket Usage stats
BucketStatisticsVO bucketStatisticsVO = _bucketStatisticsDao.findBy(bucket.getAccountId(), bucket.getId());
if(bucketStatisticsVO != null) {
bucketStatisticsVO.setSize(size);
_bucketStatisticsDao.update(bucketStatisticsVO.getId(), bucketStatisticsVO);
} else {
bucketStatisticsVO = new BucketStatisticsVO(bucket.getAccountId(), bucket.getId());
bucketStatisticsVO.setSize(size);
_bucketStatisticsDao.persist(bucketStatisticsVO);
}
}
}
}
s_logger.debug("Completed updating bucket usage for all object stores");
} catch (Exception e) {
s_logger.error("Error while fetching bucket usage", e);
} finally {
scanLock.unlock();
}
}
} finally {
scanLock.releaseRef();
}
}
}
}

View File

@ -352,6 +352,7 @@
class="com.cloud.tags.ResourceManagerUtilImpl"/> class="com.cloud.tags.ResourceManagerUtilImpl"/>
<bean id="resourceIconManager" class="com.cloud.resourceicon.ResourceIconManagerImpl" /> <bean id="resourceIconManager" class="com.cloud.resourceicon.ResourceIconManagerImpl" />
<bean id="bucketApiServiceImpl" class="org.apache.cloudstack.storage.object.BucketApiServiceImpl" />
<bean id="VMScheduleManagerImpl" class="org.apache.cloudstack.vm.schedule.VMScheduleManagerImpl" /> <bean id="VMScheduleManagerImpl" class="org.apache.cloudstack.vm.schedule.VMScheduleManagerImpl" />
<bean id="VMSchedulerImpl" class="org.apache.cloudstack.vm.schedule.VMSchedulerImpl"> <bean id="VMSchedulerImpl" class="org.apache.cloudstack.vm.schedule.VMSchedulerImpl">

View File

@ -27,6 +27,8 @@ import com.cloud.network.Network;
import com.cloud.network.VNF; import com.cloud.network.VNF;
import com.cloud.network.dao.NetworkVO; import com.cloud.network.dao.NetworkVO;
import com.cloud.server.ResourceTag; import com.cloud.server.ResourceTag;
import com.cloud.storage.BucketVO;
import com.cloud.storage.dao.BucketDao;
import com.cloud.user.Account; import com.cloud.user.Account;
import com.cloud.user.AccountManager; import com.cloud.user.AccountManager;
import com.cloud.user.AccountVO; import com.cloud.user.AccountVO;
@ -40,12 +42,17 @@ import com.cloud.utils.db.SearchCriteria;
import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine;
import org.apache.cloudstack.acl.SecurityChecker; import org.apache.cloudstack.acl.SecurityChecker;
import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.ApiCommandResourceType;
import org.apache.cloudstack.api.command.admin.storage.ListObjectStoragePoolsCmd;
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.event.ListEventsCmd;
import org.apache.cloudstack.api.command.user.resource.ListDetailOptionsCmd; import org.apache.cloudstack.api.command.user.resource.ListDetailOptionsCmd;
import org.apache.cloudstack.api.response.DetailOptionsResponse; import org.apache.cloudstack.api.response.DetailOptionsResponse;
import org.apache.cloudstack.api.response.EventResponse; import org.apache.cloudstack.api.response.EventResponse;
import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.ObjectStoreResponse;
import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreDao;
import org.apache.cloudstack.storage.datastore.db.ObjectStoreVO;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -66,6 +73,8 @@ import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class) @RunWith(MockitoJUnitRunner.class)
@ -95,6 +104,12 @@ public class QueryManagerImplTest {
@Mock @Mock
SearchCriteria searchCriteriaMock; SearchCriteria searchCriteriaMock;
@Mock
ObjectStoreDao objectStoreDao;
@Mock
BucketDao bucketDao;
private AccountVO account; private AccountVO account;
private UserVO user; private UserVO user;
@ -288,4 +303,41 @@ public class QueryManagerImplTest {
Assert.assertTrue(set.contains(domainId)); Assert.assertTrue(set.contains(domainId));
} }
@Test
public void testSearchForObjectStores() {
ListObjectStoragePoolsCmd cmd = new ListObjectStoragePoolsCmd();
List<ObjectStoreVO> objectStores = new ArrayList<>();
ObjectStoreVO os1 = new ObjectStoreVO();
os1.setName("MinIOStore");
ObjectStoreVO os2 = new ObjectStoreVO();
os1.setName("Simulator");
objectStores.add(os1);
objectStores.add(os2);
SearchBuilder<ObjectStoreVO> sb = Mockito.mock(SearchBuilder.class);
ObjectStoreVO objectStoreVO = Mockito.mock(ObjectStoreVO.class);
when(sb.entity()).thenReturn(objectStoreVO);
when(objectStoreDao.createSearchBuilder()).thenReturn(sb);
when(objectStoreDao.searchAndCount(any(), any())).thenReturn(new Pair<>(objectStores, 2));
ListResponse<ObjectStoreResponse> result = queryManagerImplSpy.searchForObjectStores(cmd);
assertEquals(2, result.getCount().intValue());
}
@Test
public void testSearchForBuckets() {
ListBucketsCmd listBucketsCmd = new ListBucketsCmd();
List<BucketVO> buckets = new ArrayList<>();
BucketVO b1 = new BucketVO();
b1.setName("test-bucket-1");
BucketVO b2 = new BucketVO();
b2.setName("test-bucket-1");
buckets.add(b1);
buckets.add(b2);
SearchBuilder<BucketVO> sb = Mockito.mock(SearchBuilder.class);
BucketVO bucketVO = Mockito.mock(BucketVO.class);
when(sb.entity()).thenReturn(bucketVO);
when(bucketDao.createSearchBuilder()).thenReturn(sb);
when(bucketDao.searchAndCount(any(), any())).thenReturn(new Pair<>(buckets, 2));
queryManagerImplSpy.searchForBuckets(listBucketsCmd);
}
} }

View File

@ -0,0 +1,111 @@
# 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.
""" BVT tests for Bucket Operations"""
#Import Local Modules
from marvin.cloudstackTestCase import *
from nose.plugins.attrib import attr
from marvin.lib.base import (ObjectStoragePool, Bucket)
from marvin.lib.utils import (cleanup_resources)
_multiprocess_shared_ = True
class TestObjectStore(cloudstackTestCase):
def setUp(self):
self.services = self.testClient.getParsedTestDataConfig()
self.apiclient = self.testClient.getApiClient()
self.dbclient = self.testClient.getDbConnection()
self.cleanup = []
return
def tearDown(self):
try:
#Clean up, terminate the created resources
cleanup_resources(self.apiclient, self.cleanup)
except Exception as e:
raise Exception("Warning: Exception during cleanup : %s" % e)
return
@attr(tags=["smoke"], required_hardware="false")
def test_01_create_bucket(self):
"""Test to create bucket in object store
"""
object_store = ObjectStoragePool.create(
self.apiclient,
"testOS-9",
"http://192.168.0.1",
"Simulator",
None
)
self.debug("Created Object Store with ID: %s" % object_store.id)
bucket = Bucket.create(
self.apiclient,
"mybucket",
object_store.id
)
list_buckets_response = Bucket.list(
self.apiclient,
id=bucket.id
)
self.assertNotEqual(
len(list_buckets_response),
0,
"Check List Bucket response"
)
bucket_response = list_buckets_response[0]
self.assertEqual(
object_store.id,
bucket_response.objectstorageid,
"Check object store id of the created Bucket"
)
self.assertEqual(
"mybucket",
bucket_response.name,
"Check Name of the created Bucket"
)
bucket.update(
self.apiclient,
quota=100
)
list_buckets_response_updated = Bucket.list(
self.apiclient,
id=bucket.id
)
bucket_response_updated = list_buckets_response_updated[0]
self.assertEqual(
100,
bucket_response_updated.quota,
"Check quota of the updated bucket"
)
self.cleanup.append(bucket)
self.cleanup.append(object_store)
return

Some files were not shown because too many files have changed in this diff Show More