mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Upgrade Assistant] Create new status endpoint (#105998)
This commit is contained in:
parent
8a571c2f7d
commit
650f45b823
41 changed files with 606 additions and 109 deletions
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [DeprecationsClient](./kibana-plugin-core-server.deprecationsclient.md) > [getAllDeprecations](./kibana-plugin-core-server.deprecationsclient.getalldeprecations.md)
|
||||
|
||||
## DeprecationsClient.getAllDeprecations property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
getAllDeprecations: () => Promise<DomainDeprecationDetails[]>;
|
||||
```
|
|
@ -0,0 +1,20 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [DeprecationsClient](./kibana-plugin-core-server.deprecationsclient.md)
|
||||
|
||||
## DeprecationsClient interface
|
||||
|
||||
Server-side client that provides access to fetch all Kibana deprecations
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface DeprecationsClient
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [getAllDeprecations](./kibana-plugin-core-server.deprecationsclient.getalldeprecations.md) | <code>() => Promise<DomainDeprecationDetails[]></code> | |
|
||||
|
|
@ -71,6 +71,7 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
|
|||
| [DeprecationAPIClientParams](./kibana-plugin-core-server.deprecationapiclientparams.md) | |
|
||||
| [DeprecationAPIResponse](./kibana-plugin-core-server.deprecationapiresponse.md) | |
|
||||
| [DeprecationInfo](./kibana-plugin-core-server.deprecationinfo.md) | |
|
||||
| [DeprecationsClient](./kibana-plugin-core-server.deprecationsclient.md) | Server-side client that provides access to fetch all Kibana deprecations |
|
||||
| [DeprecationsDetails](./kibana-plugin-core-server.deprecationsdetails.md) | |
|
||||
| [DeprecationSettings](./kibana-plugin-core-server.deprecationsettings.md) | UiSettings deprecation field options. |
|
||||
| [DeprecationsServiceSetup](./kibana-plugin-core-server.deprecationsservicesetup.md) | The deprecations service provides a way for the Kibana platform to communicate deprecated features and configs with its users. These deprecations are only communicated if the deployment is using these features. Allowing for a user tailored experience for upgrading the stack version.<!-- -->The Deprecation service is consumed by the upgrade assistant to assist with the upgrade experience.<!-- -->If a deprecated feature can be resolved without manual user intervention. Using correctiveActions.api allows the Upgrade Assistant to use this api to correct the deprecation upon a user trigger. |
|
||||
|
|
|
@ -24,5 +24,8 @@ core: {
|
|||
uiSettings: {
|
||||
client: IUiSettingsClient;
|
||||
};
|
||||
deprecations: {
|
||||
client: DeprecationsClient;
|
||||
};
|
||||
};
|
||||
```
|
||||
|
|
|
@ -18,5 +18,5 @@ export interface RequestHandlerContext
|
|||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [core](./kibana-plugin-core-server.requesthandlercontext.core.md) | <code>{</code><br/><code> savedObjects: {</code><br/><code> client: SavedObjectsClientContract;</code><br/><code> typeRegistry: ISavedObjectTypeRegistry;</code><br/><code> getClient: (options?: SavedObjectsClientProviderOptions) => SavedObjectsClientContract;</code><br/><code> getExporter: (client: SavedObjectsClientContract) => ISavedObjectsExporter;</code><br/><code> getImporter: (client: SavedObjectsClientContract) => ISavedObjectsImporter;</code><br/><code> };</code><br/><code> elasticsearch: {</code><br/><code> client: IScopedClusterClient;</code><br/><code> legacy: {</code><br/><code> client: ILegacyScopedClusterClient;</code><br/><code> };</code><br/><code> };</code><br/><code> uiSettings: {</code><br/><code> client: IUiSettingsClient;</code><br/><code> };</code><br/><code> }</code> | |
|
||||
| [core](./kibana-plugin-core-server.requesthandlercontext.core.md) | <code>{</code><br/><code> savedObjects: {</code><br/><code> client: SavedObjectsClientContract;</code><br/><code> typeRegistry: ISavedObjectTypeRegistry;</code><br/><code> getClient: (options?: SavedObjectsClientProviderOptions) => SavedObjectsClientContract;</code><br/><code> getExporter: (client: SavedObjectsClientContract) => ISavedObjectsExporter;</code><br/><code> getImporter: (client: SavedObjectsClientContract) => ISavedObjectsImporter;</code><br/><code> };</code><br/><code> elasticsearch: {</code><br/><code> client: IScopedClusterClient;</code><br/><code> legacy: {</code><br/><code> client: ILegacyScopedClusterClient;</code><br/><code> };</code><br/><code> };</code><br/><code> uiSettings: {</code><br/><code> client: IUiSettingsClient;</code><br/><code> };</code><br/><code> deprecations: {</code><br/><code> client: DeprecationsClient;</code><br/><code> };</code><br/><code> }</code> | |
|
||||
|
||||
|
|
|
@ -192,3 +192,40 @@ describe('#uiSettings', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#deprecations', () => {
|
||||
describe('#client', () => {
|
||||
test('returns the results of coreStart.deprecations.asScopedToClient', () => {
|
||||
const request = httpServerMock.createKibanaRequest();
|
||||
const coreStart = coreMock.createInternalStart();
|
||||
const context = new CoreRouteHandlerContext(coreStart, request);
|
||||
|
||||
const client = context.deprecations.client;
|
||||
expect(client).toBe(coreStart.deprecations.asScopedToClient.mock.results[0].value);
|
||||
});
|
||||
|
||||
test('lazily created', () => {
|
||||
const request = httpServerMock.createKibanaRequest();
|
||||
const coreStart = coreMock.createInternalStart();
|
||||
const context = new CoreRouteHandlerContext(coreStart, request);
|
||||
|
||||
expect(coreStart.deprecations.asScopedToClient).not.toHaveBeenCalled();
|
||||
const client = context.deprecations.client;
|
||||
expect(coreStart.deprecations.asScopedToClient).toHaveBeenCalled();
|
||||
expect(client).toBeDefined();
|
||||
});
|
||||
|
||||
test('only creates one instance', () => {
|
||||
const request = httpServerMock.createKibanaRequest();
|
||||
const coreStart = coreMock.createInternalStart();
|
||||
const context = new CoreRouteHandlerContext(coreStart, request);
|
||||
|
||||
const client1 = context.deprecations.client;
|
||||
const client2 = context.deprecations.client;
|
||||
expect(coreStart.deprecations.asScopedToClient.mock.calls.length).toBe(1);
|
||||
const mockResult = coreStart.deprecations.asScopedToClient.mock.results[0].value;
|
||||
expect(client1).toBe(mockResult);
|
||||
expect(client2).toBe(mockResult);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -21,6 +21,7 @@ import {
|
|||
LegacyScopedClusterClient,
|
||||
} from './elasticsearch';
|
||||
import { InternalUiSettingsServiceStart, IUiSettingsClient } from './ui_settings';
|
||||
import { DeprecationsClient, InternalDeprecationsServiceStart } from './deprecations';
|
||||
|
||||
class CoreElasticsearchRouteHandlerContext {
|
||||
#client?: IScopedClusterClient;
|
||||
|
@ -103,10 +104,30 @@ class CoreUiSettingsRouteHandlerContext {
|
|||
}
|
||||
}
|
||||
|
||||
class CoreDeprecationsRouteHandlerContext {
|
||||
#client?: DeprecationsClient;
|
||||
constructor(
|
||||
private readonly deprecationsStart: InternalDeprecationsServiceStart,
|
||||
private readonly elasticsearchRouterHandlerContext: CoreElasticsearchRouteHandlerContext,
|
||||
private readonly savedObjectsRouterHandlerContext: CoreSavedObjectsRouteHandlerContext
|
||||
) {}
|
||||
|
||||
public get client() {
|
||||
if (this.#client == null) {
|
||||
this.#client = this.deprecationsStart.asScopedToClient(
|
||||
this.elasticsearchRouterHandlerContext.client,
|
||||
this.savedObjectsRouterHandlerContext.client
|
||||
);
|
||||
}
|
||||
return this.#client;
|
||||
}
|
||||
}
|
||||
|
||||
export class CoreRouteHandlerContext {
|
||||
readonly elasticsearch: CoreElasticsearchRouteHandlerContext;
|
||||
readonly savedObjects: CoreSavedObjectsRouteHandlerContext;
|
||||
readonly uiSettings: CoreUiSettingsRouteHandlerContext;
|
||||
readonly deprecations: CoreDeprecationsRouteHandlerContext;
|
||||
|
||||
constructor(
|
||||
private readonly coreStart: InternalCoreStart,
|
||||
|
@ -124,5 +145,10 @@ export class CoreRouteHandlerContext {
|
|||
this.coreStart.uiSettings,
|
||||
this.savedObjects
|
||||
);
|
||||
this.deprecations = new CoreDeprecationsRouteHandlerContext(
|
||||
this.coreStart.deprecations,
|
||||
this.elasticsearch,
|
||||
this.savedObjects
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@ import {
|
|||
DeprecationsService,
|
||||
InternalDeprecationsServiceSetup,
|
||||
DeprecationsServiceSetup,
|
||||
InternalDeprecationsServiceStart,
|
||||
DeprecationsClient,
|
||||
} from './deprecations_service';
|
||||
type DeprecationsServiceContract = PublicMethodsOf<DeprecationsService>;
|
||||
|
||||
|
@ -22,6 +24,16 @@ const createSetupContractMock = () => {
|
|||
return setupContract;
|
||||
};
|
||||
|
||||
const createStartContractMock = () => {
|
||||
const mocked: jest.Mocked<InternalDeprecationsServiceStart> = {
|
||||
asScopedToClient: jest.fn(),
|
||||
};
|
||||
|
||||
mocked.asScopedToClient.mockReturnValue(createClientMock());
|
||||
|
||||
return mocked;
|
||||
};
|
||||
|
||||
const createInternalSetupContractMock = () => {
|
||||
const internalSetupContract: jest.Mocked<InternalDeprecationsServiceSetup> = {
|
||||
getRegistry: jest.fn(),
|
||||
|
@ -42,8 +54,18 @@ const createDeprecationsServiceMock = () => {
|
|||
return mocked;
|
||||
};
|
||||
|
||||
const createClientMock = () => {
|
||||
const mocked: jest.Mocked<DeprecationsClient> = {
|
||||
getAllDeprecations: jest.fn(),
|
||||
};
|
||||
mocked.getAllDeprecations.mockResolvedValue([]);
|
||||
return mocked;
|
||||
};
|
||||
|
||||
export const deprecationsServiceMock = {
|
||||
create: createDeprecationsServiceMock,
|
||||
createInternalSetupContract: createInternalSetupContractMock,
|
||||
createSetupContract: createSetupContractMock,
|
||||
createInternalStartContract: createStartContractMock,
|
||||
createClient: createClientMock,
|
||||
};
|
||||
|
|
|
@ -10,20 +10,21 @@
|
|||
import { DeprecationsService } from './deprecations_service';
|
||||
import { httpServiceMock } from '../http/http_service.mock';
|
||||
import { mockRouter } from '../http/router/router.mock';
|
||||
import { savedObjectsClientMock, elasticsearchServiceMock } from '../mocks';
|
||||
import { mockCoreContext } from '../core_context.mock';
|
||||
import { mockDeprecationsFactory } from './deprecations_factory.mock';
|
||||
import { mockDeprecationsRegistry } from './deprecations_registry.mock';
|
||||
|
||||
describe('DeprecationsService', () => {
|
||||
const coreContext = mockCoreContext.create();
|
||||
const http = httpServiceMock.createInternalSetupContract();
|
||||
const router = mockRouter.create();
|
||||
http.createRouter.mockReturnValue(router);
|
||||
const deprecationsCoreSetupDeps = { http };
|
||||
|
||||
beforeEach(() => jest.clearAllMocks());
|
||||
|
||||
describe('#setup', () => {
|
||||
const http = httpServiceMock.createInternalSetupContract();
|
||||
const router = mockRouter.create();
|
||||
http.createRouter.mockReturnValue(router);
|
||||
const deprecationsCoreSetupDeps = { http };
|
||||
|
||||
it('registers routes', () => {
|
||||
const deprecationsService = new DeprecationsService(coreContext);
|
||||
deprecationsService.setup(deprecationsCoreSetupDeps);
|
||||
|
@ -43,6 +44,23 @@ describe('DeprecationsService', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('#start', () => {
|
||||
describe('#asScopedToClient', () => {
|
||||
it('returns client with #getAllDeprecations method', async () => {
|
||||
const esClient = elasticsearchServiceMock.createScopedClusterClient();
|
||||
const savedObjectsClient = savedObjectsClientMock.create();
|
||||
const deprecationsService = new DeprecationsService(coreContext);
|
||||
|
||||
deprecationsService.setup(deprecationsCoreSetupDeps);
|
||||
|
||||
const start = deprecationsService.start();
|
||||
const deprecationsClient = start.asScopedToClient(esClient, savedObjectsClient);
|
||||
|
||||
expect(deprecationsClient.getAllDeprecations).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#registerConfigDeprecationsInfo', () => {
|
||||
const deprecationsFactory = mockDeprecationsFactory.create();
|
||||
const deprecationsRegistry = mockDeprecationsRegistry.create();
|
||||
|
|
|
@ -7,13 +7,15 @@
|
|||
*/
|
||||
|
||||
import { DeprecationsFactory } from './deprecations_factory';
|
||||
import { RegisterDeprecationsConfig } from './types';
|
||||
import { DomainDeprecationDetails, RegisterDeprecationsConfig } from './types';
|
||||
import { registerRoutes } from './routes';
|
||||
|
||||
import { CoreContext } from '../core_context';
|
||||
import { CoreService } from '../../types';
|
||||
import { InternalHttpServiceSetup } from '../http';
|
||||
import { Logger } from '../logging';
|
||||
import { IScopedClusterClient } from '../elasticsearch/client';
|
||||
import { SavedObjectsClientContract } from '../saved_objects/types';
|
||||
|
||||
/**
|
||||
* The deprecations service provides a way for the Kibana platform to communicate deprecated
|
||||
|
@ -102,6 +104,25 @@ export interface DeprecationsServiceSetup {
|
|||
registerDeprecations: (deprecationContext: RegisterDeprecationsConfig) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Server-side client that provides access to fetch all Kibana deprecations
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface DeprecationsClient {
|
||||
getAllDeprecations: () => Promise<DomainDeprecationDetails[]>;
|
||||
}
|
||||
export interface InternalDeprecationsServiceStart {
|
||||
/**
|
||||
* Creates a {@link DeprecationsClient} with provided SO client and ES client.
|
||||
*
|
||||
*/
|
||||
asScopedToClient(
|
||||
esClient: IScopedClusterClient,
|
||||
savedObjectsClient: SavedObjectsClientContract
|
||||
): DeprecationsClient;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export interface InternalDeprecationsServiceSetup {
|
||||
getRegistry: (domainId: string) => DeprecationsServiceSetup;
|
||||
|
@ -113,21 +134,24 @@ export interface DeprecationsSetupDeps {
|
|||
}
|
||||
|
||||
/** @internal */
|
||||
export class DeprecationsService implements CoreService<InternalDeprecationsServiceSetup> {
|
||||
export class DeprecationsService
|
||||
implements CoreService<InternalDeprecationsServiceSetup, InternalDeprecationsServiceStart> {
|
||||
private readonly logger: Logger;
|
||||
private readonly deprecationsFactory: DeprecationsFactory;
|
||||
|
||||
constructor(private readonly coreContext: Pick<CoreContext, 'logger' | 'configService'>) {
|
||||
this.logger = coreContext.logger.get('deprecations-service');
|
||||
this.deprecationsFactory = new DeprecationsFactory({
|
||||
logger: this.logger,
|
||||
});
|
||||
}
|
||||
|
||||
public setup({ http }: DeprecationsSetupDeps): InternalDeprecationsServiceSetup {
|
||||
this.logger.debug('Setting up Deprecations service');
|
||||
const deprecationsFactory = new DeprecationsFactory({
|
||||
logger: this.logger,
|
||||
});
|
||||
const deprecationsFactory = this.deprecationsFactory;
|
||||
|
||||
registerRoutes({ http, deprecationsFactory });
|
||||
this.registerConfigDeprecationsInfo(deprecationsFactory);
|
||||
registerRoutes({ http });
|
||||
this.registerConfigDeprecationsInfo(this.deprecationsFactory);
|
||||
|
||||
return {
|
||||
getRegistry: (domainId: string): DeprecationsServiceSetup => {
|
||||
|
@ -139,9 +163,28 @@ export class DeprecationsService implements CoreService<InternalDeprecationsServ
|
|||
};
|
||||
}
|
||||
|
||||
public start() {}
|
||||
public start(): InternalDeprecationsServiceStart {
|
||||
return {
|
||||
asScopedToClient: this.createScopedDeprecations(),
|
||||
};
|
||||
}
|
||||
|
||||
public stop() {}
|
||||
|
||||
private createScopedDeprecations(): (
|
||||
esClient: IScopedClusterClient,
|
||||
savedObjectsClient: SavedObjectsClientContract
|
||||
) => DeprecationsClient {
|
||||
return (esClient: IScopedClusterClient, savedObjectsClient: SavedObjectsClientContract) => {
|
||||
return {
|
||||
getAllDeprecations: this.deprecationsFactory.getAllDeprecations.bind(null, {
|
||||
savedObjectsClient,
|
||||
esClient,
|
||||
}),
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
private registerConfigDeprecationsInfo(deprecationsFactory: DeprecationsFactory) {
|
||||
const handledDeprecatedConfigs = this.coreContext.configService.getHandledDeprecatedConfigs();
|
||||
|
||||
|
|
|
@ -16,6 +16,8 @@ export type {
|
|||
export type {
|
||||
DeprecationsServiceSetup,
|
||||
InternalDeprecationsServiceSetup,
|
||||
InternalDeprecationsServiceStart,
|
||||
DeprecationsClient,
|
||||
} from './deprecations_service';
|
||||
|
||||
export { DeprecationsService } from './deprecations_service';
|
||||
|
|
|
@ -6,27 +6,19 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
import { IRouter } from '../../http';
|
||||
import { GetDeprecationsContext, DeprecationsGetResponse } from '../types';
|
||||
import { DeprecationsFactory } from '../deprecations_factory';
|
||||
import { DeprecationsGetResponse } from '../types';
|
||||
|
||||
interface RouteDependencies {
|
||||
deprecationsFactory: DeprecationsFactory;
|
||||
}
|
||||
|
||||
export const registerGetRoute = (router: IRouter, { deprecationsFactory }: RouteDependencies) => {
|
||||
export const registerGetRoute = (router: IRouter) => {
|
||||
router.get(
|
||||
{
|
||||
path: '/',
|
||||
validate: false,
|
||||
},
|
||||
async (context, req, res) => {
|
||||
const dependencies: GetDeprecationsContext = {
|
||||
esClient: context.core.elasticsearch.client,
|
||||
savedObjectsClient: context.core.savedObjects.client,
|
||||
};
|
||||
const deprecationsClient = context.core.deprecations.client;
|
||||
|
||||
const body: DeprecationsGetResponse = {
|
||||
deprecations: await deprecationsFactory.getAllDeprecations(dependencies),
|
||||
deprecations: await deprecationsClient.getAllDeprecations(),
|
||||
};
|
||||
|
||||
return res.ok({ body });
|
||||
|
|
|
@ -8,15 +8,8 @@
|
|||
|
||||
import { InternalHttpServiceSetup } from '../../http';
|
||||
import { registerGetRoute } from './get';
|
||||
import { DeprecationsFactory } from '../deprecations_factory';
|
||||
|
||||
export function registerRoutes({
|
||||
http,
|
||||
deprecationsFactory,
|
||||
}: {
|
||||
http: InternalHttpServiceSetup;
|
||||
deprecationsFactory: DeprecationsFactory;
|
||||
}) {
|
||||
export function registerRoutes({ http }: { http: InternalHttpServiceSetup }) {
|
||||
const router = http.createRouter('/api/deprecations');
|
||||
registerGetRoute(router, { deprecationsFactory });
|
||||
registerGetRoute(router);
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ import { StatusServiceSetup } from './status';
|
|||
import { AppenderConfigType, appendersSchema, LoggingServiceSetup } from './logging';
|
||||
import { CoreUsageDataStart } from './core_usage_data';
|
||||
import { I18nServiceSetup } from './i18n';
|
||||
import { DeprecationsServiceSetup } from './deprecations';
|
||||
import { DeprecationsServiceSetup, DeprecationsClient } from './deprecations';
|
||||
// Because of #79265 we need to explicitly import, then export these types for
|
||||
// scripts/telemetry_check.js to work as expected
|
||||
import {
|
||||
|
@ -408,6 +408,7 @@ export type {
|
|||
RegisterDeprecationsConfig,
|
||||
GetDeprecationsContext,
|
||||
DeprecationsServiceSetup,
|
||||
DeprecationsClient,
|
||||
} from './deprecations';
|
||||
|
||||
export type { AppCategory } from '../types';
|
||||
|
@ -471,6 +472,9 @@ export interface RequestHandlerContext {
|
|||
uiSettings: {
|
||||
client: IUiSettingsClient;
|
||||
};
|
||||
deprecations: {
|
||||
client: DeprecationsClient;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ import { InternalStatusServiceSetup } from './status';
|
|||
import { InternalLoggingServicePreboot, InternalLoggingServiceSetup } from './logging';
|
||||
import { CoreUsageDataStart } from './core_usage_data';
|
||||
import { I18nServiceSetup } from './i18n';
|
||||
import { InternalDeprecationsServiceSetup } from './deprecations';
|
||||
import { InternalDeprecationsServiceSetup, InternalDeprecationsServiceStart } from './deprecations';
|
||||
import type {
|
||||
InternalExecutionContextSetup,
|
||||
InternalExecutionContextStart,
|
||||
|
@ -87,6 +87,7 @@ export interface InternalCoreStart {
|
|||
uiSettings: InternalUiSettingsServiceStart;
|
||||
coreUsageData: CoreUsageDataStart;
|
||||
executionContext: InternalExecutionContextStart;
|
||||
deprecations: InternalDeprecationsServiceStart;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -236,6 +236,7 @@ function createInternalCoreStartMock() {
|
|||
uiSettings: uiSettingsServiceMock.createStartContract(),
|
||||
coreUsageData: coreUsageDataServiceMock.createStartContract(),
|
||||
executionContext: executionContextServiceMock.createInternalStartContract(),
|
||||
deprecations: deprecationsServiceMock.createInternalStartContract(),
|
||||
};
|
||||
return startDeps;
|
||||
}
|
||||
|
@ -258,6 +259,9 @@ function createCoreRequestHandlerContextMock() {
|
|||
uiSettings: {
|
||||
client: uiSettingsServiceMock.createClient(),
|
||||
},
|
||||
deprecations: {
|
||||
client: deprecationsServiceMock.createClient(),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -894,6 +894,14 @@ export interface DeprecationInfo {
|
|||
url: string;
|
||||
}
|
||||
|
||||
// @public
|
||||
export interface DeprecationsClient {
|
||||
// Warning: (ae-forgotten-export) The symbol "DomainDeprecationDetails" needs to be exported by the entry point index.d.ts
|
||||
//
|
||||
// (undocumented)
|
||||
getAllDeprecations: () => Promise<DomainDeprecationDetails[]>;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "DeprecationsDetails" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
|
@ -2102,6 +2110,9 @@ export interface RequestHandlerContext {
|
|||
uiSettings: {
|
||||
client: IUiSettingsClient;
|
||||
};
|
||||
deprecations: {
|
||||
client: DeprecationsClient;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -101,3 +101,9 @@ export const mockPrebootService = prebootServiceMock.create();
|
|||
jest.doMock('./preboot/preboot_service', () => ({
|
||||
PrebootService: jest.fn(() => mockPrebootService),
|
||||
}));
|
||||
|
||||
import { deprecationsServiceMock } from './deprecations/deprecations_service.mock';
|
||||
export const mockDeprecationService = deprecationsServiceMock.create();
|
||||
jest.doMock('./deprecations/deprecations_service', () => ({
|
||||
DeprecationsService: jest.fn(() => mockDeprecationService),
|
||||
}));
|
||||
|
|
|
@ -23,6 +23,7 @@ import {
|
|||
mockI18nService,
|
||||
mockEnvironmentService,
|
||||
mockPrebootService,
|
||||
mockDeprecationService,
|
||||
} from './server.test.mocks';
|
||||
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
|
@ -102,6 +103,7 @@ test('sets up services on "setup"', async () => {
|
|||
expect(mockStatusService.setup).not.toHaveBeenCalled();
|
||||
expect(mockLoggingService.setup).not.toHaveBeenCalled();
|
||||
expect(mockI18nService.setup).not.toHaveBeenCalled();
|
||||
expect(mockDeprecationService.setup).not.toHaveBeenCalled();
|
||||
|
||||
await server.setup();
|
||||
|
||||
|
@ -117,6 +119,7 @@ test('sets up services on "setup"', async () => {
|
|||
expect(mockStatusService.setup).toHaveBeenCalledTimes(1);
|
||||
expect(mockLoggingService.setup).toHaveBeenCalledTimes(1);
|
||||
expect(mockI18nService.setup).toHaveBeenCalledTimes(1);
|
||||
expect(mockDeprecationService.setup).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('injects legacy dependency to context#setup()', async () => {
|
||||
|
@ -166,6 +169,7 @@ test('runs services on "start"', async () => {
|
|||
expect(mockUiSettingsService.start).not.toHaveBeenCalled();
|
||||
expect(mockMetricsService.start).not.toHaveBeenCalled();
|
||||
expect(mockStatusService.start).not.toHaveBeenCalled();
|
||||
expect(mockDeprecationService.start).not.toHaveBeenCalled();
|
||||
|
||||
await server.start();
|
||||
|
||||
|
@ -174,6 +178,7 @@ test('runs services on "start"', async () => {
|
|||
expect(mockUiSettingsService.start).toHaveBeenCalledTimes(1);
|
||||
expect(mockMetricsService.start).toHaveBeenCalledTimes(1);
|
||||
expect(mockStatusService.start).toHaveBeenCalledTimes(1);
|
||||
expect(mockDeprecationService.start).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('does not fail on "setup" if there are unused paths detected', async () => {
|
||||
|
|
|
@ -317,6 +317,7 @@ export class Server {
|
|||
savedObjects: savedObjectsStart,
|
||||
exposedConfigsToUsage: this.plugins.getExposedPluginConfigsToUsage(),
|
||||
});
|
||||
const deprecationsStart = this.deprecations.start();
|
||||
this.status.start();
|
||||
|
||||
this.coreStart = {
|
||||
|
@ -328,6 +329,7 @@ export class Server {
|
|||
savedObjects: savedObjectsStart,
|
||||
uiSettings: uiSettingsStart,
|
||||
coreUsageData: coreUsageDataStart,
|
||||
deprecations: deprecationsStart,
|
||||
};
|
||||
|
||||
await this.plugins.start(this.coreStart);
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { MlAction, UpgradeAssistantStatus } from '../../common/types';
|
||||
import { MlAction, ESUpgradeStatus } from '../../common/types';
|
||||
|
||||
import { ClusterTestBed, setupClusterPage, setupEnvironment } from './helpers';
|
||||
|
||||
|
@ -21,8 +21,8 @@ describe('Cluster tab', () => {
|
|||
describe('with deprecations', () => {
|
||||
const snapshotId = '1';
|
||||
const jobId = 'deprecation_check_job';
|
||||
const upgradeStatusMockResponse: UpgradeAssistantStatus = {
|
||||
readyForUpgrade: false,
|
||||
const esDeprecationsMockResponse: ESUpgradeStatus = {
|
||||
totalCriticalDeprecations: 1,
|
||||
cluster: [
|
||||
{
|
||||
level: 'critical',
|
||||
|
@ -42,7 +42,7 @@ describe('Cluster tab', () => {
|
|||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
httpRequestsMockHelpers.setLoadEsDeprecationsResponse(upgradeStatusMockResponse);
|
||||
httpRequestsMockHelpers.setLoadEsDeprecationsResponse(esDeprecationsMockResponse);
|
||||
httpRequestsMockHelpers.setLoadDeprecationLoggingResponse({ isEnabled: true });
|
||||
|
||||
await act(async () => {
|
||||
|
@ -79,7 +79,7 @@ describe('Cluster tab', () => {
|
|||
actions.clickExpandAll();
|
||||
|
||||
// The data-test-subj is derived from the deprecation message
|
||||
const accordionTestSubj = `depgroup_${upgradeStatusMockResponse.cluster[0].message
|
||||
const accordionTestSubj = `depgroup_${esDeprecationsMockResponse.cluster[0].message
|
||||
.split(' ')
|
||||
.join('_')}`;
|
||||
|
||||
|
@ -155,7 +155,7 @@ describe('Cluster tab', () => {
|
|||
expect(upgradeRequest.method).toBe('POST');
|
||||
expect(upgradeRequest.url).toBe('/api/upgrade_assistant/ml_snapshots');
|
||||
|
||||
const accordionTestSubj = `depgroup_${upgradeStatusMockResponse.cluster[0].message
|
||||
const accordionTestSubj = `depgroup_${esDeprecationsMockResponse.cluster[0].message
|
||||
.split(' ')
|
||||
.join('_')}`;
|
||||
|
||||
|
@ -180,7 +180,7 @@ describe('Cluster tab', () => {
|
|||
component.update();
|
||||
|
||||
const request = server.requests[server.requests.length - 1];
|
||||
const mlDeprecation = upgradeStatusMockResponse.cluster[0];
|
||||
const mlDeprecation = esDeprecationsMockResponse.cluster[0];
|
||||
|
||||
expect(request.method).toBe('DELETE');
|
||||
expect(request.url).toBe(
|
||||
|
@ -212,7 +212,7 @@ describe('Cluster tab', () => {
|
|||
component.update();
|
||||
|
||||
const request = server.requests[server.requests.length - 1];
|
||||
const mlDeprecation = upgradeStatusMockResponse.cluster[0];
|
||||
const mlDeprecation = esDeprecationsMockResponse.cluster[0];
|
||||
|
||||
expect(request.method).toBe('DELETE');
|
||||
expect(request.url).toBe(
|
||||
|
@ -221,7 +221,7 @@ describe('Cluster tab', () => {
|
|||
}/${(mlDeprecation.correctiveAction! as MlAction).snapshotId}`
|
||||
);
|
||||
|
||||
const accordionTestSubj = `depgroup_${upgradeStatusMockResponse.cluster[0].message
|
||||
const accordionTestSubj = `depgroup_${esDeprecationsMockResponse.cluster[0].message
|
||||
.split(' ')
|
||||
.join('_')}`;
|
||||
|
||||
|
@ -233,7 +233,7 @@ describe('Cluster tab', () => {
|
|||
describe('no deprecations', () => {
|
||||
beforeEach(async () => {
|
||||
const noDeprecationsResponse = {
|
||||
readyForUpgrade: false,
|
||||
totalCriticalDeprecations: 0,
|
||||
cluster: [],
|
||||
indices: [],
|
||||
};
|
||||
|
|
|
@ -7,19 +7,16 @@
|
|||
|
||||
import sinon, { SinonFakeServer } from 'sinon';
|
||||
import { API_BASE_PATH } from '../../../common/constants';
|
||||
import { UpgradeAssistantStatus } from '../../../common/types';
|
||||
import { ESUpgradeStatus } from '../../../common/types';
|
||||
import { ResponseError } from '../../../public/application/lib/api';
|
||||
|
||||
// Register helpers to mock HTTP Requests
|
||||
const registerHttpRequestMockHelpers = (server: SinonFakeServer) => {
|
||||
const setLoadEsDeprecationsResponse = (
|
||||
response?: UpgradeAssistantStatus,
|
||||
error?: ResponseError
|
||||
) => {
|
||||
const setLoadEsDeprecationsResponse = (response?: ESUpgradeStatus, error?: ResponseError) => {
|
||||
const status = error ? error.statusCode || 400 : 200;
|
||||
const body = error ? error : response;
|
||||
|
||||
server.respondWith('GET', `${API_BASE_PATH}/status`, [
|
||||
server.respondWith('GET', `${API_BASE_PATH}/es_deprecations`, [
|
||||
status,
|
||||
{ 'Content-Type': 'application/json' },
|
||||
JSON.stringify(body),
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { indexSettingDeprecations } from '../../common/constants';
|
||||
import { UpgradeAssistantStatus } from '../../common/types';
|
||||
import { ESUpgradeStatus } from '../../common/types';
|
||||
|
||||
import { IndicesTestBed, setupIndicesPage, setupEnvironment } from './helpers';
|
||||
|
||||
|
@ -20,8 +20,8 @@ describe('Indices tab', () => {
|
|||
});
|
||||
|
||||
describe('with deprecations', () => {
|
||||
const upgradeStatusMockResponse: UpgradeAssistantStatus = {
|
||||
readyForUpgrade: false,
|
||||
const esDeprecationsMockResponse: ESUpgradeStatus = {
|
||||
totalCriticalDeprecations: 0,
|
||||
cluster: [],
|
||||
indices: [
|
||||
{
|
||||
|
@ -38,7 +38,7 @@ describe('Indices tab', () => {
|
|||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
httpRequestsMockHelpers.setLoadEsDeprecationsResponse(upgradeStatusMockResponse);
|
||||
httpRequestsMockHelpers.setLoadEsDeprecationsResponse(esDeprecationsMockResponse);
|
||||
httpRequestsMockHelpers.setLoadDeprecationLoggingResponse({ isEnabled: true });
|
||||
|
||||
await act(async () => {
|
||||
|
@ -93,7 +93,7 @@ describe('Indices tab', () => {
|
|||
expect(modal).not.toBe(null);
|
||||
expect(modal!.textContent).toContain('Remove deprecated settings');
|
||||
|
||||
const indexName = upgradeStatusMockResponse.indices[0].index;
|
||||
const indexName = esDeprecationsMockResponse.indices[0].index;
|
||||
|
||||
httpRequestsMockHelpers.setUpdateIndexSettingsResponse({
|
||||
acknowledged: true,
|
||||
|
@ -117,7 +117,7 @@ describe('Indices tab', () => {
|
|||
describe('no deprecations', () => {
|
||||
beforeEach(async () => {
|
||||
const noDeprecationsResponse = {
|
||||
readyForUpgrade: false,
|
||||
totalCriticalDeprecations: 0,
|
||||
cluster: [],
|
||||
indices: [],
|
||||
};
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import type { DomainDeprecationDetails } from 'kibana/public';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { deprecationsServiceMock } from 'src/core/public/mocks';
|
||||
import { UpgradeAssistantStatus } from '../../common/types';
|
||||
import { ESUpgradeStatus } from '../../common/types';
|
||||
|
||||
import { OverviewTestBed, setupOverviewPage, setupEnvironment } from './helpers';
|
||||
|
||||
|
@ -17,8 +17,8 @@ describe('Overview page', () => {
|
|||
const { server, httpRequestsMockHelpers } = setupEnvironment();
|
||||
|
||||
beforeEach(async () => {
|
||||
const esDeprecationsMockResponse: UpgradeAssistantStatus = {
|
||||
readyForUpgrade: false,
|
||||
const esDeprecationsMockResponse: ESUpgradeStatus = {
|
||||
totalCriticalDeprecations: 1,
|
||||
cluster: [
|
||||
{
|
||||
level: 'critical',
|
||||
|
|
|
@ -220,8 +220,8 @@ export interface EnrichedDeprecationInfo extends DeprecationInfo {
|
|||
correctiveAction?: ReindexAction | MlAction | IndexSettingAction;
|
||||
}
|
||||
|
||||
export interface UpgradeAssistantStatus {
|
||||
readyForUpgrade: boolean;
|
||||
export interface ESUpgradeStatus {
|
||||
totalCriticalDeprecations: number;
|
||||
cluster: EnrichedDeprecationInfo[];
|
||||
indices: EnrichedDeprecationInfo[];
|
||||
}
|
||||
|
|
|
@ -7,12 +7,12 @@
|
|||
|
||||
import React from 'react';
|
||||
|
||||
import { EnrichedDeprecationInfo, UpgradeAssistantStatus } from '../../../common/types';
|
||||
import { EnrichedDeprecationInfo, ESUpgradeStatus } from '../../../common/types';
|
||||
import { ResponseError } from '../lib/api';
|
||||
|
||||
export interface UpgradeAssistantTabProps {
|
||||
alertBanner?: React.ReactNode;
|
||||
checkupData?: UpgradeAssistantStatus | null;
|
||||
checkupData?: ESUpgradeStatus | null;
|
||||
deprecations?: EnrichedDeprecationInfo[];
|
||||
refreshCheckupData: () => void;
|
||||
error: ResponseError | null;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import { HttpSetup } from 'src/core/public';
|
||||
import { UpgradeAssistantStatus } from '../../../common/types';
|
||||
import { ESUpgradeStatus } from '../../../common/types';
|
||||
import { API_BASE_PATH } from '../../../common/constants';
|
||||
import {
|
||||
UseRequestConfig,
|
||||
|
@ -46,8 +46,8 @@ export class ApiService {
|
|||
}
|
||||
|
||||
public useLoadUpgradeStatus() {
|
||||
return this.useRequest<UpgradeAssistantStatus>({
|
||||
path: `${API_BASE_PATH}/status`,
|
||||
return this.useRequest<ESUpgradeStatus>({
|
||||
path: `${API_BASE_PATH}/es_deprecations`,
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`getUpgradeAssistantStatus returns the correct shape of data 1`] = `
|
||||
exports[`getESUpgradeStatus returns the correct shape of data 1`] = `
|
||||
Object {
|
||||
"cluster": Array [
|
||||
Object {
|
||||
|
@ -129,6 +129,6 @@ Object {
|
|||
"url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields",
|
||||
},
|
||||
],
|
||||
"readyForUpgrade": false,
|
||||
"totalCriticalDeprecations": 4,
|
||||
}
|
||||
`;
|
7
x-pack/plugins/upgrade_assistant/server/lib/__snapshots__/kibana_status.test.ts.snap
generated
Normal file
7
x-pack/plugins/upgrade_assistant/server/lib/__snapshots__/kibana_status.test.ts.snap
generated
Normal file
|
@ -0,0 +1,7 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`getKibanaUpgradeStatus returns the correct shape of data 1`] = `
|
||||
Object {
|
||||
"totalCriticalDeprecations": 1,
|
||||
}
|
||||
`;
|
|
@ -10,7 +10,7 @@ import { RequestEvent } from '@elastic/elasticsearch/lib/Transport';
|
|||
import { elasticsearchServiceMock } from 'src/core/server/mocks';
|
||||
import { DeprecationAPIResponse } from '../../common/types';
|
||||
|
||||
import { getUpgradeAssistantStatus } from './es_migration_apis';
|
||||
import { getESUpgradeStatus } from './es_deprecations_status';
|
||||
import fakeDeprecations from './__fixtures__/fake_deprecations.json';
|
||||
|
||||
const fakeIndexNames = Object.keys(fakeDeprecations.index_settings);
|
||||
|
@ -20,7 +20,7 @@ const asApiResponse = <T>(body: T): RequestEvent<T> =>
|
|||
body,
|
||||
} as RequestEvent<T>);
|
||||
|
||||
describe('getUpgradeAssistantStatus', () => {
|
||||
describe('getESUpgradeStatus', () => {
|
||||
const resolvedIndices = {
|
||||
indices: fakeIndexNames.map((indexName) => {
|
||||
// mark one index as closed to test blockerForReindexing flag
|
||||
|
@ -45,16 +45,16 @@ describe('getUpgradeAssistantStatus', () => {
|
|||
esClient.asCurrentUser.indices.resolveIndex.mockResolvedValue(asApiResponse(resolvedIndices));
|
||||
|
||||
it('calls /_migration/deprecations', async () => {
|
||||
await getUpgradeAssistantStatus(esClient);
|
||||
await getESUpgradeStatus(esClient);
|
||||
expect(esClient.asCurrentUser.migration.deprecations).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('returns the correct shape of data', async () => {
|
||||
const resp = await getUpgradeAssistantStatus(esClient);
|
||||
const resp = await getESUpgradeStatus(esClient);
|
||||
expect(resp).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('returns readyForUpgrade === false when critical issues found', async () => {
|
||||
it('returns totalCriticalDeprecations > 0 when critical issues found', async () => {
|
||||
esClient.asCurrentUser.migration.deprecations.mockResolvedValue(
|
||||
// @ts-expect-error not full interface
|
||||
asApiResponse({
|
||||
|
@ -65,13 +65,13 @@ describe('getUpgradeAssistantStatus', () => {
|
|||
})
|
||||
);
|
||||
|
||||
await expect(getUpgradeAssistantStatus(esClient)).resolves.toHaveProperty(
|
||||
'readyForUpgrade',
|
||||
false
|
||||
await expect(getESUpgradeStatus(esClient)).resolves.toHaveProperty(
|
||||
'totalCriticalDeprecations',
|
||||
1
|
||||
);
|
||||
});
|
||||
|
||||
it('returns readyForUpgrade === true when no critical issues found', async () => {
|
||||
it('returns totalCriticalDeprecations === 0 when no critical issues found', async () => {
|
||||
esClient.asCurrentUser.migration.deprecations.mockResolvedValue(
|
||||
// @ts-expect-error not full interface
|
||||
asApiResponse({
|
||||
|
@ -82,9 +82,9 @@ describe('getUpgradeAssistantStatus', () => {
|
|||
})
|
||||
);
|
||||
|
||||
await expect(getUpgradeAssistantStatus(esClient)).resolves.toHaveProperty(
|
||||
'readyForUpgrade',
|
||||
true
|
||||
await expect(getESUpgradeStatus(esClient)).resolves.toHaveProperty(
|
||||
'totalCriticalDeprecations',
|
||||
0
|
||||
);
|
||||
});
|
||||
});
|
|
@ -10,23 +10,24 @@ import { indexSettingDeprecations } from '../../common/constants';
|
|||
import {
|
||||
DeprecationAPIResponse,
|
||||
EnrichedDeprecationInfo,
|
||||
UpgradeAssistantStatus,
|
||||
ESUpgradeStatus,
|
||||
} from '../../common/types';
|
||||
|
||||
import { esIndicesStateCheck } from './es_indices_state_check';
|
||||
|
||||
export async function getUpgradeAssistantStatus(
|
||||
export async function getESUpgradeStatus(
|
||||
dataClient: IScopedClusterClient
|
||||
): Promise<UpgradeAssistantStatus> {
|
||||
): Promise<ESUpgradeStatus> {
|
||||
const { body: deprecations } = await dataClient.asCurrentUser.migration.deprecations();
|
||||
|
||||
const cluster = getClusterDeprecations(deprecations);
|
||||
const indices = await getCombinedIndexInfos(deprecations, dataClient);
|
||||
|
||||
const criticalWarnings = cluster.concat(indices).filter((d) => d.level === 'critical');
|
||||
const totalCriticalDeprecations = cluster.concat(indices).filter((d) => d.level === 'critical')
|
||||
.length;
|
||||
|
||||
return {
|
||||
readyForUpgrade: criticalWarnings.length === 0,
|
||||
totalCriticalDeprecations,
|
||||
cluster,
|
||||
indices,
|
||||
};
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { deprecationsServiceMock } from 'src/core/server/mocks';
|
||||
import { DomainDeprecationDetails } from 'src/core/server/types';
|
||||
|
||||
import { getKibanaUpgradeStatus } from './kibana_status';
|
||||
|
||||
const mockKibanaDeprecations: DomainDeprecationDetails[] = [
|
||||
{
|
||||
correctiveActions: {
|
||||
manualSteps: [
|
||||
'Using Kibana user management, change all users using the kibana_user role to the kibana_admin role.',
|
||||
'Using Kibana role-mapping management, change all role-mappings which assing the kibana_user role to the kibana_admin role.',
|
||||
],
|
||||
},
|
||||
deprecationType: 'config',
|
||||
documentationUrl: 'testDocUrl',
|
||||
level: 'critical',
|
||||
message: 'testMessage',
|
||||
requireRestart: true,
|
||||
domainId: 'security',
|
||||
},
|
||||
];
|
||||
|
||||
describe('getKibanaUpgradeStatus', () => {
|
||||
const deprecationsClient = deprecationsServiceMock.createClient();
|
||||
|
||||
deprecationsClient.getAllDeprecations.mockResolvedValue(mockKibanaDeprecations);
|
||||
|
||||
it('returns the correct shape of data', async () => {
|
||||
const resp = await getKibanaUpgradeStatus(deprecationsClient);
|
||||
expect(resp).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('returns totalCriticalDeprecations > 0 when critical issues found', async () => {
|
||||
deprecationsClient.getAllDeprecations.mockResolvedValue(mockKibanaDeprecations);
|
||||
|
||||
await expect(getKibanaUpgradeStatus(deprecationsClient)).resolves.toHaveProperty(
|
||||
'totalCriticalDeprecations',
|
||||
1
|
||||
);
|
||||
});
|
||||
|
||||
it('returns totalCriticalDeprecations === 0 when no critical issues found', async () => {
|
||||
deprecationsClient.getAllDeprecations.mockResolvedValue([]);
|
||||
|
||||
await expect(getKibanaUpgradeStatus(deprecationsClient)).resolves.toHaveProperty(
|
||||
'totalCriticalDeprecations',
|
||||
0
|
||||
);
|
||||
});
|
||||
});
|
19
x-pack/plugins/upgrade_assistant/server/lib/kibana_status.ts
Normal file
19
x-pack/plugins/upgrade_assistant/server/lib/kibana_status.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { DeprecationsClient } from 'kibana/server';
|
||||
import { DomainDeprecationDetails } from 'src/core/server/types';
|
||||
|
||||
export const getKibanaUpgradeStatus = async (deprecationsClient: DeprecationsClient) => {
|
||||
const kibanaDeprecations: DomainDeprecationDetails[] = await deprecationsClient.getAllDeprecations();
|
||||
|
||||
const totalCriticalDeprecations = kibanaDeprecations.filter((d) => d.level === 'critical').length;
|
||||
|
||||
return {
|
||||
totalCriticalDeprecations,
|
||||
};
|
||||
};
|
|
@ -94,13 +94,13 @@ export class UpgradeAssistantServerPlugin implements Plugin {
|
|||
router,
|
||||
credentialStore: this.credentialStore,
|
||||
log: this.logger,
|
||||
licensing,
|
||||
getSavedObjectsService: () => {
|
||||
if (!this.savedObjectsServiceStart) {
|
||||
throw new Error('Saved Objects Start service not available');
|
||||
}
|
||||
return this.savedObjectsServiceStart;
|
||||
},
|
||||
licensing,
|
||||
};
|
||||
|
||||
// Initialize version service with current kibana version
|
||||
|
|
|
@ -9,6 +9,7 @@ import { RequestHandler, RequestHandlerContext } from 'src/core/server';
|
|||
import {
|
||||
elasticsearchServiceMock,
|
||||
savedObjectsClientMock,
|
||||
deprecationsServiceMock,
|
||||
} from '../../../../../../src/core/server/mocks';
|
||||
|
||||
export const routeHandlerContextMock = ({
|
||||
|
@ -17,6 +18,7 @@ export const routeHandlerContextMock = ({
|
|||
client: elasticsearchServiceMock.createScopedClusterClient(),
|
||||
},
|
||||
savedObjects: { client: savedObjectsClientMock.create() },
|
||||
deprecations: { client: deprecationsServiceMock.createClient() },
|
||||
},
|
||||
} as unknown) as RequestHandlerContext;
|
||||
|
||||
|
|
|
@ -15,17 +15,17 @@ jest.mock('../lib/es_version_precheck', () => ({
|
|||
|
||||
// Need to require to get mock on named export to work.
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const MigrationApis = require('../lib/es_migration_apis');
|
||||
MigrationApis.getUpgradeAssistantStatus = jest.fn();
|
||||
const ESUpgradeStatusApis = require('../lib/es_deprecations_status');
|
||||
ESUpgradeStatusApis.getESUpgradeStatus = jest.fn();
|
||||
|
||||
import { registerClusterCheckupRoutes } from './cluster_checkup';
|
||||
import { registerESDeprecationRoutes } from './es_deprecations';
|
||||
|
||||
/**
|
||||
* Since these route callbacks are so thin, these serve simply as integration tests
|
||||
* to ensure they're wired up to the lib functions correctly. Business logic is tested
|
||||
* more thoroughly in the es_migration_apis test.
|
||||
* more thoroughly in the es_deprecations_status test.
|
||||
*/
|
||||
describe('cluster checkup API', () => {
|
||||
describe('ES deprecations API', () => {
|
||||
let mockRouter: MockRouter;
|
||||
let routeDependencies: any;
|
||||
|
||||
|
@ -34,23 +34,23 @@ describe('cluster checkup API', () => {
|
|||
routeDependencies = {
|
||||
router: mockRouter,
|
||||
};
|
||||
registerClusterCheckupRoutes(routeDependencies);
|
||||
registerESDeprecationRoutes(routeDependencies);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
describe('GET /api/upgrade_assistant/reindex/{indexName}.json', () => {
|
||||
describe('GET /api/upgrade_assistant/es_deprecations', () => {
|
||||
it('returns state', async () => {
|
||||
MigrationApis.getUpgradeAssistantStatus.mockResolvedValue({
|
||||
ESUpgradeStatusApis.getESUpgradeStatus.mockResolvedValue({
|
||||
cluster: [],
|
||||
indices: [],
|
||||
nodes: [],
|
||||
});
|
||||
const resp = await routeDependencies.router.getHandler({
|
||||
method: 'get',
|
||||
pathPattern: '/api/upgrade_assistant/status',
|
||||
pathPattern: '/api/upgrade_assistant/es_deprecations',
|
||||
})(routeHandlerContextMock, createRequestMock(), kibanaResponseFactory);
|
||||
|
||||
expect(resp.status).toEqual(200);
|
||||
|
@ -63,22 +63,22 @@ describe('cluster checkup API', () => {
|
|||
const e: any = new Error(`you can't go here!`);
|
||||
e.statusCode = 403;
|
||||
|
||||
MigrationApis.getUpgradeAssistantStatus.mockRejectedValue(e);
|
||||
ESUpgradeStatusApis.getESUpgradeStatus.mockRejectedValue(e);
|
||||
const resp = await routeDependencies.router.getHandler({
|
||||
method: 'get',
|
||||
pathPattern: '/api/upgrade_assistant/status',
|
||||
pathPattern: '/api/upgrade_assistant/es_deprecations',
|
||||
})(routeHandlerContextMock, createRequestMock(), kibanaResponseFactory);
|
||||
|
||||
expect(resp.status).toEqual(403);
|
||||
});
|
||||
|
||||
it('returns an 500 error if it throws', async () => {
|
||||
MigrationApis.getUpgradeAssistantStatus.mockRejectedValue(new Error(`scary error!`));
|
||||
ESUpgradeStatusApis.getESUpgradeStatus.mockRejectedValue(new Error('scary error!'));
|
||||
|
||||
await expect(
|
||||
routeDependencies.router.getHandler({
|
||||
method: 'get',
|
||||
pathPattern: '/api/upgrade_assistant/status',
|
||||
pathPattern: '/api/upgrade_assistant/es_deprecations',
|
||||
})(routeHandlerContextMock, createRequestMock(), kibanaResponseFactory)
|
||||
).rejects.toThrow('scary error!');
|
||||
});
|
|
@ -6,16 +6,16 @@
|
|||
*/
|
||||
|
||||
import { API_BASE_PATH } from '../../common/constants';
|
||||
import { getUpgradeAssistantStatus } from '../lib/es_migration_apis';
|
||||
import { getESUpgradeStatus } from '../lib/es_deprecations_status';
|
||||
import { versionCheckHandlerWrapper } from '../lib/es_version_precheck';
|
||||
import { RouteDependencies } from '../types';
|
||||
import { reindexActionsFactory } from '../lib/reindexing/reindex_actions';
|
||||
import { reindexServiceFactory } from '../lib/reindexing';
|
||||
|
||||
export function registerClusterCheckupRoutes({ router, licensing, log }: RouteDependencies) {
|
||||
export function registerESDeprecationRoutes({ router, licensing, log }: RouteDependencies) {
|
||||
router.get(
|
||||
{
|
||||
path: `${API_BASE_PATH}/status`,
|
||||
path: `${API_BASE_PATH}/es_deprecations`,
|
||||
validate: false,
|
||||
},
|
||||
versionCheckHandlerWrapper(
|
||||
|
@ -30,7 +30,7 @@ export function registerClusterCheckupRoutes({ router, licensing, log }: RouteDe
|
|||
response
|
||||
) => {
|
||||
try {
|
||||
const status = await getUpgradeAssistantStatus(client);
|
||||
const status = await getESUpgradeStatus(client);
|
||||
|
||||
const asCurrentUser = client.asCurrentUser;
|
||||
const reindexActions = reindexActionsFactory(savedObjectsClient, asCurrentUser);
|
|
@ -7,19 +7,22 @@
|
|||
|
||||
import { RouteDependencies } from '../types';
|
||||
|
||||
import { registerClusterCheckupRoutes } from './cluster_checkup';
|
||||
import { registerESDeprecationRoutes } from './es_deprecations';
|
||||
import { registerDeprecationLoggingRoutes } from './deprecation_logging';
|
||||
import { registerReindexIndicesRoutes } from './reindex_indices';
|
||||
import { registerTelemetryRoutes } from './telemetry';
|
||||
import { registerUpdateSettingsRoute } from './update_index_settings';
|
||||
import { registerMlSnapshotRoutes } from './ml_snapshots';
|
||||
import { ReindexWorker } from '../lib/reindexing';
|
||||
import { registerUpgradeStatusRoute } from './status';
|
||||
|
||||
export function registerRoutes(dependencies: RouteDependencies, getWorker: () => ReindexWorker) {
|
||||
registerClusterCheckupRoutes(dependencies);
|
||||
registerESDeprecationRoutes(dependencies);
|
||||
registerDeprecationLoggingRoutes(dependencies);
|
||||
registerReindexIndicesRoutes(dependencies, getWorker);
|
||||
registerTelemetryRoutes(dependencies);
|
||||
registerUpdateSettingsRoute(dependencies);
|
||||
registerMlSnapshotRoutes(dependencies);
|
||||
// Route for cloud to retrieve the upgrade status for ES and Kibana
|
||||
registerUpgradeStatusRoute(dependencies);
|
||||
}
|
||||
|
|
119
x-pack/plugins/upgrade_assistant/server/routes/status.test.ts
Normal file
119
x-pack/plugins/upgrade_assistant/server/routes/status.test.ts
Normal file
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { kibanaResponseFactory } from 'src/core/server';
|
||||
import { createMockRouter, MockRouter, routeHandlerContextMock } from './__mocks__/routes.mock';
|
||||
import { createRequestMock } from './__mocks__/request.mock';
|
||||
import { registerUpgradeStatusRoute } from './status';
|
||||
|
||||
jest.mock('../lib/es_version_precheck', () => ({
|
||||
versionCheckHandlerWrapper: (a: any) => a,
|
||||
}));
|
||||
|
||||
// Need to require to get mock on named export to work.
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const ESUpgradeStatusApis = require('../lib/es_deprecations_status');
|
||||
ESUpgradeStatusApis.getESUpgradeStatus = jest.fn();
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const KibanaUpgradeStatusApis = require('../lib/kibana_status');
|
||||
KibanaUpgradeStatusApis.getKibanaUpgradeStatus = jest.fn();
|
||||
|
||||
describe('Status API', () => {
|
||||
let mockRouter: MockRouter;
|
||||
let routeDependencies: any;
|
||||
|
||||
beforeEach(() => {
|
||||
mockRouter = createMockRouter();
|
||||
routeDependencies = {
|
||||
router: mockRouter,
|
||||
};
|
||||
registerUpgradeStatusRoute(routeDependencies);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
describe('GET /api/upgrade_assistant/status', () => {
|
||||
it('returns readyForUpgrade === false if Kibana or ES contain critical deprecations', async () => {
|
||||
ESUpgradeStatusApis.getESUpgradeStatus.mockResolvedValue({
|
||||
cluster: [
|
||||
{
|
||||
level: 'critical',
|
||||
message:
|
||||
'model snapshot [1] for job [deprecation_check_job] needs to be deleted or upgraded',
|
||||
details:
|
||||
'model snapshot [%s] for job [%s] supports minimum version [%s] and needs to be at least [%s]',
|
||||
url: 'doc_url',
|
||||
correctiveAction: {
|
||||
type: 'mlSnapshot',
|
||||
snapshotId: '1',
|
||||
jobId: 'deprecation_check_job',
|
||||
},
|
||||
},
|
||||
],
|
||||
indices: [],
|
||||
totalCriticalDeprecations: 1,
|
||||
});
|
||||
|
||||
KibanaUpgradeStatusApis.getKibanaUpgradeStatus.mockResolvedValue({
|
||||
totalCriticalDeprecations: 1,
|
||||
});
|
||||
|
||||
const resp = await routeDependencies.router.getHandler({
|
||||
method: 'get',
|
||||
pathPattern: '/api/upgrade_assistant/status',
|
||||
})(routeHandlerContextMock, createRequestMock(), kibanaResponseFactory);
|
||||
|
||||
expect(resp.status).toEqual(200);
|
||||
expect(resp.payload).toEqual({
|
||||
readyForUpgrade: false,
|
||||
details:
|
||||
'You have 1 Elasticsearch deprecation issues and 1 Kibana deprecation issues that must be resolved before upgrading.',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns readyForUpgrade === true if there are no critical deprecations', async () => {
|
||||
ESUpgradeStatusApis.getESUpgradeStatus.mockResolvedValue({
|
||||
cluster: [],
|
||||
indices: [],
|
||||
totalCriticalDeprecations: 0,
|
||||
});
|
||||
|
||||
KibanaUpgradeStatusApis.getKibanaUpgradeStatus.mockResolvedValue({
|
||||
totalCriticalDeprecations: 0,
|
||||
});
|
||||
|
||||
const resp = await routeDependencies.router.getHandler({
|
||||
method: 'get',
|
||||
pathPattern: '/api/upgrade_assistant/status',
|
||||
})(routeHandlerContextMock, createRequestMock(), kibanaResponseFactory);
|
||||
|
||||
expect(resp.status).toEqual(200);
|
||||
expect(resp.payload).toEqual({
|
||||
readyForUpgrade: true,
|
||||
details: 'All deprecation issues have been resolved.',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error if it throws', async () => {
|
||||
ESUpgradeStatusApis.getESUpgradeStatus.mockRejectedValue(new Error('test error'));
|
||||
|
||||
KibanaUpgradeStatusApis.getKibanaUpgradeStatus.mockResolvedValue({
|
||||
totalCriticalDeprecations: 0,
|
||||
});
|
||||
|
||||
await expect(
|
||||
routeDependencies.router.getHandler({
|
||||
method: 'get',
|
||||
pathPattern: '/api/upgrade_assistant/status',
|
||||
})(routeHandlerContextMock, createRequestMock(), kibanaResponseFactory)
|
||||
).rejects.toThrow('test error');
|
||||
});
|
||||
});
|
||||
});
|
73
x-pack/plugins/upgrade_assistant/server/routes/status.ts
Normal file
73
x-pack/plugins/upgrade_assistant/server/routes/status.ts
Normal file
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* 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; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { API_BASE_PATH } from '../../common/constants';
|
||||
import { getESUpgradeStatus } from '../lib/es_deprecations_status';
|
||||
import { versionCheckHandlerWrapper } from '../lib/es_version_precheck';
|
||||
import { getKibanaUpgradeStatus } from '../lib/kibana_status';
|
||||
import { RouteDependencies } from '../types';
|
||||
import { handleEsError } from '../shared_imports';
|
||||
|
||||
export function registerUpgradeStatusRoute({ router }: RouteDependencies) {
|
||||
router.get(
|
||||
{
|
||||
path: `${API_BASE_PATH}/status`,
|
||||
validate: false,
|
||||
},
|
||||
versionCheckHandlerWrapper(
|
||||
async (
|
||||
{
|
||||
core: {
|
||||
elasticsearch: { client: esClient },
|
||||
deprecations: { client: deprecationsClient },
|
||||
},
|
||||
},
|
||||
request,
|
||||
response
|
||||
) => {
|
||||
try {
|
||||
// Fetch ES upgrade status
|
||||
const { totalCriticalDeprecations: esTotalCriticalDeps } = await getESUpgradeStatus(
|
||||
esClient
|
||||
);
|
||||
// Fetch Kibana upgrade status
|
||||
const {
|
||||
totalCriticalDeprecations: kibanaTotalCriticalDeps,
|
||||
} = await getKibanaUpgradeStatus(deprecationsClient);
|
||||
const readyForUpgrade = esTotalCriticalDeps === 0 && kibanaTotalCriticalDeps === 0;
|
||||
|
||||
const getStatusMessage = () => {
|
||||
if (readyForUpgrade) {
|
||||
return i18n.translate(
|
||||
'xpack.upgradeAssistant.status.allDeprecationsResolvedMessage',
|
||||
{
|
||||
defaultMessage: 'All deprecation issues have been resolved.',
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return i18n.translate('xpack.upgradeAssistant.status.deprecationsUnresolvedMessage', {
|
||||
defaultMessage:
|
||||
'You have {esTotalCriticalDeps} Elasticsearch deprecation issues and {kibanaTotalCriticalDeps} Kibana deprecation issues that must be resolved before upgrading.',
|
||||
values: { esTotalCriticalDeps, kibanaTotalCriticalDeps },
|
||||
});
|
||||
};
|
||||
|
||||
return response.ok({
|
||||
body: {
|
||||
readyForUpgrade,
|
||||
details: getStatusMessage(),
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
return handleEsError({ error: e, response });
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
|
@ -35,7 +35,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
});
|
||||
});
|
||||
|
||||
describe('Update index settings route', () => {
|
||||
describe('POST /api/upgrade_assistant/{indexName}/index_settings', () => {
|
||||
const indexName = 'update_settings_test_index';
|
||||
const indexSettings = {
|
||||
number_of_shards: '3',
|
||||
|
@ -121,5 +121,22 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
expect(body.error).to.eql('Internal Server Error');
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET /api/upgrade_assistant/status', () => {
|
||||
it('returns a successful response', async () => {
|
||||
const { body } = await supertest
|
||||
.get('/api/upgrade_assistant/status')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.expect(200);
|
||||
|
||||
const expectedResponseKeys = ['readyForUpgrade', 'details'];
|
||||
|
||||
// We're not able to easily test different upgrade status scenarios (there are tests with mocked data to handle this)
|
||||
// so, for now, we simply verify the response returns the expected format
|
||||
expectedResponseKeys.forEach((key) => {
|
||||
expect(body[key]).to.not.equal(undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue