cloudstack/deps/xen/XenServerJava/samples/VdiAndSrOps.java

320 lines
13 KiB
Java

/*
* Copyright (c) 2008 Citrix Systems, Inc.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
import java.util.HashMap;
import java.util.Set;
import com.xensource.xenapi.APIVersion;
import com.xensource.xenapi.Connection;
import com.xensource.xenapi.Host;
import com.xensource.xenapi.PBD;
import com.xensource.xenapi.SR;
import com.xensource.xenapi.Types;
import com.xensource.xenapi.VDI;
/**
* Performs various SR and VDI tests, including creating a dummy SR.
*/
public class VdiAndSrOps extends TestBase
{
public static void RunTest(ILog logger, TargetServer server) throws Exception
{
TestBase.logger = logger;
try
{
connect(server);
APIVersion version = connection.getAPIVersion();
boolean rio = version == APIVersion.API_1_1;
for (boolean nullSmConfig : new boolean[] { true, false })
{
testSrOp("SR.create", false, nullSmConfig, version);
testSrOp("SR.forget", false, nullSmConfig, version);
testSrOp("SR.createAsync", false, nullSmConfig, version);
testSrOp("SR.forget", false, nullSmConfig, version);
testSrOp("SR.makeAsync", false, nullSmConfig, version);
testSrOp("SR.forget", false, nullSmConfig, version);
if (rio)
{
testSrOp("SR.make", true, nullSmConfig, version);
testSrOp("SR.forget", false, nullSmConfig, version);
}
testSrOp("SR.introduce", false, nullSmConfig, version);
testSrOp("SR.forget", false, nullSmConfig, version);
testSrOp("SR.introduceAsync", false, nullSmConfig, version);
testSrOp("SR.forget", false, nullSmConfig, version);
}
testVdiOp("VDI.snapshot", version);
testVdiOp("VDI.createClone", version);
testVdiOp("VDI.snapshotAsync", version);
testVdiOp("VDI.createCloneAsync", version);
} finally
{
disconnect();
}
}
private static void testVdiOp(String op, APIVersion version) throws Exception
{
/* VDI.create and its allied functions got an extra parameter 'driverParams' between rio and miami.
* However it's not commonly used. With the extra parameter void of data, the call should work on
* either machine (the bindings should silently drop the extra bit and make the call anyway). But
* if we provide a non-null last parameter, and attempt to make the call on Rio, we should get
* an exception. */
boolean rio = version == APIVersion.API_1_1;
logf("With %s host, ", rio ? "Rio" : "post-Rio");
log("--attempting " + op + " with null driverParams");
vdiOpWithNullDriverParams(connection, op);
log("--attempting " + op + " with non-null driverParams");
if (rio)
{
log("(should fail)");
}
try
{
vdiOpWithNonNullDriverParams(connection, op);
if (rio)
{
throw new Exception(op
+ " call with non-null driverParams on rio host succeeded. It is not supposed to!");
}
} catch (Types.XenAPIException ex)
{
if (rio)
{
logln("As intended, " + op + " with non-null driverParams on rio host threw an exception");
logf("\"%s\"\n", ex.getClass());
logf("\"%s\"\n", ex);
} else
{
throw ex;
}
}
}
private static void testSrOp(String op, boolean deprecated_response_ok, boolean nullSmConfig, APIVersion version)
throws Exception
{
/* SR.create and its allied functions got an extra parameter 'SMConfig' between rio and miami.
* However it's not commonly used. With the extra parameter void of data, the call should work on
* either machine (the bindings should silently drop the extra bit and make the call anyway). But
* if we provide a non-null last parameter, and attempt to make the call on Rio, we should get
* an exception. */
boolean rio = version == APIVersion.API_1_1;
logf("With %s host, ", rio ? "Rio" : "post-Rio");
try
{
if (nullSmConfig)
{
log("--attempting " + op + " with null smConfig... ");
srOpWithNullSmConfig(connection, op);
logln("success");
} else
{
log("--attempting " + op + " with non-null smConfig... ");
if (rio)
{
log("(should fail)... ");
}
try
{
srOpWithNonNullSmConfig(connection, op);
if (rio)
{
throw new Exception(op + " call with non-null smConfig host succeeded. It is not supposed to!");
}
logln("success");
} catch (Types.XenAPIException ex)
{
if (rio)
{
logln("As intended, " + op + " with non-null smConfig on rio host threw an exception");
logf("\"%s\"\n", ex.getClass());
logf("\"%s\"\n", ex);
} else
{
throw ex;
}
}
}
} catch (Types.XenAPIException ex)
{
// Bug (CA-23404) workaround: sometimes the server doesn't send a proper MESSAGE_DEPRECATED,
// so the bindings can't parse it properly. Perform manual check...
if (errorDescriptionIs(ex.errorDescription, "MESSAGE_DEPRECATED"))
{
if (deprecated_response_ok)
{
logln(op + " threw MessageDeprecated (but this is OK)");
} else
{
throw ex;
}
}
}
}
private static void srOpWithNonNullSmConfig(Connection c, String op) throws Exception
{
HashMap<String, String> smConfig = new HashMap<String, String>();
smConfig.put("testKey", "testValue");
srOpLong(c, smConfig, op);
}
private static void srOpWithNullSmConfig(Connection c, String op) throws Exception
{
HashMap<String, String> smConfig = new HashMap<String, String>();
srOpLong(c, smConfig, op);
}
private static void vdiOpWithNonNullDriverParams(Connection c, String op) throws Exception
{
HashMap<String, String> smConfig = new HashMap<String, String>();
smConfig.put("testKey", "testValue");
vdiOpLong(c, smConfig, op);
}
private static void vdiOpWithNullDriverParams(Connection c, String op) throws Exception
{
HashMap<String, String> smConfig = new HashMap<String, String>();
vdiOpLong(c, smConfig, op);
}
private static Boolean errorDescriptionIs(String[] errDesc, String firstElement)
{
return errDesc != null && errDesc.length > 0 && errDesc[0].compareTo(firstElement) == 0;
}
private static final String FAKE_VDI_NAME = "madeupvdi";
private static void vdiOpLong(Connection c, HashMap<String, String> driverParams, String op) throws Exception
{
try
{
VDI dummy = Types.toVDI(FAKE_VDI_NAME);
if (op.equals("VDI.snapshot"))
{
dummy.snapshot(c, driverParams);
} else if (op.equals("VDI.createClone"))
{
dummy.createClone(c, driverParams);
} else if (op.equals("VDI.snapshotAsync"))
{
dummy.snapshotAsync(c, driverParams);
} else if (op.equals("VDI.createCloneAsync"))
{
dummy.createCloneAsync(c, driverParams);
} else
{
throw new Exception("bad op");
}
} catch (Types.HandleInvalid ex)
{
logln("Expected error: HANDLE_INVALID. that's ok.");
/* We're happy with this, since it means that the call made it through to xen
* and an attempt was made to execute it. */
}
}
private static final String TEST_SR_NAME = "TestSR: DO NOT USE (created by VdiAndSrOps.java)";
private static final String TEST_SR_DESC = "Should be automatically deleted";
private static final String TEST_SR_TYPE = "dummy";
private static final String TEST_SR_CONTENT = "contenttype";
private static final long TEST_SR_SIZE = 100000L;
private static void srOpLong(Connection c, HashMap<String, String> smConfig, String op) throws Exception
{
try
{
Host our_host = (Host) Host.getAll(c).toArray()[0];
if (op.equals("SR.create"))
{
SR.create(c, our_host, new HashMap<String, String>(), TEST_SR_SIZE, TEST_SR_NAME, TEST_SR_DESC,
TEST_SR_TYPE, TEST_SR_CONTENT, true, smConfig);
} else if (op.equals("SR.createAsync"))
{
SR.createAsync(c, our_host, new HashMap<String, String>(), TEST_SR_SIZE, TEST_SR_NAME, TEST_SR_DESC,
TEST_SR_TYPE, TEST_SR_CONTENT, true, smConfig);
} else if (op.equals("SR.make"))
{
SR.make(c, our_host, new HashMap<String, String>(), TEST_SR_SIZE, TEST_SR_NAME, TEST_SR_DESC,
TEST_SR_TYPE, TEST_SR_CONTENT, smConfig);
} else if (op.equals("SR.makeAsync"))
{
SR.makeAsync(c, our_host, new HashMap<String, String>(), TEST_SR_SIZE, TEST_SR_NAME, TEST_SR_DESC,
TEST_SR_TYPE, TEST_SR_CONTENT, smConfig);
} else if (op.equals("SR.forget"))
{
Set<SR> srs = SR.getByNameLabel(c, TEST_SR_NAME);
for (SR sr : srs)
{
// First destroy any PBDs associated with the SR
Set<PBD> pbds = PBD.getAll(c);
for (PBD pbd : pbds)
{
if (pbd.getSR(c).equals(sr))
{
pbd.unplug(c);
pbd.destroy(c);
}
}
sr.forget(c);
break;
}
} else if (op.equals("SR.introduce"))
{
SR.introduce(c, "uuid", TEST_SR_NAME, TEST_SR_DESC, TEST_SR_TYPE, TEST_SR_CONTENT, true, smConfig);
} else if (op.equals("SR.introduceAsync"))
{
SR.introduceAsync(c, "uuid", TEST_SR_NAME, TEST_SR_DESC, TEST_SR_TYPE, TEST_SR_CONTENT, true, smConfig);
} else
{
throw new Exception("bad op");
}
} catch (Types.SrUnknownDriver ex)
{
logln("Expected error: SR unknown driver. that's ok");
} catch (Types.XenAPIException ex)
{
// Our call parameters are not good and should cause a particular error
if (errorDescriptionIs(ex.errorDescription, "SR_BACKEND_FAILURE_102"))
{
logln("Expected error: SR backend failure 102. that's ok.");
/* 'The request is missing the server parameter'
*
* We're happy with this, since it means that the call made it through to xen
* and an attempt was made to execute it. */
return;
} else if (errorDescriptionIs(ex.errorDescription, "SR_BACKEND_FAILURE_101"))
{
/* 'The request is missing the serverpath parameter' */
logln("Expected error: SR backend failure 101. that's ok.");
return;
} else
{
// otherwise, there was a more serious error, which should be
// passed upwards
throw ex;
}
}
}
}