private ServiceInstance serviceInstance;
serviceInstance = new ServiceInstance(new URL("https://"+vmwareServer+"/sdk"), userName, password, true);
Datacenter datacenter = (Datacenter)vmData.getHostSystem().getParent().getParent().getParent();
VirtualDiskManager vmd = serviceInstance.getVirtualDiskManager();
The inventory path from a host system to a data center is 'datacenter --> hostFolder --> childEntity (ComputeResource or its subtype) --> host'. So we call getParent() three times to work our way back up the path.Once we have our Virtual Disk Manager, all we have to do is assign a new UUID. Java has a really easy way of doing this (UUID.randomUUID()), but of course it can't be that simple. VMware requires a specific format for this UUID as well as a specific prefix ("60 00 C2 9") although I can't find any documentation stating the prefix. The format is normally 8-4-4-4-12 but for some reason the vmdk uuid is 16-16. This turns out to be a little tricky as I wanted something truly random. My solution comes from the java UUID object source code and its toString method. To handle the required VMware prefix, I grab the original vmdk's UUID and take the first half, adding my generated half to it and, viola a cloned vmdk.
String oldUUID = vmd.queryVirtualDiskUuid(fileName, datacenter);
String firstHalf = oldUUID.split("-")[0];
String halfUUID = genHalfVMwareUUID();
vmd.setVirtualDiskUuid(fileName, datacenter, firstHalf+"-"+halfUUID);
private String genHalfVMwareUUID() {
UUID uuid = UUID.randomUUID();
Long second = uuid.getLeastSignificantBits();
String secondHalf = longToVMwareUUID(second);
return secondHalf;
}
private String longToVMwareUUID(Long val) {
StringBuffer buffer = new StringBuffer();
// the entire long is 64 bits, we want the first two so we can add spaces
// we need to offset the whole thing by 56 to start
// (8 bits or 2 x 4 bit hex characters from the left)
// each iteration decrements by two characters, 8 bits
// e.g.
// UUID = d645da13-87f6-4e50
// UUID Binary = 1101011001000101110110100001001110000111111101100100111001010000
// UUID >> 56 = 11111111111111111111111111111111111111111111111111111111 11010110
// when we bitwise and (&) (using the digits method)
// against an 8 bit sequence we get just the last 8 bits
// 11010110
// which equals d6, the first two characters
// the second sequence would be shifted by 48
// 111111111111111111111111111111111111111111111111 1101011001000101
// bitwise and against 8 bits and we get 01000101, which in hex is 45
for (int i = 56; i >= 0; i-=8) {
buffer.append(digits(val >> i, 2));
buffer.append(" ");
}
// remove the last space
buffer.deleteCharAt(buffer.length()-1);
return buffer.toString();
}
private String digits(long val, int digits) {
// each hex character is 4 bits (2 ^ 4 = 16 possibilities)
// so multiply the number of digits desired by 4 and create a long of 1's that size
long hi = 1L << (digits * 4);
return Long.toHexString(hi | (val & (hi - 1))).substring(1);
}
Now that the UUID's have been properly dealt with; no more virtual center messages, no more paused virtual machines.
Hi Michael,
ReplyDeleteYou have solved the problem in a great way.
Data Center Management
Regards,
Banlin