From 35b7c26689c299a6edaae85425958ca0a03de1b2 Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 1 Mar 2011 11:40:40 -0800 Subject: [PATCH] Bug 8208 - bare metal provisioning able to start, stop, reboot, destroy VM --- .../com/cloud/api/commands/DestroyVMCmd.java | 9 +++++++- .../com/cloud/api/commands/RebootVMCmd.java | 9 +++++++- .../com/cloud/api/commands/StartVMCmd.java | 9 +++++++- api/src/com/cloud/api/commands/StopVMCmd.java | 10 +++++++- api/src/com/cloud/vm/UserVmService.java | 3 +++ scripts/util/ipmi.py | 20 +++++++++++++++- server/src/com/cloud/api/AddPxeServerCmd.java | 7 ++++++ .../baremetal/LinMinPxeServerManagerImpl.java | 12 +++++----- .../baremetal/LinMinPxeServerResource.java | 8 ++++++- .../com/cloud/vm/BareMetalVmManagerImpl.java | 23 +++++++++++++------ .../src/com/cloud/vm/UserVmManagerImpl.java | 10 ++++++++ .../cloud/vm/VirtualMachineManagerImpl.java | 6 +++-- utils/src/com/cloud/utils/script/Script.java | 6 +++++ 13 files changed, 111 insertions(+), 21 deletions(-) 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/vm/UserVmService.java b/api/src/com/cloud/vm/UserVmService.java index 643d63761b9..8605c3c9747 100755 --- a/api/src/com/cloud/vm/UserVmService.java +++ b/api/src/com/cloud/vm/UserVmService.java @@ -42,6 +42,7 @@ import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.exception.StorageUnavailableException; +import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.Volume; import com.cloud.template.VirtualMachineTemplate; import com.cloud.uservm.UserVm; @@ -170,4 +171,6 @@ public interface UserVmService { * @return List of UserVMs. */ List searchForUserVMs(ListVMsCmd cmd); + + HypervisorType getHypervisorTypeOfUserVM(long vmid); } diff --git a/scripts/util/ipmi.py b/scripts/util/ipmi.py index fa819c61fd1..01258b3baec 100644 --- a/scripts/util/ipmi.py +++ b/scripts/util/ipmi.py @@ -78,6 +78,7 @@ def ping(args): print o.stderr return 1 else: + print o.stdout return 0 def boot_dev(args): @@ -117,7 +118,24 @@ def reboot(args): else: return 0 -call_table = {"ping":ping, "boot_dev":boot_dev, "reboot":reboot} +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:] diff --git a/server/src/com/cloud/api/AddPxeServerCmd.java b/server/src/com/cloud/api/AddPxeServerCmd.java index 7778bca87ce..f0ec9aefee6 100644 --- a/server/src/com/cloud/api/AddPxeServerCmd.java +++ b/server/src/com/cloud/api/AddPxeServerCmd.java @@ -33,6 +33,9 @@ public class AddPxeServerCmd extends BaseCmd { @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.LONG, required = true, description="Zone in which to add the external firewall appliance.") private Long zoneId; + @Parameter(name=ApiConstants.POD_ID, type=CommandType.LONG, required = true, description="Zone in which to add the external firewall appliance.") + private Long podId; + @Parameter(name=ApiConstants.URL, type=CommandType.STRING, required = true, description="URL of the PXE server appliance.") private String url; @@ -68,6 +71,10 @@ public class AddPxeServerCmd extends BaseCmd { public String getType() { return type; } + + public Long getPod() { + return podId; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// diff --git a/server/src/com/cloud/baremetal/LinMinPxeServerManagerImpl.java b/server/src/com/cloud/baremetal/LinMinPxeServerManagerImpl.java index 73db98ef369..c6199e211c1 100644 --- a/server/src/com/cloud/baremetal/LinMinPxeServerManagerImpl.java +++ b/server/src/com/cloud/baremetal/LinMinPxeServerManagerImpl.java @@ -37,18 +37,16 @@ public class LinMinPxeServerManagerImpl extends PxeServerManagerImpl implements @Override public Host addPxeServer(AddPxeServerCmd cmd) throws InvalidParameterValueException, CloudRuntimeException { long zoneId = cmd.getZoneId(); + Long podId = cmd.getPod(); DataCenterVO zone = _dcDao.findById(zoneId); - String zoneName; if (zone == null) { throw new InvalidParameterValueException("Could not find zone with ID: " + zoneId); - } else { - zoneName = zone.getName(); - } + } - List pxeServers = _hostDao.listByTypeDataCenter(Host.Type.PxeServer, zoneId); + List pxeServers = _hostDao.listBy(Host.Type.PxeServer, null, podId, zoneId); if (pxeServers.size() != 0) { - throw new InvalidParameterValueException("Already had a PXE server in zone: " + zoneName); + throw new InvalidParameterValueException("Already had a PXE server in Pod: " + podId + " zone: " + zoneId); } URI uri; @@ -65,10 +63,12 @@ public class LinMinPxeServerManagerImpl extends PxeServerManagerImpl implements String guid = getPxeServerGuid(Long.toString(zoneId), PxeServerType.LinMin.getName(), ipAddress); Map params = new HashMap(); params.put("zone", Long.toString(zoneId)); + params.put("pod", podId.toString()); params.put("ip", ipAddress); params.put("username", username); params.put("password", password); params.put("guid", guid); + params.put("pod", Long.toString(cmd.getPod())); ServerResource resource = null; try { diff --git a/server/src/com/cloud/baremetal/LinMinPxeServerResource.java b/server/src/com/cloud/baremetal/LinMinPxeServerResource.java index 401ec2e04b4..f4222afa798 100644 --- a/server/src/com/cloud/baremetal/LinMinPxeServerResource.java +++ b/server/src/com/cloud/baremetal/LinMinPxeServerResource.java @@ -48,6 +48,7 @@ public class LinMinPxeServerResource implements ServerResource { String _password; String _ip; String _zoneId; + String _podId; class XmlReturn { NodeList nList; @@ -86,6 +87,7 @@ public class LinMinPxeServerResource implements ServerResource { _username = (String)params.get("username"); _password = (String)params.get("password"); _zoneId = (String)params.get("zone"); + _podId = (String)params.get("pod"); if (_guid == null) { throw new ConfigurationException("No Guid specified"); @@ -95,6 +97,10 @@ public class LinMinPxeServerResource implements ServerResource { throw new ConfigurationException("No Zone specified"); } + if (_podId == null) { + throw new ConfigurationException("No Pod specified"); + } + if (_ip == null) { throw new ConfigurationException("No IP specified"); } @@ -157,7 +163,7 @@ public class LinMinPxeServerResource implements ServerResource { StartupPxeServerCommand cmd = new StartupPxeServerCommand(); cmd.setName(_name); cmd.setDataCenter(_zoneId); - cmd.setPod(""); + cmd.setPod(_podId); cmd.setPrivateIpAddress(_ip); cmd.setStorageIpAddress(""); cmd.setVersion(""); diff --git a/server/src/com/cloud/vm/BareMetalVmManagerImpl.java b/server/src/com/cloud/vm/BareMetalVmManagerImpl.java index 34521df33db..306c4070685 100644 --- a/server/src/com/cloud/vm/BareMetalVmManagerImpl.java +++ b/server/src/com/cloud/vm/BareMetalVmManagerImpl.java @@ -16,6 +16,7 @@ import javax.naming.ConfigurationException; import org.apache.log4j.Logger; +import com.cloud.agent.api.StopAnswer; import com.cloud.agent.api.baremetal.PrepareLinMinPxeServerCommand; import com.cloud.agent.manager.Commands; import com.cloud.api.commands.AttachVolumeCmd; @@ -271,7 +272,9 @@ public class BareMetalVmManagerImpl extends UserVmManagerImpl implements BareMet if (_itMgr.allocate(vm, template, offering, null, null, networks, null, plan, cmd.getHypervisor(), owner) == null) { return null; } - + + // startVirtualMachine() will retrieve this property + vm.setDetail("pxeboot", "true"); _vmDao.saveDetails(vm); if (s_logger.isDebugEnabled()) { @@ -374,16 +377,12 @@ public class BareMetalVmManagerImpl extends UserVmManagerImpl implements BareMet throw new PermissionDeniedException("The owner of " + vm + " either does not exist or is disabled: " + vm.getAccountId()); } - if (profile.getTemplate() == null) { + PxeServerType pxeType = (PxeServerType) profile.getParameter(Param.PxeSeverType); + if (pxeType == null) { s_logger.debug("This is a normal IPMI start, skip prepartion of PXE server"); return true; } - s_logger.debug("This is a PXE start, prepare PXE server first"); - PxeServerType pxeType = (PxeServerType) profile.getParameter(Param.PxeSeverType); - if (pxeType == null) { - throw new CloudRuntimeException("No PXE type specified"); - } PxeServerManager pxeMgr = null; ComponentLocator locator = ComponentLocator.getLocator(ManagementService.Name); @@ -445,4 +444,14 @@ public class BareMetalVmManagerImpl extends UserVmManagerImpl implements BareMet return true; } + + @Override + public void finalizeStop(VirtualMachineProfile profile, StopAnswer answer) { + super.finalizeStop(profile, answer); + } + + @Override + public UserVm destroyVm(long vmId) throws ResourceUnavailableException, ConcurrentOperationException { + return super.destroyVm(vmId); + } } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index eb038e3257d..e5737796f14 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -2683,4 +2683,14 @@ 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(); + } } diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java index a61d9411145..45c676da67b 100755 --- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -841,8 +841,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/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()]);