@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/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;IACZ,YAAY,EAAE,IAAI,CAAA;CACnB;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,KAAK,GAAE,IAAI,EAAO,GACjB,OAAO,CAAC,MAAM,CAAC,CAUjB;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"}
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) => lock.LastModified.getTime() < fiveMinutesAgo);
45
- await Promise.all(expiredLocks.map(({ Key }) => (0, S3_1.deleteS3Object)(bucket, Key)));
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,CACvD,CAAC;IAEF,MAAM,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,IAAA,mBAAc,EAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;IAE9E,OAAO,KAAK,CAAC,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC;AAC5C,CAAC;AAbD,sCAaC;AAED;;;;;;GAMG;AACI,KAAK,UAAU,SAAS,CAC7B,MAAc,EACd,YAAoB;IAEpB,MAAM,KAAK,GAAG,MAAM,IAAA,oBAAe,EAAC;QAClC,MAAM,EAAE,MAAM;QACd,MAAM,EAAE,GAAG,UAAU,IAAI,YAAY,EAAE;KACxC,CAAC,CAAC;IAEH,OAAO,aAAa,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AACtC,CAAC;AAVD,8BAUC;AAED,KAAK,UAAU,OAAO,CACpB,MAAc,EACd,YAAoB,EACpB,QAAgB;IAEhB,MAAM,IAAA,gBAAW,EAAC;QAChB,MAAM,EAAE,MAAM;QACd,GAAG,EAAE,GAAG,UAAU,IAAI,YAAY,IAAI,QAAQ,EAAE;QAChD,IAAI,EAAE,EAAE;KACT,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,UAAU,CAC9B,MAAc,EACd,YAAoB,EACpB,QAAgB;IAEhB,MAAM,IAAA,mBAAc,EAClB,MAAM,EACN,GAAG,UAAU,IAAI,YAAY,IAAI,QAAQ,EAAE,CAC5C,CAAC;AACJ,CAAC;AATD,gCASC;AAEM,KAAK,UAAU,OAAO,CAC3B,MAAc,EACd,QAGC,EACD,QAAgB,EAChB,OAAO,GAAG,CAAC;IAEX,IAAI,QAAQ,CAAC,qBAAqB,KAAK,SAAS,EAAE;QAChD,OAAO,IAAI,CAAC;KACb;IAED,+CAA+C;IAC/C,IAAI,OAAO,GAAG,GAAG,EAAE;QACjB,OAAO,KAAK,CAAC;KACd;IAED,MAAM,qBAAqB,GAAG,QAAQ,CAAC,qBAAqB,CAAC;IAE7D,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;IAEnD,IAAI,KAAK,IAAI,qBAAqB,EAAE;QAClC,GAAG,CAAC,KAAK,CAAC,QAAQ,QAAQ,CAAC,EAAE,0CAA0C,QAAQ,CAAC,qBAAqB,qBAAqB,CAAC,CAAC;QAC5H,kCAAkC;QAClC,MAAM,IAAA,eAAK,EAAC,IAAI,CAAC,CAAC;QAClB,OAAO,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,GAAG,CAAC,CAAC,CAAC;KACzD;IAED,eAAe;IACf,MAAM,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC7C,OAAO,IAAI,CAAC;AACd,CAAC;AAhCD,0BAgCC"}
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;QACP,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE;YACtB,MAAM,IAAI,SAAS,CAAC,kCAAkC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;SAC/E;QACD,OAAO,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,GAAG,cAAc,CAAC;IACtD,CAAC,CACF,CAAC;IAEF,MAAM,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QAC1C,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE;YACb,MAAM,IAAI,SAAS,CAAC,yBAAyB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;SACtE;QACD,OAAO,IAAA,mBAAc,EAAC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC,CAAC;IAEJ,OAAO,KAAK,CAAC,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC;AAC5C,CAAC;AAvBD,sCAuBC;AAED;;;;;;GAMG;AACI,KAAK,UAAU,SAAS,CAC7B,MAAc,EACd,YAAoB;IAEpB,MAAM,KAAK,GAAG,MAAM,IAAA,oBAAe,EAAC;QAClC,MAAM,EAAE,MAAM;QACd,MAAM,EAAE,GAAG,UAAU,IAAI,YAAY,EAAE;KACxC,CAAC,CAAC;IAEH,OAAO,aAAa,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AACtC,CAAC;AAVD,8BAUC;AAED,KAAK,UAAU,OAAO,CACpB,MAAc,EACd,YAAoB,EACpB,QAAgB;IAEhB,MAAM,IAAA,gBAAW,EAAC;QAChB,MAAM,EAAE,MAAM;QACd,GAAG,EAAE,GAAG,UAAU,IAAI,YAAY,IAAI,QAAQ,EAAE;QAChD,IAAI,EAAE,EAAE;KACT,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,UAAU,CAC9B,MAAc,EACd,YAAoB,EACpB,QAAgB;IAEhB,MAAM,IAAA,mBAAc,EAClB,MAAM,EACN,GAAG,UAAU,IAAI,YAAY,IAAI,QAAQ,EAAE,CAC5C,CAAC;AACJ,CAAC;AATD,gCASC;AAEM,KAAK,UAAU,OAAO,CAC3B,MAAc,EACd,QAGC,EACD,QAAgB,EAChB,OAAO,GAAG,CAAC;IAEX,IAAI,QAAQ,CAAC,qBAAqB,KAAK,SAAS,EAAE;QAChD,OAAO,IAAI,CAAC;KACb;IAED,+CAA+C;IAC/C,IAAI,OAAO,GAAG,GAAG,EAAE;QACjB,OAAO,KAAK,CAAC;KACd;IAED,MAAM,qBAAqB,GAAG,QAAQ,CAAC,qBAAqB,CAAC;IAE7D,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;IAEnD,IAAI,KAAK,IAAI,qBAAqB,EAAE;QAClC,GAAG,CAAC,KAAK,CAAC,QAAQ,QAAQ,CAAC,EAAE,0CAA0C,QAAQ,CAAC,qBAAqB,qBAAqB,CAAC,CAAC;QAC5H,kCAAkC;QAClC,MAAM,IAAA,eAAK,EAAC,IAAI,CAAC,CAAC;QAClB,OAAO,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,GAAG,CAAC,CAAC,CAAC;KACzD;IAED,eAAe;IACf,MAAM,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC7C,OAAO,IAAI,CAAC;AACd,CAAC;AAhCD,0BAgCC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cumulus/ingest",
3
- "version": "10.1.2",
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": "10.1.2",
42
- "@cumulus/common": "10.1.2",
43
- "@cumulus/db": "10.1.2",
44
- "@cumulus/errors": "10.1.2",
45
- "@cumulus/logger": "10.1.2",
46
- "@cumulus/message": "10.1.2",
47
- "@cumulus/sftp-client": "10.1.2",
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.1",
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": "10.1.2",
65
- "@cumulus/cmrjs": "10.1.2",
66
- "@cumulus/test-data": "10.1.2",
67
- "@cumulus/types": "10.1.2"
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": "3b59753fa85064549b70ad8ed4a4ee213c5af313"
69
+ "gitHead": "07fe682da23821434372759fb1948b081da429b5"
70
70
  }
