Globus Timers Operations¶
These examples demonstrate how to create, list, and delete Timers with the SDK.
Create a timer¶
This script creates a new timer, on source and destination collections provided via the command-line. It syncs an input file or directory between the two.
Note
This example does not handle data_access
scope requirements.
See the later example to handle this.
#!/usr/bin/env python
import argparse
import datetime
import globus_sdk
# tutorial client ID
# we recommend replacing this with your own client for any production use-cases
CLIENT_ID = "61338d24-54d5-408f-a10d-66c06b59f6d2"
NATIVE_CLIENT = globus_sdk.NativeAppAuthClient(CLIENT_ID)
def do_login_flow():
# we will want to request a 'timer' scope for managing timers
scope = globus_sdk.TimersClient.scopes.timer
# run the login flow, finishing with a token exchange
NATIVE_CLIENT.oauth2_start_flow(requested_scopes=scope)
authorize_url = NATIVE_CLIENT.oauth2_get_authorize_url()
print(f"Please go to this URL and login:\n\n{authorize_url}\n")
auth_code = input("Please enter the code here: ").strip()
tokens = NATIVE_CLIENT.oauth2_exchange_code_for_tokens(auth_code)
# pull out the tokens for Globus Timers from the response
return tokens.by_resource_server[globus_sdk.TimersClient.resource_server]
def create_timers_client():
tokens = do_login_flow()
return globus_sdk.TimersClient(
authorizer=globus_sdk.AccessTokenAuthorizer(tokens["access_token"])
)
def main():
parser = argparse.ArgumentParser()
# the source, destination, and path to a file or dir to sync
parser.add_argument("SOURCE_COLLECTION")
parser.add_argument("DESTINATION_COLLECTION")
parser.add_argument("PATH")
parser.add_argument(
"--interval-seconds",
help="How frequently the timer runs, in seconds (default: 1 hour)",
default=3600,
type=int,
)
parser.add_argument(
"--days",
help="How many days to run the timer (default: 2)",
default=2,
type=int,
)
args = parser.parse_args()
client = create_timers_client()
body = globus_sdk.TransferData(
source_endpoint=args.SOURCE_COLLECTION,
destination_endpoint=args.DESTINATION_COLLECTION,
)
body.add_item(args.PATH, args.PATH)
# the timer will run until the end date, on whatever interval was requested
schedule = globus_sdk.RecurringTimerSchedule(
interval_seconds=args.interval_seconds,
end={
"condition": "time",
"datetime": datetime.datetime.now() + datetime.timedelta(days=args.days),
},
)
timer = client.create_timer(
timer=globus_sdk.TransferTimer(
name=(
"create-timer-example "
f"[created at {datetime.datetime.now().isoformat()}]"
),
body=body,
schedule=schedule,
)
)
print("Finished submitting timer.")
print(f"timer_id: {timer['timer']['job_id']}")
if __name__ == "__main__":
main()
Delete a timer¶
This script creates a new timer, on source and destination collections provided via the command-line. It syncs an input file or directory between the two.
#!/usr/bin/env python
import argparse
import globus_sdk
# tutorial client ID
# we recommend replacing this with your own client for any production use-cases
CLIENT_ID = "61338d24-54d5-408f-a10d-66c06b59f6d2"
NATIVE_CLIENT = globus_sdk.NativeAppAuthClient(CLIENT_ID)
def do_login_flow():
# we will want to request a 'timer' scope for managing timers
scope = globus_sdk.TimersClient.scopes.timer
# run the login flow, finishing with a token exchange
NATIVE_CLIENT.oauth2_start_flow(requested_scopes=scope)
authorize_url = NATIVE_CLIENT.oauth2_get_authorize_url()
print(f"Please go to this URL and login:\n\n{authorize_url}\n")
auth_code = input("Please enter the code here: ").strip()
tokens = NATIVE_CLIENT.oauth2_exchange_code_for_tokens(auth_code)
# pull out the tokens for Globus Timers from the response
return tokens.by_resource_server[globus_sdk.TimersClient.resource_server]
def create_timers_client():
tokens = do_login_flow()
return globus_sdk.TimersClient(
authorizer=globus_sdk.AccessTokenAuthorizer(tokens["access_token"])
)
def main():
parser = argparse.ArgumentParser()
parser.add_argument("TIMER_ID")
args = parser.parse_args()
client = create_timers_client()
client.delete_timer(args.TIMER_ID)
print("Finished deleting timer.")
if __name__ == "__main__":
main()
Create a timer with data_access
¶
This script is similar to the create_timer.py
example above. However, it
also handles data_access
scope requirements for the source and destination
collections.
Discovering data_access
requirements requires the use of a
TransferClient
to look up the collections. Therefore, this example may put
the user through two login flows.
As in the simpler example, this script creates a new timer, on source and destination collections provided via the command-line. It syncs an input file or directory between the two.
#!/usr/bin/env python
import argparse
import datetime
import globus_sdk
# tutorial client ID
# we recommend replacing this with your own client for any production use-cases
CLIENT_ID = "61338d24-54d5-408f-a10d-66c06b59f6d2"
NATIVE_CLIENT = globus_sdk.NativeAppAuthClient(CLIENT_ID)
def uses_data_access(transfer_client, collection_id):
doc = transfer_client.get_endpoint(collection_id)
if doc["entity_type"] != "GCSv5_mapped_collection":
return False
if doc["high_assurance"]:
return False
return True
def get_data_access_scopes(transfer_client, collection_ids):
data_access_scopes = []
for collection_id in collection_ids:
if uses_data_access(transfer_client, collection_id):
data_access_scopes.append(
globus_sdk.GCSClient.get_gcs_collection_scopes(
collection_id
).data_access
)
return data_access_scopes
def do_login_flow(data_access_scopes=None):
# we will want to request a 'timer' scope for managing timers
# and a 'transfer:all' scope for inspecting collections
#
# if there are data_access scopes to request, we'll need to 'enhance' the Timers
# scope to be shaped like this:
#
# timers_scope ->
# transfer_scope ->
# data_access1
# data_access2
#
# this scope structure encodes permission for Timers to use Transfer on the
# target collections
timer_scope = globus_sdk.TimersClient.scopes.timer
if data_access_scopes:
transfer_scope = globus_sdk.Scope(globus_sdk.TransferClient.scopes.all)
for da_scope in data_access_scopes:
transfer_scope.add_dependency(da_scope)
timer_scope = globus_sdk.Scope(globus_sdk.TimersClient.scopes.timer)
timer_scope.add_dependency(transfer_scope)
scopes = [
timer_scope,
globus_sdk.TransferClient.scopes.all,
]
# run the login flow, finishing with a token exchange
NATIVE_CLIENT.oauth2_start_flow(requested_scopes=scopes)
authorize_url = NATIVE_CLIENT.oauth2_get_authorize_url()
print(f"Please go to this URL and login:\n\n{authorize_url}\n")
auth_code = input("Please enter the code here: ").strip()
tokens = NATIVE_CLIENT.oauth2_exchange_code_for_tokens(auth_code)
# return Transfer and Timers tokens
return tokens.by_resource_server
def create_clients(data_access_scopes=None):
tokens = do_login_flow(data_access_scopes=data_access_scopes)
timers_tokens = tokens[globus_sdk.TimersClient.resource_server]
transfer_tokens = tokens[globus_sdk.TransferClient.resource_server]
timers_client = globus_sdk.TimersClient(
authorizer=globus_sdk.AccessTokenAuthorizer(timers_tokens["access_token"])
)
transfer_client = globus_sdk.TransferClient(
authorizer=globus_sdk.AccessTokenAuthorizer(transfer_tokens["access_token"])
)
return timers_client, transfer_client
def main():
parser = argparse.ArgumentParser()
# the source, destination, and path to a file or dir to sync
parser.add_argument("SOURCE_COLLECTION")
parser.add_argument("DESTINATION_COLLECTION")
parser.add_argument("PATH")
parser.add_argument(
"--interval-seconds",
help="How frequently the timer runs, in seconds (default: 1 hour)",
default=3600,
type=int,
)
parser.add_argument(
"--days",
help="How many days to run the timer (default: 2)",
default=2,
type=int,
)
args = parser.parse_args()
# login and get relevant clients, but also check if we need to re-login for
# data_access and potentially replace the timers_client as a result
timers_client, transfer_client = create_clients()
data_access_scopes = get_data_access_scopes(
transfer_client, [args.SOURCE_COLLECTION, args.DESTINATION_COLLECTION]
)
if data_access_scopes:
timers_client, _ = create_clients(data_access_scopes=data_access_scopes)
# from this point onwards, the example is the same as the basic create_timer.py
# script -- we've handled the nuance of data_access
body = globus_sdk.TransferData(
source_endpoint=args.SOURCE_COLLECTION,
destination_endpoint=args.DESTINATION_COLLECTION,
)
body.add_item(args.PATH, args.PATH)
# the timer will run until the end date, on whatever interval was requested
schedule = globus_sdk.RecurringTimerSchedule(
interval_seconds=args.interval_seconds,
end={
"condition": "time",
"datetime": datetime.datetime.now() + datetime.timedelta(days=args.days),
},
)
timer = timers_client.create_timer(
timer=globus_sdk.TransferTimer(
name=(
"create-timer-example "
f"[created at {datetime.datetime.now().isoformat()}]"
),
body=body,
schedule=schedule,
)
)
print("Finished submitting timer.")
print(f"timer_id: {timer['timer']['job_id']}")
if __name__ == "__main__":
main()