substantial cleanup of the renew method and client
authorThierry Parmentelat <thierry.parmentelat@inria.fr>
Wed, 28 May 2014 14:37:46 +0000 (16:37 +0200)
committerThierry Parmentelat <thierry.parmentelat@inria.fr>
Wed, 28 May 2014 14:37:46 +0000 (16:37 +0200)
* sfi -l aka --as-long-as-possible is supported in sfi
* sfi renew <> +2d / +3w / +4m is now working as well as the other time formats (int, rfc3339...)
* most importantly the final expiration time is trimmed to the min of credential expiration and max_slice_renewal, but goes on with these values instead of whining

sfa/client/sfi.py
sfa/managers/aggregate_manager.py
sfa/methods/Renew.py
sfa/util/sfatime.py

index fc4e609..4cceb51 100644 (file)
@@ -448,6 +448,9 @@ class Sfi:
         if canonical in ("list","resources", "describe", "provision", "allocate", "register","update","remove","delete","status","renew"):
             parser.add_option("-C","--credential",dest='show_credential',action='store_true',default=False,
                               help="show credential(s) used in human-readable form")
         if canonical in ("list","resources", "describe", "provision", "allocate", "register","update","remove","delete","status","renew"):
             parser.add_option("-C","--credential",dest='show_credential',action='store_true',default=False,
                               help="show credential(s) used in human-readable form")
+        if canonical in ("renew"):
+            parser.add_option("-l","--as-long-as-possible",dest='alap',action='store_true',default=False,
+                              help="renew as long as possible")
         # registy filter option
         if canonical in ("list", "show", "remove"):
             parser.add_option("-t", "--type", dest="type", type="choice",
         # registy filter option
         if canonical in ("list", "show", "remove"):
             parser.add_option("-t", "--type", dest="type", type="choice",
@@ -1396,7 +1399,12 @@ use this if you mean an authority instead""")
             print value
         return value
 
             print value
         return value
 
-    @declare_command("slice_hrn [<sliver_urn>...] time","sfi renew onelab.ple.heartbeat 2015-04-31")
+    @declare_command("slice_hrn [<sliver_urn>...] time",
+                     "\n".join(["sfi renew onelab.ple.heartbeat 2015-04-31",
+                                "sfi renew onelab.ple.heartbeat 2015-04-31T14:00:00Z",
+                                "sfi renew onelab.ple.heartbeat +5d",
+                                "sfi renew onelab.ple.heartbeat +3w",
+                                "sfi renew onelab.ple.heartbeat +2m",]))
     def renew(self, options, args):
         """
         renew slice (Renew)
     def renew(self, options, args):
         """
         renew slice (Renew)
@@ -1423,6 +1431,8 @@ use this if you mean an authority instead""")
         # options and call_id when supported
         api_options = {}
         api_options['call_id']=unique_call_id()
         # options and call_id when supported
         api_options = {}
         api_options['call_id']=unique_call_id()
+        if options.alap:
+            api_options['geni_extend_alap']=True
         if options.show_credential:
             show_credentials(creds)
         result =  server.Renew(sliver_urns, creds, input_time, *self.ois(server,api_options))
         if options.show_credential:
             show_credentials(creds)
         result =  server.Renew(sliver_urns, creds, input_time, *self.ois(server,api_options))
index 2864567..1521103 100644 (file)
@@ -147,14 +147,6 @@ class AggregateManager:
         call_id = options.get('call_id')
         if Callids().already_handled(call_id): return True
 
         call_id = options.get('call_id')
         if Callids().already_handled(call_id): return True
 
-        # extend as long as possible
-        if options.get('geni_extend_alap'):
-            now = datetime.datetime.now()
-            requested = utcparse(expiration_time)
-            max = adjust_datetime(now, days=int(api.config.SFA_MAX_SLICE_RENEW))
-            if requested > max:
-                expiration_time = max
-
         return api.driver.renew(xrns, expiration_time, options)
 
     def PerformOperationalAction(self, api, xrns, creds, action, options={}):
         return api.driver.renew(xrns, expiration_time, options)
 
     def PerformOperationalAction(self, api, xrns, creds, action, options={}):
index c75c781..0a7ac1a 100644 (file)
@@ -3,7 +3,7 @@ import datetime
 from sfa.util.faults import InsufficientRights
 from sfa.util.xrn import urn_to_hrn
 from sfa.util.method import Method
 from sfa.util.faults import InsufficientRights
 from sfa.util.xrn import urn_to_hrn
 from sfa.util.method import Method
-from sfa.util.sfatime import utcparse
+from sfa.util.sfatime import utcparse, add_datetime
 
 from sfa.trust.credential import Credential
 
 
 from sfa.trust.credential import Credential
 
@@ -14,7 +14,7 @@ class Renew(Method):
     Renews the resources in the specified slice or slivers by 
     extending the lifetime.
     
     Renews the resources in the specified slice or slivers by 
     extending the lifetime.
     
-    @param surn ([string]) List of URNs of to renew
+    @param urns ([string]) List of URNs of to renew
     @param credentials ([string]) of credentials
     @param expiration_time (string) requested time of expiration
     @param options (dict) options
     @param credentials ([string]) of credentials
     @param expiration_time (string) requested time of expiration
     @param options (dict) options
@@ -37,16 +37,32 @@ class Renew(Method):
                                                               options=options)
         the_credential = Credential(cred=valid_creds[0])
         actual_caller_hrn = the_credential.actual_caller_hrn()
                                                               options=options)
         the_credential = Credential(cred=valid_creds[0])
         actual_caller_hrn = the_credential.actual_caller_hrn()
