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

[Fleet] Add installed_kibana_space_id to epm-packages saved objects #120517

Merged
merged 14 commits into from
Dec 17, 2021
11 changes: 8 additions & 3 deletions packages/kbn-test/src/kbn_client/kbn_client_saved_objects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ interface SavedObjectResponse<Attributes extends Record<string, any>> {
interface GetOptions {
type: string;
id: string;
space?: string;
}

interface IndexOptions<Attributes> {
Expand Down Expand Up @@ -110,11 +111,13 @@ export class KbnClientSavedObjects {
* Get an object
*/
public async get<Attributes extends Record<string, any>>(options: GetOptions) {
this.log.debug('Gettings saved object: %j', options);
this.log.debug('Getting saved object: %j', options);

const { data } = await this.requester.request<SavedObjectResponse<Attributes>>({
description: 'get saved object',
path: uriencode`/api/saved_objects/${options.type}/${options.id}`,
path: options.space
? uriencode`/s/${options.space}/api/saved_objects/${options.type}/${options.id}`
: uriencode`/api/saved_objects/${options.type}/${options.id}`,
method: 'GET',
});
return data;
Expand Down Expand Up @@ -174,7 +177,9 @@ export class KbnClientSavedObjects {

const { data } = await this.requester.request({
description: 'delete saved object',
path: uriencode`/api/saved_objects/${options.type}/${options.id}`,
path: options.space
? uriencode`/s/${options.space}/api/saved_objects/${options.type}/${options.id}`
: uriencode`/api/saved_objects/${options.type}/${options.id}`,
method: 'DELETE',
});

Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/fleet/common/types/models/epm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,7 @@ export interface Installation extends SavedObjectAttributes {
install_version: string;
install_started_at: string;
install_source: InstallSource;
installed_kibana_space_id?: string;
keep_policies_up_to_date?: boolean;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,7 @@
"updated_at": "2021-09-30T10:47:12.961Z",
"version": "WzI1NjgsMV0=",
"attributes": {
"installed_kibana_space_id": "default",
"installed_kibana": [
{
"id": "apache-Logs-Apache-Dashboard",
Expand Down
4 changes: 1 addition & 3 deletions x-pack/plugins/fleet/dev_docs/data_model.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,12 +127,10 @@ used for other types of outputs like separate monitoring clusters, Logstash, etc
- `installed_es` - array of assets installed into Elasticsearch
- `installed_es.id` - ID in Elasticsearch of an asset (eg. `logs-system.application-1.1.2`)
- `installed_es.type` - type of Elasticsearch asset (eg. `ingest_pipeline`)
- `installed_kibana_space_id` - the id of the space the assets were installed in (eg. `default`)
hop-dev marked this conversation as resolved.
Show resolved Hide resolved
- `installed_kibana` - array of assets that were installed into Kibana
- `installed_kibana.id` - Saved Object ID (eg. `system-01c54730-fee6-11e9-8405-516218e3d268`)
- `installed_kibana.type` - Saved Object type name (eg. `dashboard`)
- One caveat with this array is that the IDs are currently space-specific so if a package's assets were installed in
one space, they may not be visible in other spaces. We also do not keep track of which space these assets were
installed into.
- `package_assets` - array of original file contents of the package as it was installed
- `package_assets.id` - Saved Object ID for a `epm-package-assets` type
- `package_assets.type` - Saved Object type for the asset. As of now, only `epm-packages-assets` are supported.
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/fleet/kibana.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"server": true,
"ui": true,
"configPath": ["xpack", "fleet"],
"requiredPlugins": ["licensing", "data", "encryptedSavedObjects", "navigation", "customIntegrations", "share"],
"requiredPlugins": ["licensing", "data", "encryptedSavedObjects", "navigation", "customIntegrations", "share", "spaces"],
"optionalPlugins": ["security", "features", "cloud", "usageCollection", "home", "globalSearch", "telemetry"],
"extraPublicDirs": ["common"],
"requiredBundles": ["kibanaReact", "esUiShared", "home", "infra", "kibanaUtils", "usageCollection"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export const Installed = ({ width, ...props }: Args) => {
install_version: props.version,
es_index_patterns: {},
installed_kibana: [],
installed_kibana_space_id: 'default',
installed_es: [],
install_status: 'installed',
install_source: 'registry',
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/fleet/server/mocks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export const createFleetRequestHandlerContextMock = (): jest.Mocked<
epm: {
internalSoClient: savedObjectsClientMock.create(),
},
spaceId: 'default',
};
};

Expand Down
5 changes: 5 additions & 0 deletions x-pack/plugins/fleet/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import type { PluginSetupContract as FeaturesPluginSetup } from '../../features/
import type { FleetConfigType, FleetAuthz } from '../common';
import { INTEGRATIONS_PLUGIN_ID } from '../common';
import type { CloudSetup } from '../../cloud/server';
import type { SpacesPluginStart } from '../../spaces/server';

import {
PLUGIN_ID,
Expand Down Expand Up @@ -96,6 +97,7 @@ export interface FleetSetupDeps {
encryptedSavedObjects: EncryptedSavedObjectsPluginSetup;
cloud?: CloudSetup;
usageCollection?: UsageCollectionSetup;
spaces: SpacesPluginStart;
telemetry?: TelemetryPluginSetup;
}

Expand Down Expand Up @@ -297,6 +299,9 @@ export class FleetPlugin
.getScopedClient(request, { excludedWrappers: ['security'] });
},
},
get spaceId() {
return deps.spaces.spacesService.getSpaceId(request);
},
};
}
);
Expand Down
6 changes: 4 additions & 2 deletions x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import type {
CopyAgentPolicyRequestSchema,
DeleteAgentPolicyRequestSchema,
GetFullAgentPolicyRequestSchema,
FleetRequestHandler,
} from '../../types';
import { FLEET_SYSTEM_PACKAGE } from '../../../common';
import type {
Expand Down Expand Up @@ -99,7 +100,7 @@ export const getOneAgentPolicyHandler: RequestHandler<
}
};

export const createAgentPolicyHandler: RequestHandler<
export const createAgentPolicyHandler: FleetRequestHandler<
undefined,
TypeOf<typeof CreateAgentPolicyRequestSchema.query>,
TypeOf<typeof CreateAgentPolicyRequestSchema.body>
Expand All @@ -108,7 +109,7 @@ export const createAgentPolicyHandler: RequestHandler<
const esClient = context.core.elasticsearch.client.asInternalUser;
const user = (await appContextService.getSecurity()?.authc.getCurrentUser(request)) || undefined;
const withSysMonitoring = request.query.sys_monitoring ?? false;

const spaceId = context.fleet.spaceId;
try {
// eslint-disable-next-line prefer-const
let [agentPolicy, newSysPackagePolicy] = await Promise.all([
Expand All @@ -132,6 +133,7 @@ export const createAgentPolicyHandler: RequestHandler<
newSysPackagePolicy.name = await incrementPackageName(soClient, FLEET_SYSTEM_PACKAGE);

await packagePolicyService.create(soClient, esClient, newSysPackagePolicy, {
spaceId,
user,
bumpRevision: false,
});
Expand Down
7 changes: 6 additions & 1 deletion x-pack/plugins/fleet/server/routes/epm/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,11 +257,13 @@ export const installPackageFromRegistryHandler: FleetRequestHandler<
const esClient = context.core.elasticsearch.client.asInternalUser;
const { pkgName, pkgVersion } = request.params;

const spaceId = context.fleet.spaceId;
const res = await installPackage({
installSource: 'registry',
savedObjectsClient,
pkgkey: pkgVersion ? `${pkgName}-${pkgVersion}` : pkgName,
esClient,
spaceId,
force: request.body?.force,
});
if (!res.error) {
Expand Down Expand Up @@ -296,10 +298,12 @@ export const bulkInstallPackagesFromRegistryHandler: FleetRequestHandler<
> = async (context, request, response) => {
const savedObjectsClient = context.fleet.epm.internalSoClient;
const esClient = context.core.elasticsearch.client.asInternalUser;
const spaceId = context.fleet.spaceId;
const bulkInstalledResponses = await bulkInstallPackages({
savedObjectsClient,
esClient,
packagesToInstall: request.body.packages,
spaceId,
});
const payload = bulkInstalledResponses.map(bulkInstallServiceResponseToHttpEntry);
const body: BulkInstallPackagesResponse = {
Expand All @@ -324,12 +328,13 @@ export const installPackageByUploadHandler: FleetRequestHandler<
const esClient = context.core.elasticsearch.client.asInternalUser;
const contentType = request.headers['content-type'] as string; // from types it could also be string[] or undefined but this is checked later
const archiveBuffer = Buffer.from(request.body);

const spaceId = context.fleet.spaceId;
const res = await installPackage({
installSource: 'upload',
savedObjectsClient,
esClient,
archiveBuffer,
spaceId,
contentType,
});
if (!res.error) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@ import type {
PackagePolicyServiceInterface,
PostPackagePolicyCreateCallback,
PutPackagePolicyUpdateCallback,
FleetRequestHandlerContext,
} from '../..';
import type {
CreatePackagePolicyRequestSchema,
UpdatePackagePolicyRequestSchema,
} from '../../types/rest_spec';
import type { FleetAuthzRouter } from '../security';
import type { FleetRequestHandler, FleetRequestHandlerContext } from '../../types';
import type { FleetRequestHandler } from '../../types';
import type { PackagePolicy } from '../../types';

import { registerRoutes } from './index';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import type {
DeletePackagePoliciesRequestSchema,
UpgradePackagePoliciesRequestSchema,
DryRunPackagePoliciesRequestSchema,
FleetRequestHandler,
} from '../../types';
import type {
CreatePackagePolicyResponse,
Expand Down Expand Up @@ -80,7 +81,7 @@ export const getOnePackagePolicyHandler: RequestHandler<
}
};

export const createPackagePolicyHandler: RequestHandler<
export const createPackagePolicyHandler: FleetRequestHandler<
undefined,
undefined,
TypeOf<typeof CreatePackagePolicyRequestSchema.body>
Expand All @@ -89,6 +90,7 @@ export const createPackagePolicyHandler: RequestHandler<
const esClient = context.core.elasticsearch.client.asInternalUser;
const user = appContextService.getSecurity()?.authc.getCurrentUser(request) || undefined;
const { force, ...newPolicy } = request.body;
const spaceId = context.fleet.spaceId;
try {
const newPackagePolicy = await packagePolicyService.enrichPolicyWithDefaultsFromPackage(
soClient,
Expand All @@ -106,6 +108,7 @@ export const createPackagePolicyHandler: RequestHandler<
const packagePolicy = await packagePolicyService.create(soClient, esClient, newData, {
user,
force,
spaceId,
});
const body: CreatePackagePolicyResponse = { item: packagePolicy };
return response.ok({
Expand Down
10 changes: 6 additions & 4 deletions x-pack/plugins/fleet/server/routes/preconfiguration/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,21 @@ import type { TypeOf } from '@kbn/config-schema';
import type { PreconfiguredAgentPolicy } from '../../../common';

import { PRECONFIGURATION_API_ROUTES } from '../../constants';
import type { FleetRequestHandler } from '../../types';
import { PutPreconfigurationSchema } from '../../types';
import { defaultIngestErrorHandler } from '../../errors';
import { ensurePreconfiguredPackagesAndPolicies, outputService } from '../../services';
import type { FleetAuthzRouter } from '../security';

export const updatePreconfigurationHandler: RequestHandler<
export const updatePreconfigurationHandler: FleetRequestHandler<
undefined,
undefined,
TypeOf<typeof PutPreconfigurationSchema.body>
> = async (context, request, response) => {
const soClient = context.core.savedObjects.client;
const esClient = context.core.elasticsearch.client.asInternalUser;
const defaultOutput = await outputService.ensureDefaultOutput(soClient);

const spaceId = context.fleet.spaceId;
const { agentPolicies, packages } = request.body;

try {
Expand All @@ -33,7 +34,8 @@ export const updatePreconfigurationHandler: RequestHandler<
esClient,
(agentPolicies as PreconfiguredAgentPolicy[]) ?? [],
packages ?? [],
defaultOutput
defaultOutput,
spaceId
);
return response.ok({ body });
} catch (error) {
Expand All @@ -50,6 +52,6 @@ export const registerRoutes = (router: FleetAuthzRouter) => {
fleet: { all: true },
},
},
updatePreconfigurationHandler
updatePreconfigurationHandler as RequestHandler
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ describe('FleetSetupHandler', () => {
epm: {
internalSoClient: savedObjectsClientMock.create(),
},
spaceId: 'default',
},
};
response = httpServerMock.createResponseFactory();
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/fleet/server/saved_objects/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ const getSavedObjectTypes = (
type: { type: 'keyword' },
},
},
installed_kibana_space_id: { type: 'keyword' },
package_assets: {
type: 'nested',
properties: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import type { SavedObjectsClientContract, ElasticsearchClient } from 'src/core/s
import { savedObjectsClientMock, elasticsearchServiceMock } from 'src/core/server/mocks';
import { loggerMock } from '@kbn/logging/mocks';

import { DEFAULT_SPACE_ID } from '../../../../../spaces/common/constants';

import { appContextService } from '../../app_context';
import { createAppContextStartContractMock } from '../../../mocks';

Expand Down Expand Up @@ -78,6 +80,7 @@ describe('_installPackage', () => {
},
installType: 'install',
installSource: 'registry',
spaceId: DEFAULT_SPACE_ID,
});

// if we have a .catch this will fail nicely (test pass)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export async function _installPackage({
packageInfo,
installType,
installSource,
spaceId,
}: {
savedObjectsClient: SavedObjectsClientContract;
savedObjectsImporter: Pick<SavedObjectsImporter, 'import' | 'resolveImportErrors'>;
Expand All @@ -66,6 +67,7 @@ export async function _installPackage({
packageInfo: InstallablePackage;
installType: InstallType;
installSource: InstallSource;
spaceId: string;
}): Promise<AssetReference[]> {
const { name: pkgName, version: pkgVersion } = packageInfo;

Expand Down Expand Up @@ -99,15 +101,12 @@ export async function _installPackage({
savedObjectsClient,
packageInfo,
installSource,
spaceId,
});
}

const kibanaAssets = await getKibanaAssets(paths);
if (installedPkg)
await deleteKibanaSavedObjectsAssets(
savedObjectsClient,
installedPkg.attributes.installed_kibana
);
if (installedPkg) await deleteKibanaSavedObjectsAssets({ savedObjectsClient, installedPkg });
// save new kibana refs before installing the assets
const installedKibanaAssetsRefs = await saveKibanaAssetsRefs(
savedObjectsClient,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ interface BulkInstallPackagesParams {
packagesToInstall: Array<string | { name: string; version: string }>;
esClient: ElasticsearchClient;
force?: boolean;
spaceId: string;
}

export async function bulkInstallPackages({
savedObjectsClient,
packagesToInstall,
esClient,
spaceId,
force,
}: BulkInstallPackagesParams): Promise<BulkInstallResponse[]> {
const logger = appContextService.getLogger();
Expand Down Expand Up @@ -70,6 +72,7 @@ export async function bulkInstallPackages({
esClient,
pkgkey: Registry.pkgToPkgKey(pkgKeyProps),
installSource,
spaceId,
force,
});
if (installResult.error) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const mockInstallation: SavedObject<Installation> = {
type: 'epm-packages',
attributes: {
id: 'test-pkg',
installed_kibana_space_id: 'default',
installed_kibana: [{ type: KibanaSavedObjectType.dashboard, id: 'dashboard-1' }],
installed_es: [{ type: ElasticsearchAssetType.ingestPipeline, id: 'pipeline' }],
package_assets: [],
Expand All @@ -37,6 +38,7 @@ const mockInstallationUpdateFail: SavedObject<Installation> = {
type: 'epm-packages',
attributes: {
id: 'test-pkg',
installed_kibana_space_id: 'default',
installed_kibana: [{ type: KibanaSavedObjectType.dashboard, id: 'dashboard-1' }],
installed_es: [{ type: ElasticsearchAssetType.ingestPipeline, id: 'pipeline' }],
package_assets: [],
Expand Down
Loading