@spinnaker/amazon 0.11.0 → 0.12.2

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 (116) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/dist/aws.settings.d.ts +1 -0
  3. package/dist/index.js +1 -1
  4. package/dist/index.js.map +1 -1
  5. package/dist/instance/awsInstanceType.service.d.ts +10 -2
  6. package/dist/instance/awsInstanceTypes.d.ts +10 -0
  7. package/dist/instance/details/CostFactor.d.ts +6 -0
  8. package/dist/search/searchResultFormatter.d.ts +2 -2
  9. package/dist/serverGroup/configure/serverGroupConfiguration.service.d.ts +14 -1
  10. package/dist/serverGroup/configure/wizard/instanceType/CpuCreditsToggle.d.ts +3 -4
  11. package/dist/serverGroup/configure/wizard/instanceType/InstanceTypeSelector.d.ts +9 -0
  12. package/dist/serverGroup/configure/wizard/instanceType/advancedMode/AdvancedModeSelector.d.ts +13 -0
  13. package/dist/serverGroup/configure/wizard/instanceType/advancedMode/InstanceProfileSelector.d.ts +9 -0
  14. package/dist/serverGroup/configure/wizard/instanceType/advancedMode/InstanceTypeRow.d.ts +11 -0
  15. package/dist/serverGroup/configure/wizard/instanceType/advancedMode/InstanceTypeTable.d.ts +14 -0
  16. package/dist/serverGroup/configure/wizard/instanceType/advancedMode/InstanceTypeTableBody.d.ts +12 -0
  17. package/dist/serverGroup/configure/wizard/instanceType/advancedMode/InstanceTypeTableParts.d.ts +15 -0
  18. package/dist/serverGroup/configure/wizard/instanceType/advancedMode/InstancesDistribution.d.ts +8 -0
  19. package/dist/serverGroup/configure/wizard/instanceType/simpleMode/SimpleModeSelector.d.ts +8 -0
  20. package/dist/serverGroup/configure/wizard/pages/ServerGroupInstanceType.d.ts +9 -6
  21. package/dist/serverGroup/details/scalingPolicy/ScalingPolicySummary.d.ts +0 -1
  22. package/dist/serverGroup/details/scalingPolicy/chart/MetricAlarmChart.d.ts +0 -4
  23. package/dist/serverGroup/details/scalingPolicy/index.d.ts +0 -1
  24. package/dist/serverGroup/details/scalingPolicy/targetTracking/TargetTrackingChart.d.ts +1 -3
  25. package/package.json +5 -5
  26. package/src/aws.module.ts +3 -3
  27. package/src/aws.settings.ts +2 -0
  28. package/src/function/details/FunctionActions.spec.tsx +15 -12
  29. package/src/function/details/FunctionActions.tsx +2 -1
  30. package/src/help/amazon.help.ts +9 -6
  31. package/src/image/image.reader.spec.ts +75 -0
  32. package/src/instance/awsInstanceType.service.spec.js +37 -71
  33. package/src/instance/awsInstanceType.service.ts +191 -0
  34. package/src/instance/awsInstanceTypes.ts +311 -0
  35. package/src/instance/details/CostFactor.tsx +29 -0
  36. package/src/instance/details/InstanceInformation.spec.tsx +2 -1
  37. package/src/instance/details/instance.details.controller.js +472 -473
  38. package/src/loadBalancer/details/LoadBalancerActions.tsx +2 -1
  39. package/src/loadBalancer/details/loadBalancerDetails.controller.spec.ts +5 -3
  40. package/src/search/{searchResultFormatter.js → searchResultFormatter.ts} +5 -4
  41. package/src/securityGroup/details/securityGroupDetail.controller.js +2 -1
  42. package/src/serverGroup/configure/AmazonImageSelectInput.spec.tsx +10 -7
  43. package/src/serverGroup/configure/serverGroupCommandBuilder.aws.service.spec.js +302 -1
  44. package/src/serverGroup/configure/serverGroupCommandBuilder.service.js +96 -24
  45. package/src/serverGroup/configure/serverGroupCommandBuilder.spec.js +25 -8
  46. package/src/serverGroup/configure/serverGroupConfiguration.service.spec.ts +6 -13
  47. package/src/serverGroup/configure/serverGroupConfiguration.service.ts +26 -1
  48. package/src/serverGroup/configure/wizard/AmazonCloneServerGroupModal.tsx +1 -1
  49. package/src/serverGroup/configure/wizard/instanceType/CpuCreditsToggle.tsx +31 -31
  50. package/src/serverGroup/configure/wizard/instanceType/InstanceTypeSelector.tsx +133 -0
  51. package/src/serverGroup/configure/wizard/instanceType/advancedMode/AdvancedModeSelector.tsx +99 -0
  52. package/src/serverGroup/configure/wizard/instanceType/advancedMode/InstanceProfileSelector.tsx +36 -0
  53. package/src/serverGroup/configure/wizard/instanceType/advancedMode/InstanceTypeRow.tsx +144 -0
  54. package/src/serverGroup/configure/wizard/instanceType/advancedMode/InstanceTypeTable.tsx +137 -0
  55. package/src/serverGroup/configure/wizard/instanceType/advancedMode/InstanceTypeTableBody.tsx +135 -0
  56. package/src/serverGroup/configure/wizard/instanceType/advancedMode/InstanceTypeTableParts.tsx +137 -0
  57. package/src/serverGroup/configure/wizard/instanceType/advancedMode/InstancesDistribution.less +5 -0
  58. package/src/serverGroup/configure/wizard/instanceType/advancedMode/InstancesDistribution.tsx +108 -0
  59. package/src/serverGroup/configure/wizard/instanceType/advancedMode/advancedMode.less +110 -0
  60. package/src/serverGroup/configure/wizard/instanceType/simpleMode/SimpleModeSelector.tsx +62 -0
  61. package/src/serverGroup/configure/wizard/pages/ServerGroupInstanceType.tsx +106 -62
  62. package/src/serverGroup/configure/wizard/pages/advancedSettings/ServerGroupAdvancedSettingsCommon.tsx +1 -1
  63. package/src/serverGroup/details/AmazonServerGroupActions.tsx +2 -1
  64. package/src/serverGroup/details/scalingPolicy/ScalingPolicySummary.tsx +7 -3
  65. package/src/serverGroup/details/scalingPolicy/StepPolicySummary.tsx +26 -28
  66. package/src/serverGroup/details/scalingPolicy/chart/MetricAlarmChart.tsx +1 -25
  67. package/src/serverGroup/details/scalingPolicy/index.ts +0 -1
  68. package/src/serverGroup/details/scalingPolicy/scalingPolicy.module.ts +1 -9
  69. package/src/serverGroup/details/scalingPolicy/scalingPolicySummary.component.ts +6 -2
  70. package/src/serverGroup/details/scalingPolicy/targetTracking/TargetTrackingChart.tsx +2 -17
  71. package/src/serverGroup/details/scalingPolicy/upsert/alarm/AlarmConfigurer.less +1 -1
  72. package/src/serverGroup/details/scalingProcesses/AutoScalingProcessService.spec.ts +1 -2
  73. package/src/serverGroup/details/sections/AdvancedSettingsDetailsSection.tsx +3 -2
  74. package/src/serverGroup/details/sections/AmazonCapacityDetailsSection.tsx +3 -8
  75. package/src/serverGroup/details/sections/InstancesDistributionDetailsSection.spec.tsx +8 -5
  76. package/src/serverGroup/details/sections/LaunchTemplateDetailsSection.spec.tsx +8 -5
  77. package/src/serverGroup/details/sections/ScalingPoliciesDetailsSection.tsx +3 -3
  78. package/src/serverGroup/details/sections/ScalingProcessesDetailsSection.tsx +3 -10
  79. package/src/serverGroup/details/sections/ScheduledActionsDetailsSection.tsx +3 -2
  80. package/src/serverGroup/details/sections/SecurityGroupsDetailsSection.tsx +3 -2
  81. package/src/serverGroup/serverGroup.transformer.spec.ts +5 -3
  82. package/src/subnet/SubnetSelectInput.spec.tsx +7 -4
  83. package/src/vpc/{VpcReader.spec.js → VpcReader.spec.ts} +2 -10
  84. package/src/vpc/VpcTag.spec.tsx +37 -0
  85. package/src/vpc/vpc.module.ts +6 -2
  86. package/dist/reactShims/aws.ngReact.d.ts +0 -11
  87. package/dist/serverGroup/details/scalingPolicy/ScalingPolicyTypeRegistry.d.ts +0 -10
  88. package/dist/serverGroup/details/scalingPolicy/alarmBasedSummary.component.d.ts +0 -2
  89. package/dist/serverGroup/details/scalingPolicy/detailsSummary.component.d.ts +0 -12
  90. package/dist/serverGroup/details/scalingPolicy/popover/scalingPolicyPopover.component.d.ts +0 -1
  91. package/dist/serverGroup/details/scalingPolicy/stepPolicySummary.component.d.ts +0 -1
  92. package/dist/serverGroup/details/scalingPolicy/targetTracking/TargetTrackingPolicy.config.d.ts +0 -1
  93. package/dist/serverGroup/details/scalingPolicy/targetTracking/targetTracking.module.d.ts +0 -2
  94. package/dist/serverGroup/details/scalingPolicy/targetTracking/targetTrackingChart.component.d.ts +0 -1
  95. package/dist/serverGroup/details/scalingPolicy/targetTracking/targetTrackingSummary.component.d.ts +0 -1
  96. package/dist/vpc/vpcTag.directive.d.ts +0 -2
  97. package/src/image/image.reader.spec.js +0 -123
  98. package/src/instance/awsInstanceType.service.js +0 -437
  99. package/src/reactShims/aws.ngReact.ts +0 -27
  100. package/src/serverGroup/details/scalingPolicy/ScalingPolicyTypeRegistry.ts +0 -18
  101. package/src/serverGroup/details/scalingPolicy/alarmBasedSummary.component.html +0 -35
  102. package/src/serverGroup/details/scalingPolicy/alarmBasedSummary.component.js +0 -60
  103. package/src/serverGroup/details/scalingPolicy/alarmBasedSummary.template.html +0 -5
  104. package/src/serverGroup/details/scalingPolicy/detailsSummary.component.ts +0 -32
  105. package/src/serverGroup/details/scalingPolicy/popover/scalingPolicyDetails.popover.html +0 -1
  106. package/src/serverGroup/details/scalingPolicy/popover/scalingPolicyPopover.component.html +0 -107
  107. package/src/serverGroup/details/scalingPolicy/popover/scalingPolicyPopover.component.ts +0 -31
  108. package/src/serverGroup/details/scalingPolicy/scalingPolicySummary.component.less +0 -15
  109. package/src/serverGroup/details/scalingPolicy/stepPolicySummary.component.ts +0 -10
  110. package/src/serverGroup/details/scalingPolicy/targetTracking/TargetTrackingPolicy.config.ts +0 -6
  111. package/src/serverGroup/details/scalingPolicy/targetTracking/targetTracking.module.ts +0 -8
  112. package/src/serverGroup/details/scalingPolicy/targetTracking/targetTrackingChart.component.ts +0 -16
  113. package/src/serverGroup/details/scalingPolicy/targetTracking/targetTrackingSummary.component.ts +0 -14
  114. package/src/serverGroup/details/scalingPolicy/targetTracking/targetTrackingSummary.html +0 -5
  115. package/src/vpc/vpcTag.directive.js +0 -34
  116. package/src/vpc/vpcTag.directive.spec.js +0 -60
