Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Ingest Manager] Ingest setup upgrade #78081

Merged
merged 30 commits into from
Sep 28, 2020

Conversation

jonathan-buttner
Copy link
Contributor

@jonathan-buttner jonathan-buttner commented Sep 21, 2020

This PR refactors the /setup api to ensure that the default packages have the latest version installed. This way when a user navigates to the ingest manager app /setup will be called and it will perform an upgrade of the default packages if a later version exists.

This was chosen instead of having the UI perform a /packages/_bulk call on each tab that the user navigates to because that's a bit too frequent than necessary.

@jonathan-buttner jonathan-buttner added v8.0.0 release_note:skip Skip the PR/issue when compiling release notes v7.10.0 labels Sep 21, 2020
@jonathan-buttner jonathan-buttner added Feature:EPM Fleet team's Elastic Package Manager (aka Integrations) project Team:Fleet Team label for Observability Data Collection Fleet team labels Sep 22, 2020
@jonathan-buttner jonathan-buttner marked this pull request as ready for review September 22, 2020 19:10
@jonathan-buttner jonathan-buttner requested a review from a team September 22, 2020 19:10
@elasticmachine
Copy link
Contributor

Pinging @elastic/ingest-management (Feature:EPM)

} else {
// getInstallation can return undefined so we'll tack on the name so when we throw an error in setup we can
// reference the name of the package that we failed to retrieve the installation information for
const installation = getInstallationAndName(savedObjectsClient, resp.name);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be better to await the getInstallation call here? If we did then I wouldn't have to change the return value and would just check if the result was undefined and throw the error here instead of in setup.ts.

const supertest = getService('supertest');
const log = getService('log');

describe('setup api', async () => {
Copy link
Contributor

@jfsiii jfsiii Sep 22, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add some tests that show the failure case(s)? I'm unclear what we intend to be returned from a POST /setup that has a failed upgrade at some point. Is it a 2xx, 4xx, or 5xx response? What's in the response body?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah so adding the failure case might be tricky. Any ideas on how to trigger a failure? This is what comes to mind:

  1. Override the default packages variable used to define which packages are installed/updated during /setup so I can create a custom one and make it malformed. Is this possible with mocha?
  2. Use an invalid registry address so kibana fails to download the packages. I believe this would require creating a new x-pack/test directory because the tests in this directory all use the docker container registry
  3. Create a malformed endpoint package in this directory and make the version really big like 100000.0.0 so it's always the latest. The number needs to be large so it's unlikely to be superseded in production. The test would start failing as soon as we created a production package with version 100000.0.1 though 🤔

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we can map out the desired behavior I am happy to help with testing. I did a few different types recently working on Registry and /setup changes.

If this is run on every setup I really want to understand/document what it should/does do.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll have to do some digging to figure out what should be returned in each failure scenario. After thinking about this more, the code changes will currently swallow the error :( because of this:

if (isBulkInstallError(resp)) {
      throw new Error(resp.error);
    }

from here: https://github.com/elastic/kibana/pull/78081/files#diff-bae6a46773afa98cb0927abf59bdd003R93

That's probably not what we want but in the current state if an error occurs it will always 500 and the response body will look like this:

body: {
  message: "some error"
}

https://github.com/elastic/kibana/blob/master/x-pack/plugins/ingest_manager/server/errors/handlers.ts#L100

The success case will always return:
200

{
  isInitialized: true
}

For the error case we could probably create a new error class that is a child of IngestManagerError and modify this function: https://github.com/elastic/kibana/blob/master/x-pack/plugins/ingest_manager/server/errors/handlers.ts#L48

to extract out the passed in status code. That way we can preserve the status code and message that occurred when the upgrade/install failed for a package and return that as a response for /setup. That way the failure functionality will change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@skh @neptunian any ideas on how to force a failure scenario in /setup? Is there a way to mock out DefaultPackages so that I can craft a fake package that causes a failure when being installed?
https://github.com/elastic/kibana/blob/master/x-pack/plugins/ingest_manager/common/types/models/epm.ts#L265

@@ -6,7 +6,32 @@

import { ElasticsearchAssetType, Installation, KibanaAssetType } from '../../../types';
import { SavedObject } from 'src/core/server';
import { getInstallType } from './install';
jest.mock('./install', () => ({
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jfsiii any ideas what I'm doing wrong here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't at first, but I think we have it now. Take a look at jfsiii@a76006f

I'll add some comments over on that commit and I can submit a PR or you can pull in whatever you wish

Update I created jonathan-buttner#7

@@ -52,6 +57,9 @@ const getHTTPResponseCode = (error: IngestManagerError): number => {
if (error instanceof PackageNotFoundError) {
return 404; // Not Found
}
if (error instanceof BulkInstallPackagesError) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's ignore type here and test 'statusCode' in error

Maybe return 'statusCode' in error ? error.statusCode : 400

@@ -18,3 +18,9 @@ export class RegistryConnectionError extends RegistryError {}
export class RegistryResponseError extends RegistryError {}
export class PackageNotFoundError extends IngestManagerError {}
export class PackageOutdatedError extends IngestManagerError {}

export class BulkInstallPackagesError extends IngestManagerError {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We avoided this for RegistryResponse and the other types. I'd like to avoid it here if possible. At worst, I think it should be a single IBulkInstallError arg, but I'm hoping we can avoid all together

@@ -6,7 +6,32 @@

import { ElasticsearchAssetType, Installation, KibanaAssetType } from '../../../types';
import { SavedObject } from 'src/core/server';
import { getInstallType } from './install';
jest.mock('./install', () => ({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't at first, but I think we have it now. Take a look at jfsiii@a76006f

I'll add some comments over on that commit and I can submit a PR or you can pull in whatever you wish

Update I created jonathan-buttner#7


for (const resp of bulkResponse) {
if (isBulkInstallError(resp)) {
throw new BulkInstallPackagesError(resp.statusCode, resp.error);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: the guard only checks for error so statusCode could be missing here

Copy link
Contributor

@jfsiii jfsiii left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀 nice work. thanks for the collaboration. I learned a lot about Jest mocking and like how the tests turned out

@jonathan-buttner
Copy link
Contributor Author

@elasticmachine merge upstream

@kibanamachine
Copy link
Contributor

💚 Build Succeeded

Metrics [docs]

distributable file count

id value diff baseline
default 45672 +1 45671

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

@jonathan-buttner jonathan-buttner merged commit e75b36a into elastic:master Sep 28, 2020
@jonathan-buttner jonathan-buttner deleted the ingest-setup-upgrade branch September 28, 2020 20:12
jonathan-buttner added a commit to jonathan-buttner/kibana that referenced this pull request Sep 28, 2020
* Adding bulk upgrade api

* Addressing comments

* Removing todo

* Changing body field

* Adding helper for getting the bulk install route

* Adding request spec

* Pulling in Johns changes

* Removing test for same package upgraded multiple times

* Adding upgrade to setup route

* Adding setup integration test

* Clean up error handling

* Beginning to add tests

* Failing jest mock tests

* Break up tests & modules for easier testing.

Deal with issue described in jestjs/jest#1075 (comment)

epm/packages/install has functions a, b, c which are independent but a can also call b and c

function a() {
  b();
  c();
}

The linked FB issue describes the cause and rationale (Jest works on "module" boundary) but TL;DR: it's easier if you split up your files

Some related links I found during this journey

 * https://medium.com/@qjli/how-to-mock-specific-module-function-in-jest-715e39a391f4
  * https://stackoverflow.com/questions/52650367/jestjs-how-to-test-function-being-called-inside-another-function
   * https://stackoverflow.com/questions/50854440/spying-on-an-imported-function-that-calls-another-function-in-jest/50855968#50855968

* Add test confirming update error result will throw

* Keep orig error. Add status code in http handler

* Leave error as-is

* Removing accidental code changes. File rename.

* Missed a function when moving to a new file

* Add missing type imports

* Lift .map lambda into named outer function

* Adding additional test

* Fixing type error

Co-authored-by: John Schulz <john.schulz@elastic.co>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
jonathan-buttner added a commit that referenced this pull request Sep 28, 2020
* Adding bulk upgrade api

* Addressing comments

* Removing todo

* Changing body field

* Adding helper for getting the bulk install route

* Adding request spec

* Pulling in Johns changes

* Removing test for same package upgraded multiple times

* Adding upgrade to setup route

* Adding setup integration test

* Clean up error handling

* Beginning to add tests

* Failing jest mock tests

* Break up tests & modules for easier testing.

Deal with issue described in jestjs/jest#1075 (comment)

epm/packages/install has functions a, b, c which are independent but a can also call b and c

function a() {
  b();
  c();
}

The linked FB issue describes the cause and rationale (Jest works on "module" boundary) but TL;DR: it's easier if you split up your files

Some related links I found during this journey

 * https://medium.com/@qjli/how-to-mock-specific-module-function-in-jest-715e39a391f4
  * https://stackoverflow.com/questions/52650367/jestjs-how-to-test-function-being-called-inside-another-function
   * https://stackoverflow.com/questions/50854440/spying-on-an-imported-function-that-calls-another-function-in-jest/50855968#50855968

* Add test confirming update error result will throw

* Keep orig error. Add status code in http handler

* Leave error as-is

* Removing accidental code changes. File rename.

* Missed a function when moving to a new file

* Add missing type imports

* Lift .map lambda into named outer function

* Adding additional test

* Fixing type error

Co-authored-by: John Schulz <john.schulz@elastic.co>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>

Co-authored-by: John Schulz <john.schulz@elastic.co>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
phillipb added a commit to phillipb/kibana that referenced this pull request Sep 29, 2020
…a into add-anomalies-to-timeline

* 'add-anomalies-to-timeline' of github.com:phillipb/kibana: (89 commits)
  Aligns several module versions across the repository (elastic#78327)
  Empty prompt and loading spinner for service map (elastic#78382)
  Change progress bar to spinner (elastic#78460)
  [QA][Code Coverage] Coverage teams lookup w/o Additional Config (elastic#77111)
  Slim down core bundle (elastic#75912)
  [Alerting] retry internal OCC calls within alertsClient (elastic#77838)
  [kbn/optimizer] only build xpack examples when building xpack plugins (elastic#78656)
  [Ingest Manager] Ingest setup upgrade (elastic#78081)
  [Ingest Manager] Surface saved object client 10,000 limitation to bulk actions UI (elastic#78520)
  fix name without a category or if field end with .text (elastic#78655)
  [Security Solution] [Detections] Log message enhancements (elastic#78429)
  [ML]DF Analytics exploration: default filter of results page by `defaultIsTraining` value in url (elastic#78303)
  [Enterprise Search] Remove all instances of KibanaContext to Kea store (elastic#78513)
  [ML] DF Analytics creation: ensure job did not fail to start before showing results link (elastic#78200)
  fix createAppNavigationHandler to use `navigateToUrl` (elastic#78583)
  Fixing a11y test failure on discover app (elastic#59975) (elastic#77614)
  [Security Solution] Initiate endpoint package upgrade from security app (elastic#77498)
  [kbn/es] use a basic build process (elastic#78090)
  [kbn/optimizer] fix .json extension handling (elastic#78524)
  Fix APM lodash imports (elastic#78438)
  ...
gmmorris added a commit to gmmorris/kibana that referenced this pull request Sep 29, 2020
* master: (365 commits)
  making expression debug info serializable (elastic#78727)
  fix lodahs imports in app-arch code (elastic#78582)
  Make Field a React.lazy export (elastic#78483)
  [Security Solution] Improves detections tests (elastic#77295)
  [TSVB] Different field format on different series is ignored (elastic#78138)
  RFC: Improve saved object migrations (elastic#66056)
  [Security Solution] Fixes url timeline flaky test (elastic#78556)
  adds retryability feature (elastic#78611)
  Aligns several module versions across the repository (elastic#78327)
  Empty prompt and loading spinner for service map (elastic#78382)
  Change progress bar to spinner (elastic#78460)
  [QA][Code Coverage] Coverage teams lookup w/o Additional Config (elastic#77111)
  Slim down core bundle (elastic#75912)
  [Alerting] retry internal OCC calls within alertsClient (elastic#77838)
  [kbn/optimizer] only build xpack examples when building xpack plugins (elastic#78656)
  [Ingest Manager] Ingest setup upgrade (elastic#78081)
  [Ingest Manager] Surface saved object client 10,000 limitation to bulk actions UI (elastic#78520)
  fix name without a category or if field end with .text (elastic#78655)
  [Security Solution] [Detections] Log message enhancements (elastic#78429)
  [ML]DF Analytics exploration: default filter of results page by `defaultIsTraining` value in url (elastic#78303)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature:EPM Fleet team's Elastic Package Manager (aka Integrations) project release_note:skip Skip the PR/issue when compiling release notes Team:Fleet Team label for Observability Data Collection Fleet team v7.10.0 v8.0.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants