Add time limit to local guard locking facility 73/55573/2
authorJim Hahn <jrh3@att.com>
Wed, 27 Jun 2018 15:04:11 +0000 (11:04 -0400)
committerJim Hahn <jrh3@att.com>
Fri, 29 Jun 2018 15:07:51 +0000 (11:07 -0400)
Modified the local policy guard locking facility to add
a time parameter.
Modified the control loop event manager to extend the lock
when lockCurrentOperation() is re-invoked.
Modified the rules to retract the lock if the lock request
was denied.
Reorder assertions in junit test.

Change-Id: Ic9b77acbb4881a5a516f30eb56664bad1a5c4d7e
Issue-ID: POLICY-872
Signed-off-by: Jim Hahn <jrh3@att.com>
controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/ControlLoopEventManager.java
controlloop/common/eventmanager/src/test/java/org/onap/policy/controlloop/eventmanager/ControlLoopEventManagerTest.java
controlloop/common/guard/src/main/java/org/onap/policy/guard/PolicyGuard.java
controlloop/common/guard/src/test/java/org/onap/policy/guard/PolicyGuardTest.java
controlloop/templates/archetype-cl-amsterdam/src/main/resources/archetype-resources/src/main/resources/__closedLoopControlName__.drl

index bc9d3df..5f36bcc 100644 (file)
@@ -60,6 +60,12 @@ public class ControlLoopEventManager implements LockCallback, Serializable {
     private static final String GENERIC_VNF_IS_CLOSED_LOOP_DISABLED = "generic-vnf.is-closed-loop-disabled";
     private static final String VSERVER_IS_CLOSED_LOOP_DISABLED = "vserver.is-closed-loop-disabled";
 
+    /**
+     * Additional time, in seconds, to add to a "lock" request. This ensures that the lock
+     * won't expire right before an operation completes.
+     */
+    private static final int ADDITIONAL_LOCK_SEC = 60;
+
     private static final Logger logger = LoggerFactory.getLogger(ControlLoopEventManager.class);
 
     private static final long serialVersionUID = -1216568161322872641L;
@@ -447,14 +453,17 @@ public class ControlLoopEventManager implements LockCallback, Serializable {
             // TODO: Make sure the current lock is for the same target.
             // Currently, it should be. But in the future it may not.
             //
-            return new LockResult<>(GuardResult.LOCK_ACQUIRED, this.targetLock);
+            GuardResult result = PolicyGuard.lockTarget(targetLock,
+                            this.currentOperation.getOperationTimeout() + ADDITIONAL_LOCK_SEC);
+            return new LockResult<>(result, this.targetLock);
         } else {
             //
             // Ask the Guard
             //
             LockResult<GuardResult, TargetLock> lockResult =
                     PolicyGuard.lockTarget(this.currentOperation.policy.getTarget().getType(),
-                            this.currentOperation.getTargetEntity(), this.onset.getRequestId(), this);
+                            this.currentOperation.getTargetEntity(), this.onset.getRequestId(), this,
+                            this.currentOperation.getOperationTimeout() + ADDITIONAL_LOCK_SEC);
             //
             // Was it acquired?
             //
index 182791d..1af4a31 100644 (file)
@@ -755,9 +755,11 @@ public class ControlLoopEventManagerTest {
 
         LockResult<GuardResult, TargetLock> lockLock = manager.lockCurrentOperation();
         assertNotNull(lockLock);
+        assertEquals(GuardResult.LOCK_ACQUIRED, lockLock.getA());
 
         LockResult<GuardResult, TargetLock> lockLockAgain = manager.lockCurrentOperation();
         assertNotNull(lockLockAgain);
+        assertEquals(GuardResult.LOCK_ACQUIRED, lockLockAgain.getA());
         assertEquals(lockLock.getB(), lockLockAgain.getB());
 
         assertEquals(lockLock.getB(), manager.unlockCurrentOperation());
index 66a25ea..64d8a2f 100644 (file)
@@ -2,7 +2,7 @@
  * ============LICENSE_START=======================================================
  * guard
  * ================================================================================
- * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -21,8 +21,6 @@
 package org.onap.policy.guard;
 
 import java.util.UUID;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
 import org.onap.policy.controlloop.policy.TargetType;
 import org.onap.policy.drools.core.lock.PolicyResourceLockManager;
 import org.onap.policy.guard.impl.PNFTargetLock;
@@ -87,15 +85,16 @@ public class PolicyGuard {
      * @param targetInstance the target instance
      * @param requestID the request Id
      * @param callback the LockCallback
+     * @param holdSec maximum number of seconds to hold the lock
      * @return the LockResult
      * @throws IllegalArgumentException if an argument is null
      */
     public static LockResult<GuardResult, TargetLock> lockTarget(TargetType targetType, String targetInstance,
-            UUID requestID, LockCallback callback) {
+            UUID requestID, LockCallback callback, int holdSec) {
         
         String owner = makeOwner(targetType, requestID);
         
-        GuardResult guardResult = managerLockTarget(targetInstance, owner);
+        GuardResult guardResult = managerLockTarget(targetInstance, owner, holdSec);
         if(guardResult != GuardResult.LOCK_ACQUIRED) {
             return LockResult.createLockResult(guardResult, null);
         }
@@ -133,31 +132,31 @@ public class PolicyGuard {
         logger.debug("Locked {}", lock);
         return LockResult.createLockResult(GuardResult.LOCK_ACQUIRED, lock);
     }
+    
+    /**
+     * Extends a lock on a target.
+     * @param lock      current lock
+     * @param holdSec maximum number of seconds to hold the lock
+     * @return the result: acquired or denied
+     */
+    public static GuardResult lockTarget(TargetLock lock, int holdSec) {
+        String owner = makeOwner(lock.getTargetType(), lock.getRequestID());
+        GuardResult result = managerLockTarget(lock.getTargetInstance(), owner, holdSec);
+        
+        logger.debug("Lock {} extend {}", lock, result);
+        return result;
+    }
 
     /**
      * Asks the manager to lock the given target.
      * @param targetInstance
      * @param owner
-     * @return the result: acquired, denied, or exception
+     * @param holdSec maximum number of seconds to hold the lock
+     * @return the result: acquired or denied
      */
-    private static GuardResult managerLockTarget(String targetInstance, String owner) {
-        try {
-            Future<Boolean> result = factory.getManager().lock(targetInstance, owner, null);
-            return(result.get() ? GuardResult.LOCK_ACQUIRED : GuardResult.LOCK_DENIED);
-            
-        } catch(IllegalStateException e) {
-            logger.warn("{} attempted to re-lock {}", owner, targetInstance);
-            return GuardResult.LOCK_DENIED;
-            
-        } catch (InterruptedException e) {
-            logger.error("exception getting lock for {}", targetInstance, e);
-            Thread.currentThread().interrupt();
-            return GuardResult.LOCK_EXCEPTION;
-            
-        } catch (ExecutionException e) {
-            logger.error("exception getting lock for {}", targetInstance, e);
-            return GuardResult.LOCK_EXCEPTION;
-        }
+    private static GuardResult managerLockTarget(String targetInstance, String owner, int holdSec) {
+        boolean result = factory.getManager().lock(targetInstance, owner, holdSec);
+        return(result ? GuardResult.LOCK_ACQUIRED : GuardResult.LOCK_DENIED);
     }
 
     /**
index b073fe5..9cd34b7 100644 (file)
@@ -25,13 +25,12 @@ import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doThrow;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import java.util.UUID;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
@@ -46,6 +45,7 @@ import org.onap.policy.guard.impl.VNFTargetLock;
 
 public class PolicyGuardTest {
     private static final String INSTANCENAME = "targetInstance";
+    private static final int LOCK_SEC = 10;
     
     private static Factory saveFactory;
     
@@ -131,7 +131,7 @@ public class PolicyGuardTest {
 
         // Test isLocked before and after lock added
         assertFalse(PolicyGuard.isLocked(type, INSTANCENAME, uuid));
-        LockResult<GuardResult, TargetLock> result = PolicyGuard.lockTarget(type, INSTANCENAME, uuid, dlcb);
+        LockResult<GuardResult, TargetLock> result = PolicyGuard.lockTarget(type, INSTANCENAME, uuid, dlcb, LOCK_SEC);
         assertTrue(PolicyGuard.isLocked(type, INSTANCENAME, uuid));
 
         assertEquals(GuardResult.LOCK_ACQUIRED, result.getA());
@@ -155,7 +155,7 @@ public class PolicyGuardTest {
 
         // Test isLocked before and after lock added
         assertFalse(PolicyGuard.isLocked(type, INSTANCENAME, uuid));
-        LockResult<GuardResult, TargetLock> result = PolicyGuard.lockTarget(type, INSTANCENAME, uuid, dlcb);
+        LockResult<GuardResult, TargetLock> result = PolicyGuard.lockTarget(type, INSTANCENAME, uuid, dlcb, LOCK_SEC);
         assertTrue(PolicyGuard.isLocked(type, INSTANCENAME, uuid));
 
         assertEquals(GuardResult.LOCK_ACQUIRED, result.getA());
@@ -180,7 +180,7 @@ public class PolicyGuardTest {
 
         // Test isLocked before and after lock added
         assertFalse(PolicyGuard.isLocked(type, INSTANCENAME, uuid));
-        LockResult<GuardResult, TargetLock> result = PolicyGuard.lockTarget(type, INSTANCENAME, uuid, dlcb);
+        LockResult<GuardResult, TargetLock> result = PolicyGuard.lockTarget(type, INSTANCENAME, uuid, dlcb, LOCK_SEC);
         assertTrue(PolicyGuard.isLocked(type, INSTANCENAME, uuid));
 
         assertEquals(GuardResult.LOCK_ACQUIRED, result.getA());
@@ -204,7 +204,7 @@ public class PolicyGuardTest {
 
         // Test isLocked before and after lock added
         assertFalse(PolicyGuard.isLocked(type, INSTANCENAME, uuid));
-        LockResult<GuardResult, TargetLock> result = PolicyGuard.lockTarget(type, INSTANCENAME, uuid, dlcb);
+        LockResult<GuardResult, TargetLock> result = PolicyGuard.lockTarget(type, INSTANCENAME, uuid, dlcb, LOCK_SEC);
         assertFalse(PolicyGuard.isLocked(type, INSTANCENAME, uuid));
 
         assertEquals(GuardResult.LOCK_EXCEPTION, result.getA());
@@ -221,18 +221,12 @@ public class PolicyGuardTest {
 
         // Test isLocked before and after lock added
         assertFalse(PolicyGuard.isLocked(type, INSTANCENAME, uuid));
-        LockResult<GuardResult, TargetLock> result = PolicyGuard.lockTarget(type, INSTANCENAME, uuid, dlcb);
+        LockResult<GuardResult, TargetLock> result = PolicyGuard.lockTarget(type, INSTANCENAME, uuid, dlcb, LOCK_SEC);
         assertTrue(PolicyGuard.isLocked(type, INSTANCENAME, uuid));
 
         assertEquals(GuardResult.LOCK_ACQUIRED, result.getA());
         assertEquals(VMTargetLock.class, result.getB().getClass());
 
-        result = PolicyGuard.lockTarget(type, INSTANCENAME, uuid, dlcb);
-        assertTrue(PolicyGuard.isLocked(type, INSTANCENAME, uuid));
-
-        assertEquals(GuardResult.LOCK_DENIED, result.getA());
-        assertNull(result.getB());
-
         // Test isLocked after lock removed
         PolicyGuard.unlockTarget(new DummyTargetLock(type, uuid));
         assertFalse(PolicyGuard.isLocked(type, INSTANCENAME, uuid));
@@ -248,13 +242,16 @@ public class PolicyGuardTest {
 
         // Test isLocked before and after lock added
         assertFalse(PolicyGuard.isLocked(type, INSTANCENAME, uuid));
-        LockResult<GuardResult, TargetLock> result = PolicyGuard.lockTarget(type, INSTANCENAME, uuid, dlcb);
+        LockResult<GuardResult, TargetLock> result = PolicyGuard.lockTarget(type, INSTANCENAME, uuid, dlcb, LOCK_SEC);
         assertTrue(PolicyGuard.isLocked(type, INSTANCENAME, uuid));
 
         assertEquals(GuardResult.LOCK_ACQUIRED, result.getA());
         assertEquals(VMTargetLock.class, result.getB().getClass());
 
-        result = PolicyGuard.lockTarget(type, INSTANCENAME, uuid, dlcb);
+        UUID uuid2 = UUID.randomUUID();
+        result = PolicyGuard.lockTarget(type, INSTANCENAME, uuid2, dlcb, LOCK_SEC);
+        assertFalse(PolicyGuard.isLocked(type, INSTANCENAME, uuid2));
+
         assertTrue(PolicyGuard.isLocked(type, INSTANCENAME, uuid));
 
         assertEquals(GuardResult.LOCK_DENIED, result.getA());
@@ -283,47 +280,41 @@ public class PolicyGuardTest {
     public void testManagerLockTarget() throws Exception {
         TargetType type = TargetType.VM;
         
-        @SuppressWarnings("unchecked")
-        Future<Boolean> fut = mock(Future.class);
-        
         mgr = mock(PolicyResourceLockManager.class);
-        when(mgr.lock(any(), any(), any())).thenReturn(fut);
 
         LockResult<GuardResult, TargetLock> result;
 
         // acquired
-        when(fut.get()).thenReturn(true);
-        result = PolicyGuard.lockTarget(type, INSTANCENAME, uuid, dlcb);
+        when(mgr.lock(anyString(), anyString(), anyInt())).thenReturn(true);
+        result = PolicyGuard.lockTarget(type, INSTANCENAME, uuid, dlcb, LOCK_SEC);
+        verify(mgr).lock(INSTANCENAME, type.toString()+":"+uuid.toString(), LOCK_SEC);
         assertEquals(GuardResult.LOCK_ACQUIRED, result.getA());
         assertEquals(VMTargetLock.class, result.getB().getClass());
 
         // denied
-        when(fut.get()).thenReturn(false);
-        result = PolicyGuard.lockTarget(type, INSTANCENAME, uuid, dlcb);
+        when(mgr.lock(anyString(), anyString(), anyInt())).thenReturn(false);
+        result = PolicyGuard.lockTarget(type, INSTANCENAME, uuid, dlcb, LOCK_SEC+2);
+        verify(mgr).lock(INSTANCENAME, type.toString()+":"+uuid.toString(), LOCK_SEC+2);
         assertEquals(GuardResult.LOCK_DENIED, result.getA());
         assertNull(result.getB());
+    }
 
-        // illegal state exception
-        doThrow(new IllegalStateException("state expected")).when(fut).get();
-        result = PolicyGuard.lockTarget(type, INSTANCENAME, uuid, dlcb);
-        assertEquals(GuardResult.LOCK_DENIED, result.getA());
-        assertNull(result.getB());
-        assertFalse(Thread.currentThread().isInterrupted());
+    @Test
+    public void testManagerLockTargetTargetLockInt() throws Exception {
+        TargetType type = TargetType.VM;
+        DummyTargetLock lock = new DummyTargetLock(type, uuid);
+        
+        mgr = mock(PolicyResourceLockManager.class);
 
-        // interrupted exception
-        doThrow(new InterruptedException("interrupt expected")).when(fut).get();
-        result = PolicyGuard.lockTarget(type, INSTANCENAME, uuid, dlcb);
-        assertEquals(GuardResult.LOCK_EXCEPTION, result.getA());
-        assertNull(result.getB());
-        // verify interrupted & reset interrupt status
-        assertTrue(Thread.interrupted());
+        // acquired
+        when(mgr.lock(anyString(), anyString(), anyInt())).thenReturn(true);
+        assertEquals(GuardResult.LOCK_ACQUIRED, PolicyGuard.lockTarget(lock, LOCK_SEC));
+        verify(mgr).lock(INSTANCENAME, type.toString()+":"+uuid.toString(), LOCK_SEC);
 
-        // exec exception
-        doThrow(new ExecutionException(new IllegalArgumentException("exec expected"))).when(fut).get();
-        result = PolicyGuard.lockTarget(type, INSTANCENAME, uuid, dlcb);
-        assertEquals(GuardResult.LOCK_EXCEPTION, result.getA());
-        assertNull(result.getB());
-        assertFalse(Thread.currentThread().isInterrupted());
+        // denied
+        when(mgr.lock(anyString(), anyString(), anyInt())).thenReturn(false);
+        assertEquals(GuardResult.LOCK_DENIED, PolicyGuard.lockTarget(lock, LOCK_SEC+1));
+        verify(mgr).lock(INSTANCENAME, type.toString()+":"+uuid.toString(), LOCK_SEC+1);
     }
 
     @Test(expected = IllegalArgumentException.class)
index b1773f5..1274d6c 100644 (file)
@@ -449,6 +449,10 @@ rule "${policyName}.EVENT.MANAGER"
                retract($event);
                retract($manager);
                retract($clTimer);
+               
+               if(result.getB() != null) {
+                    retract(result.getB());
+               }
               }
               logger.info("{}: {}: starting operation={}", 
                           $params.getClosedLoopControlName(), drools.getRule().getName(),