From caf17555b8e93439055b6954586a6f18d433c5f0 Mon Sep 17 00:00:00 2001 From: James Zhou Date: Sat, 20 May 2023 22:21:49 -0500 Subject: [PATCH 1/3] feat(CG-1343): add ssm service support --- README.md | 3 + src/enums/resources.ts | 3 + src/enums/schemasMap.ts | 3 + src/enums/serviceAliases.ts | 3 + src/enums/serviceMap.ts | 6 + src/enums/services.ts | 3 + src/properties/logger.ts | 9 ++ src/services/ssmActivation/data.ts | 130 +++++++++++++++++++++ src/services/ssmActivation/format.ts | 45 +++++++ src/services/ssmActivation/index.ts | 13 +++ src/services/ssmActivation/mutation.ts | 5 + src/services/ssmActivation/schema.graphql | 12 ++ src/services/ssmAssociation/data.ts | 126 ++++++++++++++++++++ src/services/ssmAssociation/format.ts | 76 ++++++++++++ src/services/ssmAssociation/index.ts | 13 +++ src/services/ssmAssociation/mutation.ts | 5 + src/services/ssmAssociation/schema.graphql | 58 +++++++++ src/services/ssmDocument/data.ts | 130 +++++++++++++++++++++ src/services/ssmDocument/format.ts | 57 +++++++++ src/services/ssmDocument/index.ts | 13 +++ src/services/ssmDocument/mutation.ts | 5 + src/services/ssmDocument/schema.graphql | 28 +++++ src/types/generated.ts | 76 ++++++++++++ src/utils/generateArns.ts | 22 +++- 24 files changed, 843 insertions(+), 1 deletion(-) create mode 100644 src/services/ssmActivation/data.ts create mode 100644 src/services/ssmActivation/format.ts create mode 100644 src/services/ssmActivation/index.ts create mode 100644 src/services/ssmActivation/mutation.ts create mode 100644 src/services/ssmActivation/schema.graphql create mode 100644 src/services/ssmAssociation/data.ts create mode 100644 src/services/ssmAssociation/format.ts create mode 100644 src/services/ssmAssociation/index.ts create mode 100644 src/services/ssmAssociation/mutation.ts create mode 100644 src/services/ssmAssociation/schema.graphql create mode 100644 src/services/ssmDocument/data.ts create mode 100644 src/services/ssmDocument/format.ts create mode 100644 src/services/ssmDocument/index.ts create mode 100644 src/services/ssmDocument/mutation.ts create mode 100644 src/services/ssmDocument/schema.graphql diff --git a/README.md b/README.md index d74aa4b7..de443377 100644 --- a/README.md +++ b/README.md @@ -162,6 +162,9 @@ CloudGraph AWS Provider will ask you what regions you would like to crawl and wi | ses | | | sns | kms, cloudtrail, cloudwatch, s3 | | sqs | elasticBeanstalkEnv, s3 | +| ssmActivation | | +| ssmAssociation | | +| ssmDocument | | | subnet | alb, asg, codebuild, dmsReplicationInstance, ec2, ecsService, efsMountTarget, elastiCacheCluster, elasticSearchDomain, elb, lambda, managedAirflow, natGateway, networkInterface, rdsCluster, sageMakerNotebookInstance, routeTable, vpc, vpcEndpoint, eksCluster, emrCluster, flowLog, mskCluster | | systemsManagerInstance | ec2, iamRole | | systemsManagerDocument | | diff --git a/src/enums/resources.ts b/src/enums/resources.ts index baf9d9c3..98bd888a 100644 --- a/src/enums/resources.ts +++ b/src/enums/resources.ts @@ -41,6 +41,9 @@ export default { ec2Instance: 'aws_instance', iamPolicies: 'aws_iam_polocies', // Not a real TF resource, used to organize all the policies route53Zone: 'aws_route53_zone', + ssmActivation: 'aws_ssm_activation', + ssmAssociation: 'aws_ssm_association', + ssmDocument: 'aws_ssm_document', organization: 'aws_organizations_organization', vpnConnection: 'aws_vpn_connection', ecrRepository: 'aws_ecr_repository', diff --git a/src/enums/schemasMap.ts b/src/enums/schemasMap.ts index 6b34621f..8687779b 100644 --- a/src/enums/schemasMap.ts +++ b/src/enums/schemasMap.ts @@ -110,5 +110,8 @@ export default { [services.vpnConnection]: 'awsVpnConnection', [services.organization]: 'awsOrganization', [services.wafV2WebAcl]: 'awsWafV2WebAcl', + [services.ssmActivation]: 'awsSsmActivation', + [services.ssmAssociation]: 'awsSsmAssociation', + [services.ssmDocument]: 'awsSsmDocument', tag: 'awsTag', } diff --git a/src/enums/serviceAliases.ts b/src/enums/serviceAliases.ts index b7f18c1f..ed1a7d7d 100644 --- a/src/enums/serviceAliases.ts +++ b/src/enums/serviceAliases.ts @@ -80,4 +80,7 @@ export default { [services.vpcEndpoint]: 'vpcEndpoints', [services.vpnConnection]: 'vpnConnections', [services.vpcPeeringConnection]: 'vpcPeeringConnections', + [services.ssmActivation]: 'ssmActivations', + [services.ssmAssociation]: 'ssmAssociations', + [services.ssmDocument]: 'ssmDocuments', } diff --git a/src/enums/serviceMap.ts b/src/enums/serviceMap.ts index 9e7969c1..bd70a2d3 100644 --- a/src/enums/serviceMap.ts +++ b/src/enums/serviceMap.ts @@ -106,6 +106,9 @@ import ManagedPrefixList from '../services/managedPrefixList' import MskCluster from '../services/msk' import TransitGatewayRouteTable from '../services/transitGatewayRouteTable' import VpcPeeringConnection from '../services/vpcPeeringConnection' +import SsmActivation from '../services/ssmActivation' +import SsmAssociation from '../services/ssmAssociation' +import SsmDocument from '../services/ssmDocument' /** * serviceMap is an object that contains all currently supported services for AWS @@ -218,5 +221,8 @@ export default { [services.wafV2WebAcl]: WafV2WebAcl, [services.systemsManagerInstance]: SystemsManagerInstance, [services.systemsManagerDocument]: SystemsManagerDocument, + [services.ssmActivation]: SsmActivation, + [services.ssmAssociation]: SsmAssociation, + [services.ssmDocument]: SsmDocument, tag: AwsTag, } diff --git a/src/enums/services.ts b/src/enums/services.ts index 676aeabd..000064de 100644 --- a/src/enums/services.ts +++ b/src/enums/services.ts @@ -92,6 +92,9 @@ export default { sg: 'sg', sns: 'sns', sqs: 'sqs', + ssmActivation: 'ssmActivation', + ssmAssociation: 'ssmAssociation', + ssmDocument: 'ssmDocument', subnet: 'subnet', systemsManagerInstance: 'systemsManagerInstance', systemsManagerDocument: 'systemsManagerDocument', diff --git a/src/properties/logger.ts b/src/properties/logger.ts index 7531bd44..7d88a156 100644 --- a/src/properties/logger.ts +++ b/src/properties/logger.ts @@ -712,4 +712,13 @@ export default { */ fetchedMskClusters: (num: number): string => `Fetched ${num} Msk clusters`, + /** + * SSM + */ + fetchedSsmActivations: (num: number): string => + `Fetched ${num} SSM Activations`, + fetchedSsmAssociations: (num: number): string => + `Fetched ${num} SSM Associations`, + fetchedSsmDocuments: (num: number): string => + `Fetched ${num} SSM Documents`, } diff --git a/src/services/ssmActivation/data.ts b/src/services/ssmActivation/data.ts new file mode 100644 index 00000000..5eddfd12 --- /dev/null +++ b/src/services/ssmActivation/data.ts @@ -0,0 +1,130 @@ +import CloudGraph from '@cloudgraph/sdk' +import SSM, { Activation, DescribeActivationsRequest, DescribeActivationsResult } from 'aws-sdk/clients/ssm' +import { AWSError } from 'aws-sdk/lib/error' +import { Config } from 'aws-sdk/lib/config' +import isEmpty from 'lodash/isEmpty' +import groupBy from 'lodash/groupBy' +import awsLoggerText from '../../properties/logger' +import { initTestEndpoint, setAwsRetryOptions } from '../../utils' +import AwsErrorLog from '../../utils/errorLog' +import { API_GATEWAY_CUSTOM_DELAY } from '../../config/constants' +import { AwsTag, TagMap } from '../../types' +import { convertAwsTagsToTagMap } from '../../utils/format' + +const lt = { ...awsLoggerText } +const { logger } = CloudGraph +const MAX_ACTIVATIONS = 50 +const serviceName = 'ssmActivations' +const errorLog = new AwsErrorLog(serviceName) +const endpoint = initTestEndpoint(serviceName) +const customRetrySettings = setAwsRetryOptions({ + baseDelay: API_GATEWAY_CUSTOM_DELAY, +}) + +/** + * SSM Activation + */ + +export const getActivationsForRegion = async ( + ssm: SSM +): Promise => + new Promise(async resolve => { + const activationList: Activation[] = [] + + const describeActivationsOpts: DescribeActivationsRequest = {} + const listAllActivations = (token?: string): void => { + describeActivationsOpts.MaxResults = MAX_ACTIVATIONS + if (token) { + describeActivationsOpts.NextToken = token + } + try { + ssm.describeActivations( + describeActivationsOpts, + (err: AWSError, data: DescribeActivationsResult) => { + if (err) { + errorLog.generateAwsErrorLog({ + functionName: 'ssm:describeActivations', + err, + }) + } + + if (isEmpty(data)) { + return resolve([]) + } + + const { NextToken: nextToken, ActivationList: items = [] } = data || {} + + if (isEmpty(items)) { + return resolve([]) + } + + logger.debug(lt.fetchedSsmActivations(items.length)) + + activationList.push(...items) + + if (nextToken) { + listAllActivations(nextToken) + } else { + resolve(activationList) + } + } + ) + } catch (error) { + resolve([]) + } + } + listAllActivations() + }) + +export interface RawAwsSsmActivation extends Omit { + Tags: TagMap + region: string + account +} + +export default async ({ + regions, + config, + account, +}: { + account: string + regions: string + config: Config +}): Promise<{ + [region: string]: RawAwsSsmActivation[] +}> => + new Promise(async resolve => { + const activationResult: RawAwsSsmActivation[] = [] + + const regionPromises = regions.split(',').map(region => { + const ssm = new SSM({ + ...config, + region, + endpoint, + ...customRetrySettings, + }) + + return new Promise(async resolveSsmActivationData => { + // Get SSM Activations + const activations = await getActivationsForRegion(ssm) + + if (!isEmpty(activations)) { + activationResult.push( + ...activations.map(({Tags, ...activation}) => ({ + ...activation, + region, + account, + Tags: convertAwsTagsToTagMap(Tags as AwsTag[]), + })) + ) + } + + resolveSsmActivationData() + }) + }) + + await Promise.all(regionPromises) + errorLog.reset() + + resolve(groupBy(activationResult, 'region')) + }) diff --git a/src/services/ssmActivation/format.ts b/src/services/ssmActivation/format.ts new file mode 100644 index 00000000..ad662b2d --- /dev/null +++ b/src/services/ssmActivation/format.ts @@ -0,0 +1,45 @@ +import { RawAwsSsmActivation } from './data' +import { AwsSsmActivation } from '../../types/generated' +import { formatTagsFromMap } from '../../utils/format' +import { ssmActivationArn } from '../../utils/generateArns' + +export default ({ + service, + account, + region, +}: { + service: RawAwsSsmActivation + account: string + region: string +}): AwsSsmActivation => { + const { + ActivationId: activationId, + Description: description, + DefaultInstanceName: defaultInstanceName, + IamRole: iamRole, + RegistrationLimit: registrationLimit, + RegistrationsCount: registrationsCount, + ExpirationDate: expirationDate, + Expired: expired, + CreatedDate: createdDate, + Tags: tags, + } = service + + const arn = ssmActivationArn({ region, account, id: activationId }) + + return { + id: activationId, + accountId: account, + arn, + region, + description, + defaultInstanceName, + iamRole, + registrationLimit, + registrationsCount, + expirationDate: expirationDate?.toISOString(), + expired, + createdDate: createdDate?.toISOString(), + tags: formatTagsFromMap(tags), + } +} diff --git a/src/services/ssmActivation/index.ts b/src/services/ssmActivation/index.ts new file mode 100644 index 00000000..9e5326e9 --- /dev/null +++ b/src/services/ssmActivation/index.ts @@ -0,0 +1,13 @@ +import { Service } from '@cloudgraph/sdk' +import BaseService from '../base' +import format from './format' +import getData from './data' +import mutation from './mutation' + +export default class Acm extends BaseService implements Service { + format = format.bind(this) + + getData = getData.bind(this) + + mutation = mutation +} \ No newline at end of file diff --git a/src/services/ssmActivation/mutation.ts b/src/services/ssmActivation/mutation.ts new file mode 100644 index 00000000..720ff31d --- /dev/null +++ b/src/services/ssmActivation/mutation.ts @@ -0,0 +1,5 @@ +export default `mutation($input: [AddawsSsmActivationInput!]!) { + addawsSsmActivation(input: $input, upsert: true) { + numUids + } +}` \ No newline at end of file diff --git a/src/services/ssmActivation/schema.graphql b/src/services/ssmActivation/schema.graphql new file mode 100644 index 00000000..869f41c5 --- /dev/null +++ b/src/services/ssmActivation/schema.graphql @@ -0,0 +1,12 @@ +type awsSsmActivation implements awsBaseService @key(fields: "arn") { + activationId: String @search(by: [hash, regexp]) + description: String @search(by: [hash, regexp]) + defaultInstanceName: String @search(by: [hash, regexp]) + iamRole: String @search(by: [hash, regexp]) + registrationLimit: Int @search + registrationsCount: Int @search + expirationDate: DateTime @search(by: [day]) + expired: Boolean@search + createdDate: DateTime @search(by: [day]) + tags: [awsRawTag] +} diff --git a/src/services/ssmAssociation/data.ts b/src/services/ssmAssociation/data.ts new file mode 100644 index 00000000..239b4f7e --- /dev/null +++ b/src/services/ssmAssociation/data.ts @@ -0,0 +1,126 @@ +import CloudGraph from '@cloudgraph/sdk' +import SSM, { Association, ListAssociationsRequest, ListAssociationsResult } from 'aws-sdk/clients/ssm' +import { AWSError } from 'aws-sdk/lib/error' +import { Config } from 'aws-sdk/lib/config' +import isEmpty from 'lodash/isEmpty' +import groupBy from 'lodash/groupBy' +import awsLoggerText from '../../properties/logger' +import { initTestEndpoint, setAwsRetryOptions } from '../../utils' +import AwsErrorLog from '../../utils/errorLog' +import { API_GATEWAY_CUSTOM_DELAY } from '../../config/constants' + +const lt = { ...awsLoggerText } +const { logger } = CloudGraph +const MAX_ACTIVATIONS = 50 +const serviceName = 'ssmAssociations' +const errorLog = new AwsErrorLog(serviceName) +const endpoint = initTestEndpoint(serviceName) +const customRetrySettings = setAwsRetryOptions({ + baseDelay: API_GATEWAY_CUSTOM_DELAY, +}) + +/** + * SSM Association + */ + +export const getAssociationsForRegion = async ( + ssm: SSM +): Promise => + new Promise(async resolve => { + const associationList: Association[] = [] + + const listAssociationsOpts: ListAssociationsRequest = {} + const listAllAssociations = (token?: string): void => { + listAssociationsOpts.MaxResults = MAX_ACTIVATIONS + if (token) { + listAssociationsOpts.NextToken = token + } + try { + ssm.listAssociations( + listAssociationsOpts, + (err: AWSError, data: ListAssociationsResult) => { + if (err) { + errorLog.generateAwsErrorLog({ + functionName: 'ssm:listAssociations', + err, + }) + } + + if (isEmpty(data)) { + return resolve([]) + } + + const { NextToken: nextToken, Associations: items = [] } = data || {} + + if (isEmpty(items)) { + return resolve([]) + } + + logger.debug(lt.fetchedSsmAssociations(items.length)) + + associationList.push(...items) + + if (nextToken) { + listAllAssociations(nextToken) + } else { + resolve(associationList) + } + } + ) + } catch (error) { + resolve([]) + } + } + listAllAssociations() + }) + +export interface RawAwsSsmAssociation extends Association { + region: string + account +} + +export default async ({ + regions, + config, + account, +}: { + account: string + regions: string + config: Config +}): Promise<{ + [region: string]: RawAwsSsmAssociation[] +}> => + new Promise(async resolve => { + const associationsResult: RawAwsSsmAssociation[] = [] + + const regionPromises = regions.split(',').map(region => { + const ssm = new SSM({ + ...config, + region, + endpoint, + ...customRetrySettings, + }) + + return new Promise(async resolveSsmAssociationData => { + // Get SSM Associations + const associations = await getAssociationsForRegion(ssm) + + if (!isEmpty(associations)) { + associationsResult.push( + ...associations.map((association) => ({ + ...association, + region, + account, + })) + ) + } + + resolveSsmAssociationData() + }) + }) + + await Promise.all(regionPromises) + errorLog.reset() + + resolve(groupBy(associationsResult, 'region')) + }) diff --git a/src/services/ssmAssociation/format.ts b/src/services/ssmAssociation/format.ts new file mode 100644 index 00000000..4382c82e --- /dev/null +++ b/src/services/ssmAssociation/format.ts @@ -0,0 +1,76 @@ +import { RawAwsSsmAssociation } from './data' +import { AwsSsmAssociation } from '../../types/generated' +import { ssmAssociationArn } from '../../utils/generateArns' +import { AssociationStatusAggregatedCount, TargetMap, TargetMaps } from 'aws-sdk/clients/ssm' + +export default ({ + service, + account, + region, +}: { + service: RawAwsSsmAssociation + account: string + region: string +}): AwsSsmAssociation => { + const { + Name: documentArn, + InstanceId: instanceId, + AssociationId: associationId, + AssociationVersion: associationVersion, + DocumentVersion: documentVersion, + Targets: targets, + LastExecutionDate: lastExecutionDate, + Overview: overview, + ScheduleExpression: scheduleExpression, + AssociationName: associationName, + ScheduleOffset: scheduleOffset, + TargetMaps: targetMaps, + } = service + + const arn = ssmAssociationArn({ region, account, id: associationId }) + + const formatStatusAggregatedCount = (aggregatedCount: AssociationStatusAggregatedCount): {id: string, key: string, count: number}[] => { + const result: {id: string, key: string, count: number}[] = [] + for (const [key, value] of Object.entries(aggregatedCount)) { + result.push({ id: `${key}:${value}`, key, count: value }) + } + return result + } + + const formatTargetMap = (targetMaps: TargetMaps): {id: string, key: string, values: string[]}[] => { + const result: {id: string, key: string, values: string[]}[] = [] + targetMaps.forEach(tm => { + for (const [key, value] of Object.entries(tm)) { + result.push({ id: `${key}:${value}`, key, values: value}) + } + }); + return result + } + + return { + id: arn, + accountId: account, + arn, + region, + documentArn, + instanceId, + associationId, + associationVersion, + documentVersion, + targets: targets?.map(t => ({ + id: `${t.Key}:${t.Values.join(':')}`, + key: t.Key, + value: t.Values + })) || [], + lastExecutionDate: lastExecutionDate?.toISOString(), + overview: { + status: overview?.Status, + detailedStatus: overview?.DetailedStatus, + associationStatusAggregatedCount: overview?.AssociationStatusAggregatedCount?formatStatusAggregatedCount(overview?.AssociationStatusAggregatedCount):[], + }, + scheduleExpression, + associationName, + scheduleOffset, + targetMaps: targetMaps? formatTargetMap(targetMaps) : [], + } +} diff --git a/src/services/ssmAssociation/index.ts b/src/services/ssmAssociation/index.ts new file mode 100644 index 00000000..9e5326e9 --- /dev/null +++ b/src/services/ssmAssociation/index.ts @@ -0,0 +1,13 @@ +import { Service } from '@cloudgraph/sdk' +import BaseService from '../base' +import format from './format' +import getData from './data' +import mutation from './mutation' + +export default class Acm extends BaseService implements Service { + format = format.bind(this) + + getData = getData.bind(this) + + mutation = mutation +} \ No newline at end of file diff --git a/src/services/ssmAssociation/mutation.ts b/src/services/ssmAssociation/mutation.ts new file mode 100644 index 00000000..19dde2ff --- /dev/null +++ b/src/services/ssmAssociation/mutation.ts @@ -0,0 +1,5 @@ +export default `mutation($input: [AddawsSsmAssociationInput!]!) { + addawsSsmAssociation(input: $input, upsert: true) { + numUids + } +}` \ No newline at end of file diff --git a/src/services/ssmAssociation/schema.graphql b/src/services/ssmAssociation/schema.graphql new file mode 100644 index 00000000..eb97fb51 --- /dev/null +++ b/src/services/ssmAssociation/schema.graphql @@ -0,0 +1,58 @@ +type awsSsmAssociationTargets + @generate( + query: { get: false, query: true, aggregate: false } + mutation: { add: false, delete: false } + subscription: false + ) { + id: String! @id + key: String @search(by: [hash, regexp]) + value: [String] @search(by: [hash, regexp]) +} + +type awsSsmAssociationOverviewStatusAggregatedCount + @generate( + query: { get: false, query: true, aggregate: false } + mutation: { add: false, delete: false } + subscription: false + ) { + id: String! @id + key: String @search(by: [hash, regexp]) + value: Int @search +} + +type awsSsmAssociationOverview + @generate( + query: { get: false, query: true, aggregate: false } + mutation: { add: false, delete: false } + subscription: false + ) { + status: String @search(by: [hash, regexp]) + detailedStatus: String @search(by: [hash, regexp]) + associationStatusAggregatedCount: [awsSsmAssociationOverviewStatusAggregatedCount] +} + +type awsSsmAssociationTargetMaps + @generate( + query: { get: false, query: true, aggregate: false } + mutation: { add: false, delete: false } + subscription: false + ) { + id: String! @id + key: String @search(by: [hash, regexp]) + value: [String] @search(by: [hash, regexp]) +} + +type awsSsmAssociation implements awsBaseService @key(fields: "arn") { + documentArn: String @search(by: [hash, regexp]) + instanceId: String @search(by: [hash, regexp]) + associationId: String @search(by: [hash, regexp]) + associationVersion: String @search(by: [hash, regexp]) + documentVersion: String @search(by: [hash, regexp]) + targets: [awsSsmAssociationTargets] + lastExecutionDate: DateTime @search(by: [day]) + overview: awsSsmAssociationOverview + scheduleExpression: String @search(by: [hash, regexp]) + associationName: String @search(by: [hash, regexp]) + scheduleOffset: Int @search + targetMaps: [awsSsmAssociationTargetMaps] +} diff --git a/src/services/ssmDocument/data.ts b/src/services/ssmDocument/data.ts new file mode 100644 index 00000000..3f7f7ff0 --- /dev/null +++ b/src/services/ssmDocument/data.ts @@ -0,0 +1,130 @@ +import CloudGraph from '@cloudgraph/sdk' +import SSM, { DocumentIdentifier, ListDocumentsRequest, ListDocumentsResult } from 'aws-sdk/clients/ssm' +import { AWSError } from 'aws-sdk/lib/error' +import { Config } from 'aws-sdk/lib/config' +import isEmpty from 'lodash/isEmpty' +import groupBy from 'lodash/groupBy' +import awsLoggerText from '../../properties/logger' +import { initTestEndpoint, setAwsRetryOptions } from '../../utils' +import AwsErrorLog from '../../utils/errorLog' +import { API_GATEWAY_CUSTOM_DELAY } from '../../config/constants' +import { AwsTag, TagMap } from '../../types' +import { convertAwsTagsToTagMap } from '../../utils/format' + +const lt = { ...awsLoggerText } +const { logger } = CloudGraph +const MAX_ACTIVATIONS = 50 +const serviceName = 'ssmDocuments' +const errorLog = new AwsErrorLog(serviceName) +const endpoint = initTestEndpoint(serviceName) +const customRetrySettings = setAwsRetryOptions({ + baseDelay: API_GATEWAY_CUSTOM_DELAY, +}) + +/** + * SSM Documents + */ + +export const getDocumentsForRegion = async ( + ssm: SSM +): Promise => + new Promise(async resolve => { + const documentList: DocumentIdentifier[] = [] + + const listCertificatesOpts: ListDocumentsRequest = {} + const listAllDocuments = (token?: string): void => { + listCertificatesOpts.MaxResults = MAX_ACTIVATIONS + if (token) { + listCertificatesOpts.NextToken = token + } + try { + ssm.listDocuments( + listCertificatesOpts, + (err: AWSError, data: ListDocumentsResult) => { + if (err) { + errorLog.generateAwsErrorLog({ + functionName: 'ssm:listDocuments', + err, + }) + } + + if (isEmpty(data)) { + return resolve([]) + } + + const { NextToken: nextToken, DocumentIdentifiers: items = [] } = data || {} + + if (isEmpty(items)) { + return resolve([]) + } + + logger.debug(lt.fetchedSsmDocuments(items.length)) + + documentList.push(...items) + + if (nextToken) { + listAllDocuments(nextToken) + } else { + resolve(documentList) + } + } + ) + } catch (error) { + resolve([]) + } + } + listAllDocuments() + }) + +export interface RawAwsSsmDocument extends Omit { + region: string + account + Tags: TagMap +} + +export default async ({ + regions, + config, + account, +}: { + account: string + regions: string + config: Config +}): Promise<{ + [region: string]: RawAwsSsmDocument[] +}> => + new Promise(async resolve => { + const documentsResult: RawAwsSsmDocument[] = [] + + const regionPromises = regions.split(',').map(region => { + const ssm = new SSM({ + ...config, + region, + endpoint, + ...customRetrySettings, + }) + + return new Promise(async resolveSsmDocumentsData => { + // Get SSM Documents + const documents = await getDocumentsForRegion(ssm) + + if (!isEmpty(documents)) { + documentsResult.push( + ...documents.map(({Tags, ...document}) => ({ + ...document, + region, + account, + Tags: convertAwsTagsToTagMap(Tags as AwsTag[]), + })) + ) + } + + resolveSsmDocumentsData() + }) + }) + + await Promise.all(regionPromises) + errorLog.reset() + + resolve(groupBy(documentsResult, 'region')) + }) diff --git a/src/services/ssmDocument/format.ts b/src/services/ssmDocument/format.ts new file mode 100644 index 00000000..9b50f390 --- /dev/null +++ b/src/services/ssmDocument/format.ts @@ -0,0 +1,57 @@ +import { RawAwsSsmDocument } from './data' +import { AwsSsmDocument } from '../../types/generated' +import { formatTagsFromMap } from '../../utils/format' + +export default ({ + service, + account, + region, +}: { + service: RawAwsSsmDocument + account: string + region: string +}): AwsSsmDocument => { + const { + Name: name, + CreatedDate: createdDate, + DisplayName: displayName, + Owner: owner, + VersionName: versionName, + PlatformTypes: platformTypes, + DocumentVersion: documentVersion, + DocumentType: documentType, + SchemaVersion: schemaVersion, + DocumentFormat: documentFormat, + TargetType: targetType, + Requires: requires, + ReviewStatus: reviewStatus, + Author: author, + Tags: tags, + } = service + + return { + id: name, + accountId: account, + arn: name, + region, + name, + createdDate: createdDate?.toISOString(), + displayName, + owner, + versionName, + platformTypes, + documentVersion, + documentType, + schemaVersion, + documentFormat, + targetType, + tags: formatTagsFromMap(tags), + requires: requires?.map(r => ({ + id: `${r.Name}:${r.Version}`, + name: r.Name, + version: r.Version, + })), + reviewStatus, + author, + } +} diff --git a/src/services/ssmDocument/index.ts b/src/services/ssmDocument/index.ts new file mode 100644 index 00000000..9e5326e9 --- /dev/null +++ b/src/services/ssmDocument/index.ts @@ -0,0 +1,13 @@ +import { Service } from '@cloudgraph/sdk' +import BaseService from '../base' +import format from './format' +import getData from './data' +import mutation from './mutation' + +export default class Acm extends BaseService implements Service { + format = format.bind(this) + + getData = getData.bind(this) + + mutation = mutation +} \ No newline at end of file diff --git a/src/services/ssmDocument/mutation.ts b/src/services/ssmDocument/mutation.ts new file mode 100644 index 00000000..a8d944ff --- /dev/null +++ b/src/services/ssmDocument/mutation.ts @@ -0,0 +1,5 @@ +export default `mutation($input: [AddawsAcmInput!]!) { + addawsAcm(input: $input, upsert: true) { + numUids + } +}` \ No newline at end of file diff --git a/src/services/ssmDocument/schema.graphql b/src/services/ssmDocument/schema.graphql new file mode 100644 index 00000000..4bc7e759 --- /dev/null +++ b/src/services/ssmDocument/schema.graphql @@ -0,0 +1,28 @@ +type awsSsmDocumentRequires + @generate( + query: { get: false, query: true, aggregate: false } + mutation: { add: false, delete: false } + subscription: false + ) { + id: String! @id + name: String @search(by: [hash, regexp]) + version: String @search(by: [hash, regexp]) +} + +type awsSsmDocument implements awsBaseService @key(fields: "arn") { + name: String @search(by: [hash, regexp]) + createdDate: DateTime @search(by: [day]) + displayName: String @search(by: [hash, regexp]) + owner: String @search(by: [hash, regexp]) + versionName: String @search(by: [hash, regexp]) + platformTypes: [String] @search(by: [hash, regexp]) + documentVersion: String @search(by: [hash, regexp]) + documentType: String @search(by: [hash, regexp]) + schemaVersion: String @search(by: [hash, regexp]) + documentFormat: String @search(by: [hash, regexp]) + targetType: String @search(by: [hash, regexp]) + requires: [awsSsmDocumentRequires] + reviewStatus: String @search(by: [hash, regexp]) + author: String @search(by: [hash, regexp]) + tags: [awsRawTag] +} diff --git a/src/types/generated.ts b/src/types/generated.ts index 0872d97c..8d9d85ca 100644 --- a/src/types/generated.ts +++ b/src/types/generated.ts @@ -4351,6 +4351,82 @@ export type AwsSqs = AwsBaseService & { visibilityTimeout?: Maybe; }; +export type AwsSsmActivation = AwsBaseService & { + activationId?: Maybe; + createdDate?: Maybe; + defaultInstanceName?: Maybe; + description?: Maybe; + expirationDate?: Maybe; + expired?: Maybe; + iamRole?: Maybe; + registrationLimit?: Maybe; + registrationsCount?: Maybe; + tags?: Maybe>>; +}; + +export type AwsSsmAssociation = AwsBaseService & { + associationId?: Maybe; + associationName?: Maybe; + associationVersion?: Maybe; + documentArn?: Maybe; + documentVersion?: Maybe; + instanceId?: Maybe; + lastExecutionDate?: Maybe; + overview?: Maybe; + scheduleExpression?: Maybe; + scheduleOffset?: Maybe; + targetMaps?: Maybe>>; + targets?: Maybe>>; +}; + +export type AwsSsmAssociationOverview = { + associationStatusAggregatedCount?: Maybe>>; + detailedStatus?: Maybe; + status?: Maybe; +}; + +export type AwsSsmAssociationOverviewStatusAggregatedCount = { + id: Scalars['String']; + key?: Maybe; + value?: Maybe; +}; + +export type AwsSsmAssociationTargetMaps = { + id: Scalars['String']; + key?: Maybe; + value?: Maybe>>; +}; + +export type AwsSsmAssociationTargets = { + id: Scalars['String']; + key?: Maybe; + value?: Maybe>>; +}; + +export type AwsSsmDocument = AwsBaseService & { + author?: Maybe; + createdDate?: Maybe; + displayName?: Maybe; + documentFormat?: Maybe; + documentType?: Maybe; + documentVersion?: Maybe; + name?: Maybe; + owner?: Maybe; + platformTypes?: Maybe>>; + requires?: Maybe>>; + reviewStatus?: Maybe; + schemaVersion?: Maybe; + tags?: Maybe>>; + targetType?: Maybe; + versionName?: Maybe; +}; + +export type AwsSsmDocumentRequires = { + id: Scalars['String']; + name?: Maybe; + version?: Maybe; +}; + export type AwsSubnet = AwsBaseService & { alb?: Maybe>>; asg?: Maybe>>; diff --git a/src/utils/generateArns.ts b/src/utils/generateArns.ts index fc7e921a..14ee3231 100644 --- a/src/utils/generateArns.ts +++ b/src/utils/generateArns.ts @@ -344,4 +344,24 @@ export const transitGatewayRouteTableArn = ({ region: string account: string id: string -}): string => `arn:aws:ec2:${region}:${account}:transit-gateway-routetable/${id}` \ No newline at end of file +}): string => `arn:aws:ec2:${region}:${account}:transit-gateway-routetable/${id}` + +export const ssmActivationArn = ({ + region, + account, + id, +}: { + region: string + account: string + id: string +}): string => `arn:aws:ssm:${region}:${account}:activation/${id}` + +export const ssmAssociationArn = ({ + region, + account, + id, +}: { + region: string + account: string + id: string +}): string => `arn:aws:ssm:${region}:${account}:association/${id}` From 497dec63d8ced3e29291468cb3682c9061397ca5 Mon Sep 17 00:00:00 2001 From: James Zhou Date: Sun, 21 May 2023 11:26:50 -0500 Subject: [PATCH 2/3] remove the duplicated ssmDocument, rename ssm to systemManager --- README.md | 7 +- src/enums/resources.ts | 6 +- src/enums/schemasMap.ts | 7 +- src/enums/serviceAliases.ts | 5 +- src/enums/serviceMap.ts | 12 +- src/enums/services.ts | 7 +- src/properties/logger.ts | 6 +- src/services/ssmActivation/index.ts | 13 -- src/services/ssmActivation/mutation.ts | 5 - src/services/ssmAssociation/mutation.ts | 5 - src/services/ssmDocument/data.ts | 130 ------------------ src/services/ssmDocument/format.ts | 57 -------- src/services/ssmDocument/mutation.ts | 5 - src/services/ssmDocument/schema.graphql | 28 ---- .../data.ts | 18 +-- .../format.ts | 12 +- .../index.ts | 2 +- .../systemsManagerActivation/mutation.ts | 5 + .../schema.graphql | 2 +- .../data.ts | 18 +-- .../format.ts | 14 +- .../index.ts | 2 +- .../systemsManagerAssociation/mutation.ts | 5 + .../schema.graphql | 18 +-- src/types/generated.ts | 128 +++++++---------- src/utils/generateArns.ts | 4 +- 26 files changed, 128 insertions(+), 393 deletions(-) delete mode 100644 src/services/ssmActivation/index.ts delete mode 100644 src/services/ssmActivation/mutation.ts delete mode 100644 src/services/ssmAssociation/mutation.ts delete mode 100644 src/services/ssmDocument/data.ts delete mode 100644 src/services/ssmDocument/format.ts delete mode 100644 src/services/ssmDocument/mutation.ts delete mode 100644 src/services/ssmDocument/schema.graphql rename src/services/{ssmActivation => systemsManagerActivation}/data.ts (85%) rename src/services/{ssmActivation => systemsManagerActivation}/format.ts (70%) rename src/services/{ssmAssociation => systemsManagerActivation}/index.ts (74%) create mode 100644 src/services/systemsManagerActivation/mutation.ts rename src/services/{ssmActivation => systemsManagerActivation}/schema.graphql (83%) rename src/services/{ssmAssociation => systemsManagerAssociation}/data.ts (84%) rename src/services/{ssmAssociation => systemsManagerAssociation}/format.ts (81%) rename src/services/{ssmDocument => systemsManagerAssociation}/index.ts (74%) create mode 100644 src/services/systemsManagerAssociation/mutation.ts rename src/services/{ssmAssociation => systemsManagerAssociation}/schema.graphql (73%) diff --git a/README.md b/README.md index de443377..301654a6 100644 --- a/README.md +++ b/README.md @@ -162,11 +162,10 @@ CloudGraph AWS Provider will ask you what regions you would like to crawl and wi | ses | | | sns | kms, cloudtrail, cloudwatch, s3 | | sqs | elasticBeanstalkEnv, s3 | -| ssmActivation | | -| ssmAssociation | | -| ssmDocument | | | subnet | alb, asg, codebuild, dmsReplicationInstance, ec2, ecsService, efsMountTarget, elastiCacheCluster, elasticSearchDomain, elb, lambda, managedAirflow, natGateway, networkInterface, rdsCluster, sageMakerNotebookInstance, routeTable, vpc, vpcEndpoint, eksCluster, emrCluster, flowLog, mskCluster | -| systemsManagerInstance | ec2, iamRole | +| systemsManagerActivation | | +| systemsManagerAssociation | systemsManagerInstance | +| systemsManagerInstance | ec2, iamRole, systemManagerAssociation | | systemsManagerDocument | | | transitGateway | transitGatewayAttachment, transitGatewayRouteTable, vpnConnection | | transitGatewayAttachment | transitGateway, transitGatewayRouteTable, vpc, vpnConnection | diff --git a/src/enums/resources.ts b/src/enums/resources.ts index 98bd888a..0207b207 100644 --- a/src/enums/resources.ts +++ b/src/enums/resources.ts @@ -41,9 +41,6 @@ export default { ec2Instance: 'aws_instance', iamPolicies: 'aws_iam_polocies', // Not a real TF resource, used to organize all the policies route53Zone: 'aws_route53_zone', - ssmActivation: 'aws_ssm_activation', - ssmAssociation: 'aws_ssm_association', - ssmDocument: 'aws_ssm_document', organization: 'aws_organizations_organization', vpnConnection: 'aws_vpn_connection', ecrRepository: 'aws_ecr_repository', @@ -70,6 +67,9 @@ export default { networkInterface: 'aws_network_interface', ecsTaskDefinition: 'aws_ecs_task_definition', apiGatewayRestApi: 'aws_api_gateway_rest_api', + systemsManagerActivation: 'aws_ssm_activation', + systemsManagerAssociation: 'aws_ssm_association', + systemsManagerDocument: 'aws_ssm_document', clientVpnEndpoint: 'aws_ec2_client_vpn_endpoint', apiGatewayResource: 'aws_api_gateway_resource', elastiCacheCluster: 'aws_elasticache_cluster', diff --git a/src/enums/schemasMap.ts b/src/enums/schemasMap.ts index 8687779b..f62cb66d 100644 --- a/src/enums/schemasMap.ts +++ b/src/enums/schemasMap.ts @@ -102,16 +102,15 @@ export default { [services.secretsManager]: 'awsSecretsManager', [services.ses]: 'awsSes', [services.sns]: 'awsSns', - [services.systemsManagerInstance]: 'awsSystemsManagerInstance', + [services.systemsManagerActivation]: 'awsSystemsManagerActivation', + [services.systemsManagerAssociation]: 'awsSystemsManagerAssociation', [services.systemsManagerDocument]: 'awsSystemsManagerDocument', + [services.systemsManagerInstance]: 'awsSystemsManagerInstance', [services.transitGateway]: 'awsTransitGateway', [services.transitGatewayAttachment]: 'awsTransitGatewayAttachment', [services.transitGatewayRouteTable]: 'awsTransitGatewayRouteTable', [services.vpnConnection]: 'awsVpnConnection', [services.organization]: 'awsOrganization', [services.wafV2WebAcl]: 'awsWafV2WebAcl', - [services.ssmActivation]: 'awsSsmActivation', - [services.ssmAssociation]: 'awsSsmAssociation', - [services.ssmDocument]: 'awsSsmDocument', tag: 'awsTag', } diff --git a/src/enums/serviceAliases.ts b/src/enums/serviceAliases.ts index ed1a7d7d..754779da 100644 --- a/src/enums/serviceAliases.ts +++ b/src/enums/serviceAliases.ts @@ -72,6 +72,8 @@ export default { [services.sg]: 'securityGroups', [services.securityHub]: 'securityHubs', [services.subnet]: 'subnets', + [services.systemsManagerActivation]: 'systemsManagerActivations', + [services.systemsManagerAssociation]: 'systemsManagerAssociations', [services.systemsManagerDocument]: 'systemsManagerDocuments', [services.systemsManagerInstance]: 'systemsManagerInstances', [services.transitGateway]: 'transitGateways', @@ -80,7 +82,4 @@ export default { [services.vpcEndpoint]: 'vpcEndpoints', [services.vpnConnection]: 'vpnConnections', [services.vpcPeeringConnection]: 'vpcPeeringConnections', - [services.ssmActivation]: 'ssmActivations', - [services.ssmAssociation]: 'ssmAssociations', - [services.ssmDocument]: 'ssmDocuments', } diff --git a/src/enums/serviceMap.ts b/src/enums/serviceMap.ts index bd70a2d3..06381fb6 100644 --- a/src/enums/serviceMap.ts +++ b/src/enums/serviceMap.ts @@ -96,6 +96,8 @@ import GuardDutyDetector from '../services/guardDutyDetector' import ElasticSearchDomain from '../services/elasticSearchDomain' import DmsReplicationInstance from '../services/dmsReplicationInstance' import SageMakerNotebookInstance from '../services/sageMakerNotebookInstance' +import SystemsManagerActivation from '../services/systemsManagerActivation' +import SystemsManagerAssociation from '../services/systemsManagerAssociation' import SystemsManagerInstance from '../services/systemsManagerInstance' import SystemsManagerDocument from '../services/systemsManagerDocument' import RdsClusterSnapshot from '../services/rdsClusterSnapshot' @@ -106,9 +108,6 @@ import ManagedPrefixList from '../services/managedPrefixList' import MskCluster from '../services/msk' import TransitGatewayRouteTable from '../services/transitGatewayRouteTable' import VpcPeeringConnection from '../services/vpcPeeringConnection' -import SsmActivation from '../services/ssmActivation' -import SsmAssociation from '../services/ssmAssociation' -import SsmDocument from '../services/ssmDocument' /** * serviceMap is an object that contains all currently supported services for AWS @@ -219,10 +218,9 @@ export default { [services.vpnConnection]: VpnConnection, [services.organization]: Organization, [services.wafV2WebAcl]: WafV2WebAcl, - [services.systemsManagerInstance]: SystemsManagerInstance, + [services.systemsManagerActivation]: SystemsManagerActivation, + [services.systemsManagerAssociation]: SystemsManagerAssociation, [services.systemsManagerDocument]: SystemsManagerDocument, - [services.ssmActivation]: SsmActivation, - [services.ssmAssociation]: SsmAssociation, - [services.ssmDocument]: SsmDocument, + [services.systemsManagerInstance]: SystemsManagerInstance, tag: AwsTag, } diff --git a/src/enums/services.ts b/src/enums/services.ts index 000064de..0589048f 100644 --- a/src/enums/services.ts +++ b/src/enums/services.ts @@ -92,12 +92,11 @@ export default { sg: 'sg', sns: 'sns', sqs: 'sqs', - ssmActivation: 'ssmActivation', - ssmAssociation: 'ssmAssociation', - ssmDocument: 'ssmDocument', subnet: 'subnet', - systemsManagerInstance: 'systemsManagerInstance', + systemsManagerActivation: 'systemsManagerActivation', + systemsManagerAssociation: 'systemsManagerAssociation', systemsManagerDocument: 'systemsManagerDocument', + systemsManagerInstance: 'systemsManagerInstance', transitGateway: 'transitGateway', transitGatewayAttachment: 'transitGatewayAttachment', transitGatewayRouteTable: 'transitGatewayRouteTable', diff --git a/src/properties/logger.ts b/src/properties/logger.ts index 7d88a156..175a5636 100644 --- a/src/properties/logger.ts +++ b/src/properties/logger.ts @@ -715,10 +715,8 @@ export default { /** * SSM */ - fetchedSsmActivations: (num: number): string => + fetchedSystemManagersActivations: (num: number): string => `Fetched ${num} SSM Activations`, - fetchedSsmAssociations: (num: number): string => + fetchedSystemManagersAssociations: (num: number): string => `Fetched ${num} SSM Associations`, - fetchedSsmDocuments: (num: number): string => - `Fetched ${num} SSM Documents`, } diff --git a/src/services/ssmActivation/index.ts b/src/services/ssmActivation/index.ts deleted file mode 100644 index 9e5326e9..00000000 --- a/src/services/ssmActivation/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Service } from '@cloudgraph/sdk' -import BaseService from '../base' -import format from './format' -import getData from './data' -import mutation from './mutation' - -export default class Acm extends BaseService implements Service { - format = format.bind(this) - - getData = getData.bind(this) - - mutation = mutation -} \ No newline at end of file diff --git a/src/services/ssmActivation/mutation.ts b/src/services/ssmActivation/mutation.ts deleted file mode 100644 index 720ff31d..00000000 --- a/src/services/ssmActivation/mutation.ts +++ /dev/null @@ -1,5 +0,0 @@ -export default `mutation($input: [AddawsSsmActivationInput!]!) { - addawsSsmActivation(input: $input, upsert: true) { - numUids - } -}` \ No newline at end of file diff --git a/src/services/ssmAssociation/mutation.ts b/src/services/ssmAssociation/mutation.ts deleted file mode 100644 index 19dde2ff..00000000 --- a/src/services/ssmAssociation/mutation.ts +++ /dev/null @@ -1,5 +0,0 @@ -export default `mutation($input: [AddawsSsmAssociationInput!]!) { - addawsSsmAssociation(input: $input, upsert: true) { - numUids - } -}` \ No newline at end of file diff --git a/src/services/ssmDocument/data.ts b/src/services/ssmDocument/data.ts deleted file mode 100644 index 3f7f7ff0..00000000 --- a/src/services/ssmDocument/data.ts +++ /dev/null @@ -1,130 +0,0 @@ -import CloudGraph from '@cloudgraph/sdk' -import SSM, { DocumentIdentifier, ListDocumentsRequest, ListDocumentsResult } from 'aws-sdk/clients/ssm' -import { AWSError } from 'aws-sdk/lib/error' -import { Config } from 'aws-sdk/lib/config' -import isEmpty from 'lodash/isEmpty' -import groupBy from 'lodash/groupBy' -import awsLoggerText from '../../properties/logger' -import { initTestEndpoint, setAwsRetryOptions } from '../../utils' -import AwsErrorLog from '../../utils/errorLog' -import { API_GATEWAY_CUSTOM_DELAY } from '../../config/constants' -import { AwsTag, TagMap } from '../../types' -import { convertAwsTagsToTagMap } from '../../utils/format' - -const lt = { ...awsLoggerText } -const { logger } = CloudGraph -const MAX_ACTIVATIONS = 50 -const serviceName = 'ssmDocuments' -const errorLog = new AwsErrorLog(serviceName) -const endpoint = initTestEndpoint(serviceName) -const customRetrySettings = setAwsRetryOptions({ - baseDelay: API_GATEWAY_CUSTOM_DELAY, -}) - -/** - * SSM Documents - */ - -export const getDocumentsForRegion = async ( - ssm: SSM -): Promise => - new Promise(async resolve => { - const documentList: DocumentIdentifier[] = [] - - const listCertificatesOpts: ListDocumentsRequest = {} - const listAllDocuments = (token?: string): void => { - listCertificatesOpts.MaxResults = MAX_ACTIVATIONS - if (token) { - listCertificatesOpts.NextToken = token - } - try { - ssm.listDocuments( - listCertificatesOpts, - (err: AWSError, data: ListDocumentsResult) => { - if (err) { - errorLog.generateAwsErrorLog({ - functionName: 'ssm:listDocuments', - err, - }) - } - - if (isEmpty(data)) { - return resolve([]) - } - - const { NextToken: nextToken, DocumentIdentifiers: items = [] } = data || {} - - if (isEmpty(items)) { - return resolve([]) - } - - logger.debug(lt.fetchedSsmDocuments(items.length)) - - documentList.push(...items) - - if (nextToken) { - listAllDocuments(nextToken) - } else { - resolve(documentList) - } - } - ) - } catch (error) { - resolve([]) - } - } - listAllDocuments() - }) - -export interface RawAwsSsmDocument extends Omit { - region: string - account - Tags: TagMap -} - -export default async ({ - regions, - config, - account, -}: { - account: string - regions: string - config: Config -}): Promise<{ - [region: string]: RawAwsSsmDocument[] -}> => - new Promise(async resolve => { - const documentsResult: RawAwsSsmDocument[] = [] - - const regionPromises = regions.split(',').map(region => { - const ssm = new SSM({ - ...config, - region, - endpoint, - ...customRetrySettings, - }) - - return new Promise(async resolveSsmDocumentsData => { - // Get SSM Documents - const documents = await getDocumentsForRegion(ssm) - - if (!isEmpty(documents)) { - documentsResult.push( - ...documents.map(({Tags, ...document}) => ({ - ...document, - region, - account, - Tags: convertAwsTagsToTagMap(Tags as AwsTag[]), - })) - ) - } - - resolveSsmDocumentsData() - }) - }) - - await Promise.all(regionPromises) - errorLog.reset() - - resolve(groupBy(documentsResult, 'region')) - }) diff --git a/src/services/ssmDocument/format.ts b/src/services/ssmDocument/format.ts deleted file mode 100644 index 9b50f390..00000000 --- a/src/services/ssmDocument/format.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { RawAwsSsmDocument } from './data' -import { AwsSsmDocument } from '../../types/generated' -import { formatTagsFromMap } from '../../utils/format' - -export default ({ - service, - account, - region, -}: { - service: RawAwsSsmDocument - account: string - region: string -}): AwsSsmDocument => { - const { - Name: name, - CreatedDate: createdDate, - DisplayName: displayName, - Owner: owner, - VersionName: versionName, - PlatformTypes: platformTypes, - DocumentVersion: documentVersion, - DocumentType: documentType, - SchemaVersion: schemaVersion, - DocumentFormat: documentFormat, - TargetType: targetType, - Requires: requires, - ReviewStatus: reviewStatus, - Author: author, - Tags: tags, - } = service - - return { - id: name, - accountId: account, - arn: name, - region, - name, - createdDate: createdDate?.toISOString(), - displayName, - owner, - versionName, - platformTypes, - documentVersion, - documentType, - schemaVersion, - documentFormat, - targetType, - tags: formatTagsFromMap(tags), - requires: requires?.map(r => ({ - id: `${r.Name}:${r.Version}`, - name: r.Name, - version: r.Version, - })), - reviewStatus, - author, - } -} diff --git a/src/services/ssmDocument/mutation.ts b/src/services/ssmDocument/mutation.ts deleted file mode 100644 index a8d944ff..00000000 --- a/src/services/ssmDocument/mutation.ts +++ /dev/null @@ -1,5 +0,0 @@ -export default `mutation($input: [AddawsAcmInput!]!) { - addawsAcm(input: $input, upsert: true) { - numUids - } -}` \ No newline at end of file diff --git a/src/services/ssmDocument/schema.graphql b/src/services/ssmDocument/schema.graphql deleted file mode 100644 index 4bc7e759..00000000 --- a/src/services/ssmDocument/schema.graphql +++ /dev/null @@ -1,28 +0,0 @@ -type awsSsmDocumentRequires - @generate( - query: { get: false, query: true, aggregate: false } - mutation: { add: false, delete: false } - subscription: false - ) { - id: String! @id - name: String @search(by: [hash, regexp]) - version: String @search(by: [hash, regexp]) -} - -type awsSsmDocument implements awsBaseService @key(fields: "arn") { - name: String @search(by: [hash, regexp]) - createdDate: DateTime @search(by: [day]) - displayName: String @search(by: [hash, regexp]) - owner: String @search(by: [hash, regexp]) - versionName: String @search(by: [hash, regexp]) - platformTypes: [String] @search(by: [hash, regexp]) - documentVersion: String @search(by: [hash, regexp]) - documentType: String @search(by: [hash, regexp]) - schemaVersion: String @search(by: [hash, regexp]) - documentFormat: String @search(by: [hash, regexp]) - targetType: String @search(by: [hash, regexp]) - requires: [awsSsmDocumentRequires] - reviewStatus: String @search(by: [hash, regexp]) - author: String @search(by: [hash, regexp]) - tags: [awsRawTag] -} diff --git a/src/services/ssmActivation/data.ts b/src/services/systemsManagerActivation/data.ts similarity index 85% rename from src/services/ssmActivation/data.ts rename to src/services/systemsManagerActivation/data.ts index 5eddfd12..e2239eba 100644 --- a/src/services/ssmActivation/data.ts +++ b/src/services/systemsManagerActivation/data.ts @@ -14,7 +14,7 @@ import { convertAwsTagsToTagMap } from '../../utils/format' const lt = { ...awsLoggerText } const { logger } = CloudGraph const MAX_ACTIVATIONS = 50 -const serviceName = 'ssmActivations' +const serviceName = 'systemsManagerDocumentActivations' const errorLog = new AwsErrorLog(serviceName) const endpoint = initTestEndpoint(serviceName) const customRetrySettings = setAwsRetryOptions({ @@ -22,7 +22,7 @@ const customRetrySettings = setAwsRetryOptions({ }) /** - * SSM Activation + * SystemsManagerActivation */ export const getActivationsForRegion = async ( @@ -58,7 +58,7 @@ export const getActivationsForRegion = async ( return resolve([]) } - logger.debug(lt.fetchedSsmActivations(items.length)) + logger.debug(lt.fetchedSystemManagersActivations(items.length)) activationList.push(...items) @@ -76,7 +76,7 @@ export const getActivationsForRegion = async ( listAllActivations() }) -export interface RawAwsSsmActivation extends Omit { +export interface RawAwsSystemManagerActivation extends Omit { Tags: TagMap region: string account @@ -91,10 +91,10 @@ export default async ({ regions: string config: Config }): Promise<{ - [region: string]: RawAwsSsmActivation[] + [region: string]: RawAwsSystemManagerActivation[] }> => new Promise(async resolve => { - const activationResult: RawAwsSsmActivation[] = [] + const activationResult: RawAwsSystemManagerActivation[] = [] const regionPromises = regions.split(',').map(region => { const ssm = new SSM({ @@ -104,8 +104,8 @@ export default async ({ ...customRetrySettings, }) - return new Promise(async resolveSsmActivationData => { - // Get SSM Activations + return new Promise(async resolveSystemManagerActivationData => { + // Get SystemManager Activations const activations = await getActivationsForRegion(ssm) if (!isEmpty(activations)) { @@ -119,7 +119,7 @@ export default async ({ ) } - resolveSsmActivationData() + resolveSystemManagerActivationData() }) }) diff --git a/src/services/ssmActivation/format.ts b/src/services/systemsManagerActivation/format.ts similarity index 70% rename from src/services/ssmActivation/format.ts rename to src/services/systemsManagerActivation/format.ts index ad662b2d..6467e6a7 100644 --- a/src/services/ssmActivation/format.ts +++ b/src/services/systemsManagerActivation/format.ts @@ -1,17 +1,17 @@ -import { RawAwsSsmActivation } from './data' -import { AwsSsmActivation } from '../../types/generated' +import { RawAwsSystemManagerActivation } from './data' +import { AwsSystemManagerActivation } from '../../types/generated' import { formatTagsFromMap } from '../../utils/format' -import { ssmActivationArn } from '../../utils/generateArns' +import { systemManagerActivationArn } from '../../utils/generateArns' export default ({ service, account, region, }: { - service: RawAwsSsmActivation + service: RawAwsSystemManagerActivation account: string region: string -}): AwsSsmActivation => { +}): AwsSystemManagerActivation => { const { ActivationId: activationId, Description: description, @@ -25,7 +25,7 @@ export default ({ Tags: tags, } = service - const arn = ssmActivationArn({ region, account, id: activationId }) + const arn = systemManagerActivationArn({ region, account, id: activationId }) return { id: activationId, diff --git a/src/services/ssmAssociation/index.ts b/src/services/systemsManagerActivation/index.ts similarity index 74% rename from src/services/ssmAssociation/index.ts rename to src/services/systemsManagerActivation/index.ts index 9e5326e9..21c18ac7 100644 --- a/src/services/ssmAssociation/index.ts +++ b/src/services/systemsManagerActivation/index.ts @@ -4,7 +4,7 @@ import format from './format' import getData from './data' import mutation from './mutation' -export default class Acm extends BaseService implements Service { +export default class SystemManagerActivation extends BaseService implements Service { format = format.bind(this) getData = getData.bind(this) diff --git a/src/services/systemsManagerActivation/mutation.ts b/src/services/systemsManagerActivation/mutation.ts new file mode 100644 index 00000000..bfbc27c6 --- /dev/null +++ b/src/services/systemsManagerActivation/mutation.ts @@ -0,0 +1,5 @@ +export default `mutation($input: [AddawsSystemManagerActivationInput!]!) { + addawsSystemManagerActivation(input: $input, upsert: true) { + numUids + } +}` \ No newline at end of file diff --git a/src/services/ssmActivation/schema.graphql b/src/services/systemsManagerActivation/schema.graphql similarity index 83% rename from src/services/ssmActivation/schema.graphql rename to src/services/systemsManagerActivation/schema.graphql index 869f41c5..19944fa1 100644 --- a/src/services/ssmActivation/schema.graphql +++ b/src/services/systemsManagerActivation/schema.graphql @@ -1,4 +1,4 @@ -type awsSsmActivation implements awsBaseService @key(fields: "arn") { +type awsSystemManagerActivation implements awsBaseService @key(fields: "arn") { activationId: String @search(by: [hash, regexp]) description: String @search(by: [hash, regexp]) defaultInstanceName: String @search(by: [hash, regexp]) diff --git a/src/services/ssmAssociation/data.ts b/src/services/systemsManagerAssociation/data.ts similarity index 84% rename from src/services/ssmAssociation/data.ts rename to src/services/systemsManagerAssociation/data.ts index 239b4f7e..1af83649 100644 --- a/src/services/ssmAssociation/data.ts +++ b/src/services/systemsManagerAssociation/data.ts @@ -12,7 +12,7 @@ import { API_GATEWAY_CUSTOM_DELAY } from '../../config/constants' const lt = { ...awsLoggerText } const { logger } = CloudGraph const MAX_ACTIVATIONS = 50 -const serviceName = 'ssmAssociations' +const serviceName = 'systemsManagerDocumentAssociations' const errorLog = new AwsErrorLog(serviceName) const endpoint = initTestEndpoint(serviceName) const customRetrySettings = setAwsRetryOptions({ @@ -20,7 +20,7 @@ const customRetrySettings = setAwsRetryOptions({ }) /** - * SSM Association + * SystemsManagerAssociation */ export const getAssociationsForRegion = async ( @@ -56,7 +56,7 @@ export const getAssociationsForRegion = async ( return resolve([]) } - logger.debug(lt.fetchedSsmAssociations(items.length)) + logger.debug(lt.fetchedSystemManagersAssociations(items.length)) associationList.push(...items) @@ -74,7 +74,7 @@ export const getAssociationsForRegion = async ( listAllAssociations() }) -export interface RawAwsSsmAssociation extends Association { +export interface RawAwsSystemManagerAssociation extends Association { region: string account } @@ -88,10 +88,10 @@ export default async ({ regions: string config: Config }): Promise<{ - [region: string]: RawAwsSsmAssociation[] + [region: string]: RawAwsSystemManagerAssociation[] }> => new Promise(async resolve => { - const associationsResult: RawAwsSsmAssociation[] = [] + const associationsResult: RawAwsSystemManagerAssociation[] = [] const regionPromises = regions.split(',').map(region => { const ssm = new SSM({ @@ -101,8 +101,8 @@ export default async ({ ...customRetrySettings, }) - return new Promise(async resolveSsmAssociationData => { - // Get SSM Associations + return new Promise(async resolveSystemManagerAssociationData => { + // Get SystemManager Association const associations = await getAssociationsForRegion(ssm) if (!isEmpty(associations)) { @@ -115,7 +115,7 @@ export default async ({ ) } - resolveSsmAssociationData() + resolveSystemManagerAssociationData() }) }) diff --git a/src/services/ssmAssociation/format.ts b/src/services/systemsManagerAssociation/format.ts similarity index 81% rename from src/services/ssmAssociation/format.ts rename to src/services/systemsManagerAssociation/format.ts index 4382c82e..89cde2f9 100644 --- a/src/services/ssmAssociation/format.ts +++ b/src/services/systemsManagerAssociation/format.ts @@ -1,17 +1,17 @@ -import { RawAwsSsmAssociation } from './data' -import { AwsSsmAssociation } from '../../types/generated' -import { ssmAssociationArn } from '../../utils/generateArns' -import { AssociationStatusAggregatedCount, TargetMap, TargetMaps } from 'aws-sdk/clients/ssm' +import { RawAwsSystemManagerAssociation } from './data' +import { AwsSystemManagerAssociation } from '../../types/generated' +import { systemManagerAssociationArn } from '../../utils/generateArns' +import { AssociationStatusAggregatedCount, TargetMaps } from 'aws-sdk/clients/ssm' export default ({ service, account, region, }: { - service: RawAwsSsmAssociation + service: RawAwsSystemManagerAssociation account: string region: string -}): AwsSsmAssociation => { +}): AwsSystemManagerAssociation => { const { Name: documentArn, InstanceId: instanceId, @@ -27,7 +27,7 @@ export default ({ TargetMaps: targetMaps, } = service - const arn = ssmAssociationArn({ region, account, id: associationId }) + const arn = systemManagerAssociationArn({ region, account, id: associationId }) const formatStatusAggregatedCount = (aggregatedCount: AssociationStatusAggregatedCount): {id: string, key: string, count: number}[] => { const result: {id: string, key: string, count: number}[] = [] diff --git a/src/services/ssmDocument/index.ts b/src/services/systemsManagerAssociation/index.ts similarity index 74% rename from src/services/ssmDocument/index.ts rename to src/services/systemsManagerAssociation/index.ts index 9e5326e9..b8da0d4b 100644 --- a/src/services/ssmDocument/index.ts +++ b/src/services/systemsManagerAssociation/index.ts @@ -4,7 +4,7 @@ import format from './format' import getData from './data' import mutation from './mutation' -export default class Acm extends BaseService implements Service { +export default class SystemManagerAssociation extends BaseService implements Service { format = format.bind(this) getData = getData.bind(this) diff --git a/src/services/systemsManagerAssociation/mutation.ts b/src/services/systemsManagerAssociation/mutation.ts new file mode 100644 index 00000000..72cc16e0 --- /dev/null +++ b/src/services/systemsManagerAssociation/mutation.ts @@ -0,0 +1,5 @@ +export default `mutation($input: [AddawsSystemManagerAssociationInput!]!) { + addawsSystemManagerAssociation(input: $input, upsert: true) { + numUids + } +}` \ No newline at end of file diff --git a/src/services/ssmAssociation/schema.graphql b/src/services/systemsManagerAssociation/schema.graphql similarity index 73% rename from src/services/ssmAssociation/schema.graphql rename to src/services/systemsManagerAssociation/schema.graphql index eb97fb51..ef0da567 100644 --- a/src/services/ssmAssociation/schema.graphql +++ b/src/services/systemsManagerAssociation/schema.graphql @@ -1,4 +1,4 @@ -type awsSsmAssociationTargets +type awsSystemManagerAssociationTargets @generate( query: { get: false, query: true, aggregate: false } mutation: { add: false, delete: false } @@ -9,7 +9,7 @@ type awsSsmAssociationTargets value: [String] @search(by: [hash, regexp]) } -type awsSsmAssociationOverviewStatusAggregatedCount +type awsSystemManagerAssociationOverviewStatusAggregatedCount @generate( query: { get: false, query: true, aggregate: false } mutation: { add: false, delete: false } @@ -20,7 +20,7 @@ type awsSsmAssociationOverviewStatusAggregatedCount value: Int @search } -type awsSsmAssociationOverview +type awsSystemManagerAssociationOverview @generate( query: { get: false, query: true, aggregate: false } mutation: { add: false, delete: false } @@ -28,10 +28,10 @@ type awsSsmAssociationOverview ) { status: String @search(by: [hash, regexp]) detailedStatus: String @search(by: [hash, regexp]) - associationStatusAggregatedCount: [awsSsmAssociationOverviewStatusAggregatedCount] + associationStatusAggregatedCount: [awsSystemManagerAssociationOverviewStatusAggregatedCount] } -type awsSsmAssociationTargetMaps +type awsSystemManagerAssociationTargetMaps @generate( query: { get: false, query: true, aggregate: false } mutation: { add: false, delete: false } @@ -42,17 +42,17 @@ type awsSsmAssociationTargetMaps value: [String] @search(by: [hash, regexp]) } -type awsSsmAssociation implements awsBaseService @key(fields: "arn") { +type awsSystemManagerAssociation implements awsBaseService @key(fields: "arn") { documentArn: String @search(by: [hash, regexp]) instanceId: String @search(by: [hash, regexp]) associationId: String @search(by: [hash, regexp]) associationVersion: String @search(by: [hash, regexp]) documentVersion: String @search(by: [hash, regexp]) - targets: [awsSsmAssociationTargets] + targets: [awsSystemManagerAssociationTargets] lastExecutionDate: DateTime @search(by: [day]) - overview: awsSsmAssociationOverview + overview: awsSystemManagerAssociationOverview scheduleExpression: String @search(by: [hash, regexp]) associationName: String @search(by: [hash, regexp]) scheduleOffset: Int @search - targetMaps: [awsSsmAssociationTargetMaps] + targetMaps: [awsSystemManagerAssociationTargetMaps] } diff --git a/src/types/generated.ts b/src/types/generated.ts index 8d9d85ca..2dc83a60 100644 --- a/src/types/generated.ts +++ b/src/types/generated.ts @@ -4351,82 +4351,6 @@ export type AwsSqs = AwsBaseService & { visibilityTimeout?: Maybe; }; -export type AwsSsmActivation = AwsBaseService & { - activationId?: Maybe; - createdDate?: Maybe; - defaultInstanceName?: Maybe; - description?: Maybe; - expirationDate?: Maybe; - expired?: Maybe; - iamRole?: Maybe; - registrationLimit?: Maybe; - registrationsCount?: Maybe; - tags?: Maybe>>; -}; - -export type AwsSsmAssociation = AwsBaseService & { - associationId?: Maybe; - associationName?: Maybe; - associationVersion?: Maybe; - documentArn?: Maybe; - documentVersion?: Maybe; - instanceId?: Maybe; - lastExecutionDate?: Maybe; - overview?: Maybe; - scheduleExpression?: Maybe; - scheduleOffset?: Maybe; - targetMaps?: Maybe>>; - targets?: Maybe>>; -}; - -export type AwsSsmAssociationOverview = { - associationStatusAggregatedCount?: Maybe>>; - detailedStatus?: Maybe; - status?: Maybe; -}; - -export type AwsSsmAssociationOverviewStatusAggregatedCount = { - id: Scalars['String']; - key?: Maybe; - value?: Maybe; -}; - -export type AwsSsmAssociationTargetMaps = { - id: Scalars['String']; - key?: Maybe; - value?: Maybe>>; -}; - -export type AwsSsmAssociationTargets = { - id: Scalars['String']; - key?: Maybe; - value?: Maybe>>; -}; - -export type AwsSsmDocument = AwsBaseService & { - author?: Maybe; - createdDate?: Maybe; - displayName?: Maybe; - documentFormat?: Maybe; - documentType?: Maybe; - documentVersion?: Maybe; - name?: Maybe; - owner?: Maybe; - platformTypes?: Maybe>>; - requires?: Maybe>>; - reviewStatus?: Maybe; - schemaVersion?: Maybe; - tags?: Maybe>>; - targetType?: Maybe; - versionName?: Maybe; -}; - -export type AwsSsmDocumentRequires = { - id: Scalars['String']; - name?: Maybe; - version?: Maybe; -}; - export type AwsSubnet = AwsBaseService & { alb?: Maybe>>; asg?: Maybe>>; @@ -4474,6 +4398,58 @@ export type AwsSuspendedProcess = { suspensionReason?: Maybe; }; +export type AwsSystemManagerActivation = AwsBaseService & { + activationId?: Maybe; + createdDate?: Maybe; + defaultInstanceName?: Maybe; + description?: Maybe; + expirationDate?: Maybe; + expired?: Maybe; + iamRole?: Maybe; + registrationLimit?: Maybe; + registrationsCount?: Maybe; + tags?: Maybe>>; +}; + +export type AwsSystemManagerAssociation = AwsBaseService & { + associationId?: Maybe; + associationName?: Maybe; + associationVersion?: Maybe; + documentArn?: Maybe; + documentVersion?: Maybe; + instanceId?: Maybe; + lastExecutionDate?: Maybe; + overview?: Maybe; + scheduleExpression?: Maybe; + scheduleOffset?: Maybe; + targetMaps?: Maybe>>; + targets?: Maybe>>; +}; + +export type AwsSystemManagerAssociationOverview = { + associationStatusAggregatedCount?: Maybe>>; + detailedStatus?: Maybe; + status?: Maybe; +}; + +export type AwsSystemManagerAssociationOverviewStatusAggregatedCount = { + id: Scalars['String']; + key?: Maybe; + value?: Maybe; +}; + +export type AwsSystemManagerAssociationTargetMaps = { + id: Scalars['String']; + key?: Maybe; + value?: Maybe>>; +}; + +export type AwsSystemManagerAssociationTargets = { + id: Scalars['String']; + key?: Maybe; + value?: Maybe>>; +}; + export type AwsSystemsManagerDocument = AwsBaseService & { createdDate?: Maybe; documentFormat?: Maybe; diff --git a/src/utils/generateArns.ts b/src/utils/generateArns.ts index 14ee3231..97f6e62e 100644 --- a/src/utils/generateArns.ts +++ b/src/utils/generateArns.ts @@ -346,7 +346,7 @@ export const transitGatewayRouteTableArn = ({ id: string }): string => `arn:aws:ec2:${region}:${account}:transit-gateway-routetable/${id}` -export const ssmActivationArn = ({ +export const systemManagerActivationArn = ({ region, account, id, @@ -356,7 +356,7 @@ export const ssmActivationArn = ({ id: string }): string => `arn:aws:ssm:${region}:${account}:activation/${id}` -export const ssmAssociationArn = ({ +export const systemManagerAssociationArn = ({ region, account, id, From 869e27eeffd720b17e010515259312b286db93d0 Mon Sep 17 00:00:00 2001 From: James Zhou Date: Sun, 21 May 2023 18:15:56 -0500 Subject: [PATCH 3/3] add association to instance connection --- .../systemsManagerAssociation/connections.ts | 45 +++++++++++++++++++ .../systemsManagerAssociation/index.ts | 3 ++ .../systemsManagerAssociation/schema.graphql | 1 + src/services/systemsManagerInstance/index.ts | 22 ++++----- .../systemsManagerInstance/schema.graphql | 1 + src/types/generated.ts | 2 + 6 files changed, 63 insertions(+), 11 deletions(-) create mode 100644 src/services/systemsManagerAssociation/connections.ts diff --git a/src/services/systemsManagerAssociation/connections.ts b/src/services/systemsManagerAssociation/connections.ts new file mode 100644 index 00000000..510f83fb --- /dev/null +++ b/src/services/systemsManagerAssociation/connections.ts @@ -0,0 +1,45 @@ +import { ServiceConnection } from '@cloudgraph/sdk' +import services from '../../enums/services' +import { RawAwsSystemManagerAssociation } from './data'; +import { RawAwsSystemsManagerInstance } from '../systemsManagerInstance/data'; + +export default ({ + service: systemsManagerAssociation, + data, + region, +}: { + service: RawAwsSystemManagerAssociation + data: Array<{ name: string; data: { [property: string]: any[] } }> + region: string +}): { + [property: string]: ServiceConnection[] +} => { + const { AssociationId, InstanceId } = systemsManagerAssociation + const connections: ServiceConnection[] = [] + + /** + * Find SystemManagerInstances used in SystemsManagerAssociation + */ + const instances: { + name: string + data: { [property: string]: any[] } + } = data.find(({ name }) => name === services.systemsManagerInstance) + if (instances?.data?.[region]) { + const systemsManagerInstanceInRegion: RawAwsSystemsManagerInstance[] = instances.data[region].find( + ({ InstanceId: iId }: RawAwsSystemsManagerInstance) => iId === InstanceId + ) + if (systemsManagerInstanceInRegion) { + connections.push({ + id: InstanceId, + resourceType: services.systemsManagerInstance, + relation: 'child', + field: 'systemsManagerInstances', + }) + } + } + + const result = { + [AssociationId]: connections, + } + return result +} diff --git a/src/services/systemsManagerAssociation/index.ts b/src/services/systemsManagerAssociation/index.ts index b8da0d4b..36d81c45 100644 --- a/src/services/systemsManagerAssociation/index.ts +++ b/src/services/systemsManagerAssociation/index.ts @@ -1,12 +1,15 @@ import { Service } from '@cloudgraph/sdk' import BaseService from '../base' import format from './format' +import getConnections from '../systemsManagerAssociation/connections'; import getData from './data' import mutation from './mutation' export default class SystemManagerAssociation extends BaseService implements Service { format = format.bind(this) + getConnections = getConnections.bind(this) + getData = getData.bind(this) mutation = mutation diff --git a/src/services/systemsManagerAssociation/schema.graphql b/src/services/systemsManagerAssociation/schema.graphql index ef0da567..0b9ca680 100644 --- a/src/services/systemsManagerAssociation/schema.graphql +++ b/src/services/systemsManagerAssociation/schema.graphql @@ -55,4 +55,5 @@ type awsSystemManagerAssociation implements awsBaseService @key(fields: "arn") { associationName: String @search(by: [hash, regexp]) scheduleOffset: Int @search targetMaps: [awsSystemManagerAssociationTargetMaps] + systemsManagerInstances: [awsSystemsManagerInstance] @hasInverse(field: systemManagerAssociations) } diff --git a/src/services/systemsManagerInstance/index.ts b/src/services/systemsManagerInstance/index.ts index 8e2b63d1..00cb6e33 100644 --- a/src/services/systemsManagerInstance/index.ts +++ b/src/services/systemsManagerInstance/index.ts @@ -1,14 +1,14 @@ import { Service } from '@cloudgraph/sdk' - import BaseService from '../base' - import format from './format' - import getData from './data' - import mutation from './mutation' +import BaseService from '../base' +import format from './format' +import getData from './data' +import mutation from './mutation' - export default class SystemsManagerInstance extends BaseService implements Service { - format = format.bind(this) - - getData = getData.bind(this) - - mutation = mutation - } +export default class SystemsManagerInstance extends BaseService implements Service { + format = format.bind(this) + + getData = getData.bind(this) + + mutation = mutation +} \ No newline at end of file diff --git a/src/services/systemsManagerInstance/schema.graphql b/src/services/systemsManagerInstance/schema.graphql index e4ff5624..c1ff45cd 100644 --- a/src/services/systemsManagerInstance/schema.graphql +++ b/src/services/systemsManagerInstance/schema.graphql @@ -22,6 +22,7 @@ type awsSystemsManagerInstance implements awsBaseService @key(fields: "arn") { sourceType: String @search(by: [hash, regexp]) iamRole: [awsIamRole] @hasInverse(field: systemsManagerInstances) ec2Instance: [awsEc2] @hasInverse(field: systemsManagerInstance) + systemManagerAssociations: [awsSystemManagerAssociation] @hasInverse(field: systemsManagerInstances) } type systemsManagerInstanceAssociationOverview { diff --git a/src/types/generated.ts b/src/types/generated.ts index 2dc83a60..7237d8ec 100644 --- a/src/types/generated.ts +++ b/src/types/generated.ts @@ -4422,6 +4422,7 @@ export type AwsSystemManagerAssociation = AwsBaseService & { overview?: Maybe; scheduleExpression?: Maybe; scheduleOffset?: Maybe; + systemsManagerInstances?: Maybe>>; targetMaps?: Maybe>>; targets?: Maybe>>; }; @@ -4499,6 +4500,7 @@ export type AwsSystemsManagerInstance = AwsBaseService & { resourceType?: Maybe; sourceId?: Maybe; sourceType?: Maybe; + systemManagerAssociations?: Maybe>>; }; export type AwsTag = {