[8.5] Fix SO service status when migration is disabled (#145693) (#146095)

# Backport

This will backport the following commits from `main` to `8.5`:
- [Fix SO service status when migration is disabled
(#145693)](https://github.com/elastic/kibana/pull/145693)

<!--- Backport version: 8.9.7 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Pierre
Gayvallet","email":"pierre.gayvallet@elastic.co"},"sourceCommit":{"committedDate":"2022-11-21T08:02:52Z","message":"Fix
SO service status when migration is disabled (#145693)\n\n##
Summary\r\n\r\nFix
https://github.com/elastic/kibana/issues/145558\r\n\r\nhave the SO
service status properly be green instead of being stuck to\r\nred when
the SO migration was skipped using `migration.skip:
true`.\r\n\r\nCo-authored-by: Kibana Machine
<42973632+kibanamachine@users.noreply.github.com>","sha":"75100868427f10ec8ed19a2bae811263c0ded311","branchLabelMapping":{"^v8.7.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["Team:Core","release_note:skip","backport:prev-minor","v8.6.0","v8.7.0"],"number":145693,"url":"https://github.com/elastic/kibana/pull/145693","mergeCommit":{"message":"Fix
SO service status when migration is disabled (#145693)\n\n##
Summary\r\n\r\nFix
https://github.com/elastic/kibana/issues/145558\r\n\r\nhave the SO
service status properly be green instead of being stuck to\r\nred when
the SO migration was skipped using `migration.skip:
true`.\r\n\r\nCo-authored-by: Kibana Machine
<42973632+kibanamachine@users.noreply.github.com>","sha":"75100868427f10ec8ed19a2bae811263c0ded311"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"8.6","label":"v8.6.0","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"url":"https://github.com/elastic/kibana/pull/145974","number":145974,"state":"MERGED","mergeCommit":{"sha":"a06f55b8af572e1ed8c2c6d0cb0605a936b7d7db","message":"[8.6]
Fix SO service status when migration is disabled (#145693)
(#145974)\n\n# Backport\n\nThis will backport the following commits from
`main` to `8.6`:\n- [Fix SO service status when migration is
disabled\n(#145693)](https://github.com/elastic/kibana/pull/145693)\n\n<!---
Backport version: 8.9.7 -->\n\n### Questions ?\nPlease refer to the
[Backport
tool\ndocumentation](https://github.com/sqren/backport)\n\n<!--BACKPORT
[{\"author\":{\"name\":\"Pierre\nGayvallet\",\"email\":\"pierre.gayvallet@elastic.co\"},\"sourceCommit\":{\"committedDate\":\"2022-11-21T08:02:52Z\",\"message\":\"Fix\nSO
service status when migration is disabled
(#145693)\\n\\n##\nSummary\\r\\n\\r\\nFix\nhttps://github.com/elastic/kibana/issues/145558\\r\\n\\r\\nhave
the SO\nservice status properly be green instead of being stuck
to\\r\\nred when\nthe SO migration was skipped using
`migration.skip:\ntrue`.\\r\\n\\r\\nCo-authored-by: Kibana
Machine\n<42973632+kibanamachine@users.noreply.github.com>\",\"sha\":\"75100868427f10ec8ed19a2bae811263c0ded311\",\"branchLabelMapping\":{\"^v8.7.0$\":\"main\",\"^v(\\\\d+).(\\\\d+).\\\\d+$\":\"$1.$2\"}},\"sourcePullRequest\":{\"labels\":[\"Team:Core\",\"release_note:skip\",\"backport:prev-minor\",\"v8.6.0\",\"v8.7.0\"],\"number\":145693,\"url\":\"https://github.com/elastic/kibana/pull/145693\",\"mergeCommit\":{\"message\":\"Fix\nSO
service status when migration is disabled
(#145693)\\n\\n##\nSummary\\r\\n\\r\\nFix\nhttps://github.com/elastic/kibana/issues/145558\\r\\n\\r\\nhave
the SO\nservice status properly be green instead of being stuck
to\\r\\nred when\nthe SO migration was skipped using
`migration.skip:\ntrue`.\\r\\n\\r\\nCo-authored-by: Kibana
Machine\n<42973632+kibanamachine@users.noreply.github.com>\",\"sha\":\"75100868427f10ec8ed19a2bae811263c0ded311\"}},\"sourceBranch\":\"main\",\"suggestedTargetBranches\":[\"8.6\"],\"targetPullRequestStates\":[{\"branch\":\"8.6\",\"label\":\"v8.6.0\",\"labelRegex\":\"^v(\\\\d+).(\\\\d+).\\\\d+$\",\"isSourceBranch\":false,\"state\":\"NOT_CREATED\"},{\"branch\":\"main\",\"label\":\"v8.7.0\",\"labelRegex\":\"^v8.7.0$\",\"isSourceBranch\":true,\"state\":\"MERGED\",\"url\":\"https://github.com/elastic/kibana/pull/145693\",\"number\":145693,\"mergeCommit\":{\"message\":\"Fix\nSO
service status when migration is disabled
(#145693)\\n\\n##\nSummary\\r\\n\\r\\nFix\nhttps://github.com/elastic/kibana/issues/145558\\r\\n\\r\\nhave
the SO\nservice status properly be green instead of being stuck
to\\r\\nred when\nthe SO migration was skipped using
`migration.skip:\ntrue`.\\r\\n\\r\\nCo-authored-by: Kibana
Machine\n<42973632+kibanamachine@users.noreply.github.com>\",\"sha\":\"75100868427f10ec8ed19a2bae811263c0ded311\"}}]}]\nBACKPORT-->"}},{"branch":"main","label":"v8.7.0","labelRegex":"^v8.7.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/145693","number":145693,"mergeCommit":{"message":"Fix
SO service status when migration is disabled (#145693)\n\n##
Summary\r\n\r\nFix
https://github.com/elastic/kibana/issues/145558\r\n\r\nhave the SO
service status properly be green instead of being stuck to\r\nred when
the SO migration was skipped using `migration.skip:
true`.\r\n\r\nCo-authored-by: Kibana Machine
<42973632+kibanamachine@users.noreply.github.com>","sha":"75100868427f10ec8ed19a2bae811263c0ded311"}}]}]
BACKPORT-->

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Pierre Gayvallet 2022-11-23 14:00:50 +01:00 committed by GitHub
parent ee03b4d272
commit 19fa9da8ce
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 170 additions and 42 deletions

View file

@ -17,8 +17,9 @@ import {
registerRoutesMock,
typeRegistryInstanceMock,
} from './saved_objects_service.test.mocks';
import { BehaviorSubject } from 'rxjs';
import { RawPackageInfo, Env } from '@kbn/config';
import { BehaviorSubject, firstValueFrom } from 'rxjs';
import { skip } from 'rxjs/operators';
import { type RawPackageInfo, Env } from '@kbn/config';
import { ByteSizeValue } from '@kbn/config-schema';
import { REPO_ROOT } from '@kbn/utils';
import { getEnvOptions } from '@kbn/config-mocks';
@ -247,6 +248,21 @@ describe('SavedObjectsService', () => {
expect(getTypeRegistry()).toBe(typeRegistryInstanceMock);
});
});
describe('status$', () => {
it('return correct value when migration is skipped', async () => {
const coreContext = createCoreContext({ skipMigration: true });
const soService = new SavedObjectsService(coreContext);
const setup = await soService.setup(createSetupDeps());
await soService.start(createStartDeps(false));
const serviceStatus = await firstValueFrom(setup.status$.pipe(skip(1)));
expect(serviceStatus.level.toString()).toEqual('available');
expect(serviceStatus.summary).toEqual(
'SavedObjects service has completed migrations and is available'
);
});
});
});
describe('#start()', () => {

View file

@ -6,7 +6,7 @@
* Side Public License, v 1.
*/
import { Subject, Observable, firstValueFrom } from 'rxjs';
import { Subject, Observable, firstValueFrom, of } from 'rxjs';
import { filter, take, switchMap } from 'rxjs/operators';
import type { Logger } from '@kbn/logging';
import type { ServiceStatus } from '@kbn/core-status-common';
@ -146,9 +146,13 @@ export class SavedObjectsService
registerCoreObjectTypes(this.typeRegistry);
const skipMigration = this.config.migration.skip;
return {
status$: calculateStatus$(
this.migrator$.pipe(switchMap((migrator) => migrator.getStatus$())),
skipMigration
? of({ status: 'completed' })
: this.migrator$.pipe(switchMap((migrator) => migrator.getStatus$())),
elasticsearch.status$
),
setClientFactoryProvider: (provider) => {

View file

@ -17,43 +17,7 @@ export const calculateStatus$ = (
elasticsearchStatus$: Observable<ServiceStatus>
): Observable<ServiceStatus<SavedObjectStatusMeta>> => {
const migratorStatus$: Observable<ServiceStatus<SavedObjectStatusMeta>> = rawMigratorStatus$.pipe(
map((migrationStatus) => {
if (migrationStatus.status === 'waiting_to_start') {
return {
level: ServiceStatusLevels.unavailable,
summary: `SavedObjects service is waiting to start migrations`,
};
} else if (migrationStatus.status === 'waiting_for_other_nodes') {
return {
level: ServiceStatusLevels.unavailable,
summary: `SavedObjects service is waiting for other nodes to complete the migration`,
detail:
`If no other Kibana instance is attempting ` +
`migrations, you can get past this message by deleting index ${migrationStatus.waitingIndex} and ` +
`restarting Kibana.`,
};
} else if (migrationStatus.status === 'running') {
return {
level: ServiceStatusLevels.unavailable,
summary: `SavedObjects service is running migrations`,
};
}
const statusCounts: SavedObjectStatusMeta['migratedIndices'] = { migrated: 0, skipped: 0 };
if (migrationStatus.result) {
migrationStatus.result.forEach(({ status }) => {
statusCounts[status] = (statusCounts[status] ?? 0) + 1;
});
}
return {
level: ServiceStatusLevels.available,
summary: `SavedObjects service has completed migrations and is available`,
meta: {
migratedIndices: statusCounts,
},
};
}),
map(migratorStatusToServiceStatus),
startWith({
level: ServiceStatusLevels.unavailable,
summary: `SavedObjects service is waiting to start migrations`,
@ -80,3 +44,43 @@ export const calculateStatus$ = (
})
);
};
const migratorStatusToServiceStatus = (
migrationStatus: KibanaMigratorStatus
): ServiceStatus<SavedObjectStatusMeta> => {
if (migrationStatus.status === 'waiting_to_start') {
return {
level: ServiceStatusLevels.unavailable,
summary: `SavedObjects service is waiting to start migrations`,
};
} else if (migrationStatus.status === 'waiting_for_other_nodes') {
return {
level: ServiceStatusLevels.unavailable,
summary: `SavedObjects service is waiting for other nodes to complete the migration`,
detail:
`If no other Kibana instance is attempting ` +
`migrations, you can get past this message by deleting index ${migrationStatus.waitingIndex} and ` +
`restarting Kibana.`,
};
} else if (migrationStatus.status === 'running') {
return {
level: ServiceStatusLevels.unavailable,
summary: `SavedObjects service is running migrations`,
};
}
const statusCounts: SavedObjectStatusMeta['migratedIndices'] = { migrated: 0, skipped: 0 };
if (migrationStatus.result) {
migrationStatus.result.forEach(({ status }) => {
statusCounts[status] = (statusCounts[status] ?? 0) + 1;
});
}
return {
level: ServiceStatusLevels.available,
summary: `SavedObjects service has completed migrations and is available`,
meta: {
migratedIndices: statusCounts,
},
};
};

View file

@ -0,0 +1,104 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import Path from 'path';
import Fs from 'fs';
import Util from 'util';
import { firstValueFrom } from 'rxjs';
import * as kbnTestServer from '../../../../test_helpers/kbn_server';
import { Root } from '../../../root';
const logFilePath = Path.join(__dirname, 'cleanup.log');
const asyncUnlink = Util.promisify(Fs.unlink);
async function removeLogFile() {
// ignore errors if it doesn't exist
await asyncUnlink(logFilePath).catch(() => void 0);
}
function createRoot({ skipMigration }: { skipMigration: boolean }) {
return kbnTestServer.createRootWithCorePlugins(
{
migrations: {
skip: skipMigration,
},
logging: {
appenders: {
file: {
type: 'file',
fileName: logFilePath,
layout: {
type: 'json',
},
},
},
loggers: [
{
name: 'root',
appenders: ['file'],
level: 'info',
},
],
},
},
{
oss: true,
}
);
}
describe('starting with `migration.skip: true` when indices are up to date', () => {
let esServer: kbnTestServer.TestElasticsearchUtils;
let root: Root;
beforeAll(async () => {
await removeLogFile();
});
afterAll(async () => {
if (root) {
await root.shutdown();
}
if (esServer) {
await esServer.stop();
}
await new Promise((resolve) => setTimeout(resolve, 10000));
});
it('starts and display the correct service status', async () => {
const { startES } = kbnTestServer.createTestServers({
adjustTimeout: (t: number) => jest.setTimeout(t),
settings: {
es: {
license: 'basic',
},
},
});
esServer = await startES();
// booting root a first time to setup the indices
root = createRoot({ skipMigration: false });
await root.preboot();
await root.setup();
await root.start();
await root.shutdown();
// booting another root with migration skipped this time
root = createRoot({ skipMigration: true });
await root.preboot();
const setup = await root.setup();
await root.start();
const status = await firstValueFrom(setup.status.core$);
expect(status.savedObjects.level.toString()).toEqual('available');
expect(status.savedObjects.summary).toEqual(
'SavedObjects service has completed migrations and is available'
);
});
});

View file

@ -946,7 +946,7 @@ describe('test create task metrics', () => {
end_time: endTime,
...rest
} = response;
expect(timeExecutedInMs).toBeGreaterThan(10);
expect(timeExecutedInMs).toBeGreaterThanOrEqual(10);
expect(rest).toEqual({
name: 'test',
passed: true,