Skip to content

Commit 77cbbdc

Browse files
migrate verifyReplication to aws sdk v3
Issue : S3UTILS-201
1 parent e944782 commit 77cbbdc

File tree

2 files changed

+84
-89
lines changed

2 files changed

+84
-89
lines changed

VerifyReplication/storage/s3.js

Lines changed: 74 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
const AWS = require('aws-sdk');
1+
const { S3Client, HeadObjectCommand, ListObjectsV2Command } = require('@aws-sdk/client-s3');
2+
const { NodeHttpHandler } = require('@aws-sdk/node-http-handler');
3+
const { ConfiguredRetryStrategy } = require('@smithy/util-retry');
24
const fs = require('fs');
35
const http = require('http');
46
const https = require('https');
@@ -19,7 +21,6 @@ function getClient(params) {
1921
} = params;
2022
const s3EndpointIsHttps = (endpoint && endpoint.startsWith('https:')) || false;
2123
let agent;
22-
let clientLogger;
2324

2425
if (s3EndpointIsHttps) {
2526
agent = new https.Agent({
@@ -31,61 +32,54 @@ function getClient(params) {
3132
agent = new http.Agent({ keepAlive: true });
3233
}
3334

34-
// enable/disable sdk logs
35-
if (showClientLogsIfAvailable) {
36-
// TODO: may be use werelogs
37-
clientLogger = console;
38-
}
35+
// Configure retry strategy to match original AWS SDK v2 configuration
36+
// Options specific to s3 requests - maxRetries & customBackoff
37+
// Default aws sdk retry count is 3 with an exponential delay of 2^n * 30 ms
38+
const retryStrategy = new ConfiguredRetryStrategy(
39+
defaults.AWS_SDK_REQUEST_RETRIES,
40+
(retryCount) => {
41+
// retry with exponential backoff delay capped at 60s max
42+
// between retries, and a little added jitter
43+
const backoff = Math.min(defaults.AWS_SDK_REQUEST_INITIAL_DELAY_MS
44+
* 2 ** retryCount, defaults.AWS_SDK_REQUEST_MAX_BACKOFF_LIMIT_MS)
45+
* (0.9 + Math.random() * 0.2);
46+
// show retry errors only if client logs are enabled as this may
47+
// increase log size!
48+
if (showClientLogsIfAvailable) {
49+
log.error('awssdk request error', {
50+
retryCount,
51+
backoff,
52+
});
53+
}
54+
return backoff;
55+
}
56+
);
3957

40-
const options = {
41-
accessKeyId: accessKey,
42-
secretAccessKey: secretKey,
43-
endpoint,
44-
region,
45-
sslEnabled: s3EndpointIsHttps,
46-
s3ForcePathStyle: true,
47-
apiVersions: { s3: '2006-03-01' },
48-
signatureVersion: 'v4',
49-
signatureCache: false,
50-
httpOptions: {
51-
timeout: httpTimeout,
52-
agent,
58+
const clientConfig = {
59+
region: region,
60+
credentials: {
61+
accessKeyId: accessKey,
62+
secretAccessKey: secretKey,
5363
},
54-
logger: clientLogger,
64+
endpoint,
65+
forcePathStyle: true,
66+
retryStrategy,
67+
requestHandler: new NodeHttpHandler({
68+
httpAgent: s3EndpointIsHttps ? undefined : agent,
69+
httpsAgent: s3EndpointIsHttps ? agent : undefined,
70+
requestTimeout: httpTimeout || 300000,
71+
}),
5572
};
5673

57-
/**
58-
* Options specific to s3 requests
59-
* `maxRetries` & `customBackoff` are set only to s3 requests
60-
* default aws sdk retry count is 3 with an exponential delay of 2^n * 30 ms
61-
*/
62-
const s3Options = {
63-
maxRetries: defaults.AWS_SDK_REQUEST_RETRIES,
64-
retryDelayOptions: {
65-
customBackoff: (retryCount, error) => {
66-
// retry with exponential backoff delay capped at 60s max
67-
// between retries, and a little added jitter
68-
const backoff = Math.min(defaults.AWS_SDK_REQUEST_INITIAL_DELAY_MS
69-
* 2 ** retryCount, defaults.AWS_SDK_REQUEST_MAX_BACKOFF_LIMIT_MS)
70-
* (0.9 + Math.random() * 0.2);
71-
// show retry errors only if client logs are enabled as this may
72-
// increase log size!
73-
if (showClientLogsIfAvailable) {
74-
log.error('awssdk request error', {
75-
error,
76-
retryCount,
77-
backoff,
78-
});
79-
}
80-
return backoff;
81-
},
82-
},
83-
};
74+
// Add logger if available
75+
if (showClientLogsIfAvailable) {
76+
clientConfig.logger = console;
77+
}
8478

85-
return new AWS.S3({ ...options, ...s3Options });
79+
return new S3Client(clientConfig);
8680
}
8781

88-
function getObjMd(params, cb) {
82+
async function getObjMd(params, cb) {
8983
const {
9084
client,
9185
bucket,
@@ -98,31 +92,29 @@ function getObjMd(params, cb) {
9892
return cb(new Error(errMsg));
9993
}
10094

101-
return client.headObject({
102-
Bucket: bucket,
103-
Key: key,
104-
VersionId: versionId,
105-
}, (err, data) => {
106-
if (err) {
107-
return cb(err);
95+
try {
96+
const commandParams = {
97+
Bucket: bucket,
98+
Key: key,
99+
};
100+
if (versionId) {
101+
commandParams.VersionId = versionId;
108102
}
109-
const {
110-
ContentLength,
111-
LastModified,
112-
VersionId,
113-
Metadata,
114-
} = data;
103+
104+
const data = await client.send(new HeadObjectCommand(commandParams));
115105
const resp = {
116-
size: ContentLength,
117-
lastModified: LastModified,
118-
versionId: VersionId,
119-
md: Metadata,
106+
size: data.ContentLength,
107+
lastModified: data.LastModified,
108+
versionId: data.VersionId,
109+
md: data.Metadata,
120110
};
121111
return cb(null, resp);
122-
});
112+
} catch (err) {
113+
return cb(err);
114+
}
123115
}
124116

125-
function listObjects(params, cb) {
117+
async function listObjects(params, cb) {
126118
const {
127119
client,
128120
bucket,
@@ -140,14 +132,19 @@ function listObjects(params, cb) {
140132
return cb(new Error(errMsg));
141133
}
142134

143-
// TODO: support listing all versions
144-
return client.listObjectsV2({
145-
Bucket: bucket,
146-
MaxKeys: listingLimit,
147-
Prefix: prefix,
148-
Delimiter: delimiter,
149-
ContinuationToken: nextContinuationToken,
150-
}, cb);
135+
try {
136+
// TODO: support listing all versions
137+
const data = await client.send(new ListObjectsV2Command({
138+
Bucket: bucket,
139+
MaxKeys: listingLimit,
140+
Prefix: prefix,
141+
Delimiter: delimiter,
142+
ContinuationToken: nextContinuationToken,
143+
}));
144+
return cb(null, data);
145+
} catch (err) {
146+
return cb(err);
147+
}
151148
}
152149

153150
module.exports = {

VerifyReplication/verifyReplication.js

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const async = require('async');
22

33
const storage = require('./storage');
4+
const { NotFound } = require('@aws-sdk/client-s3');
45

56
let bucketMatch = false;
67
let compareSize = false;
@@ -41,26 +42,20 @@ function verifyObjects(objectList, cb) {
4142

4243
return destinationStorage.getObjMd(params, (err, dstMd) => {
4344
++statusObj.dstProcessedCount;
44-
if (err && err.code !== 'NotFound') {
45+
if (err) {
4546
++statusObj.dstFailedMdRetrievalsCount;
4647
logger.error('error getting metadata', {
4748
error: err,
4849
bucket: statusObj.dstBucket,
4950
key: dstKey,
5051
srcLastModified,
5152
});
53+
if (err instanceof NotFound) {
54+
++statusObj.missingInDstCount;
55+
}
5256
// log the error and continue processing objects
5357
return done();
5458
}
55-
if (err && err.code === 'NotFound') {
56-
++statusObj.missingInDstCount;
57-
logger.info('object missing in destination', {
58-
key,
59-
size,
60-
srcLastModified,
61-
});
62-
return done();
63-
}
6459
const srcSize = Number.parseInt(size, 10);
6560
const dstSize = Number.parseInt(dstMd.size, 10);
6661
if (compareSize && (srcSize !== dstSize)) {
@@ -81,6 +76,9 @@ function verifyObjects(objectList, cb) {
8176
}
8277

8378
function handlePrefixes(prefixList, cb) {
79+
if (!prefixList || prefixList.length === 0) {
80+
return process.nextTick(cb);
81+
}
8482
const prefixes = prefixList.map(p => p.Prefix);
8583
return async.eachLimit(prefixes, listingWorkers, (prefix, done) => {
8684
const params = {
@@ -106,7 +104,7 @@ function listAndCompare(params, cb) {
106104
}
107105
const {
108106
IsTruncated,
109-
NextContinuationToken: nextContinuationToken,
107+
NextContinuationToken,
110108
Contents,
111109
CommonPrefixes,
112110
} = data;
@@ -118,7 +116,7 @@ function listAndCompare(params, cb) {
118116
return cb(error);
119117
}
120118
if (IsTruncated) {
121-
const listingParams = { ...params, nextContinuationToken };
119+
const listingParams = { ...params, nextContinuationToken: NextContinuationToken };
122120
return listAndCompare(listingParams, cb);
123121
}
124122
logger.info('completed listing and compare', {

0 commit comments

Comments
 (0)