Best JavaScript code snippet using mountebank
reindex_service.ts
Source:reindex_service.ts
1/*2 * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one3 * or more contributor license agreements. Licensed under the Elastic License;4 * you may not use this file except in compliance with the Elastic License.5 */6import Boom from 'boom';7import { Server } from 'hapi';8import { CallCluster } from 'src/legacy/core_plugins/elasticsearch';9import { XPackInfo } from '../../../../../xpack_main/server/lib/xpack_info';10import {11 IndexGroup,12 ReindexSavedObject,13 ReindexStatus,14 ReindexStep,15 ReindexWarning,16} from '../../../../common/types';17import {18 generateNewIndexName,19 getReindexWarnings,20 sourceNameForIndex,21 transformFlatSettings,22} from './index_settings';23import { ReindexActions } from './reindex_actions';24const VERSION_REGEX = new RegExp(/^([1-9]+)\.([0-9]+)\.([0-9]+)/);25const ML_INDICES = ['.ml-state', '.ml-anomalies', '.ml-config'];26const WATCHER_INDICES = ['.watches', '.triggered-watches'];27export interface ReindexService {28 /**29 * Checks whether or not the user has proper privileges required to reindex this index.30 * @param indexName31 */32 hasRequiredPrivileges(indexName: string): Promise<boolean>;33 /**34 * Checks an index's settings and mappings to flag potential issues during reindex.35 * Resolves to null if index does not exist.36 * @param indexName37 */38 detectReindexWarnings(indexName: string): Promise<ReindexWarning[] | null>;39 /**40 * Returns an IndexGroup if the index belongs to one, otherwise undefined.41 * @param indexName42 */43 getIndexGroup(indexName: string): IndexGroup | undefined;44 /**45 * Creates a new reindex operation for a given index.46 * @param indexName47 */48 createReindexOperation(indexName: string): Promise<ReindexSavedObject>;49 /**50 * Retrieves all reindex operations that have the given status.51 * @param status52 */53 findAllByStatus(status: ReindexStatus): Promise<ReindexSavedObject[]>;54 /**55 * Finds the reindex operation for the given index.56 * Resolves to null if there is no existing reindex operation for this index.57 * @param indexName58 */59 findReindexOperation(indexName: string): Promise<ReindexSavedObject | null>;60 /**61 * Process the reindex operation through one step of the state machine and resolves62 * to the updated reindex operation.63 * @param reindexOp64 */65 processNextStep(reindexOp: ReindexSavedObject): Promise<ReindexSavedObject>;66 /**67 * Pauses the in-progress reindex operation for a given index.68 * @param indexName69 */70 pauseReindexOperation(indexName: string): Promise<ReindexSavedObject>;71 /**72 * Resumes the paused reindex operation for a given index.73 * @param indexName74 */75 resumeReindexOperation(indexName: string): Promise<ReindexSavedObject>;76 /**77 * Cancel an in-progress reindex operation for a given index. Only allowed when the78 * reindex operation is in the ReindexStep.reindexStarted step. Relies on the ReindexWorker79 * to continue processing the reindex operation to detect that the Reindex Task in ES has been80 * cancelled.81 * @param indexName82 */83 cancelReindexing(indexName: string): Promise<ReindexSavedObject>;84}85export const reindexServiceFactory = (86 callCluster: CallCluster,87 xpackInfo: XPackInfo,88 actions: ReindexActions,89 log: Server['log']90): ReindexService => {91 // ------ Utility functions92 /**93 * If the index is a ML index that will cause jobs to fail when set to readonly,94 * turn on 'upgrade mode' to pause all ML jobs.95 * @param reindexOp96 */97 const stopMlJobs = async () => {98 await actions.incrementIndexGroupReindexes(IndexGroup.ml);99 await actions.runWhileIndexGroupLocked(IndexGroup.ml, async mlDoc => {100 await validateNodesMinimumVersion(6, 7);101 const res = await callCluster('transport.request', {102 path: '/_ml/set_upgrade_mode?enabled=true',103 method: 'POST',104 });105 if (!res.acknowledged) {106 throw new Error(`Could not stop ML jobs`);107 }108 return mlDoc;109 });110 };111 /**112 * Resumes ML jobs if there are no more remaining reindex operations.113 */114 const resumeMlJobs = async () => {115 await actions.decrementIndexGroupReindexes(IndexGroup.ml);116 await actions.runWhileIndexGroupLocked(IndexGroup.ml, async mlDoc => {117 if (mlDoc.attributes.runningReindexCount === 0) {118 const res = await callCluster('transport.request', {119 path: '/_ml/set_upgrade_mode?enabled=false',120 method: 'POST',121 });122 if (!res.acknowledged) {123 throw new Error(`Could not resume ML jobs`);124 }125 }126 return mlDoc;127 });128 };129 /**130 * Stops Watcher in Elasticsearch.131 */132 const stopWatcher = async () => {133 await actions.incrementIndexGroupReindexes(IndexGroup.watcher);134 await actions.runWhileIndexGroupLocked(IndexGroup.watcher, async watcherDoc => {135 const { acknowledged } = await callCluster('transport.request', {136 path: '/_watcher/_stop',137 method: 'POST',138 });139 if (!acknowledged) {140 throw new Error('Could not stop Watcher');141 }142 return watcherDoc;143 });144 };145 /**146 * Starts Watcher in Elasticsearch.147 */148 const startWatcher = async () => {149 await actions.decrementIndexGroupReindexes(IndexGroup.watcher);150 await actions.runWhileIndexGroupLocked(IndexGroup.watcher, async watcherDoc => {151 if (watcherDoc.attributes.runningReindexCount === 0) {152 const { acknowledged } = await callCluster('transport.request', {153 path: '/_watcher/_start',154 method: 'POST',155 });156 if (!acknowledged) {157 throw new Error('Could not start Watcher');158 }159 }160 return watcherDoc;161 });162 };163 const cleanupChanges = async (reindexOp: ReindexSavedObject) => {164 // Cancel reindex task if it was started but not completed165 if (reindexOp.attributes.lastCompletedStep === ReindexStep.reindexStarted) {166 await callCluster('tasks.cancel', {167 taskId: reindexOp.attributes.reindexTaskId,168 }).catch(e => undefined); // Ignore any exceptions trying to cancel (it may have already completed).169 }170 // Set index back to writable if we ever got past this point.171 if (reindexOp.attributes.lastCompletedStep >= ReindexStep.readonly) {172 await callCluster('indices.putSettings', {173 index: reindexOp.attributes.indexName,174 body: { 'index.blocks.write': false },175 });176 }177 if (178 reindexOp.attributes.lastCompletedStep >= ReindexStep.newIndexCreated &&179 reindexOp.attributes.lastCompletedStep < ReindexStep.aliasCreated180 ) {181 await callCluster('indices.delete', { index: reindexOp.attributes.newIndexName });182 }183 // Resume consumers if we ever got past this point.184 if (reindexOp.attributes.lastCompletedStep >= ReindexStep.indexGroupServicesStopped) {185 await resumeIndexGroupServices(reindexOp);186 }187 return reindexOp;188 };189 // ------ Functions used to process the state machine190 const validateNodesMinimumVersion = async (minMajor: number, minMinor: number) => {191 const nodesResponse = await callCluster('transport.request', {192 path: '/_nodes',193 method: 'GET',194 });195 const outDatedNodes = Object.values(nodesResponse.nodes).filter((node: any) => {196 const matches = node.version.match(VERSION_REGEX);197 const major = parseInt(matches[1], 10);198 const minor = parseInt(matches[2], 10);199 // All ES nodes must be >= 6.7.0 to pause ML jobs200 return !(major > minMajor || (major === minMajor && minor >= minMinor));201 });202 if (outDatedNodes.length > 0) {203 const nodeList = JSON.stringify(outDatedNodes.map((n: any) => n.name));204 throw new Error(205 `Some nodes are not on minimum version (${minMajor}.${minMinor}.0) required: ${nodeList}`206 );207 }208 };209 const stopIndexGroupServices = async (reindexOp: ReindexSavedObject) => {210 if (isMlIndex(reindexOp.attributes.indexName)) {211 await stopMlJobs();212 } else if (isWatcherIndex(reindexOp.attributes.indexName)) {213 await stopWatcher();214 }215 return actions.updateReindexOp(reindexOp, {216 lastCompletedStep: ReindexStep.indexGroupServicesStopped,217 });218 };219 /**220 * Sets the original index as readonly so new data can be indexed until the reindex221 * is completed.222 * @param reindexOp223 */224 const setReadonly = async (reindexOp: ReindexSavedObject) => {225 const { indexName } = reindexOp.attributes;226 const putReadonly = await callCluster('indices.putSettings', {227 index: indexName,228 body: { 'index.blocks.write': true },229 });230 if (!putReadonly.acknowledged) {231 throw new Error(`Index could not be set to readonly.`);232 }233 return actions.updateReindexOp(reindexOp, { lastCompletedStep: ReindexStep.readonly });234 };235 /**236 * Creates a new index with the same mappings and settings as the original index.237 * @param reindexOp238 */239 const createNewIndex = async (reindexOp: ReindexSavedObject) => {240 const { indexName, newIndexName } = reindexOp.attributes;241 const flatSettings = await actions.getFlatSettings(indexName);242 if (!flatSettings) {243 throw Boom.notFound(`Index ${indexName} does not exist.`);244 }245 const { settings, mappings } = transformFlatSettings(flatSettings);246 const createIndex = await callCluster('indices.create', {247 index: newIndexName,248 body: {249 settings,250 mappings,251 },252 });253 if (!createIndex.acknowledged) {254 throw Boom.badImplementation(`Index could not be created: ${newIndexName}`);255 }256 return actions.updateReindexOp(reindexOp, {257 lastCompletedStep: ReindexStep.newIndexCreated,258 });259 };260 /**261 * Begins the reindex process via Elasticsearch's Reindex API.262 * @param reindexOp263 */264 const startReindexing = async (reindexOp: ReindexSavedObject) => {265 const { indexName } = reindexOp.attributes;266 const startReindex = (await callCluster('reindex', {267 refresh: true,268 waitForCompletion: false,269 body: {270 source: { index: indexName },271 dest: { index: reindexOp.attributes.newIndexName },272 },273 })) as any;274 return actions.updateReindexOp(reindexOp, {275 lastCompletedStep: ReindexStep.reindexStarted,276 reindexTaskId: startReindex.task,277 reindexTaskPercComplete: 0,278 });279 };280 /**281 * Polls Elasticsearch's Tasks API to see if the reindex operation has been completed.282 * @param reindexOp283 */284 const updateReindexStatus = async (reindexOp: ReindexSavedObject) => {285 const taskId = reindexOp.attributes.reindexTaskId;286 // Check reindexing task progress287 const taskResponse = await callCluster('tasks.get', {288 taskId,289 waitForCompletion: false,290 });291 if (!taskResponse.completed) {292 // Updated the percent complete293 const perc = taskResponse.task.status.created / taskResponse.task.status.total;294 return actions.updateReindexOp(reindexOp, {295 reindexTaskPercComplete: perc,296 });297 } else if (taskResponse.task.status.canceled === 'by user request') {298 // Set the status to cancelled299 reindexOp = await actions.updateReindexOp(reindexOp, {300 status: ReindexStatus.cancelled,301 });302 // Do any other cleanup work necessary303 reindexOp = await cleanupChanges(reindexOp);304 } else {305 // Check that it reindexed all documents306 const { count } = await callCluster('count', { index: reindexOp.attributes.indexName });307 if (taskResponse.task.status.created < count) {308 // Include the entire task result in the error message. This should be guaranteed309 // to be JSON-serializable since it just came back from Elasticsearch.310 throw Boom.badData(`Reindexing failed: ${JSON.stringify(taskResponse)}`);311 }312 // Update the status313 reindexOp = await actions.updateReindexOp(reindexOp, {314 lastCompletedStep: ReindexStep.reindexCompleted,315 reindexTaskPercComplete: 1,316 });317 }318 // Delete the task from ES .tasks index319 const deleteTaskResp = await callCluster('delete', {320 index: '.tasks',321 id: taskId,322 });323 if (deleteTaskResp.result !== 'deleted') {324 throw Boom.badImplementation(`Could not delete reindexing task ${taskId}`);325 }326 return reindexOp;327 };328 /**329 * Creates an alias that points the old index to the new index, deletes the old index.330 * @param reindexOp331 */332 const switchAlias = async (reindexOp: ReindexSavedObject) => {333 const { indexName, newIndexName } = reindexOp.attributes;334 const existingAliases = (335 await callCluster('indices.getAlias', {336 index: indexName,337 })338 )[indexName].aliases;339 const extraAlises = Object.keys(existingAliases).map(aliasName => ({340 add: { index: newIndexName, alias: aliasName, ...existingAliases[aliasName] },341 }));342 const aliasResponse = await callCluster('indices.updateAliases', {343 body: {344 actions: [345 { add: { index: newIndexName, alias: indexName } },346 { remove_index: { index: indexName } },347 ...extraAlises,348 ],349 },350 });351 if (!aliasResponse.acknowledged) {352 throw Boom.badImplementation(`Index aliases could not be created.`);353 }354 return actions.updateReindexOp(reindexOp, {355 lastCompletedStep: ReindexStep.aliasCreated,356 });357 };358 const resumeIndexGroupServices = async (reindexOp: ReindexSavedObject) => {359 if (isMlIndex(reindexOp.attributes.indexName)) {360 await resumeMlJobs();361 } else if (isWatcherIndex(reindexOp.attributes.indexName)) {362 await startWatcher();363 }364 // Only change the status if we're still in-progress (this function is also called when the reindex fails or is cancelled)365 if (reindexOp.attributes.status === ReindexStatus.inProgress) {366 return actions.updateReindexOp(reindexOp, {367 lastCompletedStep: ReindexStep.indexGroupServicesStarted,368 });369 } else {370 return reindexOp;371 }372 };373 // ------ The service itself374 return {375 async hasRequiredPrivileges(indexName: string) {376 // If security is disabled or unavailable, return true.377 const security = xpackInfo.feature('security');378 if (!security.isAvailable() || !security.isEnabled()) {379 return true;380 }381 const names = [indexName, generateNewIndexName(indexName)];382 const sourceName = sourceNameForIndex(indexName);383 // if we have re-indexed this in the past, there will be an384 // underlying alias we will also need to update.385 if (sourceName !== indexName) {386 names.push(sourceName);387 }388 // Otherwise, query for required privileges for this index.389 const body = {390 cluster: ['manage'],391 index: [392 {393 names,394 allow_restricted_indices: true,395 privileges: ['all'],396 },397 {398 names: ['.tasks'],399 privileges: ['read', 'delete'],400 },401 ],402 } as any;403 if (isMlIndex(indexName)) {404 body.cluster = [...body.cluster, 'manage_ml'];405 }406 if (isWatcherIndex(indexName)) {407 body.cluster = [...body.cluster, 'manage_watcher'];408 }409 const resp = await callCluster('transport.request', {410 path: '/_security/user/_has_privileges',411 method: 'POST',412 body,413 });414 return resp.has_all_requested;415 },416 async detectReindexWarnings(indexName: string) {417 const flatSettings = await actions.getFlatSettings(indexName);418 if (!flatSettings) {419 return null;420 } else {421 return getReindexWarnings(flatSettings);422 }423 },424 getIndexGroup(indexName: string) {425 if (isMlIndex(indexName)) {426 return IndexGroup.ml;427 } else if (isWatcherIndex(indexName)) {428 return IndexGroup.watcher;429 }430 },431 async createReindexOperation(indexName: string) {432 const indexExists = await callCluster('indices.exists', { index: indexName });433 if (!indexExists) {434 throw Boom.notFound(`Index ${indexName} does not exist in this cluster.`);435 }436 const existingReindexOps = await actions.findReindexOperations(indexName);437 if (existingReindexOps.total !== 0) {438 const existingOp = existingReindexOps.saved_objects[0];439 if (440 existingOp.attributes.status === ReindexStatus.failed ||441 existingOp.attributes.status === ReindexStatus.cancelled442 ) {443 // Delete the existing one if it failed or was cancelled to give a chance to retry.444 await actions.deleteReindexOp(existingOp);445 } else {446 throw Boom.badImplementation(`A reindex operation already in-progress for ${indexName}`);447 }448 }449 return actions.createReindexOp(indexName);450 },451 async findReindexOperation(indexName: string) {452 const findResponse = await actions.findReindexOperations(indexName);453 // Bail early if it does not exist or there is more than one.454 if (findResponse.total === 0) {455 return null;456 } else if (findResponse.total > 1) {457 throw Boom.badImplementation(`More than one reindex operation found for ${indexName}`);458 }459 return findResponse.saved_objects[0];460 },461 findAllByStatus: actions.findAllByStatus,462 async processNextStep(reindexOp: ReindexSavedObject) {463 return actions.runWhileLocked(reindexOp, async lockedReindexOp => {464 try {465 switch (lockedReindexOp.attributes.lastCompletedStep) {466 case ReindexStep.created:467 lockedReindexOp = await stopIndexGroupServices(lockedReindexOp);468 break;469 case ReindexStep.indexGroupServicesStopped:470 lockedReindexOp = await setReadonly(lockedReindexOp);471 break;472 case ReindexStep.readonly:473 lockedReindexOp = await createNewIndex(lockedReindexOp);474 break;475 case ReindexStep.newIndexCreated:476 lockedReindexOp = await startReindexing(lockedReindexOp);477 break;478 case ReindexStep.reindexStarted:479 lockedReindexOp = await updateReindexStatus(lockedReindexOp);480 break;481 case ReindexStep.reindexCompleted:482 lockedReindexOp = await switchAlias(lockedReindexOp);483 break;484 case ReindexStep.aliasCreated:485 lockedReindexOp = await resumeIndexGroupServices(lockedReindexOp);486 break;487 case ReindexStep.indexGroupServicesStarted:488 lockedReindexOp = await actions.updateReindexOp(lockedReindexOp, {489 status: ReindexStatus.completed,490 });491 default:492 break;493 }494 } catch (e) {495 log(496 ['upgrade_assistant', 'error'],497 `Reindexing step failed: ${e instanceof Error ? e.stack : e.toString()}`498 );499 // Trap the exception and add the message to the object so the UI can display it.500 lockedReindexOp = await actions.updateReindexOp(lockedReindexOp, {501 status: ReindexStatus.failed,502 errorMessage: e.toString(),503 });504 // Cleanup any changes, ignoring any errors.505 lockedReindexOp = await cleanupChanges(lockedReindexOp).catch(err => lockedReindexOp);506 }507 return lockedReindexOp;508 });509 },510 async pauseReindexOperation(indexName: string) {511 const reindexOp = await this.findReindexOperation(indexName);512 if (!reindexOp) {513 throw new Error(`No reindex operation found for index ${indexName}`);514 }515 return actions.runWhileLocked(reindexOp, async op => {516 if (op.attributes.status === ReindexStatus.paused) {517 // Another node already paused the operation, don't do anything518 return reindexOp;519 } else if (op.attributes.status !== ReindexStatus.inProgress) {520 throw new Error(`Reindex operation must be inProgress in order to be paused.`);521 }522 return actions.updateReindexOp(op, { status: ReindexStatus.paused });523 });524 },525 async resumeReindexOperation(indexName: string) {526 const reindexOp = await this.findReindexOperation(indexName);527 if (!reindexOp) {528 throw new Error(`No reindex operation found for index ${indexName}`);529 }530 return actions.runWhileLocked(reindexOp, async op => {531 if (op.attributes.status === ReindexStatus.inProgress) {532 // Another node already resumed the operation, don't do anything533 return reindexOp;534 } else if (op.attributes.status !== ReindexStatus.paused) {535 throw new Error(`Reindex operation must be paused in order to be resumed.`);536 }537 return actions.updateReindexOp(op, { status: ReindexStatus.inProgress });538 });539 },540 async cancelReindexing(indexName: string) {541 const reindexOp = await this.findReindexOperation(indexName);542 if (!reindexOp) {543 throw new Error(`No reindex operation found for index ${indexName}`);544 } else if (reindexOp.attributes.status !== ReindexStatus.inProgress) {545 throw new Error(`Reindex operation is not in progress`);546 } else if (reindexOp.attributes.lastCompletedStep !== ReindexStep.reindexStarted) {547 throw new Error(`Reindex operation is not current waiting for reindex task to complete`);548 }549 const resp = await callCluster('tasks.cancel', {550 taskId: reindexOp.attributes.reindexTaskId,551 });552 if (resp.node_failures && resp.node_failures.length > 0) {553 throw new Error(`Could not cancel reindex.`);554 }555 return reindexOp;556 },557 };558};559export const isMlIndex = (indexName: string) => {560 const sourceName = sourceNameForIndex(indexName);561 return ML_INDICES.indexOf(sourceName) >= 0;562};563export const isWatcherIndex = (indexName: string) => {564 const sourceName = sourceNameForIndex(indexName);565 return WATCHER_INDICES.indexOf(sourceName) >= 0;...
reindex_actions.ts
Source:reindex_actions.ts
1/*2 * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one3 * or more contributor license agreements. Licensed under the Elastic License;4 * you may not use this file except in compliance with the Elastic License.5 */6import moment from 'moment';7import { CallCluster } from 'src/legacy/core_plugins/elasticsearch';8import { SavedObjectsFindResponse, SavedObjectsClientContract } from 'kibana/server';9import {10 IndexGroup,11 REINDEX_OP_TYPE,12 ReindexOperation,13 ReindexSavedObject,14 ReindexStatus,15 ReindexStep,16} from '../../../../common/types';17import { generateNewIndexName } from './index_settings';18import { FlatSettings } from './types';19// TODO: base on elasticsearch.requestTimeout?20export const LOCK_WINDOW = moment.duration(90, 'seconds');21/**22 * A collection of utility functions pulled out out of the ReindexService to make testing simpler.23 * This is NOT intended to be used by any other code.24 */25export interface ReindexActions {26 /**27 * Namespace for ML-specific actions.28 */29 // ml: MlActions;30 /**31 * Creates a new reindexOp, does not perform any pre-flight checks.32 * @param indexName33 */34 createReindexOp(indexName: string): Promise<ReindexSavedObject>;35 /**36 * Deletes a reindexOp.37 * @param reindexOp38 */39 deleteReindexOp(reindexOp: ReindexSavedObject): void;40 /**41 * Updates a ReindexSavedObject.42 * @param reindexOp43 * @param attrs44 */45 updateReindexOp(46 reindexOp: ReindexSavedObject,47 attrs?: Partial<ReindexOperation>48 ): Promise<ReindexSavedObject>;49 /**50 * Runs a callback function while locking the reindex operation. Guaranteed to unlock the reindex operation when complete.51 * @param func A function to run with the locked ML lock document. Must return a promise that resolves52 * to the updated ReindexSavedObject.53 */54 runWhileLocked(55 reindexOp: ReindexSavedObject,56 func: (reindexOp: ReindexSavedObject) => Promise<ReindexSavedObject>57 ): Promise<ReindexSavedObject>;58 /**59 * Finds the reindex operation saved object for the given index.60 * @param indexName61 */62 findReindexOperations(indexName: string): Promise<SavedObjectsFindResponse<ReindexOperation>>;63 /**64 * Returns an array of all reindex operations that have a status.65 */66 findAllByStatus(status: ReindexStatus): Promise<ReindexSavedObject[]>;67 /**68 * Retrieve index settings (in flat, dot-notation style) and mappings.69 * @param indexName70 */71 getFlatSettings(indexName: string): Promise<FlatSettings | null>;72 // ----- Functions below are for enforcing locks around groups of indices like ML or Watcher73 /**74 * Atomically increments the number of reindex operations running for an index group.75 */76 incrementIndexGroupReindexes(group: IndexGroup): Promise<void>;77 /**78 * Atomically decrements the number of reindex operations running for an index group.79 */80 decrementIndexGroupReindexes(group: IndexGroup): Promise<void>;81 /**82 * Runs a callback function while locking an index group.83 * @param func A function to run with the locked index group lock document. Must return a promise that resolves84 * to the updated ReindexSavedObject.85 */86 runWhileIndexGroupLocked(87 group: IndexGroup,88 func: (lockDoc: ReindexSavedObject) => Promise<ReindexSavedObject>89 ): Promise<void>;90 /**91 * Exposed only for testing, DO NOT USE.92 */93 _fetchAndLockIndexGroupDoc(group: IndexGroup): Promise<ReindexSavedObject>;94}95export const reindexActionsFactory = (96 client: SavedObjectsClientContract,97 callCluster: CallCluster98): ReindexActions => {99 // ----- Internal functions100 const isLocked = (reindexOp: ReindexSavedObject) => {101 if (reindexOp.attributes.locked) {102 const now = moment();103 const lockedTime = moment(reindexOp.attributes.locked);104 // If the object has been locked for more than the LOCK_WINDOW, assume the process that locked it died.105 if (now.subtract(LOCK_WINDOW) < lockedTime) {106 return true;107 }108 }109 return false;110 };111 const acquireLock = async (reindexOp: ReindexSavedObject) => {112 if (isLocked(reindexOp)) {113 throw new Error(`Another Kibana process is currently modifying this reindex operation.`);114 }115 return client.update<ReindexOperation>(116 REINDEX_OP_TYPE,117 reindexOp.id,118 { ...reindexOp.attributes, locked: moment().format() },119 { version: reindexOp.version }120 ) as Promise<ReindexSavedObject>;121 };122 const releaseLock = (reindexOp: ReindexSavedObject) => {123 return client.update<ReindexOperation>(124 REINDEX_OP_TYPE,125 reindexOp.id,126 { ...reindexOp.attributes, locked: null },127 { version: reindexOp.version }128 ) as Promise<ReindexSavedObject>;129 };130 // ----- Public interface131 return {132 async createReindexOp(indexName: string) {133 return client.create<ReindexOperation>(REINDEX_OP_TYPE, {134 indexName,135 newIndexName: generateNewIndexName(indexName),136 status: ReindexStatus.inProgress,137 lastCompletedStep: ReindexStep.created,138 locked: null,139 reindexTaskId: null,140 reindexTaskPercComplete: null,141 errorMessage: null,142 runningReindexCount: null,143 });144 },145 deleteReindexOp(reindexOp: ReindexSavedObject) {146 return client.delete(REINDEX_OP_TYPE, reindexOp.id);147 },148 async updateReindexOp(reindexOp: ReindexSavedObject, attrs: Partial<ReindexOperation> = {}) {149 if (!isLocked(reindexOp)) {150 throw new Error(`ReindexOperation must be locked before updating.`);151 }152 const newAttrs = { ...reindexOp.attributes, locked: moment().format(), ...attrs };153 return client.update<ReindexOperation>(REINDEX_OP_TYPE, reindexOp.id, newAttrs, {154 version: reindexOp.version,155 }) as Promise<ReindexSavedObject>;156 },157 async runWhileLocked(reindexOp, func) {158 reindexOp = await acquireLock(reindexOp);159 try {160 reindexOp = await func(reindexOp);161 } finally {162 reindexOp = await releaseLock(reindexOp);163 }164 return reindexOp;165 },166 findReindexOperations(indexName: string) {167 return client.find<ReindexOperation>({168 type: REINDEX_OP_TYPE,169 search: `"${indexName}"`,170 searchFields: ['indexName'],171 });172 },173 async findAllByStatus(status: ReindexStatus) {174 const firstPage = await client.find<ReindexOperation>({175 type: REINDEX_OP_TYPE,176 search: status.toString(),177 searchFields: ['status'],178 });179 if (firstPage.total === firstPage.saved_objects.length) {180 return firstPage.saved_objects;181 }182 let allOps = firstPage.saved_objects;183 let page = firstPage.page + 1;184 while (allOps.length < firstPage.total) {185 const nextPage = await client.find<ReindexOperation>({186 type: REINDEX_OP_TYPE,187 search: status.toString(),188 searchFields: ['status'],189 page,190 });191 allOps = [...allOps, ...nextPage.saved_objects];192 page++;193 }194 return allOps;195 },196 async getFlatSettings(indexName: string) {197 const flatSettings = (await callCluster('transport.request', {198 path: `/${encodeURIComponent(indexName)}?flat_settings=true`,199 })) as { [indexName: string]: FlatSettings };200 if (!flatSettings[indexName]) {201 return null;202 }203 return flatSettings[indexName];204 },205 async _fetchAndLockIndexGroupDoc(indexGroup) {206 const fetchDoc = async () => {207 try {208 // The IndexGroup enum value (a string) serves as the ID of the lock doc209 return await client.get<ReindexOperation>(REINDEX_OP_TYPE, indexGroup);210 } catch (e) {211 if (e.isBoom && e.output.statusCode === 404) {212 return await client.create<ReindexOperation>(213 REINDEX_OP_TYPE,214 {215 indexName: null,216 newIndexName: null,217 locked: null,218 status: null,219 lastCompletedStep: null,220 reindexTaskId: null,221 reindexTaskPercComplete: null,222 errorMessage: null,223 runningReindexCount: 0,224 } as any,225 { id: indexGroup }226 );227 } else {228 throw e;229 }230 }231 };232 const lockDoc = async (attempt = 1): Promise<ReindexSavedObject> => {233 try {234 // Refetch the document each time to avoid version conflicts.235 return await acquireLock(await fetchDoc());236 } catch (e) {237 if (attempt >= 10) {238 throw new Error(`Could not acquire lock for ML jobs`);239 }240 await new Promise(resolve => setTimeout(resolve, 1000));241 return lockDoc(attempt + 1);242 }243 };244 return lockDoc();245 },246 async incrementIndexGroupReindexes(indexGroup) {247 this.runWhileIndexGroupLocked(indexGroup, lockDoc =>248 this.updateReindexOp(lockDoc, {249 runningReindexCount: lockDoc.attributes.runningReindexCount! + 1,250 })251 );252 },253 async decrementIndexGroupReindexes(indexGroup) {254 this.runWhileIndexGroupLocked(indexGroup, lockDoc =>255 this.updateReindexOp(lockDoc, {256 runningReindexCount: lockDoc.attributes.runningReindexCount! - 1,257 })258 );259 },260 async runWhileIndexGroupLocked(indexGroup, func) {261 let lockDoc = await this._fetchAndLockIndexGroupDoc(indexGroup);262 try {263 lockDoc = await func(lockDoc);264 } finally {265 await releaseLock(lockDoc);266 }267 },268 };...
Using AI Code Generation
1var request = require('request');2var options = {3};4request(options, function (error, response, body) {5 if (!error && response.statusCode == 200) {6 }7});
Using AI Code Generation
1const mb = require('mountebank');2const imposter = {3 {4 {5 is: {6 }7 }8 }9};10mb.create(imposter)11 .then(() => {12 console.log('Imposter created');13 return mb.reindex();14 })15 .then(() => {16 console.log('Imposter reindexed');17 })18 .catch(error => {19 console.error('Error', error);20 });
Using AI Code Generation
1var request = require('request');2var options = {3 headers: {4 },5 json: {6 "stub": [{7 "responses": [{8 "is": {9 "headers": {10 },11 "body": {12 }13 }14 }]15 }]16 }17}18request(options, function(error, response, body) {19 console.log(body);20});21var request = require('request');22var options = {23 headers: {24 },25 json: {26 "stub": [{27 "responses": [{28 "is": {29 "headers": {30 },31 "body": {32 }33 }34 }]35 }]36 }37}38request(options, function(error, response, body) {39 console.log(body);40});
Using AI Code Generation
1const mb = require('mountebank');2const fs = require('fs');3mb.start({4}, function (error) {5 if (error) {6 console.error(error);7 } else {8 console.log('mountebank started');9 mb.reindex({10 }, function (error) {11 if (error) {12 console.error(error);13 } else {14 console.log('mountebank reindexed');15 }16 });17 }18});19 at exports._errnoException (util.js:1022:11)20 at Process.ChildProcess._handle.onexit (internal/child_process.js:190:19)21 at onErrorNT (internal/child_process.js:372:16)22 at _combinedTickCallback (internal/process/next_tick.js:138:11)23 at process._tickCallback (internal/process/next_tick.js:180:9)
Using AI Code Generation
1var mb = require('mountebank');2mb.create({port:2525}, function (error, imposter) {3 imposter.post('/reindex', function (request, response) {4 imposter.reindex();5 response.send(200);6 });7});8var mb = require('mountebank');9mb.create({port:2525}, function (error, imposter) {10 imposter.post('/reindex', function (request, response) {11 imposter.reindex();12 response.send(200);13 });14});15I am trying to use reindex() method of mountebank to test my application. But I am getting error response as "Cannot call method 'reindex' of undefined". I am using mountebank version 1.1.0. Can you please help me with this?16I am trying to use reindex() method of mountebank to test my application. But I am getting error response as "Cannot call method 'reindex' of undefined". I am using mountebank version 1.1.0. Can you please help me with this?17I am trying to use reindex() method of mountebank to test my application. But I am getting error response as "Cannot call method 'reindex' of undefined". I am using mountebank version 1.1.0. Can you please help me with this?18I'm not sure what you're trying to do. The reindex() method is
Using AI Code Generation
1var request = require('request');2var options = {3 'headers': {4 }5};6request(options, function (error, response) {7 if (error) throw new Error(error);8 console.log(response.body);9});10var request = require('request');11var options = {12 'headers': {13 }14};15request(options, function (error, response) {16 if (error) throw new Error(error);17 console.log(response.body);18});
Using AI Code Generation
1var mb = require('mountebank');2var mbHelper = require('mountebank-helper');3var mbPort = 2525;4var mbProcess = null;5var mbHelperProcess = null;6var options = {7 config: {8 }9};10mb.create(options)11 .then(function (process) {12 mbProcess = process;13 console.log('mb started');14 return mbHelper.create({ mbPort: mbPort });15 })16 .then(function (helperProcess) {17 mbHelperProcess = helperProcess;18 console.log('mb-helper started');19 return mbHelperProcess.mbHelper.addImposter({ port: 3000 });20 })21 .then(function () {22 console.log('imposter added');23 return mbHelperProcess.mbHelper.reindex();24 })25 .then(function () {26 console.log('reindex complete');27 return mbHelperProcess.mbHelper.addImposter({ port: 3001 });28 })29 .then(function () {30 console.log('imposter added');31 return mbHelperProcess.mbHelper.reindex();32 })33 .then(function () {34 console.log('reindex complete');35 mbProcess.kill();36 mbHelperProcess.kill();37 })38 .catch(function (error) {39 console.log(error);40 mbProcess.kill();41 mbHelperProcess.kill();42 });43var mb = require('mountebank');44var mbHelper = require('mountebank-helper');45var mbPort = 2525;46var mbProcess = null;47var mbHelperProcess = null;48var options = {49 config: {50 }51};52mb.create(options)53 .then(function (process) {54 mbProcess = process;55 console.log('mb started');56 return mbHelper.create({ mbPort: mbPort });57 })58 .then(function (helperProcess) {59 mbHelperProcess = helperProcess;60 console.log('mb
Using AI Code Generation
1var imposter = require('mountebank').create();2imposter.post('/reindex', function (request, response){3 imposter.reindex();4 response.statusCode = 200;5 response.end();6});7imposter.start(2525);8var mb = require('mountebank').create();9mb.post('/test', function (request, response){10 response.statusCode = 200;11 response.end();12});13mb.start(2525);14var mb = require('mountebank').create();15mb.post('/test3', function (request, response){16 response.statusCode = 200;17 response.end();18});19mb.start(2525);20var mb = require('mountebank').create();21mb.post('/test4', function (request, response){22 response.statusCode = 200;23 response.end();24});25mb.start(2525);26var mb = require('mountebank').create();27mb.post('/test5', function (request, response){28 response.statusCode = 200;29 response.end();30});31mb.start(2525);32var mb = require('mountebank').create();33mb.post('/test6', function (request, response){34 response.statusCode = 200;35 response.end();36});37mb.start(2525);38var mb = require('mountebank').create();39mb.post('/test7', function (request, response){40 response.statusCode = 200;41 response.end();42});43mb.start(2525);44var mb = require('mountebank').create();45mb.post('/test8', function (request, response){46 response.statusCode = 200;47 response.end();48});49mb.start(2525);50var mb = require('mountebank').create();51mb.post('/test9', function (request, response){52 response.statusCode = 200;53 response.end();54});55mb.start(2525);56var mb = require('mountebank').create();57mb.post('/test10', function (request, response){58 response.statusCode = 200;59 response.end();60});61mb.start(2525);62var mb = require('mountebank').create
Using AI Code Generation
1var mb = require('mountebank');2var mbHelper = require('./mbHelper');3var request = require('request');4var expect = require('expect.js');5var port = 2525;6var imposterPort = 3000;7var imposterName = 'testImposter';8var imposterPath = '/testImposter';9var imposterProtocol = 'http';10var imposterStub = {11 {12 is: {13 }14 }15};16var imposterStub2 = {17 {18 is: {19 }20 }21};22var imposterStub3 = {23 {24 is: {25 }26 }27};28var imposterStub4 = {29 {30 is: {31 }32 }33};34var imposterStub5 = {35 {36 is: {37 }38 }39};40var imposterStub6 = {41 {42 is: {43 }44 }45};46var imposterStub7 = {47 {48 is: {49 }50 }51};52var imposterStub8 = {53 {54 is: {55 }56 }57};58var imposterStub9 = {59 {60 is: {61 }62 }63};64var imposterStub10 = {65 {66 is: {67 }68 }69};70var imposterStub11 = {71 {72 is: {73 }74 }75};76var imposterStub12 = {77 {78 is: {79 }80 }81};82var imposterStub13 = {83 {84 is: {85 }86 }87};88var imposterStub14 = {89 {90 is: {
Using AI Code Generation
1const mb = require('mountebank');2const port = 2525;3mb.create({ port: port, allowInjection: true, ipWhitelist: ['*'] }, function (error, server) {4 console.log('Mountebank server is running on port ' + port);5 {6 {7 {8 is: {9 headers: {10 }11 }12 }13 }14 }15 ];16 server.createImposters(imposters, function (error, createdImposters) {17 console.log('Imposter created on port ' + createdImposters[0].port);18 server.reindex();19 });20});21[{"port":3000,"protocol":"http","stubs":[{"responses":[{"is":{"statusCode":200,"body":"Hello, World!","headers":{"Content-Type":"text/plain"}}}]}]}]
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!