mirror of
https://github.com/elastic/kibana.git
synced 2025-06-28 11:05:39 -04:00
[Fleet] Add license gate around remote synced integrations (#221636)
Closes https://github.com/elastic/kibana/issues/219488 ## Summary Add license gate around remote synced integrations - Only accounts having Enterprise license will be able to use the new remote synced integrations feature. This requirement depends on the ccr feature, which works only on Enterprise licenses, this PR makes sure that this also checked in Fleet. ### Testing 1. With a license different than enterprise - Try to create an output that enables synced integrations - it should fail with a 400: ``` POST kbn:/api/fleet/outputs { "name": "new 1", "type": "remote_elasticsearch", "hosts": [ "https://lskfgjojg" ], "is_default": false, "is_default_monitoring": false, "sync_integrations": true } ``` - Verify that the UI elements listed in https://github.com/elastic/kibana/issues/219488 are not visible 2. With Enterprise license - Check that the UI elements are visible and the remote sync integrations features work as expected ### Checklist - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] This was checked for breaking HTTP API changes, and any breaking changes have been approved by the breaking-change committee. The `release_note:breaking` label should be applied in these situations. - [ ] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [ ] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com> Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
216ac7e83e
commit
2d84e8b83c
18 changed files with 759 additions and 1584 deletions
|
@ -44288,339 +44288,6 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/api/fleet/remote_synced_integrations/status": {
|
|
||||||
"get": {
|
|
||||||
"description": "[Required authorization] Route required privileges: fleet-settings-read AND integrations-read.",
|
|
||||||
"operationId": "get-fleet-remote-synced-integrations-status",
|
|
||||||
"parameters": [],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"content": {
|
|
||||||
"application/json": {
|
|
||||||
"schema": {
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"custom_assets": {
|
|
||||||
"additionalProperties": {
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"error": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"is_deleted": {
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"package_name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"package_version": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"sync_status": {
|
|
||||||
"enum": [
|
|
||||||
"completed",
|
|
||||||
"synchronizing",
|
|
||||||
"failed",
|
|
||||||
"warning"
|
|
||||||
],
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"type": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"type",
|
|
||||||
"name",
|
|
||||||
"package_name",
|
|
||||||
"package_version",
|
|
||||||
"sync_status"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"error": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"integrations": {
|
|
||||||
"items": {
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"error": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"install_status": {
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"main": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"remote": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"main"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"package_name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"package_version": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"sync_status": {
|
|
||||||
"enum": [
|
|
||||||
"completed",
|
|
||||||
"synchronizing",
|
|
||||||
"failed",
|
|
||||||
"warning"
|
|
||||||
],
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"warning": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"sync_status",
|
|
||||||
"install_status"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"type": "array"
|
|
||||||
},
|
|
||||||
"warning": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"integrations"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"content": {
|
|
||||||
"application/json": {
|
|
||||||
"schema": {
|
|
||||||
"additionalProperties": false,
|
|
||||||
"description": "Generic Error",
|
|
||||||
"properties": {
|
|
||||||
"attributes": {},
|
|
||||||
"error": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"errorType": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"message": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"statusCode": {
|
|
||||||
"type": "number"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"message",
|
|
||||||
"attributes"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"summary": "Get CCR Remote synced integrations status",
|
|
||||||
"tags": [
|
|
||||||
"CCR Remote synced integrations"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/fleet/remote_synced_integrations/{outputId}/remote_status": {
|
|
||||||
"get": {
|
|
||||||
"description": "[Required authorization] Route required privileges: fleet-settings-read AND integrations-read.",
|
|
||||||
"operationId": "get-fleet-remote-synced-integrations-outputid-remote-status",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"in": "path",
|
|
||||||
"name": "outputId",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"content": {
|
|
||||||
"application/json": {
|
|
||||||
"schema": {
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"custom_assets": {
|
|
||||||
"additionalProperties": {
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"error": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"is_deleted": {
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"package_name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"package_version": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"sync_status": {
|
|
||||||
"enum": [
|
|
||||||
"completed",
|
|
||||||
"synchronizing",
|
|
||||||
"failed",
|
|
||||||
"warning"
|
|
||||||
],
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"type": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"type",
|
|
||||||
"name",
|
|
||||||
"package_name",
|
|
||||||
"package_version",
|
|
||||||
"sync_status"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"error": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"integrations": {
|
|
||||||
"items": {
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"error": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"install_status": {
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"main": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"remote": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"main"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"package_name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"package_version": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"sync_status": {
|
|
||||||
"enum": [
|
|
||||||
"completed",
|
|
||||||
"synchronizing",
|
|
||||||
"failed",
|
|
||||||
"warning"
|
|
||||||
],
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"warning": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"sync_status",
|
|
||||||
"install_status"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"type": "array"
|
|
||||||
},
|
|
||||||
"warning": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"integrations"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"content": {
|
|
||||||
"application/json": {
|
|
||||||
"schema": {
|
|
||||||
"additionalProperties": false,
|
|
||||||
"description": "Generic Error",
|
|
||||||
"properties": {
|
|
||||||
"attributes": {},
|
|
||||||
"error": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"errorType": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"message": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"statusCode": {
|
|
||||||
"type": "number"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"message",
|
|
||||||
"attributes"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"summary": "Get CCR Remote synced integrations status by outputId",
|
|
||||||
"tags": [
|
|
||||||
"CCR Remote synced integrations"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/fleet/service_tokens": {
|
"/api/fleet/service_tokens": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "[Required authorization] Route required privileges: fleet-agents-all.",
|
"description": "[Required authorization] Route required privileges: fleet-agents-all.",
|
||||||
|
@ -58703,9 +58370,6 @@
|
||||||
{
|
{
|
||||||
"name": "alerting"
|
"name": "alerting"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "CCR Remote synced integrations"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "connectors"
|
"name": "connectors"
|
||||||
},
|
},
|
||||||
|
|
|
@ -44288,339 +44288,6 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/api/fleet/remote_synced_integrations/status": {
|
|
||||||
"get": {
|
|
||||||
"description": "[Required authorization] Route required privileges: fleet-settings-read AND integrations-read.",
|
|
||||||
"operationId": "get-fleet-remote-synced-integrations-status",
|
|
||||||
"parameters": [],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"content": {
|
|
||||||
"application/json": {
|
|
||||||
"schema": {
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"custom_assets": {
|
|
||||||
"additionalProperties": {
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"error": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"is_deleted": {
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"package_name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"package_version": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"sync_status": {
|
|
||||||
"enum": [
|
|
||||||
"completed",
|
|
||||||
"synchronizing",
|
|
||||||
"failed",
|
|
||||||
"warning"
|
|
||||||
],
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"type": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"type",
|
|
||||||
"name",
|
|
||||||
"package_name",
|
|
||||||
"package_version",
|
|
||||||
"sync_status"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"error": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"integrations": {
|
|
||||||
"items": {
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"error": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"install_status": {
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"main": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"remote": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"main"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"package_name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"package_version": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"sync_status": {
|
|
||||||
"enum": [
|
|
||||||
"completed",
|
|
||||||
"synchronizing",
|
|
||||||
"failed",
|
|
||||||
"warning"
|
|
||||||
],
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"warning": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"sync_status",
|
|
||||||
"install_status"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"type": "array"
|
|
||||||
},
|
|
||||||
"warning": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"integrations"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"content": {
|
|
||||||
"application/json": {
|
|
||||||
"schema": {
|
|
||||||
"additionalProperties": false,
|
|
||||||
"description": "Generic Error",
|
|
||||||
"properties": {
|
|
||||||
"attributes": {},
|
|
||||||
"error": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"errorType": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"message": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"statusCode": {
|
|
||||||
"type": "number"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"message",
|
|
||||||
"attributes"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"summary": "Get CCR Remote synced integrations status",
|
|
||||||
"tags": [
|
|
||||||
"CCR Remote synced integrations"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/fleet/remote_synced_integrations/{outputId}/remote_status": {
|
|
||||||
"get": {
|
|
||||||
"description": "[Required authorization] Route required privileges: fleet-settings-read AND integrations-read.",
|
|
||||||
"operationId": "get-fleet-remote-synced-integrations-outputid-remote-status",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"in": "path",
|
|
||||||
"name": "outputId",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"content": {
|
|
||||||
"application/json": {
|
|
||||||
"schema": {
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"custom_assets": {
|
|
||||||
"additionalProperties": {
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"error": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"is_deleted": {
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"package_name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"package_version": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"sync_status": {
|
|
||||||
"enum": [
|
|
||||||
"completed",
|
|
||||||
"synchronizing",
|
|
||||||
"failed",
|
|
||||||
"warning"
|
|
||||||
],
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"type": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"type",
|
|
||||||
"name",
|
|
||||||
"package_name",
|
|
||||||
"package_version",
|
|
||||||
"sync_status"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"error": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"integrations": {
|
|
||||||
"items": {
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"error": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"install_status": {
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"main": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"remote": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"main"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"package_name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"package_version": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"sync_status": {
|
|
||||||
"enum": [
|
|
||||||
"completed",
|
|
||||||
"synchronizing",
|
|
||||||
"failed",
|
|
||||||
"warning"
|
|
||||||
],
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"updated_at": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"warning": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"sync_status",
|
|
||||||
"install_status"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"type": "array"
|
|
||||||
},
|
|
||||||
"warning": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"integrations"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"content": {
|
|
||||||
"application/json": {
|
|
||||||
"schema": {
|
|
||||||
"additionalProperties": false,
|
|
||||||
"description": "Generic Error",
|
|
||||||
"properties": {
|
|
||||||
"attributes": {},
|
|
||||||
"error": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"errorType": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"message": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"statusCode": {
|
|
||||||
"type": "number"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"message",
|
|
||||||
"attributes"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"summary": "Get CCR Remote synced integrations status by outputId",
|
|
||||||
"tags": [
|
|
||||||
"CCR Remote synced integrations"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/fleet/service_tokens": {
|
"/api/fleet/service_tokens": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "[Required authorization] Route required privileges: fleet-agents-all.",
|
"description": "[Required authorization] Route required privileges: fleet-agents-all.",
|
||||||
|
@ -58294,9 +57961,6 @@
|
||||||
{
|
{
|
||||||
"name": "alerting"
|
"name": "alerting"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "CCR Remote synced integrations"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "connectors"
|
"name": "connectors"
|
||||||
},
|
},
|
||||||
|
|
|
@ -66,7 +66,6 @@ tags:
|
||||||
Configure APM source maps. A source map allows minified files to be mapped back to original source code--allowing you to maintain the speed advantage of minified code, without losing the ability to quickly and easily debug your application.
|
Configure APM source maps. A source map allows minified files to be mapped back to original source code--allowing you to maintain the speed advantage of minified code, without losing the ability to quickly and easily debug your application.
|
||||||
For best results, uploading source maps should become a part of your deployment procedure, and not something you only do when you see unhelpful errors. That's because uploading source maps after errors happen won't make old errors magically readable--errors must occur again for source mapping to occur.
|
For best results, uploading source maps should become a part of your deployment procedure, and not something you only do when you see unhelpful errors. That's because uploading source maps after errors happen won't make old errors magically readable--errors must occur again for source mapping to occur.
|
||||||
name: APM sourcemaps
|
name: APM sourcemaps
|
||||||
- name: CCR Remote synced integrations
|
|
||||||
- name: connectors
|
- name: connectors
|
||||||
description: |
|
description: |
|
||||||
Connectors provide a central place to store connection information for services and integrations with Elastic or third party systems. Alerting rules can use connectors to run actions when rule conditions are met.
|
Connectors provide a central place to store connection information for services and integrations with Elastic or third party systems. Alerting rules can use connectors to run actions when rule conditions are met.
|
||||||
|
@ -39060,233 +39059,6 @@ paths:
|
||||||
summary: Update a proxy
|
summary: Update a proxy
|
||||||
tags:
|
tags:
|
||||||
- Fleet proxies
|
- Fleet proxies
|
||||||
/api/fleet/remote_synced_integrations/{outputId}/remote_status:
|
|
||||||
get:
|
|
||||||
description: '[Required authorization] Route required privileges: fleet-settings-read AND integrations-read.'
|
|
||||||
operationId: get-fleet-remote-synced-integrations-outputid-remote-status
|
|
||||||
parameters:
|
|
||||||
- in: path
|
|
||||||
name: outputId
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
responses:
|
|
||||||
'200':
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
additionalProperties: false
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
custom_assets:
|
|
||||||
additionalProperties:
|
|
||||||
additionalProperties: false
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
error:
|
|
||||||
type: string
|
|
||||||
is_deleted:
|
|
||||||
type: boolean
|
|
||||||
name:
|
|
||||||
type: string
|
|
||||||
package_name:
|
|
||||||
type: string
|
|
||||||
package_version:
|
|
||||||
type: string
|
|
||||||
sync_status:
|
|
||||||
enum:
|
|
||||||
- completed
|
|
||||||
- synchronizing
|
|
||||||
- failed
|
|
||||||
- warning
|
|
||||||
type: string
|
|
||||||
type:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- type
|
|
||||||
- name
|
|
||||||
- package_name
|
|
||||||
- package_version
|
|
||||||
- sync_status
|
|
||||||
type: object
|
|
||||||
error:
|
|
||||||
type: string
|
|
||||||
integrations:
|
|
||||||
items:
|
|
||||||
additionalProperties: false
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
error:
|
|
||||||
type: string
|
|
||||||
id:
|
|
||||||
type: string
|
|
||||||
install_status:
|
|
||||||
additionalProperties: false
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
main:
|
|
||||||
type: string
|
|
||||||
remote:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- main
|
|
||||||
package_name:
|
|
||||||
type: string
|
|
||||||
package_version:
|
|
||||||
type: string
|
|
||||||
sync_status:
|
|
||||||
enum:
|
|
||||||
- completed
|
|
||||||
- synchronizing
|
|
||||||
- failed
|
|
||||||
- warning
|
|
||||||
type: string
|
|
||||||
updated_at:
|
|
||||||
type: string
|
|
||||||
warning:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- sync_status
|
|
||||||
- install_status
|
|
||||||
type: array
|
|
||||||
warning:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- integrations
|
|
||||||
'400':
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
additionalProperties: false
|
|
||||||
description: Generic Error
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
attributes: {}
|
|
||||||
error:
|
|
||||||
type: string
|
|
||||||
errorType:
|
|
||||||
type: string
|
|
||||||
message:
|
|
||||||
type: string
|
|
||||||
statusCode:
|
|
||||||
type: number
|
|
||||||
required:
|
|
||||||
- message
|
|
||||||
- attributes
|
|
||||||
summary: Get CCR Remote synced integrations status by outputId
|
|
||||||
tags:
|
|
||||||
- CCR Remote synced integrations
|
|
||||||
/api/fleet/remote_synced_integrations/status:
|
|
||||||
get:
|
|
||||||
description: '[Required authorization] Route required privileges: fleet-settings-read AND integrations-read.'
|
|
||||||
operationId: get-fleet-remote-synced-integrations-status
|
|
||||||
parameters: []
|
|
||||||
responses:
|
|
||||||
'200':
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
additionalProperties: false
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
custom_assets:
|
|
||||||
additionalProperties:
|
|
||||||
additionalProperties: false
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
error:
|
|
||||||
type: string
|
|
||||||
is_deleted:
|
|
||||||
type: boolean
|
|
||||||
name:
|
|
||||||
type: string
|
|
||||||
package_name:
|
|
||||||
type: string
|
|
||||||
package_version:
|
|
||||||
type: string
|
|
||||||
sync_status:
|
|
||||||
enum:
|
|
||||||
- completed
|
|
||||||
- synchronizing
|
|
||||||
- failed
|
|
||||||
- warning
|
|
||||||
type: string
|
|
||||||
type:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- type
|
|
||||||
- name
|
|
||||||
- package_name
|
|
||||||
- package_version
|
|
||||||
- sync_status
|
|
||||||
type: object
|
|
||||||
error:
|
|
||||||
type: string
|
|
||||||
integrations:
|
|
||||||
items:
|
|
||||||
additionalProperties: false
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
error:
|
|
||||||
type: string
|
|
||||||
id:
|
|
||||||
type: string
|
|
||||||
install_status:
|
|
||||||
additionalProperties: false
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
main:
|
|
||||||
type: string
|
|
||||||
remote:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- main
|
|
||||||
package_name:
|
|
||||||
type: string
|
|
||||||
package_version:
|
|
||||||
type: string
|
|
||||||
sync_status:
|
|
||||||
enum:
|
|
||||||
- completed
|
|
||||||
- synchronizing
|
|
||||||
- failed
|
|
||||||
- warning
|
|
||||||
type: string
|
|
||||||
updated_at:
|
|
||||||
type: string
|
|
||||||
warning:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- sync_status
|
|
||||||
- install_status
|
|
||||||
type: array
|
|
||||||
warning:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- integrations
|
|
||||||
'400':
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
additionalProperties: false
|
|
||||||
description: Generic Error
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
attributes: {}
|
|
||||||
error:
|
|
||||||
type: string
|
|
||||||
errorType:
|
|
||||||
type: string
|
|
||||||
message:
|
|
||||||
type: string
|
|
||||||
statusCode:
|
|
||||||
type: number
|
|
||||||
required:
|
|
||||||
- message
|
|
||||||
- attributes
|
|
||||||
summary: Get CCR Remote synced integrations status
|
|
||||||
tags:
|
|
||||||
- CCR Remote synced integrations
|
|
||||||
/api/fleet/service_tokens:
|
/api/fleet/service_tokens:
|
||||||
post:
|
post:
|
||||||
description: '[Required authorization] Route required privileges: fleet-agents-all.'
|
description: '[Required authorization] Route required privileges: fleet-agents-all.'
|
||||||
|
|
|
@ -80,7 +80,6 @@ tags:
|
||||||
description: Cases documentation
|
description: Cases documentation
|
||||||
url: https://www.elastic.co/docs/explore-analyze/alerts-cases/cases
|
url: https://www.elastic.co/docs/explore-analyze/alerts-cases/cases
|
||||||
x-displayName: Cases
|
x-displayName: Cases
|
||||||
- name: CCR Remote synced integrations
|
|
||||||
- name: connectors
|
- name: connectors
|
||||||
description: |
|
description: |
|
||||||
Connectors provide a central place to store connection information for services and integrations with Elastic or third party systems. Alerting rules can use connectors to run actions when rule conditions are met.
|
Connectors provide a central place to store connection information for services and integrations with Elastic or third party systems. Alerting rules can use connectors to run actions when rule conditions are met.
|
||||||
|
@ -41302,233 +41301,6 @@ paths:
|
||||||
summary: Update a proxy
|
summary: Update a proxy
|
||||||
tags:
|
tags:
|
||||||
- Fleet proxies
|
- Fleet proxies
|
||||||
/api/fleet/remote_synced_integrations/{outputId}/remote_status:
|
|
||||||
get:
|
|
||||||
description: '[Required authorization] Route required privileges: fleet-settings-read AND integrations-read.'
|
|
||||||
operationId: get-fleet-remote-synced-integrations-outputid-remote-status
|
|
||||||
parameters:
|
|
||||||
- in: path
|
|
||||||
name: outputId
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
responses:
|
|
||||||
'200':
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
additionalProperties: false
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
custom_assets:
|
|
||||||
additionalProperties:
|
|
||||||
additionalProperties: false
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
error:
|
|
||||||
type: string
|
|
||||||
is_deleted:
|
|
||||||
type: boolean
|
|
||||||
name:
|
|
||||||
type: string
|
|
||||||
package_name:
|
|
||||||
type: string
|
|
||||||
package_version:
|
|
||||||
type: string
|
|
||||||
sync_status:
|
|
||||||
enum:
|
|
||||||
- completed
|
|
||||||
- synchronizing
|
|
||||||
- failed
|
|
||||||
- warning
|
|
||||||
type: string
|
|
||||||
type:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- type
|
|
||||||
- name
|
|
||||||
- package_name
|
|
||||||
- package_version
|
|
||||||
- sync_status
|
|
||||||
type: object
|
|
||||||
error:
|
|
||||||
type: string
|
|
||||||
integrations:
|
|
||||||
items:
|
|
||||||
additionalProperties: false
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
error:
|
|
||||||
type: string
|
|
||||||
id:
|
|
||||||
type: string
|
|
||||||
install_status:
|
|
||||||
additionalProperties: false
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
main:
|
|
||||||
type: string
|
|
||||||
remote:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- main
|
|
||||||
package_name:
|
|
||||||
type: string
|
|
||||||
package_version:
|
|
||||||
type: string
|
|
||||||
sync_status:
|
|
||||||
enum:
|
|
||||||
- completed
|
|
||||||
- synchronizing
|
|
||||||
- failed
|
|
||||||
- warning
|
|
||||||
type: string
|
|
||||||
updated_at:
|
|
||||||
type: string
|
|
||||||
warning:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- sync_status
|
|
||||||
- install_status
|
|
||||||
type: array
|
|
||||||
warning:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- integrations
|
|
||||||
'400':
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
additionalProperties: false
|
|
||||||
description: Generic Error
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
attributes: {}
|
|
||||||
error:
|
|
||||||
type: string
|
|
||||||
errorType:
|
|
||||||
type: string
|
|
||||||
message:
|
|
||||||
type: string
|
|
||||||
statusCode:
|
|
||||||
type: number
|
|
||||||
required:
|
|
||||||
- message
|
|
||||||
- attributes
|
|
||||||
summary: Get CCR Remote synced integrations status by outputId
|
|
||||||
tags:
|
|
||||||
- CCR Remote synced integrations
|
|
||||||
/api/fleet/remote_synced_integrations/status:
|
|
||||||
get:
|
|
||||||
description: '[Required authorization] Route required privileges: fleet-settings-read AND integrations-read.'
|
|
||||||
operationId: get-fleet-remote-synced-integrations-status
|
|
||||||
parameters: []
|
|
||||||
responses:
|
|
||||||
'200':
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
additionalProperties: false
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
custom_assets:
|
|
||||||
additionalProperties:
|
|
||||||
additionalProperties: false
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
error:
|
|
||||||
type: string
|
|
||||||
is_deleted:
|
|
||||||
type: boolean
|
|
||||||
name:
|
|
||||||
type: string
|
|
||||||
package_name:
|
|
||||||
type: string
|
|
||||||
package_version:
|
|
||||||
type: string
|
|
||||||
sync_status:
|
|
||||||
enum:
|
|
||||||
- completed
|
|
||||||
- synchronizing
|
|
||||||
- failed
|
|
||||||
- warning
|
|
||||||
type: string
|
|
||||||
type:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- type
|
|
||||||
- name
|
|
||||||
- package_name
|
|
||||||
- package_version
|
|
||||||
- sync_status
|
|
||||||
type: object
|
|
||||||
error:
|
|
||||||
type: string
|
|
||||||
integrations:
|
|
||||||
items:
|
|
||||||
additionalProperties: false
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
error:
|
|
||||||
type: string
|
|
||||||
id:
|
|
||||||
type: string
|
|
||||||
install_status:
|
|
||||||
additionalProperties: false
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
main:
|
|
||||||
type: string
|
|
||||||
remote:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- main
|
|
||||||
package_name:
|
|
||||||
type: string
|
|
||||||
package_version:
|
|
||||||
type: string
|
|
||||||
sync_status:
|
|
||||||
enum:
|
|
||||||
- completed
|
|
||||||
- synchronizing
|
|
||||||
- failed
|
|
||||||
- warning
|
|
||||||
type: string
|
|
||||||
updated_at:
|
|
||||||
type: string
|
|
||||||
warning:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- sync_status
|
|
||||||
- install_status
|
|
||||||
type: array
|
|
||||||
warning:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- integrations
|
|
||||||
'400':
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
additionalProperties: false
|
|
||||||
description: Generic Error
|
|
||||||
type: object
|
|
||||||
properties:
|
|
||||||
attributes: {}
|
|
||||||
error:
|
|
||||||
type: string
|
|
||||||
errorType:
|
|
||||||
type: string
|
|
||||||
message:
|
|
||||||
type: string
|
|
||||||
statusCode:
|
|
||||||
type: number
|
|
||||||
required:
|
|
||||||
- message
|
|
||||||
- attributes
|
|
||||||
summary: Get CCR Remote synced integrations status
|
|
||||||
tags:
|
|
||||||
- CCR Remote synced integrations
|
|
||||||
/api/fleet/service_tokens:
|
/api/fleet/service_tokens:
|
||||||
post:
|
post:
|
||||||
description: '[Required authorization] Route required privileges: fleet-agents-all.'
|
description: '[Required authorization] Route required privileges: fleet-agents-all.'
|
||||||
|
|
|
@ -12,7 +12,7 @@ import type { Output } from '../../../../types';
|
||||||
import { createFleetTestRendererMock } from '../../../../../../mock';
|
import { createFleetTestRendererMock } from '../../../../../../mock';
|
||||||
import { useFleetStatus } from '../../../../../../hooks/use_fleet_status';
|
import { useFleetStatus } from '../../../../../../hooks/use_fleet_status';
|
||||||
import { ExperimentalFeaturesService } from '../../../../../../services';
|
import { ExperimentalFeaturesService } from '../../../../../../services';
|
||||||
import { useStartServices, sendPutOutput } from '../../../../hooks';
|
import { useStartServices, sendPutOutput, licenseService } from '../../../../hooks';
|
||||||
|
|
||||||
import { EditOutputFlyout } from '.';
|
import { EditOutputFlyout } from '.';
|
||||||
|
|
||||||
|
@ -99,6 +99,7 @@ describe('EditOutputFlyout', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockStartServices(false);
|
mockStartServices(false);
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
|
jest.spyOn(licenseService, 'isEnterprise').mockClear();
|
||||||
|
|
||||||
mockedUseFleetStatus.mockReturnValue({} as any);
|
mockedUseFleetStatus.mockReturnValue({} as any);
|
||||||
});
|
});
|
||||||
|
@ -322,10 +323,11 @@ describe('EditOutputFlyout', () => {
|
||||||
expect(utils.getByText('Additional setup required')).not.toBeNull();
|
expect(utils.getByText('Additional setup required')).not.toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render the flyout if the output provided is a remote ES output', async () => {
|
it('should render the flyout if the output provided is a remote ES output and license is at least enterprise', async () => {
|
||||||
jest
|
jest
|
||||||
.spyOn(ExperimentalFeaturesService, 'get')
|
.spyOn(ExperimentalFeaturesService, 'get')
|
||||||
.mockReturnValue({ enableSyncIntegrationsOnRemote: true } as any);
|
.mockReturnValue({ enableSyncIntegrationsOnRemote: true } as any);
|
||||||
|
jest.spyOn(licenseService, 'isEnterprise').mockReturnValue(true);
|
||||||
|
|
||||||
mockedUseFleetStatus.mockReturnValue({
|
mockedUseFleetStatus.mockReturnValue({
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
|
@ -380,10 +382,48 @@ describe('EditOutputFlyout', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not render the flyout if the output is a remote ES output and the license is not at least enterprise', async () => {
|
||||||
|
jest
|
||||||
|
.spyOn(ExperimentalFeaturesService, 'get')
|
||||||
|
.mockReturnValue({ enableSyncIntegrationsOnRemote: true } as any);
|
||||||
|
jest.spyOn(licenseService, 'isEnterprise').mockReturnValue(false);
|
||||||
|
|
||||||
|
mockedUseFleetStatus.mockReturnValue({
|
||||||
|
isLoading: false,
|
||||||
|
isReady: true,
|
||||||
|
isSecretsStorageEnabled: true,
|
||||||
|
} as any);
|
||||||
|
|
||||||
|
const { utils } = renderFlyout({
|
||||||
|
type: 'remote_elasticsearch',
|
||||||
|
name: 'remote es output',
|
||||||
|
id: 'outputR',
|
||||||
|
is_default: false,
|
||||||
|
is_default_monitoring: false,
|
||||||
|
kibana_url: 'http://localhost',
|
||||||
|
sync_integrations: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
remoteEsOutputLabels.forEach((label) => {
|
||||||
|
expect(utils.queryByLabelText(label)).not.toBeNull();
|
||||||
|
});
|
||||||
|
expect(utils.queryByTestId('serviceTokenCallout')).not.toBeNull();
|
||||||
|
|
||||||
|
expect(utils.queryByTestId('settingsOutputsFlyout.typeInput')?.textContent).toContain(
|
||||||
|
'Remote Elasticsearch'
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(utils.queryByTestId('serviceTokenSecretInput')).not.toBeNull();
|
||||||
|
|
||||||
|
expect(utils.queryByTestId('remoteClusterConfigurationCallout')).not.toBeInTheDocument();
|
||||||
|
expect(utils.queryByTestId('kibanaAPIKeyCallout')).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
it('should populate secret service token input with plain text value when editing remote ES output', async () => {
|
it('should populate secret service token input with plain text value when editing remote ES output', async () => {
|
||||||
jest
|
jest
|
||||||
.spyOn(ExperimentalFeaturesService, 'get')
|
.spyOn(ExperimentalFeaturesService, 'get')
|
||||||
.mockReturnValue({ enableSyncIntegrationsOnRemote: true } as any);
|
.mockReturnValue({ enableSyncIntegrationsOnRemote: true } as any);
|
||||||
|
jest.spyOn(licenseService, 'isEnterprise').mockReturnValue(true);
|
||||||
|
|
||||||
mockedUseFleetStatus.mockReturnValue({
|
mockedUseFleetStatus.mockReturnValue({
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
|
|
|
@ -27,7 +27,7 @@ import { MultiRowInput } from '../multi_row_input';
|
||||||
|
|
||||||
import { ExperimentalFeaturesService } from '../../../../services';
|
import { ExperimentalFeaturesService } from '../../../../services';
|
||||||
|
|
||||||
import { useStartServices } from '../../../../hooks';
|
import { licenseService, useStartServices } from '../../../../hooks';
|
||||||
|
|
||||||
import type { OutputFormInputsType } from './use_output_form';
|
import type { OutputFormInputsType } from './use_output_form';
|
||||||
import { SecretFormRow } from './output_form_secret_form_row';
|
import { SecretFormRow } from './output_form_secret_form_row';
|
||||||
|
@ -54,6 +54,8 @@ export const OutputFormRemoteEsSection: React.FunctionComponent<Props> = (props)
|
||||||
sslKey: false,
|
sslKey: false,
|
||||||
});
|
});
|
||||||
const { enableSyncIntegrationsOnRemote, enableSSLSecrets } = ExperimentalFeaturesService.get();
|
const { enableSyncIntegrationsOnRemote, enableSSLSecrets } = ExperimentalFeaturesService.get();
|
||||||
|
const enableSyncIntegrations = enableSyncIntegrationsOnRemote && licenseService.isEnterprise();
|
||||||
|
|
||||||
const [isRemoteClusterInstructionsOpen, setIsRemoteClusterInstructionsOpen] =
|
const [isRemoteClusterInstructionsOpen, setIsRemoteClusterInstructionsOpen] =
|
||||||
React.useState(false);
|
React.useState(false);
|
||||||
|
|
||||||
|
@ -208,7 +210,7 @@ export const OutputFormRemoteEsSection: React.FunctionComponent<Props> = (props)
|
||||||
onToggleSecretAndClearValue={onToggleSecretAndClearValue}
|
onToggleSecretAndClearValue={onToggleSecretAndClearValue}
|
||||||
/>
|
/>
|
||||||
<EuiSpacer size="m" />
|
<EuiSpacer size="m" />
|
||||||
{enableSyncIntegrationsOnRemote ? (
|
{enableSyncIntegrations ? (
|
||||||
<>
|
<>
|
||||||
<EuiFormRow
|
<EuiFormRow
|
||||||
fullWidth
|
fullWidth
|
||||||
|
|
|
@ -11,7 +11,7 @@ import { EuiBasicTable, EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiIconTip } f
|
||||||
import type { EuiBasicTableColumn } from '@elastic/eui';
|
import type { EuiBasicTableColumn } from '@elastic/eui';
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
|
|
||||||
import { useAuthz, useLink } from '../../../../hooks';
|
import { licenseService, useAuthz, useLink } from '../../../../hooks';
|
||||||
import type { Output } from '../../../../types';
|
import type { Output } from '../../../../types';
|
||||||
|
|
||||||
import { OutputHealth } from '../edit_output_flyout/output_health';
|
import { OutputHealth } from '../edit_output_flyout/output_health';
|
||||||
|
@ -57,6 +57,7 @@ export const OutputsTable: React.FunctionComponent<OutputsTableProps> = ({
|
||||||
const authz = useAuthz();
|
const authz = useAuthz();
|
||||||
const { getHref } = useLink();
|
const { getHref } = useLink();
|
||||||
const { enableSyncIntegrationsOnRemote } = ExperimentalFeaturesService.get();
|
const { enableSyncIntegrationsOnRemote } = ExperimentalFeaturesService.get();
|
||||||
|
const enableSyncIntegrations = enableSyncIntegrationsOnRemote && licenseService.isEnterprise();
|
||||||
|
|
||||||
const columns = useMemo((): Array<EuiBasicTableColumn<Output>> => {
|
const columns = useMemo((): Array<EuiBasicTableColumn<Output>> => {
|
||||||
return [
|
return [
|
||||||
|
@ -121,7 +122,7 @@ export const OutputsTable: React.FunctionComponent<OutputsTableProps> = ({
|
||||||
defaultMessage: 'Status',
|
defaultMessage: 'Status',
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
...(enableSyncIntegrationsOnRemote
|
...(enableSyncIntegrations
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
render: (output: Output) => <IntegrationSyncStatus output={output} />,
|
render: (output: Output) => <IntegrationSyncStatus output={output} />,
|
||||||
|
@ -180,7 +181,7 @@ export const OutputsTable: React.FunctionComponent<OutputsTableProps> = ({
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}, [deleteOutput, getHref, authz.fleet.allSettings, enableSyncIntegrationsOnRemote]);
|
}, [deleteOutput, getHref, authz.fleet.allSettings, enableSyncIntegrations]);
|
||||||
|
|
||||||
return <EuiBasicTable columns={columns} items={outputs} data-test-subj="settingsOutputsTable" />;
|
return <EuiBasicTable columns={columns} items={outputs} data-test-subj="settingsOutputsTable" />;
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,12 +15,15 @@ import { GetRemoteSyncedIntegrationsStatusResponseSchema } from '../../types/mod
|
||||||
|
|
||||||
import { GetRemoteSyncedIntegrationsInfoRequestSchema } from '../../types';
|
import { GetRemoteSyncedIntegrationsInfoRequestSchema } from '../../types';
|
||||||
|
|
||||||
|
import { canEnableSyncIntegrations } from '../../services/setup/fleet_synced_integrations';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getRemoteSyncedIntegrationsStatusHandler,
|
getRemoteSyncedIntegrationsStatusHandler,
|
||||||
getRemoteSyncedIntegrationsInfoHandler,
|
getRemoteSyncedIntegrationsInfoHandler,
|
||||||
} from './handler';
|
} from './handler';
|
||||||
|
|
||||||
export const registerRoutes = (router: FleetAuthzRouter) => {
|
export const registerRoutes = (router: FleetAuthzRouter) => {
|
||||||
|
if (canEnableSyncIntegrations()) {
|
||||||
router.versioned
|
router.versioned
|
||||||
.get({
|
.get({
|
||||||
path: REMOTE_SYNCED_INTEGRATIONS_API_ROUTES.STATUS_PATTERN,
|
path: REMOTE_SYNCED_INTEGRATIONS_API_ROUTES.STATUS_PATTERN,
|
||||||
|
@ -88,4 +91,5 @@ export const registerRoutes = (router: FleetAuthzRouter) => {
|
||||||
},
|
},
|
||||||
getRemoteSyncedIntegrationsInfoHandler
|
getRemoteSyncedIntegrationsInfoHandler
|
||||||
);
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -83,6 +83,7 @@ import {
|
||||||
} from './secrets';
|
} from './secrets';
|
||||||
import { findAgentlessPolicies } from './outputs/helpers';
|
import { findAgentlessPolicies } from './outputs/helpers';
|
||||||
import { patchUpdateDataWithRequireEncryptedAADFields } from './outputs/so_helpers';
|
import { patchUpdateDataWithRequireEncryptedAADFields } from './outputs/so_helpers';
|
||||||
|
import { canEnableSyncIntegrations } from './setup/fleet_synced_integrations';
|
||||||
|
|
||||||
type Nullable<T> = { [P in keyof T]: T[P] | null };
|
type Nullable<T> = { [P in keyof T]: T[P] | null };
|
||||||
|
|
||||||
|
@ -367,6 +368,18 @@ async function updateAgentPoliciesDataOutputId(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function validateRemoteSyncIntegrationsCanBeEnabled(output: Partial<NewOutput>) {
|
||||||
|
if (
|
||||||
|
output.type === outputType.RemoteElasticsearch &&
|
||||||
|
(output.sync_integrations === true || output.sync_uninstalled_integrations === true) &&
|
||||||
|
!canEnableSyncIntegrations()
|
||||||
|
) {
|
||||||
|
throw new OutputUnauthorizedError(
|
||||||
|
'Remote sync integrations require at least an Enterprise license.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class OutputService {
|
class OutputService {
|
||||||
private get encryptedSoClient() {
|
private get encryptedSoClient() {
|
||||||
return appContextService.getInternalUserSOClient(fakeRequest);
|
return appContextService.getInternalUserSOClient(fakeRequest);
|
||||||
|
@ -679,6 +692,8 @@ class OutputService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
validateRemoteSyncIntegrationsCanBeEnabled(output);
|
||||||
|
|
||||||
const id = options?.id ? outputIdToUuid(options.id) : SavedObjectsUtils.generateId();
|
const id = options?.id ? outputIdToUuid(options.id) : SavedObjectsUtils.generateId();
|
||||||
|
|
||||||
// Store secret values if enabled; if not, store plain text values
|
// Store secret values if enabled; if not, store plain text values
|
||||||
|
@ -1103,6 +1118,7 @@ class OutputService {
|
||||||
updateData.shipper = null;
|
updateData.shipper = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
validateRemoteSyncIntegrationsCanBeEnabled(data);
|
||||||
|
|
||||||
// Store secret values if enabled; if not, store plain text values
|
// Store secret values if enabled; if not, store plain text values
|
||||||
if (await isOutputSecretStorageEnabled(esClient, soClient)) {
|
if (await isOutputSecretStorageEnabled(esClient, soClient)) {
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { licenseService } from '../license';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
createCCSIndexPatterns,
|
createCCSIndexPatterns,
|
||||||
createOrUpdateFleetSyncedIntegrationsIndex,
|
createOrUpdateFleetSyncedIntegrationsIndex,
|
||||||
|
@ -66,14 +68,18 @@ describe('fleet_synced_integrations', () => {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create index if not exists', async () => {
|
describe('with Enterprise license', () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
jest.spyOn(licenseService, 'isEnterprise').mockReturnValue(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create index if does not exist', async () => {
|
||||||
mockExists.mockResolvedValue(false);
|
mockExists.mockResolvedValue(false);
|
||||||
|
|
||||||
await createOrUpdateFleetSyncedIntegrationsIndex(esClientMock);
|
await createOrUpdateFleetSyncedIntegrationsIndex(esClientMock);
|
||||||
|
|
||||||
expect(esClientMock.indices.create).toHaveBeenCalled();
|
expect(esClientMock.indices.create).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update index if older version exists', async () => {
|
it('should update index if older version exists', async () => {
|
||||||
mockExists.mockResolvedValue(true);
|
mockExists.mockResolvedValue(true);
|
||||||
mockGetMapping.mockResolvedValue({
|
mockGetMapping.mockResolvedValue({
|
||||||
|
@ -134,4 +140,45 @@ describe('fleet_synced_integrations', () => {
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with less than Enterprise license', () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
jest.spyOn(licenseService, 'isEnterprise').mockReturnValue(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not create index', async () => {
|
||||||
|
mockExists.mockResolvedValue(false);
|
||||||
|
jest.spyOn(licenseService, 'isEnterprise').mockReturnValue(false);
|
||||||
|
|
||||||
|
await createOrUpdateFleetSyncedIntegrationsIndex(esClientMock);
|
||||||
|
|
||||||
|
expect(esClientMock.indices.create).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not update index', async () => {
|
||||||
|
mockExists.mockResolvedValue(true);
|
||||||
|
mockGetMapping.mockResolvedValue({
|
||||||
|
'fleet-synced-integrations': {
|
||||||
|
mappings: {
|
||||||
|
_meta: {
|
||||||
|
version: '0.0',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await createOrUpdateFleetSyncedIntegrationsIndex(esClientMock);
|
||||||
|
|
||||||
|
expect(esClientMock.indices.putMapping).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not create index patterns for remote clusters', async () => {
|
||||||
|
await createCCSIndexPatterns(esClientMock, soClientMock, soImporterMock);
|
||||||
|
|
||||||
|
expect(soImporterMock.import).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
expect(soClientMock.updateObjectsSpaces).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -20,6 +20,7 @@ import {
|
||||||
indexPatternTypes,
|
indexPatternTypes,
|
||||||
} from '../epm/kibana/index_pattern/install';
|
} from '../epm/kibana/index_pattern/install';
|
||||||
import { SO_SEARCH_LIMIT } from '../../constants';
|
import { SO_SEARCH_LIMIT } from '../../constants';
|
||||||
|
import { licenseService } from '../license';
|
||||||
|
|
||||||
export const FLEET_SYNCED_INTEGRATIONS_INDEX_NAME = 'fleet-synced-integrations';
|
export const FLEET_SYNCED_INTEGRATIONS_INDEX_NAME = 'fleet-synced-integrations';
|
||||||
export const FLEET_SYNCED_INTEGRATIONS_CCR_INDEX_PREFIX = 'fleet-synced-integrations-ccr-*';
|
export const FLEET_SYNCED_INTEGRATIONS_CCR_INDEX_PREFIX = 'fleet-synced-integrations-ccr-*';
|
||||||
|
@ -64,10 +65,13 @@ export const FLEET_SYNCED_INTEGRATIONS_INDEX_CONFIG = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function createOrUpdateFleetSyncedIntegrationsIndex(esClient: ElasticsearchClient) {
|
export const canEnableSyncIntegrations = () => {
|
||||||
const { enableSyncIntegrationsOnRemote } = appContextService.getExperimentalFeatures();
|
const { enableSyncIntegrationsOnRemote } = appContextService.getExperimentalFeatures();
|
||||||
|
return enableSyncIntegrationsOnRemote && licenseService.isEnterprise();
|
||||||
|
};
|
||||||
|
|
||||||
if (!enableSyncIntegrationsOnRemote) {
|
export async function createOrUpdateFleetSyncedIntegrationsIndex(esClient: ElasticsearchClient) {
|
||||||
|
if (!canEnableSyncIntegrations()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,9 +137,7 @@ export async function createCCSIndexPatterns(
|
||||||
savedObjectsClient: SavedObjectsClientContract,
|
savedObjectsClient: SavedObjectsClientContract,
|
||||||
savedObjectsImporter: ISavedObjectsImporter
|
savedObjectsImporter: ISavedObjectsImporter
|
||||||
) {
|
) {
|
||||||
const { enableSyncIntegrationsOnRemote } = appContextService.getExperimentalFeatures();
|
if (!canEnableSyncIntegrations()) {
|
||||||
|
|
||||||
if (!enableSyncIntegrationsOnRemote) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,8 @@ import { appContextService } from '../../services/app_context';
|
||||||
|
|
||||||
import { getPackageSavedObjects } from '../../services/epm/packages/get';
|
import { getPackageSavedObjects } from '../../services/epm/packages/get';
|
||||||
|
|
||||||
|
import { licenseService } from '../../services/license';
|
||||||
|
|
||||||
import { installCustomAsset, getPipeline, getComponentTemplate } from './custom_assets';
|
import { installCustomAsset, getPipeline, getComponentTemplate } from './custom_assets';
|
||||||
import {
|
import {
|
||||||
getFollowerIndexInfo,
|
getFollowerIndexInfo,
|
||||||
|
@ -1640,6 +1642,7 @@ describe('getRemoteSyncedIntegrationsStatus', () => {
|
||||||
soClientMock = savedObjectsClientMock.create();
|
soClientMock = savedObjectsClientMock.create();
|
||||||
mockedLogger = loggerMock.create();
|
mockedLogger = loggerMock.create();
|
||||||
mockedAppContextService.getLogger.mockReturnValue(mockedLogger);
|
mockedAppContextService.getLogger.mockReturnValue(mockedLogger);
|
||||||
|
jest.spyOn(licenseService, 'isEnterprise').mockReturnValue(true);
|
||||||
|
|
||||||
(installCustomAsset as jest.Mock).mockClear();
|
(installCustomAsset as jest.Mock).mockClear();
|
||||||
});
|
});
|
||||||
|
@ -1657,6 +1660,17 @@ describe('getRemoteSyncedIntegrationsStatus', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should return empty integrations array if license is less than Enterprise', async () => {
|
||||||
|
jest
|
||||||
|
.spyOn(mockedAppContextService, 'getExperimentalFeatures')
|
||||||
|
.mockReturnValue({ enableSyncIntegrationsOnRemote: true } as any);
|
||||||
|
jest.spyOn(licenseService, 'isEnterprise').mockReturnValue(false);
|
||||||
|
|
||||||
|
expect(await getRemoteSyncedIntegrationsStatus(esClientMock, soClientMock)).toEqual({
|
||||||
|
integrations: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should return error if there is an error in getFollowerIndexInfo', async () => {
|
it('should return error if there is an error in getFollowerIndexInfo', async () => {
|
||||||
jest
|
jest
|
||||||
.spyOn(mockedAppContextService, 'getExperimentalFeatures')
|
.spyOn(mockedAppContextService, 'getExperimentalFeatures')
|
||||||
|
|
|
@ -34,6 +34,8 @@ import type {
|
||||||
} from '../../../common/types';
|
} from '../../../common/types';
|
||||||
import { SyncStatus } from '../../../common/types';
|
import { SyncStatus } from '../../../common/types';
|
||||||
|
|
||||||
|
import { canEnableSyncIntegrations } from '../../services/setup/fleet_synced_integrations';
|
||||||
|
|
||||||
import type { IntegrationsData, SyncIntegrationsData, CustomAssetsData } from './model';
|
import type { IntegrationsData, SyncIntegrationsData, CustomAssetsData } from './model';
|
||||||
import { getPipeline, getComponentTemplate, CUSTOM_ASSETS_PREFIX } from './custom_assets';
|
import { getPipeline, getComponentTemplate, CUSTOM_ASSETS_PREFIX } from './custom_assets';
|
||||||
import { getFollowerIndex } from './sync_integrations_on_remote';
|
import { getFollowerIndex } from './sync_integrations_on_remote';
|
||||||
|
@ -500,10 +502,9 @@ export const getRemoteSyncedIntegrationsStatus = async (
|
||||||
esClient: ElasticsearchClient,
|
esClient: ElasticsearchClient,
|
||||||
soClient: SavedObjectsClientContract
|
soClient: SavedObjectsClientContract
|
||||||
): Promise<GetRemoteSyncedIntegrationsStatusResponse> => {
|
): Promise<GetRemoteSyncedIntegrationsStatusResponse> => {
|
||||||
const { enableSyncIntegrationsOnRemote } = appContextService.getExperimentalFeatures();
|
|
||||||
const logger = appContextService.getLogger();
|
const logger = appContextService.getLogger();
|
||||||
|
|
||||||
if (!enableSyncIntegrationsOnRemote) {
|
if (!canEnableSyncIntegrations()) {
|
||||||
return { integrations: [] };
|
return { integrations: [] };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,8 @@ import type { Output } from '../../types';
|
||||||
|
|
||||||
import { FleetNotFoundError } from '../../errors';
|
import { FleetNotFoundError } from '../../errors';
|
||||||
|
|
||||||
|
import { licenseService } from '../../services/license';
|
||||||
|
|
||||||
import { getRemoteSyncedIntegrationsInfoByOutputId } from './get_remote_status';
|
import { getRemoteSyncedIntegrationsInfoByOutputId } from './get_remote_status';
|
||||||
|
|
||||||
jest.mock('../../services/app_context');
|
jest.mock('../../services/app_context');
|
||||||
|
@ -66,6 +68,7 @@ describe('getRemoteSyncedIntegrationsInfoByOutputId', () => {
|
||||||
soClientMock = savedObjectsClientMock.create();
|
soClientMock = savedObjectsClientMock.create();
|
||||||
mockedLogger = loggerMock.create();
|
mockedLogger = loggerMock.create();
|
||||||
mockedAppContextService.getLogger.mockReturnValue(mockedLogger);
|
mockedAppContextService.getLogger.mockReturnValue(mockedLogger);
|
||||||
|
jest.spyOn(licenseService, 'isEnterprise').mockReturnValue(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
@ -82,6 +85,17 @@ describe('getRemoteSyncedIntegrationsInfoByOutputId', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should return empty integrations array if license is not at least Enterprise', async () => {
|
||||||
|
jest
|
||||||
|
.spyOn(mockedAppContextService, 'getExperimentalFeatures')
|
||||||
|
.mockReturnValue({ enableSyncIntegrationsOnRemote: true } as any);
|
||||||
|
jest.spyOn(licenseService, 'isEnterprise').mockReturnValue(false);
|
||||||
|
|
||||||
|
expect(await getRemoteSyncedIntegrationsInfoByOutputId(soClientMock, 'remote1')).toEqual({
|
||||||
|
integrations: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should return response with error if the passed outputId is not found', async () => {
|
it('should return response with error if the passed outputId is not found', async () => {
|
||||||
jest
|
jest
|
||||||
.spyOn(mockedAppContextService, 'getExperimentalFeatures')
|
.spyOn(mockedAppContextService, 'getExperimentalFeatures')
|
||||||
|
|
|
@ -17,15 +17,15 @@ import { outputService } from '../../services';
|
||||||
import { FleetError, FleetNotFoundError } from '../../errors';
|
import { FleetError, FleetNotFoundError } from '../../errors';
|
||||||
|
|
||||||
import type { GetRemoteSyncedIntegrationsStatusResponse } from '../../../common/types';
|
import type { GetRemoteSyncedIntegrationsStatusResponse } from '../../../common/types';
|
||||||
|
import { canEnableSyncIntegrations } from '../../services/setup/fleet_synced_integrations';
|
||||||
|
|
||||||
export const getRemoteSyncedIntegrationsInfoByOutputId = async (
|
export const getRemoteSyncedIntegrationsInfoByOutputId = async (
|
||||||
soClient: SavedObjectsClientContract,
|
soClient: SavedObjectsClientContract,
|
||||||
outputId: string
|
outputId: string
|
||||||
): Promise<GetRemoteSyncedIntegrationsStatusResponse> => {
|
): Promise<GetRemoteSyncedIntegrationsStatusResponse> => {
|
||||||
const { enableSyncIntegrationsOnRemote } = appContextService.getExperimentalFeatures();
|
|
||||||
const logger = appContextService.getLogger();
|
const logger = appContextService.getLogger();
|
||||||
|
|
||||||
if (!enableSyncIntegrationsOnRemote) {
|
if (!canEnableSyncIntegrations()) {
|
||||||
return { integrations: [] };
|
return { integrations: [] };
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -16,23 +16,33 @@ import { loggingSystemMock } from '@kbn/core/server/mocks';
|
||||||
|
|
||||||
import { createAppContextStartContractMock, createMockPackageService } from '../../mocks';
|
import { createAppContextStartContractMock, createMockPackageService } from '../../mocks';
|
||||||
|
|
||||||
import { appContextService, outputService, packagePolicyService } from '../../services';
|
import { outputService } from '../../services/output';
|
||||||
|
import { packagePolicyService } from '../../services/package_policy';
|
||||||
|
import { appContextService } from '../../services/app_context';
|
||||||
|
|
||||||
|
import { licenseService } from '../../services/license';
|
||||||
|
|
||||||
import { SyncIntegrationsTask, TYPE, VERSION } from './sync_integrations_task';
|
import { SyncIntegrationsTask, TYPE, VERSION } from './sync_integrations_task';
|
||||||
|
|
||||||
jest.mock('../../services', () => ({
|
jest.mock('../../services/output', () => ({
|
||||||
appContextService: {
|
|
||||||
getExperimentalFeatures: jest.fn().mockReturnValue({ enableSyncIntegrationsOnRemote: true }),
|
|
||||||
start: jest.fn(),
|
|
||||||
},
|
|
||||||
outputService: {
|
outputService: {
|
||||||
list: jest.fn(),
|
list: jest.fn(),
|
||||||
},
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
jest.mock('../../services/package_policy', () => ({
|
||||||
packagePolicyService: {
|
packagePolicyService: {
|
||||||
list: jest.fn(),
|
list: jest.fn(),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
jest.mock('../../services/app_context', () => ({
|
||||||
|
appContextService: {
|
||||||
|
getExperimentalFeatures: jest.fn().mockReturnValue({ enableSyncIntegrationsOnRemote: true }),
|
||||||
|
start: jest.fn(),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
const mockOutputService = outputService as jest.Mocked<typeof outputService>;
|
const mockOutputService = outputService as jest.Mocked<typeof outputService>;
|
||||||
const mockPackagePolicyService = packagePolicyService as jest.Mocked<typeof packagePolicyService>;
|
const mockPackagePolicyService = packagePolicyService as jest.Mocked<typeof packagePolicyService>;
|
||||||
|
|
||||||
|
@ -156,6 +166,14 @@ describe('SyncIntegrationsTask', () => {
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('With at least Enterprise license', () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
jest.spyOn(licenseService, 'isEnterprise').mockReturnValue(true);
|
||||||
|
});
|
||||||
|
afterAll(() => {
|
||||||
|
jest.spyOn(licenseService, 'isEnterprise').mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
it('Should not run if task is outdated', async () => {
|
it('Should not run if task is outdated', async () => {
|
||||||
const result = await runTask({ ...MOCK_TASK_INSTANCE, id: 'old-id' });
|
const result = await runTask({ ...MOCK_TASK_INSTANCE, id: 'old-id' });
|
||||||
|
|
||||||
|
@ -355,7 +373,12 @@ describe('SyncIntegrationsTask', () => {
|
||||||
esClient.get.mockResolvedValue({
|
esClient.get.mockResolvedValue({
|
||||||
_source: {
|
_source: {
|
||||||
remote_es_hosts: [
|
remote_es_hosts: [
|
||||||
{ hosts: ['https://remote1:9200'], name: 'remote1', sync_integrations: true },
|
{
|
||||||
|
hosts: ['https://remote1:9200'],
|
||||||
|
name: 'remote1',
|
||||||
|
sync_integrations: true,
|
||||||
|
sync_uninstalled_integrations: false,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
} as any);
|
} as any);
|
||||||
|
@ -519,4 +542,145 @@ describe('SyncIntegrationsTask', () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('With less than Enterprise license', () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
jest.spyOn(licenseService, 'isEnterprise').mockReturnValue(false);
|
||||||
|
});
|
||||||
|
afterAll(() => {
|
||||||
|
jest.spyOn(licenseService, 'isEnterprise').mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should not create fleet-synced-integrations doc', async () => {
|
||||||
|
mockOutputService.list.mockResolvedValue({
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: 'remote_elasticsearch',
|
||||||
|
name: 'remote1',
|
||||||
|
hosts: ['https://remote1:9200'],
|
||||||
|
sync_integrations: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'remote_elasticsearch',
|
||||||
|
name: 'remote2',
|
||||||
|
hosts: ['https://remote2:9200'],
|
||||||
|
sync_integrations: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
} as any);
|
||||||
|
mockPackagePolicyService.list.mockResolvedValue({
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
package: {
|
||||||
|
name: 'filestream',
|
||||||
|
version: '1.1.0',
|
||||||
|
},
|
||||||
|
inputs: [
|
||||||
|
{
|
||||||
|
streams: [
|
||||||
|
{
|
||||||
|
vars: {
|
||||||
|
pipeline: {
|
||||||
|
value: 'filestream-pipeline1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
} as any);
|
||||||
|
await runTask();
|
||||||
|
|
||||||
|
expect(esClient.index).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should not save custom assets error', async () => {
|
||||||
|
mockOutputService.list.mockResolvedValue({
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: 'remote_elasticsearch',
|
||||||
|
name: 'remote1',
|
||||||
|
hosts: ['https://remote1:9200'],
|
||||||
|
sync_integrations: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
} as any);
|
||||||
|
esClient.ingest.getPipeline.mockRejectedValue(new Error('es error'));
|
||||||
|
await runTask();
|
||||||
|
|
||||||
|
expect(esClient.index).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should not index fleet-synced-integrations doc even if sync flag changed', async () => {
|
||||||
|
mockOutputService.list.mockResolvedValue({
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: 'remote_elasticsearch',
|
||||||
|
name: 'remote2',
|
||||||
|
hosts: ['https://remote2:9200'],
|
||||||
|
sync_integrations: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
} as any);
|
||||||
|
esClient.get.mockResolvedValue({
|
||||||
|
_source: {
|
||||||
|
remote_es_hosts: [
|
||||||
|
{ hosts: ['https://remote1:9200'], name: 'remote1', sync_integrations: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
} as any);
|
||||||
|
await runTask();
|
||||||
|
|
||||||
|
expect(esClient.index).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should mark removed integrations as uninstalled if uninstall syncing is enabled', async () => {
|
||||||
|
mockOutputService.list.mockResolvedValue({
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: 'remote_elasticsearch',
|
||||||
|
name: 'remote1',
|
||||||
|
hosts: ['https://remote1:9200'],
|
||||||
|
sync_integrations: true,
|
||||||
|
sync_uninstalled_integrations: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
} as any);
|
||||||
|
esClient.get.mockResolvedValue({
|
||||||
|
_source: {
|
||||||
|
remote_es_hosts: [
|
||||||
|
{ hosts: ['https://remote1:9200'], name: 'remote1', sync_integrations: false },
|
||||||
|
],
|
||||||
|
integrations: [
|
||||||
|
{
|
||||||
|
package_name: 'system',
|
||||||
|
package_version: '0.1.0',
|
||||||
|
updated_at: new Date().toISOString(),
|
||||||
|
install_status: 'installed',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
package_name: 'package-2',
|
||||||
|
package_version: '0.2.0',
|
||||||
|
updated_at: new Date().toISOString(),
|
||||||
|
install_status: 'installed',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
package_name: 'package-3',
|
||||||
|
package_version: '0.3.0',
|
||||||
|
updated_at: new Date().toISOString(),
|
||||||
|
install_status: 'installed',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
custom_assets: {},
|
||||||
|
custom_assets_error: {},
|
||||||
|
},
|
||||||
|
} as any);
|
||||||
|
await runTask();
|
||||||
|
|
||||||
|
expect(esClient.index).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -19,9 +19,12 @@ import { errors } from '@elastic/elasticsearch';
|
||||||
import { SO_SEARCH_LIMIT, outputType } from '../../../common/constants';
|
import { SO_SEARCH_LIMIT, outputType } from '../../../common/constants';
|
||||||
import type { NewRemoteElasticsearchOutput } from '../../../common/types';
|
import type { NewRemoteElasticsearchOutput } from '../../../common/types';
|
||||||
|
|
||||||
import { appContextService, outputService } from '../../services';
|
import { outputService } from '../../services';
|
||||||
import { getInstalledPackageSavedObjects } from '../../services/epm/packages/get';
|
import { getInstalledPackageSavedObjects } from '../../services/epm/packages/get';
|
||||||
import { FLEET_SYNCED_INTEGRATIONS_INDEX_NAME } from '../../services/setup/fleet_synced_integrations';
|
import {
|
||||||
|
FLEET_SYNCED_INTEGRATIONS_INDEX_NAME,
|
||||||
|
canEnableSyncIntegrations,
|
||||||
|
} from '../../services/setup/fleet_synced_integrations';
|
||||||
|
|
||||||
import { syncIntegrationsOnRemote } from './sync_integrations_on_remote';
|
import { syncIntegrationsOnRemote } from './sync_integrations_on_remote';
|
||||||
import { getCustomAssets } from './custom_assets';
|
import { getCustomAssets } from './custom_assets';
|
||||||
|
@ -123,9 +126,7 @@ export class SyncIntegrationsTask {
|
||||||
const esClient = coreStart.elasticsearch.client.asInternalUser;
|
const esClient = coreStart.elasticsearch.client.asInternalUser;
|
||||||
const soClient = new SavedObjectsClient(coreStart.savedObjects.createInternalRepository());
|
const soClient = new SavedObjectsClient(coreStart.savedObjects.createInternalRepository());
|
||||||
|
|
||||||
const { enableSyncIntegrationsOnRemote } = appContextService.getExperimentalFeatures();
|
if (!canEnableSyncIntegrations()) {
|
||||||
|
|
||||||
if (!enableSyncIntegrationsOnRemote) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -792,7 +792,7 @@ export default function (providerContext: FtrProviderContext) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should allow to update kibana_api_key on an existing remote_elasticsearch output', async function () {
|
it('should not allow to update kibana_api_key on an existing remote_elasticsearch output if the license is not at least enterprise', async function () {
|
||||||
const res = await supertest
|
const res = await supertest
|
||||||
.post(`/api/fleet/outputs`)
|
.post(`/api/fleet/outputs`)
|
||||||
.set('kbn-xsrf', 'xxxx')
|
.set('kbn-xsrf', 'xxxx')
|
||||||
|
@ -800,13 +800,11 @@ export default function (providerContext: FtrProviderContext) {
|
||||||
name: 'Remote Output With kibana_api_key',
|
name: 'Remote Output With kibana_api_key',
|
||||||
type: 'remote_elasticsearch',
|
type: 'remote_elasticsearch',
|
||||||
hosts: ['https://test.fr:443'],
|
hosts: ['https://test.fr:443'],
|
||||||
sync_integrations: true,
|
|
||||||
kibana_url: 'https://testhost',
|
kibana_url: 'https://testhost',
|
||||||
kibana_api_key: 'aaaa',
|
|
||||||
})
|
})
|
||||||
.expect(200);
|
.expect(200);
|
||||||
const outputId = res.body.item.id;
|
const outputId = res.body.item.id;
|
||||||
const updatedRes = await supertest
|
await supertest
|
||||||
.put(`/api/fleet/outputs/${outputId}`)
|
.put(`/api/fleet/outputs/${outputId}`)
|
||||||
.set('kbn-xsrf', 'xxxx')
|
.set('kbn-xsrf', 'xxxx')
|
||||||
.send({
|
.send({
|
||||||
|
@ -817,8 +815,7 @@ export default function (providerContext: FtrProviderContext) {
|
||||||
kibana_url: 'https://testhost',
|
kibana_url: 'https://testhost',
|
||||||
kibana_api_key: 'bbbb',
|
kibana_api_key: 'bbbb',
|
||||||
})
|
})
|
||||||
.expect(200);
|
.expect(400);
|
||||||
expect(updatedRes.body.item.kibana_api_key).to.equal('bbbb');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should bump all policies in all spaces if updating the default output', async () => {
|
it('should bump all policies in all spaces if updating the default output', async () => {
|
||||||
|
@ -1824,7 +1821,7 @@ export default function (providerContext: FtrProviderContext) {
|
||||||
.expect(200);
|
.expect(200);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should allow to create a new remote_elasticsearch output with kibana_api_key field', async function () {
|
it('should not allow to create a new remote_elasticsearch output with kibana_api_key if the license is not at least enterprise', async function () {
|
||||||
await supertest
|
await supertest
|
||||||
.post(`/api/fleet/outputs`)
|
.post(`/api/fleet/outputs`)
|
||||||
.set('kbn-xsrf', 'xxxx')
|
.set('kbn-xsrf', 'xxxx')
|
||||||
|
@ -1836,7 +1833,7 @@ export default function (providerContext: FtrProviderContext) {
|
||||||
kibana_url: 'https://testhost',
|
kibana_url: 'https://testhost',
|
||||||
kibana_api_key: 'aaaa',
|
kibana_api_key: 'aaaa',
|
||||||
})
|
})
|
||||||
.expect(200);
|
.expect(400);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue