Skip to content

Commit e55d016

Browse files
author
Glover, Rene (rg9975)
committed
various fixes for fiberchannel and autoscale prefix option
1 parent 5790091 commit e55d016

File tree

16 files changed

+677
-216
lines changed

16 files changed

+677
-216
lines changed

engine/schema/pom.xml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
</dependencies>
7474
<executions>
7575
<execution>
76+
<?m2e execute onConfiguration,onIncremental?>
7677
<id>setproperty</id>
7778
<phase>validate</phase>
7879
<goals>
@@ -90,6 +91,7 @@
9091
</configuration>
9192
</execution>
9293
<execution>
94+
<?m2e execute onConfiguration,onIncremental?>
9395
<id>set-properties</id>
9496
<phase>generate-sources</phase>
9597
<goals>
@@ -106,7 +108,7 @@
106108
templateList.add("systemvmtemplate-${csVersion}.${patch}-x86_64-xen")
107109
templateList.add("systemvmtemplate-${csVersion}.${patch}-x86_64-ovm")
108110
templateList.add("systemvmtemplate-${csVersion}.${patch}-x86_64-hyperv")
109-
File file = new File("./engine/schema/dist/systemvm-templates/md5sum.txt")
111+
File file = new File("${basedir}/../../engine/schema/dist/systemvm-templates/md5sum.txt")
110112
def lines = file.readLines()
111113
for (template in templateList) {
112114
def data = lines.findAll { it.contains(template) }
@@ -128,6 +130,7 @@
128130
<artifactId>download-maven-plugin</artifactId>
129131
<version>1.6.3</version>
130132
<executions>
133+
<?m2e execute onConfiguration,onIncremental?>
131134
<execution>
132135
<id>download-checksums</id>
133136
<phase>validate</phase>
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
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 com.cloud.hypervisor.kvm.storage;
18+
19+
import java.util.Map;
20+
21+
/**
22+
* Decorator for StorageAdapters that implement asynchronous physical disk connections to improve
23+
* performance on VM starts with large numbers of disks.
24+
*/
25+
public interface AsyncPhysicalDiskConnectorDecorator {
26+
/**
27+
* Initiates a connection attempt (may or may not complete it depending on implementation)
28+
* @param path
29+
* @param pool
30+
* @param details
31+
* @return
32+
*/
33+
public boolean startConnectPhysicalDisk(String path, KVMStoragePool pool, Map<String,String> details);
34+
35+
/**
36+
* Tests if the physical disk is connected
37+
* @param path
38+
* @param pool
39+
* @param details
40+
* @return
41+
*/
42+
public boolean isConnected(String path, KVMStoragePool pool, Map<String,String> details);
43+
44+
/**
45+
* Completes a connection attempt after isConnected returns true;
46+
* @param path
47+
* @param pool
48+
* @param details
49+
* @return
50+
* @throws Exception
51+
*/
52+
public boolean finishConnectPhysicalDisk(String path, KVMStoragePool pool, Map<String,String> details) throws Exception;
53+
}

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStoragePoolManager.java

Lines changed: 86 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.lang.reflect.Modifier;
2121
import java.net.URI;
2222
import java.net.URISyntaxException;
23+
import java.util.ArrayList;
2324
import java.util.Arrays;
2425
import java.util.HashMap;
2526
import java.util.List;
@@ -42,9 +43,11 @@
4243
import com.cloud.hypervisor.kvm.resource.KVMHABase.PoolType;
4344
import com.cloud.hypervisor.kvm.resource.KVMHAMonitor;
4445
import com.cloud.storage.Storage;
46+
import com.cloud.storage.StorageManager;
4547
import com.cloud.storage.Storage.StoragePoolType;
4648
import com.cloud.storage.StorageLayer;
4749
import com.cloud.storage.Volume;
50+
import com.cloud.utils.StringUtils;
4851
import com.cloud.utils.Pair;
4952
import com.cloud.utils.Ternary;
5053
import com.cloud.utils.exception.CloudRuntimeException;
@@ -164,13 +167,30 @@ public boolean connectPhysicalDisk(StoragePoolType type, String poolUuid, String
164167
return adaptor.connectPhysicalDisk(volPath, pool, details, false);
165168
}
166169

170+
private static class ConnectingDiskInfo {
171+
ConnectingDiskInfo(VolumeObjectTO volume, StorageAdaptor adaptor, KVMStoragePool pool, Map<String, String> details) {
172+
this.volume = volume;
173+
this.adapter = adaptor;
174+
this.pool = pool;
175+
this.details = details;
176+
}
177+
VolumeObjectTO volume;
178+
KVMStoragePool pool = null;
179+
StorageAdaptor adapter = null;
180+
Map<String,String> details = null;
181+
}
182+
167183
public boolean connectPhysicalDisksViaVmSpec(VirtualMachineTO vmSpec, boolean isVMMigrate) {
168184
boolean result = false;
169185

170186
final String vmName = vmSpec.getName();
171187

172188
List<DiskTO> disks = Arrays.asList(vmSpec.getDisks());
173189

190+
191+
// disks that connect in background
192+
List<ConnectingDiskInfo> connectingDisks = new ArrayList<>();
193+
174194
for (DiskTO disk : disks) {
175195
if (disk.getType() == Volume.Type.ISO) {
176196
result = true;
@@ -187,17 +207,79 @@ public boolean connectPhysicalDisksViaVmSpec(VirtualMachineTO vmSpec, boolean is
187207
KVMStoragePool pool = getStoragePool(store.getPoolType(), store.getUuid());
188208
StorageAdaptor adaptor = getStorageAdaptor(pool.getType());
189209

190-
result = adaptor.connectPhysicalDisk(vol.getPath(), pool, disk.getDetails(), isVMMigrate);
210+
if (adaptor instanceof AsyncPhysicalDiskConnectorDecorator) {
211+
// If the adaptor supports async disk connection, we can start the connection
212+
// and return immediately, allowing the connection to complete in the background.
213+
result = ((AsyncPhysicalDiskConnectorDecorator) adaptor).startConnectPhysicalDisk(vol.getPath(), pool, disk.getDetails());
214+
if (!result) {
215+
logger.error("Failed to start connecting disks via vm spec for vm: " + vmName + " volume:" + vol.toString());
216+
return false;
217+
}
191218

192-
if (!result) {
193-
logger.error("Failed to connect disks via vm spec for vm: " + vmName + " volume:" + vol.toString());
194-
return result;
219+
// add disk to list of disks to check later
220+
connectingDisks.add(new ConnectingDiskInfo(vol, adaptor, pool, disk.getDetails()));
221+
} else {
222+
result = adaptor.connectPhysicalDisk(vol.getPath(), pool, disk.getDetails(), isVMMigrate);
223+
224+
if (!result) {
225+
logger.error("Failed to connect disks via vm spec for vm: " + vmName + " volume:" + vol.toString());
226+
return result;
227+
}
228+
}
229+
}
230+
231+
// if we have any connecting disks to check, wait for them to connect or timeout
232+
if (!connectingDisks.isEmpty()) {
233+
for (ConnectingDiskInfo connectingDisk : connectingDisks) {
234+
StorageAdaptor adaptor = connectingDisk.adapter;
235+
KVMStoragePool pool = connectingDisk.pool;
236+
VolumeObjectTO volume = connectingDisk.volume;
237+
Map<String, String> details = connectingDisk.details;
238+
long diskWaitTimeMillis = getDiskWaitTimeMillis(details);
239+
240+
// wait for the disk to connect
241+
long startTime = System.currentTimeMillis();
242+
while (System.currentTimeMillis() - startTime < diskWaitTimeMillis) {
243+
if (((AsyncPhysicalDiskConnectorDecorator) adaptor).isConnected(volume.getPath(), pool, details)) {
244+
logger.debug(String.format("Disk %s connected successfully for VM %s", volume.getPath(), vmName));
245+
break;
246+
}
247+
248+
sleep(1000); // wait for 1 second before checking again
249+
}
195250
}
196251
}
197252

198253
return result;
199254
}
200255

256+
private long getDiskWaitTimeMillis(Map<String,String> details) {
257+
int waitTimeInSec = 60; // default wait time in seconds
258+
if (details != null && details.containsKey(StorageManager.STORAGE_POOL_DISK_WAIT.toString())) {
259+
String waitTime = details.get(StorageManager.STORAGE_POOL_DISK_WAIT.toString());
260+
if (StringUtils.isNotEmpty(waitTime)) {
261+
waitTimeInSec = Integer.valueOf(waitTime).intValue();
262+
logger.debug(String.format("%s set to %s", waitTimeInSec, StorageManager.STORAGE_POOL_DISK_WAIT.toString()));
263+
}
264+
} else {
265+
// wait at least 60 seconds even if input was lower
266+
if (waitTimeInSec < 60) {
267+
logger.debug(String.format("%s was less than 60s. Increasing to 60s default.", StorageManager.STORAGE_POOL_DISK_WAIT.toString()));
268+
waitTimeInSec = 60;
269+
}
270+
}
271+
return waitTimeInSec * 1000; // convert to milliseconds
272+
}
273+
274+
private boolean sleep(long millis) {
275+
try {
276+
Thread.sleep(millis);
277+
return true;
278+
} catch (InterruptedException e) {
279+
return false;
280+
}
281+
}
282+
201283
public boolean disconnectPhysicalDisk(Map<String, String> volumeToDisconnect) {
202284
logger.debug(String.format("Disconnect physical disks using volume map: %s", volumeToDisconnect.toString()));
203285
if (MapUtils.isEmpty(volumeToDisconnect)) {

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1608,8 +1608,20 @@ public Answer dettachVolume(final DettachCommand cmd) {
16081608
storagePoolMgr.disconnectPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), vol.getPath());
16091609

16101610
return new DettachAnswer(disk);
1611-
} catch (final LibvirtException | InternalErrorException | CloudRuntimeException e) {
1612-
logger.debug(String.format("Failed to detach volume [id: %d, uuid: %s, name: %s, path: %s], due to ", vol.getId(), vol.getUuid(), vol.getName(), vol.getPath()), e);
1611+
} catch (final LibvirtException e) {
1612+
// check if the error was related to an already unplugged event - we can safely ignore
1613+
if (e.getMessage() != null && e.getMessage().contains("is already in the process of unplug")) {
1614+
logger.debug("Volume: " + vol.getPath() + " is already unplugged, ignoring the error");
1615+
return new DettachAnswer(disk);
1616+
} else {
1617+
logger.debug("Failed to detach volume: " + vol.getPath() + ", due to ", e);
1618+
return new DettachAnswer(e.toString());
1619+
}
1620+
} catch (final InternalErrorException e) {
1621+
logger.debug("Failed to detach volume: " + vol.getPath() + ", due to ", e);
1622+
return new DettachAnswer(e.toString());
1623+
} catch (final CloudRuntimeException e) {
1624+
logger.debug("Failed to detach volume: " + vol.getPath() + ", due to ", e);
16131625
return new DettachAnswer(e.toString());
16141626
} finally {
16151627
vol.clearPassphrase();

0 commit comments

Comments
 (0)