@cumulus/ingest 10.1.2 → 11.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/FtpProviderClient.d.ts +1 -1
- package/FtpProviderClient.d.ts.map +1 -1
- package/FtpProviderClient.js +6 -4
- package/FtpProviderClient.js.map +1 -1
- package/HttpProviderClient.d.ts.map +1 -1
- package/HttpProviderClient.js +5 -3
- package/HttpProviderClient.js.map +1 -1
- package/S3ProviderClient.d.ts +4 -3
- package/S3ProviderClient.d.ts.map +1 -1
- package/S3ProviderClient.js +21 -12
- package/S3ProviderClient.js.map +1 -1
- package/granule.d.ts +15 -26
- package/granule.d.ts.map +1 -1
- package/granule.js +63 -114
- package/granule.js.map +1 -1
- package/lock.d.ts +2 -2
- package/lock.d.ts.map +1 -1
- package/lock.js +12 -2
- package/lock.js.map +1 -1
- package/package.json +14 -14
- package/src/FtpProviderClient.ts +7 -5
- package/src/HttpProviderClient.js +5 -3
- package/src/S3ProviderClient.ts +21 -13
- package/src/granule.ts +74 -130
- package/src/lock.ts +14 -4
- package/src/types.ts +14 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/types.d.ts +8 -1
- package/types.d.ts.map +1 -1
- package/types.js +7 -0
- package/types.js.map +1 -1
package/lock.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lock.d.ts","sourceRoot":"","sources":["src/lock.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,IAAI;IACnB,GAAG,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"lock.d.ts","sourceRoot":"","sources":["src/lock.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,IAAI;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,IAAI,CAAA;CACpB;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,KAAK,GAAE,IAAI,EAAO,GACjB,OAAO,CAAC,MAAM,CAAC,CAoBjB;AAED;;;;;;GAMG;AACH,wBAAsB,SAAS,CAC7B,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,CAAC,CAOjB;AAcD,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAKf;AAED,wBAAsB,OAAO,CAC3B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE;IACR,EAAE,EAAE,MAAM,CAAC;IACX,qBAAqB,CAAC,EAAE,MAAM,CAAA;CAC/B,EACD,QAAQ,EAAE,MAAM,EAChB,OAAO,SAAI,GACV,OAAO,CAAC,OAAO,CAAC,CAwBlB"}
|
package/lock.js
CHANGED
|
@@ -41,8 +41,18 @@ const lockPrefix = 'lock';
|
|
|
41
41
|
**/
|
|
42
42
|
async function checkOldLocks(bucket, locks = []) {
|
|
43
43
|
const fiveMinutesAgo = Date.now() - (5 * 60 * 1000);
|
|
44
|
-
const expiredLocks = locks.filter((lock) =>
|
|
45
|
-
|
|
44
|
+
const expiredLocks = locks.filter((lock) => {
|
|
45
|
+
if (!lock.LastModified) {
|
|
46
|
+
throw new TypeError(`Could not find LastModified on ${JSON.stringify(lock)}`);
|
|
47
|
+
}
|
|
48
|
+
return lock.LastModified.getTime() < fiveMinutesAgo;
|
|
49
|
+
});
|
|
50
|
+
await Promise.all(expiredLocks.map((lock) => {
|
|
51
|
+
if (!lock.Key) {
|
|
52
|
+
throw new TypeError(`Could not find Key on ${JSON.stringify(lock)}`);
|
|
53
|
+
}
|
|
54
|
+
return (0, S3_1.deleteS3Object)(bucket, lock.Key);
|
|
55
|
+
}));
|
|
46
56
|
return locks.length - expiredLocks.length;
|
|
47
57
|
}
|
|
48
58
|
exports.checkOldLocks = checkOldLocks;
|
package/lock.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lock.js","sourceRoot":"","sources":["src/lock.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,kDAA0B;AAC1B,+CAIgC;AAChC,yDAA2C;AAE3C,MAAM,UAAU,GAAG,MAAM,CAAC;AAO1B;;;;;;;GAOG;AACI,KAAK,UAAU,aAAa,CACjC,MAAc,EACd,QAAgB,EAAE;IAElB,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAEpD,MAAM,YAAY,GAAG,KAAK,CAAC,MAAM,CAC/B,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,GAAG,cAAc,
|
|
1
|
+
{"version":3,"file":"lock.js","sourceRoot":"","sources":["src/lock.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cumulus/ingest",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "11.1.1",
|
|
4
4
|
"description": "Ingest utilities",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=12.18.0"
|
|
@@ -38,13 +38,13 @@
|
|
|
38
38
|
"author": "Cumulus Authors",
|
|
39
39
|
"license": "Apache-2.0",
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@cumulus/aws-client": "
|
|
42
|
-
"@cumulus/common": "
|
|
43
|
-
"@cumulus/db": "
|
|
44
|
-
"@cumulus/errors": "
|
|
45
|
-
"@cumulus/logger": "
|
|
46
|
-
"@cumulus/message": "
|
|
47
|
-
"@cumulus/sftp-client": "
|
|
41
|
+
"@cumulus/aws-client": "11.1.1",
|
|
42
|
+
"@cumulus/common": "11.1.1",
|
|
43
|
+
"@cumulus/db": "11.1.1",
|
|
44
|
+
"@cumulus/errors": "11.1.1",
|
|
45
|
+
"@cumulus/logger": "11.1.1",
|
|
46
|
+
"@cumulus/message": "11.1.1",
|
|
47
|
+
"@cumulus/sftp-client": "11.1.1",
|
|
48
48
|
"aws-sdk": "^2.585.0",
|
|
49
49
|
"cksum": "^1.3.0",
|
|
50
50
|
"delay": "^4.3.0",
|
|
@@ -56,15 +56,15 @@
|
|
|
56
56
|
"jsftp": "https://github.com/jkovarik/jsftp.git#add_288",
|
|
57
57
|
"lodash": "^4.17.21",
|
|
58
58
|
"mime-types": "^2.1.22",
|
|
59
|
-
"moment": "2.29.
|
|
59
|
+
"moment": "2.29.2",
|
|
60
60
|
"simplecrawler": "^1.1.9",
|
|
61
61
|
"tough-cookie": "^4.0.0"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
|
-
"@cumulus/checksum": "
|
|
65
|
-
"@cumulus/cmrjs": "
|
|
66
|
-
"@cumulus/test-data": "
|
|
67
|
-
"@cumulus/types": "
|
|
64
|
+
"@cumulus/checksum": "11.1.1",
|
|
65
|
+
"@cumulus/cmrjs": "11.1.1",
|
|
66
|
+
"@cumulus/test-data": "11.1.1",
|
|
67
|
+
"@cumulus/types": "11.1.1"
|
|
68
68
|
},
|
|
69
|
-
"gitHead": "
|
|
69
|
+
"gitHead": "07fe682da23821434372759fb1948b081da429b5"
|
|
70
70
|
}
|
package/src/FtpProviderClient.ts
CHANGED
|
@@ -215,7 +215,7 @@ class FtpProviderClient implements ProviderClient {
|
|
|
215
215
|
fileRemotePath: string,
|
|
216
216
|
destinationBucket: string,
|
|
217
217
|
destinationKey: string
|
|
218
|
-
}): Promise<{ s3uri: string, etag
|
|
218
|
+
}): Promise<{ s3uri: string, etag?: string }> {
|
|
219
219
|
const { fileRemotePath, destinationBucket, destinationKey } = params;
|
|
220
220
|
const remoteUrl = `ftp://${this.host}/${fileRemotePath}`;
|
|
221
221
|
const s3uri = S3.buildS3Uri(destinationBucket, destinationKey);
|
|
@@ -237,10 +237,12 @@ class FtpProviderClient implements ProviderClient {
|
|
|
237
237
|
readable.pipe(pass);
|
|
238
238
|
|
|
239
239
|
const s3Params = {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
240
|
+
params: {
|
|
241
|
+
Bucket: destinationBucket,
|
|
242
|
+
Key: destinationKey,
|
|
243
|
+
Body: pass,
|
|
244
|
+
ContentType: lookupMimeType(destinationKey),
|
|
245
|
+
},
|
|
244
246
|
};
|
|
245
247
|
|
|
246
248
|
try {
|
|
@@ -279,9 +279,11 @@ class HttpProviderClient {
|
|
|
279
279
|
const { ETag: etag } = await streamS3Upload(
|
|
280
280
|
uploadStream,
|
|
281
281
|
{
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
282
|
+
params: {
|
|
283
|
+
Bucket: destinationBucket,
|
|
284
|
+
Key: destinationKey,
|
|
285
|
+
ContentType: contentType,
|
|
286
|
+
},
|
|
285
287
|
}
|
|
286
288
|
);
|
|
287
289
|
|
package/src/S3ProviderClient.ts
CHANGED
|
@@ -2,7 +2,7 @@ import * as S3 from '@cumulus/aws-client/S3';
|
|
|
2
2
|
import * as log from '@cumulus/common/log';
|
|
3
3
|
import * as errors from '@cumulus/errors';
|
|
4
4
|
import { basename, dirname, join } from 'path';
|
|
5
|
-
import { ProviderClient, S3ProviderClientListItem } from './types';
|
|
5
|
+
import { ProviderClient, S3ProviderClientListItem, isS3ObjectListItem } from './types';
|
|
6
6
|
|
|
7
7
|
class S3ProviderClient implements ProviderClient {
|
|
8
8
|
private readonly bucket: string;
|
|
@@ -15,9 +15,10 @@ class S3ProviderClient implements ProviderClient {
|
|
|
15
15
|
/**
|
|
16
16
|
* Download a remote file to disk
|
|
17
17
|
*
|
|
18
|
-
* @param {
|
|
19
|
-
* @param {string}
|
|
20
|
-
* @param {string}
|
|
18
|
+
* @param {Object} params
|
|
19
|
+
* @param {string} params.remotePath - the full path to the remote file to be fetched
|
|
20
|
+
* @param {string} params.localPath - the full local destination file path
|
|
21
|
+
* @param {string} params.remoteAltBucket - alternate per-file bucket override to this.bucket
|
|
21
22
|
* bucket
|
|
22
23
|
* @returns {Promise<string>} - the path that the file was saved to
|
|
23
24
|
*/
|
|
@@ -58,14 +59,21 @@ class S3ProviderClient implements ProviderClient {
|
|
|
58
59
|
Prefix: path,
|
|
59
60
|
});
|
|
60
61
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
62
|
+
if (!objects) return [];
|
|
63
|
+
|
|
64
|
+
return objects.map((object) => {
|
|
65
|
+
if (!isS3ObjectListItem(object)) {
|
|
66
|
+
throw new TypeError(`S3 object ${object} did not have expected type`);
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
name: basename(object.Key),
|
|
70
|
+
// If the object is at the top level of the bucket, path.dirname is going
|
|
71
|
+
// to return "." as the dirname. It should instead be undefined.
|
|
72
|
+
path: dirname(object.Key) === '.' ? undefined : dirname(object.Key),
|
|
73
|
+
size: object.Size,
|
|
74
|
+
time: object.LastModified.valueOf(),
|
|
75
|
+
};
|
|
76
|
+
});
|
|
69
77
|
}
|
|
70
78
|
|
|
71
79
|
/**
|
|
@@ -129,7 +137,7 @@ class S3ProviderClient implements ProviderClient {
|
|
|
129
137
|
});
|
|
130
138
|
return { s3uri, etag };
|
|
131
139
|
} catch (error) {
|
|
132
|
-
if (error.
|
|
140
|
+
if (error.name === 'NotFound' || error.name === 'NoSuchKey') {
|
|
133
141
|
const sourceUrl = S3.buildS3Uri(sourceBucket, fileRemotePath);
|
|
134
142
|
throw new errors.FileNotFound(`Source file not found ${sourceUrl}`);
|
|
135
143
|
}
|
package/src/granule.ts
CHANGED
|
@@ -3,9 +3,9 @@ import moment from 'moment';
|
|
|
3
3
|
import { s3 } from '@cumulus/aws-client/services';
|
|
4
4
|
import * as S3 from '@cumulus/aws-client/S3';
|
|
5
5
|
import * as log from '@cumulus/common/log';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
6
|
+
import { ApiFile, DuplicateHandling } from '@cumulus/types';
|
|
7
|
+
import { FilePgModel, translatePostgresFileToApiFile, Knex } from '@cumulus/db';
|
|
8
|
+
import { RecordDoesNotExist } from '@cumulus/errors';
|
|
9
9
|
|
|
10
10
|
export interface EventWithDuplicateHandling {
|
|
11
11
|
config: {
|
|
@@ -26,7 +26,8 @@ export interface File {
|
|
|
26
26
|
key?: string,
|
|
27
27
|
fileName?: string,
|
|
28
28
|
name?: string,
|
|
29
|
-
filename?: string
|
|
29
|
+
filename?: string,
|
|
30
|
+
size?: string
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
export interface MovedGranuleFile {
|
|
@@ -49,8 +50,8 @@ export interface MoveFileParams {
|
|
|
49
50
|
|
|
50
51
|
export interface VersionedObject {
|
|
51
52
|
Bucket: string,
|
|
52
|
-
Key
|
|
53
|
-
size
|
|
53
|
+
Key?: string,
|
|
54
|
+
size?: number
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
/**
|
|
@@ -106,11 +107,14 @@ export async function listVersionedObjects(
|
|
|
106
107
|
Prefix: `${key}.v`,
|
|
107
108
|
});
|
|
108
109
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
110
|
+
if (s3list) {
|
|
111
|
+
return s3list.map(({ Key, Size }) => ({
|
|
112
|
+
Bucket: bucket,
|
|
113
|
+
Key,
|
|
114
|
+
size: Size,
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
117
|
+
return [];
|
|
114
118
|
}
|
|
115
119
|
|
|
116
120
|
/**
|
|
@@ -283,8 +287,23 @@ export async function handleDuplicateFile(params: {
|
|
|
283
287
|
return [];
|
|
284
288
|
}
|
|
285
289
|
|
|
286
|
-
|
|
287
|
-
|
|
290
|
+
/**
|
|
291
|
+
* Get the name of the file from the following properties (in order of preference):
|
|
292
|
+
* 1. fileName (e.g. 'granuleFileNamec.md')
|
|
293
|
+
* 2. name (e.g. 'granuleFileName.md')
|
|
294
|
+
* 3. key (e.g. 'stackname/filepath/granuleFileName.md')
|
|
295
|
+
* @param {File} file - file object with the above properties
|
|
296
|
+
* @returns {string | undefined} - The file name as a string or undefined
|
|
297
|
+
*/
|
|
298
|
+
export const getNameOfFile = (file: File): string | undefined => {
|
|
299
|
+
const fileName = file.fileName ?? file.name;
|
|
300
|
+
|
|
301
|
+
if (!fileName) {
|
|
302
|
+
return file.key?.split('/').pop();
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return fileName;
|
|
306
|
+
};
|
|
288
307
|
|
|
289
308
|
/**
|
|
290
309
|
* For each source file, see if there is a destination and generate the source
|
|
@@ -346,149 +365,74 @@ export function generateMoveFileParams(
|
|
|
346
365
|
}
|
|
347
366
|
|
|
348
367
|
/**
|
|
349
|
-
|
|
350
|
-
*
|
|
351
|
-
* @param {Array<Object>} sourceFiles - array of file objects, they are updated with destination
|
|
352
|
-
* location after the files are moved
|
|
353
|
-
* @param {string} sourceFiles.name - file name
|
|
354
|
-
* @param {string} sourceFiles.bucket - current bucket of file
|
|
355
|
-
* @param {string} sourceFiles.key - current S3 key of file
|
|
356
|
-
* @param {Array<Object>} destinations - array of objects defining the destination of granule files
|
|
357
|
-
* @param {string} destinations.regex - regex for matching filepath of file to new destination
|
|
358
|
-
* @param {string} destinations.bucket - aws bucket of the destination
|
|
359
|
-
* @param {string} destinations.filepath - file path/directory on the bucket for the destination
|
|
360
|
-
* @returns {Promise<Array>} returns array of source files updated with new locations.
|
|
361
|
-
*/
|
|
362
|
-
export async function moveGranuleFiles(
|
|
363
|
-
sourceFiles: File[],
|
|
364
|
-
destinations: {
|
|
365
|
-
regex: string,
|
|
366
|
-
bucket: string,
|
|
367
|
-
filepath: string
|
|
368
|
-
}[]
|
|
369
|
-
): Promise<MovedGranuleFile[]> {
|
|
370
|
-
deprecate(
|
|
371
|
-
'@cumulus/ingest/moveGranuleFiles',
|
|
372
|
-
'9.0.0'
|
|
373
|
-
);
|
|
374
|
-
const moveFileParams = generateMoveFileParams(sourceFiles, destinations);
|
|
375
|
-
const movedGranuleFiles: MovedGranuleFile[] = [];
|
|
376
|
-
const moveFileRequests = moveFileParams.map(
|
|
377
|
-
async (moveFileParam) => {
|
|
378
|
-
const { source, target, file } = moveFileParam;
|
|
379
|
-
|
|
380
|
-
if (source && target) {
|
|
381
|
-
log.debug('moveGranuleFiles', source, target);
|
|
382
|
-
|
|
383
|
-
await S3.moveObject({
|
|
384
|
-
sourceBucket: source.Bucket,
|
|
385
|
-
sourceKey: source.Key,
|
|
386
|
-
destinationBucket: target.Bucket,
|
|
387
|
-
destinationKey: target.Key,
|
|
388
|
-
copyTags: true,
|
|
389
|
-
});
|
|
390
|
-
|
|
391
|
-
movedGranuleFiles.push({
|
|
392
|
-
bucket: target.Bucket,
|
|
393
|
-
key: target.Key,
|
|
394
|
-
name: getNameOfFile(file),
|
|
395
|
-
});
|
|
396
|
-
} else {
|
|
397
|
-
let fileBucket;
|
|
398
|
-
let fileKey;
|
|
399
|
-
if (file.bucket && file.key) {
|
|
400
|
-
fileBucket = file.bucket;
|
|
401
|
-
fileKey = file.key;
|
|
402
|
-
} else if (file.filename) {
|
|
403
|
-
const parsed = S3.parseS3Uri(file.filename);
|
|
404
|
-
fileBucket = parsed.Bucket;
|
|
405
|
-
fileKey = parsed.Key;
|
|
406
|
-
} else {
|
|
407
|
-
throw new Error(`Unable to determine location of file: ${JSON.stringify(file)}`);
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
movedGranuleFiles.push({
|
|
411
|
-
bucket: fileBucket,
|
|
412
|
-
key: fileKey,
|
|
413
|
-
name: getNameOfFile(file),
|
|
414
|
-
});
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
);
|
|
418
|
-
await Promise.all(moveFileRequests);
|
|
419
|
-
return movedGranuleFiles;
|
|
420
|
-
}
|
|
421
|
-
/**
|
|
422
|
-
* Moves a granule file and updates the postgres database accordingly
|
|
368
|
+
* Moves a granule file and updates the datastore accordingly
|
|
423
369
|
* @summary Moves a granule file record according to MoveFileParams and updates database accordingly
|
|
424
370
|
* @param {MoveFileParams} moveFileParam - Parameter object describing the move operation
|
|
425
371
|
* @param {FilePgModel} filesPgModel - FilePgModel instance
|
|
426
372
|
* @param {Knex.Transaction | Knex} trx - Knex transaction or (optionally) Knex object
|
|
427
373
|
* @param {number | undefined } postgresCumulusGranuleId - postgres internal granule id
|
|
428
|
-
* @
|
|
429
|
-
* @returns {ReturnValueDataTypeHere} Brief description of the returning value here.
|
|
374
|
+
* @returns {Promise<Object>} - Returns object of type Omit<ApiFile, 'granuleId>>
|
|
430
375
|
*/
|
|
431
376
|
export async function moveGranuleFile(
|
|
432
377
|
moveFileParam: MoveFileParams,
|
|
433
378
|
filesPgModel: FilePgModel,
|
|
434
379
|
trx: Knex.Transaction | Knex,
|
|
435
|
-
postgresCumulusGranuleId: number | undefined
|
|
436
|
-
|
|
437
|
-
): Promise<MovedGranuleFile> {
|
|
380
|
+
postgresCumulusGranuleId: number | undefined
|
|
381
|
+
): Promise<Omit<ApiFile, 'granuleId'>> {
|
|
438
382
|
const { source, target, file } = moveFileParam;
|
|
439
|
-
|
|
383
|
+
|
|
384
|
+
if (source && target) {
|
|
440
385
|
log.debug('moveGranuleS3Object', source, target);
|
|
441
|
-
if (
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
386
|
+
if (!postgresCumulusGranuleId) {
|
|
387
|
+
throw new Error('postgresCumulusGranuleId must be defined to move granule file if writeToPostgres is true');
|
|
388
|
+
}
|
|
389
|
+
const updatedPgRecords = await filesPgModel.update(
|
|
390
|
+
trx,
|
|
391
|
+
{
|
|
446
392
|
granule_cumulus_id: postgresCumulusGranuleId,
|
|
447
|
-
bucket:
|
|
448
|
-
key:
|
|
449
|
-
});
|
|
450
|
-
await filesPgModel.update(trx, {
|
|
451
|
-
cumulus_id: cumulusId,
|
|
393
|
+
bucket: source.Bucket,
|
|
394
|
+
key: source.Key,
|
|
452
395
|
},
|
|
453
396
|
{
|
|
454
|
-
bucket:
|
|
455
|
-
key:
|
|
397
|
+
bucket: target.Bucket,
|
|
398
|
+
key: target.Key,
|
|
456
399
|
file_name: getNameOfFile(file),
|
|
457
|
-
}
|
|
400
|
+
}, ['*']
|
|
401
|
+
);
|
|
402
|
+
if (updatedPgRecords.length !== 1) {
|
|
403
|
+
throw new RecordDoesNotExist('Attempted to update granule on move, but granule does not exist');
|
|
458
404
|
}
|
|
405
|
+
const updatedPgRecord = updatedPgRecords[0];
|
|
406
|
+
|
|
459
407
|
await S3.moveObject({
|
|
460
|
-
sourceBucket:
|
|
461
|
-
sourceKey:
|
|
462
|
-
destinationBucket:
|
|
463
|
-
destinationKey:
|
|
408
|
+
sourceBucket: source.Bucket,
|
|
409
|
+
sourceKey: source.Key,
|
|
410
|
+
destinationBucket: target.Bucket,
|
|
411
|
+
destinationKey: target.Key,
|
|
464
412
|
copyTags: true,
|
|
465
413
|
});
|
|
466
414
|
|
|
467
415
|
return {
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
416
|
+
...translatePostgresFileToApiFile(updatedPgRecord),
|
|
417
|
+
bucket: target.Bucket,
|
|
418
|
+
key: target.Key,
|
|
419
|
+
fileName: getNameOfFile({ key: target.Key }),
|
|
471
420
|
};
|
|
472
421
|
}
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
if (file.bucket && file.key) {
|
|
476
|
-
fileBucket = file.bucket;
|
|
477
|
-
fileKey = file.key;
|
|
478
|
-
} else if (file.filename) {
|
|
422
|
+
|
|
423
|
+
if (!(file.bucket || file.key) && file.filename) {
|
|
479
424
|
const parsed = S3.parseS3Uri(file.filename);
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
} else {
|
|
483
|
-
throw new Error(
|
|
484
|
-
`Unable to determine location of file: ${JSON.stringify(file)}`
|
|
485
|
-
);
|
|
425
|
+
file.bucket = parsed.Bucket;
|
|
426
|
+
file.key = parsed.Key;
|
|
486
427
|
}
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
428
|
+
|
|
429
|
+
const postgresFileRecord = await filesPgModel.get(trx, {
|
|
430
|
+
granule_cumulus_id: postgresCumulusGranuleId,
|
|
431
|
+
bucket: file.bucket,
|
|
432
|
+
key: file.key,
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
return translatePostgresFileToApiFile(postgresFileRecord);
|
|
492
436
|
}
|
|
493
437
|
|
|
494
438
|
/**
|
package/src/lock.ts
CHANGED
|
@@ -9,8 +9,8 @@ import * as log from '@cumulus/common/log';
|
|
|
9
9
|
const lockPrefix = 'lock';
|
|
10
10
|
|
|
11
11
|
export interface Lock {
|
|
12
|
-
Key
|
|
13
|
-
LastModified
|
|
12
|
+
Key?: string,
|
|
13
|
+
LastModified?: Date
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
/**
|
|
@@ -28,10 +28,20 @@ export async function checkOldLocks(
|
|
|
28
28
|
const fiveMinutesAgo = Date.now() - (5 * 60 * 1000);
|
|
29
29
|
|
|
30
30
|
const expiredLocks = locks.filter(
|
|
31
|
-
(lock) =>
|
|
31
|
+
(lock) => {
|
|
32
|
+
if (!lock.LastModified) {
|
|
33
|
+
throw new TypeError(`Could not find LastModified on ${JSON.stringify(lock)}`);
|
|
34
|
+
}
|
|
35
|
+
return lock.LastModified.getTime() < fiveMinutesAgo;
|
|
36
|
+
}
|
|
32
37
|
);
|
|
33
38
|
|
|
34
|
-
await Promise.all(expiredLocks.map((
|
|
39
|
+
await Promise.all(expiredLocks.map((lock) => {
|
|
40
|
+
if (!lock.Key) {
|
|
41
|
+
throw new TypeError(`Could not find Key on ${JSON.stringify(lock)}`);
|
|
42
|
+
}
|
|
43
|
+
return deleteS3Object(bucket, lock.Key);
|
|
44
|
+
}));
|
|
35
45
|
|
|
36
46
|
return locks.length - expiredLocks.length;
|
|
37
47
|
}
|
package/src/types.ts
CHANGED
|
@@ -5,6 +5,13 @@ export interface ProviderClientListItem {
|
|
|
5
5
|
time: number
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
+
export interface S3ObjectListItem {
|
|
9
|
+
Bucket: string
|
|
10
|
+
Key: string
|
|
11
|
+
LastModified: Date
|
|
12
|
+
Size: number
|
|
13
|
+
}
|
|
14
|
+
|
|
8
15
|
export interface FtpProviderClientListItem extends ProviderClientListItem {
|
|
9
16
|
type: number
|
|
10
17
|
}
|
|
@@ -34,5 +41,11 @@ export interface ProviderClient {
|
|
|
34
41
|
destinationKey: string,
|
|
35
42
|
bucket?: string,
|
|
36
43
|
}
|
|
37
|
-
): Promise<{ s3uri: string, etag
|
|
44
|
+
): Promise<{ s3uri: string, etag?: string }>
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function isS3ObjectListItem(s3Object: any): s3Object is S3ObjectListItem {
|
|
48
|
+
return (s3Object as S3ObjectListItem).Key !== undefined
|
|
49
|
+
&& (s3Object as S3ObjectListItem).Size !== undefined
|
|
50
|
+
&& (s3Object as S3ObjectListItem).LastModified !== undefined;
|
|
38
51
|
}
|