You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ra...@apache.org on 2016/10/24 05:44:01 UTC

[1/3] git commit: updated refs/heads/4.9 to 72612f7

Repository: cloudstack
Updated Branches:
  refs/heads/4.9 9b9b49e10 -> 72612f79c


Emit a VOLUME_DELETE usage event when account deletion destroys an instance.

Currently the logic about volume deletion seems to be that an event
should be emitted when the volume delete is requested, not when the
deletion completes.

The VolumeStateListener specifically ignores destroy events for ROOT
volumes, assuming that the ROOT volume only gets deleted when the
instance is destroyed and the UserVmManager should take care of it.

When deleting an account, all of its resources get destroyed, but the
instance expunging circumvents the UserVmManager, and thus we miss the
VOLUME_DESTROY usage event. The account manager now attempts to
propperly destroy the vm before expunging it. This way the destroy
logic is respected, including the event emission.


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/d989c5d8
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/d989c5d8
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/d989c5d8

Branch: refs/heads/4.9
Commit: d989c5d8be1e0b8dc0d25d0402ada4039a695dc8
Parents: a664e03
Author: nnesic <ne...@greenqloud.com>
Authored: Mon Oct 12 13:15:30 2015 +0000
Committer: jeff <je...@greenqloud.com>
Committed: Fri Oct 21 09:26:59 2016 +0000

----------------------------------------------------------------------
 .../src/com/cloud/user/AccountManagerImpl.java  |  12 +-
 .../com/cloud/user/AccountManagerImplTest.java  | 220 ++-----------
 ...AccountManagerImplVolumeDeleteEventTest.java | 209 +++++++++++++
 .../cloud/user/AccountManagetImplTestBase.java  | 242 +++++++++++++++
 .../test/com/cloud/user/MockUsageEventDao.java  | 307 +++++++++++++++++++
 5 files changed, 787 insertions(+), 203 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d989c5d8/server/src/com/cloud/user/AccountManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java
index d3eb40c..2d9cdb0 100644
--- a/server/src/com/cloud/user/AccountManagerImpl.java
+++ b/server/src/com/cloud/user/AccountManagerImpl.java
@@ -159,6 +159,7 @@ import com.cloud.vm.ReservationContextImpl;
 import com.cloud.vm.UserVmManager;
 import com.cloud.vm.UserVmVO;
 import com.cloud.vm.VMInstanceVO;
+import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.VirtualMachineManager;
 import com.cloud.vm.dao.InstanceGroupDao;
 import com.cloud.vm.dao.UserVmDao;
@@ -755,8 +756,17 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
                 s_logger.debug("Expunging # of vms (accountId=" + accountId + "): " + vms.size());
             }
 
