def logout(): """Log out and revoke your tokens.""" print("Logging out and revoking tokens") # Messing with the tokens outside of the CfdeClient seems like an error-prone idea. # However, we don't have a Client instantiated here to log out with. # So, we're going to attempt to create one. try: # We'll suppress stdout, so the user isn't actually prompted to log in, # and prepare an invalid prompt response in stdin. old_stdin = sys.stdin new_stdin = StringIO("\n") sys.stdin = new_stdin # If the auth flow fires, it will read the invalid response and raise an exception, # which indicates that there are no valid existing tokens, # so the user is already logged out. old_stdout = sys.stdout with open(os.devnull, 'w') as new_stdout: sys.stdout = new_stdout client = CfdeClient(no_browser=True) # Otherwise, if the Client initializes without an auth step, we must actually logout. client.logout() except Exception as e: # If this is an invalid grant error, there are no valid existing tokens, # so we can eat the exception if len(e.args) >= 3 and e.args[2] == "invalid_grant": pass # Else, the exception was unexpected else: raise finally: sys.stdout = old_stdout sys.stdin = old_stdin print("You are logged out.")
def status(flow_id, flow_instance_id, raw, client_state_file): """Check the status of a Flow.""" if not flow_id or not flow_instance_id: if not client_state_file: client_state_file = DEFAULT_STATE_FILE try: with open(client_state_file) as f: client_state = json.load(f) flow_id = flow_id or client_state.get("flow_id") flow_instance_id = flow_instance_id or client_state.get( "flow_instance_id") service_instance = client_state.get("service_instance") if not flow_id or not flow_instance_id: raise ValueError("flow_id or flow_instance_id not found") except (FileNotFoundError, ValueError): print( "Flow not started and flow-id or flow-instance-id not specified" ) return try: cfde = CfdeClient(service_instance=service_instance) status_res = cfde.check_status(flow_id, flow_instance_id, raw=True) except Exception as e: if raw: err = repr(e) else: err = str(e) print("Error checking status for Flow '{}': {}".format( flow_instance_id, err)) return else: if raw: print(json.dumps(status_res, indent=4, sort_keys=True)) else: print(status_res["clean_status"])
def login(force_login, no_browser): """Perform the login step (which saves credentials) by initializing a CfdeClient. The Client is then discarded. """ print("Starting login check") CfdeClient(no_browser=no_browser, force=force_login) print("You are authenticated and your tokens have been cached.")
def run(data_path, author_email, catalog, schema, acl_file, output_dir, delete_dir, ignore_git, dry_run, verbose, force_login, no_browser, server, force_http, bag_kwargs_file, client_state_file, service_instance): """Start the Globus Automate Flow to ingest CFDE data into DERIVA.""" # Get any saved parameters if not client_state_file: client_state_file = DEFAULT_STATE_FILE try: with open(client_state_file) as f: state = json.load(f) if verbose: print("Loaded previous state") except FileNotFoundError: state = {} if verbose: print("No previous state found") # Read bag_kwargs_file if provided if bag_kwargs_file: with open(bag_kwargs_file) as f: bag_kwargs = json.load(f) else: bag_kwargs = {} # Read acl_file if provided if acl_file: with open(acl_file) as f: dataset_acls = json.load(f) else: dataset_acls = None # Determine author_email to use if verbose: print("Determining author email") # If user supplies email as option, will always use that as author_email state_email = state.get("author_email") # If supplied email is different from previously saved email, prompt to save # Do not prompt if user has not saved email - user may not want to save email if author_email is not None and state_email is not None and state_email != author_email: if verbose: print("Saved email mismatch with provided email") # author_email = author_email save_email = (input( "Would you like to save '{}' as your default email (" "instead of '{}')? y/n: ".format(author_email, state_email)).strip().lower() in ["y", "yes"]) elif author_email is None and state_email is not None: author_email = state_email save_email = False print("Using saved email '{}'".format(author_email)) elif author_email is None and state_email is None: if verbose: print("No saved email found and no email provided") author_email = input( "Please enter your email address for curation and updates: " ).strip() save_email = input( "Thank you. Would you like to save '{}' for future submissions? " "y/n: ".format(author_email)).strip().lower() in ["y", "yes"] # Save email in state if requested if save_email: state["author_email"] = author_email if verbose: print( "Email '{}' will be saved if the Flow initialization is successful " "and this is not a dry run".format(author_email)) try: if verbose: print("Initializing Flow") cfde = CfdeClient(no_browser=no_browser, force=force_login, service_instance=service_instance) if verbose: print("CfdeClient initialized, starting Flow") start_res = cfde.start_deriva_flow(data_path, author_email, catalog_id=catalog, schema=schema, dataset_acls=dataset_acls, output_dir=output_dir, delete_dir=delete_dir, handle_git_repos=(not ignore_git), server=server, dry_run=dry_run, verbose=verbose, force_http=force_http, **bag_kwargs) except Exception as e: print("Error while starting Flow: {}".format(repr(e))) return else: if not start_res["success"]: print("Error during Flow startup: {}".format(start_res["error"])) else: print(start_res["message"]) if not dry_run: dest_path = start_res["fair_re_dest_path"] dir_path = os.path.dirname(dest_path) filename = os.path.basename(dest_path) http_link = "{}{}".format(CONFIG["EP_URL"], dest_path) globus_web_link = ( "https://app.globus.org/file-manager?origin_id={}" "&origin_path={}".format(CONFIG["EP_UUID"], dir_path)) state["service_instance"] = service_instance state["flow_id"] = start_res["flow_id"] state["flow_instance_id"] = start_res["flow_instance_id"] state["http_link"] = http_link state["globus_web_link"] = globus_web_link with open(client_state_file, 'w') as out: json.dump(state, out) if verbose: print("State saved to '{}'".format(client_state_file)) print( "\nThe BDBag with your data is named '{}', and is available through Globus " "here:\n{}\n".format(filename, globus_web_link)) print( "You BDBag is also available via direct HTTP download here:\n{}" .format(http_link))
def run(data_path, dcc_id, catalog, schema, acl_file, output_dir, delete_dir, ignore_git, dry_run, test_submission, verbose, force_login, no_browser, server, force_http, bag_kwargs_file, client_state_file, service_instance): """Start the Globus Automate Flow to ingest CFDE data into DERIVA.""" # Get any saved parameters if not client_state_file: client_state_file = DEFAULT_STATE_FILE try: with open(client_state_file) as f: state = json.load(f) if verbose: print("Loaded previous state") except FileNotFoundError: state = {} if verbose: print("No previous state found") # Read bag_kwargs_file if provided if bag_kwargs_file: with open(bag_kwargs_file) as f: bag_kwargs = json.load(f) else: bag_kwargs = {} # Read acl_file if provided if acl_file: with open(acl_file) as f: dataset_acls = json.load(f) else: dataset_acls = None # Determine DCC ID to use if verbose: print("Determining DCC") # If user supplies DCC as option, will always use that # If supplied DCC is different from previously saved DCC, prompt to save, # unless user has not saved DCC or disabled the save prompt state_dcc = state.get("dcc_id") never_save = state.get("never_save") if not never_save and dcc_id is not None and state_dcc is not None and state_dcc != dcc_id: if verbose: print("Saved DCC '{}' mismatch with provided DCC '{}'".format(state_dcc, dcc_id)) save_dcc = (input("Would you like to save '{}' as your default DCC ID (" "instead of '{}')? y/n: ".format(dcc_id, state_dcc)) .strip().lower() in ["y", "yes"]) if not save_dcc: if (input("Would you like to disable this prompt permanently? y/n:").strip().lower() in ["y", "yes"]): state["never_save_dcc"] = True elif dcc_id is None and state_dcc is not None: dcc_id = state_dcc save_dcc = False print("Using saved DCC '{}'".format(dcc_id)) elif dcc_id is None and state_dcc is None: if verbose: print("No saved DCC ID found and no DCC provided") dcc_id = input("Please enter the CFDE identifier for your " "Data Coordinating Center: ").strip() save_dcc = input("Thank you. Would you like to save '{}' for future submissions? " "y/n: ".format(dcc_id)).strip().lower() in ["y", "yes"] # Save DCC ID in state if requested if save_dcc: state["dcc_id"] = dcc_id if verbose: print("DCC ID '{}' will be saved if the Flow initialization is successful " "and this is not a dry run" .format(dcc_id)) try: if verbose: print("Initializing Flow") cfde = CfdeClient(no_browser=no_browser, force=force_login, service_instance=service_instance) if verbose: print("CfdeClient initialized, starting Flow") start_res = cfde.start_deriva_flow(data_path, dcc_id=dcc_id, catalog_id=catalog, schema=schema, dataset_acls=dataset_acls, output_dir=output_dir, delete_dir=delete_dir, handle_git_repos=(not ignore_git), server=server, dry_run=dry_run, test_sub=test_submission, verbose=verbose, force_http=force_http, **bag_kwargs) except Exception as e: print("Error while starting Flow: {}".format(repr(e))) return else: if not start_res["success"]: print("Error during Flow startup: {}".format(start_res["error"])) else: print(start_res["message"]) if not dry_run: state["service_instance"] = service_instance state["flow_id"] = start_res["flow_id"] state["flow_instance_id"] = start_res["flow_instance_id"] state["http_link"] = start_res["http_link"] state["globus_web_link"] = start_res["globus_web_link"] with open(client_state_file, 'w') as out: json.dump(state, out) if verbose: print("State saved to '{}'".format(client_state_file)) filename = os.path.basename(start_res["cfde_dest_path"]) print("\nThe BDBag with your data is named '{}', and will be available through " "Globus here:\n{}\n".format(filename, state["globus_web_link"])) print("You BDBag will also be available via direct HTTP download here:\n{}" .format(state["http_link"]))