@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,587 @@
1
+ import { set } from 'lodash';
2
+ import React from 'react';
3
+
4
+ import type { IAccount, IStageConfigProps } from '@spinnaker/core';
5
+ import {
6
+ AccountRegionClusterSelector,
7
+ AccountService,
8
+ DeploymentStrategySelector,
9
+ HelpField,
10
+ PlatformHealthOverride,
11
+ StageConfigField,
12
+ StageConstants,
13
+ TargetSelect,
14
+ } from '@spinnaker/core';
15
+
16
+ const ECS_HEALTH_PROVIDER = 'Ecs';
17
+ const ADD_TO_LOAD_BALANCER = 'AddToLoadBalancer';
18
+
19
+ const scaleActions = [
20
+ { label: 'Scale by percentage or number', val: 'scale' },
21
+ { label: 'Scale to an exact size', val: 'scale_exact' },
22
+ { label: 'Scale to cluster size', val: 'scale_to_cluster' },
23
+ ];
24
+
25
+ const resizeTypes = [
26
+ { label: 'Scale by number of instances', val: 'incr' },
27
+ { label: 'Scale by percentage', val: 'pct' },
28
+ ];
29
+
30
+ function useForceUpdate(): () => void {
31
+ const [, setCounter] = React.useState(0);
32
+ return () => setCounter((counter) => counter + 1);
33
+ }
34
+
35
+ function useEcsAccounts(): IAccount[] {
36
+ const [accounts, setAccounts] = React.useState<IAccount[]>([]);
37
+
38
+ React.useEffect(() => {
39
+ let active = true;
40
+ AccountService.listAccounts('ecs').then((loadedAccounts) => active && setAccounts(loadedAccounts));
41
+ return () => {
42
+ active = false;
43
+ };
44
+ }, []);
45
+
46
+ return accounts;
47
+ }
48
+
49
+ function applyEcsDefaults(props: IStageConfigProps, defaults: Record<string, any> = {}, healthOverride = false): void {
50
+ const { application, stage, updateStageField } = props;
51
+ const changes: Record<string, any> = { cloudProvider: 'ecs', cloudProviderType: 'ecs' };
52
+ const defaultCredentials = application.defaultCredentials?.ecs;
53
+ const defaultRegion = application.defaultRegions?.ecs;
54
+
55
+ if (!stage.credentials && defaultCredentials) {
56
+ changes.credentials = defaultCredentials;
57
+ }
58
+
59
+ if (!stage.region && defaultRegion) {
60
+ changes.region = defaultRegion;
61
+ }
62
+
63
+ if (!stage.regions?.length) {
64
+ changes.regions = defaultRegion ? [defaultRegion] : [];
65
+ }
66
+
67
+ Object.keys(defaults).forEach((key) => {
68
+ if (stage[key] === undefined) {
69
+ changes[key] = defaults[key];
70
+ }
71
+ });
72
+
73
+ if (
74
+ healthOverride &&
75
+ stage.isNew &&
76
+ stage.interestingHealthProviderNames === undefined &&
77
+ application.attributes.platformHealthOnlyShowOverride &&
78
+ application.attributes.platformHealthOnly
79
+ ) {
80
+ changes.interestingHealthProviderNames = [ECS_HEALTH_PROVIDER];
81
+ }
82
+
83
+ updateStageField(changes);
84
+ }
85
+
86
+ function useEcsDefaults(props: IStageConfigProps, defaults: Record<string, any> = {}, healthOverride = false): void {
87
+ React.useEffect(() => applyEcsDefaults(props, defaults, healthOverride), []);
88
+ }
89
+
90
+ function pluralize(str: string, val: string | number): string {
91
+ return Number(val) === 1 ? str : `${str}s`;
92
+ }
93
+
94
+ function EcsClusterSelector(
95
+ props: IStageConfigProps & { clusterField?: string; singleRegion?: boolean; showAllRegions?: boolean },
96
+ ) {
97
+ const accounts = useEcsAccounts();
98
+ const { application, clusterField, pipeline, showAllRegions, singleRegion, stage, stageFieldUpdated } = props;
99
+
100
+ if (pipeline.strategy) {
101
+ return null;
102
+ }
103
+
104
+ return (
105
+ <AccountRegionClusterSelector
106
+ accounts={accounts}
107
+ application={application}
108
+ clusterField={clusterField}
109
+ component={stage}
110
+ onComponentUpdate={stageFieldUpdated}
111
+ showAllRegions={showAllRegions}
112
+ singleRegion={singleRegion ? 'true' : undefined}
113
+ />
114
+ );
115
+ }
116
+
117
+ function EcsTargetSelect({ stage, updateStageField }: IStageConfigProps) {
118
+ return (
119
+ <StageConfigField label="Target">
120
+ <TargetSelect
121
+ model={{ target: stage.target }}
122
+ options={StageConstants.TARGET_LIST}
123
+ onChange={(target: string) => updateStageField({ target })}
124
+ />
125
+ </StageConfigField>
126
+ );
127
+ }
128
+
129
+ function EcsHealthOverride({ application, stage, updateStageField }: IStageConfigProps) {
130
+ if (!application.attributes.platformHealthOnlyShowOverride) {
131
+ return null;
132
+ }
133
+
134
+ return (
135
+ <StageConfigField label="Task Completion">
136
+ <PlatformHealthOverride
137
+ interestingHealthProviderNames={stage.interestingHealthProviderNames || []}
138
+ onChange={(interestingHealthProviderNames) => updateStageField({ interestingHealthProviderNames })}
139
+ platformHealthType={ECS_HEALTH_PROVIDER}
140
+ />
141
+ </StageConfigField>
142
+ );
143
+ }
144
+
145
+ function setNestedStageField(props: IStageConfigProps, field: string, value: any, forceUpdate: () => void): void {
146
+ set(props.stage, field, value);
147
+ props.stageFieldUpdated();
148
+ forceUpdate();
149
+ }
150
+
151
+ function EcsServerGroupTargetStageConfig(props: IStageConfigProps & { healthOverride?: boolean }) {
152
+ useEcsDefaults(props, { target: StageConstants.TARGET_LIST[0].val }, props.healthOverride);
153
+
154
+ return (
155
+ <div className="form-horizontal">
156
+ <EcsClusterSelector {...props} />
157
+ <EcsTargetSelect {...props} />
158
+ {props.healthOverride && <EcsHealthOverride {...props} />}
159
+ </div>
160
+ );
161
+ }
162
+
163
+ export function EcsDestroyAsgStageConfig(props: IStageConfigProps) {
164
+ return <EcsServerGroupTargetStageConfig {...props} />;
165
+ }
166
+
167
+ export function EcsDisableAsgStageConfig(props: IStageConfigProps) {
168
+ return <EcsServerGroupTargetStageConfig {...props} healthOverride />;
169
+ }
170
+
171
+ export function EcsEnableAsgStageConfig(props: IStageConfigProps) {
172
+ return <EcsServerGroupTargetStageConfig {...props} healthOverride />;
173
+ }
174
+
175
+ export function EcsDisableClusterStageConfig(props: IStageConfigProps) {
176
+ const { stage, updateStageField } = props;
177
+ useEcsDefaults(props, { preferLargerOverNewer: 'false', remainingEnabledServerGroups: 1 }, true);
178
+
179
+ return (
180
+ <div className="form-horizontal">
181
+ <EcsClusterSelector {...props} />
182
+ <StageConfigField label="Disable Options">
183
+ <div className="form-inline">
184
+ Keep the{' '}
185
+ <input
186
+ className="form-control input-sm"
187
+ min="0"
188
+ onChange={(event) => updateStageField({ remainingEnabledServerGroups: Number(event.target.value) })}
189
+ required
190
+ style={{ width: '50px' }}
191
+ type="number"
192
+ value={stage.remainingEnabledServerGroups ?? 1}
193
+ />{' '}
194
+ <select
195
+ className="form-control input-sm"
196
+ onChange={(event) => updateStageField({ preferLargerOverNewer: event.target.value })}
197
+ style={{ width: '100px' }}
198
+ value={stage.preferLargerOverNewer ?? 'false'}
199
+ >
200
+ <option value="true">largest</option>
201
+ <option value="false">newest</option>
202
+ </select>{' '}
203
+ {pluralize('server group', stage.remainingEnabledServerGroups ?? 1)} enabled.
204
+ </div>
205
+ </StageConfigField>
206
+ <EcsHealthOverride {...props} />
207
+ </div>
208
+ );
209
+ }
210
+
211
+ export function EcsFindImageFromTagsStageConfig(props: IStageConfigProps) {
212
+ const { stage, updateStageField } = props;
213
+ useEcsDefaults(props);
214
+
215
+ return (
216
+ <div className="form-horizontal">
217
+ <StageConfigField label="Full Docker Image path (label or SHA-256)">
218
+ <input
219
+ className="form-control input-sm"
220
+ onChange={(event) => updateStageField({ imageLabelOrSha: event.target.value })}
221
+ type="text"
222
+ value={stage.imageLabelOrSha || ''}
223
+ />
224
+ </StageConfigField>
225
+ <div>
226
+ <h5>
227
+ Example value: <i>12345678901.dkr.ecr.us-west-2.amazonaws.com/continuous-delivery:latest</i>
228
+ </h5>
229
+ </div>
230
+ </div>
231
+ );
232
+ }
233
+
234
+ export function EcsScaleDownClusterStageConfig(props: IStageConfigProps) {
235
+ const { stage, updateStageField } = props;
236
+ useEcsDefaults(props, {
237
+ allowScaleDownActive: false,
238
+ preferLargerOverNewer: 'false',
239
+ remainingFullSizeServerGroups: 1,
240
+ });
241
+
242
+ return (
243
+ <div className="form-horizontal">
244
+ <EcsClusterSelector {...props} />
245
+ <StageConfigField label="Scale Down Options">
246
+ <div className="form-inline">
247
+ <p>
248
+ Keep the{' '}
249
+ <input
250
+ className="form-control input-sm"
251
+ min="0"
252
+ onChange={(event) => updateStageField({ remainingFullSizeServerGroups: Number(event.target.value) })}
253
+ required
254
+ style={{ width: '50px' }}
255
+ type="number"
256
+ value={stage.remainingFullSizeServerGroups ?? 1}
257
+ />{' '}
258
+ <select
259
+ className="form-control input-sm"
260
+ onChange={(event) => updateStageField({ preferLargerOverNewer: event.target.value })}
261
+ style={{ width: '100px' }}
262
+ value={stage.preferLargerOverNewer ?? 'false'}
263
+ >
264
+ <option value="true">largest</option>
265
+ <option value="false">newest</option>
266
+ </select>{' '}
267
+ {pluralize('server group', stage.remainingFullSizeServerGroups ?? 1)} at current size.
268
+ </p>
269
+ <p>The remaining server groups will be scaled down to zero instances.</p>
270
+ </div>
271
+ </StageConfigField>
272
+ <div className="form-group">
273
+ <div className="col-md-offset-3 col-md-6 checkbox">
274
+ <label>
275
+ <input
276
+ checked={Boolean(stage.allowScaleDownActive)}
277
+ onChange={(event) => updateStageField({ allowScaleDownActive: event.target.checked })}
278
+ type="checkbox"
279
+ />{' '}
280
+ Allow scale down of active server groups
281
+ </label>
282
+ </div>
283
+ </div>
284
+ </div>
285
+ );
286
+ }
287
+
288
+ export function EcsShrinkClusterStageConfig(props: IStageConfigProps) {
289
+ const { stage, updateStageField } = props;
290
+ useEcsDefaults(props, { allowDeleteActive: false, retainLargerOverNewer: 'false', shrinkToSize: 1 }, true);
291
+
292
+ return (
293
+ <div className="form-horizontal">
294
+ <EcsClusterSelector {...props} />
295
+ <StageConfigField label="Shrink Options">
296
+ <div className="form-inline">
297
+ Shrink to{' '}
298
+ <input
299
+ className="form-control input-sm"
300
+ min="0"
301
+ onChange={(event) => updateStageField({ shrinkToSize: Number(event.target.value) })}
302
+ required
303
+ style={{ width: '50px' }}
304
+ type="number"
305
+ value={stage.shrinkToSize ?? 1}
306
+ />{' '}
307
+ {pluralize('server group', stage.shrinkToSize ?? 1)}, keeping the{' '}
308
+ <select
309
+ className="form-control input-sm"
310
+ onChange={(event) => updateStageField({ retainLargerOverNewer: event.target.value })}
311
+ style={{ width: '100px' }}
312
+ value={stage.retainLargerOverNewer ?? 'false'}
313
+ >
314
+ <option value="true">largest</option>
315
+ <option value="false">newest</option>
316
+ </select>
317
+ </div>
318
+ </StageConfigField>
319
+ <div className="form-group">
320
+ <div className="col-md-offset-3 col-md-6 checkbox">
321
+ <label>
322
+ <input
323
+ checked={Boolean(stage.allowDeleteActive)}
324
+ onChange={(event) => updateStageField({ allowDeleteActive: event.target.checked })}
325
+ type="checkbox"
326
+ />{' '}
327
+ Allow deletion of active server groups
328
+ </label>
329
+ </div>
330
+ </div>
331
+ <EcsHealthOverride {...props} />
332
+ </div>
333
+ );
334
+ }
335
+
336
+ export function EcsCloneServerGroupStageConfig(props: IStageConfigProps) {
337
+ const { stage, stageFieldUpdated, updateStageField } = props;
338
+ const forceUpdate = useForceUpdate();
339
+ const capacity = stage.capacity || { desired: 1, max: 1, min: 1 };
340
+ const suspendedProcesses = stage.suspendedProcesses || [];
341
+ const addToLoadBalancerSuspended = suspendedProcesses.includes(ADD_TO_LOAD_BALANCER);
342
+ useEcsDefaults(
343
+ props,
344
+ {
345
+ capacity,
346
+ suspendedProcesses,
347
+ target: StageConstants.TARGET_LIST[0].val,
348
+ useSourceCapacity: true,
349
+ },
350
+ true,
351
+ );
352
+
353
+ const updateCapacity = (field: string, value: number) => {
354
+ updateStageField({ capacity: { ...capacity, [field]: value } });
355
+ };
356
+
357
+ const setUseSourceCapacity = (value: boolean) => {
358
+ if (value) {
359
+ delete stage.capacity;
360
+ stageFieldUpdated();
361
+ forceUpdate();
362
+ } else if (!stage.capacity) {
363
+ updateStageField({ capacity });
364
+ }
365
+ updateStageField({ useSourceCapacity: value });
366
+ };
367
+
368
+ const toggleAddToLoadBalancer = () => {
369
+ updateStageField({
370
+ suspendedProcesses: addToLoadBalancerSuspended
371
+ ? suspendedProcesses.filter((process: string) => process !== ADD_TO_LOAD_BALANCER)
372
+ : [...suspendedProcesses, ADD_TO_LOAD_BALANCER],
373
+ });
374
+ };
375
+
376
+ const deploymentFieldChanged = (key: string, value: any) => setNestedStageField(props, key, value, forceUpdate);
377
+
378
+ return (
379
+ <div className="form-horizontal">
380
+ <EcsClusterSelector {...props} clusterField="targetCluster" singleRegion />
381
+ <EcsTargetSelect {...props} />
382
+ <div className="form-group">
383
+ <div className="col-md-3 sm-label-right">Capacity</div>
384
+ <div className="col-md-9 radio">
385
+ <label>
386
+ <input
387
+ checked={stage.useSourceCapacity !== false}
388
+ id="useSourceCapacityTrue"
389
+ onChange={() => setUseSourceCapacity(true)}
390
+ type="radio"
391
+ />{' '}
392
+ Copy the capacity from the current server group <HelpField id="serverGroupCapacity.useSourceCapacityTrue" />
393
+ </label>
394
+ </div>
395
+ <div className="col-md-9 col-md-offset-3 radio">
396
+ <label>
397
+ <input
398
+ checked={stage.useSourceCapacity === false}
399
+ id="useSourceCapacityFalse"
400
+ onChange={() => setUseSourceCapacity(false)}
401
+ type="radio"
402
+ />{' '}
403
+ Let me specify the capacity <HelpField id="serverGroupCapacity.useSourceCapacityFalse" />
404
+ </label>
405
+ </div>
406
+ </div>
407
+ <div className="form-group">
408
+ <div className="col-md-2 col-md-offset-3">Min</div>
409
+ <div className="col-md-2">Max</div>
410
+ <div className="col-md-2">Desired</div>
411
+ </div>
412
+ <div className="form-group">
413
+ {(['min', 'max', 'desired'] as const).map((field) => (
414
+ <div className={field === 'min' ? 'col-md-2 col-md-offset-3' : 'col-md-2'} key={field}>
415
+ <input
416
+ className="form-control input-sm"
417
+ disabled={stage.useSourceCapacity !== false}
418
+ max={field === 'min' || field === 'desired' ? capacity.max : undefined}
419
+ min={field === 'max' ? capacity.min : 0}
420
+ onChange={(event) => updateCapacity(field, Number(event.target.value))}
421
+ required
422
+ type="number"
423
+ value={capacity[field] ?? 1}
424
+ />
425
+ </div>
426
+ ))}
427
+ </div>
428
+ <StageConfigField label="Traffic">
429
+ <div className="checkbox">
430
+ <label>
431
+ <input checked={!addToLoadBalancerSuspended} onChange={toggleAddToLoadBalancer} type="checkbox" /> Send
432
+ client requests to new instances
433
+ </label>
434
+ </div>
435
+ </StageConfigField>
436
+ <EcsHealthOverride {...props} />
437
+ <DeploymentStrategySelector
438
+ command={stage as any}
439
+ labelColumns="3"
440
+ fieldColumns="6"
441
+ onFieldChange={deploymentFieldChanged}
442
+ onStrategyChange={(command) => updateStageField({ strategy: command.strategy })}
443
+ />
444
+ </div>
445
+ );
446
+ }
447
+
448
+ export function EcsResizeAsgStageConfig(props: IStageConfigProps) {
449
+ const { stage, updateStageField } = props;
450
+ const capacity = stage.capacity || {};
451
+ useEcsDefaults(
452
+ props,
453
+ {
454
+ action: scaleActions[0].val,
455
+ capacity,
456
+ resizeType: resizeTypes[0].val,
457
+ target: StageConstants.TARGET_LIST[0].val,
458
+ targetHealthyDeployPercentage: 100,
459
+ },
460
+ true,
461
+ );
462
+
463
+ const updateResizeType = (action: string, resizeType = stage.resizeType || resizeTypes[0].val) => {
464
+ if (action === 'scale_exact') {
465
+ delete stage.scaleNum;
466
+ delete stage.scalePct;
467
+ updateStageField({ action, resizeType: 'exact' });
468
+ return;
469
+ }
470
+
471
+ const nextResizeType = resizeType === 'pct' ? 'pct' : 'incr';
472
+ const changes: Record<string, any> = { action, capacity: {}, resizeType: nextResizeType };
473
+ if (nextResizeType === 'pct') {
474
+ delete stage.scaleNum;
475
+ } else {
476
+ delete stage.scalePct;
477
+ changes.scaleNum = stage.scaleNum || 0;
478
+ }
479
+ updateStageField(changes);
480
+ };
481
+
482
+ const updateCapacity = (field: string, value: number) => {
483
+ updateStageField({ capacity: { ...capacity, [field]: value } });
484
+ };
485
+
486
+ return (
487
+ <div className="form-horizontal">
488
+ <EcsClusterSelector {...props} />
489
+ <EcsTargetSelect {...props} />
490
+ <StageConfigField label="Action" helpKey="pipeline.config.resizeAsg.action">
491
+ <select
492
+ className="form-control input-sm"
493
+ onChange={(event) => updateResizeType(event.target.value)}
494
+ required
495
+ value={stage.action ?? scaleActions[0].val}
496
+ >
497
+ {scaleActions.map((action) => (
498
+ <option key={action.val} value={action.val}>
499
+ {action.label}
500
+ </option>
501
+ ))}
502
+ </select>
503
+ </StageConfigField>
504
+ {stage.action !== 'scale_exact' && (
505
+ <>
506
+ <StageConfigField label={stage.action === 'scale_to_cluster' ? 'Additional Capacity' : 'Type'}>
507
+ <select
508
+ className="form-control input-sm"
509
+ onChange={(event) => updateResizeType(stage.action ?? scaleActions[0].val, event.target.value)}
510
+ required
511
+ value={stage.resizeType === 'exact' ? resizeTypes[0].val : stage.resizeType ?? resizeTypes[0].val}
512
+ >
513
+ {resizeTypes.map((type) => (
514
+ <option key={type.val} value={type.val}>
515
+ {type.label}
516
+ </option>
517
+ ))}
518
+ </select>
519
+ </StageConfigField>
520
+ {stage.resizeType === 'pct' && (
521
+ <StageConfigField label="Resize Percentage">
522
+ <input
523
+ className="form-control input-sm"
524
+ min="0"
525
+ onChange={(event) => updateStageField({ scalePct: Number(event.target.value) })}
526
+ style={{ width: '80px' }}
527
+ type="number"
528
+ value={stage.scalePct ?? 0}
529
+ />
530
+ <div>
531
+ <em className="subinput-note">
532
+ This is the percentage by which the target server group's capacity will be increased
533
+ </em>
534
+ </div>
535
+ </StageConfigField>
536
+ )}
537
+ {stage.resizeType !== 'pct' && (
538
+ <StageConfigField label="Resize-by Amount">
539
+ <input
540
+ className="form-control input-sm"
541
+ min="0"
542
+ onChange={(event) => updateStageField({ scaleNum: Number(event.target.value) })}
543
+ style={{ width: '80px' }}
544
+ type="number"
545
+ value={stage.scaleNum ?? 0}
546
+ />
547
+ <div>
548
+ <em className="subinput-note">
549
+ This is the exact amount by which the target server group's capacity will be increased
550
+ </em>
551
+ </div>
552
+ </StageConfigField>
553
+ )}
554
+ </>
555
+ )}
556
+ {stage.action === 'scale_exact' && (
557
+ <>
558
+ <StageConfigField label="Capacity">
559
+ <div className="row">
560
+ <div className="col-md-3">Min</div>
561
+ <div className="col-md-3">Max</div>
562
+ <div className="col-md-3">Desired</div>
563
+ </div>
564
+ </StageConfigField>
565
+ <StageConfigField label="Match Capacity">
566
+ <div className="row">
567
+ {(['min', 'max', 'desired'] as const).map((field) => (
568
+ <div className="col-md-3" key={field}>
569
+ <input
570
+ className="form-control input-sm"
571
+ onChange={(event) => updateCapacity(field, Number(event.target.value))}
572
+ type="number"
573
+ value={capacity[field] ?? 0}
574
+ />
575
+ </div>
576
+ ))}
577
+ </div>
578
+ </StageConfigField>
579
+ <StageConfigField label="">
580
+ <em className="subinput-note">This is the exact amount to which the target server group will be scaled</em>
581
+ </StageConfigField>
582
+ </>
583
+ )}
584
+ <EcsHealthOverride {...props} />
585
+ </div>
586
+ );
587
+ }
@@ -1,65 +1,29 @@
1
- 'use strict';
2
-
3
- import { module } from 'angular';
4
-
5
- import { AccountService, Registry, StageConstants } from '@spinnaker/core';
6
-
7
- export const ECS_PIPELINE_STAGES_DESTROYASG_ECSDESTROYASGSTAGE = 'spinnaker.ecs.pipeline.stage.ecs.destroyAsgStage';
8
- export const name = ECS_PIPELINE_STAGES_DESTROYASG_ECSDESTROYASGSTAGE; // for backwards compatibility
9
- module(ECS_PIPELINE_STAGES_DESTROYASG_ECSDESTROYASGSTAGE, [])
10
- .config(function () {
11
- Registry.pipeline.registerStage({
12
- provides: 'destroyServerGroup',
13
- alias: 'destroyAsg',
14
- cloudProvider: 'ecs',
15
- templateUrl: require('./destroyAsgStage.html'),
16
- executionStepLabelUrl: require('./destroyAsgStepLabel.html'),
17
- accountExtractor: (stage) => [stage.context.credentials],
18
- configAccountExtractor: (stage) => [stage.credentials],
19
- validators: [
20
- {
21
- type: 'targetImpedance',
22
- message:
23
- 'This pipeline will attempt to destroy a server group without deploying a new version into the same cluster.',
24
- },
25
- { type: 'requiredField', fieldName: 'cluster' },
26
- { type: 'requiredField', fieldName: 'target' },
27
- { type: 'requiredField', fieldName: 'regions' },
28
- { type: 'requiredField', fieldName: 'credentials', fieldLabel: 'account' },
29
- ],
30
- });
31
- })
32
- .controller('ecsDestroyAsgStageCtrl', [
33
- '$scope',
34
- function ($scope) {
35
- const stage = $scope.stage;
36
-
37
- $scope.state = {
38
- accounts: false,
39
- regionsLoaded: false,
40
- };
41
-
42
- AccountService.listAccounts('ecs').then(function (accounts) {
43
- $scope.accounts = accounts;
44
- $scope.state.accounts = true;
45
- });
46
-
47
- $scope.regions = ['us-east-1', 'us-west-1', 'eu-west-1', 'us-west-2'];
48
-
49
- $scope.targets = StageConstants.TARGET_LIST;
50
-
51
- stage.regions = stage.regions || [];
52
- stage.cloudProvider = 'ecs';
53
-
54
- if (!stage.credentials && $scope.application.defaultCredentials.ecs) {
55
- stage.credentials = $scope.application.defaultCredentials.ecs;
56
- }
57
- if (!stage.regions.length && $scope.application.defaultRegions.ecs) {
58
- stage.regions.push($scope.application.defaultRegions.ecs);
59
- }
60
-
61
- if (!stage.target) {
62
- stage.target = $scope.targets[0].val;
63
- }
64
- },
65
- ]);
1
+ import React from 'react';
2
+ import { Registry } from '@spinnaker/core';
3
+
4
+ import { EcsServerGroupStepLabel } from '../common/EcsServerGroupStepLabel';
5
+ import { EcsDestroyAsgStageConfig } from '../common/EcsStageConfigs';
6
+
7
+ export function registerEcsDestroyServerGroupStage() {
8
+ Registry.pipeline.registerStage({
9
+ provides: 'destroyServerGroup',
10
+ alias: 'destroyAsg',
11
+ cloudProvider: 'ecs',
12
+ component: EcsDestroyAsgStageConfig,
13
+ executionStepLabelComponent: (props) =>
14
+ React.createElement(EcsServerGroupStepLabel, { action: 'Destroy Server Group', ...props }),
15
+ accountExtractor: (stage) => [stage.context.credentials],
16
+ configAccountExtractor: (stage) => [stage.credentials],
17
+ validators: [
18
+ {
19
+ type: 'targetImpedance',
20
+ message:
21
+ 'This pipeline will attempt to destroy a server group without deploying a new version into the same cluster.',
22
+ },
23
+ { type: 'requiredField', fieldName: 'cluster' },
24
+ { type: 'requiredField', fieldName: 'target' },
25
+ { type: 'requiredField', fieldName: 'regions' },
26
+ { type: 'requiredField', fieldName: 'credentials', fieldLabel: 'account' },
27
+ ],
28
+ });
29
+ }