Skip to content

Commit c4becd5

Browse files
widoyadvr
authored andcommitted
storage/object: Add support for Ceph RGW Object Store (apache#8389)
This feature adds support for Ceph's RADOS Gateway (RGW) support for the Object Store feature of CloudStack. The RGW of Ceph is Amazon S3 compliant and is therefor an easy and straigforward implementation of basic S3 features. Existing Ceph environments can have the RGW added as an additional feature to a cluster already providing RBD (Block Device) to a CloudStack environment. Introduce the BucketTO to pass to the drivers. This replaces just passing the bucket's name. Some upcoming drivers require more information then just the bucket name to perform their actions, for example they require the access and secret key which belong to the account of this bucket. This is leftover code from a long time ago and this validation test has nu influence on the end result on how a URL will be used afterwards. We should support hosts pointing to an IPv6(-only) address out of the box. For the code it does not matter if it's IPv4 or IPv6. This is the admin's choice. Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com> Co-authored-by: Rohit Yadav <rohit.yadav@shapeblue.com>
1 parent a9972ea commit c4becd5

7 files changed

Lines changed: 43 additions & 34 deletions

File tree

engine/schema/src/main/java/com/cloud/storage/BucketVO.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,17 +97,23 @@ public class BucketVO implements Bucket {
9797
String uuid;
9898

9999
public BucketVO() {
100+
this.uuid = UUID.randomUUID().toString();
101+
}
102+
103+
public BucketVO(String name) {
104+
this.uuid = UUID.randomUUID().toString();
105+
this.name = name;
106+
this.state = State.Allocated;
100107
}
101108

102109
public BucketVO(long accountId, long domainId, long objectStoreId, String name, Integer quota, boolean versioning,
103-
boolean encryption, boolean objectLock, String policy)
104-
{
110+
boolean encryption, boolean objectLock, String policy) {
105111
this.accountId = accountId;
106112
this.domainId = domainId;
107113
this.objectStoreId = objectStoreId;
108114
this.name = name;
109-
state = State.Allocated;
110-
uuid = UUID.randomUUID().toString();
115+
this.state = State.Allocated;
116+
this.uuid = UUID.randomUUID().toString();
111117
this.quota = quota;
112118
this.versioning = versioning;
113119
this.encryption = encryption;

plugins/storage/object/ceph/src/main/java/org/apache/cloudstack/storage/datastore/driver/CephObjectStoreDriverImpl.java

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,25 +19,26 @@
1919
package org.apache.cloudstack.storage.datastore.driver;
2020

2121
import com.amazonaws.AmazonServiceException;
22+
import com.amazonaws.SdkClientException;
23+
import com.amazonaws.services.s3.model.BucketCrossOriginConfiguration;
24+
import com.amazonaws.services.s3.model.CORSRule;
25+
2226
import com.amazonaws.auth.AWSStaticCredentialsProvider;
2327
import com.amazonaws.auth.BasicAWSCredentials;
2428
import com.amazonaws.client.builder.AwsClientBuilder;
25-
import com.amazonaws.SdkClientException;
2629
import com.amazonaws.services.s3.AmazonS3;
2730
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
28-
import com.amazonaws.services.s3.model.AccessControlList;
2931
import com.amazonaws.services.s3.model.AmazonS3Exception;
30-
import com.amazonaws.services.s3.model.BucketCrossOriginConfiguration;
32+
import com.amazonaws.services.s3.model.AccessControlList;
3133
import com.amazonaws.services.s3.model.BucketPolicy;
3234
import com.amazonaws.services.s3.model.BucketVersioningConfiguration;
33-
import com.amazonaws.services.s3.model.CORSRule;
3435
import com.amazonaws.services.s3.model.DeleteBucketPolicyRequest;
35-
import com.amazonaws.services.s3.model.GetBucketPolicyRequest;
3636
import com.amazonaws.services.s3.model.SetBucketPolicyRequest;
37+
import com.amazonaws.services.s3.model.GetBucketPolicyRequest;
3738
import com.amazonaws.services.s3.model.SetBucketVersioningConfigurationRequest;
38-
3939
import com.cloud.agent.api.to.BucketTO;
4040
import com.cloud.agent.api.to.DataStoreTO;
41+
import org.apache.cloudstack.storage.object.Bucket;
4142
import com.cloud.storage.BucketVO;
4243
import com.cloud.storage.dao.BucketDao;
4344
import com.cloud.user.Account;
@@ -56,6 +57,7 @@
5657
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
5758
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
5859
import org.apache.cloudstack.storage.command.CommandResult;
60+
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
5961
import org.apache.cloudstack.storage.datastore.db.ObjectStoreDao;
6062
import org.apache.cloudstack.storage.datastore.db.ObjectStoreDetailsDao;
6163
import org.apache.cloudstack.storage.datastore.db.ObjectStoreVO;
@@ -68,7 +70,12 @@
6870
import org.twonote.rgwadmin4j.RgwAdmin;
6971
import org.twonote.rgwadmin4j.RgwAdminBuilder;
7072

73+
import org.apache.logging.log4j.LogManager;
74+
import org.apache.logging.log4j.Logger;
75+
7176
public class CephObjectStoreDriverImpl extends BaseObjectStoreDriverImpl {
77+
private static final Logger s_logger = LogManager.getLogger(CephObjectStoreDriverImpl.class);
78+
7279
@Inject
7380
AccountDao _accountDao;
7481

@@ -312,11 +319,7 @@ public boolean setBucketVersioning(BucketTO bucket, long storeId) {
312319
SetBucketVersioningConfigurationRequest setBucketVersioningConfigurationRequest =
313320
new SetBucketVersioningConfigurationRequest(bucket.getName(), configuration);
314321

315-
client.setBucketVersioningConfiguration(setBucketVersioningConfigurationRequest);
316322
return true;
317-
} catch (AmazonS3Exception e) {
318-
throw new CloudRuntimeException(e);
319-
}
320323
}
321324

322325
@Override

plugins/storage/object/ceph/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/CephObjectStoreLifeCycleImpl.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@
3838
import java.util.Map;
3939

4040
public class CephObjectStoreLifeCycleImpl implements ObjectStoreLifeCycle {
41-
protected Logger logger = LogManager.getLogger(getClass());
41+
42+
private static final Logger s_logger = LogManager.getLogger(CephObjectStoreLifeCycleImpl.class);
4243

4344
@Inject
4445
ObjectStoreHelper objectStoreHelper;
@@ -71,7 +72,7 @@ public DataStore initialize(Map<String, Object> dsInfos) {
7172
objectStoreParameters.put("accesskey", accessKey);
7273
objectStoreParameters.put("secretkey", secretKey);
7374

74-
logger.info("Attempting to connect to Ceph RGW at " + url + " with access key " + accessKey);
75+
s_logger.info("Attempting to connect to Ceph RGW at " + url + " with access key " + accessKey);
7576

7677
RgwAdmin rgwAdmin = new RgwAdminBuilder()
7778
.accessKey(accessKey)
@@ -80,10 +81,10 @@ public DataStore initialize(Map<String, Object> dsInfos) {
8081
.build();
8182
try {
8283
List<String> buckets = rgwAdmin.listBucket();
83-
logger.debug("Found " + buckets + " buckets at Ceph RGW: " + url);
84-
logger.info("Successfully connected to Ceph RGW: " + url);
84+
s_logger.debug("Found " + buckets + " buckets at Ceph RGW: " + url);
85+
s_logger.info("Successfully connected to Ceph RGW: " + url);
8586
} catch (Exception e) {
86-
logger.debug("Error while initializing Ceph RGW Object Store: " + e.getMessage());
87+
s_logger.debug("Error while initializing Ceph RGW Object Store: " + e.getMessage());
8788
throw new RuntimeException("Error while initializing Ceph RGW Object Store. Invalid credentials or URL");
8889
}
8990

plugins/storage/object/ceph/src/test/java/org/apache/cloudstack/storage/datastore/driver/CephObjectStoreDriverImplTest.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
import static org.mockito.Mockito.anyString;
4545
import static org.mockito.Mockito.doNothing;
4646
import static org.mockito.Mockito.doReturn;
47+
import static org.mockito.Mockito.times;
48+
import static org.mockito.Mockito.verify;
4749
import static org.mockito.Mockito.when;
4850

4951
@RunWith(MockitoJUnitRunner.class)
@@ -67,12 +69,12 @@ public class CephObjectStoreDriverImplTest {
6769
@Mock
6870
BucketDao bucketDao;
6971
@Mock
70-
Bucket bucket;
71-
@Mock
7272
AccountVO account;
7373
@Mock
7474
AccountDetailsDao accountDetailsDao;
7575

76+
Bucket bucket;
77+
7678
@Before
7779
public void setUp() {
7880
MockitoAnnotations.initMocks(this);
@@ -81,31 +83,31 @@ public void setUp() {
8183
cephObjectStoreDriverImpl._accountDao = accountDao;
8284
cephObjectStoreDriverImpl._bucketDao = bucketDao;
8385
cephObjectStoreDriverImpl._accountDetailsDao = accountDetailsDao;
86+
bucket = new BucketVO();
87+
bucket.setName("test-bucket");
8488
when(objectStoreVO.getUrl()).thenReturn("http://localhost:8000");
8589
when(objectStoreDao.findById(any())).thenReturn(objectStoreVO);
8690
}
8791

8892
@Test
8993
public void testCreateBucket() throws Exception {
90-
when(bucket.getName()).thenReturn("test-bucket");
91-
when(bucket.getObjectStoreId()).thenReturn(1L);
92-
when(bucket.getAccountId()).thenReturn(1L);
93-
when(rgwClient.getBucketAcl(anyString())).thenReturn(null);
94+
doReturn(rgwClient).when(cephObjectStoreDriverImpl).getS3Client(anyLong(), anyLong());
9495
when(accountDetailsDao.findDetail(anyLong(),anyString())).
9596
thenReturn(new AccountDetailVO(1L, "abc","def"));
96-
when(bucketDao.findById(anyLong())).thenReturn(new BucketVO());
97-
doReturn(rgwClient).when(cephObjectStoreDriverImpl).getS3Client(anyLong(), anyLong());
97+
when(bucketDao.findById(anyLong())).thenReturn(new BucketVO(bucket.getName()));
9898
Bucket bucketRet = cephObjectStoreDriverImpl.createBucket(bucket, false);
9999
assertEquals(bucketRet.getName(), bucket.getName());
100+
verify(rgwClient, times(1)).getBucketAcl(anyString());
101+
verify(rgwClient, times(1)).createBucket(anyString());
100102
}
101103

102104
@Test
103105
public void testDeleteBucket() throws Exception {
104106
String bucketName = "test-bucket";
105107
BucketTO bucket = new BucketTO(bucketName);
106108
doReturn(rgwAdmin).when(cephObjectStoreDriverImpl).getRgwAdminClient(anyLong());
107-
doNothing().when(rgwAdmin).removeBucket(anyString());
108109
boolean success = cephObjectStoreDriverImpl.deleteBucket(bucket, 1L);
109110
assertTrue(success);
111+
verify(rgwAdmin, times(1)).removeBucket(anyString());
110112
}
111113
}

server/src/main/java/org/apache/cloudstack/storage/object/BucketApiServiceImpl.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,14 +137,14 @@ public Bucket createBucket(CreateBucketCmd cmd) {
137137
ObjectStoreVO objectStoreVO = _objectStoreDao.findById(cmd.getObjectStoragePoolId());
138138
ObjectStoreEntity objectStore = (ObjectStoreEntity)_dataStoreMgr.getDataStore(objectStoreVO.getId(), DataStoreRole.Object);
139139
BucketVO bucket = _bucketDao.findById(cmd.getEntityId());
140-
BucketTO bucketTO = null;
140+
BucketTO bucketTO = new BucketTO(bucket);
141141
boolean objectLock = false;
142142
boolean bucketCreated = false;
143143
if(cmd.isObjectLocking()) {
144144
objectLock = true;
145145
}
146146
try {
147-
objectStore.createBucket(bucket, objectLock);
147+
bucketTO = new BucketTO(objectStore.createBucket(bucket, objectLock));
148148
bucketCreated = true;
149149

150150
bucket = _bucketDao.findById(cmd.getEntityId());

utils/src/main/java/com/cloud/utils/UriUtils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323
import java.io.IOException;
2424
import java.io.InputStream;
2525
import java.net.HttpURLConnection;
26-
import java.net.Inet6Address;
2726
import java.net.InetAddress;
27+
import java.net.Inet6Address;
2828
import java.net.URI;
2929
import java.net.URISyntaxException;
3030
import java.net.URLEncoder;

utils/src/test/java/com/cloud/utils/UriUtilsTest.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -281,8 +281,5 @@ public void validateUrl() {
281281

282282
Pair<String, Integer> url2 = UriUtils.validateUrl("https://www.apache.org");
283283
Assert.assertEquals(url2.first(), "www.apache.org");
284-
285-
Pair<String, Integer> url3 = UriUtils.validateUrl("https://ipv6.google.com");
286-
Assert.assertEquals(url3.first(), "ipv6.google.com");
287284
}
288285
}

0 commit comments

Comments
 (0)