Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
13360e7
intial commit. Added AddObjectStoragePool API
kishankavala Apr 21, 2023
d6507a7
implement discover object store and object store dao
kishankavala Apr 24, 2023
0681092
fix check style errors
kishankavala Apr 25, 2023
869a70e
DB changes and fixed spring component loading
kishankavala Apr 26, 2023
13b27d2
Implement list storage pools and add storage pool APIs, added minio o…
kishankavala Apr 28, 2023
aa6fe49
Added bucket create and list APIs. Implemented support for these APIs…
kishankavala May 4, 2023
0147c26
minio multi tenancy with policies, bucket operations
kishankavala May 11, 2023
d1242e2
Added UI for Object Storage Pool. Added Update/Delete Object Storage …
kishankavala May 26, 2023
5d69758
UI changes. List bucket URL and credentials
kishankavala May 27, 2023
a7aeb6e
Add Bucket UI
kishankavala May 27, 2023
3048e31
Update bucket fixes and UI changes
kishankavala May 29, 2023
df1ea86
Added bucket wise for object stores
kishankavala May 29, 2023
5576fb4
Usage API respone update, UI labels for access key, secret key
kishankavala Jun 10, 2023
85f0d22
Add ObjectStore Simulator Plugin
kishankavala Jul 7, 2023
68478fa
removed protocol from object store
kishankavala Jul 8, 2023
7f004a3
Unit Tests for ObjectStore APIs
kishankavala Jul 10, 2023
42034c3
add unit tests and smoke test for object store lifecycle
kishankavala Jul 18, 2023
d0816d7
add smoke test for bucket life cycle
kishankavala Jul 18, 2023
4bb7c51
removed duplicate import ResponseGenerator
kishankavala Jul 18, 2023
beee8ac
Add bucket usage to quota types
kishankavala Jul 18, 2023
4235ce7
Add objectstore tests to smoke tests
kishankavala Jul 26, 2023
5680da6
Addressed review comments. Reordered package imports and refactored t…
kishankavala Aug 1, 2023
150c69b
Query asymc job result in UI for create bucket operation
kishankavala Aug 5, 2023
fd020a7
Fix line-endings and add unit tests
kishankavala Aug 9, 2023
466232c
Add new-line at the end of file
kishankavala Aug 9, 2023
94bb52a
Enable multi select and quick view in UI
kishankavala Aug 10, 2023
d90ab5e
Add account details to response and access checks
kishankavala Aug 12, 2023
f1bdf05
fix build error
kishankavala Aug 14, 2023
1c67b42
Fix Object Store UI validation and notifications
kishankavala Aug 21, 2023
a72a2b1
Fix listBuckets keyword search
kishankavala Aug 21, 2023
14f0e00
Added URL and list bucket checks for add/update object store
kishankavala Aug 21, 2023
1e42211
Fix bucket creation error message
kishankavala Aug 21, 2023
d6cd842
Validate bucket name
kishankavala Aug 21, 2023
416b6cf
Add support for object store comments
kishankavala Aug 21, 2023
123f1e4
Add annotations for logging events
kishankavala Aug 21, 2023
4d9d238
Add Object Stores to Infra Summary page
kishankavala Aug 21, 2023
37bcf44
Merge main to csos branch
kishankavala Aug 29, 2023
8c229a7
fix smoke test
kishankavala Aug 29, 2023
3865a9a
Return proper error message while intializing object store
kishankavala Sep 5, 2023
799d44f
remove Power Mock
kishankavala Sep 27, 2023
ba03a84
catch all exceptions during object store update
kishankavala Sep 27, 2023
8bf772e
cleanup bucket, if there any errors during creation
kishankavala Sep 27, 2023
bee7d74
fix for powermockito removal
kishankavala Sep 28, 2023
d03808d
Add browser for object store
vishesh92 Sep 27, 2023
eaa6172
Fix upload button
vishesh92 Oct 3, 2023
62504a2
fixes in UI
vishesh92 Oct 5, 2023
5f9617d
Fix bugs in UI
vishesh92 Oct 12, 2023
e9b811e
Fix date formatting for last modified column
vishesh92 Oct 23, 2023
cc0bd0f
fix issues while uploading files
vishesh92 Oct 24, 2023
af03252
minor ui fixups
vishesh92 Oct 24, 2023
314c0bc
fixup message on file deletion
vishesh92 Oct 24, 2023
836bdb2
Add check for duplicate object store URL
kishankavala Oct 25, 2023
6139c47
Added provider name to bucket response
kishankavala Oct 25, 2023
664ec8d
Show proper error when bucket update fails for encryption and versioning
kishankavala Oct 26, 2023
6e85586
merge from main
kishankavala Oct 26, 2023
27dd747
Fix missing Inject during merge
kishankavala Oct 27, 2023
ce185d1
Remove browser tab for Simulator type bucket
vishesh92 Oct 28, 2023
2daa0f7
Add id to search criteria while listing object stores
kishankavala Oct 31, 2023
020bfe4
Add missing license and end of line
kishankavala Oct 31, 2023
43b542a
Fixup: show metadata key
vishesh92 Nov 1, 2023
07c5ca1
UI: Don't show size for directories
vishesh92 Nov 2, 2023
0be57cc
Check minio account credetials before creating bucket
kishankavala Nov 7, 2023
c854315
fix end of line
kishankavala Nov 7, 2023
edb41df
fix lint error
kishankavala Nov 7, 2023
8765ce2
Update ui/public/locales/en.json
NuxRo Nov 15, 2023
7f09921
fix smoke test failure
kishankavala Nov 29, 2023
22b2806
fix smoke test failure
kishankavala Nov 29, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ jobs:
smoke/test_nic
smoke/test_nic_adapter_type
smoke/test_non_contigiousvlan
smoke/test_object_stores
smoke/test_outofbandmanagement
smoke/test_outofbandmanagement_nestedplugin
smoke/test_over_provisioning
Expand Down
22 changes: 22 additions & 0 deletions api/src/main/java/com/cloud/event/EventTypes.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.cloudstack.config.Configuration;
import org.apache.cloudstack.ha.HAConfig;
import org.apache.cloudstack.storage.object.Bucket;
import org.apache.cloudstack.storage.object.ObjectStore;
import org.apache.cloudstack.usage.Usage;
import org.apache.cloudstack.vm.schedule.VMSchedule;

