Skip to content

Commit 45a74d0

Browse files
committed
Linstor: add HA support and small cleanups (apache#8407)
* linstor: Outline get storagepools from resourcegroup into function * linstor: move getHostname() to kvm/Pool and reimplement * linstor: implement CloudStack HA support
1 parent e15f926 commit 45a74d0

File tree

5 files changed

+71
-78
lines changed

5 files changed

+71
-78
lines changed

plugins/storage/volume/linstor/src/main/java/com/cloud/hypervisor/kvm/storage/LinstorStorageAdaptor.java

Lines changed: 3 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,11 @@
1616
// under the License.
1717
package com.cloud.hypervisor.kvm.storage;
1818

19-
import java.io.BufferedReader;
20-
import java.io.IOException;
21-
import java.io.InputStreamReader;
2219
import java.util.Collections;
2320
import java.util.HashMap;
2421
import java.util.List;
2522
import java.util.Map;
2623
import java.util.Optional;
27-
import java.util.StringJoiner;
2824

2925
import javax.annotation.Nonnull;
3026

@@ -40,7 +36,6 @@
4036
import com.linbit.linstor.api.model.ProviderKind;
4137
import com.linbit.linstor.api.model.ResourceDefinition;
4238
import com.linbit.linstor.api.model.ResourceDefinitionModify;
43-
import com.linbit.linstor.api.model.ResourceGroup;
4439
import com.linbit.linstor.api.model.ResourceGroupSpawn;
4540
import com.linbit.linstor.api.model.ResourceMakeAvailable;
4641
import com.linbit.linstor.api.model.ResourceWithVolumes;
@@ -69,28 +64,6 @@ private static String getLinstorRscName(String name) {
6964
return LinstorUtil.RSC_PREFIX + name;
7065
}
7166

72-
private String getHostname() {
73-
// either there is already some function for that in the agent or a better way.
74-
ProcessBuilder pb = new ProcessBuilder("hostname");
75-
try
76-
{
77-
String result;
78-
Process p = pb.start();
79-
final BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
80-
81-
StringJoiner sj = new StringJoiner(System.getProperty("line.separator"));
82-
reader.lines().iterator().forEachRemaining(sj::add);
83-
result = sj.toString();
84-
85-
p.waitFor();
86-
p.destroy();
87-
return result.trim();
88-
} catch (IOException | InterruptedException exc) {
89-
Thread.currentThread().interrupt();
90-
throw new CloudRuntimeException("Unable to run 'hostname' command.");
91-
}
92-
}
93-
9467
private void logLinstorAnswer(@Nonnull ApiCallRc answer) {
9568
if (answer.isError()) {
9669
s_logger.error(answer.getMessage());
@@ -121,7 +94,7 @@ private void handleLinstorApiAnswers(ApiCallRcList answers, String excMessage) {
12194
}
12295

12396
public LinstorStorageAdaptor() {
124-
localNodeName = getHostname();
97+
localNodeName = LinstorStoragePool.getHostname();
12598
}
12699

127100
@Override
@@ -504,25 +477,7 @@ public long getAvailable(LinstorStoragePool pool) {
504477
DevelopersApi linstorApi = getLinstorAPI(pool);
505478
final String rscGroupName = pool.getResourceGroup();
506479
try {
507-
List<ResourceGroup> rscGrps = linstorApi.resourceGroupList(
508-
Collections.singletonList(rscGroupName),
509-
null,
510-
null,
511-
null);
512-
513-
if (rscGrps.isEmpty()) {
514-
final String errMsg = String.format("Linstor: Resource group '%s' not found", rscGroupName);
515-
s_logger.error(errMsg);
516-
throw new CloudRuntimeException(errMsg);
517-
}
518-
519-
List<StoragePool> storagePools = linstorApi.viewStoragePools(
520-
Collections.emptyList(),
521-
rscGrps.get(0).getSelectFilter().getStoragePoolList(),
522-
null,
523-
null,
524-
null
525-
);
480+
List<StoragePool> storagePools = LinstorUtil.getRscGroupStoragePools(linstorApi, rscGroupName);
526481

527482
final long free = storagePools.stream()
528483
.filter(sp -> sp.getProviderKind() != ProviderKind.DISKLESS)
@@ -540,25 +495,7 @@ public long getUsed(LinstorStoragePool pool) {
540495
DevelopersApi linstorApi = getLinstorAPI(pool);
541496
final String rscGroupName = pool.getResourceGroup();
542497
try {
543-
List<ResourceGroup> rscGrps = linstorApi.resourceGroupList(
544-
Collections.singletonList(rscGroupName),
545-
null,
546-
null,
547-
null);
548-
549-
if (rscGrps.isEmpty()) {
550-
final String errMsg = String.format("Linstor: Resource group '%s' not found", rscGroupName);
551-
s_logger.error(errMsg);
552-
throw new CloudRuntimeException(errMsg);
553-
}
554-
555-
List<StoragePool> storagePools = linstorApi.viewStoragePools(
556-
Collections.emptyList(),
557-
rscGrps.get(0).getSelectFilter().getStoragePoolList(),
558-
null,
559-
null,
560-
null
561-
);
498+
List<StoragePool> storagePools = LinstorUtil.getRscGroupStoragePools(linstorApi, rscGroupName);
562499

563500
final long used = storagePools.stream()
564501
.filter(sp -> sp.getProviderKind() != ProviderKind.DISKLESS)

plugins/storage/volume/linstor/src/main/java/com/cloud/hypervisor/kvm/storage/LinstorStoragePool.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,22 @@
2020
import java.util.Map;
2121

2222
import com.cloud.storage.Storage;
23+
import com.cloud.utils.exception.CloudRuntimeException;
24+
import com.cloud.utils.script.OutputInterpreter;
25+
import com.cloud.utils.script.Script;
2326
import org.apache.cloudstack.utils.qemu.QemuImg;
27+
import org.apache.log4j.Logger;
28+
import org.joda.time.Duration;
2429

2530
public class LinstorStoragePool implements KVMStoragePool {
31+
private static final Logger s_logger = Logger.getLogger(LinstorStoragePool.class);
2632
private final String _uuid;
2733
private final String _sourceHost;
2834
private final int _sourcePort;
2935
private final Storage.StoragePoolType _storagePoolType;
3036
private final StorageAdaptor _storageAdaptor;
3137
private final String _resourceGroup;
38+
private final String localNodeName;
3239

3340
public LinstorStoragePool(String uuid, String host, int port, String resourceGroup,
3441
Storage.StoragePoolType storagePoolType, StorageAdaptor storageAdaptor) {
@@ -38,6 +45,7 @@ public LinstorStoragePool(String uuid, String host, int port, String resourceGro
3845
_storagePoolType = storagePoolType;
3946
_storageAdaptor = storageAdaptor;
4047
_resourceGroup = resourceGroup;
48+
localNodeName = getHostname();
4149
}
4250

4351
@Override
@@ -193,4 +201,15 @@ public Map<String, String> getDetails() {
193201
public String getResourceGroup() {
194202
return _resourceGroup;
195203
}
204+
205+
static String getHostname() {
206+
OutputInterpreter.AllLinesParser parser = new OutputInterpreter.AllLinesParser();
207+
Script sc = new Script("hostname", Duration.millis(10000L), s_logger);
208+
String res = sc.execute(parser);
209+
if (res != null) {
210+
throw new CloudRuntimeException(String.format("Unable to run 'hostname' command: %s", res));
211+
}
212+
String response = parser.getLines();
213+
return response.trim();
214+
}
196215
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package org.apache.cloudstack.storage.datastore.provider;
18+
19+
import com.cloud.exception.StorageConflictException;
20+
import com.cloud.host.HostVO;
21+
22+
public class LinstorHostListener extends DefaultHostListener {
23+
@Override
24+
public boolean hostConnect(long hostId, long poolId) throws StorageConflictException {
25+
HostVO host = hostDao.findById(hostId);
26+
if (host.getParent() == null) {
27+
host.setParent(host.getName());
28+
hostDao.update(host.getId(), host);
29+
}
30+
return super.hostConnect(hostId, poolId);
31+
}
32+
}

plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/provider/LinstorPrimaryDatastoreProviderImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public DataStoreLifeCycle getDataStoreLifeCycle() {
4848
public boolean configure(Map<String, Object> params) {
4949
lifecycle = ComponentContext.inject(LinstorPrimaryDataStoreLifeCycleImpl.class);
5050
driver = ComponentContext.inject(LinstorPrimaryDataStoreDriverImpl.class);
51-
listener = ComponentContext.inject(DefaultHostListener.class);
51+
listener = ComponentContext.inject(LinstorHostListener.class);
5252
return true;
5353
}
5454

plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/util/LinstorUtil.java

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -137,28 +137,33 @@ public static String getSnapshotPath(com.linbit.linstor.api.model.StoragePool sp
137137
return path;
138138
}
139139

140-
public static long getCapacityBytes(String linstorUrl, String rscGroupName) {
141-
DevelopersApi linstorApi = getLinstorAPI(linstorUrl);
142-
try {
143-
List<ResourceGroup> rscGrps = linstorApi.resourceGroupList(
140+
public static List<StoragePool> getRscGroupStoragePools(DevelopersApi api, String rscGroupName)
141+
throws ApiException {
142+
List<ResourceGroup> rscGrps = api.resourceGroupList(
144143
Collections.singletonList(rscGroupName),
145144
null,
146145
null,
147146
null);
148147

149-
if (rscGrps.isEmpty()) {
150-
final String errMsg = String.format("Linstor: Resource group '%s' not found", rscGroupName);
151-
s_logger.error(errMsg);
152-
throw new CloudRuntimeException(errMsg);
153-
}
148+
if (rscGrps.isEmpty()) {
149+
final String errMsg = String.format("Linstor: Resource group '%s' not found", rscGroupName);
150+
s_logger.error(errMsg);
151+
throw new CloudRuntimeException(errMsg);
152+
}
154153

155-
List<StoragePool> storagePools = linstorApi.viewStoragePools(
154+
return api.viewStoragePools(
156155
Collections.emptyList(),
157156
rscGrps.get(0).getSelectFilter().getStoragePoolList(),
158157
null,
159158
null,
160159
null
161-
);
160+
);
161+
}
162+
163+
public static long getCapacityBytes(String linstorUrl, String rscGroupName) {
164+
DevelopersApi linstorApi = getLinstorAPI(linstorUrl);
165+
try {
166+
List<StoragePool> storagePools = getRscGroupStoragePools(linstorApi, rscGroupName);
162167

163168
return storagePools.stream()
164169
.filter(sp -> sp.getProviderKind() != ProviderKind.DISKLESS)

0 commit comments

Comments
 (0)