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

Optimize graph object buffering and flushing #395

Merged
merged 26 commits into from
Dec 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
b9ef640
Optimize graph object buffering and flushing
austinkelleher Dec 13, 2020
319f1d2
Improve tests for FileSystemGraphObjectStore
austinkelleher Dec 14, 2020
27949a9
Throw if the two graph object maps get out of sync
austinkelleher Dec 16, 2020
6db9779
Initial continuous upload support
austinkelleher Dec 15, 2020
8d22caf
More tests around continuous uploads and various improvements
austinkelleher Dec 16, 2020
8196339
Additional test for FileSystemGraphObjectStore callbacks
austinkelleher Dec 16, 2020
1271491
Mark step as a failure if uploading fails in a step
austinkelleher Dec 16, 2020
b05beb8
Export relevant functions and types from uploader
austinkelleher Dec 16, 2020
5c0ad98
Remove old comment, update test descriptions.
austinkelleher Dec 16, 2020
b1c0804
Share graph object creation test utils across tests and cleanup
austinkelleher Dec 16, 2020
43e57a9
Fix typo in test function
austinkelleher Dec 16, 2020
2b1052c
Add tests for job state upload calls
austinkelleher Dec 16, 2020
47843b7
Fix test function names
austinkelleher Dec 16, 2020
ca68b8a
Test assertion improvements
austinkelleher Dec 16, 2020
06b3394
Only write prettified files to the file system on local collection
austinkelleher Dec 16, 2020
55bb7b5
Change prettyFile to prettifyFiles
austinkelleher Dec 16, 2020
2059ac5
Merge pull request #399 from JupiterOne/1849-unpretty-local-files
austinkelleher Dec 16, 2020
a627688
Merge pull request #398 from JupiterOne/1765-continuous-upload-tests
austinkelleher Dec 16, 2020
6a2c2bf
Merge pull request #397 from JupiterOne/1848-test-cleanup
austinkelleher Dec 16, 2020
b2b44c3
Merge pull request #396 from JupiterOne/1765-continuous-uploads
austinkelleher Dec 16, 2020
aba2ed6
Improve uploader queue to respect queue size instead of waiting for idle
austinkelleher Dec 18, 2020
cfbada4
Change queue size check to >= for safety
austinkelleher Dec 18, 2020
e3d379a
Merge pull request #400 from JupiterOne/1896-queue-size
austinkelleher Dec 18, 2020
cd586e1
Used shared graph object utilities and update CHANGELOG.md
austinkelleher Dec 18, 2020
d370104
Add version to CHANGELOG.md
austinkelleher Dec 18, 2020
3cb5160
Publish
austinkelleher Dec 18, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@jupiterone/cli",
"version": "5.1.0",
"version": "5.2.0",
"description": "The JupiterOne cli",
"main": "dist/src/index.js",
"types": "dist/src/index.d.ts",
Expand All @@ -24,8 +24,8 @@
"test": "jest"
},
"dependencies": {
"@jupiterone/integration-sdk-core": "^5.1.0",
"@jupiterone/integration-sdk-runtime": "^5.1.0",
"@jupiterone/integration-sdk-core": "^5.2.0",
"@jupiterone/integration-sdk-runtime": "^5.2.0",
"@lifeomic/attempt": "^3.0.0",
"commander": "^5.0.0",
"globby": "^11.0.1",
Expand Down
6 changes: 3 additions & 3 deletions packages/integration-sdk-cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@jupiterone/integration-sdk-cli",
"version": "5.1.0",
"version": "5.2.0",
"description": "The SDK for developing JupiterOne integrations",
"main": "dist/src/index.js",
"types": "dist/src/index.d.ts",
Expand All @@ -22,7 +22,7 @@
"prepack": "yarn build:dist"
},
"dependencies": {
"@jupiterone/integration-sdk-runtime": "^5.1.0",
"@jupiterone/integration-sdk-runtime": "^5.2.0",
"commander": "^5.0.0",
"globby": "^11.0.0",
"lodash": "^4.17.19",
Expand All @@ -31,7 +31,7 @@
"vis": "^4.21.0-EOL"
},
"devDependencies": {
"@jupiterone/integration-sdk-private-test-utils": "^5.1.0",
"@jupiterone/integration-sdk-private-test-utils": "^5.2.0",
"@pollyjs/adapter-node-http": "^4.0.4",
"@pollyjs/core": "^4.0.4",
"@pollyjs/persister-fs": "^4.0.4",
Expand Down
7 changes: 7 additions & 0 deletions packages/integration-sdk-cli/src/commands/collect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { createCommand } from 'commander';

import {
executeIntegrationLocally,
FileSystemGraphObjectStore,
prepareLocalStepCollection,
} from '@jupiterone/integration-sdk-runtime';

Expand Down Expand Up @@ -30,6 +31,11 @@ export function collect() {
const enableSchemaValidation = !options.disableSchemaValidation;
const config = prepareLocalStepCollection(await loadConfig(), options);
log.info('\nConfiguration loaded! Running integration...\n');

const graphObjectStore = new FileSystemGraphObjectStore({
prettifyFiles: true,
});

const results = await executeIntegrationLocally(
config,
{
Expand All @@ -39,6 +45,7 @@ export function collect() {
},
{
enableSchemaValidation,
graphObjectStore,
},
);
log.displayExecutionResults(results);
Expand Down
19 changes: 16 additions & 3 deletions packages/integration-sdk-cli/src/commands/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,19 @@ import {
createIntegrationInstanceForLocalExecution,
createIntegrationLogger,
executeIntegrationInstance,
FileSystemGraphObjectStore,
finalizeSynchronization,
getAccountFromEnvironment,
getApiBaseUrl,
getApiKeyFromEnvironment,
initiateSynchronization,
uploadCollectedData,
} from '@jupiterone/integration-sdk-runtime';

import { loadConfig } from '../config';
import * as log from '../log';
import { createPersisterApiStepGraphObjectDataUploader } from '@jupiterone/integration-sdk-runtime/dist/src/execution/uploader';

const DEFAULT_UPLOAD_CONCURRENCY = 5;

export function run() {
return createCommand('run')
Expand Down Expand Up @@ -70,6 +73,10 @@ export function run() {

const invocationConfig = await loadConfig();

const graphObjectStore = new FileSystemGraphObjectStore({
prettifyFiles: true,
});

try {
const executionResults = await executeIntegrationInstance(
logger,
Expand All @@ -82,15 +89,21 @@ export function run() {
},
{
enableSchemaValidation: true,
graphObjectStore,
createStepGraphObjectDataUploader(stepId) {
return createPersisterApiStepGraphObjectDataUploader({
stepId,
synchronizationJobContext: synchronizationContext,
uploadConcurrency: DEFAULT_UPLOAD_CONCURRENCY,
});
},
},
);

await eventPublishingQueue.onIdle();

log.displayExecutionResults(executionResults);

await uploadCollectedData(synchronizationContext);

const synchronizationResult = await finalizeSynchronization({
...synchronizationContext,
partialDatasets: executionResults.metadata.partialDatasets,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@ export async function generateVisualization(
log.warn(`Unable to find any files under path: ${resolvedIntegrationPath}`);
}

const { entities, relationships, mappedRelationships } = await retrieveIntegrationData(
entitiesAndRelationshipPaths,
);
const {
entities,
relationships,
mappedRelationships,
} = await retrieveIntegrationData(entitiesAndRelationshipPaths);

const nodeDataSets = entities.map((entity) => ({
id: getNodeIdFromEntity(entity, []),
Expand All @@ -45,18 +47,21 @@ export async function generateVisualization(
);

const {
mappedRelationshipEdges,
mappedRelationshipEdges,
mappedRelationshipNodes,
} = createMappedRelationshipNodesAndEdges({
mappedRelationships,
mappedRelationships,
explicitEntities: entities,
});

const htmlFileLocation = path.join(resolvedIntegrationPath, 'index.html');

await writeFileToPath({
path: htmlFileLocation,
content: generateVisHTML([...nodeDataSets, ...mappedRelationshipNodes], [...explicitEdgeDataSets, ...mappedRelationshipEdges]),
content: generateVisHTML(
[...nodeDataSets, ...mappedRelationshipNodes],
[...explicitEdgeDataSets, ...mappedRelationshipEdges],
),
});

return htmlFileLocation;
Expand Down
2 changes: 1 addition & 1 deletion packages/integration-sdk-core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@jupiterone/integration-sdk-core",
"version": "5.1.0",
"version": "5.2.0",
"description": "The SDK for developing JupiterOne integrations",
"main": "dist/src/index.js",
"types": "dist/src/index.d.ts",
Expand Down
6 changes: 6 additions & 0 deletions packages/integration-sdk-core/src/types/jobState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,10 @@ export interface JobState {
* flushed to reduce memory consumption.
*/
flush: () => Promise<void>;

/**
* A job state may be created with a graph object uploader. This function
* resolves when all uploads have been completed.
*/
waitUntilUploadsComplete?: () => Promise<void>;
}
12 changes: 10 additions & 2 deletions packages/integration-sdk-core/src/types/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,16 @@ import { Relationship } from './relationship';
* integration execution.
*/
export interface GraphObjectStore {
addEntities(stepId: string, newEntities: Entity[]): Promise<void>;
addEntities(
stepId: string,
newEntities: Entity[],
onEntitiesFlushed?: (entities: Entity[]) => Promise<void>,
): Promise<void>;

addRelationships(
stepId: string,
newRelationships: Relationship[],
onRelationshipsFlushed?: (relationships: Relationship[]) => Promise<void>,
): Promise<void>;

getEntity({ _key, _type }: GraphObjectLookupKey): Promise<Entity>;
Expand All @@ -30,5 +35,8 @@ export interface GraphObjectStore {
iteratee: GraphObjectIteratee<T>,
): Promise<void>;

flush(): Promise<void>;
flush(
onEntitiesFlushed?: (entities: Entity[]) => Promise<void>,
onRelationshipsFlushed?: (relationships: Relationship[]) => Promise<void>,
): Promise<void>;
}
6 changes: 3 additions & 3 deletions packages/integration-sdk-dev-tools/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@jupiterone/integration-sdk-dev-tools",
"version": "5.1.0",
"version": "5.2.0",
"description": "A collection of developer tools that will assist with building integrations.",
"repository": "[email protected]:JupiterOne/sdk.git",
"author": "JupiterOne <[email protected]>",
Expand All @@ -15,8 +15,8 @@
"access": "public"
},
"dependencies": {
"@jupiterone/integration-sdk-cli": "^5.1.0",
"@jupiterone/integration-sdk-testing": "^5.1.0",
"@jupiterone/integration-sdk-cli": "^5.2.0",
"@jupiterone/integration-sdk-testing": "^5.2.0",
"@types/jest": "^25.2.3",
"@types/node": "^14.0.5",
"@typescript-eslint/eslint-plugin": "^3.8.0",
Expand Down
4 changes: 2 additions & 2 deletions packages/integration-sdk-private-test-utils/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@jupiterone/integration-sdk-private-test-utils",
"private": true,
"version": "5.1.0",
"version": "5.2.0",
"description": "The SDK for developing JupiterOne integrations",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand All @@ -12,7 +12,7 @@
"node": "10.x || 12.x || 14.x"
},
"dependencies": {
"@jupiterone/integration-sdk-core": "^5.1.0",
"@jupiterone/integration-sdk-core": "^5.2.0",
"lodash": "^4.17.15",
"uuid": "^7.0.3"
},
Expand Down
26 changes: 26 additions & 0 deletions packages/integration-sdk-private-test-utils/src/graphObject.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Entity, ExplicitRelationship } from '@jupiterone/integration-sdk-core';
import { v4 as uuid } from 'uuid';

export function createTestEntity(partial?: Partial<Entity>): Entity {
return {
_key: uuid(),
_class: uuid(),
_type: uuid(),
[uuid()]: uuid(),
...partial,
};
}

export function createTestRelationship(
partial?: Partial<ExplicitRelationship>,
): ExplicitRelationship {
return {
_key: uuid(),
_toEntityKey: uuid(),
_fromEntityKey: uuid(),
_class: uuid(),
_type: uuid(),
[uuid()]: uuid(),
...partial,
};
}
2 changes: 2 additions & 0 deletions packages/integration-sdk-private-test-utils/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export * from './loadProjectStructure';
export * from './toUnixPath';
export * from './graphObjectStore';
export * from './graphObject';
export * from './util';
5 changes: 5 additions & 0 deletions packages/integration-sdk-private-test-utils/src/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export function sleep(ms: number) {
return new Promise((resolve) => {
setTimeout(() => resolve(), ms);
});
}
6 changes: 3 additions & 3 deletions packages/integration-sdk-runtime/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@jupiterone/integration-sdk-runtime",
"version": "5.1.0",
"version": "5.2.0",
"description": "The SDK for developing JupiterOne integrations",
"main": "dist/src/index.js",
"types": "dist/src/index.d.ts",
Expand All @@ -24,7 +24,7 @@
"prepack": "yarn build:dist"
},
"dependencies": {
"@jupiterone/integration-sdk-core": "^5.1.0",
"@jupiterone/integration-sdk-core": "^5.2.0",
"@lifeomic/alpha": "^1.1.3",
"@lifeomic/attempt": "^3.0.0",
"async-sema": "^3.1.0",
Expand All @@ -43,7 +43,7 @@
"uuid": "^7.0.3"
},
"devDependencies": {
"@jupiterone/integration-sdk-private-test-utils": "^5.1.0",
"@jupiterone/integration-sdk-private-test-utils": "^5.2.0",
"@types/uuid": "^7.0.2",
"get-port": "^5.1.1",
"memfs": "^3.2.0",
Expand Down
6 changes: 1 addition & 5 deletions packages/integration-sdk-runtime/src/__tests__/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import { BucketMap, FileSystemGraphObjectStore } from '../index';
import { FileSystemGraphObjectStore } from '../index';

describe('#storage', () => {
test('should expose BucketMap', () => {
expect(BucketMap).not.toEqual(undefined);
});

test('should expose FileSystemGraphObjectStore', () => {
expect(FileSystemGraphObjectStore).not.toEqual(undefined);
});
Expand Down
Loading