diff --git a/packages/app/src/settings.js b/packages/app/src/settings.js index 6e25d5fe98d..11e09a39688 100644 --- a/packages/app/src/settings.js +++ b/packages/app/src/settings.js @@ -221,6 +221,9 @@ window.spinnakerSettings = { defaultSecurityGroups: [], }, gce: { + feature: { + predictiveAutoscaling: true, + }, defaults: { account: 'my-google-account', instanceTypeStorage: { diff --git a/packages/google/src/autoscalingPolicy/IGceAutoscalingPolicy.ts b/packages/google/src/autoscalingPolicy/IGceAutoscalingPolicy.ts index 71d4c9843e7..96958cb4397 100644 --- a/packages/google/src/autoscalingPolicy/IGceAutoscalingPolicy.ts +++ b/packages/google/src/autoscalingPolicy/IGceAutoscalingPolicy.ts @@ -18,5 +18,5 @@ export interface IGceAutoscalingCpuUtilization { export enum GcePredictiveMethod { NONE = 'NONE', - STANDARD = 'STANDARD', + STANDARD = 'OPTIMIZE_AVAILABILITY', } diff --git a/packages/google/src/autoscalingPolicy/components/metricSettings/metricSettings.component.html b/packages/google/src/autoscalingPolicy/components/metricSettings/metricSettings.component.html index 37e8483549e..1109cabdf61 100644 --- a/packages/google/src/autoscalingPolicy/components/metricSettings/metricSettings.component.html +++ b/packages/google/src/autoscalingPolicy/components/metricSettings/metricSettings.component.html @@ -3,7 +3,7 @@
-
+
Utilization Target (%)
@@ -97,12 +97,13 @@

+
Metric Identifier
-
+
-
+
-
- Utilization Target - +
Additional Filter Expression
+
+
-
- -
-
+
+ +
+
Metric Export Scope
+
+ >
-
- Utilization target must be greater than 0.0. +
+ +
+
+
Scaling Policy
+
+ +
+
+ +
+
+
Single Instance Assignment
+
+ +
+
+
+
+
+
+
+ Utilization Target + +
+
+ +
+
+ +
+
+ Utilization target must be greater than 0.0. +
@@ -143,9 +198,11 @@ Add custom metric -
-
- - At least one metric is required. +
+
+
+ + At least one metric is required. +
diff --git a/packages/google/src/autoscalingPolicy/components/metricSettings/metricSettings.component.js b/packages/google/src/autoscalingPolicy/components/metricSettings/metricSettings.component.js index 780e458c6e8..c3ceffa0ed4 100644 --- a/packages/google/src/autoscalingPolicy/components/metricSettings/metricSettings.component.js +++ b/packages/google/src/autoscalingPolicy/components/metricSettings/metricSettings.component.js @@ -30,6 +30,16 @@ module(GOOGLE_AUTOSCALINGPOLICY_COMPONENTS_METRICSETTINGS_METRICSETTINGS_COMPONE DELTA_PER_MINUTE: 'Delta / minute', }; + this.metricScopeTypesToDisplayMap = { + TIME_SERIES_PER_INSTANCE: 'Time series per instance', + SINGLE_TIME_SERIES_PER_GROUP: 'Single time series per group', + }; + + this.scalingpolicyTypesToDisplayMap = { + UTILIZATION_TARGET: 'Utilization target', + SINGLE_INSTANCE_ASSIGNMENT: 'singleInstanceAssignment', + }; + this.addMetric = (metricType) => { if (multipleAllowedFor[metricType]) { this.policy[metricType] = this.policy[metricType] || []; @@ -54,6 +64,14 @@ module(GOOGLE_AUTOSCALINGPOLICY_COMPONENTS_METRICSETTINGS_METRICSETTINGS_COMPONE return !emptyOrUndefined(metric); }; + this.isSingleTimeSeriesPerGroup = (scopeType, index) => { + if (this.policy.customMetricUtilizations[index].metricExportScope === scopeType) return true; + }; + + this.isScalingPolicySingleInstanceAssignment = (policyType, index) => { + if (this.policy.customMetricUtilizations[index].scalingpolicy === policyType) return true; + }; + this.showNoMetricsWarning = () => { return _.every( metricTypes.map((type) => { diff --git a/packages/google/src/autoscalingPolicy/components/scalingSchedules/scalingSchedules.component.html b/packages/google/src/autoscalingPolicy/components/scalingSchedules/scalingSchedules.component.html new file mode 100644 index 00000000000..be94bf1ef7c --- /dev/null +++ b/packages/google/src/autoscalingPolicy/components/scalingSchedules/scalingSchedules.component.html @@ -0,0 +1,84 @@ + +
+ +
+ +
+
Name
+
+ +
+
+ +
+
+
+
Description
+
+ +
+
+
+
Enabled
+ +
+
+
Minimum required instances
+
+ +
+
+
+
+ CRON Expression + +
+
+ +
+
+
+
Time Zone
+
+ +
+
+
+
Duration (seconds)
+
+ +
+
+ Must be greater than 300 seconds. +
+
+
+
+
+ +
+
diff --git a/packages/google/src/autoscalingPolicy/components/scalingSchedules/scalingSchedules.component.js b/packages/google/src/autoscalingPolicy/components/scalingSchedules/scalingSchedules.component.js new file mode 100644 index 00000000000..cd33bca6503 --- /dev/null +++ b/packages/google/src/autoscalingPolicy/components/scalingSchedules/scalingSchedules.component.js @@ -0,0 +1,59 @@ +'use strict'; + +import { module } from 'angular'; +import _ from 'lodash'; +import timezones from './standardTimezone.json'; + +export const GOOGLE_AUTOSCALINGPOLICY_COMPONENTS_SCALINGSCHEDULES_SCALINGSCHEDULES_COMPONENT = + 'spinnaker.deck.gce.autoscalingPolicy.scalingSchedules.component'; +export const name = GOOGLE_AUTOSCALINGPOLICY_COMPONENTS_SCALINGSCHEDULES_SCALINGSCHEDULES_COMPONENT; // for backwards compatibility +module(GOOGLE_AUTOSCALINGPOLICY_COMPONENTS_SCALINGSCHEDULES_SCALINGSCHEDULES_COMPONENT, []).component( + 'gceAutoscalingPolicyScalingSchedules', + { + bindings: { + policy: '=', + updatePolicy: '<', + }, + templateUrl: require('./scalingSchedules.component.html'), + controller: function () { + const multipleAllowedFor = { + scalingSchedules: true, + }; + + this.timezones = timezones; + + this.addSchedule = (scheduleType) => { + if (multipleAllowedFor[scheduleType]) { + this.policy[scheduleType] = this.policy[scheduleType] || []; + this.policy[scheduleType].push({}); + } else if (emptyOrUndefined(this.policy[scheduleType])) { + this.policy[scheduleType] = {}; + } + }; + + this.deleteSchedule = (scheduleType, index) => { + if (multipleAllowedFor[scheduleType]) { + this.policy[scheduleType].splice(index, 1); + } else { + // sending an empty object to the API deletes the policy. + this.policy[scheduleType] = {}; + } + }; + + this.selectTimezone = (timezone, index) => { + const { scalingSchedules } = this.policy; + const schedule = scalingSchedules[index]; + scalingSchedules[index] = { ...schedule, timezone }; + + this.updatePolicy({ + ...this.policy, + scalingSchedules: [...scalingSchedules], + }); + }; + + function emptyOrUndefined(value) { + return _.isEqual(value, {}) || _.isUndefined(value); + } + }, + }, +); diff --git a/packages/google/src/autoscalingPolicy/components/scalingSchedules/standardTimezone.json b/packages/google/src/autoscalingPolicy/components/scalingSchedules/standardTimezone.json new file mode 100644 index 00000000000..7444240908d --- /dev/null +++ b/packages/google/src/autoscalingPolicy/components/scalingSchedules/standardTimezone.json @@ -0,0 +1,596 @@ +[ + "Africa/Abidjan", + "Africa/Accra", + "Africa/Addis_Ababa", + "Africa/Algiers", + "Africa/Asmara", + "Africa/Asmera", + "Africa/Bamako", + "Africa/Bangui", + "Africa/Banjul", + "Africa/Bissau", + "Africa/Blantyre", + "Africa/Brazzaville", + "Africa/Bujumbura", + "Africa/Cairo", + "Africa/Casablanca", + "Africa/Ceuta", + "Africa/Conakry", + "Africa/Dakar", + "Africa/Dar_es_Salaam", + "Africa/Djibouti", + "Africa/Douala", + "Africa/El_Aaiun", + "Africa/Freetown", + "Africa/Gaborone", + "Africa/Harare", + "Africa/Johannesburg", + "Africa/Juba", + "Africa/Kampala", + "Africa/Khartoum", + "Africa/Kigali", + "Africa/Kinshasa", + "Africa/Lagos", + "Africa/Libreville", + "Africa/Lome", + "Africa/Luanda", + "Africa/Lubumbashi", + "Africa/Lusaka", + "Africa/Malabo", + "Africa/Maputo", + "Africa/Maseru", + "Africa/Mbabane", + "Africa/Mogadishu", + "Africa/Monrovia", + "Africa/Nairobi", + "Africa/Ndjamena", + "Africa/Niamey", + "Africa/Nouakchott", + "Africa/Ouagadougou", + "Africa/Porto-Novo", + "Africa/Sao_Tome", + "Africa/Timbuktu", + "Africa/Tripoli", + "Africa/Tunis", + "Africa/Windhoek", + "America/Adak", + "America/Anchorage", + "America/Anguilla", + "America/Antigua", + "America/Araguaina", + "America/Argentina/Buenos_Aires", + "America/Argentina/Catamarca", + "America/Argentina/ComodRivadavia", + "America/Argentina/Cordoba", + "America/Argentina/Jujuy", + "America/Argentina/La_Rioja", + "America/Argentina/Mendoza", + "America/Argentina/Rio_Gallegos", + "America/Argentina/Salta", + "America/Argentina/San_Juan", + "America/Argentina/San_Luis", + "America/Argentina/Tucuman", + "America/Argentina/Ushuaia", + "America/Aruba", + "America/Asuncion", + "America/Atikokan", + "America/Atka", + "America/Bahia", + "America/Bahia_Banderas", + "America/Barbados", + "America/Belem", + "America/Belize", + "America/Blanc-Sablon", + "America/Boa_Vista", + "America/Bogota", + "America/Boise", + "America/Buenos_Aires", + "America/Cambridge_Bay", + "America/Campo_Grande", + "America/Cancun", + "America/Caracas", + "America/Catamarca", + "America/Cayenne", + "America/Cayman", + "America/Chicago", + "America/Chihuahua", + "America/Coral_Harbour", + "America/Cordoba", + "America/Costa_Rica", + "America/Creston", + "America/Cuiaba", + "America/Curacao", + "America/Danmarkshavn", + "America/Dawson", + "America/Dawson_Creek", + "America/Denver", + "America/Detroit", + "America/Dominica", + "America/Edmonton", + "America/Eirunepe", + "America/El_Salvador", + "America/Ensenada", + "America/Fort_Nelson", + "America/Fort_Wayne", + "America/Fortaleza", + "America/Glace_Bay", + "America/Godthab", + "America/Goose_Bay", + "America/Grand_Turk", + "America/Grenada", + "America/Guadeloupe", + "America/Guatemala", + "America/Guayaquil", + "America/Guyana", + "America/Halifax", + "America/Havana", + "America/Hermosillo", + "America/Indiana/Indianapolis", + "America/Indiana/Knox", + "America/Indiana/Marengo", + "America/Indiana/Petersburg", + "America/Indiana/Tell_City", + "America/Indiana/Vevay", + "America/Indiana/Vincennes", + "America/Indiana/Winamac", + "America/Indianapolis", + "America/Inuvik", + "America/Iqaluit", + "America/Jamaica", + "America/Jujuy", + "America/Juneau", + "America/Kentucky/Louisville", + "America/Kentucky/Monticello", + "America/Knox_IN", + "America/Kralendijk", + "America/La_Paz", + "America/Lima", + "America/Los_Angeles", + "America/Louisville", + "America/Lower_Princes", + "America/Maceio", + "America/Managua", + "America/Manaus", + "America/Marigot", + "America/Martinique", + "America/Matamoros", + "America/Mazatlan", + "America/Mendoza", + "America/Menominee", + "America/Merida", + "America/Metlakatla", + "America/Mexico_City", + "America/Miquelon", + "America/Moncton", + "America/Monterrey", + "America/Montevideo", + "America/Montreal", + "America/Montserrat", + "America/Nassau", + "America/New_York", + "America/Nipigon", + "America/Nome", + "America/Noronha", + "America/North_Dakota/Beulah", + "America/North_Dakota/Center", + "America/North_Dakota/New_Salem", + "America/Nuuk", + "America/Ojinaga", + "America/Panama", + "America/Pangnirtung", + "America/Paramaribo", + "America/Phoenix", + "America/Port_of_Spain", + "America/Port-au-Prince", + "America/Porto_Acre", + "America/Porto_Velho", + "America/Puerto_Rico", + "America/Punta_Arenas", + "America/Rainy_River", + "America/Rankin_Inlet", + "America/Recife", + "America/Regina", + "America/Resolute", + "America/Rio_Branco", + "America/Rosario", + "America/Santa_Isabel", + "America/Santarem", + "America/Santiago", + "America/Santo_Domingo", + "America/Sao_Paulo", + "America/Scoresbysund", + "America/Shiprock", + "America/Sitka", + "America/St_Barthelemy", + "America/St_Johns", + "America/St_Kitts", + "America/St_Lucia", + "America/St_Thomas", + "America/St_Vincent", + "America/Swift_Current", + "America/Tegucigalpa", + "America/Thule", + "America/Thunder_Bay", + "America/Tijuana", + "America/Toronto", + "America/Tortola", + "America/Vancouver", + "America/Virgin", + "America/Whitehorse", + "America/Winnipeg", + "America/Yakutat", + "America/Yellowknife", + "Antarctica/Casey", + "Antarctica/Davis", + "Antarctica/DumontDUrville", + "Antarctica/Macquarie", + "Antarctica/Mawson", + "Antarctica/McMurdo", + "Antarctica/Palmer", + "Antarctica/Rothera", + "Antarctica/South_Pole", + "Antarctica/Syowa", + "Antarctica/Troll", + "Antarctica/Vostok", + "Arctic/Longyearbyen", + "Asia/Aden", + "Asia/Almaty", + "Asia/Amman", + "Asia/Anadyr", + "Asia/Aqtau", + "Asia/Aqtobe", + "Asia/Ashgabat", + "Asia/Ashkhabad", + "Asia/Atyrau", + "Asia/Baghdad", + "Asia/Bahrain", + "Asia/Baku", + "Asia/Bangkok", + "Asia/Barnaul", + "Asia/Beirut", + "Asia/Bishkek", + "Asia/Brunei", + "Asia/Calcutta", + "Asia/Chita", + "Asia/Choibalsan", + "Asia/Chongqing", + "Asia/Chungking", + "Asia/Colombo", + "Asia/Dacca", + "Asia/Damascus", + "Asia/Dhaka", + "Asia/Dili", + "Asia/Dubai", + "Asia/Dushanbe", + "Asia/Famagusta", + "Asia/Gaza", + "Asia/Harbin", + "Asia/Hebron", + "Asia/Ho_Chi_Minh", + "Asia/Hong_Kong", + "Asia/Hovd", + "Asia/Irkutsk", + "Asia/Istanbul", + "Asia/Jakarta", + "Asia/Jayapura", + "Asia/Jerusalem", + "Asia/Kabul", + "Asia/Kamchatka", + "Asia/Karachi", + "Asia/Kashgar", + "Asia/Kathmandu", + "Asia/Katmandu", + "Asia/Khandyga", + "Asia/Kolkata", + "Asia/Krasnoyarsk", + "Asia/Kuala_Lumpur", + "Asia/Kuching", + "Asia/Kuwait", + "Asia/Macao", + "Asia/Macau", + "Asia/Magadan", + "Asia/Makassar", + "Asia/Manila", + "Asia/Muscat", + "Asia/Nicosia", + "Asia/Novokuznetsk", + "Asia/Novosibirsk", + "Asia/Omsk", + "Asia/Oral", + "Asia/Phnom_Penh", + "Asia/Pontianak", + "Asia/Pyongyang", + "Asia/Qatar", + "Asia/Qostanay", + "Asia/Qyzylorda", + "Asia/Rangoon", + "Asia/Riyadh", + "Asia/Saigon", + "Asia/Sakhalin", + "Asia/Samarkand", + "Asia/Seoul", + "Asia/Shanghai", + "Asia/Singapore", + "Asia/Srednekolymsk", + "Asia/Taipei", + "Asia/Tashkent", + "Asia/Tbilisi", + "Asia/Tehran", + "Asia/Tel_Aviv", + "Asia/Thimbu", + "Asia/Thimphu", + "Asia/Tokyo", + "Asia/Tomsk", + "Asia/Ujung_Pandang", + "Asia/Ulaanbaatar", + "Asia/Ulan_Bator", + "Asia/Urumqi", + "Asia/Ust-Nera", + "Asia/Vientiane", + "Asia/Vladivostok", + "Asia/Yakutsk", + "Asia/Yangon", + "Asia/Yekaterinburg", + "Asia/Yerevan", + "Atlantic/Azores", + "Atlantic/Bermuda", + "Atlantic/Canary", + "Atlantic/Cape_Verde", + "Atlantic/Faeroe", + "Atlantic/Faroe", + "Atlantic/Jan_Mayen", + "Atlantic/Madeira", + "Atlantic/Reykjavik", + "Atlantic/South_Georgia", + "Atlantic/St_Helena", + "Atlantic/Stanley", + "Australia/ACT", + "Australia/Adelaide", + "Australia/Brisbane", + "Australia/Broken_Hill", + "Australia/Canberra", + "Australia/Currie", + "Australia/Darwin", + "Australia/Eucla", + "Australia/Hobart", + "Australia/LHI", + "Australia/Lindeman", + "Australia/Lord_Howe", + "Australia/Melbourne", + "Australia/North", + "Australia/NSW", + "Australia/Perth", + "Australia/Queensland", + "Australia/South", + "Australia/Sydney", + "Australia/Tasmania", + "Australia/Victoria", + "Australia/West", + "Australia/Yancowinna", + "Brazil/Acre", + "Brazil/DeNoronha", + "Brazil/East", + "Brazil/West", + "Canada/Atlantic", + "Canada/Central", + "Canada/Eastern", + "Canada/Mountain", + "Canada/Newfoundland", + "Canada/Pacific", + "Canada/Saskatchewan", + "Canada/Yukon", + "CET", + "Chile/Continental", + "Chile/EasterIsland", + "CST6CDT", + "Cuba", + "EET", + "Egypt", + "Eire", + "EST", + "EST5EDT", + "Etc/GMT", + "Etc/GMT-0", + "Etc/GMT-1", + "Etc/GMT-10", + "Etc/GMT-11", + "Etc/GMT-12", + "Etc/GMT-13", + "Etc/GMT-14", + "Etc/GMT-2", + "Etc/GMT-3", + "Etc/GMT-4", + "Etc/GMT-5", + "Etc/GMT-6", + "Etc/GMT-7", + "Etc/GMT-8", + "Etc/GMT-9", + "Etc/GMT+0", + "Etc/GMT+1", + "Etc/GMT+10", + "Etc/GMT+11", + "Etc/GMT+12", + "Etc/GMT+2", + "Etc/GMT+3", + "Etc/GMT+4", + "Etc/GMT+5", + "Etc/GMT+6", + "Etc/GMT+7", + "Etc/GMT+8", + "Etc/GMT+9", + "Etc/GMT0", + "Etc/Greenwich", + "Etc/UCT", + "Etc/Universal", + "Etc/UTC", + "Etc/Zulu", + "Europe/Amsterdam", + "Europe/Andorra", + "Europe/Astrakhan", + "Europe/Athens", + "Europe/Belfast", + "Europe/Belgrade", + "Europe/Berlin", + "Europe/Bratislava", + "Europe/Brussels", + "Europe/Bucharest", + "Europe/Budapest", + "Europe/Busingen", + "Europe/Chisinau", + "Europe/Copenhagen", + "Europe/Dublin", + "Europe/Gibraltar", + "Europe/Guernsey", + "Europe/Helsinki", + "Europe/Isle_of_Man", + "Europe/Istanbul", + "Europe/Jersey", + "Europe/Kaliningrad", + "Europe/Kiev", + "Europe/Kirov", + "Europe/Lisbon", + "Europe/Ljubljana", + "Europe/London", + "Europe/Luxembourg", + "Europe/Madrid", + "Europe/Malta", + "Europe/Mariehamn", + "Europe/Minsk", + "Europe/Monaco", + "Europe/Moscow", + "Europe/Nicosia", + "Europe/Oslo", + "Europe/Paris", + "Europe/Podgorica", + "Europe/Prague", + "Europe/Riga", + "Europe/Rome", + "Europe/Samara", + "Europe/San_Marino", + "Europe/Sarajevo", + "Europe/Saratov", + "Europe/Simferopol", + "Europe/Skopje", + "Europe/Sofia", + "Europe/Stockholm", + "Europe/Tallinn", + "Europe/Tirane", + "Europe/Tiraspol", + "Europe/Ulyanovsk", + "Europe/Uzhgorod", + "Europe/Vaduz", + "Europe/Vatican", + "Europe/Vienna", + "Europe/Vilnius", + "Europe/Volgograd", + "Europe/Warsaw", + "Europe/Zagreb", + "Europe/Zaporozhye", + "Europe/Zurich", + "GB", + "GB-Eire", + "GMT", + "GMT-0", + "GMT+0", + "GMT0", + "Greenwich", + "Hongkong", + "HST", + "Iceland", + "Indian/Antananarivo", + "Indian/Chagos", + "Indian/Christmas", + "Indian/Cocos", + "Indian/Comoro", + "Indian/Kerguelen", + "Indian/Mahe", + "Indian/Maldives", + "Indian/Mauritius", + "Indian/Mayotte", + "Indian/Reunion", + "Iran", + "Israel", + "Jamaica", + "Japan", + "Kwajalein", + "Libya", + "MET", + "Mexico/BajaNorte", + "Mexico/BajaSur", + "Mexico/General", + "MST", + "MST7MDT", + "Navajo", + "NZ", + "NZ-CHAT", + "Pacific/Apia", + "Pacific/Auckland", + "Pacific/Bougainville", + "Pacific/Chatham", + "Pacific/Chuuk", + "Pacific/Easter", + "Pacific/Efate", + "Pacific/Enderbury", + "Pacific/Fakaofo", + "Pacific/Fiji", + "Pacific/Funafuti", + "Pacific/Galapagos", + "Pacific/Gambier", + "Pacific/Guadalcanal", + "Pacific/Guam", + "Pacific/Honolulu", + "Pacific/Johnston", + "Pacific/Kanton", + "Pacific/Kiritimati", + "Pacific/Kosrae", + "Pacific/Kwajalein", + "Pacific/Majuro", + "Pacific/Marquesas", + "Pacific/Midway", + "Pacific/Nauru", + "Pacific/Niue", + "Pacific/Norfolk", + "Pacific/Noumea", + "Pacific/Pago_Pago", + "Pacific/Palau", + "Pacific/Pitcairn", + "Pacific/Pohnpei", + "Pacific/Ponape", + "Pacific/Port_Moresby", + "Pacific/Rarotonga", + "Pacific/Saipan", + "Pacific/Samoa", + "Pacific/Tahiti", + "Pacific/Tarawa", + "Pacific/Tongatapu", + "Pacific/Truk", + "Pacific/Wake", + "Pacific/Wallis", + "Pacific/Yap", + "Poland", + "Portugal", + "PRC", + "PST8PDT", + "ROC", + "ROK", + "Singapore", + "Turkey", + "UCT", + "Universal", + "US/Alaska", + "US/Aleutian", + "US/Arizona", + "US/Central", + "US/East-Indiana", + "US/Eastern", + "US/Hawaii", + "US/Indiana-Starke", + "US/Michigan", + "US/Mountain", + "US/Pacific", + "US/Samoa", + "UTC", + "W-SU", + "WET", + "Zulu" +] diff --git a/packages/google/src/autoscalingPolicy/components/scalingSchedules/timeZoneSelect.tsx b/packages/google/src/autoscalingPolicy/components/scalingSchedules/timeZoneSelect.tsx new file mode 100644 index 00000000000..49bf82b334a --- /dev/null +++ b/packages/google/src/autoscalingPolicy/components/scalingSchedules/timeZoneSelect.tsx @@ -0,0 +1,63 @@ +import { module } from 'angular'; +import { chain } from 'lodash'; +import React from 'react'; +import type { AutocompleteResult, Option } from 'react-select'; +import { Async } from 'react-select'; +import { react2angular } from 'react2angular'; +import { withErrorBoundary } from '@spinnaker/core'; + +interface ITimezoneSelectProps { + availableTimezones: string[]; + selectedTimezone: string; + selectTimezone: (timezone: string, target?: any) => void; + target?: any; +} + +export class TimezoneSelect extends React.Component { + private loadOptions = (inputValue: string): Promise> => { + return new Promise((resolve) => { + if (!inputValue || inputValue.length < 3) { + resolve({ + options: [], + complete: false, + }); + } else { + const filteredOptions = chain(this.props.availableTimezones) + .filter((i) => i.toLowerCase().includes(inputValue)) + .map((i) => ({ value: i, label: i })) + .value(); + resolve({ + options: filteredOptions, + complete: false, + }); + } + }); + }; + + public render() { + return ( + ) => this.props.selectTimezone(selected.value, this.props.target)} + placeholder="Type at least 3 characters to search for an timezone..." + searchPromptText="Type at least 3 characters to search for an timezone..." + value={{ value: this.props.selectedTimezone, label: this.props.selectedTimezone }} + required={true} + /> + ); + } +} + +export const GCE_TIMEZONE_SELECT = 'spinnaker.gce.timezoneSelect'; +module(GCE_TIMEZONE_SELECT, []).component( + 'gceTimezoneSelect', + react2angular(withErrorBoundary(TimezoneSelect, 'gceTimezoneSelect'), [ + 'availableTimezones', + 'selectedTimezone', + 'selectTimezone', + 'target', + ]), +); diff --git a/packages/google/src/help/gce.help.ts b/packages/google/src/help/gce.help.ts index 98413e7557b..1504e111651 100644 --- a/packages/google/src/help/gce.help.ts +++ b/packages/google/src/help/gce.help.ts @@ -101,6 +101,14 @@ const helpContents: { [key: string]: string } = { 'Autoscaler adds or removes instances to maintain this usage of load-balancing capacity.', 'gce.serverGroup.scalingPolicy.customMetricUtilizations': 'Autoscaler adds or removes instances to maintain this usage for custom metric.', + 'gce.serverGroup.scalingPolicy.cronExpression': ` + Start time and recurrence using a cron expression. Examples:
+ Every day at 3 PM:
+ 0 15 * * *
+ Every week Monday to Friday at 8:30 AM:
+ 30 8 * * Mon-Fri
+ Once on 30 January 2030 at midnight:
+ 0 0 30 1 * 2030`, 'gce.serverGroup.imageName': '(Required) Image is the Google Compute Engine image. Images are restricted to the account selected.', 'gce.serverGroup.capacity': diff --git a/packages/google/src/serverGroup/configure/serverGroup.configure.gce.module.js b/packages/google/src/serverGroup/configure/serverGroup.configure.gce.module.js index 546fd4f01b6..e66cb8fa65e 100644 --- a/packages/google/src/serverGroup/configure/serverGroup.configure.gce.module.js +++ b/packages/google/src/serverGroup/configure/serverGroup.configure.gce.module.js @@ -4,6 +4,8 @@ import { module } from 'angular'; import { GOOGLE_AUTOSCALINGPOLICY_COMPONENTS_BASICSETTINGS_BASICSETTINGS_COMPONENT } from '../../autoscalingPolicy/components/basicSettings/basicSettings.component'; import { GOOGLE_AUTOSCALINGPOLICY_COMPONENTS_METRICSETTINGS_METRICSETTINGS_COMPONENT } from '../../autoscalingPolicy/components/metricSettings/metricSettings.component'; +import { GOOGLE_AUTOSCALINGPOLICY_COMPONENTS_SCALINGSCHEDULES_SCALINGSCHEDULES_COMPONENT } from '../../autoscalingPolicy/components/scalingSchedules/scalingSchedules.component'; +import { GCE_TIMEZONE_SELECT } from '../../autoscalingPolicy/components/scalingSchedules/timeZoneSelect'; import { GCE_CACHE_REFRESH } from '../../cache/cacheRefresh.component'; import { GCE_IMAGE_SELECT } from '../../image/ImageSelect'; import { GOOGLE_INSTANCE_CUSTOM_CUSTOMINSTANCEBUILDER_GCE_SERVICE } from './../../instance/custom/customInstanceBuilder.gce.service'; @@ -13,6 +15,7 @@ import { GCE_ACCELERATOR_CONFIGURER } from './wizard/advancedSettings/GceAcceler import { GOOGLE_SERVERGROUP_CONFIGURE_WIZARD_ADVANCEDSETTINGS_ADVANCEDSETTINGSSELECTOR_DIRECTIVE } from './wizard/advancedSettings/advancedSettingsSelector.directive'; import { GCE_DISK_CONFIGURER } from './wizard/advancedSettings/diskConfigurer.component'; import { GCE_AUTOHEALING_POLICY_SELECTOR } from './wizard/autoHealingPolicy/autoHealingPolicySelector.component'; +import { GCE_AUTOSCALING_POLICY_SELECTOR_COMPONENT } from './wizard/autoScalingPolicy/autoScalingPolicySelector.component'; import { GOOGLE_SERVERGROUP_CONFIGURE_WIZARD_CAPACITY_ADVANCEDCAPACITYSELECTOR_COMPONENT } from './wizard/capacity/advancedCapacitySelector.component'; import { GOOGLE_SERVERGROUP_CONFIGURE_WIZARD_CAPACITY_SIMPLECAPACITYSELECTOR_COMPONENT } from './wizard/capacity/simpleCapacitySelector.component'; import { GCE_CUSTOM_INSTANCE_CONFIGURER } from './wizard/customInstance/customInstanceConfigurer.component'; @@ -30,7 +33,9 @@ export const name = GOOGLE_SERVERGROUP_CONFIGURE_SERVERGROUP_CONFIGURE_GCE_MODUL module(GOOGLE_SERVERGROUP_CONFIGURE_SERVERGROUP_CONFIGURE_GCE_MODULE, [ GOOGLE_AUTOSCALINGPOLICY_COMPONENTS_BASICSETTINGS_BASICSETTINGS_COMPONENT, GOOGLE_AUTOSCALINGPOLICY_COMPONENTS_METRICSETTINGS_METRICSETTINGS_COMPONENT, + GOOGLE_AUTOSCALINGPOLICY_COMPONENTS_SCALINGSCHEDULES_SCALINGSCHEDULES_COMPONENT, GCE_LOAD_BALANCING_POLICY_SELECTOR, + GCE_AUTOSCALING_POLICY_SELECTOR_COMPONENT, GCE_AUTOHEALING_POLICY_SELECTOR, GOOGLE_INSTANCE_CUSTOM_CUSTOMINSTANCEBUILDER_GCE_SERVICE, GCE_CACHE_REFRESH, @@ -38,6 +43,7 @@ module(GOOGLE_SERVERGROUP_CONFIGURE_SERVERGROUP_CONFIGURE_GCE_MODULE, [ GCE_DISK_CONFIGURER, GCE_ACCELERATOR_CONFIGURER, GCE_IMAGE_SELECT, + GCE_TIMEZONE_SELECT, GOOGLE_SERVERGROUP_SERVERGROUP_TRANSFORMER, GOOGLE_SERVERGROUP_CONFIGURE_SERVERGROUPCONFIGURATION_SERVICE, GOOGLE_SERVERGROUP_CONFIGURE_WIZARD_ADVANCEDSETTINGS_ADVANCEDSETTINGSSELECTOR_DIRECTIVE, diff --git a/packages/google/src/serverGroup/configure/serverGroupConfiguration.service.js b/packages/google/src/serverGroup/configure/serverGroupConfiguration.service.js index e716a0dd482..c054b313610 100644 --- a/packages/google/src/serverGroup/configure/serverGroupConfiguration.service.js +++ b/packages/google/src/serverGroup/configure/serverGroupConfiguration.service.js @@ -151,6 +151,12 @@ angular networkReloader = refreshNetworks(command); } } + + // eslint-disable-next-line no-console + if (command.autoScalingPolicy) { + command.enableAutoScaling = true; + } + if (command.autoHealingPolicy) { command.enableAutoHealing = true; } diff --git a/packages/google/src/serverGroup/configure/wizard/autoScalingPolicy/autoScalingPolicy.html b/packages/google/src/serverGroup/configure/wizard/autoScalingPolicy/autoScalingPolicy.html new file mode 100644 index 00000000000..491cfa65bf3 --- /dev/null +++ b/packages/google/src/serverGroup/configure/wizard/autoScalingPolicy/autoScalingPolicy.html @@ -0,0 +1,20 @@ + +
+
+ Enable Autoscaling +
+
+ +
+
+
+ +
+
diff --git a/packages/google/src/serverGroup/configure/wizard/autoScalingPolicy/autoScalingPolicySelector.component.html b/packages/google/src/serverGroup/configure/wizard/autoScalingPolicy/autoScalingPolicySelector.component.html new file mode 100644 index 00000000000..7ff8bbfb5af --- /dev/null +++ b/packages/google/src/serverGroup/configure/wizard/autoScalingPolicy/autoScalingPolicySelector.component.html @@ -0,0 +1,21 @@ +
+
Basic Settings
+
+ + +
+
Metric Types
+ + +
Scaling Schedules
+
+ +
+
diff --git a/packages/google/src/serverGroup/configure/wizard/autoScalingPolicy/autoScalingPolicySelector.component.js b/packages/google/src/serverGroup/configure/wizard/autoScalingPolicy/autoScalingPolicySelector.component.js new file mode 100644 index 00000000000..b3d9d5583e5 --- /dev/null +++ b/packages/google/src/serverGroup/configure/wizard/autoScalingPolicy/autoScalingPolicySelector.component.js @@ -0,0 +1,47 @@ +/* eslint-disable no-debugger */ +import { IComponentOptions, module } from 'angular'; +import { cloneDeep } from 'lodash'; + +import { TaskMonitor } from '@spinnaker/core'; + +import { GOOGLE_AUTOSCALINGPOLICY_COMPONENTS_BASICSETTINGS_BASICSETTINGS_COMPONENT } from '../../../../autoscalingPolicy/components/basicSettings/basicSettings.component'; +import { GOOGLE_AUTOSCALINGPOLICY_COMPONENTS_METRICSETTINGS_METRICSETTINGS_COMPONENT } from '../../../../autoscalingPolicy/components/metricSettings/metricSettings.component'; +import { GOOGLE_AUTOSCALINGPOLICY_COMPONENTS_SCALINGSCHEDULES_SCALINGSCHEDULES_COMPONENT } from '../../../../autoscalingPolicy/components/scalingSchedules/scalingSchedules.component'; + +import './autoScalingPolicySelector.less'; + +const gceAutoScalingPolicySelectorComponent = { + bindings: { + policy: '<', + enabled: '<', + setAutoScalingPolicy: '&', + autoscalingPolicy: '<', + }, + templateUrl: require('./autoScalingPolicySelector.component.html'), + controller: 'gceUpsertAutoscalingPolicyCtrl', +}; + +export const GCE_AUTOSCALING_POLICY_SELECTOR_COMPONENT = 'spinnaker.gce.autoScalingPolicy.selector.component'; +module(GCE_AUTOSCALING_POLICY_SELECTOR_COMPONENT, [ + GOOGLE_AUTOSCALINGPOLICY_COMPONENTS_BASICSETTINGS_BASICSETTINGS_COMPONENT, + GOOGLE_AUTOSCALINGPOLICY_COMPONENTS_METRICSETTINGS_METRICSETTINGS_COMPONENT, + GOOGLE_AUTOSCALINGPOLICY_COMPONENTS_SCALINGSCHEDULES_SCALINGSCHEDULES_COMPONENT, +]) + .controller('gceUpsertAutoscalingPolicyCtrl', [ + '$scope', + function ($scope) { + var vm = this; + this.$onInit = function () { + this.policy = cloneDeep({}); + this.setAutoScalingPolicy({ autoscalingPolicy: this.policy }); + + this.updatePolicy = (updatedPolicy) => { + $scope.$applyAsync(() => { + this.policy = updatedPolicy; + this.setAutoScalingPolicy({ autoscalingPolicy: this.policy }); + }); + }; + }; + }, + ]) + .component('gceAutoScalingPolicySelectorComponent', gceAutoScalingPolicySelectorComponent); diff --git a/packages/google/src/serverGroup/configure/wizard/autoScalingPolicy/autoScalingPolicySelector.less b/packages/google/src/serverGroup/configure/wizard/autoScalingPolicy/autoScalingPolicySelector.less new file mode 100644 index 00000000000..6d700c7f4b9 --- /dev/null +++ b/packages/google/src/serverGroup/configure/wizard/autoScalingPolicy/autoScalingPolicySelector.less @@ -0,0 +1,15 @@ +.gce-scaling-policy-wizard { + .error-message { + margin-top: 4px; + } + + input.form-control, + select.form-control { + margin-bottom: 2px; + width: 100%; + } + + .schedule-container { + overflow: hidden; + } +} diff --git a/packages/google/src/serverGroup/configure/wizard/cloneServerGroup.gce.controller.js b/packages/google/src/serverGroup/configure/wizard/cloneServerGroup.gce.controller.js index 0c2b7dca410..b02aaf0b37f 100644 --- a/packages/google/src/serverGroup/configure/wizard/cloneServerGroup.gce.controller.js +++ b/packages/google/src/serverGroup/configure/wizard/cloneServerGroup.gce.controller.js @@ -2,7 +2,7 @@ import UIROUTER_ANGULARJS from '@uirouter/angularjs'; import * as angular from 'angular'; -import _ from 'lodash'; +import _, { isEmpty } from 'lodash'; import { FirewallLabels, INSTANCE_TYPE_SERVICE, ModalWizard, TaskMonitor } from '@spinnaker/core'; @@ -61,8 +61,9 @@ angular securityGroups: require('./securityGroups/securityGroups.html'), instanceType: require('./instanceType/instanceType.html'), capacity: require('./capacity/capacity.html'), - zones: require('./capacity/zones.html'), autoHealingPolicy: require('./autoHealingPolicy/autoHealingPolicy.html'), + autoScalingPolicy: require('./autoScalingPolicy/autoScalingPolicy.html'), + zones: require('./capacity/zones.html'), advancedSettings: require('./advancedSettings/advancedSettings.html'), }; @@ -155,7 +156,8 @@ angular .register({ page: 'capacity', subForm: 'capacitySubForm' }) .register({ page: 'zones', subForm: 'zonesSubForm' }) .register({ page: 'load-balancers', subForm: 'loadBalancerSubForm' }) - .register({ page: 'autohealing-policy', subForm: 'autoHealingPolicySubForm' }); + .register({ page: 'autohealing-policy', subForm: 'autoHealingPolicySubForm' }) + .register({ page: 'autoscaling-policy', subForm: 'autoScalingPolicySubForm' }); }) .catch((e) => { $log.error('Error generating server group command: ', e); @@ -261,6 +263,7 @@ angular this.isValid = function () { const selectedZones = $scope.command.selectZones && _.get($scope, 'command.distributionPolicy.zones.length') >= 1; + const autoScalingPolicy = $scope.command.autoscalingPolicy; return ( $scope.command && ($scope.command.viewState.disableImageSelection || $scope.command.image) && @@ -272,6 +275,11 @@ angular $scope.command.capacity.desired !== null && (!$scope.command.selectZones || selectedZones) && $scope.form.$valid && + (!autoScalingPolicy || + (autoScalingPolicy && + (!isEmpty(autoScalingPolicy.cpuUtilization) || + !isEmpty(autoScalingPolicy.customMetricUtilizations) || + !isEmpty(autoScalingPolicy.loadBalancingUtilization)))) && ModalWizard.isComplete() ); }; @@ -431,6 +439,16 @@ angular $scope.command.autoHealingPolicy = autoHealingPolicy; }; + this.onEnableAutoScalingChange = function () { + // Prevent empty auto-scaling policies from being overwritten by those of their ancestors + $scope.command.overwriteAncestorAutoScalingPolicy = + $scope.command.autoscalingPolicy != null && $scope.command.enableAutoScaling === false; + }; + + this.setAutoScalingPolicy = function (autoScalingPolicy) { + $scope.command.autoscalingPolicy = autoScalingPolicy; + }; + this.cancel = function () { $uibModalInstance.dismiss(); }; diff --git a/packages/google/src/serverGroup/configure/wizard/serverGroupWizard.html b/packages/google/src/serverGroup/configure/wizard/serverGroupWizard.html index 3fbce02bd3e..bcc72e86b7b 100644 --- a/packages/google/src/serverGroup/configure/wizard/serverGroupWizard.html +++ b/packages/google/src/serverGroup/configure/wizard/serverGroupWizard.html @@ -22,6 +22,9 @@ + + + diff --git a/packages/google/src/serverGroup/details/autoscalingPolicy/autoscalingPolicy.directive.js b/packages/google/src/serverGroup/details/autoscalingPolicy/autoscalingPolicy.directive.js index ba96bbd61c4..7ed0f7e50a0 100644 --- a/packages/google/src/serverGroup/details/autoscalingPolicy/autoscalingPolicy.directive.js +++ b/packages/google/src/serverGroup/details/autoscalingPolicy/autoscalingPolicy.directive.js @@ -6,9 +6,9 @@ import ANGULAR_UI_BOOTSTRAP from 'angular-ui-bootstrap'; import { ConfirmationModalService, SETTINGS } from '@spinnaker/core'; import { GOOGLE_AUTOSCALINGPOLICY_AUTOSCALINGPOLICY_WRITE_SERVICE } from './../../../autoscalingPolicy/autoscalingPolicy.write.service'; +import { GCE_AUTOSCALING_POLICY_SELECTOR_COMPONENT } from '../../configure/wizard/autoScalingPolicy/autoScalingPolicySelector.component'; import { GCEProviderSettings } from '../../../gce.settings'; import { GOOGLE_SERVERGROUP_DETAILS_AUTOSCALINGPOLICY_MODAL_UPSERTAUTOSCALINGPOLICY_MODAL_CONTROLLER } from './modal/upsertAutoscalingPolicy.modal.controller'; - export const GOOGLE_SERVERGROUP_DETAILS_AUTOSCALINGPOLICY_AUTOSCALINGPOLICY_DIRECTIVE = 'spinnaker.gce.instance.details.scalingPolicy.directive'; export const name = GOOGLE_SERVERGROUP_DETAILS_AUTOSCALINGPOLICY_AUTOSCALINGPOLICY_DIRECTIVE; // for backwards compatibility @@ -16,6 +16,7 @@ module(GOOGLE_SERVERGROUP_DETAILS_AUTOSCALINGPOLICY_AUTOSCALINGPOLICY_DIRECTIVE, ANGULAR_UI_BOOTSTRAP, GOOGLE_AUTOSCALINGPOLICY_AUTOSCALINGPOLICY_WRITE_SERVICE, GOOGLE_SERVERGROUP_DETAILS_AUTOSCALINGPOLICY_MODAL_UPSERTAUTOSCALINGPOLICY_MODAL_CONTROLLER, + GCE_AUTOSCALING_POLICY_SELECTOR_COMPONENT, ]).component('gceAutoscalingPolicy', { bindings: { policy: '=', @@ -27,106 +28,110 @@ module(GOOGLE_SERVERGROUP_DETAILS_AUTOSCALINGPOLICY_AUTOSCALINGPOLICY_DIRECTIVE, '$uibModal', 'gceAutoscalingPolicyWriter', function ($uibModal, gceAutoscalingPolicyWriter) { - const policy = this.policy; + var scope = this; + scope.$onInit = function () { + const policy = scope.policy; - policy.bases = []; + policy.bases = []; - if (policy.cpuUtilization) { - const basis = { - description: 'CPU Usage', - helpKey: 'gce.serverGroup.autoscaling.targetCPUUsage', - }; + if (policy.cpuUtilization) { + const basis = { + description: 'CPU Usage', + helpKey: 'gce.serverGroup.autoscaling.targetCPUUsage', + }; - if (policy.cpuUtilization.utilizationTarget) { - basis.targets = [Math.round(policy.cpuUtilization.utilizationTarget * 100) + '%']; + if (policy.cpuUtilization.utilizationTarget) { + basis.targets = [Math.round(policy.cpuUtilization.utilizationTarget * 100) + '%']; + } + + policy.bases.push(basis); } - policy.bases.push(basis); - } + if (policy.loadBalancingUtilization) { + const basis = { + description: 'HTTP Load Balancing Usage', + helpKey: 'gce.serverGroup.autoscaling.targetHTTPLoadBalancingUsage', + }; - if (policy.loadBalancingUtilization) { - const basis = { - description: 'HTTP Load Balancing Usage', - helpKey: 'gce.serverGroup.autoscaling.targetHTTPLoadBalancingUsage', - }; + if (policy.loadBalancingUtilization.utilizationTarget) { + basis.targets = [Math.round(policy.loadBalancingUtilization.utilizationTarget * 100) + '%']; + } - if (policy.loadBalancingUtilization.utilizationTarget) { - basis.targets = [Math.round(policy.loadBalancingUtilization.utilizationTarget * 100) + '%']; + policy.bases.push(basis); } - policy.bases.push(basis); - } + if (policy.customMetricUtilizations) { + const basis = { + description: policy.customMetricUtilizations.length > 1 ? 'Monitoring Metrics' : 'Monitoring Metric', + helpKey: 'gce.serverGroup.autoscaling.targetMetric', + }; - if (policy.customMetricUtilizations) { - const basis = { - description: policy.customMetricUtilizations.length > 1 ? 'Monitoring Metrics' : 'Monitoring Metric', - helpKey: 'gce.serverGroup.autoscaling.targetMetric', - }; + if (policy.customMetricUtilizations.length > 0) { + basis.targets = []; + policy.customMetricUtilizations.forEach((metric) => { + let target = metric.metric + ': ' + metric.utilizationTarget; - if (policy.customMetricUtilizations.length > 0) { - basis.targets = []; - policy.customMetricUtilizations.forEach((metric) => { - let target = metric.metric + ': ' + metric.utilizationTarget; + if (metric.utilizationTargetType === 'DELTA_PER_SECOND') { + target += '/sec'; + } else if (metric.utilizationTargetType === 'DELTA_PER_MINUTE') { + target += '/min'; + } - if (metric.utilizationTargetType === 'DELTA_PER_SECOND') { - target += '/sec'; - } else if (metric.utilizationTargetType === 'DELTA_PER_MINUTE') { - target += '/min'; - } + basis.targets.push(target); + }); + } - basis.targets.push(target); - }); + policy.bases.push(basis); } - policy.bases.push(basis); - } - - this.scaleInControlsConfigured = - policy.scaleInControl && - policy.scaleInControl.timeWindowSec && - policy.scaleInControl.maxScaledInReplicas && - (policy.scaleInControl.maxScaledInReplicas.percent || policy.scaleInControl.maxScaledInReplicas.fixed); - - if (this.scaleInControlsConfigured) { - this.maxScaledInReplicasMessage = policy.scaleInControl.maxScaledInReplicas.percent - ? `${policy.scaleInControl.maxScaledInReplicas.percent}%` - : `${policy.scaleInControl.maxScaledInReplicas.fixed}`; - - 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'), - controller: 'gceUpsertAutoscalingPolicyModalCtrl', - controllerAs: 'ctrl', - size: 'lg', - resolve: { - policy: () => this.policy, - application: () => this.application, - serverGroup: () => this.serverGroup, - }, - }); - }; + scope.scaleInControlsConfigured = + policy.scaleInControl && + policy.scaleInControl.timeWindowSec && + policy.scaleInControl.maxScaledInReplicas && + (policy.scaleInControl.maxScaledInReplicas.percent || policy.scaleInControl.maxScaledInReplicas.fixed); - this.deletePolicy = () => { - const taskMonitor = { - application: this.application, - title: `Deleting autoscaler for ${this.serverGroup.name}`, + if (scope.scaleInControlsConfigured) { + scope.maxScaledInReplicasMessage = policy.scaleInControl.maxScaledInReplicas.percent + ? `${policy.scaleInControl.maxScaledInReplicas.percent}%` + : `${policy.scaleInControl.maxScaledInReplicas.fixed}`; + + scope.timeWindowSecMessage = `${policy.scaleInControl.timeWindowSec} seconds`; + } + + scope.predictiveAutoscalingEnabled = + GCEProviderSettings.feature.predictiveAutoscaling && + policy.cpuUtilization && + policy.cpuUtilization.predictiveMethod; + + scope.editPolicy = () => { + $uibModal.open({ + templateUrl: require('./modal/upsertAutoscalingPolicy.modal.html'), + controller: 'gceUpsertAutoscalingPolicyModalCtrl', + controllerAs: 'ctrl', + size: 'lg', + resolve: { + policy: () => scope.policy, + application: () => scope.application, + serverGroup: () => scope.serverGroup, + }, + }); }; - ConfirmationModalService.confirm({ - header: `Really delete autoscaler for ${this.serverGroup.name}?`, - buttonText: 'Delete autoscaler', - account: this.serverGroup.account, - taskMonitorConfig: taskMonitor, - submitMethod: () => gceAutoscalingPolicyWriter.deleteAutoscalingPolicy(this.application, this.serverGroup), - }); + scope.deletePolicy = () => { + const taskMonitor = { + application: scope.application, + title: `Deleting autoscaler for ${scope.serverGroup.name}`, + }; + + ConfirmationModalService.confirm({ + header: `Really delete autoscaler for ${scope.serverGroup.name}?`, + buttonText: 'Delete autoscaler', + account: scope.serverGroup.account, + taskMonitorConfig: taskMonitor, + submitMethod: () => + gceAutoscalingPolicyWriter.deleteAutoscalingPolicy(scope.application, scope.serverGroup), + }); + }; }; }, ], diff --git a/packages/google/src/serverGroup/details/autoscalingPolicy/modal/GceScaleInControls.tsx b/packages/google/src/serverGroup/details/autoscalingPolicy/modal/GceScaleInControls.tsx index 77d0079504f..ae84ebd2cf0 100644 --- a/packages/google/src/serverGroup/details/autoscalingPolicy/modal/GceScaleInControls.tsx +++ b/packages/google/src/serverGroup/details/autoscalingPolicy/modal/GceScaleInControls.tsx @@ -35,10 +35,19 @@ const defaultScaleInControl: IGceScaleInControl = { function GceScaleInControls({ policy, updatePolicy }: IGceScaleInControlsProps) { function updateScaleInControl(scaleInControl: IGceScaleInControl) { - updatePolicy({ - ...policy, - scaleInControl, - }); + const scaleInControlExist = Object.keys(scaleInControl).length; + if (scaleInControlExist) { + updatePolicy({ + ...policy, + scaleInControl, + }); + } else { + const updatedPolicy: any = policy; + delete updatedPolicy['scaleInControl']; + updatePolicy({ + ...updatedPolicy, + }); + } } function getMaxReplicasUnit(): maxReplicasUnit { diff --git a/packages/google/src/serverGroup/details/autoscalingPolicy/modal/upsertAutoscalingPolicy.modal.controller.js b/packages/google/src/serverGroup/details/autoscalingPolicy/modal/upsertAutoscalingPolicy.modal.controller.js index 511fd5dca19..e019915c266 100644 --- a/packages/google/src/serverGroup/details/autoscalingPolicy/modal/upsertAutoscalingPolicy.modal.controller.js +++ b/packages/google/src/serverGroup/details/autoscalingPolicy/modal/upsertAutoscalingPolicy.modal.controller.js @@ -4,9 +4,12 @@ import { module } from 'angular'; import { cloneDeep } from 'lodash'; import { TaskMonitor } from '@spinnaker/core'; + import { GOOGLE_AUTOSCALINGPOLICY_AUTOSCALINGPOLICY_WRITE_SERVICE } from '../../../../autoscalingPolicy/autoscalingPolicy.write.service'; import { GOOGLE_AUTOSCALINGPOLICY_COMPONENTS_BASICSETTINGS_BASICSETTINGS_COMPONENT } from '../../../../autoscalingPolicy/components/basicSettings/basicSettings.component'; import { GOOGLE_AUTOSCALINGPOLICY_COMPONENTS_METRICSETTINGS_METRICSETTINGS_COMPONENT } from '../../../../autoscalingPolicy/components/metricSettings/metricSettings.component'; +import { GOOGLE_AUTOSCALINGPOLICY_COMPONENTS_SCALINGSCHEDULES_SCALINGSCHEDULES_COMPONENT } from '../../../../autoscalingPolicy/components/scalingSchedules/scalingSchedules.component'; +import { GOOGLE_SERVERGROUP_CONFIGURE_SERVERGROUP_CONFIGURE_GCE_MODULE } from '../../../configure/serverGroup.configure.gce.module'; import './upsertAutoscalingPolicy.modal.less'; @@ -17,6 +20,7 @@ module(GOOGLE_SERVERGROUP_DETAILS_AUTOSCALINGPOLICY_MODAL_UPSERTAUTOSCALINGPOLIC GOOGLE_AUTOSCALINGPOLICY_AUTOSCALINGPOLICY_WRITE_SERVICE, GOOGLE_AUTOSCALINGPOLICY_COMPONENTS_BASICSETTINGS_BASICSETTINGS_COMPONENT, GOOGLE_AUTOSCALINGPOLICY_COMPONENTS_METRICSETTINGS_METRICSETTINGS_COMPONENT, + GOOGLE_AUTOSCALINGPOLICY_COMPONENTS_SCALINGSCHEDULES_SCALINGSCHEDULES_COMPONENT, ]).controller('gceUpsertAutoscalingPolicyModalCtrl', [ 'policy', 'application', diff --git a/packages/google/src/serverGroup/details/autoscalingPolicy/modal/upsertAutoscalingPolicy.modal.html b/packages/google/src/serverGroup/details/autoscalingPolicy/modal/upsertAutoscalingPolicy.modal.html index 8cc520123f7..dd8c806c24e 100644 --- a/packages/google/src/serverGroup/details/autoscalingPolicy/modal/upsertAutoscalingPolicy.modal.html +++ b/packages/google/src/serverGroup/details/autoscalingPolicy/modal/upsertAutoscalingPolicy.modal.html @@ -17,6 +17,13 @@

Metric Types

update-policy="ctrl.updatePolicy" > +

Scaling Schedules

+
+ +