diff --git a/server/src/com/cloud/consoleproxy/AgentBasedConsoleProxyManager.java b/server/src/com/cloud/consoleproxy/AgentBasedConsoleProxyManager.java index b573b44cf66..6c07c7864bf 100644 --- a/server/src/com/cloud/consoleproxy/AgentBasedConsoleProxyManager.java +++ b/server/src/com/cloud/consoleproxy/AgentBasedConsoleProxyManager.java @@ -303,11 +303,6 @@ public class AgentBasedConsoleProxyManager implements ConsoleProxyManager, Virtu return VirtualMachineName.getConsoleProxyId(vmName); } - @Override - public boolean destroy(ConsoleProxyVO vm) throws AgentUnavailableException { - return false; - } - @Override public ConsoleProxyVO get(long id) { return null; diff --git a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java index 4ccbe5b508d..a2147189b32 100644 --- a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java +++ b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java @@ -90,8 +90,8 @@ import com.cloud.exception.ResourceUnavailableException; import com.cloud.exception.StorageUnavailableException; import com.cloud.ha.HighAvailabilityManager; import com.cloud.host.Host; -import com.cloud.host.HostVO; import com.cloud.host.Host.Type; +import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.info.ConsoleProxyConnectionInfo; import com.cloud.info.ConsoleProxyInfo; @@ -115,9 +115,9 @@ import com.cloud.servlet.ConsoleProxyServlet; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePoolVO; import com.cloud.storage.VMTemplateHostVO; +import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.storage.VMTemplateVO; import com.cloud.storage.VolumeVO; -import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.storage.dao.GuestOSDao; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VMTemplateHostDao; @@ -1545,11 +1545,6 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, ConsoleProx } } - @Override - public boolean destroy(ConsoleProxyVO proxy) throws AgentUnavailableException { - return destroyProxy(proxy.getId()); - } - @Override @DB public boolean destroyProxy(long vmId) { @@ -1846,8 +1841,9 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, ConsoleProx } value = configs.get(Config.ConsoleProxyDisableRpFilter.key()); - if(value != null && value.equalsIgnoreCase("true")) - _disable_rp_filter = true; + if(value != null && value.equalsIgnoreCase("true")) { + _disable_rp_filter = true; + } value = configs.get("system.vm.use.local.storage"); if (value != null && value.equalsIgnoreCase("true")) { @@ -1952,8 +1948,9 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, ConsoleProx buf.append(" pod=").append(dest.getPod().getId()); buf.append(" guid=Proxy.").append(profile.getId()); buf.append(" proxy_vm=").append(profile.getId()); - if(_disable_rp_filter) + if(_disable_rp_filter) { buf.append(" disable_rp_filter=true"); + } boolean externalDhcp = false; String externalDhcpStr = _configDao.getValue("direct.attach.network.externalIpAllocator.enabled"); diff --git a/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java b/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java index 84ee6ead81c..7be40f71b58 100644 --- a/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java +++ b/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java @@ -60,6 +60,7 @@ import com.cloud.server.ManagementServer; import com.cloud.storage.StorageManager; import com.cloud.storage.dao.GuestOSCategoryDao; import com.cloud.storage.dao.GuestOSDao; +import com.cloud.user.AccountManager; import com.cloud.utils.NumbersUtil; import com.cloud.utils.component.Adapters; import com.cloud.utils.component.ComponentLocator; @@ -124,7 +125,9 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager { @Inject DataCenterDao _dcDao; @Inject HostPodDao _podDao; long _serverId; + @Inject(adapter=Investigator.class) Adapters _investigators; + @Inject(adapter=FenceBuilder.class) Adapters _fenceBuilders; @Inject AgentManager _agentMgr; @Inject AlertManager _alertMgr; @@ -132,6 +135,7 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager { @Inject GuestOSDao _guestOSDao; @Inject GuestOSCategoryDao _guestOSCategoryDao; @Inject VirtualMachineManager _itMgr; + @Inject AccountManager _accountMgr; String _instance; ScheduledExecutorService _executor; @@ -833,19 +837,14 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager { } if (vm.getHostId() != null) { - Command cmd = mgr.cleanup(vm, null); - Answer ans = _agentMgr.send(work.getHostId(), cmd); - if (ans.getResult()) { - mgr.completeStopCommand(vm); - if (mgr.destroy(vm)) { - s_logger.info("Successfully stopped " + vm.toString()); - return null; - } - } - s_logger.debug("Stop for " + vm.toString() + " was unsuccessful. Detail: " + ans.getDetails()); + if (_itMgr.destroy(vm, _accountMgr.getSystemUser(), _accountMgr.getSystemAccount())) { + s_logger.info("Successfully destroy " + vm); + return null; + } + s_logger.debug("Stop for " + vm + " was unsuccessful."); } else { if (s_logger.isDebugEnabled()) { - s_logger.debug(vm.toString() + " has already been stopped"); + s_logger.debug(vm + " has already been stopped"); } return null; } @@ -853,7 +852,9 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager { s_logger.debug("Agnet is not available" + e.getMessage()); } catch (OperationTimedoutException e) { s_logger.debug("operation timed out: " + e.getMessage()); - } + } catch (ConcurrentOperationException e) { + s_logger.debug("concurrent operation: " + e.getMessage()); + } work.setTimesTried(work.getTimesTried() + 1); return (System.currentTimeMillis() >> 10) + _stopRetryInterval; diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java index a3496d7005c..7387717e2b7 100644 --- a/server/src/com/cloud/network/NetworkManager.java +++ b/server/src/com/cloud/network/NetworkManager.java @@ -117,7 +117,7 @@ public interface NetworkManager extends NetworkService { void prepare(VirtualMachineProfile profile, DeployDestination dest, ReservationContext context) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException; void release(VirtualMachineProfile vmProfile); - void deallocate(VirtualMachineProfile vm); + void cleanupNics(VirtualMachineProfile vm); List getNics (VirtualMachine vm); diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index 7d784921960..bff7676278b 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -1276,7 +1276,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag } @Override - public void deallocate(VirtualMachineProfile vm) { + public void cleanupNics(VirtualMachineProfile vm) { List nics = _nicDao.listBy(vm.getId()); for (NicVO nic : nics) { nic.setState(Nic.State.Deallocating); diff --git a/server/src/com/cloud/network/element/DhcpElement.java b/server/src/com/cloud/network/element/DhcpElement.java index 11b284c3c4f..00871a8c127 100644 --- a/server/src/com/cloud/network/element/DhcpElement.java +++ b/server/src/com/cloud/network/element/DhcpElement.java @@ -75,17 +75,17 @@ public class DhcpElement extends AdapterBase implements NetworkElement{ } @Override - public boolean implement(Network guestConfig, NetworkOffering offering, DeployDestination dest, ReservationContext context) throws ResourceUnavailableException, ConcurrentOperationException, InsufficientCapacityException { + public boolean implement(Network network, NetworkOffering offering, DeployDestination dest, ReservationContext context) throws ResourceUnavailableException, ConcurrentOperationException, InsufficientCapacityException { if (!canHandle(offering.getGuestIpType(), dest)) { return false; } - _routerMgr.deployDhcp(guestConfig, dest, context.getAccount()); + _routerMgr.deployDhcp(network, dest, context.getAccount()); return true; } @Override - public boolean prepare(Network config, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException { - if (canHandle(config.getGuestType(), dest)) { + public boolean prepare(Network network, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException { + if (canHandle(network.getGuestType(), dest)) { if (vm.getType() != VirtualMachine.Type.User) { return false; @@ -94,20 +94,20 @@ public class DhcpElement extends AdapterBase implements NetworkElement{ @SuppressWarnings("unchecked") VirtualMachineProfile uservm = (VirtualMachineProfile)vm; - return _routerMgr.addVirtualMachineIntoNetwork(config, nic, uservm, dest, context, true) != null; + return _routerMgr.addVirtualMachineIntoNetwork(network, nic, uservm, dest, context, true) != null; } else { return false; } } @Override - public boolean release(Network config, NicProfile nic, VirtualMachineProfile vm, ReservationContext context) { + public boolean release(Network network, NicProfile nic, VirtualMachineProfile vm, ReservationContext context) { return true; } @Override - public boolean shutdown(Network config, ReservationContext context) throws ConcurrentOperationException { - DomainRouterVO router = _routerDao.findByNetworkConfiguration(config.getId()); + public boolean shutdown(Network network, ReservationContext context) throws ConcurrentOperationException { + DomainRouterVO router = _routerDao.findByNetworkConfiguration(network.getId()); if (router == null) { return true; } @@ -115,7 +115,7 @@ public class DhcpElement extends AdapterBase implements NetworkElement{ } @Override - public boolean applyRules(Network config, List rules) throws ResourceUnavailableException { + public boolean applyRules(Network network, List rules) throws ResourceUnavailableException { return false; } diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 1c773fcb19a..759dd9bd91b 100644 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -315,11 +315,6 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian return _routerDao.findByPublicIpAddress(publicIpAddress); } - @Override - public boolean destroy(DomainRouterVO router) { - return destroyRouter(router.getId()); - } - @Override public boolean sendSshKeysToHost(Long hostId, String pubKey, String prvKey) { ModifySshKeysCommand cmd = new ModifySshKeysCommand(pubKey, prvKey); diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 2c8b54ccdf2..834e6669301 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -331,7 +331,6 @@ public class ManagementServerImpl implements ManagementServer { private final UploadDao _uploadDao; private final CertificateDao _certDao; - private final ScheduledExecutorService _executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("AccountChecker")); private final ScheduledExecutorService _eventExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("EventChecker")); private final StatsCollector _statsCollector; @@ -344,8 +343,6 @@ public class ManagementServerImpl implements ManagementServer { private final int _proxyRamSize; private final int _ssRamSize; - private boolean _useNewNetworking = false; - private final Map _availableIdsMap; private boolean _isHypervisorSnapshotCapable = false; @@ -431,7 +428,6 @@ public class ManagementServerImpl implements ManagementServer { _ssRamSize = NumbersUtil.parseInt(_configs.get("secstorage.ram.size"), SecondaryStorageVmManager.DEFAULT_SS_VM_RAMSIZE); _statsCollector = StatsCollector.getInstance(_configs); - _executor.scheduleAtFixedRate(new AccountCleanupTask(), cleanup, cleanup, TimeUnit.SECONDS); _purgeDelay = NumbersUtil.parseInt(_configs.get("event.purge.delay"), 0); if(_purgeDelay != 0){ @@ -443,7 +439,6 @@ public class ManagementServerImpl implements ManagementServer { for (String id: availableIds) { _availableIdsMap.put(id, true); } - _useNewNetworking = Boolean.parseBoolean(_configs.get("use.new.networking")); } protected Map getConfigs() { @@ -3222,7 +3217,7 @@ public class ManagementServerImpl implements ManagementServer { sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId); List accounts = _accountDao.search(sc, null); for (AccountVO account : accounts) { - success = (success && _accountMgr.deleteAccountInternal(account.getAccountId())); + success = (success && _accountMgr.cleanupAccount(account, UserContext.current().getCallerUserId(), UserContext.current().getCaller())); String description = "Account:" + account.getAccountId(); if(success){ EventUtils.saveEvent(User.UID_SYSTEM, account.getAccountId(), EventVO.LEVEL_INFO, EventTypes.EVENT_ACCOUNT_DELETE, "Successfully deleted " +description); @@ -3880,7 +3875,7 @@ public class ManagementServerImpl implements ManagementServer { for (AccountVO account : accounts) { s_logger.debug("Cleaning up " + account.getId()); try { - _accountMgr.deleteAccount(account); + _accountMgr.cleanupAccount(account, _accountMgr.getSystemUser().getId(), _accountMgr.getSystemAccount()); } catch (Exception e) { s_logger.error("Skipping due to error on account " + account.getId(), e); } @@ -4176,23 +4171,7 @@ public class ManagementServerImpl implements ManagementServer { @Override public VirtualMachine startSystemVM(StartSystemVMCmd cmd) { - if (_useNewNetworking) { - return startSystemVm(cmd.getId()); - } - - //verify input - Long id = cmd.getId(); - - VMInstanceVO systemVm = _vmInstanceDao.findByIdTypes(id, VirtualMachine.Type.ConsoleProxy, VirtualMachine.Type.SecondaryStorageVm); - if (systemVm == null) { - throw new ServerApiException (BaseCmd.PARAM_ERROR, "unable to find a system vm with id " + id); - } - - if (systemVm.getType().equals(VirtualMachine.Type.ConsoleProxy)){ - return startConsoleProxy(id); - } else { - return startSecondaryStorageVm(id); - } + return startSystemVm(cmd.getId()); } @Override diff --git a/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java b/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java index 4c25ac5c832..6eb57085b12 100644 --- a/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java +++ b/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java @@ -62,7 +62,6 @@ import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.HostPodDao; import com.cloud.deploy.DataCenterDeployment; import com.cloud.deploy.DeployDestination; -import com.cloud.event.Event; import com.cloud.event.EventTypes; import com.cloud.event.EventUtils; import com.cloud.event.EventVO; @@ -125,7 +124,6 @@ import com.cloud.utils.net.NfsUtils; import com.cloud.vm.NicProfile; import com.cloud.vm.NicVO; import com.cloud.vm.ReservationContext; -import com.cloud.vm.SecondaryStorageVm; import com.cloud.vm.SecondaryStorageVmVO; import com.cloud.vm.State; import com.cloud.vm.VirtualMachine; @@ -1103,12 +1101,6 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V } } - @Override - public boolean destroy(SecondaryStorageVmVO secStorageVm) - throws AgentUnavailableException { - return destroySecStorageVm(secStorageVm.getId()); - } - @Override @DB public boolean destroySecStorageVm(long vmId) { diff --git a/server/src/com/cloud/user/AccountManager.java b/server/src/com/cloud/user/AccountManager.java index f0e408bed54..c1f2270644b 100755 --- a/server/src/com/cloud/user/AccountManager.java +++ b/server/src/com/cloud/user/AccountManager.java @@ -29,13 +29,12 @@ import com.cloud.domain.Domain; import com.cloud.domain.DomainVO; import com.cloud.exception.PermissionDeniedException; import com.cloud.server.Criteria; -import com.cloud.utils.component.Manager; /** * AccountManager includes logic that deals with accounts, domains, and users. * */ -public interface AccountManager extends Manager { +public interface AccountManager extends AccountService { /** * Finds all ISOs that are usable for a user. This includes ISOs usable for the user's account and for all of the account's parent domains. @@ -106,14 +105,15 @@ public interface AccountManager extends Manager { */ boolean disableAccount(long accountId); - boolean deleteAccount(AccountVO account); + boolean deleteAccount(AccountVO account, long callerUserId, Account caller); void checkAccess(Account account, Domain domain) throws PermissionDeniedException; void checkAccess(Account account, ControlledEntity... entities) throws PermissionDeniedException; - boolean deleteAccountInternal(long accountId); + boolean cleanupAccount(AccountVO account, long callerUserId, Account caller); - UserVO createUser(CreateUserCmd cmd); + @Override + UserVO createUser(CreateUserCmd cmd); } diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java index 21e867480fb..918a72d6be2 100755 --- a/server/src/com/cloud/user/AccountManagerImpl.java +++ b/server/src/com/cloud/user/AccountManagerImpl.java @@ -22,6 +22,9 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import javax.ejb.Local; import javax.naming.ConfigurationException; @@ -45,9 +48,11 @@ import com.cloud.api.commands.LockUserCmd; import com.cloud.api.commands.UpdateAccountCmd; import com.cloud.api.commands.UpdateResourceLimitCmd; import com.cloud.api.commands.UpdateUserCmd; +import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; import com.cloud.configuration.ResourceCount.ResourceType; import com.cloud.configuration.ResourceLimitVO; +import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.configuration.dao.ResourceCountDao; import com.cloud.configuration.dao.ResourceLimitDao; import com.cloud.dc.PodVlanMapVO; @@ -83,13 +88,18 @@ import com.cloud.user.Account.State; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.UserAccountDao; import com.cloud.user.dao.UserDao; +import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.component.Adapters; +import com.cloud.utils.component.ComponentLocator; import com.cloud.utils.component.Inject; +import com.cloud.utils.component.Manager; +import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.Filter; import com.cloud.utils.db.GlobalLock; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.DomainRouterVO; import com.cloud.vm.InstanceGroupVO; @@ -100,7 +110,7 @@ import com.cloud.vm.dao.InstanceGroupDao; import com.cloud.vm.dao.UserVmDao; @Local(value={AccountManager.class, AccountService.class}) -public class AccountManagerImpl implements AccountManager, AccountService { +public class AccountManagerImpl implements AccountManager, AccountService, Manager { public static final Logger s_logger = Logger.getLogger(AccountManagerImpl.class); private String _name; @@ -130,12 +140,15 @@ public class AccountManagerImpl implements AccountManager, AccountService { @Inject private ConfigurationManager _configMgr; @Inject private VirtualNetworkApplianceManager _routerMgr; + private final ScheduledExecutorService _executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("AccountChecker")); + private final GlobalLock m_resourceCountLock = GlobalLock.getInternLock("resource.count"); UserVO _systemUser; AccountVO _systemAccount; @Inject(adapter=SecurityChecker.class) Adapters _securityCheckers; + int _cleanupInterval; @Override public boolean configure(final String name, final Map params) throws ConfigurationException { @@ -150,6 +163,14 @@ public class AccountManagerImpl implements AccountManager, AccountService { if (_systemUser == null) { throw new ConfigurationException("Unable to find the system user using " + User.UID_SYSTEM); } + + ComponentLocator locator = ComponentLocator.getCurrentLocator(); + ConfigurationDao configDao = locator.getDao(ConfigurationDao.class); + Map configs = configDao.getConfiguration(params); + + String value = configs.get(Config.AccountCleanupInterval.key()); + _cleanupInterval = NumbersUtil.parseInt(value, 60 * 60 * 24); // 1 hour. + return true; } @@ -165,6 +186,7 @@ public class AccountManagerImpl implements AccountManager, AccountService { @Override public boolean start() { + _executor.scheduleAtFixedRate(new AccountCleanupTask(), _cleanupInterval, _cleanupInterval, TimeUnit.SECONDS); return true; } @@ -752,31 +774,27 @@ public class AccountManagerImpl implements AccountManager, AccountService { } @Override - public boolean deleteAccountInternal(long accountId) { - boolean result = false; + public boolean deleteAccount(AccountVO account, long callerUserId, Account caller) { + long accountId = account.getId(); try { - List users = _userDao.listByAccount(accountId); - - for(UserVO user : users){ - //remove each user - _userDao.remove(user.getId()); - } - - result = _accountDao.remove(accountId); - if (!result) { + if (!_accountDao.remove(accountId)) { s_logger.error("Unable to delete account " + accountId); return false; } + List users = _userDao.listByAccount(accountId); + + for(UserVO user : users){ + _userDao.remove(user.getId()); + } + if (s_logger.isDebugEnabled()) { s_logger.debug("Remove account " + accountId); } - AccountVO account = _accountDao.findByIdIncludingRemoved(accountId); - deleteAccount(account); - result = true; - return result; + cleanupAccount(account, callerUserId, caller); + return true; } catch (Exception e) { s_logger.error("exception deleting account: " + accountId, e); return false; @@ -784,9 +802,8 @@ public class AccountManagerImpl implements AccountManager, AccountService { } @Override - public boolean deleteAccount(AccountVO account) { + public boolean cleanupAccount(AccountVO account, long callerUserId, Account caller) { long accountId = account.getId(); - long userId = 1L; // only admins can delete users, pass in userId 1 XXX: Shouldn't it be userId 2. boolean accountCleanupNeeded = false; try { @@ -813,13 +830,13 @@ public class AccountManagerImpl implements AccountManager, AccountService { } for (UserVmVO vm : vms) { - long startEventId = EventUtils.saveStartedEvent(userId, vm.getAccountId(), EventTypes.EVENT_VM_DESTROY, "Destroyed VM instance : " + vm.getName()); - if (!_vmMgr.destroyVirtualMachine(userId, vm.getId())) { + long startEventId = EventUtils.saveStartedEvent(callerUserId, vm.getAccountId(), EventTypes.EVENT_VM_DESTROY, "Destroyed VM instance : " + vm.getName()); + if (!_vmMgr.expunge(vm, callerUserId, caller)) { s_logger.error("Unable to destroy vm: " + vm.getId()); accountCleanupNeeded = true; - EventUtils.saveEvent(userId, vm.getAccountId(), EventVO.LEVEL_ERROR, EventTypes.EVENT_VM_DESTROY, "Unable to destroy vm: " + vm.getId(), startEventId); + EventUtils.saveEvent(callerUserId, vm.getAccountId(), EventVO.LEVEL_ERROR, EventTypes.EVENT_VM_DESTROY, "Unable to destroy vm: " + vm.getId(), startEventId); } else { - EventUtils.saveEvent(userId, vm.getAccountId(), EventVO.LEVEL_INFO, EventTypes.EVENT_VM_DESTROY, "Successfully destroyed VM instance : " + vm.getName(), startEventId); + EventUtils.saveEvent(callerUserId, vm.getAccountId(), EventVO.LEVEL_INFO, EventTypes.EVENT_VM_DESTROY, "Successfully destroyed VM instance : " + vm.getName(), startEventId); } } @@ -840,13 +857,13 @@ public class AccountManagerImpl implements AccountManager, AccountService { boolean routersCleanedUp = true; for (DomainRouterVO router : routers) { - long startEventId = EventUtils.saveStartedEvent(userId, router.getAccountId(), EventTypes.EVENT_ROUTER_DESTROY, "Starting to destroy router : " + router.getName()); + long startEventId = EventUtils.saveStartedEvent(callerUserId, router.getAccountId(), EventTypes.EVENT_ROUTER_DESTROY, "Starting to destroy router : " + router.getName()); if (!_routerMgr.destroyRouter(router.getId())) { s_logger.error("Unable to destroy router: " + router.getId()); routersCleanedUp = false; - EventUtils.saveEvent(userId, router.getAccountId(), EventVO.LEVEL_ERROR, EventTypes.EVENT_ROUTER_DESTROY, "Unable to destroy router: " + router.getName(), startEventId); + EventUtils.saveEvent(callerUserId, router.getAccountId(), EventVO.LEVEL_ERROR, EventTypes.EVENT_ROUTER_DESTROY, "Unable to destroy router: " + router.getName(), startEventId); } else { - EventUtils.saveEvent(userId, router.getAccountId(), EventVO.LEVEL_INFO, EventTypes.EVENT_ROUTER_DESTROY, "successfully destroyed router : " + router.getName(), startEventId); + EventUtils.saveEvent(callerUserId, router.getAccountId(), EventVO.LEVEL_INFO, EventTypes.EVENT_ROUTER_DESTROY, "successfully destroyed router : " + router.getName(), startEventId); } } @@ -907,7 +924,7 @@ public class AccountManagerImpl implements AccountManager, AccountService { boolean allTemplatesDeleted = true; for (VMTemplateVO template : userTemplates) { try { - allTemplatesDeleted = _tmpltMgr.delete(userId, template.getId(), null); + allTemplatesDeleted = _tmpltMgr.delete(callerUserId, template.getId(), null); } catch (Exception e) { s_logger.warn("Failed to delete template while removing account: " + template.getName() + " due to: " + e.getMessage()); allTemplatesDeleted = false; @@ -1336,12 +1353,16 @@ public class AccountManagerImpl implements AccountManager, AccountService { @Override //This method deletes the account public boolean deleteUserAccount(DeleteAccountCmd cmd) { + UserContext ctx = UserContext.current(); + long callerUserId = ctx.getCallerUserId(); + Account caller = ctx.getCaller(); + Long accountId = cmd.getId(); // If the user is a System user, return an error. We do not allow this - Account account = _accountDao.findById(accountId); + AccountVO account = _accountDao.findById(accountId); if ((account != null) && (account.getId() == Account.ACCOUNT_ID_SYSTEM)) { - throw new InvalidParameterValueException("Account id : " + accountId + " is a system account, delete is not allowed"); + throw new PermissionDeniedException("Account id : " + accountId + " is a system account, delete is not allowed"); } if(account == null){ @@ -1353,7 +1374,7 @@ public class AccountManagerImpl implements AccountManager, AccountService { return true; } - return deleteAccountInternal(accountId); + return deleteAccount(account, callerUserId, caller); } @@ -1506,5 +1527,48 @@ public class AccountManagerImpl implements AccountManager, AccountService { } return success; } + + protected class AccountCleanupTask implements Runnable { + @Override + public void run() { + try { + GlobalLock lock = GlobalLock.getInternLock("AccountCleanup"); + if (lock == null) { + s_logger.debug("Couldn't get the global lock"); + return; + } + if (!lock.lock(30)) { + s_logger.debug("Couldn't lock the db"); + return; + } + + Transaction txn = null; + try { + txn = Transaction.open(Transaction.CLOUD_DB); + + List accounts = _accountDao.findCleanups(); + s_logger.info("Found " + accounts.size() + " accounts to cleanup"); + for (AccountVO account : accounts) { + s_logger.debug("Cleaning up " + account.getId()); + try { + cleanupAccount(account, getSystemUser().getId(), getSystemAccount()); + } catch (Exception e) { + s_logger.error("Skipping due to error on account " + account.getId(), e); + } + } + } catch (Exception e) { + s_logger.error("Exception ", e); + } finally { + if(txn != null) { + txn.close(); + } + + lock.unlock(); + } + } catch (Exception e) { + s_logger.error("Exception ", e); + } + } + } } diff --git a/server/src/com/cloud/vm/UserVmManager.java b/server/src/com/cloud/vm/UserVmManager.java index c9aa34edeb1..d2ddb7208c2 100644 --- a/server/src/com/cloud/vm/UserVmManager.java +++ b/server/src/com/cloud/vm/UserVmManager.java @@ -24,6 +24,7 @@ import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.exception.StorageUnavailableException; +import com.cloud.user.Account; import com.cloud.uservm.UserVm; import com.cloud.utils.exception.ExecutionException; import com.cloud.vm.VirtualMachine.Event; @@ -48,9 +49,6 @@ public interface UserVmManager extends VirtualMachineGuru{ */ UserVmVO getVirtualMachine(long vmId); - boolean destroyVirtualMachine(long userId, long vmId); - - /** * Attaches an ISO to the virtual CDROM device of the specified VM. Will eject any existing virtual CDROM if isoPath is null. * @param vmId @@ -79,13 +77,6 @@ public interface UserVmManager extends VirtualMachineGuru{ */ HashMap getVirtualMachineStatistics(long hostId, String hostName, List vmIds); - /** - * Clean the network rules for the given VM - * @param userId - * @param instanceId the id of the instance for which the network rules should be cleaned - */ - void cleanNetworkRules(long userId, long instanceId); - /** * Releases a guest IP address for a VM. If the VM is on a direct attached network, will also unassign the IP address. * @param userVm @@ -102,4 +93,7 @@ public interface UserVmManager extends VirtualMachineGuru{ UserVm startUserVm(long vmId) throws StorageUnavailableException, ConcurrentOperationException, ExecutionException, ResourceUnavailableException, InsufficientCapacityException; + + boolean expunge(UserVmVO vm, long callerUserId, Account caller); + } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index ee2da1dab70..1ed83e62a5c 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -1005,50 +1005,6 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager _vmDao.update(userVm.getId(), userVm); } - @Override @DB - public boolean destroyVirtualMachine(long userId, long vmId) { - UserVmVO vm = _vmDao.findById(vmId); - if (vm == null || vm.getState() == State.Destroyed || vm.getState() == State.Expunging || vm.getRemoved() != null) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Unable to find vm or vm is destroyed: " + vmId); - } - return true; - } - - if (s_logger.isDebugEnabled()) { - s_logger.debug("Destroying vm " + vmId); - } - - long startEventId = EventUtils.saveStartedEvent(userId, vm.getAccountId(), EventTypes.EVENT_VM_STOP, "stopping Vm with Id: "+vmId); - - if (!stop(userId, vm)) { - s_logger.error("Unable to stop vm so we can't destroy it: " + vmId); - EventUtils.saveEvent(userId, vm.getAccountId(), EventVO.LEVEL_ERROR, EventTypes.EVENT_VM_STOP, "Error stopping VM instance : " + vmId, startEventId); - return false; - } else { - EventUtils.saveEvent(userId, vm.getAccountId(), EventVO.LEVEL_INFO, EventTypes.EVENT_VM_STOP, "Successfully stopped VM instance : " + vmId, startEventId); - } - - Transaction txn = Transaction.currentTxn(); - txn.start(); - - if (!destroy(vm)) { - return false; - } - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VM_DESTROY, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), vm.getName(), vm.getServiceOfferingId(), vm.getTemplateId(), null); - _usageEventDao.persist(usageEvent); - cleanNetworkRules(userId, vmId); - - // Mark the VM's disks as destroyed - List volumes = _volsDao.findByInstance(vmId); - for (VolumeVO volume : volumes) { - _storageMgr.destroyVolume(volume); - } - - txn.commit(); - return true; - } - @Override @DB public UserVm recoverVirtualMachine(RecoverVMCmd cmd) throws ResourceAllocationException, CloudRuntimeException { @@ -1206,7 +1162,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager @Override public boolean start() { - _executor.scheduleWithFixedDelay(new ExpungeTask(this), _expungeInterval, _expungeInterval, TimeUnit.SECONDS); + _executor.scheduleWithFixedDelay(new ExpungeTask(), _expungeInterval, _expungeInterval, TimeUnit.SECONDS); return true; } @@ -1364,19 +1320,6 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager return stopped; } - @Override @DB - public boolean destroy(UserVmVO vm) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Destroying vm " + vm.toString()); - } - if (!_itMgr.stateTransitTo(vm, VirtualMachine.Event.DestroyRequested, vm.getHostId())) { - s_logger.debug("Unable to destroy the vm because it is not in the correct state: " + vm.toString()); - return false; - } - - return true; - } - @Override public HostVO prepareForMigration(UserVmVO vm) throws StorageUnavailableException { long vmId = vm.getId(); @@ -1454,52 +1397,80 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager return true; } - @DB - public void expunge() { - List vms = _vmDao.findDestroyedVms(new Date(System.currentTimeMillis() - ((long)_expungeDelay << 10))); - s_logger.info("Found " + vms.size() + " vms to expunge."); - for (UserVmVO vm : vms) { - long vmId = vm.getId(); - releaseGuestIpAddress(vm); - vm.setGuestNetmask(null); - vm.setGuestMacAddress(null); - if (!_itMgr.stateTransitTo(vm, VirtualMachine.Event.ExpungeOperation, null)) { - s_logger.info("vm " + vmId + " is skipped because it is no longer in Destroyed or Error state"); - continue; - } + @Override + public boolean expunge(UserVmVO vm, long callerUserId, Account caller) { + try { + if (!_itMgr.advanceExpunge(vm, _accountMgr.getSystemUser(), caller)) { + s_logger.info("Did not expunge " + vm); + return false; + } + + long vmId = vm.getId(); + + //cleanup port forwarding rules + if (_rulesMgr.revokePortForwardingRule(vmId)) { + s_logger.debug("Port forwarding rules are removed successfully as a part of vm id=" + vmId + " expunge"); + } else { + s_logger.warn("Fail to remove port forwarding rules as a part of vm id=" + vmId + " expunge"); + } + + //cleanup load balancer rules + if (_lbMgr.removeVmFromLoadBalancers(vmId)) { + s_logger.debug("LB rules are removed successfully as a part of vm id=" + vmId + " expunge"); + } else { + s_logger.warn("Fail to remove lb rules as a part of vm id=" + vmId + " expunge"); + } + + _networkGroupMgr.removeInstanceFromGroups(vm.getId()); + removeInstanceFromGroup(vm.getId()); + + _itMgr.remove(vm, _accountMgr.getSystemUser(), caller); + return true; + } catch (ResourceUnavailableException e) { + s_logger.warn("Unable to expunging " + vm, e); + return false; + } catch (OperationTimedoutException e) { + s_logger.warn("Operation time out on expunging " + vm, e); + return false; + } catch (ConcurrentOperationException e) { + s_logger.warn("Concurrent operations on expunging " + vm, e); + return false; + } + + +// long vmId = vm.getId(); +// releaseGuestIpAddress(vm); +// vm.setGuestNetmask(null); +// vm.setGuestMacAddress(null); +// if (!_itMgr.stateTransitTo(vm, VirtualMachine.Event.ExpungeOperation, null)) { +// s_logger.info("vm " + vmId + " is skipped because it is no longer in Destroyed or Error state"); +// continue; +// } +// +// List vols = null; +// try { +// vols = _volsDao.findByInstanceIdDestroyed(vmId); +// _storageMgr.destroy(vm, vols); +// +// +// //cleanup load balancer rules +// if (_lbMgr.removeVmFromLoadBalancers(vmId)) { +// s_logger.debug("LB rules are removed successfully as a part of vm id=" + vmId + " expunge"); +// } else { +// s_logger.warn("Fail to remove lb rules as a part of vm id=" + vmId + " expunge"); +// } +// +// _vmDao.remove(vm.getId()); +// s_logger.debug("vm is destroyed"); +// } catch (Exception e) { +// s_logger.info("VM " + vm +" expunge failed due to ", e); +// } - List vols = null; - try { - vols = _volsDao.findByInstanceIdDestroyed(vmId); - _storageMgr.destroy(vm, vols); - - //cleanup port forwarding rules - if (_rulesMgr.revokePortForwardingRule(vmId)) { - s_logger.debug("Port forwarding rules are removed successfully as a part of vm id=" + vmId + " expunge"); - } else { - s_logger.warn("Fail to remove port forwarding rules as a part of vm id=" + vmId + " expunge"); - } - - //cleanup load balancer rules - if (_lbMgr.removeVmFromLoadBalancers(vmId)) { - s_logger.debug("LB rules are removed successfully as a part of vm id=" + vmId + " expunge"); - } else { - s_logger.warn("Fail to remove lb rules as a part of vm id=" + vmId + " expunge"); - } - - _vmDao.remove(vm.getId()); - _networkGroupMgr.removeInstanceFromGroups(vm.getId()); - removeInstanceFromGroup(vm.getId()); - s_logger.debug("vm is destroyed"); - } catch (Exception e) { - s_logger.info("VM " + vmId +" expunge failed due to " + e.getMessage()); - } - - } - - List destroyedVolumes = _volsDao.findByDetachedDestroyed(); - s_logger.info("Found " + destroyedVolumes.size() + " detached volumes to expunge."); - _storageMgr.destroy(null, destroyedVolumes); +// } +// +// List destroyedVolumes = _volsDao.findByDetachedDestroyed(); +// s_logger.info("Found " + destroyedVolumes.size() + " detached volumes to expunge."); +// _storageMgr.destroy(null, destroyedVolumes); } @Override @DB @@ -1536,46 +1507,6 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager } } - @Override - public void cleanNetworkRules(long userId, long instanceId) { -//FIXME UserVmVO vm = _vmDao.findById(instanceId); -// String guestIpAddr = vm.getGuestIpAddress(); -// long accountId = vm.getAccountId(); -// -// List loadBalancerMappings = _loadBalancerVMMapDao.listByInstanceId(vm.getId()); -// for (LoadBalancerVMMapVO loadBalancerMapping : loadBalancerMappings) { -// List lbRules = _rulesDao.listByLoadBalancerId(loadBalancerMapping.getLoadBalancerId()); -// PortForwardingRuleVO targetLbRule = null; -// for (PortForwardingRuleVO lbRule : lbRules) { -// if (lbRule.getDestinationIpAddress().equals(guestIpAddr)) { -// targetLbRule = lbRule; -// targetLbRule.setEnabled(false); -// break; -// } -// } -// -// if (targetLbRule != null) { -// String ipAddress = targetLbRule.getSourceIpAddress(); -// DomainRouterVO router = _routerDao.findById(vm.getDomainRouterId()); -// _networkMgr.updateFirewallRules(ipAddress, lbRules, router); -// -// // now that the rule has been disabled, delete it, also remove the mapping from the load balancer mapping table -// _rulesDao.remove(targetLbRule.getId()); -// _loadBalancerVMMapDao.remove(loadBalancerMapping.getId()); -// -// // save off the event for deleting the LB rule -// EventVO lbRuleEvent = new EventVO(); -// lbRuleEvent.setUserId(userId); -// lbRuleEvent.setAccountId(accountId); -// lbRuleEvent.setType(EventTypes.EVENT_NET_RULE_DELETE); -// lbRuleEvent.setDescription("deleted load balancer rule [" + targetLbRule.getSourceIpAddress() + ":" + targetLbRule.getSourcePort() + -// "]->[" + targetLbRule.getDestinationIpAddress() + ":" + targetLbRule.getDestinationPort() + "]" + " " + targetLbRule.getAlgorithm()); -// lbRuleEvent.setLevel(EventVO.LEVEL_INFO); -// _eventDao.persist(lbRuleEvent); -// } -// } - } - @Override public void deletePrivateTemplateRecord(Long templateId){ if ( templateId != null) { @@ -1885,18 +1816,32 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager } protected class ExpungeTask implements Runnable { - UserVmManagerImpl _vmMgr; - public ExpungeTask(UserVmManagerImpl vmMgr) { - _vmMgr = vmMgr; + public ExpungeTask() { } @Override public void run() { GlobalLock scanLock = GlobalLock.getInternLock("UserVMExpunge"); try { - if(scanLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION)) { + if (scanLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION)) { try { - reallyRun(); + List vms = _vmDao.findDestroyedVms(new Date(System.currentTimeMillis() - ((long)_expungeDelay << 10))); + if (s_logger.isInfoEnabled()) { + if (vms.size() == 0) { + s_logger.trace("Found " + vms.size() + " vms to expunge."); + } else { + s_logger.info("Found " + vms.size() + " vms to expunge."); + } + } + for (UserVmVO vm : vms) { + try { + expunge(vm, _accountMgr.getSystemUser().getId(), _accountMgr.getSystemAccount()); + } catch(Exception e) { + s_logger.warn("Unable to expunge " + vm, e); + } + } + } catch (Exception e) { + s_logger.error("Caught the following Exception", e); } finally { scanLock.unlock(); } @@ -1905,15 +1850,6 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager scanLock.releaseRef(); } } - - public void reallyRun() { - try { - s_logger.info("UserVm Expunge Thread is running."); - _vmMgr.expunge(); - } catch (Exception e) { - s_logger.error("Caught the following Exception", e); - } - } } private static boolean isAdmin(short accountType) { @@ -2610,7 +2546,11 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager User caller = _userDao.findById(userId); boolean status; - status = _itMgr.destroy(vm, caller, account); + try { + status = _itMgr.destroy(vm, caller, account); + } catch (OperationTimedoutException e) { + throw new CloudRuntimeException("Unable to destroy " + vm, e); + } if (status) { UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VM_DESTROY, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), vm.getName(), vm.getServiceOfferingId(), vm.getTemplateId(), null); @@ -2621,147 +2561,4 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager throw new CloudRuntimeException("Failed to destroy vm with id " + vmId); } } - -// @Override -// public OperationResponse executeRebootVM(RebootVMExecutor executor, VMOperationParam param) { -// -// final UserVmVO vm = _vmDao.findById(param.getVmId()); -// String resultDescription; -// -// if (vm == null || vm.getState() == State.Destroyed || vm.getState() == State.Expunging || vm.getRemoved() != null) { -// resultDescription = "VM does not exist or in destroying state"; -// executor.getAsyncJobMgr().completeAsyncJob(executor.getJob().getId(), -// AsyncJobResult.STATUS_FAILED, 0, resultDescription); -// if(s_logger.isDebugEnabled()) -// s_logger.debug("Execute asynchronize Reboot VM command: " +resultDescription); -// return new OperationResponse(OperationResponse.STATUS_FAILED, resultDescription); -// } -// -// if (vm.getState() == State.Running && vm.getHostId() != null) { -// RebootCommand cmd = new RebootCommand(vm.getInstanceName()); -// try { -// long seq = _agentMgr.send(vm.getHostId(), new Commands(cmd), new VMOperationListener(executor, param, vm, 0)); -// resultDescription = "Execute asynchronize Reboot VM command: sending command to agent, seq - " + seq; -// if(s_logger.isDebugEnabled()) -// s_logger.debug(resultDescription); -// return new OperationResponse(OperationResponse.STATUS_IN_PROGRESS, resultDescription); -// } catch (AgentUnavailableException e) { -// resultDescription = "Agent is not available"; -// executor.getAsyncJobMgr().completeAsyncJob(executor.getJob().getId(), -// AsyncJobResult.STATUS_FAILED, 0, resultDescription); -// return new OperationResponse(OperationResponse.STATUS_FAILED, resultDescription); -// } -// } -// resultDescription = "VM is not running or agent host is disconnected"; -// executor.getAsyncJobMgr().completeAsyncJob(executor.getJob().getId(), -// AsyncJobResult.STATUS_FAILED, 0, resultDescription); -// return new OperationResponse(OperationResponse.STATUS_FAILED, resultDescription); -// } - -// @Override @DB -// public OperationResponse executeDestroyVM(DestroyVMExecutor executor, VMOperationParam param) { -// UserVmVO vm = _vmDao.findById(param.getVmId()); -// State state = vm.getState(); -// OperationResponse response; -// String resultDescription = "Success"; -// -// if (vm == null || state == State.Destroyed || state == State.Expunging || vm.getRemoved() != null) { -// if (s_logger.isDebugEnabled()) { -// s_logger.debug("Unable to find vm or vm is destroyed: " + param.getVmId()); -// } -// resultDescription = "VM does not exist or already in destroyed state"; -// response = new OperationResponse(OperationResponse.STATUS_FAILED, resultDescription); -// executor.getAsyncJobMgr().completeAsyncJob(executor.getJob().getId(), -// AsyncJobResult.STATUS_FAILED, 0, resultDescription); -// return response; -// } -// -// if(state == State.Stopping) { -// if (s_logger.isDebugEnabled()) { -// s_logger.debug("VM is being stopped: " + param.getVmId()); -// } -// resultDescription = "VM is being stopped, please re-try later"; -// response = new OperationResponse(OperationResponse.STATUS_FAILED, resultDescription); -// executor.getAsyncJobMgr().completeAsyncJob(executor.getJob().getId(), -// AsyncJobResult.STATUS_FAILED, 0, resultDescription); -// return response; -// } -// -// if (state == State.Running) { -// if (vm.getHostId() == null) { -// resultDescription = "VM host is null (invalid VM)"; -// response = new OperationResponse(OperationResponse.STATUS_FAILED, resultDescription); -// executor.getAsyncJobMgr().completeAsyncJob(executor.getJob().getId(), -// AsyncJobResult.STATUS_FAILED, 0, resultDescription); -// if(s_logger.isDebugEnabled()) -// s_logger.debug("Execute asynchronize destroy VM command: " + resultDescription); -// return response; -// } -// -// if (!_vmDao.updateIf(vm, Event.StopRequested, vm.getHostId())) { -// resultDescription = "Failed to issue stop command, please re-try later"; -// response = new OperationResponse(OperationResponse.STATUS_FAILED, resultDescription); -// executor.getAsyncJobMgr().completeAsyncJob(executor.getJob().getId(), -// AsyncJobResult.STATUS_FAILED, 0, resultDescription); -// if(s_logger.isDebugEnabled()) -// s_logger.debug("Execute asynchronize destroy VM command:" + resultDescription); -// return response; -// } -// long childEventId = EventUtils.saveStartedEvent(param.getUserId(), param.getAccountId(), -// EventTypes.EVENT_VM_STOP, "stopping vm " + vm.getName(), 0); -// param.setChildEventId(childEventId); -// StopCommand cmd = new StopCommand(vm, vm.getInstanceName(), vm.getVnet()); -// try { -// long seq = _agentMgr.send(vm.getHostId(), new Command[] {cmd}, true, -// new VMOperationListener(executor, param, vm, 0)); -// resultDescription = "Execute asynchronize destroy VM command: sending stop command to agent, seq - " + seq; -// if(s_logger.isDebugEnabled()) -// s_logger.debug(resultDescription); -// response = new OperationResponse(OperationResponse.STATUS_IN_PROGRESS, resultDescription); -// return response; -// } catch (AgentUnavailableException e) { -// resultDescription = "Agent is not available"; -// response = new OperationResponse(OperationResponse.STATUS_FAILED, resultDescription); -// executor.getAsyncJobMgr().completeAsyncJob(executor.getJob().getId(), -// AsyncJobResult.STATUS_FAILED, 0, resultDescription); -// return response; -// } -// } -// -// Transaction txn = Transaction.currentTxn(); -// txn.start(); -// -// _accountMgr.decrementResourceCount(vm.getAccountId(), ResourceType.user_vm); -// if (!_vmDao.updateIf(vm, VirtualMachine.Event.DestroyRequested, vm.getHostId()) ) { -// resultDescription = "Unable to destroy the vm because it is not in the correct state"; -// s_logger.debug(resultDescription + vm.toString()); -// -// txn.rollback(); -// response = new OperationResponse(OperationResponse.STATUS_FAILED, resultDescription); -// executor.getAsyncJobMgr().completeAsyncJob(executor.getJob().getId(), -// AsyncJobResult.STATUS_FAILED, 0, resultDescription); -// return response; -// } -// -// // Now that the VM is destroyed, clean the network rules associated with it. -// cleanNetworkRules(param.getUserId(), vm.getId()); -// -// // Mark the VM's root disk as destroyed -// List volumes = _volsDao.findByInstanceAndType(vm.getId(), VolumeType.ROOT); -// for (VolumeVO volume : volumes) { -// _storageMgr.destroyVolume(volume); -// } -// -// // Mark the VM's data disks as detached -// volumes = _volsDao.findByInstanceAndType(vm.getId(), VolumeType.DATADISK); -// for (VolumeVO volume : volumes) { -// _volsDao.detachVolume(volume.getId()); -// } -// -// txn.commit(); -// response = new OperationResponse(OperationResponse.STATUS_SUCCEEDED, resultDescription); -// executor.getAsyncJobMgr().completeAsyncJob(executor.getJob().getId(), -// AsyncJobResult.STATUS_SUCCEEDED, 0, "success"); -// return response; -// } } diff --git a/server/src/com/cloud/vm/VirtualMachineGuru.java b/server/src/com/cloud/vm/VirtualMachineGuru.java index 3478465e612..92eabe1febf 100644 --- a/server/src/com/cloud/vm/VirtualMachineGuru.java +++ b/server/src/com/cloud/vm/VirtualMachineGuru.java @@ -145,6 +145,4 @@ public interface VirtualMachineGuru { boolean migrate(T vm, HostVO host) throws AgentUnavailableException, OperationTimedoutException; boolean completeMigration(T vm, HostVO host) throws AgentUnavailableException, OperationTimedoutException; - - boolean destroy(T vm) throws AgentUnavailableException; } diff --git a/server/src/com/cloud/vm/VirtualMachineManager.java b/server/src/com/cloud/vm/VirtualMachineManager.java index 056b2358c99..7ba0dbf8e56 100644 --- a/server/src/com/cloud/vm/VirtualMachineManager.java +++ b/server/src/com/cloud/vm/VirtualMachineManager.java @@ -21,6 +21,7 @@ import java.util.List; import java.util.Map; import com.cloud.deploy.DeploymentPlan; +import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.OperationTimedoutException; @@ -74,7 +75,7 @@ public interface VirtualMachineManager extends Manager { boolean stop(T vm, User caller, Account account) throws ResourceUnavailableException; - boolean destroy(T vm, User caller, Account account) throws ResourceUnavailableException; + boolean expunge(T vm, User caller, Account account) throws ResourceUnavailableException; void registerGuru(VirtualMachine.Type type, VirtualMachineGuru guru); @@ -84,5 +85,9 @@ public interface VirtualMachineManager extends Manager { boolean advanceStop(T vm, User caller, Account account) throws ResourceUnavailableException, OperationTimedoutException, ConcurrentOperationException; - boolean advanceDestroy(T vm, User caller, Account account) throws ResourceUnavailableException, OperationTimedoutException, ConcurrentOperationException; + boolean advanceExpunge(T vm, User caller, Account account) throws ResourceUnavailableException, OperationTimedoutException, ConcurrentOperationException; + + boolean remove(T vm, User caller, Account account); + + boolean destroy(T vm, User caller, Account account) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException; } diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java index 09d6660a840..0928645d328 100644 --- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -36,7 +36,6 @@ import com.cloud.agent.api.StopAnswer; import com.cloud.agent.api.StopCommand; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.agent.manager.Commands; -import com.cloud.capacity.dao.CapacityDao; import com.cloud.cluster.ClusterManager; import com.cloud.cluster.ClusterManagerListener; import com.cloud.cluster.ManagementServerHostVO; @@ -60,17 +59,16 @@ import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.InsufficientServerCapacityException; import com.cloud.exception.OperationTimedoutException; import com.cloud.exception.ResourceUnavailableException; -import com.cloud.hypervisor.HypervisorGuru; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.hypervisor.HypervisorGuru; import com.cloud.network.NetworkManager; import com.cloud.network.NetworkVO; import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; -import com.cloud.stateListener.VMStateListener; import com.cloud.storage.DiskOfferingVO; +import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.StorageManager; import com.cloud.storage.VMTemplateVO; -import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Volume.VolumeType; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.user.Account; @@ -113,7 +111,6 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Cluster @Inject private DomainDao _domainDao; @Inject private ClusterManager _clusterMgr; @Inject private ItWorkDao _workDao; - @Inject private CapacityDao _capacityDao; @Inject private UserVmDao _userVmDao; @Inject private DomainRouterDao _routerDao; @Inject private ConsoleProxyDao _consoleDao; @@ -238,9 +235,9 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Cluster } @Override - public boolean destroy(T vm, User caller, Account account) throws ResourceUnavailableException { + public boolean expunge(T vm, User caller, Account account) throws ResourceUnavailableException { try { - return advanceDestroy(vm, caller, account); + return advanceExpunge(vm, caller, account); } catch (OperationTimedoutException e) { throw new CloudRuntimeException("Operation timed out", e); } catch (ConcurrentOperationException e) { @@ -249,14 +246,19 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Cluster } @Override - public boolean advanceDestroy(T vm, User caller, Account account) throws ResourceUnavailableException, OperationTimedoutException, ConcurrentOperationException { - if (vm == null || vm.getState() == State.Destroyed || vm.getState() == State.Expunging || vm.getRemoved() != null) { + public boolean advanceExpunge(T vm, User caller, Account account) throws ResourceUnavailableException, OperationTimedoutException, ConcurrentOperationException { + if (vm == null || vm.getRemoved() != null) { if (s_logger.isDebugEnabled()) { s_logger.debug("Unable to find vm or vm is destroyed: " + vm); } return true; } + if (!stateTransitTo(vm, VirtualMachine.Event.ExpungeOperation, vm.getHostId())) { + s_logger.debug("Unable to destroy the vm because it is not in the correct state: " + vm.toString()); + return false; + } + if (s_logger.isDebugEnabled()) { s_logger.debug("Destroying vm " + vm); } @@ -271,9 +273,12 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Cluster EventUtils.saveEvent(userId, vm.getAccountId(), EventVO.LEVEL_INFO, EventTypes.EVENT_VM_STOP, "Successfully stopped VM instance : " + vm.getId(), startEventId); } + VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm); + + _networkMgr.cleanupNics(profile); //Clean up volumes based on the vm's instance id _storageMgr.cleanupVolumes(vm.getId()); - + VirtualMachineGuru guru = getVmGuru(vm); vm = guru.findById(vm.getId()); @@ -591,6 +596,7 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Cluster _stateMachine.addTransition(State.Stopped, VirtualMachine.Event.StopRequested, State.Stopped); _stateMachine.addTransition(State.Stopped, VirtualMachine.Event.AgentReportStopped, State.Stopped); _stateMachine.addTransition(State.Stopped, VirtualMachine.Event.OperationFailed, State.Error); + _stateMachine.addTransition(State.Stopped, VirtualMachine.Event.ExpungeOperation, State.Expunging); _stateMachine.addTransition(State.Starting, VirtualMachine.Event.OperationRetry, State.Starting); _stateMachine.addTransition(State.Starting, VirtualMachine.Event.OperationSucceeded, State.Running); _stateMachine.addTransition(State.Starting, VirtualMachine.Event.OperationFailed, State.Stopped); @@ -635,4 +641,34 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Cluster return _stateMachine.transitTO(vm, e, id, _vmDao); } } + + @Override + public boolean remove(T vm, User user, Account caller) { + return _vmDao.remove(vm.getId()); + } + + @Override + public boolean destroy(T vm, User user, Account caller) throws AgentUnavailableException, OperationTimedoutException, ConcurrentOperationException { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Destroying vm " + vm.toString()); + } + if (vm == null || vm.getState() == State.Destroyed || vm.getState() == State.Expunging || vm.getRemoved() != null) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Unable to find vm or vm is destroyed: " + vm); + } + return true; + } + + if (!advanceStop(vm, user, caller)) { + s_logger.debug("Unable to stop " + vm); + return false; + } + + if (!stateTransitTo(vm, VirtualMachine.Event.DestroyRequested, vm.getHostId())) { + s_logger.debug("Unable to destroy the vm because it is not in the correct state: " + vm.toString()); + return false; + } + + return true; + } }