elastic / kibana

Your window into the Elastic Stack
https://www.elastic.co/products/kibana
Other
19.72k stars 8.14k forks source link

Prototype: API for creating an integration #158552

Closed weltenwort closed 1 year ago

weltenwort commented 1 year ago

:notebook: Summary

While we're still figuring out the exact specification of the initial integration creation API, we could already learn about the library functions available in fleet by writing a prototype of the API.

:heavy_check_mark: Acceptance criteria

elasticmachine commented 1 year ago

Pinging @elastic/infra-monitoring-ui (Team:Infra Monitoring UI)

weltenwort commented 1 year ago

:information_source: WIP follow-up implementation issue: https://github.com/elastic/kibana/issues/159991

Kerry350 commented 1 year ago

Findings

(It's also worth looking at Kyle's brain dump: https://gist.github.com/kpollich/f2ed8f4db2d5c380b8cc4e5bf4537825)

Security concerns

fleetAuthz: {
    integrations: { installPackages: true },
}
const user = (await appContextService.getSecurity()?.authc.getCurrentUser(request)) || undefined;

const authorizationHeader = HTTPAuthorizationHeader.parseFromRequest(request, user?.username);

Install methods

const savedObjectsImporter = appContextServic
.getSavedObjects()
.createImporter(savedObjectsClient, { importSizeLimit: 15_000 });

const savedObjectTagAssignmentService = appContextService
.getSavedObjectsTagging()
.createInternalAssignmentService({ client: savedObjectsClient });

const savedObjectTagClient = appContextService
.getSavedObjectsTagging()
.createTagClient({ client: savedObjectsClient });

What do we need?

Paths

I've put a section here on paths specifically as it's very critical to the overall way installation works, and almost every helper function expects these. And because our "custom" integrations won't have a set of paths and assets that are pulled from the registry archive (or from the zip archive in the upload scenario) we need to consider how to best create interoperability. For our basic custom integrations we'll know what index templates and datastreams we want to create upfront, we can more or less hardcode these with a few variables that get changed in a template / interpolation type manner.

How these work in a "from registry" scenario:

Examples

This is an example of paths:

[

   "elastic_agent-1.8.0/LICENSE.txt",

   "elastic_agent-1.8.0/changelog.yml",

   "elastic_agent-1.8.0/data_stream/apm_server_logs/fields/agent.yml",

   "elastic_agent-1.8.0/data_stream/apm_server_logs/fields/base-fields.yml",

   "elastic_agent-1.8.0/data_stream/apm_server_logs/fields/ecs.yml",

   "elastic_agent-1.8.0/data_stream/apm_server_logs/fields/fields.yml",

   "elastic_agent-1.8.0/data_stream/apm_server_logs/manifest.yml",

   "elastic_agent-1.8.0/data_stream/apm_server_metrics/fields/agent.yml",

   "elastic_agent-1.8.0/data_stream/apm_server_metrics/fields/base-fields.yml",

   "elastic_agent-1.8.0/data_stream/apm_server_metrics/fields/beat-fields.yml",

   "elastic_agent-1.8.0/data_stream/apm_server_metrics/fields/ecs.yml",
]

This is an example of packageInfo:

{
   "name":"elastic_agent",
   "version":"1.8.0",
   "description":"Collect logs and metrics from Elastic Agents.",
   "title":"Elastic Agent",
   "format_version":"1.0.0",
   "owner":{
      "github":"elastic/elastic-agent"
   },
   "license":"basic",
   "type":"integration",
   "categories":[
      "elastic_stack"
   ],
   "conditions":{
      "kibana.version":"^8.7.1"
   },
   "screenshots":[
      {
         "src":"/img/elastic_agent_overview.png",
         "title":"Elastic Agent Overview",
         "size":"2560×1234",
         "type":"image/png"
      },
      {
         "src":"/img/elastic_agent_metrics.png",
         "title":"Elastic Agent Metrics",
         "size":"2560×1234",
         "type":"image/png"
      },
      {
         "src":"/img/elastic_agent_info.png",
         "title":"Elastic Agent Information",
         "size":"2560×1234",
         "type":"image/png"
      },
      {
         "src":"/img/elastic_agent_integrations.png",
         "title":"Elastic Agent Integrations",
         "size":"2560×1234",
         "type":"image/png"
      }
   ],
   "icons":[
      {
         "src":"/img/logo_elastic_agent.svg",
         "title":"logo Elastic Agent",
         "size":"64x64",
         "type":"image/svg+xml"
      }
   ],
   "data_streams":[
      {
         "title":"Elastic Agent",
         "release":"ga",
         "type":"logs",
         "package":"elastic_agent",
         "dataset":"elastic_agent.apm_server",
         "path":"apm_server_logs",
         "elasticsearch":{
            "index_template.mappings":{
               "dynamic":false
            }
         }
      },
      {
         "title":"Elastic Agent",
         "release":"ga",
         "type":"metrics",
         "package":"elastic_agent",
         "dataset":"elastic_agent.apm_server",
         "path":"apm_server_metrics",
         "elasticsearch":{
            "index_template.mappings":{
               "dynamic":false
            }
         }
      },
   ],
   "policy_templates":[

   ],
   "readme":"/package/elastic_agent/1.8.0/docs/README.md",
   "release":"ga"
}

Prototype

Draft PR with rough prototype code: https://github.com/elastic/kibana/pull/160003

Calling prototype API

You should be able to use a CURL command similar to the following:

curl -XPOST -u 'elastic:changeme' -H 'kbn-xsrf: something' -d '{
    "name": "my_integration",
    "dataset": "test.test",
    "type": "logs",
    "description": "Custom integration via the API"
}' 'http://localhost:5601/<BASE_PATH>/api/fleet/epm/custom_integrations'

