@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
@@ -4,7 +4,11 @@ import { AccountService, SubnetReader } from '@spinnaker/core';
4
4
 
5
5
  import { AWSProviderSettings } from '../../aws.settings';
6
6
 
7
- import { createMockAmazonServerGroupWithLt, createCustomMockLaunchTemplate } from '@spinnaker/mocks';
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, 'getCategoryForInstanceType').and.returnValue(this.$q.when('custom'));
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, 'getCategoryForInstanceType').and.returnValue(this.$q.when('selectedProfile'));
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, 'getCategoryForInstanceType').and.returnValue(this.$q.when('selectedProfile'));
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, 'getCategoryForInstanceType').and.returnValue(this.$q.when('selectedProfile'));
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, 'getCategoryForInstanceType').and.returnValue(this.$q.when('selectedProfile'));
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, 'getCategoryForInstanceType').and.returnValue(this.$q.when('selectedProfile'));
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, 'getCategoryForInstanceType').and.returnValue(this.$q.when('selectedProfile'));
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 { mock, IQService, IScope, IRootScopeService } from 'angular';
1
+ import type { IQService, IRootScopeService, IScope } from 'angular';
2
+ import { mock } from 'angular';
2
3
 
3
- import {
4
- AccountService,
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
- AWS_SERVER_GROUP_CONFIGURATION_SERVICE,
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,
@@ -83,9 +83,17 @@ export interface IAmazonServerGroupCommandViewState extends IServerGroupCommandV
83
83
  dirty: IAmazonServerGroupCommandDirty;
84
84
  spelTargetGroups: string[];
85
85
  spelLoadBalancers: string[];
86
+ useSimpleInstanceTypeSelector: boolean;
87
+ }
88
+
89
+ export interface IAmazonInstanceTypeOverride {
90
+ instanceType: string;
91
+ weightedCapacity?: number;
92
+ priority?: number;
86
93
  }
87
94
 
88
95
  export interface IAmazonServerGroupCommand extends IServerGroupCommand {
96
+ viewState: IAmazonServerGroupCommandViewState;
89
97
  associateIPv6Address?: boolean;
90
98
  associatePublicIpAddress: boolean;
91
99
  backingData: IAmazonServerGroupCommandBackingData;
@@ -103,12 +111,18 @@ export interface IAmazonServerGroupCommand extends IServerGroupCommand {
103
111
  setLaunchTemplate?: boolean;
104
112
  unlimitedCpuCredits?: boolean;
105
113
  capacityRebalance?: boolean;
106
- viewState: IAmazonServerGroupCommandViewState;
114
+ onDemandAllocationStrategy?: string;
115
+ onDemandBaseCapacity?: number;
116
+ onDemandPercentageAboveBaseCapacity?: number;
117
+ spotAllocationStrategy?: string;
118
+ spotInstancePools?: number;
119
+ launchTemplateOverridesForInstanceType?: IAmazonInstanceTypeOverride[];
107
120
 
108
121
  getBlockDeviceMappingsSource: (command: IServerGroupCommand) => IBlockDeviceMappingSource;
109
122
  selectBlockDeviceMappingsSource: (command: IServerGroupCommand, selection: string) => void;
110
123
  usePreferredZonesChanged: (command: IServerGroupCommand) => IAmazonServerGroupCommandResult;
111
124
  regionIsDeprecated: (command: IServerGroupCommand) => boolean;
125
+ launchTemplateOverridesChanged: (command: IServerGroupCommand) => void;
112
126
  }
113
127
 
114
128
  export class AwsServerGroupConfigurationService {
@@ -643,10 +657,21 @@ export class AwsServerGroupConfigurationService {
643
657
  cmd.imageChanged = (command: IAmazonServerGroupCommand): IServerGroupCommandResult =>
644
658
  this.configureInstanceTypes(command);
645
659
 
660
+ // Handles derived values for single instance type case
646
661
  cmd.instanceTypeChanged = (command: IAmazonServerGroupCommand): void => {
647
662
  command.ebsOptimized = this.awsInstanceTypeService.isEbsOptimized(command.instanceType);
648
663
  };
649
664
 
665
+ // Handles derived values for multiple instance types case
666
+ cmd.launchTemplateOverridesChanged = (command: IAmazonServerGroupCommand): void => {
667
+ // set ebsOptimized to true if all instance types in overrides are included in the hard-coded array in awsInstanceTypeService.
668
+ // this function exists for backwards compatibility with single instance type case, matching behavior in `cmd.instanceTypeChanged`
669
+ // note: this parameter has no effect on instance types with EBS optimization enabled by default.
670
+ command.ebsOptimized = command.launchTemplateOverridesForInstanceType?.every((o) =>
671
+ this.awsInstanceTypeService.isEbsOptimized(o.instanceType),
672
+ );
673
+ };
674
+
650
675
  this.applyOverrides('attachEventHandlers', cmd);
651
676
  }
652
677
  }
@@ -207,7 +207,7 @@ export class AmazonCloneServerGroupModal extends React.Component<
207
207
  />
208
208
 
209
209
  <WizardPage
210
- label="Instance Type"
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} />}
@@ -1,49 +1,49 @@
1
- import React from 'react';
2
-
1
+ import React, { useEffect, useState } from 'react';
3
2
  import { ToggleButtonGroup, ToggleSize } from '@spinnaker/core';
