@spinnaker/ecs 2026.2.2 → 2026.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. package/dist/ecs.module.d.ts +3 -1
  2. package/dist/ecsCluster/ecsCluster.read.service.d.ts +2 -3
  3. package/dist/iamRoles/iamRole.read.service.d.ts +1 -2
  4. package/dist/index.d.ts +5 -0
  5. package/dist/index.js +1 -1
  6. package/dist/index.js.map +1 -1
  7. package/dist/instance/details/EcsInstanceDetails.d.ts +50 -0
  8. package/dist/loadBalancer/loadBalancer.transformer.d.ts +1 -5
  9. package/dist/loadBalancer/targetGroup.states.d.ts +2 -1
  10. package/dist/metricAlarm/metricAlarm.read.service.d.ts +1 -2
  11. package/dist/pipeline/stages/cloneServerGroup/ecsCloneServerGroupStage.d.ts +1 -0
  12. package/dist/pipeline/stages/common/EcsServerGroupStepLabel.d.ts +7 -0
  13. package/dist/pipeline/stages/common/EcsStageConfigs.d.ts +11 -0
  14. package/dist/pipeline/stages/destroyAsg/ecsDestroyAsgStage.d.ts +1 -2
  15. package/dist/pipeline/stages/disableAsg/ecsDisableAsgStage.d.ts +1 -2
  16. package/dist/pipeline/stages/disableCluster/ecsDisableClusterStage.d.ts +1 -2
  17. package/dist/pipeline/stages/enableAsg/ecsEnableAsgStage.d.ts +1 -2
  18. package/dist/pipeline/stages/findImageFromTags/EcsFindImageFromTagsExecutionDetails.d.ts +5 -0
  19. package/dist/pipeline/stages/findImageFromTags/ecsFindImageFromTagStage.d.ts +1 -2
  20. package/dist/pipeline/stages/resizeAsg/ecsResizeAsgStage.d.ts +1 -2
  21. package/dist/pipeline/stages/scaleDownCluster/ecsScaleDownClusterStage.d.ts +1 -2
  22. package/dist/pipeline/stages/shrinkCluster/ecsShrinkClusterStage.d.ts +1 -2
  23. package/dist/placementStrategy/placementStrategy.service.d.ts +0 -1
  24. package/dist/secrets/secret.read.service.d.ts +1 -2
  25. package/dist/securityGroup/details/EcsSecurityGroupDetails.d.ts +45 -0
  26. package/dist/securityGroup/securityGroup.reader.d.ts +0 -1
  27. package/dist/securityGroup/securityGroup.transformer.d.ts +3 -2
  28. package/dist/serverGroup/configure/dockerImage.util.d.ts +3 -0
  29. package/dist/serverGroup/configure/serverGroupCommandBuilder.service.d.ts +111 -2
  30. package/dist/serverGroup/configure/serverGroupConfiguration.service.d.ts +13 -63
  31. package/dist/serverGroup/configure/wizard/EcsCloneServerGroupModal.d.ts +64 -0
  32. package/dist/serverGroup/configure/wizard/capacityProvider/CapacityProvider.d.ts +29 -4
  33. package/dist/serverGroup/configure/wizard/container/Container.d.ts +3 -3
  34. package/dist/serverGroup/configure/wizard/networking/Networking.d.ts +3 -3
  35. package/dist/serverGroup/configure/wizard/pages/AdvancedSettings.d.ts +3 -0
  36. package/dist/serverGroup/configure/wizard/pages/BasicSettings.d.ts +3 -0
  37. package/dist/serverGroup/configure/wizard/pages/ContainerSettings.d.ts +3 -0
  38. package/dist/serverGroup/configure/wizard/pages/HorizontalScalingSettings.d.ts +3 -0
  39. package/dist/serverGroup/configure/wizard/pages/LoggingSettings.d.ts +3 -0
  40. package/dist/serverGroup/configure/wizard/pages/NetworkingSettings.d.ts +3 -0
  41. package/dist/serverGroup/configure/wizard/pages/ServiceDiscoverySettings.d.ts +3 -0
  42. package/dist/serverGroup/configure/wizard/pages/TaskDefinitionSettings.d.ts +3 -0
  43. package/dist/serverGroup/configure/wizard/pages/common.d.ts +8 -0
  44. package/dist/serverGroup/configure/wizard/pages/validation.d.ts +22 -0
  45. package/dist/serverGroup/configure/wizard/serviceDiscovery/ServiceDiscovery.d.ts +5 -3
  46. package/dist/serverGroup/configure/wizard/taskDefinition/TaskDefinition.d.ts +3 -3
  47. package/dist/serverGroup/details/EcsServerGroupActions.d.ts +6 -0
  48. package/dist/serverGroup/details/ecsServerGroupDetailsGetter.d.ts +3 -0
  49. package/dist/serverGroup/details/resize/EcsResizeServerGroupModal.d.ts +43 -0
  50. package/dist/serverGroup/details/resize/index.d.ts +1 -0
  51. package/dist/serverGroup/details/rollback/EcsRollbackServerGroupModal.d.ts +46 -0
  52. package/dist/serverGroup/details/rollback/index.d.ts +1 -0
  53. package/dist/serverGroup/details/sections/EcsServerGroupDetailsSections.d.ts +9 -0
  54. package/dist/serverGroup/details/sections/EcsServerGroupEventsSection.d.ts +3 -0
  55. package/dist/serverGroup/details/sections/EcsServerGroupInformationSection.d.ts +3 -0
  56. package/dist/serverGroup/events/EcsServerGroupEventsModal.d.ts +22 -0
  57. package/dist/serverGroup/events/EventsLink.d.ts +2 -0
  58. package/dist/serverGroup/events/serverGroupEventsReader.service.d.ts +1 -1
  59. package/dist/serverGroup/serverGroup.transformer.d.ts +1 -2
  60. package/dist/serviceDiscovery/serviceDiscovery.read.service.d.ts +1 -1
  61. package/package.json +3 -9
  62. package/src/ecs.module.spec.ts +86 -0
  63. package/src/ecs.module.ts +68 -84
  64. package/src/ecsCluster/ecsCluster.read.service.ts +3 -9
  65. package/src/iamRoles/iamRole.read.service.ts +1 -7
  66. package/src/index.ts +6 -0
  67. package/src/instance/details/EcsInstanceDetails.spec.tsx +426 -0
  68. package/src/instance/details/EcsInstanceDetails.tsx +474 -0
  69. package/src/loadBalancer/details/loadBalancerDetails.tsx +1 -1
  70. package/src/loadBalancer/details/targetGroupDetails.tsx +1 -1
  71. package/src/loadBalancer/loadBalancer.transformer.ts +2 -7
  72. package/src/loadBalancer/targetGroup.states.ts +55 -53
  73. package/src/metricAlarm/metricAlarm.read.service.ts +1 -7
  74. package/src/pipeline/stages/cloneServerGroup/ecsCloneServerGroupStage.js +22 -94
  75. package/src/pipeline/stages/common/EcsServerGroupStepLabel.tsx +16 -0
  76. package/src/pipeline/stages/common/EcsStageConfigs.tsx +587 -0
  77. package/src/pipeline/stages/destroyAsg/ecsDestroyAsgStage.js +29 -65
  78. package/src/pipeline/stages/disableAsg/ecsDisableAsgStage.js +27 -70
  79. package/src/pipeline/stages/disableCluster/ecsDisableClusterStage.js +21 -84
  80. package/src/pipeline/stages/enableAsg/ecsEnableAsgStage.js +22 -73
  81. package/src/pipeline/stages/findImageFromTags/EcsFindImageFromTagsExecutionDetails.tsx +40 -0
  82. package/src/pipeline/stages/findImageFromTags/ecsFindImageFromTagStage.js +12 -24
  83. package/src/pipeline/stages/resizeAsg/ecsResizeAsgStage.js +30 -128
  84. package/src/pipeline/stages/scaleDownCluster/ecsScaleDownClusterStage.js +24 -78
  85. package/src/pipeline/stages/shrinkCluster/ecsShrinkClusterStage.js +19 -73
  86. package/src/placementStrategy/placementStrategy.service.ts +0 -6
  87. package/src/secrets/secret.read.service.ts +1 -7
  88. package/src/securityGroup/details/EcsSecurityGroupDetails.spec.tsx +245 -0
  89. package/src/securityGroup/details/EcsSecurityGroupDetails.tsx +285 -0
  90. package/src/securityGroup/securityGroup.reader.ts +0 -5
  91. package/src/securityGroup/securityGroup.transformer.js +5 -13
  92. package/src/serverGroup/configure/dockerImage.util.ts +29 -0
  93. package/src/serverGroup/configure/serverGroupCommandBuilder.service.js +215 -278
  94. package/src/serverGroup/configure/serverGroupCommandBuilder.service.spec.ts +83 -0
  95. package/src/serverGroup/configure/serverGroupConfiguration.service.ts +16 -633
  96. package/src/serverGroup/configure/wizard/EcsCloneServerGroupModal.spec.tsx +2078 -0
  97. package/src/serverGroup/configure/wizard/EcsCloneServerGroupModal.tsx +712 -0
  98. package/src/serverGroup/configure/wizard/capacityProvider/CapacityProvider.tsx +98 -49
  99. package/src/serverGroup/configure/wizard/container/Container.spec.tsx +20 -8
  100. package/src/serverGroup/configure/wizard/container/Container.tsx +53 -24
  101. package/src/serverGroup/configure/wizard/networking/Networking.tsx +60 -38
  102. package/src/serverGroup/configure/wizard/pages/AdvancedSettings.tsx +290 -0
  103. package/src/serverGroup/configure/wizard/pages/BasicSettings.tsx +101 -0
  104. package/src/serverGroup/configure/wizard/pages/ContainerSettings.tsx +10 -0
  105. package/src/serverGroup/configure/wizard/pages/HorizontalScalingSettings.tsx +137 -0
  106. package/src/serverGroup/configure/wizard/pages/LoggingSettings.tsx +60 -0
  107. package/src/serverGroup/configure/wizard/pages/NetworkingSettings.tsx +10 -0
  108. package/src/serverGroup/configure/wizard/pages/ServiceDiscoverySettings.tsx +10 -0
  109. package/src/serverGroup/configure/wizard/pages/TaskDefinitionSettings.tsx +59 -0
  110. package/src/serverGroup/configure/wizard/pages/common.ts +10 -0
  111. package/src/serverGroup/configure/wizard/pages/validation.tsx +190 -0
  112. package/src/serverGroup/configure/wizard/serviceDiscovery/ServiceDiscovery.tsx +83 -34
  113. package/src/serverGroup/configure/wizard/taskDefinition/TaskDefinition.spec.tsx +21 -8
  114. package/src/serverGroup/configure/wizard/taskDefinition/TaskDefinition.tsx +63 -33
  115. package/src/serverGroup/details/EcsServerGroupActions.spec.tsx +244 -0
  116. package/src/serverGroup/details/EcsServerGroupActions.tsx +152 -0
  117. package/src/serverGroup/details/ecsServerGroupDetailsGetter.spec.ts +110 -0
  118. package/src/serverGroup/details/ecsServerGroupDetailsGetter.ts +73 -0
  119. package/src/serverGroup/details/resize/EcsResizeServerGroupModal.spec.tsx +130 -0
  120. package/src/serverGroup/details/resize/EcsResizeServerGroupModal.tsx +263 -0
  121. package/src/serverGroup/details/resize/index.ts +1 -0
  122. package/src/serverGroup/details/rollback/EcsRollbackServerGroupModal.spec.tsx +173 -0
  123. package/src/serverGroup/details/rollback/EcsRollbackServerGroupModal.tsx +285 -0
  124. package/src/serverGroup/details/rollback/index.ts +1 -0
  125. package/src/serverGroup/details/sections/EcsServerGroupDetailsSections.spec.tsx +130 -0
  126. package/src/serverGroup/details/sections/EcsServerGroupDetailsSections.tsx +172 -0
  127. package/src/serverGroup/details/sections/EcsServerGroupEventsSection.tsx +14 -0
  128. package/src/serverGroup/details/sections/EcsServerGroupInformationSection.tsx +25 -0
  129. package/src/serverGroup/events/EcsServerGroupEventsModal.spec.tsx +109 -0
  130. package/src/serverGroup/events/EcsServerGroupEventsModal.tsx +112 -0
  131. package/src/serverGroup/events/EventsLink.tsx +18 -0
  132. package/src/serverGroup/events/serverGroupEventsReader.service.spec.ts +41 -0
  133. package/src/serverGroup/events/serverGroupEventsReader.service.ts +2 -8
  134. package/src/serverGroup/serverGroup.transformer.spec.ts +10 -24
  135. package/src/serverGroup/serverGroup.transformer.ts +1 -5
  136. package/src/serviceDiscovery/serviceDiscovery.read.service.ts +1 -1
  137. package/dist/common/common.module.d.ts +0 -1
  138. package/dist/common/footer.component.d.ts +0 -1
  139. package/dist/instance/details/instance.details.controller.d.ts +0 -2
  140. package/dist/securityGroup/details/securityGroupDetail.controller.d.ts +0 -2
  141. package/dist/securityGroup/securityGroup.module.d.ts +0 -1
  142. package/dist/serverGroup/configure/wizard/CloneServerGroup.ecs.controller.d.ts +0 -2
  143. package/dist/serverGroup/configure/wizard/advancedSettings/advancedSettings.component.d.ts +0 -2
  144. package/dist/serverGroup/configure/wizard/horizontalScaling/horizontalScaling.component.d.ts +0 -2
  145. package/dist/serverGroup/configure/wizard/location/ServerGroupBasicSettings.controller.d.ts +0 -2
  146. package/dist/serverGroup/configure/wizard/logging/logging.component.d.ts +0 -1
  147. package/dist/serverGroup/details/resize/resizeCapacity.component.d.ts +0 -1
  148. package/dist/serverGroup/details/resize/resizeServerGroup.controller.d.ts +0 -2
  149. package/dist/serverGroup/details/rollback/rollbackServerGroup.controller.d.ts +0 -2
  150. package/dist/serverGroup/details/serverGroupDetails.ecs.controller.d.ts +0 -2
  151. package/dist/serverGroup/details/serverGroupDetails.module.d.ts +0 -1
  152. package/dist/serverGroup/events/events.component.d.ts +0 -3
  153. package/dist/serverGroup/events/events.controller.d.ts +0 -19
  154. package/dist/serverGroup/serverGroup.module.d.ts +0 -1
  155. package/src/common/common.module.ts +0 -6
  156. package/src/common/footer.component.ts +0 -29
  157. package/src/instance/details/instance.details.controller.js +0 -356
  158. package/src/instance/details/instanceDetails.html +0 -204
  159. package/src/pipeline/stages/cloneServerGroup/cloneServerGroupStage.html +0 -101
  160. package/src/pipeline/stages/cloneServerGroup/cloneServerGroupStepLabel.html +0 -1
  161. package/src/pipeline/stages/destroyAsg/destroyAsgStage.html +0 -9
  162. package/src/pipeline/stages/destroyAsg/destroyAsgStepLabel.html +0 -1
  163. package/src/pipeline/stages/disableAsg/disableAsgStage.html +0 -11
  164. package/src/pipeline/stages/disableAsg/disableAsgStepLabel.html +0 -1
  165. package/src/pipeline/stages/disableCluster/disableClusterStage.html +0 -26
  166. package/src/pipeline/stages/enableAsg/enableAsgStage.html +0 -11
  167. package/src/pipeline/stages/enableAsg/enableAsgStepLabel.html +0 -1
  168. package/src/pipeline/stages/findImageFromTags/findImageFromTagsExecutionDetails.html +0 -36
  169. package/src/pipeline/stages/findImageFromTags/findImageFromTagsStage.html +0 -9
  170. package/src/pipeline/stages/resizeAsg/resizeAsgStage.html +0 -87
  171. package/src/pipeline/stages/resizeAsg/resizeAsgStepLabel.html +0 -1
  172. package/src/pipeline/stages/scaleDownCluster/scaleDownClusterStage.html +0 -35
  173. package/src/pipeline/stages/shrinkCluster/shrinkClusterStage.html +0 -34
  174. package/src/securityGroup/details/securityGroupDetail.controller.js +0 -147
  175. package/src/securityGroup/details/securityGroupDetail.html +0 -104
  176. package/src/securityGroup/securityGroup.module.ts +0 -12
  177. package/src/serverGroup/configure/wizard/CloneServerGroup.ecs.controller.js +0 -259
  178. package/src/serverGroup/configure/wizard/advancedSettings/advancedSettings.component.html +0 -194
  179. package/src/serverGroup/configure/wizard/advancedSettings/advancedSettings.component.js +0 -17
  180. package/src/serverGroup/configure/wizard/advancedSettings/advancedSettings.html +0 -10
  181. package/src/serverGroup/configure/wizard/capacityProvider/capacityProvider.html +0 -11
  182. package/src/serverGroup/configure/wizard/container/container.html +0 -9
  183. package/src/serverGroup/configure/wizard/horizontalScaling/horizontalScaling.component.html +0 -118
  184. package/src/serverGroup/configure/wizard/horizontalScaling/horizontalScaling.component.js +0 -20
  185. package/src/serverGroup/configure/wizard/horizontalScaling/horizontalScaling.html +0 -13
  186. package/src/serverGroup/configure/wizard/location/ServerGroupBasicSettings.controller.js +0 -41
  187. package/src/serverGroup/configure/wizard/location/basicSettings.html +0 -137
  188. package/src/serverGroup/configure/wizard/logging/logging.component.html +0 -29
  189. package/src/serverGroup/configure/wizard/logging/logging.component.ts +0 -12
  190. package/src/serverGroup/configure/wizard/logging/logging.html +0 -7
  191. package/src/serverGroup/configure/wizard/networking/networking.html +0 -9
  192. package/src/serverGroup/configure/wizard/serverGroupWizard.html +0 -55
  193. package/src/serverGroup/configure/wizard/serviceDiscovery/serviceDiscovery.html +0 -11
  194. package/src/serverGroup/configure/wizard/taskDefinition/taskDefinition.html +0 -51
  195. package/src/serverGroup/configure/wizard/templateSelection/templateSelection.html +0 -9
  196. package/src/serverGroup/configure/wizard/verticalScaling/verticalScaling.html +0 -10
  197. package/src/serverGroup/details/resize/resizeCapacity.component.html +0 -94
  198. package/src/serverGroup/details/resize/resizeCapacity.component.ts +0 -14
  199. package/src/serverGroup/details/resize/resizeServerGroup.controller.js +0 -85
  200. package/src/serverGroup/details/resize/resizeServerGroup.html +0 -28
  201. package/src/serverGroup/details/rollback/rollbackServerGroup.controller.js +0 -97
  202. package/src/serverGroup/details/rollback/rollbackServerGroup.html +0 -67
  203. package/src/serverGroup/details/serverGroupDetails.ecs.controller.js +0 -366
  204. package/src/serverGroup/details/serverGroupDetails.html +0 -216
  205. package/src/serverGroup/details/serverGroupDetails.module.ts +0 -5
  206. package/src/serverGroup/events/events.component.ts +0 -35
  207. package/src/serverGroup/events/events.controller.ts +0 -45
  208. package/src/serverGroup/events/events.html +0 -36
  209. package/src/serverGroup/serverGroup.module.ts +0 -6
