Skip to content

Commit

Permalink
[Fleet] Output API endpoints (elastic#118589)
Browse files Browse the repository at this point in the history
  • Loading branch information
nchaulet authored and kibanamachine committed Nov 16, 2021
1 parent d2d7759 commit 477ea81
Show file tree
Hide file tree
Showing 11 changed files with 393 additions and 29 deletions.
2 changes: 2 additions & 0 deletions x-pack/plugins/fleet/common/constants/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ export const OUTPUT_API_ROUTES = {
LIST_PATTERN: `${API_ROOT}/outputs`,
INFO_PATTERN: `${API_ROOT}/outputs/{outputId}`,
UPDATE_PATTERN: `${API_ROOT}/outputs/{outputId}`,
DELETE_PATTERN: `${API_ROOT}/outputs/{outputId}`,
CREATE_PATTERN: `${API_ROOT}/outputs`,
};

// Settings API routes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ properties:
type: string
is_default:
type: boolean
is_default_monitoring:
type: boolean
name:
type: string
type:
Expand Down
43 changes: 43 additions & 0 deletions x-pack/plugins/fleet/common/openapi/paths/outputs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,46 @@ get:
perPage:
type: integer
operationId: get-outputs
post:
summary: Outputs
description: 'Create a new output'
tags: []
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
properties:
item:
$ref: ../components/schemas/output.yaml
requestBody:
content:
application/json:
schema:
type: object
properties:
id:
type: string
name:
type: string
type:
type: string
enum: ["elasticsearch"]
is_default:
type: boolean
is_default_monitoring:
type: boolean
hosts:
type: array
items:
type: string
ca_sha256:
type: string
config_yaml:
type: string
required:
- name
- type
operationId: post-outputs
35 changes: 32 additions & 3 deletions x-pack/plugins/fleet/common/openapi/paths/outputs@{output_id}.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,23 @@ parameters:
name: outputId
in: path
required: true
delete:
summary: Output - Delete
operationId: delete-output
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
properties:
id:
type: string
required:
- id
parameters:
- $ref: ../components/headers/kbn_xsrf.yaml
put:
summary: Output - Update
operationId: update-output
Expand All @@ -29,14 +46,26 @@ put:
schema:
type: object
properties:
hosts:
name:
type: string
type:
type: string
enum: ["elasticsearch"]
is_default:
type: boolean
is_default_monitoring:
type: boolean
hosts:
type: array
items:
type: string
ca_sha256:
type: string
config:
type: object
config_yaml:
type: string
required:
- name
- type
responses:
'200':
description: OK
Expand Down
4 changes: 4 additions & 0 deletions x-pack/plugins/fleet/common/types/rest_spec/output.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ export interface GetOneOutputResponse {
item: Output;
}

export interface DeleteOutputResponse {
id: string;
}

export interface GetOneOutputRequest {
params: {
outputId: string;
Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/fleet/server/errors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ export class HostedAgentPolicyRestrictionRelatedError extends IngestManagerError
export class FleetSetupError extends IngestManagerError {}
export class GenerateServiceTokenError extends IngestManagerError {}

export class OutputUnauthorizedError extends IngestManagerError {}

export class ArtifactsClientError extends IngestManagerError {}
export class ArtifactsClientAccessDeniedError extends IngestManagerError {
constructor(deniedPackageName: string, allowedPackageName: string) {
Expand Down
55 changes: 53 additions & 2 deletions x-pack/plugins/fleet/server/routes/output/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,17 @@
import type { RequestHandler } from 'src/core/server';
import type { TypeOf } from '@kbn/config-schema';

import type { GetOneOutputRequestSchema, PutOutputRequestSchema } from '../../types';
import type { GetOneOutputResponse, GetOutputsResponse } from '../../../common';
import type {
DeleteOutputRequestSchema,
GetOneOutputRequestSchema,
PostOutputRequestSchema,
PutOutputRequestSchema,
} from '../../types';
import type {
DeleteOutputResponse,
GetOneOutputResponse,
GetOutputsResponse,
} from '../../../common';
import { outputService } from '../../services/output';
import { defaultIngestErrorHandler } from '../../errors';

Expand Down Expand Up @@ -78,3 +87,45 @@ export const putOuputHandler: RequestHandler<
return defaultIngestErrorHandler({ error, response });
}
};

export const postOuputHandler: RequestHandler<
undefined,
undefined,
TypeOf<typeof PostOutputRequestSchema.body>
> = async (context, request, response) => {
const soClient = context.core.savedObjects.client;
try {
const { id, ...data } = request.body;
const output = await outputService.create(soClient, data, { id });

const body: GetOneOutputResponse = {
item: output,
};

return response.ok({ body });
} catch (error) {
return defaultIngestErrorHandler({ error, response });
}
};

export const deleteOutputHandler: RequestHandler<TypeOf<typeof DeleteOutputRequestSchema.params>> =
async (context, request, response) => {
const soClient = context.core.savedObjects.client;
try {
await outputService.delete(soClient, request.params.outputId);

const body: DeleteOutputResponse = {
id: request.params.outputId,
};

return response.ok({ body });
} catch (error) {
if (error.isBoom && error.output.statusCode === 404) {
return response.notFound({
body: { message: `Output ${request.params.outputId} not found` },
});
}

return defaultIngestErrorHandler({ error, response });
}
};
30 changes: 28 additions & 2 deletions x-pack/plugins/fleet/server/routes/output/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,20 @@ import type { IRouter } from 'src/core/server';

import { PLUGIN_ID, OUTPUT_API_ROUTES } from '../../constants';
import {
DeleteOutputRequestSchema,
GetOneOutputRequestSchema,
GetOutputsRequestSchema,
PostOutputRequestSchema,
PutOutputRequestSchema,
} from '../../types';

import { getOneOuputHandler, getOutputsHandler, putOuputHandler } from './handler';
import {
deleteOutputHandler,
getOneOuputHandler,
getOutputsHandler,
postOuputHandler,
putOuputHandler,
} from './handler';

export const registerRoutes = (router: IRouter) => {
router.get(
Expand All @@ -37,8 +45,26 @@ export const registerRoutes = (router: IRouter) => {
{
path: OUTPUT_API_ROUTES.UPDATE_PATTERN,
validate: PutOutputRequestSchema,
options: { tags: [`access:${PLUGIN_ID}-read`] },
options: { tags: [`access:${PLUGIN_ID}-all`] },
},
putOuputHandler
);

router.post(
{
path: OUTPUT_API_ROUTES.CREATE_PATTERN,
validate: PostOutputRequestSchema,
options: { tags: [`access:${PLUGIN_ID}-all`] },
},
postOuputHandler
);

router.delete(
{
path: OUTPUT_API_ROUTES.DELETE_PATTERN,
validate: DeleteOutputRequestSchema,
options: { tags: [`access:${PLUGIN_ID}-all`] },
},
deleteOutputHandler
);
};
14 changes: 12 additions & 2 deletions x-pack/plugins/fleet/server/services/output.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import uuid from 'uuid/v5';
import type { NewOutput, Output, OutputSOAttributes } from '../types';
import { DEFAULT_OUTPUT, OUTPUT_SAVED_OBJECT_TYPE } from '../constants';
import { decodeCloudId, normalizeHostsForAgents, SO_SEARCH_LIMIT } from '../../common';
import { OutputUnauthorizedError } from '../errors';

import { appContextService } from './app_context';

Expand Down Expand Up @@ -222,10 +223,19 @@ class OutputService {
const originalOutput = await this.get(soClient, id);

if (originalOutput.is_preconfigured && !fromPreconfiguration) {
throw new Error(
throw new OutputUnauthorizedError(
`Preconfigured output ${id} cannot be deleted outside of kibana config file.`
);
}

if (originalOutput.is_default && !fromPreconfiguration) {
throw new OutputUnauthorizedError(`Default output ${id} cannot be deleted.`);
}

if (originalOutput.is_default_monitoring && !fromPreconfiguration) {
throw new OutputUnauthorizedError(`Default monitoring output ${id} cannot be deleted.`);
}

return soClient.delete(SAVED_OBJECT_TYPE, outputIdToUuid(id));
}

Expand All @@ -240,7 +250,7 @@ class OutputService {
const originalOutput = await this.get(soClient, id);

if (originalOutput.is_preconfigured && !fromPreconfiguration) {
throw new Error(
throw new OutputUnauthorizedError(
`Preconfigured output ${id} cannot be updated outside of kibana config file.`
);
}
Expand Down
23 changes: 22 additions & 1 deletion x-pack/plugins/fleet/server/types/rest_spec/output.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,37 @@ export const GetOneOutputRequestSchema = {
}),
};

export const DeleteOutputRequestSchema = {
params: schema.object({
outputId: schema.string(),
}),
};

export const GetOutputsRequestSchema = {};

export const PostOutputRequestSchema = {
body: schema.object({
id: schema.maybe(schema.string()),
name: schema.string(),
type: schema.oneOf([schema.literal('elasticsearch')]),
is_default: schema.boolean({ defaultValue: false }),
is_default_monitoring: schema.boolean({ defaultValue: false }),
hosts: schema.maybe(schema.arrayOf(schema.uri({ scheme: ['http', 'https'] }))),
ca_sha256: schema.maybe(schema.string()),
config_yaml: schema.maybe(schema.string()),
}),
};

export const PutOutputRequestSchema = {
params: schema.object({
outputId: schema.string(),
}),
body: schema.object({
name: schema.maybe(schema.string()),
is_default: schema.maybe(schema.boolean()),
is_default_monitoring: schema.maybe(schema.boolean()),
hosts: schema.maybe(schema.arrayOf(schema.uri({ scheme: ['http', 'https'] }))),
ca_sha256: schema.maybe(schema.string()),
config: schema.maybe(schema.recordOf(schema.string(), schema.any())),
config_yaml: schema.maybe(schema.string()),
}),
};
Loading

0 comments on commit 477ea81

Please sign in to comment.