Skip to content

Commit

Permalink
Merge branch 'main' into http-versioning-mute-alert
Browse files Browse the repository at this point in the history
  • Loading branch information
jcger authored Sep 5, 2023
2 parents 9ef6a38 + a9c3ca5 commit 808a9dc
Show file tree
Hide file tree
Showing 23 changed files with 433 additions and 108 deletions.
17 changes: 17 additions & 0 deletions .buildkite/pipelines/quality-gates/pipeline.kibana-tests.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
# This pipeline serves as the entry point for your service's quality gates definitions. When
# properly configured, it will be invoked automatically as part of the automated
# promotion process once a new version was rolled out in one of the various cloud stages.
#
# The updated environment is provided via ENVIRONMENT variable. The seedling
# step will branch and execute pipeline snippets at the following location:
# pipeline.tests-qa.yaml
# pipeline.tests-staging.yaml
# pipeline.tests-production.yaml
#
# Docs: https://docs.elastic.dev/serverless/qualitygates

env:
TEAM_CHANNEL: "#kibana-mission-control"
ENVIRONMENT: ${ENVIRONMENT?}

steps:
Expand All @@ -8,3 +21,7 @@ steps:
command: "make -C /agent run-environment-tests"
agents:
image: "docker.elastic.co/ci-agent-images/quality-gate-seedling:0.0.2"

notify:
- slack: "${TEAM_CHANNEL?}"
if: build.branch == "main" && build.state == "failed"
16 changes: 12 additions & 4 deletions .buildkite/pipelines/quality-gates/pipeline.tests-production.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
env:
TEAM_CHANNEL: "#kibana-serverless-release"
ENVIRONMENT: "production"
# These pipeline steps constitute the quality gate for your service within the production
# environment. Incorporate any necessary additional logic to validate the service's integrity.
# A failure in this pipeline build will prevent further progression to the subsequent stage.

steps:
- label: ":pipeline::fleet::seedling: Trigger Observability Kibana Tests for ${ENVIRONMENT}"
Expand All @@ -13,9 +13,17 @@ steps:
agents:
image: "docker.elastic.co/ci-agent-images/basic-buildkite-agent:1688566364"

- label: ":rocket: Run cp e2e tests"
trigger: "ess-k8s-production-e2e-tests"
build:
message: "${BUILDKITE_MESSAGE}"
env:
REGION_ID: aws-us-east-1
NAME_PREFIX: ci_test_${SERVICE}-promotion_

- wait: ~

- label: ":judge::seedling: Trigger Manual Tests Phase"
command: "make -C /agent trigger-manual-verification-phase"
agents:
image: "docker.elastic.co/ci-agent-images/manual-verification-agent:0.0.1"
image: "docker.elastic.co/ci-agent-images/manual-verification-agent:0.0.2"
16 changes: 12 additions & 4 deletions .buildkite/pipelines/quality-gates/pipeline.tests-qa.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
env:
TEAM_CHANNEL: "#kibana-serverless-release"
ENVIRONMENT: "qa"
# These pipeline steps constitute the quality gate for your service within the QA environment.
# Incorporate any necessary additional logic to validate the service's integrity. A failure in
# this pipeline build will prevent further progression to the subsequent stage.

steps:
- label: ":pipeline::kibana::seedling: Trigger Kibana Tests for ${ENVIRONMENT}"
Expand All @@ -23,9 +23,17 @@ steps:
agents:
image: "docker.elastic.co/ci-agent-images/basic-buildkite-agent:1688566364"

- label: ":rocket: Run cp e2e tests"
trigger: "ess-k8s-qa-e2e-tests-daily"
build:
message: "${BUILDKITE_MESSAGE}"
env:
REGION_ID: aws-eu-west-1
NAME_PREFIX: ci_test_kibana-promotion_

- wait: ~

- label: ":judge::seedling: Trigger Manual Tests Phase"
command: "make -C /agent trigger-manual-verification-phase"
agents:
image: "docker.elastic.co/ci-agent-images/manual-verification-agent:0.0.1"
image: "docker.elastic.co/ci-agent-images/manual-verification-agent:0.0.2"
16 changes: 12 additions & 4 deletions .buildkite/pipelines/quality-gates/pipeline.tests-staging.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
env:
TEAM_CHANNEL: "#kibana-serverless-release"
ENVIRONMENT: "staging"
# These pipeline steps constitute the quality gate for your service within the staging environment.
# Incorporate any necessary additional logic to validate the service's integrity. A failure in
# this pipeline build will prevent further progression to the subsequent stage.

steps:
- label: ":pipeline::fleet::seedling: Trigger Observability Kibana Tests for ${ENVIRONMENT}"
Expand All @@ -13,9 +13,17 @@ steps:
agents:
image: "docker.elastic.co/ci-agent-images/basic-buildkite-agent:1688566364"

- label: ":rocket: Run cp e2e tests"
trigger: "ess-k8s-staging-e2e-tests"
build:
message: "${BUILDKITE_MESSAGE}"
env:
REGION_ID: aws-us-east-1
NAME_PREFIX: ci_test_kibana-promotion_

- wait: ~