@@ -0,0 +1,474 @@
1
+ import React from 'react';
2
+
3
+ import type { IAmazonHealth } from '@spinnaker/amazon';
4
+ import { InstanceInformation, InstanceStatus, VpcTag } from '@spinnaker/amazon';
5
+ import type { Application, IInstanceDetailsProps, IMoniker, IRouterInjectedProps } from '@spinnaker/core';
6
+ import {
7
+ CollapsibleSection,
8
+ ConsoleOutputLink,
9
+ CopyToClipboard,
10
+ InstanceDetailsHeader,
11
+ InstanceLinks,
12
+ InstanceReader,
13
+ LabeledValue,
14
+ RecentHistoryService,
15
+ SubnetTag,
16
+ withRouter,
17
+ } from '@spinnaker/core';
18
+
19
+ interface IEcsInstanceParams {
20
+ account?: string;
21
+ accountId?: string;
22
+ instanceId: string;
23
+ provider?: string;
24
+ region?: string;
25
+ [key: string]: any;
26
+ }
27
+
28
+ export interface IEcsInstanceDetailsProps extends Partial<IInstanceDetailsProps> {
29
+ accountId?: string;
30
+ app: Application;
31
+ environment?: string;
32
+ instance?: IEcsInstanceParams;
33
+ moniker?: IMoniker;
34
+ $stateParams?: IInstanceDetailsProps['$stateParams'] & Partial<IEcsInstanceParams>;
35
+ }
36
+
37
+ interface IEcsInstanceLookup {
38
+ account?: string;
39
+ loadBalancers?: string[];
40
+ region?: string;
41
+ serverGroup?: string;
42
+ summary?: any;
43
+ targetGroups?: string[];
44
+ vpcId?: string;
45
+ }
46
+
47
+ interface IEcsLoadedInstance {
48
+ [key: string]: any;
49
+ account?: string;
50
+ baseIpAddress?: string;
51
+ healthMetrics?: IAmazonHealth[];
52
+ instanceId?: string;
53
+ region?: string;
54
+ }
55
+
56
+ interface IEcsInstanceDetailsState {
57
+ instance?: IEcsLoadedInstance;
58
+ instanceIdNotFound?: string;
59
+ loading: boolean;
60
+ }
61
+
62
+ function matchesInstance(candidate: any, instanceId: string): boolean {
63
+ return candidate === instanceId || candidate?.id === instanceId;
64
+ }
65
+
66
+ function matchesScope(candidate: any, instance: IEcsInstanceParams): boolean {
67
+ return (
68
+ (!instance.account || candidate.account === instance.account) &&
69
+ (!instance.region || candidate.region === instance.region)
70
+ );
71
+ }
72
+
73
+ function targetGroupNames(targetGroups: any): string[] {
74
+ const groups = Array.isArray(targetGroups) ? targetGroups : targetGroups ? [targetGroups] : [];
75
+ return groups
76
+ .map((targetGroup) =>
77
+ typeof targetGroup === 'string' ? targetGroup : targetGroup.targetGroupName || targetGroup.name,
78
+ )
79
+ .filter(Boolean);
80
+ }
81
+
82
+ function findInstance(app: Application, instance: IEcsInstanceParams): IEcsInstanceLookup | undefined {
83
+ if (app.isStandalone || !app.serverGroups) {
84
+ return {
85
+ account: instance.account || instance.accountId,
86
+ region: instance.region,
87
+ summary: instance,
88
+ };
89
+ }
90
+
91
+ for (const serverGroup of app.serverGroups.data || []) {
92
+ if (!matchesScope(serverGroup, instance)) {
93
+ continue;
94
+ }
95
+ const summary = (serverGroup.instances || []).find((candidate: any) =>
96
+ matchesInstance(candidate, instance.instanceId),
97
+ );
98
+ if (summary) {
99
+ return {
100
+ account: serverGroup.account,
101
+ loadBalancers: serverGroup.loadBalancers || [],
102
+ region: serverGroup.region,
103
+ serverGroup: serverGroup.name,
104
+ summary,
105
+ targetGroups: targetGroupNames(serverGroup.targetGroups || serverGroup.targetGroup),
106
+ vpcId: serverGroup.vpcId,
107
+ };
108
+ }
109
+ }
110
+
111
+ for (const loadBalancer of app.loadBalancers?.data || []) {
112
+ if (!matchesScope(loadBalancer, instance)) {
113
+ continue;
114
+ }
115
+ const summary = (loadBalancer.instances || []).find((candidate: any) =>
116
+ matchesInstance(candidate, instance.instanceId),
117
+ );
118
+ if (summary) {
119
+ return {
120
+ account: loadBalancer.account,
121
+ loadBalancers: [loadBalancer.name],
122
+ region: loadBalancer.region,
123
+ summary,
124
+ vpcId: loadBalancer.vpcId,
125
+ };
126
+ }
127
+
128
+ for (const targetGroup of loadBalancer.targetGroups || loadBalancer.targetGroup || []) {
129
+ if (!matchesScope({ account: loadBalancer.account, region: loadBalancer.region, ...targetGroup }, instance)) {
130
+ continue;
131
+ }
132
+ const targetSummary = (targetGroup.instances || []).find((candidate: any) =>
133
+ matchesInstance(candidate, instance.instanceId),
134
+ );
135
+ if (targetSummary) {
136
+ return {
137
+ account: targetGroup.account || loadBalancer.account,
138
+ region: targetGroup.region || loadBalancer.region,
139
+ summary: typeof targetSummary === 'string' ? { id: targetSummary } : targetSummary,
140
+ targetGroups: targetGroupNames(targetGroup),
141
+ vpcId: loadBalancer.vpcId,
142
+ };
143
+ }
144
+ }
145
+
146
+ for (const serverGroup of (loadBalancer.serverGroups || []).filter((candidate: any) => candidate.isDisabled)) {
147
+ const disabledSummary = (serverGroup.instances || []).find((candidate: any) =>
148
+ matchesInstance(candidate, instance.instanceId),
149
+ );
150
+ if (disabledSummary) {
151
+ return {
152
+ account: loadBalancer.account,
153
+ loadBalancers: [loadBalancer.name],
154
+ region: loadBalancer.region,
155
+ serverGroup: serverGroup.name,
156
+ summary: disabledSummary,
157
+ vpcId: loadBalancer.vpcId,
158
+ };
159
+ }
160
+ }
161
+ }
162
+
163
+ return undefined;
164
+ }
165
+
166
+ function addTargetGroupHealthDetails(
167
+ healthMetrics: IAmazonHealth[],
168
+ loadBalancers: any[],
169
+ account: string,
170
+ region: string,
171
+ ): IAmazonHealth[] {
172
+ const targetGroups = loadBalancers.flatMap((loadBalancer) =>
173
+ (loadBalancer.targetGroups || loadBalancer.targetGroup || []).map((targetGroup: any) => ({
174
+ account: loadBalancer.account,
175
+ region: loadBalancer.region,
176
+ ...targetGroup,
177
+ })),
178
+ );
179
+
180
+ return healthMetrics.map((metric) => {
181
+ if (metric.type !== 'TargetGroup' || !metric.targetGroups) {
182
+ return metric;
183
+ }
184
+
185
+ return {
186
+ ...metric,
187
+ targetGroups: metric.targetGroups.map((health: any) => {
188
+ const name = health.targetGroupName || health.name;
189
+ const targetGroup = targetGroups.find(
190
+ (candidate: any) =>
191
+ name &&
192
+ (candidate.targetGroupName || candidate.name) === name &&
193
+ candidate.account === account &&
194
+ candidate.region === region,
195
+ );
196
+ if (!targetGroup) {
197
+ return health;
198
+ }
199
+
200
+ const port =
201
+ targetGroup.healthCheckPort === 'traffic-port' || targetGroup.healthCheckPort == null
202
+ ? targetGroup.port
203
+ : targetGroup.healthCheckPort;
204
+ return {
205
+ ...health,
206
+ ...(port == null ? {} : { healthCheckPath: `:${port}${targetGroup.healthCheckPath || ''}` }),
207
+ ...(targetGroup.healthCheckProtocol
208
+ ? { healthCheckProtocol: targetGroup.healthCheckProtocol.toLowerCase() }
209
+ : {}),
210
+ };
211
+ }),
212
+ } as IAmazonHealth;
213
+ });
214
+ }
215
+
216
+ function extractHealthMetrics(
217
+ app: Application,
218
+ summary: any,
219
+ details: any,
220
+ account: string,
221
+ region: string,
222
+ ): IAmazonHealth[] {
223
+ const summaryHealth = app.isStandalone ? details.health : summary.health;
224
+ const healthMetrics = ((summaryHealth?.length ? summaryHealth : details.health) || [])
225
+ .filter((metric: IAmazonHealth) => metric.type !== 'Ecs' || metric.state !== 'Unknown')
226
+ .map((metric: IAmazonHealth) => {
227
+ const latest = (details.health || []).find((candidate: IAmazonHealth) => candidate.type === metric.type);
228
+ return latest ? { ...latest, ...metric } : { ...metric };
229
+ });
230
+
231
+ return app.isStandalone
232
+ ? healthMetrics
233
+ : addTargetGroupHealthDetails(healthMetrics, app.loadBalancers?.data || [], account, region);
234
+ }
235
+
236
+ async function loadInstance(app: Application, params: IEcsInstanceParams): Promise<IEcsLoadedInstance | undefined> {
237
+ const lookup = findInstance(app, params);
238
+ if (!lookup?.summary || !lookup.account || !lookup.region) {
239
+ return undefined;
240
+ }
241
+
242
+ RecentHistoryService.addExtraDataToLatest('instances', {
243
+ account: lookup.account,
244
+ region: lookup.region,
245
+ ...(lookup.serverGroup ? { serverGroup: lookup.serverGroup } : {}),
246
+ ...(lookup.vpcId ? { vpcId: lookup.vpcId } : {}),
247
+ });
248
+
249
+ const details = (await InstanceReader.getInstanceDetails(lookup.account, lookup.region, params.instanceId)) as any;
250
+ const instanceId = params.instanceId;
251
+ const baseIpAddress =
252
+ details.publicDnsName ||
253
+ details.privateIpAddress ||
254
+ details.networkInterface?.privateIpv4Address ||
255
+ details.privateAddress ||
256
+ details.networkInterface?.ipv6Address;
257
+
258
+ return {
259
+ ...lookup.summary,
260
+ ...details,
261
+ account: lookup.account,
262
+ baseIpAddress,
263
+ cloudProvider: details.cloudProvider || lookup.summary.cloudProvider || 'ecs',
264
+ healthMetrics: extractHealthMetrics(app, lookup.summary, details, lookup.account, lookup.region),
265
+ instanceId,
266
+ loadBalancers: lookup.loadBalancers || details.loadBalancers || lookup.summary.loadBalancers,
267
+ provider: details.provider || lookup.summary.provider || 'ecs',
268
+ region: lookup.region,
269
+ serverGroup: lookup.serverGroup || details.serverGroup || lookup.summary.serverGroup,
270
+ targetGroups: lookup.targetGroups || details.targetGroups || lookup.summary.targetGroups,
271
+ vpcId: lookup.vpcId || details.vpcId || lookup.summary.vpcId,
272
+ };
273
+ }
274
+
275
+ function NetworkAddress({ address, label }: { address?: string; label: string }): JSX.Element | null {
276
+ if (!address) {
277
+ return null;
278
+ }
279
+
280
+ const hrefAddress = address.includes(':') ? `[${address}]` : address;
281
+ return (
282
+ <>
283
+ <dt>{label}</dt>
284
+ <dd>
285
+ <a href={`http://${hrefAddress}`} target="_blank" rel="noopener noreferrer">
286
+ {address}
287
+ </a>
288
+ <CopyToClipboard text={address} toolTip="Copy to clipboard" />
289
+ </dd>
290
+ </>
291
+ );
292
+ }
293
+
294
+ export class EcsInstanceDetailsComponent extends React.Component<
295
+ IEcsInstanceDetailsProps & IRouterInjectedProps,
296
+ IEcsInstanceDetailsState
297
+ > {
298
+ public state: IEcsInstanceDetailsState = {
299
+ instance: undefined,
300
+ instanceIdNotFound: undefined,
301
+ loading: true,
302
+ };
303
+
304
+ private activeRequestId = 0;
305
+ private dataReady = false;
306
+ private isUnmounted = false;
307
+ private unsubscribeFromRefresh?: () => void;
308
+
309
+ public componentDidMount(): void {
310
+ const { app } = this.props;
311
+ const ready = app.isStandalone
312
+ ? Promise.resolve()
313
+ : Promise.all([app.serverGroups.ready(), app.loadBalancers.ready()]).then(() => undefined);
314
+
315
+ ready.then(
316
+ () => {
317
+ if (this.isUnmounted) {
318
+ return;
319
+ }
320
+ this.dataReady = true;
321
+ this.retrieveInstance();
322
+ if (!app.isStandalone && app.serverGroups?.onRefresh) {
323
+ this.unsubscribeFromRefresh = app.serverGroups.onRefresh(() => this.retrieveInstance());
324
+ }
325
+ },
326
+ () => {
327
+ if (!this.isUnmounted) {
328
+ this.closeDetails();
329
+ }
330
+ },
331
+ );
332
+ }
333
+
334
+ public componentDidUpdate(previousProps: IEcsInstanceDetailsProps): void {
335
+ const previous = this.getInstanceParams(previousProps);
336
+ const current = this.getInstanceParams();
337
+ if (
338
+ this.dataReady &&
339
+ (previous.account !== current.account ||
340
+ previous.instanceId !== current.instanceId ||
341
+ previous.region !== current.region)
342
+ ) {
343
+ this.retrieveInstance(true);
344
+ }
345
+ }
346
+
347
+ public componentWillUnmount(): void {
348
+ this.isUnmounted = true;
349
+ this.activeRequestId += 1;
350
+ this.unsubscribeFromRefresh?.();
351
+ }
352
+
353
+ private getInstanceParams(
354
+ props: IEcsInstanceDetailsProps & Partial<IRouterInjectedProps> = this.props,
355
+ ): IEcsInstanceParams {
356
+ const params = props.instance || props.$stateParams || props.stateParams || ({} as IEcsInstanceParams);
357
+ return {
358
+ ...params,
359
+ account: params.account || params.accountId || props.accountId,
360
+ instanceId: params.instanceId,
361
+ };
362
+ }
363
+
364
+ private closeDetails(): void {
365
+ this.props.stateService.go('^', { allowModalToStayOpen: true }, { location: 'replace' });
366
+ }
367
+
368
+ private retrieveInstance(clearInstance = false): void {
369
+ const requestId = ++this.activeRequestId;
370
+ const params = this.getInstanceParams();
371
+ this.setState(
372
+ clearInstance
373
+ ? { instance: undefined, instanceIdNotFound: undefined, loading: true }
374
+ : { instanceIdNotFound: undefined, loading: true },
375
+ );
376
+
377
+ loadInstance(this.props.app, params).then(
378
+ (instance) => {
379
+ if (this.isUnmounted || requestId !== this.activeRequestId) {
380
+ return;
381
+ }
382
+ this.setState({ instance, instanceIdNotFound: instance ? undefined : params.instanceId, loading: false });
383
+ },
384
+ () => {
385
+ if (this.isUnmounted || requestId !== this.activeRequestId) {
386
+ return;
387
+ }
388
+ if (this.props.app.isStandalone) {
389
+ RecentHistoryService.removeLastItem('instances');
390
+ this.setState({ instance: undefined, instanceIdNotFound: params.instanceId, loading: false });
391
+ } else {
392
+ this.closeDetails();
393
+ }
394
+ },
395
+ );
396
+ }
397
+
398
+ public render(): JSX.Element {
399
+ const { app, environment, moniker } = this.props;
400
+ const { instance, instanceIdNotFound, loading } = this.state;
401
+ const instanceId = instance?.instanceId || instanceIdNotFound || this.getInstanceParams().instanceId;
402
+
403
+ return (
404
+ <div className="details-panel">
405
+ <div className="header">
406
+ <InstanceDetailsHeader
407
+ cloudProvider="ecs"
408
+ healthState={instance?.healthState}
409
+ instanceId={instanceId}
410
+ loading={loading}
411
+ standalone={app.isStandalone}
412
+ />
413
+ </div>
414
+ {!loading && instance && (
415
+ <div className="content" data-test-id="instanceDetails.content">
416
+ <CollapsibleSection heading="Instance Information" defaultExpanded={true}>
417
+ <dl className="dl-horizontal dl-narrow">
418
+ <InstanceInformation
419
+ account={instance.account}
420
+ availabilityZone={instance.zone || instance.availabilityZone || instance.placement?.availabilityZone}
421
+ instanceType={instance.instanceType}
422
+ launchTime={instance.launchTime}
423
+ provider={instance.provider}
424
+ region={instance.region}
425
+ serverGroup={instance.serverGroup}
426
+ />
427
+ {instance.imageId && <LabeledValue label="Image ID" value={instance.imageId} />}
428
+ </dl>
429
+ </CollapsibleSection>
430
+ <InstanceStatus
431
+ healthMetrics={instance.healthMetrics || []}
432
+ healthState={instance.healthState}
433
+ metricTypes={['LoadBalancer', 'TargetGroup']}
434
+ privateIpAddress={instance.privateIpAddress || instance.networkInterface?.privateIpv4Address}
435
+ />
436
+ <CollapsibleSection heading="Networking">
437
+ <dl className="horizontal-when-filters-collapsed">
438
+ {instance.vpcId && <LabeledValue label="VPC" value={<VpcTag vpcId={instance.vpcId} />} />}
439
+ {instance.subnetId && (
440
+ <LabeledValue label="Subnet" value={<SubnetTag subnetId={instance.subnetId} />} />
441
+ )}
442
+ <NetworkAddress address={instance.networkInterface?.privateIpv4Address} label="Private address (ENI)" />
443
+ <NetworkAddress address={instance.networkInterface?.ipv6Address} label="IPv6 address (ENI)" />
444
+ <NetworkAddress address={instance.privateAddress} label="Private address (Bridge)" />
445
+ </dl>
446
+ </CollapsibleSection>
447
+ <CollapsibleSection heading="Console Output">
448
+ <ConsoleOutputLink instance={instance as any} />
449
+ </CollapsibleSection>
450
+ <InstanceLinks
451
+ address={instance.baseIpAddress}
452
+ application={app}
453
+ environment={environment}
454
+ instance={instance as any}
455
+ moniker={moniker}
456
+ />
457
+ </div>
458
+ )}
459
+ {!loading && !instance && instanceIdNotFound && (
460
+ <div className="content">
461
+ <div className="content-section">
462
+ <div className="content-body text-center">
463
+ <h3>Instance not found.</h3>
464
+ <p>{instanceIdNotFound}</p>
465
+ </div>
466
+ </div>
467
+ </div>
468
+ )}
469
+ </div>
470
+ );
471
+ }
472
+ }
473
+
474
+ export const EcsInstanceDetails = withRouter(EcsInstanceDetailsComponent);
@@ -67,7 +67,7 @@ export class EcsLoadBalancerDetails extends React.Component<
67
67
  this.setState({
68
68
  refreshListenerUnsubscribe: this.props.app
69
69
  .getDataSource('loadBalancers')
70
- .onRefresh(null, () => this.extractLoadBalancer()),
70
+ .onRefresh(() => this.extractLoadBalancer()),
71
71
  });
