package jetbrains.buildServer.clouds.vmware.stubs; import com.vmware.vim25.*; import com.vmware.vim25.mo.*; import java.rmi.RemoteException; import java.util.*; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import org.jetbrains.annotations.NotNull; /** * @author Sergey.Pak * Date: 5/13/2014 * Time: 1:07 PM */ public class FakeVirtualMachine extends VirtualMachine { private static final int GUEST_SHUTDOWN_TIMEOUT = 600; private String myName; private VirtualMachineRuntimeInfo myRuntimeInfo; private GuestInfo myGuestInfo; private VirtualMachineSnapshotInfo mySnapshotInfo; private final AtomicReference<VirtualMachineConfigInfo> myConfigInfo = new AtomicReference<VirtualMachineConfigInfo>(); private Map<String, String> myCustomUserData; private boolean myTasksSuccessfull = true; private AtomicBoolean myIsStarted = new AtomicBoolean(false); private final List<VirtualMachineSnapshotTree> myRootSnapshotList = new ArrayList<VirtualMachineSnapshotTree>(); private String myVersion; private ManagedEntity myParent; private Calendar myBootTime; private CustomizationSpec myCustomizationSpec; private AtomicBoolean myGone = new AtomicBoolean(false); public FakeVirtualMachine(final String name, final boolean isTemplate, final boolean isRunning) { super(null, createVMMor(name)); myName = name; updateVersion(); myIsStarted.set(isRunning); myConfigInfo.set(new VirtualMachineConfigInfo(){ @Override public String getName() { return myName; } @Override public boolean isTemplate() { return isTemplate; } @Override public String getChangeVersion() { return myVersion; } @Override public OptionValue[] getExtraConfig() { final OptionValue[] retval = new OptionValue[myCustomUserData.size()]; int i=0; for (final Map.Entry<String, String> entry : myCustomUserData.entrySet()) { retval[i] = new OptionValue(); retval[i].setKey(entry.getKey()); retval[i++].setValue(entry.getValue()); } return retval; } }); myRuntimeInfo = new VirtualMachineRuntimeInfo(){ @Override public VirtualMachinePowerState getPowerState() { return myIsStarted.get() ? VirtualMachinePowerState.poweredOn : VirtualMachinePowerState.poweredOff; } @Override public Calendar getBootTime() { if (myBootTime != null) return myBootTime; return super.getBootTime(); } }; mySnapshotInfo = new VirtualMachineSnapshotInfo(){ @Override public VirtualMachineSnapshotTree[] getRootSnapshotList() { return myRootSnapshotList.toArray(new VirtualMachineSnapshotTree[myRootSnapshotList.size()]); } }; myCustomUserData = new HashMap<String, String>(); enableGuestTools(); myParent = new ManagedEntity(getServerConnection(), createVMMor("parent")); } @Override public String getName() { checkIfInstanceIsGone(); return myName; } private void checkIfInstanceIsGone() { if (myGone.get()){ final ManagedObjectNotFound cause = new ManagedObjectNotFound(); cause.setObj(getMOR()); throw new RuntimeException(cause); } } @Override protected Object getCurrentProperty(final String propertyName) { checkIfInstanceIsGone(); return super.getCurrentProperty(propertyName); } @Override public VirtualMachineRuntimeInfo getRuntime() { checkIfInstanceIsGone(); return myRuntimeInfo; } @Override public VirtualMachineSnapshotInfo getSnapshot() { checkIfInstanceIsGone(); return mySnapshotInfo; } @Override public Task cloneVM_Task(final Folder folder, final String name, final VirtualMachineCloneSpec spec) throws RemoteException { final FakeVirtualMachine newVm = FakeModel.instance().addVM(name, false, spec); newVm.setParentFolder(folder.getName()); final VirtualMachineConfigInfo oldConfig = newVm.myConfigInfo.get(); newVm.myConfigInfo.set(null); newVm.myCustomizationSpec = spec.getCustomization(); final CountDownLatch latch = new CountDownLatch(1); new Thread(){ @Override public void run() { try {sleep(500);} catch (InterruptedException e) {} latch.countDown(); newVm.myConfigInfo.set(oldConfig); if (spec.isPowerOn()){ if (!newVm.myIsStarted.compareAndSet(false, true)){ //throw new RemoteException("Already started"); } } } }.start(); return longTask(latch); } @Override public Task powerOffVM_Task() throws RemoteException { if (!myIsStarted.get()){ throw new RemoteException("Already stopped"); } myIsStarted.set(false); return conditionalTask(); } @Override public Task powerOnVM_Task(final HostSystem host) throws RemoteException { if (myIsStarted.get()){ throw new RemoteException("Already started"); } myIsStarted.set(true); return conditionalTask(); } @Override public GuestInfo getGuest() { return myGuestInfo; } @Override public VirtualMachineConfigInfo getConfig() { checkIfInstanceIsGone(); return myConfigInfo.get(); } @Override public Task destroy_Task() throws RemoteException { FakeModel.instance().removeVM(getName()); return conditionalTask(); } @Override public Task reconfigVM_Task(final VirtualMachineConfigSpec spec) throws RemoteException { final OptionValue[] extraConfig = spec.getExtraConfig(); for (OptionValue opt : extraConfig) { myCustomUserData.put(opt.getKey(), opt.getValue().toString()); } return conditionalTask(); } @Override public void shutdownGuest() throws RemoteException { if (myGuestInfo != null) { try { Thread.sleep(GUEST_SHUTDOWN_TIMEOUT); updateVersion(); myIsStarted.set(false); } catch (InterruptedException e) { } } else { throw new RemoteException("no guest tools available"); } } @Override public ManagedEntity getParent() { return myParent; } public void setTasksSuccessStatus(boolean success){ myTasksSuccessfull = success; } public void addSnapshot(@NotNull final String snapshotName) { VirtualMachineSnapshotTree tree = new VirtualMachineSnapshotTree(); tree.setName(snapshotName); tree.setSnapshot(new ManagedObjectReference()); tree.setCreateTime(Calendar.getInstance()); myRootSnapshotList.add(tree); } public void removeSnapshot(@NotNull final String snapshotName) { for (VirtualMachineSnapshotTree tree : myRootSnapshotList) { if (tree.getName().equals(snapshotName)){ myRootSnapshotList.remove(tree); return; } } } public void setParentFolder(String folderName){ final FakeFolder folder = FakeModel.instance().getFolder(folderName); myParent = folder; } public void setBootTime(final Calendar bootTime) { myBootTime = bootTime; } private static Task successTask(){ return new Task(null, null) { @Override public TaskInfo getTaskInfo() throws RemoteException { final TaskInfo taskInfo = new TaskInfo(); taskInfo.setState(TaskInfoState.success); return taskInfo; } @Override public String waitForTask() throws RemoteException, InterruptedException { return Task.SUCCESS; } }; } private static Task failureTask(){ return new Task(null, null) { @Override public TaskInfo getTaskInfo() throws RemoteException { final TaskInfo taskInfo = new TaskInfo(); taskInfo.setState(TaskInfoState.error); return taskInfo; } @Override public String waitForTask() throws RemoteException, InterruptedException { return "failure"; } }; } private Task conditionalTask(){ return myTasksSuccessfull ? successTask() : failureTask(); } private Task longTask(final CountDownLatch latch){ return new Task(null, null) { @Override public TaskInfo getTaskInfo() throws RemoteException { final TaskInfo taskInfo = new TaskInfo(); taskInfo.setState(latch.getCount()==0 ? TaskInfoState.success : TaskInfoState.running); return taskInfo; } @Override public String waitForTask() throws RemoteException, InterruptedException { latch.await(); return SUCCESS; } }; } public void addCustomParam(final String key, final Object value){ myCustomUserData.put(key, String.valueOf(value)); } private void updateVersion(){ myVersion = new Date().toString(); } public void enableGuestTools(){ myGuestInfo = new GuestInfo(); Random r = new Random(); myGuestInfo.setIpAddress("192.168.1." + (1+ r.nextInt(254))); } public void disableGuestTools(){ myGuestInfo = null; } public CustomizationSpec getCustomizationSpec() { return myCustomizationSpec; } private static ManagedObjectReference createVMMor(final String name){ return new ManagedObjectReference(){ @Override public String getVal() { return "vm-" + name.hashCode(); } @Override public String get_value() { return getVal(); } @Override public String getType() { return "VirtualMachine"; } }; } public boolean isRunning(){ return myIsStarted.get(); } public void setGone(boolean gone){ myGone.set(gone); } public boolean isGone(){ return myGone.get(); } @Override public String toString() { return "FakeVirtualMachine{" + "myName='" + myName + '\'' + ", myIsStarted=" + myIsStarted + '}'; } }