@spinnaker/titus 0.0.0-2025.1-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.
Files changed (185) hide show
  1. package/CHANGELOG.md +2661 -0
  2. package/LICENSE.txt +203 -0
  3. package/dist/domain/IJobDisruptionBudget.d.ts +35 -0
  4. package/dist/domain/ITitusCredentials.d.ts +5 -0
  5. package/dist/domain/ITitusInstance.d.ts +28 -0
  6. package/dist/domain/ITitusScalingPolicy.d.ts +4 -0
  7. package/dist/domain/ITitusServerGroup.d.ts +52 -0
  8. package/dist/domain/ITitusServiceJobProcesses.d.ts +3 -0
  9. package/dist/domain/index.d.ts +5 -0
  10. package/dist/help/titus.help.d.ts +1 -0
  11. package/dist/index.d.ts +6 -0
  12. package/dist/index.js +12828 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/instance/details/TitusInstanceDetails.d.ts +25 -0
  15. package/dist/instance/details/TitusInstanceDns.d.ts +8 -0
  16. package/dist/instance/details/TitusInstanceInformation.d.ts +7 -0
  17. package/dist/instance/details/index.d.ts +4 -0
  18. package/dist/instance/details/titusInstanceDetailsUtils.d.ts +14 -0
  19. package/dist/pipeline/stages/cloneServerGroup/cloneServerGroupExecutionDetails.controller.d.ts +2 -0
  20. package/dist/pipeline/stages/cloneServerGroup/titusCloneServerGroupStage.d.ts +2 -0
  21. package/dist/pipeline/stages/destroyAsg/titusDestroyAsgStage.d.ts +2 -0
  22. package/dist/pipeline/stages/disableAsg/titusDisableAsgStage.d.ts +2 -0
  23. package/dist/pipeline/stages/disableCluster/titusDisableClusterStage.d.ts +2 -0
  24. package/dist/pipeline/stages/enableAsg/titusEnableAsgStage.d.ts +2 -0
  25. package/dist/pipeline/stages/findAmi/titusFindAmiStage.d.ts +2 -0
  26. package/dist/pipeline/stages/resizeAsg/titusResizeAsgStage.d.ts +2 -0
  27. package/dist/pipeline/stages/runJob/RunJobExecutionDetails.d.ts +16 -0
  28. package/dist/pipeline/stages/runJob/TitusRunJobStageConfig.d.ts +25 -0
  29. package/dist/pipeline/stages/runJob/TitusSecurityGroupPicker.d.ts +34 -0
  30. package/dist/pipeline/stages/runJob/titusRunJobStage.d.ts +1 -0
  31. package/dist/pipeline/stages/scaleDownCluster/titusScaleDownClusterStage.d.ts +2 -0
  32. package/dist/pipeline/stages/shrinkCluster/titusShrinkClusterStage.d.ts +2 -0
  33. package/dist/reactShims/index.d.ts +1 -0
  34. package/dist/reactShims/titus.react.injector.d.ts +11 -0
  35. package/dist/reactShims/titus.react.module.d.ts +1 -0
  36. package/dist/securityGroup/securityGroup.read.service.d.ts +2 -0
  37. package/dist/serverGroup/configure/ServerGroupCommandBuilder.d.ts +2 -0
  38. package/dist/serverGroup/configure/serverGroup.configure.titus.module.d.ts +2 -0
  39. package/dist/serverGroup/configure/serverGroupConfiguration.service.d.ts +89 -0
  40. package/dist/serverGroup/configure/wizard/TitusCloneServerGroupModal.d.ts +31 -0
  41. package/dist/serverGroup/configure/wizard/pages/ServerGroupBasicSettings.d.ts +28 -0
  42. package/dist/serverGroup/configure/wizard/pages/ServerGroupParameters.d.ts +15 -0
  43. package/dist/serverGroup/configure/wizard/pages/ServerGroupResources.d.ts +11 -0
  44. package/dist/serverGroup/configure/wizard/pages/TitusMapLayout.d.ts +4 -0
  45. package/dist/serverGroup/configure/wizard/pages/disruptionBudget/JobDisruptionBudget.d.ts +40 -0
  46. package/dist/serverGroup/configure/wizard/pages/disruptionBudget/PolicyOptions.d.ts +2 -0
  47. package/dist/serverGroup/configure/wizard/pages/disruptionBudget/RateOptions.d.ts +2 -0
  48. package/dist/serverGroup/configure/wizard/pages/disruptionBudget/WindowPicker.d.ts +23 -0
  49. package/dist/serverGroup/configure/wizard/pages/index.d.ts +4 -0
  50. package/dist/serverGroup/details/TitusCapacityDetailsSection.d.ts +11 -0
  51. package/dist/serverGroup/details/TitusLaunchConfigSection.d.ts +9 -0
  52. package/dist/serverGroup/details/TitusPackageDetailsSection.d.ts +6 -0
  53. package/dist/serverGroup/details/TitusSecurityGroups.d.ts +17 -0
  54. package/dist/serverGroup/details/capacityDetailsSection.component.d.ts +1 -0
  55. package/dist/serverGroup/details/disruptionBudget/DisruptionBudgetSection.d.ts +19 -0
  56. package/dist/serverGroup/details/disruptionBudget/EditDisruptionBudgetModal.d.ts +14 -0
  57. package/dist/serverGroup/details/index.d.ts +5 -0
  58. package/dist/serverGroup/details/launchConfigSection.component.d.ts +1 -0
  59. package/dist/serverGroup/details/resize/TitusResizeServerGroupModal.d.ts +8 -0
  60. package/dist/serverGroup/details/resize/useTaskMonitor.d.ts +25 -0
  61. package/dist/serverGroup/details/rollback/rollbackServerGroup.controller.d.ts +2 -0
  62. package/dist/serverGroup/details/scalingActivity/TitusScalingActivitiesModal.d.ts +7 -0
  63. package/dist/serverGroup/details/scalingPolicy/CreateScalingPolicyButton.d.ts +21 -0
  64. package/dist/serverGroup/details/scalingPolicy/TitusCustomScalingPolicy.d.ts +7 -0
  65. package/dist/serverGroup/details/scalingPolicy/createScalingPolicyButton.component.d.ts +1 -0
  66. package/dist/serverGroup/details/scalingPolicy/index.d.ts +3 -0
  67. package/dist/serverGroup/details/scalingPolicy/scalingPolicy.module.d.ts +1 -0
  68. package/dist/serverGroup/details/scalingPolicy/targetTracking/TitusTargetTrackingChart.d.ts +9 -0
  69. package/dist/serverGroup/details/scalingPolicy/targetTracking/UpsertTargetTrackingModal.d.ts +10 -0
  70. package/dist/serverGroup/details/scalingPolicy/titusCustomScalingPolicy.component.d.ts +1 -0
  71. package/dist/serverGroup/details/scalingPolicy/upsert/TitusScalingPolicyCommandBuilderService.d.ts +10 -0
  72. package/dist/serverGroup/details/scalingPolicy/upsert/UpsertScalingPolicyModal.d.ts +10 -0
  73. package/dist/serverGroup/details/sections/ITitusServerGroupDetailsSectionProps.d.ts +5 -0
  74. package/dist/serverGroup/details/serverGroupDetails.titus.controller.d.ts +2 -0
  75. package/dist/serverGroup/details/serviceJobProcesses/ServiceJobProcesses.d.ts +3 -0
  76. package/dist/serverGroup/details/serviceJobProcesses/ServiceJobProcessesSection.d.ts +7 -0
  77. package/dist/serverGroup/details/titusPackageDetailsSection.component.d.ts +1 -0
  78. package/dist/serverGroup/details/titusSecurityGroups.component.d.ts +1 -0
  79. package/dist/serverGroup/serverGroup.transformer.d.ts +2 -0
  80. package/dist/titus.module.d.ts +5 -0
  81. package/dist/titus.settings.d.ts +14 -0
  82. package/dist/validation/ApplicationNameValidator.d.ts +1 -0
  83. package/package.json +52 -0
  84. package/src/domain/IJobDisruptionBudget.ts +19 -0
  85. package/src/domain/ITitusCredentials.ts +6 -0
  86. package/src/domain/ITitusInstance.ts +30 -0
  87. package/src/domain/ITitusScalingPolicy.ts +5 -0
  88. package/src/domain/ITitusServerGroup.ts +56 -0
  89. package/src/domain/ITitusServiceJobProcesses.ts +3 -0
  90. package/src/domain/index.ts +5 -0
  91. package/src/help/titus.help.ts +99 -0
  92. package/src/index.ts +6 -0
  93. package/src/instance/details/TitusInstanceDetails.tsx +234 -0
  94. package/src/instance/details/TitusInstanceDns.tsx +40 -0
  95. package/src/instance/details/TitusInstanceInformation.tsx +42 -0
  96. package/src/instance/details/index.ts +4 -0
  97. package/src/instance/details/titusInstanceDetailsUtils.spec.ts +124 -0
  98. package/src/instance/details/titusInstanceDetailsUtils.ts +181 -0
  99. package/src/logo/titus.logo.less +5 -0
  100. package/src/logo/titus.logo.png +0 -0
  101. package/src/logo/titus.logo.svg +7 -0
  102. package/src/pipeline/stages/cloneServerGroup/cloneServerGroupExecutionDetails.controller.js +66 -0
  103. package/src/pipeline/stages/cloneServerGroup/cloneServerGroupExecutionDetails.html +46 -0
  104. package/src/pipeline/stages/cloneServerGroup/cloneServerGroupStage.html +106 -0
  105. package/src/pipeline/stages/cloneServerGroup/cloneServerGroupStepLabel.html +1 -0
  106. package/src/pipeline/stages/cloneServerGroup/titusCloneServerGroupStage.js +104 -0
  107. package/src/pipeline/stages/destroyAsg/destroyAsgStage.html +9 -0
  108. package/src/pipeline/stages/destroyAsg/destroyAsgStepLabel.html +1 -0
  109. package/src/pipeline/stages/destroyAsg/titusDestroyAsgStage.js +65 -0
  110. package/src/pipeline/stages/disableAsg/disableAsgStage.html +11 -0
  111. package/src/pipeline/stages/disableAsg/disableAsgStepLabel.html +1 -0
  112. package/src/pipeline/stages/disableAsg/titusDisableAsgStage.js +69 -0
  113. package/src/pipeline/stages/disableCluster/disableClusterStage.html +26 -0
  114. package/src/pipeline/stages/disableCluster/titusDisableClusterStage.js +85 -0
  115. package/src/pipeline/stages/enableAsg/enableAsgStage.html +11 -0
  116. package/src/pipeline/stages/enableAsg/enableAsgStepLabel.html +1 -0
  117. package/src/pipeline/stages/enableAsg/titusEnableAsgStage.js +73 -0
  118. package/src/pipeline/stages/findAmi/findAmiStage.html +24 -0
  119. package/src/pipeline/stages/findAmi/titusFindAmiStage.js +79 -0
  120. package/src/pipeline/stages/resizeAsg/resizeAsgStage.html +99 -0
  121. package/src/pipeline/stages/resizeAsg/resizeAsgStepLabel.html +1 -0
  122. package/src/pipeline/stages/resizeAsg/titusResizeAsgStage.js +125 -0
  123. package/src/pipeline/stages/runJob/RunJobExecutionDetails.tsx +165 -0
  124. package/src/pipeline/stages/runJob/TitusRunJobStageConfig.tsx +466 -0
  125. package/src/pipeline/stages/runJob/TitusSecurityGroupPicker.tsx +170 -0
  126. package/src/pipeline/stages/runJob/titusRunJobStage.ts +30 -0
  127. package/src/pipeline/stages/scaleDownCluster/scaleDownClusterStage.html +35 -0
  128. package/src/pipeline/stages/scaleDownCluster/titusScaleDownClusterStage.js +79 -0
  129. package/src/pipeline/stages/shrinkCluster/shrinkClusterStage.html +34 -0
  130. package/src/pipeline/stages/shrinkCluster/titusShrinkClusterStage.js +73 -0
  131. package/src/reactShims/index.ts +1 -0
  132. package/src/reactShims/titus.react.injector.ts +17 -0
  133. package/src/reactShims/titus.react.module.ts +10 -0
  134. package/src/securityGroup/securityGroup.read.service.js +15 -0
  135. package/src/serverGroup/configure/ServerGroupCommandBuilder.js +247 -0
  136. package/src/serverGroup/configure/serverGroup.configure.titus.module.js +9 -0
  137. package/src/serverGroup/configure/serverGroupCommandBuilder.spec.js +63 -0
  138. package/src/serverGroup/configure/serverGroupConfiguration.service.ts +410 -0
  139. package/src/serverGroup/configure/wizard/TitusCloneServerGroupModal.tsx +293 -0
  140. package/src/serverGroup/configure/wizard/pages/ServerGroupBasicSettings.tsx +339 -0
  141. package/src/serverGroup/configure/wizard/pages/ServerGroupParameters.less +5 -0
  142. package/src/serverGroup/configure/wizard/pages/ServerGroupParameters.tsx +217 -0
  143. package/src/serverGroup/configure/wizard/pages/ServerGroupResources.tsx +200 -0
  144. package/src/serverGroup/configure/wizard/pages/TitusMapLayout.less +3 -0
  145. package/src/serverGroup/configure/wizard/pages/TitusMapLayout.tsx +29 -0
  146. package/src/serverGroup/configure/wizard/pages/disruptionBudget/JobDisruptionBudget.tsx +285 -0
  147. package/src/serverGroup/configure/wizard/pages/disruptionBudget/PolicyOptions.tsx +112 -0
  148. package/src/serverGroup/configure/wizard/pages/disruptionBudget/RateOptions.tsx +89 -0
  149. package/src/serverGroup/configure/wizard/pages/disruptionBudget/WindowPicker.tsx +202 -0
  150. package/src/serverGroup/configure/wizard/pages/index.ts +4 -0
  151. package/src/serverGroup/details/TitusCapacityDetailsSection.tsx +66 -0
  152. package/src/serverGroup/details/TitusLaunchConfigSection.tsx +35 -0
  153. package/src/serverGroup/details/TitusPackageDetailsSection.tsx +40 -0
  154. package/src/serverGroup/details/TitusSecurityGroups.tsx +107 -0
  155. package/src/serverGroup/details/capacityDetailsSection.component.ts +12 -0
  156. package/src/serverGroup/details/disruptionBudget/DisruptionBudgetSection.tsx +226 -0
  157. package/src/serverGroup/details/disruptionBudget/EditDisruptionBudgetModal.tsx +92 -0
  158. package/src/serverGroup/details/index.ts +5 -0
  159. package/src/serverGroup/details/launchConfigSection.component.ts +12 -0
  160. package/src/serverGroup/details/resize/TitusResizeServerGroupModal.tsx +302 -0
  161. package/src/serverGroup/details/resize/useTaskMonitor.ts +30 -0
  162. package/src/serverGroup/details/rollback/rollbackServerGroup.controller.js +149 -0
  163. package/src/serverGroup/details/rollback/rollbackServerGroup.html +133 -0
  164. package/src/serverGroup/details/scalingActivity/TitusScalingActivitiesModal.tsx +81 -0
  165. package/src/serverGroup/details/scalingPolicy/CreateScalingPolicyButton.tsx +102 -0
  166. package/src/serverGroup/details/scalingPolicy/TitusCustomScalingPolicy.tsx +13 -0
  167. package/src/serverGroup/details/scalingPolicy/createScalingPolicyButton.component.ts +15 -0
  168. package/src/serverGroup/details/scalingPolicy/index.js +3 -0
  169. package/src/serverGroup/details/scalingPolicy/scalingPolicy.module.ts +7 -0
  170. package/src/serverGroup/details/scalingPolicy/targetTracking/TitusTargetTrackingChart.tsx +57 -0
  171. package/src/serverGroup/details/scalingPolicy/targetTracking/UpsertTargetTrackingModal.tsx +82 -0
  172. package/src/serverGroup/details/scalingPolicy/titusCustomScalingPolicy.component.ts +17 -0
  173. package/src/serverGroup/details/scalingPolicy/upsert/TitusScalingPolicyCommandBuilderService.ts +115 -0
  174. package/src/serverGroup/details/scalingPolicy/upsert/UpsertScalingPolicyModal.tsx +157 -0
  175. package/src/serverGroup/details/sections/ITitusServerGroupDetailsSectionProps.ts +6 -0
  176. package/src/serverGroup/details/serverGroupDetails.html +191 -0
  177. package/src/serverGroup/details/serverGroupDetails.titus.controller.js +457 -0
  178. package/src/serverGroup/details/serviceJobProcesses/ServiceJobProcesses.ts +12 -0
  179. package/src/serverGroup/details/serviceJobProcesses/ServiceJobProcessesSection.tsx +136 -0
  180. package/src/serverGroup/details/titusPackageDetailsSection.component.ts +12 -0
  181. package/src/serverGroup/details/titusSecurityGroups.component.ts +12 -0
  182. package/src/serverGroup/serverGroup.transformer.js +90 -0
  183. package/src/titus.module.ts +95 -0
  184. package/src/titus.settings.ts +22 -0
  185. package/src/validation/ApplicationNameValidator.ts +43 -0
