Skip to content

Commit b23ac40

Browse files
sandeeplocharlaLocharla, Sandeep
andauthored
CSTACKEX-50: Disable, Re-Enable, Delete Storage pool and Enter, Exit Maintenance mode (#20)
* CSTACKEX-50: Disable, Re-Enable, Delete Storage pool and Enter, Exit Storage pool workflows * CSTACKEX-50: Changes for selecting aggregate, retrieving ip interface and setting host and path * CSTACKEX-50: Fixed some issues seen while testing * CSTACKEX-50: Fixed few EOF lint issues * CSTACKEX-50: Fixed few lint issues * CSTACKEX-50: Included changes for Delete storage pool and modified some methods according to the latest design * CSTACKEX-050: Rebased the code with the latest in master * CSTACKEX-050: Fixed lint issues * CSTACKEX-050: Added some missing changes --------- Co-authored-by: Locharla, Sandeep <Sandeep.Locharla@netapp.com>
1 parent 54ddfa9 commit b23ac40

20 files changed

+1296
-249
lines changed

plugins/storage/volume/ontap/pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,14 @@
2424
<parent>
2525
<groupId>org.apache.cloudstack</groupId>
2626
<artifactId>cloudstack-plugins</artifactId>
27-
<version>4.22.0.0-SNAPSHOT</version>
27+
<version>4.23.0.0-SNAPSHOT</version>
2828
<relativePath>../../../pom.xml</relativePath>
2929
</parent>
3030
<properties>
3131
<spring-cloud.version>2021.0.7</spring-cloud.version>
3232
<openfeign.version>11.0</openfeign.version>
3333
<json.version>20230227</json.version>
34-
<jackson-databind.version>2.15.2</jackson-databind.version>
34+
<jackson-databind.version>2.13.4</jackson-databind.version>
3535
<httpclient.version>4.5.14</httpclient.version>
3636
<swagger-annotations.version>1.6.2</swagger-annotations.version>
3737
<maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>

plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/driver/OntapPrimaryDatastoreDriver.java

Lines changed: 1 addition & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,8 @@
1818
*/
1919
package org.apache.cloudstack.storage.driver;
2020

21-
import com.cloud.agent.api.Answer;
22-
import com.cloud.agent.api.to.DataObjectType;
2321
import com.cloud.agent.api.to.DataStoreTO;
2422
import com.cloud.agent.api.to.DataTO;
25-
import com.cloud.exception.InvalidParameterValueException;
2623
import com.cloud.host.Host;
2724
import com.cloud.storage.Storage;
2825
import com.cloud.storage.StoragePool;
@@ -43,14 +40,11 @@
4340
import org.apache.cloudstack.storage.command.CommandResult;
4441
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
4542
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
46-
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
4743
import org.apache.cloudstack.storage.feign.model.OntapStorage;
4844
import org.apache.cloudstack.storage.provider.StorageProviderFactory;
4945
import org.apache.cloudstack.storage.service.StorageStrategy;
50-
import org.apache.cloudstack.storage.service.model.CloudStackVolume;
5146
import org.apache.cloudstack.storage.service.model.ProtocolType;
5247
import org.apache.cloudstack.storage.utils.Constants;
53-
import org.apache.cloudstack.storage.utils.Utility;
5448
import org.apache.logging.log4j.LogManager;
5549
import org.apache.logging.log4j.Logger;
5650

@@ -87,57 +81,7 @@ public DataStoreTO getStoreTO(DataStore store) {
8781

8882
@Override
8983
public void createAsync(DataStore dataStore, DataObject dataObject, AsyncCompletionCallback<CreateCmdResult> callback) {
90-
CreateCmdResult createCmdResult = null;
91-
String path = null;
92-
String errMsg = null;
93-
if (dataStore == null) {
94-
throw new InvalidParameterValueException("createAsync: dataStore should not be null");
95-
}
96-
if (dataObject == null) {
97-
throw new InvalidParameterValueException("createAsync: dataObject should not be null");
98-
}
99-
if (callback == null) {
100-
throw new InvalidParameterValueException("createAsync: callback should not be null");
101-
}
102-
try {
103-
s_logger.info("createAsync: Started for data store [{}] and data object [{}] of type [{}]",
104-
dataStore, dataObject, dataObject.getType());
105-
if (dataObject.getType() == DataObjectType.VOLUME) {
106-
path = createCloudStackVolumeForTypeVolume(dataStore, dataObject);
107-
createCmdResult = new CreateCmdResult(path, new Answer(null, true, null));
108-
} else {
109-
errMsg = "Invalid DataObjectType (" + dataObject.getType() + ") passed to createAsync";
110-
s_logger.error(errMsg);
111-
throw new CloudRuntimeException(errMsg);
112-
}
113-
} catch (Exception e) {
114-
errMsg = e.getMessage();
115-
s_logger.error("createAsync: Failed for dataObject [{}]: {}", dataObject, errMsg);
116-
createCmdResult = new CreateCmdResult(null, new Answer(null, false, errMsg));
117-
createCmdResult.setResult(e.toString());
118-
} finally {
119-
callback.complete(createCmdResult);
120-
}
121-
}
12284

123-
private String createCloudStackVolumeForTypeVolume(DataStore dataStore, DataObject dataObject) {
124-
StoragePoolVO storagePool = storagePoolDao.findById(dataStore.getId());
125-
if(storagePool == null) {
126-
s_logger.error("createCloudStackVolume : Storage Pool not found for id: " + dataStore.getId());
127-
throw new CloudRuntimeException("createCloudStackVolume : Storage Pool not found for id: " + dataStore.getId());
128-
}
129-
Map<String, String> details = storagePoolDetailsDao.listDetailsKeyPairs(dataStore.getId());
130-
StorageStrategy storageStrategy = getStrategyByStoragePoolDetails(details);
131-
s_logger.info("createCloudStackVolumeForTypeVolume: Connection to Ontap SVM [{}] successful, preparing CloudStackVolumeRequest", details.get(Constants.SVM_NAME));
132-
CloudStackVolume cloudStackVolumeRequest = Utility.createCloudStackVolumeRequestByProtocol(storagePool, details, dataObject);
133-
CloudStackVolume cloudStackVolume = storageStrategy.createCloudStackVolume(cloudStackVolumeRequest);
134-
if (ProtocolType.ISCSI.name().equalsIgnoreCase(details.get(Constants.PROTOCOL)) && cloudStackVolume.getLun() != null && cloudStackVolume.getLun().getName() != null) {
135-
return cloudStackVolume.getLun().getName();
136-
} else {
137-
String errMsg = "createCloudStackVolumeForTypeVolume: Volume creation failed. Lun or Lun Path is null for dataObject: " + dataObject;
138-
s_logger.error(errMsg);
139-
throw new CloudRuntimeException(errMsg);
140-
}
14185
}
14286

14387
@Override
@@ -277,7 +221,7 @@ private StorageStrategy getStrategyByStoragePoolDetails(Map<String, String> deta
277221
}
278222
String protocol = details.get(Constants.PROTOCOL);
279223
OntapStorage ontapStorage = new OntapStorage(details.get(Constants.USERNAME), details.get(Constants.PASSWORD),
280-
details.get(Constants.MANAGEMENT_LIF), details.get(Constants.SVM_NAME), ProtocolType.valueOf(protocol),
224+
details.get(Constants.MANAGEMENT_LIF), details.get(Constants.SVM_NAME), Long.parseLong(details.get(Constants.SIZE)), ProtocolType.valueOf(protocol),
281225
Boolean.parseBoolean(details.get(Constants.IS_DISAGGREGATED)));
282226
StorageStrategy storageStrategy = StorageProviderFactory.getStrategy(ontapStorage);
283227
boolean isValid = storageStrategy.connect();

plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/feign/FeignConfiguration.java

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,25 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
120
package org.apache.cloudstack.storage.feign;
221

22+
import com.fasterxml.jackson.databind.ObjectMapper;
323
import feign.RequestInterceptor;
424
import feign.Retryer;
525
import feign.Client;
@@ -11,7 +31,6 @@
1131
import feign.codec.EncodeException;
1232
import com.fasterxml.jackson.core.JsonProcessingException;
1333
import com.fasterxml.jackson.databind.DeserializationFeature;
14-
import com.fasterxml.jackson.databind.json.JsonMapper;
1534
import org.apache.http.conn.ConnectionKeepAliveStrategy;
1635
import org.apache.http.conn.ssl.NoopHostnameVerifier;
1736
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
@@ -36,13 +55,11 @@ public class FeignConfiguration {
3655
private final int retryMaxInterval = 5;
3756
private final String ontapFeignMaxConnection = "80";
3857
private final String ontapFeignMaxConnectionPerRoute = "20";
39-
private final JsonMapper jsonMapper;
58+
private final ObjectMapper objectMapper;
4059

4160
public FeignConfiguration() {
42-
this.jsonMapper = JsonMapper.builder()
43-
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
44-
.findAndAddModules()
45-
.build();
61+
this.objectMapper = new ObjectMapper();
62+
this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
4663
}
4764

4865
public Client createClient() {
@@ -105,7 +122,7 @@ public void encode(Object object, Type bodyType, feign.RequestTemplate template)
105122
return;
106123
}
107124
try {
108-
byte[] jsonBytes = jsonMapper.writeValueAsBytes(object);
125+
byte[] jsonBytes = objectMapper.writeValueAsBytes(object);
109126
template.body(jsonBytes, StandardCharsets.UTF_8);
110127
template.header("Content-Type", "application/json");
111128
} catch (JsonProcessingException e) {
@@ -126,7 +143,7 @@ public Object decode(Response response, Type type) throws IOException, DecodeExc
126143
try (InputStream bodyStream = response.body().asInputStream()) {
127144
json = new String(bodyStream.readAllBytes(), StandardCharsets.UTF_8);
128145
logger.debug("Decoding JSON response: {}", json);
129-
return jsonMapper.readValue(json, jsonMapper.getTypeFactory().constructType(type));
146+
return objectMapper.readValue(json, objectMapper.getTypeFactory().constructType(type));
130147
} catch (IOException e) {
131148
logger.error("Error decoding JSON response. Status: {}, Raw body: {}", response.status(), json, e);
132149
throw new DecodeException(response.status(), "Error decoding JSON response", response.request(), e);
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.apache.cloudstack.storage.feign.client;
2+
3+
import feign.Headers;
4+
import feign.Param;
5+
import feign.QueryMap;
6+
import feign.RequestLine;
7+
import org.apache.cloudstack.storage.feign.model.IpInterface;
8+
import org.apache.cloudstack.storage.feign.model.response.OntapResponse;
9+
10+
import java.util.Map;
11+
12+
public interface NetworkFeignClient {
13+
@RequestLine("GET /api/network/ip/interfaces")
14+
@Headers({"Authorization: {authHeader}"})
15+
OntapResponse<IpInterface> getNetworkIpInterfaces(@Param("authHeader") String authHeader, @QueryMap Map<String, Object> queryParams);
16+
}

plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/feign/client/SANFeignClient.java

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -18,28 +18,32 @@
1818
*/
1919
package org.apache.cloudstack.storage.feign.client;
2020

21+
import feign.QueryMap;
2122
import org.apache.cloudstack.storage.feign.model.Igroup;
23+
import org.apache.cloudstack.storage.feign.model.IscsiService;
2224
import org.apache.cloudstack.storage.feign.model.Lun;
2325
import org.apache.cloudstack.storage.feign.model.LunMap;
2426
import org.apache.cloudstack.storage.feign.model.response.OntapResponse;
2527
import feign.Headers;
2628
import feign.Param;
2729
import feign.RequestLine;
28-
import java.net.URI;
30+
import java.util.Map;
2931

3032
//TODO: Proper URLs should be added in the RequestLine annotations below
3133
public interface SANFeignClient {
34+
// iSCSI Service APIs
35+
@RequestLine("GET /api/protocols/san/iscsi/services")
36+
@Headers({"Authorization: {authHeader}"})
37+
OntapResponse<IscsiService> getIscsiServices(@Param("authHeader") String authHeader, @QueryMap Map<String, Object> queryMap);
3238

3339
// LUN Operation APIs
34-
@RequestLine("POST /")
35-
@Headers({"Authorization: {authHeader}", "return_records: {returnRecords}"})
36-
OntapResponse<Lun> createLun(@Param("authHeader") String authHeader,
37-
@Param("returnRecords") boolean returnRecords,
38-
Lun lun);
40+
@RequestLine("POST /api/storage/luns?return_records={returnRecords}")
41+
@Headers({"Authorization: {authHeader}"})
42+
OntapResponse<Lun> createLun(@Param("authHeader") String authHeader, @Param("returnRecords") boolean returnRecords, Lun lun);
3943

40-
@RequestLine("GET /")
44+
@RequestLine("GET /api/storage/luns")
4145
@Headers({"Authorization: {authHeader}"})
42-
OntapResponse<Lun> getLunResponse(@Param("authHeader") String authHeader);
46+
OntapResponse<Lun> getLunResponse(@Param("authHeader") String authHeader, @QueryMap Map<String, Object> queryMap);
4347

4448
@RequestLine("GET /{uuid}")
4549
@Headers({"Authorization: {authHeader}"})
@@ -54,36 +58,35 @@ OntapResponse<Lun> createLun(@Param("authHeader") String authHeader,
5458
void deleteLun(@Param("authHeader") String authHeader, @Param("uuid") String uuid);
5559

5660
// iGroup Operation APIs
57-
@RequestLine("POST /")
58-
@Headers({"Authorization: {authHeader}", "return_records: {returnRecords}"})
59-
OntapResponse<Igroup> createIgroup(@Param("authHeader") String authHeader,
60-
@Param("returnRecords") boolean returnRecords,
61-
Igroup igroupRequest);
61+
@RequestLine("POST /api/protocols/san/igroups?return_records={returnRecords}")
62+
@Headers({"Authorization: {authHeader}"})
63+
OntapResponse<Igroup> createIgroup(@Param("authHeader") String authHeader, @Param("returnRecords") boolean returnRecords, Igroup igroupRequest);
6264

63-
@RequestLine("GET /")
64-
@Headers({"Authorization: {authHeader}"}) // TODO: Check this again, uuid should be part of the path?
65-
OntapResponse<Igroup> getIgroupResponse(@Param("authHeader") String authHeader, @Param("uuid") String uuid);
65+
@RequestLine("GET /api/protocols/san/igroups")
66+
@Headers({"Authorization: {authHeader}"})
67+
OntapResponse<Igroup> getIgroupResponse(@Param("authHeader") String authHeader, @QueryMap Map<String, Object> queryMap);
6668

6769
@RequestLine("GET /{uuid}")
6870
@Headers({"Authorization: {authHeader}"})
6971
Igroup getIgroupByUUID(@Param("authHeader") String authHeader, @Param("uuid") String uuid);
7072

71-
@RequestLine("DELETE /{uuid}")
73+
@RequestLine("DELETE /api/protocols/san/igroups/{uuid}")
7274
@Headers({"Authorization: {authHeader}"})
73-
void deleteIgroup(@Param("baseUri") URI baseUri, @Param("authHeader") String authHeader, @Param("uuid") String uuid);
75+
void deleteIgroup(@Param("authHeader") String authHeader, @Param("uuid") String uuid);
7476

7577
// LUN Maps Operation APIs
76-
@RequestLine("POST /")
77-
@Headers({"Authorization: {authHeader}"})
78-
OntapResponse<LunMap> createLunMap(@Param("authHeader") String authHeader, LunMap lunMap);
78+
@RequestLine("POST /api/protocols/san/lun-maps")
79+
@Headers({"Authorization: {authHeader}", "return_records: {returnRecords}"})
80+
OntapResponse<LunMap> createLunMap(@Param("authHeader") String authHeader, @Param("returnRecords") boolean returnRecords, LunMap lunMap);
81+
7982

80-
@RequestLine("GET /")
83+
@RequestLine("GET /api/protocols/san/lun-maps")
8184
@Headers({"Authorization: {authHeader}"})
82-
OntapResponse<LunMap> getLunMapResponse(@Param("authHeader") String authHeader);
85+
OntapResponse<LunMap> getLunMapResponse(@Param("authHeader") String authHeader, @QueryMap Map<String, Object> queryMap);
8386

84-
@RequestLine("DELETE /{lunUuid}/{igroupUuid}")
87+
@RequestLine("DELETE /api/protocols/san/lun-maps/{lunUuid}/{igroupUuid}")
8588
@Headers({"Authorization: {authHeader}"})
8689
void deleteLunMap(@Param("authHeader") String authHeader,
87-
@Param("lunUuid") String lunUuid,
88-
@Param("igroupUuid") String igroupUuid);
90+
@Param("lunUuid") String lunUUID,
91+
@Param("igroupUuid") String igroupUUID);
8992
}

plugins/storage/volume/ontap/src/main/java/org/apache/cloudstack/storage/feign/client/VolumeFeignClient.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,30 @@
1818
*/
1919
package org.apache.cloudstack.storage.feign.client;
2020

21+
import feign.QueryMap;
2122
import org.apache.cloudstack.storage.feign.model.Volume;
2223
import org.apache.cloudstack.storage.feign.model.response.JobResponse;
2324
import feign.Headers;
2425
import feign.Param;
2526
import feign.RequestLine;
27+
import org.apache.cloudstack.storage.feign.model.response.OntapResponse;
28+
29+
import java.util.Map;
2630

2731
public interface VolumeFeignClient {
2832

2933
@RequestLine("DELETE /api/storage/volumes/{uuid}")
3034
@Headers({"Authorization: {authHeader}"})
31-
void deleteVolume(@Param("authHeader") String authHeader, @Param("uuid") String uuid);
35+
JobResponse deleteVolume(@Param("authHeader") String authHeader, @Param("uuid") String uuid);
3236

3337
@RequestLine("POST /api/storage/volumes")
3438
@Headers({"Authorization: {authHeader}"})
3539
JobResponse createVolumeWithJob(@Param("authHeader") String authHeader, Volume volumeRequest);
3640

41+
@RequestLine("GET /api/storage/volumes")
42+
@Headers({"Authorization: {authHeader}"})
43+
OntapResponse<Volume> getAllVolumes(@Param("authHeader") String authHeader, @QueryMap Map<String, Object> queryParams);
44+
3745
@RequestLine("GET /api/storage/volumes/{uuid}")
3846
@Headers({"Authorization: {authHeader}"})
3947
Volume getVolumeByUUID(@Param("authHeader") String authHeader, @Param("uuid") String uuid);
@@ -42,4 +50,3 @@ public interface VolumeFeignClient {
4250
@Headers({"Accept: {acceptHeader}", "Authorization: {authHeader}"})
4351
JobResponse updateVolumeRebalancing(@Param("acceptHeader") String acceptHeader, @Param("uuid") String uuid, Volume volumeRequest);
4452
}
45-

0 commit comments

Comments
 (0)