4
3
  import { AwsReactInjector } from '../../../../reactShims';
5
4
 
6
- import type { IAmazonServerGroupCommand } from '../../serverGroupConfiguration.service';
7
-
8
5
  export interface ICpuCreditsToggleProps {
9
- command: IAmazonServerGroupCommand;
10
- newInstanceType?: string;
11
- newProfileType?: string;
6
+ unlimitedCpuCredits?: boolean;
7
+ selectedInstanceTypes: string[];
8
+ currentProfile: string;
12
9
  setUnlimitedCpuCredits: (unlimitedCpuCredits: boolean | undefined) => void;
13
10
  }
14
11
 
15
12
  export function CpuCreditsToggle(props: ICpuCreditsToggleProps) {
16
- const [showToggle, setShowToggle] = React.useState(false);
17
- React.useEffect(() => {
18
- if (props.newInstanceType) {
19
- const isBurstingSupportedForNewInstance = AwsReactInjector.awsInstanceTypeService.isBurstingSupported(
20
- props.newInstanceType,
21
- );
22
- if (!isBurstingSupportedForNewInstance) {
13
+ const { selectedInstanceTypes, currentProfile } = props;
14
+ const isBurstingSupportedForAllTypes = AwsReactInjector.awsInstanceTypeService.isBurstingSupportedForAllTypes(
15
+ selectedInstanceTypes,
16
+ );
17
+ const isAtleastOneTypeInProfile = AwsReactInjector.awsInstanceTypeService.getInstanceTypesInCategory(
18
+ selectedInstanceTypes,
19
+ currentProfile,
20
+ ).length
21
+ ? true
22
+ : false;
23
+
24
+ const [showToggle, setShowToggle] = useState(false);
25
+ useEffect(() => {
26
+ if (selectedInstanceTypes && selectedInstanceTypes.length) {
27
+ if (!isBurstingSupportedForAllTypes) {
23
28
  props.setUnlimitedCpuCredits(undefined);
24
29
  }
25
- setShowToggle(isBurstingSupportedForNewInstance);
30
+ setShowToggle(isBurstingSupportedForAllTypes);
26
31
  }
27
32
 
28
- if (props.newProfileType) {
29
- const { instanceType } = props.command;
30
- const isTypeInProfile = AwsReactInjector.awsInstanceTypeService.isInstanceTypeInCategory(
31
- instanceType,
32
- props.newProfileType,
33
+ if (currentProfile) {
34
+ setShowToggle(
35
+ selectedInstanceTypes &&
36
+ selectedInstanceTypes.length > 0 &&
37
+ isBurstingSupportedForAllTypes &&
38
+ isAtleastOneTypeInProfile,
33
39
  );
34
- const isBurstingSupportedForInstance = AwsReactInjector.awsInstanceTypeService.isBurstingSupported(instanceType);
35
- setShowToggle(instanceType && isTypeInProfile && isBurstingSupportedForInstance);
36
40
  }
37
- }, [props.newProfileType, props.newInstanceType]);
38
-
39
- const handleToggleChange = (state: boolean) => {
40
- props.setUnlimitedCpuCredits(state);
41
- };
41
+ }, [currentProfile, selectedInstanceTypes]);
42
42
 
43
43
  return (
44
- <div>
44
+ <div className={'row'} style={{ fontSize: '110%' }}>
45
45
  {showToggle && (
46
- <div className="row">
46
+ <div>
47
47
  <ToggleButtonGroup
48
48
  toggleSize={ToggleSize.XSMALL}
49
49
  propLabel={'Unlimited CPU credits '}
@@ -52,8 +52,8 @@ export function CpuCreditsToggle(props: ICpuCreditsToggleProps) {
52
52
  displayTextPropOffBtn={'Off'}
53
53
  tooltipPropOnBtn={'Toggle to turn ON unlimited CPU credits'}
54
54
  displayTextPropOnBtn={'On'}
55
- onClick={handleToggleChange}
56
- isPropertyActive={props.command.unlimitedCpuCredits}
55
+ onClick={(b) => props.setUnlimitedCpuCredits(b)}
56
+ isPropertyActive={props.unlimitedCpuCredits}
57
57
  />
58
58
  </div>
59
59
  )}
@@ -0,0 +1,133 @@
1
+ import type { FormikProps } from 'formik/dist/types';
2
+ import React, { useEffect, useState } from 'react';
3
+
4
+ import type { IInstanceTypeCategory } from '@spinnaker/core';
5
+ import { HelpField } from '@spinnaker/core';
6
+
7
+ import { AdvancedModeSelector } from './advancedMode/AdvancedModeSelector';
8
+ import { AWSProviderSettings } from '../../../../aws.settings';
9
+ import type { IAmazonInstanceTypeOverride, IAmazonServerGroupCommand } from '../../serverGroupConfiguration.service';
10
+ import { SimpleModeSelector } from './simpleMode/SimpleModeSelector';
11
+
12
+ export interface IInstanceTypeSelectorProps {
13
+ formik: FormikProps<IAmazonServerGroupCommand>;
14
+ instanceTypeDetails: IInstanceTypeCategory[];
15
+ }
16
+
17
+ export function InstanceTypeSelector(props: IInstanceTypeSelectorProps) {
18
+ const { instanceTypeDetails } = props;
19
+ const { values: command, setFieldValue } = props.formik;
20
+ const isLaunchTemplatesEnabled = AWSProviderSettings.serverGroups?.enableLaunchTemplates;
21
+
22
+ const useSimpleMode = command.viewState.useSimpleInstanceTypeSelector;
23
+ const [unlimitedCpuCredits, setUnlimitedCpuCredits] = useState(command.unlimitedCpuCredits);
24
+
25
+ useEffect(() => {
26
+ if (command.unlimitedCpuCredits !== unlimitedCpuCredits) {
27
+ setFieldValue('unlimitedCpuCredits', unlimitedCpuCredits);
28
+ }
29
+ }, [unlimitedCpuCredits]);
30
+
31
+ const handleModeChange = (useSimpleModeNew: boolean) => {
32
+ if (useSimpleMode !== useSimpleModeNew) {
33
+ setFieldValue('viewState', {
34
+ ...command.viewState,
35
+ useSimpleInstanceTypeSelector: useSimpleModeNew,
36
+ });
37
+
38
+ // update selected instance type(s) if mode changed.
39
+ // Simple mode uses command.instanceType to track selected type. Advanced mode uses command.launchTemplateOverridesForInstanceType to track selected types.
40
+ const multipleInstanceTypesInProps = command.launchTemplateOverridesForInstanceType;
41
+ const singleInstanceTypeInProps = command.instanceType;
42
+
43
+ const toSimple = useSimpleModeNew && multipleInstanceTypesInProps?.length;
44
+ const toAdvanced = !useSimpleModeNew && singleInstanceTypeInProps;
45
+ if (toSimple) {
46
+ const highestPriorityNum = Math.min(...multipleInstanceTypesInProps.map((it) => it.priority));
47
+ const instanceTypeWithHighestPriority = multipleInstanceTypesInProps.find(
48
+ (it) => it.priority === highestPriorityNum,
49
+ ).instanceType;
50
+
51
+ setFieldValue('instanceType', instanceTypeWithHighestPriority);
52
+ setFieldValue('launchTemplateOverridesForInstanceType', []);
53
+ command.instanceTypeChanged(command);
54
+ } else if (toAdvanced) {
55
+ const instanceTypes: IAmazonInstanceTypeOverride[] = [
56
+ {
57
+ instanceType: singleInstanceTypeInProps,
58
+ priority: 1,
59
+ },
60
+ ];
61
+ setFieldValue('instanceType', undefined);
62
+ setFieldValue('launchTemplateOverridesForInstanceType', instanceTypes);
63
+ command.launchTemplateOverridesChanged(command);
64
+ }
65
+ }
66
+ };
67
+
68
+ const showAdvancedMode = isLaunchTemplatesEnabled && !useSimpleMode;
69
+ if (showAdvancedMode) {
70
+ return (
71
+ <div className="container-fluid form-horizontal" style={{ padding: '0 15px' }}>
72
+ <div>
73
+ <p>
74
+ To configure a single instance type, use
75
+ <a className="clickable" onClick={() => handleModeChange(true)}>
76
+ <span> Simple Mode</span>
77
+ </a>
78
+ .
79
+ </p>
80
+ <i>
81
+ <b>Note:</b> If multiple instance types are already selected in advanced mode, the instance type with
82
+ highest priority will be preserved in simple mode.
83
+ </i>
84
+ </div>
85
+ <AdvancedModeSelector
86
+ formik={props.formik}
87
+ instanceTypeDetails={instanceTypeDetails}
88
+ setUnlimitedCpuCredits={setUnlimitedCpuCredits}
89
+ />
90
+ </div>
91
+ );
92
+ }
93
+
94
+ return (
95
+ <div className="container-fluid form-horizontal" style={{ padding: '0 15px' }}>
96
+ <div>
97
+ <span>To configure mixed server groups with multiple instance types,</span>
98
+ {!isLaunchTemplatesEnabled && (
99
+ <span>
100
+ <a
101
+ href={
102
+ 'https://spinnaker.io/docs/setup/other_config/server-group-launch-settings/aws-ec2/launch-templates-setup/'
103
+ }
104
+ >
105
+ <span> enable launch templates</span>
106
+ </a>
107
+ <span> and</span>
108
+ </span>
109
+ )}
110
+ <span>
111
+ <a
112
+ className={isLaunchTemplatesEnabled ? 'clickable' : 'disabled'}
113
+ onClick={isLaunchTemplatesEnabled ? () => handleModeChange(false) : () => {}}
114
+ >
115
+ <span> use Advanced Mode </span>
116
+ </a>
117
+ <HelpField id={'aws.serverGroup.advancedMode'} />.
118
+ </span>
119
+ <p></p>
120
+ {isLaunchTemplatesEnabled && (
121
+ <i>
122
+ <b>Note:</b> If an instance type is already selected in simple mode, it will be preserved in advanced mode.
123
+ </i>
124
+ )}
125
+ </div>
126
+ <SimpleModeSelector
127
+ command={command}
128
+ setUnlimitedCpuCredits={setUnlimitedCpuCredits}
129
+ setFieldValue={setFieldValue}
130
+ />
131
+ </div>
132
+ );
133
+ }
@@ -0,0 +1,99 @@
1
+ import type { FormikProps } from 'formik/dist/types';
2
+ import { keyBy } from 'lodash';
3
+ import React, { useEffect, useState } from 'react';
4
+
5
+ import { usePrevious } from '@spinnaker/core';
6
+
7
+ import { InstanceProfileSelector } from './InstanceProfileSelector';
8
+ import { InstanceTypeTable } from './InstanceTypeTable';
9
+ import { InstancesDistribution } from './InstancesDistribution';
10
+ import type { IAmazonInstanceTypeCategory } from '../../../../../instance/awsInstanceType.service';
11
+ import { AwsReactInjector } from '../../../../../reactShims';
12
+ import type { IAmazonInstanceTypeOverride, IAmazonServerGroupCommand } from '../../../serverGroupConfiguration.service';
13
+
14
+ export interface IAdvancedModeSelectorProps {
15
+ formik: FormikProps<IAmazonServerGroupCommand>;
16
+ instanceTypeDetails: IAmazonInstanceTypeCategory[];
17
+ setUnlimitedCpuCredits: (unlimitedCpuCredits: boolean | undefined) => void;
18
+ }
19
+
20
+ /**
21
+ * Note: Launch templates support is expected to be enabled if this component is rendered.
22
+ */
23
+ export function AdvancedModeSelector(props: IAdvancedModeSelectorProps) {
24
+ const { instanceTypeDetails, setUnlimitedCpuCredits } = props;
25
+ const { values: command, setFieldValue } = props.formik;
26
+
27
+ // for the case of MixedInstancesPolicy without overrides, copy command.instanceType to command.launchTemplateOverridesForInstanceType
28
+ const { instanceType, launchTemplateOverridesForInstanceType } = command;
29
+ useEffect(() => {
30
+ if (!launchTemplateOverridesForInstanceType && instanceType) {
31
+ props.formik.setFieldValue('launchTemplateOverridesForInstanceType', [
32
+ { instanceType: command.instanceType, priority: 1 },
33
+ ]);
34
+ }
35
+ });
36
+
37
+ const instanceTypesInProps: IAmazonInstanceTypeOverride[] = command.launchTemplateOverridesForInstanceType
38
+ ? command.launchTemplateOverridesForInstanceType
39
+ : undefined;
40
+
41
+ const selectedInstanceTypesMap = new Map<string, IAmazonInstanceTypeOverride>(
42
+ Object.entries(keyBy(instanceTypesInProps, 'instanceType')),
43
+ );
44
+
45
+ const [instanceProfile, setInstanceProfile] = useState(command.viewState.instanceProfile || 'custom');
46
+ const prevInstanceProfile = usePrevious(instanceProfile);
47
+
48
+ const handleProfileChange = (newProfile: string) => {
49
+ setInstanceProfile(newProfile);
50
+ setFieldValue('viewState', {
51
+ ...command.viewState,
52
+ instanceProfile: newProfile,
53
+ });
54
+
55
+ // update instance types on profile change
56
+ const hasProfileChanged = prevInstanceProfile && newProfile && prevInstanceProfile !== newProfile;
57
+ const isInstanceTypesUpdateNeeded = newProfile !== 'custom' && instanceTypesInProps && instanceTypesInProps.length;
58
+ if (hasProfileChanged && isInstanceTypesUpdateNeeded) {
59
+ const instanceTypesInProfile: string[] = AwsReactInjector.awsInstanceTypeService.getInstanceTypesInCategory(
60
+ instanceTypesInProps.map((it) => it.instanceType),
61
+ newProfile,
62
+ );
63
+ const newMultipleTypes = instanceTypesInProps.filter((o) => instanceTypesInProfile.includes(o.instanceType));
64
+ setFieldValue('launchTemplateOverridesForInstanceType', newMultipleTypes);
65
+ command.launchTemplateOverridesChanged(command);
66
+ }
67
+ };
68
+
69
+ const handleInstanceTypesChange = (types: IAmazonInstanceTypeOverride[]): void => {
70
+ setFieldValue('launchTemplateOverridesForInstanceType', types);
71
+ command.launchTemplateOverridesChanged(command);
72
+ };
73
+
74
+ if (!(instanceTypeDetails && instanceTypeDetails.length > 0)) {
75
+ return null;
76
+ }
77
+
78
+ return (
79
+ <div className={'advanced-mode-selector'}>
80
+ <InstanceProfileSelector
81
+ currentProfile={instanceProfile}
82
+ handleProfileChange={handleProfileChange}
83
+ instanceProfileList={instanceTypeDetails}
84
+ />
85
+ <InstancesDistribution formik={props.formik} />
86
+ <InstanceTypeTable
87
+ currentProfile={instanceProfile}
88
+ selectedInstanceTypesMap={selectedInstanceTypesMap}
89
+ unlimitedCpuCreditsInCmd={command.unlimitedCpuCredits}
90
+ profileDetails={instanceTypeDetails.find((p) => p.type === instanceProfile)}
91
+ availableInstanceTypesList={
92
+ (command.backingData && command.backingData.filtered && command.backingData.filtered.instanceTypes) || []
93
+ }
94
+ handleInstanceTypesChange={handleInstanceTypesChange}
95
+ setUnlimitedCpuCredits={setUnlimitedCpuCredits}
96
+ />
97
+ </div>
98
+ );
99
+ }
@@ -0,0 +1,36 @@
1
+ import React from 'react';
2
+
3
+ import type { IAmazonInstanceTypeCategory } from '../../../../../instance/awsInstanceType.service';
4
+
5
+ import './advancedMode.less';
6
+
7
+ export interface IInstanceProfileSelectorProps {
8
+ currentProfile: string;
9
+ handleProfileChange: (profile: string) => void;
10
+ instanceProfileList: IAmazonInstanceTypeCategory[];
11
+ }
12
+
13
+ export function InstanceProfileSelector(props: IInstanceProfileSelectorProps) {
14
+ return (
15
+ <div>
16
+ <h4 style={{ marginTop: '10px' }}>This application is</h4>
17
+ {props.instanceProfileList.map((profile) => (
18
+ <div key={profile.type} className={`instance-profile-header profile-button`}>
19
+ <button
20
+ type="button"
21
+ onClick={() => props.handleProfileChange(profile.type)}
22
+ className={props.currentProfile === profile.type ? 'instance-profile active' : 'instance-profile'}
23
+ >
24
+ {props.currentProfile === profile.type && <span className="far fa-check-circle selected-indicator" />}
25
+ <div className="panel-heading">
26
+ <h4>
27
+ <span className={`glyphicon glyphicon-${profile.icon}`} />
28
+ <div>{profile.label}</div>
29
+ </h4>
30
+ </div>
31
+ </button>
32
+ </div>
33
+ ))}
34
+ </div>
35
+ );
36
+ }