- label: ":judge::seedling: Trigger Manual Tests Phase"
command: "make -C /agent trigger-manual-verification-phase"
agents:
image: "docker.elastic.co/ci-agent-images/manual-verification-agent:0.0.1"
image: "docker.elastic.co/ci-agent-images/manual-verification-agent:0.0.2"
2 changes: 1 addition & 1 deletion .github/workflows/create-deploy-tag.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ concurrency:
jobs:
create-deploy-tag:
# Temporary, we need a way to limit this to a GitHub team instead of specific users
if: contains('["watson","clintandrewhall","kobelb","lukeelmers","thomasneirynck"]', github.triggering_actor)
if: contains('["watson","clintandrewhall","kobelb","lukeelmers","thomasneirynck","jbudz","mistic","delanni","Ikuni17"]', github.triggering_actor)
runs-on: ubuntu-latest
permissions:
contents: write
Expand Down
3 changes: 2 additions & 1 deletion x-pack/plugins/actions/kibana.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
"usageCollection",
"spaces",
"security",
"monitoringCollection"
"monitoringCollection",
"serverless"
],
"extraPublicDirs": [
"common"
Expand Down
17 changes: 11 additions & 6 deletions x-pack/plugins/actions/server/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,19 +64,23 @@ const connectorTypeSchema = schema.object({
maxAttempts: schema.maybe(schema.number({ min: MIN_MAX_ATTEMPTS, max: MAX_MAX_ATTEMPTS })),
});

// We leverage enabledActionTypes list by allowing the other plugins to overwrite it by using "setEnabledConnectorTypes" in the plugin setup.
// The list can be overwritten only if it's not already been set in the config.
const enabledConnectorTypesSchema = schema.arrayOf(
schema.oneOf([schema.string(), schema.literal(EnabledActionTypes.Any)]),
{
defaultValue: [AllowedHosts.Any],
}
);

export const configSchema = schema.object({
allowedHosts: schema.arrayOf(
schema.oneOf([schema.string({ hostname: true }), schema.literal(AllowedHosts.Any)]),
{
defaultValue: [AllowedHosts.Any],
}
),
enabledActionTypes: schema.arrayOf(
schema.oneOf([schema.string(), schema.literal(EnabledActionTypes.Any)]),
{
defaultValue: [AllowedHosts.Any],
}
),
enabledActionTypes: enabledConnectorTypesSchema,
preconfiguredAlertHistoryEsIndex: schema.boolean({ defaultValue: false }),
preconfigured: schema.recordOf(schema.string(), preconfiguredActionSchema, {
defaultValue: {},
Expand Down Expand Up @@ -129,6 +133,7 @@ export const configSchema = schema.object({
});

export type ActionsConfig = TypeOf<typeof configSchema>;
export type EnabledConnectorTypes = TypeOf<typeof enabledConnectorTypesSchema>;

// It would be nicer to add the proxyBypassHosts / proxyOnlyHosts restriction on
// simultaneous usage in the config validator directly, but there's no good way to express
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/actions/server/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const createSetupMock = () => {
getCaseConnectorClass: jest.fn(),
getActionsHealth: jest.fn(),
getActionsConfigurationUtilities: jest.fn(),
setEnabledConnectorTypes: jest.fn(),
};
return mock;
};
Expand Down
189 changes: 189 additions & 0 deletions x-pack/plugins/actions/server/plugin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,163 @@ describe('Actions Plugin', () => {
expect(pluginSetup.isPreconfiguredConnector('anotherConnectorId')).toEqual(false);
});
});

describe('setEnabledConnectorTypes (works only on serverless)', () => {
function setup(config: ActionsConfig) {
context = coreMock.createPluginInitializerContext<ActionsConfig>(config);
plugin = new ActionsPlugin(context);
coreSetup = coreMock.createSetup();
pluginsSetup = {
taskManager: taskManagerMock.createSetup(),
encryptedSavedObjects: encryptedSavedObjectsMock.createSetup(),
licensing: licensingMock.createSetup(),
eventLog: eventLogMock.createSetup(),
usageCollection: usageCollectionPluginMock.createSetupContract(),
features: featuresPluginMock.createSetup(),
serverless: {},
};
}

it('should set connector type enabled', async () => {
setup(getConfig());
// coreMock.createSetup doesn't support Plugin generics
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const pluginSetup = await plugin.setup(coreSetup as any, pluginsSetup);
const coreStart = coreMock.createStart();
const pluginsStart = {
licensing: licensingMock.createStart(),
taskManager: taskManagerMock.createStart(),
encryptedSavedObjects: encryptedSavedObjectsMock.createStart(),
eventLog: eventLogMock.createStart(),
};
const pluginStart = plugin.start(coreStart, pluginsStart);

pluginSetup.registerType({
id: '.server-log',
name: 'Server log',
minimumLicenseRequired: 'basic',
supportedFeatureIds: ['alerting'],
validate: {
config: { schema: schema.object({}) },
secrets: { schema: schema.object({}) },
params: { schema: schema.object({}) },
},
executor,
});
pluginSetup.registerType({
id: '.slack',
name: 'Slack',
minimumLicenseRequired: 'gold',
supportedFeatureIds: ['alerting'],
validate: {
config: { schema: schema.object({}) },
secrets: { schema: schema.object({}) },
params: { schema: schema.object({}) },
},
executor,
});
pluginSetup.setEnabledConnectorTypes(['.server-log']);
expect(pluginStart.isActionTypeEnabled('.server-log')).toBeTruthy();
expect(pluginStart.isActionTypeEnabled('.slack')).toBeFalsy();
});

it('should set all the connector types enabled when null or ["*"] passed', async () => {
setup(getConfig());
// coreMock.createSetup doesn't support Plugin generics
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const pluginSetup = await plugin.setup(coreSetup as any, pluginsSetup);
const coreStart = coreMock.createStart();
const pluginsStart = {
licensing: licensingMock.createStart(),
taskManager: taskManagerMock.createStart(),
encryptedSavedObjects: encryptedSavedObjectsMock.createStart(),
eventLog: eventLogMock.createStart(),
};
const pluginStart = plugin.start(coreStart, pluginsStart);

pluginSetup.registerType({
id: '.server-log',
name: 'Server log',
minimumLicenseRequired: 'basic',
supportedFeatureIds: ['alerting'],
validate: {
config: { schema: schema.object({}) },
secrets: { schema: schema.object({}) },
params: { schema: schema.object({}) },
},
executor,
});
pluginSetup.registerType({
id: '.index',
name: 'Index',
minimumLicenseRequired: 'basic',
supportedFeatureIds: ['alerting'],
validate: {
config: { schema: schema.object({}) },
secrets: { schema: schema.object({}) },
params: { schema: schema.object({}) },
},
executor,
});
pluginSetup.setEnabledConnectorTypes(['*']);
expect(pluginStart.isActionTypeEnabled('.server-log')).toBeTruthy();
expect(pluginStart.isActionTypeEnabled('.index')).toBeTruthy();
});

it('should set all the connector types disabled when [] passed', async () => {
setup(getConfig());
// coreMock.createSetup doesn't support Plugin generics
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const pluginSetup = await plugin.setup(coreSetup as any, pluginsSetup);
const coreStart = coreMock.createStart();
const pluginsStart = {
licensing: licensingMock.createStart(),
taskManager: taskManagerMock.createStart(),
encryptedSavedObjects: encryptedSavedObjectsMock.createStart(),
eventLog: eventLogMock.createStart(),
};
const pluginStart = plugin.start(coreStart, pluginsStart);

pluginSetup.registerType({
id: '.server-log',
name: 'Server log',
minimumLicenseRequired: 'basic',
supportedFeatureIds: ['alerting'],
validate: {
config: { schema: schema.object({}) },
secrets: { schema: schema.object({}) },
params: { schema: schema.object({}) },
},
executor,
});
pluginSetup.registerType({
id: '.index',
name: 'Index',
minimumLicenseRequired: 'basic',
supportedFeatureIds: ['alerting'],
validate: {
config: { schema: schema.object({}) },
secrets: { schema: schema.object({}) },
params: { schema: schema.object({}) },
},
executor,
});
pluginSetup.setEnabledConnectorTypes([]);
expect(pluginStart.isActionTypeEnabled('.server-log')).toBeFalsy();
expect(pluginStart.isActionTypeEnabled('.index')).toBeFalsy();
});

it('should throw if the enabledActionTypes is already set by the config', async () => {
setup({ ...getConfig(), enabledActionTypes: ['.email'] });
// coreMock.createSetup doesn't support Plugin generics
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const pluginSetup = await plugin.setup(coreSetup as any, pluginsSetup);

expect(() => pluginSetup.setEnabledConnectorTypes(['.index'])).toThrow(
"Enabled connector types can be set only if they haven't already been set in the config"
);
});
});
});

