@spinnaker/amazon 0.14.5 → 2025.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,5 @@
1
1
  /// <reference types="react" />
2
+ import type { Application } from '@spinnaker/core';
2
3
  import type { ITargetTrackingPolicyCommand } from '../ScalingPolicyWriter';
3
4
  import type { IAmazonServerGroup } from '../../../../domain';
4
5
  import './TargetMetricFields.less';
@@ -8,8 +9,9 @@ export interface ITargetMetricFieldsProps {
8
9
  cloudwatch?: boolean;
9
10
  command: ITargetTrackingPolicyCommand;
10
11
  isCustomMetric: boolean;
12
+ app: Application;
11
13
  serverGroup: IAmazonServerGroup;
12
14
  toggleMetricType?: (type: MetricType) => void;
13
15
  updateCommand: (command: ITargetTrackingPolicyCommand) => void;
14
16
  }
15
- export declare const TargetMetricFields: ({ allowDualMode, cloudwatch, command, isCustomMetric, serverGroup, toggleMetricType, updateCommand, }: ITargetMetricFieldsProps) => JSX.Element;
17
+ export declare const TargetMetricFields: ({ allowDualMode, cloudwatch, command, isCustomMetric, app, serverGroup, toggleMetricType, updateCommand, }: ITargetMetricFieldsProps) => JSX.Element;
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@spinnaker/amazon",
3
3
  "license": "Apache-2.0",
4
- "version": "0.14.5",
4
+ "version": "2025.0.0",
5
5
  "module": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
7
7
  "publishConfig": {
8
- "access": "public"
8
+ "access": "public",
9
+ "registry": "https://registry.npmjs.org"
9
10
  },
10
11
  "scripts": {
11
12
  "clean": "shx rm -rf dist",
@@ -58,5 +59,5 @@
58
59
  "shx": "0.3.3",
59
60
  "typescript": "4.3.5"
60
61
  },
61
- "gitHead": "2f7f8de7b0c43ea29ac505a9b4c0f5d9b29456f4"
62
+ "gitHead": "5b197da8614979a51dc24b0a6f92e19c3162e874"
62
63
  }
@@ -21,6 +21,11 @@ export interface ICustomizedMetricSpecification {
21
21
 
22
22
  export interface IPredefinedMetricSpecification {
23
23
  predefinedMetricType: PredefinedMetricType;
24
+ resourceLabel?: string;
24
25
  }
25
26
 
26
- export type PredefinedMetricType = 'ASGAverageCPUUtilization' | 'ASGAverageNetworkIn' | 'ASGAverageNetworkOut';
27
+ export type PredefinedMetricType =
28
+ | 'ASGAverageCPUUtilization'
29
+ | 'ASGAverageNetworkIn'
30
+ | 'ASGAverageNetworkOut'
31
+ | 'ALBRequestCountPerTarget';
@@ -405,6 +405,9 @@ angular
405
405
  spotMaxPrice = launchTemplateData.instanceMarketOptions?.spotOptions?.maxPrice;
406
406
  command.instanceType = launchTemplateData.instanceType;
407
407
  command.viewState.useSimpleInstanceTypeSelector = true;
408
+ if (launchTemplateData.userData) {
409
+ command.base64UserData = launchTemplateData.userData;
410
+ }
408
411
  }
409
412
 
410
413
  if (serverGroup.mixedInstancesPolicy) {
@@ -434,7 +437,8 @@ angular
434
437
  command.viewState.useSimpleInstanceTypeSelector = isSimpleModeEnabled(command);
435
438
  }
436
439
 
437
- const ipv6AddressCount = _.get(launchTemplateData, 'networkInterfaces[0]');
440
+ const networkInterfaces = _.get(launchTemplateData, 'networkInterfaces[0]');
441
+ const ipv6AddressCount = (networkInterfaces as INetworkInterface)?.ipv6AddressCount ?? 0;
438
442
 
439
443
  const asgSettings = AWSProviderSettings.serverGroups;
440
444
  const isTestEnv = serverGroup.accountDetails && serverGroup.accountDetails.environment === 'test';
@@ -1,3 +1,4 @@
1
+ import { get } from 'lodash';
1
2
  import * as React from 'react';
2
3
 
3
4
  import type { ICloudMetricStatistics } from '@spinnaker/core';
@@ -36,7 +37,7 @@ export function MetricAlarmChartImpl(props: IMetricAlarmChartProps) {
36
37
  return result;
37
38
  },
38
39
  { datapoints: [], unit: '' },
39
- [namespace, statistic, period, type, account, region, metricName],
40
+ [namespace, statistic, period, type, account, region, metricName, alarm.dimensions],
40
41
  );
41
42
 
