[Fleet] Disable requirement for Fleet server with standalone fleet server (#158633)

This commit is contained in:
Nicolas Chaulet 2023-05-30 15:13:50 -04:00 committed by GitHub
parent 21151dd39f
commit 0ff50e14cd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 128 additions and 9 deletions

View file

@ -1,7 +1,7 @@
newsfeed.enabled: false
xpack.security.showNavLinks: false
xpack.serverless.plugin.enabled: true
xpack.fleet.enableExperimental: ['fleetServerStandalone']
xpack.fleet.internal.fleetServerStandalone: true
xpack.fleet.internal.disableILMPolicies: true
# Management team plugins

View file

@ -206,6 +206,7 @@ export default function ({ getService }: PluginFunctionalProviderContext) {
'xpack.discoverEnhanced.actions.exploreDataInContextMenu.enabled (boolean)',
'xpack.fleet.agents.enabled (boolean)',
'xpack.fleet.enableExperimental (array)',
'xpack.fleet.internal.fleetServerStandalone (boolean)',
'xpack.fleet.developer.maxAgentPoliciesWithInactivityTimeout (number)',
'xpack.global_search.search_timeout (duration)',
'xpack.graph.canEditDrillDownUrls (boolean)',

View file

@ -21,7 +21,6 @@ export const allowedExperimentalValues = Object.freeze({
showIntegrationsSubcategories: true,
agentFqdnMode: true,
showExperimentalShipperOptions: false,
fleetServerStandalone: false,
agentTamperProtectionEnabled: false,
secretsStorage: false,
});

View file

@ -47,6 +47,7 @@ export interface FleetConfigType {
};
internal?: {
disableILMPolicies: boolean;
fleetServerStandalone: boolean;
};
}

View file

@ -5,10 +5,11 @@
* 2.0.
*/
import { ExperimentalFeaturesService } from '../applications/fleet/services';
import { useConfig } from './use_config';
export function useFleetServerStandalone() {
const isFleetServerStandalone = ExperimentalFeaturesService.get().fleetServerStandalone;
const config = useConfig();
const isFleetServerStandalone = config.internal?.fleetServerStandalone ?? false;
return { isFleetServerStandalone };
}

View file

@ -38,6 +38,9 @@ export const config: PluginConfigDescriptor = {
developer: {
maxAgentPoliciesWithInactivityTimeout: true,
},
internal: {
fleetServerStandalone: true,
},
},
deprecations: ({ renameFromRoot, unused, unusedFromRoot }) => [
// Unused settings before Fleet server exists
@ -165,6 +168,9 @@ export const config: PluginConfigDescriptor = {
disableILMPolicies: schema.boolean({
defaultValue: false,
}),
fleetServerStandalone: schema.boolean({
defaultValue: false,
}),
})
),
enabled: schema.boolean({ defaultValue: true }),

View file

