Skip to content

Commit

Permalink
[Ingest Manager] Improve agent vs kibana version checks (#76238) (#76490
Browse files Browse the repository at this point in the history
)

* Add logic spec'd in issue comments. Tests pass.

* Change fn to accept 1 (opt 2) string vs object

* Add tests based on issue comments

* Change expected error message in test

* Capitalize Kibana in error message

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
  • Loading branch information
John Schulz and elasticmachine authored Sep 3, 2020
1 parent 70be440 commit 5beb515
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 58 deletions.
70 changes: 30 additions & 40 deletions x-pack/plugins/ingest_manager/server/services/agents/enroll.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,62 +5,52 @@
*/

import { validateAgentVersion } from './enroll';
import { appContextService } from '../app_context';
import { IngestManagerAppContext } from '../../plugin';

describe('validateAgentVersion', () => {
it('should throw with agent > kibana version', () => {
appContextService.start(({
kibanaVersion: '8.0.0',
} as unknown) as IngestManagerAppContext);
expect(() =>
validateAgentVersion({
local: { elastic: { agent: { version: '8.8.0' } } },
userProvided: {},
})
).toThrowError(/Agent version is not compatible with kibana version/);
expect(() => validateAgentVersion('8.8.0', '8.0.0')).toThrowError('not compatible');
});
it('should work with agent < kibana version', () => {
appContextService.start(({
kibanaVersion: '8.0.0',
} as unknown) as IngestManagerAppContext);
validateAgentVersion({ local: { elastic: { agent: { version: '7.8.0' } } }, userProvided: {} });
validateAgentVersion('7.8.0', '8.0.0');
});

it('should work with agent = kibana version', () => {
appContextService.start(({
kibanaVersion: '8.0.0',
} as unknown) as IngestManagerAppContext);
validateAgentVersion({ local: { elastic: { agent: { version: '8.0.0' } } }, userProvided: {} });
validateAgentVersion('8.0.0', '8.0.0');
});

it('should work with SNAPSHOT version', () => {
appContextService.start(({
kibanaVersion: '8.0.0-SNAPSHOT',
} as unknown) as IngestManagerAppContext);
validateAgentVersion({
local: { elastic: { agent: { version: '8.0.0-SNAPSHOT' } } },
userProvided: {},
});
validateAgentVersion('8.0.0-SNAPSHOT', '8.0.0-SNAPSHOT');
});

it('should work with a agent using SNAPSHOT version', () => {
appContextService.start(({
kibanaVersion: '7.8.0',
} as unknown) as IngestManagerAppContext);
validateAgentVersion({
local: { elastic: { agent: { version: '7.8.0-SNAPSHOT' } } },
userProvided: {},
});
validateAgentVersion('7.8.0-SNAPSHOT', '7.8.0');
});

it('should work with a kibana using SNAPSHOT version', () => {
appContextService.start(({
kibanaVersion: '7.8.0-SNAPSHOT',
} as unknown) as IngestManagerAppContext);
validateAgentVersion({
local: { elastic: { agent: { version: '7.8.0' } } },
userProvided: {},
});
validateAgentVersion('7.8.0', '7.8.0-SNAPSHOT');
});

it('very close versions, e.g. patch/prerelease - all combos should work', () => {
validateAgentVersion('7.9.1', '7.9.2');
validateAgentVersion('7.8.1', '7.8.2');
validateAgentVersion('7.6.99', '7.6.2');
validateAgentVersion('7.6.2', '7.6.99');
validateAgentVersion('5.94.3', '5.94.1234-SNAPSHOT');
validateAgentVersion('5.94.3-SNAPSHOT', '5.94.1');
});

it('somewhat close versions, minor release is 1 or 2 versions back and is older than the stack', () => {
validateAgentVersion('7.9.1', '7.10.2');
validateAgentVersion('7.9.9', '7.11.1');
validateAgentVersion('7.6.99', '7.6.2');
validateAgentVersion('7.6.2', '7.6.99');
expect(() => validateAgentVersion('5.94.3-SNAPSHOT', '5.93.1')).toThrowError('not compatible');
expect(() => validateAgentVersion('5.94.3', '5.92.99-SNAPSHOT')).toThrowError('not compatible');
});

it('versions where Agent is a minor version or major version greater (newer) than the stack should not work', () => {
expect(() => validateAgentVersion('7.10.1', '7.9.99')).toThrowError('not compatible');
expect(() => validateAgentVersion('7.9.9', '6.11.1')).toThrowError('not compatible');
expect(() => validateAgentVersion('5.94.3', '5.92.99-SNAPSHOT')).toThrowError('not compatible');
});
});
61 changes: 44 additions & 17 deletions x-pack/plugins/ingest_manager/server/services/agents/enroll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ export async function enroll(
metadata?: { local: any; userProvided: any },
sharedId?: string
): Promise<Agent> {
validateAgentVersion(metadata);
const agentVersion = metadata?.local?.elastic?.agent?.version;
validateAgentVersion(agentVersion);

const existingAgent = sharedId ? await getAgentBySharedId(soClient, sharedId) : null;

Expand Down Expand Up @@ -89,24 +90,50 @@ async function getAgentBySharedId(soClient: SavedObjectsClientContract, sharedId
return null;
}

export function validateAgentVersion(metadata?: { local: any; userProvided: any }) {
const kibanaVersion = semver.parse(appContextService.getKibanaVersion());
if (!kibanaVersion) {
throw Boom.badRequest('Kibana version is not set');
}
const version = semver.parse(metadata?.local?.elastic?.agent?.version);
if (!version) {
throw Boom.badRequest('Agent version not provided in metadata.');
export function validateAgentVersion(
agentVersion: string,
kibanaVersion = appContextService.getKibanaVersion()
) {
const agentVersionParsed = semver.parse(agentVersion);
if (!agentVersionParsed) {
throw Boom.badRequest('Agent version not provided');
}

if (!version || !semver.lte(formatVersion(version), formatVersion(kibanaVersion))) {
throw Boom.badRequest('Agent version is not compatible with kibana version');
const kibanaVersionParsed = semver.parse(kibanaVersion);
if (!kibanaVersionParsed) {
throw Boom.badRequest('Kibana version is not set or provided');
}
}

/**
* used to remove prelease from version as includePrerelease in not working as expected
*/
function formatVersion(version: semver.SemVer) {
return `${version.major}.${version.minor}.${version.patch}`;
const diff = semver.diff(agentVersion, kibanaVersion);
switch (diff) {
// section 1) very close versions, only patch release differences - all combos should work
// Agent a.b.1 < Kibana a.b.2
// Agent a.b.2 > Kibana a.b.1
case null:
case 'prerelease':
case 'prepatch':
case 'patch':
return; // OK

// section 2) somewhat close versions, Agent minor release is 1 or 2 versions back and is older than the stack:
// Agent a.9.x < Kibana a.10.x
// Agent a.9.x < Kibana a.11.x
case 'preminor':
case 'minor':
if (
agentVersionParsed.minor < kibanaVersionParsed.minor &&
kibanaVersionParsed.minor - agentVersionParsed.minor <= 2
)
return;

// section 3) versions where Agent is a minor version or major version greater (newer) than the stack should not work:
// Agent 7.10.x > Kibana 7.9.x
// Agent 8.0.x > Kibana 7.9.x
default:
if (semver.lte(agentVersionParsed, kibanaVersionParsed)) return;
else
throw Boom.badRequest(
`Agent version ${agentVersion} is not compatible with Kibana version ${kibanaVersion}`
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ export default function (providerContext: FtrProviderContext) {
},
})
.expect(400);
expect(apiResponse.message).to.match(/Agent version is not compatible with kibana/);
expect(apiResponse.message).to.match(/is not compatible/);
});

it('should allow to enroll an agent with a valid enrollment token', async () => {
Expand Down

0 comments on commit 5beb515

Please sign in to comment.