42
43
  if (status === 'PENDING') {
@@ -60,13 +61,15 @@ export function MetricAlarmChartImpl(props: IMetricAlarmChartProps) {
60
61
 
61
62
  const now = new Date();
62
63
  const oneDayAgo = new Date(Date.now() - 1000 * 60 * 60 * 24);
63
-
64
64
  const line: IDateLine = {
65
65
  label: metricName,
66
66
  fill: 'stack',
67
67
  borderColor: 'green',
68
68
  borderWidth: 2,
69
- data: result.datapoints.map((dp) => ({ x: new Date(dp.timestamp), y: dp.average })),
69
+ data: result.datapoints.map((dp) => ({
70
+ x: new Date(dp.timestamp),
71
+ y: get(dp, [alarm.statistic.toLowerCase()], undefined),
72
+ })),
70
73
  };
71
74
 
72
75
  const setline: IDateLine = {
@@ -2,10 +2,17 @@ import { cloneDeep, set } from 'lodash';
2
2
  import * as React from 'react';
3
3
 
4
4
  import { NumberInput, ReactSelectInput } from '@spinnaker/core';
5
+ import type { Application, ILoadBalancer } from '@spinnaker/core';
5
6
 
6
7
  import type { ITargetTrackingPolicyCommand } from '../ScalingPolicyWriter';
7
8
  import { TargetTrackingChart } from './TargetTrackingChart';
8
- import type { IAmazonServerGroup, ICustomizedMetricSpecification, IScalingPolicyAlarmView } from '../../../../domain';
9
+ import type {
10
+ IAmazonApplicationLoadBalancer,
11
+ IAmazonServerGroup,
12
+ ICustomizedMetricSpecification,
13
+ IScalingPolicyAlarmView,
14
+ ITargetGroup,
15
+ } from '../../../../domain';
9
16
  import { MetricSelector } from '../upsert/alarm/MetricSelector';
10
17
 
11
18
  import './TargetMetricFields.less';
@@ -16,21 +23,36 @@ export interface ITargetMetricFieldsProps {
16
23
  cloudwatch?: boolean;
17
24
  command: ITargetTrackingPolicyCommand;
18
25
  isCustomMetric: boolean;
26
+ app: Application;
19
27
  serverGroup: IAmazonServerGroup;
20
28
  toggleMetricType?: (type: MetricType) => void;
21
29
  updateCommand: (command: ITargetTrackingPolicyCommand) => void;
22
30
  }
23
31
 
32
+ interface IalbArn {
33
+ loadBalancerArn: string;
34
+ }
35
+
36
+ interface ItargetGroupArn {
37
+ targetGroupArn: string;
38
+ }
39
+
24
40
  export const TargetMetricFields = ({
25
41
  allowDualMode,
26
42
  cloudwatch,
27
43
  command,
28
44
  isCustomMetric,
45
+ app,
29
46
  serverGroup,
30
47
  toggleMetricType,
31
48
  updateCommand,
32
49
  }: ITargetMetricFieldsProps) => {
33
- const predefinedMetrics = ['ASGAverageCPUUtilization', 'ASGAverageNetworkOut', 'ASGAverageNetworkIn'];
50
+ const predefinedMetrics = [
51
+ 'ASGAverageCPUUtilization',
52
+ 'ASGAverageNetworkOut',
53
+ 'ASGAverageNetworkIn',
54
+ 'ALBRequestCountPerTarget',
55
+ ];
34
56
  const statistics = ['Average', 'Maximum', 'Minimum', 'SampleCount', 'Sum'];
35
57
  const [unit, setUnit] = React.useState<string>(null);
36
58
 
@@ -65,6 +87,24 @@ export const TargetMetricFields = ({
65
87
  toggleMetricType(isCustomMetric ? 'predefined' : 'custom');
66
88
  };
67
89
 
90
+ const targetGroupOptions = () => {
91
+ const loadBalancers = app.loadBalancers.data as ILoadBalancer[];
92
+ const albs = loadBalancers.filter(
93
+ (lb) => lb.account === serverGroup.account && lb.region === serverGroup.region,
94
+ ) as Array<IAmazonApplicationLoadBalancer & IalbArn>;
95
+ const targetGroups = albs.flatMap((alb) =>
96
+ alb.targetGroups
97
+ .filter((tg) => serverGroup.targetGroups.some((serverGroupTg) => serverGroupTg === tg.name))
98
+ .map((tg) => ({ ...tg, loadBalancerArn: alb.loadBalancerArn })),
99
+ ) as Array<ITargetGroup & IalbArn & ItargetGroupArn>;
100
+ return targetGroups.map((tg) => ({
101
+ label: tg.name,
102
+ value: `${tg.loadBalancerArn.substring(tg.loadBalancerArn.indexOf('app'))}/${tg.targetGroupArn.substring(
103
+ tg.targetGroupArn.indexOf('targetgroup'),
104
+ )}`,
105
+ }));
106
+ };
107
+
68
108
  return (
69
109
  <div className="TargetMetricFields sp-margin-l-xaxis">
70
110
  <p>
@@ -94,6 +134,7 @@ export const TargetMetricFields = ({
94
134
  inputClassName="metric-select-input"
95
135
  />
96
136
  )}
137
+
97
138
  {isCustomMetric && (
98
139
  <MetricSelector
99
140
  alarm={command.targetTrackingConfiguration.customizedMetricSpecification as IScalingPolicyAlarmView}
@@ -108,6 +149,26 @@ export const TargetMetricFields = ({
108
149
  )}
109
150
  </div>
110
151
  </div>
152
+ {!isCustomMetric &&
153
+ command.targetTrackingConfiguration.predefinedMetricSpecification?.predefinedMetricType ===
154
+ 'ALBRequestCountPerTarget' && (
155
+ <div className="row sp-margin-s-yaxis">
156
+ <div className="col-md-2 sm-label-right">Target Group</div>
157
+ <div className="col-md-10 content-fields horizontal">
158
+ <ReactSelectInput
159
+ value={command.targetTrackingConfiguration.predefinedMetricSpecification?.resourceLabel}
160
+ options={targetGroupOptions()}
161
+ onChange={(e) =>
162
+ setCommandField(
163
+ 'targetTrackingConfiguration.predefinedMetricSpecification.resourceLabel',
164
+ e.target.value,
165
+ )
166
+ }
167
+ inputClassName="metric-select-input"
168
+ />
169
+ </div>
170
+ </div>
171
+ )}
111
172
  <div className="row sp-margin-s-yaxis">
112
173
  <div className="col-md-2 sm-label-right">Target</div>
113
174
  <div className="col-md-10 content-fields horizontal">
@@ -17,6 +17,7 @@ const predefinedMetricTypeMapping: Dictionary<string> = {
17
17
  ASGAverageCPUUtilization: 'CPUUtilization',
18
18
  ASGAverageNetworkIn: 'NetworkIn',
19
19
  ASGAverageNetworkOut: 'NetworkOut',
20
+ ALBRequestCountPerTarget: 'RequestCountPerTarget',
20
21
  };
21
22
 
22
23
  export const TargetTrackingChart = ({ config, serverGroup, updateUnit }: ITargetTrackingChartProps) => {
@@ -40,12 +41,11 @@ export const TargetTrackingChart = ({ config, serverGroup, updateUnit }: ITarget
40
41
 
41
42
  const synchronizeAlarm = () => {
42
43
  const customMetric = config?.customizedMetricSpecification;
44
+ const predefMetric = config?.predefinedMetricSpecification;
43
45
  const updatedAlarm = {
44
46
  ...alarm,
45
47
  dimensions: customMetric?.dimensions || [{ name: 'AutoScalingGroupName', value: serverGroup.name }],
46
- metricName:
47
- customMetric?.metricName ||
48
- predefinedMetricTypeMapping[config?.predefinedMetricSpecification?.predefinedMetricType],
48
+ metricName: customMetric?.metricName || predefinedMetricTypeMapping[predefMetric?.predefinedMetricType],
49
49
  namespace: customMetric?.namespace || 'AWS/EC2',
50
50
  threshold: config?.targetValue,
51
51
  };
@@ -54,6 +54,20 @@ export const TargetTrackingChart = ({ config, serverGroup, updateUnit }: ITarget
54
54
  updatedAlarm.statistic = customMetric?.statistic;
55
55
  }
56
56
 
57
+ if (predefMetric && predefMetric.predefinedMetricType === 'ALBRequestCountPerTarget') {
58
+ updatedAlarm.statistic = 'Sum';
59
+ updatedAlarm.namespace = 'AWS/ApplicationELB';
60
+ if (predefMetric?.resourceLabel) {
61
+ const parts = predefMetric?.resourceLabel.split('/');
62
+ const loadBalancer = parts.slice(0, 3).join('/');
63
+ const targetGroup = parts.slice(3).join('/');
64
+ updatedAlarm.dimensions = [
65
+ { name: 'LoadBalancer', value: loadBalancer },
66
+ { name: 'TargetGroup', value: targetGroup },
67
+ ];
68
+ }
69
+ }
70
+
57
71
  setAlarm(updatedAlarm);
58
72
  };
59
73
 
@@ -58,6 +58,7 @@ export const UpsertTargetTrackingModal = ({
58
58
  cloudwatch={false}
59
59
  command={command as ITargetTrackingPolicyCommand}
60
60
  isCustomMetric={isCustom}
61
+ app={app}
61
62
  serverGroup={serverGroup}
62
63
  toggleMetricType={(t) => setIsCustom(t === 'custom')}
63
64
  updateCommand={setCommand}