From ad5d5b8c6d235ffe5c516c15cccd2d1757497ff7 Mon Sep 17 00:00:00 2001 From: JinnyChien Date: Mon, 22 Oct 2018 12:03:53 +0100 Subject: [PATCH 1/2] new file: .gitattributes new file: LICENSE new file: README.md new file: rdsds_server/image/RDSDS_Workflow.jpg new file: rdsds_server/image/SSO.png new file: rdsds_server/image/SSO_1.png new file: rdsds_server/psql/__init__.py new file: rdsds_server/psql/create_tbls.sql new file: rdsds_server/psql/database.ini new file: rdsds_server/psql/dump_all.sql new file: rdsds_server/rdsds/__init__.py new file: rdsds_server/rdsds/connect.py new file: rdsds_server/rdsds/db_config.py new file: rdsds_server/rdsds/db_manage.py new file: rdsds_server/rdsds/dsds_rest_service.py new file: rdsds_server/rdsds/fts3.py new file: rdsds_server/rdsds/rdsds_email.py new file: rdsds_server/rdsds/transfer.py --- .gitattributes | 3 + LICENSE | 201 +++ README.md | 236 ++++ rdsds_server/image/RDSDS_Workflow.jpg | Bin 0 -> 74933 bytes rdsds_server/image/SSO.png | Bin 0 -> 98997 bytes rdsds_server/image/SSO_1.png | Bin 0 -> 39041 bytes rdsds_server/psql/__init__.py | 0 rdsds_server/psql/create_tbls.sql | 66 + rdsds_server/psql/database.ini | 5 + rdsds_server/psql/dump_all.sql | 392 ++++++ rdsds_server/rdsds/__init__.py | 19 + rdsds_server/rdsds/connect.py | 38 + rdsds_server/rdsds/db_config.py | 19 + rdsds_server/rdsds/db_manage.py | 737 ++++++++++ rdsds_server/rdsds/dsds_rest_service.py | 1700 +++++++++++++++++++++++ rdsds_server/rdsds/fts3.py | 135 ++ rdsds_server/rdsds/rdsds_email.py | 110 ++ rdsds_server/rdsds/transfer.py | 14 + 18 files changed, 3675 insertions(+) create mode 100755 .gitattributes create mode 100755 LICENSE create mode 100755 README.md create mode 100755 rdsds_server/image/RDSDS_Workflow.jpg create mode 100755 rdsds_server/image/SSO.png create mode 100755 rdsds_server/image/SSO_1.png create mode 100755 rdsds_server/psql/__init__.py create mode 100755 rdsds_server/psql/create_tbls.sql create mode 100755 rdsds_server/psql/database.ini create mode 100755 rdsds_server/psql/dump_all.sql create mode 100755 rdsds_server/rdsds/__init__.py create mode 100755 rdsds_server/rdsds/connect.py create mode 100755 rdsds_server/rdsds/db_config.py create mode 100755 rdsds_server/rdsds/db_manage.py create mode 100755 rdsds_server/rdsds/dsds_rest_service.py create mode 100755 rdsds_server/rdsds/fts3.py create mode 100755 rdsds_server/rdsds/rdsds_email.py create mode 100755 rdsds_server/rdsds/transfer.py diff --git a/.gitattributes b/.gitattributes new file mode 100755 index 0000000..3ab78cc --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +*.js linguist-language=python +*.css linguist-language=python +*.html linguist-language=python diff --git a/LICENSE b/LICENSE new file mode 100755 index 0000000..a770e3f --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018 European Molecular Biology Laboratory + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100755 index 0000000..0713067 --- /dev/null +++ b/README.md @@ -0,0 +1,236 @@ +# RDSDS - Reference DataSet Distribution Service + +# Introduction +The Reference Data Set Distribution Service (RDSDS) is offered as a component in the [ELIXIR Compute Platform](https://www.elixir-europe.org/platforms/compute) to distribute reference data sets from the [ELIXIR Data Platform](https://www.elixir-europe.org/platforms/data) and from individual researchers from where the data sets originate to where the data sets are to be analysed. This service holds technical metadata relating to the data stored in the Reference Data Set and the files that comprises a dataset release version. Once a release has been made, the files will be transferred to sites subscribing to releases of this Reference Data Set using existing services and file transfer protocols and services (e.g. FTS3, Globus Online and GridFTP). + +# Workflow + +![image](https://github.com/EMBL-EBI-TSI/RDSDS/blob/devel/rdsds_server/image/RDSDS_Workflow.jpg) + +# RDSDS Client +`Client Side`, RDSDS Client use ELIXIR AAI for authentication, make sure the client environment installed browser service. At the moment, RDSDS is running on ELIXIR Test environment, please be confirmed if you belong to ELIXIR Test VO (Virtual Organisation), if you can more details [here](https://perun.elixir-czech.cz/fed/registrar//registrar/?vo=elixir_test). + +Currently support 'Windows 10 Pro', 'Centos 7', 'Fedora 28', 'Ubuntu' and 'Mac OS' + +# RDSDS Server +`Server Side` requirements are Python 2.7, Flask 0.11.1, Postgres >= 9.x and SQLAlchemy + +## Setup + +Virtualenv is preferred but since python 2.7 is needed you can easily install directly. + +* Install Flask: [Installation](http://flask.pocoo.org/docs/0.12/installation/). +* Install postgresql + * [Mac OS](https://postgresapp.com/) + * [Windows & Linux](https://www.bigsql.org/postgresql/installers.jsp) +* Install Sqlalchemy: [Installation](http://pythoncentral.io/how-to-install-sqlalchemy/) + +## Setup database + +Import file dsds.sql (creates, user, db, tables, sets user password and db ownership) +```` +psql < create_tbls.sql +```` + +# RDSDS Usage + +### Data Set Registration + +***JSON template*** +```` +{ +"SourceSiteName": "EMBL-EBI", +"TransferSource": "gsiftp://dsds-gridftp1.ebi.ac.uk:2811/gridftp/100files", +"Protocol": "gridftp", +"Hostname": "dsds-gridftp1.ebi.ac.uk", +"Port": "2811", +"FilePath": "/gridftp/100files", +"CreatorName": "Jinny Chien", +"CreatorEmail": "jinnychien@ebi.ac.uk", +"DatasetName": "marinemetagenomics" +} +```` + +***Login in with Google account*** +![image](https://github.com/EMBL-EBI-TSI/RDSDS/blob/devel/rdsds_server/image/SSO.png) +![image](https://github.com/EMBL-EBI-TSI/RDSDS/blob/devel/rdsds_server/image/SSO_1.png) +```` +(dsds>)_ +```` + +***Register single dataset*** +```` +(dsds>)reg )reg + +### Unregister a Data Set +If the data set status is not released, Data Provider can unregister it
+ +***Unregister dataset*** +```` +(dsds>)unreg -d datasetPID +```` +
+ +### Declare a file to the Data Set +After Data Provider registered and got dataset PID. Then they can add file definition does not verify existence. This action does not check remote file’s existence.
+ +***JSON template*** +```` +{ +“FileName”: “/ERR268/ERR268106/ERR268106.fastq.gz”, +“DatasetPID”: “embl-ebi-20161117-23456” +} +```` + +***declare to add a single file/multiple files to the dataset*** +```` +(dsds>)declare )declare + +### Index a file/folder to the Data Set +After Data Provider registered and got dataset PID. Then they can add a file or folder (recursive) and verify files existence (remote sites).
+ +***Index to add a file/folder to the dataset*** +```` +(dsds>)index -d datasetPID +```` + +***Index a nominated folder to the dataset*** +```` +(dsds>)index -d datasetPID -f foldername +```` +
+ +### List details of the Data Set or Subscriber +This command will perform the file list of the specific dataset PID or list the subscribered dataset PID or the details of the specific dataset PID
+ +***List files of the dataset*** +```` +(dsds>)list -d datasetPID +```` + +***List different version files of the dataset*** +```` +(dsds>)list -d datasetPID -v releaseversion +```` + +***List active subscribed datasetPID*** +```` +(dsds>)list -u username +```` + +***Show detail of subscribed datasetPID*** +```` +(dsds>)list -u username -d datasetPID +```` +
+ +### Verify the Data Set +Data Provider can verify that the defined dataset is available to be released and check the integrity
+ +***Verify file existence before dataset releases*** +```` +(dsds>)verify -d datasetPID +```` + +***Verify integrity checking after releasing*** +```` +(dsds>)verify -d datasetPID -v release_version +```` +
+ +### Compare the difference +Data consumer search different version files of dataset to get the transfer list and perform the data transfer
+ +***Find difference between release versions*** +```` +(dsds>)diff -d datasetPID -f release_version -t release_version +```` +
+ +### Release the Data Set +When data set is released, data transfer will be performed in backgrpund
+ +***Release the dataset and subscribers will get the notification when the registered dataset updates*** +```` +(dsds>)release -d datasetPID -v release_version +```` + +
+ +### Delete the file +Data Provider can delete one file from a dataset that they have not released yet. If the dataset is released, there will be a warning reminder
+ +***Delete a single file of the dataset*** +```` +(dsds>)delete -d datasetPID -f filename +```` +
+ +### Subscription +Data consumer subscribes which data set he/she wants, then they will get the Emial notification on every release and data transfer will be run in background.
+ +***Add subscriber JSON template*** +```` +{ +"FullName": "Kevin EBI", +"Username": "Kevin", +"Email": "jinnychien@ebi.ac.uk", +"Organisation": "EMBL-EBI", +"Hostname": "hx-gridftp-test.ebi.ac.uk", +"Port": "2811", +"FilePath": "/data01/test/test_folder/" +} +```` + +***Add subscriber*** +```` +(dsds>)adduser )deluser -u username +```` + +***Activate subscriber*** +```` +(dsds>)activate -u username +```` + +***Subscribe users and datasetPID*** +```` +(dsds>)sub -u username -d datasetPID +```` + +***Unsubscribe users and datasetPID*** +```` +(dsds>)unsub -u username -d datasetPID +```` +
+ +### Show all command lines information +Display all available command list and its description to help Data Provider to choose.
+ +***Show all useful comment line information*** +```` +(dsds>)help +```` +***Show help for specific command*** +```` +(dsds>)help +```` diff --git a/rdsds_server/image/RDSDS_Workflow.jpg b/rdsds_server/image/RDSDS_Workflow.jpg new file mode 100755 index 0000000000000000000000000000000000000000..b169a2d7e9ffc04b8f2dd7cea73816db380daec3 GIT binary patch literal 74933 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 F{{gg-sJ8$B literal 0 HcmV?d00001 diff --git a/rdsds_server/image/SSO.png b/rdsds_server/image/SSO.png new file mode 100755 index 0000000000000000000000000000000000000000..ef6fbd447e48ecc8ef50ee589eae1a51b4673f3d GIT binary patch literal 98997 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⪼2QBi63yP^HaaLu6i{rF00f-;?P%f$x@C_?OC# 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π%K`A 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 X^K}gCf%A*ppaUL5Ju_Xr&NbxUKU&5+ literal 0 HcmV?d00001 diff --git a/rdsds_server/image/SSO_1.png b/rdsds_server/image/SSO_1.png new file mode 100755 index 0000000000000000000000000000000000000000..400cf0cc56ee3ae5a330768cf675318f68646691 GIT binary patch literal 39041 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', 401, {'WWWAuthenticate': 'Basic realm="Login Required"'}) + + +#login decorator function +def login_required(f): + @wraps(f) + def decorated_function(*args, **kwargs): + try: + token = request.headers['token'] # fetch the user authorized token from the client +# logging.info(token) +# logging.info("fetched token from decorated @login") + authorized_user_list = crud(token, '', "get_session", '') + #checks whether a valid session exists in session table with proposed token + if authorized_user_list: + authorized_user = authorized_user_list[0][0] + else: + abort(401) + except NameError: + logging.error('user not authorized for this resource') + abort(401) + return f(*args, **kwargs) + return decorated_function + +# internal functions used by endpoint functions + +def delete_files(): + try: + dpid = request.form['dpid'] + filepath = request.form['filepath'] + file_id = crud('', dpid, "file_id", filepath) + dataset_last_version = crud('', dpid, "dataset_get_last_version", '') + dataset_version_int = dataset_last_version[0][0] + dataset_working_version = dataset_version_int + 1 + if file_id: + for name in file_id: + file_id = name[0] + delete_file = crud(dataset_working_version, dpid, "delete_file", file_id) + return delete_file + else: + logging.warning('[Delete Files] There is no File_id!! This file does not exist!!') + except: + logging.warning('[Delete Files] There is no datasetPID or FilePath') + + +def dataset_status_check(dpid): + +# Check dataset status and return the result to the client side let users choose to delete or not + dataset_status = crud('', dpid, "dataset_status", '') + for status in dataset_status: + status_result = status[0] + return status_result + +def list_dataset(dpid, version): + + if version == 'none': + dataset_last_version = crud('', dpid, "get_dataset_last_version", '') + dataset_version_int = dataset_last_version[0][0] + current_working_dataset = dataset_version_int + 1 + serv_message = crud(current_working_dataset, dpid, "list_dataset", '') + else: + dataset_version_int = version + serv_message = crud(dataset_version_int, dpid, "list_dataset", '') + return serv_message + +def verify_file(dpid): + + # Get file information from local DB + client_response = [] + DBfile_name_dic = sorted(DBfile_check(dpid)) + + # Get file information from remote site + file_exists_dic = sorted(fremotefile_exist_check(dpid)) + # Compare if remote files are the same in local DB + # Remote Site -> Local DB + for n in file_exists_dic: + if n in DBfile_name_dic: + client_response.append("Filename and Timestamp are matched on Remote Site") + else: + message = checksum_check(dpid, n[0]) + client_response.append('[WARNING], ' + n[0] + ' does not exist in remote site or File/Timestamp changes, will continue checking file checksum') + logging.error(message) + logging.error(' %s does not exist in remote site or File/Timestamp changes, will continue checking file checksum', n[0]) + client_response.append('\n'+message) + +# # Compare if local DB files are the same in remote site + # Local DB -> Remote Site + for m in DBfile_name_dic: + if m in file_exists_dic: + client_response.append("Filename and Timestamp are matched on Local DB") + else: + message = checksum_check(dpid, m[0]) + client_response.append('[WARNING], ' + m[0] + ' does not exist in local DB or File/Timestamp changes, will continue checking file checksum') + logging.error(message) + logging.error(' %s does not exist in local DB or File/Timestamp changes, will continue checking file checksum', m[0]) + client_response.append('\n' + message) + response = '\n'.join(map(str, client_response)) + return response + +def check_proxy_cert(): + ## We cannot use /tmp because http as a system user does not read from /tmp + if os.path.islink("/var/www/files/proxy.crt"): + logging.info('/var/www/files/proxy.crt exists and continue checking the details') + grid_proxy_cmd = """grid-proxy-info -debug -f /var/www/files/x509up_u1000""" + status, proxy_output = commands.getstatusoutput(grid_proxy_cmd) + available_time = proxy_output.split()[-1] + error_message = proxy_output.split()[0] + if "0:00:00" in available_time: + logging.warning('Proxy certificate is not available') + return False + elif "ERROR" in available_time: + logging.warning('Proxy certificate is not available') + return False + elif "ERROR" in error_message: + logging.warning('Proxy certificate is not available') + return False + else: + return True + else: + logging.warning('Proxy certificate missing. Please check grid-proxy-info') + return False + +def diff(dpid, v1, v2): + + server_message = crud(v1, dpid, "diff_db_version", v2) + return server_message + +def get_subscription(): + + subs_list = crud('', '', "get_subs", '') + return subs_list + +def data_transfer(dpid, diff_list, subscriber_email): + + # Create a host_trans_temp with the source hostname and destination hostname + # Create a gridftp_trans_file_temp with the file names + # Perform globus-url-copy command line (Gridftp) + # Remove two files after the transfer is done + + updatetime = time.strftime("%a %b %d %H:%M:%S %Y", time.localtime()) + logging.info('Tansfer time is %s', updatetime) + + file_path = crud('', dpid, "file_location", '') + filelist = [] + sourcelist = [] + for row in file_path: + hostname = row[2] + + subscriptions = get_subscription() + for row in subscriptions: + subscriber_dataset = row[1] + if subscriber_dataset == dpid: + subs_hostname_list = crud('', dpid, "get_subs_host", '') + for host in subs_hostname_list: + destination_list = host[0] + folder_path = host[1] + sourcelist.append('@source'+'\n'+hostname+'\n'+'@destination'+'\n'+destination_list) + + host_trans_temp = tempfile.NamedTemporaryFile() + gridftp_trans_file_temp = tempfile.NamedTemporaryFile() + + host_trans_temp.writelines(sourcelist) + host_trans_temp.seek(0) + + trans_sourceurl = host_trans_temp.name + + # Create a gsiftp_file.txt with the file names + targetlist = [] + for n in diff_list: + + targetlist.append("gsiftp://" + n + " gsiftp://" + folder_path + n + n.split("/")[-1] +'\n') + + logging.info('filelist temp %s', gridftp_trans_file_temp) + logging.info('filelist file name %s :', gridftp_trans_file_temp.name) + gridftp_trans_file_temp.writelines(targetlist) + gridftp_trans_file_temp.seek(0) + + trans_destinationurl = gridftp_trans_file_temp.name + logging.info(trans_destinationurl) + + # Command line sample: time globus-url-copy -rst -p 50 -af hosts.txt -f gsiftp_file.txt + + verbose_mode = "-rst -vb -p 50 -af" + verbose_1_mode = '-cd -f' + transfer_cmd = """globus-url-copy %s %s %s %s """ % (verbose_mode, trans_sourceurl, verbose_1_mode, trans_destinationurl) + status, transfer_output = commands.getstatusoutput(transfer_cmd) + + if "error" in transfer_output: + logging.error('[ERROR] Something wrong during transfer, please check it') + logging.error(transfer_output) + logging.error("[ERROR] File Transfer is failed, please check it!!!") + email_method.fail_content(dpid, diff_list, subscriber_email) + + + elif "failed" in transfer_output: + logging.error('[ERROR] Something wrong during transfer, please check it') + logging.error(transfer_output) + logging.error("[ERROR] File Transfer is failed, please check it!!!") + email_method.fail_content(dpid, diff_list, subscriber_email) + + logging.info("File Transfer is done") + email_method.success_content(dpid, diff_list, subscriber_email) + + logging.info('Remove two files: host_trans_temp and gridftp_trans_file_temp') + endtime = time.strftime("%a %b %d %H:%M:%S %Y", time.localtime()) + logging.info('transfer end time %s', endtime) + host_trans_temp.close() + gridftp_trans_file_temp.close() + +def fts3_transfer(dpid, diff_list, subscriber_email): + + # Create a transfer_list with the source hostname and destination hostname + # Perform fts3-transfer-submit command line + # Remove transfer_list after the transfer is done + + updatetime = time.strftime("%a %b %d %H:%M:%S %Y", time.localtime()) + logging.info('transfer time %s', updatetime) + file_num = len(diff_list) + + if fts_transfer.delegate(fts3_host, proxy_path) == True: + filetransfer = fts_transfer.create_transferlist(dpid, diff_list) + status_id = fts_transfer.submit(fts3_host, proxy_path, filetransfer) + fts_query = fts_transfer.status(status_id, fts3_host, proxy_path) + result = fts_query['query_status'] + all_info = fts_query['query_info'] + + if result.count("FINISHED") == file_num: + logging.info('Finished files are the same with the expected transferred files') + logging.info("File Transfer is done") + email_method.success_content(dpid, diff_list, subscriber_email) + return True + + elif "SUBMITTED" in result: + fts_query = fts_transfer.status(status_id, fts3_host, proxy_path) + result = fts_query['query_status'] + all_info = fts_query['query_info'] + logging.info('FINISHED ITEMS ARE %s', result.count("FINISHED")) + logging.info('SUBMITTED ITEMS ARE %s', result.count("SUBMITTED")) + logging.info('FAILED ITEMS ARE %s', result.count("FAILED")) + if fts_query.count("FINISHED") == file_num: + logging.info('Finished files are the same with the expected transferred files') + logging.info("File Transfer is done") + email_method.success_content(dpid, diff_list, subscriber_email) + return True + elif "FAILED" in fts_query: + logging.error('[ERROR] Something wrong during transfer, please check it') + logging.error("[ERROR] File Transfer is failed, please check it!!!") + email_method.fail_fts_content(dpid, diff_list, subscriber_email, result, all_info) + return False + else: + logging.error('[ERROR] Something wrong during transfer, please check it') + logging.error("[ERROR] File Transfer is failed, please check it!!!") + email_method.fail_fts_content(dpid, diff_list, subscriber_email, result, all_info) + return False + + else: + logging.error('[ERROR] Something wrong during transfer, please check it') + email_method.fail_fts_content(dpid, diff_list, subscriber_email, result, all_info) + return False + else: + email_method.fail_fts_delegation(dpid, diff_list, subscriber_email) + return False + +#####REST Endpoint Functions####### + +# Endpoint for validation of auth token and creation of session if user validated +# this is the only endpoint available without a decorator @login_required, meaning it is open and can be + +@app.route('/api/v1.0/cli_auth', methods=['POST']) + +def cli_auth(): + token = request.headers['token']# fetch the user authorized token from the client + print token + endpoint = "https://login.elixir-czech.org/oidc/userinfo?access_token=" + resp = requests.get(endpoint+token) + user_data = json.loads(resp.text)# get user info from token + print "this is user data" + global user_email + user_email = user_data['email']# extract email from userinfo + print user_email + username_token = user_data['preferred_username'] + print username_token + print "this is username" + if username_token is not None: + session = crud(token, username_token, "create_session", '') + print "this is sesson" + print session + return user_email + " authenticated!" + else: + return "Unable to authenticacte user" + +@app.route('/api/v1.0/check_proxy', methods=['GET']) +@login_required +def check_proxy(): + + serv_response = check_proxy_cert() + logging.info('This is serv_response from check_proxy_cert() called from /check_proxy endpoint!') + json_response = jsonify(serv_response) + response = make_response(json_response) + response.headers['Content-Type'] = "application/json" + return response + +@app.route('/api/v1.0/dataset/verify_file', methods=['GET']) +@login_required + +def verify_files(): + + dpid = request.form['dpid'] + return_msg = [] + if check_proxy_cert() == True: + return_msg.append("Proxy Cert is valid!!!") + verified = verify_file(dpid) + return_msg.append(verified) + response = '\n'.join(map(str, return_msg)) + return response + else: + logging.warning("[WARNING] GridFTP proxy certificate is not valid.!!!") + return 'GridFTP proxy certificate is not valid.' + +@app.route('/api/v1.0/dataset/datasetpid_existence', methods=['POST']) +@login_required +def datasetpid_existence(dpid): + + datasetpid_existence = crud('', dpid, "datasetpid_existence", '') + if datasetpid_existence: + return True + else: + logging.error('Dataset PID does not exist') + return False + +@app.route('/api/v1.0/dataset/username_existence', methods=['POST']) +@login_required +def username_existence(username): + + username_existence = crud('', '', "username_existence", username) + if username_existence: + return True + else: + logging.error('Username does not exist') + return False + +@app.route('/api/v1.0/dataset/verify', methods=['GET']) +@login_required +def verify(): + + client_response = [] + client_data = request.data + logging.info(request) + dpid = request.form['dpid'] + version = request.form['version'] + + if datasetpid_existence(dpid) == True: + client_response.append('This datasetpid exists\n') + + # Will check file existence, checksum and release version + if dpid and version != 'none': + if check_proxy_cert() == True: + # Check dataset version + version_check = dataset_version_check(dpid) + if version_check == "": + client_response.append('There is no released version information in DB\n') + logging.info('There is no released version information in DB') + elif version == version_check: + client_response.append('Current released version is matched\n') + logging.info('Current released version is matched') + else: + client_response.append(('Current released version {}, version is not matched. Previous version is {}\n').format(version, version_check)) + logging.info('Current released version %s, version is not matched. Previous version is %s'.format(version, version_check)) + status = dataset_status_check(dpid) + if status == "Open": + client_response.append('Dataset Status is Open and will verify the file existence\n') + logging.info('Dataset Status is Open and will verify the file existence') + verify_file_return = verify_file(dpid) + client_response.append(verify_file_return) + + elif status == "Released": + client_response.append('Dataset status is Released and will do integrity checking\n') + logging.info('Dataset status is Released and will do integrity checking') + integrity_check_return = integrity_check(dpid) + client_response.append(integrity_check_return) + else: + client_response.append('Dataset status is not Open or Released Please check dataset status\n') + logging.info('Dataset status is not Open or Released Please check dataset status') + else: + logger.warning("[WARNING] Proxy certificate is not valid!!!") + client_response.append('GridFTP proxy certificate not found.') + client_response.append('Proxy certificate is not valid!!!') + + elif dpid and version == 'none': + if check_proxy_cert() == True: + status = dataset_status_check(dpid) + + if status == "Open": + client_response.append('Dataset status is Open and will verify the file existence\n') + logging.info('Dataset status is Open and will verify the file existence') + verify_file_return = verify_file(dpid) + client_response.append(verify_file_return) + elif status == "Released": + client_response.append('Dataset status is Released and will do integrity checking\n') + logging.info('Dataset status is Released and will do integrity checking') + integrity_check_return = integrity_check(dpid) + client_response.append(integrity_check_return) + else: + client_response.append('Dataset status is not Open or Released, please check dataset status\n') + logging.info('Dataset status is not Open or Released, please check dataset status') + else: + logger.warning("[WARNING] Proxy certificate is not valid!!!") + client_response.append('Proxy certificate is not valid!!!') + + elif version: + client_response.append('Please add DatasetPID information\n') + logging.info('Need to add DatasetPID information') + + else: + client_response.append('Please add the value\n') + logging.info('Please add the value') + + else: + client_response.append('This datasetpid does not exist\n') + logging.error('This datasetpid does not exist') + + response = '\n'.join(map(str, client_response)) + return response + + +@app.route('/api/v1.0/dataset/diff_db_version', methods=['GET']) +@login_required +def diff_db_version(): + + dpid = request.form['dpid'] + v1 = request.form['version1'] + v2 = request.form['version2'] + + diff_result = [] + if datasetpid_existence(dpid) == True: + diff_result.append('This datasetpid exists') + diff_list1 = list_dataset(dpid, v1) + diff_list2 = list_dataset(dpid, v2) + dataset_diff = difflib.Differ() + diff = dataset_diff.compare(diff_list1, diff_list2) + diff_string = '\n'.join(diff) + for line in diff_string.splitlines(): + if line.startswith("-"): + diff_result.append(line) + for line in diff_string.splitlines(): + if line.startswith("+"): + diff_result.append(line) + logging.info(sorted(diff_result)) + else: + diff_result.append('This datasetpid does not exist') + logging.error('This datasetpid does not exist') + + json_response = jsonify(diff_result) + return json_response + +@app.route('/api/v1.0/dataset/list/', methods=['GET']) +@login_required +def list(dpid): + + serv_message = [] + if datasetpid_existence(dpid) == True: + serv_message.append('This datasetpid exists') + version = request.form['version'] + if version == '0': + version = 'none' + dataset_last_version = crud('', dpid, "get_dataset_last_version", '') + dataset_version_int = dataset_last_version[0][0] + current_working_dataset = dataset_last_version[0][0] + 1 + dataset_list = list_dataset(dpid, version) + serv_message.append('Last released version is '+str(dataset_version_int)) + serv_message.append('Current working version is '+str(current_working_dataset)) + serv_message.append(dataset_list) + else: + serv_message = list_dataset(dpid, version) + else: + serv_message.append('This datasetpid does not exist') + logging.error('This datasetpid does not exist') + + json_response = jsonify(serv_message) + response = make_response(json_response) + response.headers['Content-Type'] = "application/json" + return response + + +@app.route('/api/v1.0/dataset/sub_list/', methods=['GET']) +@login_required +def sub_list(username): + + # List the subscribed datasetPID + # Status should be Active + serv_message = [] + + if username_existence(username) == True: + serv_message.append('This username exists') + sub_list = crud('', '', "sub_list", username) + serv_message.append(sub_list) + else: + serv_message.append('This username does not exist') + logging.error('%s this username does not exist', username) + + json_response = jsonify(serv_message) + response = make_response(json_response) + response.headers['Content-Type'] = "application/json" + return json_response + + +@app.route('/api/v1.0/dataset/sub_list_detail/', methods=['GET']) +@login_required +def sub_list_detail(): + + dpid = request.form['dpid'] + username = request.form['username'] + serv_message = [] + + if datasetpid_existence(dpid) == True: + serv_message.append('This datasetpid exists') + serv_message = crud('', dpid, "sub_list_detail", username) + + else: + serv_message.append('This datasetpid does not exist') + logging.error('This datasetpid does not exist') + + json_response = jsonify(serv_message) + response = make_response(json_response) + response.headers['Content-Type'] = "application/json" + return json_response + +@app.route('/api/v1.0/register_single', methods=['POST']) +@login_required +def single_register(): + if not request.json: + abort(400) + d = request.json + i = 1 + serv_message = crud(d, '', "reg_single", i) + json_response = jsonify(serv_message) + return json_response + +@app.route('/api/v1.0/register_multiple', methods=['POST']) +@login_required +def multiple_register(): + if not request.json: + abort(400) + d = request.json + final_response = [] + for i in range(len(d["Source"])): + serv_message = crud(d, '', "reg_multiple", i) + final_response.extend(serv_message) + final_response = jsonify(final_response) + return final_response + + +@app.route('/api/v1.0/unregister/', methods=['PUT']) +@login_required +def unregister(dpid): + + client_response = [] + if datasetpid_existence(dpid) == True: + client_response.append('This datasetpid exists') + + i = 1 + crud('', dpid, "unreg", i) + client_response.append(dpid + str(' succesfully unregistered')) + logging.info('%s succesfully unregistered', dpid) + + else: + client_response.append('This datasetpid does not exist') + logging.error('This datasetpid does not exist') + + response = '\n'.join(map(str, client_response)) + return response + +@app.route('/api/v1.0/dataset/add_file/', methods=['PUT']) +@login_required +def add_file(dpid): + i = 1 + if not request.json: + abort(400) + d = request.json + # add single file + if (len(d["FileName"][0]) == 1 and len(d["DatasetPID"][0]) == 1): + serv_message = crud(d, dpid, "add_file", i, d["FileName"]) + json_response = jsonify(serv_message) + get_timestamp(dpid) + + return json_response + + # add multiple files to the dataset and print on the screen + elif (len(d["FileName"][0]) != 1 and len(d["DatasetPID"][0]) == 1): + for i in d["FileName"]: + serv_message = crud(d, dpid, "add_files", i, d["FileName"]) + json_response = jsonify(serv_message) + get_timestamp(dpid) + + return json_response + + # add multiple files to multiple datasets + elif (len(d["FileName"][0]) != 1 and len(d["DatasetPID"][0]) != 1): + logging.warning('[WARNING] Multiple files to: multiple datasets are not yet supported!!') + +def fremotefile_exist_check(dpid): + + file_path = crud('', dpid, "file_location", '') + final_result = [] + + for row in file_path: + hostname = row[2] + folder = row[1] + keepalive_cmd = "-keepalive 150" + recursive_cmd = "dir -r" + cmd = """uberftp %s %s "%s %s" """ % (hostname, keepalive_cmd, recursive_cmd, folder) + status, queryfile_output = commands.getstatusoutput(cmd) + files = queryfile_output.split("\n") + pattern = '((\/.*\.)({}))'.format(suffix) + + for l in files: + result = re.search(pattern, l) + if result: + logging.info('Show remote file name and timestamp') + logging.info(result.group(1)) + timestamp = timestamp_check(result.group(1), hostname) + final_result.append((result.group(1), timestamp)) + return final_result + +def DBfile_check(dpid): + + dataset_last_version = crud('', dpid, "get_dataset_last_version", '') + dataset_version_int = dataset_last_version[0][0] + file_info = crud('', dpid, "file_info_DBfile_check", '') + + reply = [] + for file_num in file_info: + reply.append(file_num) + final_response = reply + return final_response + +def collect_file_list(filename): + + if filename in file_list: + ###This file is already on the list, don't need to add it + logging.info('This file %s is already on the list, dont need to add it', filename) + pass + else: + ###only add new file + file_list.append(filename) + return file_list + +def query_folder(folder_path): + + list_cmd = "-list" + path_cmd = folder_path + cmd = """globus-url-copy %s %s """ % (list_cmd, path_cmd) + status, queryfile_output = commands.getstatusoutput(cmd) + files = queryfile_output.split("\n") + compare_folder_or_file(files) + +def compare_folder_or_file(files): + + for query_info in files[1:]: + folder_name = query_info.replace(" ", "") + folder_path = files[0] + folder_name + ### / in the end, it means this is a folder not a file + if query_info[-1:] == "/": + query_folder(folder_path) + + elif query_info[-1:] == "": + pass + else: + result = re.search(pattern, files[0]) + if result: + filename = (result.group(1))+folder_name + collect_file_list(filename) + +def check_file_folder_path(hostname, full_path): + + recursive_cmd = "dir" + cmd = """uberftp %s "%s %s" """ % (hostname, recursive_cmd, full_path) + status, queryfile_output = commands.getstatusoutput(cmd) + + if "error" in queryfile_output: + logging.error('Folder or File path does not match') + logging.error(queryfile_output) + return False + elif "No match" in queryfile_output: + logging.error('Folder or File path does not match') + logging.error(queryfile_output) + return False + elif "500 Command failed" in queryfile_output: + logging.error('Folder or File path does not match') + logging.error(queryfile_output) + return False + elif "failed" in queryfile_output: + logging.error('Folder or File path does not match') + logging.error(queryfile_output) + return False + else: + return True + +@app.route('/api/v1.0/dataset/index_folder', methods=['POST']) +@login_required +def index_folder(): + + # Get file locations and compare if there is any foldername + dpid = request.form['dpid'] + foldername = request.form['foldername'] + final_result = [] + remotefile_list = [] + file_total = 0 + + if datasetpid_existence(dpid) == True: + final_result.append('This datasetpid exists') + + if check_proxy_cert() == True: + if foldername: + logging.info('There is a foldername %s', foldername) + # Get file path from DB + file_path = crud('', dpid, "file_location", '') + # get list of existing files in db and the last dataset version + db_files = list_dataset(dpid, 'none') + # If there is no file in DB + if not db_files: + db_files = '#' + # Query remote site information via uberftp command + add_file = '' + delete_file = '' + + for row in file_path: + hostname = row[2] + full_path = foldername + list_cmd = "-list" + gsi_cmd = "gsiftp://" + port_cmd = ":2811" + cmd = """globus-url-copy %s %s%s%s%s """ % (list_cmd, gsi_cmd, hostname, port_cmd, full_path) + + if check_file_folder_path(hostname, full_path) == True: + logging.info('File/Folder Path is Correct!!!') + status, queryfile_output = commands.getstatusoutput(cmd) + files = queryfile_output.split("\n") + + msg = '' + for l in files[1:]: + folder_name = l.replace(" ", "") + folder_path = files[0] + folder_name + ### / in the end, it means this is a folder not a file + if l[-1:] == "/": + query_folder(folder_path) + elif l[-1:] == "": + pass + else: + filename = full_path + folder_name + collect_file_list(filename) + + for single_file in file_list: + file_total += 1 + if single_file not in db_files: + # import file names to DB + logging.info('%s this file does not exist in DB, will add it', single_file) + add_file = single_file + if single_file in db_files: + msg = single_file, "File is already in Database !!!" + final_result.extend(msg) + msg = '' + + if add_file: + # add file only if file not already deleted for current working version + # should be checked if we have many deleted files + dataset_last_version = crud('', dpid, "get_dataset_last_version", '') + dataset_version_int = dataset_last_version[0][0] + dataset_working_version = dataset_version_int + 1 + deleted_file = crud(dataset_working_version, dpid, 'get_deleted_files', '') + if deleted_file: + if add_file not in deleted_file: + remote_filenames = crud(dataset_working_version, dpid, "index_add_files", '', add_file) + final_result.extend(remote_filenames) + + else: + logging.warning('%s not adding already marked deleted file', add_file) + else: + remote_filenames = crud(dataset_working_version, dpid, "index_add_files", '', add_file) + final_result.extend(remote_filenames) + add_file = '' + # Files should not be deleted + # If this file is in DB but not in remote site, delete it + + # If this file is in DB but not in remote site, delete it + delete_list = [] + for n in db_files: + if n not in file_list: + logging.warning("[WARNING] %s this file is not here!!!", n) + delete_list.append(n) + else: + continue + for list in delete_list: + file_id = crud('', dpid, "file_id", list) + if file_id: + for name in file_id: + file_id = name[0] + delete_file = crud('', dpid, "delete_file", file_id) + logging.info('%s this file is deleted', delete_file) + else: + logging.warning("There is no File_id!! This file does not exist!!") + final_result = jsonify(final_result) + get_timestamp(dpid) + + if final_result: + return final_result + else: + logging.warning('No new files indexed!') + return jsonify("No new files indexed!") + else: + final_result.append("This file/folder path is not correct!!! Please check it") + logging.error('This file/folder path is not correct!!! Please check it') + json_response = jsonify(final_result) + return json_response + + else: + logging.warning("Can't get foldername information") + + else: + logger.warning("[WARNING] GridFTP proxy certificate is not valid.!!!") + final_result.append('GridFTP proxy certificate is not valid.') + json_response = jsonify(final_result) + return json_response + else: + final_result.append('This datasetpid does not exist') + logging.error('%s this datasetpid does not exist', dpid) + json_response = jsonify(final_result) + return json_response + +@app.route('/api/v1.0/dataset/index', methods=['POST']) +@login_required +def index(): + + dpid = request.form['dpid'] + logging.info('There is no foldername') + + final_result = [] + remotefile_list = [] + file_total = 0 + + if datasetpid_existence(dpid) == True: + final_result.append('This datasetpid exists') + + if check_proxy_cert() == True: + file_path = crud('', dpid, "file_location", '') + db_files = list_dataset(dpid, 'none') + # If there is no file in DB + if not db_files: + db_files = '#' + add_file = '' + for row in file_path: + hostname = row[2] + full_path = row[1] + list_cmd = "-list" + gsi_cmd = "gsiftp://" + port_cmd = ":2811" + cmd = """globus-url-copy %s %s%s%s%s """ % (list_cmd, gsi_cmd, hostname, port_cmd, full_path) + check_file_folder_path(hostname, full_path) + + if check_file_folder_path(hostname, full_path) == True: + logging.info('File/Folder Path is Correct!!!') + status, queryfile_output = commands.getstatusoutput(cmd) + files = queryfile_output.split("\n") + + msg = '' + + for l in files[1:]: + folder_name = l.replace(" ", "") + folder_path = files[0] + folder_name + ### / in the end, it means this is a folder not a file + if l[-1:] == "/": + query_folder(folder_path) + elif l[-1:] == "": + pass + else: + filename = full_path + folder_name + collect_file_list(filename) + + for single_file in file_list: + file_total += 1 + + if single_file not in db_files: + # import file names to DB + logging.info('%s this file does not exist in DB, will add it', single_file) + add_file = single_file + if single_file in db_files: + msg = single_file, "File is already in Database !!!" + final_result.extend(msg) + msg = '' + + if add_file: + # add file only if file not already deleted for current working version + # should be checked if we have many deleted files + dataset_last_version = crud('', dpid, "get_dataset_last_version", '') + dataset_version_int = dataset_last_version[0][0] + dataset_working_version = dataset_version_int + 1 + deleted_file = crud(dataset_working_version, dpid, 'get_deleted_files', '') + + if deleted_file: + if add_file not in deleted_file: + remote_filenames = crud(dataset_working_version, dpid, "index_add_files", '', add_file) + final_result.extend(remote_filenames) + + else: + logging.warning('%s not adding already marked deleted file', add_file) + else: + remote_filenames = crud(dataset_working_version, dpid, "index_add_files", '', add_file) + final_result.extend(remote_filenames) + add_file = '' + # Files should not be deleted + # If this file is in DB but not in remote site, delete it + delete_list = [] + for n in db_files: + if n not in file_list: + logging.warning("[WARNING] %s this file is not here!!!", n) + delete_list.append(n) + else: + continue + for list in delete_list: + final_result.append(list) + + print "final_result", final_result + final_result = jsonify(final_result) + get_timestamp(dpid) + + if final_result: + return final_result + else: + logging.warning('No new files indexed!') + return jsonify("No new files indexed!") + + else: + final_result.append("This file/folder path is not correct!!! Please check it") + logging.error('This file/folder path is not correct!!! Please check it') + json_response = jsonify(final_result) + return json_response + + + else: + logging.warning("[WARNING] GridFTP proxy certificate is not valid.!!!") + final_result.append('GridFTP proxy certificate is not valid.') + json_response = jsonify(final_result) + return json_response + + else: + final_result.append('This datasetpid does not exist') + logging.error('This datasetpid does not exist') + json_response = jsonify(final_result) + return json_response + +@app.route('/api/v1.0/dataset/file_id_check', methods=['GET']) +@login_required +def file_id_check(): + + dpid = request.form['dpid'] + filepath = request.form['filepath'] + file_id = crud('', dpid, "file_id", filepath) + + if file_id: + for name in file_id: + file_id = name[0] + return file_id + else: + logging.warning("There is no Fileid!! This file does not exist!!") + +@app.route('/api/v1.0/dataset/dataset_status_check', methods=['POST']) +@login_required +def dataset_status_chk(): + + dpid = request.form['dpid'] + client_response = [] + if datasetpid_existence(dpid) == True: + client_response = dataset_status_check(dpid) + return client_response + else: + logging.error('%s this datasetpid does not exist', dpid) + return "This datasetpid does not exist" + +def dataset_version_check(dpid): +# Check dataset status and return the result to the client side let users choose to delete or not + + dataset_status = crud('', dpid, "dataset_status", '') + for status in dataset_status: + version_result = status[1] + return str(version_result) + +@app.route('/api/v1.0/dataset/release_version_check', methods=['POST']) +def release_version_check(): + + dpid = request.form['dpid'] + dataset_status = crud('', dpid, "dataset_status", '') + for status in dataset_status: + version_result = status[1] + return str(version_result) + +@app.route('/api/v1.0/dataset/file_version_check', methods=['POST']) +@login_required +def file_version_check(): + + dpid = request.form['dpid'] + filename = request.form['filename'] + get_file_last_version = crud('', dpid, "get_file_last_version", filename) + get_file_last_version_int = get_file_last_version[0][0] + return str(get_file_last_version_int) + +def get_checksum(dpid, diff_list): + + updatetime = time.strftime("%a %b %d %H:%M:%S %Y", time.localtime()) + logging.info('Get checksum time %s', updatetime) + + file_path = crud('', dpid, "file_location", '') + + for filepath in diff_list: + for row in file_path: + hostname = row[2] + checksum_cmd = "quote cksm md5 0 -1" + cmd = """uberftp %s "%s %s" """ % (hostname, checksum_cmd, filepath) + status, checksum_output = commands.getstatusoutput(cmd) + checksum_lines = StringIO.StringIO(checksum_output) + lines = checksum_lines.readlines() + myline = lines[2] + checksum = myline.split()[1] + update_checksum = crud('', checksum, "update_checksum", filepath) + logging.info('Update Checksum %s', update_checksum) + return "updating_checksum" + + +def get_filesize(dpid, diff_list): + + updatetime = time.strftime("%a %b %d %H:%M:%S %Y", time.localtime()) + logging.info('Get filesize time %s', updatetime) + + file_path = crud('', dpid, "file_location", '') + + for filepath in diff_list: + for row in file_path: + hostname = row[2] + filesize_cmd = "size" + cmd = """uberftp %s "%s %s" """ % (hostname, filesize_cmd, filepath) + status, filesize_output = commands.getstatusoutput(cmd) + filesize_lines = StringIO.StringIO(filesize_output) + lines = filesize_lines.readlines() + filesize = lines[2] + update_filesize = crud('', filesize, "update_filesize", filepath) + logging.info('update_filesize %s', update_filesize) + return "update_filesize" + + +def get_timestamp(dpid): + + dpid = request.form['dpid'] + file_info = crud('', dpid, "file_info", '') + file_path = crud('', dpid, "file_location", '') + + for file in file_info: + filepath = file[1] + + for row in file_path: + hostname = row[2] + keepalive_cmd = "-keepalive 150" + recursive_cmd = "dir -r" + cmd = """uberftp %s %s "%s %s" """ % (hostname, keepalive_cmd, recursive_cmd, filepath) + status, timestamp_output = commands.getstatusoutput(cmd) + timestamp_lines = StringIO.StringIO(timestamp_output) + lines = timestamp_lines.readlines() + timestamp_line = lines[2] + files = timestamp_line.split()[-4:] + gridftp_timestamp = ' '.join(files[0:3]) + + update_gridftp_timestamp = crud('', gridftp_timestamp, "update_gridftp_timestamp", filepath) +# logging.info('update_gridftp_timestamp', update_gridftp_timestamp) +# logging.info('update_gridftp_timestamp %s ', update_gridftp_timestamp) +# return("update_timestamp") + +def timestamp_check(file, hostname): + + keepalive_cmd = "-keepalive 150" + recursive_cmd = "dir -r" + cmd = """uberftp %s %s "%s %s" """ % (hostname, keepalive_cmd, recursive_cmd, file) + status, timestamp_output = commands.getstatusoutput(cmd) + timestamp_lines = StringIO.StringIO(timestamp_output) + lines = timestamp_lines.readlines() + timestamp_line = lines[2] + files = timestamp_line.split()[-4:] + gridftp_timestamp = ' '.join(files[0:3]) + return gridftp_timestamp + +def integrity_check(dpid): + + message = [] + file_info = crud('', dpid, "file_info", '') + file_path = crud('', dpid, "file_location", '') + + filelist = [] + for file in file_info: + filepath = file[1] + for row in file_path: + hostname = row[2] + checksum_cmd = "quote cksm md5 0 -1" + cmd = """uberftp %s "%s %s" """ % (hostname, checksum_cmd, filepath) + status, checksum_output = commands.getstatusoutput(cmd) + checksum_debug = checksum_output.split() + checksum_lines = StringIO.StringIO(checksum_output) + lines = checksum_lines.readlines() + myline = lines[2] + checksum = myline.split()[1] + + file_checksum = crud('', dpid, "file_checksum", filepath) + + for num in file_checksum: + filechecksum_db = num[0] + if filechecksum_db == checksum: + message = "Checksum Match!!" + continue + + else: + message = "Checksum Not match!! Please check this file\n", filepath + logging.warning("Checksum Not match!! Please check this file\n") + filelist.append(filepath) + + print filelist + return message + +def checksum_check(dpid, file): + + message = [] + logging.info('Checking single file Checksum') + file_path = crud('', dpid, "file_location", '') + for row in file_path: + hostname = row[2] + checksum_cmd = "quote cksm md5 0 -1" + cmd = """uberftp %s "%s %s" """ % (hostname, checksum_cmd, file) + status, checksum_output = commands.getstatusoutput(cmd) + checksum_debug = checksum_output.split() + checksum_lines = StringIO.StringIO(checksum_output) + lines = checksum_lines.readlines() + myline = lines[2] + checksum = myline.split()[1] + + file_checksum = crud('', dpid, "file_checksum", file) + + for num in file_checksum: + filechecksum_db = num[0] + # Checksum should be empty on initial index, after dataset release, checksum should be added into local DB. + # Compare dataset status is open, it should be initial index or afterwards index + if filechecksum_db == '': + logging.info('There is no checksum information to compare') + dataset_last_version = crud('', dpid, "get_dataset_last_version", '') + dataset_version_int = dataset_last_version[0][0] + if dataset_version_int == 0: + message = "No checksum because this dataset is initial and does not release yet.\n" + logging.warning("No checksum because this dataset is initial and does not release yet.\n") + else: + message = "This dataset was release before but there is no checksum recorded into DB. Please check the checksum of file\n" + logging.warning("This dataset was release before but there is no checksum recorded into DB. Please check the checksum of file\n") + else: + if filechecksum_db == checksum: + message = "Checksum Match!!\n" + continue + else: + message = "Checksum Not match!! Please check this file" + file + "\n" + logging.warning("Checksum Not match!! Please check this file %s", file) + return message + +@app.route('/api/v1.0/dataset/release_dataset', methods=['POST']) +@login_required +def release_dataset(): + + #update the dataset status in DB + dpid = request.form['dpid'] + version = request.form['version'] + update_release_status = crud('', dpid, "update_release_status", version) + logging.info('Update Release Status is %s', update_release_status) + + ########## subscription notifications + # gets all subscriptions + # checks if current dataset to be released is in subscriptions + # sends an email only to subscribers who subscribed to currently released dataset + subscriptions = get_subscription() + for row in subscriptions: + subscriber_dataset = row[1] + if subscriber_dataset == dpid: + logging.info('Subscriber_dataset and current released dataset match') + subscriber_email = row[2] + subscriber_username = row[3] + dataset_last_version = crud('', subscriber_dataset, "get_dataset_last_version", '') + dataset_last_version_int = dataset_last_version[0][0] + + dpid = subscriber_dataset + v2 = dataset_last_version_int + v1 = dataset_last_version_int + + diff_list = diff(dpid, v1, v2) + logging.info('diff for last two releases') + logging.info(diff_list) + + get_checksum(dpid, diff_list) + get_filesize(dpid, diff_list) + + email_method.start_transfer_email(subscriber_dataset, diff_list, subscriber_email) + + ### Compare which port that subscriber provides (gridftp: 2811, FTS3: 8446, HTTPS: 8443, SRMv2: 8443) + transfer_port_choice = crud(subscriber_username, '', "transfer_port_choice", '') + logging.info('Subscriber port is %s', transfer_port_choice[0][0]) + + if transfer_port_choice[0][0] == "2811": + logging.info('Will use globus url copy to transfer files') + data_transfer(dpid, diff_list, subscriber_email) + elif transfer_port_choice[0][0] == "8446": + logging.info('Will use FTS3 to transfer files') + fts3_transfer(dpid, diff_list, subscriber_email) + # Other ports will choose FTS3 by default + else: + logging.info('Will use FTS3 to transfer files') + fts3_transfer(dpid, diff_list, subscriber_email) + + else: + pass + update_release_status = crud('', dpid, "update_release_status", version) + json_response = jsonify(update_release_status) + return json_response + + +@app.route('/api/v1.0/dataset/release_dataset_without_version', methods=['POST']) +@login_required +def release_dataset_without_version(): + + # update the dataset status in DB + dpid = request.form['dpid'] + #### There is no release version, so we should get the latest dataset working version here + dataset_version = crud('', dpid, "get_dataset_last_version", '') + dataset_version_int = dataset_version[0][0] + dataset_working_version = dataset_version_int + 1 + logging.info('dataset current working version is %s', dataset_working_version) + + update_release_status = crud('', dpid, "update_release_status", dataset_working_version) + logging.info('Update Release Status is %s', update_release_status) + + ########## subscription notifications + # gets all subscriptions + # checks if current dataset to be released is in subscriptions + # sends an email only to subscribers who subscribed to currently released dataset + subscriptions = get_subscription() + for row in subscriptions: + subscriber_dataset = row[1] + if subscriber_dataset == dpid: + logging.info('Subscriber_dataset and current released dataset match') + subscriber_email = row[2] + subscriber_username = row[3] + dataset_last_version = crud('', subscriber_dataset, "get_dataset_last_version", '') + dataset_last_version_int = dataset_last_version[0][0] + + dpid = subscriber_dataset + v2 = dataset_last_version_int + v1 = dataset_last_version_int + + diff_list = diff(dpid, v1, v2) + logging.info('diff for last two releases') + logging.info(diff_list) + + get_checksum(dpid, diff_list) + get_filesize(dpid, diff_list) + + email_method.start_transfer_email(subscriber_dataset, diff_list, subscriber_email) + + ### Compare which port that subscriber provides (gridftp: 2811, FTS3: 8446, HTTPS: 8443, SRMv2: 8443) + transfer_port_choice = crud(subscriber_username, '', "transfer_port_choice", '') + logging.info('Subscriber port is %s', transfer_port_choice[0][0]) + + if transfer_port_choice[0][0] == "2811": + logging.info('Will use globus url copy to transfer files') + data_transfer(dpid, diff_list, subscriber_email) + elif transfer_port_choice[0][0] == "8446": + logging.info('Will use FTS3 to transfer files') + fts3_transfer(dpid, diff_list, subscriber_email) + # Other ports will choose FTS3 by default + else: + logging.info('Will use FTS3 to transfer files') + fts3_transfer(dpid, diff_list, subscriber_email) + else: + pass + + update_release_status = crud('', dpid, "update_release_status", dataset_working_version) + json_response = jsonify(update_release_status) + return json_response + +@app.route('/api/v1.0/dataset/delete', methods=['DELETE']) +@login_required +def delete(): + + try: + dpid = request.form['dpid'] + filepath = request.form['filepath'] + file_id = crud('', dpid, "file_id", filepath) + if file_id: + logging.info('[DELETE] this is file_id %s', file_id) + else: + logging.error('%s this filePath is incorrect', filepath) + return "This filePath is incorrect" + + dataset_last_version = crud('', dpid, "get_dataset_last_version", '') + dataset_version_int = dataset_last_version[0][0] + dataset_working_version = dataset_version_int + 1 + if file_id: + for name in file_id: + file_id = name[0] + delete_file = crud(dataset_working_version, dpid, "delete_file", file_id) + return delete_file + else: + logging.warning("There is no File_id!! This file does not exist!!") + return "There is no File_id, This file does not exist!!" + except: + logging.warning("There is no datasetPID or FilePath") + return "There is no datasetPID or FilePath" + +@app.route('/api/v1.0/add_subscriber', methods=['POST']) +@login_required +def add_subscriber(): + + if not request.json: + abort(400) + d = request.json + subscriber_list = crud('', '', "list_subscriber", '') + if not subscriber_list: + subscriber_list = '#' + add_subscriber = [] + msg = '' + + for name in subscriber_list: + username = name[0] + + if username == d["Username"]: + msg = d["Username"], " is already in Database !!!" + logging.info(msg) + add_subscriber.append(msg) + msg = '' + else: + logging.warning(("%s This subscriber is not in DB, will add it") % (username)) + add_subscriber = crud(d, '', "add_subscriber", d["Username"]) + + json_response = jsonify(add_subscriber) + logging.info(json_response) + return json_response + +@app.route('/api/v1.0/activate_subscriber', methods=['POST']) +@login_required +def activate_subscriber(): + # This action is to activate the deleted subscriber, then he/she can re-subscribe datasets + + username = request.form['username'] + status = [] + + activate_status = crud('', '', "activate_subscriber", username) + if activate_status == True: + status.append("This subscriber is already listed and status is active again") + + else: + logging.warning("Activate is not working, please check it!!!") + status.append("Activate is not working, please check it!!!") + + json_response = jsonify(status) + logging.info(json_response) + return json_response + +@app.route('/api/v1.0/del_subscriber', methods=['DELETE']) +@login_required +def del_subscriber(): + # If this subscriber is deleted, the relationship of previous subscribed datasets are deleted + + username = request.form['username'] + if username_existence(username) == True: + logging.info('%s this username exists', username) + try: +# delete_subscriber = crud('', '', "delete_subscriber", username) +# return delete_subscriber + return True + except: + logging.warning('There is no username') + return "There is no username" + else: + logging.error('% this username does not exist, username') + return "This username does not exist" + + +@app.route('/api/v1.0/dataset/subscriber_status', methods=['POST']) +@login_required +def subscriber_status(): + + username = request.form['username'] + if username_existence(username) == True: + logging.info('%s this username exists', username) + subscriber_status = crud('', '', "subscriber_status", username) + for status in subscriber_status: + status_result = status[0] + logging.info('subscriber status: %s', status_result) + return status_result + else: + logging.error('%s this username does not exist', username) + return "Error" + +@app.route('/api/v1.0/subscribe_user', methods=['POST']) +@login_required +def subscribe_user(): + + username = request.form['username'] + dpid = request.form['dpid'] + + subscribe_status = [] + + if datasetpid_existence(dpid) == True: + subscribe_status.append('This datasetpid exists') + + if check_proxy_cert() == True: + try: + subscribe_user = crud('', dpid, "subscribe_user", username) + if subscribe_user == True: + subscribe_status.append('This user and dataset are already subscribed!!!') + logging.info('This user %s and dataset %s are already subscribed!!!', username, dpid) + else: + logging.warning('Subscription is not working, because the same data is in DB!!!') + subscribe_status.append('Subscription is not working, because the same data is in DB!!!') + except: + logging.error('There is a problem to subscribe_user') + subscribe_status.append('There is a problem to subscribe_user') + else: + logger.warning("[WARNING] Proxy certificate is not valid") + subscribe_status.append('Please use grid-proxy-init command line to generate a proxy certificate!!!') + + else: + subscribe_status.append('This datasetpid does not exist') + logging.error('% this datasetpid does not exist', dpid) + + json_response = jsonify(subscribe_status) + logging.info(json_response) + return json_response + +@app.route('/api/v1.0/unsubscribe_user', methods=['POST']) +@login_required +def unsubscribe_user(): + + username = request.form['username'] + dpid = request.form['dpid'] + + unsubscribe_status = [] + + if datasetpid_existence(dpid) == True: + unsubscribe_status.append('This datasetpid exists') + + try: + unsubscribe_user = crud('', dpid, "unsubscribe_user", username) + + if unsubscribe_user == True: + unsubscribe_status.append('This user and dataset are already unsubscribed!!!') + logging.info('This user %s and dataset %s are already unsubscribed!!!', username, dpid) + else: + logging.warning("Unsubscription is not working, please check it!!!") + unsubscribe_status.append('Unsubscription is not working, please check it!!!') + except: + logging.warning("There is a problem to unsubscribe_user") + unsubscribe_status.append('There is a problem to unsubscribe_user') + + else: + unsubscribe_status.append('This datasetpid does not exist') + logging.error('% this datasetpid does not exist', dpid) + + json_response = jsonify(unsubscribe_status) + logging.info(json_response) + return json_response + +@app.route('/api/v1.0/subscription_check', methods=['POST']) +@login_required +def subscription_check(): + + username = request.form['username'] + dpid = request.form['dpid'] + + status = dataset_status_check(dpid) + + sub_email = crud('', '', "get_one_sub_email", username) + for email in sub_email: + subscriber_email = email[0] + + if status == "Open": + ### Will check if there is previous release version + dataset_last_version = crud('', dpid, "get_dataset_last_version", '') + dataset_version_int = dataset_last_version[0][0] + logging.info('Previous Version is: %s', dataset_version_int) + + if dataset_version_int == 0: + logging.info('There is no previous release version, so files will be transferred when the dataset releases') + return "There is no previous release version, so files will be transferred when the dataset releases" + else: + version = dataset_version_int + transfer_list = crud(dataset_version_int, dpid, "list_dataset", '') + + ### Compare which port that subscriber provides (gridftp: 2811, FTS3: 8446, HTTPS: 8443, SRMv2: 8443) + transfer_port_choice = crud(username, '', "transfer_port_choice", '') + logging.info('Subscriber port is %s', transfer_port_choice[0][0]) + + if transfer_port_choice[0][0] == "2811": + logging.info('Will use globus url copy to transfer files') + result = single_person_transfer(dpid, transfer_list, username) + if result == True: + logging.info('File Transfer is done') + return "File Transfer is done" + else: + logging.error('File Transfer has a problem, please check it!') + return "File Transfer has a problem, please check it!" + elif transfer_port_choice[0][0] == "8446": + logging.info('Will use FTS3 to transfer files') + result = fts3_transfer(dpid, transfer_list, subscriber_email) + if result == True: + logging.info('File Transfer is done') + return "File Transfer is done" + else: + logging.error('File Transfer has a problem, please check it!') + return "File Transfer has a problem, please check it!" + # other ports will choose FTS3 for transfer by default + else: + logging.info('Will use FTS3 to transfer files') + result = fts3_transfer(dpid, transfer_list, subscriber_email) + if result == True: + logging.info('File Transfer is done') + return "File Transfer is done" + else: + logging.error('File Transfer has a problem, please check it!') + return "File Transfer has a problem, please check it!" + + elif status == "Released": + ### Get the release version, then transfer all current files from the remote site + dataset_last_version = crud('', dpid, "get_dataset_last_version", '') + dataset_version_int = dataset_last_version[0][0] + logging.info('Previous Version is: %s', dataset_version_int) + + version = dataset_version_int + transfer_list = crud(dataset_version_int, dpid, "list_dataset", '') + + ### Compare which port that subscriber provides (gridftp: 2811, FTS3: 8446, HTTPS: 8443, SRMv2: 8443) + transfer_port_choice = crud(username, '', "transfer_port_choice", '') + logging.info('Subscriber port is %s', transfer_port_choice[0][0]) + + if transfer_port_choice[0][0] == "2811": + logging.info('Will use globus url copy to transfer files') + result = single_person_transfer(dpid, transfer_list, username) + if result == True: + logging.info('File Transfer is done') + return "File Transfer is done" + else: + logging.error('File Transfer has a problem, please check it!') + return "File Transfer has a problem, please check it!" + elif transfer_port_choice[0][0] == "8446": + logging.info('Will use FTS3 to transfer files') + result = fts3_transfer(dpid, transfer_list, subscriber_email) + if result == True: + logging.info('File Transfer is done') + return "File Transfer is done" + else: + logging.error('File Transfer has a problem, please check it!') + return "File Transfer has a problem, please check it!" + # other ports will choose FTS3 for transfer by default + else: + logging.info('Will use FTS3 to transfer files') + result = fts3_transfer(dpid, transfer_list, subscriber_email) + if result == True: + logging.info('File Transfer is done') + return "File Transfer is done" + else: + logging.error('File Transfer has a problem, please check it!') + return "File Transfer has a problem, please check it!" + else: + logging.warning('Dataset status is not Open or Released Please check dataset status') + return "Dataset status is not Open or Released Please check dataset status" + +def single_person_transfer(dpid, transfer_list, username): + + # This situation is when single person subscribes one dataset, if this dataset has previous release version, files should be transferred to target site + # Create a host_temp with the source hostname and destination hostname + # Create a gridftp_file_temp with the file names + # Perform globus-url-copy command line (Gridftp) + # Remove two files after the transfer is done + + updatetime = time.strftime("%a %b %d %H:%M:%S %Y", time.localtime()) + logging.info('transfer time %s', updatetime) + + file_path = crud('', dpid, "file_location", '') + sourcelist = [] + for row in file_path: + hostname = row[2] + + sub_list = crud('', '', "get_one_sub_host", username) + for host in sub_list: + destination_list = host[0] + folder_path = host[1] + + sourcelist.append('@source' + '\n' + hostname + '\n' + '@destination' + '\n' + destination_list) + + ### Create a temp file for host and gridftp_file + host_temp = tempfile.NamedTemporaryFile() + gridftp_file_temp = tempfile.NamedTemporaryFile() + try: + logging.info('hostname: %s', host_temp) + logging.info('hostname file name: %s', host_temp.name) + host_temp.writelines(sourcelist) + host_temp.seek(0) + sourceurl = host_temp.name + + targetlist = [] + logging.info('Total files are %s', len(transfer_list)) + for n in transfer_list: + + targetlist.append("gsiftp://" + n + " gsiftp://" + folder_path + n + n.split("/")[-1] + '\n') + + logging.info('filelist temp: %s', gridftp_file_temp) + logging.info('filelist file name: %s', gridftp_file_temp.name) + gridftp_file_temp.writelines(targetlist) + gridftp_file_temp.seek(0) + + destinationurl = gridftp_file_temp.name + + # Command line sample: globus-url-copy -rst -p 50 -af hosts.txt -f gsiftp_file.txt + verbose_mode = "-rst -p 50 -af" + verbose_1_mode = '-cd -f' + transfer_cmd = """globus-url-copy %s %s %s %s """ % (verbose_mode, sourceurl, verbose_1_mode, destinationurl) + + status, transfer_output = commands.getstatusoutput(transfer_cmd) + + ### Get subsciber email + sub_email = crud('', '', "get_one_sub_email", username) + for email in sub_email: + subscriber_email = email[0] + + if "error" in transfer_output: + logging.error('[ERROR] Something wrong during transfer, please check it') + logging.error(transfer_output) + logging.error("[ERROR] File Transfer is failed, please check it!!!") + email_method.fail_content(dpid, transfer_list, subscriber_email) + + elif "failed" in transfer_output: + logging.error('[ERROR] Something wrong during transfer, please check it') + logging.error(transfer_output) + logging.error("[ERROR] File Transfer is failed, please check it!!!") + email_method.fail_content(dpid, transfer_list, subscriber_email) + + logging.info("File Transfer is done") + email_method.success_content(dpid, transfer_list, subscriber_email) + + finally: + logging.info('Remove two files: host_temp and gsiftp_file_temp') + endtime = time.strftime("%a %b %d %H:%M:%S %Y", time.localtime()) + logging.info('transfer end time %s', endtime) + host_temp.close() + gridftp_file_temp.close() + diff --git a/rdsds_server/rdsds/fts3.py b/rdsds_server/rdsds/fts3.py new file mode 100755 index 0000000..da288c1 --- /dev/null +++ b/rdsds_server/rdsds/fts3.py @@ -0,0 +1,135 @@ +#!/usr/bin/python + +from transfer import Transfer +import commands +import os +import logging +import StringIO +import time +from db_manage import crud +import tempfile +# Log setting and generate a logfile on the current place +logpath = os.getcwd() + "/dsds_server_logs" +logging.basicConfig(level=logging.INFO, format='[%(levelname)s] %(asctime)s - %(message)s', filename=logpath) +logger = logging.getLogger('dsds_server_logs') + +class FTS(Transfer): + + def __init__(self): + self.dpid = [] + self.diff_list = [] + self.subscriber_email = [] + self.fts_status_id = [] + self.fts3_host = [] + self.proxy_path = [] + self.filetransfer = [] + + def create_transferlist(self, dpid, diff_list): + + file_path = crud('', dpid, "file_location", '') + filetransfer = [] + for row in file_path: + hostname = row[2] + subscriptions = crud('', '', "get_subs", '') + for row in subscriptions: + subscriber_dataset = row[1] + if subscriber_dataset == dpid: + subs_hostname_list = crud('', dpid, "get_subs_host", '') + for host in subs_hostname_list: + destination_list = host[0] + folder_path = host[1] + + for n in diff_list: + filetransfer.append("gsiftp://" + hostname + n + " gsiftp://" + destination_list + folder_path[:-1] + n + '\n') + return filetransfer + + def delegate(self, fts3_host, proxy_path): + """ FTS fts-delegation-init""" + verbose_mode = "-v -s" + verbose_mode1 = "--proxy" + fts3_delegation_cmd = """ fts-delegation-init %s %s %s %s""" % (verbose_mode, fts3_host, verbose_mode1, proxy_path) + fts3_delegation_output = commands.getstatusoutput(fts3_delegation_cmd) + + if "problem" in fts3_delegation_output[1]: + logging.error('[ERROR] Something wrong on FTS delegation') + logging.error(fts3_delegation_output[1]) + return False + elif "expired" in fts3_delegation_output[1]: + logging.error('[ERROR] Something wrong on FTS delegation') + logging.error(fts3_delegation_output[1]) + return False + else: + return True + + def submit(self, fts3_host, proxy_path, filetransfer): + """ FTS fts-transfer-submit""" + try: + fts3_temp_file = tempfile.NamedTemporaryFile() + logging.info('fts3_temp: %s', fts3_temp_file) + logging.info('fts3_temp_name: %s', fts3_temp_file.name) + fts3_temp_file.writelines(filetransfer) + fts3_temp_file.seek(0) + transfer_list = fts3_temp_file.name + try: + verbose_mode1 = '-o -m --retry 0 -s' + verbose_mode2 = '--proxy' + verbose_mode3 = '-f' + fts3_transfer_submit_cmd = """ fts-transfer-submit %s %s %s %s %s %s""" % ( + verbose_mode1, fts3_host, verbose_mode2, proxy_path, verbose_mode3, transfer_list) + print fts3_transfer_submit_cmd + fts3_transfer_submit_output = commands.getstatusoutput(fts3_transfer_submit_cmd) + print fts3_transfer_submit_output + fts_status_id = fts3_transfer_submit_output[1] + return fts_status_id + except TypeError: + return False + finally: + logging.info('Remove this file: transfer_list') + endtime = time.strftime("%a %b %d %H:%M:%S %Y", time.localtime()) + logging.info('transfer end time %s', endtime) + fts3_temp_file.close() + + def status(self, fts_status_id, fts3_host, proxy_path): + + """ fts-transfer-status """ + query_num = 10 + while query_num > 0: + logging.info('Query time is %s', query_num) + verbose_mode1 = '-s' + verbose_mode2 = '--proxy' + verbose_mode3 = '-d -l' + filter_cmd = '| grep State:' + filter_cmd_2 = '| grep Reason:' + + fts3_transfer_status_cmd = """ fts-transfer-status %s %s %s %s %s %s %s""" % ( + verbose_mode1, fts3_host, verbose_mode2, proxy_path, verbose_mode3, fts_status_id, filter_cmd) + + fts3_transfer_total_status_cmd = """ fts-transfer-status %s %s %s %s %s %s %s""" % ( + verbose_mode1, fts3_host, verbose_mode2, proxy_path, verbose_mode3, fts_status_id, filter_cmd_2) + + fts3_transfer_status_output = commands.getstatusoutput(fts3_transfer_status_cmd) + fts_status_lines = StringIO.StringIO(fts3_transfer_status_output) + lines = fts_status_lines.readlines() + logging.info('FTS3 Transfer Status is %s', lines[0]) + + fts3_transfer_total_status_output = commands.getstatusoutput(fts3_transfer_total_status_cmd) + fts_total_status_lines = StringIO.StringIO(fts3_transfer_total_status_output) + reason = fts_total_status_lines.readlines() + logging.info('FTS3 Transfer Status Reason is %s', reason[0]) + query_num -= 1 + time.sleep(5) + + return {'query_status': lines[0], 'query_info': reason[0]} + + def cancel(self, fts_status_id, fts3_host, proxy_path): + + try: + verbose_mode = '-v -s' + verbose_mode1 = '--proxy' + filter_cmd = '| grep' + fts3_transfer_cancel_cmd = """ fts-transfer-cancel %s %s %s %s %s %s %s""" % ( + verbose_mode, fts3_host, verbose_mode1, proxy_path, fts_status_id, filter_cmd, fts_status_id) + fts3_transfer_cancel_output = commands.getstatusoutput(fts3_transfer_cancel_cmd) + return fts3_transfer_cancel_output + except TypeError: + return False diff --git a/rdsds_server/rdsds/rdsds_email.py b/rdsds_server/rdsds/rdsds_email.py new file mode 100755 index 0000000..6aad873 --- /dev/null +++ b/rdsds_server/rdsds/rdsds_email.py @@ -0,0 +1,110 @@ +#!/usr/bin/python + +import smtplib +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText +from email.header import Header + +class EMAIL_METHOD(): + + def start_transfer_email(self, dpid, diff_list, subscriber_email): + email_body = [] + email_body.append(dpid) + for element in diff_list: + email_body.append(element) + sum = len(diff_list) + email_body.append("Total files will be transferred: %s" % sum) + email_body_str = "\n".join(email_body) + self.send_email(subscriber_email, email_body_str) + return True + + def success_content(self, dpid, diff_list, subscriber_email): + email_body = [] + email_body.append(dpid) + for element in diff_list: + email_body.append(element) + email_body.append("File Transfer is done") + email_body.append("Total files are already transferred: %s" % len(diff_list)) + email_body_str = "\n".join(email_body) + self.send_transfer_result(subscriber_email, email_body_str) + return True + + def fail_content(self, dpid, diff_list, subscriber_email): + email_body = [] + email_body.append(dpid) + for element in diff_list: + email_body.append(element) + email_body.append("[ERROR] File Transfer is failed, please check it!!!") + email_body_str = "\n".join(email_body) + self.send_transfer_error(subscriber_email, email_body_str) + return False + + def fail_fts_content(self, dpid, diff_list, subscriber_email, result, all_info): + email_body = [] + email_body.append(dpid) + for element in diff_list: + email_body.append(element) + email_body.append("[ERROR] File Transfer is failed, please check it!!!") + email_body.append("FINISHED ITEMS ARE: %s" % result.count("FINISHED")) + email_body.append("SUBMITTED ITEMS ARE: %s" % result.count("SUBMITTED")) + email_body.append("FAILED ITEMS ARE: %s" % result.count("FAILED")) + email_body.append("Details: %s" % all_info) + email_body_str = "\n".join(email_body) + self.send_transfer_error(subscriber_email, email_body_str) + return False + + def fail_fts_delegation(self, dpid, diff_list, subscriber_email): + email_body = [] + email_body.append(dpid) + for element in diff_list: + email_body.append(element) + email_body.append("[ERROR] Something wrong on FTS delegation.") + email_body_str = "\n".join(email_body) + self.send_transfer_error(subscriber_email, email_body_str) + return False + + def success_fts_delegation(self, dpid, diff_list, subscriber_email): + email_body = [] + email_body.append(dpid) + for element in diff_list: + email_body.append(element) + email_body.append("FTS delegation Correct!!") + email_body_str = "\n".join(email_body) + self.send_transfer_result(subscriber_email, email_body_str) + return True + + def send_email(self, subscriber, transfer_list): + smtp = smtplib.SMTP() + smtp.connect('localhost') + msgRoot = MIMEMultipart("alternative") + msgRoot['Subject'] = Header("DSDS Dataset Subscription Service", "utf-8") + msgRoot['From'] = "service@dsds-service.ebi.ac.uk" + msgRoot['To'] = subscriber + text = MIMEText(transfer_list, "plain", "utf-8") + msgRoot.attach(text) + smtp.sendmail("service@dsds-service.ebi.ac.uk", [subscriber], msgRoot.as_string()) + + def send_transfer_result(self, subscriber, transfer_list): + smtp = smtplib.SMTP() + smtp.connect('localhost') + msgRoot = MIMEMultipart("alternative") + msgRoot['Subject'] = Header("DSDS Dataset Subscription Service Transfer is Done", "utf-8") + msgRoot['From'] = "service@dsds-service.ebi.ac.uk" + msgRoot['To'] = subscriber + text = MIMEText(transfer_list, "plain", "utf-8") + msgRoot.attach(text) + smtp.sendmail("service@dsds-service.ebi.ac.uk", [subscriber], msgRoot.as_string()) + + def send_transfer_error(self, subscriber, transfer_list): + smtp = smtplib.SMTP() + smtp.connect('localhost') + msgRoot = MIMEMultipart("alternative") + msgRoot['Subject'] = Header("DSDS Dataset Subscription Service Transfer is failed", "utf-8") + msgRoot['From'] = "service@dsds-service.ebi.ac.uk" + msgRoot['To'] = subscriber + msgRoot['To'] = "rdsds@ebi.ac.uk" + text = MIMEText(transfer_list, "plain", "utf-8") + msgRoot.attach(text) + smtp.sendmail("service@dsds-service.ebi.ac.uk", [subscriber], msgRoot.as_string()) + smtp.sendmail("service@dsds-service.ebi.ac.uk", "rdsds@ebi.ac.uk", msgRoot.as_string()) + diff --git a/rdsds_server/rdsds/transfer.py b/rdsds_server/rdsds/transfer.py new file mode 100755 index 0000000..7412826 --- /dev/null +++ b/rdsds_server/rdsds/transfer.py @@ -0,0 +1,14 @@ +#!/usr/bin/python + +class Transfer(object): + + def __init__(self): + pass + def delegate(self): + pass + def submit(self): + pass + def cancel(self): + pass + def status(self): + pass From 7abb69a3837b83f0d6a3612ca07cff247d9ed56d Mon Sep 17 00:00:00 2001 From: JinnyChien Date: Thu, 20 Jun 2019 12:20:17 +0100 Subject: [PATCH 2/2] new file: main.py --- rdsds_server/rdsds/main.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 rdsds_server/rdsds/main.py diff --git a/rdsds_server/rdsds/main.py b/rdsds_server/rdsds/main.py new file mode 100644 index 0000000..7e711c6 --- /dev/null +++ b/rdsds_server/rdsds/main.py @@ -0,0 +1,18 @@ +from flask import Flask, jsonify +from flask_swagger import swagger + +app = Flask(__name__) + + +@app.route("/api/v1.0/doc") +def spec(): + swag = swagger(app) + swag['info']['version'] = "1.0" + swag['info']['title'] = "Reference Data Set Distribution Service" + swag['info']['service description'] = "This service provides and manages the technical metadata lifecycle relating to reference dataset stored in the ELIXIR data federation" + swag['info']['service contact'] = "rdsds@ebi.ac.uk" + swag['info']['service license'] = "Apache 2" + return jsonify(swag) + +if __name__ == '__main__': + app.run(host='0.0.0.0', debug=True, port=80) \ No newline at end of file