mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Synthetics UI] return 404 in project monitor APIs with non-existing spaces. (#149136)
## Summary Closes #148930 Returns a 404 when the project monitor APIs are called with a non-existent space. When testing, note that the API _does_ return 404, but the @elastic/synthetics package seems to ignore this. Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: shahzad31 <shahzad31comp@gmail.com>
This commit is contained in:
parent
cf907f7a98
commit
1d5e25ae27
14 changed files with 65 additions and 36 deletions
|
@ -19,7 +19,6 @@ import {
|
|||
import { euiStyled } from '@kbn/kibana-react-plugin/common';
|
||||
|
||||
import { OverviewStatusState } from '../../../../../../../common/runtime_types';
|
||||
import { useSyntheticsRefreshContext } from '../../../../contexts/synthetics_refresh_context';
|
||||
|
||||
import * as labels from '../labels';
|
||||
import { MonitorTestRunsCount } from './monitor_test_runs';
|
||||
|
@ -27,8 +26,6 @@ import { MonitorTestRunsSparkline } from './monitor_test_runs_sparkline';
|
|||
|
||||
export const MonitorStats = ({ status }: { status: OverviewStatusState | null }) => {
|
||||
const { euiTheme } = useEuiTheme();
|
||||
const { lastRefresh } = useSyntheticsRefreshContext();
|
||||
const to = new Date(lastRefresh).toISOString();
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -67,9 +64,9 @@ export const MonitorStats = ({ status }: { status: OverviewStatusState | null })
|
|||
<EuiFlexItem
|
||||
css={{ display: 'flex', flexDirection: 'row', gap: euiTheme.size.l, height: '200px' }}
|
||||
>
|
||||
<MonitorTestRunsCount to={to} />
|
||||
<MonitorTestRunsCount />
|
||||
<EuiFlexItem grow={true}>
|
||||
<MonitorTestRunsSparkline to={to} />
|
||||
<MonitorTestRunsSparkline />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexItem>
|
||||
</EuiPanel>
|
||||
|
|
|
@ -11,30 +11,25 @@ import { useKibana } from '@kbn/kibana-react-plugin/public';
|
|||
import { useTheme } from '@kbn/observability-plugin/public';
|
||||
import { ReportTypes } from '@kbn/observability-plugin/public';
|
||||
|
||||
import { useAbsoluteDate } from '../../../../hooks';
|
||||
import { ClientPluginsStart } from '../../../../../../plugin';
|
||||
import * as labels from '../labels';
|
||||
|
||||
interface MonitorCompleteCountProps {
|
||||
from?: string;
|
||||
to?: string;
|
||||
}
|
||||
|
||||
export const MonitorTestRunsCount = ({
|
||||
from = 'now-30d',
|
||||
to = 'now',
|
||||
}: MonitorCompleteCountProps) => {
|
||||
export const MonitorTestRunsCount = () => {
|
||||
const { observability } = useKibana<ClientPluginsStart>().services;
|
||||
const theme = useTheme();
|
||||
|
||||
const { ExploratoryViewEmbeddable } = observability;
|
||||
|
||||
const { from: absFrom, to: absTo } = useAbsoluteDate({ from: 'now-30d', to: 'now' });
|
||||
|
||||
return (
|
||||
<ExploratoryViewEmbeddable
|
||||
align="left"
|
||||
reportType={ReportTypes.SINGLE_METRIC}
|
||||
attributes={[
|
||||
{
|
||||
time: { from, to },
|
||||
time: { from: absFrom, to: absTo },
|
||||
reportDefinitions: {
|
||||
'monitor.id': [],
|
||||
'observer.geo.name': [],
|
||||
|
|
|
@ -10,20 +10,19 @@ import React from 'react';
|
|||
import { useKibana } from '@kbn/kibana-react-plugin/public';
|
||||
import { useTheme } from '@kbn/observability-plugin/public';
|
||||
|
||||
import { useAbsoluteDate } from '../../../../hooks';
|
||||
import { ClientPluginsStart } from '../../../../../../plugin';
|
||||
import * as labels from '../labels';
|
||||
|
||||
interface Props {
|
||||
from?: string;
|
||||
to?: string;
|
||||
}
|
||||
export const MonitorTestRunsSparkline = ({ from = 'now-30d', to = 'now' }: Props) => {
|
||||
export const MonitorTestRunsSparkline = () => {
|
||||
const { observability } = useKibana<ClientPluginsStart>().services;
|
||||
|
||||
const { ExploratoryViewEmbeddable } = observability;
|
||||
|
||||
const theme = useTheme();
|
||||
|
||||
const { from, to } = useAbsoluteDate({ from: 'now-30d', to: 'now' });
|
||||
|
||||
return (
|
||||
<ExploratoryViewEmbeddable
|
||||
reportType="kpi-over-time"
|
||||
|
|
|
@ -28,7 +28,7 @@ import { MlPluginSetup as MlSetup } from '@kbn/ml-plugin/server';
|
|||
import { RuleRegistryPluginSetupContract } from '@kbn/rule-registry-plugin/server';
|
||||
import { SecurityPluginStart } from '@kbn/security-plugin/server';
|
||||
import { CloudSetup } from '@kbn/cloud-plugin/server';
|
||||
import { SpacesPluginSetup } from '@kbn/spaces-plugin/server';
|
||||
import { SpacesPluginStart } from '@kbn/spaces-plugin/server';
|
||||
import { FleetStartContract } from '@kbn/fleet-plugin/server';
|
||||
import { BfetchServerSetup } from '@kbn/bfetch-plugin/server';
|
||||
import { UptimeEsClient } from '../../lib';
|
||||
|
@ -54,7 +54,7 @@ export interface UptimeServerSetup {
|
|||
router: UptimeRouter;
|
||||
config: UptimeConfig;
|
||||
cloud?: CloudSetup;
|
||||
spaces: SpacesPluginSetup;
|
||||
spaces: SpacesPluginStart;
|
||||
fleet: FleetStartContract;
|
||||
security: SecurityPluginStart;
|
||||
savedObjectsClient?: SavedObjectsClientContract;
|
||||
|
@ -76,7 +76,6 @@ export interface UptimeCorePluginsSetup {
|
|||
usageCollection: UsageCollectionSetup;
|
||||
ml: MlSetup;
|
||||
cloud?: CloudSetup;
|
||||
spaces: SpacesPluginSetup;
|
||||
ruleRegistry: RuleRegistryPluginSetupContract;
|
||||
encryptedSavedObjects: EncryptedSavedObjectsPluginSetup;
|
||||
taskManager: TaskManagerSetupContract;
|
||||
|
@ -90,4 +89,5 @@ export interface UptimeCorePluginsStart {
|
|||
encryptedSavedObjects: EncryptedSavedObjectsPluginStart;
|
||||
taskManager: TaskManagerStartContract;
|
||||
telemetry: TelemetryPluginStart;
|
||||
spaces: SpacesPluginStart;
|
||||
}
|
||||
|
|
|
@ -86,7 +86,6 @@ export class Plugin implements PluginType {
|
|||
logger: this.logger,
|
||||
telemetry: this.telemetryEventsSender,
|
||||
isDev: this.initContext.env.mode.dev,
|
||||
spaces: plugins.spaces,
|
||||
} as UptimeServerSetup;
|
||||
|
||||
this.syntheticsService = new SyntheticsService(this.server);
|
||||
|
@ -126,6 +125,7 @@ export class Plugin implements PluginType {
|
|||
this.server.fleet = pluginsStart.fleet;
|
||||
this.server.encryptedSavedObjects = pluginsStart.encryptedSavedObjects;
|
||||
this.server.savedObjectsClient = this.savedObjectsClient;
|
||||
this.server.spaces = pluginsStart.spaces;
|
||||
}
|
||||
|
||||
this.syntheticsService?.start(pluginsStart.taskManager);
|
||||
|
|
|
@ -58,8 +58,6 @@ export const addSyntheticsMonitorRoute: SyntheticsRestApiRouteFactory = () => ({
|
|||
// usually id is auto generated, but this is useful for testing
|
||||
const { id } = request.query;
|
||||
|
||||
const spaceId = server.spaces.spacesService.getSpaceId(request);
|
||||
|
||||
const monitor: SyntheticsMonitor = request.body as SyntheticsMonitor;
|
||||
const monitorType = monitor[ConfigKey.MONITOR_TYPE];
|
||||
const monitorWithDefaults = {
|
||||
|
@ -79,6 +77,7 @@ export const addSyntheticsMonitorRoute: SyntheticsRestApiRouteFactory = () => ({
|
|||
);
|
||||
|
||||
try {
|
||||
const { id: spaceId } = await server.spaces.spacesService.getActiveSpace(request);
|
||||
const { errors, newMonitor } = await syncNewMonitor({
|
||||
normalizedMonitor: validationResult.decodedMonitor,
|
||||
server,
|
||||
|
|
|
@ -41,7 +41,6 @@ export const addSyntheticsProjectMonitorRoute: SyntheticsRestApiRouteFactory = (
|
|||
const { projectName } = request.params;
|
||||
const decodedProjectName = decodeURI(projectName);
|
||||
const monitors = (request.body?.monitors as ProjectMonitor[]) || [];
|
||||
const spaceId = server.spaces.spacesService.getSpaceId(request);
|
||||
|
||||
if (monitors.length > 250) {
|
||||
return response.badRequest({
|
||||
|
@ -52,6 +51,7 @@ export const addSyntheticsProjectMonitorRoute: SyntheticsRestApiRouteFactory = (
|
|||
}
|
||||
|
||||
try {
|
||||
const { id: spaceId } = await server.spaces.spacesService.getActiveSpace(request);
|
||||
const encryptedSavedObjectsClient = server.encryptedSavedObjects.getClient();
|
||||
|
||||
const pushMonitorFormatter = new ProjectMonitorFormatter({
|
||||
|
@ -74,6 +74,11 @@ export const addSyntheticsProjectMonitorRoute: SyntheticsRestApiRouteFactory = (
|
|||
};
|
||||
} catch (error) {
|
||||
server.logger.error(`Error adding monitors to project ${decodedProjectName}`);
|
||||
if (error.output.statusCode === 404) {
|
||||
const spaceId = server.spaces.spacesService.getSpaceId(request);
|
||||
return response.notFound({ body: { message: `Kibana space '${spaceId}' does not exist` } });
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
|
|
|
@ -39,9 +39,11 @@ export const addSyntheticsProjectMonitorRouteLegacy: SyntheticsStreamingRouteFac
|
|||
syntheticsMonitorClient,
|
||||
subject,
|
||||
}): Promise<any> => {
|
||||
const monitors = (request.body?.monitors as ProjectMonitor[]) || [];
|
||||
|
||||
try {
|
||||
const monitors = (request.body?.monitors as ProjectMonitor[]) || [];
|
||||
const spaceId = server.spaces.spacesService.getSpaceId(request);
|
||||
const { id: spaceId } = await server.spaces.spacesService.getActiveSpace(request);
|
||||
|
||||
const { keep_stale: keepStale, project: projectId } = request.body || {};
|
||||
const { publicLocations, privateLocations } = await getAllLocations(
|
||||
server,
|
||||
|
@ -76,7 +78,13 @@ export const addSyntheticsProjectMonitorRouteLegacy: SyntheticsStreamingRouteFac
|
|||
failedStaleMonitors: pushMonitorFormatter.failedStaleMonitors,
|
||||
});
|
||||
} catch (error) {
|
||||
subject?.error(error);
|
||||
if (error?.output?.statusCode === 404) {
|
||||
const spaceId = server.spaces.spacesService.getSpaceId(request);
|
||||
subject?.next(`Unable to create monitors. Kibana space '${spaceId}' does not exist.`);
|
||||
subject?.next({ failedMonitors: monitors.map((m) => m.id) });
|
||||
} else {
|
||||
subject?.error(error);
|
||||
}
|
||||
} finally {
|
||||
subject?.complete();
|
||||
}
|
||||
|
|
|
@ -35,9 +35,9 @@ export const deleteMonitorBulk = async ({
|
|||
request: KibanaRequest;
|
||||
}) => {
|
||||
const { logger, telemetry, stackVersion } = server;
|
||||
const spaceId = server.spaces.spacesService.getSpaceId(request);
|
||||
|
||||
try {
|
||||
const { id: spaceId } = await server.spaces.spacesService.getActiveSpace(request);
|
||||
const deleteSyncPromise = syntheticsMonitorClient.deleteMonitors(
|
||||
monitors.map((normalizedMonitor) => ({
|
||||
...normalizedMonitor.attributes,
|
||||
|
|
|
@ -88,7 +88,6 @@ export const deleteMonitor = async ({
|
|||
request: KibanaRequest;
|
||||
}) => {
|
||||
const { logger, telemetry, stackVersion } = server;
|
||||
const spaceId = server.spaces.spacesService.getSpaceId(request);
|
||||
|
||||
const { monitor, monitorWithSecret } = await getMonitorToDelete(
|
||||
monitorId,
|
||||
|
@ -96,6 +95,7 @@ export const deleteMonitor = async ({
|
|||
server
|
||||
);
|
||||
try {
|
||||
const { id: spaceId } = await server.spaces.spacesService.getActiveSpace(request);
|
||||
const deleteSyncPromise = syntheticsMonitorClient.deleteMonitors(
|
||||
[
|
||||
{
|
||||
|
|
|
@ -56,9 +56,9 @@ export const editSyntheticsMonitorRoute: SyntheticsRestApiRouteFactory = () => (
|
|||
const monitor = request.body as SyntheticsMonitor;
|
||||
const { monitorId } = request.params;
|
||||
|
||||
const spaceId = server.spaces.spacesService.getSpaceId(request);
|
||||
|
||||
try {
|
||||
const { id: spaceId } = await server.spaces.spacesService.getActiveSpace(request);
|
||||
|
||||
const previousMonitor: SavedObject<EncryptedSyntheticsMonitor> = await savedObjectsClient.get(
|
||||
syntheticsMonitorType,
|
||||
monitorId
|
||||
|
|
|
@ -27,8 +27,7 @@ export const addSyntheticsParamsRoute: SyntheticsRestApiRouteFactory = () => ({
|
|||
writeAccess: true,
|
||||
handler: async ({ request, server, savedObjectsClient }): Promise<any> => {
|
||||
const { namespaces, ...data } = request.body as SyntheticsParam;
|
||||
|
||||
const spaceId = server.spaces.spacesService.getSpaceId(request);
|
||||
const { id: spaceId } = await server.spaces.spacesService.getActiveSpace(request);
|
||||
|
||||
const result = await savedObjectsClient.create(syntheticsParamType, data, {
|
||||
initialNamespaces: (namespaces ?? []).length > 0 ? namespaces : [spaceId],
|
||||
|
|
|
@ -99,6 +99,20 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
});
|
||||
});
|
||||
|
||||
it('project monitors - returns 404 for non-existing spaces', async () => {
|
||||
const project = `test-project-${uuidv4()}`;
|
||||
await supertest
|
||||
.put(
|
||||
`/s/i_dont_exist${API_URLS.SYNTHETICS_MONITORS_PROJECT_UPDATE.replace(
|
||||
'{projectName}',
|
||||
project
|
||||
)}`
|
||||
)
|
||||
.set('kbn-xsrf', 'true')
|
||||
.send(projectMonitors)
|
||||
.expect(404);
|
||||
});
|
||||
|
||||
it('project monitors - handles browser monitors', async () => {
|
||||
const successfulMonitors = [projectMonitors.monitors[0]];
|
||||
const project = `test-project-${uuidv4()}`;
|
||||
|
|
|
@ -559,6 +559,19 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
}
|
||||
});
|
||||
|
||||
it('project monitors - returns error if the space does not exist', async () => {
|
||||
const messages = await parseStreamApiResponse(
|
||||
kibanaServerUrl + '/s/i_dont_exist' + API_URLS.SYNTHETICS_MONITORS_PROJECT_LEGACY,
|
||||
JSON.stringify(projectMonitors)
|
||||
);
|
||||
|
||||
expect(messages).to.have.length(2);
|
||||
expect(messages[0]).to.equal(
|
||||
"Unable to create monitors. Kibana space 'i_dont_exist' does not exist."
|
||||
);
|
||||
expect(messages[1].failedMonitors).to.eql(projectMonitors.monitors.map((m) => m.id));
|
||||
});
|
||||
|
||||
it('project monitors - returns a list of successfully updated monitors', async () => {
|
||||
try {
|
||||
await supertest
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue