Skip to content

Commit

Permalink
[Fleet] Support kibana_namespace in preconfiguration
Browse files Browse the repository at this point in the history
  • Loading branch information
nchaulet committed May 21, 2024
1 parent 3290d39 commit d9aca86
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export type InputsOverride = Partial<NewPackagePolicyInput> & {

export interface PreconfiguredAgentPolicy extends Omit<NewAgentPolicy, 'namespace' | 'id'> {
id: string | number;
kibana_namespace?: string;
namespace?: string;
package_policies: Array<
| (Partial<Omit<NewPackagePolicy, 'inputs' | 'package'>> & {
Expand Down
4 changes: 2 additions & 2 deletions x-pack/plugins/fleet/server/saved_objects/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -587,7 +587,7 @@ export const getSavedObjectTypes = (
name: PACKAGES_SAVED_OBJECT_TYPE,
indexPattern: INGEST_SAVED_OBJECT_INDEX,
hidden: false,
namespaceType: useSpaceAwareness ? 'single' : 'agnostic',
namespaceType: 'agnostic',
management: {
importableAndExportable: false,
},
Expand Down Expand Up @@ -680,7 +680,7 @@ export const getSavedObjectTypes = (
name: ASSETS_SAVED_OBJECT_TYPE,
indexPattern: INGEST_SAVED_OBJECT_INDEX,
hidden: false,
namespaceType: useSpaceAwareness ? 'single' : 'agnostic',
namespaceType: 'agnostic',
management: {
importableAndExportable: false,
},
Expand Down
6 changes: 5 additions & 1 deletion x-pack/plugins/fleet/server/services/agent_policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,11 @@ class AgentPolicyService {
created: boolean;
policy?: AgentPolicy;
}> {
const { id, ...preconfiguredAgentPolicy } = omit(config, 'package_policies');
const {
id,
kibana_namespace: kibanaNamespace,
...preconfiguredAgentPolicy
} = omit(config, 'package_policies');
const newAgentPolicyDefaults: Pick<NewAgentPolicy, 'namespace' | 'monitoring_enabled'> = {
namespace: 'default',
monitoring_enabled: ['logs', 'metrics'],
Expand Down
64 changes: 64 additions & 0 deletions x-pack/plugins/fleet/server/services/preconfiguration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ jest.mock('./app_context', () => ({
getExperimentalFeatures: jest.fn().mockReturnValue({
agentless: false,
}),
getInternalUserSOClientForSpaceId: jest.fn(),
},
}));

Expand Down Expand Up @@ -1124,6 +1125,69 @@ describe('policy preconfiguration', () => {
expect(policies[0].id).toBe('test-id');
expect(nonFatalErrorsB.length).toBe(0);
});

it('should used a namespaced saved objet client if the agent policy kibana_namespace is set', async () => {
const TEST_NAMESPACE = 'test';
const namespacedSOClient = getPutPreconfiguredPackagesMock();
const soClient = getPutPreconfiguredPackagesMock();
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;

jest
.mocked(appContextService)
.getInternalUserSOClientForSpaceId.mockReturnValue(namespacedSOClient);

await ensurePreconfiguredPackagesAndPolicies(
soClient,
esClient,
[
{
name: 'Test policy',
namespace: 'default',
id: 'test-id',
kibana_namespace: TEST_NAMESPACE,
is_managed: true,
package_policies: [
{
package: { name: 'test_package' },
name: 'test_package1',
},
],
},
] as PreconfiguredAgentPolicy[],
[{ name: 'test_package', version: '3.0.0' }],
mockDefaultOutput,
mockDefaultDownloadService,
DEFAULT_SPACE_ID
);

jest.mocked(appContextService.getExperimentalFeatures).mockReturnValue({
agentless: true,
} as any);

expect(appContextService.getInternalUserSOClientForSpaceId).toBeCalledTimes(1);
expect(appContextService.getInternalUserSOClientForSpaceId).toBeCalledWith(TEST_NAMESPACE);

expect(mockedPackagePolicyService.create).toBeCalledTimes(1);
expect(mockedPackagePolicyService.create).toBeCalledWith(
namespacedSOClient, // namespaced so client
expect.anything(), // es client
expect.objectContaining({
name: 'test_package1',
}),
expect.anything() // options
);

expect(spyAgentPolicyServiceUpdate).toBeCalledTimes(1);
expect(spyAgentPolicyServiceUpdate).toBeCalledWith(
namespacedSOClient, // namespaced so client
expect.anything(), // es client
expect.anything(), // id
expect.objectContaining({
is_managed: true,
}),
expect.anything() // options
);
});
});

describe('with bundled packages', () => {
Expand Down
39 changes: 28 additions & 11 deletions x-pack/plugins/fleet/server/services/preconfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,14 +174,20 @@ export async function ensurePreconfiguredPackagesAndPolicies(
);
}

const namespacedSoClient = preconfiguredAgentPolicy.kibana_namespace
? appContextService.getInternalUserSOClientForSpaceId(
preconfiguredAgentPolicy.kibana_namespace
)
: soClient;

const { created, policy } = await agentPolicyService.ensurePreconfiguredAgentPolicy(
soClient,
namespacedSoClient,
esClient,
omit(preconfiguredAgentPolicy, 'is_managed') // Don't add `is_managed` until the policy has been fully configured
omit(preconfiguredAgentPolicy, 'is_managed', 'kibana_namespace') // Don't add `is_managed` until the policy has been fully configured
);

if (!created) {
if (!policy) return { created, policy };
if (!policy) return { created, policy, namespacedSoClient };
if (!policy.is_managed && !preconfiguredAgentPolicy.is_managed) return { created, policy };
const { hasChanged, fields } = comparePreconfiguredPolicyToCurrent(
preconfiguredAgentPolicy,
Expand All @@ -194,22 +200,23 @@ export async function ensurePreconfiguredPackagesAndPolicies(
};
if (hasChanged) {
const updatedPolicy = await agentPolicyService.update(
soClient,
namespacedSoClient,
esClient,
String(preconfiguredAgentPolicy.id),
newFields,
{
force: true,
}
);
return { created, policy: updatedPolicy };
return { created, policy: updatedPolicy, namespacedSoClient };
}
return { created, policy };
return { created, policy, namespacedSoClient };
}

return {
created,
policy,
namespacedSoClient,
shouldAddIsManagedFlag: preconfiguredAgentPolicy.is_managed,
};
})
Expand All @@ -227,13 +234,17 @@ export async function ensurePreconfiguredPackagesAndPolicies(
continue;
}
fulfilledPolicies.push(policyResult.value);
const { created, policy, shouldAddIsManagedFlag } = policyResult.value;
const { created, policy, shouldAddIsManagedFlag, namespacedSoClient } = policyResult.value;

if (created || policies[i].is_managed) {
if (!namespacedSoClient) {
throw new Error('No soClient created for that policy');
}
const preconfiguredAgentPolicy = policies[i];
const { package_policies: packagePolicies } = preconfiguredAgentPolicy;

const agentPolicyWithPackagePolicies = await agentPolicyService.get(
soClient,
namespacedSoClient,
policy!.id,
true
);
Expand Down Expand Up @@ -287,7 +298,7 @@ export async function ensurePreconfiguredPackagesAndPolicies(
logger.debug(`Adding preconfigured package policies ${packagePoliciesToAdd}`);
const s = apm.startSpan('Add preconfigured package policies', 'preconfiguration');
await addPreconfiguredPolicyPackages(
soClient,
namespacedSoClient,
esClient,
policy!,
packagePoliciesToAdd!,
Expand All @@ -299,7 +310,7 @@ export async function ensurePreconfiguredPackagesAndPolicies(
// Add the is_managed flag after configuring package policies to avoid errors
if (shouldAddIsManagedFlag) {
await agentPolicyService.update(
soClient,
namespacedSoClient,
esClient,
policy!.id,
{ is_managed: true },
Expand Down Expand Up @@ -338,7 +349,13 @@ export function comparePreconfiguredPolicyToCurrent(
) {
// Namespace is omitted from being compared because even for managed policies, we still
// want users to be able to pick their own namespace: https://github.com/elastic/kibana/issues/110533
const configTopLevelFields = omit(policyFromConfig, 'package_policies', 'id', 'namespace');
const configTopLevelFields = omit(
policyFromConfig,
'package_policies',
'id',
'namespace',
'kibana_namespace'
);
const currentTopLevelFields = pick(currentPolicy, ...Object.keys(configTopLevelFields));

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ export const PreconfiguredFleetProxiesSchema = schema.arrayOf(
export const PreconfiguredAgentPoliciesSchema = schema.arrayOf(
schema.object({
...AgentPolicyBaseSchema,
kibana_namespace: schema.maybe(schema.string()),
namespace: schema.maybe(AgentPolicyNamespaceSchema),
id: schema.maybe(schema.oneOf([schema.string(), schema.number()])),
is_default: schema.maybe(schema.boolean()),
Expand Down

0 comments on commit d9aca86

Please sign in to comment.