@ -19,10 +19,10 @@ import { agentServiceMock } from '../../services/agents/agent_service.mock';
import { appContextService } from '../../services/app_context';
import { setupFleet } from '../../services/setup';
import type { FleetRequestHandlerContext } from '../../types';
import { hasFleetServers } from '../../services/fleet_server';
import { createFleetAuthzMock } from '../../../common/mocks';
import { fleetSetupHandler } from './handlers';
import { fleetSetupHandler, getFleetStatusHandler } from './handlers';
jest.mock('../../services/setup', () => {
return {
@ -31,6 +31,8 @@ jest.mock('../../services/setup', () => {
};
});
jest.mock('../../services/fleet_server');
const mockSetupFleet = setupFleet as jest.MockedFunction<typeof setupFleet>;
describe('FleetSetupHandler', () => {
@ -115,3 +117,108 @@ describe('FleetSetupHandler', () => {
});
});
});
describe('FleetStatusHandler', () => {
let context: AwaitedProperties<Omit<FleetRequestHandlerContext, 'resolve'>>;
let response: ReturnType<typeof httpServerMock.createResponseFactory>;
let request: ReturnType<typeof httpServerMock.createKibanaRequest>;
beforeEach(async () => {
context = {
...xpackMocks.createRequestHandlerContext(),
fleet: {
agentClient: {
asCurrentUser: agentServiceMock.createClient(),
asInternalUser: agentServiceMock.createClient(),
},
authz: createFleetAuthzMock(),
packagePolicyService: {
asCurrentUser: createPackagePolicyServiceMock(),
asInternalUser: createPackagePolicyServiceMock(),
},
internalSoClient: savedObjectsClientMock.create(),
spaceId: 'default',
limitedToPackages: undefined,
},
};
response = httpServerMock.createResponseFactory();
request = httpServerMock.createKibanaRequest({
method: 'post',
path: '/api/fleet/status',
});
// prevents `Logger not set.` and other appContext errors
appContextService.start(createAppContextStartContractMock());
});
afterEach(async () => {
jest.clearAllMocks();
appContextService.stop();
});
it('POST /status w/200 and body without missing requirements', async () => {
jest
.mocked(appContextService.getSecurity().authc.apiKeys.areAPIKeysEnabled)
.mockResolvedValue(true);
jest.mocked(hasFleetServers).mockResolvedValue(true);
await getFleetStatusHandler(
coreMock.createCustomRequestHandlerContext(context),
request,
response
);
const expectedBody = {
isReady: true,
missing_optional_features: [],
missing_requirements: [],
};
expect(response.customError).toHaveBeenCalledTimes(0);
expect(response.ok).toHaveBeenCalledWith({ body: expectedBody });
});
it('POST /status w/200 and body with missing requirements', async () => {
jest
.mocked(appContextService.getSecurity().authc.apiKeys.areAPIKeysEnabled)
.mockResolvedValue(false);
jest.mocked(hasFleetServers).mockResolvedValue(false);
await getFleetStatusHandler(
coreMock.createCustomRequestHandlerContext(context),
request,
response
);
const expectedBody = {
isReady: false,
missing_optional_features: [],
missing_requirements: ['api_keys', 'fleet_server'],
};
expect(response.customError).toHaveBeenCalledTimes(0);
expect(response.ok).toHaveBeenCalledWith({ body: expectedBody });
});
it('POST /status w/200 with fleet server standalone', async () => {
jest.mocked(hasFleetServers).mockResolvedValue(false);
appContextService.start(
createAppContextStartContractMock({
internal: {
fleetServerStandalone: true,
},
} as any)
);
jest
.mocked(appContextService.getSecurity().authc.apiKeys.areAPIKeysEnabled)
.mockResolvedValue(true);
await getFleetStatusHandler(
coreMock.createCustomRequestHandlerContext(context),
request,
response
);
const expectedBody = {
isReady: true,
missing_optional_features: [],
missing_requirements: [],
};
expect(response.customError).toHaveBeenCalledTimes(0);
expect(response.ok).toHaveBeenCalledWith({ body: expectedBody });
});
});

View file

@ -19,10 +19,12 @@ export const getFleetStatusHandler: FleetRequestHandler = async (context, reques
.getSecurity()
.authc.apiKeys.areAPIKeysEnabled();
const coreContext = await context.core;
const isFleetServerSetup = await hasFleetServers(
const isFleetServerMissing = !(await hasFleetServers(
coreContext.elasticsearch.client.asInternalUser
);
));
const isFleetServerStandalone =
appContextService.getConfig()?.internal?.fleetServerStandalone ?? false;
const missingRequirements: GetFleetStatusResponse['missing_requirements'] = [];
const missingOptionalFeatures: GetFleetStatusResponse['missing_optional_features'] = [];
@ -30,7 +32,7 @@ export const getFleetStatusHandler: FleetRequestHandler = async (context, reques
missingRequirements.push('api_keys');
}
if (!isFleetServerSetup) {
if (!isFleetServerStandalone && isFleetServerMissing) {
missingRequirements.push('fleet_server');
}

View file

@ -122,6 +122,7 @@ describe('_installPackage', () => {
createAppContextStartContractMock({
internal: {
disableILMPolicies: true,
fleetServerStandalone: false,
},
})
);
@ -172,6 +173,7 @@ describe('_installPackage', () => {
createAppContextStartContractMock({
internal: {
disableILMPolicies: false,
fleetServerStandalone: false,
},
})
);