[maps] fix layers are not displayed in offline environment and map.includeElasticMapsService not set to false (#152396)

Fixes https://github.com/elastic/kibana/issues/152389

PR adds check to ensure client has access to EMS before using EMS fonts.
If the client does not have access to EMS fonts then a warning is logged
and map falls back to open sans fonts served from Kibana server.
This commit is contained in:
Nathan Reese 2023-03-01 08:00:59 -07:00 committed by GitHub
parent f23346e4a6
commit 0c2e2c9b6f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 89 additions and 22 deletions

View file

@ -155,12 +155,13 @@ export class MbMap extends Component<Props, State> {
async _createMbMapInstance(initialView: MapCenterAndZoom | null): Promise<MapboxMap> {
this._reportUsage();
const glyphsUrlTemplate = await getGlyphUrl();
return new Promise((resolve) => {
const mbStyle = {
version: 8 as 8,
sources: {},
layers: [],
glyphs: getGlyphUrl(),
glyphs: glyphsUrlTemplate,
};
const options: MapOptions = {

View file

@ -5,60 +5,88 @@
* 2.0.
*/
import { getGlyphUrl, makePublicExecutionContext } from './util';
const MOCK_EMS_SETTINGS = {
isEMSEnabled: () => true,
};
import {
getGlyphUrl,
makePublicExecutionContext,
testOnlyClearCanAccessEmsFontsPromise,
} from './util';
describe('getGlyphUrl', () => {
describe('EMS enabled', () => {
beforeAll(() => {
beforeEach(() => {
require('./kibana_services').getHttp = () => ({
basePath: {
prepend: (url) => url, // No need to actually prepend a dev basepath for test
prepend: (path) => `abc${path}`,
},
});
testOnlyClearCanAccessEmsFontsPromise();
});
describe('EMS proxy disabled', () => {
describe('offline', () => {
beforeAll(() => {
require('./kibana_services').getEMSSettings = () => {
return {
getEMSFontLibraryUrl() {
return 'foobar';
return 'https://tiles.maps.elastic.co/fonts/{fontstack}/{range}.pbf';
},
isEMSEnabled() {
return true;
},
};
};
require('node-fetch').default = () => {
throw new Error('Simulated offline environment with no EMS access');
};
});
test('should return EMS fonts URL', async () => {
expect(getGlyphUrl()).toBe('foobar');
test('should return kibana fonts template URL', async () => {
expect(await getGlyphUrl()).toBe('abc/api/maps/fonts/{fontstack}/{range}');
});
});
describe('online', () => {
beforeAll(() => {
require('./kibana_services').getEMSSettings = () => {
return {
getEMSFontLibraryUrl() {
return 'https://tiles.maps.elastic.co/fonts/{fontstack}/{range}.pbf';
},
isEMSEnabled() {
return true;
},
};
};
require('node-fetch').default = () => {
return Promise.resolve({ status: 200 });
};
});
test('should return EMS fonts template URL', async () => {
expect(await getGlyphUrl()).toBe(
'https://tiles.maps.elastic.co/fonts/{fontstack}/{range}.pbf'
);
});
});
});
describe('EMS disabled', () => {
beforeAll(() => {
const mockHttp = {
basePath: {
prepend: (path) => `abc${path}`,
},
require('./kibana_services').getHttp = () => {
return {
basePath: {
prepend: (path) => `abc${path}`,
},
};
};
require('./kibana_services').getHttp = () => mockHttp;
require('./kibana_services').getEMSSettings = () => {
return {
...MOCK_EMS_SETTINGS,
isEMSEnabled: () => false,
};
};
});
test('should return kibana fonts URL', async () => {
expect(getGlyphUrl()).toBe('abc/api/maps/fonts/{fontstack}/{range}');
test('should return kibana fonts template URL', async () => {
expect(await getGlyphUrl()).toBe('abc/api/maps/fonts/{fontstack}/{range}');
});
});
});

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import fetch from 'node-fetch';
import { EMSClient, FileLayer, TMSService } from '@elastic/ems-client';
import type { KibanaExecutionContext } from '@kbn/core/public';
import { FONTS_API_PATH } from '../common/constants';
@ -60,9 +61,46 @@ async function getEMSClient(): Promise<EMSClient> {
return emsClient;
}
export function getGlyphUrl(): string {
let canAccessEmsFontsPromise: Promise<boolean> | null = null;
async function canAccessEmsFonts(): Promise<boolean> {
if (!canAccessEmsFontsPromise) {
canAccessEmsFontsPromise = new Promise(async (resolve) => {
try {
const emsSettings = getEMSSettings();
if (!emsSettings!.isEMSEnabled()) {
resolve(false);
}
const emsFontUrlTemplate = emsSettings!.getEMSFontLibraryUrl();
const emsFontUrl = emsFontUrlTemplate
.replace('{fontstack}', 'Open Sans')
.replace('{range}', '0-255');
const resp = await fetch(emsFontUrl, {
method: 'HEAD',
});
if (resp.status >= 400) {
throw new Error(`status: ${resp.status}`);
}
resolve(true);
} catch (error) {
// eslint-disable-next-line no-console
console.warn(
`Unable to access fonts from Elastic Maps Service (EMS). Set kibana.yml 'map.includeElasticMapsService: false' to avoid unnecessary EMS requests.`
);
resolve(false);
}
});
}
return canAccessEmsFontsPromise;
}
// test only function to reset singleton for different test cases.
export function testOnlyClearCanAccessEmsFontsPromise() {
canAccessEmsFontsPromise = null;
}
export async function getGlyphUrl(): Promise<string> {
const emsSettings = getEMSSettings();
if (!emsSettings!.isEMSEnabled()) {
if (!emsSettings!.isEMSEnabled() || !(await canAccessEmsFonts())) {
return getHttp().basePath.prepend(`/${FONTS_API_PATH}/{fontstack}/{range}`);
}