72
72
  } else {
73
73
  this.setState({
@@ -88,7 +88,7 @@ export class EcsTargetGroupDetails extends React.Component<IEcsTargetGroupProps,
88
88
  this.setState({
89
89
  refreshListenerUnsubscribe: this.props.app
90
90
  .getDataSource('loadBalancers')
91
- .onRefresh(null, () => this.extractTargetGroup()),
91
+ .onRefresh(() => this.extractTargetGroup()),
92
92
  });
93
93
  } else {
94
94
  this.setState({
@@ -1,12 +1,7 @@
1
- import type { IQService } from 'angular';
2
-
3
1
  import type { IEcsLoadBalancer, IEcsLoadBalancerSourceData, IEcsTargetGroup } from '../domain/IEcsLoadBalancer';
4
2
 
5
3
  export class EcsLoadBalancerTransformer {
6
- public static $inject = ['$q'];
7
- constructor(private $q: IQService) {}
8
-
9
- public normalizeLoadBalancer(loadBalancer: IEcsLoadBalancerSourceData): PromiseLike<IEcsLoadBalancer> {
4
+ public normalizeLoadBalancer(loadBalancer: IEcsLoadBalancerSourceData): Promise<IEcsLoadBalancer> {
10
5
  loadBalancer.targetGroups.forEach((tg: IEcsTargetGroup) => {
11
6
  tg.region = loadBalancer.region;
12
7
  tg.account = loadBalancer.account;
@@ -16,6 +11,6 @@ export class EcsLoadBalancerTransformer {
16
11
  tg.serverGroups = tgServiceMap[tg.targetGroupArn];
17
12
  }
18
13
  });
19
- return this.$q.resolve(loadBalancer);
14
+ return Promise.resolve(loadBalancer);
20
15
  }
21
16
  }
@@ -1,59 +1,61 @@
1
- import type { StateParams } from '@uirouter/angularjs';
2
- import { module } from 'angular';
3
-
4
- import type { ApplicationStateProvider, INestedState } from '@spinnaker/core';
5
- import { APPLICATION_STATE_PROVIDER } from '@spinnaker/core';
1
+ import type { INestedState } from '@spinnaker/core';
2
+ import { registerApplicationState } from '@spinnaker/core';
6
3
 
7
4
  import { EcsTargetGroupDetails } from '../loadBalancer/details/targetGroupDetails';
8
5
  //import { IEcsTargetGroup } from '../domain/IEcsLoadBalancer';
9
6
 
10
- export const ECS_TARGET_GROUP_STATES = 'spinnaker.ecs.loadBalancer.targetGroup.states';
11
- module(ECS_TARGET_GROUP_STATES, [APPLICATION_STATE_PROVIDER]).config([
12
- 'applicationStateProvider',
13
- (applicationStateProvider: ApplicationStateProvider) => {
14
- const ecsTargetGroupDetails: INestedState = {
15
- name: 'ecsTargetGroupDetails',
16
- url: '/ecsTargetGroupDetails/:provider/:accountId/:region/:vpcId/:loadBalancerName/:name',
17
- params: {
18
- vpcId: {
19
- value: null,
20
- squash: true,
21
- },
22
- },
23
- views: {
24
- 'detail@../insight': {
25
- component: EcsTargetGroupDetails,
26
- $type: 'react',
27
- },
28
- },
29
- resolve: {
30
- accountId: ['$stateParams', ($stateParams: StateParams) => $stateParams.accountId],
31
- name: ['$stateParams', ($stateParams: StateParams) => $stateParams.name],
32
- provider: ['$stateParams', ($stateParams: StateParams) => $stateParams.provider],
33
- // resolve flat params into an IEcsTargetGroup
34
- targetGroup: [
35
- '$stateParams',
36
- ($stateParams: StateParams) => {
37
- return {
38
- loadBalancerName: $stateParams.loadBalancerName,
39
- targetGroupName: $stateParams.name,
40
- accountId: $stateParams.accountId,
41
- region: $stateParams.region,
42
- vpcId: $stateParams.vpcId,
43
- };
44
- },
45
- ],
46
- },
47
- data: {
48
- pageTitleDetails: {
49
- title: 'Target Group Details',
50
- nameParam: 'name',
51
- accountParam: 'accountId',
52
- regionParam: 'region',
53
- },
54
- },
55
- };
7
+ interface IEcsTargetGroupStateParams {
8
+ accountId: string;
9
+ loadBalancerName: string;
10
+ name: string;
11
+ provider: string;
12
+ region: string;
13
+ vpcId: string;
14
+ }
56
15
 
57
- applicationStateProvider.addInsightDetailState(ecsTargetGroupDetails);
16
+ export const ECS_TARGET_GROUP_DETAILS_STATE: INestedState = {
17
+ name: 'ecsTargetGroupDetails',
18
+ url: '/ecsTargetGroupDetails/:provider/:accountId/:region/:vpcId/:loadBalancerName/:name',
19
+ params: {
20
+ vpcId: {
21
+ value: null,
22
+ squash: true,
23
+ },
58
24
  },
59
- ]);
25
+ views: {
26
+ 'detail@../insight': {
27
+ component: EcsTargetGroupDetails,
28
+ $type: 'react',
29
+ },
30
+ },
31
+ resolve: {
32
+ accountId: ['$stateParams', ($stateParams: IEcsTargetGroupStateParams) => $stateParams.accountId],
33
+ name: ['$stateParams', ($stateParams: IEcsTargetGroupStateParams) => $stateParams.name],
34
+ provider: ['$stateParams', ($stateParams: IEcsTargetGroupStateParams) => $stateParams.provider],
35
+ // resolve flat params into an IEcsTargetGroup
36
+ targetGroup: [
37
+ '$stateParams',
38
+ ($stateParams: IEcsTargetGroupStateParams) => {
39
+ return {
40
+ loadBalancerName: $stateParams.loadBalancerName,
41
+ targetGroupName: $stateParams.name,
42
+ accountId: $stateParams.accountId,
43
+ region: $stateParams.region,
44
+ vpcId: $stateParams.vpcId,
45
+ };
46
+ },
47
+ ],
48
+ },
49
+ data: {
50
+ pageTitleDetails: {
51
+ title: 'Target Group Details',
52
+ nameParam: 'name',
53
+ accountParam: 'accountId',
54
+ regionParam: 'region',
55
+ },
56
+ },
57
+ };
58
+
59
+ registerApplicationState((applicationStateProvider) => {
60
+ applicationStateProvider.addInsightDetailState(ECS_TARGET_GROUP_DETAILS_STATE);
61
+ });
@@ -1,14 +1,8 @@
1
- import { module } from 'angular';
2
-
3
1
  import { REST } from '@spinnaker/core';
4
2
  import type { IMetricAlarmDescriptor } from './MetricAlarm';
5
3
 
6
4
  export class MetricAlarmReader {
7
- public listMetricAlarms(): PromiseLike<IMetricAlarmDescriptor[]> {
5
+ public listMetricAlarms(): Promise<IMetricAlarmDescriptor[]> {
8
6
  return REST('/ecs/cloudMetrics/alarms').get();
9
7
  }
10
8
  }
11
-
12
- export const METRIC_ALARM_READ_SERVICE = 'spinnaker.ecs.metricAlarm.read.service';
13
-
14
- module(METRIC_ALARM_READ_SERVICE, []).service('metricAlarmReader', MetricAlarmReader);