Skip to content

Commit

Permalink
CR-6006_ensure-log-index (#711)
Browse files Browse the repository at this point in the history
* implemented ensure-index command
* bump version
  • Loading branch information
rotem-codefresh authored Aug 18, 2021
1 parent 2804065 commit dc81849
Show file tree
Hide file tree
Showing 4 changed files with 182 additions and 1 deletion.
42 changes: 42 additions & 0 deletions lib/interface/cli/commands/offline-logs/ensure-index.cmd.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
const { MongoClient } = require("mongodb");
const Command = require("../../Command");
const cmd = require("./base.cmd");
const utils = require('./utils')

const command = new Command({
command: "ensure-index",
parent: cmd,
description:
"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.",
webDocs: {
category: "Logs",
title: "Ensures one or more offline-logs collections has indexes",
},
builder: (yargs) =>
yargs.example(
'codefresh offline-logs ensure-index --uri "mongodb://192.168.99.100:27017" --db logs'
),
handler: async (argv) => {
const { uri, db } = argv;
const client = new MongoClient(uri);
await client.connect();
const database = client.db(db);
const failedCollections = [];
for (const collection of utils.defaultCollections) {
try {
await utils.ensureIndex(database, collection);
} catch (error) {
console.error(`failed to ensure index of collection '${collection}', error: ${error.message}`);
failedCollections.push(collection);
}
}
client.close();
if (failedCollections.length) {
throw new Error(
`failed to ensure indexes of ${failedCollections.join(", ")}`
);
}
},
});

module.exports = command;
77 changes: 77 additions & 0 deletions lib/interface/cli/commands/offline-logs/ensure-index.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// const {Db, Collection} = require('mongodb');
const { Collection } = require('yaml/types');
const utils = require('./utils')

describe("ensure-index", () => {
describe("ensureIndex", () => {
utils.getUserInput = jest.fn()
const mockCollection = {
indexExists: jest.fn(),
estimatedDocumentCount: jest.fn().mockReturnValue(700),
createIndex: jest.fn(),
};
const mockDatabase = {
collection() {
return mockCollection;
},
};

beforeEach(() => {
mockCollection.indexExists.mockClear();
mockCollection.estimatedDocumentCount.mockClear();
mockCollection.createIndex.mockClear();
utils.getUserInput.mockClear();
});

it("index does not exists and user says yes on prompt", async () => {
//setup
mockCollection.indexExists.mockReturnValue(false);
utils.getUserInput.mockReturnValue(true);
const collection = 'whatever';
const expectedIndexObj = { accountId: 1, jobId: 1 }

//execute
await utils.ensureIndex(mockDatabase, collection);

//check
expect(mockCollection.indexExists).toBeCalledTimes(1);
expect(mockCollection.indexExists).toBeCalledWith("accountId_1_jobId_1");
expect(mockCollection.estimatedDocumentCount).toBeCalledTimes(1);
expect(utils.getUserInput).toBeCalledTimes(1);
expect(mockCollection.createIndex).toBeCalledTimes(1);
expect(mockCollection.createIndex).toBeCalledWith(expectedIndexObj)
});
it("index does not exists and user says no on prompt", async () => {
//setup
mockCollection.indexExists.mockReturnValue(false);
utils.getUserInput.mockReturnValue(false);
const collection = 'whatever';

//execute
await utils.ensureIndex(mockDatabase, collection);

//check
expect(mockCollection.indexExists).toBeCalledTimes(1);
expect(mockCollection.indexExists).toBeCalledWith("accountId_1_jobId_1");
expect(mockCollection.estimatedDocumentCount).toBeCalledTimes(1);
expect(utils.getUserInput).toBeCalledTimes(1);
expect(mockCollection.createIndex).toBeCalledTimes(0);
});
it("index exists", async () => {
//setup
mockCollection.indexExists.mockReturnValue(true);
const collection = 'whatever';

//execute
await utils.ensureIndex(mockDatabase, collection);

//check
expect(mockCollection.indexExists).toBeCalledTimes(1);
expect(mockCollection.indexExists).toBeCalledWith("accountId_1_jobId_1");
expect(mockCollection.estimatedDocumentCount).toBeCalledTimes(0);
expect(utils.getUserInput).toBeCalledTimes(0);
expect(mockCollection.createIndex).toBeCalledTimes(0);
});

});
});
62 changes: 62 additions & 0 deletions lib/interface/cli/commands/offline-logs/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,74 @@ const writeLogsToFile = function (
const checkRemnant = function (lowerBound, cutoffDateObj) {
return Math.ceil(cutoffDateObj.diff(lowerBound, "days"));
};
///////////////////////////////////////////////////////////////
const ensureIndex = async function (database, collection) {
const collectionObj = database.collection(collection);
const indexName = "accountId_1_jobId_1";

const indexExist = await collectionObj.indexExists(indexName)

if (indexExist) {
console.info(
`index '${indexName}' already exists in collection '${collection}'`
);
return;
}

const documentsCount = await collectionObj.estimatedDocumentCount();

const queryStr = `There are approximately ${documentsCount} documents on collection '${collection}'.
do you want to create an index for it? (creating an index for a large collection may take a while,
but can improve performance on future read operations) [yes/no] `;

const userInput = await this.getUserInput(queryStr);

if (!userInput) {
console.info(`skipping collection '${collection}'`);
return;
}

await collectionObj.createIndex(
{ accountId: 1, jobId: 1 },
);
console.info(
`index '${indexName}' was created for collection '${collection}'`
);
};

const getUserInput = async function (queryStr) {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});

const questionAsync = (query) =>
new Promise((resolve) => rl.question(query, resolve));

try {
const userInput = (await questionAsync(queryStr)).toLowerCase();

switch (userInput) {
case "yes":
case "y":
return true;
case "no":
case "n":
return false;
default:
console.warn("invalid input");
return false;
}
} finally {
rl.close();
}
};

module.exports = {
objectIdFromDate,
writeLogsToFile,
checkRemnant,
ensureIndex,
getUserInput,
defaultCollections,
};
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "codefresh",
"version": "0.77.0",
"version": "0.78.0",
"description": "Codefresh command line utility",
"main": "index.js",
"preferGlobal": true,
Expand Down

0 comments on commit dc81849

Please sign in to comment.