@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,29 @@
1
+ import type { IEcsDockerImage } from './serverGroupConfiguration.service';
2
+
3
+ export function buildEcsImageId(image: any): string {
4
+ if (image.imageId) {
5
+ return image.imageId;
6
+ }
7
+ if (image.fromContext) {
8
+ return image.imageLabelOrSha;
9
+ }
10
+ if (image.fromTrigger && !image.tag) {
11
+ return `${image.registry}/${image.repository} (Tag resolved at runtime)`;
12
+ }
13
+ if (image.registry && image.repository && image.tag) {
14
+ return `${image.registry}/${image.repository}:${image.tag}`;
15
+ }
16
+ return image.reference || image.repository || '';
17
+ }
18
+
19
+ export function normalizeEcsDockerImage(image: any): IEcsDockerImage {
20
+ return {
21
+ ...image,
22
+ imageId: buildEcsImageId(image),
23
+ message: image.message || '',
24
+ fromTrigger: !!image.fromTrigger,
25
+ fromContext: !!image.fromContext,
26
+ stageId: image.stageId || '',
27
+ imageLabelOrSha: image.imageLabelOrSha || '',
28
+ };
29
+ }
@@ -1,281 +1,218 @@
1
- 'use strict';
2
-
3
- import * as angular from 'angular';
4
1
  import _ from 'lodash';
5
2
 