@@ -0,0 +1,149 @@
1
+ 'use strict';
2
+
3
+ import { module } from 'angular';
4
+
5
+ import { get } from 'lodash';
6
+ import { SERVER_GROUP_WRITER, TaskMonitor } from '@spinnaker/core';
7
+
8
+ export const TITUS_SERVERGROUP_DETAILS_ROLLBACK_ROLLBACKSERVERGROUP_CONTROLLER =
9
+ 'spinnaker.titus.serverGroup.details.rollback.controller';
10
+ export const name = TITUS_SERVERGROUP_DETAILS_ROLLBACK_ROLLBACKSERVERGROUP_CONTROLLER; // for backwards compatibility
11
+ module(TITUS_SERVERGROUP_DETAILS_ROLLBACK_ROLLBACKSERVERGROUP_CONTROLLER, [SERVER_GROUP_WRITER]).controller(
12
+ 'titusRollbackServerGroupCtrl',
13
+ [
14
+ '$scope',
15
+ '$uibModalInstance',
16
+ 'serverGroupWriter',
17
+ 'application',
18
+ 'serverGroup',
19
+ 'previousServerGroup',
20
+ 'disabledServerGroups',
21
+ 'allServerGroups',
22
+ function (
23
+ $scope,
24
+ $uibModalInstance,
25
+ serverGroupWriter,
26
+ application,
27
+ serverGroup,
28
+ previousServerGroup,
29
+ disabledServerGroups,
30
+ allServerGroups,
31
+ ) {
32
+ $scope.serverGroup = serverGroup;
33
+ $scope.disabledServerGroups = disabledServerGroups.sort((a, b) => b.name.localeCompare(a.name));
34
+ $scope.allServerGroups = allServerGroups.sort((a, b) => b.name.localeCompare(a.name));
35
+ $scope.verification = {};
36
+
37
+ const desired = serverGroup.capacity.desired;
38
+
39
+ let rollbackType = 'EXPLICIT';
40
+
41
+ if (allServerGroups.length === 0 && serverGroup.entityTags) {
42
+ const previousServerGroup = get(serverGroup, 'entityTags.creationMetadata.value.previousServerGroup');
43
+ if (previousServerGroup) {
44
+ rollbackType = 'PREVIOUS_IMAGE';
45
+ $scope.previousServerGroup = {
46
+ name: previousServerGroup.name,
47
+ imageName: previousServerGroup.imageName,
48
+ };
49
+
50
+ if (previousServerGroup.imageId && previousServerGroup.imageId !== previousServerGroup.imageName) {
51
+ $scope.previousServerGroup.imageId = previousServerGroup.imageId;
52
+ }
53
+ }
54
+ }
55
+
56
+ let healthyPercent;
57
+ if (desired < 10) {
58
+ healthyPercent = 100;
59
+ } else if (desired < 20) {
60
+ // accept 1 instance in an unknown state during rollback
61
+ healthyPercent = 90;
62
+ } else {
63
+ healthyPercent = 95;
64
+ }
65
+
66
+ $scope.command = {
67
+ rollbackType: rollbackType,
68
+ rollbackContext: {
69
+ imageId: previousServerGroup ? previousServerGroup.imageId : undefined,
70
+ rollbackServerGroupName: serverGroup.name,
71
+ restoreServerGroupName: previousServerGroup ? previousServerGroup.name : undefined,
72
+ targetHealthyRollbackPercentage: healthyPercent,
73
+ delayBeforeDisableSeconds: 0,
74
+ },
75
+ targetGroups: serverGroup.targetGroups,
76
+ securityGroups: serverGroup.securityGroups,
77
+ };
78
+
79
+ $scope.minHealthy = function (percent) {
80
+ return Math.ceil((desired * percent) / 100);
81
+ };
82
+
83
+ if (application && application.attributes) {
84
+ if (application.attributes.platformHealthOnlyShowOverride && application.attributes.platformHealthOnly) {
85
+ $scope.command.interestingHealthProviderNames = ['Titus'];
86
+ }
87
+
88
+ $scope.command.platformHealthOnlyShowOverride = application.attributes.platformHealthOnlyShowOverride;
89
+ }
90
+
91
+ this.isValid = function () {
92
+ const command = $scope.command;
93
+ if (!$scope.verification.verified) {
94
+ return false;
95
+ }
96
+
97
+ if (rollbackType === 'PREVIOUS_IMAGE') {
98
+ // no need to validate when using an explicit image
99
+ return true;
100
+ }
101
+
102
+ return command.rollbackContext.restoreServerGroupName !== undefined;
103
+ };
104
+
105
+ $scope.taskMonitor = new TaskMonitor({
106
+ application: application,
107
+ title: 'Rollback ' + serverGroup.name,
108
+ modalInstance: $uibModalInstance,
109
+ });
110
+
111
+ this.rollback = function () {
112
+ if (!this.isValid()) {
113
+ return;
114
+ }
115
+
116
+ const submitMethod = function () {
117
+ return serverGroupWriter.rollbackServerGroup(serverGroup, application, $scope.command);
118
+ };
119
+
120
+ $scope.taskMonitor.submit(submitMethod);
121
+ };
122
+
123
+ this.cancel = function () {
124
+ $uibModalInstance.dismiss();
125
+ };
126
+
127
+ this.label = function (serverGroup) {
128
+ if (!serverGroup) {
129
+ return '';
130
+ }
131
+
132
+ if (!serverGroup.buildInfo || !serverGroup.buildInfo.images) {
133
+ return serverGroup.name;
134
+ }
135
+
136
+ let imageName = serverGroup.buildInfo.images[0];
137
+ if (imageName.indexOf('/') > 0) {
138
+ imageName = imageName.substring(imageName.indexOf('/') + 1);
139
+ }
140
+
141
+ return serverGroup.name + ' (' + imageName + ')';
142
+ };
143
+
144
+ this.group = function (serverGroup) {
145
+ return serverGroup.isDisabled ? 'Disabled Server Groups' : 'Enabled Server Groups';
146
+ };
147
+ },
148
+ ],
149
+ );
@@ -0,0 +1,133 @@
1
+ <div modal-page class="confirmation-modal">
2
+ <task-monitor monitor="taskMonitor"></task-monitor>
3
+ <form role="form">
4
+ <modal-close dismiss="$dismiss()"></modal-close>
5
+ <div class="modal-header">
6
+ <h4 class="modal-title">Rollback {{serverGroup.name}}</h4>
7
+ </div>
8
+ <div class="modal-body confirmation-modal">
9
+ <div class="row">
10
+ <div class="col-sm-3 sm-label-right">Restore to</div>
11
+ <div class="col-sm-7">
12
+ <ui-select
13
+ ng-model="command.rollbackContext.restoreServerGroupName"
14
+ class="form-control input-sm"
15
+ ng-if="command.rollbackType === 'EXPLICIT'"
16
+ >
17
+ <ui-select-match placeholder="Select...">{{ctrl.label($select.selected)}}</ui-select-match>
18
+ <ui-select-choices group-by="ctrl.group" repeat="serverGroup.name as serverGroup in allServerGroups">
19
+ <span ng-bind-html="ctrl.label(serverGroup)"></span>
20
+ </ui-select-choices>
21
+ </ui-select>
22
+ <div ng-if="command.rollbackType === 'PREVIOUS_IMAGE'" style="margin-top: 5px">
23
+ {{ previousServerGroup.name }} <span class="small">(no longer deployed)</span><br />
24
+ <span class="small">
25
+ <strong>Image</strong>: {{ previousServerGroup.imageName}}
26
+ <span ng-if="previousServerGroup.imageId">({{ previousServerGroup.imageId }})</span><br />
27
+ </span>
28
+ </div>
29
+ </div>
30
+ </div>
31
+
32
+ <div class="row" ng-if="command.platformHealthOnlyShowOverride">
33
+ <div class="col-sm-10 col-sm-offset-1">
34
+ <platform-health-override
35
+ command="command"
36
+ platform-health-type="'Titus'"
37
+ show-help-details="true"
38
+ field-columns="12"
39
+ >
40
+ </platform-health-override>
41
+ </div>
42
+ </div>
43
+
44
+ <task-reason command="command"></task-reason>
45
+
46
+ <div class="row">
47
+ <div class="col-sm-11 col-sm-offset-1">
48
+ Wait
49
+ <input
50
+ placeholder="0"
51
+ min="0"
52
+ type="number"
53
+ ng-model="command.rollbackContext.delayBeforeDisableSeconds"
54
+ class="form-control input-sm inline-number"
55
+ />
56
+ seconds before disabling <em>{{ ctrl.label(serverGroup) }}</em>.
57
+ </div>
58
+ </div>
59
+
60
+ <div class="row">
61
+ <div class="col-sm-11 col-sm-offset-1">
62
+ Consider rollback successful when
63
+ <input
64
+ type="number"
65
+ min="0"
66
+ max="100"
67
+ ng-model="command.rollbackContext.targetHealthyRollbackPercentage"
68
+ class="form-control input-sm inline-number"
69
+ />
70
+ percent of instances are healthy.
71
+ </div>
72
+ </div>
73
+
74
+ <div class="row">
75
+ <div class="col-sm-4 sm-label-right">Rollback Operations</div>
76
+ </div>
77
+ <div class="row" ng-if="command.rollbackType === 'EXPLICIT'">
78
+ <div class="col-sm-11 col-sm-offset-1">
79
+ <ol>
80
+ <li>Enable <em>{{ command.rollbackContext.restoreServerGroupName || 'previous server group' }}</em></li>
81
+ <li>
82
+ Resize <em>{{ command.rollbackContext.restoreServerGroupName || 'previous server group' }}</em> to [
83
+ <strong>min</strong>: {{serverGroup.capacity.desired}}, <strong>max</strong>: {{ serverGroup.capacity.max
84
+ }}, <strong>desired</strong>: {{ serverGroup.capacity.desired }} ]<br />(minimum capacity pinned at
85
+ {{serverGroup.capacity.desired}} to prevent autoscaling down during rollback)
86
+ </li>
87
+
88
+ <li ng-if="command.rollbackContext.targetHealthyRollbackPercentage < 100">
89
+ Wait for at least {{minHealthy(command.rollbackContext.targetHealthyRollbackPercentage)}} instances to
90
+ report as healthy
91
+ </li>
92
+ <li>Disable {{ serverGroup.name }}</li>
93
+ <li>
94
+ Restore minimum capacity of
95
+ <em>{{ command.rollbackContext.restoreServerGroupName || 'previous server group' }}</em> [
96
+ <strong>min</strong>: {{ serverGroup.capacity.min }} ]
97
+ </li>
98
+ </ol>
99
+ <p>This rollback will affect server groups in {{ serverGroup.account }} ({{ serverGroup.region }}).</p>
100
+ </div>
101
+ </div>
102
+ <div class="row" ng-if="command.rollbackType === 'PREVIOUS_IMAGE'">
103
+ <div class="col-sm-11 col-sm-offset-1">
104
+ <ol>
105
+ <li>
106
+ Deploy <em>{{ previousServerGroup.imageId }}</em> [ <strong>min</strong>:
107
+ {{serverGroup.capacity.desired}}, <strong>max</strong>: {{ serverGroup.capacity.max }},
108
+ <strong>desired</strong>: {{ serverGroup.capacity.desired }} ]<br />(minimum capacity pinned at
109
+ {{serverGroup.capacity.desired}} to prevent autoscaling down during deploy)
110
+ </li>
111
+ <li ng-if="command.rollbackContext.targetHealthyRollbackPercentage < 100">
112
+ Wait for at least {{minHealthy(command.rollbackContext.targetHealthyRollbackPercentage)}} instances to
113
+ report as healthy
114
+ </li>
115
+ <li>Disable <em>{{ serverGroup.name }}</em></li>
116
+ <li>
117
+ Restore minimum capacity of <em>new server group</em> [ <strong>min</strong>: {{ serverGroup.capacity.min
118
+ }} ]
119
+ </li>
120
+ </ol>
121
+ <p>This rollback will affect server groups in {{ serverGroup.account }} ({{ serverGroup.region }}).</p>
122
+ </div>
123
+ </div>
124
+ </div>
125
+ <aws-footer
126
+ action="ctrl.rollback()"
127
+ cancel="ctrl.cancel()"
128
+ is-valid="ctrl.isValid()"
129
+ account="serverGroup.account"
130
+ verification="verification"
131
+ ></aws-footer>
132
+ </form>
133
+ </div>
@@ -0,0 +1,81 @@
1
+ import { DateTime } from 'luxon';
2
+ import * as React from 'react';
3
+
4
+ import type { ICapacity, IModalComponentProps } from '@spinnaker/core';
5
+ import { ModalBody, ModalFooter, ModalHeader, ServerGroupReader, Spinner, useData } from '@spinnaker/core';
6
+
7
+ import type { ITitusServerGroup } from '../../../domain';
8
+
9
+ export interface ITitusScalingActivitiesProps extends IModalComponentProps {
10
+ serverGroup: ITitusServerGroup;
11
+ }
12
+
13
+ type JobState = 'Accepted' | 'KillInitiated' | 'Finished';
14
+
15
+ interface ITitusScalingEvent {
16
+ capacity: ICapacity;
17
+ date: string;
18
+ jobId: string;
19
+ jobState: JobState;
20
+ reasonCode: string;
21
+ reasonMessage: string;
22
+ }
23
+
24
+ export const TitusScalingActivitiesModal = ({ dismissModal, serverGroup }: ITitusScalingActivitiesProps) => {
25
+ const fetchScalingActivities = () => ServerGroupReader.getScalingActivities(serverGroup);
26
+
27
+ const { result: scalingActivities, status, error } = useData(fetchScalingActivities, [], [serverGroup.id]);
28
+ const loading = status === 'PENDING';
29
+
30
+ const formatDate = (date: string) => {
31
+ const newDate = new Date(date);
32
+ return DateTime.fromJSDate(newDate).toFormat('yyyy-MM-dd HH:mm:ss ZZZZ');
33
+ };
34
+
35
+ return (
36
+ <>
37
+ <ModalHeader>{`Scaling activities for ${serverGroup.name}`}</ModalHeader>
38
+ <ModalBody>
39
+ <div className="flex-1 heading-3">
40
+ {loading && (
41
+ <div className="horizontal center sp-margin-xl-yaxis">
42
+ <Spinner />
43
+ </div>
44
+ )}
45
+ {!loading && Boolean(error) && (
46
+ <div className="horizontal center sp-margin-xl-yaxis">
47
+ <h4>{`There was an error loading scaling activities for ${serverGroup.name}. Please try again later.`}</h4>
48
+ </div>
49
+ )}
50
+ {!loading && !error && !Boolean(scalingActivities.length) && (
51
+ <div className="horizontal center sp-margin-xl-yaxis">
52
+ <h4>{`No scaling activities found for ${serverGroup.name}.`}</h4>
53
+ </div>
54
+ )}
55
+ {!loading && !error && Boolean(scalingActivities.length) && (
56
+ <div className="middle sp-margin-xl-yaxis">
57
+ {scalingActivities.map((a: ITitusScalingEvent, i) => (
58
+ <div key={`${i}-${a.jobId}`} className="sp-margin-xl-yaxis">
59
+ <p className="clearfix">
60
+ <span className={`label label-${a.jobState !== 'KillInitiated' ? 'success' : 'danger'} pull-left`}>
61
+ {a.jobState}
62
+ </span>
63
+ <span className="label label-default pull-right">{formatDate(a.date)}</span>
64
+ </p>
65
+ <p>{`${a.reasonMessage} Desired capacity is ${a.capacity?.desired || 'unknown'}.`}</p>
66
+ </div>
67
+ ))}
68
+ </div>
69
+ )}
70
+ </div>
71
+ </ModalBody>
72
+ <ModalFooter
73
+ primaryActions={
74
+ <button className="btn btn-primary" onClick={dismissModal}>
75
+ Close
76
+ </button>
77
+ }
78
+ />
79
+ </>
80
+ );
81
+ };
@@ -0,0 +1,102 @@
1
+ import React from 'react';
2
+
3
+ import { PolicyTypeSelectionModal } from '@spinnaker/amazon';
4
+ import type { Application, IServerGroup } from '@spinnaker/core';
5
+ import { AccountService, ReactModal } from '@spinnaker/core';
6
+
7
+ import { TitusReactInjector } from '../../../reactShims';
8
+ import type { IUpsertTargetTrackingModalProps } from './targetTracking/UpsertTargetTrackingModal';
9
+ import { UpsertTargetTrackingModal } from './targetTracking/UpsertTargetTrackingModal';
10
+ import type { IUpsertScalingPolicyModalProps } from './upsert/UpsertScalingPolicyModal';
11
+ import { UpsertScalingPolicyModal } from './upsert/UpsertScalingPolicyModal';
12
+
13
+ export interface ICreateScalingPolicyButtonProps {
14
+ application: Application;
15
+ serverGroup: IServerGroup;
16
+ }
17
+
18
+ export interface ICreateScalingPolicyButtonState {
19
+ showSelection: boolean;
20
+ showModal: boolean;
21
+ typeSelection: string;
22
+ awsAccount: string;
23
+ }
24
+
25
+ export class CreateScalingPolicyButton extends React.Component<
26
+ ICreateScalingPolicyButtonProps,
27
+ ICreateScalingPolicyButtonState
28
+ > {
29
+ constructor(props: ICreateScalingPolicyButtonProps) {
30
+ super(props);
31
+ this.state = {
32
+ showSelection: false,
33
+ showModal: false,
34
+ typeSelection: null,
35
+ awsAccount: null,
36
+ };
37
+ AccountService.getAccountDetails(props.serverGroup.account).then((details) => {
38
+ this.setState({ awsAccount: details.awsAccount });
39
+ });
40
+ }
41
+
42
+ public handleClick = (): void => {
43
+ this.setState({ showSelection: true });
44
+ };
45
+
46
+ public createStepPolicy(): void {
47
+ const { serverGroup, application } = this.props;
48
+
49
+ const upsertProps = {
50
+ app: application,
51
+ policy: TitusReactInjector.titusServerGroupTransformer.constructNewStepScalingPolicyTemplate(serverGroup),
52
+ serverGroup,
53
+ } as IUpsertScalingPolicyModalProps;
54
+ const modalProps = { dialogClassName: 'wizard-modal modal-lg' };
55
+ ReactModal.show(UpsertScalingPolicyModal, upsertProps, modalProps);
56
+ }
57
+
58
+ public createTargetTrackingPolicy(): void {
59
+ const { serverGroup, application } = this.props;
60
+ const upsertProps = {
61
+ app: application,
62
+ policy: TitusReactInjector.titusServerGroupTransformer.constructNewTargetTrackingPolicyTemplate(serverGroup),
63
+ serverGroup,
64
+ } as IUpsertTargetTrackingModalProps;
65
+ const modalProps = { dialogClassName: 'wizard-modal modal-lg' };
66
+ ReactModal.show(UpsertTargetTrackingModal, upsertProps, modalProps);
67
+ }
68
+
69
+ public typeSelected = (typeSelection: string): void => {
70
+ this.setState({ typeSelection, showSelection: false, showModal: true });
71
+ if (typeSelection === 'step') {
72
+ this.createStepPolicy();
73
+ }
74
+ if (typeSelection === 'targetTracking') {
75
+ this.createTargetTrackingPolicy();
76
+ }
77
+ };
78
+
79
+ public showModalCallback = (): void => {
80
+ this.setState({ showSelection: false, showModal: false, typeSelection: null });
81
+ };
82
+
83
+ public render() {
84
+ const { min, max } = this.props.serverGroup.capacity;
85
+ return (
86
+ <div>
87
+ {this.state.awsAccount ? (
88
+ <a className="clickable" onClick={this.handleClick}>
89
+ Create new scaling policy
90
+ </a>
91
+ ) : null}
92
+ {this.state.showSelection && (
93
+ <PolicyTypeSelectionModal
94
+ warnOnMinMaxCapacity={min === max}
95
+ typeSelectedCallback={this.typeSelected}
96
+ showCallback={this.showModalCallback}
97
+ />
98
+ )}
99
+ </div>
100
+ );
101
+ }
102
+ }
@@ -0,0 +1,13 @@
1
+ import type * as React from 'react';
2
+ import type { Application, IServerGroup } from '@spinnaker/core';
3
+ import { overridableComponent } from '@spinnaker/core';
4
+
5
+ export interface ITitusCustomScalingPolicyProps {
6
+ application: Application;
7
+ serverGroup: IServerGroup;
8
+ }
9
+
10
+ export const TitusCustomScalingPolicy: React.ComponentType<ITitusCustomScalingPolicyProps> = overridableComponent(
11
+ () => null,
12
+ 'titus.serverGroup.details.customScaling',
13
+ );
@@ -0,0 +1,15 @@
1
+ import { module } from 'angular';
2
+ import { react2angular } from 'react2angular';
3
+
4
+ import { withErrorBoundary } from '@spinnaker/core';
5
+
6
+ import { CreateScalingPolicyButton } from './CreateScalingPolicyButton';
7
+
8
+ export const TITUS_CREATE_SCALING_POLICY_BUTTON = 'spinnaker.titus.serverGroup.details.scaling.policy.button';
9
+ module(TITUS_CREATE_SCALING_POLICY_BUTTON, []).component(
10
+ 'titusCreateScalingPolicyButton',
11
+ react2angular(withErrorBoundary(CreateScalingPolicyButton, 'titusCreateScalingPolicyButton'), [
12
+ 'application',
13
+ 'serverGroup',
14
+ ]),
15
+ );
@@ -0,0 +1,3 @@
1
+ export * from './targetTracking/TitusTargetTrackingChart';
2
+ export { UpsertTargetTrackingModal as TitusUpsertTargetTrackingModal } from './targetTracking/UpsertTargetTrackingModal';
3
+ export { UpsertScalingPolicyModal as TitusUpsertScalingPolicyModal } from './upsert/UpsertScalingPolicyModal';
@@ -0,0 +1,7 @@
1
+ import { module } from 'angular';
2
+
3
+ import { TITUS_CREATE_SCALING_POLICY_BUTTON } from './createScalingPolicyButton.component';
4
+ import { TITUS_SERVERGROUP_CUSTOM_SCALING_COMPONENT } from './titusCustomScalingPolicy.component';
5
+
6
+ export const SCALING_POLICY_MODULE = 'spinnaker.titus.scalingPolicy.module';
7
+ module(SCALING_POLICY_MODULE, [TITUS_CREATE_SCALING_POLICY_BUTTON, TITUS_SERVERGROUP_CUSTOM_SCALING_COMPONENT]);
@@ -0,0 +1,57 @@
1
+ import * as React from 'react';
2
+
3
+ import type { IAmazonServerGroup, IScalingPolicyAlarm, ITargetTrackingConfiguration } from '@spinnaker/amazon';
4
+ import { MetricAlarmChart } from '@spinnaker/amazon';
5
+ import type { ICloudMetricStatistics } from '@spinnaker/core';
6
+
7
+ export interface ITitusTargetTrackingChartProps {
8
+ config: ITargetTrackingConfiguration;
9
+ serverGroup: IAmazonServerGroup;
10
+ unit?: string;
11
+ updateUnit?: (unit: string) => void;
12
+ }
13
+
14
+ export const TitusTargetTrackingChart = ({ config, serverGroup, unit, updateUnit }: ITitusTargetTrackingChartProps) => {
15
+ const [alarm, setAlarm] = React.useState<IScalingPolicyAlarm>({
16
+ alarmName: null,
17
+ alarmArn: null,
18
+ metricName: null,
19
+ namespace: null,
20
+ statistic: 'Average',
21
+ dimensions: [],
22
+ period: 60,
23
+ threshold: config.targetValue,
24
+ comparisonOperator: 'GreaterThanThreshold',
25
+ okactions: [],
26
+ insufficientDataActions: [],
27
+ alarmActions: [],
28
+ evaluationPeriods: null,
29
+ alarmDescription: null,
30
+ unit: null,
31
+ });
32
+
33
+ const synchronizeAlarm = () => {
34
+ const customMetric = config?.customizedMetricSpecification;
35
+ const updatedAlarm = {
36
+ ...alarm,
37
+ dimensions: customMetric?.dimensions,
38
+ metricName: customMetric?.metricName,
39
+ namespace: customMetric?.namespace,
40
+ statistic: customMetric?.statistic,
41
+ threshold: config?.targetValue,
42
+ };
43
+ setAlarm(updatedAlarm);
44
+ };
45
+
46
+ React.useEffect(() => {
47
+ synchronizeAlarm();
48
+ }, [config]);
49
+
50
+ const onChartLoaded = (stats: ICloudMetricStatistics) => {
51
+ if (unit) {
52
+ updateUnit(stats.unit);
53
+ }
54
+ };
55
+
56
+ return <MetricAlarmChart alarm={alarm} onChartLoaded={onChartLoaded} serverGroup={serverGroup} />;
57
+ };
@@ -0,0 +1,82 @@
1
+ import * as React from 'react';
2
+
3
+ import type {
4
+ IAmazonServerGroup,
5
+ ITargetTrackingPolicy,
6
+ ITargetTrackingPolicyCommand,
7
+ IUpsertScalingPolicyCommand,
8
+ } from '@spinnaker/amazon';
9
+ import { TargetMetricFields, TargetTrackingAdditionalSettings } from '@spinnaker/amazon';
10
+ import type { Application, IModalComponentProps } from '@spinnaker/core';
11
+ import { TaskMonitorModal } from '@spinnaker/core';
12
+
13
+ import type { ITitusServerGroup } from '../../../../domain';
14
+ import { TitusScalingPolicyCommandBuilder } from '../upsert/TitusScalingPolicyCommandBuilderService';
15
+
16
+ export interface IUpsertTargetTrackingModalProps extends IModalComponentProps {
17
+ app: Application;
18
+ policy: ITargetTrackingPolicy;
19
+ serverGroup: ITitusServerGroup;
20
+ }
21
+
22
+ export const UpsertTargetTrackingModal = ({
23
+ app,
24
+ closeModal,
25
+ dismissModal,
26
+ policy,
27
+ serverGroup,
28
+ }: IUpsertTargetTrackingModalProps) => {
29
+ const [isCustom, setIsCustom] = React.useState<boolean>(
30
+ Boolean(policy.targetTrackingConfiguration?.customizedMetricSpecification),
31
+ );
32
+
33
+ const [command, setCommand] = React.useState<IUpsertScalingPolicyCommand>({} as IUpsertScalingPolicyCommand);
34
+ React.useEffect(() => {
35
+ const baseCommand = TitusScalingPolicyCommandBuilder.buildNewCommand('TargetTracking', serverGroup, policy);
36
+ setCommand(baseCommand);
37
+ }, []);
38
+
39
+ const mode = policy.id ? 'Update' : 'Create';
40
+
41
+ return (
42
+ <TaskMonitorModal<IUpsertScalingPolicyCommand>
43
+ closeModal={closeModal}
44
+ dismissModal={dismissModal}
45
+ title={`${mode} scaling policy`}
46
+ application={app}
47
+ description={`${mode} scaling policy for ${serverGroup.name}`}
48
+ initialValues={command}
49
+ mapValuesToTask={() => ({
50
+ application: app,
51
+ job: [
52
+ {
53
+ type: 'upsertScalingPolicy',
54
+ ...command,
55
+ },
56
+ ],
57
+ })}
58
+ render={() => (
59
+ <div className="modal-body">
60
+ <h4 className="section-heading">Target Metric</h4>
61
+ <TargetMetricFields
62
+ allowDualMode={false}
63
+ cloudwatch={true}
64
+ command={command as ITargetTrackingPolicyCommand}
65
+ isCustomMetric={isCustom}
66
+ app={app}
67
+ serverGroup={(serverGroup as unknown) as IAmazonServerGroup}
68
+ toggleMetricType={(t) => setIsCustom(t === 'custom')}
69
+ updateCommand={setCommand}
70
+ />
71
+ <h4 className="section-heading">Additional Settings</h4>
72
+ <TargetTrackingAdditionalSettings
73
+ command={command}
74
+ cooldowns={true}
75
+ policyName={policy.policyName}
76
+ updateCommand={setCommand}
77
+ />
78
+ </div>
79
+ )}
80
+ />
81
+ );
82
+ };
@@ -0,0 +1,17 @@
1
+ import { module } from 'angular';
2
+ import { react2angular } from 'react2angular';
3
+
4
+ import { withErrorBoundary } from '@spinnaker/core';
5
+
6
+ import { TitusCustomScalingPolicy } from './TitusCustomScalingPolicy';
7
+
8
+ export const TITUS_SERVERGROUP_CUSTOM_SCALING_COMPONENT =
9
+ 'spinnaker.application.titus.serverGroup.customScaling.component';
10
+
11
+ module(TITUS_SERVERGROUP_CUSTOM_SCALING_COMPONENT, []).component(
12
+ 'titusCustomScalingPolicy',
13
+ react2angular(withErrorBoundary(TitusCustomScalingPolicy, 'titusCustomScalingPolicy'), [
14
+ 'application',
15
+ 'serverGroup',
16
+ ]),
17
+ );