-        self.api.logger.info("interface: %s\tcaller-hrn: %s\ttarget-urns: %s\texp:%s\tmethod-name: %s"%\
+        self.api.logger.info("interface: %s\tcaller-hrn: %s\ttarget-urns: %s\texpiration:%s\tmethod-name: %s"%\
                              (self.api.interface, actual_caller_hrn, urns, expiration_time,self.name))
 
 
                              (self.api.interface, actual_caller_hrn, urns, expiration_time,self.name))
 
 
+        # extend as long as possible : take the min of requested and now+SFA_MAX_SLICE_RENEW
+        if options.get('geni_extend_alap'):
+            # ignore requested time and set to max
+            expiration_time = add_datetime(datetime.datetime.utcnow(), days=int(self.api.config.SFA_MAX_SLICE_RENEW))
+
         # Validate that the time does not go beyond the credential's expiration time
         # Validate that the time does not go beyond the credential's expiration time
-        requested_time = utcparse(expiration_time)
+        requested_expire = utcparse(expiration_time)
+        self.api.logger.info("requested_expire = %s"%requested_expire)
+        credential_expire = the_credential.get_expiration()
+        self.api.logger.info("credential_expire = %s"%credential_expire)
         max_renew_days = int(self.api.config.SFA_MAX_SLICE_RENEW)
         max_renew_days = int(self.api.config.SFA_MAX_SLICE_RENEW)
-        if requested_time > Credential(cred=valid_creds[0]).get_expiration():
-            raise InsufficientRights('Renewsliver: Credential expires before requested expiration time')
-        if requested_time > datetime.datetime.utcnow() + datetime.timedelta(days=max_renew_days):
-            raise Exception('Cannot renew > %s days from now' % max_renew_days)
-        return self.api.manager.Renew(self.api, urns, creds, expiration_time, options)
+        max_expire = datetime.datetime.utcnow() + datetime.timedelta (days=max_renew_days)
+        if requested_expire > credential_expire:
+            # used to throw an InsufficientRights exception here, this was not right
+            self.api.logger.warning("Requested expiration %s, after credential expiration (%s) -> trimming to the latter/sooner"%\
+                                    (requested_expire, credential_expire))
+            requested_expire = credential_expire
+        if requested_expire > max_expire:
+            # likewise
+            self.api.logger.warning("Requested expiration %s, after maximal expiration %s days (%s) -> trimming to the latter/sooner"%\
+                                    (requested_expire, self.api.config.SFA_MAX_SLICE_RENEW,max_expire))
+            requested_expire = max_expire
+
+        return self.api.manager.Renew(self.api, urns, creds, requested_expire, options)
     
     
index d14f44b..27418b2 100644 (file)
@@ -24,6 +24,7 @@ from types import StringTypes
 import dateutil.parser
 import datetime
 import time
 import dateutil.parser
 import datetime
 import time
