2424from . import __version__
2525from .helpers import cloud_credential_printer as printer
2626from .helpers .cache import Cache
27+ from .helpers .checkout_lock import CheckoutLock
2728from .helpers .config import ConfigManager
2829from .helpers .credentials import EncryptedFileCredentialManager , FileCredentialManager
2930from .helpers .split import profile_split
@@ -792,6 +793,17 @@ def _checkout(
792793 }
793794 raise e
794795
796+ def _check_cache (self , passphrase : Optional [str ], profile_name : str , mode : str ) -> Optional [dict ]:
797+ credentials = Cache (passphrase = passphrase ).get_credentials (profile_name = profile_name , mode = mode )
798+ if credentials :
799+ expiration_timestamp_str = jmespath .search (
800+ expression = self .cachable_modes [mode ]['expiration_jmespath' ], data = credentials
801+ ).replace ('Z' , '' )
802+ expires = datetime .fromisoformat (expiration_timestamp_str )
803+ if datetime .utcnow () < expires :
804+ return credentials
805+ return None
806+
795807 @staticmethod
796808 def _should_check_force_renew (app , force_renew , console ):
797809 return app in ['AWS' , 'AWS Standalone' ] and force_renew and not console
@@ -903,25 +915,14 @@ def _access_checkout(
903915 self ._validate_justification (justification )
904916
905917 if mode in self .cachable_modes :
906- self .silent = True # CANNOT output anything other than the expected JSON
907- # we need to check the cache for the credentials first and then check to see if they are expired
908- # if not simply return those credentials, if they are expired, continue to do an actual checkout
918+ self .silent = True
909919 app_type = self .cachable_modes [mode ]['app_type' ]
910- credentials = Cache ( passphrase = passphrase ). get_credentials ( profile_name = alias or profile , mode = mode )
920+ credentials = self . _check_cache ( passphrase , alias or profile , mode )
911921 if credentials :
912- expiration_timestamp_str = jmespath .search (
913- expression = self .cachable_modes [mode ]['expiration_jmespath' ], data = credentials
914- ).replace ('Z' , '' )
915- expires = datetime .fromisoformat (expiration_timestamp_str )
916- now = datetime .utcnow ()
917- if now >= expires : # check to ensure the credentials are still valid, if not, set to None and get new
918- credentials = None
919- else :
920- cached_credentials_found = True
922+ cached_credentials_found = True
921923
922924 parts = self ._split_profile_into_parts (profile )
923925
924- # create this params once so we can use it multiple places
925926 params = {
926927 'app_name' : parts ['app' ],
927928 'blocktime' : blocktime ,
@@ -936,30 +937,41 @@ def _access_checkout(
936937 'ticket_type' : ticket_type ,
937938 }
938939
939- if not cached_credentials_found : # nothing found in cache, cache is expired, or not a cachable mode
940- response = self ._checkout (** params )
941- app_type = self ._get_app_type (response ['appContainerId' ])
942- credentials = response ['credentials' ]
943- console_fallback = response .get ('console-fallback' )
940+ if not cached_credentials_found :
941+ if mode in self .cachable_modes :
942+ with CheckoutLock (profile_key = alias or profile , mode = mode ):
943+ credentials = self ._check_cache (passphrase , alias or profile , mode )
944+ if credentials :
945+ cached_credentials_found = True
946+ else :
947+ response = self ._checkout (** params )
948+ app_type = self ._get_app_type (response ['appContainerId' ])
949+ credentials = response ['credentials' ]
950+ console_fallback = response .get ('console-fallback' )
951+ Cache (passphrase = passphrase ).save_credentials (
952+ profile_name = alias or profile , credentials = credentials , mode = mode
953+ )
954+ else :
955+ response = self ._checkout (** params )
956+ app_type = self ._get_app_type (response ['appContainerId' ])
957+ credentials = response ['credentials' ]
958+ console_fallback = response .get ('console-fallback' )
944959
945- # this handles the --force-renew flag
946- # lets check to see if we should checkin this profile first and check it out again
947960 if self ._should_check_force_renew (app_type , force_renew , console ):
948961 expiration = datetime .fromisoformat (credentials ['expirationTime' ].replace ('Z' , '' ))
949962 now = datetime .utcnow ()
950963 diff = (expiration - now ).total_seconds () / 60.0
951- if diff < force_renew : # time to checkin the profile so we can refresh creds
964+ if diff < force_renew :
952965 self .print ('checking in the profile to get renewed credentials....standby' )
953966 self .checkin (profile = profile , console = console )
954967 response = self ._checkout (** params )
955- cached_credentials_found = False # need to write new creds to cache
956968 credentials = response ['credentials' ]
957969 console_fallback = response .get ('console-fallback' )
970+ if mode in self .cachable_modes :
971+ Cache (passphrase = passphrase ).save_credentials (
972+ profile_name = alias or profile , credentials = credentials , mode = mode
973+ )
958974
959- if mode in self .cachable_modes and not cached_credentials_found :
960- Cache (passphrase = passphrase ).save_credentials (
961- profile_name = alias or profile , credentials = credentials , mode = mode
962- )
963975 return app_type , console_fallback , credentials , k8s_processor
964976
965977 def checkout (
0 commit comments