6
- import { AccountService, INSTANCE_TYPE_SERVICE } from '@spinnaker/core';
7
-
8
- import { ECS_SERVER_GROUP_CONFIGURATION_SERVICE } from './serverGroupConfiguration.service';
9
-
10
- export const ECS_SERVERGROUP_CONFIGURE_SERVERGROUPCOMMANDBUILDER_SERVICE =
11
- 'spinnaker.ecs.serverGroupCommandBuilder.service';
12
- export const name = ECS_SERVERGROUP_CONFIGURE_SERVERGROUPCOMMANDBUILDER_SERVICE; // for backwards compatibility
13
- angular
14
- .module(ECS_SERVERGROUP_CONFIGURE_SERVERGROUPCOMMANDBUILDER_SERVICE, [
15
- INSTANCE_TYPE_SERVICE,
16
- ECS_SERVER_GROUP_CONFIGURATION_SERVICE,
17
- ])
18
- .factory('ecsServerGroupCommandBuilder', [
19
- '$q',
20
- 'instanceTypeService',
21
- 'ecsServerGroupConfigurationService',
22
- function ($q, instanceTypeService, ecsServerGroupConfigurationService) {
23
- function reconcileUpstreamImages(image, upstreamImages) {
24
- if (image.fromContext) {
25
- const matchingImage = upstreamImages.find((otherImage) => image.stageId === otherImage.stageId);
26
-
27
- if (matchingImage) {
28
- image.cluster = matchingImage.cluster;
29
- image.pattern = matchingImage.pattern;
30
- image.repository = matchingImage.repository;
31
- return image;
32
- } else {
33
- return null;
34
- }
35
- } else if (image.fromTrigger) {
36
- const matchingImage = upstreamImages.find((otherImage) => {
37
- return (
38
- image.registry === otherImage.registry &&
39
- image.repository === otherImage.repository &&
40
- image.tag === otherImage.tag
41
- );
42
- });
43
-
44
- if (matchingImage) {
45
- return image;
46
- } else {
47
- return null;
48
- }
49
- } else {
50
- return image;
51
- }
52
- }
53
-
54
- function findUpstreamImages(current, all, visited = {}) {
55
- // This actually indicates a loop in the stage dependencies.
56
- if (visited[current.refId]) {
57
- return [];
58
- } else {
59
- visited[current.refId] = true;
60
- }
61
- let result = [];
62
- if (current.type === 'findImageFromTags') {
63
- result.push({
64
- fromContext: true,
65
- imageLabelOrSha: current.imageLabelOrSha,
66
- stageId: current.refId,
67
- });
68
- }
69
- current.requisiteStageRefIds.forEach(function (id) {
70
- const next = all.find((stage) => stage.refId === id);
71
- if (next) {
72
- result = result.concat(findUpstreamImages(next, all, visited));
73
- }
74
- });
75
-
76
- return result;
77
- }
78
-
79
- function findTriggerImages(triggers) {
80
- const result = triggers
81
- .filter((trigger) => {
82
- return trigger.type === 'docker';
83
- })
84
- .map((trigger) => {
85
- return {
86
- fromTrigger: true,
87
- repository: trigger.repository,
88
- account: trigger.account,
89
- organization: trigger.organization,
90
- registry: trigger.registry,
91
- tag: trigger.tag,
92
- };
93
- });
94
-
95
- return result;
96
- }
97
-
98
- function buildNewServerGroupCommand(application, defaults) {
99
- defaults = defaults || {};
100
- const credentialsLoader = AccountService.getCredentialsKeyedByAccount('ecs');
101
-
102
- const defaultCredentials = defaults.account || application.defaultCredentials.ecs;
103
- const defaultRegion = defaults.region || application.defaultRegions.ecs;
104
-
105
- const preferredZonesLoader = AccountService.getAvailabilityZonesForAccountAndRegion(
106
- 'ecs',
107
- defaultCredentials,
108
- defaultRegion,
109
- );
110
-
111
- return $q
112
- .all({
113
- preferredZones: preferredZonesLoader,
114
- credentialsKeyedByAccount: credentialsLoader,
115
- })
116
- .then(function (asyncData) {
117
- const availabilityZones = asyncData.preferredZones;
118
-
119
- let defaultIamRole = 'None (No IAM role)';
120
- defaultIamRole = defaultIamRole.replace('{{application}}', application.name);
121
-
122
- const defaultImageCredentials = 'None (No registry credentials)';
123
-
124
- const command = {
125
- application: application.name,
126
- credentials: defaultCredentials,
127
- region: defaultRegion,
128
- strategy: '',
129
- capacity: {
130
- min: 1,
131
- max: 1,
132
- desired: 1,
133
- },
134
- launchType: 'EC2',
135
- healthCheckType: 'EC2',
136
- selectedProvider: 'ecs',
137
- iamRole: defaultIamRole,
138
- dockerImageCredentialsSecret: defaultImageCredentials,
139
- availabilityZones: availabilityZones,
140
- subnetType: '',
141
- securityGroupNames: [],
142
- healthCheckGracePeriodSeconds: '',
143
- placementConstraints: [],
144
- placementStrategyName: '',
145
- taskDefinitionArtifact: {},
146
- useTaskDefinitionArtifact: false,
147
- placementStrategySequence: [],
148
- serviceDiscoveryAssociations: [],
149
- ecsClusterName: '',
150
- targetGroup: '',
151
- copySourceScalingPoliciesAndActions: true,
152
- preferSourceCapacity: true,
153
- useSourceCapacity: true,
154
- enableDeploymentCircuitBreaker: false,
155
- viewState: {
156
- useAllImageSelection: false,
157
- useSimpleCapacity: true,
158
- usePreferredZones: true,
159
- mode: defaults.mode || 'create',
160
- disableStrategySelection: true,
161
- dirty: {},
162
- },
163
- };
164
-
165
- if (
166
- application.attributes &&
167
- application.attributes.platformHealthOnlyShowOverride &&
168
- application.attributes.platformHealthOnly
169
- ) {
170
- command.interestingHealthProviderNames = ['ecs'];
171
- }
172
-
173
- return command;
174
- });
175
- }
176
-
177
- function buildServerGroupCommandFromPipeline(application, originalCluster, current, pipeline) {
178
- const pipelineCluster = _.cloneDeep(originalCluster);
179
- const region = Object.keys(pipelineCluster.availabilityZones)[0];
180
- // var instanceTypeCategoryLoader = instanceTypeService.getCategoryForInstanceType('ecs', pipelineCluster.instanceType);
181
-
182
- const commandOptions = { account: pipelineCluster.account, region: region };
183
- return buildNewServerGroupCommand(application, commandOptions).then(function (command) {
184
- const zones = pipelineCluster.availabilityZones[region];
185
- const usePreferredZones = zones.join(',') === command.availabilityZones.join(',');
186
-
187
- let contextImages = findUpstreamImages(current, pipeline.stages) || [];
188
- contextImages = contextImages.concat(findTriggerImages(pipeline.triggers));
189
-
190
- if (command.docker && command.docker.image) {
191
- command.docker.image = reconcileUpstreamImages(command.docker.image, contextImages);
192
- }
193
-
194
- const viewState = {
195
- instanceProfile: undefined,
196
- disableImageSelection: true,
197
- useSimpleCapacity:
198
- pipelineCluster.capacity.min === pipelineCluster.capacity.max &&
199
- pipelineCluster.useSourceCapacity !== true,
200
- usePreferredZones: usePreferredZones,
201
- mode: 'editPipeline',
202
- submitButtonLabel: 'Done',
203
- templatingEnabled: true,
204
- existingPipelineCluster: true,
205
- dirty: {},
206
- contextImages: contextImages,
207
- pipeline: pipeline,
208
- currentStage: current,
209
- };
210
-
211
- const viewOverrides = {
212
- region: region,
213
- credentials: pipelineCluster.account,
214
- availabilityZones: pipelineCluster.availabilityZones[region],
215
- viewState: viewState,
216
- };
217
-
218
- pipelineCluster.strategy = pipelineCluster.strategy || '';
219
-
220
- return angular.extend({}, command, pipelineCluster, viewOverrides);
221
- });
222
- }
223
-
224
- // Only used to prepare view requiring template selecting
225
- function buildNewServerGroupCommandForPipeline(current, pipeline) {
226
- let contextImages = findUpstreamImages(current, pipeline.stages) || [];
227
- contextImages = contextImages.concat(findTriggerImages(pipeline.triggers));
228
-
229
- return $q.when({
230
- viewState: {
231
- requiresTemplateSelection: true,
232
- // applies viewState overrides after template selection
233
- overrides: {
234
- viewState: {
235
- mode: 'editPipeline',
236
- contextImages: contextImages,
237
- pipeline: pipeline,
238
- currentStage: current,
239
- },
240
- },
241
- },
242
- });
243
- }
244
-
245
- function buildUpdateServerGroupCommand(serverGroup) {
246
- const command = {
247
- type: 'modifyAsg',
248
- asgs: [{ asgName: serverGroup.name, region: serverGroup.region }],
249
- healthCheckType: serverGroup.asg.healthCheckType,
250
- credentials: serverGroup.account,
251
- };
252
- ecsServerGroupConfigurationService.configureUpdateCommand(command);
253
- return command;
254
- }
255
-
256
- function buildServerGroupCommandFromExisting(application, serverGroup, mode = 'clone') {
257
- // do NOT copy: deployment strategy. DO copy: account, region, cluster name, stack
258
- // TODO: query for & pull in ECS-specific data that would be useful, e.g, network mode, launch type
259
- const commandOptions = { account: serverGroup.account, region: serverGroup.region };
260
- return buildNewServerGroupCommand(application, commandOptions).then(function (command) {
261
- command.credentials = serverGroup.account;
262
- command.app = serverGroup.moniker.app;
263
- command.stack = serverGroup.moniker.stack;
264
- command.region = serverGroup.region;
265
- command.ecsClusterName = serverGroup.ecsCluster;
266
- command.capacity = serverGroup.capacity;
267
- command.viewState.mode = mode;
268
-
269
- return command;
270
- });
271
- }
272
-
273
- return {
274
- buildNewServerGroupCommand: buildNewServerGroupCommand,
275
- buildServerGroupCommandFromExisting: buildServerGroupCommandFromExisting,
276
- buildNewServerGroupCommandForPipeline: buildNewServerGroupCommandForPipeline,
277
- buildServerGroupCommandFromPipeline: buildServerGroupCommandFromPipeline,
278
- buildUpdateServerGroupCommand: buildUpdateServerGroupCommand,
279
- };
3
+ import { AccountService } from '@spinnaker/core';
4
+
5
+ import { EcsServerGroupConfigurationService } from './serverGroupConfiguration.service';
6
+
7
+ function reconcileUpstreamImages(image, upstreamImages) {
8
+ if (image.fromContext) {
9
+ const matchingImage = upstreamImages.find((otherImage) => image.stageId === otherImage.stageId);
10
+ if (matchingImage) {
11
+ image.cluster = matchingImage.cluster;
12
+ image.pattern = matchingImage.pattern;
13
+ image.repository = matchingImage.repository;
14
+ return image;
15
+ }
16
+ return null;
17
+ }
18
+ if (image.fromTrigger) {
19
+ const matchingImage = upstreamImages.find(
20
+ (otherImage) =>
21
+ image.registry === otherImage.registry &&
22
+ image.repository === otherImage.repository &&
23
+ image.tag === otherImage.tag,
24
+ );
25
+ return matchingImage ? image : null;
26
+ }
27
+ return image;
28
+ }
29
+
30
+ function findUpstreamImages(current, all, visited = {}) {
31
+ if (visited[current.refId]) {
32
+ return [];
33
+ }
34
+ visited[current.refId] = true;
35
+ let result = [];
36
+ if (current.type === 'findImageFromTags') {
37
+ result.push({ fromContext: true, imageLabelOrSha: current.imageLabelOrSha, stageId: current.refId });
38
+ }
39
+ current.requisiteStageRefIds.forEach((id) => {
40
+ const next = all.find((stage) => stage.refId === id);
41
+ if (next) {
42
+ result = result.concat(findUpstreamImages(next, all, visited));
43
+ }
44
+ });
45
+ return result;
46
+ }
47
+
48
+ function findTriggerImages(triggers) {
49
+ return triggers
50
+ .filter((trigger) => trigger.type === 'docker')
51
+ .map((trigger) => ({
52
+ fromTrigger: true,
53
+ repository: trigger.repository,
54
+ account: trigger.account,
55
+ organization: trigger.organization,
56
+ registry: trigger.registry,
57
+ tag: trigger.tag,
58
+ }));
59
+ }
60
+
61
+ function buildNewServerGroupCommand(application, defaults) {
62
+ defaults = defaults || {};
63
+ const defaultCredentials = defaults.account || application.defaultCredentials.ecs;
64
+ const defaultRegion = defaults.region || application.defaultRegions.ecs;
65
+
66
+ return Promise.all([
67
+ AccountService.getAvailabilityZonesForAccountAndRegion('ecs', defaultCredentials, defaultRegion),
68
+ AccountService.getCredentialsKeyedByAccount('ecs'),
69
+ ]).then(([availabilityZones]) => {
70
+ const command = {
71
+ application: application.name,
72
+ credentials: defaultCredentials,
73
+ region: defaultRegion,
74
+ strategy: '',
75
+ capacity: { min: 1, max: 1, desired: 1 },
76
+ launchType: 'EC2',
77
+ healthCheckType: 'EC2',
78
+ selectedProvider: 'ecs',
79
+ iamRole: 'None (No IAM role)',
80
+ dockerImageCredentialsSecret: 'None (No registry credentials)',
81
+ availabilityZones,
82
+ subnetType: '',
83
+ securityGroupNames: [],
84
+ healthCheckGracePeriodSeconds: '',
85
+ placementConstraints: [],
86
+ placementStrategyName: '',
87
+ taskDefinitionArtifact: {},
88
+ useTaskDefinitionArtifact: false,
89
+ placementStrategySequence: [],
90
+ serviceDiscoveryAssociations: [],
91
+ ecsClusterName: '',
92
+ targetGroup: '',
93
+ copySourceScalingPoliciesAndActions: true,
94
+ preferSourceCapacity: true,
95
+ useSourceCapacity: true,
96
+ enableDeploymentCircuitBreaker: false,
97
+ viewState: {
98
+ useAllImageSelection: false,
99
+ useSimpleCapacity: true,
100
+ usePreferredZones: true,
101
+ mode: defaults.mode || 'create',
102
+ disableStrategySelection: true,
103
+ dirty: {},
104
+ },
105
+ };
106
+
107
+ if (application.attributes?.platformHealthOnlyShowOverride && application.attributes.platformHealthOnly) {
108
+ command.interestingHealthProviderNames = ['ecs'];
109
+ }
110
+
111
+ return command;
112
+ });
113
+ }
114
+
115
+ function buildServerGroupCommandFromPipeline(application, originalCluster, current, pipeline) {
116
+ const pipelineCluster = _.cloneDeep(originalCluster);
117
+ const availabilityZonesByRegion = pipelineCluster.availabilityZones || {};
118
+ const region = Object.keys(availabilityZonesByRegion)[0] || pipelineCluster.region || application.defaultRegions?.ecs;
119
+ const commandOptions = { account: pipelineCluster.account, region };
120
+ return buildNewServerGroupCommand(application, commandOptions).then((command) => {
121
+ const zones = availabilityZonesByRegion[region] || command.availabilityZones || [];
122
+ const usePreferredZones = zones.join(',') === (command.availabilityZones || []).join(',');
123
+ let contextImages = findUpstreamImages(current, pipeline.stages) || [];
124
+ contextImages = contextImages.concat(findTriggerImages(pipeline.triggers));
125
+
126
+ if (command.docker?.image) {
127
+ command.docker.image = reconcileUpstreamImages(command.docker.image, contextImages);
128
+ }
129
+
130
+ const viewState = {
131
+ instanceProfile: undefined,
132
+ disableImageSelection: true,
133
+ useSimpleCapacity:
134
+ !!pipelineCluster.capacity &&
135
+ pipelineCluster.capacity.min === pipelineCluster.capacity.max &&
136
+ pipelineCluster.useSourceCapacity !== true,
137
+ usePreferredZones,
138
+ mode: 'editPipeline',
139
+ submitButtonLabel: 'Done',
140
+ templatingEnabled: true,
141
+ existingPipelineCluster: true,
142
+ dirty: {},
143
+ contextImages,
144
+ pipeline,
145
+ currentStage: current,
146
+ };
147
+
148
+ pipelineCluster.strategy = pipelineCluster.strategy || '';
149
+ return Object.assign({}, command, pipelineCluster, {
150
+ region,
151
+ credentials: pipelineCluster.account,
152
+ availabilityZones: zones,
153
+ viewState,
154
+ });
155
+ });
156
+ }
157
+
158
+ function buildNewServerGroupCommandForPipeline(current, pipeline) {
159
+ let contextImages = findUpstreamImages(current, pipeline.stages) || [];
160
+ contextImages = contextImages.concat(findTriggerImages(pipeline.triggers));
161
+ return Promise.resolve({
162
+ viewState: {
163
+ requiresTemplateSelection: true,
164
+ overrides: { viewState: { mode: 'editPipeline', contextImages, pipeline, currentStage: current } },
280
165
  },
281
- ]);
166
+ });
167
+ }
168
+
169
+ function buildUpdateServerGroupCommand(serverGroup, configurationService) {
170
+ const command = {
171
+ type: 'modifyAsg',
172
+ asgs: [{ asgName: serverGroup.name, region: serverGroup.region }],
173
+ healthCheckType: serverGroup.asg?.healthCheckType,
174
+ credentials: serverGroup.account,
175
+ };
176
+ configurationService.configureUpdateCommand(command);
177
+ return command;
178
+ }
179
+
180
+ function buildServerGroupCommandFromExisting(application, serverGroup, mode = 'clone') {
181
+ const commandOptions = { account: serverGroup.account, region: serverGroup.region };
182
+ return buildNewServerGroupCommand(application, commandOptions).then((command) => {
183
+ command.credentials = serverGroup.account;
184
+ command.app = serverGroup.moniker.app;
185
+ command.stack = serverGroup.moniker.stack;
186
+ command.region = serverGroup.region;
187
+ command.ecsClusterName = serverGroup.ecsCluster;
188
+ command.capacity = serverGroup.capacity;
189
+ command.viewState.mode = mode;
190
+ return command;
191
+ });
192
+ }
193
+
194
+ export class EcsServerGroupCommandBuilder {
195
+ constructor() {
196
+ this.configurationService = new EcsServerGroupConfigurationService();
197
+ }
198
+
199
+ buildNewServerGroupCommand(application, defaults) {
200
+ return buildNewServerGroupCommand(application, defaults);
201
+ }
202
+
203
+ buildServerGroupCommandFromExisting(application, serverGroup, mode) {
204
+ return buildServerGroupCommandFromExisting(application, serverGroup, mode);
205
+ }
206
+
207
+ buildNewServerGroupCommandForPipeline(current, pipeline) {
208
+ return buildNewServerGroupCommandForPipeline(current, pipeline);
209
+ }
210
+
211
+ buildServerGroupCommandFromPipeline(application, originalCluster, current, pipeline) {
212
+ return buildServerGroupCommandFromPipeline(application, originalCluster, current, pipeline);
213
+ }
214
+
215
+ buildUpdateServerGroupCommand(serverGroup) {
216
+ return buildUpdateServerGroupCommand(serverGroup, this.configurationService);
217
+ }
218
+ }
@@ -0,0 +1,83 @@
1
+ import { AccountService } from '@spinnaker/core';
2
+
3
+ import { EcsServerGroupCommandBuilder } from './serverGroupCommandBuilder.service';
4
+
5
+ describe('EcsServerGroupCommandBuilder', () => {
6
+ it('builds a new server group command when no defaults are provided (create flow passes null)', async () => {
7
+ spyOn(AccountService, 'getAvailabilityZonesForAccountAndRegion').and.returnValue(Promise.resolve(['us-west-2a']));
8
+ spyOn(AccountService, 'getCredentialsKeyedByAccount').and.returnValue(Promise.resolve({}));
9
+
10
+ const command = await new EcsServerGroupCommandBuilder().buildNewServerGroupCommand(
11
+ {
12
+ defaultCredentials: { ecs: 'ecs-prod' },
13
+ defaultRegions: { ecs: 'us-west-2' },
14
+ name: 'api',
15
+ } as any,
16
+ null,
17
+ );
18
+
19
+ expect(command.credentials).toBe('ecs-prod');
20
+ expect(command.region).toBe('us-west-2');
21
+ });
22
+
23
+ it('builds pipeline commands when availability zones are missing', async () => {
24
+ spyOn(AccountService, 'getAvailabilityZonesForAccountAndRegion').and.returnValue(Promise.resolve(['us-west-2a']));
25
+ spyOn(AccountService, 'getCredentialsKeyedByAccount').and.returnValue(Promise.resolve({}));
26
+
27
+ const command = await new EcsServerGroupCommandBuilder().buildServerGroupCommandFromPipeline(
28
+ {
29
+ defaultCredentials: { ecs: 'ecs-prod' },
30
+ defaultRegions: { ecs: 'us-west-2' },
31
+ name: 'api',
32
+ } as any,
33
+ {
34
+ account: 'ecs-prod',
35
+ capacity: { min: 1, max: 1 },
36
+ useSourceCapacity: false,
37
+ },
38
+ { requisiteStageRefIds: [], refId: '1', type: 'deploy' },
39
+ { stages: [], triggers: [] },
40
+ );
41
+
42
+ expect(command.region).toBe('us-west-2');
43
+ expect(command.availabilityZones).toEqual(['us-west-2a']);
44
+ });
45
+
46
+ it('builds pipeline commands when source capacity omits explicit capacity', async () => {
47
+ spyOn(AccountService, 'getAvailabilityZonesForAccountAndRegion').and.returnValue(Promise.resolve(['us-west-2a']));
48
+ spyOn(AccountService, 'getCredentialsKeyedByAccount').and.returnValue(Promise.resolve({}));
49
+
50
+ const command = await new EcsServerGroupCommandBuilder().buildServerGroupCommandFromPipeline(
51
+ {
52
+ defaultCredentials: { ecs: 'ecs-prod' },
53
+ defaultRegions: { ecs: 'us-west-2' },
54
+ name: 'api',
55
+ } as any,
56
+ {
57
+ account: 'ecs-prod',
58
+ useSourceCapacity: true,
59
+ },
60
+ { requisiteStageRefIds: [], refId: '1', type: 'deploy' },
61
+ { stages: [], triggers: [] },
62
+ );
63
+
64
+ expect(command.viewState.useSimpleCapacity).toBe(false);
65
+ });
66
+
67
+ it('builds update commands for ECS server groups without ASG metadata', () => {
68
+ const command = new EcsServerGroupCommandBuilder().buildUpdateServerGroupCommand({
69
+ account: 'ecs-prod',
70
+ name: 'api-main-v001',
71
+ region: 'eu-west-1',
72
+ } as any);
73
+
74
+ expect(command).toEqual(
75
+ jasmine.objectContaining({
76
+ asgs: [{ asgName: 'api-main-v001', region: 'eu-west-1' }],
77
+ credentials: 'ecs-prod',
78
+ healthCheckType: undefined,
79
+ type: 'modifyAsg',
80
+ }),
81
+ );
82
+ });
83
+ });