Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add asset.kind handling to assets API #159065

Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions x-pack/plugins/asset_manager/common/types_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,17 @@ export const assetTypeRT = rt.union([

export type AssetType = rt.TypeOf<typeof assetTypeRT>;

export type AssetKind = 'cluster' | 'host' | 'pod' | 'container' | 'service';
export const assetKindRT = rt.union([
rt.literal('cluster'),
rt.literal('host'),
rt.literal('pod'),
rt.literal('container'),
rt.literal('service'),
rt.literal('alert'),
]);

export type AssetKind = rt.TypeOf<typeof assetKindRT>;

export type AssetStatus =
| 'CREATING'
| 'ACTIVE'
Expand Down Expand Up @@ -124,10 +134,11 @@ export interface K8sCluster extends WithTimestamp {

export interface AssetFilters {
type?: AssetType | AssetType[];
kind?: AssetKind;
kind?: AssetKind | AssetKind[];
ean?: string | string[];
id?: string;
typeLike?: string;
kindLike?: string;
eanLike?: string;
collectionVersion?: number | 'latest' | 'all';
from?: string;
Expand Down
25 changes: 13 additions & 12 deletions x-pack/plugins/asset_manager/server/lib/get_all_related_assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import { ElasticsearchClient } from '@kbn/core/server';
import { flatten, without } from 'lodash';
import { Asset, AssetType, Relation, RelationField } from '../../common/types_api';
import { Asset, AssetType, AssetKind, Relation, RelationField } from '../../common/types_api';
import { getAssets } from './get_assets';
import { getRelatedAssets } from './get_related_assets';
import { AssetNotFoundError } from './errors';
Expand All @@ -19,6 +19,7 @@ interface GetAllRelatedAssetsOptions {
to?: string;
relation: Relation;
type?: AssetType[];
kind?: AssetKind[];
maxDistance: number;
size: number;
}
Expand All @@ -28,7 +29,7 @@ export async function getAllRelatedAssets(
options: GetAllRelatedAssetsOptions
) {
// How to put size into this?
const { ean, from, to, relation, maxDistance, type = [] } = options;
const { ean, from, to, relation, maxDistance, kind = [] } = options;

const primary = await findPrimary(esClient, { ean, from, to });

Expand All @@ -42,10 +43,10 @@ export async function getAllRelatedAssets(
to,
visitedEans: [primary['asset.ean'], ...relatedAssets.map((asset) => asset['asset.ean'])],
};
// if we enforce the type filter before the last query we'll miss nodes with
// possible edges to the requested types
if (currentDistance === maxDistance && type.length) {
queryOptions.type = type;
// if we enforce the kind filter before the last query we'll miss nodes with
// possible edges to the requested kind values
if (currentDistance === maxDistance && kind.length) {
queryOptions.kind = kind;
}

const results = flatten(
Expand All @@ -66,8 +67,8 @@ export async function getAllRelatedAssets(

return {
primary,
[relation]: type.length
? relatedAssets.filter((asset) => asset['asset.type'] && type.includes(asset['asset.type']))
[relation]: kind.length
? relatedAssets.filter((asset) => asset['asset.kind'] && kind.includes(asset['asset.kind']))
: relatedAssets,
};
}
Expand Down Expand Up @@ -95,13 +96,13 @@ async function findPrimary(

type FindRelatedAssetsOptions = Pick<
GetAllRelatedAssetsOptions,
'relation' | 'type' | 'from' | 'to'
'relation' | 'kind' | 'from' | 'to'
> & { visitedEans: string[] };

async function findRelatedAssets(
esClient: ElasticsearchClient,
primary: Asset,
{ relation, from, to, type, visitedEans }: FindRelatedAssetsOptions
{ relation, from, to, kind = [], visitedEans }: FindRelatedAssetsOptions
): Promise<Asset[]> {
const relationField = relationToDirectField(relation);
const directlyRelatedEans = toArray(primary[relationField]);
Expand All @@ -111,7 +112,7 @@ async function findRelatedAssets(
// get the directly related assets we haven't visited already
directlyRelatedAssets = await getAssets({
esClient,
filters: { ean: without(directlyRelatedEans, ...visitedEans), from, to, type },
filters: { ean: without(directlyRelatedEans, ...visitedEans), from, to, kind },
});
}

Expand All @@ -122,7 +123,7 @@ async function findRelatedAssets(
relation,
from,
to,
type,
kind,
});

return [...directlyRelatedAssets, ...indirectlyRelatedAssets];
Expand Down
14 changes: 11 additions & 3 deletions x-pack/plugins/asset_manager/server/lib/get_assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export async function getAssets({
});
}

if (filters.type?.length) {
if (filters.type) {
must.push({
terms: {
['asset.type']: Array.isArray(filters.type) ? filters.type : [filters.type],
Expand All @@ -46,8 +46,8 @@ export async function getAssets({

if (filters.kind) {
must.push({
term: {
['asset.kind']: filters.kind,
terms: {
['asset.kind']: Array.isArray(filters.kind) ? filters.kind : [filters.kind],
},
});
}
Expand Down Expand Up @@ -76,6 +76,14 @@ export async function getAssets({
});
}

if (filters.kindLike) {
must.push({
wildcard: {
['asset.kind']: filters.kindLike,
},
});
}

if (filters.eanLike) {
must.push({
wildcard: {
Expand Down
10 changes: 5 additions & 5 deletions x-pack/plugins/asset_manager/server/lib/get_related_assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import { QueryDslQueryContainer, SearchRequest } from '@elastic/elasticsearch/lib/api/types';
import { debug } from '../../common/debug_log';
import { Asset, AssetType, Relation, RelationField } from '../../common/types_api';
import { Asset, AssetKind, Relation, RelationField } from '../../common/types_api';
import { ASSETS_INDEX_PREFIX } from '../constants';
import { ElasticsearchAccessorOptions } from '../types';

Expand All @@ -18,7 +18,7 @@ interface GetRelatedAssetsOptions extends ElasticsearchAccessorOptions {
from?: string;
to?: string;
relation: Relation;
type?: AssetType[];
kind?: AssetKind[];
}

export async function getRelatedAssets({
Expand All @@ -29,7 +29,7 @@ export async function getRelatedAssets({
ean,
excludeEans,
relation,
type,
kind,
}: GetRelatedAssetsOptions): Promise<Asset[]> {
const relationField = relationToIndirectField(relation);
const must: QueryDslQueryContainer[] = [
Expand All @@ -40,10 +40,10 @@ export async function getRelatedAssets({
},
];

if (type?.length) {
if (kind?.length) {
must.push({
terms: {
['asset.type']: type,
['asset.kind']: kind,
},
});
}
Expand Down
35 changes: 29 additions & 6 deletions x-pack/plugins/asset_manager/server/routes/assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
createLiteralValueFromUndefinedRT,
} from '@kbn/io-ts-utils';
import { debug } from '../../common/debug_log';
import { AssetType, assetTypeRT, relationRT } from '../../common/types_api';
import { AssetType, assetTypeRT, AssetKind, assetKindRT, relationRT } from '../../common/types_api';
import { ASSET_MANAGER_API_BASE } from '../constants';
import { getAssets } from '../lib/get_assets';
import { getAllRelatedAssets } from '../lib/get_all_related_assets';
Expand All @@ -25,14 +25,19 @@ import { getEsClientFromContext } from './utils';
import { AssetNotFoundError } from '../lib/errors';
import { isValidRange, toArray } from '../lib/utils';

function maybeArrayRT(t: rt.Mixed) {
return rt.union([rt.array(t), t]);
}

const sizeRT = rt.union([inRangeFromStringRt(1, 100), createLiteralValueFromUndefinedRT(10)]);
const assetDateRT = rt.union([dateRt, datemathStringRt]);
const getAssetsQueryOptionsRT = rt.exact(
rt.partial({
from: assetDateRT,
to: assetDateRT,
type: rt.union([rt.array(assetTypeRT), assetTypeRT]),
ean: rt.union([rt.array(rt.string), rt.string]),
type: maybeArrayRT(assetTypeRT),
kind: maybeArrayRT(assetKindRT),
ean: maybeArrayRT(rt.string),
size: sizeRT,
})
);
Expand All @@ -46,7 +51,8 @@ const getAssetsDiffQueryOptionsRT = rt.exact(
bTo: assetDateRT,
}),
rt.partial({
type: rt.union([rt.array(assetTypeRT), assetTypeRT]),
type: maybeArrayRT(assetTypeRT),
kind: maybeArrayRT(assetKindRT),
}),
])
);
Expand All @@ -62,7 +68,8 @@ const getRelatedAssetsQueryOptionsRT = rt.exact(
}),
rt.partial({
to: assetDateRT,
type: rt.union([rt.array(assetTypeRT), assetTypeRT]),
type: maybeArrayRT(assetTypeRT),
kind: maybeArrayRT(assetKindRT),
}),
])
);
Expand All @@ -89,14 +96,25 @@ export function assetsRoutes<T extends RequestHandlerContext>({ router }: SetupR
});
}

if (filters.kind && filters.ean) {
return res.badRequest({
body: 'Filters "kind" and "ean" are mutually exclusive but found both.',
});
}

const esClient = await getEsClientFromContext(context);

console.log('IN ASSETS ENDPOINT', JSON.stringify({ filters, size }));
jasonrhodes marked this conversation as resolved.
Show resolved Hide resolved

try {
const results = await getAssets({ esClient, size, filters });
return res.ok({ body: { results } });
} catch (error: unknown) {
debug('error looking up asset records', error);
return res.customError({ statusCode: 500 });
return res.customError({
statusCode: 500,
body: { message: 'Error while looking up asset records - ' + `${error}` },
});
}
}
);
Expand All @@ -116,6 +134,7 @@ export function assetsRoutes<T extends RequestHandlerContext>({ router }: SetupR
const esClient = await getEsClientFromContext(context);

const type = toArray<AssetType>(req.query.type);
const kind = toArray<AssetKind>(req.query.kind);

if (to && !isValidRange(from, to)) {
return res.badRequest({
Expand All @@ -131,6 +150,7 @@ export function assetsRoutes<T extends RequestHandlerContext>({ router }: SetupR
from,
to,
type,
kind,
maxDistance,
size,
relation,
Expand Down Expand Up @@ -158,6 +178,7 @@ export function assetsRoutes<T extends RequestHandlerContext>({ router }: SetupR
async (context, req, res) => {
const { aFrom, aTo, bFrom, bTo } = req.query;
const type = toArray<AssetType>(req.query.type);
const kind = toArray<AssetKind>(req.query.kind);

if (!isValidRange(aFrom, aTo)) {
return res.badRequest({
Expand All @@ -180,6 +201,7 @@ export function assetsRoutes<T extends RequestHandlerContext>({ router }: SetupR
from: aFrom,
to: aTo,
type,
kind,
},
});

Expand All @@ -189,6 +211,7 @@ export function assetsRoutes<T extends RequestHandlerContext>({ router }: SetupR
from: bFrom,
to: bTo,
type,
kind,
},
});

Expand Down
32 changes: 18 additions & 14 deletions x-pack/plugins/asset_manager/server/routes/sample_assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,38 +103,42 @@ export function sampleAssetsRoutes<T extends RequestHandlerContext>({
async (context, req, res) => {
const esClient = await getEsClientFromContext(context);

const sampleDataIndices = await esClient.indices.get({
index: 'assets-*-sample_data',
const sampleDataStreams = await esClient.indices.getDataStream({
name: 'assets-*-sample_data',
expand_wildcards: 'all',
});

const deletedIndices: string[] = [];
const deletedDataStreams: string[] = [];
let errorWhileDeleting: string | null = null;
const indicesToDelete = Object.keys(sampleDataIndices);
const dataStreamsToDelete = sampleDataStreams.data_streams.map((ds) => ds.name);

for (let i = 0; i < indicesToDelete.length; i++) {
const index = indicesToDelete[i];
for (let i = 0; i < dataStreamsToDelete.length; i++) {
const dsName = dataStreamsToDelete[i];
try {
await esClient.indices.delete({ index });
deletedIndices.push(index);
await esClient.indices.deleteDataStream({ name: dsName });
deletedDataStreams.push(dsName);
} catch (error: any) {
errorWhileDeleting =
typeof error.message === 'string'
? error.message
: `Unknown error occurred while deleting indices, at index ${index}`;
: `Unknown error occurred while deleting sample data streams, at data stream name: ${dsName}`;
break;
}
}

if (deletedIndices.length === indicesToDelete.length) {
return res.ok({ body: { deleted: deletedIndices } });
if (!errorWhileDeleting && deletedDataStreams.length === dataStreamsToDelete.length) {
return res.ok({ body: { deleted: deletedDataStreams } });
} else {
console.log('\n\n\n500 500 500 500 500\n\n\n');
jasonrhodes marked this conversation as resolved.
Show resolved Hide resolved
return res.custom({
statusCode: 500,
body: {
message: ['Not all matching indices were deleted', errorWhileDeleting].join(' - '),
deleted: deletedIndices,
matching: indicesToDelete,
message: [
'TEST change - Not all found data streams were deleted',
errorWhileDeleting,
].join(' - '),
deleted: deletedDataStreams,
matching: dataStreamsToDelete,
},
});
}
Expand Down
6 changes: 5 additions & 1 deletion x-pack/test/api_integration/apis/asset_manager/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ export async function createSampleAssets(
}

export async function deleteSampleAssets(supertest: KibanaSupertest) {
return await supertest.delete(SAMPLE_ASSETS_ENDPOINT).set('kbn-xsrf', 'xxx').expect(200);
const result = await supertest.delete(SAMPLE_ASSETS_ENDPOINT).set('kbn-xsrf', 'xxx');
// console.log('DELETE RESULT STATUS', result.status);
// console.log('DELETE RESULT BODY', JSON.stringify(result.body));
jasonrhodes marked this conversation as resolved.
Show resolved Hide resolved
expect(result.status).to.be(200);
return result;
}

export async function viewSampleAssetDocs(supertest: KibanaSupertest) {
Expand Down
Loading