Skip to content
This repository has been archived by the owner on Sep 3, 2024. It is now read-only.

Commit

Permalink
Merge pull request #43 from JupiterOne/fix-new-steps
Browse files Browse the repository at this point in the history
fix: steps added in v2 and handle 403 errors
  • Loading branch information
RonaldEAM authored Mar 15, 2023
2 parents cf73c4f + 2f59ebd commit 257acd9
Show file tree
Hide file tree
Showing 12 changed files with 516 additions and 200 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"@jupiterone/integration-sdk-dev-tools": "^8.30.2",
"@jupiterone/integration-sdk-testing": "^8.30.2",
"@types/node": "^18.8.3",
"@types/node-fetch": "^2.6.2",
"jest-fetch-mock": "^3.0.3",
"type-fest": "^0.20.2"
},
Expand Down
93 changes: 53 additions & 40 deletions src/collector/ServicesClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,18 @@ import { URLSearchParams } from 'url';
import { retry } from '@lifeomic/attempt';

import { IntegrationConfig } from '../types';
import { fatalRequestError, retryableRequestError } from './error';
import { HardwareAsset, PaginatedResponse, SnipeItUser } from './types';
import { retryableRequestError } from './error';
import {
HardwareAsset,
PaginatedResponse,
SnipeItUser,
ResourceIteratee,
HardwareLicense,
SnipeItConsumable,
ConsumableUser,
Location,
} from './types';
import { IntegrationProviderAPIError } from '@jupiterone/integration-sdk-core';

/**
* Services Api
Expand All @@ -25,61 +35,59 @@ export class ServicesClient {
}

async fetchUser(username: string): Promise<SnipeItUser | undefined> {
const usersResponse = await this.fetch<PaginatedResponse>('users', {
search: username,
});
const usersResponse = await this.fetch<PaginatedResponse<SnipeItUser>>(
'users',
{
search: username,
},
);
if (usersResponse.total > 0) return usersResponse.rows[0];
}

async iterateHardware(
iteratee: (asset: HardwareAsset) => Promise<void>,
): Promise<void> {
const limit = 500;
let offset = 0;
let total = 0;

do {
const response: PaginatedResponse = await this.fetch('hardware', {
offset: offset.toString(),
});
if (!response.rows) {
break;
}
total = response.total;
offset += limit;
for (const resource of response.rows) {
await iteratee(resource);
}
} while (offset < total);
async iterateHardware(iteratee: ResourceIteratee<HardwareAsset>) {
const hardwareAssets = await this.iterateAll<HardwareAsset>('hardware');
for (const hardware of hardwareAssets) {
await iteratee(hardware);
}
}

listLocations(): Promise<object[]> {
return this.iterateAll('locations');
listLocations() {
return this.iterateAll<Location>('locations');
}

listConsumables(): Promise<object[]> {
return this.iterateAll('consumables');
listConsumables() {
return this.iterateAll<SnipeItConsumable>('consumables');
}

listHardwareLicenses(id: number): Promise<object[]> {
return this.iterateAll(`hardware/${id}/licenses`);
async iterateHardwareLicenses(
id: number,
iteratee: ResourceIteratee<HardwareLicense>,
) {
const licenses = await this.iterateAll<HardwareLicense>(
`hardware/${id}/licenses`,
);
for (const license of licenses) {
await iteratee(license);
}
}

listUsers(): Promise<object[]> {
return this.iterateAll('users');
listUsers() {
return this.iterateAll<SnipeItUser>('users');
}

listConsumableUsers(consumableId: string): Promise<object[]> {
return this.iterateAll(`consumables/view/${consumableId}/users`);
listConsumableUsers(consumableId: string) {
return this.iterateAll<ConsumableUser>(
`consumables/view/${consumableId}/users`,
);
}

async iterateAll<T = object[]>(url: string): Promise<T> {
const data: any[] = [];
async iterateAll<T = unknown>(url: string): Promise<T[]> {
const data: T[] = [];
const limit = 500;
let offset = 0;
let total = 0;
do {
const response: PaginatedResponse = await this.fetch(url, {
const response = await this.fetch<PaginatedResponse<T>>(url, {
offset: offset.toString(),
limit: limit.toString(),
});
Expand All @@ -90,7 +98,7 @@ export class ServicesClient {
offset += limit;
data.push(...response.rows);
} while (offset < total);
return (data as unknown) as T;
return data;
}

fetch<T = object>(
Expand Down Expand Up @@ -122,7 +130,12 @@ export class ServicesClient {
if (isRetryableRequest(response)) {
throw retryableRequestError(response);
} else {
throw fatalRequestError(response);
throw new IntegrationProviderAPIError({
code: 'SnipeItClientApiError',
status: response.status,
endpoint: response.url,
statusText: response.statusText,
});
}
},
{
Expand Down
6 changes: 0 additions & 6 deletions src/collector/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,3 @@ export function retryableRequestError(response: Response): RetryableError {
`Encountered retryable response from provider (status=${response.status})`,
);
}

export function fatalRequestError(response: Response): Error {
return new Error(
`Encountered unexpected response from provider (status="${response.status}")`,
);
}
Loading

0 comments on commit 257acd9

Please sign in to comment.