Expand Down Expand Up @@ -714,6 +716,16 @@ public class EventTypes {
// SystemVM
public static final String EVENT_LIVE_PATCH_SYSTEMVM = "LIVE.PATCH.SYSTEM.VM";

// OBJECT STORE
public static final String EVENT_OBJECT_STORE_CREATE = "OBJECT.STORE.CREATE";
public static final String EVENT_OBJECT_STORE_DELETE = "OBJECT.STORE.DELETE";
public static final String EVENT_OBJECT_STORE_UPDATE = "OBJECT.STORE.UPDATE";

// BUCKETS
public static final String EVENT_BUCKET_CREATE = "BUCKET.CREATE";
public static final String EVENT_BUCKET_DELETE = "BUCKET.DELETE";
public static final String EVENT_BUCKET_UPDATE = "BUCKET.UPDATE";

static {

// TODO: need a way to force author adding event types to declare the entity details as well, with out braking
Expand Down Expand Up @@ -1151,6 +1163,16 @@ public class EventTypes {
entityEventDetails.put(EVENT_IMAGE_STORE_DATA_MIGRATE, ImageStore.class);
entityEventDetails.put(EVENT_IMAGE_STORE_OBJECT_DOWNLOAD, ImageStore.class);
entityEventDetails.put(EVENT_LIVE_PATCH_SYSTEMVM, "SystemVMs");

//Object Store
entityEventDetails.put(EVENT_OBJECT_STORE_CREATE, ObjectStore.class);
entityEventDetails.put(EVENT_OBJECT_STORE_UPDATE, ObjectStore.class);
entityEventDetails.put(EVENT_OBJECT_STORE_DELETE, ObjectStore.class);

//Buckets
entityEventDetails.put(EVENT_BUCKET_CREATE, Bucket.class);
entityEventDetails.put(EVENT_BUCKET_UPDATE, Bucket.class);
entityEventDetails.put(EVENT_BUCKET_DELETE, Bucket.class);
}

public static String getEntityForEvent(String eventName) {
Expand Down
3 changes: 2 additions & 1 deletion api/src/main/java/com/cloud/server/ResourceTag.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ public enum ResourceObjectType {
GuestOs(false, true),
NetworkOffering(false, true),
VpcOffering(true, false),
Domain(false, false, true);
Domain(false, false, true),
ObjectStore(false, false, true);


ResourceObjectType(boolean resourceTagsSupport, boolean resourceMetadataSupport) {
Expand Down
4 changes: 3 additions & 1 deletion api/src/main/java/com/cloud/storage/DataStoreRole.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import com.cloud.utils.exception.CloudRuntimeException;

public enum DataStoreRole {
Primary("primary"), Image("image"), ImageCache("imagecache"), Backup("backup");
Primary("primary"), Image("image"), ImageCache("imagecache"), Backup("backup"), Object("object");

public boolean isImageStore() {
return (role.equalsIgnoreCase("image") || role.equalsIgnoreCase("imagecache")) ? true : false;
Expand All @@ -45,6 +45,8 @@ public static DataStoreRole getRole(String role) {
return ImageCache;
} else if (role.equalsIgnoreCase("backup")) {
return Backup;
} else if (role.equalsIgnoreCase("object")) {
return Object;
} else {
throw new CloudRuntimeException("can't identify the role");
}
Expand Down
8 changes: 8 additions & 0 deletions api/src/main/java/com/cloud/storage/StorageService.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,19 @@
import org.apache.cloudstack.api.command.admin.storage.CreateSecondaryStagingStoreCmd;
import org.apache.cloudstack.api.command.admin.storage.CreateStoragePoolCmd;
import org.apache.cloudstack.api.command.admin.storage.DeleteImageStoreCmd;
import org.apache.cloudstack.api.command.admin.storage.DeleteObjectStoragePoolCmd;
import org.apache.cloudstack.api.command.admin.storage.DeletePoolCmd;
import org.apache.cloudstack.api.command.admin.storage.DeleteSecondaryStagingStoreCmd;
import org.apache.cloudstack.api.command.admin.storage.SyncStoragePoolCmd;
import org.apache.cloudstack.api.command.admin.storage.UpdateObjectStoragePoolCmd;
import org.apache.cloudstack.api.command.admin.storage.UpdateStoragePoolCmd;

import com.cloud.exception.DiscoveryException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.ResourceInUseException;
import com.cloud.exception.ResourceUnavailableException;
import org.apache.cloudstack.storage.object.ObjectStore;

public interface StorageService {
/**
Expand Down Expand Up @@ -109,4 +112,9 @@ public interface StorageService {

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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ enum EntityType {
SERVICE_OFFERING(false), DISK_OFFERING(false), NETWORK_OFFERING(false),
ZONE(false), POD(false), CLUSTER(false), HOST(false), DOMAIN(false),
PRIMARY_STORAGE(false), SECONDARY_STORAGE(false), VR(false), SYSTEM_VM(false),
AUTOSCALE_VM_GROUP(true), MANAGEMENT_SERVER(false),;
AUTOSCALE_VM_GROUP(true), MANAGEMENT_SERVER(false), OBJECT_STORAGE(false);

private final boolean usersAllowed;

Expand Down Expand Up @@ -78,6 +78,7 @@ static public List<EntityType> getNotAllowedTypesForNonAdmins(RoleType roleType)
list.add(EntityType.VR);
list.add(EntityType.SYSTEM_VM);
list.add(EntityType.MANAGEMENT_SERVER);
list.add(EntityType.OBJECT_STORAGE);
if (roleType != RoleType.DomainAdmin) {
list.add(EntityType.DOMAIN);
list.add(EntityType.SERVICE_OFFERING);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ public enum ApiCommandResourceType {
VmSnapshot(com.cloud.vm.snapshot.VMSnapshot.class),
Role(org.apache.cloudstack.acl.Role.class),
VpnCustomerGateway(com.cloud.network.Site2SiteCustomerGateway.class),
ManagementServer(org.apache.cloudstack.management.ManagementServerHost.class);
ManagementServer(org.apache.cloudstack.management.ManagementServerHost.class),
ObjectStore(org.apache.cloudstack.storage.object.ObjectStore.class),
Bucket(org.apache.cloudstack.storage.object.Bucket.class);

private final Class<?> clazz;

Expand Down
7 changes: 7 additions & 0 deletions api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -1049,10 +1049,17 @@ public class ApiConstants {
public static final String MTU = "mtu";
public static final String AUTO_ENABLE_KVM_HOST = "autoenablekvmhost";
public static final String LIST_APIS = "listApis";
public static final String OBJECT_STORAGE_ID = "objectstorageid";
public static final String VERSIONING = "versioning";
public static final String OBJECT_LOCKING = "objectlocking";
public static final String ENCRYPTION = "encryption";
public static final String QUOTA = "quota";
public static final String ACCESS_KEY = "accesskey";

public static final String SOURCE_NAT_IP = "sourcenatipaddress";
public static final String SOURCE_NAT_IP_ID = "sourcenatipaddressid";
public static final String HAS_RULES = "hasrules";
public static final String OBJECT_STORAGE = "objectstore";

public static final String MANAGEMENT = "management";
public static final String IS_VNF = "isvnf";
Expand Down
4 changes: 4 additions & 0 deletions api/src/main/java/org/apache/cloudstack/api/BaseCmd.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import org.apache.cloudstack.network.lb.ApplicationLoadBalancerService;
import org.apache.cloudstack.network.lb.InternalLoadBalancerVMService;
import org.apache.cloudstack.query.QueryService;
import org.apache.cloudstack.storage.object.BucketApiService;
import org.apache.cloudstack.storage.ImageStoreService;
import org.apache.cloudstack.storage.template.VnfTemplateManager;
import org.apache.cloudstack.usage.UsageService;
Expand Down Expand Up @@ -216,6 +217,9 @@ public static enum CommandType {
public Ipv6Service ipv6Service;
@Inject
public VnfTemplateManager vnfTemplateManager;
@Inject
public BucketApiService _bucketService;


public abstract void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException,
ResourceAllocationException, NetworkRuleConflictException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.Map;
import java.util.Set;

import org.apache.cloudstack.storage.object.Bucket;
import org.apache.cloudstack.affinity.AffinityGroup;
import org.apache.cloudstack.affinity.AffinityGroupResponse;
import org.apache.cloudstack.api.ApiConstants.HostDetails;
Expand All @@ -37,6 +38,7 @@
import org.apache.cloudstack.api.response.BackupOfferingResponse;
import org.apache.cloudstack.api.response.BackupResponse;
import org.apache.cloudstack.api.response.BackupScheduleResponse;
import org.apache.cloudstack.api.response.BucketResponse;
import org.apache.cloudstack.api.response.CapacityResponse;
import org.apache.cloudstack.api.response.ClusterResponse;
import org.apache.cloudstack.api.response.ConditionResponse;
Expand Down Expand Up @@ -82,6 +84,7 @@
import org.apache.cloudstack.api.response.NetworkResponse;
import org.apache.cloudstack.api.response.NicResponse;
import org.apache.cloudstack.api.response.NicSecondaryIpResponse;
import org.apache.cloudstack.api.response.ObjectStoreResponse;
import org.apache.cloudstack.api.response.OvsProviderResponse;
import org.apache.cloudstack.api.response.PhysicalNetworkResponse;
import org.apache.cloudstack.api.response.PodResponse;
Expand Down Expand Up @@ -145,6 +148,7 @@
import org.apache.cloudstack.region.PortableIp;
import org.apache.cloudstack.region.PortableIpRange;
import org.apache.cloudstack.region.Region;
import org.apache.cloudstack.storage.object.ObjectStore;
import org.apache.cloudstack.usage.Usage;

import com.cloud.capacity.Capacity;
Expand Down Expand Up @@ -533,4 +537,8 @@ List<TemplateResponse> createTemplateResponses(ResponseView view, VirtualMachine
FirewallResponse createIpv6FirewallRuleResponse(FirewallRule acl);

IpQuarantineResponse createQuarantinedIpsResponse(PublicIpQuarantine publicIp);

ObjectStoreResponse createObjectStoreResponse(ObjectStore os);

BucketResponse createBucketResponse(Bucket bucket);
}
Original file line number Diff line number Diff line change
@@ -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());
}
}
}
Loading