@spinnaker/amazon 0.11.1 → 0.12.3
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.
- package/CHANGELOG.md +43 -0
- package/dist/domain/IAmazonLaunchTemplate.d.ts +1 -1
- package/dist/domain/IAmazonServerGroup.d.ts +10 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/instance/awsInstanceType.service.d.ts +10 -2
- package/dist/instance/awsInstanceTypes.d.ts +10 -0
- package/dist/instance/details/CostFactor.d.ts +6 -0
- package/dist/reactShims/aws.react.injector.d.ts +2 -1
- package/dist/search/searchResultFormatter.d.ts +2 -2
- package/dist/serverGroup/configure/serverGroupCommandBuilder.service.d.ts +17 -2
- package/dist/serverGroup/configure/serverGroupConfiguration.service.d.ts +39 -0
- package/dist/serverGroup/configure/wizard/instanceType/CpuCreditsToggle.d.ts +3 -4
- package/dist/serverGroup/configure/wizard/instanceType/InstanceTypeSelector.d.ts +9 -0
- package/dist/serverGroup/configure/wizard/instanceType/advancedMode/AdvancedModeSelector.d.ts +13 -0
- package/dist/serverGroup/configure/wizard/instanceType/advancedMode/InstanceProfileSelector.d.ts +9 -0
- package/dist/serverGroup/configure/wizard/instanceType/advancedMode/InstanceTypeRow.d.ts +11 -0
- package/dist/serverGroup/configure/wizard/instanceType/advancedMode/InstanceTypeTable.d.ts +14 -0
- package/dist/serverGroup/configure/wizard/instanceType/advancedMode/InstanceTypeTableBody.d.ts +12 -0
- package/dist/serverGroup/configure/wizard/instanceType/advancedMode/InstanceTypeTableParts.d.ts +15 -0
- package/dist/serverGroup/configure/wizard/instanceType/advancedMode/InstancesDistribution.d.ts +8 -0
- package/dist/serverGroup/configure/wizard/instanceType/simpleMode/SimpleModeSelector.d.ts +8 -0
- package/dist/serverGroup/configure/wizard/pages/ServerGroupInstanceType.d.ts +9 -6
- package/dist/serverGroup/serverGroup.transformer.d.ts +2 -1
- package/package.json +5 -5
- package/src/domain/IAmazonLaunchTemplate.ts +1 -1
- package/src/domain/IAmazonServerGroup.ts +11 -0
- package/src/function/details/FunctionActions.spec.tsx +10 -9
- package/src/help/amazon.help.ts +9 -6
- package/src/image/image.reader.spec.ts +75 -0
- package/src/instance/awsInstanceType.service.spec.js +37 -71
- package/src/instance/awsInstanceType.service.ts +191 -0
- package/src/instance/awsInstanceTypes.ts +311 -0
- package/src/instance/details/CostFactor.tsx +29 -0
- package/src/instance/details/InstanceInformation.spec.tsx +2 -1
- package/src/instance/details/instance.details.controller.js +471 -473
- package/src/loadBalancer/details/loadBalancerDetails.controller.spec.ts +5 -3
- package/src/reactShims/aws.react.injector.ts +2 -1
- package/src/search/{searchResultFormatter.js → searchResultFormatter.ts} +5 -4
- package/src/serverGroup/configure/AmazonImageSelectInput.spec.tsx +10 -7
- package/src/serverGroup/configure/serverGroupCommandBuilder.aws.service.spec.js +302 -1
- package/src/serverGroup/configure/{serverGroupCommandBuilder.service.js → serverGroupCommandBuilder.service.ts} +182 -73
- package/src/serverGroup/configure/serverGroupCommandBuilder.spec.js +25 -8
- package/src/serverGroup/configure/serverGroupConfiguration.service.spec.ts +6 -13
- package/src/serverGroup/configure/serverGroupConfiguration.service.ts +53 -0
- package/src/serverGroup/configure/wizard/AmazonCloneServerGroupModal.tsx +1 -1
- package/src/serverGroup/configure/wizard/instanceType/CpuCreditsToggle.tsx +31 -31
- package/src/serverGroup/configure/wizard/instanceType/InstanceTypeSelector.tsx +133 -0
- package/src/serverGroup/configure/wizard/instanceType/advancedMode/AdvancedModeSelector.tsx +99 -0
- package/src/serverGroup/configure/wizard/instanceType/advancedMode/InstanceProfileSelector.tsx +36 -0
- package/src/serverGroup/configure/wizard/instanceType/advancedMode/InstanceTypeRow.tsx +144 -0
- package/src/serverGroup/configure/wizard/instanceType/advancedMode/InstanceTypeTable.tsx +138 -0
- package/src/serverGroup/configure/wizard/instanceType/advancedMode/InstanceTypeTableBody.tsx +135 -0
- package/src/serverGroup/configure/wizard/instanceType/advancedMode/InstanceTypeTableParts.tsx +137 -0
- package/src/serverGroup/configure/wizard/instanceType/advancedMode/InstancesDistribution.less +5 -0
- package/src/serverGroup/configure/wizard/instanceType/advancedMode/InstancesDistribution.tsx +108 -0
- package/src/serverGroup/configure/wizard/instanceType/advancedMode/advancedMode.less +110 -0
- package/src/serverGroup/configure/wizard/instanceType/simpleMode/SimpleModeSelector.tsx +62 -0
- package/src/serverGroup/configure/wizard/pages/ServerGroupInstanceType.tsx +107 -62
- package/src/serverGroup/configure/wizard/pages/advancedSettings/ServerGroupAdvancedSettingsCommon.tsx +1 -1
- package/src/serverGroup/details/scalingPolicy/scalingPolicySummary.component.ts +6 -2
- package/src/serverGroup/details/scalingProcesses/AutoScalingProcessService.spec.ts +1 -2
- package/src/serverGroup/details/sections/InstancesDistributionDetailsSection.spec.tsx +8 -5
- package/src/serverGroup/details/sections/LaunchTemplateDetailsSection.spec.tsx +8 -5
- package/src/serverGroup/serverGroup.transformer.spec.ts +5 -3
- package/src/serverGroup/serverGroup.transformer.ts +24 -22
- package/src/subnet/SubnetSelectInput.spec.tsx +7 -4
- package/src/vpc/{VpcReader.spec.js → VpcReader.spec.ts} +2 -10
- package/src/vpc/VpcTag.spec.tsx +37 -0
- package/src/vpc/vpc.module.ts +6 -2
- package/dist/vpc/vpcTag.directive.d.ts +0 -2
- package/src/image/image.reader.spec.js +0 -123
- package/src/instance/awsInstanceType.service.js +0 -437
- package/src/vpc/vpcTag.directive.js +0 -34
- package/src/vpc/vpcTag.directive.spec.js +0 -60
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import type { IQService } from 'angular';
|
|
1
2
|
import * as angular from 'angular';
|
|
2
3
|
import _ from 'lodash';
|
|
3
4
|
|
|
5
|
+
import type { Application, InstanceTypeService } from '@spinnaker/core';
|
|
4
6
|
import {
|
|
5
7
|
AccountService,
|
|
6
8
|
DeploymentStrategyRegistry,
|
|
@@ -8,13 +10,45 @@ import {
|
|
|
8
10
|
NameUtils,
|
|
9
11
|
SubnetReader,
|
|
10
12
|
} from '@spinnaker/core';
|
|
11
|
-
import { AWSProviderSettings } from '../../aws.settings';
|
|
12
13
|
|
|
14
|
+
import { AWSProviderSettings } from '../../aws.settings';
|
|
15
|
+
import type { IAmazonLaunchTemplateOverrides, ILaunchTemplateData } from '../../domain';
|
|
16
|
+
import type { IAmazonServerGroup, IAmazonServerGroupView, INetworkInterface } from '../../domain';
|
|
17
|
+
import type {
|
|
18
|
+
AwsServerGroupConfigurationService,
|
|
19
|
+
IAmazonInstanceTypeOverride,
|
|
20
|
+
IAmazonServerGroupCommand,
|
|
21
|
+
IAmazonServerGroupCommandViewState,
|
|
22
|
+
IAmazonServerGroupDeployConfiguration,
|
|
23
|
+
} from './serverGroupConfiguration.service';
|
|
13
24
|
import { AWS_SERVER_GROUP_CONFIGURATION_SERVICE } from './serverGroupConfiguration.service';
|
|
14
25
|
|
|
15
26
|
export const AMAZON_SERVERGROUP_CONFIGURE_SERVERGROUPCOMMANDBUILDER_SERVICE =
|
|
16
27
|
'spinnaker.amazon.serverGroupCommandBuilder.service';
|
|
17
28
|
export const name = AMAZON_SERVERGROUP_CONFIGURE_SERVERGROUPCOMMANDBUILDER_SERVICE; // for backwards compatibility
|
|
29
|
+
|
|
30
|
+
export interface AwsServerGroupCommandBuilder {
|
|
31
|
+
buildNewServerGroupCommand(
|
|
32
|
+
application: Application,
|
|
33
|
+
defaults?: { account?: string; region?: string; subnet?: string; mode?: string },
|
|
34
|
+
): PromiseLike<Partial<IAmazonServerGroupCommand>>;
|
|
35
|
+
|
|
36
|
+
buildServerGroupCommandFromExisting(
|
|
37
|
+
application: Application,
|
|
38
|
+
serverGroup: IAmazonServerGroupView,
|
|
39
|
+
mode?: string,
|
|
40
|
+
): PromiseLike<Partial<IAmazonServerGroupCommand>>;
|
|
41
|
+
|
|
42
|
+
buildNewServerGroupCommandForPipeline(): PromiseLike<Partial<IAmazonServerGroupCommand>>;
|
|
43
|
+
|
|
44
|
+
buildServerGroupCommandFromPipeline(
|
|
45
|
+
application: Application,
|
|
46
|
+
originalCluster: IAmazonServerGroupDeployConfiguration,
|
|
47
|
+
): PromiseLike<Partial<IAmazonServerGroupCommand>>;
|
|
48
|
+
|
|
49
|
+
buildUpdateServerGroupCommand(serverGroup: IAmazonServerGroup): Partial<IAmazonServerGroupCommand>;
|
|
50
|
+
}
|
|
51
|
+
|
|
18
52
|
angular
|
|
19
53
|
.module(AMAZON_SERVERGROUP_CONFIGURE_SERVERGROUPCOMMANDBUILDER_SERVICE, [
|
|
20
54
|
INSTANCE_TYPE_SERVICE,
|
|
@@ -24,9 +58,15 @@ angular
|
|
|
24
58
|
'$q',
|
|
25
59
|
'instanceTypeService',
|
|
26
60
|
'awsServerGroupConfigurationService',
|
|
27
|
-
function (
|
|
28
|
-
|
|
29
|
-
|
|
61
|
+
function (
|
|
62
|
+
$q: IQService,
|
|
63
|
+
instanceTypeService: InstanceTypeService,
|
|
64
|
+
awsServerGroupConfigurationService: AwsServerGroupConfigurationService,
|
|
65
|
+
) {
|
|
66
|
+
function buildNewServerGroupCommand(
|
|
67
|
+
application: Application,
|
|
68
|
+
defaults: { account?: string; region?: string; subnet?: string; mode?: string } = {},
|
|
69
|
+
) {
|
|
30
70
|
const credentialsLoader = AccountService.getCredentialsKeyedByAccount('aws');
|
|
31
71
|
|
|
32
72
|
const defaultCredentials =
|
|
@@ -45,14 +85,14 @@ angular
|
|
|
45
85
|
.then(function ([preferredZones, credentialsKeyedByAccount]) {
|
|
46
86
|
const credentials = credentialsKeyedByAccount[defaultCredentials];
|
|
47
87
|
const keyPair = credentials ? credentials.defaultKeyPair : null;
|
|
48
|
-
const applicationAwsSettings =
|
|
88
|
+
const applicationAwsSettings = application.attributes?.providerSettings?.aws ?? {};
|
|
49
89
|
|
|
50
90
|
let defaultIamRole = AWSProviderSettings.defaults.iamRole || 'BaseIAMRole';
|
|
51
91
|
defaultIamRole = defaultIamRole.replace('{{application}}', application.name);
|
|
52
92
|
|
|
53
93
|
const useAmiBlockDeviceMappings = applicationAwsSettings.useAmiBlockDeviceMappings || false;
|
|
54
94
|
|
|
55
|
-
const command = {
|
|
95
|
+
const command: Partial<IAmazonServerGroupCommand> = {
|
|
56
96
|
application: application.name,
|
|
57
97
|
credentials: defaultCredentials,
|
|
58
98
|
region: defaultRegion,
|
|
@@ -86,6 +126,7 @@ angular
|
|
|
86
126
|
copySourceCustomBlockDeviceMappings: false, // default to using block device mappings from current instance type
|
|
87
127
|
viewState: {
|
|
88
128
|
instanceProfile: 'custom',
|
|
129
|
+
useSimpleInstanceTypeSelector: true,
|
|
89
130
|
useAllImageSelection: false,
|
|
90
131
|
useSimpleCapacity: true,
|
|
91
132
|
usePreferredZones: true,
|
|
@@ -93,47 +134,46 @@ angular
|
|
|
93
134
|
disableStrategySelection: true,
|
|
94
135
|
dirty: {},
|
|
95
136
|
submitButtonLabel: getSubmitButtonLabel(defaults.mode || 'create'),
|
|
96
|
-
},
|
|
137
|
+
} as IAmazonServerGroupCommandViewState,
|
|
97
138
|
};
|
|
98
139
|
|
|
99
|
-
if (
|
|
100
|
-
application.attributes &&
|
|
101
|
-
application.attributes.platformHealthOnlyShowOverride &&
|
|
102
|
-
application.attributes.platformHealthOnly
|
|
103
|
-
) {
|
|
140
|
+
if (application.attributes?.platformHealthOnlyShowOverride && application.attributes?.platformHealthOnly) {
|
|
104
141
|
command.interestingHealthProviderNames = ['Amazon'];
|
|
105
142
|
}
|
|
106
143
|
|
|
107
|
-
if (
|
|
108
|
-
defaultCredentials === 'test' &&
|
|
109
|
-
AWSProviderSettings.serverGroups &&
|
|
110
|
-
AWSProviderSettings.serverGroups.enableIPv6
|
|
111
|
-
) {
|
|
144
|
+
if (defaultCredentials === 'test' && AWSProviderSettings.serverGroups?.enableIPv6) {
|
|
112
145
|
command.associateIPv6Address = true;
|
|
113
146
|
}
|
|
114
147
|
|
|
115
|
-
if (AWSProviderSettings.serverGroups
|
|
148
|
+
if (AWSProviderSettings.serverGroups?.enableIMDSv2) {
|
|
116
149
|
/**
|
|
117
150
|
* Older SDKs do not support IMDSv2. A timestamp can be optionally configured at which any apps created after can safely default to using IMDSv2.
|
|
118
151
|
*/
|
|
119
152
|
const appAgeRequirement = AWSProviderSettings.serverGroups.defaultIMDSv2AppAgeLimit;
|
|
120
|
-
const creationDate = application.attributes
|
|
153
|
+
const creationDate = application.attributes?.createTs;
|
|
121
154
|
|
|
122
|
-
command.requireIMDSv2 =
|
|
123
|
-
appAgeRequirement && creationDate && Number(creationDate) > appAgeRequirement ? true : false;
|
|
155
|
+
command.requireIMDSv2 = appAgeRequirement && creationDate && Number(creationDate) > appAgeRequirement;
|
|
124
156
|
}
|
|
125
157
|
|
|
126
158
|
return command;
|
|
127
159
|
});
|
|
128
160
|
}
|
|
129
161
|
|
|
130
|
-
function buildServerGroupCommandFromPipeline(
|
|
162
|
+
function buildServerGroupCommandFromPipeline(
|
|
163
|
+
application: Application,
|
|
164
|
+
originalCluster: IAmazonServerGroupDeployConfiguration,
|
|
165
|
+
) {
|
|
131
166
|
const pipelineCluster = _.cloneDeep(originalCluster);
|
|
132
167
|
const region = Object.keys(pipelineCluster.availabilityZones)[0];
|
|
133
|
-
|
|
168
|
+
|
|
169
|
+
const instanceTypes = pipelineCluster.launchTemplateOverridesForInstanceType
|
|
170
|
+
? pipelineCluster.launchTemplateOverridesForInstanceType.map((o) => o.instanceType)
|
|
171
|
+
: [pipelineCluster.instanceType];
|
|
172
|
+
const instanceTypeCategoryLoader = instanceTypeService.getCategoryForMultipleInstanceTypes(
|
|
134
173
|
'aws',
|
|
135
|
-
|
|
174
|
+
instanceTypes,
|
|
136
175
|
);
|
|
176
|
+
|
|
137
177
|
const commandOptions = { account: pipelineCluster.account, region: region };
|
|
138
178
|
const asyncLoader = $q.all([
|
|
139
179
|
buildNewServerGroupCommand(application, commandOptions),
|
|
@@ -156,6 +196,7 @@ angular
|
|
|
156
196
|
templatingEnabled: true,
|
|
157
197
|
existingPipelineCluster: true,
|
|
158
198
|
dirty: {},
|
|
199
|
+
useSimpleInstanceTypeSelector: isSimpleModeEnabled(pipelineCluster),
|
|
159
200
|
};
|
|
160
201
|
|
|
161
202
|
const viewOverrides = {
|
|
@@ -177,11 +218,11 @@ angular
|
|
|
177
218
|
return $q.when({
|
|
178
219
|
viewState: {
|
|
179
220
|
requiresTemplateSelection: true,
|
|
180
|
-
},
|
|
221
|
+
} as IAmazonServerGroupCommandViewState,
|
|
181
222
|
});
|
|
182
223
|
}
|
|
183
224
|
|
|
184
|
-
function getSubmitButtonLabel(mode) {
|
|
225
|
+
function getSubmitButtonLabel(mode: string) {
|
|
185
226
|
switch (mode) {
|
|
186
227
|
case 'createPipeline':
|
|
187
228
|
return 'Add';
|
|
@@ -194,38 +235,52 @@ angular
|
|
|
194
235
|
}
|
|
195
236
|
}
|
|
196
237
|
|
|
197
|
-
function buildUpdateServerGroupCommand(serverGroup) {
|
|
198
|
-
const command = {
|
|
238
|
+
function buildUpdateServerGroupCommand(serverGroup: IAmazonServerGroup) {
|
|
239
|
+
const command = ({
|
|
199
240
|
type: 'modifyAsg',
|
|
200
241
|
asgs: [{ asgName: serverGroup.name, region: serverGroup.region }],
|
|
201
242
|
cooldown: serverGroup.asg.defaultCooldown,
|
|
202
|
-
enabledMetrics:
|
|
243
|
+
enabledMetrics: (serverGroup.asg?.enabledMetrics ?? []).map((m) => m.metric),
|
|
203
244
|
healthCheckGracePeriod: serverGroup.asg.healthCheckGracePeriod,
|
|
204
245
|
healthCheckType: serverGroup.asg.healthCheckType,
|
|
205
246
|
terminationPolicies: angular.copy(serverGroup.asg.terminationPolicies),
|
|
206
247
|
credentials: serverGroup.account,
|
|
207
248
|
capacityRebalance: serverGroup.asg.capacityRebalance,
|
|
208
|
-
};
|
|
249
|
+
} as Partial<IAmazonServerGroupCommand>) as IAmazonServerGroupCommand;
|
|
209
250
|
awsServerGroupConfigurationService.configureUpdateCommand(command);
|
|
210
251
|
return command;
|
|
211
252
|
}
|
|
212
253
|
|
|
213
|
-
function buildServerGroupCommandFromExisting(
|
|
254
|
+
function buildServerGroupCommandFromExisting(
|
|
255
|
+
application: Application,
|
|
256
|
+
serverGroup: IAmazonServerGroupView,
|
|
257
|
+
mode = 'clone',
|
|
258
|
+
) {
|
|
214
259
|
const preferredZonesLoader = AccountService.getPreferredZonesByAccount('aws');
|
|
215
260
|
const subnetsLoader = SubnetReader.listSubnets();
|
|
216
261
|
|
|
217
262
|
const serverGroupName = NameUtils.parseServerGroupName(serverGroup.asg.autoScalingGroupName);
|
|
218
263
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
264
|
+
let instanceTypes;
|
|
265
|
+
if (serverGroup.mixedInstancesPolicy) {
|
|
266
|
+
const ltOverrides = serverGroup.mixedInstancesPolicy?.launchTemplateOverridesForInstanceType;
|
|
267
|
+
// note: single launch template case is currently the only supported case for mixed instances policy
|
|
268
|
+
instanceTypes = ltOverrides
|
|
269
|
+
? ltOverrides.map((o) => o.instanceType)
|
|
270
|
+
: [serverGroup.mixedInstancesPolicy?.launchTemplates[0]?.launchTemplateData?.instanceType];
|
|
271
|
+
} else if (serverGroup.launchTemplate) {
|
|
272
|
+
instanceTypes = [_.get(serverGroup, 'launchTemplate.launchTemplateData.instanceType')];
|
|
273
|
+
} else if (serverGroup.launchConfig) {
|
|
274
|
+
instanceTypes = [_.get(serverGroup, 'launchConfig.instanceType')];
|
|
275
|
+
}
|
|
276
|
+
const instanceTypeCategoryLoader = instanceTypeService.getCategoryForMultipleInstanceTypes(
|
|
277
|
+
'aws',
|
|
278
|
+
instanceTypes,
|
|
279
|
+
);
|
|
225
280
|
|
|
226
281
|
return $q
|
|
227
282
|
.all([preferredZonesLoader, subnetsLoader, instanceTypeCategoryLoader])
|
|
228
|
-
.then(
|
|
283
|
+
.then(([preferredZones, subnets, instanceProfile]) => {
|
|
229
284
|
const zones = serverGroup.asg.availabilityZones.sort();
|
|
230
285
|
let usePreferredZones = false;
|
|
231
286
|
const preferredZonesForAccount = preferredZones[serverGroup.account];
|
|
@@ -237,10 +292,10 @@ angular
|
|
|
237
292
|
// These processes should never be copied over, as the affect launching instances and enabling traffic
|
|
238
293
|
const enabledProcesses = ['Launch', 'Terminate', 'AddToLoadBalancer'];
|
|
239
294
|
|
|
240
|
-
const applicationAwsSettings =
|
|
295
|
+
const applicationAwsSettings = application.attributes?.providerSettings?.aws ?? {};
|
|
241
296
|
const useAmiBlockDeviceMappings = applicationAwsSettings.useAmiBlockDeviceMappings || false;
|
|
242
297
|
|
|
243
|
-
const existingTags = {};
|
|
298
|
+
const existingTags: { [key: string]: string } = {};
|
|
244
299
|
// These tags are applied by Clouddriver (if configured to do so), regardless of what the user might enter
|
|
245
300
|
// Might be worth feature flagging this if it turns out other folks are hard-coding these values
|
|
246
301
|
const reservedTags = ['spinnaker:application', 'spinnaker:stack', 'spinnaker:details'];
|
|
@@ -252,7 +307,7 @@ angular
|
|
|
252
307
|
});
|
|
253
308
|
}
|
|
254
309
|
|
|
255
|
-
const command = {
|
|
310
|
+
const command: Partial<IAmazonServerGroupCommand> = {
|
|
256
311
|
application: application.name,
|
|
257
312
|
strategy: '',
|
|
258
313
|
stack: serverGroupName.stack,
|
|
@@ -295,14 +350,10 @@ angular
|
|
|
295
350
|
submitButtonLabel: getSubmitButtonLabel(mode),
|
|
296
351
|
isNew: false,
|
|
297
352
|
dirty: {},
|
|
298
|
-
},
|
|
353
|
+
} as IAmazonServerGroupCommandViewState,
|
|
299
354
|
};
|
|
300
355
|
|
|
301
|
-
if (
|
|
302
|
-
application.attributes &&
|
|
303
|
-
application.attributes.platformHealthOnlyShowOverride &&
|
|
304
|
-
application.attributes.platformHealthOnly
|
|
305
|
-
) {
|
|
356
|
+
if (application.attributes?.platformHealthOnlyShowOverride && application.attributes?.platformHealthOnly) {
|
|
306
357
|
command.interestingHealthProviderNames = ['Amazon'];
|
|
307
358
|
}
|
|
308
359
|
|
|
@@ -318,7 +369,7 @@ angular
|
|
|
318
369
|
const vpcZoneIdentifier = serverGroup.asg.vpczoneIdentifier;
|
|
319
370
|
if (vpcZoneIdentifier !== '') {
|
|
320
371
|
const subnetId = vpcZoneIdentifier.split(',')[0];
|
|
321
|
-
const subnet =
|
|
372
|
+
const subnet = subnets.find((x) => x.id === subnetId);
|
|
322
373
|
command.subnetType = subnet.purpose;
|
|
323
374
|
command.vpcId = subnet.vpcId;
|
|
324
375
|
} else {
|
|
@@ -333,7 +384,8 @@ angular
|
|
|
333
384
|
keyPair: serverGroup.launchConfig.keyName,
|
|
334
385
|
associatePublicIpAddress: serverGroup.launchConfig.associatePublicIpAddress,
|
|
335
386
|
ramdiskId: serverGroup.launchConfig.ramdiskId,
|
|
336
|
-
instanceMonitoring:
|
|
387
|
+
instanceMonitoring:
|
|
388
|
+
serverGroup.launchConfig.instanceMonitoring && serverGroup.launchConfig.instanceMonitoring.enabled,
|
|
337
389
|
ebsOptimized: serverGroup.launchConfig.ebsOptimized,
|
|
338
390
|
spotPrice: serverGroup.launchConfig.spotPrice,
|
|
339
391
|
});
|
|
@@ -341,18 +393,46 @@ angular
|
|
|
341
393
|
command.base64UserData = serverGroup.launchConfig.userData;
|
|
342
394
|
}
|
|
343
395
|
command.viewState.imageId = serverGroup.launchConfig.imageId;
|
|
396
|
+
command.viewState.useSimpleInstanceTypeSelector = true;
|
|
344
397
|
}
|
|
345
398
|
|
|
346
|
-
if (serverGroup.launchTemplate) {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
launchTemplateData.
|
|
350
|
-
launchTemplateData.instanceMarketOptions
|
|
351
|
-
launchTemplateData.
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
399
|
+
if (serverGroup.launchTemplate || serverGroup.mixedInstancesPolicy) {
|
|
400
|
+
let launchTemplateData: ILaunchTemplateData, spotMaxPrice: string;
|
|
401
|
+
if (serverGroup.launchTemplate) {
|
|
402
|
+
launchTemplateData = serverGroup.launchTemplate.launchTemplateData;
|
|
403
|
+
spotMaxPrice = launchTemplateData.instanceMarketOptions?.spotOptions?.maxPrice;
|
|
404
|
+
command.instanceType = launchTemplateData.instanceType;
|
|
405
|
+
command.viewState.useSimpleInstanceTypeSelector = true;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
if (serverGroup.mixedInstancesPolicy) {
|
|
409
|
+
const mip = serverGroup.mixedInstancesPolicy;
|
|
410
|
+
// note: single launch template case is currently the only supported case for mixed instances policy
|
|
411
|
+
launchTemplateData = mip?.launchTemplates?.[0]?.launchTemplateData;
|
|
412
|
+
spotMaxPrice = mip?.instancesDistribution?.spotMaxPrice;
|
|
413
|
+
command.securityGroups = launchTemplateData.networkInterfaces
|
|
414
|
+
? (launchTemplateData.networkInterfaces.find((ni) => ni.deviceIndex === 0) ?? {}).groups
|
|
415
|
+
: launchTemplateData.securityGroups;
|
|
416
|
+
command.onDemandAllocationStrategy = mip.instancesDistribution.onDemandAllocationStrategy;
|
|
417
|
+
command.onDemandBaseCapacity = mip.instancesDistribution.onDemandBaseCapacity;
|
|
418
|
+
command.onDemandPercentageAboveBaseCapacity =
|
|
419
|
+
mip.instancesDistribution.onDemandPercentageAboveBaseCapacity;
|
|
420
|
+
command.spotAllocationStrategy = mip.instancesDistribution.spotAllocationStrategy;
|
|
421
|
+
command.spotInstancePools = mip.instancesDistribution.spotInstancePools;
|
|
422
|
+
|
|
423
|
+
// 'launchTemplateOverridesForInstanceType' is used for multiple instance types case, 'instanceType' is used for all other cases.
|
|
424
|
+
if (mip.launchTemplateOverridesForInstanceType) {
|
|
425
|
+
command.launchTemplateOverridesForInstanceType = getInstanceTypesWithPriority(
|
|
426
|
+
mip.launchTemplateOverridesForInstanceType,
|
|
427
|
+
);
|
|
428
|
+
} else {
|
|
429
|
+
command.instanceType = launchTemplateData.instanceType;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
command.viewState.useSimpleInstanceTypeSelector = isSimpleModeEnabled(command);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
const ipv6AddressCount = _.get(launchTemplateData, 'networkInterfaces[0]');
|
|
356
436
|
|
|
357
437
|
const asgSettings = AWSProviderSettings.serverGroups;
|
|
358
438
|
const isTestEnv = serverGroup.accountDetails && serverGroup.accountDetails.environment === 'test';
|
|
@@ -360,17 +440,14 @@ angular
|
|
|
360
440
|
asgSettings && asgSettings.enableIPv6 && asgSettings.setIPv6InTest && isTestEnv;
|
|
361
441
|
|
|
362
442
|
angular.extend(command, {
|
|
363
|
-
instanceType: launchTemplateData.instanceType,
|
|
364
443
|
iamRole: launchTemplateData.iamInstanceProfile.name,
|
|
365
444
|
keyPair: launchTemplateData.keyName,
|
|
366
445
|
associateIPv6Address: shouldAutoEnableIPv6 || Boolean(ipv6AddressCount),
|
|
367
446
|
ramdiskId: launchTemplateData.ramdiskId,
|
|
368
|
-
instanceMonitoring: launchTemplateData.monitoring.enabled,
|
|
447
|
+
instanceMonitoring: launchTemplateData.monitoring && launchTemplateData.monitoring.enabled,
|
|
369
448
|
ebsOptimized: launchTemplateData.ebsOptimized,
|
|
370
|
-
spotPrice:
|
|
371
|
-
requireIMDSv2: Boolean(
|
|
372
|
-
launchTemplateData.metadataOptions && launchTemplateData.metadataOptions.httpTokens === 'required',
|
|
373
|
-
),
|
|
449
|
+
spotPrice: spotMaxPrice || undefined,
|
|
450
|
+
requireIMDSv2: Boolean(launchTemplateData.metadataOptions?.httpTokens === 'required'),
|
|
374
451
|
unlimitedCpuCredits: launchTemplateData.creditSpecification
|
|
375
452
|
? launchTemplateData.creditSpecification.cpuCredits === 'unlimited'
|
|
376
453
|
: undefined,
|
|
@@ -393,8 +470,8 @@ angular
|
|
|
393
470
|
|
|
394
471
|
if (serverGroup.launchTemplate && serverGroup.launchTemplate.launchTemplateData.networkInterfaces) {
|
|
395
472
|
const networkInterface =
|
|
396
|
-
serverGroup.launchTemplate.launchTemplateData.networkInterfaces.find((ni) => ni.deviceIndex === 0)
|
|
397
|
-
{};
|
|
473
|
+
serverGroup.launchTemplate.launchTemplateData.networkInterfaces.find((ni) => ni.deviceIndex === 0) ??
|
|
474
|
+
({} as INetworkInterface);
|
|
398
475
|
command.securityGroups = networkInterface.groups;
|
|
399
476
|
}
|
|
400
477
|
|
|
@@ -402,12 +479,44 @@ angular
|
|
|
402
479
|
});
|
|
403
480
|
}
|
|
404
481
|
|
|
482
|
+
// Since Deck allows changing priority of instance types via drag handle, fill priority field explicitly if empty
|
|
483
|
+
function getInstanceTypesWithPriority(
|
|
484
|
+
instanceTypeOverrides: IAmazonLaunchTemplateOverrides[],
|
|
485
|
+
): IAmazonInstanceTypeOverride[] {
|
|
486
|
+
let explicitPriority = 1;
|
|
487
|
+
return _.sortBy(instanceTypeOverrides, ['priority']).map((override) => {
|
|
488
|
+
const { instanceType, weightedCapacity } = override;
|
|
489
|
+
let priority;
|
|
490
|
+
if (override.priority) {
|
|
491
|
+
priority = override.priority;
|
|
492
|
+
explicitPriority = override.priority + 1;
|
|
493
|
+
} else {
|
|
494
|
+
priority = explicitPriority++;
|
|
495
|
+
}
|
|
496
|
+
return { instanceType, weightedCapacity, priority };
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
function isSimpleModeEnabled(
|
|
501
|
+
command: IAmazonServerGroupDeployConfiguration | Partial<IAmazonServerGroupCommand>,
|
|
502
|
+
) {
|
|
503
|
+
const isAdvancedModeEnabledInCommand =
|
|
504
|
+
command.onDemandAllocationStrategy ||
|
|
505
|
+
command.onDemandBaseCapacity ||
|
|
506
|
+
command.onDemandPercentageAboveBaseCapacity ||
|
|
507
|
+
command.spotAllocationStrategy ||
|
|
508
|
+
command.spotInstancePools ||
|
|
509
|
+
(command.launchTemplateOverridesForInstanceType && command.launchTemplateOverridesForInstanceType.length > 0);
|
|
510
|
+
|
|
511
|
+
return !isAdvancedModeEnabledInCommand;
|
|
512
|
+
}
|
|
513
|
+
|
|
405
514
|
return {
|
|
406
|
-
buildNewServerGroupCommand
|
|
407
|
-
buildServerGroupCommandFromExisting
|
|
408
|
-
buildNewServerGroupCommandForPipeline
|
|
409
|
-
buildServerGroupCommandFromPipeline
|
|
410
|
-
buildUpdateServerGroupCommand
|
|
411
|
-
};
|
|
515
|
+
buildNewServerGroupCommand,
|
|
516
|
+
buildServerGroupCommandFromExisting,
|
|
517
|
+
buildNewServerGroupCommandForPipeline,
|
|
518
|
+
buildServerGroupCommandFromPipeline,
|
|
519
|
+
buildUpdateServerGroupCommand,
|
|
520
|
+
} as AwsServerGroupCommandBuilder;
|
|
412
521
|
},
|
|
413
522
|
]);
|
|
@@ -4,7 +4,11 @@ import { AccountService, SubnetReader } from '@spinnaker/core';
|
|
|
4
4
|
|
|
5
5
|
import { AWSProviderSettings } from '../../aws.settings';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
createMockAmazonServerGroupWithLt,
|
|
9
|
+
createCustomMockLaunchTemplate,
|
|
10
|
+
mockLaunchTemplate,
|
|
11
|
+
} from '@spinnaker/mocks';
|
|
8
12
|
|
|
9
13
|
describe('awsServerGroupCommandBuilder', function () {
|
|
10
14
|
const AccountServiceFixture = require('./AccountServiceFixtures');
|
|
@@ -64,7 +68,7 @@ describe('awsServerGroupCommandBuilder', function () {
|
|
|
64
68
|
|
|
65
69
|
describe('buildServerGroupCommandFromExisting', function () {
|
|
66
70
|
it('sets usePreferredZones flag based on initial value', function () {
|
|
67
|
-
spyOn(this.instanceTypeService, '
|
|
71
|
+
spyOn(this.instanceTypeService, 'getCategoryForMultipleInstanceTypes').and.returnValue(this.$q.when('custom'));
|
|
68
72
|
const baseServerGroup = {
|
|
69
73
|
account: 'prod',
|
|
70
74
|
region: 'us-west-1',
|
|
@@ -72,6 +76,7 @@ describe('awsServerGroupCommandBuilder', function () {
|
|
|
72
76
|
availabilityZones: ['g', 'h', 'i'],
|
|
73
77
|
vpczoneIdentifier: '',
|
|
74
78
|
},
|
|
79
|
+
launchTemplate: mockLaunchTemplate,
|
|
75
80
|
};
|
|
76
81
|
let command = null;
|
|
77
82
|
|
|
@@ -101,7 +106,9 @@ describe('awsServerGroupCommandBuilder', function () {
|
|
|
101
106
|
});
|
|
102
107
|
|
|
103
108
|
it('sets profile and instance type if available', function () {
|
|
104
|
-
spyOn(this.instanceTypeService, '
|
|
109
|
+
spyOn(this.instanceTypeService, 'getCategoryForMultipleInstanceTypes').and.returnValue(
|
|
110
|
+
this.$q.when('selectedProfile'),
|
|
111
|
+
);
|
|
105
112
|
|
|
106
113
|
const baseServerGroup = {
|
|
107
114
|
account: 'prod',
|
|
@@ -131,7 +138,9 @@ describe('awsServerGroupCommandBuilder', function () {
|
|
|
131
138
|
});
|
|
132
139
|
|
|
133
140
|
it('copies suspended processes unless the mode is "editPipeline"', function () {
|
|
134
|
-
spyOn(this.instanceTypeService, '
|
|
141
|
+
spyOn(this.instanceTypeService, 'getCategoryForMultipleInstanceTypes').and.returnValue(
|
|
142
|
+
this.$q.when('selectedProfile'),
|
|
143
|
+
);
|
|
135
144
|
|
|
136
145
|
const baseServerGroup = {
|
|
137
146
|
account: 'prod',
|
|
@@ -167,7 +176,9 @@ describe('awsServerGroupCommandBuilder', function () {
|
|
|
167
176
|
});
|
|
168
177
|
|
|
169
178
|
it('copies tags not in the reserved list:', function () {
|
|
170
|
-
spyOn(this.instanceTypeService, '
|
|
179
|
+
spyOn(this.instanceTypeService, 'getCategoryForMultipleInstanceTypes').and.returnValue(
|
|
180
|
+
this.$q.when('selectedProfile'),
|
|
181
|
+
);
|
|
171
182
|
|
|
172
183
|
const baseServerGroup = {
|
|
173
184
|
account: 'prod',
|
|
@@ -208,7 +219,9 @@ describe('awsServerGroupCommandBuilder', function () {
|
|
|
208
219
|
});
|
|
209
220
|
|
|
210
221
|
it('sets unlimitedCpuCredits to false when building from source server group with standard credits', function () {
|
|
211
|
-
spyOn(this.instanceTypeService, '
|
|
222
|
+
spyOn(this.instanceTypeService, 'getCategoryForMultipleInstanceTypes').and.returnValue(
|
|
223
|
+
this.$q.when('selectedProfile'),
|
|
224
|
+
);
|
|
212
225
|
|
|
213
226
|
const baseServerGroup = createMockAmazonServerGroupWithLt(
|
|
214
227
|
createCustomMockLaunchTemplate('testLtCpuCredits', {
|
|
@@ -229,7 +242,9 @@ describe('awsServerGroupCommandBuilder', function () {
|
|
|
229
242
|
});
|
|
230
243
|
|
|
231
244
|
it('sets unlimitedCpuCredits to true when building from source server group with unlimited credits', function () {
|
|
232
|
-
spyOn(this.instanceTypeService, '
|
|
245
|
+
spyOn(this.instanceTypeService, 'getCategoryForMultipleInstanceTypes').and.returnValue(
|
|
246
|
+
this.$q.when('selectedProfile'),
|
|
247
|
+
);
|
|
233
248
|
|
|
234
249
|
const baseServerGroup = createMockAmazonServerGroupWithLt(
|
|
235
250
|
createCustomMockLaunchTemplate('testLtCpuCredits', {
|
|
@@ -250,7 +265,9 @@ describe('awsServerGroupCommandBuilder', function () {
|
|
|
250
265
|
});
|
|
251
266
|
|
|
252
267
|
it('sets unlimitedCpuCredits to undefined when building from source server group with cpu credits unset', function () {
|
|
253
|
-
spyOn(this.instanceTypeService, '
|
|
268
|
+
spyOn(this.instanceTypeService, 'getCategoryForMultipleInstanceTypes').and.returnValue(
|
|
269
|
+
this.$q.when('selectedProfile'),
|
|
270
|
+
);
|
|
254
271
|
|
|
255
272
|
const baseServerGroup = createMockAmazonServerGroupWithLt();
|
|
256
273
|
|
|
@@ -1,19 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { IQService, IRootScopeService, IScope } from 'angular';
|
|
2
|
+
import { mock } from 'angular';
|
|
2
3
|
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
ApplicationModelBuilder,
|
|
6
|
-
CacheInitializerService,
|
|
7
|
-
LoadBalancerReader,
|
|
8
|
-
SecurityGroupReader,
|
|
9
|
-
SubnetReader,
|
|
10
|
-
} from '@spinnaker/core';
|
|
4
|
+
import type { CacheInitializerService, LoadBalancerReader, SecurityGroupReader } from '@spinnaker/core';
|
|
5
|
+
import { AccountService, ApplicationModelBuilder, SubnetReader } from '@spinnaker/core';
|
|
11
6
|
|
|
12
7
|
import { KeyPairsReader } from '../../keyPairs';
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
AwsServerGroupConfigurationService,
|
|
16
|
-
} from './serverGroupConfiguration.service';
|
|
8
|
+
import type { AwsServerGroupConfigurationService } from './serverGroupConfiguration.service';
|
|
9
|
+
import { AWS_SERVER_GROUP_CONFIGURATION_SERVICE } from './serverGroupConfiguration.service';
|
|
17
10
|
|
|
18
11
|
describe('Service: awsServerGroupConfiguration', function () {
|
|
19
12
|
let service: AwsServerGroupConfigurationService,
|
|
@@ -80,15 +80,44 @@ export interface IAmazonServerGroupCommandBackingData extends IServerGroupComman
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
export interface IAmazonServerGroupCommandViewState extends IServerGroupCommandViewState {
|
|
83
|
+
isNew: boolean;
|
|
83
84
|
dirty: IAmazonServerGroupCommandDirty;
|
|
84
85
|
spelTargetGroups: string[];
|
|
85
86
|
spelLoadBalancers: string[];
|
|
87
|
+
useSimpleInstanceTypeSelector: boolean;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface IAmazonInstanceTypeOverride {
|
|
91
|
+
instanceType: string;
|
|
92
|
+
weightedCapacity?: string;
|
|
93
|
+
priority?: number;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* We model server group commands in two subtly different ways.
|
|
98
|
+
* It's unclear what the intention is, but we should converge on a single model eventually.
|
|
99
|
+
*
|
|
100
|
+
* This model is stored in a Aws Deploy Stage under `clusters[]`.
|
|
101
|
+
* It is also sent across the wire during a deploy task from infrastructure view
|
|
102
|
+
* (i.e., "clone server group", "create server group")
|
|
103
|
+
*/
|
|
104
|
+
export interface IAmazonServerGroupDeployConfiguration extends IAmazonServerGroupCommand_Internal {
|
|
105
|
+
account: string;
|
|
106
|
+
availabilityZones: {
|
|
107
|
+
[region: string]: string[];
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
interface IAmazonServerGroupCommand_Internal extends IAmazonServerGroupCommand {
|
|
112
|
+
// widen 'string[]' to 'any' so we can narrow it to an incompatible type in IAmazonServerGroupDeployConfiguration
|
|
113
|
+
availabilityZones: any;
|
|
86
114
|
}
|
|
87
115
|
|
|
88
116
|
export interface IAmazonServerGroupCommand extends IServerGroupCommand {
|
|
89
117
|
associateIPv6Address?: boolean;
|
|
90
118
|
associatePublicIpAddress: boolean;
|
|
91
119
|
backingData: IAmazonServerGroupCommandBackingData;
|
|
120
|
+
base64UserData: string;
|
|
92
121
|
copySourceCustomBlockDeviceMappings: boolean;
|
|
93
122
|
ebsOptimized: boolean;
|
|
94
123
|
healthCheckGracePeriod: number;
|
|
@@ -103,12 +132,25 @@ export interface IAmazonServerGroupCommand extends IServerGroupCommand {
|
|
|
103
132
|
setLaunchTemplate?: boolean;
|
|
104
133
|
unlimitedCpuCredits?: boolean;
|
|
105
134
|
capacityRebalance?: boolean;
|
|
135
|
+
ramdiskId?: string;
|
|
106
136
|
viewState: IAmazonServerGroupCommandViewState;
|
|
137
|
+
source: {
|
|
138
|
+
account: string;
|
|
139
|
+
region: string;
|
|
140
|
+
asgName: string;
|
|
141
|
+
};
|
|
142
|
+
onDemandAllocationStrategy?: string;
|
|
143
|
+
onDemandBaseCapacity?: number;
|
|
144
|
+
onDemandPercentageAboveBaseCapacity?: number;
|
|
145
|
+
spotAllocationStrategy?: string;
|
|
146
|
+
spotInstancePools?: number;
|
|
147
|
+
launchTemplateOverridesForInstanceType?: IAmazonInstanceTypeOverride[];
|
|
107
148
|
|
|
108
149
|
getBlockDeviceMappingsSource: (command: IServerGroupCommand) => IBlockDeviceMappingSource;
|
|
109
150
|
selectBlockDeviceMappingsSource: (command: IServerGroupCommand, selection: string) => void;
|
|
110
151
|
usePreferredZonesChanged: (command: IServerGroupCommand) => IAmazonServerGroupCommandResult;
|
|
111
152
|
regionIsDeprecated: (command: IServerGroupCommand) => boolean;
|
|
153
|
+
launchTemplateOverridesChanged: (command: IServerGroupCommand) => void;
|
|
112
154
|
}
|
|
113
155
|
|
|
114
156
|
export class AwsServerGroupConfigurationService {
|
|
@@ -643,10 +685,21 @@ export class AwsServerGroupConfigurationService {
|
|
|
643
685
|
cmd.imageChanged = (command: IAmazonServerGroupCommand): IServerGroupCommandResult =>
|
|
644
686
|
this.configureInstanceTypes(command);
|
|
645
687
|
|
|
688
|
+
// Handles derived values for single instance type case
|
|
646
689
|
cmd.instanceTypeChanged = (command: IAmazonServerGroupCommand): void => {
|
|
647
690
|
command.ebsOptimized = this.awsInstanceTypeService.isEbsOptimized(command.instanceType);
|
|
648
691
|
};
|
|
649
692
|
|
|
693
|
+
// Handles derived values for multiple instance types case
|
|
694
|
+
cmd.launchTemplateOverridesChanged = (command: IAmazonServerGroupCommand): void => {
|
|
695
|
+
// set ebsOptimized to true if all instance types in overrides are included in the hard-coded array in awsInstanceTypeService.
|
|
696
|
+
// this function exists for backwards compatibility with single instance type case, matching behavior in `cmd.instanceTypeChanged`
|
|
697
|
+
// note: this parameter has no effect on instance types with EBS optimization enabled by default.
|
|
698
|
+
command.ebsOptimized = command.launchTemplateOverridesForInstanceType?.every((o) =>
|
|
699
|
+
this.awsInstanceTypeService.isEbsOptimized(o.instanceType),
|
|
700
|
+
);
|
|
701
|
+
};
|
|
702
|
+
|
|
650
703
|
this.applyOverrides('attachEventHandlers', cmd);
|
|
651
704
|
}
|
|
652
705
|
}
|
|
@@ -207,7 +207,7 @@ export class AmazonCloneServerGroupModal extends React.Component<
|
|
|
207
207
|
/>
|
|
208
208
|
|
|
209
209
|
<WizardPage
|
|
210
|
-
label=
|
|
210
|
+
label={command.viewState.useSimpleInstanceTypeSelector ? 'Instance Type' : 'Instance Types'}
|
|
211
211
|
wizard={wizard}
|
|
212
212
|
order={nextIdx()}
|
|
213
213
|
render={({ innerRef }) => <ServerGroupInstanceType ref={innerRef} formik={formik} />}
|