1- import { Config } from 'aws-sdk'
2- import ECS , { Service } from 'aws-sdk/clients/ecs'
31import CloudGraph from '@cloudgraph/sdk'
4- import flatMap from 'lodash/flatMap'
2+ import { Config } from 'aws-sdk'
3+ import ECS , { ListServicesRequest , Service } from 'aws-sdk/clients/ecs'
54import groupBy from 'lodash/groupBy'
65import isEmpty from 'lodash/isEmpty'
6+ import services from '../../enums/services'
77import awsLoggerText from '../../properties/logger'
88import { AwsTag , TagMap } from '../../types'
9- import { convertAwsTagsToTagMap } from '../../utils/format'
10- import AwsErrorLog from '../../utils/errorLog'
119import { initTestEndpoint } from '../../utils'
12- import EcsClusterClass from '../ecsCluster'
13- import { RawAwsEcsCluster } from '../ecsCluster/data'
10+ import AwsErrorLog from '../../utils/errorLog'
11+ import { convertAwsTagsToTagMap } from '../../utils/format'
12+ import { listClusterArnsForRegion , RawAwsEcsCluster } from '../ecsCluster/data'
1413
1514const lt = { ...awsLoggerText }
1615const { logger } = CloudGraph
1716const serviceName = 'ECS service'
1817const errorLog = new AwsErrorLog ( serviceName )
1918const endpoint = initTestEndpoint ( serviceName )
20-
19+ const MAX_ITEMS = 100
2120export interface RawAwsEcsService extends Service {
2221 region : string
2322 Tags ?: TagMap
23+ ClusterArn : string
2424}
2525
26+ export const listServicesArnForRegion = async (
27+ ecs : ECS ,
28+ cluster : string
29+ ) : Promise < string [ ] > =>
30+ new Promise < string [ ] > ( resolve => {
31+ const serviceArnList : string [ ] = [ ]
32+ const getRestApisOpts : ListServicesRequest = {
33+ cluster,
34+ maxResults : MAX_ITEMS ,
35+ }
36+ const listAllServiceArns = ( token ?: string ) : void => {
37+ if ( token ) {
38+ getRestApisOpts . nextToken = token
39+ }
40+ try {
41+ ecs . listServices ( { cluster } , ( err , data ) => {
42+ if ( err ) {
43+ errorLog . generateAwsErrorLog ( {
44+ functionName : 'ecs:listServices' ,
45+ err,
46+ } )
47+ }
48+
49+ if ( isEmpty ( data ) ) {
50+ return resolve ( [ ] )
51+ }
52+
53+ const { serviceArns = [ ] , nextToken } = data
54+
55+ serviceArnList . push ( ...serviceArns )
56+
57+ if ( nextToken ) {
58+ listAllServiceArns ( nextToken )
59+ } else {
60+ resolve ( serviceArnList )
61+ }
62+ } )
63+ } catch ( error ) {
64+ resolve ( [ ] )
65+ }
66+ }
67+ listAllServiceArns ( )
68+ } )
69+
2670export default async ( {
2771 regions,
2872 config,
73+ rawData,
2974} : {
3075 regions : string
3176 config : Config
77+ rawData : any
3278} ) : Promise < {
3379 [ region : string ] : RawAwsEcsService [ ]
3480} > =>
3581 new Promise ( async resolve => {
3682 const ecsServices : RawAwsEcsService [ ] = [ ]
37- const ecsClusterClass = new EcsClusterClass ( { logger : CloudGraph . logger } )
38- const clusterResult = await ecsClusterClass . getData ( {
39- ...config ,
40- regions,
41- } )
42- const ecsClusters : RawAwsEcsCluster [ ] = flatMap ( clusterResult )
83+ const regionPromises = [ ]
84+ const ecsClusterData : Array < { region : string ; clusterArn : string } > = [ ]
85+
86+ const existingData : { [ property : string ] : RawAwsEcsCluster [ ] } =
87+ rawData ?. find ( ( { name } ) => name === services . ecsCluster ) ?. data || { }
88+
89+ if ( isEmpty ( existingData ) ) {
90+ // Refresh data
91+ regions . split ( ',' ) . map ( region => {
92+ const ecsClient = new ECS ( { ...config , region, endpoint } )
93+ const regionPromise = new Promise < void > ( async resolveRegion => {
94+ const clusterArnList = await listClusterArnsForRegion ( ecsClient )
95+ if ( ! isEmpty ( clusterArnList ) ) {
96+ ecsClusterData . push (
97+ ...clusterArnList . map ( arn => ( {
98+ clusterArn : arn ,
99+ region,
100+ } ) )
101+ )
102+ }
103+ resolveRegion ( )
104+ } )
105+ regionPromises . push ( regionPromise )
106+ return null
107+ } )
108+ await Promise . all ( regionPromises )
109+ } else {
110+ // Uses existing data
111+ regions . split ( ',' ) . map ( region => {
112+ if ( ! isEmpty ( existingData [ region ] ) ) {
113+ ecsClusterData . push (
114+ ...existingData [ region ] . map ( ecsCluster => ( {
115+ clusterArn : ecsCluster . clusterArn ,
116+ region,
117+ } ) )
118+ )
119+ }
120+ return null
121+ } )
122+ }
43123
44124 /**
45125 * Get the arns of all the services
46126 */
47127 let ecsServiceArns : any = await Promise . all (
48- ecsClusters . map (
49- async ( { clusterName : cluster , region } ) =>
128+ ecsClusterData . map (
129+ async ( { clusterArn : cluster , region } ) =>
50130 new Promise ( resolveEcsData =>
51131 new ECS ( { ...config , region, endpoint } ) . listServices (
52132 { cluster } ,
@@ -81,10 +161,10 @@ export default async ({
81161 * Get all the details for each service
82162 */
83163 const ecsServicePromises = ecsServiceArns . map (
84- async ( { region, serviceArns : services , cluster } ) =>
164+ async ( { region, serviceArns, cluster } ) =>
85165 new Promise < void > ( resolveEcsData =>
86166 new ECS ( { ...config , region, endpoint } ) . describeServices (
87- { services, cluster } ,
167+ { services : serviceArns , cluster } ,
88168 ( err , data ) => {
89169 if ( err ) {
90170 errorLog . generateAwsErrorLog ( {
@@ -97,14 +177,15 @@ export default async ({
97177 return resolveEcsData ( )
98178 }
99179
100- const { services = [ ] } = data
180+ const { services : servicesList = [ ] } = data
101181
102- logger . debug ( lt . fetchedEcsServices ( services . length ) )
182+ logger . debug ( lt . fetchedEcsServices ( servicesList . length ) )
103183
104184 ecsServices . push (
105- ...services . map ( service => ( {
185+ ...servicesList . map ( service => ( {
106186 region,
107187 ...service ,
188+ ClusterArn : cluster ,
108189 Tags : convertAwsTagsToTagMap ( service . tags as AwsTag [ ] ) ,
109190 } ) )
110191 )
0 commit comments