@spinnaker/ecs 2026.2.4 → 2026.3.1

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,137 @@
1
+ import React from 'react';
2
+
3
+ import { HelpField } from '@spinnaker/core';
4
+
5
+ import { EcsCapacityProvider } from '../capacityProvider/CapacityProvider';
6
+ import type { IEcsWizardPageProps } from './common';
7
+
8
+ export const HorizontalScalingSettings = ({ command, configureCommand, onFieldChange }: IEcsWizardPageProps) => {
9
+ const useCapacityProviders =
10
+ command.computeOption === 'capacityProviders' ||
11
+ (!command.computeOption && (command.capacityProviderStrategy || []).length > 0);
12
+ const capacity = command.capacity || {};
13
+ const updateCapacity = (field: string, value: number) => onFieldChange('capacity', { ...capacity, [field]: value });
14
+
15
+ return (
16
+ <div className="container-fluid form-horizontal" data-test-id="EcsServerGroupWizard.horizontalScaling">
17
+ <div className="form-group">
18
+ <div className="col-md-4 sm-label-right">
19
+ <b>Compute options</b> <HelpField id="ecs.computeOptions" />
20
+ </div>
21
+ <div className="col-md-2 radio">
22
+ <label>
23
+ <input
24
+ checked={!useCapacityProviders}
25
+ data-test-id="ServerGroup.computeOptionsLaunchType"
26
+ id="computeOptionsLaunchType"
27
+ onChange={() => {
28
+ onFieldChange('computeOption', 'launchType');
29
+ onFieldChange('capacityProviderStrategy', []);
30
+ }}
31
+ type="radio"
32
+ />{' '}
33
+ Launch type
34
+ </label>
35
+ </div>
36
+ <div className="col-md-3 radio">
37
+ <label>
38
+ <input
39
+ checked={useCapacityProviders}
40
+ data-test-id="ServerGroup.computeOptionsCapacityProviders"
41
+ id="computeOptionsCapacityProviders"
42
+ onChange={() => {
43
+ onFieldChange('computeOption', 'capacityProviders');
44
+ onFieldChange('launchType', '');
45
+ }}
46
+ type="radio"
47
+ />{' '}
48
+ Capacity Providers
49
+ </label>
50
+ </div>
51
+ </div>
52
+
53
+ {useCapacityProviders ? (
54
+ <div className="form-group">
55
+ <EcsCapacityProvider command={command} configureCommand={configureCommand} onFieldChange={onFieldChange} />
56
+ </div>
57
+ ) : (
58
+ <div className="form-group">
59
+ <div className="col-md-5 sm-label-right">
60
+ Launch Type <HelpField id="ecs.launchtype" />
61
+ </div>
62
+ <div className="col-md-3">
63
+ <select
64
+ aria-label="Launch type"
65
+ className="form-control input-sm"
66
+ data-test-id="ServerGroup.launchType"
67
+ onChange={(event) => onFieldChange('launchType', event.target.value)}
68
+ value={command.launchType || ''}
69
+ >
70
+ <option value="">Select...</option>
71
+ {(command.backingData.launchTypes || []).map((launchType) => (
72
+ <option key={launchType} value={launchType}>
73
+ {launchType}
74
+ </option>
75
+ ))}
76
+ </select>
77
+ </div>
78
+ </div>
79
+ )}
80
+
81
+ <hr />
82
+ {[
83
+ ['desired', 'Desired capacity', 'ecs.capacity.desired'],
84
+ ['min', 'Minimum', 'ecs.capacity.minimum'],
85
+ ['max', 'Maximum', 'ecs.capacity.maximum'],
86
+ ].map(([field, label, help]) => (
87
+ <div className="form-group" key={field}>
88
+ <div className="col-md-5 sm-label-right">
89
+ {label} <HelpField id={help} />
90
+ </div>
91
+ <div className="col-md-2">
92
+ <input
93
+ aria-label={`${label === 'Minimum' || label === 'Maximum' ? `${label} capacity` : label}`}
94
+ className="form-control input-sm no-spel"
95
+ data-test-id={`ServerGroup.capacity.${field}`}
96
+ onChange={(event) => updateCapacity(field, event.target.valueAsNumber)}
97
+ type="number"
98
+ value={capacity[field] ?? ''}
99
+ />
100
+ </div>
101
+ </div>
102
+ ))}
103
+
104
+ <div className="form-group">
105
+ <div className="col-md-12 checkbox">
106
+ <label>
107
+ <input
108
+ checked={!!command.useSourceCapacity}
109
+ data-test-id="ServerGroup.useSourceCapacity"
110
+ onChange={(event) => {
111
+ onFieldChange('useSourceCapacity', event.target.checked);
112
+ onFieldChange('preferSourceCapacity', event.target.checked);
113
+ }}
114
+ type="checkbox"
115
+ />{' '}
116
+ <b>If available, use the previous server group's capacity</b>
117
+ </label>{' '}
118
+ <HelpField id="ecs.capacity.overwrite" />
119
+ </div>
120
+ </div>
121
+ <div className="form-group">
122
+ <div className="col-md-12 checkbox">
123
+ <label>
124
+ <input
125
+ checked={!!command.copySourceScalingPoliciesAndActions}
126
+ data-test-id="ServerGroup.copySourceScalingPoliciesAndActions"
127
+ onChange={(event) => onFieldChange('copySourceScalingPoliciesAndActions', event.target.checked)}
128
+ type="checkbox"
129
+ />{' '}
130
+ <b>If available, copy the previous server group's autoscaling policies</b>
131
+ </label>{' '}
132
+ <HelpField id="ecs.capacity.copySourceScalingPoliciesAndActions" />
133
+ </div>
134
+ </div>
135
+ </div>
136
+ );
137
+ };
@@ -0,0 +1,60 @@
1
+ import React from 'react';
2
+
3
+ import { HelpField, MapEditor } from '@spinnaker/core';
4
+
5
+ import type { IEcsWizardPageProps } from './common';
6
+
7
+ const logDrivers = [
8
+ 'None',
9
+ 'awslogs',
10
+ 'fluentd',
11
+ 'gelf',
12
+ 'journald',
13
+ 'json-file',
14
+ 'logentries',
15
+ 'splunk',
16
+ 'sumologic',
17
+ 'syslog',
18
+ ];
19
+
20
+ export const LoggingSettings = ({ command, onFieldChange }: IEcsWizardPageProps) => (
21
+ <div className="container-fluid form-horizontal" data-test-id="EcsServerGroupWizard.logging">
22
+ <div className="form-group">
23
+ <div className="col-md-5 sm-label-right">
24
+ <b>Log driver (Optional)</b> <HelpField id="ecs.logDriver" />
25
+ </div>
26
+ <div className="col-md-7">
27
+ <select
28
+ aria-label="Log driver"
29
+ className="form-control input-sm"
30
+ data-test-id="Logging.logDriver"
31
+ onChange={(event) => onFieldChange('logDriver', event.target.value)}
32
+ value={command.logDriver || ''}
33
+ >
34
+ <option value="">Select...</option>
35
+ {logDrivers.map((driver) => (
36
+ <option key={driver} value={driver}>
37
+ {driver}
38
+ </option>
39
+ ))}
40
+ </select>
41
+ </div>
42
+ </div>
43
+ {command.logDriver && command.logDriver !== 'None' ? (
44
+ <div className="form-group">
45
+ <div className="sm-label-left">
46
+ <b>Logging options (optional)</b> <HelpField id="ecs.logOptions" />
47
+ </div>
48
+ <MapEditor
49
+ allowEmpty={true}
50
+ keyLabel="Logging option"
51
+ model={command.logOptions || {}}
52
+ onChange={(logOptions) => onFieldChange('logOptions', logOptions)}
53
+ valueLabel="Logging option value"
54
+ />
55
+ </div>
56
+ ) : (
57
+ <div className="form-group">Logging options are not available for your log driver selection.</div>
58
+ )}
59
+ </div>
60
+ );
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+
3
+ import type { IEcsWizardPageProps } from './common';
4
+ import { EcsNetworking } from '../networking/Networking';
5
+
6
+ export const NetworkingSettings = ({ command, configureCommand, onFieldChange }: IEcsWizardPageProps) => (
7
+ <div data-test-id="EcsServerGroupWizard.networking">
8
+ <EcsNetworking command={command} configureCommand={configureCommand} onFieldChange={onFieldChange} />
9
+ </div>
10
+ );
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+
3
+ import type { IEcsWizardPageProps } from './common';
4
+ import { ServiceDiscovery } from '../serviceDiscovery/ServiceDiscovery';
5
+
6
+ export const ServiceDiscoverySettings = ({ command, configureCommand, onFieldChange }: IEcsWizardPageProps) => (
7
+ <div data-test-id="EcsServerGroupWizard.serviceDiscovery">
8
+ <ServiceDiscovery command={command} configureCommand={configureCommand} onFieldChange={onFieldChange} />
9
+ </div>
10
+ );
@@ -0,0 +1,59 @@
1
+ import React from 'react';
2
+
3
+ import { HelpField } from '@spinnaker/core';
4
+
5
+ import type { IEcsWizardPageProps } from './common';
6
+ import { TaskDefinition } from '../taskDefinition/TaskDefinition';
7
+
8
+ export const TaskDefinitionSettings = ({ command, configureCommand, onFieldChange }: IEcsWizardPageProps) => (
9
+ <div className="clearfix" data-test-id="EcsServerGroupWizard.taskDefinition">
10
+ <div className="row">
11
+ <div className="col-md-12">
12
+ <div className="container-fluid form-horizontal">
13
+ <div className="form-group">
14
+ <div className="col-md-4 sm-label-right">
15
+ <b>Task Definition source</b> <HelpField id="ecs.taskDefinition" />
16
+ </div>
17
+ <div className="col-md-2 radio">
18
+ <label>
19
+ <input
20
+ checked={!command.useTaskDefinitionArtifact}
21
+ data-test-id="ServerGroup.useInputs"
22
+ id="taskDefinitionSourceInputs"
23
+ onChange={() => onFieldChange('useTaskDefinitionArtifact', false)}
24
+ type="radio"
25
+ />{' '}
26
+ Inputs
27
+ </label>
28
+ </div>
29
+ <div className="col-md-2 radio">
30
+ <label>
31
+ <input
32
+ checked={command.useTaskDefinitionArtifact}
33
+ data-test-id="ServerGroup.useArtifacts"
34
+ disabled={command.viewState.mode === 'create'}
35
+ id="taskDefinitionSourceArtifact"
36
+ onChange={() => onFieldChange('useTaskDefinitionArtifact', true)}
37
+ type="radio"
38
+ />{' '}
39
+ Artifact
40
+ </label>
41
+ </div>
42
+ </div>
43
+ {command.viewState.mode === 'create' && (
44
+ <div className="color-text-caption">
45
+ <hr />
46
+ <em>Artifacts not supported outside of pipelines.</em>
47
+ </div>
48
+ )}
49
+ </div>
50
+ </div>
51
+ {command.useTaskDefinitionArtifact && (
52
+ <div className="col-md-12">
53
+ <hr />
54
+ <TaskDefinition command={command} configureCommand={configureCommand} onFieldChange={onFieldChange} />
55
+ </div>
56
+ )}
57
+ </div>
58
+ </div>
59
+ );
@@ -0,0 +1,10 @@
1
+ import type { Application } from '@spinnaker/core';
2
+
3
+ import type { IEcsServerGroupCommand } from '../../serverGroupConfiguration.service';
4
+
5
+ export interface IEcsWizardPageProps {
6
+ application: Application;
7
+ command: IEcsServerGroupCommand;
8
+ configureCommand: (query?: string) => Promise<void>;
9
+ onFieldChange: (field: string, value: any) => void;
10
+ }
@@ -0,0 +1,190 @@
1
+ import React from 'react';
2
+
3
+ import type { IWizardPageComponent } from '@spinnaker/core';
4
+
5
+ import type { IEcsServerGroupCommand } from '../../serverGroupConfiguration.service';
6
+
7
+ type ValidationErrors = { [key: string]: any };
8
+ type Validator = (values: IEcsServerGroupCommand) => ValidationErrors;
9
+
10
+ const required = (value: any): boolean => value !== undefined && value !== null && value !== '';
11
+ const validInteger = (value: any): boolean => Number.isFinite(value) && Number.isInteger(value) && value >= 0;
12
+ const usableCapacityProviderStrategyItem = (item: any): boolean =>
13
+ required(item?.capacityProvider) && validInteger(item?.base) && validInteger(item?.weight);
14
+ const hasRowErrors = (errors: ValidationErrors[]): boolean => errors.some((error) => Object.keys(error).length > 0);
15
+ const isExpressionLanguage = (value: string): boolean => value?.includes('${');
16
+ const isStackPattern = (value = ''): boolean =>
17
+ isExpressionLanguage(value) || /^([a-zA-Z_0-9._${}]*(\${.+})*)*$/.test(value);
18
+ const isDetailPattern = (value = ''): boolean =>
19
+ isExpressionLanguage(value) || /^([a-zA-Z_0-9._${}-]*(\${.+})*)*$/.test(value);
20
+
21
+ const validateTargetGroupMappings = (values: IEcsServerGroupCommand): ValidationErrors => {
22
+ const targetGroupMappings = (values.targetGroupMappings || []).map((mapping) => {
23
+ const errors: ValidationErrors = {};
24
+ if (values.useTaskDefinitionArtifact && !required(mapping.containerName)) {
25
+ errors.containerName = 'Container name is required.';
26
+ }
27
+ if (!required(mapping.targetGroup)) {
28
+ errors.targetGroup = 'Target group is required.';
29
+ }
30
+ if (!validInteger(mapping.containerPort)) {
31
+ errors.containerPort = 'Container port must be a non-negative integer.';
32
+ }
33
+ return errors;
34
+ });
35
+ return hasRowErrors(targetGroupMappings) ? { targetGroupMappings } : {};
36
+ };
37
+
38
+ export const validateEcsBasicSettings: Validator = (values) => {
39
+ const errors: ValidationErrors = {};
40
+ if (!required(values.credentials)) {
41
+ errors.credentials = 'Account is required.';
42
+ }
43
+ if (!required(values.region)) {
44
+ errors.region = 'Region is required.';
45
+ }
46
+ if (!required(values.ecsClusterName)) {
47
+ errors.ecsClusterName = 'ECS cluster is required.';
48
+ }
49
+ if (!isStackPattern(values.stack)) {
50
+ errors.stack = 'Only dot(.) and underscore(_) special characters are allowed in the Stack field.';
51
+ }
52
+ if (!isDetailPattern(values.freeFormDetails)) {
53
+ errors.freeFormDetails =
54
+ 'Only dot(.), underscore(_), and dash(-) special characters are allowed in the Detail field.';
55
+ }
56
+ return errors;
57
+ };
58
+
59
+ export const validateEcsTaskDefinition: Validator = (values) => {
60
+ if (!values.useTaskDefinitionArtifact) {
61
+ return {};
62
+ }
63
+ const errors: ValidationErrors = validateTargetGroupMappings(values);
64
+ if (!values.taskDefinitionArtifact?.artifact && !values.taskDefinitionArtifact?.artifactId) {
65
+ errors.taskDefinitionArtifact = 'Task definition artifact is required.';
66
+ }
67
+ const containerMappings = (values.containerMappings || []).map((mapping) => {
68
+ const mappingErrors: ValidationErrors = {};
69
+ if (!required(mapping.containerName)) {
70
+ mappingErrors.containerName = 'Container name is required.';
71
+ }
72
+ if (!required(mapping.imageDescription?.imageId)) {
73
+ mappingErrors.imageDescription = 'Container image is required.';
74
+ }
75
+ return mappingErrors;
76
+ });
77
+ if (hasRowErrors(containerMappings)) {
78
+ errors.containerMappings = containerMappings;
79
+ }
80
+ return errors;
81
+ };
82
+
83
+ export const validateEcsContainer: Validator = (values) => {
84
+ if (values.useTaskDefinitionArtifact) {
85
+ return {};
86
+ }
87
+ const errors: ValidationErrors = validateTargetGroupMappings(values);
88
+ if (!required(values.imageDescription?.imageId)) {
89
+ errors.imageDescription = { imageId: 'Container image is required.' };
90
+ }
91
+ return errors;
92
+ };
93
+
94
+ export const validateEcsServiceDiscovery: Validator = (values) => {
95
+ const serviceDiscoveryAssociations = (values.serviceDiscoveryAssociations || []).map((association) => {
96
+ const errors: ValidationErrors = {};
97
+ if (values.useTaskDefinitionArtifact && !required(association.containerName)) {
98
+ errors.containerName = 'Container name is required.';
99
+ }
100
+ if (!required(association.registry?.id) && !required(association.registry?.displayName)) {
101
+ errors.registry = 'Service registry is required.';
102
+ }
103
+ if (!validInteger(association.containerPort)) {
104
+ errors.containerPort = 'Container port must be a non-negative integer.';
105
+ }
106
+ return errors;
107
+ });
108
+ return hasRowErrors(serviceDiscoveryAssociations) ? { serviceDiscoveryAssociations } : {};
109
+ };
110
+
111
+ export const validateEcsCapacity: Validator = (values) => {
112
+ const capacity = values.capacity || {};
113
+ const useCapacityProviders =
114
+ values.computeOption === 'capacityProviders' ||
115
+ (!values.computeOption && (values.capacityProviderStrategy || []).length > 0);
116
+ const validationErrors: ValidationErrors = {};
117
+ const errors: ValidationErrors = {};
118
+ ['min', 'desired', 'max'].forEach((field) => {
119
+ if (!validInteger(capacity[field])) {
120
+ errors[field] = 'Capacity must be a non-negative integer.';
121
+ }
122
+ });
123
+ if (Object.keys(errors).length === 0) {
124
+ if (capacity.min > capacity.max) {
125
+ errors.min = 'Minimum capacity cannot exceed maximum capacity.';
126
+ }
127
+ if (capacity.desired < capacity.min || capacity.desired > capacity.max) {
128
+ errors.desired = 'Desired capacity must be between minimum and maximum capacity.';
129
+ }
130
+ }
131
+ if (!useCapacityProviders && !required(values.launchType)) {
132
+ validationErrors.launchType = 'Launch type is required.';
133
+ }
134
+ if (useCapacityProviders && values.useDefaultCapacityProviders !== false) {
135
+ const defaultStrategy = values.backingData?.filtered?.defaultCapacityProviderStrategy || [];
136
+ if (!defaultStrategy.length || !defaultStrategy.every(usableCapacityProviderStrategyItem)) {
137
+ validationErrors.capacityProviderStrategy = 'A usable default capacity provider strategy is required.';
138
+ }
139
+ }
140
+ if (useCapacityProviders && values.useDefaultCapacityProviders === false) {
141
+ const strategy = values.capacityProviderStrategy || [];
142
+ if (!strategy.length) {
143
+ validationErrors.capacityProviderStrategy = 'At least one capacity provider is required.';
144
+ } else {
145
+ const strategyErrors = strategy.map((item) => {
146
+ const itemErrors: ValidationErrors = {};
147
+ if (!required(item.capacityProvider)) {
148
+ itemErrors.capacityProvider = 'Capacity provider is required.';
149
+ }
150
+ if (!validInteger(item.base)) {
151
+ itemErrors.base = 'Base must be a non-negative integer.';
152
+ }
153
+ if (!validInteger(item.weight)) {
154
+ itemErrors.weight = 'Weight must be a non-negative integer.';
155
+ }
156
+ return itemErrors;
157
+ });
158
+ if (hasRowErrors(strategyErrors)) {
159
+ validationErrors.capacityProviderStrategy = strategyErrors;
160
+ }
161
+ }
162
+ }
163
+ if (Object.keys(errors).length) {
164
+ validationErrors.capacity = errors;
165
+ }
166
+ return validationErrors;
167
+ };
168
+
169
+ export const validateEcsServerGroup: Validator = (values) => ({
170
+ ...validateEcsBasicSettings(values),
171
+ ...validateEcsTaskDefinition(values),
172
+ ...validateEcsContainer(values),
173
+ ...validateEcsServiceDiscovery(values),
174
+ ...validateEcsCapacity(values),
175
+ });
176
+
177
+ interface IEcsWizardPageValidationProps {
178
+ children: React.ReactElement;
179
+ validator: Validator;
180
+ }
181
+
182
+ export class EcsWizardPageValidation
183
+ extends React.Component<IEcsWizardPageValidationProps>
184
+ implements IWizardPageComponent<IEcsServerGroupCommand> {
185
+ public validate = (values: IEcsServerGroupCommand) => this.props.validator(values);
186
+
187
+ public render() {
188
+ return React.Children.only(this.props.children);
189
+ }
190
+ }