Skip to content

Commit fae9034

Browse files
committed
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 <[email protected]>
2 parents a664e03 + d989c5d commit fae9034

File tree

5 files changed

+787
-203
lines changed

5 files changed

+787
-203
lines changed

server/src/com/cloud/user/AccountManagerImpl.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@
159159
import com.cloud.vm.UserVmManager;
160160
import com.cloud.vm.UserVmVO;
161161
import com.cloud.vm.VMInstanceVO;
162+
import com.cloud.vm.VirtualMachine;
162163
import com.cloud.vm.VirtualMachineManager;
163164
import com.cloud.vm.dao.InstanceGroupDao;
164165
import com.cloud.vm.dao.UserVmDao;
@@ -755,8 +756,17 @@ protected boolean cleanupAccount(AccountVO account, long callerUserId, Account c
755756
s_logger.debug("Expunging # of vms (accountId=" + accountId + "): " + vms.size());
756757
}
757758

758-
// no need to catch exception at this place as expunging vm should pass in order to perform further cleanup
759759
for (UserVmVO vm : vms) {
760+
if (vm.getState() != VirtualMachine.State.Destroyed && vm.getState() != VirtualMachine.State.Expunging) {
761+
try {
762+
_vmMgr.destroyVm(vm.getId());
763+
} catch (Exception e) {
764+
e.printStackTrace();
765+
s_logger.warn("Failed destroying instance " + vm.getUuid() + " as part of account deletion.");
766+
}
767+
}
768+
// no need to catch exception at this place as expunging vm
769+
// should pass in order to perform further cleanup
760770
if (!_vmMgr.expunge(vm, callerUserId, caller)) {
761771
s_logger.error("Unable to expunge vm: " + vm.getId());
762772
accountCleanupNeeded = true;

server/test/com/cloud/user/AccountManagerImplTest.java

Lines changed: 18 additions & 202 deletions
Original file line numberDiff line numberDiff line change
@@ -16,220 +16,35 @@
1616
// under the License.
1717
package com.cloud.user;
1818

19-
import java.lang.reflect.Field;
2019
import java.net.InetAddress;
2120
import java.net.UnknownHostException;
22-
import java.util.Arrays;
2321
import java.util.ArrayList;
24-
25-
import javax.inject.Inject;
26-
22+
import java.util.Arrays;
2723
import com.cloud.server.auth.UserAuthenticator;
2824
import com.cloud.utils.Pair;
29-
import org.junit.After;
25+
3026
import org.junit.Assert;
31-
import org.junit.Before;
3227
import org.junit.Test;
33-
import org.junit.runner.RunWith;
3428
import org.mockito.Mock;
3529
import org.mockito.Mockito;
36-
import org.mockito.runners.MockitoJUnitRunner;
37-
3830
import org.apache.cloudstack.acl.ControlledEntity;
39-
import org.apache.cloudstack.acl.SecurityChecker;
4031
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
41-
import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
42-
import org.apache.cloudstack.context.CallContext;
43-
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
44-
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
45-
import org.apache.cloudstack.framework.messagebus.MessageBus;
46-
import org.apache.cloudstack.region.gslb.GlobalLoadBalancerRuleDao;
47-
48-
import com.cloud.vm.snapshot.VMSnapshotManager;
4932
import com.cloud.vm.snapshot.VMSnapshotVO;
50-
import com.cloud.vm.snapshot.dao.VMSnapshotDao;
51-
52-
import com.cloud.configuration.ConfigurationManager;
53-
import com.cloud.configuration.dao.ResourceCountDao;
54-
import com.cloud.configuration.dao.ResourceLimitDao;
55-
import com.cloud.dc.dao.DataCenterDao;
56-
import com.cloud.dc.dao.DataCenterVnetDao;
57-
import com.cloud.dc.dao.DedicatedResourceDao;
5833
import com.cloud.domain.Domain;
5934
import com.cloud.domain.DomainVO;
60-
import com.cloud.domain.dao.DomainDao;
6135
import com.cloud.exception.ConcurrentOperationException;
6236
import com.cloud.exception.ResourceUnavailableException;
63-
import com.cloud.network.as.AutoScaleManager;
64-
import com.cloud.network.dao.AccountGuestVlanMapDao;
65-
import com.cloud.network.dao.IPAddressDao;
66-
import com.cloud.network.dao.NetworkDao;
67-
import com.cloud.network.dao.RemoteAccessVpnDao;
68-
import com.cloud.network.dao.VpnUserDao;
69-
import com.cloud.network.security.SecurityGroupManager;
70-
import com.cloud.network.security.dao.SecurityGroupDao;
71-
import com.cloud.network.vpc.VpcManager;
72-
import com.cloud.network.vpn.RemoteAccessVpnService;
73-
import com.cloud.network.vpn.Site2SiteVpnManager;
74-
import com.cloud.projects.ProjectManager;
75-
import com.cloud.projects.dao.ProjectAccountDao;
76-
import com.cloud.projects.dao.ProjectDao;
77-
import com.cloud.storage.VolumeApiService;
78-
import com.cloud.storage.dao.SnapshotDao;
79-
import com.cloud.storage.dao.VMTemplateDao;
80-
import com.cloud.storage.dao.VolumeDao;
81-
import com.cloud.storage.snapshot.SnapshotManager;
82-
import com.cloud.template.TemplateManager;
8337
import com.cloud.user.Account.State;
84-
import com.cloud.user.dao.AccountDao;
85-
import com.cloud.user.dao.UserAccountDao;
86-
import com.cloud.user.dao.UserDao;
87-
import com.cloud.vm.UserVmManager;
38+
import com.cloud.vm.UserVmManagerImpl;
8839
import com.cloud.vm.UserVmVO;
8940
import com.cloud.vm.VMInstanceVO;
90-
import com.cloud.vm.VirtualMachineManager;
91-
import com.cloud.vm.dao.DomainRouterDao;
92-
import com.cloud.vm.dao.InstanceGroupDao;
93-
import com.cloud.vm.dao.UserVmDao;
94-
import com.cloud.vm.dao.VMInstanceDao;
95-
import org.springframework.test.util.ReflectionTestUtils;
9641

97-
@RunWith(MockitoJUnitRunner.class)
98-
public class AccountManagerImplTest {
99-
@Mock
100-
AccountDao _accountDao;
101-
@Mock
102-
ConfigurationDao _configDao;
103-
@Mock
104-
ResourceCountDao _resourceCountDao;
105-
@Mock
106-
UserDao _userDao;
107-
@Mock
108-
InstanceGroupDao _vmGroupDao;
109-
@Mock
110-
UserAccountDao _userAccountDao;
111-
@Mock
112-
VolumeDao _volumeDao;
113-
@Mock
114-
UserVmDao _userVmDao;
115-
@Mock
116-
VMTemplateDao _templateDao;
117-
@Mock
118-
NetworkDao _networkDao;
119-
@Mock
120-
SecurityGroupDao _securityGroupDao;
121-
@Mock
122-
VMInstanceDao _vmDao;
123-
@Mock
124-
protected SnapshotDao _snapshotDao;
125-
@Mock
126-
protected VMTemplateDao _vmTemplateDao;
127-
@Mock
128-
SecurityGroupManager _networkGroupMgr;
129-
@Mock
130-
NetworkOrchestrationService _networkMgr;
131-
@Mock
132-
SnapshotManager _snapMgr;
133-
@Mock
134-
UserVmManager _vmMgr;
135-
@Mock
136-
TemplateManager _tmpltMgr;
137-
@Mock
138-
ConfigurationManager _configMgr;
139-
@Mock
140-
VirtualMachineManager _itMgr;
141-
@Mock
142-
RemoteAccessVpnDao _remoteAccessVpnDao;
143-
@Mock
144-
RemoteAccessVpnService _remoteAccessVpnMgr;
145-
@Mock
146-
VpnUserDao _vpnUser;
147-
@Mock
148-
DataCenterDao _dcDao;
149-
@Mock
150-
DomainManager _domainMgr;
151-
@Mock
152-
ProjectManager _projectMgr;
153-
@Mock
154-
ProjectDao _projectDao;
155-
@Mock
156-
AccountDetailsDao _accountDetailsDao;
157-
@Mock
158-
DomainDao _domainDao;
159-
@Mock
160-
ProjectAccountDao _projectAccountDao;
161-
@Mock
162-
IPAddressDao _ipAddressDao;
163-
@Mock
164-
VpcManager _vpcMgr;
165-
@Mock
166-
DomainRouterDao _routerDao;
167-
@Mock
168-
Site2SiteVpnManager _vpnMgr;
169-
@Mock
170-
AutoScaleManager _autoscaleMgr;
171-
@Mock
172-
VolumeApiService volumeService;
173-
@Mock
174-
AffinityGroupDao _affinityGroupDao;
175-
@Mock
176-
AccountGuestVlanMapDao _accountGuestVlanMapDao;
177-
@Mock
178-
DataCenterVnetDao _dataCenterVnetDao;
179-
@Mock
180-
ResourceLimitService _resourceLimitMgr;
181-
@Mock
182-
ResourceLimitDao _resourceLimitDao;
183-
@Mock
184-
DedicatedResourceDao _dedicatedDao;
185-
@Mock
186-
GlobalLoadBalancerRuleDao _gslbRuleDao;
187-
@Mock
188-
MessageBus _messageBus;
18942

190-
@Mock
191-
VMSnapshotManager _vmSnapshotMgr;
192-
@Mock
193-
VMSnapshotDao _vmSnapshotDao;
43+
public class AccountManagerImplTest extends AccountManagetImplTestBase {
19444

195-
@Mock
196-
User callingUser;
197-
@Mock
198-
Account callingAccount;
199-
200-
AccountManagerImpl accountManager;
201-
202-
@Mock
203-
SecurityChecker securityChecker;
20445

20546
@Mock
206-
private UserAuthenticator userAuthenticator;
207-
208-
@Before
209-
public void setup() throws NoSuchFieldException, SecurityException,
210-
IllegalArgumentException, IllegalAccessException {
211-
accountManager = new AccountManagerImpl();
212-
for (Field field : AccountManagerImpl.class.getDeclaredFields()) {
213-
if (field.getAnnotation(Inject.class) != null) {
214-
field.setAccessible(true);
215-
try {
216-
Field mockField = this.getClass().getDeclaredField(
217-
field.getName());
218-
field.set(accountManager, mockField.get(this));
219-
} catch (Exception e) {
220-
// ignore missing fields
221-
}
222-
}
223-
}
224-
ReflectionTestUtils.setField(accountManager, "_userAuthenticators", Arrays.asList(userAuthenticator));
225-
accountManager.setSecurityCheckers(Arrays.asList(securityChecker));
226-
CallContext.register(callingUser, callingAccount);
227-
}
228-
229-
@After
230-
public void cleanup() {
231-
CallContext.unregister();
232-
}
47+
UserVmManagerImpl _vmMgr;
23348

23449
@Test
23550
public void disableAccountNotexisting()
@@ -240,7 +55,7 @@ public void disableAccountNotexisting()
24055

24156
@Test
24257
public void disableAccountDisabled() throws ConcurrentOperationException,
243-
ResourceUnavailableException {
58+
ResourceUnavailableException {
24459
AccountVO disabledAccount = new AccountVO();
24560
disabledAccount.setState(State.disabled);
24661
Mockito.when(_accountDao.findById(42l)).thenReturn(disabledAccount);
@@ -249,7 +64,7 @@ public void disableAccountDisabled() throws ConcurrentOperationException,
24964

25065
@Test
25166
public void disableAccount() throws ConcurrentOperationException,
252-
ResourceUnavailableException {
67+
ResourceUnavailableException {
25368
AccountVO account = new AccountVO();
25469
account.setState(State.enabled);
25570
Mockito.when(_accountDao.findById(42l)).thenReturn(account);
@@ -272,17 +87,17 @@ public void deleteUserAccount() {
27287
Mockito.when(_accountDao.findById(42l)).thenReturn(account);
27388
Mockito.when(
27489
securityChecker.checkAccess(Mockito.any(Account.class),
275-
Mockito.any(ControlledEntity.class), Mockito.any(AccessType.class),
276-
Mockito.anyString()))
277-
.thenReturn(true);
90+
Mockito.any(ControlledEntity.class), Mockito.any(AccessType.class),
91+
Mockito.anyString()))
92+
.thenReturn(true);
27893
Mockito.when(_accountDao.remove(42l)).thenReturn(true);
27994
Mockito.when(_configMgr.releaseAccountSpecificVirtualRanges(42l))
280-
.thenReturn(true);
95+
.thenReturn(true);
28196
Mockito.when(_domainMgr.getDomain(Mockito.anyLong())).thenReturn(domain);
28297
Mockito.when(
28398
securityChecker.checkAccess(Mockito.any(Account.class),
28499
Mockito.any(Domain.class)))
285-
.thenReturn(true);
100+
.thenReturn(true);
286101
Mockito.when(_vmSnapshotDao.listByAccountId(Mockito.anyLong())).thenReturn(new ArrayList<VMSnapshotVO>());
287102

288103
Assert.assertTrue(accountManager.deleteUserAccount(42));
@@ -301,10 +116,10 @@ public void deleteUserAccountCleanup() {
301116
securityChecker.checkAccess(Mockito.any(Account.class),
302117
Mockito.any(ControlledEntity.class), Mockito.any(AccessType.class),
303118
Mockito.anyString()))
304-
.thenReturn(true);
119+
.thenReturn(true);
305120
Mockito.when(_accountDao.remove(42l)).thenReturn(true);
306121
Mockito.when(_configMgr.releaseAccountSpecificVirtualRanges(42l))
307-
.thenReturn(true);
122+
.thenReturn(true);
308123
Mockito.when(_userVmDao.listByAccountId(42l)).thenReturn(
309124
Arrays.asList(Mockito.mock(UserVmVO.class)));
310125
Mockito.when(
@@ -314,7 +129,7 @@ public void deleteUserAccountCleanup() {
314129
Mockito.when(
315130
securityChecker.checkAccess(Mockito.any(Account.class),
316131
Mockito.any(Domain.class)))
317-
.thenReturn(true);
132+
.thenReturn(true);
318133

319134
Assert.assertTrue(accountManager.deleteUserAccount(42));
320135
// assert that this was NOT a clean delete
@@ -327,7 +142,7 @@ public void deleteUserAccountCleanup() {
327142
public void testAuthenticateUser() throws UnknownHostException {
328143
Pair<Boolean, UserAuthenticator.ActionOnFailedAuthentication> successAuthenticationPair = new Pair<>(true, null);
329144
Pair<Boolean, UserAuthenticator.ActionOnFailedAuthentication> failureAuthenticationPair = new Pair<>(false,
330-
UserAuthenticator.ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT);
145+
UserAuthenticator.ActionOnFailedAuthentication.INCREMENT_INCORRECT_LOGIN_ATTEMPT_COUNT);
331146

332147
UserAccountVO userAccountVO = new UserAccountVO();
333148
userAccountVO.setSource(User.Source.UNKNOWN);
@@ -353,6 +168,7 @@ public void testAuthenticateUser() throws UnknownHostException {
353168
Mockito.verify(userAuthenticator, Mockito.times(1)).authenticate("test", "fail", 1L, null);
354169
Mockito.verify(userAuthenticator, Mockito.never()).authenticate("test", null, 1L, null);
355170
Mockito.verify(userAuthenticator, Mockito.never()).authenticate("test", "", 1L, null);
356-
357171
}
172+
173+
358174
}

0 commit comments

Comments
 (0)