Skip to content

Commit 0ffdb9a

Browse files
[CLOUDSTACK-10241] Duplicated file SRs being created in XenServer pools
Due to a race condition between multiple management servers, in some rare cases, CloudStack is creating multiple file SRs to the same secondary folder. This causes a problem when introducing the SR to the XenServer pools, as “there will be VDIs with duplicated UUIDs“. The VDIs are the same, but they are seen in different SRs, and therefore cause an error. The solution to avoid race conditions between management servers is to use a deterministic srUuid for the file SR to be created (we are leaving XenServer with the burden of managing race conditions). The UUID is based on the SR file path and is generated using UUID#nameUUIDFromBytes. Therefore, if there is an SR with the generated UUID, this means that some other management server has just created it. An exception will occur and it will contain a message saying 'Db_exn.Uniqueness_constraint_violation'. In these unlikely events, we catch the exception and use the method retrieveAlreadyConfiguredSrWithoutException to get the SR that has already been created for the given mount point.
1 parent bc1b5fb commit 0ffdb9a

4 files changed

Lines changed: 761 additions & 214 deletions

File tree

plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java

Lines changed: 82 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,52 @@
1717
package com.cloud.hypervisor.xenserver.resource;
1818

1919

20+
import java.io.BufferedReader;
21+
import java.io.BufferedWriter;
22+
import java.io.File;
23+
import java.io.FileOutputStream;
24+
import java.io.IOException;
25+
import java.io.InputStreamReader;
26+
import java.io.OutputStreamWriter;
27+
import java.net.MalformedURLException;
28+
import java.net.URI;
29+
import java.net.URISyntaxException;
30+
import java.net.URL;
31+
import java.net.URLConnection;
32+
import java.nio.charset.Charset;
33+
import java.util.ArrayList;
34+
import java.util.Date;
35+
import java.util.HashMap;
36+
import java.util.HashSet;
37+
import java.util.Iterator;
38+
import java.util.LinkedList;
39+
import java.util.List;
40+
import java.util.Map;
41+
import java.util.Objects;
42+
import java.util.Properties;
43+
import java.util.Queue;
44+
import java.util.Random;
45+
import java.util.Set;
46+
import java.util.UUID;
47+
import java.util.concurrent.TimeoutException;
48+
49+
import javax.naming.ConfigurationException;
50+
import javax.xml.parsers.DocumentBuilderFactory;
51+
import javax.xml.parsers.ParserConfigurationException;
52+
53+
import org.apache.cloudstack.storage.to.TemplateObjectTO;
54+
import org.apache.cloudstack.storage.to.VolumeObjectTO;
2055
import org.apache.commons.collections.MapUtils;
56+
import org.apache.commons.io.FileUtils;
57+
import org.apache.log4j.Logger;
58+
import org.apache.xmlrpc.XmlRpcException;
59+
import org.joda.time.Duration;
60+
import org.w3c.dom.Document;
61+
import org.w3c.dom.Node;
62+
import org.w3c.dom.NodeList;
63+
import org.xml.sax.InputSource;
64+
import org.xml.sax.SAXException;
65+
2166
import com.cloud.agent.IAgentControl;
2267
import com.cloud.agent.api.Answer;
2368
import com.cloud.agent.api.Command;
@@ -112,49 +157,6 @@
112157
import com.xensource.xenapi.VLAN;
113158
import com.xensource.xenapi.VM;
114159
import com.xensource.xenapi.XenAPIObject;
115-
import org.apache.cloudstack.storage.to.TemplateObjectTO;
116-
import org.apache.cloudstack.storage.to.VolumeObjectTO;
117-
import org.apache.commons.io.FileUtils;
118-
import org.apache.log4j.Logger;
119-
import org.apache.xmlrpc.XmlRpcException;
120-
import org.joda.time.Duration;
121-
import org.w3c.dom.Document;
122-
import org.w3c.dom.Node;
123-
import org.w3c.dom.NodeList;
124-
import org.xml.sax.InputSource;
125-
import org.xml.sax.SAXException;
126-
127-
import javax.naming.ConfigurationException;
128-
import javax.xml.parsers.DocumentBuilderFactory;
129-
import javax.xml.parsers.ParserConfigurationException;
130-
import java.io.BufferedReader;
131-
import java.io.BufferedWriter;
132-
import java.io.File;
133-
import java.io.FileOutputStream;
134-
import java.io.IOException;
135-
import java.io.InputStreamReader;
136-
import java.io.OutputStreamWriter;
137-
import java.net.MalformedURLException;
138-
import java.net.URI;
139-
import java.net.URISyntaxException;
140-
import java.net.URL;
141-
import java.net.URLConnection;
142-
import java.nio.charset.Charset;
143-
import java.util.ArrayList;
144-
import java.util.Date;
145-
import java.util.HashMap;
146-
import java.util.HashSet;
147-
import java.util.Iterator;
148-
import java.util.LinkedList;
149-
import java.util.List;
150-
import java.util.Map;
151-
import java.util.Objects;
152-
import java.util.Properties;
153-
import java.util.Queue;
154-
import java.util.Random;
155-
import java.util.Set;
156-
import java.util.UUID;
157-
import java.util.concurrent.TimeoutException;
158160

