Skip to content

Commit

Permalink
Merge branch 'master' into reportingg/csv-flaky-test
Browse files Browse the repository at this point in the history
  • Loading branch information
kibanamachine authored Sep 27, 2021
2 parents 428c0d9 + b303d0f commit d7bae83
Show file tree
Hide file tree
Showing 59 changed files with 1,947 additions and 537 deletions.
9 changes: 8 additions & 1 deletion .buildkite/scripts/steps/storybooks/build_and_upload.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,20 @@ const path = require('path');
const STORYBOOKS = [
'apm',
'canvas',
'codeeditor',
'ci_composite',
'url_template_editor',
'codeeditor',
'dashboard',
'dashboard_enhanced',
'data_enhanced',
'embeddable',
'expression_error',
'expression_image',
'expression_metric',
'expression_repeat_image',
'expression_reveal_image',
'expression_shape',
'expression_tagcloud',
'fleet',
'infra',
'security_solution',
Expand Down
18 changes: 17 additions & 1 deletion docs/user/dashboard/lens.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -441,4 +441,20 @@ Pagination in a data table is unsupported. To use pagination in data tables, cre
[%collapsible]
====
Specifying the color for a single data point, such as a single bar or line, is unsupported.
====
====

[discrete]
[[is-it-possible-to-inspect-the-elasticsearch-queries-in-Lens]]
.*How do I inspect {es} queries in visualizations?*
[%collapsible]
====
You can inspect the requests sent by the visualization to {es} using the Inspector. It can be accessed within the editor or in the dashboard.
====

[discrete]
[[how-to-isolate-a-single-series-in-a-chart]]
.*How do I isolate a single series in a chart?*
[%collapsible]
====
For area, line, and bar charts, press Shift, then click the series in the legend. All other series are automatically unselected.
====
3 changes: 2 additions & 1 deletion test/functional/apps/dashboard/dashboard_unsaved_state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
let unsavedPanelCount = 0;
const testQuery = 'Test Query';

describe('dashboard unsaved state', () => {
// FLAKY https://github.com/elastic/kibana/issues/112812
describe.skip('dashboard unsaved state', () => {
before(async () => {
await esArchiver.load('test/functional/fixtures/es_archiver/dashboard/current/kibana');
await kibanaServer.uiSettings.replace({
Expand Down
1 change: 1 addition & 0 deletions test/scripts/jenkins_storybook.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ yarn storybook --site expression_repeat_image
yarn storybook --site expression_reveal_image
yarn storybook --site expression_shape
yarn storybook --site expression_tagcloud
yarn storybook --site fleet
yarn storybook --site infra
yarn storybook --site security_solution
yarn storybook --site ui_actions_enhanced
Expand Down
7 changes: 7 additions & 0 deletions x-pack/plugins/actions/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,10 @@ export * from './rewrite_request_case';
export const BASE_ACTION_API_PATH = '/api/actions';
export const INTERNAL_BASE_ACTION_API_PATH = '/internal/actions';
export const ACTIONS_FEATURE_ID = 'actions';

// supported values for `service` in addition to nodemailer's list of well-known services
export enum AdditionalEmailServices {
ELASTIC_CLOUD = 'elastic_cloud',
EXCHANGE = 'exchange_server',
OTHER = 'other',
}
8 changes: 1 addition & 7 deletions x-pack/plugins/actions/server/builtin_action_types/email.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { Logger } from '../../../../../src/core/server';
import { ActionType, ActionTypeExecutorOptions, ActionTypeExecutorResult } from '../types';
import { ActionsConfigurationUtilities } from '../actions_config';
import { renderMustacheString, renderMustacheObject } from '../lib/mustache_renderer';
import { AdditionalEmailServices } from '../../common';

export type EmailActionType = ActionType<
ActionTypeConfigType,
Expand All @@ -33,13 +34,6 @@ export type EmailActionTypeExecutorOptions = ActionTypeExecutorOptions<
// config definition
export type ActionTypeConfigType = TypeOf<typeof ConfigSchema>;

// supported values for `service` in addition to nodemailer's list of well-known services
export enum AdditionalEmailServices {
ELASTIC_CLOUD = 'elastic_cloud',
EXCHANGE = 'exchange_server',
OTHER = 'other',
}

// these values for `service` require users to fill in host/port/secure
export const CUSTOM_HOST_PORT_SERVICES: string[] = [AdditionalEmailServices.OTHER];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import qs from 'query-string';
import axios from 'axios';
import stringify from 'json-stable-stringify';
import { Logger } from '../../../../../../src/core/server';
import { request } from './axios_utils';
import { ActionsConfigurationUtilities } from '../../actions_config';
Expand Down Expand Up @@ -59,7 +60,7 @@ export async function requestOAuthClientCredentialsToken(
expiresIn: res.data.expires_in,
};
} else {
const errString = JSON.stringify(res.data);
const errString = stringify(res.data);
logger.warn(
`error thrown getting the access token from ${tokenUrl} for clientID: ${clientId}: ${errString}`
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ import { Logger } from '../../../../../../src/core/server';
import { ActionsConfigurationUtilities } from '../../actions_config';
import { CustomHostSettings } from '../../config';
import { getNodeSSLOptions, getSSLSettingsFromConfig } from './get_node_ssl_options';
import { AdditionalEmailServices } from '../email';
import { sendEmailGraphApi } from './send_email_graph_api';
import { requestOAuthClientCredentialsToken } from './request_oauth_client_credentials_token';
import { ProxySettings } from '../../types';
import { AdditionalEmailServices } from '../../../common';

// an email "service" which doesn't actually send, just returns what it would send
export const JSON_TRANSPORT_SERVICE = '__json';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
* 2.0.
*/

// @ts-expect-error missing type def
import stringify from 'json-stringify-safe';
import axios, { AxiosResponse } from 'axios';
import { Logger } from '../../../../../../src/core/server';
import { request } from './axios_utils';
Expand Down Expand Up @@ -41,9 +43,9 @@ export async function sendEmailGraphApi(
validateStatus: () => true,
});
if (res.status === 202) {
return res;
return res.data;
}
const errString = JSON.stringify(res.data);
const errString = stringify(res.data);
logger.warn(
`error thrown sending Microsoft Exchange email for clientID: ${sendEmailOptions.options.transport.clientId}: ${errString}`
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import { IRouter } from 'kibana/server';
import nodemailerGetService from 'nodemailer/lib/well-known';
import SMTPConnection from 'nodemailer/lib/smtp-connection';
import { ILicenseState } from '../lib';
import { INTERNAL_BASE_ACTION_API_PATH } from '../../common';
import { AdditionalEmailServices, INTERNAL_BASE_ACTION_API_PATH } from '../../common';
import { ActionsRequestHandlerContext } from '../types';
import { verifyAccessAndContext } from './verify_access_and_context';
import { AdditionalEmailServices, ELASTIC_CLOUD_SERVICE } from '../builtin_action_types/email';
import { ELASTIC_CLOUD_SERVICE } from '../builtin_action_types/email';

const paramSchema = schema.object({
service: schema.string(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ export const createAgentPolicyHandler: RequestHandler<
});
}

await agentPolicyService.createFleetPolicyChangeAction(soClient, agentPolicy.id);
await agentPolicyService.createFleetServerPolicy(soClient, agentPolicy.id);

const body: CreateAgentPolicyResponse = {
item: agentPolicy,
Expand Down
14 changes: 6 additions & 8 deletions x-pack/plugins/fleet/server/routes/setup/handlers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@ import type { PostFleetSetupResponse } from '../../../common';
import { RegistryError } from '../../errors';
import { createAppContextStartContractMock, xpackMocks } from '../../mocks';
import { appContextService } from '../../services/app_context';
import { setupIngestManager } from '../../services/setup';
import { setupFleet } from '../../services/setup';

import { fleetSetupHandler } from './handlers';

jest.mock('../../services/setup', () => {
return {
setupIngestManager: jest.fn(),
setupFleet: jest.fn(),
};
});

const mockSetupIngestManager = setupIngestManager as jest.MockedFunction<typeof setupIngestManager>;
const mockSetupFleet = setupFleet as jest.MockedFunction<typeof setupFleet>;

describe('FleetSetupHandler', () => {
let context: ReturnType<typeof xpackMocks.createRequestHandlerContext>;
Expand All @@ -45,7 +45,7 @@ describe('FleetSetupHandler', () => {
});

it('POST /setup succeeds w/200 and body of resolved value', async () => {
mockSetupIngestManager.mockImplementation(() =>
mockSetupFleet.mockImplementation(() =>
Promise.resolve({
isInitialized: true,
nonFatalErrors: [],
Expand All @@ -59,9 +59,7 @@ describe('FleetSetupHandler', () => {
});

it('POST /setup fails w/500 on custom error', async () => {
mockSetupIngestManager.mockImplementation(() =>
Promise.reject(new Error('SO method mocked to throw'))
);
mockSetupFleet.mockImplementation(() => Promise.reject(new Error('SO method mocked to throw')));
await fleetSetupHandler(context, request, response);

expect(response.customError).toHaveBeenCalledTimes(1);
Expand All @@ -74,7 +72,7 @@ describe('FleetSetupHandler', () => {
});

it('POST /setup fails w/502 on RegistryError', async () => {
mockSetupIngestManager.mockImplementation(() =>
mockSetupFleet.mockImplementation(() =>
Promise.reject(new RegistryError('Registry method mocked to throw'))
);

Expand Down
4 changes: 2 additions & 2 deletions x-pack/plugins/fleet/server/routes/setup/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import type { RequestHandler } from 'src/core/server';

import { appContextService } from '../../services';
import type { GetFleetStatusResponse, PostFleetSetupResponse } from '../../../common';
import { setupIngestManager } from '../../services/setup';
import { setupFleet } from '../../services/setup';
import { hasFleetServers } from '../../services/fleet_server';
import { defaultIngestErrorHandler } from '../../errors';

Expand Down Expand Up @@ -46,7 +46,7 @@ export const fleetSetupHandler: RequestHandler = async (context, request, respon
try {
const soClient = context.core.savedObjects.client;
const esClient = context.core.elasticsearch.client.asCurrentUser;
const setupStatus = await setupIngestManager(soClient, esClient);
const setupStatus = await setupFleet(soClient, esClient);
const body: PostFleetSetupResponse = {
...setupStatus,
nonFatalErrors: setupStatus.nonFatalErrors.map((e) => {
Expand Down
74 changes: 73 additions & 1 deletion x-pack/plugins/fleet/server/services/agent_policy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@

import { elasticsearchServiceMock, savedObjectsClientMock } from 'src/core/server/mocks';

import type { AgentPolicy, NewAgentPolicy } from '../types';
import type { AgentPolicy, FullAgentPolicy, NewAgentPolicy } from '../types';

import { agentPolicyService } from './agent_policy';
import { agentPolicyUpdateEventHandler } from './agent_policy_update';

import { getAgentsByKuery } from './agents';
import { packagePolicyService } from './package_policy';
import { appContextService } from './app_context';
import { outputService } from './output';
import { getFullAgentPolicy } from './agent_policies';

function getSavedObjectMock(agentPolicyAttributes: any) {
const mock = savedObjectsClientMock.create();
Expand Down Expand Up @@ -47,9 +50,18 @@ function getSavedObjectMock(agentPolicyAttributes: any) {
return mock;
}

jest.mock('./output');
jest.mock('./agent_policy_update');
jest.mock('./agents');
jest.mock('./package_policy');
jest.mock('./app_context');
jest.mock('./agent_policies/full_agent_policy');

const mockedAppContextService = appContextService as jest.Mocked<typeof appContextService>;
const mockedOutputService = outputService as jest.Mocked<typeof outputService>;
const mockedGetFullAgentPolicy = getFullAgentPolicy as jest.Mock<
ReturnType<typeof getFullAgentPolicy>
>;

function getAgentPolicyUpdateMock() {
return agentPolicyUpdateEventHandler as unknown as jest.Mock<
Expand Down Expand Up @@ -214,4 +226,64 @@ describe('agent policy', () => {
expect(calledWith[2]).toHaveProperty('is_managed', true);
});
});

describe('createFleetServerPolicy', () => {
beforeEach(() => {
mockedGetFullAgentPolicy.mockReset();
});
it('should not create a .fleet-policy document if we cannot get the full policy', async () => {
const soClient = savedObjectsClientMock.create();
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
mockedAppContextService.getInternalUserESClient.mockReturnValue(esClient);
mockedOutputService.getDefaultOutputId.mockResolvedValue('default-output');
mockedGetFullAgentPolicy.mockResolvedValue(null);

soClient.get.mockResolvedValue({
attributes: {},
id: 'policy123',
type: 'mocked',
references: [],
});
await agentPolicyService.createFleetServerPolicy(soClient, 'policy123');

expect(esClient.create).not.toBeCalled();
});

it('should create a .fleet-policy document if we can get the full policy', async () => {
const soClient = savedObjectsClientMock.create();
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
mockedAppContextService.getInternalUserESClient.mockReturnValue(esClient);
mockedOutputService.getDefaultOutputId.mockResolvedValue('default-output');
mockedGetFullAgentPolicy.mockResolvedValue({
id: 'policy123',
revision: 1,
inputs: [
{
id: 'input-123',
},
],
} as FullAgentPolicy);

soClient.get.mockResolvedValue({
attributes: {},
id: 'policy123',
type: 'mocked',
references: [],
});
await agentPolicyService.createFleetServerPolicy(soClient, 'policy123');

expect(esClient.create).toBeCalledWith(
expect.objectContaining({
index: '.fleet-policies',
body: expect.objectContaining({
'@timestamp': expect.anything(),
data: { id: 'policy123', inputs: [{ id: 'input-123' }], revision: 1 },
default_fleet_server: false,
policy_id: 'policy123',
revision_idx: 1,
}),
})
);
});
});
});
13 changes: 3 additions & 10 deletions x-pack/plugins/fleet/server/services/agent_policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,7 @@ class AgentPolicyService {
throw new Error('Copied agent policy not found');
}

await this.createFleetPolicyChangeAction(soClient, newAgentPolicy.id);
await this.createFleetServerPolicy(soClient, newAgentPolicy.id);

return updatedAgentPolicy;
}
Expand Down Expand Up @@ -655,25 +655,18 @@ class AgentPolicyService {
};
}

public async createFleetPolicyChangeAction(
public async createFleetServerPolicy(
soClient: SavedObjectsClientContract,
agentPolicyId: string
) {
// Use internal ES client so we have permissions to write to .fleet* indices
const esClient = appContextService.getInternalUserESClient();
const defaultOutputId = await outputService.getDefaultOutputId(soClient);

if (!defaultOutputId) {
return;
}

await this.createFleetPolicyChangeFleetServer(soClient, esClient, agentPolicyId);
}

public async createFleetPolicyChangeFleetServer(
soClient: SavedObjectsClientContract,
esClient: ElasticsearchClient,
agentPolicyId: string
) {
const policy = await agentPolicyService.get(soClient, agentPolicyId);
const fullPolicy = await agentPolicyService.getFullAgentPolicy(soClient, agentPolicyId);
if (!policy || !fullPolicy || !fullPolicy.revision) {
Expand Down
4 changes: 2 additions & 2 deletions x-pack/plugins/fleet/server/services/agent_policy_update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ export async function agentPolicyUpdateEventHandler(
name: 'Default',
agentPolicyId,
});
await agentPolicyService.createFleetPolicyChangeAction(internalSoClient, agentPolicyId);
await agentPolicyService.createFleetServerPolicy(internalSoClient, agentPolicyId);
}

if (action === 'updated') {
await agentPolicyService.createFleetPolicyChangeAction(internalSoClient, agentPolicyId);
await agentPolicyService.createFleetServerPolicy(internalSoClient, agentPolicyId);
}

if (action === 'deleted') {
Expand Down
Loading

0 comments on commit d7bae83

Please sign in to comment.