Skip to content
Closed
Show file tree
Hide file tree
Changes from 9 commits
Commits
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
5 changes: 5 additions & 0 deletions client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,11 @@
<artifactId>cloud-plugin-storage-object-minio</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-plugin-storage-object-huawei-obs</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-plugin-storage-object-simulator</artifactId>
Expand Down
3 changes: 2 additions & 1 deletion plugins/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@
<module>storage/volume/primera</module>
<module>storage/object/minio</module>
<module>storage/object/simulator</module>
<module>storage/object/huawei-obs</module>


<module>storage-allocators/random</module>
Expand All @@ -155,7 +156,7 @@

</modules>
<dependencies>
<dependency>
<dependency>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tab

Suggested change
<dependency>
<dependency>

<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-server</artifactId>
<version>${project.version}</version>
Expand Down
44 changes: 44 additions & 0 deletions plugins/storage/object/huawei-obs/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<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">
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<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">
<!--
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-huawei-obs</artifactId>
<name>Apache CloudStack Plugin - Huawei OBS 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>com.huawei.storage</groupId>
<artifactId>esdk-obs-java</artifactId>
<version>3.23.9</version>
</dependency>
<dependency>
<groupId>com.huaweicloud.sdk</groupId>
<artifactId>huaweicloud-sdk-iam</artifactId>
<version>3.1.69</version>
<exclusions>
<exclusion>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package org.apache.cloudstack.storage.datastore.lifecycle;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
package org.apache.cloudstack.storage.datastore.lifecycle;
// 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 com.obs.services.ObsClient;
import com.obs.services.model.ListBucketsRequest;
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 HuaweiObsObjectStoreLifeCycleImpl implements ObjectStoreLifeCycle {

private static final Logger LOG = Logger.getLogger(HuaweiObsObjectStoreLifeCycleImpl.class);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
private static final Logger LOG = Logger.getLogger(HuaweiObsObjectStoreLifeCycleImpl.class);
protected Logger logger = LogManager.getLogger(getClass());

Also need to update the log4j import


@Inject
ObjectStoreHelper objectStoreHelper;
@Inject
ObjectStoreProviderManager objectStoreMgr;

public HuaweiObsObjectStoreLifeCycleImpl() {
}

@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("Huawei OBS 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);

try {
//check credentials
ObsClient obsClient = new ObsClient(accessKey, secretKey, url);
// Test connection by listing buckets
ListBucketsRequest request = new ListBucketsRequest();
request.setQueryLocation(true);
obsClient.listBucketsV2(request);
LOG.debug("Successfully connected to Huawei OBS EndPoint: " + url);
} catch (Exception ex) {
LOG.debug("Error while initializing Huawei OBS Object Store: " + ex.getMessage());
throw new RuntimeException("Error while initializing Huawei OBS Object Store. Invalid credentials or endpoint 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;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package org.apache.cloudstack.storage.datastore.provider;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
package org.apache.cloudstack.storage.datastore.provider;
// 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.HuaweiObsObjectStoreDriverImpl;
import org.apache.cloudstack.storage.datastore.lifecycle.HuaweiObsObjectStoreLifeCycleImpl;
import org.apache.cloudstack.storage.object.ObjectStoreDriver;
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 HuaweiObsObjectStoreProviderImpl implements ObjectStoreProvider {

@Inject
ObjectStoreProviderManager storeMgr;

private final String providerName = "Huawei OBS";
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(HuaweiObsObjectStoreLifeCycleImpl.class);
driver = ComponentContext.inject(HuaweiObsObjectStoreDriverImpl.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<>();
types.add(DataStoreProviderType.OBJECT);
return types;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
name=storage-object-huawei-obs
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
name=storage-object-huawei-obs
# 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-huawei-obs

parent=storage
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<beans xmlns="http://www.springframework.org/schema/beans"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<beans xmlns="http://www.springframework.org/schema/beans"
<!--
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="huaweiObsStoreProviderImpl" class="org.apache.cloudstack.storage.datastore.provider.HuaweiObsObjectStoreProviderImpl" />
</beans>
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package org.apache.cloudstack.storage.datastore.driver;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
package org.apache.cloudstack.storage.datastore.driver;
// 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 com.obs.services.ObsClient;
import com.obs.services.model.CreateBucketRequest;
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.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.mockito.Mockito;

@RunWith(MockitoJUnitRunner.class)
public class HuaweiObsObjectStoreDriverImplTest {

@Spy
HuaweiObsObjectStoreDriverImpl huaweiObsObjectStoreDriverImpl = new HuaweiObsObjectStoreDriverImpl();

@Mock
ObsClient obsClient;
@Mock
ObjectStoreDao objectStoreDao;
@Mock
ObjectStoreVO objectStoreVO;
@Mock
ObjectStoreDetailsDao objectStoreDetailsDao;
@Mock
AccountDao accountDao;
@Mock
BucketDao bucketDao;
@Mock
AccountVO account;
@Mock
AccountDetailsDao accountDetailsDao;

Bucket bucket;
String bucketName = "test-bucket";

@Before
public void setUp() {
huaweiObsObjectStoreDriverImpl._storeDao = objectStoreDao;
huaweiObsObjectStoreDriverImpl._storeDetailsDao = objectStoreDetailsDao;
huaweiObsObjectStoreDriverImpl._accountDao = accountDao;
huaweiObsObjectStoreDriverImpl._bucketDao = bucketDao;
huaweiObsObjectStoreDriverImpl._accountDetailsDao = accountDetailsDao;
bucket = new BucketVO(0, 0, 0, bucketName, 100, false, false, false, "public");
}

@Test
public void testCreateBucket() throws Exception {
Mockito.doReturn(obsClient).when(huaweiObsObjectStoreDriverImpl).getObsClient(Mockito.anyLong());
Mockito.when(accountDao.findById(Mockito.anyLong())).thenReturn(account);
Mockito.when(accountDetailsDao.findDetail(Mockito.anyLong(), Mockito.anyString())).thenReturn(new AccountDetailVO(1L, "abc", "def"));
Mockito.when(obsClient.headBucket(bucketName)).thenReturn(false);
CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
createBucketRequest.setAcl(com.obs.services.model.AccessControlList.REST_CANNED_PUBLIC_READ_WRITE);
Mockito.when(bucketDao.findById(Mockito.anyLong())).thenReturn(new BucketVO(0, 0, 0, bucketName, 100, false, false, false, "public"));
Mockito.when(objectStoreVO.getUrl()).thenReturn("http://test-bucket.localhost:9000");
Mockito.when(objectStoreDao.findById(Mockito.any())).thenReturn(objectStoreVO);
Bucket bucketRet = huaweiObsObjectStoreDriverImpl.createBucket(bucket, false);
assertEquals(bucketRet.getName(), bucket.getName());
Mockito.verify(obsClient, Mockito.times(1)).headBucket(Mockito.anyString());
Mockito.verify(obsClient, Mockito.times(1)).createBucket(Mockito.any(CreateBucketRequest.class));
}

@Test
public void testDeleteBucket() throws Exception {
Mockito.doReturn(obsClient).when(huaweiObsObjectStoreDriverImpl).getObsClient(Mockito.anyLong());
Mockito.when(obsClient.headBucket(bucketName)).thenReturn(true);
boolean success = huaweiObsObjectStoreDriverImpl.deleteBucket(bucketName, 1L);
assertTrue(success);
Mockito.verify(obsClient, Mockito.times(1)).headBucket(Mockito.anyString());
Mockito.verify(obsClient, Mockito.times(1)).deleteBucket(Mockito.anyString());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package org.apache.cloudstack.storage.datastore.provider;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
package org.apache.cloudstack.storage.datastore.provider;
// 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 HuaweiObsObjectStoreProviderImplTest {

private HuaweiObsObjectStoreProviderImpl huaweiObsObjectStoreProviderImpl;

@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
huaweiObsObjectStoreProviderImpl = new HuaweiObsObjectStoreProviderImpl();
}

@Test
public void testGetName() {
String name = huaweiObsObjectStoreProviderImpl.getName();
assertEquals("Huawei OBS", name);
}

@Test
public void testGetTypes() {
Set<DataStoreProviderType> types = huaweiObsObjectStoreProviderImpl.getTypes();
assertEquals(1, types.size());
assertEquals("OBJECT", types.toArray()[0].toString());
}
}
2 changes: 1 addition & 1 deletion ui/src/views/infra/AddObjectStorage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export default {
inject: ['parentFetchData'],
data () {
return {
providers: ['MinIO', 'Simulator'],
providers: ['MinIO', 'Huawei OBS', 'Simulator'],
zones: [],
loading: false
}
Expand Down