Results

Hitting the API will produce the following epm-packages installation Saved Object:

{
   "_index":".kibana_ingest_8.9.0_001",
   "_id":"epm-packages:my_integration",
   "_score":3.2696838,
   "_source":{
      "epm-packages":{
         "installed_kibana":[

         ],
         "installed_kibana_space_id":"default",
         "installed_es":[
            {
               "id":"logs-test.test-1.0.0",
               "type":"ingest_pipeline"
            },
            {
               "id":"logs-test.test",
               "type":"index_template"
            },
            {
               "id":"logs-test.test@package",
               "type":"component_template"
            },
            {
               "id":"logs-test.test@custom",
               "type":"component_template"
            }
         ],
         "package_assets":[
            {
               "id":"ab9e295a-520d-599d-a469-49a81aed1842",
               "type":"epm-packages-assets"
            },
            {
               "id":"ac57f446-bde4-5a17-a10f-0ee4384e8c59",
               "type":"epm-packages-assets"
            },
            {
               "id":"0fae5f7e-ea49-516e-8126-8fc36f247182",
               "type":"epm-packages-assets"
            }
         ],
         "es_index_patterns":{
            "test.test":"logs-test.test-*"
         },
         "name":"my_integration",
         "version":"1.0.0",
         "install_version":"1.0.0",
         "install_status":"installed",
         "install_started_at":"2023-06-20T11:32:09.777Z",
         "install_source":"custom",
         "install_format_schema_version":"1.0.0",
         "verification_status":"unknown"
      },
      "type":"epm-packages",
      "references":[

      ],
      "managed":false,
      "coreMigrationVersion":"8.8.0",
      "typeMigrationVersion":"8.6.0",
      "updated_at":"2023-06-20T11:32:10.603Z",
      "created_at":"2023-06-20T11:32:09.777Z"
   }

It will also produce our minimal assets:

Screenshot 2023-06-20 at 13 04 15

And show up on the installed integrations page (however, with a verification warning at the moment):

Screenshot 2023-06-20 at 13 04 35

It will also be returned from the fleet/epm/packages/installed endpoint, e.g:

{
   "name":"my_integration",
   "version":"1.0.0",
   "status":"installed",
   "dataStreams":[
      {
         "name":"logs-test.test-*",
         "title":"test.test"
      }
   ]
},
Kerry350 commented 1 year ago

Closing as we've finished the prototype work and investigations.