Skip to content

Commit

Permalink
feat(google): add predictive autoscaling support (#8495)
Browse files Browse the repository at this point in the history
* feat(google): add feature flag for predictive autoscaling

* refactor(google): move autoscaling policy interfaces and layout components to autoscalingPolicy directory

Currently, the only Typescript/React components of the autoscaling policy modal are specific to the scale-in control feature. In the next commit, we will add support for predictive autoscaling, so in order to share these interfaces and layout components, lift them to the top level.

* feat(google): add predictive autoscaling support (add/edit policy modal)

* feat(google): add predictive autoscaling support (SG details view)

* fix(google): sp/scaleDownInConfigured/scaleInControlsConfigured

I think we missed one spot when we renamed scale-in to scale-down.

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
maggieneterval and mergify[bot] committed Aug 14, 2020
1 parent a6f9bc0 commit 0be2a84
Show file tree
Hide file tree
Showing 14 changed files with 109 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { isEmpty } from 'lodash';

import { ILayoutProps } from '@spinnaker/core';

import './gceScaleInControls.less';
import './gceAutoscalingFieldLayout.less';

// todo(mneterval): remove when GCE Autoscaling Controls are entirely converted to React & Formik
export function GceAutoScalingFieldLayout(props: ILayoutProps) {
Expand All @@ -13,7 +13,7 @@ export function GceAutoScalingFieldLayout(props: ILayoutProps) {
const { hidden, messageNode } = validation;

return (
<div className="gce-scale-in-controls">
<div className="gce-autoscaling-layout">
{showLabel && (
<label className="col-md-3 sm-label-right">
{label}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export interface IGceAutoscalingPolicy {
cpuUtilization: IGceAutoscalingCpuUtilization;
scaleInControl: IGceScaleInControl;
}

export interface IGceScaleInControl {
maxScaledInReplicas?: {
fixed?: number;
percent?: number;
};
timeWindowSec?: number;
}

export interface IGceAutoscalingCpuUtilization {
predictiveMethod?: GcePredictiveMethod;
utilizationTarget?: number;
}

export enum GcePredictiveMethod {
NONE = 'NONE',
STANDARD = 'STANDARD',
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { module } from 'angular';

import React from 'react';
import { react2angular } from 'react2angular';

import { CheckboxInput, FormField, HelpField, IFormInputProps, LayoutProvider } from '@spinnaker/core';

import { GceAutoScalingFieldLayout } from '../../GceAutoScalingFieldLayout';
import { IGceAutoscalingPolicy, GcePredictiveMethod } from '../../IGceAutoscalingPolicy';
import { GCEProviderSettings } from '../../../gce.settings';

interface IGcePredictiveAutoscalingProps {
policy: IGceAutoscalingPolicy;
updatePolicy: (policy: IGceAutoscalingPolicy) => void;
}

function GcePredictiveAutoscaling({ policy, updatePolicy }: IGcePredictiveAutoscalingProps) {
if (!GCEProviderSettings.feature.predictiveAutoscaling) {
return null;
}

function togglePredictiveAutoscaling(predictiveMethod: GcePredictiveMethod) {
updatePolicy({
...policy,
cpuUtilization: {
...policy.cpuUtilization,
predictiveMethod,
},
});
}

return (
<LayoutProvider value={GceAutoScalingFieldLayout}>
<div className="row">
<FormField
help={<HelpField id="gce.serverGroup.scalingPolicy.predictiveAutoscaling" />}
input={(inputProps: IFormInputProps) => <CheckboxInput {...inputProps} />}
label="Enable predictive autoscaling"
onChange={(e: React.ChangeEvent<any>) => {
togglePredictiveAutoscaling(e.target.checked ? GcePredictiveMethod.STANDARD : GcePredictiveMethod.NONE);
}}
value={policy?.cpuUtilization?.predictiveMethod === GcePredictiveMethod.STANDARD}
/>
</div>
</LayoutProvider>
);
}

export const GCE_PREDICTIVE_AUTOSCALING = 'spinnaker.gce.predictiveAutoscaling';
module(GCE_PREDICTIVE_AUTOSCALING, []).component(
'gcePredictiveAutoscaling',
react2angular(GcePredictiveAutoscaling, ['policy', 'updatePolicy']),
);
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
</button>
</div>
</div>
<gce-predictive-autoscaling policy="$ctrl.policy" update-policy="$ctrl.updatePolicy">
</gce-predictive-autoscaling>
</div>
<button
ng-hide="$ctrl.showMetric('cpuUtilization')"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ module(GOOGLE_AUTOSCALINGPOLICY_COMPONENTS_METRICSETTINGS_METRICSETTINGS_COMPONE
bindings: {
policy: '=',
showNoMetricsWarning: '=',
updatePolicy: '<',
},
templateUrl: require('./metricSettings.component.html'),
controller: function() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// todo(mneterval): remove when GCE Autoscaling Controls are entirely converted to React & Formik
.gce-scale-in-controls {
.gce-autoscaling-layout {
.checkbox {
margin-left: 5px;
margin-top: 7px;
Expand Down
2 changes: 2 additions & 0 deletions app/scripts/modules/google/src/autoscalingPolicy/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './IGceAutoscalingPolicy';
export * from './GceAutoScalingFieldLayout';
2 changes: 2 additions & 0 deletions app/scripts/modules/google/src/gce.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { IAP_INTERCEPTOR } from 'google/interceptors/iap.interceptor';
import { LOAD_BALANCER_SET_TRANSFORMER } from './loadBalancer/loadBalancer.setTransformer';
import { GCE_SERVER_GROUP_DISK_DESCRIPTIONS } from './serverGroup/details/ServerGroupDiskDescriptions';
import { GCE_SCALE_IN_CONTROLS } from './serverGroup/details/autoscalingPolicy/modal/GceScaleInControls';
import { GCE_PREDICTIVE_AUTOSCALING } from './autoscalingPolicy/components/metricSettings/GcePredictiveAutoscaling';
import { GceImageReader } from './image';
import './help/gce.help';

Expand Down Expand Up @@ -66,6 +67,7 @@ module(GOOGLE_MODULE, [
IAP_INTERCEPTOR,
GCE_SERVER_GROUP_DISK_DESCRIPTIONS,
GCE_SCALE_IN_CONTROLS,
GCE_PREDICTIVE_AUTOSCALING,
GOOGLE_SERVERGROUP_DETAILS_SERVERGROUP_DETAILS_GCE_MODULE,
GOOGLE_SERVERGROUP_CONFIGURE_SERVERGROUPCOMMANDBUILDER_SERVICE,
GOOGLE_SERVERGROUP_CONFIGURE_WIZARD_CLONESERVERGROUP_GCE_CONTROLLER,
Expand Down
3 changes: 3 additions & 0 deletions app/scripts/modules/google/src/gce.settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ export interface IGCEProviderSettings extends IProviderSettings {
zone?: string;
instanceTypeStorage?: IInstanceStorage;
};
feature?: {
predictiveAutoscaling?: boolean;
};
}

export const GCEProviderSettings: IGCEProviderSettings = (SETTINGS.providers.gce as IGCEProviderSettings) || {
Expand Down
2 changes: 2 additions & 0 deletions app/scripts/modules/google/src/help/gce.help.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ const helpContents: { [key: string]: string } = {
'How long to wait before collecting information from a new instance. This should be at least the time it takes to initialize the instance.',
'gce.serverGroup.scalingPolicy.cpuUtilization':
'Autoscaler adds or removes instances to maintain this CPU usage on each instance.',
'gce.serverGroup.scalingPolicy.predictiveAutoscaling':
'Autoscaler adds or removes instances based on forecasted load. You must set a CPU utilization target to enable predictive autoscaling.',
'gce.serverGroup.scalingPolicy.loadBalancingUtilization':
'Autoscaler adds or removes instances to maintain this usage of load-balancing capacity.',
'gce.serverGroup.scalingPolicy.customMetricUtilizations':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
<dd ng-repeat-end>
<div ng-repeat="target in basis.targets">{{target}}</div>
</dd>
<dt ng-if="$ctrl.predictiveAutoscalingEnabled">
Predictive Autoscaling
</dt>
<dd ng-if="$ctrl.predictiveAutoscalingEnabled">
{{$ctrl.policy.cpuUtilization.predictiveMethod}}
</dd>
<dt>
Min # VMs
<help-field key="gce.serverGroup.autoscaling.minVMs"></help-field>
Expand Down Expand Up @@ -37,7 +43,7 @@
<dt ng-if="$ctrl.scaleInControlsConfigured">
Scale-in Time Window
</dt>
<dd ng-if="$ctrl.scaleDownInConfigured">{{$ctrl.timeWindowSecMessage}}</dd>
<dd ng-if="$ctrl.scaleInControlsConfigured">{{$ctrl.timeWindowSecMessage}}</dd>
<dt ng-if="$ctrl.serverGroup.autoscalingMessages">Messages</dt>
<dd ng-if="$ctrl.serverGroup.autoscalingMessages" ng-repeat="message in $ctrl.serverGroup.autoscalingMessages">
{{message}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { ConfirmationModalService, SETTINGS } from '@spinnaker/core';
import { GOOGLE_AUTOSCALINGPOLICY_AUTOSCALINGPOLICY_WRITE_SERVICE } from './../../../autoscalingPolicy/autoscalingPolicy.write.service';
import { GOOGLE_SERVERGROUP_DETAILS_AUTOSCALINGPOLICY_MODAL_UPSERTAUTOSCALINGPOLICY_MODAL_CONTROLLER } from './modal/upsertAutoscalingPolicy.modal.controller';
import ANGULAR_UI_BOOTSTRAP from 'angular-ui-bootstrap';
import { GCEProviderSettings } from '../../../gce.settings';

export const GOOGLE_SERVERGROUP_DETAILS_AUTOSCALINGPOLICY_AUTOSCALINGPOLICY_DIRECTIVE =
'spinnaker.gce.instance.details.scalingPolicy.directive';
Expand Down Expand Up @@ -93,6 +94,11 @@ module(GOOGLE_SERVERGROUP_DETAILS_AUTOSCALINGPOLICY_AUTOSCALINGPOLICY_DIRECTIVE,
this.timeWindowSecMessage = `${policy.scaleInControl.timeWindowSec} seconds`;
}

this.predictiveAutoscalingEnabled =
GCEProviderSettings.feature.predictiveAutoscaling &&
policy.cpuUtilization &&
policy.cpuUtilization.predictiveMethod;

this.editPolicy = () => {
$uibModal.open({
templateUrl: require('./modal/upsertAutoscalingPolicy.modal.html'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,13 @@ import { isEmpty } from 'lodash';

import { CheckboxInput, FormField, LayoutProvider, NumberInput, ReactSelectInput } from '@spinnaker/core';

import { GceAutoScalingFieldLayout } from './GceAutoScalingFieldLayout';
import { GceAutoScalingFieldLayout, IGceAutoscalingPolicy, IGceScaleInControl } from '../../../../autoscalingPolicy';

enum maxReplicasUnit {
fixed = 'fixed',
percent = 'percent',
}

interface IGceScaleInControl {
maxScaledInReplicas?: {
fixed?: number;
percent?: number;
};
timeWindowSec?: number;
}

interface IGceAutoscalingPolicy {
scaleInControl: IGceScaleInControl;
}

interface IGceScaleInControlsProps {
policy: IGceAutoscalingPolicy;
updatePolicy: (policy: IGceAutoscalingPolicy) => void;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ <h4 class="section-heading">Basic Settings</h4>
<gce-autoscaling-policy-basic-settings policy="ctrl.policy" update-policy="ctrl.updatePolicy" />
</div>
<h4 class="section-heading">Metric Types</h4>
<gce-autoscaling-policy-metric-settings show-no-metrics-warning="ctrl.showNoMetricsWarning" policy="ctrl.policy">
<gce-autoscaling-policy-metric-settings
show-no-metrics-warning="ctrl.showNoMetricsWarning"
policy="ctrl.policy"
update-policy="ctrl.updatePolicy"
>
</gce-autoscaling-policy-metric-settings>
</div>
</ng-form>
Expand Down

0 comments on commit 0be2a84

Please sign in to comment.