+import re
 
 from sfa.util.sfalogging import logger
 
 
 from sfa.util.sfalogging import logger
 
@@ -35,16 +36,36 @@ the timezone, so that it's compatible with normal datetime.datetime objects.
 
 For safety this can also handle inputs that are either timestamps, or datetimes
 """
 
 For safety this can also handle inputs that are either timestamps, or datetimes
 """
+
+    def handle_shorthands (input):
+        """recognize string like +5d or +3w or +2m as 
+        2 days, 3 weeks or 2 months from now"""
+        if input.startswith('+'):
+            match=re.match (r"([0-9]+)([dwm])",input[1:])
+            if match:
+                how_many=int(match.group(1))
+                what=match.group(2)
+                if what == 'd':         d=datetime.timedelta(days=how_many)
+                elif what == 'w':       d=datetime.timedelta(weeks=how_many)
+                elif what == 'm':       d=datetime.timedelta(weeks=4*how_many)
+                return datetime.datetime.utcnow()+d
+
     # prepare the input for the checks below by
     # casting strings ('1327098335') to ints
     if isinstance(input, StringTypes):
         try:
             input = int(input)
         except ValueError:
     # prepare the input for the checks below by
     # casting strings ('1327098335') to ints
     if isinstance(input, StringTypes):
         try:
             input = int(input)
         except ValueError:
-            pass
+            try:
+                new_input=handle_shorthands(input)
+                if new_input is not None: input=new_input
+            except:
+                import traceback
+                traceback.print_exc()
 
 
+    #################### here we go
     if isinstance (input, datetime.datetime):
     if isinstance (input, datetime.datetime):
-        logger.warn ("argument to utcparse already a datetime - doing nothing")
+        #logger.info ("argument to utcparse already a datetime - doing nothing")
         return input
     elif isinstance (input, StringTypes):
         t = dateutil.parser.parse(input)
         return input
     elif isinstance (input, StringTypes):
         t = dateutil.parser.parse(input)
@@ -65,9 +86,23 @@ def datetime_to_utc(input):
 def datetime_to_epoch(input):
     return int(time.mktime(input.timetuple()))
 
 def datetime_to_epoch(input):
     return int(time.mktime(input.timetuple()))
 
-def adjust_datetime(input, days=0, hours=0, minutes=0, seconds=0):
+def add_datetime(input, days=0, hours=0, minutes=0, seconds=0):
     """
     Adjust the input date by the specified delta (in seconds).
     """
     dt = utcparse(input)
     return dt + datetime.timedelta(days=days, hours=hours, minutes=minutes, seconds=seconds)
     """
     Adjust the input date by the specified delta (in seconds).
     """
     dt = utcparse(input)
     return dt + datetime.timedelta(days=days, hours=hours, minutes=minutes, seconds=seconds)
+
+if __name__ == '__main__':
+    for input in [
+            '+2d',
+            '+3w',
+            '+2m',
+            1401282977.575632,
+            1401282977,
+            '1401282977',
+            '2014-05-28',
+            '2014-05-28T15:18',
+            '2014-05-28T15:18:30',
+    ]:
+        print "input=%20s -> parsed %s"%(input,datetime_to_string(utcparse(input)))