@@ -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: string }> {
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
- Bucket: destinationBucket,
241
- Key: destinationKey,
242
- Body: pass,
243
- ContentType: lookupMimeType(destinationKey),
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
- Bucket: destinationBucket,
283
- Key: destinationKey,
284
- ContentType: contentType,
282
+ params: {
283
+ Bucket: destinationBucket,
284
+ Key: destinationKey,
285
+ ContentType: contentType,
286
+ },
285
287
  }
286
288
  );
287
289
 
@@ -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 {string} remotePath - the full path to the remote file to be fetched
19
- * @param {string} localPath - the full local destination file path
20
- * @param {string} param.remoteAltBucket - alternate per-file bucket override to this.bucket
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
- return objects.map(({ Key, Size, LastModified }) => ({
62
- name: basename(Key),
63
- // If the object is at the top level of the bucket, path.dirname is going
64
- // to return "." as the dirname. It should instead be undefined.
65
- path: dirname(Key) === '.' ? undefined : dirname(Key),
66
- size: Size,
67
- time: LastModified.valueOf(),
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.code === 'NotFound' || error.code === 'NoSuchKey') {
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 { deprecate } from '@cumulus/common/util';
7
- import { DuplicateHandling } from '@cumulus/types';
8
- import { FilePgModel, Knex } from '@cumulus/db';
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: string,
53
- size: number
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
- return s3list.map(({ Key, Size }) => ({
110
- Bucket: bucket,
111
- Key,
112
- size: Size,
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
- export const getNameOfFile = (file: File): string | undefined =>
287
- file.fileName ?? file.name;
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
- * Moves granule files from one S3 location to another.
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
- * @param {boolean} writeToPostgres - explicit flag to enable/disable postgres database updates
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
- writeToPostgres: boolean = true
437
- ): Promise<MovedGranuleFile> {
380
+ postgresCumulusGranuleId: number | undefined
381
+ ): Promise<Omit<ApiFile, 'granuleId'>> {
438
382
  const { source, target, file } = moveFileParam;
439
- if (moveFileParam.source && moveFileParam.target) {
383
+
384
+ if (source && target) {
440
385
  log.debug('moveGranuleS3Object', source, target);
441
- if (writeToPostgres) {
442
- if (!postgresCumulusGranuleId) {
443
- throw new Error('postgresCumulusGranuleId must be defined to move granule file if writeToPostgres is true');
444
- }
445
- const cumulusId = await filesPgModel.getRecordCumulusId(trx, {
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: moveFileParam.source.Bucket,
448
- key: moveFileParam.source.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: moveFileParam.target.Bucket,
455
- key: moveFileParam.target.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: moveFileParam.source.Bucket,
461
- sourceKey: moveFileParam.source.Key,
462
- destinationBucket: moveFileParam.target.Bucket,
463
- destinationKey: moveFileParam.target.Key,
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
- bucket: moveFileParam.target.Bucket,
469
- key: moveFileParam.target.Key,
470
- name: getNameOfFile(file),
416
+ ...translatePostgresFileToApiFile(updatedPgRecord),
417
+ bucket: target.Bucket,
418
+ key: target.Key,
419
+ fileName: getNameOfFile({ key: target.Key }),
471
420
  };
472
421
  }
473
- let fileBucket;
474
- let fileKey;
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
- fileBucket = parsed.Bucket;
481
- fileKey = parsed.Key;
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
- return {
488
- bucket: fileBucket,
489
- key: fileKey,
490
- name: getNameOfFile(file),
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: string,
13
- LastModified: Date
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) => lock.LastModified.getTime() < fiveMinutesAgo
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(({ Key }) => deleteS3Object(bucket, Key)));
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: string }>
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
  }