Skip to content

Commit 6001772

Browse files
DK101010DK101010JoaoJandre
authored
multi local storage handling for kvm (#6699)
Co-authored-by: DK101010 <dirk.klahre@itelligence.de> Co-authored-by: João Jandre <48719461+JoaoJandre@users.noreply.github.com>
1 parent 0735b91 commit 6001772

7 files changed

Lines changed: 220 additions & 72 deletions

File tree

api/src/main/java/com/cloud/agent/api/StoragePoolInfo.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ public StoragePoolInfo(String uuid, String host, String hostPath, String localPa
5252
this.details = details;
5353
}
5454

55+
public StoragePoolInfo(String uuid, String host, String hostPath, String localPath, StoragePoolType poolType, long capacityBytes, long availableBytes,
56+
Map<String, String> details, String name) {
57+
this(uuid, host, hostPath, localPath, poolType, capacityBytes, availableBytes);
58+
this.details = details;
59+
this.name = name;
60+
}
61+
5562
public long getCapacityBytes() {
5663
return capacityBytes;
5764
}

api/src/main/java/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,10 @@ public Long getId() {
119119
return id;
120120
}
121121

122+
public void setId(Long id) {
123+
this.id = id;
124+
}
125+
122126
public String getHostName() {
123127
return hostName;
124128
}

api/src/main/java/org/apache/cloudstack/api/command/admin/storage/ListStoragePoolsCmd.java

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.apache.cloudstack.api.BaseListCmd;
2525
import org.apache.cloudstack.api.Parameter;
2626
import org.apache.cloudstack.api.response.ClusterResponse;
27+
import org.apache.cloudstack.api.response.HostResponse;
2728
import org.apache.cloudstack.api.response.ListResponse;
2829
import org.apache.cloudstack.api.response.PodResponse;
2930
import org.apache.cloudstack.api.response.StoragePoolResponse;
@@ -63,16 +64,25 @@ public class ListStoragePoolsCmd extends BaseListCmd {
6364
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = StoragePoolResponse.class, description = "the ID of the storage pool")
6465
private Long id;
6566

66-
@Parameter(name = ApiConstants.SCOPE, type = CommandType.STRING, entityType = StoragePoolResponse.class, description = "the ID of the storage pool")
67+
@Parameter(name = ApiConstants.SCOPE, type = CommandType.STRING, entityType = StoragePoolResponse.class, description = "the scope of the storage pool")
6768
private String scope;
6869

70+
6971
@Parameter(name = ApiConstants.STATUS, type = CommandType.STRING, description = "the status of the storage pool")
7072
private String status;
7173

74+
@Parameter(name = ApiConstants.HOST_ID, type = CommandType.UUID, entityType = HostResponse.class, description = "host ID of the storage pools")
75+
private Long hostId;
76+
77+
7278
/////////////////////////////////////////////////////
7379
/////////////////// Accessors ///////////////////////
7480
/////////////////////////////////////////////////////
7581

82+
public Long getHostId() {
83+
return hostId;
84+
}
85+
7686
public Long getClusterId() {
7787
return clusterId;
7888
}
@@ -81,6 +91,10 @@ public String getIpAddress() {
8191
return ipAddress;
8292
}
8393

94+
public void setIpAddress(String ipAddress) {
95+
this.ipAddress = ipAddress;
96+
}
97+
8498
public String getStoragePoolName() {
8599
return storagePoolName;
86100
}
@@ -108,6 +122,15 @@ public Long getId() {
108122
public void setId(Long id) {
109123
this.id = id;
110124
}
125+
126+
public String getScope() {
127+
return scope;
128+
}
129+
130+
public void setScope(String scope) {
131+
this.scope = scope;
132+
}
133+
111134
/////////////////////////////////////////////////////
112135
/////////////// API Implementation///////////////////
113136
/////////////////////////////////////////////////////
@@ -123,8 +146,4 @@ public void execute() {
123146
response.setResponseName(getCommandName());
124147
this.setResponseObject(response);
125148
}
126-
127-
public String getScope() {
128-
return scope;
129-
}
130149
}

plugins/storage/volume/default/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImpl.java

Lines changed: 25 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import com.cloud.alert.AlertManager;
2828
import com.cloud.exception.InvalidParameterValueException;
2929
import com.cloud.exception.StorageConflictException;
30+
import com.cloud.exception.StorageUnavailableException;
3031
import com.cloud.host.Host;
3132
import com.cloud.host.HostVO;
3233
import com.cloud.host.dao.HostDao;
@@ -44,7 +45,6 @@
4445
import com.cloud.storage.dao.VolumeDao;
4546
import com.cloud.user.dao.UserDao;
4647
import com.cloud.utils.NumbersUtil;
47-
import com.cloud.utils.UriUtils;
4848
import com.cloud.utils.db.DB;
4949
import com.cloud.utils.exception.CloudRuntimeException;
5050
import com.cloud.vm.VirtualMachineManager;
@@ -67,10 +67,6 @@
6767
import org.apache.log4j.Logger;
6868

6969
import javax.inject.Inject;
70-
import java.io.UnsupportedEncodingException;
71-
import java.net.URI;
72-
import java.net.URISyntaxException;
73-
import java.net.URLDecoder;
7470
import java.util.ArrayList;
7571
import java.util.List;
7672
import java.util.Map;
@@ -138,64 +134,26 @@ public DataStore initialize(Map<String, Object> dsInfos) {
138134

139135
PrimaryDataStoreParameters parameters = new PrimaryDataStoreParameters();
140136

141-
UriUtils.UriInfo uriInfo = UriUtils.getUriInfo(url);
142-
143-
String scheme = uriInfo.getScheme();
144-
String storageHost = uriInfo.getStorageHost();
145-
String storagePath = uriInfo.getStoragePath();
146-
try {
147-
if (scheme == null) {
148-
throw new InvalidParameterValueException("scheme is null " + url + ", add nfs:// (or cifs://) as a prefix");
149-
} else if (scheme.equalsIgnoreCase("nfs")) {
150-
if (storageHost == null || storagePath == null || storageHost.trim().isEmpty() || storagePath.trim().isEmpty()) {
151-
throw new InvalidParameterValueException("host or path is null, should be nfs://hostname/path");
152-
}
153-
} else if (scheme.equalsIgnoreCase("cifs")) {
154-
// Don't validate against a URI encoded URI.
155-
URI cifsUri = new URI(url);
156-
String warnMsg = UriUtils.getCifsUriParametersProblems(cifsUri);
157-
if (warnMsg != null) {
158-
throw new InvalidParameterValueException(warnMsg);
159-
}
160-
} else if (scheme.equalsIgnoreCase("sharedMountPoint")) {
161-
if (storagePath == null) {
162-
throw new InvalidParameterValueException("host or path is null, should be sharedmountpoint://localhost/path");
163-
}
164-
} else if (scheme.equalsIgnoreCase("rbd")) {
165-
if (storagePath == null) {
166-
throw new InvalidParameterValueException("host or path is null, should be rbd://hostname/pool");
167-
}
168-
} else if (scheme.equalsIgnoreCase("gluster")) {
169-
if (storageHost == null || storagePath == null || storageHost.trim().isEmpty() || storagePath.trim().isEmpty()) {
170-
throw new InvalidParameterValueException("host or path is null, should be gluster://hostname/volume");
171-
}
172-
}
173-
} catch (URISyntaxException e) {
174-
throw new InvalidParameterValueException(url + " is not a valid uri");
175-
}
176-
177137
String tags = (String)dsInfos.get("tags");
178138
Map<String, String> details = (Map<String, String>)dsInfos.get("details");
179139

180140
parameters.setTags(tags);
181141
parameters.setDetails(details);
182142

183-
String hostPath = null;
184-
try {
185-
hostPath = URLDecoder.decode(storagePath, "UTF-8");
186-
} catch (UnsupportedEncodingException e) {
187-
s_logger.error("[ignored] we are on a platform not supporting \"UTF-8\"!?!", e);
188-
}
189-
if (hostPath == null) { // if decoding fails, use getPath() anyway
190-
hostPath = storagePath;
191-
}
143+
String scheme = dsInfos.get("scheme").toString();
144+
String storageHost = dsInfos.get("host").toString();
145+
String hostPath = dsInfos.get("hostPath").toString();
146+
String uri = String.format("%s://%s%s", scheme, storageHost, hostPath);
147+
192148
Object localStorage = dsInfos.get("localStorage");
193-
if (localStorage != null) {
194-
hostPath = hostPath.replaceFirst("/", "");
149+
if (localStorage != null) {
150+
hostPath = hostPath.contains("//") ? hostPath.replaceFirst("/", "") : hostPath;
195151
hostPath = hostPath.replace("+", " ");
196152
}
197-
String userInfo = uriInfo.getUserInfo();
198-
int port = uriInfo.getPort();
153+
154+
String userInfo = dsInfos.get("userInfo") != null ? dsInfos.get("userInfo").toString() : null;
155+
int port = dsInfos.get("port") != null ? Integer.parseInt(dsInfos.get("port").toString()) : -1;
156+
199157
if (s_logger.isDebugEnabled()) {
200158
s_logger.debug("createPool Params @ scheme - " + scheme + " storageHost - " + storageHost + " hostPath - " + hostPath + " port - " + port);
201159
}
@@ -312,16 +270,16 @@ public DataStore initialize(Map<String, Object> dsInfos) {
312270
parameters.setPort(0);
313271
parameters.setPath(hostPath);
314272
} else {
315-
s_logger.warn("Unable to figure out the scheme for URI: " + uriInfo);
316-
throw new IllegalArgumentException("Unable to figure out the scheme for URI: " + uriInfo);
273+
s_logger.warn("Unable to figure out the scheme for URI: " + scheme);
274+
throw new IllegalArgumentException("Unable to figure out the scheme for URI: " + scheme);
317275
}
318276
}
319277

320278
if (localStorage == null) {
321279
List<StoragePoolVO> pools = primaryDataStoreDao.listPoolByHostPath(storageHost, hostPath);
322280
if (!pools.isEmpty() && !scheme.equalsIgnoreCase("sharedmountpoint")) {
323281
Long oldPodId = pools.get(0).getPodId();
324-
throw new CloudRuntimeException("Storage pool " + uriInfo + " already in use by another pod (id=" + oldPodId + ")");
282+
throw new CloudRuntimeException("Storage pool " + hostPath + " already in use by another pod (id=" + oldPodId + ")");
325283
}
326284
}
327285

@@ -550,7 +508,16 @@ private HypervisorType getHypervisorType(long hostId) {
550508

551509
@Override
552510
public boolean attachHost(DataStore store, HostScope scope, StoragePoolInfo existingInfo) {
553-
dataStoreHelper.attachHost(store, scope, existingInfo);
511+
DataStore dataStore = dataStoreHelper.attachHost(store, scope, existingInfo);
512+
if(existingInfo.getCapacityBytes() == 0){
513+
try {
514+
storageMgr.connectHostToSharedPool(scope.getScopeId(), dataStore.getId());
515+
} catch (StorageUnavailableException ex) {
516+
s_logger.error("Storage unavailable ",ex);
517+
} catch (StorageConflictException ex) {
518+
s_logger.error("Storage already exists ",ex);
519+
}
520+
}
554521
return true;
555522
}
556523

server/src/main/java/com/cloud/api/query/QueryManagerImpl.java

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2793,10 +2793,29 @@ private Pair<List<AsyncJobJoinVO>, Integer> searchForAsyncJobsInternal(ListAsync
27932793

27942794
@Override
27952795
public ListResponse<StoragePoolResponse> searchForStoragePools(ListStoragePoolsCmd cmd) {
2796-
Pair<List<StoragePoolJoinVO>, Integer> result = searchForStoragePoolsInternal(cmd);
2797-
ListResponse<StoragePoolResponse> response = new ListResponse<StoragePoolResponse>();
2796+
Pair<List<StoragePoolJoinVO>, Integer> result = cmd.getHostId() != null ? searchForLocalStorages(cmd) : searchForStoragePoolsInternal(cmd);
2797+
return createStoragesPoolResponse(result);
2798+
}
2799+
2800+
private Pair<List<StoragePoolJoinVO>, Integer> searchForLocalStorages(ListStoragePoolsCmd cmd) {
2801+
long id = cmd.getHostId();
2802+
String scope = ScopeType.HOST.toString();
2803+
Pair<List<StoragePoolJoinVO>, Integer> localStorages;
2804+
2805+
ListHostsCmd listHostsCmd = new ListHostsCmd();
2806+
listHostsCmd.setId(id);
2807+
Pair<List<HostJoinVO>, Integer> hosts = searchForServersInternal(listHostsCmd);
2808+
2809+
cmd.setScope(scope);
2810+
localStorages = searchForStoragePoolsInternal(cmd);
27982811

2799-
List<StoragePoolResponse> poolResponses = ViewResponseHelper.createStoragePoolResponse(result.first().toArray(new StoragePoolJoinVO[result.first().size()]));
2812+
return localStorages;
2813+
}
2814+
2815+
private ListResponse<StoragePoolResponse> createStoragesPoolResponse(Pair<List<StoragePoolJoinVO>, Integer> storagePools) {
2816+
ListResponse<StoragePoolResponse> response = new ListResponse<>();
2817+
2818+
List<StoragePoolResponse> poolResponses = ViewResponseHelper.createStoragePoolResponse(storagePools.first().toArray(new StoragePoolJoinVO[storagePools.first().size()]));
28002819
for (StoragePoolResponse poolResponse : poolResponses) {
28012820
DataStore store = dataStoreManager.getPrimaryDataStore(poolResponse.getId());
28022821
if (store != null) {
@@ -2816,7 +2835,7 @@ public ListResponse<StoragePoolResponse> searchForStoragePools(ListStoragePoolsC
28162835
}
28172836
}
28182837

2819-
response.setResponses(poolResponses, result.second());
2838+
response.setResponses(poolResponses, storagePools.second());
28202839
return response;
28212840
}
28222841

0 commit comments

Comments
 (0)