-
Notifications
You must be signed in to change notification settings - Fork 62
GPII-3138: Update snapsets in data base #626
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 8 commits
74dde50
ee30bb2
1c0f38a
b5dd8c0
f7068c0
e2f4e63
554ae82
f145f66
8f54a33
67f7bd6
c48d7ae
f029df2
5f2f1b5
750cdf3
0e41600
22d6605
574236f
d6547d3
8520379
ef1e721
0181c42
9bb64af
a4541ba
e026465
f4c41a6
6723b6e
2e0bb55
fae02da
831a762
582b3d7
c401c97
54defe7
58fdde7
0862af6
79abd7d
2b8cbeb
59f03a8
6ee716e
9a090a1
a9eec11
a4cf452
63c1a11
7ce1b84
afc6888
75456ba
230c8f0
23b27e4
33f1741
2c48ca5
d9ac25e
ebde69d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,162 @@ | ||
| /*! | ||
| Copyright 2018 OCAD University | ||
|
|
||
| Licensed under the New BSD license. You may not use this file except in | ||
| compliance with this License. | ||
|
|
||
| You may obtain a copy of the License at | ||
| https://github.com/GPII/universal/blob/master/LICENSE.txt | ||
| */ | ||
|
|
||
| // This script modifies the preferences data base: | ||
| // 1. Finds all the Prefs Safes of type "snapset" (prefsSafesType = "snapset"), | ||
| // 2. Finds all the GPII Keys associated with each snapset Prefs Safe | ||
| // 3. Deletes the found Prefs Safes and associated GPII Keys | ||
| // | ||
| // A sample command that runs this script: | ||
| // node deleteSnapsets.js $COUCHDBURL | ||
|
|
||
| "use strict"; | ||
|
|
||
| var http = require("http"), | ||
| url = require("url"), | ||
| fluid = require("infusion"); | ||
|
|
||
| var gpii = fluid.registerNamespace("gpii"); | ||
| fluid.registerNamespace("gpii.dataLoader"); | ||
| fluid.setLogging(fluid.logLevel.INFO) | ||
|
|
||
| var dbLoader = gpii.dataLoader; | ||
| dbLoader.couchDbUrl = process.argv[2]; | ||
| if (!fluid.isValue(dbLoader.couchDbUrl)) { | ||
| fluid.log ("COUCHDB_URL environment variable must be defined"); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would be useful to also output the command usage:
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
| process.exit(1); | ||
| } | ||
| fluid.log("COUCHDB_URL: '" + dbLoader.couchDbUrl + "'"); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. COUCHDB_URL can (and usually will) contain credentials. Please do not write it to the log without sanitization. It looks like
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for pointing that out, @mrtyler. I've gone with logging the
I don't think any of those contain sensitive information, but I could be wrong. What do you think?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks good. |
||
| dbLoader.prefsSafesViewUrl = dbLoader.couchDbUrl + "/_design/views/_view/findSnapsetPrefsSafes"; | ||
| dbLoader.gpiiKeyViewUrl = dbLoader.couchDbUrl + "/_design/views/_view/findGpiiKeysByPrefsSafeId"; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do you think to define the full url here to provide a general view:
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since we now use the get-all-gpiikeys view, this is no longer needed -- "overtaken by events". |
||
| dbLoader.parsedCouchDbUrl = url.parse(dbLoader.couchDbUrl); | ||
| dbLoader.docsToRemove=[]; | ||
|
|
||
| /** | ||
| * Find the Prefs Safes of type "snapSet", add them to an array of records to | ||
| * remove, then use them to find their associated GPII Key(s). | ||
| * @param {Object} response - The response from the data base containing the | ||
| * snapSet Prefs Safes as a JSON string. | ||
| */ | ||
| dbLoader.processSnapsets = function (response) { | ||
| var snapSetsString = ""; | ||
| response.setEncoding("utf8"); | ||
| response.on("data", function (chunk) { | ||
| snapSetsString += chunk; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See below |
||
| }); | ||
| response.on("end", function () { | ||
| dbLoader.snapSets = JSON.parse(snapSetsString); | ||
| fluid.each(dbLoader.snapSets.rows, function (aSnapset) { | ||
| aSnapset.value._deleted = true; | ||
| dbLoader.docsToRemove.push(aSnapset.value); | ||
| }); | ||
| dbLoader.addGpiiKeysAndBulkDelete(dbLoader.snapSets.rows, dbLoader.docsToRemove); | ||
| }); | ||
| }; | ||
|
|
||
| /** | ||
| * Find the GPII key records associated with the given snapset Prefs Safes, | ||
| * delete each one as found, and then batch delete all the snapset Prefs Safes. | ||
| * @param {Array} snapSets - The snapsets of interest. | ||
| * @param {Array} docsToRemove - Array of records to delete. | ||
| */ | ||
| dbLoader.addGpiiKeysAndBulkDelete = function (snapSets, docsToRemove) { | ||
| fluid.each(snapSets, function (aSnapset) { | ||
| var gpiiKeyId = aSnapset.value._id; | ||
| fluid.log("Snapset: " + gpiiKeyId); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Output a more meaningful message such as "Finding GPII keys associated with the snapset prefs safe id: ".
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've updated all the log messages to be very simple, such as you have suggested. Actual snapset or gpiikeys internal information such as the "_id" field are no longer logged. |
||
| var gpiiKeyViewUrl = dbLoader.gpiiKeyViewUrl + "?key=%22" + gpiiKeyId + "%22"; | ||
| var getGpiiKeysRequest = http.request(gpiiKeyViewUrl, function (resp) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Worrying lack of abstraction in all of this work. At the least there should be a wrapper for the process of invoking an HTTP request and waiting for responses from it as some kind of promise-producer. I don't want to slow down this work one atom so I'm not suggesting that it be re-expressed using https://github.com/fluid-project/kettle/blob/master/docs/DataSources.md#simple-example-of-using-an-http-datasource but something needs to happen to unwrap the tangle in this method which by line 88 we are 4 closures deep. It's hard to follow this expression of the algorithm, it is brittle, and seems prone to races which are already causing confusion. Also consider utilities like https://docs.fluidproject.org/infusion/development/PromisesAPI.html#fluidpromisesequencesources-options |
||
| var respString = ""; | ||
| resp.setEncoding("utf8"); | ||
| resp.on("data", function (chunk) { | ||
| respString += chunk; | ||
| }); | ||
| // This response "end" event doesn't finish until after the call to | ||
| // doBatchDelete() below, which is too late to add the GPII Key to | ||
| // docsToRemove and have them removed. | ||
| // Note - if there is a way to determine the final "end" event, then | ||
| // it could call doBatchDelete(). | ||
| resp.on("end", function () { | ||
| var gpiiKeyRecords = JSON.parse(respString); | ||
| fluid.each(gpiiKeyRecords.rows, function (gpiiKey) { | ||
| fluid.log("GPII Key: " + gpiiKey.value._id); | ||
| dbLoader.deleteGpiiKey(gpiiKey.value); | ||
| }); | ||
| }); | ||
| }); | ||
| getGpiiKeysRequest.on("error", function (e) { | ||
| fluid.log("Error finding snapsets' associated GPII Keys: " + e.message); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this should be "snapset's", unless the error message is going to contain errors from all the snapsets that failed?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The closest log message to this old one now has no apostrophe: "Error finding snapset Prefs Safes associated GPII Keys". |
||
| }); | ||
| getGpiiKeysRequest.end(); | ||
| }); | ||
| dbLoader.doBatchDelete(docsToRemove); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Deleting all prefs safe records here at the end of the script doesn't guarantee it to be run as the last task due to the aync nature of http requests above for getting and deleting gpii keys.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right, but it's another instance of "overtaken by events": The latest code handles the asynchrony. |
||
| }; | ||
|
|
||
| /** | ||
| * Delete the given GPII Key record. | ||
| * @param {Object} gpiiKey - The key to delete. | ||
| */ | ||
| dbLoader.deleteGpiiKey = function (gpiiKey) { | ||
| var deleteOptions = { | ||
| hostname: dbLoader.parsedCouchDbUrl.hostname, | ||
| port: dbLoader.parsedCouchDbUrl.port, | ||
| path: "", // filled in below. | ||
| method: "DELETE", | ||
| headers: { | ||
| "Accept": "application/json" | ||
| } | ||
| }; | ||
| deleteOptions.path = "/gpii/" + gpiiKey._id + "?rev=" + gpiiKey._rev; | ||
| var deleteGpiiKeyRequest = http.request(deleteOptions, function (res) { | ||
| fluid.log("STATUS: " + res.statusCode); | ||
| fluid.log("HEADERS: " + JSON.stringify(res.headers, null, 2)); | ||
| }); | ||
| deleteGpiiKeyRequest.on("error", function (e) { | ||
| fluid.log("Error finding GPII Key: " + e.message); | ||
| }); | ||
| deleteGpiiKeyRequest.end(); | ||
| }; | ||
|
|
||
| /** | ||
| * Delete the snapset Prefs Safes and their associated GPII Keys. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function only deletes prefs safes, not gpii keys.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With the use of promises, this now does delete all prefs safes and associated gpii keys. |
||
| * @param {Array} docsToRemove - Array of records to delete. | ||
| */ | ||
| dbLoader.doBatchDelete = function (docsToRemove) { | ||
| var batchDeleteOptions = { | ||
| hostname: dbLoader.parsedCouchDbUrl.hostname, | ||
| port: dbLoader.parsedCouchDbUrl.port, | ||
| path: "/gpii/_bulk_docs", | ||
| method: "POST", | ||
| headers: { | ||
| "Accept": "application/json", | ||
| "Content-Length": 0, // filled in below | ||
| "Content-Type": "application/json" | ||
| } | ||
| }; | ||
| var batchPostData = JSON.stringify({"docs": docsToRemove}); | ||
| batchDeleteOptions.headers["Content-Length"] = Buffer.byteLength(batchPostData); | ||
| var batchDeleteReq = http.request(batchDeleteOptions, function (res) { | ||
| fluid.log("STATUS: " + res.statusCode); | ||
| fluid.log("HEADERS: " + JSON.stringify(res.headers, null, 2)); | ||
| res.on('end', function () { | ||
| fluid.log('Batch deletion of snapsets'); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. snapsets -> snapset prefs safes.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Due to the refactoring, the log message includes "Prefs Safes", and also "GPII Keys".
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe this is clearer as "Finished batch deletion of..."?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And this one is now "Bulk deletion completed." |
||
| }); | ||
| }); | ||
| batchDeleteReq.on('error', function (e) { | ||
| fluid.log("Error deleting snapset Prefs Safes: " + e.message); | ||
| }); | ||
| batchDeleteReq.write(batchPostData); | ||
| batchDeleteReq.end(); | ||
| }; | ||
|
|
||
| dbLoader.snapSetsRequest = http.request(dbLoader.prefsSafesViewUrl, dbLoader.processSnapsets); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The couchdb url on the GPII cloud might be using https instead http. Will find out by testing with the developer cloud.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any progress on this, @cindyli ?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry about the confusion. I meant YOU will find out when testing with the cloud, not me. It's also worth to check with @mrtyler on this information since production/staging might act differently than dev clusters. |
||
| dbLoader.snapSetsRequest.on("error", function (e) { | ||
| fluid.log("Error finding snapsets Prefs Safes: " + e.message); | ||
| }); | ||
| dbLoader.snapSetsRequest.end(); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,6 +10,12 @@ | |
| }, | ||
| "findAuthorizationByAccessToken": { | ||
| "map": "function(doc) {if (doc.type === 'gpiiAppInstallationAuthorization' && doc.revoked === false) {emit(doc.accessToken, {'_id': doc.clientId, 'authorization': doc})}}" | ||
| }, | ||
| "findSnapsetPrefsSafes": { | ||
| "map": "function(doc) {if (doc.type === 'prefsSafe' && doc.prefsSafeType === 'snapset') {emit(doc._id, doc)}}" | ||
| }, | ||
| "findGpiiKeysByPrefsSafeId": { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This view is no longer used and can be removed.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok, deleted. |
||
| "map": "function(doc) {if (doc.type === 'gpiiKey') {emit(doc.prefsSafeId, doc)}}" | ||
| } | ||
| } | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update the usage too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure.