@spotinst/spinnaker-deck
Version:
Spinnaker-Deck service, forked with support to Spotinst
215 lines (187 loc) • 7.8 kB
JavaScript
;
import { module } from 'angular';
import { TaskMonitor } from '@spinnaker/core';
import { ScalingPolicyWriter } from '../ScalingPolicyWriter';
import { AMAZON_SERVERGROUP_DETAILS_SCALINGPOLICY_UPSERT_ALARM_ALARMCONFIGURER_COMPONENT } from './alarm/alarmConfigurer.component';
import { AMAZON_SERVERGROUP_DETAILS_SCALINGPOLICY_UPSERT_SIMPLE_SIMPLEPOLICYACTION_COMPONENT } from './simple/simplePolicyAction.component';
import { STEP_POLICY_ACTION } from './step/stepPolicyAction.component';
import './upsertScalingPolicy.modal.less';
export const AMAZON_SERVERGROUP_DETAILS_SCALINGPOLICY_UPSERT_UPSERTSCALINGPOLICY_CONTROLLER =
'spinnaker.amazon.serverGroup.details.scalingPolicy.upsertScalingPolicy.controller';
export const name = AMAZON_SERVERGROUP_DETAILS_SCALINGPOLICY_UPSERT_UPSERTSCALINGPOLICY_CONTROLLER; // for backwards compatibility
module(AMAZON_SERVERGROUP_DETAILS_SCALINGPOLICY_UPSERT_UPSERTSCALINGPOLICY_CONTROLLER, [
AMAZON_SERVERGROUP_DETAILS_SCALINGPOLICY_UPSERT_SIMPLE_SIMPLEPOLICYACTION_COMPONENT,
STEP_POLICY_ACTION,
AMAZON_SERVERGROUP_DETAILS_SCALINGPOLICY_UPSERT_ALARM_ALARMCONFIGURER_COMPONENT,
]).controller('awsUpsertScalingPolicyCtrl', [
'$uibModalInstance',
'serverGroup',
'application',
'policy',
function ($uibModalInstance, serverGroup, application, policy) {
this.serverGroup = serverGroup;
this.viewState = {
isNew: !policy.policyARN,
multipleAlarms: policy.alarms.length > 1,
metricsLoaded: false,
namespacesLoaded: false,
};
function createCommand() {
return {
name: policy.policyName,
serverGroupName: serverGroup.name,
credentials: serverGroup.account,
region: serverGroup.region,
provider: serverGroup.type,
adjustmentType: policy.adjustmentType,
minAdjustmentMagnitude: policy.minAdjustmentMagnitude || 1,
};
}
function initializeAlarm(command, policy) {
const alarm = policy.alarms[0];
command.alarm = {
name: alarm.alarmName,
region: serverGroup.region,
actionsEnabled: true,
alarmDescription: alarm.alarmDescription,
comparisonOperator: alarm.comparisonOperator,
dimensions: alarm.dimensions,
evaluationPeriods: alarm.evaluationPeriods,
period: alarm.period,
threshold: alarm.threshold,
namespace: alarm.namespace,
metricName: alarm.metricName,
statistic: alarm.statistic,
unit: alarm.unit,
alarmActionArns: alarm.alarmActions,
insufficientDataActionArns: alarm.insufficientDataActions,
okActionArns: alarm.okActions,
};
}
this.initialize = () => {
const command = createCommand();
initializeAlarm(command, policy);
if (command.adjustmentType === 'ExactCapacity') {
this.viewState.operator = 'Set to';
this.viewState.adjustmentType = 'instances';
} else {
let adjustmentBasis = policy.scalingAdjustment;
if (policy.stepAdjustments && policy.stepAdjustments.length) {
adjustmentBasis = policy.stepAdjustments[0].scalingAdjustment;
}
this.viewState.operator = adjustmentBasis > 0 ? 'Add' : 'Remove';
this.viewState.adjustmentType = policy.adjustmentType === 'ChangeInCapacity' ? 'instances' : 'percent of group';
}
if (policy.stepAdjustments && policy.stepAdjustments.length) {
initializeStepPolicy(command, policy);
} else {
initializeSimplePolicy(command, policy);
}
this.command = command;
};
function initializeStepPolicy(command, policy) {
const threshold = command.alarm.threshold;
command.step = {
estimatedInstanceWarmup: policy.estimatedInstanceWarmup || command.cooldown || 600,
metricAggregationType: 'Average',
};
command.step.stepAdjustments = policy.stepAdjustments.map((adjustment) => {
const step = {
scalingAdjustment: Math.abs(adjustment.scalingAdjustment),
};
if (adjustment.metricIntervalUpperBound !== undefined) {
step.metricIntervalUpperBound = adjustment.metricIntervalUpperBound + threshold;
}
if (adjustment.metricIntervalLowerBound !== undefined) {
step.metricIntervalLowerBound = adjustment.metricIntervalLowerBound + threshold;
}
return step;
});
}
function initializeSimplePolicy(command, policy) {
command.simple = {
cooldown: policy.cooldown || 600,
scalingAdjustment: Math.abs(policy.scalingAdjustment) || 1,
};
}
this.boundsChanged = () => {
const source = this.viewState.comparatorBound === 'min' ? 'metricIntervalLowerBound' : 'metricIntervalUpperBound';
const target = source === 'metricIntervalLowerBound' ? 'metricIntervalUpperBound' : 'metricIntervalLowerBound';
if (this.command.step) {
const steps = this.command.step.stepAdjustments;
steps.forEach((step, index) => {
if (steps.length > index + 1) {
steps[index + 1][target] = step[source];
}
});
// remove the source boundary from the last step
delete steps[steps.length - 1][source];
}
};
this.switchMode = () => {
const command = this.command;
const cooldownOrWarmup = command.step ? command.step.estimatedInstanceWarmup : command.simple.cooldown;
if (command.step) {
const policy = { cooldown: cooldownOrWarmup };
delete command.step;
initializeSimplePolicy(command, policy);
} else {
const stepAdjustments = [
{
scalingAdjustment: command.simple.scalingAdjustment,
},
];
if (this.viewState.comparatorBound === 'min') {
stepAdjustments[0].metricIntervalUpperBound = 0;
} else {
stepAdjustments[0].metricIntervalLowerBound = 0;
}
delete command.simple;
initializeStepPolicy(command, {
estimatedInstanceWarmup: cooldownOrWarmup,
stepAdjustments: stepAdjustments,
});
this.boundsChanged();
}
};
this.action = this.viewState.isNew ? 'Create' : 'Edit';
const prepareCommandForSubmit = () => {
const command = _.cloneDeep(this.command);
if (command.adjustmentType !== 'PercentChangeInCapacity') {
delete command.minAdjustmentMagnitude;
}
if (command.step) {
// adjust metricIntervalLowerBound/UpperBound for each step based on alarm threshold
command.step.stepAdjustments.forEach((step) => {
if (this.viewState.operator === 'Remove') {
step.scalingAdjustment = 0 - step.scalingAdjustment;
delete command.step.estimatedInstanceWarmup;
}
if (step.metricIntervalLowerBound !== undefined) {
step.metricIntervalLowerBound -= command.alarm.threshold;
}
if (step.metricIntervalUpperBound !== undefined) {
step.metricIntervalUpperBound -= command.alarm.threshold;
}
});
} else {
if (this.viewState.operator === 'Remove') {
command.simple.scalingAdjustment = 0 - command.simple.scalingAdjustment;
}
}
return command;
};
this.taskMonitor = new TaskMonitor({
application: application,
title: this.action + ' scaling policy for ' + serverGroup.name,
modalInstance: $uibModalInstance,
});
this.save = () => {
const command = prepareCommandForSubmit();
const submitMethod = () => ScalingPolicyWriter.upsertScalingPolicy(application, command);
this.taskMonitor.submit(submitMethod);
};
this.cancel = $uibModalInstance.dismiss;
this.initialize();
},
]);