-            // no need to catch exception at this place as expunging vm should pass in order to perform further cleanup
             for (UserVmVO vm : vms) {
+                if (vm.getState() != VirtualMachine.State.Destroyed && vm.getState() != VirtualMachine.State.Expunging) {
+                    try {
+                        _vmMgr.destroyVm(vm.getId());
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                        s_logger.warn("Failed destroying instance " + vm.getUuid() + " as part of account deletion.");
+                    }
+                }
+                // no need to catch exception at this place as expunging vm
+                // should pass in order to perform further cleanup
                 if (!_vmMgr.expunge(vm, callerUserId, caller)) {
                     s_logger.error("Unable to expunge vm: " + vm.getId());
                     accountCleanupNeeded = true;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d989c5d8/server/test/com/cloud/user/AccountManagerImplTest.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/user/AccountManagerImplTest.java b/server/test/com/cloud/user/AccountManagerImplTest.java
index a895ec2..2788049 100644
--- a/server/test/com/cloud/user/AccountManagerImplTest.java
+++ b/server/test/com/cloud/user/AccountManagerImplTest.java
@@ -16,220 +16,35 @@
 // under the License.
 package com.cloud.user;
 
-import java.lang.reflect.Field;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
-import java.util.Arrays;
 import java.util.ArrayList;
-
-import javax.inject.Inject;
-
+import java.util.Arrays;
 import com.cloud.server.auth.UserAuthenticator;
 import com.cloud.utils.Pair;
-import org.junit.After;
+
 import org.junit.Assert;
-import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.Mockito;
-import org.mockito.runners.MockitoJUnitRunner;
-
 import org.apache.cloudstack.acl.ControlledEntity;
-import org.apache.cloudstack.acl.SecurityChecker;
 import org.apache.cloudstack.acl.SecurityChecker.AccessType;
-import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
-import org.apache.cloudstack.context.CallContext;
-import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
-import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
-import org.apache.cloudstack.framework.messagebus.MessageBus;
-import org.apache.cloudstack.region.gslb.GlobalLoadBalancerRuleDao;
-
-import com.cloud.vm.snapshot.VMSnapshotManager;
 import com.cloud.vm.snapshot.VMSnapshotVO;
-import com.cloud.vm.snapshot.dao.VMSnapshotDao;
-
-import com.cloud.configuration.ConfigurationManager;
-import com.cloud.configuration.dao.ResourceCountDao;
-import com.cloud.configuration.dao.ResourceLimitDao;
-import com.cloud.dc.dao.DataCenterDao;
-import com.cloud.dc.dao.DataCenterVnetDao;
-import com.cloud.dc.dao.DedicatedResourceDao;
 import com.cloud.domain.Domain;
 import com.cloud.domain.DomainVO;
-import com.cloud.domain.dao.DomainDao;
 import com.cloud.exception.ConcurrentOperationException;
 import com.cloud.exception.ResourceUnavailableException;
-import com.cloud.network.as.AutoScaleManager;
-import com.cloud.network.dao.AccountGuestVlanMapDao;
-import com.cloud.network.dao.IPAddressDao;
-import com.cloud.network.dao.NetworkDao;
-import com.cloud.network.dao.RemoteAccessVpnDao;
-import com.cloud.network.dao.VpnUserDao;
-import com.cloud.network.security.SecurityGroupManager;
-import com.cloud.network.security.dao.SecurityGroupDao;
-import com.cloud.network.vpc.VpcManager;
-import com.cloud.network.vpn.RemoteAccessVpnService;
-import com.cloud.network.vpn.Site2SiteVpnManager;
-import com.cloud.projects.ProjectManager;
-import com.cloud.projects.dao.ProjectAccountDao;
-import com.cloud.projects.dao.ProjectDao;
-import com.cloud.storage.VolumeApiService;
-import com.cloud.storage.dao.SnapshotDao;
-import com.cloud.storage.dao.VMTemplateDao;
-import com.cloud.storage.dao.VolumeDao;
-import com.cloud.storage.snapshot.SnapshotManager;
-import com.cloud.template.TemplateManager;
 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.vm.UserVmManager;
+import com.cloud.vm.UserVmManagerImpl;
 import com.cloud.vm.UserVmVO;
 import com.cloud.vm.VMInstanceVO;
-import com.cloud.vm.VirtualMachineManager;
-import com.cloud.vm.dao.DomainRouterDao;
-import com.cloud.vm.dao.InstanceGroupDao;
-import com.cloud.vm.dao.UserVmDao;
-import com.cloud.vm.dao.VMInstanceDao;
-import org.springframework.test.util.ReflectionTestUtils;
 
-@RunWith(MockitoJUnitRunner.class)
-public class AccountManagerImplTest {
-    @Mock
-    AccountDao _accountDao;
-    @Mock
-    ConfigurationDao _configDao;
-    @Mock
-    ResourceCountDao _resourceCountDao;
-    @Mock
-    UserDao _userDao;
-    @Mock
-    InstanceGroupDao _vmGroupDao;
-    @Mock
-    UserAccountDao _userAccountDao;
-    @Mock
-    VolumeDao _volumeDao;
-    @Mock
-    UserVmDao _userVmDao;
-    @Mock
-    VMTemplateDao _templateDao;
-    @Mock
-    NetworkDao _networkDao;
-    @Mock
-    SecurityGroupDao _securityGroupDao;
-    @Mock
-    VMInstanceDao _vmDao;
-    @Mock
-    protected SnapshotDao _snapshotDao;
-    @Mock
-    protected VMTemplateDao _vmTemplateDao;
-    @Mock
-    SecurityGroupManager _networkGroupMgr;
-    @Mock
-    NetworkOrchestrationService _networkMgr;
-    @Mock
-    SnapshotManager _snapMgr;
-    @Mock
-    UserVmManager _vmMgr;
-    @Mock
-    TemplateManager _tmpltMgr;
-    @Mock
-    ConfigurationManager _configMgr;
-    @Mock
-    VirtualMachineManager _itMgr;
-    @Mock
-    RemoteAccessVpnDao _remoteAccessVpnDao;
-    @Mock
-    RemoteAccessVpnService _remoteAccessVpnMgr;
-    @Mock
-    VpnUserDao _vpnUser;
-    @Mock
-    DataCenterDao _dcDao;
-    @Mock
-    DomainManager _domainMgr;
-    @Mock
-    ProjectManager _projectMgr;
-    @Mock
-    ProjectDao _projectDao;
-    @Mock
-    AccountDetailsDao _accountDetailsDao;
-    @Mock
-    DomainDao _domainDao;
-    @Mock
-    ProjectAccountDao _projectAccountDao;
-    @Mock
-    IPAddressDao _ipAddressDao;
-    @Mock
-    VpcManager _vpcMgr;
-    @Mock
-    DomainRouterDao _routerDao;
-    @Mock
-    Site2SiteVpnManager _vpnMgr;
-    @Mock
-    AutoScaleManager _autoscaleMgr;
-    @Mock
-    VolumeApiService volumeService;
-    @Mock
-    AffinityGroupDao _affinityGroupDao;
-    @Mock
-    AccountGuestVlanMapDao _accountGuestVlanMapDao;
-    @Mock
-    DataCenterVnetDao _dataCenterVnetDao;
-    @Mock
-    ResourceLimitService _resourceLimitMgr;
-    @Mock
-    ResourceLimitDao _resourceLimitDao;
-    @Mock
-    DedicatedResourceDao _dedicatedDao;
-    @Mock
-    GlobalLoadBalancerRuleDao _gslbRuleDao;
-    @Mock
-    MessageBus _messageBus;
 
-    @Mock
-    VMSnapshotManager _vmSnapshotMgr;
-    @Mock
-    VMSnapshotDao _vmSnapshotDao;
+public class AccountManagerImplTest extends AccountManagetImplTestBase {
 
-    @Mock
-    User callingUser;
-    @Mock
-    Account callingAccount;
-
-    AccountManagerImpl accountManager;
-
-    @Mock
-    SecurityChecker securityChecker;
 
     @Mock
-    private UserAuthenticator userAuthenticator;
-
-    @Before
-    public void setup() throws NoSuchFieldException, SecurityException,
-            IllegalArgumentException, IllegalAccessException {
-        accountManager = new AccountManagerImpl();
-        for (Field field : AccountManagerImpl.class.getDeclaredFields()) {
-            if (field.getAnnotation(Inject.class) != null) {
-                field.setAccessible(true);
-                try {
-                    Field mockField = this.getClass().getDeclaredField(
-                            field.getName());
-                    field.set(accountManager, mockField.get(this));
-                } catch (Exception e) {
-                    // ignore missing fields
-                }
-            }
-        }
-        ReflectionTestUtils.setField(accountManager, "_userAuthenticators", Arrays.asList(userAuthenticator));
-        accountManager.setSecurityCheckers(Arrays.asList(securityChecker));
-        CallContext.register(callingUser, callingAccount);
-    }
-
-    @After
-    public void cleanup() {
-        CallContext.unregister();
-    }
+    UserVmManagerImpl _vmMgr;
 
     @Test
     public void disableAccountNotexisting()
@@ -240,7 +55,7 @@ public class AccountManagerImplTest {
 
     @Test
     public void disableAccountDisabled() throws ConcurrentOperationException,
-            ResourceUnavailableException {
+    ResourceUnavailableException {
         AccountVO disabledAccount = new AccountVO();
         disabledAccount.setState(State.disabled);
         Mockito.when(_accountDao.findById(42l)).thenReturn(disabledAccount);
@@ -249,7 +64,7 @@ public class AccountManagerImplTest {
 
     @Test
     public void disableAccount() throws ConcurrentOperationException,
-            ResourceUnavailableException {
+    ResourceUnavailableException {
         AccountVO account = new AccountVO();
         account.setState(State.enabled);
         Mockito.when(_accountDao.findById(42l)).thenReturn(account);
@@ -272,17 +87,17 @@ public class AccountManagerImplTest {
         Mockito.when(_accountDao.findById(42l)).thenReturn(account);
         Mockito.when(
                 securityChecker.checkAccess(Mockito.any(Account.class),
-                    Mockito.any(ControlledEntity.class), Mockito.any(AccessType.class),
-                    Mockito.anyString()))
-                .thenReturn(true);
+                        Mockito.any(ControlledEntity.class), Mockito.any(AccessType.class),
+                        Mockito.anyString()))
+        .thenReturn(true);
         Mockito.when(_accountDao.remove(42l)).thenReturn(true);
         Mockito.when(_configMgr.releaseAccountSpecificVirtualRanges(42l))
-                .thenReturn(true);
+        .thenReturn(true);
         Mockito.when(_domainMgr.getDomain(Mockito.anyLong())).thenReturn(domain);
         Mockito.when(
                 securityChecker.checkAccess(Mockito.any(Account.class),
                         Mockito.any(Domain.class)))
-                .thenReturn(true);
+        .thenReturn(true);
         Mockito.when(_vmSnapshotDao.listByAccountId(Mockito.anyLong())).thenReturn(new ArrayList<VMSnapshotVO>());
 
         Assert.assertTrue(accountManager.deleteUserAccount(42));
@@ -301,10 +116,10 @@ public class AccountManagerImplTest {
                 securityChecker.checkAccess(Mockito.any(Account.class),
                         Mockito.any(ControlledEntity.class), Mockito.any(AccessType.class),
                         Mockito.anyString()))
-                .thenReturn(true);
+        .thenReturn(true);
         Mockito.when(_accountDao.remove(42l)).thenReturn(true);
         Mockito.when(_configMgr.releaseAccountSpecificVirtualRanges(42l))
-                .thenReturn(true);
+        .thenReturn(true);
         Mockito.when(_userVmDao.listByAccountId(42l)).thenReturn(
                 Arrays.asList(Mockito.mock(UserVmVO.class)));
         Mockito.when(
@@ -314,7 +129,7 @@ public class AccountManagerImplTest {
         Mockito.when(
                 securityChecker.checkAccess(Mockito.any(Account.class),
                         Mockito.any(Domain.class)))
-                .thenReturn(true);
+        .thenReturn(true);
 
         Assert.assertTrue(accountManager.deleteUserAccount(42));
         // assert that this was NOT a clean delete
@@ -327,7 +142,7 @@ public class AccountManagerImplTest {
     public void testAuthenticateUser() throws UnknownHostException {
         Pair<Boolean, UserAuthenticator.ActionOnFailedAuthentication> successAuthenticationPair = new Pair<>(true, null);
         Pair<Boolean, UserAuthenticator.ActionOnFailedAuthentication> failureAuthenticationPair = new Pair<>(false,
-                                                                                                             UserAuthenticator.ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT);
+                UserAuthenticator.ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT);
 
         UserAccountVO userAccountVO = new UserAccountVO();
         userAccountVO.setSource(User.Source.UNKNOWN);
@@ -353,6 +168,7 @@ public class AccountManagerImplTest {
         Mockito.verify(userAuthenticator, Mockito.times(1)).authenticate("test", "fail", 1L, null);
         Mockito.verify(userAuthenticator, Mockito.never()).authenticate("test", null, 1L, null);
         Mockito.verify(userAuthenticator, Mockito.never()).authenticate("test", "", 1L, null);
-
     }
+
+
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d989c5d8/server/test/com/cloud/user/AccountManagerImplVolumeDeleteEventTest.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/user/AccountManagerImplVolumeDeleteEventTest.java b/server/test/com/cloud/user/AccountManagerImplVolumeDeleteEventTest.java
new file mode 100644
index 0000000..43c8cfc
--- /dev/null
+++ b/server/test/com/cloud/user/AccountManagerImplVolumeDeleteEventTest.java
@@ -0,0 +1,209 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.user;
+
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyLong;
+import static org.mockito.Mockito.anyString;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cloudstack.acl.ControlledEntity;
+import org.apache.cloudstack.acl.SecurityChecker.AccessType;
+import org.apache.cloudstack.engine.cloud.entity.api.VirtualMachineEntity;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mockito;
+import org.mockito.Spy;
+
+import com.cloud.domain.DomainVO;
+import com.cloud.event.EventTypes;
+import com.cloud.event.UsageEventUtils;
+import com.cloud.event.UsageEventVO;
+import com.cloud.exception.AgentUnavailableException;
+import com.cloud.exception.CloudException;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.service.ServiceOfferingVO;
+import com.cloud.storage.VolumeVO;
+import com.cloud.storage.Volume.Type;
+import com.cloud.vm.UserVmManagerImpl;
+import com.cloud.vm.UserVmVO;
+import com.cloud.vm.VirtualMachine;
+
+
+public class AccountManagerImplVolumeDeleteEventTest extends AccountManagetImplTestBase {
+
+    private static final Long ACCOUNT_ID = 1l;
+    private static final String VOLUME_UUID = "vol-111111";
+
+    @Spy
+    @InjectMocks
+    UserVmManagerImpl _vmMgr;
+    Map<String, Object> oldFields = new HashMap<>();
+    UserVmVO vm = mock(UserVmVO.class);
+
+
+    // Configures the static fields of the UsageEventUtils class, Storing the
+    // previous values to be restored during the cleanup phase, to avoid
+    // interference with other unit tests.
+    protected UsageEventUtils setupUsageUtils() throws NoSuchMethodException, SecurityException, IllegalAccessException,
+    IllegalArgumentException, InvocationTargetException {
+
+        _usageEventDao = new MockUsageEventDao();
+        UsageEventUtils utils = new UsageEventUtils();
+
+        List<String> usageUtilsFields = new ArrayList<String>();
+        usageUtilsFields.add("usageEventDao");
+        usageUtilsFields.add("accountDao");
+        usageUtilsFields.add("dcDao");
+        usageUtilsFields.add("configDao");
+
+        for (String fieldName : usageUtilsFields) {
+            try {
+                Field f = UsageEventUtils.class.getDeclaredField(fieldName);
+                f.setAccessible(true);
+                Field staticField = UsageEventUtils.class.getDeclaredField("s_" + fieldName);
+                staticField.setAccessible(true);
+                oldFields.put(f.getName(), staticField.get(null));
+                f.set(utils,
+                        this.getClass().getSuperclass().getDeclaredField("_" + fieldName).get(this));
+            } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
+                e.printStackTrace();
+            }
+        }
+        Method method;
+        method = UsageEventUtils.class.getDeclaredMethod("init");
+        method.setAccessible(true);
+        method.invoke(utils);
+        return utils;
+    }
+
+
+    protected void defineMocksBehavior()
+            throws AgentUnavailableException, ConcurrentOperationException, CloudException {
+
+        AccountVO account = new AccountVO();
+        account.setId(ACCOUNT_ID);
+        when(_accountDao.remove(ACCOUNT_ID)).thenReturn(true);
+        when(_accountDao.findById(ACCOUNT_ID)).thenReturn(account);
+
+        DomainVO domain = new DomainVO();
+        VirtualMachineEntity vmEntity = mock(VirtualMachineEntity.class);
+
+        when(_orchSrvc.getVirtualMachine(anyString())).thenReturn(vmEntity);
+        when(vmEntity.destroy(anyString())).thenReturn(true);
+
+        Mockito.doReturn(vm).when(_vmDao).findById(anyLong());
+
+        VolumeVO vol = new VolumeVO(VOLUME_UUID, 1l, 1l, 1l, 1l, 1l, "folder", "path", null, 50, Type.ROOT);
+        vol.setDisplayVolume(true);
+        List<VolumeVO> volumes = new ArrayList<>();
+        volumes.add(vol);
+
+        when(securityChecker.checkAccess(any(Account.class), any(ControlledEntity.class), any(AccessType.class),
+                anyString())).thenReturn(true);
+
+        when(_userVmDao.findById(anyLong())).thenReturn(vm);
+        when(_userVmDao.listByAccountId(ACCOUNT_ID)).thenReturn(Arrays.asList(vm));
+        when(_userVmDao.findByUuid(any(String.class))).thenReturn(vm);
+
+        when(_volumeDao.findByInstance(anyLong())).thenReturn(volumes);
+
+        ServiceOfferingVO offering = mock(ServiceOfferingVO.class);
+        when(offering.getCpu()).thenReturn(500);
+        when(offering.getId()).thenReturn(1l);
+        when(offering.getCpu()).thenReturn(500);
+        when(offering.getRamSize()).thenReturn(500);
+        when(_serviceOfferingDao.findByIdIncludingRemoved(anyLong(), anyLong()))
+        .thenReturn(offering);
+
+        when(_domainMgr.getDomain(anyLong())).thenReturn(domain);
+
+        Mockito.doReturn(true).when(_vmMgr).expunge(any(UserVmVO.class), anyLong(), any(Account.class));
+
+    }
+
+    @Before
+    public void init()
+            throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
+            InvocationTargetException, AgentUnavailableException, ConcurrentOperationException, CloudException {
+
+        setupUsageUtils();
+        defineMocksBehavior();
+    }
+
+    @After
+    // Restores static fields of the UsageEventUtil class to previous values.
+    public void cleanupUsageUtils() throws ReflectiveOperationException, SecurityException {
+
+        UsageEventUtils utils = new UsageEventUtils();
+        for (String fieldName : oldFields.keySet()) {
+            Field f = UsageEventUtils.class.getDeclaredField(fieldName);
+            f.setAccessible(true);
+            f.set(utils, oldFields.get(fieldName));
+        }
+        Method method = UsageEventUtils.class.getDeclaredMethod("init");
+        method.setAccessible(true);
+        method.invoke(utils);
+    }
+
+    @SuppressWarnings("unchecked")
+    protected List<UsageEventVO> deleteUserAccountRootVolumeUsageEvents(boolean vmDestroyedPrior)
+            throws AgentUnavailableException, ConcurrentOperationException, CloudException {
+
+        when(vm.getState())
+        .thenReturn(vmDestroyedPrior ? VirtualMachine.State.Destroyed : VirtualMachine.State.Running);
+        when(vm.getRemoved()).thenReturn(vmDestroyedPrior ? new Date() : null);
+        accountManager.deleteUserAccount(ACCOUNT_ID);
+
+        return _usageEventDao.listAll();
+    }
+
+    @Test
+    // If the VM is alerady destroyed, no events should get emitted
+    public void destroyedVMRootVolumeUsageEvent() throws SecurityException, IllegalArgumentException,
+    ReflectiveOperationException, AgentUnavailableException, ConcurrentOperationException, CloudException {
+        List<UsageEventVO> emittedEvents = deleteUserAccountRootVolumeUsageEvents(true);
+        Assert.assertEquals(0, emittedEvents.size());
+    }
+
+    @Test
+    // If the VM is running, we should see one emitted event for the root
+    // volume.
+    public void runningVMRootVolumeUsageEvent() throws SecurityException, IllegalArgumentException,
+    ReflectiveOperationException, AgentUnavailableException, ConcurrentOperationException, CloudException {
+        List<UsageEventVO> emittedEvents = deleteUserAccountRootVolumeUsageEvents(false);
+        Assert.assertEquals(1, emittedEvents.size());
+        UsageEventVO event = emittedEvents.get(0);
+        Assert.assertEquals(EventTypes.EVENT_VOLUME_DELETE, event.getType());
+        Assert.assertEquals(VOLUME_UUID, event.getResourceName());
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d989c5d8/server/test/com/cloud/user/AccountManagetImplTestBase.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/user/AccountManagetImplTestBase.java b/server/test/com/cloud/user/AccountManagetImplTestBase.java
new file mode 100644
index 0000000..5f1e841
--- /dev/null
+++ b/server/test/com/cloud/user/AccountManagetImplTestBase.java
@@ -0,0 +1,242 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.user;
+
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.inject.Inject;
+
+import org.apache.cloudstack.acl.SecurityChecker;
+import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
+import org.apache.cloudstack.engine.service.api.OrchestrationService;
+import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
+import org.apache.cloudstack.framework.messagebus.MessageBus;
+import org.apache.cloudstack.region.gslb.GlobalLoadBalancerRuleDao;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import com.cloud.configuration.ConfigurationManager;
+import com.cloud.configuration.dao.ResourceCountDao;
+import com.cloud.configuration.dao.ResourceLimitDao;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.dc.dao.DataCenterVnetDao;
+import com.cloud.dc.dao.DedicatedResourceDao;
+import com.cloud.domain.dao.DomainDao;
+import com.cloud.event.dao.UsageEventDao;
+import com.cloud.network.as.AutoScaleManager;
+import com.cloud.network.dao.AccountGuestVlanMapDao;
+import com.cloud.network.dao.IPAddressDao;
+import com.cloud.network.dao.NetworkDao;
+import com.cloud.network.dao.RemoteAccessVpnDao;
+import com.cloud.network.dao.VpnUserDao;
+import com.cloud.network.security.SecurityGroupManager;
+import com.cloud.network.security.dao.SecurityGroupDao;
+import com.cloud.network.vpc.VpcManager;
+import com.cloud.network.vpn.RemoteAccessVpnService;
+import com.cloud.network.vpn.Site2SiteVpnManager;
+import com.cloud.projects.ProjectManager;
+import com.cloud.projects.dao.ProjectAccountDao;
+import com.cloud.projects.dao.ProjectDao;
+import com.cloud.server.auth.UserAuthenticator;
+import com.cloud.service.dao.ServiceOfferingDao;
+import com.cloud.storage.VolumeApiService;
+import com.cloud.storage.dao.SnapshotDao;
+import com.cloud.storage.dao.VMTemplateDao;
+import com.cloud.storage.dao.VolumeDao;
+import com.cloud.storage.snapshot.SnapshotManager;
+import com.cloud.template.TemplateManager;
+import com.cloud.user.dao.AccountDao;
+import com.cloud.user.dao.UserAccountDao;
+import com.cloud.user.dao.UserDao;
+import com.cloud.vm.VirtualMachineManager;
+import com.cloud.vm.dao.DomainRouterDao;
+import com.cloud.vm.dao.InstanceGroupDao;
+import com.cloud.vm.dao.UserVmDao;
+import com.cloud.vm.dao.VMInstanceDao;
+import com.cloud.vm.snapshot.VMSnapshotManager;
+import com.cloud.vm.snapshot.dao.VMSnapshotDao;
+
+@RunWith(MockitoJUnitRunner.class)
+public class AccountManagetImplTestBase {
+
+    @Mock
+    AccountDao _accountDao;
+    @Mock
+    ConfigurationDao _configDao;
+    @Mock
+    ResourceCountDao _resourceCountDao;
+    @Mock
+    UserDao _userDao;
+    @Mock
+    InstanceGroupDao _vmGroupDao;
+    @Mock
+    UserAccountDao _userAccountDao;
+    @Mock
+    VolumeDao _volumeDao;
+    @Mock
+    UserVmDao _userVmDao;
+    @Mock
+    VMTemplateDao _templateDao;
+    @Mock
+    NetworkDao _networkDao;
+    @Mock
+    SecurityGroupDao _securityGroupDao;
+    @Mock
+    VMInstanceDao _vmDao;
+    @Mock
+    protected SnapshotDao _snapshotDao;
+    @Mock
+    protected VMTemplateDao _vmTemplateDao;
+    @Mock
+    SecurityGroupManager _networkGroupMgr;
+    @Mock
+    NetworkOrchestrationService _networkMgr;
+    @Mock
+    SnapshotManager _snapMgr;
+    @Mock
+    TemplateManager _tmpltMgr;
+    @Mock
+    ConfigurationManager _configMgr;
+    @Mock
+    VirtualMachineManager _itMgr;
+    @Mock
+    RemoteAccessVpnDao _remoteAccessVpnDao;
+    @Mock
+    RemoteAccessVpnService _remoteAccessVpnMgr;
+    @Mock
+    VpnUserDao _vpnUser;
+    @Mock
+    DataCenterDao _dcDao;
+    @Mock
+    DomainManager _domainMgr;
+    @Mock
+    ProjectManager _projectMgr;
+    @Mock
+    ProjectDao _projectDao;
+    @Mock
+    AccountDetailsDao _accountDetailsDao;
+    @Mock
+    DomainDao _domainDao;
+    @Mock
+    ProjectAccountDao _projectAccountDao;
+    @Mock
+    IPAddressDao _ipAddressDao;
+    @Mock
+    VpcManager _vpcMgr;
+    @Mock
+    DomainRouterDao _routerDao;
+    @Mock
+    Site2SiteVpnManager _vpnMgr;
+    @Mock
+    AutoScaleManager _autoscaleMgr;
+    @Mock
+    VolumeApiService volumeService;
+    @Mock
+    AffinityGroupDao _affinityGroupDao;
+    @Mock
+    AccountGuestVlanMapDao _accountGuestVlanMapDao;
+    @Mock
+    DataCenterVnetDao _dataCenterVnetDao;
+    @Mock
+    ResourceLimitService _resourceLimitMgr;
+    @Mock
+    ResourceLimitDao _resourceLimitDao;
+    @Mock
+    DedicatedResourceDao _dedicatedDao;
+    @Mock
+    GlobalLoadBalancerRuleDao _gslbRuleDao;
+    @Mock
+    MessageBus _messageBus;
+    @Mock
+    VMSnapshotManager _vmSnapshotMgr;
+    @Mock
+    VMSnapshotDao _vmSnapshotDao;
+    @Mock
+    User callingUser;
+    @Mock
+    Account callingAccount;
+
+    @Mock
+    SecurityChecker securityChecker;
+    @Mock
+    UserAuthenticator userAuthenticator;
+    @Mock
+    ServiceOfferingDao _serviceOfferingDao;
+    @Mock
+    ServiceOfferingDao _offeringDao;
+    @Mock
+    OrchestrationService _orchSrvc;
+
+
+    AccountManagerImpl accountManager;
+
+    UsageEventDao _usageEventDao = new MockUsageEventDao();
+
+    @Before
+    public void setup()
+            throws NoSuchFieldException, SecurityException,
+            IllegalArgumentException, IllegalAccessException {
+        accountManager = new AccountManagerImpl();
+        Map<String, Field> declaredFields = getInheritedFields(this.getClass());
+        for (Field field : AccountManagerImpl.class.getDeclaredFields()) {
+            if (field.getAnnotation(Inject.class) != null) {
+                field.setAccessible(true);
+                if (declaredFields.containsKey(field.getName())) {
+                    Field mockField = declaredFields.get(field.getName());
+                    field.set(accountManager, mockField.get(this));
+                }
+            }
+        }
+        ReflectionTestUtils.setField(accountManager, "_userAuthenticators", Arrays.asList(userAuthenticator));
+        accountManager.setSecurityCheckers(Arrays.asList(securityChecker));
+        CallContext.register(callingUser, callingAccount);
+    }
+
+    @After
+    public void cleanup() {
+        CallContext.unregister();
+    }
+
+    public static Map<String, Field> getInheritedFields(Class<?> type) {
+        Map<String, Field> fields = new HashMap<>();
+        for (Class<?> c = type; c != null; c = c.getSuperclass()) {
+            for (Field f : c.getDeclaredFields()) {
+                fields.put(f.getName(), f);
+            }
+        }
+        return fields;
+    }
+
+    public static Map<Class<?>, Field> getInheritedFieldsByClass(Class<?> type) {
+        Map<Class<?>, Field> fields = new HashMap<>();
+        for (Class<?> c = type; c != null; c = c.getSuperclass()) {
+            for (Field f : c.getDeclaredFields()) {
+                fields.put(f.getType(), f);
+            }
+        }
+        return fields;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d989c5d8/server/test/com/cloud/user/MockUsageEventDao.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/user/MockUsageEventDao.java b/server/test/com/cloud/user/MockUsageEventDao.java
new file mode 100644
index 0000000..4959b83
--- /dev/null
+++ b/server/test/com/cloud/user/MockUsageEventDao.java
@@ -0,0 +1,307 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.user;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+import javax.naming.ConfigurationException;
+
+import com.cloud.event.UsageEventVO;
+import com.cloud.event.dao.UsageEventDao;
+import com.cloud.utils.Pair;
+import com.cloud.utils.db.Attribute;
+import com.cloud.utils.db.Filter;
+import com.cloud.utils.db.GenericSearchBuilder;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+
+public class MockUsageEventDao implements UsageEventDao{
+
+    List<UsageEventVO> persistedItems;
+
+    public MockUsageEventDao() {
+        persistedItems = new ArrayList<UsageEventVO>();
+    }
+
+    @Override
+    public UsageEventVO findById(Long id) {
+        return null;
+    }
+
+    @Override
+    public UsageEventVO findByIdIncludingRemoved(Long id) {
+        return null;
+    }
+
+    @Override
+    public UsageEventVO findById(Long id, boolean fresh) {
+        return null;
+    }
+
+    @Override
+    public UsageEventVO findByUuid(String uuid) {
+        return null;
+    }
+
+    @Override
+    public UsageEventVO findByUuidIncludingRemoved(String uuid) {
+        return null;
+    }
+
+    @Override
+    public UsageEventVO createForUpdate() {
+        return null;
+    }
+
+    @Override
+    public SearchBuilder<UsageEventVO> createSearchBuilder() {
+        return null;
+    }
+
+    @Override
+    public <K> GenericSearchBuilder<UsageEventVO, K> createSearchBuilder(
+            Class<K> clazz) {
+        return null;
+    }
+
+    @Override
+    public UsageEventVO createForUpdate(Long id) {
+        return null;
+    }
+
+    @Override
+    public SearchCriteria<UsageEventVO> createSearchCriteria() {
+        return null;
+    }
+
+    @Override
+    public List<UsageEventVO> lockRows(SearchCriteria<UsageEventVO> sc,
+            Filter filter, boolean exclusive) {
+        return null;
+    }
+
+    @Override
+    public UsageEventVO lockOneRandomRow(SearchCriteria<UsageEventVO> sc,
+            boolean exclusive) {
+        return null;
+    }
+
+    @Override
+    public UsageEventVO lockRow(Long id, Boolean exclusive) {
+        return null;
+    }
+
+    @Override
+    public UsageEventVO acquireInLockTable(Long id) {
+        return null;
+    }
+
+    @Override
+    public UsageEventVO acquireInLockTable(Long id, int seconds) {
+        return null;
+    }
+
+    @Override
+    public boolean releaseFromLockTable(Long id) {
+        return false;
+    }
+
+    @Override
+    public boolean update(Long id, UsageEventVO entity) {
+        return false;
+    }
+
+    @Override
+    public int update(UsageEventVO entity, SearchCriteria<UsageEventVO> sc) {
+        return 0;
+    }
+
+    @Override
+    public List<UsageEventVO> listAll() {
+        return persistedItems;
+    }
+
+    @Override
+    public List<UsageEventVO> listAll(Filter filter) {
+        return null;
+    }
+
+    @Override
+    public List<UsageEventVO> search(SearchCriteria<UsageEventVO> sc,
+            Filter filter) {
+        return null;
+    }
+
+    @Override
+    public List<UsageEventVO> search(SearchCriteria<UsageEventVO> sc,
+            Filter filter, boolean enableQueryCache) {
+        return null;
+    }
+
+    @Override
+    public List<UsageEventVO> searchIncludingRemoved(
+            SearchCriteria<UsageEventVO> sc, Filter filter, Boolean lock,
+            boolean cache) {
+        return null;
+    }
+
+    @Override
+    public List<UsageEventVO> searchIncludingRemoved(
+            SearchCriteria<UsageEventVO> sc, Filter filter, Boolean lock,
+            boolean cache, boolean enableQueryCache) {
+        return null;
+    }
+
+    @Override
+    public <M> List<M> customSearchIncludingRemoved(SearchCriteria<M> sc,
+            Filter filter) {
+        return null;
+    }
+
+    @Override
+    public List<UsageEventVO> listAllIncludingRemoved() {
+        return null;
+    }
+
+    @Override
+    public List<UsageEventVO> listAllIncludingRemoved(Filter filter) {
+        return null;
+    }
+
+    @Override
+    public UsageEventVO persist(UsageEventVO entity) {
+        persistedItems.add(entity);
+        return entity;
+    }
+
+    @Override
+    public boolean remove(Long id) {
+        return false;
+    }
+
+    @Override
+    public int remove(SearchCriteria<UsageEventVO> sc) {
+        return 0;
+    }
+
+    @Override
+    public boolean expunge(Long id) {
+        return false;
+    }
+
+    @Override
+    public int expunge(SearchCriteria<UsageEventVO> sc) {
+        return 0;
+    }
+
+    @Override
+    public void expunge() {
+
+    }
+
+    @Override
+    public <K> K getNextInSequence(Class<K> clazz, String name) {
+        return null;
+    }
+
+    @Override
+    public boolean configure(String name, Map<String, Object> params)
+            throws ConfigurationException {
+        return false;
+    }
+
+    @Override
+    public <M> List<M> customSearch(SearchCriteria<M> sc, Filter filter) {
+        return null;
+    }
+
+    @Override
+    public boolean lockInLockTable(String id) {
+        return false;
+    }
+
+    @Override
+    public boolean lockInLockTable(String id, int seconds) {
+        return false;
+    }
+
+    @Override
+    public boolean unlockFromLockTable(String id) {
+        return false;
+    }
+
+    @Override
+    public <K> K getRandomlyIncreasingNextInSequence(Class<K> clazz, String name) {
+        return null;
+    }
+
+    @Override
+    public UsageEventVO findOneBy(SearchCriteria<UsageEventVO> sc) {
+        return null;
+    }
+
+    @Override
+    public Class<UsageEventVO> getEntityBeanType() {
+        return null;
+    }
+
+    @Override
+    public Pair<List<UsageEventVO>, Integer> searchAndCount(
+            SearchCriteria<UsageEventVO> sc, Filter filter) {
+        return null;
+    }
+
+    @Override
+    public Pair<List<UsageEventVO>, Integer> searchAndDistinctCount(SearchCriteria<UsageEventVO> sc, Filter filter) {
+        return null;
+    }
+
+    @Override
+    public Map<String, Attribute> getAllAttributes() {
+        return null;
+    }
+
+    @Override
+    public List<UsageEventVO> listLatestEvents(Date endDate) {
+        return null;
+    }
+
+    @Override
+    public List<UsageEventVO> getLatestEvent() {
+        return null;
+    }
+
+    @Override
+    public List<UsageEventVO> getRecentEvents(Date endDate) {
+        return null;
+    }
+
+    @Override
+    public List<UsageEventVO> listDirectIpEvents(Date startDate, Date endDate,
+            long zoneId) {
+        return null;
+    }
+
+    @Override
+    public void saveDetails(long eventId, Map<String, String> details) {
+
+    }
+
+}


[3/3] git commit: updated refs/heads/4.9 to 72612f7

Posted by ra...@apache.org.
Merge release branch 4.8 to 4.9

* 4.8:
  Emit a VOLUME_DELETE usage event when account deletion destroys an instance.


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/72612f79
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/72612f79
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/72612f79

Branch: refs/heads/4.9
Commit: 72612f79cdb65caf25b06036dc3d618ba76738a9
Parents: 9b9b49e fae9034
Author: Rajani Karuturi <ra...@accelerite.com>
Authored: Mon Oct 24 11:13:06 2016 +0530
Committer: Rajani Karuturi <ra...@accelerite.com>
Committed: Mon Oct 24 11:13:06 2016 +0530

----------------------------------------------------------------------
 .../src/com/cloud/user/AccountManagerImpl.java  |  12 +-
 .../com/cloud/user/AccountManagerImplTest.java  | 220 ++-----------
 ...AccountManagerImplVolumeDeleteEventTest.java | 209 +++++++++++++
 .../cloud/user/AccountManagetImplTestBase.java  | 242 +++++++++++++++
 .../test/com/cloud/user/MockUsageEventDao.java  | 307 +++++++++++++++++++
 5 files changed, 787 insertions(+), 203 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/72612f79/server/src/com/cloud/user/AccountManagerImpl.java
----------------------------------------------------------------------


[2/3] git commit: updated refs/heads/4.9 to 72612f7

Posted by ra...@apache.org.
Merge pull request #1624 from greenqloud/pr-volume-usage-events-fixes-4.8

Fixes regarding VOLUME_DELETE events resulting from account deletionNew version of #1491.

**Original Description**
New version of #1373, but updated for the 4.7 branch with another fix that allows it to properly find expunged root volumes. This is a bug fix, which is why we target the 4.7 branch.

Original pull request:
Fixes regarding usage event emission.

UsageEventUtils was previously not checking deleted accounts, which meant that if an account was deleted that had some resources running on it, those resources would get destroyed without emitting any events.

Furthermore, the VOLUME_DELETE event of ROOT volumes is the responsibility of the UserVmManager, which gets circumvented when expunging resources following the account deletion. Added a check to the AccountManager which catches the ROOT volumes that need to be deleted and emits events for them.

To test this: Create a new user. As that user, create and destroy an instance. This should cause the VM_CREATE, VM_START, VM_STOP, VM_DESTROY, VOLUME_CREATE, and VOLUME_DELETE events to be emitted.
Create a new instance as the same user. Log in as admin, and delete the user. The same set of events should be emitted, and there should be no duplicate DELETE events for the ROOT volume of the previous instance.

* pr/1624:
  Emit a VOLUME_DELETE usage event when account deletion destroys an instance.

Signed-off-by: Rajani Karuturi <ra...@accelerite.com>


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/fae90341
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/fae90341
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/fae90341

Branch: refs/heads/4.9
Commit: fae90341beb51fd0daa1814ec2f8700c0894e551
Parents: a664e03 d989c5d
Author: Rajani Karuturi <ra...@accelerite.com>
Authored: Sat Oct 22 19:42:20 2016 +0530
Committer: Rajani Karuturi <ra...@accelerite.com>
Committed: Sat Oct 22 19:42:20 2016 +0530

----------------------------------------------------------------------
 .../src/com/cloud/user/AccountManagerImpl.java  |  12 +-
 .../com/cloud/user/AccountManagerImplTest.java  | 220 ++-----------
 ...AccountManagerImplVolumeDeleteEventTest.java | 209 +++++++++++++
 .../cloud/user/AccountManagetImplTestBase.java  | 242 +++++++++++++++
 .../test/com/cloud/user/MockUsageEventDao.java  | 307 +++++++++++++++++++
 5 files changed, 787 insertions(+), 203 deletions(-)
----------------------------------------------------------------------