/***************************************************************************
* Copyright (c) 2013 VMware, Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
/***************************************************************************
* Copyright (c) 2012 VMware, Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
package com.vmware.vhadoop.adaptor.vc;
import java.util.List;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.vmware.vhadoop.adaptor.vc.VCConnection.MoRefAndProps;
import com.vmware.vhadoop.adaptor.vc.VCConnection.VCCredentials;
import com.vmware.vhadoop.adaptor.vc.VCUtils.AsyncArrayResultTransformer;
import com.vmware.vhadoop.adaptor.vc.VCUtils.AsyncResultTransformer;
import com.vmware.vhadoop.adaptor.vc.VCUtils.CastingResultTransformer;
import com.vmware.vhadoop.external.VCActionDTOTypes.FolderDTO;
import com.vmware.vhadoop.external.VCActionDTOTypes.HostDTO;
import com.vmware.vhadoop.external.VCActionDTOTypes.VMDTO;
import com.vmware.vhadoop.external.VCActionDTOTypes.VMPowerState;
import com.vmware.vim25.ManagedObjectReference;
import com.vmware.vim25.TaskInfoState;
import com.vmware.vim25.VirtualMachinePowerState;
/**
* Represents an implementation of the necessary methods in VCActions to support the VHM
* Each method returns an asynchronous result which may or may not represent an async call in reality
* Some async return type encapsulate a wait for a property change to occur
* All return types are DTO classes designed to abstractly represent the state of a VC entity
*
*/
public class VCAdaptor extends AbstractVCAdaptor {
private VCConnection _connection;
private static final Logger _log = Logger.getLogger(VCAdaptor.class.getName());
/* These are property keys for finding out properties of a VC object
* The keys should only exist within the scope of the VCAdaptor */
private static final String VC_PROPERTY_HOST_FOR_VM = "runtime.host";
private static final String VC_PROPERTY_HOSTNAME_OF_GUEST = "guest.hostName";
private static final String VC_PROPERTY_RUNTIME_POWERSTATE = "runtime.powerState";
private static final String VC_MOREF_TYPE_VM = "VirtualMachine";
private static final String VC_MOREF_TYPE_FOLDER = "Folder";
private static final String POWER_STATE_VALUE_ON = "POWERED_ON";
private static final String POWER_STATE_VALUE_OFF = "POWERED_OFF";
public VCAdaptor(VCCredentials credentials) {
_connection = new VCConnection(credentials);
}
@Override
public boolean testConnection() {
return _connection.connect();
}
// Used for testing, forces log out of vc without orderly VHM disconnect.
public void dropConnection() {
_log.log(Level.SEVERE, "Forcing drop of VC connection for testing");
_connection.disconnect(true);
}
@Override
public Future<VMDTO> powerOffVM(VMDTO vm) {
ManagedObjectReference futureTaskResult = null;
try {
futureTaskResult = _connection.getVimPort().powerOffVMTask((ManagedObjectReference)vm._moId);
} catch (Exception e) {
return null;
}
AsyncResultTransformer<VMDTO> resultsTransformer = new AsyncResultTransformer<VMDTO>(
_connection.new MoRefAndProps((ManagedObjectReference)vm._moId, vm._name), _connection) {
@Override
public VMDTO transform(MoRefAndProps moRefProps) {
VMDTO newDTO = new VMDTO(moRefProps._name);
newDTO._moId = moRefProps._moref;
return newDTO;
}
};
resultsTransformer.setWaitForPropsOnObj(futureTaskResult);
resultsTransformer.addWaitProperty("info.state", "state", new Object[]{TaskInfoState.SUCCESS, TaskInfoState.ERROR});
return resultsTransformer;
}
@Override
public Future<VMDTO> shutdownGuest(VMDTO vm) {
try {
// ShutdownGuest does not return task to track; caller is expected to check/ensure power-off.
_connection.getVimPort().shutdownGuest((ManagedObjectReference)vm._moId);
return null;
} catch (Exception e) {
_log.log(Level.SEVERE, "Exception invoking shutdownGuest; switching to powerOffVM");
return powerOffVM(vm);
}
}
@Override
public Future<VMDTO> powerOnVM(VMDTO vm) {
ManagedObjectReference futureTaskResult = null;
try {
futureTaskResult = _connection.getVimPort().powerOnVMTask(
(ManagedObjectReference)vm._moId, null);
} catch (Exception e) {
return null;
}
AsyncResultTransformer<VMDTO> resultsTransformer = new AsyncResultTransformer<VMDTO>(
_connection.new MoRefAndProps((ManagedObjectReference)vm._moId, vm._name), _connection) {
@Override
public VMDTO transform(MoRefAndProps moRefProps) {
VMDTO newDTO = new VMDTO(moRefProps._name);
newDTO._moId = moRefProps._moref;
return newDTO;
}
};
resultsTransformer.setWaitForPropsOnObj(futureTaskResult);
resultsTransformer.addWaitProperty("info.state", "state", new Object[]{TaskInfoState.SUCCESS, TaskInfoState.ERROR});
return resultsTransformer;
}
@Override
public Future<FolderDTO> getFolderForName(FolderDTO rootFolder, final String name) {
MoRefAndProps result = null;
if (rootFolder == null) {
/* TODO: RootFolder is a made-up name here */
result = _connection.new MoRefAndProps(_connection.getServiceContent().getRootFolder(), "RootFolder");
} else {
result = _connection.findObjectFromRoot((ManagedObjectReference)rootFolder._moId, VC_MOREF_TYPE_FOLDER, name, null);
}
AsyncResultTransformer<FolderDTO> resultsTransformer = new AsyncResultTransformer<FolderDTO>(result, _connection) {
@Override
public FolderDTO transform(MoRefAndProps moRefProps) {
FolderDTO newDTO = new FolderDTO(moRefProps._name);
newDTO._moId = moRefProps._moref;
return newDTO;
}
};
if (result == null) {
_log.log(Level.SEVERE, "Could not find VC folder with name "+name);
return null;
}
return resultsTransformer;
}
@Override
public Future<VMDTO[]> listVMsInFolder(FolderDTO folder) {
final String[] propKeys = {VC_PROPERTY_HOST_FOR_VM, VC_PROPERTY_HOSTNAME_OF_GUEST, VC_PROPERTY_RUNTIME_POWERSTATE};
MoRefAndProps[] result = _connection.findObjectsFromRoot(
(ManagedObjectReference)folder._moId, VC_MOREF_TYPE_VM, propKeys);
AsyncArrayResultTransformer<VMDTO> resultsTransformer = new AsyncArrayResultTransformer<VMDTO>(result, _connection) {
@Override
public VMDTO transform(MoRefAndProps moRefProps) {
VMDTO vm = new VMDTO(moRefProps._name);
vm._moId = moRefProps._moref;
vm.setCurrentStateProperties(moRefProps._properties);
return vm;
}
@Override
public VMDTO[] toArray(List<VMDTO> list) {
return list.toArray(new VMDTO[0]);
}
};
return resultsTransformer;
}
@Override
public Future<FolderDTO> getRootFolder() {
return getFolderForName(null, null);
}
/* Note that the refresh parameter here represents the clear understanding that the properties
* contained within the VMDTO passed in may be stale and could be refreshed if desired */
@Override
public Future<VMPowerState> getPowerState(VMDTO vm, boolean refresh) {
VirtualMachinePowerState powerStateValue;
if (!refresh) {
powerStateValue = (VirtualMachinePowerState)vm.getStateProperty(VC_PROPERTY_RUNTIME_POWERSTATE);
} else {
/* Assumption that this is blocking */
powerStateValue = (VirtualMachinePowerState)_connection.refreshStateProperty(
(ManagedObjectReference)vm._moId, VC_PROPERTY_RUNTIME_POWERSTATE);
vm.addStateProperty(VC_PROPERTY_RUNTIME_POWERSTATE, powerStateValue);
}
VMPowerState result;
if (powerStateValue.name().equals(POWER_STATE_VALUE_ON)) {
result = VMPowerState.POWERED_ON;
} else if (powerStateValue.name().equals(POWER_STATE_VALUE_OFF)) {
result = VMPowerState.POWERED_OFF;
} else {
result = VMPowerState.UNKNOWN;
}
return new CastingResultTransformer<VMPowerState>(result);
}
@Override
public Future<HostDTO> getHostForVM(VMDTO vm, boolean refresh) {
ManagedObjectReference moref;
if (!refresh) {
moref = (ManagedObjectReference)vm.getStateProperty(VC_PROPERTY_HOST_FOR_VM);
} else {
/* Assumption that this is blocking */
moref = (ManagedObjectReference)_connection.refreshStateProperty(
(ManagedObjectReference)vm._moId, VC_PROPERTY_HOST_FOR_VM);
vm.addStateProperty(VC_PROPERTY_HOST_FOR_VM, moref);
}
HostDTO host = new HostDTO(moref.getValue());
host._moId = moref;
return new CastingResultTransformer<HostDTO>(host);
}
@Override
public String getVMHostname(VMDTO vm) {
return (String)vm.getStateProperty(VC_PROPERTY_HOSTNAME_OF_GUEST);
}
}