Skip to content

Commit dc81849

Browse files
CR-6006_ensure-log-index (#711)
* implemented ensure-index command * bump version
1 parent 2804065 commit dc81849

File tree

4 files changed

+182
-1
lines changed

4 files changed

+182
-1
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
const { MongoClient } = require("mongodb");
2+
const Command = require("../../Command");
3+
const cmd = require("./base.cmd");
4+
const utils = require('./utils')
5+
6+
const command = new Command({
7+
command: "ensure-index",
8+
parent: cmd,
9+
description:
10+
"Checks whether a collection has indexes and gives the user an option to add them. Adding an index may improve performance of some of the read operations.",
11+
webDocs: {
12+
category: "Logs",
13+
title: "Ensures one or more offline-logs collections has indexes",
14+
},
15+
builder: (yargs) =>
16+
yargs.example(
17+
'codefresh offline-logs ensure-index --uri "mongodb://192.168.99.100:27017" --db logs'
18+
),
19+
handler: async (argv) => {
20+
const { uri, db } = argv;
21+
const client = new MongoClient(uri);
22+
await client.connect();
23+
const database = client.db(db);
24+
const failedCollections = [];
25+
for (const collection of utils.defaultCollections) {
26+
try {
27+
await utils.ensureIndex(database, collection);
28+
} catch (error) {
29+
console.error(`failed to ensure index of collection '${collection}', error: ${error.message}`);
30+
failedCollections.push(collection);
31+
}
32+
}
33+
client.close();
34+
if (failedCollections.length) {
35+
throw new Error(
36+
`failed to ensure indexes of ${failedCollections.join(", ")}`
37+
);
38+
}
39+
},
40+
});
41+
42+
module.exports = command;
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// const {Db, Collection} = require('mongodb');
2+
const { Collection } = require('yaml/types');
3+
const utils = require('./utils')
4+
5+
describe("ensure-index", () => {
6+
describe("ensureIndex", () => {
7+
utils.getUserInput = jest.fn()
8+
const mockCollection = {
9+
indexExists: jest.fn(),
10+
estimatedDocumentCount: jest.fn().mockReturnValue(700),
11+
createIndex: jest.fn(),
12+
};
13+
const mockDatabase = {
14+
collection() {
15+
return mockCollection;
16+
},
17+
};
18+
19+
beforeEach(() => {
20+
mockCollection.indexExists.mockClear();
21+
mockCollection.estimatedDocumentCount.mockClear();
22+
mockCollection.createIndex.mockClear();
23+
utils.getUserInput.mockClear();
24+
});
25+
26+
it("index does not exists and user says yes on prompt", async () => {
27+
//setup
28+
mockCollection.indexExists.mockReturnValue(false);
29+
utils.getUserInput.mockReturnValue(true);
30+
const collection = 'whatever';
31+
const expectedIndexObj = { accountId: 1, jobId: 1 }
32+
33+
//execute
34+
await utils.ensureIndex(mockDatabase, collection);
35+
36+
//check
37+
expect(mockCollection.indexExists).toBeCalledTimes(1);
38+
expect(mockCollection.indexExists).toBeCalledWith("accountId_1_jobId_1");
39+
expect(mockCollection.estimatedDocumentCount).toBeCalledTimes(1);
40+
expect(utils.getUserInput).toBeCalledTimes(1);
41+
expect(mockCollection.createIndex).toBeCalledTimes(1);
42+
expect(mockCollection.createIndex).toBeCalledWith(expectedIndexObj)
43+
});
44+
it("index does not exists and user says no on prompt", async () => {
45+
//setup
46+
mockCollection.indexExists.mockReturnValue(false);
47+
utils.getUserInput.mockReturnValue(false);
48+
const collection = 'whatever';
49+
50+
//execute
51+
await utils.ensureIndex(mockDatabase, collection);
52+
53+
//check
54+
expect(mockCollection.indexExists).toBeCalledTimes(1);
55+
expect(mockCollection.indexExists).toBeCalledWith("accountId_1_jobId_1");
56+
expect(mockCollection.estimatedDocumentCount).toBeCalledTimes(1);
57+
expect(utils.getUserInput).toBeCalledTimes(1);
58+
expect(mockCollection.createIndex).toBeCalledTimes(0);
59+
});
60+
it("index exists", async () => {
61+
//setup
62+
mockCollection.indexExists.mockReturnValue(true);
63+
const collection = 'whatever';
64+
65+
//execute
66+
await utils.ensureIndex(mockDatabase, collection);
67+
68+
//check
69+
expect(mockCollection.indexExists).toBeCalledTimes(1);
70+
expect(mockCollection.indexExists).toBeCalledWith("accountId_1_jobId_1");
71+
expect(mockCollection.estimatedDocumentCount).toBeCalledTimes(0);
72+
expect(utils.getUserInput).toBeCalledTimes(0);
73+
expect(mockCollection.createIndex).toBeCalledTimes(0);
74+
});
75+
76+
});
77+
});

lib/interface/cli/commands/offline-logs/utils.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,74 @@ const writeLogsToFile = function (
3232
const checkRemnant = function (lowerBound, cutoffDateObj) {
3333
return Math.ceil(cutoffDateObj.diff(lowerBound, "days"));
3434
};
35+
///////////////////////////////////////////////////////////////
36+
const ensureIndex = async function (database, collection) {
37+
const collectionObj = database.collection(collection);
38+
const indexName = "accountId_1_jobId_1";
3539

40+
const indexExist = await collectionObj.indexExists(indexName)
3641

42+
if (indexExist) {
43+
console.info(
44+
`index '${indexName}' already exists in collection '${collection}'`
45+
);
46+
return;
47+
}
48+
49+
const documentsCount = await collectionObj.estimatedDocumentCount();
50+
51+
const queryStr = `There are approximately ${documentsCount} documents on collection '${collection}'.
52+
do you want to create an index for it? (creating an index for a large collection may take a while,
53+
but can improve performance on future read operations) [yes/no] `;
54+
55+
const userInput = await this.getUserInput(queryStr);
56+
57+
if (!userInput) {
58+
console.info(`skipping collection '${collection}'`);
59+
return;
60+
}
61+
62+
await collectionObj.createIndex(
63+
{ accountId: 1, jobId: 1 },
64+
);
65+
console.info(
66+
`index '${indexName}' was created for collection '${collection}'`
67+
);
68+
};
69+
70+
const getUserInput = async function (queryStr) {
71+
const rl = readline.createInterface({
72+
input: process.stdin,
73+
output: process.stdout,
74+
});
75+
76+
const questionAsync = (query) =>
77+
new Promise((resolve) => rl.question(query, resolve));
78+
79+
try {
80+
const userInput = (await questionAsync(queryStr)).toLowerCase();
81+
82+
switch (userInput) {
83+
case "yes":
84+
case "y":
85+
return true;
86+
case "no":
87+
case "n":
88+
return false;
89+
default:
90+
console.warn("invalid input");
91+
return false;
92+
}
93+
} finally {
94+
rl.close();
95+
}
96+
};
3797

3898
module.exports = {
3999
objectIdFromDate,
40100
writeLogsToFile,
41101
checkRemnant,
102+
ensureIndex,
103+
getUserInput,
42104
defaultCollections,
43105
};

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "codefresh",
3-
"version": "0.77.0",
3+
"version": "0.78.0",
44
"description": "Codefresh command line utility",
55
"main": "index.js",
66
"preferGlobal": true,

0 commit comments

Comments
 (0)