describe('start()', () => {
Expand Down Expand Up @@ -396,6 +553,38 @@ describe('Actions Plugin', () => {
};
});

it('should throw when there is an invalid connector type in enabledActionTypes', async () => {
const pluginSetup = await plugin.setup(coreSetup, {
...pluginsSetup,
encryptedSavedObjects: {
...pluginsSetup.encryptedSavedObjects,
canEncrypt: true,
},
serverless: {},
});

pluginSetup.registerType({
id: '.server-log',
name: 'Server log',
minimumLicenseRequired: 'basic',
supportedFeatureIds: ['alerting'],
validate: {
config: { schema: schema.object({}) },
secrets: { schema: schema.object({}) },
params: { schema: schema.object({}) },
},
executor,
});

pluginSetup.setEnabledConnectorTypes(['.server-log', 'non-existing']);

await expect(async () =>
plugin.start(coreStart, { ...pluginsStart, serverless: {} })
).rejects.toThrowErrorMatchingInlineSnapshot(
`"Action type \\"non-existing\\" is not registered."`
);
});

describe('getActionsClientWithRequest()', () => {
it('should not throw error when ESO plugin has encryption key', async () => {
await plugin.setup(coreSetup, {
Expand Down
Loading

0 comments on commit 808a9dc

Please sign in to comment.