159161
/**
160162
* CitrixResourceBase encapsulates the calls to the XenServer Xapi process to
@@ -239,7 +241,7 @@ private static boolean isAlienVm(final VM vm, final Connection conn) throws XenA
239241
protected String _guestNetworkName;
240242
protected int _heartbeatInterval = 60;
241243
protected int _heartbeatTimeout = 120;
242-
protected final XsHost _host = new XsHost();
244+
protected XsHost _host = new XsHost();
243245
protected String _instance; // instance name (default is usually "VM")
244246
protected boolean _isOvs = false;
245247
protected String _linkLocalPrivateNetworkName;
@@ -1158,7 +1160,7 @@ public VBD createVbd(final Connection conn, final DiskTO volume, final String vm
11581160
vbdr.userdevice = "autodetect";
11591161
final Long deviceId = volume.getDiskSeq();
11601162
if (deviceId != null && (!isDeviceUsed(conn, vm, deviceId) || deviceId > 3)) {
1161-
vbdr.userdevice = deviceId.toString();
1163+
vbdr.userdevice = deviceId.toString();
11621164
}
11631165
}
11641166
final VBD vbd = VBD.create(conn, vbdr);
@@ -1342,7 +1344,7 @@ public VM createVmFromTemplate(final Connection conn, final VirtualMachineTO vmS
13421344

13431345
final Integer speed = vmSpec.getMinSpeed();
13441346
if (speed != null) {
1345-
int cpuWeight = _maxWeight; // cpu_weight
1347+
int cpuWeight = _maxWeight; // cpu_weight
13461348
int utilization = 0; // max CPU cap, default is unlimited
13471349

13481350
// weight based allocation, CPU weight is calculated per VCPU
@@ -1855,7 +1857,7 @@ protected void fillHostInfo(final Connection conn, final StartupRoutingCommand c
18551857
boolean supportsClonedVolumes = result != null && result.first() != null && result.first() &&
18561858
result.second() != null && result.second().length() > 0;
18571859

1858-
cmd.setSupportsClonedVolumes(supportsClonedVolumes);
1860+
cmd.setSupportsClonedVolumes(supportsClonedVolumes);
18591861
} catch (NumberFormatException ex) {
18601862
s_logger.warn("Issue sending 'xe sm-list' via SSH to XenServer host: " + ex.getMessage());
18611863
}
@@ -2497,34 +2499,34 @@ private String resignatureIscsiSr(Connection conn, Host host, Map<String, String
24972499
}
24982500

24992501
private void checkIfIscsiSrExisits(Connection conn, String srNameLabel, String target, String targetiqn, String lunid) throws XenAPIException, XmlRpcException {
2500-
final Set<SR> srs = SR.getByNameLabel(conn, srNameLabel);
2501-
for (final SR sr : srs) {
2502-
if (!(SRType.LVMOISCSI.equals(sr.getType(conn)))) {
2503-
continue;
2504-
}
2505-
final Set<PBD> pbds = sr.getPBDs(conn);
2506-
if (pbds.isEmpty()) {
2507-
continue;
2508-
}
2509-
final PBD pbd = pbds.iterator().next();
2510-
final Map<String, String> dc = pbd.getDeviceConfig(conn);
2511-
if (dc == null) {
2512-
continue;
2513-
}
2514-
if (dc.get("target") == null) {
2515-
continue;
2516-
}
2517-
if (dc.get("targetIQN") == null) {
2518-
continue;
2519-
}
2520-
if (dc.get("lunid") == null) {
2521-
continue;
2522-
}
2523-
if (target.equals(dc.get("target")) && targetiqn.equals(dc.get("targetIQN")) && lunid.equals(dc.get("lunid"))) {
2524-
throw new CloudRuntimeException("There is a SR using the same configuration target:" + dc.get("target") + ", targetIQN:" + dc.get("targetIQN")
2525-
+ ", lunid:" + dc.get("lunid") + " for pool " + srNameLabel + "on host:" + _host.getUuid());
2526-
}
2527-
}
2502+
final Set<SR> srs = SR.getByNameLabel(conn, srNameLabel);
2503+
for (final SR sr : srs) {
2504+
if (!(SRType.LVMOISCSI.equals(sr.getType(conn)))) {
2505+
continue;
2506+
}
2507+
final Set<PBD> pbds = sr.getPBDs(conn);
2508+
if (pbds.isEmpty()) {
2509+
continue;
2510+
}
2511+
final PBD pbd = pbds.iterator().next();
2512+
final Map<String, String> dc = pbd.getDeviceConfig(conn);
2513+
if (dc == null) {
2514+
continue;
2515+
}
2516+
if (dc.get("target") == null) {
2517+
continue;
2518+
}
2519+
if (dc.get("targetIQN") == null) {
2520+
continue;
2521+
}
2522+
if (dc.get("lunid") == null) {
2523+
continue;
2524+
}
2525+
if (target.equals(dc.get("target")) && targetiqn.equals(dc.get("targetIQN")) && lunid.equals(dc.get("lunid"))) {
2526+
throw new CloudRuntimeException("There is a SR using the same configuration target:" + dc.get("target") + ", targetIQN:" + dc.get("targetIQN")
2527+
+ ", lunid:" + dc.get("lunid") + " for pool " + srNameLabel + "on host:" + _host.getUuid());
2528+
}
2529+
}
25282530

25292531
}
25302532

@@ -2795,7 +2797,7 @@ protected XsLocalNetwork getManagementNetwork(final Connection conn) throws XmlR
27952797
final Bond bond = mgmtPifRec.bondSlaveOf;
27962798
if (!isRefNull(bond)) {
27972799
final String msg = "Management interface is on slave(" + mgmtPifRec.uuid + ") of bond(" + bond.getUuid(conn) + ") on host(" + _host.getUuid()
2798-
+ "), please move management interface to bond!";
2800+
+ "), please move management interface to bond!";
27992801
s_logger.warn(msg);
28002802
throw new CloudRuntimeException(msg);
28012803
}
@@ -3015,7 +3017,7 @@ public SR getNfsSR(final Connection conn, final String poolid, final String uuid
30153017

30163018
if (server.equals(dc.get("server")) && serverpath.equals(dc.get("serverpath"))) {
30173019
throw new CloudRuntimeException("There is a SR using the same configuration server:" + dc.get("server") + ", serverpath:" + dc.get("serverpath")
3018-
+ " for pool " + uuid + " on host:" + _host.getUuid());
3020+
+ " for pool " + uuid + " on host:" + _host.getUuid());
30193021
}
30203022

30213023
}
@@ -3404,7 +3406,7 @@ public long getVMSnapshotChainSize(final Connection conn, final VolumeObjectTO v
34043406
s_logger.debug("memoryVDI size+parent :"+size);
34053407
}
34063408
}
3407-
} catch (Exception e) {
3409+
} catch (Exception e) {
34083410
s_logger.debug("Exception occurs when calculate snapshot capacity for memory: due to " + e.toString());
34093411
continue;
34103412
}
@@ -5308,8 +5310,8 @@ public boolean createVmdataFiles(final String vmName, final List<String[]> vmDat
53085310
if (result && content != null && !content.isEmpty()) {
53095311
File file = new File(folder+"/"+fileName+".txt");
53105312
try (OutputStreamWriter fw = new OutputStreamWriter(new FileOutputStream(file.getAbsoluteFile()),"UTF-8");
5311-
BufferedWriter bw = new BufferedWriter(fw);
5312-
) {
5313+
BufferedWriter bw = new BufferedWriter(fw);
5314+
) {
53135315
bw.write(content);
53145316
s_logger.debug("created file: "+ file + " in folder:"+folder);
53155317
} catch (final IOException ex) {

0 commit comments

Comments
 (0)