diff --git a/api/src/com/cloud/agent/api/StartupPxeServerCommand.java b/api/src/com/cloud/agent/api/StartupPxeServerCommand.java new file mode 100644 index 00000000000..487f54c463d --- /dev/null +++ b/api/src/com/cloud/agent/api/StartupPxeServerCommand.java @@ -0,0 +1,9 @@ +package com.cloud.agent.api; + +import com.cloud.host.Host; + +public class StartupPxeServerCommand extends StartupCommand { + public StartupPxeServerCommand() { + super(Host.Type.PxeServer); + } +} diff --git a/api/src/com/cloud/agent/api/baremetal/PrepareLinMinPxeServerAnswer.java b/api/src/com/cloud/agent/api/baremetal/PrepareLinMinPxeServerAnswer.java new file mode 100644 index 00000000000..94d1b284667 --- /dev/null +++ b/api/src/com/cloud/agent/api/baremetal/PrepareLinMinPxeServerAnswer.java @@ -0,0 +1,14 @@ +package com.cloud.agent.api.baremetal; + +import com.cloud.agent.api.Answer; + +public class PrepareLinMinPxeServerAnswer extends Answer { + public PrepareLinMinPxeServerAnswer(PrepareLinMinPxeServerCommand cmd) { + super(cmd, true, "SUCCESS"); + } + + public PrepareLinMinPxeServerAnswer(PrepareLinMinPxeServerCommand cmd, String details) { + super(cmd, false, details); + } + +} diff --git a/api/src/com/cloud/agent/api/baremetal/PrepareLinMinPxeServerCommand.java b/api/src/com/cloud/agent/api/baremetal/PrepareLinMinPxeServerCommand.java new file mode 100644 index 00000000000..33a65377eff --- /dev/null +++ b/api/src/com/cloud/agent/api/baremetal/PrepareLinMinPxeServerCommand.java @@ -0,0 +1,63 @@ +package com.cloud.agent.api.baremetal; + +import com.cloud.agent.api.Command; + +public class PrepareLinMinPxeServerCommand extends Command { + String ip; + String mac; + String netMask; + String gateway; + String dns; + String template; + String vmName; + String hostName; + + @Override + public boolean executeInSequence() { + return true; + } + + public PrepareLinMinPxeServerCommand(String ip, String mac, String netMask, String gateway, String dns, String template, String vmName, String hostName) { + this.ip = ip; + this.mac = mac; + this.netMask = netMask; + this.gateway = gateway; + this.dns = dns; + this.template = template; + this.vmName = vmName; + this.hostName = hostName; + } + + public String getIp() { + return ip; + } + + public String getMac() { + return mac; + } + + public String getNetMask() { + return netMask; + } + + public String getGateWay() { + return gateway; + } + + public String getDns() { + return dns; + } + + public String getTemplate() { + return template; + } + + public String getVmName() { + return vmName; + } + + public String getHostName() { + return hostName; + } + +} diff --git a/api/src/com/cloud/api/ApiConstants.java b/api/src/com/cloud/api/ApiConstants.java index db4c90d3a50..849128dd105 100755 --- a/api/src/com/cloud/api/ApiConstants.java +++ b/api/src/com/cloud/api/ApiConstants.java @@ -195,5 +195,14 @@ public class ApiConstants { public static final String GUEST_IP_TYPE = "guestiptype"; public static final String HOST_TAGS = "hosttags"; public static final String SSH_KEYPAIR = "keypair"; + public static final String HOST_CPU_CAPACITY = "hostcpucapacity"; + public static final String HOST_CPU_NUM = "hostcpunum"; + public static final String HOST_MEM_CAPACITY = "hostmemcapacity"; + public static final String HOST_MAC = "hostmac"; + public static final String HOST_TAG = "hosttag"; + public static final String PXE_SERVER_TYPE = "pxeservertype"; + public static final String LINMIN_USERNAME = "linminusername"; + public static final String LINMIN_PASSWORD = "linminpassword"; + public static final String LINMIN_APID = "linminapid"; } diff --git a/api/src/com/cloud/api/BaseCmd.java b/api/src/com/cloud/api/BaseCmd.java index eceb2dbd426..0c52cf718e4 100755 --- a/api/src/com/cloud/api/BaseCmd.java +++ b/api/src/com/cloud/api/BaseCmd.java @@ -53,6 +53,7 @@ import com.cloud.user.UserContext; import com.cloud.utils.Pair; import com.cloud.utils.component.ComponentLocator; import com.cloud.vm.UserVmService; +import com.cloud.vm.BareMetalVmService; public abstract class BaseCmd { private static final Logger s_logger = Logger.getLogger(BaseCmd.class.getName()); @@ -109,6 +110,7 @@ public abstract class BaseCmd { public static RulesService _rulesService; public static LoadBalancingRulesService _lbService; public static RemoteAccessVpnService _ravService; + public static BareMetalVmService _bareMetalVmService; static void setComponents(ResponseGenerator generator) { @@ -130,6 +132,7 @@ public abstract class BaseCmd { _lbService = locator.getManager(LoadBalancingRulesService.class); _ravService = locator.getManager(RemoteAccessVpnService.class); _responseGenerator = generator; + _bareMetalVmService = locator.getManager(BareMetalVmService.class); } public abstract void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException; diff --git a/api/src/com/cloud/api/commands/AddHostCmd.java b/api/src/com/cloud/api/commands/AddHostCmd.java index 63a41324ec6..71810ea5756 100644 --- a/api/src/com/cloud/api/commands/AddHostCmd.java +++ b/api/src/com/cloud/api/commands/AddHostCmd.java @@ -66,6 +66,23 @@ public class AddHostCmd extends BaseCmd { @Parameter(name=ApiConstants.HYPERVISOR, type=CommandType.STRING, required=true, description="hypervisor type of the host") private String hypervisor; + + @Parameter(name=ApiConstants.HOST_CPU_CAPACITY, type=CommandType.LONG, description="Only for hypervisor is BareMetal, HZ per CPU of host") + private Long cpuCapacity; + + @Parameter(name=ApiConstants.HOST_CPU_NUM, type=CommandType.LONG, description="Only for hypervisor is BareMetal, number of CPU on host") + private Long cpuNum; + + @Parameter(name=ApiConstants.HOST_MEM_CAPACITY, type=CommandType.LONG, description="Only for hypervisor is BareMetal, memory capacity of host(in MB)") + private Long memCapacity; + + @Parameter(name=ApiConstants.HOST_MAC, type=CommandType.STRING, description="Only for hypervisor is BareMetal, Mac of PXE nic") + private String mac; + + @Parameter(name=ApiConstants.HOST_TAG, type=CommandType.STRING, description="Only for hypervisor is BareMetal, Tag of host") + private String hostTag; + + @Parameter(name=ApiConstants.HOST_TAGS, type=CommandType.LIST, collectionType=CommandType.STRING, description="list of tags to be added to the host") private List hostTags; @@ -110,6 +127,26 @@ public class AddHostCmd extends BaseCmd { return hostTags; } + public Long getCpuCapacity() { + return cpuCapacity; + } + + public Long getCpuNum() { + return cpuNum; + } + + public Long getMemCapacity() { + return memCapacity; + } + + public String getMac() { + return mac; + } + + public String getHostTag() { + return hostTag; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/com/cloud/api/commands/DeployVMCmd.java b/api/src/com/cloud/api/commands/DeployVMCmd.java index ef830ecdb67..c3733bb95b4 100644 --- a/api/src/com/cloud/api/commands/DeployVMCmd.java +++ b/api/src/com/cloud/api/commands/DeployVMCmd.java @@ -38,6 +38,7 @@ import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.hypervisor.Hypervisor; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.offering.ServiceOffering; import com.cloud.template.VirtualMachineTemplate; @@ -236,7 +237,12 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { UserVm result; try { UserContext.current().setEventDetails("Vm Id: "+getEntityId()); - result = _userVmService.startVirtualMachine(this); + if (getHypervisor() == HypervisorType.BareMetal) { + result = _bareMetalVmService.startVirtualMachine(this); + } else { + result = _userVmService.startVirtualMachine(this); + } + if (result != null) { UserVmResponse response = _responseGenerator.createUserVmResponse(result); response.setResponseName(getCommandName()); @@ -260,7 +266,6 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { @Override public void create() throws ResourceAllocationException{ try { - //Verify that all objects exist before passing them to the service Account owner = _accountService.getActiveAccount(getAccountName(), getDomainId()); if (owner == null) { @@ -282,28 +287,34 @@ public class DeployVMCmd extends BaseAsyncCreateCmd { if (template == null) { throw new InvalidParameterValueException("Unable to use template " + templateId); } + + UserVm vm = null; + if (getHypervisor() == HypervisorType.BareMetal) { + vm = _bareMetalVmService.createVirtualMachine(this); + } else { + if (zone.getNetworkType() == NetworkType.Basic) { + if (getNetworkIds() != null) { + throw new InvalidParameterValueException("Can't specify network Ids in Basic zone"); + } else { + vm = _userVmService.createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, securityGroupIdList, owner, name, + displayName, diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName); + } + } else { + if (zone.isSecurityGroupEnabled()) { + vm = _userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, getNetworkIds(), securityGroupIdList, + owner, name, displayName, diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName); + } else { + if (securityGroupIdList != null && !securityGroupIdList.isEmpty()) { + throw new InvalidParameterValueException("Can't create vm with security groups; security group feature is not enabled per zone"); + } + vm = _userVmService.createAdvancedVirtualMachine(zone, serviceOffering, template, getNetworkIds(), owner, name, displayName, + diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName); + } + } + } - UserVm vm = null; - - if (zone.getNetworkType() == NetworkType.Basic){ - if (getNetworkIds() != null) { - throw new InvalidParameterValueException("Can't specify network Ids in Basic zone"); - } else { - vm = _userVmService.createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, securityGroupIdList, owner, name, displayName, diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName); - } - } else { - if (zone.isSecurityGroupEnabled()) { - vm = _userVmService.createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, getNetworkIds(), securityGroupIdList, owner, name, displayName, diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName); - } else { - if (securityGroupIdList != null && !securityGroupIdList.isEmpty()) { - throw new InvalidParameterValueException("Can't create vm with security groups; security group feature is not enabled per zone"); - } - vm = _userVmService.createAdvancedVirtualMachine(zone, serviceOffering, template, getNetworkIds(), owner, name, displayName, diskOfferingId, size, group, getHypervisor(), userData, sshKeyPairName); - } - } - - if (vm != null){ - setEntityId(vm.getId()); + if (vm != null) { + setEntityId(vm.getId()); } else { throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Failed to deploy vm"); } diff --git a/api/src/com/cloud/api/commands/DestroyVMCmd.java b/api/src/com/cloud/api/commands/DestroyVMCmd.java index 3fd4bc1cc07..3a44ed19857 100644 --- a/api/src/com/cloud/api/commands/DestroyVMCmd.java +++ b/api/src/com/cloud/api/commands/DestroyVMCmd.java @@ -30,6 +30,7 @@ import com.cloud.async.AsyncJob; import com.cloud.event.EventTypes; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.user.Account; import com.cloud.user.UserContext; import com.cloud.uservm.UserVm; @@ -95,7 +96,13 @@ public class DestroyVMCmd extends BaseAsyncCmd { @Override public void execute() throws ResourceUnavailableException, ConcurrentOperationException{ UserContext.current().setEventDetails("Vm Id: "+getId()); - UserVm result = _userVmService.destroyVm(this); + UserVm result; + if (_userVmService.getHypervisorTypeOfUserVM(getId()) == HypervisorType.BareMetal) { + result = _bareMetalVmService.destroyVm(this); + } else { + result = _userVmService.destroyVm(this); + } + if (result != null) { UserVmResponse response = _responseGenerator.createUserVmResponse(result); response.setResponseName("virtualmachine"); diff --git a/api/src/com/cloud/api/commands/RebootVMCmd.java b/api/src/com/cloud/api/commands/RebootVMCmd.java index e087acd5d37..dc1669fd80d 100644 --- a/api/src/com/cloud/api/commands/RebootVMCmd.java +++ b/api/src/com/cloud/api/commands/RebootVMCmd.java @@ -30,6 +30,7 @@ import com.cloud.async.AsyncJob; import com.cloud.event.EventTypes; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.user.Account; import com.cloud.user.UserContext; import com.cloud.uservm.UserVm; @@ -94,7 +95,13 @@ public class RebootVMCmd extends BaseAsyncCmd { @Override public void execute() throws ResourceUnavailableException, InsufficientCapacityException{ UserContext.current().setEventDetails("Vm Id: "+getId()); - UserVm result = _userVmService.rebootVirtualMachine(this); + UserVm result; + if (_userVmService.getHypervisorTypeOfUserVM(getId()) == HypervisorType.BareMetal) { + result = _bareMetalVmService.rebootVirtualMachine(this); + } else { + result = _userVmService.rebootVirtualMachine(this); + } + if (result !=null){ UserVmResponse response = _responseGenerator.createUserVmResponse(result); response.setResponseName(getCommandName()); diff --git a/api/src/com/cloud/api/commands/StartVMCmd.java b/api/src/com/cloud/api/commands/StartVMCmd.java index 640c75b9bce..389de61828f 100644 --- a/api/src/com/cloud/api/commands/StartVMCmd.java +++ b/api/src/com/cloud/api/commands/StartVMCmd.java @@ -33,6 +33,7 @@ import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.exception.StorageUnavailableException; +import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.user.Account; import com.cloud.user.UserContext; import com.cloud.uservm.UserVm; @@ -104,7 +105,13 @@ public class StartVMCmd extends BaseAsyncCmd { public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ResourceAllocationException{ try { UserContext.current().setEventDetails("Vm Id: "+getId()); - UserVm result = _userVmService.startVirtualMachine(this); + UserVm result; + if (_userVmService.getHypervisorTypeOfUserVM(getId()) == HypervisorType.BareMetal) { + result = _bareMetalVmService.startVirtualMachine(this); + } else { + result = _userVmService.startVirtualMachine(this); + } + if (result != null){ UserVmResponse response = _responseGenerator.createUserVmResponse(result); response.setResponseName(getCommandName()); diff --git a/api/src/com/cloud/api/commands/StopVMCmd.java b/api/src/com/cloud/api/commands/StopVMCmd.java index 4162bd91e66..bdef118bd8c 100644 --- a/api/src/com/cloud/api/commands/StopVMCmd.java +++ b/api/src/com/cloud/api/commands/StopVMCmd.java @@ -29,6 +29,7 @@ import com.cloud.api.response.UserVmResponse; import com.cloud.async.AsyncJob; import com.cloud.event.EventTypes; import com.cloud.exception.ConcurrentOperationException; +import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.user.Account; import com.cloud.user.UserContext; import com.cloud.uservm.UserVm; @@ -107,7 +108,14 @@ public class StopVMCmd extends BaseAsyncCmd { @Override public void execute() throws ServerApiException, ConcurrentOperationException{ UserContext.current().setEventDetails("Vm Id: "+getId()); - UserVm result = _userVmService.stopVirtualMachine(getId(), isForced()); + UserVm result; + + if (_userVmService.getHypervisorTypeOfUserVM(getId()) == HypervisorType.BareMetal) { + result = _bareMetalVmService.stopVirtualMachine(getId(), isForced()); + } else { + result = _userVmService.stopVirtualMachine(getId(), isForced()); + } + if (result != null) { UserVmResponse response = _responseGenerator.createUserVmResponse(result); response.setResponseName(getCommandName()); diff --git a/api/src/com/cloud/deploy/DeploymentPlanner.java b/api/src/com/cloud/deploy/DeploymentPlanner.java index e37217d6420..dd9e3d85eb6 100644 --- a/api/src/com/cloud/deploy/DeploymentPlanner.java +++ b/api/src/com/cloud/deploy/DeploymentPlanner.java @@ -44,6 +44,17 @@ public interface DeploymentPlanner extends Adapter { */ boolean check(VirtualMachineProfile vm, DeploymentPlan plan, DeployDestination dest, ExcludeList exclude); + /** + * canHandle is called before plan to determine if the plan can do the allocation. Planers should be exclusive so planner writer must + * make sure only one planer->canHandle return true in the planner list + * + * @param vm virtual machine. + * @param plan deployment plan that tells you where it's being deployed to. + * @param avoid avoid these data centers, pods, clusters, or hosts. + * @return true if it's okay to allocate; false or not + */ + boolean canHandle(VirtualMachineProfile vm, DeploymentPlan plan, ExcludeList avoid); + public static class ExcludeList { private Set _dcIds; private Set _podIds; diff --git a/api/src/com/cloud/host/Host.java b/api/src/com/cloud/host/Host.java index ef5baf1cb53..d620e631b7f 100755 --- a/api/src/com/cloud/host/Host.java +++ b/api/src/com/cloud/host/Host.java @@ -32,7 +32,8 @@ public interface Host { SecondaryStorage(false), ConsoleProxy(true), ExternalFirewall(false), - ExternalLoadBalancer(false); + ExternalLoadBalancer(false), + PxeServer(false); boolean _virtual; private Type(boolean virtual) { diff --git a/api/src/com/cloud/hypervisor/Hypervisor.java b/api/src/com/cloud/hypervisor/Hypervisor.java index 8e3805ea93b..a759050c36a 100644 --- a/api/src/com/cloud/hypervisor/Hypervisor.java +++ b/api/src/com/cloud/hypervisor/Hypervisor.java @@ -27,6 +27,8 @@ public class Hypervisor { VMware, VirtualBox, Parralels, + BareMetal, + Any; /*If you don't care about the hypervisor type*/ public static HypervisorType getType(String hypervisor) { @@ -46,9 +48,11 @@ public class Hypervisor { return HypervisorType.VirtualBox; } else if (hypervisor.equalsIgnoreCase("Parralels")) { return HypervisorType.Parralels; + }else if (hypervisor.equalsIgnoreCase("BareMetal")) { + return HypervisorType.BareMetal; } else if (hypervisor.equalsIgnoreCase("Any")) { return HypervisorType.Any; - } else { + } else { return HypervisorType.None; } } diff --git a/api/src/com/cloud/network/Network.java b/api/src/com/cloud/network/Network.java index 3af47467616..ec6e712311e 100644 --- a/api/src/com/cloud/network/Network.java +++ b/api/src/com/cloud/network/Network.java @@ -73,6 +73,8 @@ public interface Network extends ControlledEntity { public static final Provider DhcpServer = new Provider("DhcpServer"); public static final Provider JuniperSRX = new Provider("JuniperSRX"); public static final Provider F5BigIp = new Provider("F5BigIp"); + public static final Provider ExternalDhcpServer = new Provider("ExternalDhcpServer"); + public static final Provider ExternalGateWay = new Provider("ExternalGateWay"); private String name; diff --git a/api/src/com/cloud/offering/ServiceOffering.java b/api/src/com/cloud/offering/ServiceOffering.java index 6fa754ae4ed..7fa98b5e453 100755 --- a/api/src/com/cloud/offering/ServiceOffering.java +++ b/api/src/com/cloud/offering/ServiceOffering.java @@ -78,5 +78,4 @@ public interface ServiceOffering { * @return tag that should be present on the host needed, optional parameter */ String getHostTag(); - } diff --git a/api/src/com/cloud/storage/Storage.java b/api/src/com/cloud/storage/Storage.java index 5e5adb27b48..66b4c1c0a8e 100644 --- a/api/src/com/cloud/storage/Storage.java +++ b/api/src/com/cloud/storage/Storage.java @@ -23,7 +23,8 @@ public class Storage { RAW(false, false, false), VHD(true, true, true), ISO(false, false, false), - OVA(true, true, true, "ova"); + OVA(true, true, true, "ova"), + BAREMETAL(false, false, false); private final boolean thinProvisioned; private final boolean supportSparse; diff --git a/api/src/com/cloud/vm/BareMetalVmService.java b/api/src/com/cloud/vm/BareMetalVmService.java new file mode 100644 index 00000000000..eed95666d99 --- /dev/null +++ b/api/src/com/cloud/vm/BareMetalVmService.java @@ -0,0 +1,4 @@ +package com.cloud.vm; + +public interface BareMetalVmService extends UserVmService { +} diff --git a/api/src/com/cloud/vm/UserVmService.java b/api/src/com/cloud/vm/UserVmService.java index d1e1e9b996a..43d6fde09ad 100755 --- a/api/src/com/cloud/vm/UserVmService.java +++ b/api/src/com/cloud/vm/UserVmService.java @@ -265,4 +265,9 @@ public interface UserVmService { * @return List of UserVMs. */ List searchForUserVMs(ListVMsCmd cmd); + + HypervisorType getHypervisorTypeOfUserVM(long vmid); + + UserVm createVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, + StorageUnavailableException, ResourceAllocationException; } diff --git a/api/src/com/cloud/vm/VirtualMachine.java b/api/src/com/cloud/vm/VirtualMachine.java index a5449faef97..cbf64da9483 100755 --- a/api/src/com/cloud/vm/VirtualMachine.java +++ b/api/src/com/cloud/vm/VirtualMachine.java @@ -145,7 +145,13 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, StateObject User, DomainRouter, ConsoleProxy, - SecondaryStorageVm + SecondaryStorageVm, + + /* + * UserBareMetal is only used for selecting VirtualMachineGuru, there is no + * VM with this type. UserBareMetal should treat exactly as User. + */ + UserBareMetal, } public String getInstanceName(); diff --git a/api/src/com/cloud/vm/VirtualMachineProfile.java b/api/src/com/cloud/vm/VirtualMachineProfile.java index d3cece441ae..0d2f88b15ad 100644 --- a/api/src/com/cloud/vm/VirtualMachineProfile.java +++ b/api/src/com/cloud/vm/VirtualMachineProfile.java @@ -47,7 +47,8 @@ public interface VirtualMachineProfile { public static final Param VmPassword = new Param("VmPassword"); public static final Param ControlNic = new Param("ControlNic"); public static final Param RestartNetwork = new Param("RestartNetwork"); - + public static final Param PxeSeverType = new Param("PxeSeverType"); + private String name; public Param(String name) { diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index d347a9566b9..79a65130d93 100755 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -251,4 +251,5 @@ restartNetwork=com.cloud.api.commands.RestartNetworkCmd;15 registerSSHKeyPair=com.cloud.api.commands.RegisterSSHKeyPairCmd;15 createSSHKeyPair=com.cloud.api.commands.CreateSSHKeyPairCmd;15 deleteSSHKeyPair=com.cloud.api.commands.DeleteSSHKeyPairCmd;15 -listSSHKeyPairs=com.cloud.api.commands.ListSSHKeyPairsCmd;15 +listSSHKeyPairs=com.cloud.api.commands.ListSSHKeyPairsCmd;15 + diff --git a/client/tomcatconf/components.xml.in b/client/tomcatconf/components.xml.in index 70dc0409d5d..89f80d6b88d 100755 --- a/client/tomcatconf/components.xml.in +++ b/client/tomcatconf/components.xml.in @@ -76,6 +76,7 @@ + diff --git a/scripts/util/ipmi.py b/scripts/util/ipmi.py new file mode 100644 index 00000000000..01258b3baec --- /dev/null +++ b/scripts/util/ipmi.py @@ -0,0 +1,164 @@ +#!/usr/bin/python + +import sys, os, subprocess, errno, re +from os.path import exists + +TOOl_PATH = "/usr/bin/ipmitool" + +try: + from subprocess import check_call + from subprocess import CalledProcessError +except ImportError: + def check_call(*popenargs, **kwargs): + import subprocess + retcode = subprocess.call(*popenargs, **kwargs) + cmd = kwargs.get("args") + if cmd is None: cmd = popenargs[0] + if retcode: raise CalledProcessError(retcode, cmd) + return retcode + + class CalledProcessError(Exception): + def __init__(self, returncode, cmd): + self.returncode = returncode ; self.cmd = cmd + def __str__(self): return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode) + +class Command: + def __init__(self,name,parent=None): + self.__name = name + self.__parent = parent + def __getattr__(self,name): + if name == "_print": name = "print" + return Command(name,self) + def __call__(self,*args): + class CommandOutput: + def __init__(self,ret,stdout,stderr): + self.stdout = stdout + self.stderr = stderr + self.ret = ret + + cmd = self.__get_recursive_name() + list(args) + #print " ",cmd + popen = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE) + m = popen.communicate() + ret = popen.wait() + return CommandOutput(ret,*m) + def __get_recursive_name(self,sep=None): + m = self + l = [] + while m is not None: + l.append(m.__name) + m = m.__parent + l.reverse() + if sep: return sep.join(l) + else: return l + def __str__(self): + return ''%self.__get_recursive_name(sep=" ") + + def __repr__(self): return self.__str__() + + +ipmitool = Command("ipmitool") + +def check_tool(): + if exists(TOOl_PATH) == False: + print "Can not find ipmitool" + return False + +def ping(args): + hostname = args.get("hostname") + usrname = args.get("usrname") + password = args.get("password") + + if hostname == None: + print "No hostname" + return 1 + + o = ipmitool("-H", hostname, "-U", usrname, "-P", password, "chassis", "power", "status") + if o.ret: + print o.stderr + return 1 + else: + print o.stdout + return 0 + +def boot_dev(args): + hostname = args.get("hostname") + usrname = args.get("usrname") + password = args.get("password") + dev = args.get("dev") + + if hostname == None: + print "No hostname" + return 1 + + if dev == None: + print "No boot device specified" + return 1 + + o = ipmitool("-H", hostname, "-U", usrname, "-P", password, "chassis", "bootdev", dev) + if o.ret: + print o.stderr + return 1 + else: + return 0 + +def reboot(args): + hostname = args.get("hostname") + usrname = args.get("usrname") + password = args.get("password") + + if hostname == None: + print "No hostname" + return 1 + + o = ipmitool("-H", hostname, "-U", usrname, "-P", password, "chassis", "power", "reset") + if o.ret: + print o.stderr + return 1 + else: + return 0 + +def power(args): + hostname = args.get("hostname") + usrname = args.get("usrname") + password = args.get("password") + action = args.get("action") + + if hostname == None: + print "No hostname" + return 1 + + o = ipmitool("-H", hostname, "-U", usrname, "-P", password, "chassis", "power", action) + if o.ret: + print o.stderr + return 1 + else: + return 0 + +call_table = {"ping":ping, "boot_dev":boot_dev, "reboot":reboot, "power":power} +def dispatch(args): + cmd = args[1] + params = args[2:] + func_params = {} + + if call_table.has_key(cmd) == False: + print "No function %s" % cmd + return 1 + + for p in params: + pairs = p.split("=") + if len(pairs) != 2: + print "Invalid parameter %s" % p + return 1 + func_params[pairs[0]] = pairs[1] + + func = call_table[cmd] + return func(func_params) + +if __name__ == "__main__": + if check_tool() == False: + sys.exit(1) + if len(sys.argv) < 2: + print "Not enough arguments, at least one" + sys.exit(1) + sys.exit(dispatch(sys.argv)) diff --git a/server/src/com/cloud/agent/manager/AgentManagerImpl.java b/server/src/com/cloud/agent/manager/AgentManagerImpl.java index 74153412e5f..6200097e8e0 100755 --- a/server/src/com/cloud/agent/manager/AgentManagerImpl.java +++ b/server/src/com/cloud/agent/manager/AgentManagerImpl.java @@ -63,6 +63,7 @@ import com.cloud.agent.api.StartupCommand; import com.cloud.agent.api.StartupExternalFirewallCommand; import com.cloud.agent.api.StartupExternalLoadBalancerCommand; import com.cloud.agent.api.StartupProxyCommand; +import com.cloud.agent.api.StartupPxeServerCommand; import com.cloud.agent.api.StartupRoutingCommand; import com.cloud.agent.api.StartupStorageCommand; import com.cloud.agent.api.UnsupportedAnswer; @@ -750,14 +751,45 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, String url = cmd.getUrl(); String username = cmd.getUsername(); String password = cmd.getPassword(); + Long memCapacity = cmd.getMemCapacity(); + Long cpuCapacity = cmd.getCpuCapacity(); + Long cpuNum = cmd.getCpuNum(); + String mac = cmd.getMac(); + String hostTag = cmd.getHostTag(); + MapbareMetalParams = new HashMap(); + // this is for standalone option if (clusterName == null && clusterId == null) { clusterName = "Standalone-" + url; } + + if (cmd.getHypervisor().equalsIgnoreCase(Hypervisor.HypervisorType.BareMetal.toString())) { + if (memCapacity == null) { + memCapacity = Long.valueOf(0); + } + if (cpuCapacity == null) { + cpuCapacity = Long.valueOf(0); + } + if (cpuNum == null) { + cpuNum = Long.valueOf(0); + } + if (mac == null) { + mac = "unknown"; + } + + bareMetalParams.put("cpuNum", cpuNum.toString()); + bareMetalParams.put("cpuCapacity", cpuCapacity.toString()); + bareMetalParams.put("memCapacity", memCapacity.toString()); + bareMetalParams.put("mac", mac); + if (hostTag != null) { + bareMetalParams.put("hostTag", hostTag); + } + } + List hostTags = cmd.getHostTags(); - return discoverHosts(dcId, podId, clusterId, clusterName, url, - username, password, cmd.getHypervisor(), hostTags); + return discoverHostsFull(dcId, podId, clusterId, clusterName, url, + username, password, cmd.getHypervisor(), hostTags, bareMetalParams); } @Override @@ -775,6 +807,14 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, String clusterName, String url, String username, String password, String hypervisorType, List hostTags) throws IllegalArgumentException, DiscoveryException, InvalidParameterValueException { + return discoverHostsFull(dcId, podId, clusterId, clusterName, url, username, password, hypervisorType, hostTags, null); + } + + + private List discoverHostsFull(Long dcId, Long podId, Long clusterId, + String clusterName, String url, String username, String password, + String hypervisorType, ListhostTags, Mapparams) throws IllegalArgumentException, + DiscoveryException, InvalidParameterValueException { URI uri = null; // Check if the zone exists in the system @@ -868,6 +908,10 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, boolean isHypervisorTypeSupported = false; while (en.hasMoreElements()) { Discoverer discoverer = en.nextElement(); + if (params != null) { + discoverer.putParam(params); + } + if (!discoverer.matchHypervisor(hypervisorType)) { continue; } @@ -2356,6 +2400,8 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, type = Host.Type.ExternalFirewall; } else if (startup instanceof StartupExternalLoadBalancerCommand) { type = Host.Type.ExternalLoadBalancer; + } else if (startup instanceof StartupPxeServerCommand) { + type = Host.Type.PxeServer; } else { assert false : "Did someone add a new Startup command?"; } @@ -2690,7 +2736,7 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, // If this command is from a KVM agent, or from an agent that has a // null hypervisor type, don't do the CIDR check if (hypervisorType == null || hypervisorType == HypervisorType.KVM - || hypervisorType == HypervisorType.VMware) { + || hypervisorType == HypervisorType.VMware || hypervisorType == HypervisorType.BareMetal) { doCidrCheck = false; } diff --git a/server/src/com/cloud/configuration/DefaultComponentLibrary.java b/server/src/com/cloud/configuration/DefaultComponentLibrary.java index 8fb78863a12..9c3821ee245 100644 --- a/server/src/com/cloud/configuration/DefaultComponentLibrary.java +++ b/server/src/com/cloud/configuration/DefaultComponentLibrary.java @@ -295,6 +295,7 @@ public class DefaultComponentLibrary extends ComponentLibraryBase implements Com addManager("VirtualMachineManager", ClusteredVirtualMachineManagerImpl.class); addManager("HypervisorGuruManager", HypervisorGuruManagerImpl.class); + ComponentInfo info = addManager("ConsoleProxyManager", ConsoleProxyManagerImpl.class); info.addParameter("consoleproxy.sslEnabled", "true"); } diff --git a/server/src/com/cloud/deploy/BareMetalPlanner.java b/server/src/com/cloud/deploy/BareMetalPlanner.java new file mode 100644 index 00000000000..e1319997967 --- /dev/null +++ b/server/src/com/cloud/deploy/BareMetalPlanner.java @@ -0,0 +1,80 @@ +package com.cloud.deploy; + +import java.util.List; + +import javax.ejb.Local; + +import org.apache.log4j.Logger; + +import com.cloud.exception.InsufficientServerCapacityException; +import com.cloud.host.Host; +import com.cloud.host.HostVO; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.offering.ServiceOffering; +import com.cloud.service.ServiceOfferingVO; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachineProfile; +import com.cloud.vm.VirtualMachineProfileImpl; + +@Local(value=DeploymentPlanner.class) +public class BareMetalPlanner extends FirstFitPlanner implements DeploymentPlanner { + private static final Logger s_logger = Logger.getLogger(BareMetalPlanner.class); + + @Override + public DeployDestination plan(VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoid) throws InsufficientServerCapacityException { + VirtualMachine vm = vmProfile.getVirtualMachine(); + ServiceOffering offering = vmProfile.getServiceOffering(); + String hostTag = null; + + if (offering.getTags() != null) { + String[] tags = offering.getTags().split(","); + if (tags.length > 0) { + hostTag = tags[0]; + } + } + + if (hostTag != null) { + List hosts = _hostDao.listBy(Host.Type.Routing, vm.getDataCenterId()); + HostVO target = null; + for (HostVO h : hosts) { + _hostDao.loadDetails(h); + if (h.getDetail("hostTag") != null && h.getDetail("hostTag").equalsIgnoreCase(hostTag)) { + target = h; + break; + } + } + + if (target == null) { + s_logger.warn("Cannot find host with tag " + hostTag); + return null; + } + + int cpu = target.getCpus(); + int speed = target.getSpeed().intValue(); + Long ramSize = target.getTotalMemory() / (1024L*1024L); + ServiceOfferingVO newOffering = new ServiceOfferingVO(offering.getName(), cpu, ramSize.intValue(), speed, offering.getRateMbps(), + offering.getMulticastRateMbps(), false, offering.getDisplayText(), offering.getUseLocalStorage(), false, offering.getTags(), false); + ((VirtualMachineProfileImpl)vmProfile).setServiceOffering(newOffering); + } + + DeployDestination dest = super.plan(vmProfile, plan, avoid); + + if (hostTag == null && dest != null) { + Host h = dest.getHost(); + if (h.getCpus() != offering.getCpu() || h.getTotalMemory() != offering.getRamSize() || h.getSpeed() != offering.getSpeed()) { + throw new CloudRuntimeException(String.format("Bare Metal only allows one VM one host, " + + "the offering capcacity doesn't equal to host capacity(offering: cpu number:%$1s, cpu speed:%$2s," + + "ram size:%3$s; host: cpu number:%$4s, cpu speed:%$5s, ram size:%$6s)", offering.getCpu(), offering.getSpeed(), + offering.getRamSize(), h.getCpus(), h.getSpeed(), h.getTotalMemory())); + } + } + + return dest; + } + + @Override + public boolean canHandle(VirtualMachineProfile vm, DeploymentPlan plan, ExcludeList avoid) { + return vm.getHypervisorType() == HypervisorType.BareMetal; + } +} diff --git a/server/src/com/cloud/deploy/FirstFitPlanner.java b/server/src/com/cloud/deploy/FirstFitPlanner.java index 7230840cbc2..60542feebbd 100644 --- a/server/src/com/cloud/deploy/FirstFitPlanner.java +++ b/server/src/com/cloud/deploy/FirstFitPlanner.java @@ -24,12 +24,14 @@ import com.cloud.dc.Pod; import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.HostPodDao; +import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.exception.InsufficientServerCapacityException; import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.Status; import com.cloud.host.dao.DetailsDao; import com.cloud.host.dao.HostDao; +import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.offering.ServiceOffering; import com.cloud.org.Cluster; import com.cloud.storage.DiskOfferingVO; @@ -57,22 +59,22 @@ import com.cloud.vm.dao.VMInstanceDao; @Local(value=DeploymentPlanner.class) public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { private static final Logger s_logger = Logger.getLogger(FirstFitPlanner.class); - @Inject private HostDao _hostDao; - @Inject private DataCenterDao _dcDao; - @Inject private HostPodDao _podDao; - @Inject private ClusterDao _clusterDao; - @Inject DetailsDao _hostDetailsDao = null; - @Inject GuestOSDao _guestOSDao = null; - @Inject GuestOSCategoryDao _guestOSCategoryDao = null; - @Inject private DiskOfferingDao _diskOfferingDao; - @Inject private StoragePoolHostDao _poolHostDao; - @Inject private UserVmDao _vmDao; - @Inject VMInstanceDao _vmInstanceDao; + @Inject protected HostDao _hostDao; + @Inject protected DataCenterDao _dcDao; + @Inject protected HostPodDao _podDao; + @Inject protected ClusterDao _clusterDao; + @Inject protected DetailsDao _hostDetailsDao = null; + @Inject protected GuestOSDao _guestOSDao = null; + @Inject protected GuestOSCategoryDao _guestOSCategoryDao = null; + @Inject protected DiskOfferingDao _diskOfferingDao; + @Inject protected StoragePoolHostDao _poolHostDao; + @Inject protected UserVmDao _vmDao; + @Inject protected VMInstanceDao _vmInstanceDao; @Inject protected VolumeDao _volsDao; - @Inject CapacityManager _capacityMgr; - @Inject ConfigurationDao _configDao; + @Inject protected CapacityManager _capacityMgr; + @Inject protected ConfigurationDao _configDao; @Inject protected StoragePoolDao _storagePoolDao; - @Inject CapacityDao _capacityDao; + @Inject protected CapacityDao _capacityDao; @Inject(adapter=StoragePoolAllocator.class) protected Adapters _storagePoolAllocators; @@ -248,6 +250,12 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { List suitableHosts = findSuitableHosts(vmProfile, potentialPlan, avoid, RETURN_UPTO_ALL); //if found suitable hosts in this cluster, find suitable storage pools for each volume of the VM if(suitableHosts != null && !suitableHosts.isEmpty()){ + if (vmProfile.getHypervisorType() == HypervisorType.BareMetal) { + Pod pod = _podDao.findById(clusterVO.getPodId()); + DeployDestination dest = new DeployDestination(dc, pod, clusterVO, suitableHosts.get(0)); + return dest; + } + if (_allocationAlgorithm != null && _allocationAlgorithm.equalsIgnoreCase("random")) { Collections.shuffle(suitableHosts); } @@ -462,6 +470,7 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { break; } } + if(suitableVolumeStoragePools.isEmpty()){ s_logger.debug("No suitable pools found"); } @@ -475,4 +484,9 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { // TODO Auto-generated method stub return false; } + + @Override + public boolean canHandle(VirtualMachineProfile vm, DeploymentPlan plan, ExcludeList avoid) { + return vm.getHypervisorType() != HypervisorType.BareMetal; + } } diff --git a/server/src/com/cloud/deploy/SimplePlanner.java b/server/src/com/cloud/deploy/SimplePlanner.java index 35beb8d86fa..e309daff268 100644 --- a/server/src/com/cloud/deploy/SimplePlanner.java +++ b/server/src/com/cloud/deploy/SimplePlanner.java @@ -26,12 +26,14 @@ import com.cloud.dc.Pod; import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.HostPodDao; +import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.host.Host; import com.cloud.host.Host.Type; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.org.Cluster; import com.cloud.utils.component.Inject; +import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; @Local(value=DeploymentPlanner.class) @@ -68,4 +70,10 @@ public class SimplePlanner extends PlannerBase implements DeploymentPlanner { protected SimplePlanner() { super(); } + + //TODO: set it to true if you want to use it + @Override + public boolean canHandle(VirtualMachineProfile vm, DeploymentPlan plan, ExcludeList avoid) { + return false; + } } diff --git a/server/src/com/cloud/hypervisor/kvm/discoverer/KvmServerDiscoverer.java b/server/src/com/cloud/hypervisor/kvm/discoverer/KvmServerDiscoverer.java index 1c4b028929c..b881243b8ca 100644 --- a/server/src/com/cloud/hypervisor/kvm/discoverer/KvmServerDiscoverer.java +++ b/server/src/com/cloud/hypervisor/kvm/discoverer/KvmServerDiscoverer.java @@ -1,7 +1,5 @@ package com.cloud.hypervisor.kvm.discoverer; -import java.io.IOException; -import java.io.InputStream; import java.net.InetAddress; import java.net.URI; import java.util.HashMap; @@ -38,6 +36,7 @@ import com.cloud.resource.ServerResource; import com.cloud.utils.component.ComponentLocator; import com.cloud.utils.component.Inject; import com.cloud.utils.script.Script; +import com.cloud.utils.ssh.SSHCmdHelper; import com.trilead.ssh2.ChannelCondition; import com.trilead.ssh2.SCPClient; import com.trilead.ssh2.Session; @@ -101,85 +100,6 @@ public class KvmServerDiscoverer extends DiscovererBase implements Discoverer, // TODO Auto-generated method stub return false; } - - private static boolean sshExecuteCmd(com.trilead.ssh2.Connection sshConnection, String cmd) { - s_logger.debug("Executing cmd: " + cmd); - Session sshSession = null; - try { - sshSession = sshConnection.openSession(); - // There is a bug in Trilead library, wait a second before - // starting a shell and executing commands, from http://spci.st.ewi.tudelft.nl/chiron/xref/nl/tudelft/swerl/util/SSHConnection.html - Thread.sleep(1000); - - if (sshSession == null) { - return false; - } - - sshSession.execCommand(cmd); - - InputStream stdout = sshSession.getStdout(); - InputStream stderr = sshSession.getStderr(); - - - byte[] buffer = new byte[8192]; - while (true) { - if (stdout == null || stderr == null) { - return false; - } - - if ((stdout.available() == 0) && (stderr.available() == 0)) { - int conditions = sshSession.waitForCondition( - ChannelCondition.STDOUT_DATA - | ChannelCondition.STDERR_DATA - | ChannelCondition.EOF, 120000); - - if ((conditions & ChannelCondition.TIMEOUT) != 0) { - s_logger.info("Timeout while waiting for data from peer."); - break; - } - - if ((conditions & ChannelCondition.EOF) != 0) { - if ((conditions & (ChannelCondition.STDOUT_DATA | ChannelCondition.STDERR_DATA)) == 0) { - break; - } - } - } - - while (stdout.available() > 0) { - stdout.read(buffer); - } - - while (stderr.available() > 0) { - stderr.read(buffer); - } - } - - Thread.sleep(1000); - if (sshSession.getExitStatus() != 0) { - return false; - } - - return true; - } catch (IOException e) { - s_logger.debug("Executing cmd: " + cmd + " failed, due to: " + e.toString()); - return false; - } catch (InterruptedException e) { - return false; - } catch (Exception e) { - return false; - } finally { - if (sshSession != null) - sshSession.close(); - } - } - - private static boolean sshExecuteCmd(com.trilead.ssh2.Connection sshConnection, String cmd, int nTimes) { - for (int i = 0; i < nTimes; i ++) { - if (sshExecuteCmd(sshConnection, cmd)) - return true; - } - return false; - } @Override public Map> find(long dcId, @@ -222,7 +142,7 @@ public class KvmServerDiscoverer extends DiscovererBase implements Discoverer, return null; } - if (!sshExecuteCmd(sshConnection, "lsmod|grep kvm >& /dev/null", 3)) { + if (!SSHCmdHelper.sshExecuteCmd(sshConnection, "lsmod|grep kvm >& /dev/null", 3)) { s_logger.debug("It's not a KVM enabled machine"); return null; } @@ -241,7 +161,7 @@ public class KvmServerDiscoverer extends DiscovererBase implements Discoverer, parameters += " -N " + _kvmPrivateNic; } - sshExecuteCmd(sshConnection, "/usr/bin/setup_agent.sh " + parameters + " 1>&2", 3); + SSHCmdHelper.sshExecuteCmd(sshConnection, "/usr/bin/setup_agent.sh " + parameters + " 1>&2", 3); KvmDummyResourceBase kvmResource = new KvmDummyResourceBase(); Map params = new HashMap(); diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java index f63ab90479b..a83217c05e3 100644 --- a/server/src/com/cloud/network/NetworkManager.java +++ b/server/src/com/cloud/network/NetworkManager.java @@ -42,6 +42,7 @@ import com.cloud.user.AccountVO; import com.cloud.utils.Pair; import com.cloud.vm.Nic; import com.cloud.vm.NicProfile; +import com.cloud.vm.NicVO; import com.cloud.vm.ReservationContext; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; diff --git a/server/src/com/cloud/network/element/DhcpElement.java b/server/src/com/cloud/network/element/DhcpElement.java index f73de949ddd..8d2c23ad436 100644 --- a/server/src/com/cloud/network/element/DhcpElement.java +++ b/server/src/com/cloud/network/element/DhcpElement.java @@ -80,6 +80,8 @@ public class DhcpElement extends AdapterBase implements NetworkElement, Password if (provider != null && provider.equalsIgnoreCase(Provider.JuniperSRX.getName()) && ipType == GuestIpType.Virtual) { return true; + } else if (dc.getDhcpProvider().equalsIgnoreCase(Provider.ExternalDhcpServer.getName())){ + return false; } else { if (dc.getNetworkType() == NetworkType.Basic) { return (ipType == GuestIpType.Direct && trafficType == TrafficType.Guest); diff --git a/server/src/com/cloud/resource/Discoverer.java b/server/src/com/cloud/resource/Discoverer.java index eba1aaf7c61..8d92a47d44e 100644 --- a/server/src/com/cloud/resource/Discoverer.java +++ b/server/src/com/cloud/resource/Discoverer.java @@ -45,4 +45,5 @@ public interface Discoverer extends Adapter { boolean matchHypervisor(String hypervisor); Hypervisor.HypervisorType getHypervisorType(); + public void putParam(Map params); } diff --git a/server/src/com/cloud/resource/DiscovererBase.java b/server/src/com/cloud/resource/DiscovererBase.java index 77678c53f91..03ac483a537 100644 --- a/server/src/com/cloud/resource/DiscovererBase.java +++ b/server/src/com/cloud/resource/DiscovererBase.java @@ -18,6 +18,7 @@ package com.cloud.resource; import java.net.URL; +import java.util.HashMap; import java.util.Map; import javax.naming.ConfigurationException; @@ -44,6 +45,14 @@ public abstract class DiscovererBase implements Discoverer { return null; } + + @Override + public void putParam(Map params) { + if (_params == null) { + _params = new HashMap(); + } + _params.putAll(params); + } @Override public String getName() { diff --git a/server/src/com/cloud/resource/DummyHostDiscoverer.java b/server/src/com/cloud/resource/DummyHostDiscoverer.java index a50c5eb1c33..def7167eab6 100644 --- a/server/src/com/cloud/resource/DummyHostDiscoverer.java +++ b/server/src/com/cloud/resource/DummyHostDiscoverer.java @@ -103,5 +103,11 @@ public class DummyHostDiscoverer implements Discoverer { @Override public void postDiscovery(List hosts, long msId) { //do nothing + } + + @Override + public void putParam(Map params) { + // TODO Auto-generated method stub + } } diff --git a/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java b/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java index b14941ea0f1..79cd61d807f 100755 --- a/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java +++ b/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java @@ -441,7 +441,11 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem List tmplts = listBy(sc); Collections.shuffle(tmplts); - return tmplts.get(0); + if (tmplts.size() > 0) { + return tmplts.get(0); + } else { + return null; + } } @Override diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java index 8af7ed2d391..5cde61eb696 100755 --- a/server/src/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/com/cloud/template/TemplateManagerImpl.java @@ -349,7 +349,8 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe &&(!url.toLowerCase().endsWith("qcow2"))&&(!url.toLowerCase().endsWith("qcow2.zip")) &&(!url.toLowerCase().endsWith("qcow2.bz2"))&&(!url.toLowerCase().endsWith("qcow2.gz")) &&(!url.toLowerCase().endsWith("ova"))&&(!url.toLowerCase().endsWith("ova.zip")) - &&(!url.toLowerCase().endsWith("ova.bz2"))&&(!url.toLowerCase().endsWith("ova.gz"))){ + &&(!url.toLowerCase().endsWith("ova.bz2"))&&(!url.toLowerCase().endsWith("ova.gz")) + &&hypervisorType != HypervisorType.BareMetal){ throw new InvalidParameterValueException("Please specify a valid "+format.toLowerCase()); } @@ -379,27 +380,36 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe if (imgfmt == null) { throw new IllegalArgumentException("Image format is incorrect " + format + ". Supported formats are " + EnumUtils.listValues(ImageFormat.values())); } - - URI uri = new URI(url); - if ((uri.getScheme() == null) || (!uri.getScheme().equalsIgnoreCase("http") && !uri.getScheme().equalsIgnoreCase("https") && !uri.getScheme().equalsIgnoreCase("file"))) { - throw new IllegalArgumentException("Unsupported scheme for url: " + url); - } - int port = uri.getPort(); - if (!(port == 80 || port == 443 || port == -1)) { - throw new IllegalArgumentException("Only ports 80 and 443 are allowed"); - } - String host = uri.getHost(); - try { - InetAddress hostAddr = InetAddress.getByName(host); - if (hostAddr.isAnyLocalAddress() || hostAddr.isLinkLocalAddress() || hostAddr.isLoopbackAddress() || hostAddr.isMulticastAddress() ) { - throw new IllegalArgumentException("Illegal host specified in url"); - } - if (hostAddr instanceof Inet6Address) { - throw new IllegalArgumentException("IPV6 addresses not supported (" + hostAddr.getHostAddress() + ")"); - } - } catch (UnknownHostException uhe) { - throw new IllegalArgumentException("Unable to resolve " + host); - } + + String uriStr; + if (url.startsWith("baremetal://")) { + uriStr = url.substring("baremetal://".length()); + } else { + URI uri = new URI(url); + if ((uri.getScheme() == null) + || (!uri.getScheme().equalsIgnoreCase("http") && !uri.getScheme().equalsIgnoreCase("https") && !uri.getScheme() + .equalsIgnoreCase("file"))) { + throw new IllegalArgumentException("Unsupported scheme for url: " + url); + } + + int port = uri.getPort(); + if (!(port == 80 || port == 443 || port == -1)) { + throw new IllegalArgumentException("Only ports 80 and 443 are allowed"); + } + String host = uri.getHost(); + try { + InetAddress hostAddr = InetAddress.getByName(host); + if (hostAddr.isAnyLocalAddress() || hostAddr.isLinkLocalAddress() || hostAddr.isLoopbackAddress() || hostAddr.isMulticastAddress()) { + throw new IllegalArgumentException("Illegal host specified in url"); + } + if (hostAddr instanceof Inet6Address) { + throw new IllegalArgumentException("IPV6 addresses not supported (" + hostAddr.getHostAddress() + ")"); + } + } catch (UnknownHostException uhe) { + throw new IllegalArgumentException("Unable to resolve " + host); + } + uriStr = uri.toString(); + } // Check that the resource limit for templates/ISOs won't be exceeded UserVO user = _userDao.findById(userId); @@ -427,13 +437,13 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe } } - return create(userId, accountId, zoneId, name, displayText, isPublic, featured, isExtractable, imgfmt, diskType, uri, chksum, requiresHvm, bits, enablePassword, guestOSId, bootable, hypervisorType); + return create(userId, accountId, zoneId, name, displayText, isPublic, featured, isExtractable, imgfmt, diskType, uriStr, chksum, requiresHvm, bits, enablePassword, guestOSId, bootable, hypervisorType); } catch (URISyntaxException e) { throw new IllegalArgumentException("Invalid URL " + url); } } - private VMTemplateVO create(long userId, long accountId, Long zoneId, String name, String displayText, boolean isPublic, boolean featured, boolean isExtractable, ImageFormat format, TemplateType type, URI url, String chksum, boolean requiresHvm, int bits, boolean enablePassword, long guestOSId, boolean bootable, HypervisorType hyperType) { + private VMTemplateVO create(long userId, long accountId, Long zoneId, String name, String displayText, boolean isPublic, boolean featured, boolean isExtractable, ImageFormat format, TemplateType type, String url, String chksum, boolean requiresHvm, int bits, boolean enablePassword, long guestOSId, boolean bootable, HypervisorType hyperType) { Long id = _tmpltDao.getNextInSequence(Long.class, "id"); AccountVO account = _accountDao.findById(accountId); @@ -441,7 +451,7 @@ public class TemplateManagerImpl implements TemplateManager, Manager, TemplateSe throw new IllegalArgumentException("Only admins can create templates in all zones"); } - VMTemplateVO template = new VMTemplateVO(id, name, format, isPublic, featured, isExtractable, type, url.toString(), requiresHvm, bits, accountId, chksum, displayText, enablePassword, guestOSId, bootable, hyperType); + VMTemplateVO template = new VMTemplateVO(id, name, format, isPublic, featured, isExtractable, type, url, requiresHvm, bits, accountId, chksum, displayText, enablePassword, guestOSId, bootable, hyperType); if (zoneId == null) { List dcs = _dcDao.listAllIncludingRemoved(); diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 2517a469aa9..9b547fd596a 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -197,68 +197,68 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager private static final Logger s_logger = Logger.getLogger(UserVmManagerImpl.class); private static final int ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION = 3; // 3 seconds - @Inject HostDao _hostDao = null; - @Inject DetailsDao _detailsDao = null; - @Inject DomainRouterDao _routerDao = null; - @Inject ServiceOfferingDao _offeringDao = null; - @Inject DiskOfferingDao _diskOfferingDao = null; - @Inject UserStatisticsDao _userStatsDao = null; - @Inject VMTemplateDao _templateDao = null; - @Inject VMTemplateHostDao _templateHostDao = null; - @Inject DomainDao _domainDao = null; - @Inject ResourceLimitDao _limitDao = null; - @Inject UserVmDao _vmDao = null; - @Inject VolumeDao _volsDao = null; - @Inject DataCenterDao _dcDao = null; - @Inject FirewallRulesDao _rulesDao = null; - @Inject LoadBalancerVMMapDao _loadBalancerVMMapDao = null; - @Inject LoadBalancerDao _loadBalancerDao = null; - @Inject IPAddressDao _ipAddressDao = null; - @Inject HostPodDao _podDao = null; - @Inject CapacityDao _capacityDao = null; - @Inject NetworkManager _networkMgr = null; - @Inject StorageManager _storageMgr = null; - @Inject SnapshotManager _snapshotMgr = null; - @Inject AgentManager _agentMgr = null; - @Inject ConfigurationManager _configMgr = null; - @Inject AccountDao _accountDao = null; - @Inject UserDao _userDao = null; - @Inject SnapshotDao _snapshotDao = null; - @Inject GuestOSDao _guestOSDao = null; - @Inject GuestOSCategoryDao _guestOSCategoryDao = null; - @Inject HighAvailabilityManager _haMgr = null; - @Inject AlertManager _alertMgr = null; - @Inject AccountManager _accountMgr; - @Inject AccountService _accountService; - @Inject AsyncJobManager _asyncMgr; - @Inject VlanDao _vlanDao; - @Inject ClusterDao _clusterDao; - @Inject AccountVlanMapDao _accountVlanMapDao; - @Inject StoragePoolDao _storagePoolDao; - @Inject VMTemplateHostDao _vmTemplateHostDao; - @Inject SecurityGroupManager _networkGroupMgr; - @Inject ServiceOfferingDao _serviceOfferingDao; - @Inject NetworkOfferingDao _networkOfferingDao; - @Inject EventDao _eventDao = null; - @Inject InstanceGroupDao _vmGroupDao; - @Inject InstanceGroupVMMapDao _groupVMMapDao; - @Inject VirtualMachineManager _itMgr; - @Inject NetworkDao _networkDao; - @Inject VirtualNetworkApplianceManager _routerMgr; - @Inject NicDao _nicDao; - @Inject RulesManager _rulesMgr; - @Inject LoadBalancingRulesManager _lbMgr; - @Inject UsageEventDao _usageEventDao; - @Inject SSHKeyPairDao _sshKeyPairDao; - @Inject UserVmDetailsDao _vmDetailsDao; + @Inject protected HostDao _hostDao = null; + @Inject protected DetailsDao _detailsDao = null; + @Inject protected DomainRouterDao _routerDao = null; + @Inject protected ServiceOfferingDao _offeringDao = null; + @Inject protected DiskOfferingDao _diskOfferingDao = null; + @Inject protected UserStatisticsDao _userStatsDao = null; + @Inject protected VMTemplateDao _templateDao = null; + @Inject protected VMTemplateHostDao _templateHostDao = null; + @Inject protected DomainDao _domainDao = null; + @Inject protected ResourceLimitDao _limitDao = null; + @Inject protected UserVmDao _vmDao = null; + @Inject protected VolumeDao _volsDao = null; + @Inject protected DataCenterDao _dcDao = null; + @Inject protected FirewallRulesDao _rulesDao = null; + @Inject protected LoadBalancerVMMapDao _loadBalancerVMMapDao = null; + @Inject protected LoadBalancerDao _loadBalancerDao = null; + @Inject protected IPAddressDao _ipAddressDao = null; + @Inject protected HostPodDao _podDao = null; + @Inject protected CapacityDao _capacityDao = null; + @Inject protected NetworkManager _networkMgr = null; + @Inject protected StorageManager _storageMgr = null; + @Inject protected SnapshotManager _snapshotMgr = null; + @Inject protected AgentManager _agentMgr = null; + @Inject protected ConfigurationManager _configMgr = null; + @Inject protected AccountDao _accountDao = null; + @Inject protected UserDao _userDao = null; + @Inject protected SnapshotDao _snapshotDao = null; + @Inject protected GuestOSDao _guestOSDao = null; + @Inject protected GuestOSCategoryDao _guestOSCategoryDao = null; + @Inject protected HighAvailabilityManager _haMgr = null; + @Inject protected AlertManager _alertMgr = null; + @Inject protected AccountManager _accountMgr; + @Inject protected AccountService _accountService; + @Inject protected AsyncJobManager _asyncMgr; + @Inject protected VlanDao _vlanDao; + @Inject protected ClusterDao _clusterDao; + @Inject protected AccountVlanMapDao _accountVlanMapDao; + @Inject protected StoragePoolDao _storagePoolDao; + @Inject protected VMTemplateHostDao _vmTemplateHostDao; + @Inject protected SecurityGroupManager _networkGroupMgr; + @Inject protected ServiceOfferingDao _serviceOfferingDao; + @Inject protected NetworkOfferingDao _networkOfferingDao; + @Inject protected EventDao _eventDao = null; + @Inject protected InstanceGroupDao _vmGroupDao; + @Inject protected InstanceGroupVMMapDao _groupVMMapDao; + @Inject protected VirtualMachineManager _itMgr; + @Inject protected NetworkDao _networkDao; + @Inject protected VirtualNetworkApplianceManager _routerMgr; + @Inject protected NicDao _nicDao; + @Inject protected RulesManager _rulesMgr; + @Inject protected LoadBalancingRulesManager _lbMgr; + @Inject protected UsageEventDao _usageEventDao; + @Inject protected SSHKeyPairDao _sshKeyPairDao; + @Inject protected UserVmDetailsDao _vmDetailsDao; - ScheduledExecutorService _executor = null; - int _expungeInterval; - int _expungeDelay; + protected ScheduledExecutorService _executor = null; + protected int _expungeInterval; + protected int _expungeDelay; - String _name; - String _instance; - String _zone; + protected String _name; + protected String _instance; + protected String _zone; private ConfigurationDao _configDao; @@ -1826,7 +1826,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager } } - private boolean validPassword(String password) { + protected boolean validPassword(String password) { if (password == null || password.length() == 0) { return false; } @@ -2190,6 +2190,10 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager @Override @ActionEvent (eventType=EventTypes.EVENT_VM_CREATE, eventDescription="starting Vm", async=true) public UserVm startVirtualMachine(DeployVMCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException, ConcurrentOperationException { + return startVirtualMachine(cmd, null); + } + + protected UserVm startVirtualMachine(DeployVMCmd cmd, Map additonalParams) throws ResourceUnavailableException, InsufficientCapacityException, ConcurrentOperationException { long vmId = cmd.getEntityId(); UserVmVO vm = _vmDao.findById(vmId); _vmDao.loadDetails(vm); @@ -2226,6 +2230,9 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager try { Map params = new HashMap(); + if (additonalParams != null) { + params.putAll(additonalParams); + } params.put(VirtualMachineProfile.Param.VmPassword, password); vm = _itMgr.start(vm, params, caller, owner); } finally { @@ -2761,6 +2768,21 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager return _vmDao.search(sc, searchFilter); } - - + + @Override + public HypervisorType getHypervisorTypeOfUserVM(long vmid) { + UserVmVO userVm = _vmDao.findById(vmid); + if (userVm == null) { + throw new InvalidParameterValueException("unable to find a virtual machine with id " + vmid); + } + + return userVm.getHypervisorType(); + } + + @Override + public UserVm createVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, + StorageUnavailableException, ResourceAllocationException { + // TODO Auto-generated method stub + return null; + } } diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java index 0ab2243d5f2..6333a6e8e26 100755 --- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -134,6 +134,7 @@ import com.cloud.utils.fsm.StateMachine2; import com.cloud.vm.ItWorkVO.Step; import com.cloud.vm.VirtualMachine.Event; import com.cloud.vm.VirtualMachine.State; +import com.cloud.vm.VirtualMachine.Type; import com.cloud.vm.dao.ConsoleProxyDao; import com.cloud.vm.dao.DomainRouterDao; import com.cloud.vm.dao.NicDao; @@ -251,9 +252,11 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene if (template.getFormat() == ImageFormat.ISO) { _storageMgr.allocateRawVolume(VolumeType.ROOT, "ROOT-" + vm.getId(), rootDiskOffering.first(), rootDiskOffering.second(), vm, owner); - } else { + } else if (template.getFormat() == ImageFormat.BAREMETAL) { + }else { _storageMgr.allocateTemplatedVolume(VolumeType.ROOT, "ROOT-" + vm.getId(), rootDiskOffering.first(), template, vm, owner); } + for (Pair offering : dataDiskOfferings) { _storageMgr.allocateRawVolume(VolumeType.DATADISK, "DATA-" + vm.getId(), offering.first(), offering.second(), vm, owner); } @@ -299,6 +302,11 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene return (VirtualMachineGuru)_vmGurus.get(vm.getType()); } + @SuppressWarnings("unchecked") + private VirtualMachineGuru getBareMetalVmGuru(T vm) { + return (VirtualMachineGuru)_vmGurus.get(Type.UserBareMetal); + } + @Override public boolean expunge(T vm, User caller, Account account) throws ResourceUnavailableException { try { @@ -524,7 +532,13 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene public T advanceStart(T vm, Map params, User caller, Account account) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException { long vmId = vm.getId(); - VirtualMachineGuru vmGuru = getVmGuru(vm); + VirtualMachineGuru vmGuru; + if (vm.getHypervisorType() == HypervisorType.BareMetal) { + vmGuru = getBareMetalVmGuru(vm); + } else { + vmGuru = getVmGuru(vm); + } + vm = vmGuru.findById(vm.getId()); Ternary start = changeToStartState(vmGuru, vm, caller, account); if (start == null) { @@ -570,7 +584,11 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene VirtualMachineProfileImpl vmProfile = new VirtualMachineProfileImpl(vm, template, offering, account, params); DeployDestination dest = null; for (DeploymentPlanner planner : _planners) { - dest = planner.plan(vmProfile, plan, avoids); + if (planner.canHandle(vmProfile, plan, avoids)) { + dest = planner.plan(vmProfile, plan, avoids); + } else { + continue; + } if (dest != null) { avoids.addHost(dest.getHost().getId()); journal.record("Deployment found ", vmProfile, dest); @@ -590,7 +608,9 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene } try { - _storageMgr.prepare(vmProfile, dest); + if (vm.getHypervisorType() != HypervisorType.BareMetal) { + _storageMgr.prepare(vmProfile, dest); + } _networkMgr.prepare(vmProfile, dest, ctx); vmGuru.finalizeVirtualMachineProfile(vmProfile, dest, ctx); @@ -851,8 +871,10 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene } try { - _storageMgr.release(profile); - s_logger.debug("Successfully released storage resources for the vm " + vm); + if (vm.getHypervisorType() != HypervisorType.BareMetal) { + _storageMgr.release(profile); + s_logger.debug("Successfully released storage resources for the vm " + vm); + } } catch (Exception e) { s_logger.warn("Unable to release storage resources.", e); } diff --git a/server/src/com/cloud/vm/VirtualMachineProfileImpl.java b/server/src/com/cloud/vm/VirtualMachineProfileImpl.java index ecb826501fb..265e314870c 100644 --- a/server/src/com/cloud/vm/VirtualMachineProfileImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineProfileImpl.java @@ -229,4 +229,8 @@ public class VirtualMachineProfileImpl implements Virtua public Map getParameters() { return _params; } + + public void setServiceOffering(ServiceOfferingVO offering) { + _offering = offering; + } } diff --git a/utils/src/com/cloud/utils/script/Script.java b/utils/src/com/cloud/utils/script/Script.java index 614be735e1c..ea6fe12f250 100755 --- a/utils/src/com/cloud/utils/script/Script.java +++ b/utils/src/com/cloud/utils/script/Script.java @@ -154,6 +154,12 @@ public class Script implements Callable { return execute(new OutputInterpreter.OutputLogger(_logger)); } + @Override + public String toString() { + String[] command = _command.toArray(new String[_command.size()]); + return buildCommandLine(command); + } + public String execute(OutputInterpreter interpreter) { String[] command = _command.toArray(new String[_command.size()]); diff --git a/utils/src/com/cloud/utils/ssh/SSHCmdHelper.java b/utils/src/com/cloud/utils/ssh/SSHCmdHelper.java new file mode 100644 index 00000000000..2798c2d754e --- /dev/null +++ b/utils/src/com/cloud/utils/ssh/SSHCmdHelper.java @@ -0,0 +1,96 @@ +package com.cloud.utils.ssh; + +import java.io.IOException; +import java.io.InputStream; + +import org.apache.log4j.Logger; + +import com.trilead.ssh2.ChannelCondition; +import com.trilead.ssh2.Session; + +public class SSHCmdHelper { + private static final Logger s_logger = Logger.getLogger(SSHCmdHelper.class); + + public static boolean sshExecuteCmd(com.trilead.ssh2.Connection sshConnection, String cmd, int nTimes) { + for (int i = 0; i < nTimes; i ++) { + if (sshExecuteCmdOneShot(sshConnection, cmd)) + return true; + } + return false; + } + + public static boolean sshExecuteCmd(com.trilead.ssh2.Connection sshConnection, String cmd) { + return sshExecuteCmd(sshConnection, cmd, 3); + } + + public static boolean sshExecuteCmdOneShot(com.trilead.ssh2.Connection sshConnection, String cmd) { + s_logger.debug("Executing cmd: " + cmd); + Session sshSession = null; + try { + sshSession = sshConnection.openSession(); + // There is a bug in Trilead library, wait a second before + // starting a shell and executing commands, from http://spci.st.ewi.tudelft.nl/chiron/xref/nl/tudelft/swerl/util/SSHConnection.html + Thread.sleep(1000); + + if (sshSession == null) { + return false; + } + + sshSession.execCommand(cmd); + + InputStream stdout = sshSession.getStdout(); + InputStream stderr = sshSession.getStderr(); + + + byte[] buffer = new byte[8192]; + while (true) { + if (stdout == null || stderr == null) { + return false; + } + + if ((stdout.available() == 0) && (stderr.available() == 0)) { + int conditions = sshSession.waitForCondition( + ChannelCondition.STDOUT_DATA + | ChannelCondition.STDERR_DATA + | ChannelCondition.EOF, 120000); + + if ((conditions & ChannelCondition.TIMEOUT) != 0) { + s_logger.info("Timeout while waiting for data from peer."); + break; + } + + if ((conditions & ChannelCondition.EOF) != 0) { + if ((conditions & (ChannelCondition.STDOUT_DATA | ChannelCondition.STDERR_DATA)) == 0) { + break; + } + } + } + + while (stdout.available() > 0) { + stdout.read(buffer); + } + + while (stderr.available() > 0) { + stderr.read(buffer); + } + } + + Thread.sleep(1000); + if (sshSession.getExitStatus() != 0) { + return false; + } + + return true; + } catch (IOException e) { + s_logger.debug("Executing cmd: " + cmd + " failed, due to: " + e.toString()); + return false; + } catch (InterruptedException e) { + return false; + } catch (Exception e) { + return false; + } finally { + if (sshSession != null) + sshSession.close(); + } + } +}