Skip to content

Commit bb7499d

Browse files
committed
šŸ› use SUR date instead of the infostore one to have an update LastModified date
Issue: CLDSRV-878
1 parent 4aac273 commit bb7499d

File tree

4 files changed

+31
-12
lines changed

4 files changed

+31
-12
lines changed

ā€Žlib/routes/veeam/get.jsā€Ž

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ function getVeeamFile(request, response, bucketMd, log) {
3434

3535
// Extract the last modified date, but do not include it when computing
3636
// the file's ETag (md5)
37-
const modified = fileToBuild.value.LastModified;
37+
const modified = bucketMetrics?.date || fileToBuild.value.LastModified;
3838
delete fileToBuild.value.LastModified;
3939

4040
// The SOSAPI metrics are dynamically computed using the SUR backend.
@@ -53,15 +53,14 @@ function getVeeamFile(request, response, bucketMd, log) {
5353
return respondWithData(request, response, log, data,
5454
buildHeadXML(builder.buildObject(fileToBuild.value)), modified);
5555
};
56+
5657
if (!isSystemXML(request.objectKey)) {
5758
const bucketKey = `${bucketMd._name}_${new Date(bucketMd._creationDate).getTime()}`;
5859
return UtilizationService.getUtilizationMetrics('bucket', bucketKey, null, {}, (err, bucketMetrics) => {
5960
if (err) {
60-
// Handle errors from UtilizationService/scubaclient
61-
// axios errors have status in err.response.status
6261
const statusCode = err.response?.status || err.statusCode || err.code;
62+
6363
// Only handle 404 gracefully (no metrics available yet, e.g. post-install)
64-
// For 404, continue with static capacity data (Used=0 from bucket metadata)
6564
if (statusCode === 404) {
6665
log.warn('UtilizationService returned 404 when fetching capacity metrics', {
6766
method: 'getVeeamFile',
@@ -70,14 +69,17 @@ function getVeeamFile(request, response, bucketMd, log) {
7069
});
7170
return finalizeRequest();
7271
}
72+
7373
log.error('error fetching capacity metrics from UtilizationService', {
7474
method: 'getVeeamFile',
7575
bucket: request.bucketName,
7676
error: err.message || err.code,
7777
statusCode,
7878
});
79+
7980
return responseXMLBody(errors.InternalError, null, response, log);
8081
}
82+
8183
return finalizeRequest(bucketMetrics);
8284
});
8385
}

ā€Žlib/routes/veeam/head.jsā€Ž

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,33 @@ function headVeeamFile(request, response, bucketMd, log) {
1717
if (!bucketMd) {
1818
return responseXMLBody(errors.NoSuchBucket, null, response, log);
1919
}
20+
2021
return metadata.getBucket(request.bucketName, log, (err, data) => {
2122
if (err) {
2223
return responseXMLBody(errors.InternalError, null, response, log);
2324
}
25+
2426
const fileToBuild = getFileToBuild(request, data._capabilities?.VeeamSOSApi);
2527
if (fileToBuild.error) {
2628
return responseXMLBody(fileToBuild.error, null, response, log);
2729
}
28-
let modified = new Date().toISOString();
29-
// Extract the last modified date, but do not include it when computing
30-
// the file's ETag (md5)
31-
modified = fileToBuild.value.LastModified;
30+
31+
// Extract the last modified date, but do not include it when computing the file's ETag (md5)
32+
const modified = fileToBuild.value.LastModified;
3233
delete fileToBuild.value.LastModified;
3334
// Recompute file content to generate appropriate content-md5 header
3435
const builder = new xml2js.Builder({
3536
headless: true,
3637
});
3738
const dataBuffer = Buffer.from(buildHeadXML(builder.buildObject(fileToBuild)));
38-
return responseContentHeaders(null, {}, getResponseHeader(request, data,
39-
dataBuffer, modified, log), response, log);
39+
40+
return responseContentHeaders(
41+
null,
42+
{},
43+
getResponseHeader(request, data, dataBuffer, modified, log),
44+
response,
45+
log,
46+
);
4047
});
4148
}
4249

ā€Žlib/routes/veeam/utils.jsā€Ž

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,13 +172,15 @@ function isSystemXML(objectKey) {
172172
*/
173173
function getFileToBuild(request, data, inlineLastModified = false) {
174174
const _isSystemXML = isSystemXML(request.objectKey);
175-
const fileToBuild = _isSystemXML ? data?.SystemInfo
176-
: data?.CapacityInfo;
175+
const fileToBuild = _isSystemXML ? data?.SystemInfo : data?.CapacityInfo;
176+
177177
if (!fileToBuild) {
178178
return { error: errors.NoSuchKey };
179179
}
180+
180181
const modified = fileToBuild.LastModified || (new Date()).toISOString();
181182
const fieldName = _isSystemXML ? 'SystemInfo' : 'CapacityInfo';
183+
182184
if (inlineLastModified) {
183185
fileToBuild.LastModified = modified;
184186
return {

ā€Žtests/unit/routes/veeam-routes.jsā€Ž

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,10 @@ describe('Veeam routes - comprehensive unit tests', () => {
164164
});
165165

166166
it('should successfully use metrics when UtilizationService returns data', done => {
167+
const metricsDate = '2026-03-26T19:00:08.996Z';
167168
const bucketMetrics = {
168169
bytesTotal: 123456789,
170+
date: metricsDate,
169171
};
170172
utilizationStub.callsArgWith(4, null, bucketMetrics);
171173

@@ -179,6 +181,12 @@ describe('Veeam routes - comprehensive unit tests', () => {
179181
assert(response.writeHead.calledWith(200), 'should return 200 with metrics');
180182
assert(utilizationStub.calledOnce, 'should call UtilizationService once');
181183
assert(response.end.called, 'response should be ended');
184+
185+
const lastModifiedCall = response.setHeader.getCalls()
186+
.find(call => call.args[0] === 'Last-Modified');
187+
assert(lastModifiedCall, 'Last-Modified header should be set');
188+
assert.strictEqual(lastModifiedCall.args[1], metricsDate,
189+
'Last-Modified should use the date from bucketMetrics');
182190
done();
183191
});
184192
});

0 commit comments

Comments
Ā (0)