@@ -13,6 +13,7 @@ import {
13
13
  SETTINGS,
14
14
  } from '@spinnaker/core';
15
15
 
16
+ import { AWSProviderSettings } from '../../aws.settings';
16
17
  import { LoadBalancerTypes } from '../configure/LoadBalancerTypes';
17
18
  import type { IAmazonLoadBalancer, IAmazonLoadBalancerDeleteCommand } from '../../domain';
18
19
  import type { ILoadBalancerFromStateParams } from './loadBalancerDetails.controller';
@@ -114,7 +115,7 @@ export class LoadBalancerActions extends React.Component<ILoadBalancerActionsPro
114
115
 
115
116
  return (
116
117
  <div style={{ display: 'inline-block' }}>
117
- {SETTINGS.awsAdHocInfraWritesEnabled && (
118
+ {AWSProviderSettings.adHocInfraWritesEnabled && (
118
119
  <Dropdown className="dropdown" id="load-balancer-actions-dropdown">
119
120
  <Dropdown.Toggle className="btn btn-sm btn-primary dropdown-toggle">
120
121
  <span>Load Balancer Actions</span>
@@ -1,7 +1,9 @@
1
- import { IControllerService, IRootScopeService, mock } from 'angular';
2
- import { StateService } from '@uirouter/core';
1
+ import type { StateService } from '@uirouter/core';
2
+ import type { IControllerService, IRootScopeService } from 'angular';
3
+ import { mock } from 'angular';
3
4
 
4
- import { ApplicationModelBuilder, ISubnet } from '@spinnaker/core';
5
+ import type { ISubnet } from '@spinnaker/core';
6
+ import { ApplicationModelBuilder } from '@spinnaker/core';
5
7
 
6
8
  import { AWS_LOAD_BALANCER_DETAILS_CTRL, AwsLoadBalancerDetailsController } from './loadBalancerDetails.controller';
7
9
 
@@ -1,18 +1,19 @@
1
- 'use strict';
2
-
3
1
  import { module } from 'angular';
4
2
 
3
+ import type { ISecurityGroupSearchResult } from '@spinnaker/core';
4
+ import type { ISearchResultFormatter } from '@spinnaker/core';
5
+
5
6
  import { VpcReader } from '../vpc/VpcReader';
6
7
 
7
8
  export const AMAZON_SEARCH_SEARCHRESULTFORMATTER = 'spinnaker.amazon.search.searchResultFormatter';
8
9
  export const name = AMAZON_SEARCH_SEARCHRESULTFORMATTER; // for backwards compatibility
9
10
  module(AMAZON_SEARCH_SEARCHRESULTFORMATTER, []).factory('awsSearchResultFormatter', function () {
10
11
  return {
11
- securityGroups: function (entry) {
12
+ securityGroups: function (entry: ISecurityGroupSearchResult) {
12
13
  return VpcReader.getVpcName(entry.vpcId).then(function (vpcName) {
13
14
  const region = vpcName ? entry.region + ' - ' + vpcName.toLowerCase() : entry.region;
14
15
  return entry.name + ' (' + region + ')';
15
16
  });
16
- },
17
+ } as ISearchResultFormatter,
17
18
  };
18
19
  });
@@ -17,6 +17,7 @@ import {
17
17
  SETTINGS,
18
18
  } from '@spinnaker/core';
19
19
 
20
+ import { AWSProviderSettings } from '../../aws.settings';
20
21
  import { AMAZON_SECURITYGROUP_CLONE_CLONESECURITYGROUP_CONTROLLER } from '../clone/cloneSecurityGroup.controller';
21
22
  import { VpcReader } from '../../vpc/VpcReader';
22
23
 
@@ -46,7 +47,7 @@ angular
46
47
  // needed for standalone instances
47
48
  $scope.detailsTemplateUrl = CloudProviderRegistry.getValue('aws', 'securityGroup.detailsTemplateUrl');
48
49
 
49
- $scope.isDisabled = !SETTINGS.awsAdHocInfraWritesEnabled;
50
+ $scope.isDisabled = !AWSProviderSettings.adHocInfraWritesEnabled;
50
51
 
51
52
  $scope.state = {
52
53
  loading: true,
@@ -1,13 +1,16 @@
1
- import React from 'react';
2
- import { mockHttpClient } from 'core/api/mock/jasmine';
3
1
  import { mock } from 'angular';
4
- import { ShallowWrapper, ReactWrapper, shallow, mount } from 'enzyme';
2
+ import type { ReactWrapper, ShallowWrapper } from 'enzyme';
3
+ import { mount, shallow } from 'enzyme';
4
+ import React from 'react';
5
5
 
6
- import { IAmazonImage } from '../../image';
7
- import { Application } from 'core/application';
8
- import { REACT_MODULE } from 'core/reactShims';
6
+ import { Application } from '@spinnaker/core';
7
+ import { REACT_MODULE } from '@spinnaker/core';
9
8
 
10
- import { AmazonImageSelectInput, IAmazonImageSelectorProps, IAmazonImageSelectorState } from './AmazonImageSelectInput';
9
+ import type { IAmazonImageSelectorProps, IAmazonImageSelectorState } from './AmazonImageSelectInput';
10
+ import { AmazonImageSelectInput } from './AmazonImageSelectInput';
11
+ // eslint-disable-next-line @spinnaker/import-from-npm-not-relative
12
+ import { mockHttpClient } from '../../../../core/src/api/mock/jasmine';
13
+ import type { IAmazonImage } from '../../image';
11
14
  const application = new Application('testapp', null, []);
12
15
  const region = 'us-region-1';
13
16
  const credentials = 'prodaccount';
@@ -3,16 +3,24 @@
3
3
  import { AccountService, SubnetReader } from '@spinnaker/core';
4
4
 
5
5
  import { AWSProviderSettings } from '../../aws.settings';
6
+ import {
7
+ createCustomMockLaunchTemplate,
8
+ mockLaunchTemplate,
9
+ mockLaunchTemplateData,
10
+ mockServerGroup,
11
+ } from '@spinnaker/mocks';
6
12
 
7
13
  describe('Service: awsServerGroup', function () {
8
14
  beforeEach(window.module(require('./serverGroupCommandBuilder.service').name));
9
15
 
16
+ let instanceTypeService;
10
17
  beforeEach(
11
18
  window.inject(function (awsServerGroupCommandBuilder, _instanceTypeService_, _$q_, $rootScope) {
12
19
  this.service = awsServerGroupCommandBuilder;
13
20
  this.$q = _$q_;
14
21
  this.$scope = $rootScope;
15
- spyOn(_instanceTypeService_, 'getCategoryForInstanceType').and.returnValue(_$q_.when('custom'));
22
+ instanceTypeService = _instanceTypeService_;
23
+ spyOn(instanceTypeService, 'getCategoryForMultipleInstanceTypes').and.returnValue(_$q_.when('custom'));
16
24
  }),
17
25
  );
18
26
 
@@ -30,6 +38,7 @@ describe('Service: awsServerGroup', function () {
30
38
  min: 1,
31
39
  max: 1,
32
40
  },
41
+ instanceType: 'm5.large',
33
42
  };
34
43
 
35
44
  AWSProviderSettings.defaults = {
@@ -77,6 +86,73 @@ describe('Service: awsServerGroup', function () {
77
86
  this.$scope.$digest();
78
87
  expect(command.viewState.usePreferredZones).toBe(false);
79
88
  });
89
+
90
+ describe('extracts instanceProfile from pipeline cluster correctly', function () {
91
+ const cluster = {
92
+ account: 'prod',
93
+ availabilityZones: {
94
+ 'us-west-1': ['d', 'g'],
95
+ },
96
+ capacity: {
97
+ min: 1,
98
+ max: 1,
99
+ },
100
+ instanceType: 'm5.large',
101
+ };
102
+
103
+ const clusters = [
104
+ {
105
+ desc: 'single instance type',
106
+ cluster: {
107
+ ...cluster,
108
+ instanceType: 'r5.large',
109
+ },
110
+ expected: {
111
+ instanceTypes: ['r5.large'],
112
+ useSimpleInstanceTypeSelector: true,
113
+ },
114
+ },
115
+ {
116
+ desc: 'multiple instance types',
117
+ cluster: {
118
+ ...cluster,
119
+ spotAllocationStrategy: 'capacity-optimized',
120
+ launchTemplateOverridesForInstanceType: [
121
+ {
122
+ instanceType: 't3.nano',
123
+ weightedCapacity: '2',
124
+ },
125
+ {
126
+ instanceType: 't3.micro',
127
+ weightedCapacity: '4',
128
+ },
129
+ ],
130
+ },
131
+ expected: {
132
+ instanceTypes: ['t3.nano', 't3.micro'],
133
+ useSimpleInstanceTypeSelector: false,
134
+ },
135
+ },
136
+ ];
137
+
138
+ clusters.forEach((test) => {
139
+ it(`cluster with ${test.desc}`, function () {
140
+ let actualCommand = null;
141
+ this.service.buildServerGroupCommandFromPipeline({}, test.cluster).then(function (result) {
142
+ actualCommand = result;
143
+ });
144
+ this.$scope.$digest();
145
+
146
+ expect(instanceTypeService.getCategoryForMultipleInstanceTypes).toHaveBeenCalledWith(
147
+ 'aws',
148
+ test.expected.instanceTypes,
149
+ );
150
+ expect(actualCommand.viewState.useSimpleInstanceTypeSelector).toBe(
151
+ test.expected.useSimpleInstanceTypeSelector,
152
+ );
153
+ });
154
+ });
155
+ });
80
156
  });
81
157
 
82
158
  describe('buildServerGroupCommandFromExisting', function () {
@@ -97,6 +173,7 @@ describe('Service: awsServerGroup', function () {
97
173
  { processName: 'AddToLoadBalancer' },
98
174
  ],
99
175
  },
176
+ launchTemplate: mockLaunchTemplate,
100
177
  };
101
178
  var command = null;
102
179
  this.service.buildServerGroupCommandFromExisting({}, serverGroup).then(function (result) {
@@ -114,6 +191,7 @@ describe('Service: awsServerGroup', function () {
114
191
  vpczoneIdentifier: '',
115
192
  suspendedProcesses: [],
116
193
  },
194
+ launchTemplate: mockLaunchTemplate,
117
195
  };
118
196
  var command = null;
119
197
  this.service.buildServerGroupCommandFromExisting({}, serverGroup, 'editPipeline').then(function (result) {
@@ -125,5 +203,228 @@ describe('Service: awsServerGroup', function () {
125
203
  expect(command.viewState.useSimpleCapacity).toBe(false);
126
204
  expect(command.useSourceCapacity).toBe(true);
127
205
  });
206
+
207
+ describe('extracts properties from server group correctly', function () {
208
+ const sgCommon = {
209
+ ...mockServerGroup,
210
+ asg: {
211
+ autoScalingGroupName: 'myasg-test-v000',
212
+ availabilityZones: [],
213
+ vpczoneIdentifier: '',
214
+ suspendedProcesses: [],
215
+ enabledMetrics: [],
216
+ },
217
+ };
218
+
219
+ const testLt = createCustomMockLaunchTemplate('test-lt', {
220
+ ...mockLaunchTemplateData,
221
+ instanceMarketOptions: {
222
+ spotOptions: {
223
+ maxPrice: '0.50',
224
+ },
225
+ },
226
+ networkInterfaces: [
227
+ {
228
+ deviceIndex: 0,
229
+ groups: ['my-sg'],
230
+ ipv6AddressCount: 1,
231
+ ipv6Addresses: [],
232
+ privateIpAddresses: [],
233
+ },
234
+ ],
235
+ keyName: 'test',
236
+ kernelId: 'kernal-abc',
237
+ ramDiskId: 'ramDisk-123',
238
+ userData: 'thisisfakeuserdata',
239
+ instanceType: 'm5.large',
240
+ });
241
+
242
+ const serverGroupsWithoutMip = [
243
+ {
244
+ desc: 'launchConfig',
245
+ sg: {
246
+ ...sgCommon,
247
+ launchConfig: {
248
+ instanceType: 'r5.large',
249
+ securityGroups: [],
250
+ },
251
+ },
252
+ expected: {
253
+ instanceType: 'r5.large',
254
+ launchTemplateOverridesForInstanceType: undefined,
255
+ instanceTypesParam: ['r5.large'],
256
+ useSimpleInstanceTypeSelector: true,
257
+ },
258
+ },
259
+ {
260
+ desc: 'launchTemplate',
261
+ sg: {
262
+ ...sgCommon,
263
+ launchTemplate: testLt,
264
+ },
265
+ expected: {
266
+ instanceType: 'm5.large',
267
+ launchTemplateOverridesForInstanceType: undefined,
268
+ instanceTypesParam: ['m5.large'],
269
+ useSimpleInstanceTypeSelector: true,
270
+ spotPrice: '0.50',
271
+ associateIPv6Address: true,
272
+ securityGroups: ['my-sg'],
273
+ },
274
+ },
275
+ ];
276
+
277
+ const mipCommon = {
278
+ instancesDistribution: {
279
+ onDemandAllocationStrategy: 'prioritized',
280
+ onDemandBaseCapacity: 1,
281
+ onDemandPercentageAboveBaseCapacity: 50,
282
+ spotAllocationStrategy: 'capacity-optimized',
283
+ },
284
+ };
285
+
286
+ const serverGroupsWithMip = [
287
+ {
288
+ desc: 'mixedInstancesPolicy without overrides',
289
+ sg: {
290
+ ...sgCommon,
291
+ mixedInstancesPolicy: {
292
+ instancesDistribution: {
293
+ onDemandAllocationStrategy: 'prioritized',
294
+ onDemandBaseCapacity: 1,
295
+ onDemandPercentageAboveBaseCapacity: 50,
296
+ spotAllocationStrategy: 'capacity-optimized',
297
+ spotMaxPrice: '1.5',
298
+ },
299
+ allowedInstanceTypes: ['m5.large'],
300
+ launchTemplates: [testLt],
301
+ },
302
+ },
303
+ expected: {
304
+ instanceType: 'm5.large',
305
+ launchTemplateOverridesForInstanceType: undefined,
306
+ instanceTypesParam: ['m5.large'],
307
+ useSimpleInstanceTypeSelector: false,
308
+ spotPrice: '1.5',
309
+ associateIPv6Address: true,
310
+ securityGroups: ['my-sg'],
311
+ },
312
+ },
313
+ {
314
+ desc: 'mixedInstancesPolicy with overrides and no priority',
315
+ sg: {
316
+ ...sgCommon,
317
+ mixedInstancesPolicy: {
318
+ ...mipCommon,
319
+ launchTemplates: [mockLaunchTemplate],
320
+ allowedInstanceTypes: ['t3.nano', 'm5.large'],
321
+ launchTemplateOverridesForInstanceType: [
322
+ { instanceType: 't3.nano', weightedCapacity: '2' },
323
+ { instanceType: 'm5.large', weightedCapacity: '4' },
324
+ ],
325
+ },
326
+ },
327
+ expected: {
328
+ instanceType: undefined,
329
+ launchTemplateOverridesForInstanceType: [
330
+ { instanceType: 't3.nano', priority: 1, weightedCapacity: '2' },
331
+ { instanceType: 'm5.large', priority: 2, weightedCapacity: '4' },
332
+ ],
333
+ instanceTypesParam: ['t3.nano', 'm5.large'],
334
+ useSimpleInstanceTypeSelector: false,
335
+ },
336
+ },
337
+ {
338
+ desc: 'mixedInstancesPolicy with overrides and all instance types have priority',
339
+ sg: {
340
+ ...sgCommon,
341
+ mixedInstancesPolicy: {
342
+ ...mipCommon,
343
+ launchTemplates: [mockLaunchTemplate],
344
+ allowedInstanceTypes: ['t3.nano', 'm5.large'],
345
+ launchTemplateOverridesForInstanceType: [
346
+ { instanceType: 't3.nano', weightedCapacity: '2', priority: 2 },
347
+ { instanceType: 'm5.large', weightedCapacity: '4', priority: 1 },
348
+ ],
349
+ },
350
+ },
351
+ expected: {
352
+ instanceType: undefined,
353
+ launchTemplateOverridesForInstanceType: [
354
+ ,
355
+ { instanceType: 'm5.large', weightedCapacity: '4', priority: 1 },
356
+ { instanceType: 't3.nano', weightedCapacity: '2', priority: 2 },
357
+ ],
358
+ instanceTypesParam: ['t3.nano', 'm5.large'],
359
+ useSimpleInstanceTypeSelector: false,
360
+ },
361
+ },
362
+ {
363
+ desc: 'mixedInstancesPolicy with overrides and some instance types have priority',
364
+ sg: {
365
+ ...sgCommon,
366
+ mixedInstancesPolicy: {
367
+ ...mipCommon,
368
+ launchTemplates: [mockLaunchTemplate],
369
+ allowedInstanceTypes: ['t3.nano', 't3.micro', 't2.nano', 't2.micro'],
370
+ launchTemplateOverridesForInstanceType: [
371
+ { instanceType: 't3.nano' },
372
+ { instanceType: 't3.micro', priority: 2 },
373
+ { instanceType: 't2.nano' },
374
+ { instanceType: 't2.micro', priority: 1 },
375
+ ],
376
+ },
377
+ },
378
+ expected: {
379
+ instanceType: undefined,
380
+ launchTemplateOverridesForInstanceType: [
381
+ { instanceType: 't2.micro', priority: 1 },
382
+ { instanceType: 't3.micro', priority: 2 },
383
+ { instanceType: 't3.nano', priority: 3 },
384
+ { instanceType: 't2.nano', priority: 4 },
385
+ ],
386
+ instanceTypesParam: ['t3.nano', 't3.micro', 't2.nano', 't2.micro'],
387
+ useSimpleInstanceTypeSelector: false,
388
+ },
389
+ },
390
+ ];
391
+
392
+ [...serverGroupsWithoutMip, ...serverGroupsWithMip].forEach((test) => {
393
+ it(`extracts instanceProfile, instanceType and useSimpleInstanceTypeSelector from server group with ${test.desc} correctly`, function () {
394
+ let actualCommand = null;
395
+ this.service.buildServerGroupCommandFromExisting({}, test.sg, 'clone').then(function (result) {
396
+ actualCommand = result;
397
+ });
398
+ this.$scope.$digest();
399
+
400
+ expect(instanceTypeService.getCategoryForMultipleInstanceTypes).toHaveBeenCalledWith(
401
+ 'aws',
402
+ test.expected.instanceTypesParam,
403
+ );
404
+ expect(actualCommand.instanceType).toBe(test.expected.instanceType);
405
+ expect(actualCommand.viewState.useSimpleInstanceTypeSelector).toBe(
406
+ test.expected.useSimpleInstanceTypeSelector,
407
+ );
408
+ test.expected.spotPrice && expect(actualCommand.spotPrice).toBe(test.expected.spotPrice);
409
+ });
410
+ });
411
+
412
+ serverGroupsWithMip.forEach((test) => {
413
+ it(`extracts launchTemplateOverridesForInstanceType and sets explicit priority correctly for server group with ${test.desc}`, function () {
414
+ let actualCommand = null;
415
+ this.service.buildServerGroupCommandFromExisting({}, test.sg, 'clone').then(function (result) {
416
+ actualCommand = result;
417
+ });
418
+ this.$scope.$digest();
419
+
420
+ expect(
421
+ _.isEqual(
422
+ actualCommand.launchTemplateOverridesForInstanceType,
423
+ test.expected.launchTemplateOverridesForInstanceType,
424
+ ).toBeTruthy,
425
+ );
426
+ });
427
+ });
428
+ });
128
429
  });
129
430
  });
@@ -86,6 +86,7 @@ angular
86
86
  copySourceCustomBlockDeviceMappings: false, // default to using block device mappings from current instance type
87
87
  viewState: {
88
88
  instanceProfile: 'custom',
89
+ useSimpleInstanceTypeSelector: true,
89
90
  useAllImageSelection: false,
90
91
  useSimpleCapacity: true,
91
92
  usePreferredZones: true,
@@ -130,10 +131,15 @@ angular
130
131
  function buildServerGroupCommandFromPipeline(application, originalCluster) {
131
132
  const pipelineCluster = _.cloneDeep(originalCluster);
132
133
  const region = Object.keys(pipelineCluster.availabilityZones)[0];
133
- const instanceTypeCategoryLoader = instanceTypeService.getCategoryForInstanceType(
134
+
135
+ let instanceTypes = pipelineCluster.launchTemplateOverridesForInstanceType
136
+ ? pipelineCluster.launchTemplateOverridesForInstanceType.map((o) => o.instanceType)
137
+ : [pipelineCluster.instanceType];
138
+ const instanceTypeCategoryLoader = instanceTypeService.getCategoryForMultipleInstanceTypes(
134
139
  'aws',
135
- pipelineCluster.instanceType,
140
+ instanceTypes,
136
141
  );
142
+
137
143
  const commandOptions = { account: pipelineCluster.account, region: region };
138
144
  const asyncLoader = $q.all([
139
145
  buildNewServerGroupCommand(application, commandOptions),
@@ -156,6 +162,7 @@ angular
156
162
  templatingEnabled: true,
157
163
  existingPipelineCluster: true,
158
164
  dirty: {},
165
+ useSimpleInstanceTypeSelector: isSimpleModeEnabled(pipelineCluster),
159
166
  };
160
167
 
161
168
  const viewOverrides = {
@@ -213,15 +220,23 @@ angular
213
220
  function buildServerGroupCommandFromExisting(application, serverGroup, mode = 'clone') {
214
221
  const preferredZonesLoader = AccountService.getPreferredZonesByAccount('aws');
215
222
  const subnetsLoader = SubnetReader.listSubnets();
216
-
217
223
  const serverGroupName = NameUtils.parseServerGroupName(serverGroup.asg.autoScalingGroupName);
218
224
 
219
- const instanceType = serverGroup.launchConfig
220
- ? serverGroup.launchConfig.instanceType
221
- : serverGroup.launchTemplate
222
- ? serverGroup.launchTemplate.launchTemplateData.instanceType
223
- : null;
224
- const instanceTypeCategoryLoader = instanceTypeService.getCategoryForInstanceType('aws', instanceType);
225
+ let instanceTypes;
226
+ if (serverGroup.mixedInstancesPolicy) {
227
+ const ltOverrides = _.get(serverGroup, 'mixedInstancesPolicy.launchTemplateOverridesForInstanceType');
228
+ instanceTypes = ltOverrides
229
+ ? ltOverrides.map((o) => o.instanceType)
230
+ : [_.get(serverGroup, 'mixedInstancesPolicy.launchTemplates[0].launchTemplateData.instanceType')]; // note: single launch template case is currently the only supported case for mixed instances policy
231
+ } else if (serverGroup.launchTemplate) {
232
+ instanceTypes = [_.get(serverGroup, 'launchTemplate.launchTemplateData.instanceType')];
233
+ } else if (serverGroup.launchConfig) {
234
+ instanceTypes = [_.get(serverGroup, 'launchConfig.instanceType')];
235
+ }
236
+ const instanceTypeCategoryLoader = instanceTypeService.getCategoryForMultipleInstanceTypes(
237
+ 'aws',
238
+ instanceTypes,
239
+ );
225
240
 
226
241
  return $q
227
242
  .all([preferredZonesLoader, subnetsLoader, instanceTypeCategoryLoader])
@@ -333,7 +348,8 @@ angular
333
348
  keyPair: serverGroup.launchConfig.keyName,
334
349
  associatePublicIpAddress: serverGroup.launchConfig.associatePublicIpAddress,
335
350
  ramdiskId: serverGroup.launchConfig.ramdiskId,
336
- instanceMonitoring: serverGroup.launchConfig.instanceMonitoring.enabled,
351
+ instanceMonitoring:
352
+ serverGroup.launchConfig.instanceMonitoring && serverGroup.launchConfig.instanceMonitoring.enabled,
337
353
  ebsOptimized: serverGroup.launchConfig.ebsOptimized,
338
354
  spotPrice: serverGroup.launchConfig.spotPrice,
339
355
  });
@@ -341,18 +357,47 @@ angular
341
357
  command.base64UserData = serverGroup.launchConfig.userData;
342
358
  }
343
359
  command.viewState.imageId = serverGroup.launchConfig.imageId;
360
+ command.viewState.useSimpleInstanceTypeSelector = true;
344
361
  }
345
362
 
346
- if (serverGroup.launchTemplate) {
347
- const { launchTemplateData } = serverGroup.launchTemplate;
348
- const maxPrice =
349
- launchTemplateData.instanceMarketOptions &&
350
- launchTemplateData.instanceMarketOptions.spotOptions &&
351
- launchTemplateData.instanceMarketOptions.spotOptions.maxPrice;
352
- const { ipv6AddressCount } =
353
- launchTemplateData.networkInterfaces &&
354
- launchTemplateData.networkInterfaces.length &&
355
- launchTemplateData.networkInterfaces[0];
363
+ if (serverGroup.launchTemplate || serverGroup.mixedInstancesPolicy) {
364
+ let launchTemplateData, spotMaxPrice;
365
+ if (serverGroup.launchTemplate) {
366
+ launchTemplateData = serverGroup.launchTemplate.launchTemplateData;
367
+ spotMaxPrice = _.get(launchTemplateData, 'instanceMarketOptions.spotOptions.maxPrice');
368
+
369
+ command.instanceType = launchTemplateData.instanceType;
370
+ command.viewState.useSimpleInstanceTypeSelector = true;
371
+ }
372
+
373
+ if (serverGroup.mixedInstancesPolicy) {
374
+ const mip = serverGroup.mixedInstancesPolicy;
375
+ launchTemplateData = _.get(mip, 'launchTemplates[0].launchTemplateData'); // note: single launch template case is currently the only supported case for mixed instances policy
376
+ spotMaxPrice = _.get(mip, 'instancesDistribution.spotMaxPrice');
377
+
378
+ command.securityGroups = launchTemplateData.networkInterfaces
379
+ ? (launchTemplateData.networkInterfaces.find((ni) => ni.deviceIndex === 0) || {}).groups
380
+ : _.get(launchTemplateData, 'securityGroups');
381
+ command.onDemandAllocationStrategy = mip.instancesDistribution.onDemandAllocationStrategy;
382
+ command.onDemandBaseCapacity = mip.instancesDistribution.onDemandBaseCapacity;
383
+ command.onDemandPercentageAboveBaseCapacity =
384
+ mip.instancesDistribution.onDemandPercentageAboveBaseCapacity;
385
+ command.spotAllocationStrategy = mip.instancesDistribution.spotAllocationStrategy;
386
+ command.spotInstancePools = mip.instancesDistribution.spotInstancePools;
387
+
388
+ // 'launchTemplateOverridesForInstanceType' is used for multiple instance types case, 'instanceType' is used for all other cases.
389
+ if (mip.launchTemplateOverridesForInstanceType) {
390
+ command.launchTemplateOverridesForInstanceType = getInstanceTypesWithPriority(
391
+ mip.launchTemplateOverridesForInstanceType,
392
+ );
393
+ } else {
394
+ command.instanceType = launchTemplateData.instanceType;
395
+ }
396
+
397
+ command.viewState.useSimpleInstanceTypeSelector = isSimpleModeEnabled(command);
398
+ }
399
+
400
+ const ipv6AddressCount = _.get(launchTemplateData, 'networkInterfaces[0]');
356
401
 
357
402
  const asgSettings = AWSProviderSettings.serverGroups;
358
403
  const isTestEnv = serverGroup.accountDetails && serverGroup.accountDetails.environment === 'test';
@@ -360,16 +405,15 @@ angular
360
405
  asgSettings && asgSettings.enableIPv6 && asgSettings.setIPv6InTest && isTestEnv;
361
406
 
362
407
  angular.extend(command, {
363
- instanceType: launchTemplateData.instanceType,
364
408
  iamRole: launchTemplateData.iamInstanceProfile.name,
365
409
  keyPair: launchTemplateData.keyName,
366
410
  associateIPv6Address: shouldAutoEnableIPv6 || Boolean(ipv6AddressCount),
367
411
  ramdiskId: launchTemplateData.ramdiskId,
368
- instanceMonitoring: launchTemplateData.monitoring.enabled,
412
+ instanceMonitoring: launchTemplateData.monitoring && launchTemplateData.monitoring.enabled,
369
413
  ebsOptimized: launchTemplateData.ebsOptimized,
370
- spotPrice: maxPrice || undefined,
414
+ spotPrice: spotMaxPrice || undefined,
371
415
  requireIMDSv2: Boolean(
372
- launchTemplateData.metadataOptions && launchTemplateData.metadataOptions.httpTokens === 'required',
416
+ launchTemplateData.metadataOptions && launchTemplateData.metadataOptions.httpsTokens === 'required',
373
417
  ),
374
418
  unlimitedCpuCredits: launchTemplateData.creditSpecification
375
419
  ? launchTemplateData.creditSpecification.cpuCredits === 'unlimited'
@@ -402,6 +446,34 @@ angular
402
446
  });
403
447
  }
404
448
 
449
+ // Since Deck allows changing priority of instance types via drag handle, fill priority field explicitly if empty
450
+ function getInstanceTypesWithPriority(instanceTypeOverrides) {
451
+ let explicitPriority = 1;
452
+ return _.sortBy(instanceTypeOverrides, ['priority']).map((override) => {
453
+ const { instanceType, weightedCapacity } = override;
454
+ let priority;
455
+ if (override.priority) {
456
+ priority = override.priority;
457
+ explicitPriority = override.priority + 1;
458
+ } else {
459
+ priority = explicitPriority++;
460
+ }
461
+ return { instanceType, weightedCapacity, priority };
462
+ });
463
+ }
464
+
465
+ function isSimpleModeEnabled(command) {
466
+ const isAdvancedModeEnabledInCommand =
467
+ command.onDemandAllocationStrategy ||
468
+ command.onDemandBaseCapacity ||
469
+ command.onDemandPercentageAboveBaseCapacity ||
470
+ command.spotAllocationStrategy ||
471
+ command.spotInstancePools ||
472
+ (command.launchTemplateOverridesForInstanceType && command.launchTemplateOverridesForInstanceType.length > 0);
473
+
474
+ return !isAdvancedModeEnabledInCommand;
475
+ }
476
+
405
477
  return {
406
478
  buildNewServerGroupCommand: buildNewServerGroupCommand,
407
479
  buildServerGroupCommandFromExisting: buildServerGroupCommandFromExisting,