/**
* Copyright 1999-2010 University of Chicago
*
* 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 org.globus.workspace.remoting.admin.defaults;
import com.google.gson.Gson;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.globus.workspace.groupauthz.Group;
import org.globus.workspace.groupauthz.GroupAuthz;
import org.globus.workspace.remoting.admin.VMTranslation;
import org.globus.workspace.service.WorkspaceHome;
import org.globus.workspace.service.binding.authorization.CreationAuthorizationCallout;
import org.globus.workspace.service.binding.vm.VirtualMachine;
import org.nimbus.authz.AuthzDBException;
import org.nimbus.authz.UserAlias;
import org.nimbustools.api._repr._Caller;
import org.nimbustools.api.repr.Caller;
import org.nimbustools.api.repr.ReprFactory;
import org.nimbustools.api.repr.vm.ResourceAllocation;
import org.nimbustools.api.repr.vm.VM;
import org.nimbustools.api.services.admin.RemoteAdminToolsManagement;
import org.nimbustools.api.services.rm.DoesNotExistException;
import org.nimbustools.api.services.rm.ManageException;
import org.nimbustools.api.services.rm.Manager;
import org.nimbus.authz.AuthzDBAdapter;
import org.nimbustools.api.services.rm.OperationDisabledException;
import javax.sql.DataSource;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
/**
* Remote class that connects service and RemoteAdminToolsMain
* Handles DB queries and information requests
*/
public class DefaultRemoteAdminToolsMgmt implements RemoteAdminToolsManagement {
protected static final Log logger =
LogFactory.getLog(DefaultRemoteAdminToolsMgmt.class.getName());
protected Manager manager;
protected ReprFactory reprFactory;
protected DataSource authzDataSource;
protected WorkspaceHome workspaceHome;
protected CreationAuthorizationCallout authzCallout;
private AuthzDBAdapter authz;
private final Gson gson;
private String errorMsg;
public DefaultRemoteAdminToolsMgmt() {
this.gson = new Gson();
}
public String getAllRunningVMs() throws RemoteException {
try {
VM[] allRunningVms = manager.getGlobalAll();
final List<VMTranslation> vmts = new ArrayList<VMTranslation>(allRunningVms.length);
for(int i = 0; i < allRunningVms.length; i++) {
vmts.add(translateVM(allRunningVms[i]));
}
return gson.toJson(vmts);
}
catch (ManageException e) {
throw new RemoteException(e.getMessage());
}
}
public String getAllVMsByHost(String hostname) throws RemoteException {
VM[] vms = getVMByHost(hostname);
if(vms == null)
return null;
final List<VMTranslation> vmts = new ArrayList<VMTranslation>(vms.length);
for(int i = 0; i < vms.length; i++) {
vmts.add(translateVM(vms[i]));
}
return gson.toJson(vmts);
}
public String getAllVMsByGroupId(String groupId) throws RemoteException {
Group group = getGroupByGroupId(groupId);
VM[] vms = getAllVMsByGroup(group);
if(vms == null)
return null;
final List<VMTranslation> vmts = new ArrayList<VMTranslation>(vms.length);
for(int i = 0; i < vms.length; i++) {
vmts.add(translateVM(vms[i]));
}
return gson.toJson(vmts);
}
public String getAllVMsByGroupName(String groupName) throws RemoteException {
Group group = getGroupByGroupName(groupName);
VM[] vms = getAllVMsByGroup(group);
if(vms == null)
return null;
final List<VMTranslation> vmts = new ArrayList<VMTranslation>(vms.length);
for(int i = 0; i < vms.length; i++) {
vmts.add(translateVM(vms[i]));
}
return gson.toJson(vmts);
}
public String getVMsByDN(String userDN) throws RemoteException {
try {
final _Caller caller = this.reprFactory._newCaller();
caller.setIdentity(userDN);
VM[] vms = manager.getAllByCaller(caller);
if(vms.length == 0)
return null;
final List<VMTranslation> vmts = new ArrayList<VMTranslation>(vms.length);
for(int i = 0; i < vms.length; i++) {
vmts.add(translateVM(vms[i]));
}
return gson.toJson(vmts);
}
catch (ManageException e) {
throw new RemoteException(e.getMessage());
}
}
public String getVMsByUser(String user) throws RemoteException {
try {
authz = new AuthzDBAdapter(authzDataSource);
String userId = authz.getCanonicalUserIdFromFriendlyName(user);
VM[] vms = getVMsByUserId(userId);
final List<VMTranslation> vmts = new ArrayList<VMTranslation>(vms.length);
for(int i = 0; i < vms.length; i++) {
vmts.add(translateVM(vms[i]));
}
return gson.toJson(vmts);
}
catch (AuthzDBException e) {
return null;
}
}
public String getVMsByState(String state) throws RemoteException {
try {
VM[] vms = manager.getGlobalAll();
final List<VMTranslation> vmts = new ArrayList<VMTranslation>();
for(VM vm : vms) {
if(vm.getState().getState().equalsIgnoreCase(state))
vmts.add(translateVM(vm));
}
if(vmts.size() == 0)
return null;
return gson.toJson(vmts);
}
catch(ManageException e) {
throw new RemoteException(e.getMessage());
}
}
public Hashtable<String, String[]> showVMsForAllHosts() throws RemoteException {
try {
List<String> hostnames = new ArrayList<String>();
VM[] vms = manager.getGlobalAll();
if(vms.length == 0)
return null;
for(int i = 0; i < vms.length; i++) {
String id = vms[i].getID();
String host = workspaceHome.find(id).getVM().getNode();
if(!hostnames.contains(host))
hostnames.add(host);
}
Hashtable<String, String[]> allVMs = new Hashtable<String, String[]>();
for(String hostname : hostnames) {
vms = getVMByHost(hostname);
String[] parsedVMs = new String[vms.length];
for(int i = 0; i < vms.length; i++) {
parsedVMs[i] = vms[i].getID();
}
allVMs.put(hostname, parsedVMs);
}
return allVMs;
}
catch(ManageException e) {
throw new RemoteException(e.getMessage());
}
catch(DoesNotExistException e) {
throw new RemoteException(e.getMessage());
}
}
/*
* This class handles shutdown by host, id and all.
* The constants for int type are in the interface for this class
* typeID is either the id or hostname, depending on if shutting down by id or host, or null if shutting down all
* seconds is optional
*/
public String shutdown(int type, String typeID, String seconds, boolean force) throws RemoteException {
try {
VM[] vms;
String returnMsg = null;
vms = typeSet(type, typeID);
if(vms == null || vms.length == 0)
return errorMsg;
for(int i = 0; i < vms.length; i++) {
String id = vms[i].getID();
Caller caller = vms[i].getCreator();
try {
manager.shutdown(id, manager.INSTANCE, null, caller);
} catch (OperationDisabledException e) {
logger.warn("Shutdown is currently disabled for instance " + id);
if (returnMsg == null) {
returnMsg = "Shutdown is currently disabled for instance " + id;
} else {
returnMsg += "\nShutdown is currently disabled for instance " + id;
}
}
}
//checks every 3 seconds to see if one of the vms has entered propagation mode
//up to a max of 30 seconds before trashing all vms
//I decided against checking every single vm for entering propagation mode since they mostly enter at
//about the same speed
if(seconds == null) {
for(int i = 0; i <= 10; i++) {
Thread.sleep(3000);
vms = typeSet(type, typeID);
if(vms[0].getState().getState().equals("Propagated"))
break;
}
}
//same as above, but max time is the amount of seconds entered by the user
else {
int mill = (Integer.parseInt(seconds)) * 1000;
for(int i = 0; i <= mill; i += 3000) {
Thread.sleep(3000);
vms = typeSet(type, typeID);
if(vms[0].getState().getState().equals("Propagated"))
break;
}
}
//eventually trashes all vms regardless of whether or not they enter propagation mode
vms = typeSet(type, typeID);
for(int i = 0; i < vms.length; i++) {
String id = vms[i].getID();
Caller caller = vms[i].getCreator();
if (force || vms[i].getState().getState().equals("Propagated")) {
manager.trash(id, manager.INSTANCE, caller);
} else {
if (returnMsg == null) {
returnMsg = "Instance " + id + " not trashed because it is was not shut down correctly and --force is off";
} else {
returnMsg += "\nInstance " + id + " not trashed because it is was not shut down correctly and --force is off";
}
}
}
return returnMsg;
}
catch (ManageException e) {
throw new RemoteException(e.getMessage());
}
catch (DoesNotExistException e) {
throw new RemoteException(e.getMessage());
}
catch (InterruptedException e) {
throw new RemoteException(e.getMessage());
}
}
/*
* This class handles cleanup by host, id and all.
* The constants for int type are in the interface for this class
* typeID is either the id or hostname, depending on if cleaning up by id or host, or null if cleaning up all
*/
public String cleanup(int type, String typeID) throws RemoteException {
try {
VM[] vms;
vms = typeSet(type, typeID);
if(vms == null || vms.length == 0)
return errorMsg;
for(int i = 0; i < vms.length; i++) {
String id = vms[i].getID();
Caller caller = vms[i].getCreator();
manager.cleanup(id, manager.INSTANCE, caller);
}
return null;
}
catch (ManageException e) {
throw new RemoteException(e.getMessage());
}
catch (DoesNotExistException e) {
throw new RemoteException(e.getMessage());
}
catch (OperationDisabledException e) {
throw new RemoteException(e.getMessage());
}
}
private VM[] typeSet(int type, String typeID) throws RemoteException {
try {
if(type == SHUTDOWN_HOST || type == CLEANUP_HOST)
return getVMByHost(typeID);
else if(type == SHUTDOWN_ID || type == CLEANUP_ID)
return getVMById(typeID);
else if(type == SHUTDOWN_UNAME || type == CLEANUP_UNAME) {
authz = new AuthzDBAdapter(authzDataSource);
String userId = authz.getCanonicalUserIdFromFriendlyName(typeID);
VM[] vms = getVMsByUserId(userId);
if(vms == null)
errorMsg = "No VMs with user name " + typeID + " found";
return vms;
}
else if(type == SHUTDOWN_DN || type == CLEANUP_DN) {
final _Caller caller = this.reprFactory._newCaller();
caller.setIdentity(typeID);
VM[] vms = manager.getAllByCaller(caller);
if(vms.length == 0)
errorMsg = "No VMs with DN " + typeID + " found";
return vms;
}
else if(type == SHUTDOWN_GID || type == CLEANUP_GID) {
Group group = getGroupByGroupId(typeID);
if(group == null)
return null;
VM[] vms = getAllVMsByGroup(group);
if(vms == null)
errorMsg = "No VMs with group id " + typeID + " found";
return vms;
}
else if(type == SHUTDOWN_GNAME || type == CLEANUP_GNAME) {
Group group = getGroupByGroupName(typeID);
if(group == null)
return null;
VM[] vms = getAllVMsByGroup(group);
if(vms == null)
errorMsg = "No VMs with group name " + typeID + " found";
return vms;
}
else {
VM[] vms = manager.getGlobalAll();
if(vms.length == 0)
errorMsg = "No running VMs available for shutdown or cleanup";
return vms;
}
}
catch (ManageException e) {
throw new RemoteException(e.getMessage());
}
catch (AuthzDBException e) {
errorMsg = "User " + typeID + " does not exist";
return null;
}
}
private VM[] getVMsByUserId(String userId) throws RemoteException {
try {
List<UserAlias> userAlias;
userAlias = authz.getUserAliases(userId);
List<UserAlias> dnAlias = new ArrayList<UserAlias>(userAlias.size());
for(int i = 0; i < userAlias.size(); i++) {
if(userAlias.get(i).getAliasType() == AuthzDBAdapter.ALIAS_TYPE_DN)
dnAlias.add(userAlias.get(i));
}
if(dnAlias.size() == 0) {
return null;
}
else if(dnAlias.size() > 1)
throw new RemoteException("User_Alias size: " + dnAlias.size());
String aliasDN = dnAlias.get(0).getAliasName();
final _Caller caller = this.reprFactory._newCaller();
caller.setIdentity(aliasDN);
VM[] vmsByCaller = manager.getAllByCaller(caller);
return vmsByCaller;
}
catch (AuthzDBException e) {
throw new RemoteException(e.getMessage());
}
catch (ManageException e) {
return null;
}
}
private VM[] getVMById(String id) {
try {
if(!manager.exists(id, manager.INSTANCE)) {
errorMsg = "VM ID: " + id + " does not exist";
return null;
}
VM[] vms = new VM[1];
VM instance = manager.getInstance(id);
vms[0] = instance;
return vms;
}
catch (DoesNotExistException e) {
errorMsg = "VM ID: " + id + " does not exist";
return null;
}
catch (ManageException e) {
errorMsg = "VM ID: " + id + " does not exist";
return null;
}
}
/*
* Looks through all running vms and compares hostnames
*/
private VM[] getVMByHost(String hostname) {
try {
ArrayList<VM> vms;
VM[] all = manager.getGlobalAll();
int cnt = 0;
vms = new ArrayList<VM>(all.length);
for(int i = 0; i < all.length; i++) {
String id = all[i].getID();
String host = workspaceHome.find(id).getVM().getNode();
if(host.equals(hostname))
vms.add(all[i]);
}
if(vms.size() == 0) {
errorMsg = "No vms with hostname " + hostname + " found";
return null;
}
else
return vms.toArray(new VM[0]);
}
catch (DoesNotExistException e) {
errorMsg = "Hostname " + hostname + " not found";
return null;
}
catch (ManageException e) {
errorMsg = "No running VMs found";
return null;
}
}
private VM[] getAllVMsByGroup(Group group) throws RemoteException {
try {
if(group != null) {
String[] dns = group.getIdentities();
if(dns == null || dns.length == 0)
return null;
authz = new AuthzDBAdapter(authzDataSource);
ArrayList<VM> allVMs = new ArrayList<VM>(0);
for(int i = 0; i < dns.length; i++) {
final _Caller caller = this.reprFactory._newCaller();
caller.setIdentity(dns[i]);
VM[] vmsByCaller = manager.getAllByCaller(caller);
for(int j = 0; j < vmsByCaller.length; j++) {
allVMs.add(vmsByCaller[j]);
}
}
if(allVMs.size() == 0)
return null;
VM[] vms = new VM[allVMs.size()];
return allVMs.toArray(vms);
}
return null;
}
catch (ManageException e) {
throw new RemoteException(e.getMessage());
}
}
private Group getGroupByGroupId(String groupId) {
int id;
try {
id = Integer.parseInt(groupId);
}
catch(NumberFormatException e) {
errorMsg = "Group id must be a positive integer";
return null;
}
GroupAuthz groupAuthz = (GroupAuthz) authzCallout;
Group[] groups = groupAuthz.getGroups();
if(id <= 0 || id > groups.length || groups[id -1] == null) {
errorMsg = "Group " + groupId + " not found";
return null;
}
return groups[id -1];
}
private Group getGroupByGroupName(String groupName) {
GroupAuthz groupAuthz = (GroupAuthz) authzCallout;
Group[] groups = groupAuthz.getGroups();
for(int i = 0; i < groups.length; i++) {
if(groups[i] != null && groups[i].getName().equals(groupName))
return groups[i];
}
errorMsg = "Group " + groupName + " not found";
return null;
}
/*
* Translates vm info into string format for passing over rmi with Gson
*/
private VMTranslation translateVM(VM vm) throws RemoteException {
try {
GroupAuthz groupAuthz = (GroupAuthz) authzCallout;
String id = vm.getID();
VirtualMachine vmlong = workspaceHome.find(id).getVM();
String node = vmlong.getNode();
String creatorId = vm.getCreator().getIdentity();
String groupId = Integer.toString(groupAuthz.getGroupIDFromCaller(creatorId));
String groupName = groupAuthz.getGroupName(creatorId);
String state = vm.getState().getState();
String startTime = vm.getSchedule().getStartTime().getTime().toString();
String endTime = vm.getSchedule().getDestructionTime().getTime().toString();
ResourceAllocation ra = vm.getResourceAllocation();
String memory = Integer.toString(ra.getMemory());
String cpuCount = Integer.toString(ra.getIndCpuCount());
String uri = vm.getVMFiles()[0].getURI().getPath();
VMTranslation vmt = new VMTranslation(id, node, creatorId, groupId, groupName, state, startTime, endTime,
memory, cpuCount, uri);
return vmt;
}
catch (ManageException e) {
throw new RemoteException(e.getMessage());
}
catch (DoesNotExistException e) {
throw new RemoteException(e.getMessage());
}
catch (Exception e) {
throw new RemoteException(e.getMessage());
}
}
public void setManager(Manager manager) {
this.manager = manager;
}
public void setReprFactory(ReprFactory reprFactory) {
this.reprFactory = reprFactory;
}
public void setAuthzDataSource(DataSource authzDataSource) {
this.authzDataSource = authzDataSource;
}
public void setWorkspaceHome(WorkspaceHome workspaceHome) {
this.workspaceHome = workspaceHome;
}
public void setAuthzCallout(CreationAuthorizationCallout authzCallout) {
this.authzCallout = authzCallout;
}
}