UNPKG

@pulumi/awsx

Version:

[![Actions Status](https://github.com/pulumi/pulumi-awsx/workflows/master/badge.svg)](https://github.com/pulumi/pulumi-awsx/actions) [![Slack](http://www.pulumi.com/images/docs/badges/slack.svg)](https://slack.pulumi.com) [![NPM version](https://badge.fur

250 lines • 11.3 kB
"use strict"; // Copyright 2016-2018, Pulumi Corporation. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.StepScalingPolicy = void 0; exports.convertSteps = convertSteps; exports.convertUpperSteps = convertUpperSteps; exports.convertLowerSteps = convertLowerSteps; const aws = __importStar(require("@pulumi/aws")); const pulumi = __importStar(require("@pulumi/pulumi")); const utils = __importStar(require("../utils")); /** * Step scaling policies increase or decrease the current capacity of your Auto Scaling group based * on a set of scaling adjustments, known as step adjustments. The adjustments vary based on the * size of the alarm breach. * * For example, consider the following StepScaling description for an ASG that has both a current * capacity and a desired capacity of 10. The current and desired capacity is maintained while the * aggregated metric value is greater than 40 and less than 60. * * ```ts * const policy = { * // ... other values * adjustmentType: "PercentChangeInCapacity", * steps: { * upper: [{ value: 60, adjustment: 10 }, { value: 70, adjustment: 30 }], * lower: [{ value: 40, adjustment: -10 }, { value: 30, adjustment: -30 }] * }, * }; * ``` * * If the metric value gets to 60, Application Auto Scaling increases the desired capacity of the * group by 1, to 11. That's based on the second step adjustment of the scale-out policy (add 10 * percent of 10). After the new capacity is added, Application Auto Scaling increases the current * capacity to 11. If the metric value rises to 70 even after this increase in capacity, Application * Auto Scaling increases the target capacity by 3, to 14. That's based on the third step adjustment * of the scale-out policy (add 30 percent of 11, 3.3, rounded down to 3). * * If the metric value gets to 40, Application Auto Scaling decreases the target capacity by 1, to * 13, based on the second step adjustment of the scale-in policy (remove 10 percent of 14, 1.4, * rounded down to 1). If the metric value falls to 30 even after this decrease in capacity, * Application Auto Scaling decreases the target capacity by 3, to 10, based on the third step * adjustment of the scale-in policy (remove 30 percent of 13, 3.9, rounded down to 3). */ class StepScalingPolicy extends pulumi.ComponentResource { /** * Underlying [Policy] created to define the scaling strategy for the upper set of steps. */ upperPolicy; /** * Alarm that invokes [upperPolicy] when the metric goes above the lowest value of the upper * range of steps. */ upperAlarm; /** * Underlying [Policy] created to define the scaling strategy for the lower set of steps. */ lowerPolicy; /** * Alarm that invokes [lowerPolicy] when the metric goes below the highest value of the lower * range of steps. */ lowerAlarm; constructor(name, group, args, opts = {}) { super("awsx:autoscaling:StepScalingPolicy", name, undefined, { parent: group, ...opts }); if (!args.steps.upper && !args.steps.lower) { throw new Error("At least one of [args.steps.upper] and [args.steps.lower] must be provided."); } const convertedSteps = pulumi.output(args.steps).apply(s => convertSteps(s)); const metricAggregationType = pulumi.output(args.metric.statistic).apply(s => { if (s !== "Minimum" && s !== "Maximum" && s !== "Average") { throw new Error(`[args.metric.statistic] must be one of "Minimum", "Maximum" or "Average", but was: ${s}`); } return s; }); const commonArgs = { autoscalingGroupName: group.group.name, policyType: "StepScaling", metricAggregationType, ...args, }; // AutoScaling recommends a metric of 60 to ensure that adjustments can happen in a timely // manner. const metric = args.metric.withPeriod(60); const evaluationPeriods = utils.ifUndefined(args.evaluationPeriods, 1); if (args.steps.upper) { this.upperPolicy = new aws.autoscaling.Policy(`${name}-upper`, { ...commonArgs, stepAdjustments: convertedSteps.upper.stepAdjustments, }, { parent: this }); this.upperAlarm = metric.createAlarm(`${name}-upper`, { evaluationPeriods, // step ranges and alarms are inclusive on the lower end. comparisonOperator: "GreaterThanOrEqualToThreshold", threshold: convertedSteps.upper.threshold, alarmActions: [this.upperPolicy.arn], }, { parent: this }); } if (args.steps.lower) { this.lowerPolicy = new aws.autoscaling.Policy(`${name}-lower`, { ...commonArgs, stepAdjustments: convertedSteps.lower.stepAdjustments, }, { parent: this }); this.lowerAlarm = metric.createAlarm(`${name}-lower`, { evaluationPeriods, // step ranges and alarms are inclusive on the upper end. comparisonOperator: "LessThanOrEqualToThreshold", threshold: convertedSteps.lower.threshold, alarmActions: [this.lowerPolicy.arn], }, { parent: this }); } this.registerOutputs(); } } exports.StepScalingPolicy = StepScalingPolicy; /** @internal */ function convertSteps(steps) { // First, order so that smaller values comes first. const upperSteps = sortSteps(steps.upper); const lowerSteps = sortSteps(steps.lower); const result = { upper: convertUpperSteps(upperSteps), lower: convertLowerSteps(lowerSteps), }; if (upperSteps && lowerSteps) { const lowerStep = lowerSteps[lowerSteps.length - 1]; const upperStep = upperSteps[0]; if (lowerStep.value >= upperStep.value) { throw new Error(`Lower and upper steps cannot overlap. Lower step value ${lowerStep.value} greater than upper step value ${upperStep.value}`); } } return result; } /** @internal */ function convertUpperSteps(upperSteps) { // First, order so that smaller values comes first. upperSteps = sortSteps(upperSteps); if (!upperSteps) { return undefined; } if (upperSteps.length === 0) { throw new Error("[args.steps.upper] must be non-empty."); } // The threshold is the value of the first step. This is the point where we'll set the alarm // to fire. Note: in the aws description, steps are offset from this. So if the breach-point is // 50, and the step value is 65, then we'll set metricIntervalLowerBound to 15. const threshold = upperSteps[0].value; const stepAdjustments = []; for (let i = 0, n = upperSteps.length; i < n; i++) { const step = upperSteps[i]; const nextStep = i === n - 1 ? undefined : upperSteps[i + 1]; if (nextStep) { if (step.value === nextStep.value) { throw new Error(`Upper steps contained two steps with the same [value]: ${step.value}`); } } stepAdjustments.push({ metricIntervalLowerBound: (step.value - threshold).toString(), // if this is the last step, extend it to infinity (using 'undefined'). Otherwise, // extend it to the next step. metricIntervalUpperBound: nextStep ? (nextStep.value - threshold).toString() : undefined, scalingAdjustment: step.adjustment, }); } return { threshold, stepAdjustments }; } function sortSteps(steps) { if (!steps) { return undefined; } return steps.sort((s1, s2) => s1.value - s2.value); } /** @internal */ function convertLowerSteps(lowerSteps) { // First, order so that smaller values comes first. lowerSteps = sortSteps(lowerSteps); if (!lowerSteps) { return undefined; } if (lowerSteps.length === 0) { throw new Error("[args.steps.lower] must be non-empty."); } // The threshold is the value of the last step. This is the point where we'll set the alarm to // fire. Note: in the aws description, steps are offset from this. So if the breach-point is // 50, and the step value is 35, then we'll set metricIntervalUpperBound to -15. const threshold = lowerSteps[lowerSteps.length - 1].value; const stepAdjustments = []; for (let i = 0, n = lowerSteps.length; i < n; i++) { const step = lowerSteps[i]; const previousStep = i === 0 ? undefined : lowerSteps[i - 1]; if (previousStep) { if (step.value === previousStep.value) { throw new Error(`Lower steps contained two steps with the same [value]: ${step.value}`); } } stepAdjustments.push({ // if this is the first step, extend it to -infinity (using 'undefined'). Otherwise, // extend it to the next step. metricIntervalLowerBound: previousStep ? (previousStep.value - threshold).toString() : undefined, metricIntervalUpperBound: (step.value - threshold).toString(), scalingAdjustment: step.adjustment, }); } return { threshold, stepAdjustments }; } //# sourceMappingURL=stepScaling.js.map